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_TTNAMEID_H
114 #include <freetype/ttnameid.h>
116 #ifdef HAVE_FREETYPE_FTOUTLN_H
117 #include <freetype/ftoutln.h>
119 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
120 #include <freetype/internal/sfnt.h>
122 #ifdef HAVE_FREETYPE_FTTRIGON_H
123 #include <freetype/fttrigon.h>
125 #ifdef HAVE_FREETYPE_FTWINFNT_H
126 #include <freetype/ftwinfnt.h>
128 #ifdef HAVE_FREETYPE_FTMODAPI_H
129 #include <freetype/ftmodapi.h>
131 #ifdef HAVE_FREETYPE_FTLCDFIL_H
132 #include <freetype/ftlcdfil.h>
135 #ifndef HAVE_FT_TRUETYPEENGINETYPE
138 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
139 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
140 FT_TRUETYPE_ENGINE_TYPE_PATENTED
141 } FT_TrueTypeEngineType;
144 static FT_Library library = 0;
151 static FT_Version_t FT_Version;
152 static DWORD FT_SimpleVersion;
154 static void *ft_handle = NULL;
156 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
157 MAKE_FUNCPTR(FT_Vector_Unit);
158 MAKE_FUNCPTR(FT_Done_Face);
159 MAKE_FUNCPTR(FT_Get_Char_Index);
160 MAKE_FUNCPTR(FT_Get_Module);
161 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
163 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
164 MAKE_FUNCPTR(FT_Init_FreeType);
165 MAKE_FUNCPTR(FT_Load_Glyph);
166 MAKE_FUNCPTR(FT_Matrix_Multiply);
167 #ifdef FT_MULFIX_INLINED
168 #define pFT_MulFix FT_MULFIX_INLINED
170 MAKE_FUNCPTR(FT_MulFix);
172 MAKE_FUNCPTR(FT_New_Face);
173 MAKE_FUNCPTR(FT_New_Memory_Face);
174 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
175 MAKE_FUNCPTR(FT_Outline_Transform);
176 MAKE_FUNCPTR(FT_Outline_Translate);
177 MAKE_FUNCPTR(FT_Select_Charmap);
178 MAKE_FUNCPTR(FT_Set_Charmap);
179 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
180 MAKE_FUNCPTR(FT_Vector_Transform);
181 MAKE_FUNCPTR(FT_Render_Glyph);
182 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
183 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
184 static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*);
185 static FT_ULong (*pFT_Get_Next_Char)(FT_Face,FT_ULong,FT_UInt*);
186 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
187 #ifdef HAVE_FREETYPE_FTLCDFIL_H
188 static FT_Error (*pFT_Library_SetLcdFilter)(FT_Library, FT_LcdFilter);
190 #ifdef HAVE_FREETYPE_FTWINFNT_H
191 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
194 #ifdef SONAME_LIBFONTCONFIG
195 #include <fontconfig/fontconfig.h>
196 MAKE_FUNCPTR(FcConfigGetCurrent);
197 MAKE_FUNCPTR(FcFontList);
198 MAKE_FUNCPTR(FcFontSetDestroy);
199 MAKE_FUNCPTR(FcInit);
200 MAKE_FUNCPTR(FcObjectSetAdd);
201 MAKE_FUNCPTR(FcObjectSetCreate);
202 MAKE_FUNCPTR(FcObjectSetDestroy);
203 MAKE_FUNCPTR(FcPatternCreate);
204 MAKE_FUNCPTR(FcPatternDestroy);
205 MAKE_FUNCPTR(FcPatternGetBool);
206 MAKE_FUNCPTR(FcPatternGetString);
212 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
213 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
214 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
217 #ifndef ft_encoding_none
218 #define FT_ENCODING_NONE ft_encoding_none
220 #ifndef ft_encoding_ms_symbol
221 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
223 #ifndef ft_encoding_unicode
224 #define FT_ENCODING_UNICODE ft_encoding_unicode
226 #ifndef ft_encoding_apple_roman
227 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
230 #ifdef WORDS_BIGENDIAN
231 #define GET_BE_WORD(x) (x)
233 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
236 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
243 FT_Short internal_leading;
246 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
247 So to let this compile on older versions of FreeType we'll define the
248 new structure here. */
250 FT_Short height, width;
251 FT_Pos size, x_ppem, y_ppem;
257 NEWTEXTMETRICEXW ntm;
261 typedef struct tagFace {
266 DWORD font_data_size;
269 FONTSIGNATURE fs_links;
271 FT_Fixed font_version;
273 Bitmap_Size size; /* set if face is a bitmap */
274 BOOL external; /* TRUE if we should manually add this font to the registry */
275 struct tagFamily *family;
276 /* Cached data for Enum */
277 struct enum_data *cached_enum_data;
280 typedef struct tagFamily {
282 const WCHAR *FamilyName;
288 INT adv; /* These three hold to widths of the unrotated chars */
306 typedef struct tagHFONTLIST {
321 struct list hfontlist;
322 OUTLINETEXTMETRICW *potm;
323 DWORD total_kern_pairs;
324 KERNINGPAIR *kern_pairs;
325 struct list child_fonts;
327 /* the following members can be accessed without locking, they are never modified after creation */
329 struct font_mapping *mapping;
352 const WCHAR *font_name;
356 #define GM_BLOCK_SIZE 128
357 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
359 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
360 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
361 #define UNUSED_CACHE_SIZE 10
362 static struct list child_font_list = LIST_INIT(child_font_list);
363 static struct list system_links = LIST_INIT(system_links);
365 static struct list font_subst_list = LIST_INIT(font_subst_list);
367 static struct list font_list = LIST_INIT(font_list);
369 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
370 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
371 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
373 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
374 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
375 'W','i','n','d','o','w','s','\\',
376 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
377 'F','o','n','t','s','\0'};
379 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
380 'W','i','n','d','o','w','s',' ','N','T','\\',
381 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
382 'F','o','n','t','s','\0'};
384 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
385 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
386 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
387 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
389 static const WCHAR * const SystemFontValues[4] = {
396 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
397 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
399 /* Interesting and well-known (frequently-assumed!) font names */
400 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
401 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 };
402 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
403 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
404 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
405 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
406 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
407 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
409 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
410 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
411 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
412 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
413 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
414 'E','u','r','o','p','e','a','n','\0'};
415 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
416 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
417 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
418 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
419 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
420 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
421 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
422 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
423 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
424 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
425 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
426 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
428 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
438 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
446 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
455 typedef struct tagFontSubst {
471 static struct list mappings_list = LIST_INIT( mappings_list );
473 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
475 static CRITICAL_SECTION freetype_cs;
476 static CRITICAL_SECTION_DEBUG critsect_debug =
479 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
480 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
482 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
484 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
486 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
487 static BOOL use_default_fallback = FALSE;
489 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
491 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
492 'W','i','n','d','o','w','s',' ','N','T','\\',
493 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
494 'S','y','s','t','e','m','L','i','n','k',0};
496 /****************************************
497 * Notes on .fon files
499 * The fonts System, FixedSys and Terminal are special. There are typically multiple
500 * versions installed for different resolutions and codepages. Windows stores which one to use
501 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
503 * FIXEDFON.FON FixedSys
505 * OEMFONT.FON Terminal
506 * LogPixels Current dpi set by the display control panel applet
507 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
508 * also has a LogPixels value that appears to mirror this)
510 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
511 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
512 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
513 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
514 * so that makes sense.
516 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
517 * to be mapped into the registry on Windows 2000 at least).
520 * ega80woa.fon=ega80850.fon
521 * ega40woa.fon=ega40850.fon
522 * cga80woa.fon=cga80850.fon
523 * cga40woa.fon=cga40850.fon
526 /* These are all structures needed for the GSUB table */
528 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
529 #define TATEGAKI_LOWER_BOUND 0x02F1
545 GSUB_ScriptRecord ScriptRecord[1];
551 } GSUB_LangSysRecord;
556 GSUB_LangSysRecord LangSysRecord[1];
560 WORD LookupOrder; /* Reserved */
561 WORD ReqFeatureIndex;
563 WORD FeatureIndex[1];
569 } GSUB_FeatureRecord;
573 GSUB_FeatureRecord FeatureRecord[1];
577 WORD FeatureParams; /* Reserved */
579 WORD LookupListIndex[1];
598 } GSUB_CoverageFormat1;
603 WORD StartCoverageIndex;
609 GSUB_RangeRecord RangeRecord[1];
610 } GSUB_CoverageFormat2;
613 WORD SubstFormat; /* = 1 */
616 } GSUB_SingleSubstFormat1;
619 WORD SubstFormat; /* = 2 */
623 }GSUB_SingleSubstFormat2;
625 #ifdef HAVE_CARBON_CARBON_H
626 static char *find_cache_dir(void)
630 static char cached_path[MAX_PATH];
631 static const char *wine = "/Wine", *fonts = "/Fonts";
633 if(*cached_path) return cached_path;
635 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
638 WARN("can't create cached data folder\n");
641 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
644 WARN("can't create cached data path\n");
648 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
650 ERR("Could not create full path\n");
654 strcat(cached_path, wine);
656 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
658 WARN("Couldn't mkdir %s\n", cached_path);
662 strcat(cached_path, fonts);
663 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
665 WARN("Couldn't mkdir %s\n", cached_path);
672 /******************************************************************
675 * Extracts individual TrueType font files from a Mac suitcase font
676 * and saves them into the user's caches directory (see
678 * Returns a NULL terminated array of filenames.
680 * We do this because they are apps that try to read ttf files
681 * themselves and they don't like Mac suitcase files.
683 static char **expand_mac_font(const char *path)
690 const char *filename;
694 unsigned int size, max_size;
697 TRACE("path %s\n", path);
699 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
702 WARN("failed to get ref\n");
706 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
709 TRACE("no data fork, so trying resource fork\n");
710 res_ref = FSOpenResFile(&ref, fsRdPerm);
713 TRACE("unable to open resource fork\n");
720 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
723 CloseResFile(res_ref);
727 out_dir = find_cache_dir();
729 filename = strrchr(path, '/');
730 if(!filename) filename = path;
733 /* output filename has the form out_dir/filename_%04x.ttf */
734 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
741 unsigned short *num_faces_ptr, num_faces, face;
744 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
746 fond = Get1IndResource(fond_res, idx);
748 TRACE("got fond resource %d\n", idx);
751 fam_rec = *(FamRec**)fond;
752 num_faces_ptr = (unsigned short *)(fam_rec + 1);
753 num_faces = GET_BE_WORD(*num_faces_ptr);
755 assoc = (AsscEntry*)(num_faces_ptr + 1);
756 TRACE("num faces %04x\n", num_faces);
757 for(face = 0; face < num_faces; face++, assoc++)
760 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
761 unsigned short size, font_id;
764 size = GET_BE_WORD(assoc->fontSize);
765 font_id = GET_BE_WORD(assoc->fontID);
768 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
772 TRACE("trying to load sfnt id %04x\n", font_id);
773 sfnt = GetResource(sfnt_res, font_id);
776 TRACE("can't get sfnt resource %04x\n", font_id);
780 output = HeapAlloc(GetProcessHeap(), 0, output_len);
785 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
787 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
788 if(fd != -1 || errno == EEXIST)
792 unsigned char *sfnt_data;
795 sfnt_data = *(unsigned char**)sfnt;
796 write(fd, sfnt_data, GetHandleSize(sfnt));
800 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
803 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
805 ret.array[ret.size++] = output;
809 WARN("unable to create %s\n", output);
810 HeapFree(GetProcessHeap(), 0, output);
813 ReleaseResource(sfnt);
816 ReleaseResource(fond);
819 CloseResFile(res_ref);
824 #endif /* HAVE_CARBON_CARBON_H */
826 static inline BOOL is_win9x(void)
828 return GetVersion() & 0x80000000;
831 This function builds an FT_Fixed from a double. It fails if the absolute
832 value of the float number is greater than 32768.
834 static inline FT_Fixed FT_FixedFromFloat(double f)
840 This function builds an FT_Fixed from a FIXED. It simply put f.value
841 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
843 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
845 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
849 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
854 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
855 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
857 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
858 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
860 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
862 if(face_name && strcmpiW(face_name, family->FamilyName))
864 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
868 file = strrchr(face->file, '/');
873 if(!strcasecmp(file, file_nameA))
875 HeapFree(GetProcessHeap(), 0, file_nameA);
880 HeapFree(GetProcessHeap(), 0, file_nameA);
884 static Family *find_family_from_name(const WCHAR *name)
888 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
890 if(!strcmpiW(family->FamilyName, name))
897 static void DumpSubstList(void)
901 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
903 if(psub->from.charset != -1 || psub->to.charset != -1)
904 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
905 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
907 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
908 debugstr_w(psub->to.name));
913 static LPWSTR strdupW(LPCWSTR p)
916 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
917 ret = HeapAlloc(GetProcessHeap(), 0, len);
922 static LPSTR strdupA(LPCSTR p)
925 DWORD len = (strlen(p) + 1);
926 ret = HeapAlloc(GetProcessHeap(), 0, len);
931 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
936 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
938 if(!strcmpiW(element->from.name, from_name) &&
939 (element->from.charset == from_charset ||
940 element->from.charset == -1))
947 #define ADD_FONT_SUBST_FORCE 1
949 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
951 FontSubst *from_exist, *to_exist;
953 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
955 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
957 list_remove(&from_exist->entry);
958 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
959 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
960 HeapFree(GetProcessHeap(), 0, from_exist);
966 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
970 HeapFree(GetProcessHeap(), 0, subst->to.name);
971 subst->to.name = strdupW(to_exist->to.name);
974 list_add_tail(subst_list, &subst->entry);
979 HeapFree(GetProcessHeap(), 0, subst->from.name);
980 HeapFree(GetProcessHeap(), 0, subst->to.name);
981 HeapFree(GetProcessHeap(), 0, subst);
985 static void split_subst_info(NameCs *nc, LPSTR str)
987 CHAR *p = strrchr(str, ',');
992 nc->charset = strtol(p+1, NULL, 10);
995 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
996 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
997 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
1000 static void LoadSubstList(void)
1004 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1008 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1009 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1010 &hkey) == ERROR_SUCCESS) {
1012 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1013 &valuelen, &datalen, NULL, NULL);
1015 valuelen++; /* returned value doesn't include room for '\0' */
1016 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1017 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1021 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1022 &dlen) == ERROR_SUCCESS) {
1023 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1025 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1026 split_subst_info(&psub->from, value);
1027 split_subst_info(&psub->to, data);
1029 /* Win 2000 doesn't allow mapping between different charsets
1030 or mapping of DEFAULT_CHARSET */
1031 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1032 psub->to.charset == DEFAULT_CHARSET) {
1033 HeapFree(GetProcessHeap(), 0, psub->to.name);
1034 HeapFree(GetProcessHeap(), 0, psub->from.name);
1035 HeapFree(GetProcessHeap(), 0, psub);
1037 add_font_subst(&font_subst_list, psub, 0);
1039 /* reset dlen and vlen */
1043 HeapFree(GetProcessHeap(), 0, data);
1044 HeapFree(GetProcessHeap(), 0, value);
1050 /*****************************************************************
1051 * get_name_table_entry
1053 * Supply the platform, encoding, language and name ids in req
1054 * and if the name exists the function will fill in the string
1055 * and string_len members. The string is owned by FreeType so
1056 * don't free it. Returns TRUE if the name is found else FALSE.
1058 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1061 FT_UInt num_names, name_index;
1063 if(FT_IS_SFNT(ft_face))
1065 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1067 for(name_index = 0; name_index < num_names; name_index++)
1069 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1071 if((name.platform_id == req->platform_id) &&
1072 (name.encoding_id == req->encoding_id) &&
1073 (name.language_id == req->language_id) &&
1074 (name.name_id == req->name_id))
1076 req->string = name.string;
1077 req->string_len = name.string_len;
1084 req->string_len = 0;
1088 static WCHAR *get_familyname(FT_Face ft_face)
1090 WCHAR *family = NULL;
1093 name.platform_id = TT_PLATFORM_MICROSOFT;
1094 name.encoding_id = TT_MS_ID_UNICODE_CS;
1095 name.language_id = GetUserDefaultLCID();
1096 name.name_id = TT_NAME_ID_FONT_FAMILY;
1098 if(get_name_table_entry(ft_face, &name))
1102 /* String is not nul terminated and string_len is a byte length. */
1103 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1104 for(i = 0; i < name.string_len / 2; i++)
1106 WORD *tmp = (WORD *)&name.string[i * 2];
1107 family[i] = GET_BE_WORD(*tmp);
1110 TRACE("Got localised name %s\n", debugstr_w(family));
1117 /*****************************************************************
1120 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
1121 * of FreeType that don't export this function.
1124 static FT_Error load_sfnt_table(FT_Face ft_face, FT_ULong table, FT_Long offset, FT_Byte *buf, FT_ULong *len)
1129 /* If the FT_Load_Sfnt_Table function is there we'll use it */
1130 if(pFT_Load_Sfnt_Table)
1132 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, len);
1134 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
1135 else /* Do it the hard way */
1137 TT_Face tt_face = (TT_Face) ft_face;
1138 SFNT_Interface *sfnt;
1139 if (FT_Version.major==2 && FT_Version.minor==0)
1142 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
1146 /* A field was added in the middle of the structure in 2.1.x */
1147 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
1149 err = sfnt->load_any(tt_face, table, offset, buf, len);
1157 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
1158 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
1159 "Please upgrade your freetype library.\n");
1162 err = FT_Err_Unimplemented_Feature;
1168 static inline int TestStyles(DWORD flags, DWORD styles)
1170 return (flags & styles) == styles;
1173 static int StyleOrdering(Face *face)
1175 if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1177 if (TestStyles(face->ntmFlags, NTM_ITALIC))
1179 if (TestStyles(face->ntmFlags, NTM_BOLD))
1181 if (TestStyles(face->ntmFlags, NTM_REGULAR))
1184 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1185 debugstr_w(face->family->FamilyName),
1186 debugstr_w(face->StyleName),
1192 /* Add a style of face to a font family using an ordering of the list such
1193 that regular fonts come before bold and italic, and single styles come
1194 before compound styles. */
1195 static void AddFaceToFamily(Face *face, Family *family)
1199 LIST_FOR_EACH( entry, &family->faces )
1201 Face *ent = LIST_ENTRY(entry, Face, entry);
1202 if (StyleOrdering(face) < StyleOrdering(ent)) break;
1204 list_add_before( entry, &face->entry );
1207 #define ADDFONT_EXTERNAL_FONT 0x01
1208 #define ADDFONT_FORCE_BITMAP 0x02
1209 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1213 TT_Header *pHeader = NULL;
1214 WCHAR *english_family, *localised_family, *StyleW;
1218 struct list *family_elem_ptr, *face_elem_ptr;
1220 FT_Long face_index = 0, num_faces;
1221 #ifdef HAVE_FREETYPE_FTWINFNT_H
1222 FT_WinFNT_HeaderRec winfnt_header;
1224 int i, bitmap_num, internal_leading;
1227 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1228 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1230 #ifdef HAVE_CARBON_CARBON_H
1231 if(file && !fake_family)
1233 char **mac_list = expand_mac_font(file);
1236 BOOL had_one = FALSE;
1238 for(cursor = mac_list; *cursor; cursor++)
1241 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1242 HeapFree(GetProcessHeap(), 0, *cursor);
1244 HeapFree(GetProcessHeap(), 0, mac_list);
1249 #endif /* HAVE_CARBON_CARBON_H */
1252 char *family_name = fake_family;
1256 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1257 err = pFT_New_Face(library, file, face_index, &ft_face);
1260 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1261 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1265 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1269 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*/
1270 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1271 pFT_Done_Face(ft_face);
1275 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1276 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1277 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1278 pFT_Done_Face(ft_face);
1282 if(FT_IS_SFNT(ft_face))
1284 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1285 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1286 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1288 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1289 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1290 pFT_Done_Face(ft_face);
1294 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1295 we don't want to load these. */
1296 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1300 if(!load_sfnt_table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1302 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1303 pFT_Done_Face(ft_face);
1309 if(!ft_face->family_name || !ft_face->style_name) {
1310 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1311 pFT_Done_Face(ft_face);
1315 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1317 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1318 pFT_Done_Face(ft_face);
1324 localised_family = get_familyname(ft_face);
1325 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1327 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1328 HeapFree(GetProcessHeap(), 0, localised_family);
1329 num_faces = ft_face->num_faces;
1330 pFT_Done_Face(ft_face);
1333 HeapFree(GetProcessHeap(), 0, localised_family);
1337 family_name = ft_face->family_name;
1341 My_FT_Bitmap_Size *size = NULL;
1344 if(!FT_IS_SCALABLE(ft_face))
1345 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1347 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1348 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1349 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1351 localised_family = NULL;
1353 localised_family = get_familyname(ft_face);
1354 if(localised_family && !strcmpiW(localised_family, english_family)) {
1355 HeapFree(GetProcessHeap(), 0, localised_family);
1356 localised_family = NULL;
1361 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1362 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1363 if(!strcmpiW(family->FamilyName, localised_family ? localised_family : english_family))
1368 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1369 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1370 list_init(&family->faces);
1371 list_add_tail(&font_list, &family->entry);
1373 if(localised_family) {
1374 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1375 subst->from.name = strdupW(english_family);
1376 subst->from.charset = -1;
1377 subst->to.name = strdupW(localised_family);
1378 subst->to.charset = -1;
1379 add_font_subst(&font_subst_list, subst, 0);
1382 HeapFree(GetProcessHeap(), 0, localised_family);
1383 HeapFree(GetProcessHeap(), 0, english_family);
1385 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1386 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1387 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1389 internal_leading = 0;
1390 memset(&fs, 0, sizeof(fs));
1392 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1394 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1395 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1396 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1397 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1398 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1399 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1400 if(pOS2->version == 0) {
1403 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1404 fs.fsCsb[0] |= FS_LATIN1;
1406 fs.fsCsb[0] |= FS_SYMBOL;
1409 #ifdef HAVE_FREETYPE_FTWINFNT_H
1410 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1412 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1413 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1414 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1416 internal_leading = winfnt_header.internal_leading;
1420 face_elem_ptr = list_head(&family->faces);
1421 while(face_elem_ptr) {
1422 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1423 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1424 if(!strcmpiW(face->StyleName, StyleW) &&
1425 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1426 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1427 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1428 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1431 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1432 HeapFree(GetProcessHeap(), 0, StyleW);
1433 pFT_Done_Face(ft_face);
1436 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1437 TRACE("Original font is newer so skipping this one\n");
1438 HeapFree(GetProcessHeap(), 0, StyleW);
1439 pFT_Done_Face(ft_face);
1442 TRACE("Replacing original with this one\n");
1443 list_remove(&face->entry);
1444 HeapFree(GetProcessHeap(), 0, face->file);
1445 HeapFree(GetProcessHeap(), 0, face->StyleName);
1446 HeapFree(GetProcessHeap(), 0, face);
1451 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1452 face->cached_enum_data = NULL;
1453 face->StyleName = StyleW;
1456 face->file = strdupA(file);
1457 face->font_data_ptr = NULL;
1458 face->font_data_size = 0;
1463 face->font_data_ptr = font_data_ptr;
1464 face->font_data_size = font_data_size;
1466 face->face_index = face_index;
1468 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1469 face->ntmFlags |= NTM_ITALIC;
1470 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1471 face->ntmFlags |= NTM_BOLD;
1472 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1473 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1474 face->family = family;
1475 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1477 memset(&face->fs_links, 0, sizeof(face->fs_links));
1479 if(FT_IS_SCALABLE(ft_face)) {
1480 memset(&face->size, 0, sizeof(face->size));
1481 face->scalable = TRUE;
1483 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1484 size->height, size->width, size->size >> 6,
1485 size->x_ppem >> 6, size->y_ppem >> 6);
1486 face->size.height = size->height;
1487 face->size.width = size->width;
1488 face->size.size = size->size;
1489 face->size.x_ppem = size->x_ppem;
1490 face->size.y_ppem = size->y_ppem;
1491 face->size.internal_leading = internal_leading;
1492 face->scalable = FALSE;
1495 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1497 if (pFT_Load_Sfnt_Table && !pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1499 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1500 face->ntmFlags |= NTM_PS_OPENTYPE;
1503 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1504 face->fs.fsCsb[0], face->fs.fsCsb[1],
1505 face->fs.fsUsb[0], face->fs.fsUsb[1],
1506 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1509 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1510 for(i = 0; i < ft_face->num_charmaps; i++) {
1511 switch(ft_face->charmaps[i]->encoding) {
1512 case FT_ENCODING_UNICODE:
1513 case FT_ENCODING_APPLE_ROMAN:
1514 face->fs.fsCsb[0] |= FS_LATIN1;
1516 case FT_ENCODING_MS_SYMBOL:
1517 face->fs.fsCsb[0] |= FS_SYMBOL;
1525 if (!(face->fs.fsCsb[0] & FS_SYMBOL))
1526 have_installed_roman_font = TRUE;
1528 AddFaceToFamily(face, family);
1530 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1532 num_faces = ft_face->num_faces;
1533 pFT_Done_Face(ft_face);
1534 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1535 debugstr_w(StyleW));
1536 } while(num_faces > ++face_index);
1540 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1542 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1545 static void DumpFontList(void)
1549 struct list *family_elem_ptr, *face_elem_ptr;
1551 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1552 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1553 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1554 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1555 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1556 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1558 TRACE(" %d", face->size.height);
1565 /***********************************************************
1566 * The replacement list is a way to map an entire font
1567 * family onto another family. For example adding
1569 * [HKCU\Software\Wine\Fonts\Replacements]
1570 * "Wingdings"="Winedings"
1572 * would enumerate the Winedings font both as Winedings and
1573 * Wingdings. However if a real Wingdings font is present the
1574 * replacement does not take place.
1577 static void LoadReplaceList(void)
1580 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1585 struct list *family_elem_ptr, *face_elem_ptr;
1588 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1589 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1591 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1592 &valuelen, &datalen, NULL, NULL);
1594 valuelen++; /* returned value doesn't include room for '\0' */
1595 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1596 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1600 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1601 &dlen) == ERROR_SUCCESS) {
1602 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1603 /* "NewName"="Oldname" */
1604 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1606 /* Find the old family and hence all of the font files
1608 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1609 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1610 if(!strcmpiW(family->FamilyName, data)) {
1611 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1612 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1613 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1614 debugstr_w(face->StyleName), familyA);
1615 /* Now add a new entry with the new family name */
1616 AddFontToList(face->file, face->font_data_ptr, face->font_data_size, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1621 /* reset dlen and vlen */
1625 HeapFree(GetProcessHeap(), 0, data);
1626 HeapFree(GetProcessHeap(), 0, value);
1631 /*************************************************************
1634 static BOOL init_system_links(void)
1638 DWORD type, max_val, max_data, val_len, data_len, index;
1639 WCHAR *value, *data;
1640 WCHAR *entry, *next;
1641 SYSTEM_LINKS *font_link, *system_font_link;
1642 CHILD_FONT *child_font;
1643 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1644 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1650 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1652 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1653 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1654 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1655 val_len = max_val + 1;
1656 data_len = max_data;
1658 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1660 memset(&fs, 0, sizeof(fs));
1661 psub = get_font_subst(&font_subst_list, value, -1);
1662 /* Don't store fonts that are only substitutes for other fonts */
1665 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
1668 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1669 font_link->font_name = strdupW(value);
1670 list_init(&font_link->links);
1671 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1674 CHILD_FONT *child_font;
1676 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
1678 next = entry + strlenW(entry) + 1;
1680 face_name = strchrW(entry, ',');
1684 while(isspaceW(*face_name))
1687 psub = get_font_subst(&font_subst_list, face_name, -1);
1689 face_name = psub->to.name;
1691 face = find_face_from_filename(entry, face_name);
1694 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1698 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1699 child_font->face = face;
1700 child_font->font = NULL;
1701 fs.fsCsb[0] |= face->fs.fsCsb[0];
1702 fs.fsCsb[1] |= face->fs.fsCsb[1];
1703 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1704 list_add_tail(&font_link->links, &child_font->entry);
1706 family = find_family_from_name(font_link->font_name);
1709 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1711 face->fs_links = fs;
1714 list_add_tail(&system_links, &font_link->entry);
1715 val_len = max_val + 1;
1716 data_len = max_data;
1719 HeapFree(GetProcessHeap(), 0, value);
1720 HeapFree(GetProcessHeap(), 0, data);
1724 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1727 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1728 system_font_link->font_name = strdupW(System);
1729 list_init(&system_font_link->links);
1731 face = find_face_from_filename(tahoma_ttf, Tahoma);
1734 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1735 child_font->face = face;
1736 child_font->font = NULL;
1737 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
1738 list_add_tail(&system_font_link->links, &child_font->entry);
1740 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1742 if(!strcmpiW(font_link->font_name, Tahoma))
1744 CHILD_FONT *font_link_entry;
1745 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1747 CHILD_FONT *new_child;
1748 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1749 new_child->face = font_link_entry->face;
1750 new_child->font = NULL;
1751 list_add_tail(&system_font_link->links, &new_child->entry);
1756 list_add_tail(&system_links, &system_font_link->entry);
1760 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1763 struct dirent *dent;
1764 char path[MAX_PATH];
1766 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1768 dir = opendir(dirname);
1770 WARN("Can't open directory %s\n", debugstr_a(dirname));
1773 while((dent = readdir(dir)) != NULL) {
1774 struct stat statbuf;
1776 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1779 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1781 sprintf(path, "%s/%s", dirname, dent->d_name);
1783 if(stat(path, &statbuf) == -1)
1785 WARN("Can't stat %s\n", debugstr_a(path));
1788 if(S_ISDIR(statbuf.st_mode))
1789 ReadFontDir(path, external_fonts);
1791 AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1797 static void load_fontconfig_fonts(void)
1799 #ifdef SONAME_LIBFONTCONFIG
1800 void *fc_handle = NULL;
1809 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1811 TRACE("Wine cannot find the fontconfig library (%s).\n",
1812 SONAME_LIBFONTCONFIG);
1815 #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;}
1816 LOAD_FUNCPTR(FcConfigGetCurrent);
1817 LOAD_FUNCPTR(FcFontList);
1818 LOAD_FUNCPTR(FcFontSetDestroy);
1819 LOAD_FUNCPTR(FcInit);
1820 LOAD_FUNCPTR(FcObjectSetAdd);
1821 LOAD_FUNCPTR(FcObjectSetCreate);
1822 LOAD_FUNCPTR(FcObjectSetDestroy);
1823 LOAD_FUNCPTR(FcPatternCreate);
1824 LOAD_FUNCPTR(FcPatternDestroy);
1825 LOAD_FUNCPTR(FcPatternGetBool);
1826 LOAD_FUNCPTR(FcPatternGetString);
1829 if(!pFcInit()) return;
1831 config = pFcConfigGetCurrent();
1832 pat = pFcPatternCreate();
1833 os = pFcObjectSetCreate();
1834 pFcObjectSetAdd(os, FC_FILE);
1835 pFcObjectSetAdd(os, FC_SCALABLE);
1836 fontset = pFcFontList(config, pat, os);
1837 if(!fontset) return;
1838 for(i = 0; i < fontset->nfont; i++) {
1841 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1843 TRACE("fontconfig: %s\n", file);
1845 /* We're just interested in OT/TT fonts for now, so this hack just
1846 picks up the scalable fonts without extensions .pf[ab] to save time
1847 loading every other font */
1849 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1851 TRACE("not scalable\n");
1855 len = strlen( file );
1856 if(len < 4) continue;
1857 ext = &file[ len - 3 ];
1858 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1859 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT);
1861 pFcFontSetDestroy(fontset);
1862 pFcObjectSetDestroy(os);
1863 pFcPatternDestroy(pat);
1869 static BOOL load_font_from_data_dir(LPCWSTR file)
1872 const char *data_dir = wine_get_data_dir();
1874 if (!data_dir) data_dir = wine_get_build_dir();
1881 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1883 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1885 strcpy(unix_name, data_dir);
1886 strcat(unix_name, "/fonts/");
1888 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1890 EnterCriticalSection( &freetype_cs );
1891 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1892 LeaveCriticalSection( &freetype_cs );
1893 HeapFree(GetProcessHeap(), 0, unix_name);
1898 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
1900 static const WCHAR slashW[] = {'\\','\0'};
1902 WCHAR windowsdir[MAX_PATH];
1905 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1906 strcatW(windowsdir, fontsW);
1907 strcatW(windowsdir, slashW);
1908 strcatW(windowsdir, file);
1909 if ((unixname = wine_get_unix_file_name(windowsdir))) {
1910 EnterCriticalSection( &freetype_cs );
1911 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1912 LeaveCriticalSection( &freetype_cs );
1913 HeapFree(GetProcessHeap(), 0, unixname);
1918 static void load_system_fonts(void)
1921 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1922 const WCHAR * const *value;
1924 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1927 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1928 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1929 strcatW(windowsdir, fontsW);
1930 for(value = SystemFontValues; *value; value++) {
1931 dlen = sizeof(data);
1932 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1936 sprintfW(pathW, fmtW, windowsdir, data);
1937 if((unixname = wine_get_unix_file_name(pathW))) {
1938 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1939 HeapFree(GetProcessHeap(), 0, unixname);
1942 load_font_from_data_dir(data);
1949 /*************************************************************
1951 * This adds registry entries for any externally loaded fonts
1952 * (fonts from fontconfig or FontDirs). It also deletes entries
1953 * of no longer existing fonts.
1956 static void update_reg_entries(void)
1958 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
1963 struct list *family_elem_ptr, *face_elem_ptr;
1965 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1966 static const WCHAR spaceW[] = {' ', '\0'};
1969 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
1970 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
1971 ERR("Can't create Windows font reg key\n");
1975 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
1976 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
1977 ERR("Can't create Windows font reg key\n");
1981 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1982 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
1983 ERR("Can't create external font reg key\n");
1987 /* enumerate the fonts and add external ones to the two keys */
1989 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1990 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1991 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1992 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1993 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1994 if(!face->external) continue;
1996 if (!(face->ntmFlags & NTM_REGULAR))
1997 len = len_fam + strlenW(face->StyleName) + 1;
1998 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1999 strcpyW(valueW, family->FamilyName);
2000 if(len != len_fam) {
2001 strcatW(valueW, spaceW);
2002 strcatW(valueW, face->StyleName);
2004 strcatW(valueW, TrueType);
2006 file = wine_get_dos_file_name(face->file);
2008 len = strlenW(file) + 1;
2011 if((path = strrchr(face->file, '/')) == NULL)
2015 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
2017 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2018 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2020 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2021 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2022 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2024 HeapFree(GetProcessHeap(), 0, file);
2025 HeapFree(GetProcessHeap(), 0, valueW);
2029 if(external_key) RegCloseKey(external_key);
2030 if(win9x_key) RegCloseKey(win9x_key);
2031 if(winnt_key) RegCloseKey(winnt_key);
2035 static void delete_external_font_keys(void)
2037 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2038 DWORD dlen, vlen, datalen, valuelen, i, type;
2042 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2043 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2044 ERR("Can't create Windows font reg key\n");
2048 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2049 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2050 ERR("Can't create Windows font reg key\n");
2054 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2055 ERR("Can't create external font reg key\n");
2059 /* Delete all external fonts added last time */
2061 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2062 &valuelen, &datalen, NULL, NULL);
2063 valuelen++; /* returned value doesn't include room for '\0' */
2064 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2065 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2067 dlen = datalen * sizeof(WCHAR);
2070 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2071 &dlen) == ERROR_SUCCESS) {
2073 RegDeleteValueW(winnt_key, valueW);
2074 RegDeleteValueW(win9x_key, valueW);
2075 /* reset dlen and vlen */
2079 HeapFree(GetProcessHeap(), 0, data);
2080 HeapFree(GetProcessHeap(), 0, valueW);
2082 /* Delete the old external fonts key */
2083 RegCloseKey(external_key);
2084 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2087 if(win9x_key) RegCloseKey(win9x_key);
2088 if(winnt_key) RegCloseKey(winnt_key);
2091 /*************************************************************
2092 * WineEngAddFontResourceEx
2095 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2101 if (ft_handle) /* do it only if we have freetype up and running */
2106 FIXME("Ignoring flags %x\n", flags);
2108 if((unixname = wine_get_unix_file_name(file)))
2110 EnterCriticalSection( &freetype_cs );
2111 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2112 LeaveCriticalSection( &freetype_cs );
2113 HeapFree(GetProcessHeap(), 0, unixname);
2115 if (!ret && !strchrW(file, '\\')) {
2116 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2117 ret = load_font_from_winfonts_dir(file);
2119 /* Try in datadir/fonts (or builddir/fonts),
2120 * needed for Magic the Gathering Online
2122 ret = load_font_from_data_dir(file);
2129 /*************************************************************
2130 * WineEngAddFontMemResourceEx
2133 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2137 if (ft_handle) /* do it only if we have freetype up and running */
2139 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2141 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2142 memcpy(pFontCopy, pbFont, cbFont);
2144 EnterCriticalSection( &freetype_cs );
2145 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
2146 LeaveCriticalSection( &freetype_cs );
2150 TRACE("AddFontToList failed\n");
2151 HeapFree(GetProcessHeap(), 0, pFontCopy);
2154 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2155 * For now return something unique but quite random
2157 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2158 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2165 /*************************************************************
2166 * WineEngRemoveFontResourceEx
2169 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2176 static const struct nls_update_font_list
2178 UINT ansi_cp, oem_cp;
2179 const char *oem, *fixed, *system;
2180 const char *courier, *serif, *small, *sserif;
2181 /* these are for font substitutes */
2182 const char *shelldlg, *tmsrmn;
2183 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2187 const char *from, *to;
2188 } arial_0, courier_new_0, times_new_roman_0;
2189 } nls_update_font_list[] =
2191 /* Latin 1 (United States) */
2192 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2193 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2194 "Tahoma","Times New Roman",
2195 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2198 /* Latin 1 (Multilingual) */
2199 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2200 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2201 "Tahoma","Times New Roman", /* FIXME unverified */
2202 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2205 /* Eastern Europe */
2206 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2207 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2208 "Tahoma","Times New Roman", /* FIXME unverified */
2209 "Fixedsys,238", "System,238",
2210 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2211 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2212 { "Arial CE,0", "Arial,238" },
2213 { "Courier New CE,0", "Courier New,238" },
2214 { "Times New Roman CE,0", "Times New Roman,238" }
2217 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2218 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2219 "Tahoma","Times New Roman", /* FIXME unverified */
2220 "Fixedsys,204", "System,204",
2221 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2222 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2223 { "Arial Cyr,0", "Arial,204" },
2224 { "Courier New Cyr,0", "Courier New,204" },
2225 { "Times New Roman Cyr,0", "Times New Roman,204" }
2228 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2229 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2230 "Tahoma","Times New Roman", /* FIXME unverified */
2231 "Fixedsys,161", "System,161",
2232 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2233 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2234 { "Arial Greek,0", "Arial,161" },
2235 { "Courier New Greek,0", "Courier New,161" },
2236 { "Times New Roman Greek,0", "Times New Roman,161" }
2239 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2240 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2241 "Tahoma","Times New Roman", /* FIXME unverified */
2242 "Fixedsys,162", "System,162",
2243 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2244 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2245 { "Arial Tur,0", "Arial,162" },
2246 { "Courier New Tur,0", "Courier New,162" },
2247 { "Times New Roman Tur,0", "Times New Roman,162" }
2250 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2251 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2252 "Tahoma","Times New Roman", /* FIXME unverified */
2253 "Fixedsys,177", "System,177",
2254 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2255 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2259 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2260 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2261 "Tahoma","Times New Roman", /* FIXME unverified */
2262 "Fixedsys,178", "System,178",
2263 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2264 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2268 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2269 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2270 "Tahoma","Times New Roman", /* FIXME unverified */
2271 "Fixedsys,186", "System,186",
2272 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2273 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2274 { "Arial Baltic,0", "Arial,186" },
2275 { "Courier New Baltic,0", "Courier New,186" },
2276 { "Times New Roman Baltic,0", "Times New Roman,186" }
2279 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2280 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2281 "Tahoma","Times New Roman", /* FIXME unverified */
2282 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2286 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2287 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2288 "Tahoma","Times New Roman", /* FIXME unverified */
2289 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2293 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2294 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2295 "MS UI Gothic","MS Serif",
2296 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2299 /* Chinese Simplified */
2300 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2301 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2302 "SimSun", "NSimSun",
2303 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2307 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2308 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2310 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2313 /* Chinese Traditional */
2314 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2315 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2316 "PMingLiU", "MingLiU",
2317 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2322 static const WCHAR *font_links_list[] =
2324 Lucida_Sans_Unicode,
2325 Microsoft_Sans_Serif,
2329 static const struct font_links_defaults_list
2331 /* Keyed off substitution for "MS Shell Dlg" */
2332 const WCHAR *shelldlg;
2333 /* Maximum of four substitutes, plus terminating NULL pointer */
2334 const WCHAR *substitutes[5];
2335 } font_links_defaults_list[] =
2337 /* Non East-Asian */
2338 { Tahoma, /* FIXME unverified ordering */
2339 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2341 /* Below lists are courtesy of
2342 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2346 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2348 /* Chinese Simplified */
2350 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2354 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2356 /* Chinese Traditional */
2358 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2362 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2364 return ( ansi_cp == 932 /* CP932 for Japanese */
2365 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2366 || ansi_cp == 949 /* CP949 for Korean */
2367 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2370 static inline HKEY create_fonts_NT_registry_key(void)
2374 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2375 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2379 static inline HKEY create_fonts_9x_registry_key(void)
2383 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2384 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2388 static inline HKEY create_config_fonts_registry_key(void)
2392 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2393 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2397 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2399 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2400 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2401 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2402 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2405 static void set_value_key(HKEY hkey, const char *name, const char *value)
2408 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2410 RegDeleteValueA(hkey, name);
2413 static void update_font_info(void)
2415 char buf[40], cpbuf[40];
2418 UINT i, ansi_cp = 0, oem_cp = 0;
2421 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2424 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2425 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2426 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2427 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2428 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2430 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2431 if (is_dbcs_ansi_cp(ansi_cp))
2432 use_default_fallback = TRUE;
2435 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2437 if (!strcmp( buf, cpbuf )) /* already set correctly */
2442 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2444 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2446 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2449 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2453 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2454 nls_update_font_list[i].oem_cp == oem_cp)
2456 hkey = create_config_fonts_registry_key();
2457 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2458 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2459 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2462 hkey = create_fonts_NT_registry_key();
2463 add_font_list(hkey, &nls_update_font_list[i]);
2466 hkey = create_fonts_9x_registry_key();
2467 add_font_list(hkey, &nls_update_font_list[i]);
2470 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2472 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2473 strlen(nls_update_font_list[i].shelldlg)+1);
2474 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2475 strlen(nls_update_font_list[i].tmsrmn)+1);
2477 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2478 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2479 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2480 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2481 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2482 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2483 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2484 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2486 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2487 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2488 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2496 /* Delete the FontSubstitutes from other locales */
2497 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2499 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2500 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2501 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2507 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2509 /* Clear out system links */
2510 RegDeleteKeyW(HKEY_LOCAL_MACHINE, system_link);
2513 static void populate_system_links(HKEY hkey, const WCHAR *name, const WCHAR *const *values)
2523 WCHAR buff[MAX_PATH];
2527 static const WCHAR comma[] = {',',0};
2529 RegDeleteValueW(hkey, name);
2534 for (i = 0; values[i] != NULL; i++)
2537 if (!strcmpiW(name,value))
2539 psub = get_font_subst(&font_subst_list, value, -1);
2541 value = psub->to.name;
2542 family = find_family_from_name(value);
2546 /* Use first extant filename for this Family */
2547 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2551 file = strrchr(face->file, '/');
2560 fileLen = MultiByteToWideChar(CP_UNIXCP, 0, file, -1, NULL, 0);
2561 fileW = HeapAlloc(GetProcessHeap(), 0, fileLen * sizeof(WCHAR));
2562 MultiByteToWideChar(CP_UNIXCP, 0, file, -1, fileW, fileLen);
2563 entryLen = strlenW(fileW) + 1 + strlenW(value) + 1;
2564 if (sizeof(buff)-(data-buff) < entryLen + 1)
2566 WARN("creating SystemLink for %s, ran out of buffer space\n", debugstr_w(name));
2567 HeapFree(GetProcessHeap(), 0, fileW);
2570 strcpyW(data, fileW);
2571 strcatW(data, comma);
2572 strcatW(data, value);
2574 TRACE("added SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(fileW));
2575 HeapFree(GetProcessHeap(), 0, fileW);
2581 RegSetValueExW(hkey, name, 0, REG_MULTI_SZ, (BYTE*)buff, (data-buff) * sizeof(WCHAR));
2583 TRACE("no SystemLink fonts found for %s\n", debugstr_w(name));
2585 TRACE("removed SystemLink for %s\n", debugstr_w(name));
2588 static void update_system_links(void)
2596 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2598 if (!RegCreateKeyExW(HKEY_LOCAL_MACHINE, system_link, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, &disposition))
2600 if (disposition == REG_OPENED_EXISTING_KEY)
2602 TRACE("SystemLink key already exists, doing nothing\n");
2607 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2609 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2614 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2616 if (!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name))
2618 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2619 populate_system_links(hkey, font_links_list[j], font_links_defaults_list[i].substitutes);
2621 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2622 populate_system_links(hkey, psub->to.name, font_links_defaults_list[i].substitutes);
2625 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2627 populate_system_links(hkey, font_links_defaults_list[i].substitutes[0], NULL);
2632 WARN("there is no SystemLink default list for MS Shell Dlg %s\n", debugstr_w(psub->to.name));
2634 WARN("failed to create SystemLink key\n");
2638 static BOOL init_freetype(void)
2640 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2643 "Wine cannot find the FreeType font library. To enable Wine to\n"
2644 "use TrueType fonts please install a version of FreeType greater than\n"
2645 "or equal to 2.0.5.\n"
2646 "http://www.freetype.org\n");
2650 #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;}
2652 LOAD_FUNCPTR(FT_Vector_Unit)
2653 LOAD_FUNCPTR(FT_Done_Face)
2654 LOAD_FUNCPTR(FT_Get_Char_Index)
2655 LOAD_FUNCPTR(FT_Get_Module)
2656 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2657 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2658 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2659 LOAD_FUNCPTR(FT_Init_FreeType)
2660 LOAD_FUNCPTR(FT_Load_Glyph)
2661 LOAD_FUNCPTR(FT_Matrix_Multiply)
2662 #ifndef FT_MULFIX_INLINED
2663 LOAD_FUNCPTR(FT_MulFix)
2665 LOAD_FUNCPTR(FT_New_Face)
2666 LOAD_FUNCPTR(FT_New_Memory_Face)
2667 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2668 LOAD_FUNCPTR(FT_Outline_Transform)
2669 LOAD_FUNCPTR(FT_Outline_Translate)
2670 LOAD_FUNCPTR(FT_Select_Charmap)
2671 LOAD_FUNCPTR(FT_Set_Charmap)
2672 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2673 LOAD_FUNCPTR(FT_Vector_Transform)
2674 LOAD_FUNCPTR(FT_Render_Glyph)
2677 /* Don't warn if these ones are missing */
2678 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
2679 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
2680 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
2681 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
2682 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2683 #ifdef HAVE_FREETYPE_FTLCDFIL_H
2684 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
2686 #ifdef HAVE_FREETYPE_FTWINFNT_H
2687 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2689 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2690 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2691 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2692 <= 2.0.3 has FT_Sqrt64 */
2696 if(pFT_Init_FreeType(&library) != 0) {
2697 ERR("Can't init FreeType library\n");
2698 wine_dlclose(ft_handle, NULL, 0);
2702 FT_Version.major = FT_Version.minor = FT_Version.patch = -1;
2703 if (pFT_Library_Version)
2704 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2706 if (FT_Version.major<=0)
2712 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2713 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2714 ((FT_Version.minor << 8) & 0x00ff00) |
2715 ((FT_Version.patch ) & 0x0000ff);
2721 "Wine cannot find certain functions that it needs inside the FreeType\n"
2722 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2723 "FreeType to at least version 2.0.5.\n"
2724 "http://www.freetype.org\n");
2725 wine_dlclose(ft_handle, NULL, 0);
2730 /*************************************************************
2733 * Initialize FreeType library and create a list of available faces
2735 BOOL WineEngInit(void)
2737 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2738 static const WCHAR pathW[] = {'P','a','t','h',0};
2740 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2741 WCHAR windowsdir[MAX_PATH];
2744 const char *data_dir;
2748 /* update locale dependent font info in registry */
2751 if(!init_freetype()) return FALSE;
2753 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2754 ERR("Failed to create font mutex\n");
2757 WaitForSingleObject(font_mutex, INFINITE);
2759 delete_external_font_keys();
2761 /* load the system bitmap fonts */
2762 load_system_fonts();
2764 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2765 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2766 strcatW(windowsdir, fontsW);
2767 if((unixname = wine_get_unix_file_name(windowsdir)))
2769 ReadFontDir(unixname, FALSE);
2770 HeapFree(GetProcessHeap(), 0, unixname);
2773 /* load the system truetype fonts */
2774 data_dir = wine_get_data_dir();
2775 if (!data_dir) data_dir = wine_get_build_dir();
2776 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2777 strcpy(unixname, data_dir);
2778 strcat(unixname, "/fonts/");
2779 ReadFontDir(unixname, TRUE);
2780 HeapFree(GetProcessHeap(), 0, unixname);
2783 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2784 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2785 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2787 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2788 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2789 &hkey) == ERROR_SUCCESS) {
2790 LPWSTR data, valueW;
2791 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2792 &valuelen, &datalen, NULL, NULL);
2794 valuelen++; /* returned value doesn't include room for '\0' */
2795 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2796 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2799 dlen = datalen * sizeof(WCHAR);
2801 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
2802 &dlen) == ERROR_SUCCESS) {
2803 if(data[0] && (data[1] == ':'))
2805 if((unixname = wine_get_unix_file_name(data)))
2807 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2808 HeapFree(GetProcessHeap(), 0, unixname);
2811 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
2813 WCHAR pathW[MAX_PATH];
2814 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2817 sprintfW(pathW, fmtW, windowsdir, data);
2818 if((unixname = wine_get_unix_file_name(pathW)))
2820 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2821 HeapFree(GetProcessHeap(), 0, unixname);
2824 load_font_from_data_dir(data);
2826 /* reset dlen and vlen */
2831 HeapFree(GetProcessHeap(), 0, data);
2832 HeapFree(GetProcessHeap(), 0, valueW);
2836 load_fontconfig_fonts();
2838 /* then look in any directories that we've specified in the config file */
2839 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2840 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2846 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2848 len += sizeof(WCHAR);
2849 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2850 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2852 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2853 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2854 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2855 TRACE( "got font path %s\n", debugstr_a(valueA) );
2859 LPSTR next = strchr( ptr, ':' );
2860 if (next) *next++ = 0;
2861 ReadFontDir( ptr, TRUE );
2864 HeapFree( GetProcessHeap(), 0, valueA );
2866 HeapFree( GetProcessHeap(), 0, valueW );
2875 update_reg_entries();
2877 update_system_links();
2878 init_system_links();
2880 ReleaseMutex(font_mutex);
2885 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2888 TT_HoriHeader *pHori;
2892 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2893 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2895 if(height == 0) height = 16;
2897 /* Calc. height of EM square:
2899 * For +ve lfHeight we have
2900 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2901 * Re-arranging gives:
2902 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2904 * For -ve lfHeight we have
2906 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2907 * with il = winAscent + winDescent - units_per_em]
2912 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2913 ppem = MulDiv(ft_face->units_per_EM, height,
2914 pHori->Ascender - pHori->Descender);
2916 ppem = MulDiv(ft_face->units_per_EM, height,
2917 pOS2->usWinAscent + pOS2->usWinDescent);
2925 static struct font_mapping *map_font_file( const char *name )
2927 struct font_mapping *mapping;
2931 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2932 if (fstat( fd, &st ) == -1) goto error;
2934 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2936 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2938 mapping->refcount++;
2943 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2946 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2949 if (mapping->data == MAP_FAILED)
2951 HeapFree( GetProcessHeap(), 0, mapping );
2954 mapping->refcount = 1;
2955 mapping->dev = st.st_dev;
2956 mapping->ino = st.st_ino;
2957 mapping->size = st.st_size;
2958 list_add_tail( &mappings_list, &mapping->entry );
2966 static void unmap_font_file( struct font_mapping *mapping )
2968 if (!--mapping->refcount)
2970 list_remove( &mapping->entry );
2971 munmap( mapping->data, mapping->size );
2972 HeapFree( GetProcessHeap(), 0, mapping );
2976 static LONG load_VDMX(GdiFont*, LONG);
2978 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
2985 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
2989 if (!(font->mapping = map_font_file( face->file )))
2991 WARN("failed to map %s\n", debugstr_a(face->file));
2994 data_ptr = font->mapping->data;
2995 data_size = font->mapping->size;
2999 data_ptr = face->font_data_ptr;
3000 data_size = face->font_data_size;
3003 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3005 ERR("FT_New_Face rets %d\n", err);
3009 /* set it here, as load_VDMX needs it */
3010 font->ft_face = ft_face;
3012 if(FT_IS_SCALABLE(ft_face)) {
3013 /* load the VDMX table if we have one */
3014 font->ppem = load_VDMX(font, height);
3016 font->ppem = calc_ppem_for_height(ft_face, height);
3017 TRACE("height %d => ppem %d\n", height, font->ppem);
3019 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3020 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3022 font->ppem = height;
3023 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3024 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3030 static int get_nearest_charset(Face *face, int *cp)
3032 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3033 a single face with the requested charset. The idea is to check if
3034 the selected font supports the current ANSI codepage, if it does
3035 return the corresponding charset, else return the first charset */
3038 int acp = GetACP(), i;
3042 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3043 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3044 return csi.ciCharset;
3046 for(i = 0; i < 32; i++) {
3048 if(face->fs.fsCsb[0] & fs0) {
3049 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
3051 return csi.ciCharset;
3054 FIXME("TCI failing on %x\n", fs0);
3058 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3059 face->fs.fsCsb[0], face->file);
3061 return DEFAULT_CHARSET;
3064 static GdiFont *alloc_font(void)
3066 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
3068 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
3069 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3071 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3072 ret->total_kern_pairs = (DWORD)-1;
3073 ret->kern_pairs = NULL;
3074 list_init(&ret->hfontlist);
3075 list_init(&ret->child_fonts);
3079 static void free_font(GdiFont *font)
3081 struct list *cursor, *cursor2;
3084 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
3086 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
3087 struct list *first_hfont;
3088 HFONTLIST *hfontlist;
3089 list_remove(cursor);
3092 first_hfont = list_head(&child->font->hfontlist);
3093 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3094 DeleteObject(hfontlist->hfont);
3095 HeapFree(GetProcessHeap(), 0, hfontlist);
3096 free_font(child->font);
3098 HeapFree(GetProcessHeap(), 0, child);
3101 if (font->ft_face) pFT_Done_Face(font->ft_face);
3102 if (font->mapping) unmap_font_file( font->mapping );
3103 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
3104 HeapFree(GetProcessHeap(), 0, font->potm);
3105 HeapFree(GetProcessHeap(), 0, font->name);
3106 for (i = 0; i < font->gmsize; i++)
3107 HeapFree(GetProcessHeap(),0,font->gm[i]);
3108 HeapFree(GetProcessHeap(), 0, font->gm);
3109 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
3110 HeapFree(GetProcessHeap(), 0, font);
3114 /*************************************************************
3117 * load the vdmx entry for the specified height
3120 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3121 ( ( (FT_ULong)_x4 << 24 ) | \
3122 ( (FT_ULong)_x3 << 16 ) | \
3123 ( (FT_ULong)_x2 << 8 ) | \
3126 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3141 static LONG load_VDMX(GdiFont *font, LONG height)
3145 BYTE devXRatio, devYRatio;
3146 USHORT numRecs, numRatios;
3147 DWORD result, offset = -1;
3151 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
3153 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
3156 /* FIXME: need the real device aspect ratio */
3160 numRecs = GET_BE_WORD(hdr[1]);
3161 numRatios = GET_BE_WORD(hdr[2]);
3163 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
3164 for(i = 0; i < numRatios; i++) {
3167 offset = (3 * 2) + (i * sizeof(Ratios));
3168 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
3171 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
3173 if((ratio.xRatio == 0 &&
3174 ratio.yStartRatio == 0 &&
3175 ratio.yEndRatio == 0) ||
3176 (devXRatio == ratio.xRatio &&
3177 devYRatio >= ratio.yStartRatio &&
3178 devYRatio <= ratio.yEndRatio))
3180 offset = (3 * 2) + (numRatios * 4) + (i * 2);
3181 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
3182 offset = GET_BE_WORD(tmp);
3188 FIXME("No suitable ratio found\n");
3192 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
3194 BYTE startsz, endsz;
3197 recs = GET_BE_WORD(group.recs);
3198 startsz = group.startsz;
3199 endsz = group.endsz;
3201 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
3203 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
3204 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
3205 if(result == GDI_ERROR) {
3206 FIXME("Failed to retrieve vTable\n");
3211 for(i = 0; i < recs; i++) {
3212 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3213 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3214 ppem = GET_BE_WORD(vTable[i * 3]);
3216 if(yMax + -yMin == height) {
3219 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3222 if(yMax + -yMin > height) {
3225 goto end; /* failed */
3227 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3228 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3229 ppem = GET_BE_WORD(vTable[i * 3]);
3230 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3236 TRACE("ppem not found for height %d\n", height);
3240 if(ppem < startsz || ppem > endsz)
3243 for(i = 0; i < recs; i++) {
3245 yPelHeight = GET_BE_WORD(vTable[i * 3]);
3247 if(yPelHeight > ppem)
3250 if(yPelHeight == ppem) {
3251 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3252 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3253 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
3259 HeapFree(GetProcessHeap(), 0, vTable);
3265 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3267 if(font->font_desc.hash != fd->hash) return TRUE;
3268 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3269 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3270 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3271 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3274 static void calc_hash(FONT_DESC *pfd)
3276 DWORD hash = 0, *ptr, two_chars;
3280 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3282 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3284 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3286 pwc = (WCHAR *)&two_chars;
3288 *pwc = toupperW(*pwc);
3290 *pwc = toupperW(*pwc);
3294 hash ^= !pfd->can_use_bitmap;
3299 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3304 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3308 fd.can_use_bitmap = can_use_bitmap;
3311 /* try the child list */
3312 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
3313 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3314 if(!fontcmp(ret, &fd)) {
3315 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3316 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3317 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3318 if(hflist->hfont == hfont)
3324 /* try the in-use list */
3325 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3326 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3327 if(!fontcmp(ret, &fd)) {
3328 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3329 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3330 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3331 if(hflist->hfont == hfont)
3334 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3335 hflist->hfont = hfont;
3336 list_add_head(&ret->hfontlist, &hflist->entry);
3341 /* then the unused list */
3342 font_elem_ptr = list_head(&unused_gdi_font_list);
3343 while(font_elem_ptr) {
3344 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3345 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3346 if(!fontcmp(ret, &fd)) {
3347 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3348 assert(list_empty(&ret->hfontlist));
3349 TRACE("Found %p in unused list\n", ret);
3350 list_remove(&ret->entry);
3351 list_add_head(&gdi_font_list, &ret->entry);
3352 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3353 hflist->hfont = hfont;
3354 list_add_head(&ret->hfontlist, &hflist->entry);
3361 static void add_to_cache(GdiFont *font)
3363 static DWORD cache_num = 1;
3365 font->cache_num = cache_num++;
3366 list_add_head(&gdi_font_list, &font->entry);
3369 /*************************************************************
3370 * create_child_font_list
3372 static BOOL create_child_font_list(GdiFont *font)
3375 SYSTEM_LINKS *font_link;
3376 CHILD_FONT *font_link_entry, *new_child;
3380 psub = get_font_subst(&font_subst_list, font->name, -1);
3381 font_name = psub ? psub->to.name : font->name;
3382 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3384 if(!strcmpiW(font_link->font_name, font_name))
3386 TRACE("found entry in system list\n");
3387 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3389 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3390 new_child->face = font_link_entry->face;
3391 new_child->font = NULL;
3392 list_add_tail(&font->child_fonts, &new_child->entry);
3393 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3400 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3401 * Sans Serif. This is how asian windows get default fallbacks for fonts
3403 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3404 font->charset != OEM_CHARSET &&
3405 strcmpiW(font_name,szDefaultFallbackLink) != 0)
3406 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3408 if(!strcmpiW(font_link->font_name,szDefaultFallbackLink))
3410 TRACE("found entry in default fallback list\n");
3411 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3413 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3414 new_child->face = font_link_entry->face;
3415 new_child->font = NULL;
3416 list_add_tail(&font->child_fonts, &new_child->entry);
3417 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3427 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3429 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3431 if (pFT_Set_Charmap)
3434 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3436 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3438 for (i = 0; i < ft_face->num_charmaps; i++)
3440 if (ft_face->charmaps[i]->encoding == encoding)
3442 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3443 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3445 switch (ft_face->charmaps[i]->platform_id)
3448 cmap_def = ft_face->charmaps[i];
3450 case 0: /* Apple Unicode */
3451 cmap0 = ft_face->charmaps[i];
3453 case 1: /* Macintosh */
3454 cmap1 = ft_face->charmaps[i];
3457 cmap2 = ft_face->charmaps[i];
3459 case 3: /* Microsoft */
3460 cmap3 = ft_face->charmaps[i];
3465 if (cmap3) /* prefer Microsoft cmap table */
3466 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3468 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3470 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3472 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3474 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3476 return ft_err == FT_Err_Ok;
3479 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3482 /*************************************************************
3483 * WineEngCreateFontInstance
3486 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
3489 Face *face, *best, *best_bitmap;
3490 Family *family, *last_resort_family;
3491 struct list *family_elem_ptr, *face_elem_ptr;
3492 INT height, width = 0;
3493 unsigned int score = 0, new_score;
3494 signed int diff = 0, newdiff;
3495 BOOL bd, it, can_use_bitmap;
3500 FontSubst *psub = NULL;
3502 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
3503 lf.lfWidth = abs(lf.lfWidth);
3505 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
3507 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3508 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3509 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3512 if(dc->GraphicsMode == GM_ADVANCED)
3513 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
3516 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3517 font scaling abilities. */
3518 dcmat.eM11 = dcmat.eM22 = dc->vport2WorldValid ? fabs(dc->xformWorld2Vport.eM22) : 1.0;
3519 dcmat.eM21 = dcmat.eM12 = 0;
3522 /* Try to avoid not necessary glyph transformations */
3523 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
3525 lf.lfHeight *= fabs(dcmat.eM11);
3526 lf.lfWidth *= fabs(dcmat.eM11);
3527 dcmat.eM11 = dcmat.eM22 = 1.0;
3530 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
3531 dcmat.eM21, dcmat.eM22);
3534 EnterCriticalSection( &freetype_cs );
3536 /* check the cache first */
3537 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3538 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3539 LeaveCriticalSection( &freetype_cs );
3543 TRACE("not in cache\n");
3544 if(list_empty(&font_list)) /* No fonts installed */
3546 TRACE("No fonts installed\n");
3547 LeaveCriticalSection( &freetype_cs );
3550 if(!have_installed_roman_font)
3552 TRACE("No roman font installed\n");
3553 LeaveCriticalSection( &freetype_cs );
3559 ret->font_desc.matrix = dcmat;
3560 ret->font_desc.lf = lf;
3561 ret->font_desc.can_use_bitmap = can_use_bitmap;
3562 calc_hash(&ret->font_desc);
3563 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3564 hflist->hfont = hfont;
3565 list_add_head(&ret->hfontlist, &hflist->entry);
3567 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3568 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3569 original value lfCharSet. Note this is a special case for
3570 Symbol and doesn't happen at least for "Wingdings*" */
3572 if(!strcmpiW(lf.lfFaceName, SymbolW))
3573 lf.lfCharSet = SYMBOL_CHARSET;
3575 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3576 switch(lf.lfCharSet) {
3577 case DEFAULT_CHARSET:
3578 csi.fs.fsCsb[0] = 0;
3581 FIXME("Untranslated charset %d\n", lf.lfCharSet);
3582 csi.fs.fsCsb[0] = 0;
3588 if(lf.lfFaceName[0] != '\0') {
3589 SYSTEM_LINKS *font_link;
3590 CHILD_FONT *font_link_entry;
3591 LPWSTR FaceName = lf.lfFaceName;
3594 * Check for a leading '@' this signals that the font is being
3595 * requested in tategaki mode (vertical writing substitution) but
3596 * does not affect the fontface that is to be selected.
3598 if (lf.lfFaceName[0]=='@')
3599 FaceName = &lf.lfFaceName[1];
3601 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
3604 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
3605 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
3606 if (psub->to.charset != -1)
3607 lf.lfCharSet = psub->to.charset;
3610 /* We want a match on name and charset or just name if
3611 charset was DEFAULT_CHARSET. If the latter then
3612 we fixup the returned charset later in get_nearest_charset
3613 where we'll either use the charset of the current ansi codepage
3614 or if that's unavailable the first charset that the font supports.
3616 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3617 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3618 if (!strcmpiW(family->FamilyName, FaceName) ||
3619 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
3621 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3622 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3623 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3624 if(face->scalable || can_use_bitmap)
3631 * Try check the SystemLink list first for a replacement font.
3632 * We may find good replacements there.
3634 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3636 if(!strcmpiW(font_link->font_name, FaceName) ||
3637 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
3639 TRACE("found entry in system list\n");
3640 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3642 face = font_link_entry->face;
3643 family = face->family;
3644 if(csi.fs.fsCsb[0] &
3645 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
3647 if(face->scalable || can_use_bitmap)
3655 psub = NULL; /* substitution is no more relevant */
3657 /* If requested charset was DEFAULT_CHARSET then try using charset
3658 corresponding to the current ansi codepage */
3659 if (!csi.fs.fsCsb[0])
3662 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
3663 FIXME("TCI failed on codepage %d\n", acp);
3664 csi.fs.fsCsb[0] = 0;
3666 lf.lfCharSet = csi.ciCharset;
3669 /* Face families are in the top 4 bits of lfPitchAndFamily,
3670 so mask with 0xF0 before testing */
3672 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
3673 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
3674 strcpyW(lf.lfFaceName, defFixed);
3675 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
3676 strcpyW(lf.lfFaceName, defSerif);
3677 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
3678 strcpyW(lf.lfFaceName, defSans);
3680 strcpyW(lf.lfFaceName, defSans);
3681 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3682 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3683 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
3684 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3685 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3686 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3687 if(face->scalable || can_use_bitmap)
3693 last_resort_family = NULL;
3694 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3695 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3696 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3697 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3698 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
3701 if(can_use_bitmap && !last_resort_family)
3702 last_resort_family = family;
3707 if(last_resort_family) {
3708 family = last_resort_family;
3709 csi.fs.fsCsb[0] = 0;
3713 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3714 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3715 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3716 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3717 if(face->scalable) {
3718 csi.fs.fsCsb[0] = 0;
3719 WARN("just using first face for now\n");
3722 if(can_use_bitmap && !last_resort_family)
3723 last_resort_family = family;
3726 if(!last_resort_family) {
3727 FIXME("can't find a single appropriate font - bailing\n");
3729 LeaveCriticalSection( &freetype_cs );
3733 WARN("could only find a bitmap font - this will probably look awful!\n");
3734 family = last_resort_family;
3735 csi.fs.fsCsb[0] = 0;
3738 it = lf.lfItalic ? 1 : 0;
3739 bd = lf.lfWeight > 550 ? 1 : 0;
3741 height = lf.lfHeight;
3743 face = best = best_bitmap = NULL;
3744 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
3746 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3750 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
3751 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
3752 new_score = (italic ^ it) + (bold ^ bd);
3753 if(!best || new_score <= score)
3755 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3756 italic, bold, it, bd);
3759 if(best->scalable && score == 0) break;
3763 newdiff = height - (signed int)(best->size.height);
3765 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
3766 if(!best_bitmap || new_score < score ||
3767 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
3769 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
3772 if(score == 0 && diff == 0) break;
3779 face = best->scalable ? best : best_bitmap;
3780 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
3781 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
3785 if(csi.fs.fsCsb[0]) {
3786 ret->charset = lf.lfCharSet;
3787 ret->codepage = csi.ciACP;
3790 ret->charset = get_nearest_charset(face, &ret->codepage);
3792 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
3793 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
3795 ret->aveWidth = height ? lf.lfWidth : 0;
3797 if(!face->scalable) {
3798 /* Windows uses integer scaling factors for bitmap fonts */
3799 INT scale, scaled_height;
3801 /* FIXME: rotation of bitmap fonts is ignored */
3802 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
3804 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
3805 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3807 if (height != 0) height = diff;
3808 height += face->size.height;
3810 scale = (height + face->size.height - 1) / face->size.height;
3811 scaled_height = scale * face->size.height;
3812 /* Only jump to the next height if the difference <= 25% original height */
3813 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
3814 /* The jump between unscaled and doubled is delayed by 1 */
3815 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
3816 ret->scale_y = scale;
3818 width = face->size.x_ppem >> 6;
3819 height = face->size.y_ppem >> 6;
3823 TRACE("font scale y: %f\n", ret->scale_y);
3825 ret->ft_face = OpenFontFace(ret, face, width, height);
3830 LeaveCriticalSection( &freetype_cs );
3834 ret->ntmFlags = face->ntmFlags;
3836 if (ret->charset == SYMBOL_CHARSET &&
3837 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
3840 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
3844 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
3847 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
3848 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
3849 ret->underline = lf.lfUnderline ? 0xff : 0;
3850 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
3851 create_child_font_list(ret);
3853 if (lf.lfFaceName[0]=='@') /* We need to try to load the GSUB table */
3855 int length = WineEngGetFontData (ret, GSUB_TAG , 0, NULL, 0);
3856 if (length != GDI_ERROR)
3858 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
3859 WineEngGetFontData(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
3860 TRACE("Loaded GSUB table of %i bytes\n",length);
3864 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
3867 LeaveCriticalSection( &freetype_cs );
3871 static void dump_gdi_font_list(void)
3874 struct list *elem_ptr;
3876 TRACE("---------- gdiFont Cache ----------\n");
3877 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
3878 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3879 TRACE("gdiFont=%p %s %d\n",
3880 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3883 TRACE("---------- Unused gdiFont Cache ----------\n");
3884 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
3885 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3886 TRACE("gdiFont=%p %s %d\n",
3887 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3891 /*************************************************************
3892 * WineEngDestroyFontInstance
3894 * free the gdiFont associated with this handle
3897 BOOL WineEngDestroyFontInstance(HFONT handle)
3902 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3906 EnterCriticalSection( &freetype_cs );
3908 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
3910 struct list *first_hfont = list_head(&gdiFont->hfontlist);
3911 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3912 if(hflist->hfont == handle)
3914 TRACE("removing child font %p from child list\n", gdiFont);
3915 list_remove(&gdiFont->entry);
3916 LeaveCriticalSection( &freetype_cs );
3921 TRACE("destroying hfont=%p\n", handle);
3923 dump_gdi_font_list();
3925 font_elem_ptr = list_head(&gdi_font_list);
3926 while(font_elem_ptr) {
3927 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3928 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3930 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3931 while(hfontlist_elem_ptr) {
3932 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3933 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3934 if(hflist->hfont == handle) {
3935 list_remove(&hflist->entry);
3936 HeapFree(GetProcessHeap(), 0, hflist);
3940 if(list_empty(&gdiFont->hfontlist)) {
3941 TRACE("Moving to Unused list\n");
3942 list_remove(&gdiFont->entry);
3943 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3948 font_elem_ptr = list_head(&unused_gdi_font_list);
3949 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3950 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3951 while(font_elem_ptr) {
3952 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3953 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3954 TRACE("freeing %p\n", gdiFont);
3955 list_remove(&gdiFont->entry);
3958 LeaveCriticalSection( &freetype_cs );
3962 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
3963 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
3968 if (face->cached_enum_data)
3971 *pelf = face->cached_enum_data->elf;
3972 *pntm = face->cached_enum_data->ntm;
3973 *ptype = face->cached_enum_data->type;
3977 font = alloc_font();
3979 if(face->scalable) {
3980 height = -2048; /* 2048 is the most common em size */
3983 height = face->size.y_ppem >> 6;
3984 width = face->size.x_ppem >> 6;
3986 font->scale_y = 1.0;
3988 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
3994 font->name = strdupW(face->family->FamilyName);
3995 font->ntmFlags = face->ntmFlags;
3997 if (WineEngGetOutlineTextMetrics(font, 0, NULL))
3999 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
4001 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
4003 lstrcpynW(pelf->elfLogFont.lfFaceName,
4004 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
4006 lstrcpynW(pelf->elfFullName,
4007 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
4009 lstrcpynW(pelf->elfStyle,
4010 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
4015 WineEngGetTextMetrics(font, (TEXTMETRICW *)&pntm->ntmTm);
4017 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
4019 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
4020 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
4021 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
4024 pntm->ntmTm.ntmFlags = face->ntmFlags;
4025 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
4026 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
4027 pntm->ntmFontSig = face->fs;
4029 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
4031 pelf->elfLogFont.lfEscapement = 0;
4032 pelf->elfLogFont.lfOrientation = 0;
4033 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
4034 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
4035 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
4036 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
4037 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
4038 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
4039 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
4040 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
4041 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
4042 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
4043 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
4046 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
4047 *ptype |= TRUETYPE_FONTTYPE;
4048 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
4049 *ptype |= DEVICE_FONTTYPE;
4050 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
4051 *ptype |= RASTER_FONTTYPE;
4053 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
4054 if (face->cached_enum_data)
4056 face->cached_enum_data->elf = *pelf;
4057 face->cached_enum_data->ntm = *pntm;
4058 face->cached_enum_data->type = *ptype;
4064 /*************************************************************
4068 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
4072 struct list *family_elem_ptr, *face_elem_ptr;
4074 NEWTEXTMETRICEXW ntm;
4083 lf.lfCharSet = DEFAULT_CHARSET;
4084 lf.lfPitchAndFamily = 0;
4085 lf.lfFaceName[0] = 0;
4089 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
4092 EnterCriticalSection( &freetype_cs );
4093 if(plf->lfFaceName[0]) {
4095 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
4098 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
4099 debugstr_w(psub->to.name));
4101 strcpyW(lf.lfFaceName, psub->to.name);
4105 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4106 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4107 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
4108 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4109 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4110 GetEnumStructs(face, &elf, &ntm, &type);
4111 for(i = 0; i < 32; i++) {
4112 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
4113 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
4114 strcpyW(elf.elfScript, OEM_DOSW);
4115 i = 32; /* break out of loop */
4116 } else if(!(face->fs.fsCsb[0] & (1L << i)))
4119 fs.fsCsb[0] = 1L << i;
4121 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
4123 csi.ciCharset = DEFAULT_CHARSET;
4124 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
4125 if(csi.ciCharset != DEFAULT_CHARSET) {
4126 elf.elfLogFont.lfCharSet =
4127 ntm.ntmTm.tmCharSet = csi.ciCharset;
4129 strcpyW(elf.elfScript, ElfScriptsW[i]);
4131 FIXME("Unknown elfscript for bit %d\n", i);
4134 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
4135 debugstr_w(elf.elfLogFont.lfFaceName),
4136 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
4137 csi.ciCharset, type, debugstr_w(elf.elfScript),
4138 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
4139 ntm.ntmTm.ntmFlags);
4140 /* release section before callback (FIXME) */
4141 LeaveCriticalSection( &freetype_cs );
4142 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
4143 EnterCriticalSection( &freetype_cs );
4149 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4150 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4151 face_elem_ptr = list_head(&family->faces);
4152 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4153 GetEnumStructs(face, &elf, &ntm, &type);
4154 for(i = 0; i < 32; i++) {
4155 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
4156 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
4157 strcpyW(elf.elfScript, OEM_DOSW);
4158 i = 32; /* break out of loop */
4159 } else if(!(face->fs.fsCsb[0] & (1L << i)))
4162 fs.fsCsb[0] = 1L << i;
4164 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
4166 csi.ciCharset = DEFAULT_CHARSET;
4167 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
4168 if(csi.ciCharset != DEFAULT_CHARSET) {
4169 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
4172 strcpyW(elf.elfScript, ElfScriptsW[i]);
4174 FIXME("Unknown elfscript for bit %d\n", i);
4177 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4178 debugstr_w(elf.elfLogFont.lfFaceName),
4179 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
4180 csi.ciCharset, type, debugstr_w(elf.elfScript),
4181 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
4182 ntm.ntmTm.ntmFlags);
4183 /* release section before callback (FIXME) */
4184 LeaveCriticalSection( &freetype_cs );
4185 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return 0;
4186 EnterCriticalSection( &freetype_cs );
4190 LeaveCriticalSection( &freetype_cs );
4194 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
4196 pt->x.value = vec->x >> 6;
4197 pt->x.fract = (vec->x & 0x3f) << 10;
4198 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
4199 pt->y.value = vec->y >> 6;
4200 pt->y.fract = (vec->y & 0x3f) << 10;
4201 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
4205 /***************************************************
4206 * According to the MSDN documentation on WideCharToMultiByte,
4207 * certain codepages cannot set the default_used parameter.
4208 * This returns TRUE if the codepage can set that parameter, false else
4209 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4211 static BOOL codepage_sets_default_used(UINT codepage)
4225 * GSUB Table handling functions
4228 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
4230 const GSUB_CoverageFormat1* cf1;
4234 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
4236 int count = GET_BE_WORD(cf1->GlyphCount);
4238 TRACE("Coverage Format 1, %i glyphs\n",count);
4239 for (i = 0; i < count; i++)
4240 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
4244 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
4246 const GSUB_CoverageFormat2* cf2;
4249 cf2 = (GSUB_CoverageFormat2*)cf1;
4251 count = GET_BE_WORD(cf2->RangeCount);
4252 TRACE("Coverage Format 2, %i ranges\n",count);
4253 for (i = 0; i < count; i++)
4255 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
4257 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
4258 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
4260 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4261 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4267 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4272 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4274 const GSUB_ScriptList *script;
4275 const GSUB_Script *deflt = NULL;
4277 script = (GSUB_ScriptList*)((LPBYTE)header + GET_BE_WORD(header->ScriptList));
4279 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4280 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4282 const GSUB_Script *scr;
4285 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4286 scr = (GSUB_Script*)((LPBYTE)script + offset);
4288 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4290 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4296 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4300 const GSUB_LangSys *Lang;
4302 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4304 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4306 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4307 Lang = (GSUB_LangSys*)((LPBYTE)script + offset);
4309 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4312 offset = GET_BE_WORD(script->DefaultLangSys);
4315 Lang = (GSUB_LangSys*)((LPBYTE)script + offset);
4321 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4324 const GSUB_FeatureList *feature;
4325 feature = (GSUB_FeatureList*)((LPBYTE)header + GET_BE_WORD(header->FeatureList));
4327 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4328 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4330 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4331 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4333 const GSUB_Feature *feat;
4334 feat = (GSUB_Feature*)((LPBYTE)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4341 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4345 const GSUB_LookupList *lookup;
4346 lookup = (GSUB_LookupList*)((LPBYTE)header + GET_BE_WORD(header->LookupList));
4348 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
4349 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
4351 const GSUB_LookupTable *look;
4352 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
4353 look = (GSUB_LookupTable*)((LPBYTE)lookup + offset);
4354 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
4355 if (GET_BE_WORD(look->LookupType) != 1)
4356 FIXME("We only handle SubType 1\n");
4361 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
4363 const GSUB_SingleSubstFormat1 *ssf1;
4364 offset = GET_BE_WORD(look->SubTable[j]);
4365 ssf1 = (GSUB_SingleSubstFormat1*)((LPBYTE)look+offset);
4366 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
4368 int offset = GET_BE_WORD(ssf1->Coverage);
4369 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
4370 if (GSUB_is_glyph_covered((LPBYTE)ssf1+offset, glyph) != -1)
4372 TRACE(" Glyph 0x%x ->",glyph);
4373 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4374 TRACE(" 0x%x\n",glyph);
4379 const GSUB_SingleSubstFormat2 *ssf2;
4383 ssf2 = (GSUB_SingleSubstFormat2 *)ssf1;
4384 offset = GET_BE_WORD(ssf1->Coverage);
4385 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4386 index = GSUB_is_glyph_covered((LPBYTE)ssf2+offset, glyph);
4387 TRACE(" Coverage index %i\n",index);
4390 TRACE(" Glyph is 0x%x ->",glyph);
4391 glyph = GET_BE_WORD(ssf2->Substitute[index]);
4392 TRACE("0x%x\n",glyph);
4401 static const char* get_opentype_script(const GdiFont *font)
4404 * I am not sure if this is the correct way to generate our script tag
4407 switch (font->charset)
4409 case ANSI_CHARSET: return "latn";
4410 case BALTIC_CHARSET: return "latn"; /* ?? */
4411 case CHINESEBIG5_CHARSET: return "hani";
4412 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4413 case GB2312_CHARSET: return "hani";
4414 case GREEK_CHARSET: return "grek";
4415 case HANGUL_CHARSET: return "hang";
4416 case RUSSIAN_CHARSET: return "cyrl";
4417 case SHIFTJIS_CHARSET: return "kana";
4418 case TURKISH_CHARSET: return "latn"; /* ?? */
4419 case VIETNAMESE_CHARSET: return "latn";
4420 case JOHAB_CHARSET: return "latn"; /* ?? */
4421 case ARABIC_CHARSET: return "arab";
4422 case HEBREW_CHARSET: return "hebr";
4423 case THAI_CHARSET: return "thai";
4424 default: return "latn";
4428 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
4430 const GSUB_Header *header;
4431 const GSUB_Script *script;
4432 const GSUB_LangSys *language;
4433 const GSUB_Feature *feature;
4435 if (!font->GSUB_Table)
4438 header = font->GSUB_Table;
4440 script = GSUB_get_script_table(header, get_opentype_script(font));
4443 TRACE("Script not found\n");
4446 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
4449 TRACE("Language not found\n");
4452 feature = GSUB_get_feature(header, language, "vrt2");
4454 feature = GSUB_get_feature(header, language, "vert");
4457 TRACE("vrt2/vert feature not found\n");
4460 return GSUB_apply_feature(header, feature, glyph);
4463 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
4467 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
4468 WCHAR wc = (WCHAR)glyph;
4470 BOOL *default_used_pointer;
4473 default_used_pointer = NULL;
4474 default_used = FALSE;
4475 if (codepage_sets_default_used(font->codepage))
4476 default_used_pointer = &default_used;
4477 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
4480 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
4481 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
4482 return get_GSUB_vert_glyph(font,ret);
4485 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL && glyph < 0x100)
4486 glyph = glyph + 0xf000;
4487 glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
4488 return get_GSUB_vert_glyph(font,glyphId);
4491 /*************************************************************
4492 * WineEngGetGlyphIndices
4495 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4496 LPWORD pgi, DWORD flags)
4499 int default_char = -1;
4501 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
4503 for(i = 0; i < count; i++)
4505 pgi[i] = get_glyph_index(font, lpstr[i]);
4508 if (default_char == -1)
4510 if (FT_IS_SFNT(font->ft_face))
4512 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(font->ft_face, ft_sfnt_os2);
4513 default_char = (pOS2->usDefaultChar ? get_glyph_index(font, pOS2->usDefaultChar) : 0);
4518 WineEngGetTextMetrics(font, &textm);
4519 default_char = textm.tmDefaultChar;
4522 pgi[i] = default_char;
4528 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
4530 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
4531 return !memcmp(matrix, &identity, sizeof(FMAT2));
4534 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
4536 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
4537 return !memcmp(matrix, &identity, sizeof(MAT2));
4540 /*************************************************************
4541 * WineEngGetGlyphOutline
4543 * Behaves in exactly the same way as the win32 api GetGlyphOutline
4544 * except that the first parameter is the HWINEENGFONT of the font in
4545 * question rather than an HDC.
4548 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
4549 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4552 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
4553 FT_Face ft_face = incoming_font->ft_face;
4554 GdiFont *font = incoming_font;
4555 FT_UInt glyph_index;
4556 DWORD width, height, pitch, needed = 0;
4557 FT_Bitmap ft_bitmap;
4559 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
4561 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
4562 double widthRatio = 1.0;
4563 FT_Matrix transMat = identityMat;
4564 FT_Matrix transMatUnrotated;
4565 BOOL needsTransform = FALSE;
4566 BOOL tategaki = (font->GSUB_Table != NULL);
4567 UINT original_index;
4569 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
4570 buflen, buf, lpmat);
4572 TRACE("font transform %f %f %f %f\n",
4573 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
4574 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
4577 EnterCriticalSection( &freetype_cs );
4579 if(format & GGO_GLYPH_INDEX) {
4580 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
4581 original_index = glyph;
4582 format &= ~GGO_GLYPH_INDEX;
4584 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
4585 ft_face = font->ft_face;
4586 original_index = glyph_index;
4589 if(format & GGO_UNHINTED) {
4590 load_flags |= FT_LOAD_NO_HINTING;
4591 format &= ~GGO_UNHINTED;
4594 /* tategaki never appears to happen to lower glyph index */
4595 if (glyph_index < TATEGAKI_LOWER_BOUND )
4598 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
4599 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
4600 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
4601 font->gmsize * sizeof(GM*));
4603 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
4604 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
4606 *lpgm = FONT_GM(font,original_index)->gm;
4607 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4608 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4609 lpgm->gmCellIncX, lpgm->gmCellIncY);
4610 LeaveCriticalSection( &freetype_cs );
4611 return 1; /* FIXME */
4615 if (!font->gm[original_index / GM_BLOCK_SIZE])
4616 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4618 /* Scaling factor */
4623 WineEngGetTextMetrics(font, &tm);
4625 widthRatio = (double)font->aveWidth;
4626 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
4629 widthRatio = font->scale_y;
4631 /* Scaling transform */
4632 if (widthRatio != 1.0 || font->scale_y != 1.0)
4635 scaleMat.xx = FT_FixedFromFloat(widthRatio);
4638 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
4640 pFT_Matrix_Multiply(&scaleMat, &transMat);
4641 needsTransform = TRUE;
4644 /* Slant transform */
4645 if (font->fake_italic) {
4648 slantMat.xx = (1 << 16);
4649 slantMat.xy = ((1 << 16) >> 2);
4651 slantMat.yy = (1 << 16);
4652 pFT_Matrix_Multiply(&slantMat, &transMat);
4653 needsTransform = TRUE;
4656 /* Rotation transform */
4657 transMatUnrotated = transMat;
4658 if(font->orientation && !tategaki) {
4659 FT_Matrix rotationMat;
4661 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
4662 pFT_Vector_Unit(&vecAngle, angle);
4663 rotationMat.xx = vecAngle.x;
4664 rotationMat.xy = -vecAngle.y;
4665 rotationMat.yx = -rotationMat.xy;
4666 rotationMat.yy = rotationMat.xx;
4668 pFT_Matrix_Multiply(&rotationMat, &transMat);
4669 needsTransform = TRUE;
4672 /* World transform */
4673 if (!is_identity_FMAT2(&font->font_desc.matrix))
4676 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
4677 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
4678 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
4679 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
4680 pFT_Matrix_Multiply(&worldMat, &transMat);
4681 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
4682 needsTransform = TRUE;
4685 /* Extra transformation specified by caller */
4686 if (!is_identity_MAT2(lpmat))
4689 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
4690 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
4691 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
4692 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
4693 pFT_Matrix_Multiply(&extraMat, &transMat);
4694 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
4695 needsTransform = TRUE;
4698 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
4699 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
4700 format == GGO_GRAY8_BITMAP))
4702 load_flags |= FT_LOAD_NO_BITMAP;
4705 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
4708 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
4709 LeaveCriticalSection( &freetype_cs );
4713 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
4714 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
4716 adv = (INT)((ft_face->glyph->metrics.horiAdvance) + 63) >> 6;
4718 bbx = (right - left) >> 6;
4720 if(!needsTransform) {
4721 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
4722 bottom = (ft_face->glyph->metrics.horiBearingY -
4723 ft_face->glyph->metrics.height) & -64;
4724 lpgm->gmCellIncX = adv;
4725 lpgm->gmCellIncY = 0;
4729 for(xc = 0; xc < 2; xc++) {
4730 for(yc = 0; yc < 2; yc++) {
4731 vec.x = (ft_face->glyph->metrics.horiBearingX +
4732 xc * ft_face->glyph->metrics.width);
4733 vec.y = ft_face->glyph->metrics.horiBearingY -
4734 yc * ft_face->glyph->metrics.height;
4735 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
4736 pFT_Vector_Transform(&vec, &transMat);
4737 if(xc == 0 && yc == 0) {
4738 left = right = vec.x;
4739 top = bottom = vec.y;
4741 if(vec.x < left) left = vec.x;
4742 else if(vec.x > right) right = vec.x;
4743 if(vec.y < bottom) bottom = vec.y;
4744 else if(vec.y > top) top = vec.y;
4749 right = (right + 63) & -64;
4750 bottom = bottom & -64;
4751 top = (top + 63) & -64;
4753 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
4754 vec.x = ft_face->glyph->metrics.horiAdvance;
4756 pFT_Vector_Transform(&vec, &transMat);
4757 lpgm->gmCellIncX = (vec.x+63) >> 6;
4758 lpgm->gmCellIncY = -((vec.y+63) >> 6);
4760 vec.x = ft_face->glyph->metrics.horiAdvance;
4762 pFT_Vector_Transform(&vec, &transMatUnrotated);
4763 adv = (vec.x+63) >> 6;
4765 lpgm->gmBlackBoxX = (right - left) >> 6;
4766 lpgm->gmBlackBoxY = (top - bottom) >> 6;
4767 lpgm->gmptGlyphOrigin.x = left >> 6;
4768 lpgm->gmptGlyphOrigin.y = top >> 6;
4770 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
4771 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
4772 lpgm->gmCellIncX, lpgm->gmCellIncY);
4774 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
4775 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
4777 FONT_GM(font,original_index)->gm = *lpgm;
4778 FONT_GM(font,original_index)->adv = adv;
4779 FONT_GM(font,original_index)->lsb = lsb;
4780 FONT_GM(font,original_index)->bbx = bbx;
4781 FONT_GM(font,original_index)->init = TRUE;
4784 if(format == GGO_METRICS)
4786 LeaveCriticalSection( &freetype_cs );
4787 return 1; /* FIXME */
4790 if(ft_face->glyph->format != ft_glyph_format_outline &&
4791 (format == GGO_NATIVE || format == GGO_BEZIER ||
4792 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
4793 format == GGO_GRAY8_BITMAP))
4795 TRACE("loaded a bitmap\n");
4796 LeaveCriticalSection( &freetype_cs );
4802 width = lpgm->gmBlackBoxX;
4803 height = lpgm->gmBlackBoxY;
4804 pitch = ((width + 31) >> 5) << 2;
4805 needed = pitch * height;
4807 if(!buf || !buflen) break;
4809 switch(ft_face->glyph->format) {
4810 case ft_glyph_format_bitmap:
4812 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4813 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
4814 INT h = ft_face->glyph->bitmap.rows;
4816 memcpy(dst, src, w);
4817 src += ft_face->glyph->bitmap.pitch;
4823 case ft_glyph_format_outline:
4824 ft_bitmap.width = width;
4825 ft_bitmap.rows = height;
4826 ft_bitmap.pitch = pitch;
4827 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
4828 ft_bitmap.buffer = buf;
4831 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4833 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4835 /* Note: FreeType will only set 'black' bits for us. */
4836 memset(buf, 0, needed);
4837 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4841 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4842 LeaveCriticalSection( &freetype_cs );
4847 case GGO_GRAY2_BITMAP:
4848 case GGO_GRAY4_BITMAP:
4849 case GGO_GRAY8_BITMAP:
4850 case WINE_GGO_GRAY16_BITMAP:
4852 unsigned int mult, row, col;
4855 width = lpgm->gmBlackBoxX;
4856 height = lpgm->gmBlackBoxY;
4857 pitch = (width + 3) / 4 * 4;
4858 needed = pitch * height;
4860 if(!buf || !buflen) break;
4862 switch(ft_face->glyph->format) {
4863 case ft_glyph_format_bitmap:
4865 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
4866 INT h = ft_face->glyph->bitmap.rows;
4869 for(x = 0; x < pitch; x++)
4871 if(x < ft_face->glyph->bitmap.width)
4872 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
4876 src += ft_face->glyph->bitmap.pitch;
4879 LeaveCriticalSection( &freetype_cs );
4882 case ft_glyph_format_outline:
4884 ft_bitmap.width = width;
4885 ft_bitmap.rows = height;
4886 ft_bitmap.pitch = pitch;
4887 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
4888 ft_bitmap.buffer = buf;
4891 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4893 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4895 memset(ft_bitmap.buffer, 0, buflen);
4897 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
4899 if(format == GGO_GRAY2_BITMAP)
4901 else if(format == GGO_GRAY4_BITMAP)
4903 else if(format == GGO_GRAY8_BITMAP)
4905 else /* format == WINE_GGO_GRAY16_BITMAP */
4907 LeaveCriticalSection( &freetype_cs );
4913 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
4914 LeaveCriticalSection( &freetype_cs );
4919 for(row = 0; row < height; row++) {
4921 for(col = 0; col < width; col++, ptr++) {
4922 *ptr = (((int)*ptr) * mult + 128) / 256;
4929 case WINE_GGO_HRGB_BITMAP:
4930 case WINE_GGO_HBGR_BITMAP:
4931 case WINE_GGO_VRGB_BITMAP:
4932 case WINE_GGO_VBGR_BITMAP:
4933 #ifdef HAVE_FREETYPE_FTLCDFIL_H
4935 switch (ft_face->glyph->format)
4937 case FT_GLYPH_FORMAT_BITMAP:
4942 width = lpgm->gmBlackBoxX;
4943 height = lpgm->gmBlackBoxY;
4945 needed = pitch * height;
4947 if (!buf || !buflen) break;
4949 memset(buf, 0, buflen);
4951 src = ft_face->glyph->bitmap.buffer;
4952 src_pitch = ft_face->glyph->bitmap.pitch;
4956 for (x = 0; x < width; x++)
4958 if ( src[x / 8] & (1 << ( (7 - (x % 8)))) )
4959 ((unsigned int *)dst)[x] = ~0u;
4968 case FT_GLYPH_FORMAT_OUTLINE:
4972 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
4973 INT x_shift, y_shift;
4975 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
4976 FT_Render_Mode render_mode =
4977 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
4978 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
4980 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
4982 if ( render_mode == FT_RENDER_MODE_LCD)
4984 lpgm->gmBlackBoxX += 2;
4985 lpgm->gmptGlyphOrigin.x -= 1;
4989 lpgm->gmBlackBoxY += 2;
4990 lpgm->gmptGlyphOrigin.y += 1;
4994 width = lpgm->gmBlackBoxX;
4995 height = lpgm->gmBlackBoxY;
4997 needed = pitch * height;
4999 if (!buf || !buflen) break;
5001 memset(buf, 0, buflen);
5003 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
5005 if ( needsTransform )
5006 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
5008 if ( pFT_Library_SetLcdFilter )
5009 pFT_Library_SetLcdFilter( library, lcdfilter );
5010 pFT_Render_Glyph (ft_face->glyph, render_mode);
5012 src = ft_face->glyph->bitmap.buffer;
5013 src_pitch = ft_face->glyph->bitmap.pitch;
5014 src_width = ft_face->glyph->bitmap.width;
5015 src_height = ft_face->glyph->bitmap.rows;
5017 if ( render_mode == FT_RENDER_MODE_LCD)
5025 rgb_interval = src_pitch;
5030 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
5031 if ( x_shift < 0 ) x_shift = 0;
5032 if ( x_shift + (src_width / hmul) > width )
5033 x_shift = width - (src_width / hmul);
5035 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
5036 if ( y_shift < 0 ) y_shift = 0;
5037 if ( y_shift + (src_height / vmul) > height )
5038 y_shift = height - (src_height / vmul);
5040 dst += x_shift + y_shift * ( pitch / 4 );
5041 while ( src_height )
5043 for ( x = 0; x < src_width / hmul; x++ )
5047 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
5048 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5049 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
5050 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5054 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
5055 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5056 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
5057 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5060 src += src_pitch * vmul;
5069 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
5070 LeaveCriticalSection ( &freetype_cs );
5077 LeaveCriticalSection( &freetype_cs );
5083 int contour, point = 0, first_pt;
5084 FT_Outline *outline = &ft_face->glyph->outline;
5085 TTPOLYGONHEADER *pph;
5087 DWORD pph_start, cpfx, type;
5089 if(buflen == 0) buf = NULL;
5091 if (needsTransform && buf) {
5092 pFT_Outline_Transform(outline, &transMat);
5095 for(contour = 0; contour < outline->n_contours; contour++) {
5097 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5100 pph->dwType = TT_POLYGON_TYPE;
5101 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5103 needed += sizeof(*pph);
5105 while(point <= outline->contours[contour]) {
5106 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5107 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5108 TT_PRIM_LINE : TT_PRIM_QSPLINE;
5112 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5115 } while(point <= outline->contours[contour] &&
5116 (outline->tags[point] & FT_Curve_Tag_On) ==
5117 (outline->tags[point-1] & FT_Curve_Tag_On));
5118 /* At the end of a contour Windows adds the start point, but
5120 if(point > outline->contours[contour] &&
5121 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
5123 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
5125 } else if(point <= outline->contours[contour] &&
5126 outline->tags[point] & FT_Curve_Tag_On) {
5127 /* add closing pt for bezier */
5129 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5137 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5140 pph->cb = needed - pph_start;
5146 /* Convert the quadratic Beziers to cubic Beziers.
5147 The parametric eqn for a cubic Bezier is, from PLRM:
5148 r(t) = at^3 + bt^2 + ct + r0
5149 with the control points:
5154 A quadratic Beizer has the form:
5155 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5157 So equating powers of t leads to:
5158 r1 = 2/3 p1 + 1/3 p0
5159 r2 = 2/3 p1 + 1/3 p2
5160 and of course r0 = p0, r3 = p2
5163 int contour, point = 0, first_pt;
5164 FT_Outline *outline = &ft_face->glyph->outline;
5165 TTPOLYGONHEADER *pph;
5167 DWORD pph_start, cpfx, type;
5168 FT_Vector cubic_control[4];
5169 if(buflen == 0) buf = NULL;
5171 if (needsTransform && buf) {
5172 pFT_Outline_Transform(outline, &transMat);
5175 for(contour = 0; contour < outline->n_contours; contour++) {
5177 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5180 pph->dwType = TT_POLYGON_TYPE;
5181 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5183 needed += sizeof(*pph);
5185 while(point <= outline->contours[contour]) {
5186 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5187 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5188 TT_PRIM_LINE : TT_PRIM_CSPLINE;
5191 if(type == TT_PRIM_LINE) {
5193 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5197 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5200 /* FIXME: Possible optimization in endpoint calculation
5201 if there are two consecutive curves */
5202 cubic_control[0] = outline->points[point-1];
5203 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
5204 cubic_control[0].x += outline->points[point].x + 1;
5205 cubic_control[0].y += outline->points[point].y + 1;
5206 cubic_control[0].x >>= 1;
5207 cubic_control[0].y >>= 1;
5209 if(point+1 > outline->contours[contour])
5210 cubic_control[3] = outline->points[first_pt];
5212 cubic_control[3] = outline->points[point+1];
5213 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
5214 cubic_control[3].x += outline->points[point].x + 1;
5215 cubic_control[3].y += outline->points[point].y + 1;
5216 cubic_control[3].x >>= 1;
5217 cubic_control[3].y >>= 1;
5220 /* r1 = 1/3 p0 + 2/3 p1
5221 r2 = 1/3 p2 + 2/3 p1 */
5222 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
5223 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
5224 cubic_control[2] = cubic_control[1];
5225 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
5226 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
5227 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
5228 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
5230 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
5231 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
5232 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
5237 } while(point <= outline->contours[contour] &&
5238 (outline->tags[point] & FT_Curve_Tag_On) ==
5239 (outline->tags[point-1] & FT_Curve_Tag_On));
5240 /* At the end of a contour Windows adds the start point,
5241 but only for Beziers and we've already done that.
5243 if(point <= outline->contours[contour] &&
5244 outline->tags[point] & FT_Curve_Tag_On) {
5245 /* This is the closing pt of a bezier, but we've already
5246 added it, so just inc point and carry on */
5253 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5256 pph->cb = needed - pph_start;
5262 FIXME("Unsupported format %d\n", format);
5263 LeaveCriticalSection( &freetype_cs );
5266 LeaveCriticalSection( &freetype_cs );
5270 static BOOL get_bitmap_text_metrics(GdiFont *font)
5272 FT_Face ft_face = font->ft_face;
5273 #ifdef HAVE_FREETYPE_FTWINFNT_H
5274 FT_WinFNT_HeaderRec winfnt_header;
5276 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
5277 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
5278 font->potm->otmSize = size;
5280 #define TM font->potm->otmTextMetrics
5281 #ifdef HAVE_FREETYPE_FTWINFNT_H
5282 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
5284 TM.tmHeight = winfnt_header.pixel_height;
5285 TM.tmAscent = winfnt_header.ascent;
5286 TM.tmDescent = TM.tmHeight - TM.tmAscent;
5287 TM.tmInternalLeading = winfnt_header.internal_leading;
5288 TM.tmExternalLeading = winfnt_header.external_leading;
5289 TM.tmAveCharWidth = winfnt_header.avg_width;
5290 TM.tmMaxCharWidth = winfnt_header.max_width;
5291 TM.tmWeight = winfnt_header.weight;
5293 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
5294 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
5295 TM.tmFirstChar = winfnt_header.first_char;
5296 TM.tmLastChar = winfnt_header.last_char;
5297 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
5298 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
5299 TM.tmItalic = winfnt_header.italic;
5300 TM.tmUnderlined = font->underline;
5301 TM.tmStruckOut = font->strikeout;
5302 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
5303 TM.tmCharSet = winfnt_header.charset;
5308 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
5309 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
5310 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5311 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
5312 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
5313 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
5314 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
5315 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
5317 TM.tmDigitizedAspectX = 96; /* FIXME */
5318 TM.tmDigitizedAspectY = 96; /* FIXME */
5320 TM.tmLastChar = 255;
5321 TM.tmDefaultChar = 32;
5322 TM.tmBreakChar = 32;
5323 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
5324 TM.tmUnderlined = font->underline;
5325 TM.tmStruckOut = font->strikeout;
5326 /* NB inverted meaning of TMPF_FIXED_PITCH */
5327 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
5328 TM.tmCharSet = font->charset;
5336 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
5338 double scale_x, scale_y;
5342 scale_x = (double)font->aveWidth;
5343 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5346 scale_x = font->scale_y;
5348 scale_x *= fabs(font->font_desc.matrix.eM11);
5349 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5351 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5352 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5354 SCALE_Y(ptm->tmHeight);
5355 SCALE_Y(ptm->tmAscent);
5356 SCALE_Y(ptm->tmDescent);
5357 SCALE_Y(ptm->tmInternalLeading);
5358 SCALE_Y(ptm->tmExternalLeading);
5359 SCALE_Y(ptm->tmOverhang);
5361 SCALE_X(ptm->tmAveCharWidth);
5362 SCALE_X(ptm->tmMaxCharWidth);
5368 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
5370 double scale_x, scale_y;
5374 scale_x = (double)font->aveWidth;
5375 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5378 scale_x = font->scale_y;
5380 scale_x *= fabs(font->font_desc.matrix.eM11);
5381 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5383 scale_font_metrics(font, &potm->otmTextMetrics);
5385 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5386 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5388 SCALE_Y(potm->otmAscent);
5389 SCALE_Y(potm->otmDescent);
5390 SCALE_Y(potm->otmLineGap);
5391 SCALE_Y(potm->otmsCapEmHeight);
5392 SCALE_Y(potm->otmsXHeight);
5393 SCALE_Y(potm->otmrcFontBox.top);
5394 SCALE_Y(potm->otmrcFontBox.bottom);
5395 SCALE_X(potm->otmrcFontBox.left);
5396 SCALE_X(potm->otmrcFontBox.right);
5397 SCALE_Y(potm->otmMacAscent);
5398 SCALE_Y(potm->otmMacDescent);
5399 SCALE_Y(potm->otmMacLineGap);
5400 SCALE_X(potm->otmptSubscriptSize.x);
5401 SCALE_Y(potm->otmptSubscriptSize.y);
5402 SCALE_X(potm->otmptSubscriptOffset.x);
5403 SCALE_Y(potm->otmptSubscriptOffset.y);
5404 SCALE_X(potm->otmptSuperscriptSize.x);
5405 SCALE_Y(potm->otmptSuperscriptSize.y);
5406 SCALE_X(potm->otmptSuperscriptOffset.x);
5407 SCALE_Y(potm->otmptSuperscriptOffset.y);
5408 SCALE_Y(potm->otmsStrikeoutSize);
5409 SCALE_Y(potm->otmsStrikeoutPosition);
5410 SCALE_Y(potm->otmsUnderscoreSize);
5411 SCALE_Y(potm->otmsUnderscorePosition);
5417 /*************************************************************
5418 * WineEngGetTextMetrics
5421 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
5424 EnterCriticalSection( &freetype_cs );
5426 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
5427 if(!get_bitmap_text_metrics(font))
5429 LeaveCriticalSection( &freetype_cs );
5435 LeaveCriticalSection( &freetype_cs );
5438 *ptm = font->potm->otmTextMetrics;
5439 scale_font_metrics(font, ptm);
5440 LeaveCriticalSection( &freetype_cs );
5444 static BOOL face_has_symbol_charmap(FT_Face ft_face)
5448 for(i = 0; i < ft_face->num_charmaps; i++)
5450 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
5456 /*************************************************************
5457 * WineEngGetOutlineTextMetrics
5460 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
5461 OUTLINETEXTMETRICW *potm)
5463 FT_Face ft_face = font->ft_face;
5464 UINT needed, lenfam, lensty, ret;
5466 TT_HoriHeader *pHori;
5467 TT_Postscript *pPost;
5468 FT_Fixed x_scale, y_scale;
5469 WCHAR *family_nameW, *style_nameW;
5470 static const WCHAR spaceW[] = {' ', '\0'};
5472 INT ascent, descent;
5474 TRACE("font=%p\n", font);
5476 if(!FT_IS_SCALABLE(ft_face))
5480 EnterCriticalSection( &freetype_cs );
5483 if(cbSize >= font->potm->otmSize)
5485 memcpy(potm, font->potm, font->potm->otmSize);
5486 scale_outline_font_metrics(font, potm);
5488 LeaveCriticalSection( &freetype_cs );
5489 return font->potm->otmSize;
5493 needed = sizeof(*potm);
5495 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
5496 family_nameW = strdupW(font->name);
5498 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
5500 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
5501 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
5502 style_nameW, lensty/sizeof(WCHAR));
5504 /* These names should be read from the TT name table */
5506 /* length of otmpFamilyName */
5509 /* length of otmpFaceName */
5510 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
5511 needed += lenfam; /* just the family name */
5513 needed += lenfam + lensty; /* family + " " + style */
5516 /* length of otmpStyleName */
5519 /* length of otmpFullName */
5520 needed += lenfam + lensty;
5523 x_scale = ft_face->size->metrics.x_scale;
5524 y_scale = ft_face->size->metrics.y_scale;
5526 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
5528 FIXME("Can't find OS/2 table - not TT font?\n");
5533 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
5535 FIXME("Can't find HHEA table - not TT font?\n");
5540 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
5542 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",
5543 pOS2->usWinAscent, pOS2->usWinDescent,
5544 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
5545 ft_face->ascender, ft_face->descender, ft_face->height,
5546 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
5547 ft_face->bbox.yMax, ft_face->bbox.yMin);
5549 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
5550 font->potm->otmSize = needed;
5552 #define TM font->potm->otmTextMetrics
5554 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
5555 ascent = pHori->Ascender;
5556 descent = -pHori->Descender;
5558 ascent = pOS2->usWinAscent;
5559 descent = pOS2->usWinDescent;
5563 TM.tmAscent = font->yMax;
5564 TM.tmDescent = -font->yMin;
5565 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
5567 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
5568 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
5569 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
5570 - ft_face->units_per_EM, y_scale) + 32) >> 6;
5573 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5576 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
5578 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
5579 ((ascent + descent) -
5580 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
5582 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
5583 if (TM.tmAveCharWidth == 0) {
5584 TM.tmAveCharWidth = 1;
5586 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
5587 TM.tmWeight = (font->fake_bold || (ft_face->style_flags & FT_STYLE_FLAG_BOLD)) ? FW_BOLD : FW_REGULAR;
5589 TM.tmDigitizedAspectX = 300;
5590 TM.tmDigitizedAspectY = 300;
5591 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
5592 * symbol range to 0 - f0ff
5595 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
5600 case 1257: /* Baltic */
5601 TM.tmLastChar = 0xf8fd;
5604 TM.tmLastChar = 0xf0ff;
5606 TM.tmBreakChar = 0x20;
5607 TM.tmDefaultChar = 0x1f;
5611 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
5612 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
5614 if(pOS2->usFirstCharIndex <= 1)
5615 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
5616 else if (pOS2->usFirstCharIndex > 0xff)
5617 TM.tmBreakChar = 0x20;
5619 TM.tmBreakChar = pOS2->usFirstCharIndex;
5620 TM.tmDefaultChar = TM.tmBreakChar - 1;
5622 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
5623 TM.tmUnderlined = font->underline;
5624 TM.tmStruckOut = font->strikeout;
5626 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
5627 if(!FT_IS_FIXED_WIDTH(ft_face) &&
5628 (pOS2->version == 0xFFFFU ||
5629 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
5630 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
5632 TM.tmPitchAndFamily = 0;
5634 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
5636 case PAN_FAMILY_SCRIPT:
5637 TM.tmPitchAndFamily |= FF_SCRIPT;
5640 case PAN_FAMILY_DECORATIVE:
5641 TM.tmPitchAndFamily |= FF_DECORATIVE;
5646 case PAN_FAMILY_TEXT_DISPLAY:
5647 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
5648 /* which is clearly not what the panose spec says. */
5650 if(TM.tmPitchAndFamily == 0 || /* fixed */
5651 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
5652 TM.tmPitchAndFamily = FF_MODERN;
5655 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
5660 TM.tmPitchAndFamily |= FF_DONTCARE;
5663 case PAN_SERIF_COVE:
5664 case PAN_SERIF_OBTUSE_COVE:
5665 case PAN_SERIF_SQUARE_COVE:
5666 case PAN_SERIF_OBTUSE_SQUARE_COVE:
5667 case PAN_SERIF_SQUARE:
5668 case PAN_SERIF_THIN:
5669 case PAN_SERIF_BONE:
5670 case PAN_SERIF_EXAGGERATED:
5671 case PAN_SERIF_TRIANGLE:
5672 TM.tmPitchAndFamily |= FF_ROMAN;
5675 case PAN_SERIF_NORMAL_SANS:
5676 case PAN_SERIF_OBTUSE_SANS:
5677 case PAN_SERIF_PERP_SANS:
5678 case PAN_SERIF_FLARED:
5679 case PAN_SERIF_ROUNDED:
5680 TM.tmPitchAndFamily |= FF_SWISS;
5687 if(FT_IS_SCALABLE(ft_face))
5688 TM.tmPitchAndFamily |= TMPF_VECTOR;
5690 if(FT_IS_SFNT(ft_face))
5692 if (font->ntmFlags & NTM_PS_OPENTYPE)
5693 TM.tmPitchAndFamily |= TMPF_DEVICE;
5695 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
5698 TM.tmCharSet = font->charset;
5700 font->potm->otmFiller = 0;
5701 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
5702 font->potm->otmfsSelection = pOS2->fsSelection;
5703 font->potm->otmfsType = pOS2->fsType;
5704 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
5705 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
5706 font->potm->otmItalicAngle = 0; /* POST table */
5707 font->potm->otmEMSquare = ft_face->units_per_EM;
5708 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
5709 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
5710 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
5711 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
5712 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
5713 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
5714 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
5715 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
5716 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
5717 font->potm->otmMacAscent = TM.tmAscent;
5718 font->potm->otmMacDescent = -TM.tmDescent;
5719 font->potm->otmMacLineGap = font->potm->otmLineGap;
5720 font->potm->otmusMinimumPPEM = 0; /* TT Header */
5721 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
5722 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
5723 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
5724 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
5725 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
5726 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
5727 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
5728 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
5729 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
5730 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
5732 font->potm->otmsUnderscoreSize = 0;
5733 font->potm->otmsUnderscorePosition = 0;
5735 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
5736 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
5740 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
5741 cp = (char*)font->potm + sizeof(*font->potm);
5742 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
5743 strcpyW((WCHAR*)cp, family_nameW);
5745 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
5746 strcpyW((WCHAR*)cp, style_nameW);
5748 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
5749 strcpyW((WCHAR*)cp, family_nameW);
5750 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
5751 strcatW((WCHAR*)cp, spaceW);
5752 strcatW((WCHAR*)cp, style_nameW);
5753 cp += lenfam + lensty;
5756 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
5757 strcpyW((WCHAR*)cp, family_nameW);
5758 strcatW((WCHAR*)cp, spaceW);
5759 strcatW((WCHAR*)cp, style_nameW);
5762 if(potm && needed <= cbSize)
5764 memcpy(potm, font->potm, font->potm->otmSize);
5765 scale_outline_font_metrics(font, potm);
5769 HeapFree(GetProcessHeap(), 0, style_nameW);
5770 HeapFree(GetProcessHeap(), 0, family_nameW);
5772 LeaveCriticalSection( &freetype_cs );
5776 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
5778 HFONTLIST *hfontlist;
5779 child->font = alloc_font();
5780 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
5781 if(!child->font->ft_face)
5783 free_font(child->font);
5788 child->font->font_desc = font->font_desc;
5789 child->font->ntmFlags = child->face->ntmFlags;
5790 child->font->orientation = font->orientation;
5791 child->font->scale_y = font->scale_y;
5792 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
5793 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
5794 list_add_head(&child->font->hfontlist, &hfontlist->entry);
5795 child->font->base_font = font;
5796 list_add_head(&child_font_list, &child->font->entry);
5797 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
5801 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
5804 CHILD_FONT *child_font;
5807 font = font->base_font;
5809 *linked_font = font;
5811 if((*glyph = get_glyph_index(font, c)))
5814 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
5816 if(!child_font->font)
5817 if(!load_child_font(font, child_font))
5820 if(!child_font->font->ft_face)
5822 g = get_glyph_index(child_font->font, c);
5826 *linked_font = child_font->font;
5833 /*************************************************************
5834 * WineEngGetCharWidth
5837 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5840 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5843 FT_UInt glyph_index;
5844 GdiFont *linked_font;
5846 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5849 EnterCriticalSection( &freetype_cs );
5850 for(c = firstChar; c <= lastChar; c++) {
5851 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5852 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5853 &gm, 0, NULL, &identity);
5854 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
5856 LeaveCriticalSection( &freetype_cs );
5860 /*************************************************************
5861 * WineEngGetCharABCWidths
5864 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5867 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5870 FT_UInt glyph_index;
5871 GdiFont *linked_font;
5873 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
5875 if(!FT_IS_SCALABLE(font->ft_face))
5879 EnterCriticalSection( &freetype_cs );
5881 for(c = firstChar; c <= lastChar; c++) {
5882 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
5883 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5884 &gm, 0, NULL, &identity);
5885 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
5886 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
5887 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
5888 FONT_GM(linked_font,glyph_index)->bbx;
5890 LeaveCriticalSection( &freetype_cs );
5894 /*************************************************************
5895 * WineEngGetCharABCWidthsI
5898 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
5901 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5904 FT_UInt glyph_index;
5905 GdiFont *linked_font;
5907 if(!FT_HAS_HORIZONTAL(font->ft_face))
5911 EnterCriticalSection( &freetype_cs );
5913 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
5915 for(c = firstChar; c < firstChar+count; c++) {
5916 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
5917 &gm, 0, NULL, &identity);
5918 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
5919 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
5920 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
5921 - FONT_GM(linked_font,c)->bbx;
5924 for(c = 0; c < count; c++) {
5925 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
5926 &gm, 0, NULL, &identity);
5927 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
5928 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
5929 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
5930 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
5933 LeaveCriticalSection( &freetype_cs );
5937 /*************************************************************
5938 * WineEngGetTextExtentExPoint
5941 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
5942 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
5944 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5949 FT_UInt glyph_index;
5950 GdiFont *linked_font;
5952 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
5956 EnterCriticalSection( &freetype_cs );
5959 WineEngGetTextMetrics(font, &tm);
5960 size->cy = tm.tmHeight;
5962 for(idx = 0; idx < count; idx++) {
5963 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
5964 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
5965 &gm, 0, NULL, &identity);
5966 size->cx += FONT_GM(linked_font,glyph_index)->adv;
5968 if (! pnfit || ext <= max_ext) {
5978 LeaveCriticalSection( &freetype_cs );
5979 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
5983 /*************************************************************
5984 * WineEngGetTextExtentExPointI
5987 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
5988 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
5990 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
5996 TRACE("%p, %p, %d, %d, %p\n", font, indices, count, max_ext, size);
5999 EnterCriticalSection( &freetype_cs );
6002 WineEngGetTextMetrics(font, &tm);
6003 size->cy = tm.tmHeight;
6005 for(idx = 0; idx < count; idx++) {
6006 WineEngGetGlyphOutline(font, indices[idx],
6007 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
6009 size->cx += FONT_GM(font,indices[idx])->adv;
6011 if (! pnfit || ext <= max_ext) {
6021 LeaveCriticalSection( &freetype_cs );
6022 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6026 /*************************************************************
6027 * WineEngGetFontData
6030 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
6033 FT_Face ft_face = font->ft_face;
6037 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6038 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
6039 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
6041 if(!FT_IS_SFNT(ft_face))
6049 if(table) { /* MS tags differ in endianness from FT ones */
6050 table = table >> 24 | table << 24 |
6051 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
6054 /* make sure value of len is the value freetype says it needs */
6057 FT_ULong needed = 0;
6058 err = load_sfnt_table(ft_face, table, offset, NULL, &needed);
6059 if( !err && needed < len) len = needed;
6061 err = load_sfnt_table(ft_face, table, offset, buf, &len);
6064 TRACE("Can't find table %c%c%c%c\n",
6065 /* bytes were reversed */
6066 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
6067 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
6073 /*************************************************************
6074 * WineEngGetTextFace
6077 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
6079 INT n = strlenW(font->name) + 1;
6081 lstrcpynW(str, font->name, count);
6082 return min(count, n);
6087 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
6089 if (fs) *fs = font->fs;
6090 return font->charset;
6093 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6095 GdiFont *font = dc->gdiFont, *linked_font;
6096 struct list *first_hfont;
6100 EnterCriticalSection( &freetype_cs );
6101 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
6102 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
6103 if(font == linked_font)
6104 *new_hfont = dc->hFont;
6107 first_hfont = list_head(&linked_font->hfontlist);
6108 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
6110 LeaveCriticalSection( &freetype_cs );
6114 /* Retrieve a list of supported Unicode ranges for a given font.
6115 * Can be called with NULL gs to calculate the buffer size. Returns
6116 * the number of ranges found.
6118 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
6120 DWORD num_ranges = 0;
6122 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
6125 FT_ULong char_code, char_code_prev;
6128 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
6130 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6131 face->num_glyphs, glyph_code, char_code);
6133 if (!glyph_code) return 0;
6137 gs->ranges[0].wcLow = (USHORT)char_code;
6138 gs->ranges[0].cGlyphs = 0;
6139 gs->cGlyphsSupported = 0;
6145 if (char_code < char_code_prev)
6147 ERR("expected increasing char code from FT_Get_Next_Char\n");
6150 if (char_code - char_code_prev > 1)
6155 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
6156 gs->ranges[num_ranges - 1].cGlyphs = 1;
6157 gs->cGlyphsSupported++;
6162 gs->ranges[num_ranges - 1].cGlyphs++;
6163 gs->cGlyphsSupported++;
6165 char_code_prev = char_code;
6166 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
6170 FIXME("encoding %u not supported\n", face->charmap->encoding);
6175 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
6178 DWORD num_ranges = get_font_unicode_ranges(font->ft_face, glyphset);
6180 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
6183 glyphset->cbThis = size;
6184 glyphset->cRanges = num_ranges;
6189 /*************************************************************
6192 BOOL WineEngFontIsLinked(GdiFont *font)
6196 EnterCriticalSection( &freetype_cs );
6197 ret = !list_empty(&font->child_fonts);
6198 LeaveCriticalSection( &freetype_cs );
6202 static BOOL is_hinting_enabled(void)
6204 /* Use the >= 2.2.0 function if available */
6205 if(pFT_Get_TrueType_Engine_Type)
6207 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
6208 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
6210 #ifdef FT_DRIVER_HAS_HINTER
6215 /* otherwise if we've been compiled with < 2.2.0 headers
6216 use the internal macro */
6217 mod = pFT_Get_Module(library, "truetype");
6218 if(mod && FT_DRIVER_HAS_HINTER(mod))
6226 static BOOL is_subpixel_rendering_enabled( void )
6228 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6229 return pFT_Library_SetLcdFilter &&
6230 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
6236 /*************************************************************************
6237 * GetRasterizerCaps (GDI32.@)
6239 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6241 static int hinting = -1;
6242 static int subpixel = -1;
6246 hinting = is_hinting_enabled();
6247 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
6250 if ( subpixel == -1 )
6252 subpixel = is_subpixel_rendering_enabled();
6253 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
6256 lprs->nSize = sizeof(RASTERIZER_STATUS);
6257 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
6259 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
6260 lprs->nLanguageID = 0;
6264 /*************************************************************
6265 * WineEngRealizationInfo
6267 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
6269 FIXME("(%p, %p): stub!\n", font, info);
6272 if(FT_IS_SCALABLE(font->ft_face))
6275 info->cache_num = font->cache_num;
6276 info->unknown2 = -1;
6280 /*************************************************************************
6281 * Kerning support for TrueType fonts
6283 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
6285 struct TT_kern_table
6291 struct TT_kern_subtable
6300 USHORT horizontal : 1;
6302 USHORT cross_stream: 1;
6303 USHORT override : 1;
6304 USHORT reserved1 : 4;
6310 struct TT_format0_kern_subtable
6314 USHORT entrySelector;
6325 static DWORD parse_format0_kern_subtable(GdiFont *font,
6326 const struct TT_format0_kern_subtable *tt_f0_ks,
6327 const USHORT *glyph_to_char,
6328 KERNINGPAIR *kern_pair, DWORD cPairs)
6331 const struct TT_kern_pair *tt_kern_pair;
6333 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
6335 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
6337 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
6338 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
6339 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
6341 if (!kern_pair || !cPairs)
6344 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
6346 nPairs = min(nPairs, cPairs);
6348 for (i = 0; i < nPairs; i++)
6350 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
6351 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
6352 /* this algorithm appears to better match what Windows does */
6353 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
6354 if (kern_pair->iKernAmount < 0)
6356 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
6357 kern_pair->iKernAmount -= font->ppem;
6359 else if (kern_pair->iKernAmount > 0)
6361 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
6362 kern_pair->iKernAmount += font->ppem;
6364 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
6366 TRACE("left %u right %u value %d\n",
6367 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
6371 TRACE("copied %u entries\n", nPairs);
6375 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6379 const struct TT_kern_table *tt_kern_table;
6380 const struct TT_kern_subtable *tt_kern_subtable;
6382 USHORT *glyph_to_char;
6385 EnterCriticalSection( &freetype_cs );
6386 if (font->total_kern_pairs != (DWORD)-1)
6388 if (cPairs && kern_pair)
6390 cPairs = min(cPairs, font->total_kern_pairs);
6391 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6392 LeaveCriticalSection( &freetype_cs );
6395 LeaveCriticalSection( &freetype_cs );
6396 return font->total_kern_pairs;
6399 font->total_kern_pairs = 0;
6401 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
6403 if (length == GDI_ERROR)
6405 TRACE("no kerning data in the font\n");
6406 LeaveCriticalSection( &freetype_cs );
6410 buf = HeapAlloc(GetProcessHeap(), 0, length);
6413 WARN("Out of memory\n");
6414 LeaveCriticalSection( &freetype_cs );
6418 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
6420 /* build a glyph index to char code map */
6421 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
6424 WARN("Out of memory allocating a glyph index to char code map\n");
6425 HeapFree(GetProcessHeap(), 0, buf);
6426 LeaveCriticalSection( &freetype_cs );
6430 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
6436 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
6438 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
6439 font->ft_face->num_glyphs, glyph_code, char_code);
6443 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
6445 /* FIXME: This doesn't match what Windows does: it does some fancy
6446 * things with duplicate glyph index to char code mappings, while
6447 * we just avoid overriding existing entries.
6449 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
6450 glyph_to_char[glyph_code] = (USHORT)char_code;
6452 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
6459 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
6460 for (n = 0; n <= 65535; n++)
6461 glyph_to_char[n] = (USHORT)n;
6464 tt_kern_table = buf;
6465 nTables = GET_BE_WORD(tt_kern_table->nTables);
6466 TRACE("version %u, nTables %u\n",
6467 GET_BE_WORD(tt_kern_table->version), nTables);
6469 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
6471 for (i = 0; i < nTables; i++)
6473 struct TT_kern_subtable tt_kern_subtable_copy;
6475 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
6476 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
6477 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
6479 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
6480 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
6481 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
6483 /* According to the TrueType specification this is the only format
6484 * that will be properly interpreted by Windows and OS/2
6486 if (tt_kern_subtable_copy.coverage.bits.format == 0)
6488 DWORD new_chunk, old_total = font->total_kern_pairs;
6490 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6491 glyph_to_char, NULL, 0);
6492 font->total_kern_pairs += new_chunk;
6494 if (!font->kern_pairs)
6495 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
6496 font->total_kern_pairs * sizeof(*font->kern_pairs));
6498 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
6499 font->total_kern_pairs * sizeof(*font->kern_pairs));
6501 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
6502 glyph_to_char, font->kern_pairs + old_total, new_chunk);
6505 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
6507 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
6510 HeapFree(GetProcessHeap(), 0, glyph_to_char);
6511 HeapFree(GetProcessHeap(), 0, buf);
6513 if (cPairs && kern_pair)
6515 cPairs = min(cPairs, font->total_kern_pairs);
6516 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
6517 LeaveCriticalSection( &freetype_cs );
6520 LeaveCriticalSection( &freetype_cs );
6521 return font->total_kern_pairs;
6524 #else /* HAVE_FREETYPE */
6526 /*************************************************************************/
6528 BOOL WineEngInit(void)
6532 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
6536 BOOL WineEngDestroyFontInstance(HFONT hfont)
6541 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
6546 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
6547 LPWORD pgi, DWORD flags)
6552 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
6553 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
6556 ERR("called but we don't have FreeType\n");
6560 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
6562 ERR("called but we don't have FreeType\n");
6566 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
6567 OUTLINETEXTMETRICW *potm)
6569 ERR("called but we don't have FreeType\n");
6573 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
6576 ERR("called but we don't have FreeType\n");
6580 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
6583 ERR("called but we don't have FreeType\n");
6587 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
6590 ERR("called but we don't have FreeType\n");
6594 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
6595 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6597 ERR("called but we don't have FreeType\n");
6601 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
6602 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
6604 ERR("called but we don't have FreeType\n");
6608 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
6611 ERR("called but we don't have FreeType\n");
6615 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
6617 ERR("called but we don't have FreeType\n");
6621 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6627 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
6633 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
6639 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
6642 return DEFAULT_CHARSET;
6645 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6650 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
6652 FIXME("(%p, %p): stub\n", font, glyphset);
6656 BOOL WineEngFontIsLinked(GdiFont *font)
6661 /*************************************************************************
6662 * GetRasterizerCaps (GDI32.@)
6664 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6666 lprs->nSize = sizeof(RASTERIZER_STATUS);
6668 lprs->nLanguageID = 0;
6672 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
6674 ERR("called but we don't have FreeType\n");
6678 BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
6680 ERR("called but we don't have FreeType\n");
6684 #endif /* HAVE_FREETYPE */