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/unicode.h"
88 #include "wine/debug.h"
89 #include "wine/list.h"
91 WINE_DEFAULT_DEBUG_CHANNEL(font);
95 #ifdef HAVE_FT2BUILD_H
98 #ifdef HAVE_FREETYPE_FREETYPE_H
99 #include <freetype/freetype.h>
101 #ifdef HAVE_FREETYPE_FTGLYPH_H
102 #include <freetype/ftglyph.h>
104 #ifdef HAVE_FREETYPE_TTTABLES_H
105 #include <freetype/tttables.h>
107 #ifdef HAVE_FREETYPE_FTTYPES_H
108 #include <freetype/fttypes.h>
110 #ifdef HAVE_FREETYPE_FTSNAMES_H
111 #include <freetype/ftsnames.h>
113 # ifdef HAVE_FREETYPE_FTNAMES_H
114 # include <freetype/ftnames.h>
117 #ifdef HAVE_FREETYPE_TTNAMEID_H
118 #include <freetype/ttnameid.h>
120 #ifdef HAVE_FREETYPE_FTOUTLN_H
121 #include <freetype/ftoutln.h>
123 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
124 #include <freetype/internal/sfnt.h>
126 #ifdef HAVE_FREETYPE_FTTRIGON_H
127 #include <freetype/fttrigon.h>
129 #ifdef HAVE_FREETYPE_FTWINFNT_H
130 #include <freetype/ftwinfnt.h>
132 #ifdef HAVE_FREETYPE_FTMODAPI_H
133 #include <freetype/ftmodapi.h>
135 #ifdef HAVE_FREETYPE_FTLCDFIL_H
136 #include <freetype/ftlcdfil.h>
139 #ifndef HAVE_FT_TRUETYPEENGINETYPE
142 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
143 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
144 FT_TRUETYPE_ENGINE_TYPE_PATENTED
145 } FT_TrueTypeEngineType;
148 static FT_Library library = 0;
155 static FT_Version_t FT_Version;
156 static DWORD FT_SimpleVersion;
158 static void *ft_handle = NULL;
160 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
161 MAKE_FUNCPTR(FT_Vector_Unit);
162 MAKE_FUNCPTR(FT_Done_Face);
163 MAKE_FUNCPTR(FT_Get_Char_Index);
164 MAKE_FUNCPTR(FT_Get_Module);
165 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
166 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
167 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
168 MAKE_FUNCPTR(FT_Init_FreeType);
169 MAKE_FUNCPTR(FT_Load_Glyph);
170 MAKE_FUNCPTR(FT_Matrix_Multiply);
171 #ifdef FT_MULFIX_INLINED
172 #define pFT_MulFix FT_MULFIX_INLINED
174 MAKE_FUNCPTR(FT_MulFix);
176 MAKE_FUNCPTR(FT_New_Face);
177 MAKE_FUNCPTR(FT_New_Memory_Face);
178 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
179 MAKE_FUNCPTR(FT_Outline_Transform);
180 MAKE_FUNCPTR(FT_Outline_Translate);
181 MAKE_FUNCPTR(FT_Select_Charmap);
182 MAKE_FUNCPTR(FT_Set_Charmap);
183 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
184 MAKE_FUNCPTR(FT_Vector_Transform);
185 MAKE_FUNCPTR(FT_Render_Glyph);
186 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
187 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
188 static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*);
189 static FT_ULong (*pFT_Get_Next_Char)(FT_Face,FT_ULong,FT_UInt*);
190 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
191 #ifdef HAVE_FREETYPE_FTLCDFIL_H
192 static FT_Error (*pFT_Library_SetLcdFilter)(FT_Library, FT_LcdFilter);
194 #ifdef HAVE_FREETYPE_FTWINFNT_H
195 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
198 #ifdef SONAME_LIBFONTCONFIG
199 #include <fontconfig/fontconfig.h>
200 MAKE_FUNCPTR(FcConfigGetCurrent);
201 MAKE_FUNCPTR(FcFontList);
202 MAKE_FUNCPTR(FcFontSetDestroy);
203 MAKE_FUNCPTR(FcInit);
204 MAKE_FUNCPTR(FcObjectSetAdd);
205 MAKE_FUNCPTR(FcObjectSetCreate);
206 MAKE_FUNCPTR(FcObjectSetDestroy);
207 MAKE_FUNCPTR(FcPatternCreate);
208 MAKE_FUNCPTR(FcPatternDestroy);
209 MAKE_FUNCPTR(FcPatternGetBool);
210 MAKE_FUNCPTR(FcPatternGetString);
216 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
217 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
218 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
221 #ifndef ft_encoding_none
222 #define FT_ENCODING_NONE ft_encoding_none
224 #ifndef ft_encoding_ms_symbol
225 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
227 #ifndef ft_encoding_unicode
228 #define FT_ENCODING_UNICODE ft_encoding_unicode
230 #ifndef ft_encoding_apple_roman
231 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
234 #ifdef WORDS_BIGENDIAN
235 #define GET_BE_WORD(x) (x)
237 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
240 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
247 FT_Short internal_leading;
250 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
251 So to let this compile on older versions of FreeType we'll define the
252 new structure here. */
254 FT_Short height, width;
255 FT_Pos size, x_ppem, y_ppem;
261 NEWTEXTMETRICEXW ntm;
265 typedef struct tagFace {
270 DWORD font_data_size;
273 FONTSIGNATURE fs_links;
275 FT_Fixed font_version;
277 Bitmap_Size size; /* set if face is a bitmap */
278 BOOL external; /* TRUE if we should manually add this font to the registry */
279 struct tagFamily *family;
280 /* Cached data for Enum */
281 struct enum_data *cached_enum_data;
284 typedef struct tagFamily {
286 const WCHAR *FamilyName;
292 INT adv; /* These three hold to widths of the unrotated chars */
310 typedef struct tagHFONTLIST {
325 struct list hfontlist;
326 OUTLINETEXTMETRICW *potm;
327 DWORD total_kern_pairs;
328 KERNINGPAIR *kern_pairs;
329 struct list child_fonts;
331 /* the following members can be accessed without locking, they are never modified after creation */
333 struct font_mapping *mapping;
356 const WCHAR *font_name;
360 #define GM_BLOCK_SIZE 128
361 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
363 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
364 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
365 #define UNUSED_CACHE_SIZE 10
366 static struct list child_font_list = LIST_INIT(child_font_list);
367 static struct list system_links = LIST_INIT(system_links);
369 static struct list font_subst_list = LIST_INIT(font_subst_list);
371 static struct list font_list = LIST_INIT(font_list);
373 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
374 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
375 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
377 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
378 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
379 'W','i','n','d','o','w','s','\\',
380 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
381 'F','o','n','t','s','\0'};
383 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
384 'W','i','n','d','o','w','s',' ','N','T','\\',
385 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
386 'F','o','n','t','s','\0'};
388 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
389 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
390 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
391 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
393 static const WCHAR * const SystemFontValues[4] = {
400 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
401 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
403 /* Interesting and well-known (frequently-assumed!) font names */
404 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
405 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 };
406 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
407 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
408 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
409 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
410 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
411 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
413 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
414 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
415 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
416 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
417 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
418 'E','u','r','o','p','e','a','n','\0'};
419 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
420 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
421 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
422 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
423 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
424 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
425 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
426 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
427 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
428 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
429 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
430 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
432 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
442 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
450 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
459 typedef struct tagFontSubst {
475 static struct list mappings_list = LIST_INIT( mappings_list );
477 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
479 static CRITICAL_SECTION freetype_cs;
480 static CRITICAL_SECTION_DEBUG critsect_debug =
483 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
484 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
486 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
488 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
490 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
491 static BOOL use_default_fallback = FALSE;
493 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
495 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
496 'W','i','n','d','o','w','s',' ','N','T','\\',
497 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
498 'S','y','s','t','e','m','L','i','n','k',0};
500 /****************************************
501 * Notes on .fon files
503 * The fonts System, FixedSys and Terminal are special. There are typically multiple
504 * versions installed for different resolutions and codepages. Windows stores which one to use
505 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
507 * FIXEDFON.FON FixedSys
509 * OEMFONT.FON Terminal
510 * LogPixels Current dpi set by the display control panel applet
511 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
512 * also has a LogPixels value that appears to mirror this)
514 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
515 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
516 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
517 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
518 * so that makes sense.
520 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
521 * to be mapped into the registry on Windows 2000 at least).
524 * ega80woa.fon=ega80850.fon
525 * ega40woa.fon=ega40850.fon
526 * cga80woa.fon=cga80850.fon
527 * cga40woa.fon=cga40850.fon
530 /* These are all structures needed for the GSUB table */
532 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
533 #define TATEGAKI_LOWER_BOUND 0x02F1
549 GSUB_ScriptRecord ScriptRecord[1];
555 } GSUB_LangSysRecord;
560 GSUB_LangSysRecord LangSysRecord[1];
564 WORD LookupOrder; /* Reserved */
565 WORD ReqFeatureIndex;
567 WORD FeatureIndex[1];
573 } GSUB_FeatureRecord;
577 GSUB_FeatureRecord FeatureRecord[1];
581 WORD FeatureParams; /* Reserved */
583 WORD LookupListIndex[1];
602 } GSUB_CoverageFormat1;
607 WORD StartCoverageIndex;
613 GSUB_RangeRecord RangeRecord[1];
614 } GSUB_CoverageFormat2;
617 WORD SubstFormat; /* = 1 */
620 } GSUB_SingleSubstFormat1;
623 WORD SubstFormat; /* = 2 */
627 }GSUB_SingleSubstFormat2;
629 #ifdef HAVE_CARBON_CARBON_H
630 static char *find_cache_dir(void)
634 static char cached_path[MAX_PATH];
635 static const char *wine = "/Wine", *fonts = "/Fonts";
637 if(*cached_path) return cached_path;
639 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
642 WARN("can't create cached data folder\n");
645 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
648 WARN("can't create cached data path\n");
652 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
654 ERR("Could not create full path\n");
658 strcat(cached_path, wine);
660 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
662 WARN("Couldn't mkdir %s\n", cached_path);
666 strcat(cached_path, fonts);
667 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
669 WARN("Couldn't mkdir %s\n", cached_path);
676 /******************************************************************
679 * Extracts individual TrueType font files from a Mac suitcase font
680 * and saves them into the user's caches directory (see
682 * Returns a NULL terminated array of filenames.
684 * We do this because they are apps that try to read ttf files
685 * themselves and they don't like Mac suitcase files.
687 static char **expand_mac_font(const char *path)
694 const char *filename;
698 unsigned int size, max_size;
701 TRACE("path %s\n", path);
703 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
706 WARN("failed to get ref\n");
710 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
713 TRACE("no data fork, so trying resource fork\n");
714 res_ref = FSOpenResFile(&ref, fsRdPerm);
717 TRACE("unable to open resource fork\n");
724 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
727 CloseResFile(res_ref);
731 out_dir = find_cache_dir();
733 filename = strrchr(path, '/');
734 if(!filename) filename = path;
737 /* output filename has the form out_dir/filename_%04x.ttf */
738 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
745 unsigned short *num_faces_ptr, num_faces, face;
748 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
750 fond = Get1IndResource(fond_res, idx);
752 TRACE("got fond resource %d\n", idx);
755 fam_rec = *(FamRec**)fond;
756 num_faces_ptr = (unsigned short *)(fam_rec + 1);
757 num_faces = GET_BE_WORD(*num_faces_ptr);
759 assoc = (AsscEntry*)(num_faces_ptr + 1);
760 TRACE("num faces %04x\n", num_faces);
761 for(face = 0; face < num_faces; face++, assoc++)
764 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
765 unsigned short size, font_id;
768 size = GET_BE_WORD(assoc->fontSize);
769 font_id = GET_BE_WORD(assoc->fontID);
772 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
776 TRACE("trying to load sfnt id %04x\n", font_id);
777 sfnt = GetResource(sfnt_res, font_id);
780 TRACE("can't get sfnt resource %04x\n", font_id);
784 output = HeapAlloc(GetProcessHeap(), 0, output_len);
789 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
791 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
792 if(fd != -1 || errno == EEXIST)
796 unsigned char *sfnt_data;
799 sfnt_data = *(unsigned char**)sfnt;
800 write(fd, sfnt_data, GetHandleSize(sfnt));
804 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
807 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
809 ret.array[ret.size++] = output;
813 WARN("unable to create %s\n", output);
814 HeapFree(GetProcessHeap(), 0, output);
817 ReleaseResource(sfnt);
820 ReleaseResource(fond);
823 CloseResFile(res_ref);
828 #endif /* HAVE_CARBON_CARBON_H */
830 static inline BOOL is_win9x(void)
832 return GetVersion() & 0x80000000;
835 This function builds an FT_Fixed from a double. It fails if the absolute
836 value of the float number is greater than 32768.
838 static inline FT_Fixed FT_FixedFromFloat(double f)
844 This function builds an FT_Fixed from a FIXED. It simply put f.value
845 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
847 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
849 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
853 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
858 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
859 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
861 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
862 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
864 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
866 if(face_name && strcmpiW(face_name, family->FamilyName))
868 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
872 file = strrchr(face->file, '/');
877 if(!strcasecmp(file, file_nameA))
879 HeapFree(GetProcessHeap(), 0, file_nameA);
884 HeapFree(GetProcessHeap(), 0, file_nameA);
888 static Family *find_family_from_name(const WCHAR *name)
892 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
894 if(!strcmpiW(family->FamilyName, name))
901 static void DumpSubstList(void)
905 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
907 if(psub->from.charset != -1 || psub->to.charset != -1)
908 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
909 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
911 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
912 debugstr_w(psub->to.name));
917 static LPWSTR strdupW(LPCWSTR p)
920 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
921 ret = HeapAlloc(GetProcessHeap(), 0, len);
926 static LPSTR strdupA(LPCSTR p)
929 DWORD len = (strlen(p) + 1);
930 ret = HeapAlloc(GetProcessHeap(), 0, len);
935 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
940 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
942 if(!strcmpiW(element->from.name, from_name) &&
943 (element->from.charset == from_charset ||
944 element->from.charset == -1))
951 #define ADD_FONT_SUBST_FORCE 1
953 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
955 FontSubst *from_exist, *to_exist;
957 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
959 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
961 list_remove(&from_exist->entry);
962 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
963 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
964 HeapFree(GetProcessHeap(), 0, from_exist);
970 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
974 HeapFree(GetProcessHeap(), 0, subst->to.name);
975 subst->to.name = strdupW(to_exist->to.name);
978 list_add_tail(subst_list, &subst->entry);
983 HeapFree(GetProcessHeap(), 0, subst->from.name);
984 HeapFree(GetProcessHeap(), 0, subst->to.name);
985 HeapFree(GetProcessHeap(), 0, subst);
989 static void split_subst_info(NameCs *nc, LPSTR str)
991 CHAR *p = strrchr(str, ',');
996 nc->charset = strtol(p+1, NULL, 10);
999 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
1000 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1001 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
1004 static void LoadSubstList(void)
1008 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1012 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1013 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1014 &hkey) == ERROR_SUCCESS) {
1016 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1017 &valuelen, &datalen, NULL, NULL);
1019 valuelen++; /* returned value doesn't include room for '\0' */
1020 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1021 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1025 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1026 &dlen) == ERROR_SUCCESS) {
1027 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1029 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1030 split_subst_info(&psub->from, value);
1031 split_subst_info(&psub->to, data);
1033 /* Win 2000 doesn't allow mapping between different charsets
1034 or mapping of DEFAULT_CHARSET */
1035 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1036 psub->to.charset == DEFAULT_CHARSET) {
1037 HeapFree(GetProcessHeap(), 0, psub->to.name);
1038 HeapFree(GetProcessHeap(), 0, psub->from.name);
1039 HeapFree(GetProcessHeap(), 0, psub);
1041 add_font_subst(&font_subst_list, psub, 0);
1043 /* reset dlen and vlen */
1047 HeapFree(GetProcessHeap(), 0, data);
1048 HeapFree(GetProcessHeap(), 0, value);
1054 /*****************************************************************
1055 * get_name_table_entry
1057 * Supply the platform, encoding, language and name ids in req
1058 * and if the name exists the function will fill in the string
1059 * and string_len members. The string is owned by FreeType so
1060 * don't free it. Returns TRUE if the name is found else FALSE.
1062 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1065 FT_UInt num_names, name_index;
1067 if(FT_IS_SFNT(ft_face))
1069 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1071 for(name_index = 0; name_index < num_names; name_index++)
1073 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1075 if((name.platform_id == req->platform_id) &&
1076 (name.encoding_id == req->encoding_id) &&
1077 (name.language_id == req->language_id) &&
1078 (name.name_id == req->name_id))
1080 req->string = name.string;
1081 req->string_len = name.string_len;
1088 req->string_len = 0;
1092 static WCHAR *get_familyname(FT_Face ft_face)
1094 WCHAR *family = NULL;
1097 name.platform_id = TT_PLATFORM_MICROSOFT;
1098 name.encoding_id = TT_MS_ID_UNICODE_CS;
1099 name.language_id = GetUserDefaultLCID();
1100 name.name_id = TT_NAME_ID_FONT_FAMILY;
1102 if(get_name_table_entry(ft_face, &name))
1106 /* String is not nul terminated and string_len is a byte length. */
1107 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1108 for(i = 0; i < name.string_len / 2; i++)
1110 WORD *tmp = (WORD *)&name.string[i * 2];
1111 family[i] = GET_BE_WORD(*tmp);
1114 TRACE("Got localised name %s\n", debugstr_w(family));
1121 /*****************************************************************
1124 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
1125 * of FreeType that don't export this function.
1128 static FT_Error load_sfnt_table(FT_Face ft_face, FT_ULong table, FT_Long offset, FT_Byte *buf, FT_ULong *len)
1133 /* If the FT_Load_Sfnt_Table function is there we'll use it */
1134 if(pFT_Load_Sfnt_Table)
1136 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, len);
1138 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
1139 else /* Do it the hard way */
1141 TT_Face tt_face = (TT_Face) ft_face;
1142 SFNT_Interface *sfnt;
1143 if (FT_Version.major==2 && FT_Version.minor==0)
1146 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
1150 /* A field was added in the middle of the structure in 2.1.x */
1151 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
1153 err = sfnt->load_any(tt_face, table, offset, buf, len);
1161 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
1162 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
1163 "Please upgrade your freetype library.\n");
1166 err = FT_Err_Unimplemented_Feature;
1172 static inline int TestStyles(DWORD flags, DWORD styles)
1174 return (flags & styles) == styles;
1177 static int StyleOrdering(Face *face)
1179 if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1181 if (TestStyles(face->ntmFlags, NTM_ITALIC))
1183 if (TestStyles(face->ntmFlags, NTM_BOLD))
1185 if (TestStyles(face->ntmFlags, NTM_REGULAR))
1188 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1189 debugstr_w(face->family->FamilyName),
1190 debugstr_w(face->StyleName),
1196 /* Add a style of face to a font family using an ordering of the list such
1197 that regular fonts come before bold and italic, and single styles come
1198 before compound styles. */
1199 static void AddFaceToFamily(Face *face, Family *family)
1203 LIST_FOR_EACH( entry, &family->faces )
1205 Face *ent = LIST_ENTRY(entry, Face, entry);
1206 if (StyleOrdering(face) < StyleOrdering(ent)) break;
1208 list_add_before( entry, &face->entry );
1211 #define ADDFONT_EXTERNAL_FONT 0x01
1212 #define ADDFONT_FORCE_BITMAP 0x02
1213 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1217 TT_Header *pHeader = NULL;
1218 WCHAR *english_family, *localised_family, *StyleW;
1222 struct list *family_elem_ptr, *face_elem_ptr;
1224 FT_Long face_index = 0, num_faces;
1225 #ifdef HAVE_FREETYPE_FTWINFNT_H
1226 FT_WinFNT_HeaderRec winfnt_header;
1228 int i, bitmap_num, internal_leading;
1231 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1232 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1234 #ifdef HAVE_CARBON_CARBON_H
1235 if(file && !fake_family)
1237 char **mac_list = expand_mac_font(file);
1240 BOOL had_one = FALSE;
1242 for(cursor = mac_list; *cursor; cursor++)
1245 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1246 HeapFree(GetProcessHeap(), 0, *cursor);
1248 HeapFree(GetProcessHeap(), 0, mac_list);
1253 #endif /* HAVE_CARBON_CARBON_H */
1256 char *family_name = fake_family;
1260 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1261 err = pFT_New_Face(library, file, face_index, &ft_face);
1264 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1265 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1269 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1273 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*/
1274 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1275 pFT_Done_Face(ft_face);
1279 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1280 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1281 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1282 pFT_Done_Face(ft_face);
1286 if(FT_IS_SFNT(ft_face))
1288 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1289 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1290 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1292 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1293 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1294 pFT_Done_Face(ft_face);
1298 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1299 we don't want to load these. */
1300 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1304 if(!load_sfnt_table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1306 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1307 pFT_Done_Face(ft_face);
1313 if(!ft_face->family_name || !ft_face->style_name) {
1314 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1315 pFT_Done_Face(ft_face);
1319 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1321 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1322 pFT_Done_Face(ft_face);
1328 localised_family = get_familyname(ft_face);
1329 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1331 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1332 HeapFree(GetProcessHeap(), 0, localised_family);
1333 num_faces = ft_face->num_faces;
1334 pFT_Done_Face(ft_face);
1337 HeapFree(GetProcessHeap(), 0, localised_family);
1341 family_name = ft_face->family_name;
1345 My_FT_Bitmap_Size *size = NULL;
1348 if(!FT_IS_SCALABLE(ft_face))
1349 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1351 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1352 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1353 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1355 localised_family = NULL;
1357 localised_family = get_familyname(ft_face);
1358 if(localised_family && !strcmpiW(localised_family, english_family)) {
1359 HeapFree(GetProcessHeap(), 0, localised_family);
1360 localised_family = NULL;
1365 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1366 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1367 if(!strcmpiW(family->FamilyName, localised_family ? localised_family : english_family))
1372 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1373 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1374 list_init(&family->faces);
1375 list_add_tail(&font_list, &family->entry);
1377 if(localised_family) {
1378 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1379 subst->from.name = strdupW(english_family);
1380 subst->from.charset = -1;
1381 subst->to.name = strdupW(localised_family);
1382 subst->to.charset = -1;
1383 add_font_subst(&font_subst_list, subst, 0);
1386 HeapFree(GetProcessHeap(), 0, localised_family);
1387 HeapFree(GetProcessHeap(), 0, english_family);
1389 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1390 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1391 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1393 internal_leading = 0;
1394 memset(&fs, 0, sizeof(fs));
1396 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1398 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1399 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1400 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1401 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1402 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1403 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1404 if(pOS2->version == 0) {
1407 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1408 fs.fsCsb[0] |= FS_LATIN1;
1410 fs.fsCsb[0] |= FS_SYMBOL;
1413 #ifdef HAVE_FREETYPE_FTWINFNT_H
1414 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1416 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1417 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1418 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1420 internal_leading = winfnt_header.internal_leading;
1424 face_elem_ptr = list_head(&family->faces);
1425 while(face_elem_ptr) {
1426 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1427 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1428 if(!strcmpiW(face->StyleName, StyleW) &&
1429 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1430 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1431 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1432 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1435 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1436 HeapFree(GetProcessHeap(), 0, StyleW);
1437 pFT_Done_Face(ft_face);
1440 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1441 TRACE("Original font is newer so skipping this one\n");
1442 HeapFree(GetProcessHeap(), 0, StyleW);
1443 pFT_Done_Face(ft_face);
1446 TRACE("Replacing original with this one\n");
1447 list_remove(&face->entry);
1448 HeapFree(GetProcessHeap(), 0, face->file);
1449 HeapFree(GetProcessHeap(), 0, face->StyleName);
1450 HeapFree(GetProcessHeap(), 0, face);
1455 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1456 face->cached_enum_data = NULL;
1457 face->StyleName = StyleW;
1460 face->file = strdupA(file);
1461 face->font_data_ptr = NULL;
1462 face->font_data_size = 0;
1467 face->font_data_ptr = font_data_ptr;
1468 face->font_data_size = font_data_size;
1470 face->face_index = face_index;
1472 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1473 face->ntmFlags |= NTM_ITALIC;
1474 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1475 face->ntmFlags |= NTM_BOLD;
1476 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1477 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1478 face->family = family;
1479 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1481 memset(&face->fs_links, 0, sizeof(face->fs_links));
1483 if(FT_IS_SCALABLE(ft_face)) {
1484 memset(&face->size, 0, sizeof(face->size));
1485 face->scalable = TRUE;
1487 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1488 size->height, size->width, size->size >> 6,
1489 size->x_ppem >> 6, size->y_ppem >> 6);
1490 face->size.height = size->height;
1491 face->size.width = size->width;
1492 face->size.size = size->size;
1493 face->size.x_ppem = size->x_ppem;
1494 face->size.y_ppem = size->y_ppem;
1495 face->size.internal_leading = internal_leading;
1496 face->scalable = FALSE;
1499 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1501 if (pFT_Load_Sfnt_Table && !pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1503 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1504 face->ntmFlags |= NTM_PS_OPENTYPE;
1507 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1508 face->fs.fsCsb[0], face->fs.fsCsb[1],
1509 face->fs.fsUsb[0], face->fs.fsUsb[1],
1510 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1513 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1514 for(i = 0; i < ft_face->num_charmaps; i++) {
1515 switch(ft_face->charmaps[i]->encoding) {
1516 case FT_ENCODING_UNICODE:
1517 case FT_ENCODING_APPLE_ROMAN:
1518 face->fs.fsCsb[0] |= FS_LATIN1;
1520 case FT_ENCODING_MS_SYMBOL:
1521 face->fs.fsCsb[0] |= FS_SYMBOL;
1529 if (!(face->fs.fsCsb[0] & FS_SYMBOL))
1530 have_installed_roman_font = TRUE;
1532 AddFaceToFamily(face, family);
1534 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1536 num_faces = ft_face->num_faces;
1537 pFT_Done_Face(ft_face);
1538 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1539 debugstr_w(StyleW));
1540 } while(num_faces > ++face_index);
1544 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1546 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1549 static void DumpFontList(void)
1553 struct list *family_elem_ptr, *face_elem_ptr;
1555 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1556 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1557 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1558 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1559 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1560 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1562 TRACE(" %d", face->size.height);
1569 /***********************************************************
1570 * The replacement list is a way to map an entire font
1571 * family onto another family. For example adding
1573 * [HKCU\Software\Wine\Fonts\Replacements]
1574 * "Wingdings"="Winedings"
1576 * would enumerate the Winedings font both as Winedings and
1577 * Wingdings. However if a real Wingdings font is present the
1578 * replacement does not take place.
1581 static void LoadReplaceList(void)
1584 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1589 struct list *family_elem_ptr, *face_elem_ptr;
1592 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1593 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1595 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1596 &valuelen, &datalen, NULL, NULL);
1598 valuelen++; /* returned value doesn't include room for '\0' */
1599 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1600 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1604 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1605 &dlen) == ERROR_SUCCESS) {
1606 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1607 /* "NewName"="Oldname" */
1608 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1610 /* Find the old family and hence all of the font files
1612 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1613 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1614 if(!strcmpiW(family->FamilyName, data)) {
1615 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1616 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1617 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1618 debugstr_w(face->StyleName), familyA);
1619 /* Now add a new entry with the new family name */
1620 AddFontToList(face->file, face->font_data_ptr, face->font_data_size, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1625 /* reset dlen and vlen */
1629 HeapFree(GetProcessHeap(), 0, data);
1630 HeapFree(GetProcessHeap(), 0, value);
1635 /*************************************************************
1638 static BOOL init_system_links(void)
1642 DWORD type, max_val, max_data, val_len, data_len, index;
1643 WCHAR *value, *data;
1644 WCHAR *entry, *next;
1645 SYSTEM_LINKS *font_link, *system_font_link;
1646 CHILD_FONT *child_font;
1647 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1648 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1654 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1656 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1657 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1658 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1659 val_len = max_val + 1;
1660 data_len = max_data;
1662 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1664 memset(&fs, 0, sizeof(fs));
1665 psub = get_font_subst(&font_subst_list, value, -1);
1666 /* Don't store fonts that are only substitutes for other fonts */
1669 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
1672 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1673 font_link->font_name = strdupW(value);
1674 list_init(&font_link->links);
1675 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1678 CHILD_FONT *child_font;
1680 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
1682 next = entry + strlenW(entry) + 1;
1684 face_name = strchrW(entry, ',');
1688 while(isspaceW(*face_name))
1691 psub = get_font_subst(&font_subst_list, face_name, -1);
1693 face_name = psub->to.name;
1695 face = find_face_from_filename(entry, face_name);
1698 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1702 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1703 child_font->face = face;
1704 child_font->font = NULL;
1705 fs.fsCsb[0] |= face->fs.fsCsb[0];
1706 fs.fsCsb[1] |= face->fs.fsCsb[1];
1707 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1708 list_add_tail(&font_link->links, &child_font->entry);
1710 family = find_family_from_name(font_link->font_name);
1713 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1715 face->fs_links = fs;
1718 list_add_tail(&system_links, &font_link->entry);
1719 val_len = max_val + 1;
1720 data_len = max_data;
1723 HeapFree(GetProcessHeap(), 0, value);
1724 HeapFree(GetProcessHeap(), 0, data);
1728 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1731 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1732 system_font_link->font_name = strdupW(System);
1733 list_init(&system_font_link->links);
1735 face = find_face_from_filename(tahoma_ttf, Tahoma);
1738 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1739 child_font->face = face;
1740 child_font->font = NULL;
1741 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
1742 list_add_tail(&system_font_link->links, &child_font->entry);
1744 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1746 if(!strcmpiW(font_link->font_name, Tahoma))
1748 CHILD_FONT *font_link_entry;
1749 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1751 CHILD_FONT *new_child;
1752 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1753 new_child->face = font_link_entry->face;
1754 new_child->font = NULL;
1755 list_add_tail(&system_font_link->links, &new_child->entry);
1760 list_add_tail(&system_links, &system_font_link->entry);
1764 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1767 struct dirent *dent;
1768 char path[MAX_PATH];
1770 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1772 dir = opendir(dirname);
1774 WARN("Can't open directory %s\n", debugstr_a(dirname));
1777 while((dent = readdir(dir)) != NULL) {
1778 struct stat statbuf;
1780 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1783 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1785 sprintf(path, "%s/%s", dirname, dent->d_name);
1787 if(stat(path, &statbuf) == -1)
1789 WARN("Can't stat %s\n", debugstr_a(path));
1792 if(S_ISDIR(statbuf.st_mode))
1793 ReadFontDir(path, external_fonts);
1795 AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1801 static void load_fontconfig_fonts(void)
1803 #ifdef SONAME_LIBFONTCONFIG
1804 void *fc_handle = NULL;
1813 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1815 TRACE("Wine cannot find the fontconfig library (%s).\n",
1816 SONAME_LIBFONTCONFIG);
1819 #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;}
1820 LOAD_FUNCPTR(FcConfigGetCurrent);
1821 LOAD_FUNCPTR(FcFontList);
1822 LOAD_FUNCPTR(FcFontSetDestroy);
1823 LOAD_FUNCPTR(FcInit);
1824 LOAD_FUNCPTR(FcObjectSetAdd);
1825 LOAD_FUNCPTR(FcObjectSetCreate);
1826 LOAD_FUNCPTR(FcObjectSetDestroy);
1827 LOAD_FUNCPTR(FcPatternCreate);
1828 LOAD_FUNCPTR(FcPatternDestroy);
1829 LOAD_FUNCPTR(FcPatternGetBool);
1830 LOAD_FUNCPTR(FcPatternGetString);
1833 if(!pFcInit()) return;
1835 config = pFcConfigGetCurrent();
1836 pat = pFcPatternCreate();
1837 os = pFcObjectSetCreate();
1838 pFcObjectSetAdd(os, FC_FILE);
1839 pFcObjectSetAdd(os, FC_SCALABLE);
1840 fontset = pFcFontList(config, pat, os);
1841 if(!fontset) return;
1842 for(i = 0; i < fontset->nfont; i++) {
1845 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1847 TRACE("fontconfig: %s\n", file);
1849 /* We're just interested in OT/TT fonts for now, so this hack just
1850 picks up the scalable fonts without extensions .pf[ab] to save time
1851 loading every other font */
1853 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1855 TRACE("not scalable\n");
1859 len = strlen( file );
1860 if(len < 4) continue;
1861 ext = &file[ len - 3 ];
1862 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1863 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT);
1865 pFcFontSetDestroy(fontset);
1866 pFcObjectSetDestroy(os);
1867 pFcPatternDestroy(pat);
1873 static BOOL load_font_from_data_dir(LPCWSTR file)
1876 const char *data_dir = wine_get_data_dir();
1878 if (!data_dir) data_dir = wine_get_build_dir();
1885 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1887 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1889 strcpy(unix_name, data_dir);
1890 strcat(unix_name, "/fonts/");
1892 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1894 EnterCriticalSection( &freetype_cs );
1895 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1896 LeaveCriticalSection( &freetype_cs );
1897 HeapFree(GetProcessHeap(), 0, unix_name);
1902 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
1904 static const WCHAR slashW[] = {'\\','\0'};
1906 WCHAR windowsdir[MAX_PATH];
1909 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1910 strcatW(windowsdir, fontsW);
1911 strcatW(windowsdir, slashW);
1912 strcatW(windowsdir, file);
1913 if ((unixname = wine_get_unix_file_name(windowsdir))) {
1914 EnterCriticalSection( &freetype_cs );
1915 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1916 LeaveCriticalSection( &freetype_cs );
1917 HeapFree(GetProcessHeap(), 0, unixname);
1922 static void load_system_fonts(void)
1925 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1926 const WCHAR * const *value;
1928 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1931 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1932 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1933 strcatW(windowsdir, fontsW);
1934 for(value = SystemFontValues; *value; value++) {
1935 dlen = sizeof(data);
1936 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1940 sprintfW(pathW, fmtW, windowsdir, data);
1941 if((unixname = wine_get_unix_file_name(pathW))) {
1942 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1943 HeapFree(GetProcessHeap(), 0, unixname);
1946 load_font_from_data_dir(data);
1953 /*************************************************************
1955 * This adds registry entries for any externally loaded fonts
1956 * (fonts from fontconfig or FontDirs). It also deletes entries
1957 * of no longer existing fonts.
1960 static void update_reg_entries(void)
1962 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
1967 struct list *family_elem_ptr, *face_elem_ptr;
1969 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1970 static const WCHAR spaceW[] = {' ', '\0'};
1973 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1974 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1975 ERR("Can't create Windows font reg key\n");
1979 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
1980 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
1981 ERR("Can't create Windows font reg key\n");
1985 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1986 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
1987 ERR("Can't create external font reg key\n");
1991 /* enumerate the fonts and add external ones to the two keys */
1993 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1994 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1995 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1996 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1997 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1998 if(!face->external) continue;
2000 if (!(face->ntmFlags & NTM_REGULAR))
2001 len = len_fam + strlenW(face->StyleName) + 1;
2002 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2003 strcpyW(valueW, family->FamilyName);
2004 if(len != len_fam) {
2005 strcatW(valueW, spaceW);
2006 strcatW(valueW, face->StyleName);
2008 strcatW(valueW, TrueType);
2010 file = wine_get_dos_file_name(face->file);
2012 len = strlenW(file) + 1;
2015 if((path = strrchr(face->file, '/')) == NULL)
2019 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
2021 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2022 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2024 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2025 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2026 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2028 HeapFree(GetProcessHeap(), 0, file);
2029 HeapFree(GetProcessHeap(), 0, valueW);
2033 if(external_key) RegCloseKey(external_key);
2034 if(win9x_key) RegCloseKey(win9x_key);
2035 if(winnt_key) RegCloseKey(winnt_key);
2039 static void delete_external_font_keys(void)
2041 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2042 DWORD dlen, vlen, datalen, valuelen, i, type;
2046 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2047 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2048 ERR("Can't create Windows font reg key\n");
2052 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2053 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2054 ERR("Can't create Windows font reg key\n");
2058 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2059 ERR("Can't create external font reg key\n");
2063 /* Delete all external fonts added last time */
2065 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2066 &valuelen, &datalen, NULL, NULL);
2067 valuelen++; /* returned value doesn't include room for '\0' */
2068 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2069 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2071 dlen = datalen * sizeof(WCHAR);
2074 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2075 &dlen) == ERROR_SUCCESS) {
2077 RegDeleteValueW(winnt_key, valueW);
2078 RegDeleteValueW(win9x_key, valueW);
2079 /* reset dlen and vlen */
2083 HeapFree(GetProcessHeap(), 0, data);
2084 HeapFree(GetProcessHeap(), 0, valueW);
2086 /* Delete the old external fonts key */
2087 RegCloseKey(external_key);
2088 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2091 if(win9x_key) RegCloseKey(win9x_key);
2092 if(winnt_key) RegCloseKey(winnt_key);
2095 /*************************************************************
2096 * WineEngAddFontResourceEx
2099 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2105 if (ft_handle) /* do it only if we have freetype up and running */
2110 FIXME("Ignoring flags %x\n", flags);
2112 if((unixname = wine_get_unix_file_name(file)))
2114 EnterCriticalSection( &freetype_cs );
2115 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2116 LeaveCriticalSection( &freetype_cs );
2117 HeapFree(GetProcessHeap(), 0, unixname);
2119 if (!ret && !strchrW(file, '\\')) {
2120 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2121 ret = load_font_from_winfonts_dir(file);
2123 /* Try in datadir/fonts (or builddir/fonts),
2124 * needed for Magic the Gathering Online
2126 ret = load_font_from_data_dir(file);
2133 /*************************************************************
2134 * WineEngAddFontMemResourceEx
2137 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2141 if (ft_handle) /* do it only if we have freetype up and running */
2143 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2145 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2146 memcpy(pFontCopy, pbFont, cbFont);
2148 EnterCriticalSection( &freetype_cs );
2149 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
2150 LeaveCriticalSection( &freetype_cs );
2154 TRACE("AddFontToList failed\n");
2155 HeapFree(GetProcessHeap(), 0, pFontCopy);
2158 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2159 * For now return something unique but quite random
2161 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2162 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2169 /*************************************************************
2170 * WineEngRemoveFontResourceEx
2173 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2180 static const struct nls_update_font_list
2182 UINT ansi_cp, oem_cp;
2183 const char *oem, *fixed, *system;
2184 const char *courier, *serif, *small, *sserif;
2185 /* these are for font substitutes */
2186 const char *shelldlg, *tmsrmn;
2187 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2191 const char *from, *to;
2192 } arial_0, courier_new_0, times_new_roman_0;
2193 } nls_update_font_list[] =
2195 /* Latin 1 (United States) */
2196 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2197 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2198 "Tahoma","Times New Roman",
2199 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2202 /* Latin 1 (Multilingual) */
2203 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2204 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2205 "Tahoma","Times New Roman", /* FIXME unverified */
2206 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2209 /* Eastern Europe */
2210 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2211 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2212 "Tahoma","Times New Roman", /* FIXME unverified */
2213 "Fixedsys,238", "System,238",
2214 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2215 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2216 { "Arial CE,0", "Arial,238" },
2217 { "Courier New CE,0", "Courier New,238" },
2218 { "Times New Roman CE,0", "Times New Roman,238" }
2221 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2222 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2223 "Tahoma","Times New Roman", /* FIXME unverified */
2224 "Fixedsys,204", "System,204",
2225 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2226 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2227 { "Arial Cyr,0", "Arial,204" },
2228 { "Courier New Cyr,0", "Courier New,204" },
2229 { "Times New Roman Cyr,0", "Times New Roman,204" }
2232 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2233 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2234 "Tahoma","Times New Roman", /* FIXME unverified */
2235 "Fixedsys,161", "System,161",
2236 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2237 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2238 { "Arial Greek,0", "Arial,161" },
2239 { "Courier New Greek,0", "Courier New,161" },
2240 { "Times New Roman Greek,0", "Times New Roman,161" }
2243 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2244 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2245 "Tahoma","Times New Roman", /* FIXME unverified */
2246 "Fixedsys,162", "System,162",
2247 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2248 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2249 { "Arial Tur,0", "Arial,162" },
2250 { "Courier New Tur,0", "Courier New,162" },
2251 { "Times New Roman Tur,0", "Times New Roman,162" }
2254 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2255 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2256 "Tahoma","Times New Roman", /* FIXME unverified */
2257 "Fixedsys,177", "System,177",
2258 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2259 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2263 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2264 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2265 "Tahoma","Times New Roman", /* FIXME unverified */
2266 "Fixedsys,178", "System,178",
2267 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2268 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2272 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2273 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2274 "Tahoma","Times New Roman", /* FIXME unverified */
2275 "Fixedsys,186", "System,186",
2276 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2277 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2278 { "Arial Baltic,0", "Arial,186" },
2279 { "Courier New Baltic,0", "Courier New,186" },
2280 { "Times New Roman Baltic,0", "Times New Roman,186" }
2283 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2284 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2285 "Tahoma","Times New Roman", /* FIXME unverified */
2286 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2290 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2291 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2292 "Tahoma","Times New Roman", /* FIXME unverified */
2293 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2297 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2298 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2299 "MS UI Gothic","MS Serif",
2300 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2303 /* Chinese Simplified */
2304 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2305 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2306 "SimSun", "NSimSun",
2307 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2311 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2312 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2314 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2317 /* Chinese Traditional */
2318 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2319 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2320 "PMingLiU", "MingLiU",
2321 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2326 static const WCHAR *font_links_list[] =
2328 Lucida_Sans_Unicode,
2329 Microsoft_Sans_Serif,
2333 static const struct font_links_defaults_list
2335 /* Keyed off substitution for "MS Shell Dlg" */
2336 const WCHAR *shelldlg;
2337 /* Maximum of four substitutes, plus terminating NULL pointer */
2338 const WCHAR *substitutes[5];
2339 } font_links_defaults_list[] =
2341 /* Non East-Asian */
2342 { Tahoma, /* FIXME unverified ordering */
2343 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2345 /* Below lists are courtesy of
2346 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2350 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2352 /* Chinese Simplified */
2354 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2358 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2360 /* Chinese Traditional */
2362 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2366 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2368 return ( ansi_cp == 932 /* CP932 for Japanese */
2369 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2370 || ansi_cp == 949 /* CP949 for Korean */
2371 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2374 static inline HKEY create_fonts_NT_registry_key(void)
2378 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2379 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2383 static inline HKEY create_fonts_9x_registry_key(void)
2387 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2388 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2392 static inline HKEY create_config_fonts_registry_key(void)
2396 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2397 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2401 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2403 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2404 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2405 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2406 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2409 static void set_value_key(HKEY hkey, const char *name, const char *value)
2412 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2414 RegDeleteValueA(hkey, name);
2417 static void update_font_info(void)
2419 char buf[40], cpbuf[40];
2422 UINT i, ansi_cp = 0, oem_cp = 0;
2425 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2428 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2429 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2430 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2431 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2432 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2434 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2435 if (is_dbcs_ansi_cp(ansi_cp))
2436 use_default_fallback = TRUE;
2439 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2441 if (!strcmp( buf, cpbuf )) /* already set correctly */
2446 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2448 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2450 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2453 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2457 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2458 nls_update_font_list[i].oem_cp == oem_cp)
2460 hkey = create_config_fonts_registry_key();
2461 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2462 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2463 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2466 hkey = create_fonts_NT_registry_key();
2467 add_font_list(hkey, &nls_update_font_list[i]);
2470 hkey = create_fonts_9x_registry_key();
2471 add_font_list(hkey, &nls_update_font_list[i]);
2474 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2476 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2477 strlen(nls_update_font_list[i].shelldlg)+1);
2478 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2479 strlen(nls_update_font_list[i].tmsrmn)+1);
2481 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2482 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2483 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2484 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2485 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2486 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2487 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2488 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2490 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2491 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2492 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2500 /* Delete the FontSubstitutes from other locales */
2501 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2503 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2504 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2505 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2511 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2513 /* Clear out system links */
2514 RegDeleteKeyW(HKEY_LOCAL_MACHINE, system_link);
2517 static void populate_system_links(HKEY hkey, const WCHAR *name, const WCHAR *const *values)
2527 WCHAR buff[MAX_PATH];
2531 static const WCHAR comma[] = {',',0};
2533 RegDeleteValueW(hkey, name);
2538 for (i = 0; values[i] != NULL; i++)
2541 if (!strcmpiW(name,value))
2543 psub = get_font_subst(&font_subst_list, value, -1);
2545 value = psub->to.name;
2546 family = find_family_from_name(value);
2550 /* Use first extant filename for this Family */
2551 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2555 file = strrchr(face->file, '/');
2564 fileLen = MultiByteToWideChar(CP_UNIXCP, 0, file, -1, NULL, 0);
2565 fileW = HeapAlloc(GetProcessHeap(), 0, fileLen * sizeof(WCHAR));
2566 MultiByteToWideChar(CP_UNIXCP, 0, file, -1, fileW, fileLen);
2567 entryLen = strlenW(fileW) + 1 + strlenW(value) + 1;
2568 if (sizeof(buff)-(data-buff) < entryLen + 1)
2570 WARN("creating SystemLink for %s, ran out of buffer space\n", debugstr_w(name));
2571 HeapFree(GetProcessHeap(), 0, fileW);
2574 strcpyW(data, fileW);
2575 strcatW(data, comma);
2576 strcatW(data, value);
2578 TRACE("added SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(fileW));
2579 HeapFree(GetProcessHeap(), 0, fileW);
2585 RegSetValueExW(hkey, name, 0, REG_MULTI_SZ, (BYTE*)buff, (data-buff) * sizeof(WCHAR));
2587 TRACE("no SystemLink fonts found for %s\n", debugstr_w(name));
2589 TRACE("removed SystemLink for %s\n", debugstr_w(name));
2592 static void update_system_links(void)
2600 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2602 if (!RegCreateKeyExW(HKEY_LOCAL_MACHINE, system_link, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, &disposition))
2604 if (disposition == REG_OPENED_EXISTING_KEY)
2606 TRACE("SystemLink key already exists, doing nothing\n");
2611 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2613 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2618 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2620 if (!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name))
2622 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2623 populate_system_links(hkey, font_links_list[j], font_links_defaults_list[i].substitutes);
2625 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2626 populate_system_links(hkey, psub->to.name, font_links_defaults_list[i].substitutes);
2629 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2631 populate_system_links(hkey, font_links_defaults_list[i].substitutes[0], NULL);
2636 WARN("there is no SystemLink default list for MS Shell Dlg %s\n", debugstr_w(psub->to.name));
2638 WARN("failed to create SystemLink key\n");
2642 static BOOL init_freetype(void)
2644 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2647 "Wine cannot find the FreeType font library. To enable Wine to\n"
2648 "use TrueType fonts please install a version of FreeType greater than\n"
2649 "or equal to 2.0.5.\n"
2650 "http://www.freetype.org\n");
2654 #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;}
2656 LOAD_FUNCPTR(FT_Vector_Unit)
2657 LOAD_FUNCPTR(FT_Done_Face)
2658 LOAD_FUNCPTR(FT_Get_Char_Index)
2659 LOAD_FUNCPTR(FT_Get_Module)
2660 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2661 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2662 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2663 LOAD_FUNCPTR(FT_Init_FreeType)
2664 LOAD_FUNCPTR(FT_Load_Glyph)
2665 LOAD_FUNCPTR(FT_Matrix_Multiply)
2666 #ifndef FT_MULFIX_INLINED
2667 LOAD_FUNCPTR(FT_MulFix)
2669 LOAD_FUNCPTR(FT_New_Face)
2670 LOAD_FUNCPTR(FT_New_Memory_Face)
2671 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2672 LOAD_FUNCPTR(FT_Outline_Transform)
2673 LOAD_FUNCPTR(FT_Outline_Translate)
2674 LOAD_FUNCPTR(FT_Select_Charmap)
2675 LOAD_FUNCPTR(FT_Set_Charmap)
2676 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2677 LOAD_FUNCPTR(FT_Vector_Transform)
2678 LOAD_FUNCPTR(FT_Render_Glyph)
2681 /* Don't warn if these ones are missing */
2682 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
2683 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
2684 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
2685 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
2686 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2687 #ifdef HAVE_FREETYPE_FTLCDFIL_H
2688 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
2690 #ifdef HAVE_FREETYPE_FTWINFNT_H
2691 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2693 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2694 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2695 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2696 <= 2.0.3 has FT_Sqrt64 */
2700 if(pFT_Init_FreeType(&library) != 0) {
2701 ERR("Can't init FreeType library\n");
2702 wine_dlclose(ft_handle, NULL, 0);
2706 FT_Version.major = FT_Version.minor = FT_Version.patch = -1;
2707 if (pFT_Library_Version)
2708 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2710 if (FT_Version.major<=0)
2716 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2717 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2718 ((FT_Version.minor << 8) & 0x00ff00) |
2719 ((FT_Version.patch ) & 0x0000ff);
2725 "Wine cannot find certain functions that it needs inside the FreeType\n"
2726 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2727 "FreeType to at least version 2.0.5.\n"
2728 "http://www.freetype.org\n");
2729 wine_dlclose(ft_handle, NULL, 0);
2734 /*************************************************************
2737 * Initialize FreeType library and create a list of available faces
2739 BOOL WineEngInit(void)
2741 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2742 static const WCHAR pathW[] = {'P','a','t','h',0};
2744 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2745 WCHAR windowsdir[MAX_PATH];
2748 const char *data_dir;
2752 /* update locale dependent font info in registry */
2755 if(!init_freetype()) return FALSE;
2757 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2758 ERR("Failed to create font mutex\n");
2761 WaitForSingleObject(font_mutex, INFINITE);
2763 delete_external_font_keys();
2765 /* load the system bitmap fonts */
2766 load_system_fonts();
2768 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2769 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2770 strcatW(windowsdir, fontsW);
2771 if((unixname = wine_get_unix_file_name(windowsdir)))
2773 ReadFontDir(unixname, FALSE);
2774 HeapFree(GetProcessHeap(), 0, unixname);
2777 /* load the system truetype fonts */
2778 data_dir = wine_get_data_dir();
2779 if (!data_dir) data_dir = wine_get_build_dir();
2780 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2781 strcpy(unixname, data_dir);
2782 strcat(unixname, "/fonts/");
2783 ReadFontDir(unixname, TRUE);
2784 HeapFree(GetProcessHeap(), 0, unixname);
2787 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2788 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2789 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2791 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2792 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2793 &hkey) == ERROR_SUCCESS) {
2794 LPWSTR data, valueW;
2795 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2796 &valuelen, &datalen, NULL, NULL);
2798 valuelen++; /* returned value doesn't include room for '\0' */
2799 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2800 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2803 dlen = datalen * sizeof(WCHAR);
2805 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
2806 &dlen) == ERROR_SUCCESS) {
2807 if(data[0] && (data[1] == ':'))
2809 if((unixname = wine_get_unix_file_name(data)))
2811 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2812 HeapFree(GetProcessHeap(), 0, unixname);
2815 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
2817 WCHAR pathW[MAX_PATH];
2818 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2821 sprintfW(pathW, fmtW, windowsdir, data);
2822 if((unixname = wine_get_unix_file_name(pathW)))
2824 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2825 HeapFree(GetProcessHeap(), 0, unixname);
2828 load_font_from_data_dir(data);
2830 /* reset dlen and vlen */
2835 HeapFree(GetProcessHeap(), 0, data);
2836 HeapFree(GetProcessHeap(), 0, valueW);
2840 load_fontconfig_fonts();
2842 /* then look in any directories that we've specified in the config file */
2843 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2844 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2850 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2852 len += sizeof(WCHAR);
2853 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2854 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2856 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2857 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2858 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2859 TRACE( "got font path %s\n", debugstr_a(valueA) );
2863 LPSTR next = strchr( ptr, ':' );
2864 if (next) *next++ = 0;
2865 ReadFontDir( ptr, TRUE );
2868 HeapFree( GetProcessHeap(), 0, valueA );
2870 HeapFree( GetProcessHeap(), 0, valueW );
2879 update_reg_entries();
2881 update_system_links();
2882 init_system_links();
2884 ReleaseMutex(font_mutex);
2889 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2892 TT_HoriHeader *pHori;
2896 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2897 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2899 if(height == 0) height = 16;
2901 /* Calc. height of EM square:
2903 * For +ve lfHeight we have
2904 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2905 * Re-arranging gives:
2906 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2908 * For -ve lfHeight we have
2910 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2911 * with il = winAscent + winDescent - units_per_em]
2916 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2917 ppem = MulDiv(ft_face->units_per_EM, height,
2918 pHori->Ascender - pHori->Descender);
2920 ppem = MulDiv(ft_face->units_per_EM, height,
2921 pOS2->usWinAscent + pOS2->usWinDescent);
2929 static struct font_mapping *map_font_file( const char *name )
2931 struct font_mapping *mapping;
2935 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2936 if (fstat( fd, &st ) == -1) goto error;
2938 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2940 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2942 mapping->refcount++;
2947 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2950 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2953 if (mapping->data == MAP_FAILED)
2955 HeapFree( GetProcessHeap(), 0, mapping );
2958 mapping->refcount = 1;
2959 mapping->dev = st.st_dev;
2960 mapping->ino = st.st_ino;
2961 mapping->size = st.st_size;
2962 list_add_tail( &mappings_list, &mapping->entry );
2970 static void unmap_font_file( struct font_mapping *mapping )
2972 if (!--mapping->refcount)
2974 list_remove( &mapping->entry );
2975 munmap( mapping->data, mapping->size );
2976 HeapFree( GetProcessHeap(), 0, mapping );
2980 static LONG load_VDMX(GdiFont*, LONG);
2982 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
2989 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
2993 if (!(font->mapping = map_font_file( face->file )))
2995 WARN("failed to map %s\n", debugstr_a(face->file));
2998 data_ptr = font->mapping->data;
2999 data_size = font->mapping->size;
3003 data_ptr = face->font_data_ptr;
3004 data_size = face->font_data_size;
3007 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3009 ERR("FT_New_Face rets %d\n", err);
3013 /* set it here, as load_VDMX needs it */
3014 font->ft_face = ft_face;
3016 if(FT_IS_SCALABLE(ft_face)) {
3017 /* load the VDMX table if we have one */
3018 font->ppem = load_VDMX(font, height);
3020 font->ppem = calc_ppem_for_height(ft_face, height);
3021 TRACE("height %d => ppem %d\n", height, font->ppem);
3023 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3024 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3026 font->ppem = height;
3027 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3028 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3034 static int get_nearest_charset(Face *face, int *cp)
3036 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3037 a single face with the requested charset. The idea is to check if
3038 the selected font supports the current ANSI codepage, if it does
3039 return the corresponding charset, else return the first charset */
3042 int acp = GetACP(), i;
3046 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3047 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3048 return csi.ciCharset;
3050 for(i = 0; i < 32; i++) {
3052 if(face->fs.fsCsb[0] & fs0) {
3053 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
3055 return csi.ciCharset;
3058 FIXME("TCI failing on %x\n", fs0);
3062 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3063 face->fs.fsCsb[0], face->file);
3065 return DEFAULT_CHARSET;
3068 static GdiFont *alloc_font(void)
3070 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
3072 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
3073 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3075 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3076 ret->total_kern_pairs = (DWORD)-1;
3077 ret->kern_pairs = NULL;
3078 list_init(&ret->hfontlist);
3079 list_init(&ret->child_fonts);
3083 static void free_font(GdiFont *font)
3085 struct list *cursor, *cursor2;
3088 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
3090 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
3091 struct list *first_hfont;
3092 HFONTLIST *hfontlist;
3093 list_remove(cursor);
3096 first_hfont = list_head(&child->font->hfontlist);
3097 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3098 DeleteObject(hfontlist->hfont);
3099 HeapFree(GetProcessHeap(), 0, hfontlist);
3100 free_font(child->font);
3102 HeapFree(GetProcessHeap(), 0, child);
3105 if (font->ft_face) pFT_Done_Face(font->ft_face);
3106 if (font->mapping) unmap_font_file( font->mapping );
3107 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
3108 HeapFree(GetProcessHeap(), 0, font->potm);
3109 HeapFree(GetProcessHeap(), 0, font->name);
3110 for (i = 0; i < font->gmsize; i++)
3111 HeapFree(GetProcessHeap(),0,font->gm[i]);
3112 HeapFree(GetProcessHeap(), 0, font->gm);
3113 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
3114 HeapFree(GetProcessHeap(), 0, font);
3118 /*************************************************************
3121 * load the vdmx entry for the specified height
3124 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3125 ( ( (FT_ULong)_x4 << 24 ) | \
3126 ( (FT_ULong)_x3 << 16 ) | \
3127 ( (FT_ULong)_x2 << 8 ) | \
3130 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3145 static LONG load_VDMX(GdiFont *font, LONG height)
3149 BYTE devXRatio, devYRatio;
3150 USHORT numRecs, numRatios;
3151 DWORD result, offset = -1;
3155 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
3157 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
3160 /* FIXME: need the real device aspect ratio */
3164 numRecs = GET_BE_WORD(hdr[1]);
3165 numRatios = GET_BE_WORD(hdr[2]);
3167 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
3168 for(i = 0; i < numRatios; i++) {
3171 offset = (3 * 2) + (i * sizeof(Ratios));
3172 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
3175 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
3177 if((ratio.xRatio == 0 &&
3178 ratio.yStartRatio == 0 &&
3179 ratio.yEndRatio == 0) ||
3180 (devXRatio == ratio.xRatio &&
3181 devYRatio >= ratio.yStartRatio &&
3182 devYRatio <= ratio.yEndRatio))
3184 offset = (3 * 2) + (numRatios * 4) + (i * 2);
3185 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
3186 offset = GET_BE_WORD(tmp);
3192 FIXME("No suitable ratio found\n");
3196 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
3198 BYTE startsz, endsz;
3201 recs = GET_BE_WORD(group.recs);
3202 startsz = group.startsz;
3203 endsz = group.endsz;
3205 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
3207 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
3208 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
3209 if(result == GDI_ERROR) {
3210 FIXME("Failed to retrieve vTable\n");
3215 for(i = 0; i < recs; i++) {
3216 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3217 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3218 ppem = GET_BE_WORD(vTable[i * 3]);
3220 if(yMax + -yMin == height) {
3223 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3226 if(yMax + -yMin > height) {
3229 goto end; /* failed */
3231 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3232 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3233 ppem = GET_BE_WORD(vTable[i * 3]);
3234 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3240 TRACE("ppem not found for height %d\n", height);
3244 if(ppem < startsz || ppem > endsz)
3247 for(i = 0; i < recs; i++) {
3249 yPelHeight = GET_BE_WORD(vTable[i * 3]);
3251 if(yPelHeight > ppem)
3254 if(yPelHeight == ppem) {
3255 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3256 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3257 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
3263 HeapFree(GetProcessHeap(), 0, vTable);
3269 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3271 if(font->font_desc.hash != fd->hash) return TRUE;
3272 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3273 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3274 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3275 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3278 static void calc_hash(FONT_DESC *pfd)
3280 DWORD hash = 0, *ptr, two_chars;
3284 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3286 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3288 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3290 pwc = (WCHAR *)&two_chars;
3292 *pwc = toupperW(*pwc);
3294 *pwc = toupperW(*pwc);
3298 hash ^= !pfd->can_use_bitmap;
3303 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3308 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3312 fd.can_use_bitmap = can_use_bitmap;
3315 /* try the child list */
3316 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
3317 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3318 if(!fontcmp(ret, &fd)) {
3319 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3320 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3321 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3322 if(hflist->hfont == hfont)
3328 /* try the in-use list */
3329 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3330 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3331 if(!fontcmp(ret, &fd)) {
3332 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3333 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3334 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3335 if(hflist->hfont == hfont)
3338 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3339 hflist->hfont = hfont;
3340 list_add_head(&ret->hfontlist, &hflist->entry);
3345 /* then the unused list */
3346 font_elem_ptr = list_head(&unused_gdi_font_list);
3347 while(font_elem_ptr) {
3348 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3349 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3350 if(!fontcmp(ret, &fd)) {
3351 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3352 assert(list_empty(&ret->hfontlist));
3353 TRACE("Found %p in unused list\n", ret);
3354 list_remove(&ret->entry);
3355 list_add_head(&gdi_font_list, &ret->entry);
3356 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3357 hflist->hfont = hfont;
3358 list_add_head(&ret->hfontlist, &hflist->entry);
3365 static void add_to_cache(GdiFont *font)
3367 static DWORD cache_num = 1;
3369 font->cache_num = cache_num++;
3370 list_add_head(&gdi_font_list, &font->entry);
3373 /*************************************************************
3374 * create_child_font_list
3376 static BOOL create_child_font_list(GdiFont *font)
3379 SYSTEM_LINKS *font_link;
3380 CHILD_FONT *font_link_entry, *new_child;
3384 psub = get_font_subst(&font_subst_list, font->name, -1);
3385 font_name = psub ? psub->to.name : font->name;
3386 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3388 if(!strcmpiW(font_link->font_name, font_name))
3390 TRACE("found entry in system list\n");
3391 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3393 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3394 new_child->face = font_link_entry->face;
3395 new_child->font = NULL;
3396 list_add_tail(&font->child_fonts, &new_child->entry);
3397 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3404 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3405 * Sans Serif. This is how asian windows get default fallbacks for fonts
3407 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3408 font->charset != OEM_CHARSET &&
3409 strcmpiW(font_name,szDefaultFallbackLink) != 0)
3410 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3412 if(!strcmpiW(font_link->font_name,szDefaultFallbackLink))
3414 TRACE("found entry in default fallback list\n");
3415 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3417 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3418 new_child->face = font_link_entry->face;
3419 new_child->font = NULL;
3420 list_add_tail(&font->child_fonts, &new_child->entry);
3421 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3431 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3433 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3435 if (pFT_Set_Charmap)
3438 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3440 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3442 for (i = 0; i < ft_face->num_charmaps; i++)
3444 if (ft_face->charmaps[i]->encoding == encoding)
3446 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3447 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3449 switch (ft_face->charmaps[i]->platform_id)
3452 cmap_def = ft_face->charmaps[i];
3454 case 0: /* Apple Unicode */
3455 cmap0 = ft_face->charmaps[i];
3457 case 1: /* Macintosh */
3458 cmap1 = ft_face->charmaps[i];
3461 cmap2 = ft_face->charmaps[i];
3463 case 3: /* Microsoft */
3464 cmap3 = ft_face->charmaps[i];
3469 if (cmap3) /* prefer Microsoft cmap table */
3470 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3472 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3474 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3476 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3478 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3480 return ft_err == FT_Err_Ok;
3483 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3486 /*************************************************************
3487 * WineEngCreateFontInstance
3490 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
3493 Face *face, *best, *best_bitmap;
3494 Family *family, *last_resort_family;
3495 struct list *family_elem_ptr, *face_elem_ptr;
3496 INT height, width = 0;
3497 unsigned int score = 0, new_score;
3498 signed int diff = 0, newdiff;
3499 BOOL bd, it, can_use_bitmap;
3504 FontSubst *psub = NULL;
3506 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
3507 lf.lfWidth = abs(lf.lfWidth);
3509 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
3511 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3512 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3513 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3516 if(dc->GraphicsMode == GM_ADVANCED)
3517 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
3520 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3521 font scaling abilities. */
3522 dcmat.eM11 = dcmat.eM22 = dc->vport2WorldValid ? fabs(dc->xformWorld2Vport.eM22) : 1.0;
3523 dcmat.eM21 = dcmat.eM12 = 0;
3526 /* Try to avoid not necessary glyph transformations */
3527 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
3529 lf.lfHeight *= fabs(dcmat.eM11);
3530 lf.lfWidth *= fabs(dcmat.eM11);
3531 dcmat.eM11 = dcmat.eM22 = 1.0;
3534 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
3535 dcmat.eM21, dcmat.eM22);
3538 EnterCriticalSection( &freetype_cs );
3540 /* check the cache first */
3541 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3542 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3543 LeaveCriticalSection( &freetype_cs );
3547 TRACE("not in cache\n");
3548 if(list_empty(&font_list)) /* No fonts installed */
3550 TRACE("No fonts installed\n");
3551 LeaveCriticalSection( &freetype_cs );
3554 if(!have_installed_roman_font)
3556 TRACE("No roman font installed\n");
3557 LeaveCriticalSection( &freetype_cs );
3563 ret->font_desc.matrix = dcmat;
3564 ret->font_desc.lf = lf;
3565 ret->font_desc.can_use_bitmap = can_use_bitmap;
3566 calc_hash(&ret->font_desc);
3567 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3568 hflist->hfont = hfont;
3569 list_add_head(&ret->hfontlist, &hflist->entry);
3571 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3572 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3573 original value lfCharSet. Note this is a special case for
3574 Symbol and doesn't happen at least for "Wingdings*" */
3576 if(!strcmpiW(lf.lfFaceName, SymbolW))
3577 lf.lfCharSet = SYMBOL_CHARSET;
3579 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3580 switch(lf.lfCharSet) {
3581 case DEFAULT_CHARSET:
3582 csi.fs.fsCsb[0] = 0;
3585 FIXME("Untranslated charset %d\n", lf.lfCharSet);
3586 csi.fs.fsCsb[0] = 0;
3592 if(lf.lfFaceName[0] != '\0') {
3593 SYSTEM_LINKS *font_link;
3594 CHILD_FONT *font_link_entry;
3595 LPWSTR FaceName = lf.lfFaceName;
3598 * Check for a leading '@' this signals that the font is being
3599 * requested in tategaki mode (vertical writing substitution) but
3600 * does not affect the fontface that is to be selected.
3602 if (lf.lfFaceName[0]=='@')
3603 FaceName = &lf.lfFaceName[1];
3605 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
3608 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
3609 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
3610 if (psub->to.charset != -1)
3611 lf.lfCharSet = psub->to.charset;
3614 /* We want a match on name and charset or just name if
3615 charset was DEFAULT_CHARSET. If the latter then
3616 we fixup the returned charset later in get_nearest_charset
3617 where we'll either use the charset of the current ansi codepage
3618 or if that's unavailable the first charset that the font supports.
3620 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3621 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3622 if (!strcmpiW(family->FamilyName, FaceName) ||
3623 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
3625 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3626 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3627 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3628 if(face->scalable || can_use_bitmap)
3635 * Try check the SystemLink list first for a replacement font.
3636 * We may find good replacements there.
3638 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3640 if(!strcmpiW(font_link->font_name, FaceName) ||
3641 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
3643 TRACE("found entry in system list\n");
3644 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3646 face = font_link_entry->face;
3647 family = face->family;
3648 if(csi.fs.fsCsb[0] &
3649 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
3651 if(face->scalable || can_use_bitmap)
3659 psub = NULL; /* substitution is no more relevant */
3661 /* If requested charset was DEFAULT_CHARSET then try using charset
3662 corresponding to the current ansi codepage */
3663 if (!csi.fs.fsCsb[0])
3666 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
3667 FIXME("TCI failed on codepage %d\n", acp);
3668 csi.fs.fsCsb[0] = 0;
3670 lf.lfCharSet = csi.ciCharset;
3673 /* Face families are in the top 4 bits of lfPitchAndFamily,
3674 so mask with 0xF0 before testing */
3676 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
3677 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
3678 strcpyW(lf.lfFaceName, defFixed);
3679 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
3680 strcpyW(lf.lfFaceName, defSerif);
3681 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
3682 strcpyW(lf.lfFaceName, defSans);
3684 strcpyW(lf.lfFaceName, defSans);
3685 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3686 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3687 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
3688 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3689 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3690 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3691 if(face->scalable || can_use_bitmap)
3697 last_resort_family = NULL;
3698 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3699 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3700 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3701 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3702 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
3705 if(can_use_bitmap && !last_resort_family)
3706 last_resort_family = family;
3711 if(last_resort_family) {
3712 family = last_resort_family;
3713 csi.fs.fsCsb[0] = 0;
3717 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3718 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3719 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3720 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3721 if(face->scalable) {
3722 csi.fs.fsCsb[0] = 0;
3723 WARN("just using first face for now\n");
3726 if(can_use_bitmap && !last_resort_family)
3727 last_resort_family = family;
3730 if(!last_resort_family) {
3731 FIXME("can't find a single appropriate font - bailing\n");
3733 LeaveCriticalSection( &freetype_cs );
3737 WARN("could only find a bitmap font - this will probably look awful!\n");
3738 family = last_resort_family;
3739 csi.fs.fsCsb[0] = 0;
3742 it = lf.lfItalic ? 1 : 0;
3743 bd = lf.lfWeight > 550 ? 1 : 0;
3745 height = lf.lfHeight;
3747 face = best = best_bitmap = NULL;
3748 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
3750 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3754 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
3755 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
3756 new_score = (italic ^ it) + (bold ^ bd);
3757 if(!best || new_score <= score)
3759 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3760 italic, bold, it, bd);
3763 if(best->scalable && score == 0) break;
3767 newdiff = height - (signed int)(best->size.height);
3769 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
3770 if(!best_bitmap || new_score < score ||
3771 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
3773 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
3776 if(score == 0 && diff == 0) break;
3783 face = best->scalable ? best : best_bitmap;
3784 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
3785 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
3789 if(csi.fs.fsCsb[0]) {
3790 ret->charset = lf.lfCharSet;
3791 ret->codepage = csi.ciACP;
3794 ret->charset = get_nearest_charset(face, &ret->codepage);
3796 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
3797 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
3799 ret->aveWidth = height ? lf.lfWidth : 0;
3801 if(!face->scalable) {
3802 /* Windows uses integer scaling factors for bitmap fonts */
3803 INT scale, scaled_height;
3805 /* FIXME: rotation of bitmap fonts is ignored */
3806 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
3808 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
3809 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3811 if (height != 0) height = diff;
3812 height += face->size.height;
3814 scale = (height + face->size.height - 1) / face->size.height;
3815 scaled_height = scale * face->size.height;
3816 /* Only jump to the next height if the difference <= 25% original height */
3817 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
3818 /* The jump between unscaled and doubled is delayed by 1 */
3819 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
3820 ret->scale_y = scale;
3822 width = face->size.x_ppem >> 6;
3823 height = face->size.y_ppem >> 6;
3827 TRACE("font scale y: %f\n", ret->scale_y);
3829 ret->ft_face = OpenFontFace(ret, face, width, height);
3834 LeaveCriticalSection( &freetype_cs );
3838 ret->ntmFlags = face->ntmFlags;
3840 if (ret->charset == SYMBOL_CHARSET &&
3841 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
3844 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
3848 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
3851 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
3852 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
3853 ret->underline = lf.lfUnderline ? 0xff : 0;
3854 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
3855 create_child_font_list(ret);
3857 if (lf.lfFaceName[0]=='@') /* We need to try to load the GSUB table */
3859 int length = WineEngGetFontData (ret, GSUB_TAG , 0, NULL, 0);
3860 if (length != GDI_ERROR)
3862 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
3863 WineEngGetFontData(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
3864 TRACE("Loaded GSUB table of %i bytes\n",length);
3868 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
3871 LeaveCriticalSection( &freetype_cs );
3875 static void dump_gdi_font_list(void)
3878 struct list *elem_ptr;
3880 TRACE("---------- gdiFont Cache ----------\n");
3881 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
3882 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3883 TRACE("gdiFont=%p %s %d\n",
3884 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3887 TRACE("---------- Unused gdiFont Cache ----------\n");
3888 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
3889 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3890 TRACE("gdiFont=%p %s %d\n",
3891 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3895 /*************************************************************
3896 * WineEngDestroyFontInstance
3898 * free the gdiFont associated with this handle
3901 BOOL WineEngDestroyFontInstance(HFONT handle)
3906 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3910 EnterCriticalSection( &freetype_cs );
3912 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
3914 struct list *first_hfont = list_head(&gdiFont->hfontlist);
3915 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3916 if(hflist->hfont == handle)
3918 TRACE("removing child font %p from child list\n", gdiFont);
3919 list_remove(&gdiFont->entry);
3920 LeaveCriticalSection( &freetype_cs );
3925 TRACE("destroying hfont=%p\n", handle);
3927 dump_gdi_font_list();
3929 font_elem_ptr = list_head(&gdi_font_list);
3930 while(font_elem_ptr) {
3931 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3932 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3934 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3935 while(hfontlist_elem_ptr) {
3936 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3937 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3938 if(hflist->hfont == handle) {
3939 list_remove(&hflist->entry);
3940 HeapFree(GetProcessHeap(), 0, hflist);
3944 if(list_empty(&gdiFont->hfontlist)) {
3945 TRACE("Moving to Unused list\n");
3946 list_remove(&gdiFont->entry);
3947 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3952 font_elem_ptr = list_head(&unused_gdi_font_list);
3953 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3954 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3955 while(font_elem_ptr) {
3956 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3957 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3958 TRACE("freeing %p\n", gdiFont);
3959 list_remove(&gdiFont->entry);
3962 LeaveCriticalSection( &freetype_cs );
3966 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
3967 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
3972 if (face->cached_enum_data)
3975 *pelf = face->cached_enum_data->elf;
3976 *pntm = face->cached_enum_data->ntm;
3977 *ptype = face->cached_enum_data->type;
3981 font = alloc_font();
3983 if(face->scalable) {
3984 height = -2048; /* 2048 is the most common em size */
3987 height = face->size.y_ppem >> 6;
3988 width = face->size.x_ppem >> 6;
3990 font->scale_y = 1.0;
3992 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
3998 font->name = strdupW(face->family->FamilyName);
3999 font->ntmFlags = face->ntmFlags;
4001 if (WineEngGetOutlineTextMetrics(font, 0, NULL))
4003 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
4005 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
4007 lstrcpynW(pelf->elfLogFont.lfFaceName,
4008 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
4010 lstrcpynW(pelf->elfFullName,
4011 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
4013 lstrcpynW(pelf->elfStyle,
4014 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
4019 WineEngGetTextMetrics(font, (TEXTMETRICW *)&pntm->ntmTm);
4021 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
4023 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
4024 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
4025 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
4028 pntm->ntmTm.ntmFlags = face->ntmFlags;
4029 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
4030 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
4031 pntm->ntmFontSig = face->fs;
4033 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
4035 pelf->elfLogFont.lfEscapement = 0;
4036 pelf->elfLogFont.lfOrientation = 0;
4037 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
4038 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
4039 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
4040 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
4041 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
4042 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
4043 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
4044 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
4045 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
4046 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
4047 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
4050 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
4051 *ptype |= TRUETYPE_FONTTYPE;
4052 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
4053 *ptype |= DEVICE_FONTTYPE;
4054 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
4055 *ptype |= RASTER_FONTTYPE;
4057 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
4058 if (face->cached_enum_data)
4060 face->cached_enum_data->elf = *pelf;
4061 face->cached_enum_data->ntm = *pntm;
4062 face->cached_enum_data->type = *ptype;
4068 /*************************************************************
4072 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
4076 struct list *family_elem_ptr, *face_elem_ptr;
4078 NEWTEXTMETRICEXW ntm;
4087 lf.lfCharSet = DEFAULT_CHARSET;
4088 lf.lfPitchAndFamily = 0;
4089 lf.lfFaceName[0] = 0;
4093 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
4096 EnterCriticalSection( &freetype_cs );
4097 if(plf->lfFaceName[0]) {
4099 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
4102 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
4103 debugstr_w(psub->to.name));
4105 strcpyW(lf.lfFaceName, psub->to.name);
4109 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4110 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4111 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
4112 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4113 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4114 GetEnumStructs(face, &elf, &ntm, &type);
4115 for(i = 0; i < 32; i++) {
4116 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
4117 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
4118 strcpyW(elf.elfScript, OEM_DOSW);
4119 i = 32; /* break out of loop */
4120 } else if(!(face->fs.fsCsb[0] & (1L << i)))
4123 fs.fsCsb[0] = 1L << i;
4125 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
4127 csi.ciCharset = DEFAULT_CHARSET;
4128 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
4129 if(csi.ciCharset != DEFAULT_CHARSET) {
4130 elf.elfLogFont.lfCharSet =
4131 ntm.ntmTm.tmCharSet = csi.ciCharset;
4133 strcpyW(elf.elfScript, ElfScriptsW[i]);
4135 FIXME("Unknown elfscript for bit %d\n", i);
4138 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
4139 debugstr_w(elf.elfLogFont.lfFaceName),
4140 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
4141 csi.ciCharset, type, debugstr_w(elf.elfScript),
4142 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
4143 ntm.ntmTm.ntmFlags);
4144 /* release section before callback (FIXME) */
4145 LeaveCriticalSection( &freetype_cs );
4146 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
4147 EnterCriticalSection( &freetype_cs );
4153 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4154 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4155 face_elem_ptr = list_head(&family->faces);
4156 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4157 GetEnumStructs(face, &elf, &ntm, &type);
4158 for(i = 0; i < 32; i++) {
4159 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
4160 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
4161 strcpyW(elf.elfScript, OEM_DOSW);
4162 i = 32; /* break out of loop */
4163 } else if(!(face->fs.fsCsb[0] & (1L << i)))
4166 fs.fsCsb[0] = 1L << i;
4168 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
4170 csi.ciCharset = DEFAULT_CHARSET;
4171 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
4172 if(csi.ciCharset != DEFAULT_CHARSET) {
4173 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
4176 strcpyW(elf.elfScript, ElfScriptsW[i]);
4178 FIXME("Unknown elfscript for bit %d\n", i);
4181 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4182 debugstr_w(elf.elfLogFont.lfFaceName),
4183 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
4184 csi.ciCharset, type, debugstr_w(elf.elfScript),
4185 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
4186 ntm.ntmTm.ntmFlags);
4187 /* release section before callback (FIXME) */
4188 LeaveCriticalSection( &freetype_cs );
4189 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
4190 EnterCriticalSection( &freetype_cs );
4194 LeaveCriticalSection( &freetype_cs );
4198 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
4200 pt->x.value = vec->x >> 6;
4201 pt->x.fract = (vec->x & 0x3f) << 10;
4202 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
4203 pt->y.value = vec->y >> 6;
4204 pt->y.fract = (vec->y & 0x3f) << 10;
4205 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
4209 /***************************************************
4210 * According to the MSDN documentation on WideCharToMultiByte,
4211 * certain codepages cannot set the default_used parameter.
4212 * This returns TRUE if the codepage can set that parameter, false else
4213 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4215 static BOOL codepage_sets_default_used(UINT codepage)
4229 * GSUB Table handling functions
4232 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
4234 const GSUB_CoverageFormat1* cf1;
4238 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
4240 int count = GET_BE_WORD(cf1->GlyphCount);
4242 TRACE("Coverage Format 1, %i glyphs\n",count);
4243 for (i = 0; i < count; i++)
4244 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
4248 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
4250 const GSUB_CoverageFormat2* cf2;
4253 cf2 = (GSUB_CoverageFormat2*)cf1;
4255 count = GET_BE_WORD(cf2->RangeCount);
4256 TRACE("Coverage Format 2, %i ranges\n",count);
4257 for (i = 0; i < count; i++)
4259 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
4261 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
4262 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
4264 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4265 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4271 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4276 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4278 const GSUB_ScriptList *script;
4279 const GSUB_Script *deflt = NULL;
4281 script = (GSUB_ScriptList*)((LPBYTE)header + GET_BE_WORD(header->ScriptList));
4283 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4284 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4286 const GSUB_Script *scr;
4289 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4290 scr = (GSUB_Script*)((LPBYTE)script + offset);
4292 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4294 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4300 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4304 const GSUB_LangSys *Lang;
4306 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4308 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4310 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4311 Lang = (GSUB_LangSys*)((LPBYTE)script + offset);
4313 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4316 offset = GET_BE_WORD(script->DefaultLangSys);
4319 Lang = (GSUB_LangSys*)((LPBYTE)script + offset);
4325 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4328 const GSUB_FeatureList *feature;
4329 feature = (GSUB_FeatureList*)((LPBYTE)header + GET_BE_WORD(header->FeatureList));
4331 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4332 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4334 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4335 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4337 const GSUB_Feature *feat;
4338 feat = (GSUB_Feature*)((LPBYTE)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4345 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4349 const GSUB_LookupList *lookup;
4350 lookup = (GSUB_LookupList*)((LPBYTE)header + GET_BE_WORD(header->LookupList));
4352 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
4353 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
4355 const GSUB_LookupTable *look;
4356 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
4357 look = (GSUB_LookupTable*)((LPBYTE)lookup + offset);
4358 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
4359 if (GET_BE_WORD(look->LookupType) != 1)
4360 FIXME("We only handle SubType 1\n");
4365 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
4367 const GSUB_SingleSubstFormat1 *ssf1;
4368 offset = GET_BE_WORD(look->SubTable[j]);
4369 ssf1 = (GSUB_SingleSubstFormat1*)((LPBYTE)look+offset);
4370 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
4372 int offset = GET_BE_WORD(ssf1->Coverage);
4373 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
4374 if (GSUB_is_glyph_covered((LPBYTE)ssf1+offset, glyph) != -1)
4376 TRACE(" Glyph 0x%x ->",glyph);
4377 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4378 TRACE(" 0x%x\n",glyph);
4383 const GSUB_SingleSubstFormat2 *ssf2;
4387 ssf2 = (GSUB_SingleSubstFormat2 *)ssf1;
4388 offset = GET_BE_WORD(ssf1->Coverage);
4389 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4390 index = GSUB_is_glyph_covered((LPBYTE)ssf2+offset, glyph);
4391 TRACE(" Coverage index %i\n",index);
4394 TRACE(" Glyph is 0x%x ->",glyph);
4395 glyph = GET_BE_WORD(ssf2->Substitute[index]);
4396 TRACE("0x%x\n",glyph);
4405 static const char* get_opentype_script(const GdiFont *font)
4408 * I am not sure if this is the correct way to generate our script tag
4411 switch (font->charset)
4413 case ANSI_CHARSET: return "latn";
4414 case BALTIC_CHARSET: return "latn"; /* ?? */
4415 case CHINESEBIG5_CHARSET: return "hani";
4416 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4417 case GB2312_CHARSET: return "hani";
4418 case GREEK_CHARSET: return "grek";
4419 case HANGUL_CHARSET: return "hang";
4420 case RUSSIAN_CHARSET: return "cyrl";
4421 case SHIFTJIS_CHARSET: return "kana";
4422 case TURKISH_CHARSET: return "latn"; /* ?? */
4423 case VIETNAMESE_CHARSET: return "latn";
4424 case JOHAB_CHARSET: return "latn"; /* ?? */
4425 case ARABIC_CHARSET: return "arab";
4426 case HEBREW_CHARSET: return "hebr";
4427 case THAI_CHARSET: return "thai";
4428 default: return "latn";
4432 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
4434 const GSUB_Header *header;
4435 const GSUB_Script *script;
4436 const GSUB_LangSys *language;
4437 const GSUB_Feature *feature;
4439 if (!font->GSUB_Table)
4442 header = font->GSUB_Table;
4444 script = GSUB_get_script_table(header, get_opentype_script(font));
4447 TRACE("Script not found\n");
4450 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
4453 TRACE("Language not found\n");
4456 feature = GSUB_get_feature(header, language, "vrt2");
4458 feature = GSUB_get_feature(header, language, "vert");
4461 TRACE("vrt2/vert feature not found\n");
4464 return GSUB_apply_feature(header, feature, glyph);
4467 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
4471 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
4472 WCHAR wc = (WCHAR)glyph;
4474 BOOL *default_used_pointer;
4477 default_used_pointer = NULL;
4478 default_used = FALSE;
4479 if (codepage_sets_default_used(font->codepage))
4480 default_used_pointer = &default_used;
4481 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
4484 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
4485 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
4486 return get_GSUB_vert_glyph(font,ret);
4489 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL && glyph < 0x100)
4490 glyph = glyph + 0xf000;
4491 glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
4492 return get_GSUB_vert_glyph(font,glyphId);
4495 /*************************************************************
4496 * WineEngGetGlyphIndices
4499 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4500 LPWORD pgi, DWORD flags)
4503 int default_char = -1;
4505 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
4507 for(i = 0; i < count; i++)
4509 pgi[i] = get_glyph_index(font, lpstr[i]);
4512 if (default_char == -1)
4514 if (FT_IS_SFNT(font->ft_face))
4516 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
4517 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
4522 WineEngGetTextMetrics(font, &textm);
4523 default_char = textm.tmDefaultChar;
4526 pgi[i] = default_char;
4532 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
4534 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
4535 return !memcmp(matrix, &identity, sizeof(FMAT2));
4538 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
4540 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
4541 return !memcmp(matrix, &identity, sizeof(MAT2));
4544 /*************************************************************
4545 * WineEngGetGlyphOutline
4547 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4548 * except that the first parameter is the HWINEENGFONT of the font in
4549 * question rather than an HDC.
4552 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
4553 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4556 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
4557 FT_Face ft_face = incoming_font->ft_face;
4558 GdiFont *font = incoming_font;
4559 FT_UInt glyph_index;
4560 DWORD width, height, pitch, needed = 0;
4561 FT_Bitmap ft_bitmap;
4563 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
4565 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
4566 double widthRatio = 1.0;
4567 FT_Matrix transMat = identityMat;
4568 FT_Matrix transMatUnrotated;
4569 BOOL needsTransform = FALSE;
4570 BOOL tategaki = (font->GSUB_Table != NULL);
4571 UINT original_index;
4573 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
4574 buflen, buf, lpmat);
4576 TRACE("font transform %f %f %f %f\n",
4577 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
4578 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
4581 EnterCriticalSection( &freetype_cs );
4583 if(format & GGO_GLYPH_INDEX) {
4584 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
4585 original_index = glyph;
4586 format &= ~GGO_GLYPH_INDEX;
4588 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
4589 ft_face = font->ft_face;
4590 original_index = glyph_index;
4593 if(format & GGO_UNHINTED) {
4594 load_flags |= FT_LOAD_NO_HINTING;
4595 format &= ~GGO_UNHINTED;
4598 /* tategaki never appears to happen to lower glyph index */
4599 if (glyph_index < TATEGAKI_LOWER_BOUND )
4602 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
4603 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
4604 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
4605 font->gmsize * sizeof(GM*));
4607 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
4608 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
4610 *lpgm = FONT_GM(font,original_index)->gm;
4611 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4612 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4613 lpgm->gmCellIncX, lpgm->gmCellIncY);
4614 LeaveCriticalSection( &freetype_cs );
4615 return 1; /* FIXME */
4619 if (!font->gm[original_index / GM_BLOCK_SIZE])
4620 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4622 /* Scaling factor */
4627 WineEngGetTextMetrics(font, &tm);
4629 widthRatio = (double)font->aveWidth;
4630 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
4633 widthRatio = font->scale_y;
4635 /* Scaling transform */
4636 if (widthRatio != 1.0 || font->scale_y != 1.0)
4639 scaleMat.xx = FT_FixedFromFloat(widthRatio);
4642 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
4644 pFT_Matrix_Multiply(&scaleMat, &transMat);
4645 needsTransform = TRUE;
4648 /* Slant transform */
4649 if (font->fake_italic) {
4652 slantMat.xx = (1 << 16);
4653 slantMat.xy = ((1 << 16) >> 2);
4655 slantMat.yy = (1 << 16);
4656 pFT_Matrix_Multiply(&slantMat, &transMat);
4657 needsTransform = TRUE;
4660 /* Rotation transform */
4661 transMatUnrotated = transMat;
4662 if(font->orientation && !tategaki) {
4663 FT_Matrix rotationMat;
4665 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
4666 pFT_Vector_Unit(&vecAngle, angle);
4667 rotationMat.xx = vecAngle.x;
4668 rotationMat.xy = -vecAngle.y;
4669 rotationMat.yx = -rotationMat.xy;
4670 rotationMat.yy = rotationMat.xx;
4672 pFT_Matrix_Multiply(&rotationMat, &transMat);
4673 needsTransform = TRUE;
4676 /* World transform */
4677 if (!is_identity_FMAT2(&font->font_desc.matrix))
4680 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
4681 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
4682 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
4683 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
4684 pFT_Matrix_Multiply(&worldMat, &transMat);
4685 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
4686 needsTransform = TRUE;
4689 /* Extra transformation specified by caller */
4690 if (!is_identity_MAT2(lpmat))
4693 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
4694 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
4695 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
4696 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
4697 pFT_Matrix_Multiply(&extraMat, &transMat);
4698 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
4699 needsTransform = TRUE;
4702 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
4703 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
4704 format == GGO_GRAY8_BITMAP))
4706 load_flags |= FT_LOAD_NO_BITMAP;
4709 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
4712 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
4713 LeaveCriticalSection( &freetype_cs );
4717 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
4718 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
4720 adv = (INT)((ft_face->glyph->metrics.horiAdvance) + 63) >> 6;
4722 bbx = (right - left) >> 6;
4724 if(!needsTransform) {
4725 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
4726 bottom = (ft_face->glyph->metrics.horiBearingY -
4727 ft_face->glyph->metrics.height) & -64;
4728 lpgm->gmCellIncX = adv;
4729 lpgm->gmCellIncY = 0;
4733 for(xc = 0; xc < 2; xc++) {
4734 for(yc = 0; yc < 2; yc++) {
4735 vec.x = (ft_face->glyph->metrics.horiBearingX +
4736 xc * ft_face->glyph->metrics.width);
4737 vec.y = ft_face->glyph->metrics.horiBearingY -
4738 yc * ft_face->glyph->metrics.height;
4739 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
4740 pFT_Vector_Transform(&vec, &transMat);
4741 if(xc == 0 && yc == 0) {
4742 left = right = vec.x;
4743 top = bottom = vec.y;
4745 if(vec.x < left) left = vec.x;
4746 else if(vec.x > right) right = vec.x;
4747 if(vec.y < bottom) bottom = vec.y;
4748 else if(vec.y > top) top = vec.y;
4753 right = (right + 63) & -64;
4754 bottom = bottom & -64;
4755 top = (top + 63) & -64;
4757 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
4758 vec.x = ft_face->glyph->metrics.horiAdvance;
4760 pFT_Vector_Transform(&vec, &transMat);
4761 lpgm->gmCellIncX = (vec.x+63) >> 6;
4762 lpgm->gmCellIncY = -((vec.y+63) >> 6);
4764 vec.x = ft_face->glyph->metrics.horiAdvance;
4766 pFT_Vector_Transform(&vec, &transMatUnrotated);
4767 adv = (vec.x+63) >> 6;
4769 lpgm->gmBlackBoxX = (right - left) >> 6;
4770 lpgm->gmBlackBoxY = (top - bottom) >> 6;
4771 lpgm->gmptGlyphOrigin.x = left >> 6;
4772 lpgm->gmptGlyphOrigin.y = top >> 6;
4774 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4775 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4776 lpgm->gmCellIncX, lpgm->gmCellIncY);
4778 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
4779 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
4781 FONT_GM(font,original_index)->gm = *lpgm;
4782 FONT_GM(font,original_index)->adv = adv;
4783 FONT_GM(font,original_index)->lsb = lsb;
4784 FONT_GM(font,original_index)->bbx = bbx;
4785 FONT_GM(font,original_index)->init = TRUE;
4788 if(format == GGO_METRICS)
4790 LeaveCriticalSection( &freetype_cs );
4791 return 1; /* FIXME */
4794 if(ft_face->glyph->format != ft_glyph_format_outline &&
4795 (format == GGO_NATIVE || format == GGO_BEZIER ||
4796 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
4797 format == GGO_GRAY8_BITMAP))
4799 TRACE("loaded a bitmap\n");
4800 LeaveCriticalSection( &freetype_cs );
4806 width = lpgm->gmBlackBoxX;
4807 height = lpgm->gmBlackBoxY;
4808 pitch = ((width + 31) >> 5) << 2;
4809 needed = pitch * height;
4811 if(!buf || !buflen) break;
4813 switch(ft_face->glyph->format) {
4814 case ft_glyph_format_bitmap:
4816 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4817 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
4818 INT h = ft_face->glyph->bitmap.rows;
4820 memcpy(dst, src, w);
4821 src += ft_face->glyph->bitmap.pitch;
4827 case ft_glyph_format_outline:
4828 ft_bitmap.width = width;
4829 ft_bitmap.rows = height;
4830 ft_bitmap.pitch = pitch;
4831 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
4832 ft_bitmap.buffer = buf;
4835 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4837 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4839 /* Note: FreeType will only set 'black' bits for us. */
4840 memset(buf, 0, needed);
4841 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4845 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4846 LeaveCriticalSection( &freetype_cs );
4851 case GGO_GRAY2_BITMAP:
4852 case GGO_GRAY4_BITMAP:
4853 case GGO_GRAY8_BITMAP:
4854 case WINE_GGO_GRAY16_BITMAP:
4856 unsigned int mult, row, col;
4859 width = lpgm->gmBlackBoxX;
4860 height = lpgm->gmBlackBoxY;
4861 pitch = (width + 3) / 4 * 4;
4862 needed = pitch * height;
4864 if(!buf || !buflen) break;
4866 switch(ft_face->glyph->format) {
4867 case ft_glyph_format_bitmap:
4869 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4870 INT h = ft_face->glyph->bitmap.rows;
4873 for(x = 0; x < pitch; x++)
4875 if(x < ft_face->glyph->bitmap.width)
4876 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
4880 src += ft_face->glyph->bitmap.pitch;
4883 LeaveCriticalSection( &freetype_cs );
4886 case ft_glyph_format_outline:
4888 ft_bitmap.width = width;
4889 ft_bitmap.rows = height;
4890 ft_bitmap.pitch = pitch;
4891 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
4892 ft_bitmap.buffer = buf;
4895 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4897 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4899 memset(ft_bitmap.buffer, 0, buflen);
4901 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4903 if(format == GGO_GRAY2_BITMAP)
4905 else if(format == GGO_GRAY4_BITMAP)
4907 else if(format == GGO_GRAY8_BITMAP)
4909 else /* format == WINE_GGO_GRAY16_BITMAP */
4911 LeaveCriticalSection( &freetype_cs );
4917 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4918 LeaveCriticalSection( &freetype_cs );
4923 for(row = 0; row < height; row++) {
4925 for(col = 0; col < width; col++, ptr++) {
4926 *ptr = (((int)*ptr) * mult + 128) / 256;
4933 case WINE_GGO_HRGB_BITMAP:
4934 case WINE_GGO_HBGR_BITMAP:
4935 case WINE_GGO_VRGB_BITMAP:
4936 case WINE_GGO_VBGR_BITMAP:
4937 #ifdef HAVE_FREETYPE_FTLCDFIL_H
4939 switch (ft_face->glyph->format)
4941 case FT_GLYPH_FORMAT_BITMAP:
4946 width = lpgm->gmBlackBoxX;
4947 height = lpgm->gmBlackBoxY;
4949 needed = pitch * height;
4951 if (!buf || !buflen) break;
4953 memset(buf, 0, buflen);
4955 src = ft_face->glyph->bitmap.buffer;
4956 src_pitch = ft_face->glyph->bitmap.pitch;
4960 for (x = 0; x < width; x++)
4962 if ( src[x / 8] & (1 << ( (7 - (x % 8)))) )
4963 ((unsigned int *)dst)[x] = ~0u;
4972 case FT_GLYPH_FORMAT_OUTLINE:
4976 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
4977 INT x_shift, y_shift;
4979 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
4980 FT_Render_Mode render_mode =
4981 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
4982 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
4984 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
4986 if ( render_mode == FT_RENDER_MODE_LCD)
4988 lpgm->gmBlackBoxX += 2;
4989 lpgm->gmptGlyphOrigin.x -= 1;
4993 lpgm->gmBlackBoxY += 2;
4994 lpgm->gmptGlyphOrigin.y += 1;
4998 width = lpgm->gmBlackBoxX;
4999 height = lpgm->gmBlackBoxY;
5001 needed = pitch * height;
5003 if (!buf || !buflen) break;
5005 memset(buf, 0, buflen);
5007 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
5009 if ( needsTransform )
5010 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
5012 if ( pFT_Library_SetLcdFilter )
5013 pFT_Library_SetLcdFilter( library, lcdfilter );
5014 pFT_Render_Glyph (ft_face->glyph, render_mode);
5016 src = ft_face->glyph->bitmap.buffer;
5017 src_pitch = ft_face->glyph->bitmap.pitch;
5018 src_width = ft_face->glyph->bitmap.width;
5019 src_height = ft_face->glyph->bitmap.rows;
5021 if ( render_mode == FT_RENDER_MODE_LCD)
5029 rgb_interval = src_pitch;
5034 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
5035 if ( x_shift < 0 ) x_shift = 0;
5036 if ( x_shift + (src_width / hmul) > width )
5037 x_shift = width - (src_width / hmul);
5039 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
5040 if ( y_shift < 0 ) y_shift = 0;
5041 if ( y_shift + (src_height / vmul) > height )
5042 y_shift = height - (src_height / vmul);
5044 dst += x_shift + y_shift * ( pitch / 4 );
5045 while ( src_height )
5047 for ( x = 0; x < src_width / hmul; x++ )
5051 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
5052 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5053 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
5054 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5058 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
5059 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5060 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
5061 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5064 src += src_pitch * vmul;
5073 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
5074 LeaveCriticalSection ( &freetype_cs );
5081 LeaveCriticalSection( &freetype_cs );
5087 int contour, point = 0, first_pt;
5088 FT_Outline *outline = &ft_face->glyph->outline;
5089 TTPOLYGONHEADER *pph;
5091 DWORD pph_start, cpfx, type;
5093 if(buflen == 0) buf = NULL;
5095 if (needsTransform && buf) {
5096 pFT_Outline_Transform(outline, &transMat);
5099 for(contour = 0; contour < outline->n_contours; contour++) {
5101 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5104 pph->dwType = TT_POLYGON_TYPE;
5105 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5107 needed += sizeof(*pph);
5109 while(point <= outline->contours[contour]) {
5110 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5111 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5112 TT_PRIM_LINE : TT_PRIM_QSPLINE;
5116 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5119 } while(point <= outline->contours[contour] &&
5120 (outline->tags[point] & FT_Curve_Tag_On) ==
5121 (outline->tags[point-1] & FT_Curve_Tag_On));
5122 /* At the end of a contour Windows adds the start point, but
5124 if(point > outline->contours[contour] &&
5125 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
5127 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
5129 } else if(point <= outline->contours[contour] &&
5130 outline->tags[point] & FT_Curve_Tag_On) {
5131 /* add closing pt for bezier */
5133 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5141 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5144 pph->cb = needed - pph_start;
5150 /* Convert the quadratic Beziers to cubic Beziers.
5151 The parametric eqn for a cubic Bezier is, from PLRM:
5152 r(t) = at^3 + bt^2 + ct + r0
5153 with the control points:
5158 A quadratic Beizer has the form:
5159 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5161 So equating powers of t leads to:
5162 r1 = 2/3 p1 + 1/3 p0
5163 r2 = 2/3 p1 + 1/3 p2
5164 and of course r0 = p0, r3 = p2
5167 int contour, point = 0, first_pt;
5168 FT_Outline *outline = &ft_face->glyph->outline;
5169 TTPOLYGONHEADER *pph;
5171 DWORD pph_start, cpfx, type;
5172 FT_Vector cubic_control[4];
5173 if(buflen == 0) buf = NULL;
5175 if (needsTransform && buf) {
5176 pFT_Outline_Transform(outline, &transMat);
5179 for(contour = 0; contour < outline->n_contours; contour++) {
5181 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5184 pph->dwType = TT_POLYGON_TYPE;
5185 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5187 needed += sizeof(*pph);
5189 while(point <= outline->contours[contour]) {
5190 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5191 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5192 TT_PRIM_LINE : TT_PRIM_CSPLINE;
5195 if(type == TT_PRIM_LINE) {
5197 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5201 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5204 /* FIXME: Possible optimization in endpoint calculation
5205 if there are two consecutive curves */
5206 cubic_control[0] = outline->points[point-1];
5207 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
5208 cubic_control[0].x += outline->points[point].x + 1;
5209 cubic_control[0].y += outline->points[point].y + 1;
5210 cubic_control[0].x >>= 1;
5211 cubic_control[0].y >>= 1;
5213 if(point+1 > outline->contours[contour])
5214 cubic_control[3] = outline->points[first_pt];
5216 cubic_control[3] = outline->points[point+1];
5217 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
5218 cubic_control[3].x += outline->points[point].x + 1;
5219 cubic_control[3].y += outline->points[point].y + 1;
5220 cubic_control[3].x >>= 1;
5221 cubic_control[3].y >>= 1;
5224 /* r1 = 1/3 p0 + 2/3 p1
5225 r2 = 1/3 p2 + 2/3 p1 */
5226 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
5227 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
5228 cubic_control[2] = cubic_control[1];
5229 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
5230 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
5231 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
5232 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
5234 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
5235 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
5236 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
5241 } while(point <= outline->contours[contour] &&
5242 (outline->tags[point] & FT_Curve_Tag_On) ==
5243 (outline->tags[point-1] & FT_Curve_Tag_On));
5244 /* At the end of a contour Windows adds the start point,
5245 but only for Beziers and we've already done that.
5247 if(point <= outline->contours[contour] &&
5248 outline->tags[point] & FT_Curve_Tag_On) {
5249 /* This is the closing pt of a bezier, but we've already
5250 added it, so just inc point and carry on */
5257 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5260 pph->cb = needed - pph_start;
5266 FIXME("Unsupported format %d\n", format);
5267 LeaveCriticalSection( &freetype_cs );
5270 LeaveCriticalSection( &freetype_cs );
5274 static BOOL get_bitmap_text_metrics(GdiFont *font)
5276 FT_Face ft_face = font->ft_face;
5277 #ifdef HAVE_FREETYPE_FTWINFNT_H
5278 FT_WinFNT_HeaderRec winfnt_header;
5280 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
5281 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
5282 font->potm->otmSize = size;
5284 #define TM font->potm->otmTextMetrics
5285 #ifdef HAVE_FREETYPE_FTWINFNT_H
5286 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
5288 TM.tmHeight = winfnt_header.pixel_height;
5289 TM.tmAscent = winfnt_header.ascent;
5290 TM.tmDescent = TM.tmHeight - TM.tmAscent;
5291 TM.tmInternalLeading = winfnt_header.internal_leading;
5292 TM.tmExternalLeading = winfnt_header.external_leading;
5293 TM.tmAveCharWidth = winfnt_header.avg_width;
5294 TM.tmMaxCharWidth = winfnt_header.max_width;
5295 TM.tmWeight = winfnt_header.weight;
5297 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
5298 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
5299 TM.tmFirstChar = winfnt_header.first_char;
5300 TM.tmLastChar = winfnt_header.last_char;
5301 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
5302 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
5303 TM.tmItalic = winfnt_header.italic;
5304 TM.tmUnderlined = font->underline;
5305 TM.tmStruckOut = font->strikeout;
5306 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
5307 TM.tmCharSet = winfnt_header.charset;
5312 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
5313 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
5314 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5315 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
5316 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
5317 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
5318 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
5319 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
5321 TM.tmDigitizedAspectX = 96; /* FIXME */
5322 TM.tmDigitizedAspectY = 96; /* FIXME */
5324 TM.tmLastChar = 255;
5325 TM.tmDefaultChar = 32;
5326 TM.tmBreakChar = 32;
5327 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
5328 TM.tmUnderlined = font->underline;
5329 TM.tmStruckOut = font->strikeout;
5330 /* NB inverted meaning of TMPF_FIXED_PITCH */
5331 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
5332 TM.tmCharSet = font->charset;
5340 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
5342 double scale_x, scale_y;
5346 scale_x = (double)font->aveWidth;
5347 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5350 scale_x = font->scale_y;
5352 scale_x *= fabs(font->font_desc.matrix.eM11);
5353 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5355 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5356 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5358 SCALE_Y(ptm->tmHeight);
5359 SCALE_Y(ptm->tmAscent);
5360 SCALE_Y(ptm->tmDescent);
5361 SCALE_Y(ptm->tmInternalLeading);
5362 SCALE_Y(ptm->tmExternalLeading);
5363 SCALE_Y(ptm->tmOverhang);
5365 SCALE_X(ptm->tmAveCharWidth);
5366 SCALE_X(ptm->tmMaxCharWidth);
5372 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
5374 double scale_x, scale_y;
5378 scale_x = (double)font->aveWidth;
5379 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5382 scale_x = font->scale_y;
5384 scale_x *= fabs(font->font_desc.matrix.eM11);
5385 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5387 scale_font_metrics(font, &potm->otmTextMetrics);
5389 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5390 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5392 SCALE_Y(potm->otmAscent);
5393 SCALE_Y(potm->otmDescent);
5394 SCALE_Y(potm->otmLineGap);
5395 SCALE_Y(potm->otmsCapEmHeight);
5396 SCALE_Y(potm->otmsXHeight);
5397 SCALE_Y(potm->otmrcFontBox.top);
5398 SCALE_Y(potm->otmrcFontBox.bottom);
5399 SCALE_X(potm->otmrcFontBox.left);
5400 SCALE_X(potm->otmrcFontBox.right);
5401 SCALE_Y(potm->otmMacAscent);
5402 SCALE_Y(potm->otmMacDescent);
5403 SCALE_Y(potm->otmMacLineGap);
5404 SCALE_X(potm->otmptSubscriptSize.x);
5405 SCALE_Y(potm->otmptSubscriptSize.y);
5406 SCALE_X(potm->otmptSubscriptOffset.x);
5407 SCALE_Y(potm->otmptSubscriptOffset.y);
5408 SCALE_X(potm->otmptSuperscriptSize.x);
5409 SCALE_Y(potm->otmptSuperscriptSize.y);
5410 SCALE_X(potm->otmptSuperscriptOffset.x);
5411 SCALE_Y(potm->otmptSuperscriptOffset.y);
5412 SCALE_Y(potm->otmsStrikeoutSize);
5413 SCALE_Y(potm->otmsStrikeoutPosition);
5414 SCALE_Y(potm->otmsUnderscoreSize);
5415 SCALE_Y(potm->otmsUnderscorePosition);
5421 /*************************************************************
5422 * WineEngGetTextMetrics
5425 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
5428 EnterCriticalSection( &freetype_cs );
5430 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
5431 if(!get_bitmap_text_metrics(font))
5433 LeaveCriticalSection( &freetype_cs );
5439 LeaveCriticalSection( &freetype_cs );
5442 *ptm = font->potm->otmTextMetrics;
5443 scale_font_metrics(font, ptm);
5444 LeaveCriticalSection( &freetype_cs );
5448 static BOOL face_has_symbol_charmap(FT_Face ft_face)
5452 for(i = 0; i < ft_face->num_charmaps; i++)
5454 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
5460 /*************************************************************
5461 * WineEngGetOutlineTextMetrics
5464 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
5465 OUTLINETEXTMETRICW *potm)
5467 FT_Face ft_face = font->ft_face;
5468 UINT needed, lenfam, lensty, ret;
5470 TT_HoriHeader *pHori;
5471 TT_Postscript *pPost;
5472 FT_Fixed x_scale, y_scale;
5473 WCHAR *family_nameW, *style_nameW;
5474 static const WCHAR spaceW[] = {' ', '\0'};
5476 INT ascent, descent;
5478 TRACE("font=%p\n", font);
5480 if(!FT_IS_SCALABLE(ft_face))
5484 EnterCriticalSection( &freetype_cs );
5487 if(cbSize >= font->potm->otmSize)
5489 memcpy(potm, font->potm, font->potm->otmSize);
5490 scale_outline_font_metrics(font, potm);
5492 LeaveCriticalSection( &freetype_cs );
5493 return font->potm->otmSize;
5497 needed = sizeof(*potm);
5499 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
5500 family_nameW = strdupW(font->name);
5502 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
5504 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
5505 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
5506 style_nameW, lensty/sizeof(WCHAR));
5508 /* These names should be read from the TT name table */
5510 /* length of otmpFamilyName */
5513 /* length of otmpFaceName */
5514 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
5515 needed += lenfam; /* just the family name */
5517 needed += lenfam + lensty; /* family + " " + style */
5520 /* length of otmpStyleName */
5523 /* length of otmpFullName */
5524 needed += lenfam + lensty;
5527 x_scale = ft_face->size->metrics.x_scale;
5528 y_scale = ft_face->size->metrics.y_scale;
5530 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
5532 FIXME("Can't find OS/2 table - not TT font?\n");
5537 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
5539 FIXME("Can't find HHEA table - not TT font?\n");
5544 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
5546 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",
5547 pOS2->usWinAscent, pOS2->usWinDescent,
5548 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
5549 ft_face->ascender, ft_face->descender, ft_face->height,
5550 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
5551 ft_face->bbox.yMax, ft_face->bbox.yMin);
5553 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
5554 font->potm->otmSize = needed;
5556 #define TM font->potm->otmTextMetrics
5558 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
5559 ascent = pHori->Ascender;
5560 descent = -pHori->Descender;
5562 ascent = pOS2->usWinAscent;
5563 descent = pOS2->usWinDescent;
5567 TM.tmAscent = font->yMax;
5568 TM.tmDescent = -font->yMin;
5569 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
5571 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
5572 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
5573 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
5574 - ft_face->units_per_EM, y_scale) + 32) >> 6;
5577 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5580 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
5582 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
5583 ((ascent + descent) -
5584 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
5586 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
5587 if (TM.tmAveCharWidth == 0) {
5588 TM.tmAveCharWidth = 1;
5590 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
5591 TM.tmWeight = (font->fake_bold || (ft_face->style_flags & FT_STYLE_FLAG_BOLD)) ? FW_BOLD : FW_REGULAR;
5593 TM.tmDigitizedAspectX = 300;
5594 TM.tmDigitizedAspectY = 300;
5595 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
5596 * symbol range to 0 - f0ff
5599 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
5604 case 1257: /* Baltic */
5605 TM.tmLastChar = 0xf8fd;
5608 TM.tmLastChar = 0xf0ff;
5610 TM.tmBreakChar = 0x20;
5611 TM.tmDefaultChar = 0x1f;
5615 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
5616 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
5618 if(pOS2->usFirstCharIndex <= 1)
5619 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
5620 else if (pOS2->usFirstCharIndex > 0xff)
5621 TM.tmBreakChar = 0x20;
5623 TM.tmBreakChar = pOS2->usFirstCharIndex;
5624 TM.tmDefaultChar = TM.tmBreakChar - 1;
5626 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
5627 TM.tmUnderlined = font->underline;
5628 TM.tmStruckOut = font->strikeout;
5630 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
5631 if(!FT_IS_FIXED_WIDTH(ft_face) &&
5632 (pOS2->version == 0xFFFFU ||
5633 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
5634 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
5636 TM.tmPitchAndFamily = 0;
5638 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
5640 case PAN_FAMILY_SCRIPT:
5641 TM.tmPitchAndFamily |= FF_SCRIPT;
5644 case PAN_FAMILY_DECORATIVE:
5645 TM.tmPitchAndFamily |= FF_DECORATIVE;
5650 case PAN_FAMILY_TEXT_DISPLAY:
5651 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
5652 /* which is clearly not what the panose spec says. */
5654 if(TM.tmPitchAndFamily == 0 || /* fixed */
5655 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
5656 TM.tmPitchAndFamily = FF_MODERN;
5659 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
5664 TM.tmPitchAndFamily |= FF_DONTCARE;
5667 case PAN_SERIF_COVE:
5668 case PAN_SERIF_OBTUSE_COVE:
5669 case PAN_SERIF_SQUARE_COVE:
5670 case PAN_SERIF_OBTUSE_SQUARE_COVE:
5671 case PAN_SERIF_SQUARE:
5672 case PAN_SERIF_THIN:
5673 case PAN_SERIF_BONE:
5674 case PAN_SERIF_EXAGGERATED:
5675 case PAN_SERIF_TRIANGLE:
5676 TM.tmPitchAndFamily |= FF_ROMAN;
5679 case PAN_SERIF_NORMAL_SANS:
5680 case PAN_SERIF_OBTUSE_SANS:
5681 case PAN_SERIF_PERP_SANS:
5682 case PAN_SERIF_FLARED:
5683 case PAN_SERIF_ROUNDED:
5684 TM.tmPitchAndFamily |= FF_SWISS;
5691 if(FT_IS_SCALABLE(ft_face))
5692 TM.tmPitchAndFamily |= TMPF_VECTOR;
5694 if(FT_IS_SFNT(ft_face))
5696 if (font->ntmFlags & NTM_PS_OPENTYPE)
5697 TM.tmPitchAndFamily |= TMPF_DEVICE;
5699 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
5702 TM.tmCharSet = font->charset;
5704 font->potm->otmFiller = 0;
5705 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
5706 font->potm->otmfsSelection = pOS2->fsSelection;
5707 font->potm->otmfsType = pOS2->fsType;
5708 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
5709 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
5710 font->potm->otmItalicAngle = 0; /* POST table */
5711 font->potm->otmEMSquare = ft_face->units_per_EM;
5712 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
5713 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
5714 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
5715 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
5716 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
5717 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
5718 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
5719 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
5720 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
5721 font->potm->otmMacAscent = TM.tmAscent;
5722 font->potm->otmMacDescent = -TM.tmDescent;
5723 font->potm->otmMacLineGap = font->potm->otmLineGap;
5724 font->potm->otmusMinimumPPEM = 0; /* TT Header */
5725 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
5726 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
5727 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
5728 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
5729 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
5730 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
5731 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
5732 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
5733 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
5734 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
5736 font->potm->otmsUnderscoreSize = 0;
5737 font->potm->otmsUnderscorePosition = 0;
5739 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
5740 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
5744 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
5745 cp = (char*)font->potm + sizeof(*font->potm);
5746 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
5747 strcpyW((WCHAR*)cp, family_nameW);
5749 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
5750 strcpyW((WCHAR*)cp, style_nameW);
5752 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
5753 strcpyW((WCHAR*)cp, family_nameW);
5754 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
5755 strcatW((WCHAR*)cp, spaceW);
5756 strcatW((WCHAR*)cp, style_nameW);
5757 cp += lenfam + lensty;
5760 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
5761 strcpyW((WCHAR*)cp, family_nameW);
5762 strcatW((WCHAR*)cp, spaceW);
5763 strcatW((WCHAR*)cp, style_nameW);
5766 if(potm && needed <= cbSize)
5768 memcpy(potm, font->potm, font->potm->otmSize);
5769 scale_outline_font_metrics(font, potm);
5773 HeapFree(GetProcessHeap(), 0, style_nameW);
5774 HeapFree(GetProcessHeap(), 0, family_nameW);
5776 LeaveCriticalSection( &freetype_cs );
5780 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
5782 HFONTLIST *hfontlist;
5783 child->font = alloc_font();
5784 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
5785 if(!child->font->ft_face)
5787 free_font(child->font);
5792 child->font->font_desc = font->font_desc;
5793 child->font->ntmFlags = child->face->ntmFlags;
5794 child->font->orientation = font->orientation;
5795 child->font->scale_y = font->scale_y;
5796 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
5797 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
5798 list_add_head(&child->font->hfontlist, &hfontlist->entry);
5799 child->font->base_font = font;
5800 list_add_head(&child_font_list, &child->font->entry);
5801 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
5805 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
5808 CHILD_FONT *child_font;
5811 font = font->base_font;
5813 *linked_font = font;
5815 if((*glyph = get_glyph_index(font, c)))
5818 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
5820 if(!child_font->font)
5821 if(!load_child_font(font, child_font))
5824 if(!child_font->font->ft_face)
5826 g = get_glyph_index(child_font->font, c);
5830 *linked_font = child_font->font;
5837 /*************************************************************
5838 * WineEngGetCharWidth
5841 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5844 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5847 FT_UInt glyph_index;
5848 GdiFont *linked_font;
5850 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5853 EnterCriticalSection( &freetype_cs );
5854 for(c = firstChar; c <= lastChar; c++) {
5855 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5856 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5857 &gm, 0, NULL, &identity);
5858 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
5860 LeaveCriticalSection( &freetype_cs );
5864 /*************************************************************
5865 * WineEngGetCharABCWidths
5868 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5871 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5874 FT_UInt glyph_index;
5875 GdiFont *linked_font;
5877 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5879 if(!FT_IS_SCALABLE(font->ft_face))
5883 EnterCriticalSection( &freetype_cs );
5885 for(c = firstChar; c <= lastChar; c++) {
5886 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5887 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5888 &gm, 0, NULL, &identity);
5889 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
5890 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
5891 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
5892 FONT_GM(linked_font,glyph_index)->bbx;
5894 LeaveCriticalSection( &freetype_cs );
5898 /*************************************************************
5899 * WineEngGetCharABCWidthsI
5902 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
5905 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5908 FT_UInt glyph_index;
5909 GdiFont *linked_font;
5911 if(!FT_HAS_HORIZONTAL(font->ft_face))
5915 EnterCriticalSection( &freetype_cs );
5917 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
5919 for(c = firstChar; c < firstChar+count; c++) {
5920 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
5921 &gm, 0, NULL, &identity);
5922 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
5923 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
5924 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
5925 - FONT_GM(linked_font,c)->bbx;
5928 for(c = 0; c < count; c++) {
5929 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
5930 &gm, 0, NULL, &identity);
5931 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
5932 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
5933 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
5934 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
5937 LeaveCriticalSection( &freetype_cs );
5941 /*************************************************************
5942 * WineEngGetTextExtentExPoint
5945 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
5946 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
5948 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5953 FT_UInt glyph_index;
5954 GdiFont *linked_font;
5956 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
5960 EnterCriticalSection( &freetype_cs );
5963 WineEngGetTextMetrics(font, &tm);
5964 size->cy = tm.tmHeight;
5966 for(idx = 0; idx < count; idx++) {
5967 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
5968 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5969 &gm, 0, NULL, &identity);
5970 size->cx += FONT_GM(linked_font,glyph_index)->adv;
5972 if (! pnfit || ext <= max_ext) {
5982 LeaveCriticalSection( &freetype_cs );
5983 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
5987 /*************************************************************
5988 * WineEngGetTextExtentExPointI
5991 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
5992 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
5994 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6000 TRACE("%p, %p, %d, %d, %p\n", font, indices, count, max_ext, size);
6003 EnterCriticalSection( &freetype_cs );
6006 WineEngGetTextMetrics(font, &tm);
6007 size->cy = tm.tmHeight;
6009 for(idx = 0; idx < count; idx++) {
6010 WineEngGetGlyphOutline(font, indices[idx],
6011 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
6013 size->cx += FONT_GM(font,indices[idx])->adv;
6015 if (! pnfit || ext <= max_ext) {
6025 LeaveCriticalSection( &freetype_cs );
6026 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6030 /*************************************************************
6031 * WineEngGetFontData
6034 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
6037 FT_Face ft_face = font->ft_face;
6041 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6042 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
6043 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
6045 if(!FT_IS_SFNT(ft_face))
6053 if(table) { /* MS tags differ in endianness from FT ones */
6054 table = table >> 24 | table << 24 |
6055 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
6058 /* make sure value of len is the value freetype says it needs */
6061 FT_ULong needed = 0;
6062 err = load_sfnt_table(ft_face, table, offset, NULL, &needed);
6063 if( !err && needed < len) len = needed;
6065 err = load_sfnt_table(ft_face, table, offset, buf, &len);
6068 TRACE("Can't find table %c%c%c%c\n",
6069 /* bytes were reversed */
6070 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
6071 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
6077 /*************************************************************
6078 * WineEngGetTextFace
6081 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
6083 INT n = strlenW(font->name) + 1;
6085 lstrcpynW(str, font->name, count);
6086 return min(count, n);
6091 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
6093 if (fs) *fs = font->fs;
6094 return font->charset;
6097 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6099 GdiFont *font = dc->gdiFont, *linked_font;
6100 struct list *first_hfont;
6104 EnterCriticalSection( &freetype_cs );
6105 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
6106 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
6107 if(font == linked_font)
6108 *new_hfont = dc->hFont;
6111 first_hfont = list_head(&linked_font->hfontlist);
6112 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
6114 LeaveCriticalSection( &freetype_cs );
6118 /* Retrieve a list of supported Unicode ranges for a given font.
6119 * Can be called with NULL gs to calculate the buffer size. Returns
6120 * the number of ranges found.
6122 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
6124 DWORD num_ranges = 0;
6126 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
6129 FT_ULong char_code, char_code_prev;
6132 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
6134 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6135 face->num_glyphs, glyph_code, char_code);
6137 if (!glyph_code) return 0;
6141 gs->ranges[0].wcLow = (USHORT)char_code;
6142 gs->ranges[0].cGlyphs = 0;
6143 gs->cGlyphsSupported = 0;
6149 if (char_code < char_code_prev)
6151 ERR("expected increasing char code from FT_Get_Next_Char\n");
6154 if (char_code - char_code_prev > 1)
6159 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
6160 gs->ranges[num_ranges - 1].cGlyphs = 1;
6161 gs->cGlyphsSupported++;
6166 gs->ranges[num_ranges - 1].cGlyphs++;
6167 gs->cGlyphsSupported++;
6169 char_code_prev = char_code;
6170 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
6174 FIXME("encoding %u not supported\n", face->charmap->encoding);
6179 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
6182 DWORD num_ranges = get_font_unicode_ranges(font->ft_face, glyphset);
6184 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
6187 glyphset->cbThis = size;
6188 glyphset->cRanges = num_ranges;
6193 /*************************************************************
6196 BOOL WineEngFontIsLinked(GdiFont *font)
6200 EnterCriticalSection( &freetype_cs );
6201 ret = !list_empty(&font->child_fonts);
6202 LeaveCriticalSection( &freetype_cs );
6206 static BOOL is_hinting_enabled(void)
6208 /* Use the >= 2.2.0 function if available */
6209 if(pFT_Get_TrueType_Engine_Type)
6211 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
6212 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
6214 #ifdef FT_DRIVER_HAS_HINTER
6219 /* otherwise if we've been compiled with < 2.2.0 headers
6220 use the internal macro */
6221 mod = pFT_Get_Module(library, "truetype");
6222 if(mod && FT_DRIVER_HAS_HINTER(mod))
6230 static BOOL is_subpixel_rendering_enabled( void )
6232 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6233 return pFT_Library_SetLcdFilter &&
6234 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
6240 /*************************************************************************
6241 * GetRasterizerCaps (GDI32.@)
6243 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6245 static int hinting = -1;
6246 static int subpixel = -1;
6250 hinting = is_hinting_enabled();
6251 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
6254 if ( subpixel == -1 )
6256 subpixel = is_subpixel_rendering_enabled();
6257 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
6260 lprs->nSize = sizeof(RASTERIZER_STATUS);
6261 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
6263 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
6264 lprs->nLanguageID = 0;
6268 /*************************************************************
6269 * WineEngRealizationInfo
6271 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
6273 FIXME("(%p, %p): stub!\n", font, info);
6276 if(FT_IS_SCALABLE(font->ft_face))
6279 info->cache_num = font->cache_num;
6280 info->unknown2 = -1;
6284 /*************************************************************************
6285 * Kerning support for TrueType fonts
6287 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
6289 struct TT_kern_table
6295 struct TT_kern_subtable
6304 USHORT horizontal : 1;
6306 USHORT cross_stream: 1;
6307 USHORT override : 1;
6308 USHORT reserved1 : 4;
6314 struct TT_format0_kern_subtable
6318 USHORT entrySelector;
6329 static DWORD parse_format0_kern_subtable(GdiFont *font,
6330 const struct TT_format0_kern_subtable *tt_f0_ks,
6331 const USHORT *glyph_to_char,
6332 KERNINGPAIR *kern_pair, DWORD cPairs)
6335 const struct TT_kern_pair *tt_kern_pair;
6337 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
6339 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
6341 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
6342 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
6343 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
6345 if (!kern_pair || !cPairs)
6348 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
6350 nPairs = min(nPairs, cPairs);
6352 for (i = 0; i < nPairs; i++)
6354 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
6355 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
6356 /* this algorithm appears to better match what Windows does */
6357 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
6358 if (kern_pair->iKernAmount < 0)
6360 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
6361 kern_pair->iKernAmount -= font->ppem;
6363 else if (kern_pair->iKernAmount > 0)
6365 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
6366 kern_pair->iKernAmount += font->ppem;
6368 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
6370 TRACE("left %u right %u value %d\n",
6371 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
6375 TRACE("copied %u entries\n", nPairs);
6379 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6383 const struct TT_kern_table *tt_kern_table;
6384 const struct TT_kern_subtable *tt_kern_subtable;
6386 USHORT *glyph_to_char;
6389 EnterCriticalSection( &freetype_cs );
6390 if (font->total_kern_pairs != (DWORD)-1)
6392 if (cPairs && kern_pair)
6394 cPairs = min(cPairs, font->total_kern_pairs);
6395 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6396 LeaveCriticalSection( &freetype_cs );
6399 LeaveCriticalSection( &freetype_cs );
6400 return font->total_kern_pairs;
6403 font->total_kern_pairs = 0;
6405 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
6407 if (length == GDI_ERROR)
6409 TRACE("no kerning data in the font\n");
6410 LeaveCriticalSection( &freetype_cs );
6414 buf = HeapAlloc(GetProcessHeap(), 0, length);
6417 WARN("Out of memory\n");
6418 LeaveCriticalSection( &freetype_cs );
6422 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
6424 /* build a glyph index to char code map */
6425 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
6428 WARN("Out of memory allocating a glyph index to char code map\n");
6429 HeapFree(GetProcessHeap(), 0, buf);
6430 LeaveCriticalSection( &freetype_cs );
6434 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
6440 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
6442 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
6443 font->ft_face->num_glyphs, glyph_code, char_code);
6447 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
6449 /* FIXME: This doesn't match what Windows does: it does some fancy
6450 * things with duplicate glyph index to char code mappings, while
6451 * we just avoid overriding existing entries.
6453 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
6454 glyph_to_char[glyph_code] = (USHORT)char_code;
6456 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
6463 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
6464 for (n = 0; n <= 65535; n++)
6465 glyph_to_char[n] = (USHORT)n;
6468 tt_kern_table = buf;
6469 nTables = GET_BE_WORD(tt_kern_table->nTables);
6470 TRACE("version %u, nTables %u\n",
6471 GET_BE_WORD(tt_kern_table->version), nTables);
6473 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
6475 for (i = 0; i < nTables; i++)
6477 struct TT_kern_subtable tt_kern_subtable_copy;
6479 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
6480 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
6481 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
6483 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
6484 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
6485 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
6487 /* According to the TrueType specification this is the only format
6488 * that will be properly interpreted by Windows and OS/2
6490 if (tt_kern_subtable_copy.coverage.bits.format == 0)
6492 DWORD new_chunk, old_total = font->total_kern_pairs;
6494 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6495 glyph_to_char, NULL, 0);
6496 font->total_kern_pairs += new_chunk;
6498 if (!font->kern_pairs)
6499 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
6500 font->total_kern_pairs * sizeof(*font->kern_pairs));
6502 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
6503 font->total_kern_pairs * sizeof(*font->kern_pairs));
6505 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6506 glyph_to_char, font->kern_pairs + old_total, new_chunk);
6509 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
6511 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
6514 HeapFree(GetProcessHeap(), 0, glyph_to_char);
6515 HeapFree(GetProcessHeap(), 0, buf);
6517 if (cPairs && kern_pair)
6519 cPairs = min(cPairs, font->total_kern_pairs);
6520 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6521 LeaveCriticalSection( &freetype_cs );
6524 LeaveCriticalSection( &freetype_cs );
6525 return font->total_kern_pairs;
6528 #else /* HAVE_FREETYPE */
6530 /*************************************************************************/
6532 BOOL WineEngInit(void)
6536 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
6540 BOOL WineEngDestroyFontInstance(HFONT hfont)
6545 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
6550 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
6551 LPWORD pgi, DWORD flags)
6556 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
6557 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
6560 ERR("called but we don't have FreeType\n");
6564 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
6566 ERR("called but we don't have FreeType\n");
6570 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
6571 OUTLINETEXTMETRICW *potm)
6573 ERR("called but we don't have FreeType\n");
6577 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
6580 ERR("called but we don't have FreeType\n");
6584 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
6587 ERR("called but we don't have FreeType\n");
6591 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
6594 ERR("called but we don't have FreeType\n");
6598 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
6599 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6601 ERR("called but we don't have FreeType\n");
6605 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
6606 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6608 ERR("called but we don't have FreeType\n");
6612 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
6615 ERR("called but we don't have FreeType\n");
6619 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
6621 ERR("called but we don't have FreeType\n");
6625 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6631 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6637 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
6643 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
6646 return DEFAULT_CHARSET;
6649 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6654 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
6656 FIXME("(%p, %p): stub\n", font, glyphset);
6660 BOOL WineEngFontIsLinked(GdiFont *font)
6665 /*************************************************************************
6666 * GetRasterizerCaps (GDI32.@)
6668 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6670 lprs->nSize = sizeof(RASTERIZER_STATUS);
6672 lprs->nLanguageID = 0;
6676 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6678 ERR("called but we don't have FreeType\n");
6682 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
6684 ERR("called but we don't have FreeType\n");
6688 #endif /* HAVE_FREETYPE */