2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
5 * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
7 * This file contains the WineEng* functions.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "wine/port.h"
29 #ifdef HAVE_SYS_STAT_H
30 # include <sys/stat.h>
32 #ifdef HAVE_SYS_MMAN_H
33 # include <sys/mman.h>
42 #ifdef HAVE_CARBON_CARBON_H
43 #define LoadResource __carbon_LoadResource
44 #define CompareString __carbon_CompareString
45 #define GetCurrentThread __carbon_GetCurrentThread
46 #define GetCurrentProcess __carbon_GetCurrentProcess
47 #define AnimatePalette __carbon_AnimatePalette
48 #define EqualRgn __carbon_EqualRgn
49 #define FillRgn __carbon_FillRgn
50 #define FrameRgn __carbon_FrameRgn
51 #define GetPixel __carbon_GetPixel
52 #define InvertRgn __carbon_InvertRgn
53 #define LineTo __carbon_LineTo
54 #define OffsetRgn __carbon_OffsetRgn
55 #define PaintRgn __carbon_PaintRgn
56 #define Polygon __carbon_Polygon
57 #define ResizePalette __carbon_ResizePalette
58 #define SetRectRgn __carbon_SetRectRgn
59 #include <Carbon/Carbon.h>
62 #undef GetCurrentThread
65 #undef GetCurrentProcess
78 #endif /* HAVE_CARBON_CARBON_H */
86 #include "gdi_private.h"
87 #include "wine/library.h"
88 #include "wine/unicode.h"
89 #include "wine/debug.h"
90 #include "wine/list.h"
94 WINE_DEFAULT_DEBUG_CHANNEL(font);
98 #ifdef HAVE_FT2BUILD_H
101 #ifdef HAVE_FREETYPE_FREETYPE_H
102 #include <freetype/freetype.h>
104 #ifdef HAVE_FREETYPE_FTGLYPH_H
105 #include <freetype/ftglyph.h>
107 #ifdef HAVE_FREETYPE_TTTABLES_H
108 #include <freetype/tttables.h>
110 #ifdef HAVE_FREETYPE_FTTYPES_H
111 #include <freetype/fttypes.h>
113 #ifdef HAVE_FREETYPE_FTSNAMES_H
114 #include <freetype/ftsnames.h>
116 #ifdef HAVE_FREETYPE_TTNAMEID_H
117 #include <freetype/ttnameid.h>
119 #ifdef HAVE_FREETYPE_FTOUTLN_H
120 #include <freetype/ftoutln.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_Done_Face);
158 MAKE_FUNCPTR(FT_Get_Char_Index);
159 MAKE_FUNCPTR(FT_Get_First_Char);
160 MAKE_FUNCPTR(FT_Get_Module);
161 MAKE_FUNCPTR(FT_Get_Next_Char);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
163 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
164 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
165 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
166 MAKE_FUNCPTR(FT_Init_FreeType);
167 MAKE_FUNCPTR(FT_Library_Version);
168 MAKE_FUNCPTR(FT_Load_Glyph);
169 MAKE_FUNCPTR(FT_Load_Sfnt_Table);
170 MAKE_FUNCPTR(FT_Matrix_Multiply);
171 #ifdef FT_MULFIX_INLINED
172 #define pFT_MulFix FT_MULFIX_INLINED
174 MAKE_FUNCPTR(FT_MulFix);
176 MAKE_FUNCPTR(FT_New_Face);
177 MAKE_FUNCPTR(FT_New_Memory_Face);
178 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
179 MAKE_FUNCPTR(FT_Outline_Transform);
180 MAKE_FUNCPTR(FT_Outline_Translate);
181 MAKE_FUNCPTR(FT_Render_Glyph);
182 MAKE_FUNCPTR(FT_Select_Charmap);
183 MAKE_FUNCPTR(FT_Set_Charmap);
184 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
185 MAKE_FUNCPTR(FT_Vector_Transform);
186 MAKE_FUNCPTR(FT_Vector_Unit);
187 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
188 #ifdef HAVE_FREETYPE_FTLCDFIL_H
189 static FT_Error (*pFT_Library_SetLcdFilter)(FT_Library, FT_LcdFilter);
192 #ifdef SONAME_LIBFONTCONFIG
193 #include <fontconfig/fontconfig.h>
194 MAKE_FUNCPTR(FcConfigGetCurrent);
195 MAKE_FUNCPTR(FcFontList);
196 MAKE_FUNCPTR(FcFontSetDestroy);
197 MAKE_FUNCPTR(FcInit);
198 MAKE_FUNCPTR(FcObjectSetAdd);
199 MAKE_FUNCPTR(FcObjectSetCreate);
200 MAKE_FUNCPTR(FcObjectSetDestroy);
201 MAKE_FUNCPTR(FcPatternCreate);
202 MAKE_FUNCPTR(FcPatternDestroy);
203 MAKE_FUNCPTR(FcPatternGetBool);
204 MAKE_FUNCPTR(FcPatternGetString);
210 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
211 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
212 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
215 #ifndef ft_encoding_none
216 #define FT_ENCODING_NONE ft_encoding_none
218 #ifndef ft_encoding_ms_symbol
219 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
221 #ifndef ft_encoding_unicode
222 #define FT_ENCODING_UNICODE ft_encoding_unicode
224 #ifndef ft_encoding_apple_roman
225 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
228 #ifdef WORDS_BIGENDIAN
229 #define GET_BE_WORD(x) (x)
231 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
234 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
241 FT_Short internal_leading;
244 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
245 So to let this compile on older versions of FreeType we'll define the
246 new structure here. */
248 FT_Short height, width;
249 FT_Pos size, x_ppem, y_ppem;
255 NEWTEXTMETRICEXW ntm;
259 typedef struct tagFace {
265 DWORD font_data_size;
269 FT_Fixed font_version;
272 Bitmap_Size size; /* set if face is a bitmap */
273 BOOL external; /* TRUE if we should manually add this font to the registry */
274 struct tagFamily *family;
275 /* Cached data for Enum */
276 struct enum_data *cached_enum_data;
279 typedef struct tagFamily {
284 struct list *replacement;
289 INT adv; /* These three hold to widths of the unrotated chars */
307 typedef struct tagHFONTLIST {
322 struct list hfontlist;
323 OUTLINETEXTMETRICW *potm;
324 DWORD total_kern_pairs;
325 KERNINGPAIR *kern_pairs;
326 struct list child_fonts;
328 /* the following members can be accessed without locking, they are never modified after creation */
330 struct font_mapping *mapping;
345 UINT ntmCellHeight, ntmAvgWidth;
354 const WCHAR *font_name;
359 struct enum_charset_element {
362 WCHAR name[LF_FACESIZE];
365 struct enum_charset_list {
367 struct enum_charset_element element[32];
370 #define GM_BLOCK_SIZE 128
371 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
373 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
374 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
375 #define UNUSED_CACHE_SIZE 10
376 static struct list child_font_list = LIST_INIT(child_font_list);
377 static struct list system_links = LIST_INIT(system_links);
379 static struct list font_subst_list = LIST_INIT(font_subst_list);
381 static struct list font_list = LIST_INIT(font_list);
383 struct freetype_physdev
385 struct gdi_physdev dev;
389 static inline struct freetype_physdev *get_freetype_dev( PHYSDEV dev )
391 return (struct freetype_physdev *)dev;
394 static const struct gdi_dc_funcs freetype_funcs;
396 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
397 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
398 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
400 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
401 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
402 'W','i','n','d','o','w','s','\\',
403 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
404 'F','o','n','t','s','\0'};
406 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
407 'W','i','n','d','o','w','s',' ','N','T','\\',
408 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
409 'F','o','n','t','s','\0'};
411 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
412 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
413 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
414 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
416 static const WCHAR * const SystemFontValues[] = {
423 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
424 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
426 /* Interesting and well-known (frequently-assumed!) font names */
427 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
428 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 };
429 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
430 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
431 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
432 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
433 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
434 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
436 static const WCHAR arial[] = {'A','r','i','a','l',0};
437 static const WCHAR bitstream_vera_sans[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
438 static const WCHAR bitstream_vera_sans_mono[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',' ','M','o','n','o',0};
439 static const WCHAR bitstream_vera_serif[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','e','r','i','f',0};
440 static const WCHAR courier_new[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
441 static const WCHAR liberation_mono[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
442 static const WCHAR liberation_sans[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
443 static const WCHAR liberation_serif[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
444 static const WCHAR times_new_roman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
445 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
447 static const WCHAR *default_serif_list[] =
451 bitstream_vera_serif,
455 static const WCHAR *default_fixed_list[] =
459 bitstream_vera_sans_mono,
463 static const WCHAR *default_sans_list[] =
476 typedef struct tagFontSubst {
482 /* Registry font cache key and value names */
483 static const WCHAR wine_fonts_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
484 'F','o','n','t','s',0};
485 static const WCHAR wine_fonts_cache_key[] = {'C','a','c','h','e',0};
486 static const WCHAR english_name_value[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
487 static const WCHAR face_index_value[] = {'I','n','d','e','x',0};
488 static const WCHAR face_ntmflags_value[] = {'N','t','m','f','l','a','g','s',0};
489 static const WCHAR face_version_value[] = {'V','e','r','s','i','o','n',0};
490 static const WCHAR face_vertical_value[] = {'V','e','r','t','i','c','a','l',0};
491 static const WCHAR face_height_value[] = {'H','e','i','g','h','t',0};
492 static const WCHAR face_width_value[] = {'W','i','d','t','h',0};
493 static const WCHAR face_size_value[] = {'S','i','z','e',0};
494 static const WCHAR face_x_ppem_value[] = {'X','p','p','e','m',0};
495 static const WCHAR face_y_ppem_value[] = {'Y','p','p','e','m',0};
496 static const WCHAR face_internal_leading_value[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
497 static const WCHAR face_font_sig_value[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
498 static const WCHAR face_full_name_value[] = {'F','u','l','l',' ','N','a','m','e','\0'};
511 static struct list mappings_list = LIST_INIT( mappings_list );
513 static CRITICAL_SECTION freetype_cs;
514 static CRITICAL_SECTION_DEBUG critsect_debug =
517 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
518 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
520 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
522 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
524 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
525 static BOOL use_default_fallback = FALSE;
527 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
528 static BOOL get_outline_text_metrics(GdiFont *font);
529 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm);
531 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
532 'W','i','n','d','o','w','s',' ','N','T','\\',
533 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
534 'S','y','s','t','e','m','L','i','n','k',0};
536 static const WCHAR internal_system_link[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
537 'F','o','n','t','L','i','n','k','\\',
538 'S','y','s','t','e','m','L','i','n','k',0};
540 /****************************************
541 * Notes on .fon files
543 * The fonts System, FixedSys and Terminal are special. There are typically multiple
544 * versions installed for different resolutions and codepages. Windows stores which one to use
545 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
547 * FIXEDFON.FON FixedSys
549 * OEMFONT.FON Terminal
550 * LogPixels Current dpi set by the display control panel applet
551 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
552 * also has a LogPixels value that appears to mirror this)
554 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
555 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
556 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
557 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
558 * so that makes sense.
560 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
561 * to be mapped into the registry on Windows 2000 at least).
564 * ega80woa.fon=ega80850.fon
565 * ega40woa.fon=ega40850.fon
566 * cga80woa.fon=cga80850.fon
567 * cga40woa.fon=cga40850.fon
570 /* These are all structures needed for the GSUB table */
572 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
573 #define TATEGAKI_LOWER_BOUND 0x02F1
589 GSUB_ScriptRecord ScriptRecord[1];
595 } GSUB_LangSysRecord;
600 GSUB_LangSysRecord LangSysRecord[1];
604 WORD LookupOrder; /* Reserved */
605 WORD ReqFeatureIndex;
607 WORD FeatureIndex[1];
613 } GSUB_FeatureRecord;
617 GSUB_FeatureRecord FeatureRecord[1];
621 WORD FeatureParams; /* Reserved */
623 WORD LookupListIndex[1];
642 } GSUB_CoverageFormat1;
647 WORD StartCoverageIndex;
653 GSUB_RangeRecord RangeRecord[1];
654 } GSUB_CoverageFormat2;
657 WORD SubstFormat; /* = 1 */
660 } GSUB_SingleSubstFormat1;
663 WORD SubstFormat; /* = 2 */
667 }GSUB_SingleSubstFormat2;
669 #ifdef HAVE_CARBON_CARBON_H
670 static char *find_cache_dir(void)
674 static char cached_path[MAX_PATH];
675 static const char *wine = "/Wine", *fonts = "/Fonts";
677 if(*cached_path) return cached_path;
679 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
682 WARN("can't create cached data folder\n");
685 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
688 WARN("can't create cached data path\n");
692 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
694 ERR("Could not create full path\n");
698 strcat(cached_path, wine);
700 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
702 WARN("Couldn't mkdir %s\n", cached_path);
706 strcat(cached_path, fonts);
707 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
709 WARN("Couldn't mkdir %s\n", cached_path);
716 /******************************************************************
719 * Extracts individual TrueType font files from a Mac suitcase font
720 * and saves them into the user's caches directory (see
722 * Returns a NULL terminated array of filenames.
724 * We do this because they are apps that try to read ttf files
725 * themselves and they don't like Mac suitcase files.
727 static char **expand_mac_font(const char *path)
734 const char *filename;
738 unsigned int size, max_size;
741 TRACE("path %s\n", path);
743 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
746 WARN("failed to get ref\n");
750 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
753 TRACE("no data fork, so trying resource fork\n");
754 res_ref = FSOpenResFile(&ref, fsRdPerm);
757 TRACE("unable to open resource fork\n");
764 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
767 CloseResFile(res_ref);
771 out_dir = find_cache_dir();
773 filename = strrchr(path, '/');
774 if(!filename) filename = path;
777 /* output filename has the form out_dir/filename_%04x.ttf */
778 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
785 unsigned short *num_faces_ptr, num_faces, face;
788 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
790 fond = Get1IndResource(fond_res, idx);
792 TRACE("got fond resource %d\n", idx);
795 fam_rec = *(FamRec**)fond;
796 num_faces_ptr = (unsigned short *)(fam_rec + 1);
797 num_faces = GET_BE_WORD(*num_faces_ptr);
799 assoc = (AsscEntry*)(num_faces_ptr + 1);
800 TRACE("num faces %04x\n", num_faces);
801 for(face = 0; face < num_faces; face++, assoc++)
804 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
805 unsigned short size, font_id;
808 size = GET_BE_WORD(assoc->fontSize);
809 font_id = GET_BE_WORD(assoc->fontID);
812 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
816 TRACE("trying to load sfnt id %04x\n", font_id);
817 sfnt = GetResource(sfnt_res, font_id);
820 TRACE("can't get sfnt resource %04x\n", font_id);
824 output = HeapAlloc(GetProcessHeap(), 0, output_len);
829 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
831 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
832 if(fd != -1 || errno == EEXIST)
836 unsigned char *sfnt_data;
839 sfnt_data = *(unsigned char**)sfnt;
840 write(fd, sfnt_data, GetHandleSize(sfnt));
844 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
847 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
849 ret.array[ret.size++] = output;
853 WARN("unable to create %s\n", output);
854 HeapFree(GetProcessHeap(), 0, output);
857 ReleaseResource(sfnt);
860 ReleaseResource(fond);
863 CloseResFile(res_ref);
868 #endif /* HAVE_CARBON_CARBON_H */
870 static inline BOOL is_win9x(void)
872 return GetVersion() & 0x80000000;
875 This function builds an FT_Fixed from a double. It fails if the absolute
876 value of the float number is greater than 32768.
878 static inline FT_Fixed FT_FixedFromFloat(double f)
884 This function builds an FT_Fixed from a FIXED. It simply put f.value
885 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
887 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
889 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
893 static const struct list *get_face_list_from_family(const Family *family)
895 if (!list_empty(&family->faces))
896 return &family->faces;
898 return family->replacement;
901 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
906 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
907 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
909 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
910 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
912 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
914 const struct list *face_list;
915 if(face_name && strcmpiW(face_name, family->FamilyName))
917 face_list = get_face_list_from_family(family);
918 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
922 file = strrchr(face->file, '/');
927 if(!strcasecmp(file, file_nameA))
929 HeapFree(GetProcessHeap(), 0, file_nameA);
934 HeapFree(GetProcessHeap(), 0, file_nameA);
938 static Family *find_family_from_name(const WCHAR *name)
942 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
944 if(!strcmpiW(family->FamilyName, name))
951 static Family *find_family_from_any_name(const WCHAR *name)
955 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
957 if(!strcmpiW(family->FamilyName, name))
959 if(family->EnglishName && !strcmpiW(family->EnglishName, name))
966 static void DumpSubstList(void)
970 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
972 if(psub->from.charset != -1 || psub->to.charset != -1)
973 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
974 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
976 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
977 debugstr_w(psub->to.name));
982 static LPWSTR strdupW(LPCWSTR p)
985 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
986 ret = HeapAlloc(GetProcessHeap(), 0, len);
991 static LPSTR strdupA(LPCSTR p)
994 DWORD len = (strlen(p) + 1);
995 ret = HeapAlloc(GetProcessHeap(), 0, len);
1000 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
1005 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
1007 if(!strcmpiW(element->from.name, from_name) &&
1008 (element->from.charset == from_charset ||
1009 element->from.charset == -1))
1016 #define ADD_FONT_SUBST_FORCE 1
1018 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
1020 FontSubst *from_exist, *to_exist;
1022 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
1024 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
1026 list_remove(&from_exist->entry);
1027 HeapFree(GetProcessHeap(), 0, from_exist->from.name);
1028 HeapFree(GetProcessHeap(), 0, from_exist->to.name);
1029 HeapFree(GetProcessHeap(), 0, from_exist);
1035 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
1039 HeapFree(GetProcessHeap(), 0, subst->to.name);
1040 subst->to.name = strdupW(to_exist->to.name);
1043 list_add_tail(subst_list, &subst->entry);
1048 HeapFree(GetProcessHeap(), 0, subst->from.name);
1049 HeapFree(GetProcessHeap(), 0, subst->to.name);
1050 HeapFree(GetProcessHeap(), 0, subst);
1054 static WCHAR *towstr(UINT cp, const char *str)
1059 len = MultiByteToWideChar(cp, 0, str, -1, NULL, 0);
1060 wstr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1061 MultiByteToWideChar(cp, 0, str, -1, wstr, len);
1065 static void split_subst_info(NameCs *nc, LPSTR str)
1067 CHAR *p = strrchr(str, ',');
1071 nc->charset = strtol(p+1, NULL, 10);
1074 nc->name = towstr(CP_ACP, str);
1077 static void LoadSubstList(void)
1081 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1085 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1086 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1087 &hkey) == ERROR_SUCCESS) {
1089 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1090 &valuelen, &datalen, NULL, NULL);
1092 valuelen++; /* returned value doesn't include room for '\0' */
1093 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1094 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1098 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1099 &dlen) == ERROR_SUCCESS) {
1100 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1102 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1103 split_subst_info(&psub->from, value);
1104 split_subst_info(&psub->to, data);
1106 /* Win 2000 doesn't allow mapping between different charsets
1107 or mapping of DEFAULT_CHARSET */
1108 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1109 psub->to.charset == DEFAULT_CHARSET) {
1110 HeapFree(GetProcessHeap(), 0, psub->to.name);
1111 HeapFree(GetProcessHeap(), 0, psub->from.name);
1112 HeapFree(GetProcessHeap(), 0, psub);
1114 add_font_subst(&font_subst_list, psub, 0);
1116 /* reset dlen and vlen */
1120 HeapFree(GetProcessHeap(), 0, data);
1121 HeapFree(GetProcessHeap(), 0, value);
1127 /*****************************************************************
1128 * get_name_table_entry
1130 * Supply the platform, encoding, language and name ids in req
1131 * and if the name exists the function will fill in the string
1132 * and string_len members. The string is owned by FreeType so
1133 * don't free it. Returns TRUE if the name is found else FALSE.
1135 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1138 FT_UInt num_names, name_index;
1140 if(FT_IS_SFNT(ft_face))
1142 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1144 for(name_index = 0; name_index < num_names; name_index++)
1146 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1148 if((name.platform_id == req->platform_id) &&
1149 ((name.encoding_id == TT_MS_ID_UNICODE_CS) || (name.encoding_id == TT_MS_ID_SYMBOL_CS)) &&
1150 (name.language_id == req->language_id) &&
1151 (name.name_id == req->name_id))
1153 req->string = name.string;
1154 req->string_len = name.string_len;
1161 req->string_len = 0;
1165 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, FT_UShort language_id)
1170 name.platform_id = TT_PLATFORM_MICROSOFT;
1171 name.language_id = language_id;
1172 name.name_id = name_id;
1174 if(get_name_table_entry(ft_face, &name))
1178 /* String is not nul terminated and string_len is a byte length. */
1179 ret = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1180 for(i = 0; i < name.string_len / 2; i++)
1182 WORD *tmp = (WORD *)&name.string[i * 2];
1183 ret[i] = GET_BE_WORD(*tmp);
1186 TRACE("Got localised name %s\n", debugstr_w(ret));
1192 static inline BOOL faces_equal( const Face *f1, const Face *f2 )
1194 if (strcmpiW( f1->StyleName, f2->StyleName )) return FALSE;
1195 if (f1->scalable) return TRUE;
1196 if (f1->size.y_ppem != f2->size.y_ppem) return FALSE;
1197 return !memcmp( &f1->fs, &f2->fs, sizeof(f1->fs) );
1200 static inline void free_face( Face *face )
1202 HeapFree( GetProcessHeap(), 0, face->file );
1203 HeapFree( GetProcessHeap(), 0, face->StyleName );
1204 HeapFree( GetProcessHeap(), 0, face->FullName );
1205 HeapFree( GetProcessHeap(), 0, face->cached_enum_data );
1206 HeapFree( GetProcessHeap(), 0, face );
1209 static inline void free_family( Family *family )
1211 Face *face, *cursor2;
1213 LIST_FOR_EACH_ENTRY_SAFE( face, cursor2, &family->faces, Face, entry )
1215 list_remove( &face->entry );
1218 HeapFree( GetProcessHeap(), 0, family->FamilyName );
1219 HeapFree( GetProcessHeap(), 0, family->EnglishName );
1220 HeapFree( GetProcessHeap(), 0, family );
1223 static inline int style_order(const Face *face)
1225 switch (face->ntmFlags & (NTM_REGULAR | NTM_BOLD | NTM_ITALIC))
1233 case NTM_BOLD | NTM_ITALIC:
1236 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1237 debugstr_w(face->family->FamilyName),
1238 debugstr_w(face->StyleName),
1244 static BOOL insert_face_in_family_list( Face *face, Family *family )
1248 LIST_FOR_EACH_ENTRY( cursor, &family->faces, Face, entry )
1250 if (faces_equal( face, cursor ))
1252 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1253 debugstr_w(family->FamilyName), debugstr_w(face->StyleName),
1254 cursor->font_version, face->font_version);
1256 if (face->font_version <= cursor->font_version)
1258 TRACE("Original font %s is newer so skipping %s\n",
1259 debugstr_a(cursor->file), debugstr_a(face->file));
1264 TRACE("Replacing original %s with %s\n",
1265 debugstr_a(cursor->file), debugstr_a(face->file));
1266 list_add_before( &cursor->entry, &face->entry );
1267 face->family = family;
1268 list_remove( &cursor->entry);
1269 free_face( cursor );
1274 TRACE("Adding new %s\n", debugstr_a(face->file));
1276 if (style_order( face ) < style_order( cursor )) break;
1279 list_add_before( &cursor->entry, &face->entry );
1280 face->family = family;
1284 /****************************************************************
1285 * NB This function stores the ptrs to the strings to save copying.
1286 * Don't free them after calling.
1288 static Family *create_family( WCHAR *name, WCHAR *english_name )
1290 Family * const family = HeapAlloc( GetProcessHeap(), 0, sizeof(*family) );
1291 family->FamilyName = name;
1292 family->EnglishName = english_name;
1293 list_init( &family->faces );
1294 family->replacement = &family->faces;
1299 static LONG reg_load_dword(HKEY hkey, const WCHAR *value, DWORD *data)
1302 LONG r = RegQueryValueExW(hkey, value, NULL, &type, NULL, &needed);
1303 if(r != ERROR_SUCCESS) return r;
1304 if(type != REG_DWORD || needed != sizeof(DWORD)) return ERROR_BAD_CONFIGURATION;
1305 return RegQueryValueExW(hkey, value, NULL, &type, (BYTE*)data, &needed);
1308 static inline LONG reg_save_dword(HKEY hkey, const WCHAR *value, DWORD data)
1310 return RegSetValueExW(hkey, value, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD));
1313 static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family)
1316 DWORD num_strikes, max_strike_key_len;
1318 /* If we have a File Name key then this is a real font, not just the parent
1319 key of a bunch of non-scalable strikes */
1320 if(RegQueryValueExA(hkey_face, "File Name", NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1323 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1324 face->cached_enum_data = NULL;
1326 face->file = HeapAlloc(GetProcessHeap(), 0, needed);
1327 RegQueryValueExA(hkey_face, "File Name", NULL, NULL, (BYTE*)face->file, &needed);
1329 face->StyleName = strdupW(face_name);
1331 if(RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1333 WCHAR *fullName = HeapAlloc(GetProcessHeap(), 0, needed);
1334 RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, (BYTE*)fullName, &needed);
1335 face->FullName = fullName;
1338 face->FullName = NULL;
1340 reg_load_dword(hkey_face, face_index_value, (DWORD*)&face->face_index);
1341 reg_load_dword(hkey_face, face_ntmflags_value, &face->ntmFlags);
1342 reg_load_dword(hkey_face, face_version_value, (DWORD*)&face->font_version);
1343 reg_load_dword(hkey_face, face_vertical_value, (DWORD*)&face->vertical);
1345 needed = sizeof(face->fs);
1346 RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
1348 if(reg_load_dword(hkey_face, face_height_value, (DWORD*)&face->size.height) != ERROR_SUCCESS)
1350 face->scalable = TRUE;
1351 memset(&face->size, 0, sizeof(face->size));
1355 face->scalable = FALSE;
1356 reg_load_dword(hkey_face, face_width_value, (DWORD*)&face->size.width);
1357 reg_load_dword(hkey_face, face_size_value, (DWORD*)&face->size.size);
1358 reg_load_dword(hkey_face, face_x_ppem_value, (DWORD*)&face->size.x_ppem);
1359 reg_load_dword(hkey_face, face_y_ppem_value, (DWORD*)&face->size.y_ppem);
1360 reg_load_dword(hkey_face, face_internal_leading_value, (DWORD*)&face->size.internal_leading);
1362 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1363 face->size.height, face->size.width, face->size.size >> 6,
1364 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1367 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1368 face->fs.fsCsb[0], face->fs.fsCsb[1],
1369 face->fs.fsUsb[0], face->fs.fsUsb[1],
1370 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1372 insert_face_in_family_list(face, family);
1374 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
1377 /* do we have any bitmap strikes? */
1378 RegQueryInfoKeyW(hkey_face, NULL, NULL, NULL, &num_strikes, &max_strike_key_len, NULL, NULL,
1379 NULL, NULL, NULL, NULL);
1380 if(num_strikes != 0)
1382 WCHAR strike_name[10];
1383 DWORD strike_index = 0;
1385 needed = sizeof(strike_name) / sizeof(WCHAR);
1386 while(RegEnumKeyExW(hkey_face, strike_index++, strike_name, &needed,
1387 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1390 RegOpenKeyExW(hkey_face, strike_name, 0, KEY_ALL_ACCESS, &hkey_strike);
1391 load_face(hkey_strike, face_name, family);
1392 RegCloseKey(hkey_strike);
1393 needed = sizeof(strike_name) / sizeof(WCHAR);
1398 static void load_font_list_from_cache(HKEY hkey_font_cache)
1400 DWORD max_family_key_len, size;
1402 DWORD family_index = 0;
1406 RegQueryInfoKeyW(hkey_font_cache, NULL, NULL, NULL, NULL, &max_family_key_len, NULL, NULL,
1407 NULL, NULL, NULL, NULL);
1408 family_name = HeapAlloc(GetProcessHeap(), 0, (max_family_key_len + 1) * sizeof(WCHAR));
1410 size = max_family_key_len + 1;
1411 while(RegEnumKeyExW(hkey_font_cache, family_index++, family_name, &size,
1412 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1414 WCHAR *english_family = NULL;
1415 DWORD face_index = 0;
1417 DWORD max_face_key_len;
1419 RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
1420 TRACE("opened family key %s\n", debugstr_w(family_name));
1421 if(RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, NULL, &size) == ERROR_SUCCESS)
1423 english_family = HeapAlloc(GetProcessHeap(), 0, size);
1424 RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE*)english_family, &size);
1427 family = create_family(strdupW(family_name), english_family);
1428 list_add_tail(&font_list, &family->entry);
1432 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1433 subst->from.name = strdupW(english_family);
1434 subst->from.charset = -1;
1435 subst->to.name = strdupW(family_name);
1436 subst->to.charset = -1;
1437 add_font_subst(&font_subst_list, subst, 0);
1440 RegQueryInfoKeyW(hkey_family, NULL, NULL, NULL, NULL, &max_face_key_len, NULL, NULL,
1441 NULL, NULL, NULL, NULL);
1443 face_name = HeapAlloc(GetProcessHeap(), 0, (max_face_key_len + 1) * sizeof(WCHAR));
1444 size = max_face_key_len + 1;
1445 while(RegEnumKeyExW(hkey_family, face_index++, face_name, &size,
1446 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1450 RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face);
1451 load_face(hkey_face, face_name, family);
1452 RegCloseKey(hkey_face);
1453 size = max_face_key_len + 1;
1455 HeapFree(GetProcessHeap(), 0, face_name);
1456 RegCloseKey(hkey_family);
1457 size = max_family_key_len + 1;
1460 HeapFree(GetProcessHeap(), 0, family_name);
1463 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1466 HKEY hkey_wine_fonts;
1468 /* We don't want to create the fonts key as volatile, so open this first */
1469 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1470 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1471 if(ret != ERROR_SUCCESS)
1473 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1477 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1478 KEY_ALL_ACCESS, NULL, hkey, disposition);
1479 RegCloseKey(hkey_wine_fonts);
1483 static void add_face_to_cache(Face *face)
1485 HKEY hkey_font_cache, hkey_family, hkey_face;
1486 WCHAR *face_key_name;
1488 create_font_cache_key(&hkey_font_cache, NULL);
1490 RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0,
1491 NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL);
1492 if(face->family->EnglishName)
1493 RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName,
1494 (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR));
1497 face_key_name = face->StyleName;
1500 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1501 face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1502 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1504 RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
1507 HeapFree(GetProcessHeap(), 0, face_key_name);
1509 RegSetValueExA(hkey_face, "File Name", 0, REG_BINARY, (BYTE*)face->file, strlen(face->file) + 1);
1511 RegSetValueExW(hkey_face, face_full_name_value, 0, REG_SZ, (BYTE*)face->FullName,
1512 (strlenW(face->FullName) + 1) * sizeof(WCHAR));
1514 reg_save_dword(hkey_face, face_index_value, face->face_index);
1515 reg_save_dword(hkey_face, face_ntmflags_value, face->ntmFlags);
1516 reg_save_dword(hkey_face, face_version_value, face->font_version);
1517 reg_save_dword(hkey_face, face_vertical_value, face->vertical);
1519 RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs));
1523 reg_save_dword(hkey_face, face_height_value, face->size.height);
1524 reg_save_dword(hkey_face, face_width_value, face->size.width);
1525 reg_save_dword(hkey_face, face_size_value, face->size.size);
1526 reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem);
1527 reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem);
1528 reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading);
1530 RegCloseKey(hkey_face);
1531 RegCloseKey(hkey_family);
1532 RegCloseKey(hkey_font_cache);
1535 static WCHAR *prepend_at(WCHAR *family)
1542 str = HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR) * (strlenW(family) + 2));
1544 strcpyW(str + 1, family);
1545 HeapFree(GetProcessHeap(), 0, family);
1549 static void get_family_names( FT_Face ft_face, WCHAR **name, WCHAR **english, BOOL vertical )
1551 *english = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1552 if (!*english) *english = towstr( CP_ACP, ft_face->family_name );
1554 *name = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, GetSystemDefaultLCID() );
1560 else if (!strcmpiW( *name, *english ))
1562 HeapFree( GetProcessHeap(), 0, *english );
1568 *name = prepend_at( *name );
1569 *english = prepend_at( *english );
1573 static Family *get_family( FT_Face ft_face, BOOL vertical )
1576 WCHAR *name, *english_name;
1578 get_family_names( ft_face, &name, &english_name, vertical );
1580 family = find_family_from_name( name );
1584 family = create_family( name, english_name );
1585 list_add_tail( &font_list, &family->entry );
1589 FontSubst *subst = HeapAlloc( GetProcessHeap(), 0, sizeof(*subst) );
1590 subst->from.name = strdupW( english_name );
1591 subst->from.charset = -1;
1592 subst->to.name = strdupW( name );
1593 subst->to.charset = -1;
1594 add_font_subst( &font_subst_list, subst, 0 );
1599 HeapFree( GetProcessHeap(), 0, name );
1600 HeapFree( GetProcessHeap(), 0, english_name );
1606 static inline FT_Fixed get_font_version( FT_Face ft_face )
1608 FT_Fixed version = 0;
1611 header = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head );
1612 if (header) version = header->Font_Revision;
1617 static inline DWORD get_ntm_flags( FT_Face ft_face )
1620 FT_ULong table_size = 0;
1622 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) flags |= NTM_ITALIC;
1623 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD) flags |= NTM_BOLD;
1624 if (flags == 0) flags = NTM_REGULAR;
1626 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL, &table_size ))
1627 flags |= NTM_PS_OPENTYPE;
1632 static inline int get_bitmap_internal_leading( FT_Face ft_face )
1634 int internal_leading = 0;
1635 FT_WinFNT_HeaderRec winfnt_header;
1637 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1638 internal_leading = winfnt_header.internal_leading;
1640 return internal_leading;
1643 static inline void get_fontsig( FT_Face ft_face, FONTSIGNATURE *fs )
1648 FT_WinFNT_HeaderRec winfnt_header;
1651 memset( fs, 0, sizeof(*fs) );
1653 os2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 );
1656 fs->fsUsb[0] = os2->ulUnicodeRange1;
1657 fs->fsUsb[1] = os2->ulUnicodeRange2;
1658 fs->fsUsb[2] = os2->ulUnicodeRange3;
1659 fs->fsUsb[3] = os2->ulUnicodeRange4;
1661 if (os2->version == 0)
1663 if (pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
1664 fs->fsCsb[0] = FS_LATIN1;
1666 fs->fsCsb[0] = FS_SYMBOL;
1670 fs->fsCsb[0] = os2->ulCodePageRange1;
1671 fs->fsCsb[1] = os2->ulCodePageRange2;
1676 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1678 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1679 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1680 if (TranslateCharsetInfo( (DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET ))
1685 if (fs->fsCsb[0] == 0)
1687 /* let's see if we can find any interesting cmaps */
1688 for (i = 0; i < ft_face->num_charmaps; i++)
1690 switch (ft_face->charmaps[i]->encoding)
1692 case FT_ENCODING_UNICODE:
1693 case FT_ENCODING_APPLE_ROMAN:
1694 fs->fsCsb[0] |= FS_LATIN1;
1696 case FT_ENCODING_MS_SYMBOL:
1697 fs->fsCsb[0] |= FS_SYMBOL;
1706 #define ADDFONT_EXTERNAL_FONT 0x01
1707 #define ADDFONT_FORCE_BITMAP 0x02
1708 #define ADDFONT_ADD_TO_CACHE 0x04
1710 static Face *create_face( FT_Face ft_face, FT_Long face_index, const char *file, void *font_data_ptr, DWORD font_data_size,
1711 DWORD flags, BOOL vertical )
1713 Face *face = HeapAlloc( GetProcessHeap(), 0, sizeof(*face) );
1714 My_FT_Bitmap_Size *size = (My_FT_Bitmap_Size *)ft_face->available_sizes;
1716 face->StyleName = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
1717 if (!face->StyleName)
1718 face->StyleName = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1719 if (!face->StyleName)
1721 face->StyleName = towstr( CP_ACP, ft_face->style_name );
1724 face->FullName = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
1725 if (!face->FullName)
1726 face->FullName = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1728 face->FullName = prepend_at( face->FullName );
1732 face->file = strdupA( file );
1733 face->font_data_ptr = NULL;
1734 face->font_data_size = 0;
1739 face->font_data_ptr = font_data_ptr;
1740 face->font_data_size = font_data_size;
1743 face->face_index = face_index;
1744 get_fontsig( ft_face, &face->fs );
1745 face->ntmFlags = get_ntm_flags( ft_face );
1746 face->font_version = get_font_version( ft_face );
1748 if (FT_IS_SCALABLE( ft_face ))
1750 memset( &face->size, 0, sizeof(face->size) );
1751 face->scalable = TRUE;
1755 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1756 size->height, size->width, size->size >> 6,
1757 size->x_ppem >> 6, size->y_ppem >> 6);
1758 face->size.height = size->height;
1759 face->size.width = size->width;
1760 face->size.size = size->size;
1761 face->size.x_ppem = size->x_ppem;
1762 face->size.y_ppem = size->y_ppem;
1763 face->size.internal_leading = get_bitmap_internal_leading( ft_face );
1764 face->scalable = FALSE;
1767 face->vertical = vertical;
1768 face->external = (flags & ADDFONT_EXTERNAL_FONT) != 0;
1769 face->family = NULL;
1770 face->cached_enum_data = NULL;
1772 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1773 face->fs.fsCsb[0], face->fs.fsCsb[1],
1774 face->fs.fsUsb[0], face->fs.fsUsb[1],
1775 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1780 static void AddFaceToList(FT_Face ft_face, const char *file, void *font_data_ptr, DWORD font_data_size,
1781 FT_Long face_index, DWORD flags, BOOL vertical)
1786 face = create_face( ft_face, face_index, file, font_data_ptr, font_data_size, flags, vertical );
1787 family = get_family( ft_face, vertical );
1788 if (!insert_face_in_family_list( face, family ))
1794 if (flags & ADDFONT_ADD_TO_CACHE)
1795 add_face_to_cache( face );
1797 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1798 debugstr_w(face->StyleName));
1801 static FT_Face new_ft_face( const char *file, void *font_data_ptr, DWORD font_data_size,
1802 FT_Long face_index, BOOL allow_bitmap )
1810 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1811 err = pFT_New_Face(library, file, face_index, &ft_face);
1815 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1816 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1821 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1825 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1826 if (!FT_IS_SCALABLE( ft_face ) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0)))
1828 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1832 if (!FT_IS_SFNT( ft_face ))
1834 if (FT_IS_SCALABLE( ft_face ) || !allow_bitmap )
1836 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1842 if (!(pOS2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 )) ||
1843 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_hhea ) ||
1844 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head ))
1846 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1847 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1851 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1852 we don't want to load these. */
1853 if (!memcmp( pOS2->achVendID, "Wine", sizeof(pOS2->achVendID) ))
1857 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len ))
1859 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1865 if (!ft_face->family_name || !ft_face->style_name)
1867 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1873 pFT_Done_Face( ft_face );
1877 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, DWORD flags)
1880 FT_Long face_index = 0, num_faces;
1883 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1884 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1886 #ifdef HAVE_CARBON_CARBON_H
1889 char **mac_list = expand_mac_font(file);
1892 BOOL had_one = FALSE;
1894 for(cursor = mac_list; *cursor; cursor++)
1897 AddFontToList(*cursor, NULL, 0, flags);
1898 HeapFree(GetProcessHeap(), 0, *cursor);
1900 HeapFree(GetProcessHeap(), 0, mac_list);
1905 #endif /* HAVE_CARBON_CARBON_H */
1908 ft_face = new_ft_face( file, font_data_ptr, font_data_size, face_index, flags & ADDFONT_FORCE_BITMAP );
1909 if (!ft_face) return 0;
1911 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1913 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1914 pFT_Done_Face(ft_face);
1918 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags, FALSE);
1921 if (FT_HAS_VERTICAL(ft_face))
1923 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags, TRUE);
1927 num_faces = ft_face->num_faces;
1928 pFT_Done_Face(ft_face);
1929 } while(num_faces > ++face_index);
1933 static void DumpFontList(void)
1937 struct list *family_elem_ptr, *face_elem_ptr;
1939 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1940 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1941 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1942 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1943 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1944 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1946 TRACE(" %d", face->size.height);
1953 /***********************************************************
1954 * The replacement list is a way to map an entire font
1955 * family onto another family. For example adding
1957 * [HKCU\Software\Wine\Fonts\Replacements]
1958 * "Wingdings"="Winedings"
1960 * would enumerate the Winedings font both as Winedings and
1961 * Wingdings. However if a real Wingdings font is present the
1962 * replacement does not take place.
1965 static void LoadReplaceList(void)
1968 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1973 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1974 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1976 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1977 &valuelen, &datalen, NULL, NULL);
1979 valuelen++; /* returned value doesn't include room for '\0' */
1980 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1981 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1985 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1986 &dlen) == ERROR_SUCCESS) {
1987 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1988 /* "NewName"="Oldname" */
1989 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1991 if(!find_family_from_any_name(value))
1993 Family * const family = find_family_from_any_name(data);
1996 Family * const new_family = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family));
1997 if (new_family != NULL)
1999 TRACE("mapping %s to %s\n", debugstr_w(data), debugstr_w(value));
2000 new_family->FamilyName = strdupW(value);
2001 new_family->EnglishName = NULL;
2002 list_init(&new_family->faces);
2003 new_family->replacement = &family->faces;
2004 list_add_tail(&font_list, &new_family->entry);
2009 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(data));
2014 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value));
2016 /* reset dlen and vlen */
2020 HeapFree(GetProcessHeap(), 0, data);
2021 HeapFree(GetProcessHeap(), 0, value);
2026 static const WCHAR *font_links_list[] =
2028 Lucida_Sans_Unicode,
2029 Microsoft_Sans_Serif,
2033 static const struct font_links_defaults_list
2035 /* Keyed off substitution for "MS Shell Dlg" */
2036 const WCHAR *shelldlg;
2037 /* Maximum of four substitutes, plus terminating NULL pointer */
2038 const WCHAR *substitutes[5];
2039 } font_links_defaults_list[] =
2041 /* Non East-Asian */
2042 { Tahoma, /* FIXME unverified ordering */
2043 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2045 /* Below lists are courtesy of
2046 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2050 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2052 /* Chinese Simplified */
2054 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2058 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2060 /* Chinese Traditional */
2062 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2067 static SYSTEM_LINKS *find_font_link(const WCHAR *name)
2069 SYSTEM_LINKS *font_link;
2071 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2073 if(!strcmpiW(font_link->font_name, name))
2080 static void populate_system_links(const WCHAR *name, const WCHAR *const *values)
2092 SYSTEM_LINKS *font_link;
2094 psub = get_font_subst(&font_subst_list, name, -1);
2095 /* Don't store fonts that are only substitutes for other fonts */
2098 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name));
2102 font_link = find_font_link(name);
2103 if (font_link == NULL)
2105 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2106 font_link->font_name = strdupW(name);
2107 list_init(&font_link->links);
2108 list_add_tail(&system_links, &font_link->entry);
2111 memset(&font_link->fs, 0, sizeof font_link->fs);
2112 for (i = 0; values[i] != NULL; i++)
2114 const struct list *face_list;
2115 CHILD_FONT *child_font;
2118 if (!strcmpiW(name,value))
2120 psub = get_font_subst(&font_subst_list, value, -1);
2122 value = psub->to.name;
2123 family = find_family_from_name(value);
2127 /* Use first extant filename for this Family */
2128 face_list = get_face_list_from_family(family);
2129 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
2133 file = strrchr(face->file, '/');
2142 fileW = towstr(CP_UNIXCP, file);
2144 face = find_face_from_filename(fileW, value);
2147 TRACE("Unable to find file %s face name %s\n", debugstr_w(fileW), debugstr_w(value));
2151 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2152 child_font->face = face;
2153 child_font->font = NULL;
2154 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2155 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2156 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
2157 list_add_tail(&font_link->links, &child_font->entry);
2159 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(fileW));
2160 HeapFree(GetProcessHeap(), 0, fileW);
2166 /*************************************************************
2169 static BOOL init_system_links(void)
2173 DWORD type, max_val, max_data, val_len, data_len, index;
2174 WCHAR *value, *data;
2175 WCHAR *entry, *next;
2176 SYSTEM_LINKS *font_link, *system_font_link;
2177 CHILD_FONT *child_font;
2178 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
2179 static const WCHAR System[] = {'S','y','s','t','e','m',0};
2180 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2185 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
2187 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
2188 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
2189 data = HeapAlloc(GetProcessHeap(), 0, max_data);
2190 val_len = max_val + 1;
2191 data_len = max_data;
2193 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
2195 psub = get_font_subst(&font_subst_list, value, -1);
2196 /* Don't store fonts that are only substitutes for other fonts */
2199 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
2202 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2203 font_link->font_name = strdupW(value);
2204 memset(&font_link->fs, 0, sizeof font_link->fs);
2205 list_init(&font_link->links);
2206 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
2209 CHILD_FONT *child_font;
2211 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
2213 next = entry + strlenW(entry) + 1;
2215 face_name = strchrW(entry, ',');
2219 while(isspaceW(*face_name))
2222 psub = get_font_subst(&font_subst_list, face_name, -1);
2224 face_name = psub->to.name;
2226 face = find_face_from_filename(entry, face_name);
2229 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
2233 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2234 child_font->face = face;
2235 child_font->font = NULL;
2236 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2237 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2238 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
2239 list_add_tail(&font_link->links, &child_font->entry);
2241 list_add_tail(&system_links, &font_link->entry);
2243 val_len = max_val + 1;
2244 data_len = max_data;
2247 HeapFree(GetProcessHeap(), 0, value);
2248 HeapFree(GetProcessHeap(), 0, data);
2253 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2255 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2259 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2261 const FontSubst *psub2;
2262 psub2 = get_font_subst(&font_subst_list, font_links_defaults_list[i].shelldlg, -1);
2264 if ((!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name) || (psub2 && !strcmpiW(psub2->to.name,psub->to.name))))
2266 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2267 populate_system_links(font_links_list[j], font_links_defaults_list[i].substitutes);
2269 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2270 populate_system_links(psub->to.name, font_links_defaults_list[i].substitutes);
2272 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2274 populate_system_links(font_links_defaults_list[i].substitutes[0], NULL);
2280 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2283 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2284 system_font_link->font_name = strdupW(System);
2285 memset(&system_font_link->fs, 0, sizeof system_font_link->fs);
2286 list_init(&system_font_link->links);
2288 face = find_face_from_filename(tahoma_ttf, Tahoma);
2291 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2292 child_font->face = face;
2293 child_font->font = NULL;
2294 system_font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2295 system_font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2296 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
2297 list_add_tail(&system_font_link->links, &child_font->entry);
2299 font_link = find_font_link(Tahoma);
2300 if (font_link != NULL)
2302 CHILD_FONT *font_link_entry;
2303 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2305 CHILD_FONT *new_child;
2306 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2307 new_child->face = font_link_entry->face;
2308 new_child->font = NULL;
2309 system_font_link->fs.fsCsb[0] |= font_link_entry->face->fs.fsCsb[0];
2310 system_font_link->fs.fsCsb[1] |= font_link_entry->face->fs.fsCsb[1];
2311 list_add_tail(&system_font_link->links, &new_child->entry);
2314 list_add_tail(&system_links, &system_font_link->entry);
2318 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2321 struct dirent *dent;
2322 char path[MAX_PATH];
2324 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2326 dir = opendir(dirname);
2328 WARN("Can't open directory %s\n", debugstr_a(dirname));
2331 while((dent = readdir(dir)) != NULL) {
2332 struct stat statbuf;
2334 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2337 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2339 sprintf(path, "%s/%s", dirname, dent->d_name);
2341 if(stat(path, &statbuf) == -1)
2343 WARN("Can't stat %s\n", debugstr_a(path));
2346 if(S_ISDIR(statbuf.st_mode))
2347 ReadFontDir(path, external_fonts);
2350 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2351 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2352 AddFontToList(path, NULL, 0, addfont_flags);
2359 #ifdef SONAME_LIBFONTCONFIG
2360 static void load_fontconfig_fonts(void)
2362 void *fc_handle = NULL;
2371 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2373 TRACE("Wine cannot find the fontconfig library (%s).\n",
2374 SONAME_LIBFONTCONFIG);
2377 #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;}
2378 LOAD_FUNCPTR(FcConfigGetCurrent);
2379 LOAD_FUNCPTR(FcFontList);
2380 LOAD_FUNCPTR(FcFontSetDestroy);
2381 LOAD_FUNCPTR(FcInit);
2382 LOAD_FUNCPTR(FcObjectSetAdd);
2383 LOAD_FUNCPTR(FcObjectSetCreate);
2384 LOAD_FUNCPTR(FcObjectSetDestroy);
2385 LOAD_FUNCPTR(FcPatternCreate);
2386 LOAD_FUNCPTR(FcPatternDestroy);
2387 LOAD_FUNCPTR(FcPatternGetBool);
2388 LOAD_FUNCPTR(FcPatternGetString);
2391 if(!pFcInit()) return;
2393 config = pFcConfigGetCurrent();
2394 pat = pFcPatternCreate();
2395 os = pFcObjectSetCreate();
2396 pFcObjectSetAdd(os, FC_FILE);
2397 pFcObjectSetAdd(os, FC_SCALABLE);
2398 fontset = pFcFontList(config, pat, os);
2399 if(!fontset) return;
2400 for(i = 0; i < fontset->nfont; i++) {
2403 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2405 TRACE("fontconfig: %s\n", file);
2407 /* We're just interested in OT/TT fonts for now, so this hack just
2408 picks up the scalable fonts without extensions .pf[ab] to save time
2409 loading every other font */
2411 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2413 TRACE("not scalable\n");
2417 len = strlen( file );
2418 if(len < 4) continue;
2419 ext = &file[ len - 3 ];
2420 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2421 AddFontToList(file, NULL, 0, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2423 pFcFontSetDestroy(fontset);
2424 pFcObjectSetDestroy(os);
2425 pFcPatternDestroy(pat);
2430 #elif defined(HAVE_CARBON_CARBON_H)
2432 static void load_mac_font_callback(const void *value, void *context)
2434 CFStringRef pathStr = value;
2438 len = CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr);
2439 path = HeapAlloc(GetProcessHeap(), 0, len);
2440 if (path && CFStringGetFileSystemRepresentation(pathStr, path, len))
2442 TRACE("font file %s\n", path);
2443 AddFontToList(path, NULL, 0, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2445 HeapFree(GetProcessHeap(), 0, path);
2448 static void load_mac_fonts(void)
2450 CFStringRef removeDupesKey;
2451 CFBooleanRef removeDupesValue;
2452 CFDictionaryRef options;
2453 CTFontCollectionRef col;
2455 CFMutableSetRef paths;
2458 removeDupesKey = kCTFontCollectionRemoveDuplicatesOption;
2459 removeDupesValue = kCFBooleanTrue;
2460 options = CFDictionaryCreate(NULL, (const void**)&removeDupesKey, (const void**)&removeDupesValue, 1,
2461 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2462 col = CTFontCollectionCreateFromAvailableFonts(options);
2463 if (options) CFRelease(options);
2466 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
2470 descs = CTFontCollectionCreateMatchingFontDescriptors(col);
2474 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
2478 paths = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
2481 WARN("CFSetCreateMutable failed\n");
2486 for (i = 0; i < CFArrayGetCount(descs); i++)
2488 CTFontDescriptorRef desc;
2497 desc = CFArrayGetValueAtIndex(descs, i);
2499 /* CTFontDescriptor doesn't support kCTFontURLAttribute until 10.6, so
2500 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
2501 font = CTFontCreateWithFontDescriptor(desc, 0, NULL);
2502 if (!font) continue;
2504 atsFont = CTFontGetPlatformFont(font, NULL);
2511 status = ATSFontGetFileReference(atsFont, &fsref);
2513 if (status != noErr) continue;
2515 url = CFURLCreateFromFSRef(NULL, &fsref);
2518 ext = CFURLCopyPathExtension(url);
2521 BOOL skip = (CFStringCompare(ext, CFSTR("pfa"), kCFCompareCaseInsensitive) == kCFCompareEqualTo ||
2522 CFStringCompare(ext, CFSTR("pfb"), kCFCompareCaseInsensitive) == kCFCompareEqualTo);
2531 path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
2533 if (!path) continue;
2535 CFSetAddValue(paths, path);
2541 CFSetApplyFunction(paths, load_mac_font_callback, NULL);
2547 static BOOL load_font_from_data_dir(LPCWSTR file)
2550 const char *data_dir = wine_get_data_dir();
2552 if (!data_dir) data_dir = wine_get_build_dir();
2559 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
2561 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
2563 strcpy(unix_name, data_dir);
2564 strcat(unix_name, "/fonts/");
2566 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
2568 EnterCriticalSection( &freetype_cs );
2569 ret = AddFontToList(unix_name, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2570 LeaveCriticalSection( &freetype_cs );
2571 HeapFree(GetProcessHeap(), 0, unix_name);
2576 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
2578 static const WCHAR slashW[] = {'\\','\0'};
2580 WCHAR windowsdir[MAX_PATH];
2583 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2584 strcatW(windowsdir, fontsW);
2585 strcatW(windowsdir, slashW);
2586 strcatW(windowsdir, file);
2587 if ((unixname = wine_get_unix_file_name(windowsdir))) {
2588 EnterCriticalSection( &freetype_cs );
2589 ret = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP);
2590 LeaveCriticalSection( &freetype_cs );
2591 HeapFree(GetProcessHeap(), 0, unixname);
2596 static void load_system_fonts(void)
2599 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
2600 const WCHAR * const *value;
2602 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2605 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
2606 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2607 strcatW(windowsdir, fontsW);
2608 for(value = SystemFontValues; *value; value++) {
2609 dlen = sizeof(data);
2610 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
2614 sprintfW(pathW, fmtW, windowsdir, data);
2615 if((unixname = wine_get_unix_file_name(pathW))) {
2616 added = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2617 HeapFree(GetProcessHeap(), 0, unixname);
2620 load_font_from_data_dir(data);
2627 /*************************************************************
2629 * This adds registry entries for any externally loaded fonts
2630 * (fonts from fontconfig or FontDirs). It also deletes entries
2631 * of no longer existing fonts.
2634 static void update_reg_entries(void)
2636 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2641 struct list *family_elem_ptr, *face_elem_ptr;
2643 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2646 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2647 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2648 ERR("Can't create Windows font reg key\n");
2652 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2653 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2654 ERR("Can't create Windows font reg key\n");
2658 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
2659 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
2660 ERR("Can't create external font reg key\n");
2664 /* enumerate the fonts and add external ones to the two keys */
2666 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2667 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2668 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2669 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2670 if(!face->external) continue;
2674 len = strlenW(face->FullName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2675 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2676 strcpyW(valueW, face->FullName);
2680 len = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2681 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2682 strcpyW(valueW, family->FamilyName);
2685 file = wine_get_dos_file_name(face->file);
2687 len = strlenW(file) + 1;
2690 if((path = strrchr(face->file, '/')) == NULL)
2694 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
2696 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2697 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2699 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2700 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2701 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2703 HeapFree(GetProcessHeap(), 0, file);
2704 HeapFree(GetProcessHeap(), 0, valueW);
2708 if(external_key) RegCloseKey(external_key);
2709 if(win9x_key) RegCloseKey(win9x_key);
2710 if(winnt_key) RegCloseKey(winnt_key);
2714 static void delete_external_font_keys(void)
2716 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2717 DWORD dlen, vlen, datalen, valuelen, i, type;
2721 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2722 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2723 ERR("Can't create Windows font reg key\n");
2727 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2728 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2729 ERR("Can't create Windows font reg key\n");
2733 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2734 ERR("Can't create external font reg key\n");
2738 /* Delete all external fonts added last time */
2740 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2741 &valuelen, &datalen, NULL, NULL);
2742 valuelen++; /* returned value doesn't include room for '\0' */
2743 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2744 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2746 dlen = datalen * sizeof(WCHAR);
2749 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2750 &dlen) == ERROR_SUCCESS) {
2752 RegDeleteValueW(winnt_key, valueW);
2753 RegDeleteValueW(win9x_key, valueW);
2754 /* reset dlen and vlen */
2758 HeapFree(GetProcessHeap(), 0, data);
2759 HeapFree(GetProcessHeap(), 0, valueW);
2761 /* Delete the old external fonts key */
2762 RegCloseKey(external_key);
2763 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2766 if(win9x_key) RegCloseKey(win9x_key);
2767 if(winnt_key) RegCloseKey(winnt_key);
2770 /*************************************************************
2771 * WineEngAddFontResourceEx
2774 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2780 if (ft_handle) /* do it only if we have freetype up and running */
2785 FIXME("Ignoring flags %x\n", flags);
2787 if((unixname = wine_get_unix_file_name(file)))
2789 DWORD addfont_flags = ADDFONT_FORCE_BITMAP;
2791 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
2792 EnterCriticalSection( &freetype_cs );
2793 ret = AddFontToList(unixname, NULL, 0, addfont_flags);
2794 LeaveCriticalSection( &freetype_cs );
2795 HeapFree(GetProcessHeap(), 0, unixname);
2797 if (!ret && !strchrW(file, '\\')) {
2798 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2799 ret = load_font_from_winfonts_dir(file);
2801 /* Try in datadir/fonts (or builddir/fonts),
2802 * needed for Magic the Gathering Online
2804 ret = load_font_from_data_dir(file);
2811 /*************************************************************
2812 * WineEngAddFontMemResourceEx
2815 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2819 if (ft_handle) /* do it only if we have freetype up and running */
2821 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2823 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2824 memcpy(pFontCopy, pbFont, cbFont);
2826 EnterCriticalSection( &freetype_cs );
2827 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, ADDFONT_FORCE_BITMAP);
2828 LeaveCriticalSection( &freetype_cs );
2832 TRACE("AddFontToList failed\n");
2833 HeapFree(GetProcessHeap(), 0, pFontCopy);
2836 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2837 * For now return something unique but quite random
2839 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2840 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2847 /*************************************************************
2848 * WineEngRemoveFontResourceEx
2851 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2854 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
2858 static char *get_ttf_file_name( LPCWSTR font_file, LPCWSTR font_path )
2864 if (!font_file) return NULL;
2866 file_len = strlenW( font_file );
2868 if (font_path && font_path[0])
2870 int path_len = strlenW( font_path );
2871 fullname = HeapAlloc( GetProcessHeap(), 0, (file_len + path_len + 2) * sizeof(WCHAR) );
2872 if (!fullname) return NULL;
2873 memcpy( fullname, font_path, path_len * sizeof(WCHAR) );
2874 fullname[path_len] = '\\';
2875 memcpy( fullname + path_len + 1, font_file, (file_len + 1) * sizeof(WCHAR) );
2879 int len = GetFullPathNameW( font_file, 0, NULL, NULL );
2880 if (!len) return NULL;
2881 fullname = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
2882 if (!fullname) return NULL;
2883 GetFullPathNameW( font_file, len, fullname, NULL );
2886 unix_name = wine_get_unix_file_name( fullname );
2887 HeapFree( GetProcessHeap(), 0, fullname );
2891 #include <pshpack1.h>
2894 WORD num_of_resources;
2898 CHAR dfCopyright[60];
2904 WORD dfInternalLeading;
2905 WORD dfExternalLeading;
2913 BYTE dfPitchAndFamily;
2924 CHAR szFaceName[LF_FACESIZE];
2927 #include <poppack.h>
2929 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
2930 NEWTEXTMETRICEXW *pntm, LPDWORD ptype);
2932 static BOOL get_fontdir( const char *unix_name, struct fontdir *fd )
2934 FT_Face ft_face = new_ft_face( unix_name, NULL, 0, 0, FALSE );
2937 WCHAR *name, *english_name;
2939 NEWTEXTMETRICEXW ntm;
2942 if (!ft_face) return FALSE;
2943 face = create_face( ft_face, 0, unix_name, NULL, 0, 0, FALSE );
2944 get_family_names( ft_face, &name, &english_name, FALSE );
2945 family = create_family( name, english_name );
2946 insert_face_in_family_list( face, family );
2947 pFT_Done_Face( ft_face );
2949 GetEnumStructs( face, &elf, &ntm, &type );
2950 free_family( family );
2952 if ((type & TRUETYPE_FONTTYPE) == 0) return FALSE;
2954 memset( fd, 0, sizeof(*fd) );
2956 fd->num_of_resources = 1;
2958 fd->dfVersion = 0x200;
2959 fd->dfSize = sizeof(*fd);
2960 strcpy( fd->dfCopyright, "Wine fontdir" );
2961 fd->dfType = 0x4003; /* 0x0080 set if private */
2962 fd->dfPoints = ntm.ntmTm.ntmSizeEM;
2964 fd->dfHorizRes = 72;
2965 fd->dfAscent = ntm.ntmTm.tmAscent;
2966 fd->dfInternalLeading = ntm.ntmTm.tmInternalLeading;
2967 fd->dfExternalLeading = ntm.ntmTm.tmExternalLeading;
2968 fd->dfItalic = ntm.ntmTm.tmItalic;
2969 fd->dfUnderline = ntm.ntmTm.tmUnderlined;
2970 fd->dfStrikeOut = ntm.ntmTm.tmStruckOut;
2971 fd->dfWeight = ntm.ntmTm.tmWeight;
2972 fd->dfCharSet = ntm.ntmTm.tmCharSet;
2974 fd->dfPixHeight = ntm.ntmTm.tmHeight;
2975 fd->dfPitchAndFamily = ntm.ntmTm.tmPitchAndFamily;
2976 fd->dfAvgWidth = ntm.ntmTm.tmAveCharWidth;
2977 fd->dfMaxWidth = ntm.ntmTm.tmMaxCharWidth;
2978 fd->dfFirstChar = ntm.ntmTm.tmFirstChar;
2979 fd->dfLastChar = ntm.ntmTm.tmLastChar;
2980 fd->dfDefaultChar = ntm.ntmTm.tmDefaultChar;
2981 fd->dfBreakChar = ntm.ntmTm.tmBreakChar;
2982 fd->dfWidthBytes = 0;
2984 fd->dfFace = FIELD_OFFSET( struct fontdir, szFaceName );
2986 WideCharToMultiByte( CP_ACP, 0, elf.elfLogFont.lfFaceName, -1, fd->szFaceName, LF_FACESIZE, NULL, NULL );
2991 #define NE_FFLAGS_LIBMODULE 0x8000
2992 #define NE_OSFLAGS_WINDOWS 0x02
2994 static const char dos_string[0x40] = "This is a TrueType resource file";
2995 static const char FONTRES[] = {'F','O','N','T','R','E','S',':'};
2997 #include <pshpack2.h>
3018 struct ne_typeinfo fontdir_type;
3019 struct ne_nameinfo fontdir_name;
3020 struct ne_typeinfo scalable_type;
3021 struct ne_nameinfo scalable_name;
3023 BYTE fontdir_res_name[8];
3026 #include <poppack.h>
3028 static BOOL create_fot( const WCHAR *resource, const WCHAR *font_file, const struct fontdir *fontdir )
3032 DWORD size, written;
3034 BYTE import_name_len, res_name_len, non_res_name_len, font_file_len;
3035 char *font_fileA, *last_part, *ext;
3036 IMAGE_DOS_HEADER dos;
3037 IMAGE_OS2_HEADER ne =
3039 IMAGE_OS2_SIGNATURE, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE, 0,
3041 0, sizeof(ne), sizeof(ne), 0, 0, 0, 0,
3042 0, 4, 2, NE_OSFLAGS_WINDOWS, 0, 0, 0, 0, 0x300
3044 struct rsrc_tab rsrc_tab =
3048 { 0, 0, 0x0c50, 0x2c, 0 },
3050 { 0, 0, 0x0c50, 0x8001, 0 },
3052 { 7,'F','O','N','T','D','I','R'}
3055 memset( &dos, 0, sizeof(dos) );
3056 dos.e_magic = IMAGE_DOS_SIGNATURE;
3057 dos.e_lfanew = sizeof(dos) + sizeof(dos_string);
3059 /* import name is last part\0, resident name is last part without extension
3060 non-resident name is "FONTRES:" + lfFaceName */
3062 font_file_len = WideCharToMultiByte( CP_ACP, 0, font_file, -1, NULL, 0, NULL, NULL );
3063 font_fileA = HeapAlloc( GetProcessHeap(), 0, font_file_len );
3064 WideCharToMultiByte( CP_ACP, 0, font_file, -1, font_fileA, font_file_len, NULL, NULL );
3066 last_part = strrchr( font_fileA, '\\' );
3067 if (last_part) last_part++;
3068 else last_part = font_fileA;
3069 import_name_len = strlen( last_part ) + 1;
3071 ext = strchr( last_part, '.' );
3072 if (ext) res_name_len = ext - last_part;
3073 else res_name_len = import_name_len - 1;
3075 non_res_name_len = sizeof( FONTRES ) + strlen( fontdir->szFaceName );
3077 ne.ne_cbnrestab = 1 + non_res_name_len + 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
3078 ne.ne_restab = ne.ne_rsrctab + sizeof(rsrc_tab);
3079 ne.ne_modtab = ne.ne_imptab = ne.ne_restab + 1 + res_name_len + 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
3080 ne.ne_enttab = ne.ne_imptab + 1 + import_name_len; /* len + string */
3082 ne.ne_nrestab = ne.ne_enttab + ne.ne_cbenttab + 2 + dos.e_lfanew; /* there are 2 bytes of 0 after entry tab */
3084 rsrc_tab.scalable_name.off = (ne.ne_nrestab + ne.ne_cbnrestab + 0xf) >> 4;
3085 rsrc_tab.scalable_name.len = (font_file_len + 0xf) >> 4;
3086 rsrc_tab.fontdir_name.off = rsrc_tab.scalable_name.off + rsrc_tab.scalable_name.len;
3087 rsrc_tab.fontdir_name.len = (fontdir->dfSize + 0xf) >> 4;
3089 size = (rsrc_tab.fontdir_name.off + rsrc_tab.fontdir_name.len) << 4;
3090 start = ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
3094 HeapFree( GetProcessHeap(), 0, font_fileA );
3098 memcpy( ptr, &dos, sizeof(dos) );
3099 memcpy( ptr + sizeof(dos), dos_string, sizeof(dos_string) );
3100 memcpy( ptr + dos.e_lfanew, &ne, sizeof(ne) );
3102 ptr = start + dos.e_lfanew + ne.ne_rsrctab;
3103 memcpy( ptr, &rsrc_tab, sizeof(rsrc_tab) );
3105 ptr = start + dos.e_lfanew + ne.ne_restab;
3106 *ptr++ = res_name_len;
3107 memcpy( ptr, last_part, res_name_len );
3109 ptr = start + dos.e_lfanew + ne.ne_imptab;
3110 *ptr++ = import_name_len;
3111 memcpy( ptr, last_part, import_name_len );
3113 ptr = start + ne.ne_nrestab;
3114 *ptr++ = non_res_name_len;
3115 memcpy( ptr, FONTRES, sizeof(FONTRES) );
3116 memcpy( ptr + sizeof(FONTRES), fontdir->szFaceName, strlen( fontdir->szFaceName ) );
3118 ptr = start + (rsrc_tab.scalable_name.off << 4);
3119 memcpy( ptr, font_fileA, font_file_len );
3121 ptr = start + (rsrc_tab.fontdir_name.off << 4);
3122 memcpy( ptr, fontdir, fontdir->dfSize );
3124 file = CreateFileW( resource, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
3125 if (file != INVALID_HANDLE_VALUE)
3127 if (WriteFile( file, start, size, &written, NULL ) && written == size)
3129 CloseHandle( file );
3132 HeapFree( GetProcessHeap(), 0, start );
3133 HeapFree( GetProcessHeap(), 0, font_fileA );
3138 /*************************************************************
3139 * WineEngCreateScalableFontResource
3142 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
3143 LPCWSTR font_file, LPCWSTR font_path )
3145 char *unix_name = get_ttf_file_name( font_file, font_path );
3146 struct fontdir fontdir;
3149 if (!unix_name || !get_fontdir( unix_name, &fontdir ))
3150 SetLastError( ERROR_INVALID_PARAMETER );
3153 if (hidden) fontdir.dfType |= 0x80;
3154 ret = create_fot( resource, font_file, &fontdir );
3157 HeapFree( GetProcessHeap(), 0, unix_name );
3161 static const struct nls_update_font_list
3163 UINT ansi_cp, oem_cp;
3164 const char *oem, *fixed, *system;
3165 const char *courier, *serif, *small, *sserif_96, *sserif_120;
3166 /* these are for font substitutes */
3167 const char *shelldlg, *tmsrmn;
3168 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
3172 const char *from, *to;
3173 } arial_0, courier_new_0, times_new_roman_0;
3174 } nls_update_font_list[] =
3176 /* Latin 1 (United States) */
3177 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
3178 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3179 "Tahoma","Times New Roman",
3180 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3183 /* Latin 1 (Multilingual) */
3184 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
3185 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3186 "Tahoma","Times New Roman", /* FIXME unverified */
3187 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3190 /* Eastern Europe */
3191 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
3192 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
3193 "Tahoma","Times New Roman", /* FIXME unverified */
3194 "Fixedsys,238", "System,238",
3195 "Courier New,238", "MS Serif,238", "Small Fonts,238",
3196 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
3197 { "Arial CE,0", "Arial,238" },
3198 { "Courier New CE,0", "Courier New,238" },
3199 { "Times New Roman CE,0", "Times New Roman,238" }
3202 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
3203 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
3204 "Tahoma","Times New Roman", /* FIXME unverified */
3205 "Fixedsys,204", "System,204",
3206 "Courier New,204", "MS Serif,204", "Small Fonts,204",
3207 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
3208 { "Arial Cyr,0", "Arial,204" },
3209 { "Courier New Cyr,0", "Courier New,204" },
3210 { "Times New Roman Cyr,0", "Times New Roman,204" }
3213 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
3214 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
3215 "Tahoma","Times New Roman", /* FIXME unverified */
3216 "Fixedsys,161", "System,161",
3217 "Courier New,161", "MS Serif,161", "Small Fonts,161",
3218 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
3219 { "Arial Greek,0", "Arial,161" },
3220 { "Courier New Greek,0", "Courier New,161" },
3221 { "Times New Roman Greek,0", "Times New Roman,161" }
3224 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
3225 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
3226 "Tahoma","Times New Roman", /* FIXME unverified */
3227 "Fixedsys,162", "System,162",
3228 "Courier New,162", "MS Serif,162", "Small Fonts,162",
3229 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
3230 { "Arial Tur,0", "Arial,162" },
3231 { "Courier New Tur,0", "Courier New,162" },
3232 { "Times New Roman Tur,0", "Times New Roman,162" }
3235 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
3236 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
3237 "Tahoma","Times New Roman", /* FIXME unverified */
3238 "Fixedsys,177", "System,177",
3239 "Courier New,177", "MS Serif,177", "Small Fonts,177",
3240 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
3244 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
3245 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
3246 "Tahoma","Times New Roman", /* FIXME unverified */
3247 "Fixedsys,178", "System,178",
3248 "Courier New,178", "MS Serif,178", "Small Fonts,178",
3249 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
3253 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
3254 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
3255 "Tahoma","Times New Roman", /* FIXME unverified */
3256 "Fixedsys,186", "System,186",
3257 "Courier New,186", "MS Serif,186", "Small Fonts,186",
3258 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
3259 { "Arial Baltic,0", "Arial,186" },
3260 { "Courier New Baltic,0", "Courier New,186" },
3261 { "Times New Roman Baltic,0", "Times New Roman,186" }
3264 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
3265 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3266 "Tahoma","Times New Roman", /* FIXME unverified */
3267 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3271 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
3272 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
3273 "Tahoma","Times New Roman", /* FIXME unverified */
3274 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3278 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
3279 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
3280 "MS UI Gothic","MS Serif",
3281 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3284 /* Chinese Simplified */
3285 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
3286 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3287 "SimSun", "NSimSun",
3288 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3292 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
3293 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3295 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3298 /* Chinese Traditional */
3299 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
3300 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3301 "PMingLiU", "MingLiU",
3302 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3307 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
3309 return ( ansi_cp == 932 /* CP932 for Japanese */
3310 || ansi_cp == 936 /* CP936 for Chinese Simplified */
3311 || ansi_cp == 949 /* CP949 for Korean */
3312 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
3315 static inline HKEY create_fonts_NT_registry_key(void)
3319 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
3320 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3324 static inline HKEY create_fonts_9x_registry_key(void)
3328 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
3329 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3333 static inline HKEY create_config_fonts_registry_key(void)
3337 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
3338 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3342 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl, int dpi)
3344 const char *sserif = (dpi <= 108) ? fl->sserif_96 : fl->sserif_120;
3346 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
3347 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
3348 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)sserif, strlen(sserif)+1);
3349 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
3352 static void set_value_key(HKEY hkey, const char *name, const char *value)
3355 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
3357 RegDeleteValueA(hkey, name);
3360 static void update_font_info(void)
3362 static const WCHAR logpixels[] = { 'L','o','g','P','i','x','e','l','s',0 };
3363 char buf[40], cpbuf[40];
3366 UINT i, ansi_cp = 0, oem_cp = 0;
3367 DWORD screen_dpi = 96, font_dpi = 0;
3370 if (RegOpenKeyA(HKEY_LOCAL_MACHINE,
3371 "System\\CurrentControlSet\\Hardware Profiles\\Current\\Software\\Fonts",
3372 &hkey) == ERROR_SUCCESS)
3374 reg_load_dword(hkey, logpixels, &screen_dpi);
3378 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
3381 reg_load_dword(hkey, logpixels, &font_dpi);
3383 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3384 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
3385 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3386 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
3387 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
3389 /* Setup Default_Fallback usage for DBCS ANSI codepages */
3390 if (is_dbcs_ansi_cp(ansi_cp))
3391 use_default_fallback = TRUE;
3394 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
3396 if (!strcmp( buf, cpbuf ) && screen_dpi == font_dpi) /* already set correctly */
3401 TRACE("updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
3402 buf, font_dpi, ansi_cp, oem_cp, screen_dpi);
3404 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
3405 ansi_cp, oem_cp, screen_dpi);
3407 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
3408 RegSetValueExW(hkey, logpixels, 0, REG_DWORD, (const BYTE *)&screen_dpi, sizeof(screen_dpi));
3411 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
3415 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
3416 nls_update_font_list[i].oem_cp == oem_cp)
3418 hkey = create_config_fonts_registry_key();
3419 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
3420 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
3421 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
3424 hkey = create_fonts_NT_registry_key();
3425 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3428 hkey = create_fonts_9x_registry_key();
3429 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3432 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3434 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
3435 strlen(nls_update_font_list[i].shelldlg)+1);
3436 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
3437 strlen(nls_update_font_list[i].tmsrmn)+1);
3439 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
3440 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
3441 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
3442 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
3443 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
3444 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
3445 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
3446 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
3448 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
3449 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
3450 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
3458 /* Delete the FontSubstitutes from other locales */
3459 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3461 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
3462 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
3463 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
3469 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
3472 static BOOL init_freetype(void)
3474 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
3477 "Wine cannot find the FreeType font library. To enable Wine to\n"
3478 "use TrueType fonts please install a version of FreeType greater than\n"
3479 "or equal to 2.0.5.\n"
3480 "http://www.freetype.org\n");
3484 #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;}
3486 LOAD_FUNCPTR(FT_Done_Face)
3487 LOAD_FUNCPTR(FT_Get_Char_Index)
3488 LOAD_FUNCPTR(FT_Get_First_Char)
3489 LOAD_FUNCPTR(FT_Get_Module)
3490 LOAD_FUNCPTR(FT_Get_Next_Char)
3491 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
3492 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
3493 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
3494 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
3495 LOAD_FUNCPTR(FT_Init_FreeType)
3496 LOAD_FUNCPTR(FT_Library_Version)
3497 LOAD_FUNCPTR(FT_Load_Glyph)
3498 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
3499 LOAD_FUNCPTR(FT_Matrix_Multiply)
3500 #ifndef FT_MULFIX_INLINED
3501 LOAD_FUNCPTR(FT_MulFix)
3503 LOAD_FUNCPTR(FT_New_Face)
3504 LOAD_FUNCPTR(FT_New_Memory_Face)
3505 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
3506 LOAD_FUNCPTR(FT_Outline_Transform)
3507 LOAD_FUNCPTR(FT_Outline_Translate)
3508 LOAD_FUNCPTR(FT_Render_Glyph)
3509 LOAD_FUNCPTR(FT_Select_Charmap)
3510 LOAD_FUNCPTR(FT_Set_Charmap)
3511 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
3512 LOAD_FUNCPTR(FT_Vector_Transform)
3513 LOAD_FUNCPTR(FT_Vector_Unit)
3515 /* Don't warn if these ones are missing */
3516 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
3517 #ifdef HAVE_FREETYPE_FTLCDFIL_H
3518 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
3521 if(pFT_Init_FreeType(&library) != 0) {
3522 ERR("Can't init FreeType library\n");
3523 wine_dlclose(ft_handle, NULL, 0);
3527 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
3529 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
3530 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
3531 ((FT_Version.minor << 8) & 0x00ff00) |
3532 ((FT_Version.patch ) & 0x0000ff);
3534 font_driver = &freetype_funcs;
3539 "Wine cannot find certain functions that it needs inside the FreeType\n"
3540 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3541 "FreeType to at least version 2.1.4.\n"
3542 "http://www.freetype.org\n");
3543 wine_dlclose(ft_handle, NULL, 0);
3548 static void init_font_list(void)
3550 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
3551 static const WCHAR pathW[] = {'P','a','t','h',0};
3553 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
3554 WCHAR windowsdir[MAX_PATH];
3556 const char *data_dir;
3558 delete_external_font_keys();
3560 /* load the system bitmap fonts */
3561 load_system_fonts();
3563 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3564 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3565 strcatW(windowsdir, fontsW);
3566 if((unixname = wine_get_unix_file_name(windowsdir)))
3568 ReadFontDir(unixname, FALSE);
3569 HeapFree(GetProcessHeap(), 0, unixname);
3572 /* load the system truetype fonts */
3573 data_dir = wine_get_data_dir();
3574 if (!data_dir) data_dir = wine_get_build_dir();
3575 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
3577 strcpy(unixname, data_dir);
3578 strcat(unixname, "/fonts/");
3579 ReadFontDir(unixname, TRUE);
3580 HeapFree(GetProcessHeap(), 0, unixname);
3583 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3584 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3585 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3587 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
3588 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
3589 &hkey) == ERROR_SUCCESS)
3591 LPWSTR data, valueW;
3592 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3593 &valuelen, &datalen, NULL, NULL);
3595 valuelen++; /* returned value doesn't include room for '\0' */
3596 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3597 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3600 dlen = datalen * sizeof(WCHAR);
3602 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
3603 &dlen) == ERROR_SUCCESS)
3605 if(data[0] && (data[1] == ':'))
3607 if((unixname = wine_get_unix_file_name(data)))
3609 AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3610 HeapFree(GetProcessHeap(), 0, unixname);
3613 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
3615 WCHAR pathW[MAX_PATH];
3616 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3619 sprintfW(pathW, fmtW, windowsdir, data);
3620 if((unixname = wine_get_unix_file_name(pathW)))
3622 added = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3623 HeapFree(GetProcessHeap(), 0, unixname);
3626 load_font_from_data_dir(data);
3628 /* reset dlen and vlen */
3633 HeapFree(GetProcessHeap(), 0, data);
3634 HeapFree(GetProcessHeap(), 0, valueW);
3638 #ifdef SONAME_LIBFONTCONFIG
3639 load_fontconfig_fonts();
3640 #elif defined(HAVE_CARBON_CARBON_H)
3644 /* then look in any directories that we've specified in the config file */
3645 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3646 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
3652 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
3654 len += sizeof(WCHAR);
3655 valueW = HeapAlloc( GetProcessHeap(), 0, len );
3656 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
3658 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
3659 valueA = HeapAlloc( GetProcessHeap(), 0, len );
3660 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
3661 TRACE( "got font path %s\n", debugstr_a(valueA) );
3666 LPSTR next = strchr( ptr, ':' );
3667 if (next) *next++ = 0;
3668 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
3669 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
3671 strcpy( unixname, home );
3672 strcat( unixname, ptr + 1 );
3673 ReadFontDir( unixname, TRUE );
3674 HeapFree( GetProcessHeap(), 0, unixname );
3677 ReadFontDir( ptr, TRUE );
3680 HeapFree( GetProcessHeap(), 0, valueA );
3682 HeapFree( GetProcessHeap(), 0, valueW );
3688 static BOOL move_to_front(const WCHAR *name)
3690 Family *family, *cursor2;
3691 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
3693 if(!strcmpiW(family->FamilyName, name))
3695 list_remove(&family->entry);
3696 list_add_head(&font_list, &family->entry);
3703 static BOOL set_default(const WCHAR **name_list)
3707 if (move_to_front(*name_list)) return TRUE;
3714 static void reorder_font_list(void)
3716 set_default( default_serif_list );
3717 set_default( default_fixed_list );
3718 set_default( default_sans_list );
3721 /*************************************************************
3724 * Initialize FreeType library and create a list of available faces
3726 BOOL WineEngInit(void)
3728 HKEY hkey_font_cache;
3732 /* update locale dependent font info in registry */
3735 if(!init_freetype()) return FALSE;
3737 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
3739 ERR("Failed to create font mutex\n");
3742 WaitForSingleObject(font_mutex, INFINITE);
3744 create_font_cache_key(&hkey_font_cache, &disposition);
3746 if(disposition == REG_CREATED_NEW_KEY)
3749 load_font_list_from_cache(hkey_font_cache);
3751 RegCloseKey(hkey_font_cache);
3753 reorder_font_list();
3760 if(disposition == REG_CREATED_NEW_KEY)
3761 update_reg_entries();
3763 init_system_links();
3765 ReleaseMutex(font_mutex);
3770 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
3773 TT_HoriHeader *pHori;
3777 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3778 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3780 if(height == 0) height = 16;
3782 /* Calc. height of EM square:
3784 * For +ve lfHeight we have
3785 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3786 * Re-arranging gives:
3787 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3789 * For -ve lfHeight we have
3791 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3792 * with il = winAscent + winDescent - units_per_em]
3797 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
3798 ppem = MulDiv(ft_face->units_per_EM, height,
3799 pHori->Ascender - pHori->Descender);
3801 ppem = MulDiv(ft_face->units_per_EM, height,
3802 pOS2->usWinAscent + pOS2->usWinDescent);
3810 static struct font_mapping *map_font_file( const char *name )
3812 struct font_mapping *mapping;
3816 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
3817 if (fstat( fd, &st ) == -1) goto error;
3819 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
3821 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
3823 mapping->refcount++;
3828 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
3831 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
3834 if (mapping->data == MAP_FAILED)
3836 HeapFree( GetProcessHeap(), 0, mapping );
3839 mapping->refcount = 1;
3840 mapping->dev = st.st_dev;
3841 mapping->ino = st.st_ino;
3842 mapping->size = st.st_size;
3843 list_add_tail( &mappings_list, &mapping->entry );
3851 static void unmap_font_file( struct font_mapping *mapping )
3853 if (!--mapping->refcount)
3855 list_remove( &mapping->entry );
3856 munmap( mapping->data, mapping->size );
3857 HeapFree( GetProcessHeap(), 0, mapping );
3861 static LONG load_VDMX(GdiFont*, LONG);
3863 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
3870 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
3874 if (!(font->mapping = map_font_file( face->file )))
3876 WARN("failed to map %s\n", debugstr_a(face->file));
3879 data_ptr = font->mapping->data;
3880 data_size = font->mapping->size;
3884 data_ptr = face->font_data_ptr;
3885 data_size = face->font_data_size;
3888 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3890 ERR("FT_New_Face rets %d\n", err);
3894 /* set it here, as load_VDMX needs it */
3895 font->ft_face = ft_face;
3897 if(FT_IS_SCALABLE(ft_face)) {
3898 /* load the VDMX table if we have one */
3899 font->ppem = load_VDMX(font, height);
3901 font->ppem = calc_ppem_for_height(ft_face, height);
3902 TRACE("height %d => ppem %d\n", height, font->ppem);
3904 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3905 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3907 font->ppem = height;
3908 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3909 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3915 static int get_nearest_charset(const WCHAR *family_name, Face *face, int *cp)
3917 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3918 a single face with the requested charset. The idea is to check if
3919 the selected font supports the current ANSI codepage, if it does
3920 return the corresponding charset, else return the first charset */
3923 int acp = GetACP(), i;
3927 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3929 const SYSTEM_LINKS *font_link;
3931 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
3932 return csi.ciCharset;
3934 font_link = find_font_link(family_name);
3935 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
3936 return csi.ciCharset;
3939 for(i = 0; i < 32; i++) {
3941 if(face->fs.fsCsb[0] & fs0) {
3942 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
3944 return csi.ciCharset;
3947 FIXME("TCI failing on %x\n", fs0);
3951 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3952 face->fs.fsCsb[0], face->file);
3954 return DEFAULT_CHARSET;
3957 static GdiFont *alloc_font(void)
3959 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
3961 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
3962 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3964 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3965 ret->total_kern_pairs = (DWORD)-1;
3966 ret->kern_pairs = NULL;
3967 list_init(&ret->hfontlist);
3968 list_init(&ret->child_fonts);
3972 static void free_font(GdiFont *font)
3974 struct list *cursor, *cursor2;
3977 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
3979 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
3980 list_remove(cursor);
3982 free_font(child->font);
3983 HeapFree(GetProcessHeap(), 0, child);
3986 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->hfontlist)
3988 HFONTLIST *hfontlist = LIST_ENTRY(cursor, HFONTLIST, entry);
3989 DeleteObject(hfontlist->hfont);
3990 list_remove(&hfontlist->entry);
3991 HeapFree(GetProcessHeap(), 0, hfontlist);
3994 if (font->ft_face) pFT_Done_Face(font->ft_face);
3995 if (font->mapping) unmap_font_file( font->mapping );
3996 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
3997 HeapFree(GetProcessHeap(), 0, font->potm);
3998 HeapFree(GetProcessHeap(), 0, font->name);
3999 for (i = 0; i < font->gmsize; i++)
4000 HeapFree(GetProcessHeap(),0,font->gm[i]);
4001 HeapFree(GetProcessHeap(), 0, font->gm);
4002 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
4003 HeapFree(GetProcessHeap(), 0, font);
4007 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
4009 FT_Face ft_face = font->ft_face;
4013 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
4020 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
4022 /* make sure value of len is the value freetype says it needs */
4025 FT_ULong needed = 0;
4026 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
4027 if( !err && needed < len) len = needed;
4029 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
4032 TRACE("Can't find table %c%c%c%c\n",
4033 /* bytes were reversed */
4034 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
4035 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
4041 /*************************************************************
4044 * load the vdmx entry for the specified height
4047 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
4048 ( ( (FT_ULong)_x4 << 24 ) | \
4049 ( (FT_ULong)_x3 << 16 ) | \
4050 ( (FT_ULong)_x2 << 8 ) | \
4053 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
4068 static LONG load_VDMX(GdiFont *font, LONG height)
4072 BYTE devXRatio, devYRatio;
4073 USHORT numRecs, numRatios;
4074 DWORD result, offset = -1;
4078 result = get_font_data(font, MS_VDMX_TAG, 0, hdr, 6);
4080 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
4083 /* FIXME: need the real device aspect ratio */
4087 numRecs = GET_BE_WORD(hdr[1]);
4088 numRatios = GET_BE_WORD(hdr[2]);
4090 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
4091 for(i = 0; i < numRatios; i++) {
4094 offset = (3 * 2) + (i * sizeof(Ratios));
4095 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
4098 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
4100 if((ratio.xRatio == 0 &&
4101 ratio.yStartRatio == 0 &&
4102 ratio.yEndRatio == 0) ||
4103 (devXRatio == ratio.xRatio &&
4104 devYRatio >= ratio.yStartRatio &&
4105 devYRatio <= ratio.yEndRatio))
4107 offset = (3 * 2) + (numRatios * 4) + (i * 2);
4108 get_font_data(font, MS_VDMX_TAG, offset, &tmp, 2);
4109 offset = GET_BE_WORD(tmp);
4115 FIXME("No suitable ratio found\n");
4119 if(get_font_data(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
4121 BYTE startsz, endsz;
4124 recs = GET_BE_WORD(group.recs);
4125 startsz = group.startsz;
4126 endsz = group.endsz;
4128 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
4130 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
4131 result = get_font_data(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
4132 if(result == GDI_ERROR) {
4133 FIXME("Failed to retrieve vTable\n");
4138 for(i = 0; i < recs; i++) {
4139 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4140 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4141 ppem = GET_BE_WORD(vTable[i * 3]);
4143 if(yMax + -yMin == height) {
4146 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4149 if(yMax + -yMin > height) {
4152 goto end; /* failed */
4154 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4155 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4156 ppem = GET_BE_WORD(vTable[i * 3]);
4157 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4163 TRACE("ppem not found for height %d\n", height);
4167 HeapFree(GetProcessHeap(), 0, vTable);
4173 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
4175 if(font->font_desc.hash != fd->hash) return TRUE;
4176 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
4177 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
4178 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
4179 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
4182 static void calc_hash(FONT_DESC *pfd)
4184 DWORD hash = 0, *ptr, two_chars;
4188 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
4190 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
4192 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
4194 pwc = (WCHAR *)&two_chars;
4196 *pwc = toupperW(*pwc);
4198 *pwc = toupperW(*pwc);
4202 hash ^= !pfd->can_use_bitmap;
4207 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
4212 struct list *font_elem_ptr, *hfontlist_elem_ptr;
4216 fd.can_use_bitmap = can_use_bitmap;
4219 /* try the child list */
4220 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
4221 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4222 if(!fontcmp(ret, &fd)) {
4223 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4224 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
4225 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4226 if(hflist->hfont == hfont)
4232 /* try the in-use list */
4233 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
4234 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4235 if(!fontcmp(ret, &fd)) {
4236 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4237 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
4238 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4239 if(hflist->hfont == hfont)
4242 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
4243 hflist->hfont = hfont;
4244 list_add_head(&ret->hfontlist, &hflist->entry);
4249 /* then the unused list */
4250 font_elem_ptr = list_head(&unused_gdi_font_list);
4251 while(font_elem_ptr) {
4252 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4253 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4254 if(!fontcmp(ret, &fd)) {
4255 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4256 assert(list_empty(&ret->hfontlist));
4257 TRACE("Found %p in unused list\n", ret);
4258 list_remove(&ret->entry);
4259 list_add_head(&gdi_font_list, &ret->entry);
4260 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
4261 hflist->hfont = hfont;
4262 list_add_head(&ret->hfontlist, &hflist->entry);
4269 static void add_to_cache(GdiFont *font)
4271 static DWORD cache_num = 1;
4273 font->cache_num = cache_num++;
4274 list_add_head(&gdi_font_list, &font->entry);
4277 /*************************************************************
4278 * create_child_font_list
4280 static BOOL create_child_font_list(GdiFont *font)
4283 SYSTEM_LINKS *font_link;
4284 CHILD_FONT *font_link_entry, *new_child;
4288 psub = get_font_subst(&font_subst_list, font->name, -1);
4289 font_name = psub ? psub->to.name : font->name;
4290 font_link = find_font_link(font_name);
4291 if (font_link != NULL)
4293 TRACE("found entry in system list\n");
4294 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4296 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4297 new_child->face = font_link_entry->face;
4298 new_child->font = NULL;
4299 list_add_tail(&font->child_fonts, &new_child->entry);
4300 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
4305 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
4306 * Sans Serif. This is how asian windows get default fallbacks for fonts
4308 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
4309 font->charset != OEM_CHARSET &&
4310 strcmpiW(font_name,szDefaultFallbackLink) != 0)
4312 font_link = find_font_link(szDefaultFallbackLink);
4313 if (font_link != NULL)
4315 TRACE("found entry in default fallback list\n");
4316 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4318 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4319 new_child->face = font_link_entry->face;
4320 new_child->font = NULL;
4321 list_add_tail(&font->child_fonts, &new_child->entry);
4322 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
4331 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
4333 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
4335 if (pFT_Set_Charmap)
4338 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
4340 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
4342 for (i = 0; i < ft_face->num_charmaps; i++)
4344 if (ft_face->charmaps[i]->encoding == encoding)
4346 TRACE("found cmap with platform_id %u, encoding_id %u\n",
4347 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
4349 switch (ft_face->charmaps[i]->platform_id)
4352 cmap_def = ft_face->charmaps[i];
4354 case 0: /* Apple Unicode */
4355 cmap0 = ft_face->charmaps[i];
4357 case 1: /* Macintosh */
4358 cmap1 = ft_face->charmaps[i];
4361 cmap2 = ft_face->charmaps[i];
4363 case 3: /* Microsoft */
4364 cmap3 = ft_face->charmaps[i];
4369 if (cmap3) /* prefer Microsoft cmap table */
4370 ft_err = pFT_Set_Charmap(ft_face, cmap3);
4372 ft_err = pFT_Set_Charmap(ft_face, cmap1);
4374 ft_err = pFT_Set_Charmap(ft_face, cmap2);
4376 ft_err = pFT_Set_Charmap(ft_face, cmap0);
4378 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
4380 return ft_err == FT_Err_Ok;
4383 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
4387 /*************************************************************
4390 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
4391 LPCWSTR output, const DEVMODEW *devmode )
4393 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
4395 if (!physdev) return FALSE;
4396 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
4401 /*************************************************************
4404 static BOOL freetype_DeleteDC( PHYSDEV dev )
4406 struct freetype_physdev *physdev = get_freetype_dev( dev );
4407 HeapFree( GetProcessHeap(), 0, physdev );
4411 static FT_Encoding pick_charmap( FT_Face face, int charset )
4413 static const FT_Encoding regular_order[] = { FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, FT_ENCODING_MS_SYMBOL, 0 };
4414 static const FT_Encoding symbol_order[] = { FT_ENCODING_MS_SYMBOL, FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, 0 };
4415 const FT_Encoding *encs = regular_order;
4417 if (charset == SYMBOL_CHARSET) encs = symbol_order;
4421 if (select_charmap( face, *encs )) break;
4427 /*************************************************************
4428 * freetype_SelectFont
4430 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont )
4432 struct freetype_physdev *physdev = get_freetype_dev( dev );
4434 Face *face, *best, *best_bitmap;
4435 Family *family, *last_resort_family;
4436 const struct list *family_elem_ptr, *face_list, *face_elem_ptr;
4437 INT height, width = 0;
4438 unsigned int score = 0, new_score;
4439 signed int diff = 0, newdiff;
4440 BOOL bd, it, can_use_bitmap, want_vertical;
4445 FontSubst *psub = NULL;
4446 DC *dc = get_dc_ptr( dev->hdc );
4447 const SYSTEM_LINKS *font_link;
4449 if (!hfont) /* notification that the font has been changed by another driver */
4452 physdev->font = NULL;
4453 release_dc_ptr( dc );
4457 GetObjectW( hfont, sizeof(lf), &lf );
4458 lf.lfWidth = abs(lf.lfWidth);
4460 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
4462 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
4463 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
4464 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
4467 if(dc->GraphicsMode == GM_ADVANCED)
4469 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
4470 /* Try to avoid not necessary glyph transformations */
4471 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
4473 lf.lfHeight *= fabs(dcmat.eM11);
4474 lf.lfWidth *= fabs(dcmat.eM11);
4475 dcmat.eM11 = dcmat.eM22 = 1.0;
4480 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
4481 font scaling abilities. */
4482 dcmat.eM11 = dcmat.eM22 = 1.0;
4483 dcmat.eM21 = dcmat.eM12 = 0;
4484 if (dc->vport2WorldValid)
4486 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
4487 lf.lfOrientation = -lf.lfOrientation;
4488 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
4489 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
4493 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
4494 dcmat.eM21, dcmat.eM22);
4497 EnterCriticalSection( &freetype_cs );
4499 /* check the cache first */
4500 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4501 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
4505 if(list_empty(&font_list)) /* No fonts installed */
4507 TRACE("No fonts installed\n");
4511 TRACE("not in cache\n");
4514 ret->font_desc.matrix = dcmat;
4515 ret->font_desc.lf = lf;
4516 ret->font_desc.can_use_bitmap = can_use_bitmap;
4517 calc_hash(&ret->font_desc);
4518 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
4519 hflist->hfont = hfont;
4520 list_add_head(&ret->hfontlist, &hflist->entry);
4522 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4523 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4524 original value lfCharSet. Note this is a special case for
4525 Symbol and doesn't happen at least for "Wingdings*" */
4527 if(!strcmpiW(lf.lfFaceName, SymbolW))
4528 lf.lfCharSet = SYMBOL_CHARSET;
4530 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
4531 switch(lf.lfCharSet) {
4532 case DEFAULT_CHARSET:
4533 csi.fs.fsCsb[0] = 0;
4536 FIXME("Untranslated charset %d\n", lf.lfCharSet);
4537 csi.fs.fsCsb[0] = 0;
4543 if(lf.lfFaceName[0] != '\0') {
4544 CHILD_FONT *font_link_entry;
4545 LPWSTR FaceName = lf.lfFaceName;
4547 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
4550 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
4551 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
4552 if (psub->to.charset != -1)
4553 lf.lfCharSet = psub->to.charset;
4556 /* We want a match on name and charset or just name if
4557 charset was DEFAULT_CHARSET. If the latter then
4558 we fixup the returned charset later in get_nearest_charset
4559 where we'll either use the charset of the current ansi codepage
4560 or if that's unavailable the first charset that the font supports.
4562 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4563 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4564 if (!strcmpiW(family->FamilyName, FaceName) ||
4565 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
4567 font_link = find_font_link(family->FamilyName);
4568 face_list = get_face_list_from_family(family);
4569 LIST_FOR_EACH(face_elem_ptr, face_list) {
4570 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4571 if (!(face->scalable || can_use_bitmap))
4573 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4575 if (font_link != NULL &&
4576 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4578 if (!csi.fs.fsCsb[0])
4584 /* Search by full face name. */
4585 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4586 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4587 face_list = get_face_list_from_family(family);
4588 LIST_FOR_EACH(face_elem_ptr, face_list) {
4589 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4590 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
4591 (face->scalable || can_use_bitmap))
4593 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4595 font_link = find_font_link(family->FamilyName);
4596 if (font_link != NULL &&
4597 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4604 * Try check the SystemLink list first for a replacement font.
4605 * We may find good replacements there.
4607 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
4609 if(!strcmpiW(font_link->font_name, FaceName) ||
4610 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
4612 TRACE("found entry in system list\n");
4613 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4615 const SYSTEM_LINKS *links;
4617 face = font_link_entry->face;
4618 if (!(face->scalable || can_use_bitmap))
4620 family = face->family;
4621 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4623 links = find_font_link(family->FamilyName);
4624 if (links != NULL && csi.fs.fsCsb[0] & links->fs.fsCsb[0])
4631 psub = NULL; /* substitution is no more relevant */
4633 /* If requested charset was DEFAULT_CHARSET then try using charset
4634 corresponding to the current ansi codepage */
4635 if (!csi.fs.fsCsb[0])
4638 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
4639 FIXME("TCI failed on codepage %d\n", acp);
4640 csi.fs.fsCsb[0] = 0;
4642 lf.lfCharSet = csi.ciCharset;
4645 want_vertical = (lf.lfFaceName[0] == '@');
4647 /* Face families are in the top 4 bits of lfPitchAndFamily,
4648 so mask with 0xF0 before testing */
4650 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
4651 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
4652 strcpyW(lf.lfFaceName, defFixed);
4653 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
4654 strcpyW(lf.lfFaceName, defSerif);
4655 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
4656 strcpyW(lf.lfFaceName, defSans);
4658 strcpyW(lf.lfFaceName, defSans);
4659 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4660 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4661 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
4662 font_link = find_font_link(family->FamilyName);
4663 face_list = get_face_list_from_family(family);
4664 LIST_FOR_EACH(face_elem_ptr, face_list) {
4665 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4666 if (!(face->scalable || can_use_bitmap))
4668 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4670 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4676 last_resort_family = NULL;
4677 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4678 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4679 font_link = find_font_link(family->FamilyName);
4680 face_list = get_face_list_from_family(family);
4681 LIST_FOR_EACH(face_elem_ptr, face_list) {
4682 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4683 if(face->vertical == want_vertical &&
4684 (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4685 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]))) {
4688 if(can_use_bitmap && !last_resort_family)
4689 last_resort_family = family;
4694 if(last_resort_family) {
4695 family = last_resort_family;
4696 csi.fs.fsCsb[0] = 0;
4700 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4701 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4702 face_list = get_face_list_from_family(family);
4703 LIST_FOR_EACH(face_elem_ptr, face_list) {
4704 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4705 if(face->scalable && face->vertical == want_vertical) {
4706 csi.fs.fsCsb[0] = 0;
4707 WARN("just using first face for now\n");
4710 if(can_use_bitmap && !last_resort_family)
4711 last_resort_family = family;
4714 if(!last_resort_family) {
4715 FIXME("can't find a single appropriate font - bailing\n");
4721 WARN("could only find a bitmap font - this will probably look awful!\n");
4722 family = last_resort_family;
4723 csi.fs.fsCsb[0] = 0;
4726 it = lf.lfItalic ? 1 : 0;
4727 bd = lf.lfWeight > 550 ? 1 : 0;
4729 height = lf.lfHeight;
4731 face = best = best_bitmap = NULL;
4732 font_link = find_font_link(family->FamilyName);
4733 face_list = get_face_list_from_family(family);
4734 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
4736 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4737 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]) ||
4742 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
4743 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
4744 new_score = (italic ^ it) + (bold ^ bd);
4745 if(!best || new_score <= score)
4747 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4748 italic, bold, it, bd);
4751 if(best->scalable && score == 0) break;
4755 newdiff = height - (signed int)(best->size.height);
4757 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
4758 if(!best_bitmap || new_score < score ||
4759 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
4761 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
4764 if(score == 0 && diff == 0) break;
4771 face = best->scalable ? best : best_bitmap;
4772 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
4773 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
4776 height = lf.lfHeight;
4780 if(csi.fs.fsCsb[0]) {
4781 ret->charset = lf.lfCharSet;
4782 ret->codepage = csi.ciACP;
4785 ret->charset = get_nearest_charset(family->FamilyName, face, &ret->codepage);
4787 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
4788 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
4790 ret->aveWidth = height ? lf.lfWidth : 0;
4792 if(!face->scalable) {
4793 /* Windows uses integer scaling factors for bitmap fonts */
4794 INT scale, scaled_height;
4795 GdiFont *cachedfont;
4797 /* FIXME: rotation of bitmap fonts is ignored */
4798 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
4800 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
4801 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4802 dcmat.eM11 = dcmat.eM22 = 1.0;
4803 /* As we changed the matrix, we need to search the cache for the font again,
4804 * otherwise we might explode the cache. */
4805 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4806 TRACE("Found cached font after non-scalable matrix rescale!\n");
4811 calc_hash(&ret->font_desc);
4813 if (height != 0) height = diff;
4814 height += face->size.height;
4816 scale = (height + face->size.height - 1) / face->size.height;
4817 scaled_height = scale * face->size.height;
4818 /* Only jump to the next height if the difference <= 25% original height */
4819 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
4820 /* The jump between unscaled and doubled is delayed by 1 */
4821 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
4822 ret->scale_y = scale;
4824 width = face->size.x_ppem >> 6;
4825 height = face->size.y_ppem >> 6;
4829 TRACE("font scale y: %f\n", ret->scale_y);
4831 ret->ft_face = OpenFontFace(ret, face, width, height);
4840 ret->ntmFlags = face->ntmFlags;
4842 pick_charmap( ret->ft_face, ret->charset );
4844 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
4845 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
4846 ret->underline = lf.lfUnderline ? 0xff : 0;
4847 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
4848 create_child_font_list(ret);
4850 if (face->vertical) /* We need to try to load the GSUB table */
4852 int length = get_font_data(ret, GSUB_TAG , 0, NULL, 0);
4853 if (length != GDI_ERROR)
4855 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
4856 get_font_data(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
4857 TRACE("Loaded GSUB table of %i bytes\n",length);
4861 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
4868 physdev->font = ret;
4870 LeaveCriticalSection( &freetype_cs );
4871 release_dc_ptr( dc );
4872 return ret ? hfont : 0;
4875 static void dump_gdi_font_list(void)
4878 struct list *elem_ptr;
4880 TRACE("---------- gdiFont Cache ----------\n");
4881 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
4882 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4883 TRACE("gdiFont=%p %s %d\n",
4884 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4887 TRACE("---------- Unused gdiFont Cache ----------\n");
4888 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
4889 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4890 TRACE("gdiFont=%p %s %d\n",
4891 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4894 TRACE("---------- Child gdiFont Cache ----------\n");
4895 LIST_FOR_EACH(elem_ptr, &child_font_list) {
4896 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4897 TRACE("gdiFont=%p %s %d\n",
4898 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4902 /*************************************************************
4903 * WineEngDestroyFontInstance
4905 * free the gdiFont associated with this handle
4908 BOOL WineEngDestroyFontInstance(HFONT handle)
4913 struct list *font_elem_ptr, *hfontlist_elem_ptr;
4917 EnterCriticalSection( &freetype_cs );
4919 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
4921 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4922 while(hfontlist_elem_ptr) {
4923 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4924 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4925 if(hflist->hfont == handle) {
4926 TRACE("removing child font %p from child list\n", gdiFont);
4927 list_remove(&gdiFont->entry);
4928 LeaveCriticalSection( &freetype_cs );
4934 TRACE("destroying hfont=%p\n", handle);
4936 dump_gdi_font_list();
4938 font_elem_ptr = list_head(&gdi_font_list);
4939 while(font_elem_ptr) {
4940 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4941 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
4943 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4944 while(hfontlist_elem_ptr) {
4945 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4946 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4947 if(hflist->hfont == handle) {
4948 list_remove(&hflist->entry);
4949 HeapFree(GetProcessHeap(), 0, hflist);
4953 if(list_empty(&gdiFont->hfontlist)) {
4954 TRACE("Moving to Unused list\n");
4955 list_remove(&gdiFont->entry);
4956 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
4961 font_elem_ptr = list_head(&unused_gdi_font_list);
4962 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
4963 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4964 while(font_elem_ptr) {
4965 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4966 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4967 TRACE("freeing %p\n", gdiFont);
4968 list_remove(&gdiFont->entry);
4971 LeaveCriticalSection( &freetype_cs );
4975 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
4982 id += IDS_FIRST_SCRIPT;
4983 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
4984 if (!rsrc) return 0;
4985 hMem = LoadResource( gdi32_module, rsrc );
4986 if (!hMem) return 0;
4988 p = LockResource( hMem );
4990 while (id--) p += *p + 1;
4992 i = min(LF_FACESIZE - 1, *p);
4993 memcpy(buffer, p + 1, i * sizeof(WCHAR));
4999 /***************************************************
5000 * create_enum_charset_list
5002 * This function creates charset enumeration list because in DEFAULT_CHARSET
5003 * case, the ANSI codepage's charset takes precedence over other charsets.
5004 * This function works as a filter other than DEFAULT_CHARSET case.
5006 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
5011 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
5012 csi.fs.fsCsb[0] != 0) {
5013 list->element[n].mask = csi.fs.fsCsb[0];
5014 list->element[n].charset = csi.ciCharset;
5015 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5018 else { /* charset is DEFAULT_CHARSET or invalid. */
5022 /* Set the current codepage's charset as the first element. */
5024 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
5025 csi.fs.fsCsb[0] != 0) {
5026 list->element[n].mask = csi.fs.fsCsb[0];
5027 list->element[n].charset = csi.ciCharset;
5028 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5029 mask |= csi.fs.fsCsb[0];
5033 /* Fill out left elements. */
5034 for (i = 0; i < 32; i++) {
5036 fs.fsCsb[0] = 1L << i;
5038 if (fs.fsCsb[0] & mask)
5039 continue; /* skip, already added. */
5040 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
5041 continue; /* skip, this is an invalid fsCsb bit. */
5043 list->element[n].mask = fs.fsCsb[0];
5044 list->element[n].charset = csi.ciCharset;
5045 load_script_name( i, list->element[n].name );
5046 mask |= fs.fsCsb[0];
5050 /* add catch all mask for remaining bits */
5053 list->element[n].mask = ~mask;
5054 list->element[n].charset = DEFAULT_CHARSET;
5055 load_script_name( IDS_OTHER - IDS_FIRST_SCRIPT, list->element[n].name );
5064 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
5065 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
5070 if (face->cached_enum_data)
5073 *pelf = face->cached_enum_data->elf;
5074 *pntm = face->cached_enum_data->ntm;
5075 *ptype = face->cached_enum_data->type;
5079 font = alloc_font();
5081 if(face->scalable) {
5085 height = face->size.y_ppem >> 6;
5086 width = face->size.x_ppem >> 6;
5088 font->scale_y = 1.0;
5090 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
5096 font->name = strdupW(face->family->FamilyName);
5097 font->ntmFlags = face->ntmFlags;
5099 if (get_outline_text_metrics(font))
5101 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
5103 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
5104 pntm->ntmTm.ntmCellHeight = font->ntmCellHeight;
5105 pntm->ntmTm.ntmAvgWidth = font->ntmAvgWidth;
5107 lstrcpynW(pelf->elfLogFont.lfFaceName,
5108 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
5110 lstrcpynW(pelf->elfFullName,
5111 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
5113 lstrcpynW(pelf->elfStyle,
5114 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
5119 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
5121 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
5122 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
5123 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
5125 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
5127 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
5129 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
5130 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
5133 pntm->ntmTm.ntmFlags = face->ntmFlags;
5134 pntm->ntmFontSig = face->fs;
5136 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
5138 pelf->elfLogFont.lfEscapement = 0;
5139 pelf->elfLogFont.lfOrientation = 0;
5140 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
5141 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
5142 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
5143 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
5144 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
5145 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
5146 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
5147 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
5148 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
5149 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
5150 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
5153 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
5154 *ptype |= TRUETYPE_FONTTYPE;
5155 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
5156 *ptype |= DEVICE_FONTTYPE;
5157 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
5158 *ptype |= RASTER_FONTTYPE;
5160 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
5161 if (face->cached_enum_data)
5163 face->cached_enum_data->elf = *pelf;
5164 face->cached_enum_data->ntm = *pntm;
5165 face->cached_enum_data->type = *ptype;
5171 static BOOL family_matches(Family *family, const LOGFONTW *lf)
5173 const struct list *face_list, *face_elem_ptr;
5175 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
5177 face_list = get_face_list_from_family(family);
5178 LIST_FOR_EACH(face_elem_ptr, face_list)
5180 Face *face = LIST_ENTRY(face_elem_ptr, Face, entry);
5182 if (face->FullName && !strcmpiW(lf->lfFaceName, face->FullName)) return TRUE;
5188 static BOOL face_matches(const WCHAR *family_name, Face *face, const LOGFONTW *lf)
5190 if (!strcmpiW(lf->lfFaceName, family_name)) return TRUE;
5192 return (face->FullName && !strcmpiW(lf->lfFaceName, face->FullName));
5195 static BOOL enum_face_charsets(const Family *family, Face *face, struct enum_charset_list *list,
5196 FONTENUMPROCW proc, LPARAM lparam)
5199 NEWTEXTMETRICEXW ntm;
5203 GetEnumStructs(face, &elf, &ntm, &type);
5204 for(i = 0; i < list->total; i++) {
5205 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
5206 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
5207 load_script_name( IDS_OEM_DOS - IDS_FIRST_SCRIPT, elf.elfScript );
5208 i = list->total; /* break out of loop after enumeration */
5212 if(!(face->fs.fsCsb[0] & list->element[i].mask)) continue;
5213 /* use the DEFAULT_CHARSET case only if no other charset is present */
5214 if (list->element[i].charset == DEFAULT_CHARSET &&
5215 (face->fs.fsCsb[0] & ~list->element[i].mask)) continue;
5216 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
5217 strcpyW(elf.elfScript, list->element[i].name);
5218 if (!elf.elfScript[0])
5219 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
5221 /* Font Replacement */
5222 if (family != face->family)
5224 strcpyW(elf.elfLogFont.lfFaceName, family->FamilyName);
5226 strcpyW(elf.elfFullName, face->FullName);
5228 strcpyW(elf.elfFullName, family->FamilyName);
5230 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
5231 debugstr_w(elf.elfLogFont.lfFaceName),
5232 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
5233 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
5234 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
5235 ntm.ntmTm.ntmFlags);
5236 /* release section before callback (FIXME) */
5237 LeaveCriticalSection( &freetype_cs );
5238 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
5239 EnterCriticalSection( &freetype_cs );
5244 /*************************************************************
5245 * freetype_EnumFonts
5247 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
5251 const struct list *family_elem_ptr, *face_list, *face_elem_ptr;
5253 struct enum_charset_list enum_charsets;
5257 lf.lfCharSet = DEFAULT_CHARSET;
5258 lf.lfPitchAndFamily = 0;
5259 lf.lfFaceName[0] = 0;
5263 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
5265 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
5268 EnterCriticalSection( &freetype_cs );
5269 if(plf->lfFaceName[0]) {
5271 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
5274 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
5275 debugstr_w(psub->to.name));
5277 strcpyW(lf.lfFaceName, psub->to.name);
5281 LIST_FOR_EACH(family_elem_ptr, &font_list) {
5282 family = LIST_ENTRY(family_elem_ptr, Family, entry);
5283 if(family_matches(family, plf)) {
5284 face_list = get_face_list_from_family(family);
5285 LIST_FOR_EACH(face_elem_ptr, face_list) {
5286 face = LIST_ENTRY(face_elem_ptr, Face, entry);
5287 if (!face_matches(family->FamilyName, face, plf)) continue;
5288 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
5293 LIST_FOR_EACH(family_elem_ptr, &font_list) {
5294 family = LIST_ENTRY(family_elem_ptr, Family, entry);
5295 face_list = get_face_list_from_family(family);
5296 face_elem_ptr = list_head(face_list);
5297 face = LIST_ENTRY(face_elem_ptr, Face, entry);
5298 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
5301 LeaveCriticalSection( &freetype_cs );
5305 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
5307 pt->x.value = vec->x >> 6;
5308 pt->x.fract = (vec->x & 0x3f) << 10;
5309 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
5310 pt->y.value = vec->y >> 6;
5311 pt->y.fract = (vec->y & 0x3f) << 10;
5312 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
5316 /***************************************************
5317 * According to the MSDN documentation on WideCharToMultiByte,
5318 * certain codepages cannot set the default_used parameter.
5319 * This returns TRUE if the codepage can set that parameter, false else
5320 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
5322 static BOOL codepage_sets_default_used(UINT codepage)
5336 * GSUB Table handling functions
5339 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
5341 const GSUB_CoverageFormat1* cf1;
5345 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
5347 int count = GET_BE_WORD(cf1->GlyphCount);
5349 TRACE("Coverage Format 1, %i glyphs\n",count);
5350 for (i = 0; i < count; i++)
5351 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
5355 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
5357 const GSUB_CoverageFormat2* cf2;
5360 cf2 = (const GSUB_CoverageFormat2*)cf1;
5362 count = GET_BE_WORD(cf2->RangeCount);
5363 TRACE("Coverage Format 2, %i ranges\n",count);
5364 for (i = 0; i < count; i++)
5366 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
5368 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
5369 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
5371 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
5372 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
5378 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
5383 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
5385 const GSUB_ScriptList *script;
5386 const GSUB_Script *deflt = NULL;
5388 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
5390 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
5391 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
5393 const GSUB_Script *scr;
5396 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
5397 scr = (const GSUB_Script*)((const BYTE*)script + offset);
5399 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
5401 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
5407 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
5411 const GSUB_LangSys *Lang;
5413 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
5415 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
5417 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
5418 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5420 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
5423 offset = GET_BE_WORD(script->DefaultLangSys);
5426 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5432 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
5435 const GSUB_FeatureList *feature;
5436 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
5438 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
5439 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
5441 int index = GET_BE_WORD(lang->FeatureIndex[i]);
5442 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
5444 const GSUB_Feature *feat;
5445 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
5452 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
5456 const GSUB_LookupList *lookup;
5457 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
5459 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
5460 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
5462 const GSUB_LookupTable *look;
5463 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
5464 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
5465 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
5466 if (GET_BE_WORD(look->LookupType) != 1)
5467 FIXME("We only handle SubType 1\n");
5472 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
5474 const GSUB_SingleSubstFormat1 *ssf1;
5475 offset = GET_BE_WORD(look->SubTable[j]);
5476 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
5477 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
5479 int offset = GET_BE_WORD(ssf1->Coverage);
5480 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
5481 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
5483 TRACE(" Glyph 0x%x ->",glyph);
5484 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
5485 TRACE(" 0x%x\n",glyph);
5490 const GSUB_SingleSubstFormat2 *ssf2;
5494 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
5495 offset = GET_BE_WORD(ssf1->Coverage);
5496 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
5497 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
5498 TRACE(" Coverage index %i\n",index);
5501 TRACE(" Glyph is 0x%x ->",glyph);
5502 glyph = GET_BE_WORD(ssf2->Substitute[index]);
5503 TRACE("0x%x\n",glyph);
5512 static const char* get_opentype_script(const GdiFont *font)
5515 * I am not sure if this is the correct way to generate our script tag
5518 switch (font->charset)
5520 case ANSI_CHARSET: return "latn";
5521 case BALTIC_CHARSET: return "latn"; /* ?? */
5522 case CHINESEBIG5_CHARSET: return "hani";
5523 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
5524 case GB2312_CHARSET: return "hani";
5525 case GREEK_CHARSET: return "grek";
5526 case HANGUL_CHARSET: return "hang";
5527 case RUSSIAN_CHARSET: return "cyrl";
5528 case SHIFTJIS_CHARSET: return "kana";
5529 case TURKISH_CHARSET: return "latn"; /* ?? */
5530 case VIETNAMESE_CHARSET: return "latn";
5531 case JOHAB_CHARSET: return "latn"; /* ?? */
5532 case ARABIC_CHARSET: return "arab";
5533 case HEBREW_CHARSET: return "hebr";
5534 case THAI_CHARSET: return "thai";
5535 default: return "latn";
5539 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
5541 const GSUB_Header *header;
5542 const GSUB_Script *script;
5543 const GSUB_LangSys *language;
5544 const GSUB_Feature *feature;
5546 if (!font->GSUB_Table)
5549 header = font->GSUB_Table;
5551 script = GSUB_get_script_table(header, get_opentype_script(font));
5554 TRACE("Script not found\n");
5557 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
5560 TRACE("Language not found\n");
5563 feature = GSUB_get_feature(header, language, "vrt2");
5565 feature = GSUB_get_feature(header, language, "vert");
5568 TRACE("vrt2/vert feature not found\n");
5571 return GSUB_apply_feature(header, feature, glyph);
5574 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
5578 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
5579 WCHAR wc = (WCHAR)glyph;
5581 BOOL *default_used_pointer;
5584 default_used_pointer = NULL;
5585 default_used = FALSE;
5586 if (codepage_sets_default_used(font->codepage))
5587 default_used_pointer = &default_used;
5588 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
5590 if (font->codepage == CP_SYMBOL && wc < 0x100)
5591 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)wc);
5596 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
5597 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
5601 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
5603 if (glyph < 0x100) glyph += 0xf000;
5604 /* there is a number of old pre-Unicode "broken" TTFs, which
5605 do have symbols at U+00XX instead of U+f0XX */
5606 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
5607 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
5609 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
5614 /*************************************************************
5615 * freetype_GetGlyphIndices
5617 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
5619 struct freetype_physdev *physdev = get_freetype_dev( dev );
5622 BOOL got_default = FALSE;
5626 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
5627 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
5630 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
5632 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
5637 EnterCriticalSection( &freetype_cs );
5639 for(i = 0; i < count; i++)
5641 pgi[i] = get_glyph_index(physdev->font, lpstr[i]);
5646 if (FT_IS_SFNT(physdev->font->ft_face))
5648 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(physdev->font->ft_face, ft_sfnt_os2);
5649 default_char = (pOS2->usDefaultChar ? get_glyph_index(physdev->font, pOS2->usDefaultChar) : 0);
5654 get_text_metrics(physdev->font, &textm);
5655 default_char = textm.tmDefaultChar;
5659 pgi[i] = default_char;
5662 LeaveCriticalSection( &freetype_cs );
5666 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
5668 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
5669 return !memcmp(matrix, &identity, sizeof(FMAT2));
5672 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
5674 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
5675 return !memcmp(matrix, &identity, sizeof(MAT2));
5678 static inline BYTE get_max_level( UINT format )
5682 case GGO_GRAY2_BITMAP: return 4;
5683 case GGO_GRAY4_BITMAP: return 16;
5684 case GGO_GRAY8_BITMAP: return 64;
5689 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5691 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
5692 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5695 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
5696 FT_Face ft_face = incoming_font->ft_face;
5697 GdiFont *font = incoming_font;
5698 FT_UInt glyph_index;
5699 DWORD width, height, pitch, needed = 0;
5700 FT_Bitmap ft_bitmap;
5702 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
5704 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
5705 double widthRatio = 1.0;
5706 FT_Matrix transMat = identityMat;
5707 FT_Matrix transMatUnrotated;
5708 BOOL needsTransform = FALSE;
5709 BOOL tategaki = (font->GSUB_Table != NULL);
5710 UINT original_index;
5712 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
5713 buflen, buf, lpmat);
5715 TRACE("font transform %f %f %f %f\n",
5716 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
5717 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
5719 if(format & GGO_GLYPH_INDEX) {
5720 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
5721 original_index = glyph;
5722 format &= ~GGO_GLYPH_INDEX;
5724 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
5725 ft_face = font->ft_face;
5726 original_index = glyph_index;
5729 if(format & GGO_UNHINTED) {
5730 load_flags |= FT_LOAD_NO_HINTING;
5731 format &= ~GGO_UNHINTED;
5734 /* tategaki never appears to happen to lower glyph index */
5735 if (glyph_index < TATEGAKI_LOWER_BOUND )
5738 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
5739 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
5740 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
5741 font->gmsize * sizeof(GM*));
5743 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
5744 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
5746 *lpgm = FONT_GM(font,original_index)->gm;
5747 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5748 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5749 lpgm->gmCellIncX, lpgm->gmCellIncY);
5750 return 1; /* FIXME */
5754 if (!font->gm[original_index / GM_BLOCK_SIZE])
5755 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
5757 /* Scaling factor */
5762 get_text_metrics(font, &tm);
5764 widthRatio = (double)font->aveWidth;
5765 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5768 widthRatio = font->scale_y;
5770 /* Scaling transform */
5771 if (widthRatio != 1.0 || font->scale_y != 1.0)
5774 scaleMat.xx = FT_FixedFromFloat(widthRatio);
5777 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
5779 pFT_Matrix_Multiply(&scaleMat, &transMat);
5780 needsTransform = TRUE;
5783 /* Slant transform */
5784 if (font->fake_italic) {
5787 slantMat.xx = (1 << 16);
5788 slantMat.xy = ((1 << 16) >> 2);
5790 slantMat.yy = (1 << 16);
5791 pFT_Matrix_Multiply(&slantMat, &transMat);
5792 needsTransform = TRUE;
5795 /* Rotation transform */
5796 transMatUnrotated = transMat;
5797 if(font->orientation && !tategaki) {
5798 FT_Matrix rotationMat;
5800 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
5801 pFT_Vector_Unit(&vecAngle, angle);
5802 rotationMat.xx = vecAngle.x;
5803 rotationMat.xy = -vecAngle.y;
5804 rotationMat.yx = -rotationMat.xy;
5805 rotationMat.yy = rotationMat.xx;
5807 pFT_Matrix_Multiply(&rotationMat, &transMat);
5808 needsTransform = TRUE;
5811 /* World transform */
5812 if (!is_identity_FMAT2(&font->font_desc.matrix))
5815 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
5816 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
5817 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
5818 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
5819 pFT_Matrix_Multiply(&worldMat, &transMat);
5820 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
5821 needsTransform = TRUE;
5824 /* Extra transformation specified by caller */
5825 if (!is_identity_MAT2(lpmat))
5828 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
5829 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
5830 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
5831 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
5832 pFT_Matrix_Multiply(&extraMat, &transMat);
5833 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
5834 needsTransform = TRUE;
5837 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
5838 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
5839 format == GGO_GRAY8_BITMAP))
5841 load_flags |= FT_LOAD_NO_BITMAP;
5844 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
5847 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
5851 if(!needsTransform) {
5852 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
5853 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
5854 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
5856 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
5857 bottom = (ft_face->glyph->metrics.horiBearingY -
5858 ft_face->glyph->metrics.height) & -64;
5859 lpgm->gmCellIncX = adv;
5860 lpgm->gmCellIncY = 0;
5867 for(xc = 0; xc < 2; xc++) {
5868 for(yc = 0; yc < 2; yc++) {
5869 vec.x = (ft_face->glyph->metrics.horiBearingX +
5870 xc * ft_face->glyph->metrics.width);
5871 vec.y = ft_face->glyph->metrics.horiBearingY -
5872 yc * ft_face->glyph->metrics.height;
5873 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
5874 pFT_Vector_Transform(&vec, &transMat);
5875 if(xc == 0 && yc == 0) {
5876 left = right = vec.x;
5877 top = bottom = vec.y;
5879 if(vec.x < left) left = vec.x;
5880 else if(vec.x > right) right = vec.x;
5881 if(vec.y < bottom) bottom = vec.y;
5882 else if(vec.y > top) top = vec.y;
5887 right = (right + 63) & -64;
5888 bottom = bottom & -64;
5889 top = (top + 63) & -64;
5891 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
5892 vec.x = ft_face->glyph->metrics.horiAdvance;
5894 pFT_Vector_Transform(&vec, &transMat);
5895 lpgm->gmCellIncX = (vec.x+63) >> 6;
5896 lpgm->gmCellIncY = -((vec.y+63) >> 6);
5898 vec.x = ft_face->glyph->metrics.horiAdvance;
5900 pFT_Vector_Transform(&vec, &transMatUnrotated);
5901 adv = (vec.x+63) >> 6;
5905 bbx = (right - left) >> 6;
5906 lpgm->gmBlackBoxX = (right - left) >> 6;
5907 lpgm->gmBlackBoxY = (top - bottom) >> 6;
5908 lpgm->gmptGlyphOrigin.x = left >> 6;
5909 lpgm->gmptGlyphOrigin.y = top >> 6;
5911 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5912 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5913 lpgm->gmCellIncX, lpgm->gmCellIncY);
5915 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
5916 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
5918 FONT_GM(font,original_index)->gm = *lpgm;
5919 FONT_GM(font,original_index)->adv = adv;
5920 FONT_GM(font,original_index)->lsb = lsb;
5921 FONT_GM(font,original_index)->bbx = bbx;
5922 FONT_GM(font,original_index)->init = TRUE;
5925 if(format == GGO_METRICS)
5927 return 1; /* FIXME */
5930 if(ft_face->glyph->format != ft_glyph_format_outline &&
5931 (format == GGO_NATIVE || format == GGO_BEZIER))
5933 TRACE("loaded a bitmap\n");
5939 width = lpgm->gmBlackBoxX;
5940 height = lpgm->gmBlackBoxY;
5941 pitch = ((width + 31) >> 5) << 2;
5942 needed = pitch * height;
5944 if(!buf || !buflen) break;
5946 switch(ft_face->glyph->format) {
5947 case ft_glyph_format_bitmap:
5949 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5950 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
5951 INT h = ft_face->glyph->bitmap.rows;
5953 memcpy(dst, src, w);
5954 src += ft_face->glyph->bitmap.pitch;
5960 case ft_glyph_format_outline:
5961 ft_bitmap.width = width;
5962 ft_bitmap.rows = height;
5963 ft_bitmap.pitch = pitch;
5964 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
5965 ft_bitmap.buffer = buf;
5968 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5970 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5972 /* Note: FreeType will only set 'black' bits for us. */
5973 memset(buf, 0, needed);
5974 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5978 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5983 case GGO_GRAY2_BITMAP:
5984 case GGO_GRAY4_BITMAP:
5985 case GGO_GRAY8_BITMAP:
5986 case WINE_GGO_GRAY16_BITMAP:
5988 unsigned int max_level, row, col;
5991 width = lpgm->gmBlackBoxX;
5992 height = lpgm->gmBlackBoxY;
5993 pitch = (width + 3) / 4 * 4;
5994 needed = pitch * height;
5996 if(!buf || !buflen) break;
5998 max_level = get_max_level( format );
6000 switch(ft_face->glyph->format) {
6001 case ft_glyph_format_bitmap:
6003 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
6004 INT h = ft_face->glyph->bitmap.rows;
6006 memset( buf, 0, needed );
6008 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
6009 if (src[x / 8] & masks[x % 8]) dst[x] = max_level;
6010 src += ft_face->glyph->bitmap.pitch;
6015 case ft_glyph_format_outline:
6017 ft_bitmap.width = width;
6018 ft_bitmap.rows = height;
6019 ft_bitmap.pitch = pitch;
6020 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
6021 ft_bitmap.buffer = buf;
6024 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
6026 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
6028 memset(ft_bitmap.buffer, 0, buflen);
6030 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
6032 if (max_level != 255)
6034 for (row = 0, start = buf; row < height; row++)
6036 for (col = 0, ptr = start; col < width; col++, ptr++)
6037 *ptr = (((int)*ptr) * (max_level + 1)) / 256;
6045 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
6051 case WINE_GGO_HRGB_BITMAP:
6052 case WINE_GGO_HBGR_BITMAP:
6053 case WINE_GGO_VRGB_BITMAP:
6054 case WINE_GGO_VBGR_BITMAP:
6055 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6057 switch (ft_face->glyph->format)
6059 case FT_GLYPH_FORMAT_BITMAP:
6064 width = lpgm->gmBlackBoxX;
6065 height = lpgm->gmBlackBoxY;
6067 needed = pitch * height;
6069 if (!buf || !buflen) break;
6071 memset(buf, 0, buflen);
6073 src = ft_face->glyph->bitmap.buffer;
6074 src_pitch = ft_face->glyph->bitmap.pitch;
6076 height = min( height, ft_face->glyph->bitmap.rows );
6079 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
6081 if ( src[x / 8] & masks[x % 8] )
6082 ((unsigned int *)dst)[x] = ~0u;
6091 case FT_GLYPH_FORMAT_OUTLINE:
6095 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
6096 INT x_shift, y_shift;
6098 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
6099 FT_Render_Mode render_mode =
6100 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
6101 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
6103 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
6105 if ( render_mode == FT_RENDER_MODE_LCD)
6107 lpgm->gmBlackBoxX += 2;
6108 lpgm->gmptGlyphOrigin.x -= 1;
6112 lpgm->gmBlackBoxY += 2;
6113 lpgm->gmptGlyphOrigin.y += 1;
6117 width = lpgm->gmBlackBoxX;
6118 height = lpgm->gmBlackBoxY;
6120 needed = pitch * height;
6122 if (!buf || !buflen) break;
6124 memset(buf, 0, buflen);
6126 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
6128 if ( needsTransform )
6129 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
6131 if ( pFT_Library_SetLcdFilter )
6132 pFT_Library_SetLcdFilter( library, lcdfilter );
6133 pFT_Render_Glyph (ft_face->glyph, render_mode);
6135 src = ft_face->glyph->bitmap.buffer;
6136 src_pitch = ft_face->glyph->bitmap.pitch;
6137 src_width = ft_face->glyph->bitmap.width;
6138 src_height = ft_face->glyph->bitmap.rows;
6140 if ( render_mode == FT_RENDER_MODE_LCD)
6148 rgb_interval = src_pitch;
6153 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
6154 if ( x_shift < 0 ) x_shift = 0;
6155 if ( x_shift + (src_width / hmul) > width )
6156 x_shift = width - (src_width / hmul);
6158 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
6159 if ( y_shift < 0 ) y_shift = 0;
6160 if ( y_shift + (src_height / vmul) > height )
6161 y_shift = height - (src_height / vmul);
6163 dst += x_shift + y_shift * ( pitch / 4 );
6164 while ( src_height )
6166 for ( x = 0; x < src_width / hmul; x++ )
6170 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
6171 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6172 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
6173 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6177 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
6178 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6179 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
6180 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6183 src += src_pitch * vmul;
6192 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
6204 int contour, point = 0, first_pt;
6205 FT_Outline *outline = &ft_face->glyph->outline;
6206 TTPOLYGONHEADER *pph;
6208 DWORD pph_start, cpfx, type;
6210 if(buflen == 0) buf = NULL;
6212 if (needsTransform && buf) {
6213 pFT_Outline_Transform(outline, &transMat);
6216 for(contour = 0; contour < outline->n_contours; contour++) {
6218 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6221 pph->dwType = TT_POLYGON_TYPE;
6222 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6224 needed += sizeof(*pph);
6226 while(point <= outline->contours[contour]) {
6227 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6228 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6229 TT_PRIM_LINE : TT_PRIM_QSPLINE;
6233 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6236 } while(point <= outline->contours[contour] &&
6237 (outline->tags[point] & FT_Curve_Tag_On) ==
6238 (outline->tags[point-1] & FT_Curve_Tag_On));
6239 /* At the end of a contour Windows adds the start point, but
6241 if(point > outline->contours[contour] &&
6242 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
6244 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
6246 } else if(point <= outline->contours[contour] &&
6247 outline->tags[point] & FT_Curve_Tag_On) {
6248 /* add closing pt for bezier */
6250 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6258 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6261 pph->cb = needed - pph_start;
6267 /* Convert the quadratic Beziers to cubic Beziers.
6268 The parametric eqn for a cubic Bezier is, from PLRM:
6269 r(t) = at^3 + bt^2 + ct + r0
6270 with the control points:
6275 A quadratic Bezier has the form:
6276 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6278 So equating powers of t leads to:
6279 r1 = 2/3 p1 + 1/3 p0
6280 r2 = 2/3 p1 + 1/3 p2
6281 and of course r0 = p0, r3 = p2
6284 int contour, point = 0, first_pt;
6285 FT_Outline *outline = &ft_face->glyph->outline;
6286 TTPOLYGONHEADER *pph;
6288 DWORD pph_start, cpfx, type;
6289 FT_Vector cubic_control[4];
6290 if(buflen == 0) buf = NULL;
6292 if (needsTransform && buf) {
6293 pFT_Outline_Transform(outline, &transMat);
6296 for(contour = 0; contour < outline->n_contours; contour++) {
6298 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6301 pph->dwType = TT_POLYGON_TYPE;
6302 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6304 needed += sizeof(*pph);
6306 while(point <= outline->contours[contour]) {
6307 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6308 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6309 TT_PRIM_LINE : TT_PRIM_CSPLINE;
6312 if(type == TT_PRIM_LINE) {
6314 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6318 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6321 /* FIXME: Possible optimization in endpoint calculation
6322 if there are two consecutive curves */
6323 cubic_control[0] = outline->points[point-1];
6324 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
6325 cubic_control[0].x += outline->points[point].x + 1;
6326 cubic_control[0].y += outline->points[point].y + 1;
6327 cubic_control[0].x >>= 1;
6328 cubic_control[0].y >>= 1;
6330 if(point+1 > outline->contours[contour])
6331 cubic_control[3] = outline->points[first_pt];
6333 cubic_control[3] = outline->points[point+1];
6334 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
6335 cubic_control[3].x += outline->points[point].x + 1;
6336 cubic_control[3].y += outline->points[point].y + 1;
6337 cubic_control[3].x >>= 1;
6338 cubic_control[3].y >>= 1;
6341 /* r1 = 1/3 p0 + 2/3 p1
6342 r2 = 1/3 p2 + 2/3 p1 */
6343 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
6344 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
6345 cubic_control[2] = cubic_control[1];
6346 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
6347 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
6348 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
6349 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
6351 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
6352 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
6353 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
6358 } while(point <= outline->contours[contour] &&
6359 (outline->tags[point] & FT_Curve_Tag_On) ==
6360 (outline->tags[point-1] & FT_Curve_Tag_On));
6361 /* At the end of a contour Windows adds the start point,
6362 but only for Beziers and we've already done that.
6364 if(point <= outline->contours[contour] &&
6365 outline->tags[point] & FT_Curve_Tag_On) {
6366 /* This is the closing pt of a bezier, but we've already
6367 added it, so just inc point and carry on */
6374 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6377 pph->cb = needed - pph_start;
6383 FIXME("Unsupported format %d\n", format);
6389 static BOOL get_bitmap_text_metrics(GdiFont *font)
6391 FT_Face ft_face = font->ft_face;
6392 FT_WinFNT_HeaderRec winfnt_header;
6393 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
6394 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
6395 font->potm->otmSize = size;
6397 #define TM font->potm->otmTextMetrics
6398 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
6400 TM.tmHeight = winfnt_header.pixel_height;
6401 TM.tmAscent = winfnt_header.ascent;
6402 TM.tmDescent = TM.tmHeight - TM.tmAscent;
6403 TM.tmInternalLeading = winfnt_header.internal_leading;
6404 TM.tmExternalLeading = winfnt_header.external_leading;
6405 TM.tmAveCharWidth = winfnt_header.avg_width;
6406 TM.tmMaxCharWidth = winfnt_header.max_width;
6407 TM.tmWeight = winfnt_header.weight;
6409 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
6410 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
6411 TM.tmFirstChar = winfnt_header.first_char;
6412 TM.tmLastChar = winfnt_header.last_char;
6413 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
6414 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
6415 TM.tmItalic = winfnt_header.italic;
6416 TM.tmUnderlined = font->underline;
6417 TM.tmStruckOut = font->strikeout;
6418 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
6419 TM.tmCharSet = winfnt_header.charset;
6423 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
6424 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
6425 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6426 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
6427 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
6428 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
6429 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
6430 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
6432 TM.tmDigitizedAspectX = 96; /* FIXME */
6433 TM.tmDigitizedAspectY = 96; /* FIXME */
6435 TM.tmLastChar = 255;
6436 TM.tmDefaultChar = 32;
6437 TM.tmBreakChar = 32;
6438 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
6439 TM.tmUnderlined = font->underline;
6440 TM.tmStruckOut = font->strikeout;
6441 /* NB inverted meaning of TMPF_FIXED_PITCH */
6442 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
6443 TM.tmCharSet = font->charset;
6451 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
6453 double scale_x, scale_y;
6457 scale_x = (double)font->aveWidth;
6458 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6461 scale_x = font->scale_y;
6463 scale_x *= fabs(font->font_desc.matrix.eM11);
6464 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6466 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6467 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6469 SCALE_Y(ptm->tmHeight);
6470 SCALE_Y(ptm->tmAscent);
6471 SCALE_Y(ptm->tmDescent);
6472 SCALE_Y(ptm->tmInternalLeading);
6473 SCALE_Y(ptm->tmExternalLeading);
6474 SCALE_Y(ptm->tmOverhang);
6476 SCALE_X(ptm->tmAveCharWidth);
6477 SCALE_X(ptm->tmMaxCharWidth);
6483 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
6485 double scale_x, scale_y;
6489 scale_x = (double)font->aveWidth;
6490 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6493 scale_x = font->scale_y;
6495 scale_x *= fabs(font->font_desc.matrix.eM11);
6496 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6498 scale_font_metrics(font, &potm->otmTextMetrics);
6500 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6501 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6503 SCALE_Y(potm->otmAscent);
6504 SCALE_Y(potm->otmDescent);
6505 SCALE_Y(potm->otmLineGap);
6506 SCALE_Y(potm->otmsCapEmHeight);
6507 SCALE_Y(potm->otmsXHeight);
6508 SCALE_Y(potm->otmrcFontBox.top);
6509 SCALE_Y(potm->otmrcFontBox.bottom);
6510 SCALE_X(potm->otmrcFontBox.left);
6511 SCALE_X(potm->otmrcFontBox.right);
6512 SCALE_Y(potm->otmMacAscent);
6513 SCALE_Y(potm->otmMacDescent);
6514 SCALE_Y(potm->otmMacLineGap);
6515 SCALE_X(potm->otmptSubscriptSize.x);
6516 SCALE_Y(potm->otmptSubscriptSize.y);
6517 SCALE_X(potm->otmptSubscriptOffset.x);
6518 SCALE_Y(potm->otmptSubscriptOffset.y);
6519 SCALE_X(potm->otmptSuperscriptSize.x);
6520 SCALE_Y(potm->otmptSuperscriptSize.y);
6521 SCALE_X(potm->otmptSuperscriptOffset.x);
6522 SCALE_Y(potm->otmptSuperscriptOffset.y);
6523 SCALE_Y(potm->otmsStrikeoutSize);
6524 SCALE_Y(potm->otmsStrikeoutPosition);
6525 SCALE_Y(potm->otmsUnderscoreSize);
6526 SCALE_Y(potm->otmsUnderscorePosition);
6532 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
6536 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
6538 /* Make sure that the font has sane width/height ratio */
6541 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
6543 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
6548 *ptm = font->potm->otmTextMetrics;
6549 scale_font_metrics(font, ptm);
6553 static BOOL face_has_symbol_charmap(FT_Face ft_face)
6557 for(i = 0; i < ft_face->num_charmaps; i++)
6559 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
6565 static BOOL get_outline_text_metrics(GdiFont *font)
6568 FT_Face ft_face = font->ft_face;
6569 UINT needed, lenfam, lensty, lenface, lenfull;
6571 TT_HoriHeader *pHori;
6572 TT_Postscript *pPost;
6573 FT_Fixed x_scale, y_scale;
6574 WCHAR *family_nameW, *style_nameW, *face_nameW, *full_nameW;
6576 INT ascent, descent;
6578 TRACE("font=%p\n", font);
6580 if(!FT_IS_SCALABLE(ft_face))
6583 needed = sizeof(*font->potm);
6585 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
6586 family_nameW = strdupW(font->name);
6588 style_nameW = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
6590 style_nameW = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
6593 FIXME("failed to read style_nameW for font %s!\n", wine_dbgstr_w(font->name));
6594 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0) * sizeof(WCHAR);
6595 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
6596 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, style_nameW, lensty/sizeof(WCHAR));
6599 lensty = (strlenW(style_nameW) + 1) * sizeof(WCHAR);
6601 face_nameW = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
6603 face_nameW = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES );
6606 FIXME("failed to read face_nameW for font %s!\n", wine_dbgstr_w(font->name));
6607 face_nameW = strdupW(font->name);
6609 if (font->name[0] == '@') face_nameW = prepend_at( face_nameW );
6610 lenface = (strlenW(face_nameW) + 1) * sizeof(WCHAR);
6612 full_nameW = get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, GetSystemDefaultLangID() );
6614 full_nameW = get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, TT_MS_LANGID_ENGLISH_UNITED_STATES );
6617 WCHAR fake_nameW[] = {'f','a','k','e',' ','n','a','m','e', 0};
6618 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w(font->name));
6619 full_nameW = strdupW(fake_nameW);
6621 lenfull = (strlenW(full_nameW) + 1) * sizeof(WCHAR);
6623 /* These names should be read from the TT name table */
6625 /* length of otmpFamilyName */
6628 /* length of otmpFaceName */
6631 /* length of otmpStyleName */
6634 /* length of otmpFullName */
6638 x_scale = ft_face->size->metrics.x_scale;
6639 y_scale = ft_face->size->metrics.y_scale;
6641 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
6643 FIXME("Can't find OS/2 table - not TT font?\n");
6647 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
6649 FIXME("Can't find HHEA table - not TT font?\n");
6653 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
6655 TRACE("OS/2 winA = %d winD = %d typoA = %d typoD = %d typoLG = %d avgW %d FT_Face a = %d, d = %d, h = %d: HORZ a = %d, d = %d lg = %d maxY = %ld minY = %ld\n",
6656 pOS2->usWinAscent, pOS2->usWinDescent,
6657 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
6658 pOS2->xAvgCharWidth,
6659 ft_face->ascender, ft_face->descender, ft_face->height,
6660 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
6661 ft_face->bbox.yMax, ft_face->bbox.yMin);
6663 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
6664 font->potm->otmSize = needed;
6666 #define TM font->potm->otmTextMetrics
6668 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
6669 ascent = pHori->Ascender;
6670 descent = -pHori->Descender;
6672 ascent = pOS2->usWinAscent;
6673 descent = pOS2->usWinDescent;
6676 font->ntmCellHeight = ascent + descent;
6677 font->ntmAvgWidth = pOS2->xAvgCharWidth;
6680 TM.tmAscent = font->yMax;
6681 TM.tmDescent = -font->yMin;
6682 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
6684 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
6685 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
6686 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
6687 - ft_face->units_per_EM, y_scale) + 32) >> 6;
6690 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6693 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6695 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
6696 ((ascent + descent) -
6697 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
6699 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
6700 if (TM.tmAveCharWidth == 0) {
6701 TM.tmAveCharWidth = 1;
6703 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
6704 TM.tmWeight = FW_REGULAR;
6705 if (font->fake_bold)
6706 TM.tmWeight = FW_BOLD;
6709 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
6711 if (pOS2->usWeightClass > FW_MEDIUM)
6712 TM.tmWeight = pOS2->usWeightClass;
6714 else if (pOS2->usWeightClass <= FW_MEDIUM)
6715 TM.tmWeight = pOS2->usWeightClass;
6718 TM.tmDigitizedAspectX = 96; /* FIXME */
6719 TM.tmDigitizedAspectY = 96; /* FIXME */
6720 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6721 * symbol range to 0 - f0ff
6724 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
6729 case 1257: /* Baltic */
6730 TM.tmLastChar = 0xf8fd;
6733 TM.tmLastChar = 0xf0ff;
6735 TM.tmBreakChar = 0x20;
6736 TM.tmDefaultChar = 0x1f;
6740 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
6741 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
6743 if(pOS2->usFirstCharIndex <= 1)
6744 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
6745 else if (pOS2->usFirstCharIndex > 0xff)
6746 TM.tmBreakChar = 0x20;
6748 TM.tmBreakChar = pOS2->usFirstCharIndex;
6749 TM.tmDefaultChar = TM.tmBreakChar - 1;
6751 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
6752 TM.tmUnderlined = font->underline;
6753 TM.tmStruckOut = font->strikeout;
6755 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6756 if(!FT_IS_FIXED_WIDTH(ft_face) &&
6757 (pOS2->version == 0xFFFFU ||
6758 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
6759 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
6761 TM.tmPitchAndFamily = 0;
6763 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
6765 case PAN_FAMILY_SCRIPT:
6766 TM.tmPitchAndFamily |= FF_SCRIPT;
6769 case PAN_FAMILY_DECORATIVE:
6770 TM.tmPitchAndFamily |= FF_DECORATIVE;
6775 case PAN_FAMILY_TEXT_DISPLAY:
6776 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
6777 /* which is clearly not what the panose spec says. */
6779 if(TM.tmPitchAndFamily == 0 || /* fixed */
6780 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
6781 TM.tmPitchAndFamily = FF_MODERN;
6784 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
6789 TM.tmPitchAndFamily |= FF_DONTCARE;
6792 case PAN_SERIF_COVE:
6793 case PAN_SERIF_OBTUSE_COVE:
6794 case PAN_SERIF_SQUARE_COVE:
6795 case PAN_SERIF_OBTUSE_SQUARE_COVE:
6796 case PAN_SERIF_SQUARE:
6797 case PAN_SERIF_THIN:
6798 case PAN_SERIF_BONE:
6799 case PAN_SERIF_EXAGGERATED:
6800 case PAN_SERIF_TRIANGLE:
6801 TM.tmPitchAndFamily |= FF_ROMAN;
6804 case PAN_SERIF_NORMAL_SANS:
6805 case PAN_SERIF_OBTUSE_SANS:
6806 case PAN_SERIF_PERP_SANS:
6807 case PAN_SERIF_FLARED:
6808 case PAN_SERIF_ROUNDED:
6809 TM.tmPitchAndFamily |= FF_SWISS;
6816 if(FT_IS_SCALABLE(ft_face))
6817 TM.tmPitchAndFamily |= TMPF_VECTOR;
6819 if(FT_IS_SFNT(ft_face))
6821 if (font->ntmFlags & NTM_PS_OPENTYPE)
6822 TM.tmPitchAndFamily |= TMPF_DEVICE;
6824 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
6827 TM.tmCharSet = font->charset;
6829 font->potm->otmFiller = 0;
6830 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
6831 font->potm->otmfsSelection = pOS2->fsSelection;
6832 font->potm->otmfsType = pOS2->fsType;
6833 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
6834 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
6835 font->potm->otmItalicAngle = 0; /* POST table */
6836 font->potm->otmEMSquare = ft_face->units_per_EM;
6837 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
6838 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
6839 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
6840 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
6841 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
6842 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
6843 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
6844 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
6845 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
6846 font->potm->otmMacAscent = TM.tmAscent;
6847 font->potm->otmMacDescent = -TM.tmDescent;
6848 font->potm->otmMacLineGap = font->potm->otmLineGap;
6849 font->potm->otmusMinimumPPEM = 0; /* TT Header */
6850 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
6851 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
6852 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
6853 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
6854 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
6855 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
6856 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
6857 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
6858 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
6859 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
6861 font->potm->otmsUnderscoreSize = 0;
6862 font->potm->otmsUnderscorePosition = 0;
6864 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
6865 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
6869 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
6870 cp = (char*)font->potm + sizeof(*font->potm);
6871 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
6872 strcpyW((WCHAR*)cp, family_nameW);
6874 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
6875 strcpyW((WCHAR*)cp, style_nameW);
6877 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
6878 strcpyW((WCHAR*)cp, face_nameW);
6880 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
6881 strcpyW((WCHAR*)cp, full_nameW);
6885 HeapFree(GetProcessHeap(), 0, style_nameW);
6886 HeapFree(GetProcessHeap(), 0, family_nameW);
6887 HeapFree(GetProcessHeap(), 0, face_nameW);
6888 HeapFree(GetProcessHeap(), 0, full_nameW);
6892 /*************************************************************
6893 * freetype_GetGlyphOutline
6895 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
6896 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
6898 struct freetype_physdev *physdev = get_freetype_dev( dev );
6903 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
6904 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
6908 EnterCriticalSection( &freetype_cs );
6909 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, buflen, buf, lpmat );
6910 LeaveCriticalSection( &freetype_cs );
6914 /*************************************************************
6915 * freetype_GetTextMetrics
6917 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
6919 struct freetype_physdev *physdev = get_freetype_dev( dev );
6924 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
6925 return dev->funcs->pGetTextMetrics( dev, metrics );
6929 EnterCriticalSection( &freetype_cs );
6930 ret = get_text_metrics( physdev->font, metrics );
6931 LeaveCriticalSection( &freetype_cs );
6935 /*************************************************************
6936 * freetype_GetOutlineTextMetrics
6938 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
6940 struct freetype_physdev *physdev = get_freetype_dev( dev );
6945 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
6946 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
6949 TRACE("font=%p\n", physdev->font);
6951 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
6954 EnterCriticalSection( &freetype_cs );
6956 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
6958 if(cbSize >= physdev->font->potm->otmSize)
6960 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
6961 scale_outline_font_metrics(physdev->font, potm);
6963 ret = physdev->font->potm->otmSize;
6965 LeaveCriticalSection( &freetype_cs );
6969 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
6971 HFONTLIST *hfontlist;
6972 child->font = alloc_font();
6973 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
6974 if(!child->font->ft_face)
6976 free_font(child->font);
6981 child->font->font_desc = font->font_desc;
6982 child->font->ntmFlags = child->face->ntmFlags;
6983 child->font->orientation = font->orientation;
6984 child->font->scale_y = font->scale_y;
6985 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
6986 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
6987 child->font->name = strdupW(child->face->family->FamilyName);
6988 list_add_head(&child->font->hfontlist, &hfontlist->entry);
6989 child->font->base_font = font;
6990 list_add_head(&child_font_list, &child->font->entry);
6991 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
6995 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
6998 CHILD_FONT *child_font;
7001 font = font->base_font;
7003 *linked_font = font;
7005 if((*glyph = get_glyph_index(font, c)))
7007 *glyph = get_GSUB_vert_glyph(font, *glyph);
7011 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
7013 if(!child_font->font)
7014 if(!load_child_font(font, child_font))
7017 if(!child_font->font->ft_face)
7019 g = get_glyph_index(child_font->font, c);
7020 g = get_GSUB_vert_glyph(child_font->font, g);
7024 *linked_font = child_font->font;
7031 /*************************************************************
7032 * freetype_GetCharWidth
7034 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
7036 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7039 FT_UInt glyph_index;
7040 GdiFont *linked_font;
7041 struct freetype_physdev *physdev = get_freetype_dev( dev );
7045 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
7046 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
7049 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
7052 EnterCriticalSection( &freetype_cs );
7053 for(c = firstChar; c <= lastChar; c++) {
7054 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
7055 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
7056 &gm, 0, NULL, &identity);
7057 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
7059 LeaveCriticalSection( &freetype_cs );
7063 /*************************************************************
7064 * freetype_GetCharABCWidths
7066 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
7068 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7071 FT_UInt glyph_index;
7072 GdiFont *linked_font;
7073 struct freetype_physdev *physdev = get_freetype_dev( dev );
7077 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
7078 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
7081 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
7084 EnterCriticalSection( &freetype_cs );
7086 for(c = firstChar; c <= lastChar; c++) {
7087 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
7088 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
7089 &gm, 0, NULL, &identity);
7090 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
7091 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
7092 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
7093 FONT_GM(linked_font,glyph_index)->bbx;
7095 LeaveCriticalSection( &freetype_cs );
7099 /*************************************************************
7100 * freetype_GetCharABCWidthsI
7102 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
7104 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7107 FT_UInt glyph_index;
7108 GdiFont *linked_font;
7109 struct freetype_physdev *physdev = get_freetype_dev( dev );
7113 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
7114 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
7117 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
7121 EnterCriticalSection( &freetype_cs );
7123 get_glyph_index_linked(physdev->font, 'a', &linked_font, &glyph_index);
7125 for(c = firstChar; c < firstChar+count; c++) {
7126 get_glyph_outline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
7127 &gm, 0, NULL, &identity);
7128 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
7129 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
7130 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
7131 - FONT_GM(linked_font,c)->bbx;
7134 for(c = 0; c < count; c++) {
7135 get_glyph_outline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
7136 &gm, 0, NULL, &identity);
7137 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
7138 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
7139 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
7140 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
7143 LeaveCriticalSection( &freetype_cs );
7147 /*************************************************************
7148 * freetype_GetTextExtentExPoint
7150 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count,
7151 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
7153 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7158 FT_UInt glyph_index;
7159 GdiFont *linked_font;
7160 struct freetype_physdev *physdev = get_freetype_dev( dev );
7164 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
7165 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, max_ext, pnfit, dxs, size );
7168 TRACE("%p, %s, %d, %d, %p\n", physdev->font, debugstr_wn(wstr, count), count, max_ext, size);
7171 EnterCriticalSection( &freetype_cs );
7174 get_text_metrics( physdev->font, &tm );
7175 size->cy = tm.tmHeight;
7177 for(idx = 0; idx < count; idx++) {
7178 get_glyph_index_linked( physdev->font, wstr[idx], &linked_font, &glyph_index );
7179 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
7180 &gm, 0, NULL, &identity);
7181 size->cx += FONT_GM(linked_font,glyph_index)->adv;
7183 if (! pnfit || ext <= max_ext) {
7193 LeaveCriticalSection( &freetype_cs );
7194 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
7198 /*************************************************************
7199 * freetype_GetTextExtentExPointI
7201 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count,
7202 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size )
7204 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7209 struct freetype_physdev *physdev = get_freetype_dev( dev );
7213 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
7214 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, max_ext, pnfit, dxs, size );
7217 TRACE("%p, %p, %d, %d, %p\n", physdev->font, indices, count, max_ext, size);
7220 EnterCriticalSection( &freetype_cs );
7223 get_text_metrics(physdev->font, &tm);
7224 size->cy = tm.tmHeight;
7226 for(idx = 0; idx < count; idx++) {
7227 get_glyph_outline(physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &identity);
7228 size->cx += FONT_GM(physdev->font,indices[idx])->adv;
7230 if (! pnfit || ext <= max_ext) {
7240 LeaveCriticalSection( &freetype_cs );
7241 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
7245 /*************************************************************
7246 * freetype_GetFontData
7248 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
7250 struct freetype_physdev *physdev = get_freetype_dev( dev );
7254 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
7255 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
7258 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
7259 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
7260 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
7262 return get_font_data( physdev->font, table, offset, buf, cbData );
7265 /*************************************************************
7266 * freetype_GetTextFace
7268 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
7271 struct freetype_physdev *physdev = get_freetype_dev( dev );
7275 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
7276 return dev->funcs->pGetTextFace( dev, count, str );
7279 n = strlenW(physdev->font->name) + 1;
7282 lstrcpynW(str, physdev->font->name, count);
7288 /*************************************************************
7289 * freetype_GetTextCharsetInfo
7291 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
7293 struct freetype_physdev *physdev = get_freetype_dev( dev );
7297 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
7298 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
7300 if (fs) *fs = physdev->font->fs;
7301 return physdev->font->charset;
7304 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
7306 GdiFont *font = dc->gdiFont, *linked_font;
7307 struct list *first_hfont;
7311 EnterCriticalSection( &freetype_cs );
7312 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
7313 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
7314 if(font == linked_font)
7315 *new_hfont = dc->hFont;
7318 first_hfont = list_head(&linked_font->hfontlist);
7319 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
7321 LeaveCriticalSection( &freetype_cs );
7325 /* Retrieve a list of supported Unicode ranges for a given font.
7326 * Can be called with NULL gs to calculate the buffer size. Returns
7327 * the number of ranges found.
7329 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
7331 DWORD num_ranges = 0;
7333 if (face->charmap->encoding == FT_ENCODING_UNICODE)
7336 FT_ULong char_code, char_code_prev;
7339 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
7341 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
7342 face->num_glyphs, glyph_code, char_code);
7344 if (!glyph_code) return 0;
7348 gs->ranges[0].wcLow = (USHORT)char_code;
7349 gs->ranges[0].cGlyphs = 0;
7350 gs->cGlyphsSupported = 0;
7356 if (char_code < char_code_prev)
7358 ERR("expected increasing char code from FT_Get_Next_Char\n");
7361 if (char_code - char_code_prev > 1)
7366 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
7367 gs->ranges[num_ranges - 1].cGlyphs = 1;
7368 gs->cGlyphsSupported++;
7373 gs->ranges[num_ranges - 1].cGlyphs++;
7374 gs->cGlyphsSupported++;
7376 char_code_prev = char_code;
7377 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
7381 FIXME("encoding %u not supported\n", face->charmap->encoding);
7386 /*************************************************************
7387 * freetype_GetFontUnicodeRanges
7389 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
7391 struct freetype_physdev *physdev = get_freetype_dev( dev );
7392 DWORD size, num_ranges;
7396 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
7397 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
7400 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
7401 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
7404 glyphset->cbThis = size;
7405 glyphset->cRanges = num_ranges;
7406 glyphset->flAccel = 0;
7411 /*************************************************************
7412 * freetype_FontIsLinked
7414 static BOOL freetype_FontIsLinked( PHYSDEV dev )
7416 struct freetype_physdev *physdev = get_freetype_dev( dev );
7421 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
7422 return dev->funcs->pFontIsLinked( dev );
7426 EnterCriticalSection( &freetype_cs );
7427 ret = !list_empty(&physdev->font->child_fonts);
7428 LeaveCriticalSection( &freetype_cs );
7432 static BOOL is_hinting_enabled(void)
7434 /* Use the >= 2.2.0 function if available */
7435 if(pFT_Get_TrueType_Engine_Type)
7437 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
7438 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
7440 #ifdef FT_DRIVER_HAS_HINTER
7445 /* otherwise if we've been compiled with < 2.2.0 headers
7446 use the internal macro */
7447 mod = pFT_Get_Module(library, "truetype");
7448 if(mod && FT_DRIVER_HAS_HINTER(mod))
7456 static BOOL is_subpixel_rendering_enabled( void )
7458 #ifdef HAVE_FREETYPE_FTLCDFIL_H
7459 return pFT_Library_SetLcdFilter &&
7460 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
7466 /*************************************************************************
7467 * GetRasterizerCaps (GDI32.@)
7469 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7471 static int hinting = -1;
7472 static int subpixel = -1;
7476 hinting = is_hinting_enabled();
7477 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
7480 if ( subpixel == -1 )
7482 subpixel = is_subpixel_rendering_enabled();
7483 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
7486 lprs->nSize = sizeof(RASTERIZER_STATUS);
7487 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
7489 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
7490 lprs->nLanguageID = 0;
7494 /*************************************************************
7495 * freetype_GdiRealizationInfo
7497 static BOOL freetype_GdiRealizationInfo( PHYSDEV dev, void *ptr )
7499 struct freetype_physdev *physdev = get_freetype_dev( dev );
7500 realization_info_t *info = ptr;
7504 dev = GET_NEXT_PHYSDEV( dev, pGdiRealizationInfo );
7505 return dev->funcs->pGdiRealizationInfo( dev, ptr );
7508 FIXME("(%p, %p): stub!\n", physdev->font, info);
7511 if(FT_IS_SCALABLE(physdev->font->ft_face))
7514 info->cache_num = physdev->font->cache_num;
7515 info->unknown2 = -1;
7519 /*************************************************************************
7520 * Kerning support for TrueType fonts
7522 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
7524 struct TT_kern_table
7530 struct TT_kern_subtable
7539 USHORT horizontal : 1;
7541 USHORT cross_stream: 1;
7542 USHORT override : 1;
7543 USHORT reserved1 : 4;
7549 struct TT_format0_kern_subtable
7553 USHORT entrySelector;
7564 static DWORD parse_format0_kern_subtable(GdiFont *font,
7565 const struct TT_format0_kern_subtable *tt_f0_ks,
7566 const USHORT *glyph_to_char,
7567 KERNINGPAIR *kern_pair, DWORD cPairs)
7570 const struct TT_kern_pair *tt_kern_pair;
7572 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
7574 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
7576 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7577 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
7578 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
7580 if (!kern_pair || !cPairs)
7583 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
7585 nPairs = min(nPairs, cPairs);
7587 for (i = 0; i < nPairs; i++)
7589 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
7590 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
7591 /* this algorithm appears to better match what Windows does */
7592 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
7593 if (kern_pair->iKernAmount < 0)
7595 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
7596 kern_pair->iKernAmount -= font->ppem;
7598 else if (kern_pair->iKernAmount > 0)
7600 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
7601 kern_pair->iKernAmount += font->ppem;
7603 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
7605 TRACE("left %u right %u value %d\n",
7606 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
7610 TRACE("copied %u entries\n", nPairs);
7614 /*************************************************************
7615 * freetype_GetKerningPairs
7617 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
7621 const struct TT_kern_table *tt_kern_table;
7622 const struct TT_kern_subtable *tt_kern_subtable;
7624 USHORT *glyph_to_char;
7626 struct freetype_physdev *physdev = get_freetype_dev( dev );
7628 if (!(font = physdev->font))
7630 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
7631 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
7635 EnterCriticalSection( &freetype_cs );
7636 if (font->total_kern_pairs != (DWORD)-1)
7638 if (cPairs && kern_pair)
7640 cPairs = min(cPairs, font->total_kern_pairs);
7641 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7643 else cPairs = font->total_kern_pairs;
7645 LeaveCriticalSection( &freetype_cs );
7649 font->total_kern_pairs = 0;
7651 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
7653 if (length == GDI_ERROR)
7655 TRACE("no kerning data in the font\n");
7656 LeaveCriticalSection( &freetype_cs );
7660 buf = HeapAlloc(GetProcessHeap(), 0, length);
7663 WARN("Out of memory\n");
7664 LeaveCriticalSection( &freetype_cs );
7668 get_font_data(font, MS_KERN_TAG, 0, buf, length);
7670 /* build a glyph index to char code map */
7671 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
7674 WARN("Out of memory allocating a glyph index to char code map\n");
7675 HeapFree(GetProcessHeap(), 0, buf);
7676 LeaveCriticalSection( &freetype_cs );
7680 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
7686 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
7688 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7689 font->ft_face->num_glyphs, glyph_code, char_code);
7693 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7695 /* FIXME: This doesn't match what Windows does: it does some fancy
7696 * things with duplicate glyph index to char code mappings, while
7697 * we just avoid overriding existing entries.
7699 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
7700 glyph_to_char[glyph_code] = (USHORT)char_code;
7702 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
7709 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
7710 for (n = 0; n <= 65535; n++)
7711 glyph_to_char[n] = (USHORT)n;
7714 tt_kern_table = buf;
7715 nTables = GET_BE_WORD(tt_kern_table->nTables);
7716 TRACE("version %u, nTables %u\n",
7717 GET_BE_WORD(tt_kern_table->version), nTables);
7719 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
7721 for (i = 0; i < nTables; i++)
7723 struct TT_kern_subtable tt_kern_subtable_copy;
7725 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
7726 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
7727 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
7729 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7730 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
7731 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
7733 /* According to the TrueType specification this is the only format
7734 * that will be properly interpreted by Windows and OS/2
7736 if (tt_kern_subtable_copy.coverage.bits.format == 0)
7738 DWORD new_chunk, old_total = font->total_kern_pairs;
7740 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7741 glyph_to_char, NULL, 0);
7742 font->total_kern_pairs += new_chunk;
7744 if (!font->kern_pairs)
7745 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
7746 font->total_kern_pairs * sizeof(*font->kern_pairs));
7748 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
7749 font->total_kern_pairs * sizeof(*font->kern_pairs));
7751 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7752 glyph_to_char, font->kern_pairs + old_total, new_chunk);
7755 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
7757 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
7760 HeapFree(GetProcessHeap(), 0, glyph_to_char);
7761 HeapFree(GetProcessHeap(), 0, buf);
7763 if (cPairs && kern_pair)
7765 cPairs = min(cPairs, font->total_kern_pairs);
7766 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7768 else cPairs = font->total_kern_pairs;
7770 LeaveCriticalSection( &freetype_cs );
7774 static const struct gdi_dc_funcs freetype_funcs =
7776 NULL, /* pAbortDoc */
7777 NULL, /* pAbortPath */
7778 NULL, /* pAlphaBlend */
7779 NULL, /* pAngleArc */
7782 NULL, /* pBeginPath */
7783 NULL, /* pBlendImage */
7785 NULL, /* pCloseFigure */
7786 NULL, /* pCreateCompatibleDC */
7787 freetype_CreateDC, /* pCreateDC */
7788 freetype_DeleteDC, /* pDeleteDC */
7789 NULL, /* pDeleteObject */
7790 NULL, /* pDeviceCapabilities */
7791 NULL, /* pEllipse */
7793 NULL, /* pEndPage */
7794 NULL, /* pEndPath */
7795 freetype_EnumFonts, /* pEnumFonts */
7796 NULL, /* pEnumICMProfiles */
7797 NULL, /* pExcludeClipRect */
7798 NULL, /* pExtDeviceMode */
7799 NULL, /* pExtEscape */
7800 NULL, /* pExtFloodFill */
7801 NULL, /* pExtSelectClipRgn */
7802 NULL, /* pExtTextOut */
7803 NULL, /* pFillPath */
7804 NULL, /* pFillRgn */
7805 NULL, /* pFlattenPath */
7806 freetype_FontIsLinked, /* pFontIsLinked */
7807 NULL, /* pFrameRgn */
7808 NULL, /* pGdiComment */
7809 freetype_GdiRealizationInfo, /* pGdiRealizationInfo */
7810 NULL, /* pGetBoundsRect */
7811 freetype_GetCharABCWidths, /* pGetCharABCWidths */
7812 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
7813 freetype_GetCharWidth, /* pGetCharWidth */
7814 NULL, /* pGetDeviceCaps */
7815 NULL, /* pGetDeviceGammaRamp */
7816 freetype_GetFontData, /* pGetFontData */
7817 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
7818 freetype_GetGlyphIndices, /* pGetGlyphIndices */
7819 freetype_GetGlyphOutline, /* pGetGlyphOutline */
7820 NULL, /* pGetICMProfile */
7821 NULL, /* pGetImage */
7822 freetype_GetKerningPairs, /* pGetKerningPairs */
7823 NULL, /* pGetNearestColor */
7824 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
7825 NULL, /* pGetPixel */
7826 NULL, /* pGetSystemPaletteEntries */
7827 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
7828 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
7829 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
7830 freetype_GetTextFace, /* pGetTextFace */
7831 freetype_GetTextMetrics, /* pGetTextMetrics */
7832 NULL, /* pGradientFill */
7833 NULL, /* pIntersectClipRect */
7834 NULL, /* pInvertRgn */
7836 NULL, /* pModifyWorldTransform */
7838 NULL, /* pOffsetClipRgn */
7839 NULL, /* pOffsetViewportOrg */
7840 NULL, /* pOffsetWindowOrg */
7841 NULL, /* pPaintRgn */
7844 NULL, /* pPolyBezier */
7845 NULL, /* pPolyBezierTo */
7846 NULL, /* pPolyDraw */
7847 NULL, /* pPolyPolygon */
7848 NULL, /* pPolyPolyline */
7849 NULL, /* pPolygon */
7850 NULL, /* pPolyline */
7851 NULL, /* pPolylineTo */
7852 NULL, /* pPutImage */
7853 NULL, /* pRealizeDefaultPalette */
7854 NULL, /* pRealizePalette */
7855 NULL, /* pRectangle */
7856 NULL, /* pResetDC */
7857 NULL, /* pRestoreDC */
7858 NULL, /* pRoundRect */
7860 NULL, /* pScaleViewportExt */
7861 NULL, /* pScaleWindowExt */
7862 NULL, /* pSelectBitmap */
7863 NULL, /* pSelectBrush */
7864 NULL, /* pSelectClipPath */
7865 freetype_SelectFont, /* pSelectFont */
7866 NULL, /* pSelectPalette */
7867 NULL, /* pSelectPen */
7868 NULL, /* pSetArcDirection */
7869 NULL, /* pSetBkColor */
7870 NULL, /* pSetBkMode */
7871 NULL, /* pSetDCBrushColor */
7872 NULL, /* pSetDCPenColor */
7873 NULL, /* pSetDIBColorTable */
7874 NULL, /* pSetDIBitsToDevice */
7875 NULL, /* pSetDeviceClipping */
7876 NULL, /* pSetDeviceGammaRamp */
7877 NULL, /* pSetLayout */
7878 NULL, /* pSetMapMode */
7879 NULL, /* pSetMapperFlags */
7880 NULL, /* pSetPixel */
7881 NULL, /* pSetPolyFillMode */
7882 NULL, /* pSetROP2 */
7883 NULL, /* pSetRelAbs */
7884 NULL, /* pSetStretchBltMode */
7885 NULL, /* pSetTextAlign */
7886 NULL, /* pSetTextCharacterExtra */
7887 NULL, /* pSetTextColor */
7888 NULL, /* pSetTextJustification */
7889 NULL, /* pSetViewportExt */
7890 NULL, /* pSetViewportOrg */
7891 NULL, /* pSetWindowExt */
7892 NULL, /* pSetWindowOrg */
7893 NULL, /* pSetWorldTransform */
7894 NULL, /* pStartDoc */
7895 NULL, /* pStartPage */
7896 NULL, /* pStretchBlt */
7897 NULL, /* pStretchDIBits */
7898 NULL, /* pStrokeAndFillPath */
7899 NULL, /* pStrokePath */
7900 NULL, /* pUnrealizePalette */
7901 NULL, /* pWidenPath */
7902 NULL, /* wine_get_wgl_driver */
7903 GDI_PRIORITY_FONT_DRV /* priority */
7906 #else /* HAVE_FREETYPE */
7908 /*************************************************************************/
7910 BOOL WineEngInit(void)
7914 BOOL WineEngDestroyFontInstance(HFONT hfont)
7919 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7921 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7925 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7927 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7931 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
7933 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
7937 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
7938 LPCWSTR font_file, LPCWSTR font_path )
7944 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
7949 /*************************************************************************
7950 * GetRasterizerCaps (GDI32.@)
7952 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7954 lprs->nSize = sizeof(RASTERIZER_STATUS);
7956 lprs->nLanguageID = 0;
7960 #endif /* HAVE_FREETYPE */