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 == req->encoding_id) &&
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.encoding_id = TT_MS_ID_UNICODE_CS;
1172 name.language_id = language_id;
1173 name.name_id = name_id;
1175 if(get_name_table_entry(ft_face, &name))
1179 /* String is not nul terminated and string_len is a byte length. */
1180 ret = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1181 for(i = 0; i < name.string_len / 2; i++)
1183 WORD *tmp = (WORD *)&name.string[i * 2];
1184 ret[i] = GET_BE_WORD(*tmp);
1187 TRACE("Got localised name %s\n", debugstr_w(ret));
1193 static inline BOOL faces_equal( const Face *f1, const Face *f2 )
1195 if (strcmpiW( f1->StyleName, f2->StyleName )) return FALSE;
1196 if (f1->scalable) return TRUE;
1197 if (f1->size.y_ppem != f2->size.y_ppem) return FALSE;
1198 return !memcmp( &f1->fs, &f2->fs, sizeof(f1->fs) );
1201 static inline void free_face( Face *face )
1203 HeapFree( GetProcessHeap(), 0, face->file );
1204 HeapFree( GetProcessHeap(), 0, face->StyleName );
1205 HeapFree( GetProcessHeap(), 0, face->FullName );
1206 HeapFree( GetProcessHeap(), 0, face->cached_enum_data );
1207 HeapFree( GetProcessHeap(), 0, face );
1210 static inline void free_family( Family *family )
1212 Face *face, *cursor2;
1214 LIST_FOR_EACH_ENTRY_SAFE( face, cursor2, &family->faces, Face, entry )
1216 list_remove( &face->entry );
1219 HeapFree( GetProcessHeap(), 0, family->FamilyName );
1220 HeapFree( GetProcessHeap(), 0, family->EnglishName );
1221 HeapFree( GetProcessHeap(), 0, family );
1224 static inline int style_order(const Face *face)
1226 switch (face->ntmFlags & (NTM_REGULAR | NTM_BOLD | NTM_ITALIC))
1234 case NTM_BOLD | NTM_ITALIC:
1237 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1238 debugstr_w(face->family->FamilyName),
1239 debugstr_w(face->StyleName),
1245 static BOOL insert_face_in_family_list( Face *face, Family *family )
1249 LIST_FOR_EACH_ENTRY( cursor, &family->faces, Face, entry )
1251 if (faces_equal( face, cursor ))
1253 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1254 debugstr_w(family->FamilyName), debugstr_w(face->StyleName),
1255 cursor->font_version, face->font_version);
1257 if (face->font_version <= cursor->font_version)
1259 TRACE("Original font %s is newer so skipping %s\n",
1260 debugstr_a(cursor->file), debugstr_a(face->file));
1265 TRACE("Replacing original %s with %s\n",
1266 debugstr_a(cursor->file), debugstr_a(face->file));
1267 list_add_before( &cursor->entry, &face->entry );
1268 face->family = family;
1269 list_remove( &cursor->entry);
1270 free_face( cursor );
1275 TRACE("Adding new %s\n", debugstr_a(face->file));
1277 if (style_order( face ) < style_order( cursor )) break;
1280 list_add_before( &cursor->entry, &face->entry );
1281 face->family = family;
1285 /****************************************************************
1286 * NB This function stores the ptrs to the strings to save copying.
1287 * Don't free them after calling.
1289 static Family *create_family( WCHAR *name, WCHAR *english_name )
1291 Family * const family = HeapAlloc( GetProcessHeap(), 0, sizeof(*family) );
1292 family->FamilyName = name;
1293 family->EnglishName = english_name;
1294 list_init( &family->faces );
1295 family->replacement = &family->faces;
1300 static LONG reg_load_dword(HKEY hkey, const WCHAR *value, DWORD *data)
1303 LONG r = RegQueryValueExW(hkey, value, NULL, &type, NULL, &needed);
1304 if(r != ERROR_SUCCESS) return r;
1305 if(type != REG_DWORD || needed != sizeof(DWORD)) return ERROR_BAD_CONFIGURATION;
1306 return RegQueryValueExW(hkey, value, NULL, &type, (BYTE*)data, &needed);
1309 static inline LONG reg_save_dword(HKEY hkey, const WCHAR *value, DWORD data)
1311 return RegSetValueExW(hkey, value, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD));
1314 static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family)
1317 DWORD num_strikes, max_strike_key_len;
1319 /* If we have a File Name key then this is a real font, not just the parent
1320 key of a bunch of non-scalable strikes */
1321 if(RegQueryValueExA(hkey_face, "File Name", NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1324 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1325 face->cached_enum_data = NULL;
1327 face->file = HeapAlloc(GetProcessHeap(), 0, needed);
1328 RegQueryValueExA(hkey_face, "File Name", NULL, NULL, (BYTE*)face->file, &needed);
1330 face->StyleName = strdupW(face_name);
1332 if(RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1334 WCHAR *fullName = HeapAlloc(GetProcessHeap(), 0, needed);
1335 RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, (BYTE*)fullName, &needed);
1336 face->FullName = fullName;
1339 face->FullName = NULL;
1341 reg_load_dword(hkey_face, face_index_value, (DWORD*)&face->face_index);
1342 reg_load_dword(hkey_face, face_ntmflags_value, &face->ntmFlags);
1343 reg_load_dword(hkey_face, face_version_value, (DWORD*)&face->font_version);
1344 reg_load_dword(hkey_face, face_vertical_value, (DWORD*)&face->vertical);
1346 needed = sizeof(face->fs);
1347 RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
1349 if(reg_load_dword(hkey_face, face_height_value, (DWORD*)&face->size.height) != ERROR_SUCCESS)
1351 face->scalable = TRUE;
1352 memset(&face->size, 0, sizeof(face->size));
1356 face->scalable = FALSE;
1357 reg_load_dword(hkey_face, face_width_value, (DWORD*)&face->size.width);
1358 reg_load_dword(hkey_face, face_size_value, (DWORD*)&face->size.size);
1359 reg_load_dword(hkey_face, face_x_ppem_value, (DWORD*)&face->size.x_ppem);
1360 reg_load_dword(hkey_face, face_y_ppem_value, (DWORD*)&face->size.y_ppem);
1361 reg_load_dword(hkey_face, face_internal_leading_value, (DWORD*)&face->size.internal_leading);
1363 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1364 face->size.height, face->size.width, face->size.size >> 6,
1365 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1368 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1369 face->fs.fsCsb[0], face->fs.fsCsb[1],
1370 face->fs.fsUsb[0], face->fs.fsUsb[1],
1371 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1373 insert_face_in_family_list(face, family);
1375 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
1378 /* do we have any bitmap strikes? */
1379 RegQueryInfoKeyW(hkey_face, NULL, NULL, NULL, &num_strikes, &max_strike_key_len, NULL, NULL,
1380 NULL, NULL, NULL, NULL);
1381 if(num_strikes != 0)
1383 WCHAR strike_name[10];
1384 DWORD strike_index = 0;
1386 needed = sizeof(strike_name) / sizeof(WCHAR);
1387 while(RegEnumKeyExW(hkey_face, strike_index++, strike_name, &needed,
1388 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1391 RegOpenKeyExW(hkey_face, strike_name, 0, KEY_ALL_ACCESS, &hkey_strike);
1392 load_face(hkey_strike, face_name, family);
1393 RegCloseKey(hkey_strike);
1394 needed = sizeof(strike_name) / sizeof(WCHAR);
1399 static void load_font_list_from_cache(HKEY hkey_font_cache)
1401 DWORD max_family_key_len, size;
1403 DWORD family_index = 0;
1407 RegQueryInfoKeyW(hkey_font_cache, NULL, NULL, NULL, NULL, &max_family_key_len, NULL, NULL,
1408 NULL, NULL, NULL, NULL);
1409 family_name = HeapAlloc(GetProcessHeap(), 0, (max_family_key_len + 1) * sizeof(WCHAR));
1411 size = max_family_key_len + 1;
1412 while(RegEnumKeyExW(hkey_font_cache, family_index++, family_name, &size,
1413 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1415 WCHAR *english_family = NULL;
1416 DWORD face_index = 0;
1418 DWORD max_face_key_len;
1420 RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
1421 TRACE("opened family key %s\n", debugstr_w(family_name));
1422 if(RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, NULL, &size) == ERROR_SUCCESS)
1424 english_family = HeapAlloc(GetProcessHeap(), 0, size);
1425 RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE*)english_family, &size);
1428 family = create_family(strdupW(family_name), english_family);
1429 list_add_tail(&font_list, &family->entry);
1433 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1434 subst->from.name = strdupW(english_family);
1435 subst->from.charset = -1;
1436 subst->to.name = strdupW(family_name);
1437 subst->to.charset = -1;
1438 add_font_subst(&font_subst_list, subst, 0);
1441 RegQueryInfoKeyW(hkey_family, NULL, NULL, NULL, NULL, &max_face_key_len, NULL, NULL,
1442 NULL, NULL, NULL, NULL);
1444 face_name = HeapAlloc(GetProcessHeap(), 0, (max_face_key_len + 1) * sizeof(WCHAR));
1445 size = max_face_key_len + 1;
1446 while(RegEnumKeyExW(hkey_family, face_index++, face_name, &size,
1447 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1451 RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face);
1452 load_face(hkey_face, face_name, family);
1453 RegCloseKey(hkey_face);
1454 size = max_face_key_len + 1;
1456 HeapFree(GetProcessHeap(), 0, face_name);
1457 RegCloseKey(hkey_family);
1458 size = max_family_key_len + 1;
1461 HeapFree(GetProcessHeap(), 0, family_name);
1464 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1467 HKEY hkey_wine_fonts;
1469 /* We don't want to create the fonts key as volatile, so open this first */
1470 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1471 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1472 if(ret != ERROR_SUCCESS)
1474 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1478 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1479 KEY_ALL_ACCESS, NULL, hkey, disposition);
1480 RegCloseKey(hkey_wine_fonts);
1484 static void add_face_to_cache(Face *face)
1486 HKEY hkey_font_cache, hkey_family, hkey_face;
1487 WCHAR *face_key_name;
1489 create_font_cache_key(&hkey_font_cache, NULL);
1491 RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0,
1492 NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL);
1493 if(face->family->EnglishName)
1494 RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName,
1495 (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR));
1498 face_key_name = face->StyleName;
1501 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1502 face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1503 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1505 RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
1508 HeapFree(GetProcessHeap(), 0, face_key_name);
1510 RegSetValueExA(hkey_face, "File Name", 0, REG_BINARY, (BYTE*)face->file, strlen(face->file) + 1);
1512 RegSetValueExW(hkey_face, face_full_name_value, 0, REG_SZ, (BYTE*)face->FullName,
1513 (strlenW(face->FullName) + 1) * sizeof(WCHAR));
1515 reg_save_dword(hkey_face, face_index_value, face->face_index);
1516 reg_save_dword(hkey_face, face_ntmflags_value, face->ntmFlags);
1517 reg_save_dword(hkey_face, face_version_value, face->font_version);
1518 reg_save_dword(hkey_face, face_vertical_value, face->vertical);
1520 RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs));
1524 reg_save_dword(hkey_face, face_height_value, face->size.height);
1525 reg_save_dword(hkey_face, face_width_value, face->size.width);
1526 reg_save_dword(hkey_face, face_size_value, face->size.size);
1527 reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem);
1528 reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem);
1529 reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading);
1531 RegCloseKey(hkey_face);
1532 RegCloseKey(hkey_family);
1533 RegCloseKey(hkey_font_cache);
1536 static WCHAR *prepend_at(WCHAR *family)
1543 str = HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR) * (strlenW(family) + 2));
1545 strcpyW(str + 1, family);
1546 HeapFree(GetProcessHeap(), 0, family);
1550 static void get_family_names( FT_Face ft_face, WCHAR **name, WCHAR **english, BOOL vertical )
1552 *english = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1553 if (!*english) *english = towstr( CP_ACP, ft_face->family_name );
1555 *name = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, GetUserDefaultLCID() );
1561 else if (!strcmpiW( *name, *english ))
1563 HeapFree( GetProcessHeap(), 0, *english );
1569 *name = prepend_at( *name );
1570 *english = prepend_at( *english );
1574 static Family *get_family( FT_Face ft_face, BOOL vertical )
1577 WCHAR *name, *english_name;
1579 get_family_names( ft_face, &name, &english_name, vertical );
1581 family = find_family_from_name( name );
1585 family = create_family( name, english_name );
1586 list_add_tail( &font_list, &family->entry );
1590 FontSubst *subst = HeapAlloc( GetProcessHeap(), 0, sizeof(*subst) );
1591 subst->from.name = strdupW( english_name );
1592 subst->from.charset = -1;
1593 subst->to.name = strdupW( name );
1594 subst->to.charset = -1;
1595 add_font_subst( &font_subst_list, subst, 0 );
1600 HeapFree( GetProcessHeap(), 0, name );
1601 HeapFree( GetProcessHeap(), 0, english_name );
1607 static inline FT_Fixed get_font_version( FT_Face ft_face )
1609 FT_Fixed version = 0;
1612 header = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head );
1613 if (header) version = header->Font_Revision;
1618 static inline DWORD get_ntm_flags( FT_Face ft_face )
1621 FT_ULong table_size = 0;
1623 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) flags |= NTM_ITALIC;
1624 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD) flags |= NTM_BOLD;
1625 if (flags == 0) flags = NTM_REGULAR;
1627 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL, &table_size ))
1628 flags |= NTM_PS_OPENTYPE;
1633 static inline int get_bitmap_internal_leading( FT_Face ft_face )
1635 int internal_leading = 0;
1636 FT_WinFNT_HeaderRec winfnt_header;
1638 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1639 internal_leading = winfnt_header.internal_leading;
1641 return internal_leading;
1644 static inline void get_fontsig( FT_Face ft_face, FONTSIGNATURE *fs )
1649 FT_WinFNT_HeaderRec winfnt_header;
1652 memset( fs, 0, sizeof(*fs) );
1654 os2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 );
1657 fs->fsUsb[0] = os2->ulUnicodeRange1;
1658 fs->fsUsb[1] = os2->ulUnicodeRange2;
1659 fs->fsUsb[2] = os2->ulUnicodeRange3;
1660 fs->fsUsb[3] = os2->ulUnicodeRange4;
1662 if (os2->version == 0)
1664 if (pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
1665 fs->fsCsb[0] = FS_LATIN1;
1667 fs->fsCsb[0] = FS_SYMBOL;
1671 fs->fsCsb[0] = os2->ulCodePageRange1;
1672 fs->fsCsb[1] = os2->ulCodePageRange2;
1677 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1679 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1680 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1681 if (TranslateCharsetInfo( (DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET ))
1686 if (fs->fsCsb[0] == 0)
1688 /* let's see if we can find any interesting cmaps */
1689 for (i = 0; i < ft_face->num_charmaps; i++)
1691 switch (ft_face->charmaps[i]->encoding)
1693 case FT_ENCODING_UNICODE:
1694 case FT_ENCODING_APPLE_ROMAN:
1695 fs->fsCsb[0] |= FS_LATIN1;
1697 case FT_ENCODING_MS_SYMBOL:
1698 fs->fsCsb[0] |= FS_SYMBOL;
1707 #define ADDFONT_EXTERNAL_FONT 0x01
1708 #define ADDFONT_FORCE_BITMAP 0x02
1709 #define ADDFONT_ADD_TO_CACHE 0x04
1711 static Face *create_face( FT_Face ft_face, FT_Long face_index, const char *file, void *font_data_ptr, DWORD font_data_size,
1712 DWORD flags, BOOL vertical )
1714 Face *face = HeapAlloc( GetProcessHeap(), 0, sizeof(*face) );
1715 My_FT_Bitmap_Size *size = (My_FT_Bitmap_Size *)ft_face->available_sizes;
1717 face->StyleName = towstr( CP_ACP, ft_face->style_name );
1718 face->FullName = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1721 face->file = strdupA( file );
1722 face->font_data_ptr = NULL;
1723 face->font_data_size = 0;
1728 face->font_data_ptr = font_data_ptr;
1729 face->font_data_size = font_data_size;
1732 face->face_index = face_index;
1733 get_fontsig( ft_face, &face->fs );
1734 face->ntmFlags = get_ntm_flags( ft_face );
1735 face->font_version = get_font_version( ft_face );
1737 if (FT_IS_SCALABLE( ft_face ))
1739 memset( &face->size, 0, sizeof(face->size) );
1740 face->scalable = TRUE;
1744 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1745 size->height, size->width, size->size >> 6,
1746 size->x_ppem >> 6, size->y_ppem >> 6);
1747 face->size.height = size->height;
1748 face->size.width = size->width;
1749 face->size.size = size->size;
1750 face->size.x_ppem = size->x_ppem;
1751 face->size.y_ppem = size->y_ppem;
1752 face->size.internal_leading = get_bitmap_internal_leading( ft_face );
1753 face->scalable = FALSE;
1756 face->vertical = vertical;
1757 face->external = (flags & ADDFONT_EXTERNAL_FONT) != 0;
1758 face->family = NULL;
1759 face->cached_enum_data = NULL;
1761 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1762 face->fs.fsCsb[0], face->fs.fsCsb[1],
1763 face->fs.fsUsb[0], face->fs.fsUsb[1],
1764 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1769 static void AddFaceToList(FT_Face ft_face, const char *file, void *font_data_ptr, DWORD font_data_size,
1770 FT_Long face_index, DWORD flags, BOOL vertical)
1775 face = create_face( ft_face, face_index, file, font_data_ptr, font_data_size, flags, vertical );
1776 family = get_family( ft_face, vertical );
1777 if (!insert_face_in_family_list( face, family ))
1783 if (flags & ADDFONT_ADD_TO_CACHE)
1784 add_face_to_cache( face );
1786 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1787 debugstr_w(face->StyleName));
1790 static FT_Face new_ft_face( const char *file, void *font_data_ptr, DWORD font_data_size,
1791 FT_Long face_index, BOOL allow_bitmap )
1799 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1800 err = pFT_New_Face(library, file, face_index, &ft_face);
1804 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1805 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1810 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1814 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1815 if (!FT_IS_SCALABLE( ft_face ) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0)))
1817 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1821 if (!FT_IS_SFNT( ft_face ))
1823 if (FT_IS_SCALABLE( ft_face ) || !allow_bitmap )
1825 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1831 if (!(pOS2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 )) ||
1832 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_hhea ) ||
1833 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head ))
1835 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1836 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1840 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1841 we don't want to load these. */
1842 if (!memcmp( pOS2->achVendID, "Wine", sizeof(pOS2->achVendID) ))
1846 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len ))
1848 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1854 if (!ft_face->family_name || !ft_face->style_name)
1856 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1862 pFT_Done_Face( ft_face );
1866 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, DWORD flags)
1869 FT_Long face_index = 0, num_faces;
1872 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1873 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1875 #ifdef HAVE_CARBON_CARBON_H
1878 char **mac_list = expand_mac_font(file);
1881 BOOL had_one = FALSE;
1883 for(cursor = mac_list; *cursor; cursor++)
1886 AddFontToList(*cursor, NULL, 0, flags);
1887 HeapFree(GetProcessHeap(), 0, *cursor);
1889 HeapFree(GetProcessHeap(), 0, mac_list);
1894 #endif /* HAVE_CARBON_CARBON_H */
1897 ft_face = new_ft_face( file, font_data_ptr, font_data_size, face_index, flags & ADDFONT_FORCE_BITMAP );
1898 if (!ft_face) return 0;
1900 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1902 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1903 pFT_Done_Face(ft_face);
1907 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags, FALSE);
1910 if (FT_HAS_VERTICAL(ft_face))
1912 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags, TRUE);
1916 num_faces = ft_face->num_faces;
1917 pFT_Done_Face(ft_face);
1918 } while(num_faces > ++face_index);
1922 static void DumpFontList(void)
1926 struct list *family_elem_ptr, *face_elem_ptr;
1928 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1929 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1930 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1931 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1932 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1933 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1935 TRACE(" %d", face->size.height);
1942 /***********************************************************
1943 * The replacement list is a way to map an entire font
1944 * family onto another family. For example adding
1946 * [HKCU\Software\Wine\Fonts\Replacements]
1947 * "Wingdings"="Winedings"
1949 * would enumerate the Winedings font both as Winedings and
1950 * Wingdings. However if a real Wingdings font is present the
1951 * replacement does not take place.
1954 static void LoadReplaceList(void)
1957 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1962 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1963 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1965 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1966 &valuelen, &datalen, NULL, NULL);
1968 valuelen++; /* returned value doesn't include room for '\0' */
1969 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1970 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1974 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1975 &dlen) == ERROR_SUCCESS) {
1976 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1977 /* "NewName"="Oldname" */
1978 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1980 if(!find_family_from_any_name(value))
1982 Family * const family = find_family_from_any_name(data);
1985 Family * const new_family = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family));
1986 if (new_family != NULL)
1988 TRACE("mapping %s to %s\n", debugstr_w(data), debugstr_w(value));
1989 new_family->FamilyName = strdupW(value);
1990 new_family->EnglishName = NULL;
1991 list_init(&new_family->faces);
1992 new_family->replacement = &family->faces;
1993 list_add_tail(&font_list, &new_family->entry);
1998 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(data));
2003 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value));
2005 /* reset dlen and vlen */
2009 HeapFree(GetProcessHeap(), 0, data);
2010 HeapFree(GetProcessHeap(), 0, value);
2015 static const WCHAR *font_links_list[] =
2017 Lucida_Sans_Unicode,
2018 Microsoft_Sans_Serif,
2022 static const struct font_links_defaults_list
2024 /* Keyed off substitution for "MS Shell Dlg" */
2025 const WCHAR *shelldlg;
2026 /* Maximum of four substitutes, plus terminating NULL pointer */
2027 const WCHAR *substitutes[5];
2028 } font_links_defaults_list[] =
2030 /* Non East-Asian */
2031 { Tahoma, /* FIXME unverified ordering */
2032 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2034 /* Below lists are courtesy of
2035 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2039 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2041 /* Chinese Simplified */
2043 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2047 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2049 /* Chinese Traditional */
2051 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2056 static SYSTEM_LINKS *find_font_link(const WCHAR *name)
2058 SYSTEM_LINKS *font_link;
2060 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2062 if(!strcmpiW(font_link->font_name, name))
2069 static void populate_system_links(const WCHAR *name, const WCHAR *const *values)
2081 SYSTEM_LINKS *font_link;
2083 psub = get_font_subst(&font_subst_list, name, -1);
2084 /* Don't store fonts that are only substitutes for other fonts */
2087 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name));
2091 font_link = find_font_link(name);
2092 if (font_link == NULL)
2094 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2095 font_link->font_name = strdupW(name);
2096 list_init(&font_link->links);
2097 list_add_tail(&system_links, &font_link->entry);
2100 memset(&font_link->fs, 0, sizeof font_link->fs);
2101 for (i = 0; values[i] != NULL; i++)
2103 const struct list *face_list;
2104 CHILD_FONT *child_font;
2107 if (!strcmpiW(name,value))
2109 psub = get_font_subst(&font_subst_list, value, -1);
2111 value = psub->to.name;
2112 family = find_family_from_name(value);
2116 /* Use first extant filename for this Family */
2117 face_list = get_face_list_from_family(family);
2118 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
2122 file = strrchr(face->file, '/');
2131 fileW = towstr(CP_UNIXCP, file);
2133 face = find_face_from_filename(fileW, value);
2136 TRACE("Unable to find file %s face name %s\n", debugstr_w(fileW), debugstr_w(value));
2140 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2141 child_font->face = face;
2142 child_font->font = NULL;
2143 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2144 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2145 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
2146 list_add_tail(&font_link->links, &child_font->entry);
2148 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(fileW));
2149 HeapFree(GetProcessHeap(), 0, fileW);
2155 /*************************************************************
2158 static BOOL init_system_links(void)
2162 DWORD type, max_val, max_data, val_len, data_len, index;
2163 WCHAR *value, *data;
2164 WCHAR *entry, *next;
2165 SYSTEM_LINKS *font_link, *system_font_link;
2166 CHILD_FONT *child_font;
2167 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
2168 static const WCHAR System[] = {'S','y','s','t','e','m',0};
2169 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2174 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
2176 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
2177 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
2178 data = HeapAlloc(GetProcessHeap(), 0, max_data);
2179 val_len = max_val + 1;
2180 data_len = max_data;
2182 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
2184 psub = get_font_subst(&font_subst_list, value, -1);
2185 /* Don't store fonts that are only substitutes for other fonts */
2188 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
2191 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2192 font_link->font_name = strdupW(value);
2193 memset(&font_link->fs, 0, sizeof font_link->fs);
2194 list_init(&font_link->links);
2195 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
2198 CHILD_FONT *child_font;
2200 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
2202 next = entry + strlenW(entry) + 1;
2204 face_name = strchrW(entry, ',');
2208 while(isspaceW(*face_name))
2211 psub = get_font_subst(&font_subst_list, face_name, -1);
2213 face_name = psub->to.name;
2215 face = find_face_from_filename(entry, face_name);
2218 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
2222 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2223 child_font->face = face;
2224 child_font->font = NULL;
2225 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2226 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2227 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
2228 list_add_tail(&font_link->links, &child_font->entry);
2230 list_add_tail(&system_links, &font_link->entry);
2232 val_len = max_val + 1;
2233 data_len = max_data;
2236 HeapFree(GetProcessHeap(), 0, value);
2237 HeapFree(GetProcessHeap(), 0, data);
2242 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2244 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2248 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2250 const FontSubst *psub2;
2251 psub2 = get_font_subst(&font_subst_list, font_links_defaults_list[i].shelldlg, -1);
2253 if ((!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name) || (psub2 && !strcmpiW(psub2->to.name,psub->to.name))))
2255 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2256 populate_system_links(font_links_list[j], font_links_defaults_list[i].substitutes);
2258 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2259 populate_system_links(psub->to.name, font_links_defaults_list[i].substitutes);
2261 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2263 populate_system_links(font_links_defaults_list[i].substitutes[0], NULL);
2269 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2272 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2273 system_font_link->font_name = strdupW(System);
2274 memset(&system_font_link->fs, 0, sizeof system_font_link->fs);
2275 list_init(&system_font_link->links);
2277 face = find_face_from_filename(tahoma_ttf, Tahoma);
2280 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2281 child_font->face = face;
2282 child_font->font = NULL;
2283 system_font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2284 system_font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2285 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
2286 list_add_tail(&system_font_link->links, &child_font->entry);
2288 font_link = find_font_link(Tahoma);
2289 if (font_link != NULL)
2291 CHILD_FONT *font_link_entry;
2292 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2294 CHILD_FONT *new_child;
2295 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2296 new_child->face = font_link_entry->face;
2297 new_child->font = NULL;
2298 system_font_link->fs.fsCsb[0] |= font_link_entry->face->fs.fsCsb[0];
2299 system_font_link->fs.fsCsb[1] |= font_link_entry->face->fs.fsCsb[1];
2300 list_add_tail(&system_font_link->links, &new_child->entry);
2303 list_add_tail(&system_links, &system_font_link->entry);
2307 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2310 struct dirent *dent;
2311 char path[MAX_PATH];
2313 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2315 dir = opendir(dirname);
2317 WARN("Can't open directory %s\n", debugstr_a(dirname));
2320 while((dent = readdir(dir)) != NULL) {
2321 struct stat statbuf;
2323 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2326 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2328 sprintf(path, "%s/%s", dirname, dent->d_name);
2330 if(stat(path, &statbuf) == -1)
2332 WARN("Can't stat %s\n", debugstr_a(path));
2335 if(S_ISDIR(statbuf.st_mode))
2336 ReadFontDir(path, external_fonts);
2339 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2340 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2341 AddFontToList(path, NULL, 0, addfont_flags);
2348 #ifdef SONAME_LIBFONTCONFIG
2349 static void load_fontconfig_fonts(void)
2351 void *fc_handle = NULL;
2360 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2362 TRACE("Wine cannot find the fontconfig library (%s).\n",
2363 SONAME_LIBFONTCONFIG);
2366 #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;}
2367 LOAD_FUNCPTR(FcConfigGetCurrent);
2368 LOAD_FUNCPTR(FcFontList);
2369 LOAD_FUNCPTR(FcFontSetDestroy);
2370 LOAD_FUNCPTR(FcInit);
2371 LOAD_FUNCPTR(FcObjectSetAdd);
2372 LOAD_FUNCPTR(FcObjectSetCreate);
2373 LOAD_FUNCPTR(FcObjectSetDestroy);
2374 LOAD_FUNCPTR(FcPatternCreate);
2375 LOAD_FUNCPTR(FcPatternDestroy);
2376 LOAD_FUNCPTR(FcPatternGetBool);
2377 LOAD_FUNCPTR(FcPatternGetString);
2380 if(!pFcInit()) return;
2382 config = pFcConfigGetCurrent();
2383 pat = pFcPatternCreate();
2384 os = pFcObjectSetCreate();
2385 pFcObjectSetAdd(os, FC_FILE);
2386 pFcObjectSetAdd(os, FC_SCALABLE);
2387 fontset = pFcFontList(config, pat, os);
2388 if(!fontset) return;
2389 for(i = 0; i < fontset->nfont; i++) {
2392 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2394 TRACE("fontconfig: %s\n", file);
2396 /* We're just interested in OT/TT fonts for now, so this hack just
2397 picks up the scalable fonts without extensions .pf[ab] to save time
2398 loading every other font */
2400 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2402 TRACE("not scalable\n");
2406 len = strlen( file );
2407 if(len < 4) continue;
2408 ext = &file[ len - 3 ];
2409 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2410 AddFontToList(file, NULL, 0, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2412 pFcFontSetDestroy(fontset);
2413 pFcObjectSetDestroy(os);
2414 pFcPatternDestroy(pat);
2419 #elif defined(HAVE_CARBON_CARBON_H)
2421 static void load_mac_font_callback(const void *value, void *context)
2423 CFStringRef pathStr = value;
2427 len = CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr);
2428 path = HeapAlloc(GetProcessHeap(), 0, len);
2429 if (path && CFStringGetFileSystemRepresentation(pathStr, path, len))
2431 TRACE("font file %s\n", path);
2432 AddFontToList(path, NULL, 0, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2434 HeapFree(GetProcessHeap(), 0, path);
2437 static void load_mac_fonts(void)
2439 CFStringRef removeDupesKey;
2440 CFBooleanRef removeDupesValue;
2441 CFDictionaryRef options;
2442 CTFontCollectionRef col;
2444 CFMutableSetRef paths;
2447 removeDupesKey = kCTFontCollectionRemoveDuplicatesOption;
2448 removeDupesValue = kCFBooleanTrue;
2449 options = CFDictionaryCreate(NULL, (const void**)&removeDupesKey, (const void**)&removeDupesValue, 1,
2450 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2451 col = CTFontCollectionCreateFromAvailableFonts(options);
2452 if (options) CFRelease(options);
2455 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
2459 descs = CTFontCollectionCreateMatchingFontDescriptors(col);
2463 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
2467 paths = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
2470 WARN("CFSetCreateMutable failed\n");
2475 for (i = 0; i < CFArrayGetCount(descs); i++)
2477 CTFontDescriptorRef desc;
2486 desc = CFArrayGetValueAtIndex(descs, i);
2488 /* CTFontDescriptor doesn't support kCTFontURLAttribute until 10.6, so
2489 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
2490 font = CTFontCreateWithFontDescriptor(desc, 0, NULL);
2491 if (!font) continue;
2493 atsFont = CTFontGetPlatformFont(font, NULL);
2500 status = ATSFontGetFileReference(atsFont, &fsref);
2502 if (status != noErr) continue;
2504 url = CFURLCreateFromFSRef(NULL, &fsref);
2507 ext = CFURLCopyPathExtension(url);
2510 BOOL skip = (CFStringCompare(ext, CFSTR("pfa"), kCFCompareCaseInsensitive) == kCFCompareEqualTo ||
2511 CFStringCompare(ext, CFSTR("pfb"), kCFCompareCaseInsensitive) == kCFCompareEqualTo);
2520 path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
2522 if (!path) continue;
2524 CFSetAddValue(paths, path);
2530 CFSetApplyFunction(paths, load_mac_font_callback, NULL);
2536 static BOOL load_font_from_data_dir(LPCWSTR file)
2539 const char *data_dir = wine_get_data_dir();
2541 if (!data_dir) data_dir = wine_get_build_dir();
2548 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
2550 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
2552 strcpy(unix_name, data_dir);
2553 strcat(unix_name, "/fonts/");
2555 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
2557 EnterCriticalSection( &freetype_cs );
2558 ret = AddFontToList(unix_name, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2559 LeaveCriticalSection( &freetype_cs );
2560 HeapFree(GetProcessHeap(), 0, unix_name);
2565 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
2567 static const WCHAR slashW[] = {'\\','\0'};
2569 WCHAR windowsdir[MAX_PATH];
2572 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2573 strcatW(windowsdir, fontsW);
2574 strcatW(windowsdir, slashW);
2575 strcatW(windowsdir, file);
2576 if ((unixname = wine_get_unix_file_name(windowsdir))) {
2577 EnterCriticalSection( &freetype_cs );
2578 ret = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP);
2579 LeaveCriticalSection( &freetype_cs );
2580 HeapFree(GetProcessHeap(), 0, unixname);
2585 static void load_system_fonts(void)
2588 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
2589 const WCHAR * const *value;
2591 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2594 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
2595 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2596 strcatW(windowsdir, fontsW);
2597 for(value = SystemFontValues; *value; value++) {
2598 dlen = sizeof(data);
2599 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
2603 sprintfW(pathW, fmtW, windowsdir, data);
2604 if((unixname = wine_get_unix_file_name(pathW))) {
2605 added = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2606 HeapFree(GetProcessHeap(), 0, unixname);
2609 load_font_from_data_dir(data);
2616 /*************************************************************
2618 * This adds registry entries for any externally loaded fonts
2619 * (fonts from fontconfig or FontDirs). It also deletes entries
2620 * of no longer existing fonts.
2623 static void update_reg_entries(void)
2625 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2630 struct list *family_elem_ptr, *face_elem_ptr;
2632 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2635 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2636 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2637 ERR("Can't create Windows font reg key\n");
2641 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2642 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2643 ERR("Can't create Windows font reg key\n");
2647 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
2648 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
2649 ERR("Can't create external font reg key\n");
2653 /* enumerate the fonts and add external ones to the two keys */
2655 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2656 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2657 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2658 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2659 if(!face->external) continue;
2663 len = strlenW(face->FullName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2664 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2665 strcpyW(valueW, face->FullName);
2669 len = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2670 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2671 strcpyW(valueW, family->FamilyName);
2674 file = wine_get_dos_file_name(face->file);
2676 len = strlenW(file) + 1;
2679 if((path = strrchr(face->file, '/')) == NULL)
2683 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
2685 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2686 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2688 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2689 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2690 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2692 HeapFree(GetProcessHeap(), 0, file);
2693 HeapFree(GetProcessHeap(), 0, valueW);
2697 if(external_key) RegCloseKey(external_key);
2698 if(win9x_key) RegCloseKey(win9x_key);
2699 if(winnt_key) RegCloseKey(winnt_key);
2703 static void delete_external_font_keys(void)
2705 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2706 DWORD dlen, vlen, datalen, valuelen, i, type;
2710 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2711 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2712 ERR("Can't create Windows font reg key\n");
2716 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2717 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2718 ERR("Can't create Windows font reg key\n");
2722 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2723 ERR("Can't create external font reg key\n");
2727 /* Delete all external fonts added last time */
2729 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2730 &valuelen, &datalen, NULL, NULL);
2731 valuelen++; /* returned value doesn't include room for '\0' */
2732 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2733 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2735 dlen = datalen * sizeof(WCHAR);
2738 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2739 &dlen) == ERROR_SUCCESS) {
2741 RegDeleteValueW(winnt_key, valueW);
2742 RegDeleteValueW(win9x_key, valueW);
2743 /* reset dlen and vlen */
2747 HeapFree(GetProcessHeap(), 0, data);
2748 HeapFree(GetProcessHeap(), 0, valueW);
2750 /* Delete the old external fonts key */
2751 RegCloseKey(external_key);
2752 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2755 if(win9x_key) RegCloseKey(win9x_key);
2756 if(winnt_key) RegCloseKey(winnt_key);
2759 /*************************************************************
2760 * WineEngAddFontResourceEx
2763 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2769 if (ft_handle) /* do it only if we have freetype up and running */
2774 FIXME("Ignoring flags %x\n", flags);
2776 if((unixname = wine_get_unix_file_name(file)))
2778 DWORD addfont_flags = ADDFONT_FORCE_BITMAP;
2780 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
2781 EnterCriticalSection( &freetype_cs );
2782 ret = AddFontToList(unixname, NULL, 0, addfont_flags);
2783 LeaveCriticalSection( &freetype_cs );
2784 HeapFree(GetProcessHeap(), 0, unixname);
2786 if (!ret && !strchrW(file, '\\')) {
2787 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2788 ret = load_font_from_winfonts_dir(file);
2790 /* Try in datadir/fonts (or builddir/fonts),
2791 * needed for Magic the Gathering Online
2793 ret = load_font_from_data_dir(file);
2800 /*************************************************************
2801 * WineEngAddFontMemResourceEx
2804 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2808 if (ft_handle) /* do it only if we have freetype up and running */
2810 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2812 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2813 memcpy(pFontCopy, pbFont, cbFont);
2815 EnterCriticalSection( &freetype_cs );
2816 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, ADDFONT_FORCE_BITMAP);
2817 LeaveCriticalSection( &freetype_cs );
2821 TRACE("AddFontToList failed\n");
2822 HeapFree(GetProcessHeap(), 0, pFontCopy);
2825 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2826 * For now return something unique but quite random
2828 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2829 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2836 /*************************************************************
2837 * WineEngRemoveFontResourceEx
2840 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2843 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
2847 static char *get_ttf_file_name( LPCWSTR font_file, LPCWSTR font_path )
2853 if (!font_file) return NULL;
2855 file_len = strlenW( font_file );
2857 if (font_path && font_path[0])
2859 int path_len = strlenW( font_path );
2860 fullname = HeapAlloc( GetProcessHeap(), 0, (file_len + path_len + 2) * sizeof(WCHAR) );
2861 if (!fullname) return NULL;
2862 memcpy( fullname, font_path, path_len * sizeof(WCHAR) );
2863 fullname[path_len] = '\\';
2864 memcpy( fullname + path_len + 1, font_file, (file_len + 1) * sizeof(WCHAR) );
2868 int len = GetFullPathNameW( font_file, 0, NULL, NULL );
2869 if (!len) return NULL;
2870 fullname = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
2871 if (!fullname) return NULL;
2872 GetFullPathNameW( font_file, len, fullname, NULL );
2875 unix_name = wine_get_unix_file_name( fullname );
2876 HeapFree( GetProcessHeap(), 0, fullname );
2880 #include <pshpack1.h>
2883 WORD num_of_resources;
2887 CHAR dfCopyright[60];
2893 WORD dfInternalLeading;
2894 WORD dfExternalLeading;
2902 BYTE dfPitchAndFamily;
2913 CHAR szFaceName[LF_FACESIZE];
2916 #include <poppack.h>
2918 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
2919 NEWTEXTMETRICEXW *pntm, LPDWORD ptype);
2921 static BOOL get_fontdir( const char *unix_name, struct fontdir *fd )
2923 FT_Face ft_face = new_ft_face( unix_name, NULL, 0, 0, FALSE );
2926 WCHAR *name, *english_name;
2928 NEWTEXTMETRICEXW ntm;
2931 if (!ft_face) return FALSE;
2932 face = create_face( ft_face, 0, unix_name, NULL, 0, 0, FALSE );
2933 get_family_names( ft_face, &name, &english_name, FALSE );
2934 family = create_family( name, english_name );
2935 insert_face_in_family_list( face, family );
2936 pFT_Done_Face( ft_face );
2938 GetEnumStructs( face, &elf, &ntm, &type );
2939 free_family( family );
2941 if ((type & TRUETYPE_FONTTYPE) == 0) return FALSE;
2943 memset( fd, 0, sizeof(*fd) );
2945 fd->num_of_resources = 1;
2947 fd->dfVersion = 0x200;
2948 fd->dfSize = sizeof(*fd);
2949 strcpy( fd->dfCopyright, "Wine fontdir" );
2950 fd->dfType = 0x4003; /* 0x0080 set if private */
2951 fd->dfPoints = ntm.ntmTm.ntmSizeEM;
2953 fd->dfHorizRes = 72;
2954 fd->dfAscent = ntm.ntmTm.tmAscent;
2955 fd->dfInternalLeading = ntm.ntmTm.tmInternalLeading;
2956 fd->dfExternalLeading = ntm.ntmTm.tmExternalLeading;
2957 fd->dfItalic = ntm.ntmTm.tmItalic;
2958 fd->dfUnderline = ntm.ntmTm.tmUnderlined;
2959 fd->dfStrikeOut = ntm.ntmTm.tmStruckOut;
2960 fd->dfWeight = ntm.ntmTm.tmWeight;
2961 fd->dfCharSet = ntm.ntmTm.tmCharSet;
2963 fd->dfPixHeight = ntm.ntmTm.tmHeight;
2964 fd->dfPitchAndFamily = ntm.ntmTm.tmPitchAndFamily;
2965 fd->dfAvgWidth = ntm.ntmTm.tmAveCharWidth;
2966 fd->dfMaxWidth = ntm.ntmTm.tmMaxCharWidth;
2967 fd->dfFirstChar = ntm.ntmTm.tmFirstChar;
2968 fd->dfLastChar = ntm.ntmTm.tmLastChar;
2969 fd->dfDefaultChar = ntm.ntmTm.tmDefaultChar;
2970 fd->dfBreakChar = ntm.ntmTm.tmBreakChar;
2971 fd->dfWidthBytes = 0;
2973 fd->dfFace = FIELD_OFFSET( struct fontdir, szFaceName );
2975 WideCharToMultiByte( CP_ACP, 0, elf.elfLogFont.lfFaceName, -1, fd->szFaceName, LF_FACESIZE, NULL, NULL );
2980 #define NE_FFLAGS_LIBMODULE 0x8000
2981 #define NE_OSFLAGS_WINDOWS 0x02
2983 static const char dos_string[0x40] = "This is a TrueType resource file";
2984 static const char FONTRES[] = {'F','O','N','T','R','E','S',':'};
2986 #include <pshpack2.h>
3007 struct ne_typeinfo fontdir_type;
3008 struct ne_nameinfo fontdir_name;
3009 struct ne_typeinfo scalable_type;
3010 struct ne_nameinfo scalable_name;
3012 BYTE fontdir_res_name[8];
3015 #include <poppack.h>
3017 static BOOL create_fot( const WCHAR *resource, const WCHAR *font_file, const struct fontdir *fontdir )
3021 DWORD size, written;
3023 BYTE import_name_len, res_name_len, non_res_name_len, font_file_len;
3024 char *font_fileA, *last_part, *ext;
3025 IMAGE_DOS_HEADER dos;
3026 IMAGE_OS2_HEADER ne =
3028 IMAGE_OS2_SIGNATURE, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE, 0,
3030 0, sizeof(ne), sizeof(ne), 0, 0, 0, 0,
3031 0, 4, 2, NE_OSFLAGS_WINDOWS, 0, 0, 0, 0, 0x300
3033 struct rsrc_tab rsrc_tab =
3037 { 0, 0, 0x0c50, 0x2c, 0 },
3039 { 0, 0, 0x0c50, 0x8001, 0 },
3041 { 7,'F','O','N','T','D','I','R'}
3044 memset( &dos, 0, sizeof(dos) );
3045 dos.e_magic = IMAGE_DOS_SIGNATURE;
3046 dos.e_lfanew = sizeof(dos) + sizeof(dos_string);
3048 /* import name is last part\0, resident name is last part without extension
3049 non-resident name is "FONTRES:" + lfFaceName */
3051 font_file_len = WideCharToMultiByte( CP_ACP, 0, font_file, -1, NULL, 0, NULL, NULL );
3052 font_fileA = HeapAlloc( GetProcessHeap(), 0, font_file_len );
3053 WideCharToMultiByte( CP_ACP, 0, font_file, -1, font_fileA, font_file_len, NULL, NULL );
3055 last_part = strrchr( font_fileA, '\\' );
3056 if (last_part) last_part++;
3057 else last_part = font_fileA;
3058 import_name_len = strlen( last_part ) + 1;
3060 ext = strchr( last_part, '.' );
3061 if (ext) res_name_len = ext - last_part;
3062 else res_name_len = import_name_len - 1;
3064 non_res_name_len = sizeof( FONTRES ) + strlen( fontdir->szFaceName );
3066 ne.ne_cbnrestab = 1 + non_res_name_len + 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
3067 ne.ne_restab = ne.ne_rsrctab + sizeof(rsrc_tab);
3068 ne.ne_modtab = ne.ne_imptab = ne.ne_restab + 1 + res_name_len + 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
3069 ne.ne_enttab = ne.ne_imptab + 1 + import_name_len; /* len + string */
3071 ne.ne_nrestab = ne.ne_enttab + ne.ne_cbenttab + 2 + dos.e_lfanew; /* there are 2 bytes of 0 after entry tab */
3073 rsrc_tab.scalable_name.off = (ne.ne_nrestab + ne.ne_cbnrestab + 0xf) >> 4;
3074 rsrc_tab.scalable_name.len = (font_file_len + 0xf) >> 4;
3075 rsrc_tab.fontdir_name.off = rsrc_tab.scalable_name.off + rsrc_tab.scalable_name.len;
3076 rsrc_tab.fontdir_name.len = (fontdir->dfSize + 0xf) >> 4;
3078 size = (rsrc_tab.fontdir_name.off + rsrc_tab.fontdir_name.len) << 4;
3079 start = ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
3083 HeapFree( GetProcessHeap(), 0, font_fileA );
3087 memcpy( ptr, &dos, sizeof(dos) );
3088 memcpy( ptr + sizeof(dos), dos_string, sizeof(dos_string) );
3089 memcpy( ptr + dos.e_lfanew, &ne, sizeof(ne) );
3091 ptr = start + dos.e_lfanew + ne.ne_rsrctab;
3092 memcpy( ptr, &rsrc_tab, sizeof(rsrc_tab) );
3094 ptr = start + dos.e_lfanew + ne.ne_restab;
3095 *ptr++ = res_name_len;
3096 memcpy( ptr, last_part, res_name_len );
3098 ptr = start + dos.e_lfanew + ne.ne_imptab;
3099 *ptr++ = import_name_len;
3100 memcpy( ptr, last_part, import_name_len );
3102 ptr = start + ne.ne_nrestab;
3103 *ptr++ = non_res_name_len;
3104 memcpy( ptr, FONTRES, sizeof(FONTRES) );
3105 memcpy( ptr + sizeof(FONTRES), fontdir->szFaceName, strlen( fontdir->szFaceName ) );
3107 ptr = start + (rsrc_tab.scalable_name.off << 4);
3108 memcpy( ptr, font_fileA, font_file_len );
3110 ptr = start + (rsrc_tab.fontdir_name.off << 4);
3111 memcpy( ptr, fontdir, fontdir->dfSize );
3113 file = CreateFileW( resource, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
3114 if (file != INVALID_HANDLE_VALUE)
3116 if (WriteFile( file, start, size, &written, NULL ) && written == size)
3118 CloseHandle( file );
3121 HeapFree( GetProcessHeap(), 0, start );
3122 HeapFree( GetProcessHeap(), 0, font_fileA );
3127 /*************************************************************
3128 * WineEngCreateScalableFontResource
3131 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
3132 LPCWSTR font_file, LPCWSTR font_path )
3134 char *unix_name = get_ttf_file_name( font_file, font_path );
3135 struct fontdir fontdir;
3138 if (!unix_name || !get_fontdir( unix_name, &fontdir ))
3139 SetLastError( ERROR_INVALID_PARAMETER );
3142 if (hidden) fontdir.dfType |= 0x80;
3143 ret = create_fot( resource, font_file, &fontdir );
3146 HeapFree( GetProcessHeap(), 0, unix_name );
3150 static const struct nls_update_font_list
3152 UINT ansi_cp, oem_cp;
3153 const char *oem, *fixed, *system;
3154 const char *courier, *serif, *small, *sserif_96, *sserif_120;
3155 /* these are for font substitutes */
3156 const char *shelldlg, *tmsrmn;
3157 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
3161 const char *from, *to;
3162 } arial_0, courier_new_0, times_new_roman_0;
3163 } nls_update_font_list[] =
3165 /* Latin 1 (United States) */
3166 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
3167 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3168 "Tahoma","Times New Roman",
3169 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3172 /* Latin 1 (Multilingual) */
3173 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
3174 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3175 "Tahoma","Times New Roman", /* FIXME unverified */
3176 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3179 /* Eastern Europe */
3180 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
3181 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
3182 "Tahoma","Times New Roman", /* FIXME unverified */
3183 "Fixedsys,238", "System,238",
3184 "Courier New,238", "MS Serif,238", "Small Fonts,238",
3185 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
3186 { "Arial CE,0", "Arial,238" },
3187 { "Courier New CE,0", "Courier New,238" },
3188 { "Times New Roman CE,0", "Times New Roman,238" }
3191 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
3192 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
3193 "Tahoma","Times New Roman", /* FIXME unverified */
3194 "Fixedsys,204", "System,204",
3195 "Courier New,204", "MS Serif,204", "Small Fonts,204",
3196 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
3197 { "Arial Cyr,0", "Arial,204" },
3198 { "Courier New Cyr,0", "Courier New,204" },
3199 { "Times New Roman Cyr,0", "Times New Roman,204" }
3202 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
3203 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
3204 "Tahoma","Times New Roman", /* FIXME unverified */
3205 "Fixedsys,161", "System,161",
3206 "Courier New,161", "MS Serif,161", "Small Fonts,161",
3207 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
3208 { "Arial Greek,0", "Arial,161" },
3209 { "Courier New Greek,0", "Courier New,161" },
3210 { "Times New Roman Greek,0", "Times New Roman,161" }
3213 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
3214 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
3215 "Tahoma","Times New Roman", /* FIXME unverified */
3216 "Fixedsys,162", "System,162",
3217 "Courier New,162", "MS Serif,162", "Small Fonts,162",
3218 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
3219 { "Arial Tur,0", "Arial,162" },
3220 { "Courier New Tur,0", "Courier New,162" },
3221 { "Times New Roman Tur,0", "Times New Roman,162" }
3224 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
3225 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
3226 "Tahoma","Times New Roman", /* FIXME unverified */
3227 "Fixedsys,177", "System,177",
3228 "Courier New,177", "MS Serif,177", "Small Fonts,177",
3229 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
3233 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
3234 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
3235 "Tahoma","Times New Roman", /* FIXME unverified */
3236 "Fixedsys,178", "System,178",
3237 "Courier New,178", "MS Serif,178", "Small Fonts,178",
3238 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
3242 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
3243 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
3244 "Tahoma","Times New Roman", /* FIXME unverified */
3245 "Fixedsys,186", "System,186",
3246 "Courier New,186", "MS Serif,186", "Small Fonts,186",
3247 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
3248 { "Arial Baltic,0", "Arial,186" },
3249 { "Courier New Baltic,0", "Courier New,186" },
3250 { "Times New Roman Baltic,0", "Times New Roman,186" }
3253 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
3254 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3255 "Tahoma","Times New Roman", /* FIXME unverified */
3256 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3260 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
3261 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
3262 "Tahoma","Times New Roman", /* FIXME unverified */
3263 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3267 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
3268 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
3269 "MS UI Gothic","MS Serif",
3270 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3273 /* Chinese Simplified */
3274 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
3275 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3276 "SimSun", "NSimSun",
3277 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3281 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
3282 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3284 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3287 /* Chinese Traditional */
3288 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
3289 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3290 "PMingLiU", "MingLiU",
3291 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3296 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
3298 return ( ansi_cp == 932 /* CP932 for Japanese */
3299 || ansi_cp == 936 /* CP936 for Chinese Simplified */
3300 || ansi_cp == 949 /* CP949 for Korean */
3301 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
3304 static inline HKEY create_fonts_NT_registry_key(void)
3308 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
3309 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3313 static inline HKEY create_fonts_9x_registry_key(void)
3317 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
3318 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3322 static inline HKEY create_config_fonts_registry_key(void)
3326 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
3327 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3331 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl, int dpi)
3333 const char *sserif = (dpi <= 108) ? fl->sserif_96 : fl->sserif_120;
3335 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
3336 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
3337 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)sserif, strlen(sserif)+1);
3338 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
3341 static void set_value_key(HKEY hkey, const char *name, const char *value)
3344 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
3346 RegDeleteValueA(hkey, name);
3349 static void update_font_info(void)
3351 static const WCHAR logpixels[] = { 'L','o','g','P','i','x','e','l','s',0 };
3352 char buf[40], cpbuf[40];
3355 UINT i, ansi_cp = 0, oem_cp = 0;
3356 DWORD screen_dpi = 96, font_dpi = 0;
3359 if (RegOpenKeyA(HKEY_LOCAL_MACHINE,
3360 "System\\CurrentControlSet\\Hardware Profiles\\Current\\Software\\Fonts",
3361 &hkey) == ERROR_SUCCESS)
3363 reg_load_dword(hkey, logpixels, &screen_dpi);
3367 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
3370 reg_load_dword(hkey, logpixels, &font_dpi);
3372 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3373 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
3374 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3375 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
3376 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
3378 /* Setup Default_Fallback usage for DBCS ANSI codepages */
3379 if (is_dbcs_ansi_cp(ansi_cp))
3380 use_default_fallback = TRUE;
3383 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
3385 if (!strcmp( buf, cpbuf ) && screen_dpi == font_dpi) /* already set correctly */
3390 TRACE("updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
3391 buf, font_dpi, ansi_cp, oem_cp, screen_dpi);
3393 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
3394 ansi_cp, oem_cp, screen_dpi);
3396 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
3397 RegSetValueExW(hkey, logpixels, 0, REG_DWORD, (const BYTE *)&screen_dpi, sizeof(screen_dpi));
3400 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
3404 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
3405 nls_update_font_list[i].oem_cp == oem_cp)
3407 hkey = create_config_fonts_registry_key();
3408 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
3409 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
3410 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
3413 hkey = create_fonts_NT_registry_key();
3414 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3417 hkey = create_fonts_9x_registry_key();
3418 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3421 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3423 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
3424 strlen(nls_update_font_list[i].shelldlg)+1);
3425 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
3426 strlen(nls_update_font_list[i].tmsrmn)+1);
3428 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
3429 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
3430 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
3431 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
3432 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
3433 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
3434 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
3435 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
3437 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
3438 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
3439 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
3447 /* Delete the FontSubstitutes from other locales */
3448 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3450 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
3451 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
3452 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
3458 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
3461 static BOOL init_freetype(void)
3463 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
3466 "Wine cannot find the FreeType font library. To enable Wine to\n"
3467 "use TrueType fonts please install a version of FreeType greater than\n"
3468 "or equal to 2.0.5.\n"
3469 "http://www.freetype.org\n");
3473 #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;}
3475 LOAD_FUNCPTR(FT_Done_Face)
3476 LOAD_FUNCPTR(FT_Get_Char_Index)
3477 LOAD_FUNCPTR(FT_Get_First_Char)
3478 LOAD_FUNCPTR(FT_Get_Module)
3479 LOAD_FUNCPTR(FT_Get_Next_Char)
3480 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
3481 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
3482 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
3483 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
3484 LOAD_FUNCPTR(FT_Init_FreeType)
3485 LOAD_FUNCPTR(FT_Library_Version)
3486 LOAD_FUNCPTR(FT_Load_Glyph)
3487 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
3488 LOAD_FUNCPTR(FT_Matrix_Multiply)
3489 #ifndef FT_MULFIX_INLINED
3490 LOAD_FUNCPTR(FT_MulFix)
3492 LOAD_FUNCPTR(FT_New_Face)
3493 LOAD_FUNCPTR(FT_New_Memory_Face)
3494 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
3495 LOAD_FUNCPTR(FT_Outline_Transform)
3496 LOAD_FUNCPTR(FT_Outline_Translate)
3497 LOAD_FUNCPTR(FT_Render_Glyph)
3498 LOAD_FUNCPTR(FT_Select_Charmap)
3499 LOAD_FUNCPTR(FT_Set_Charmap)
3500 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
3501 LOAD_FUNCPTR(FT_Vector_Transform)
3502 LOAD_FUNCPTR(FT_Vector_Unit)
3504 /* Don't warn if these ones are missing */
3505 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
3506 #ifdef HAVE_FREETYPE_FTLCDFIL_H
3507 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
3510 if(pFT_Init_FreeType(&library) != 0) {
3511 ERR("Can't init FreeType library\n");
3512 wine_dlclose(ft_handle, NULL, 0);
3516 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
3518 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
3519 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
3520 ((FT_Version.minor << 8) & 0x00ff00) |
3521 ((FT_Version.patch ) & 0x0000ff);
3523 font_driver = &freetype_funcs;
3528 "Wine cannot find certain functions that it needs inside the FreeType\n"
3529 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3530 "FreeType to at least version 2.1.4.\n"
3531 "http://www.freetype.org\n");
3532 wine_dlclose(ft_handle, NULL, 0);
3537 static void init_font_list(void)
3539 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
3540 static const WCHAR pathW[] = {'P','a','t','h',0};
3542 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
3543 WCHAR windowsdir[MAX_PATH];
3545 const char *data_dir;
3547 delete_external_font_keys();
3549 /* load the system bitmap fonts */
3550 load_system_fonts();
3552 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3553 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3554 strcatW(windowsdir, fontsW);
3555 if((unixname = wine_get_unix_file_name(windowsdir)))
3557 ReadFontDir(unixname, FALSE);
3558 HeapFree(GetProcessHeap(), 0, unixname);
3561 /* load the system truetype fonts */
3562 data_dir = wine_get_data_dir();
3563 if (!data_dir) data_dir = wine_get_build_dir();
3564 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
3566 strcpy(unixname, data_dir);
3567 strcat(unixname, "/fonts/");
3568 ReadFontDir(unixname, TRUE);
3569 HeapFree(GetProcessHeap(), 0, unixname);
3572 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3573 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3574 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3576 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
3577 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
3578 &hkey) == ERROR_SUCCESS)
3580 LPWSTR data, valueW;
3581 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3582 &valuelen, &datalen, NULL, NULL);
3584 valuelen++; /* returned value doesn't include room for '\0' */
3585 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3586 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3589 dlen = datalen * sizeof(WCHAR);
3591 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
3592 &dlen) == ERROR_SUCCESS)
3594 if(data[0] && (data[1] == ':'))
3596 if((unixname = wine_get_unix_file_name(data)))
3598 AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3599 HeapFree(GetProcessHeap(), 0, unixname);
3602 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
3604 WCHAR pathW[MAX_PATH];
3605 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3608 sprintfW(pathW, fmtW, windowsdir, data);
3609 if((unixname = wine_get_unix_file_name(pathW)))
3611 added = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3612 HeapFree(GetProcessHeap(), 0, unixname);
3615 load_font_from_data_dir(data);
3617 /* reset dlen and vlen */
3622 HeapFree(GetProcessHeap(), 0, data);
3623 HeapFree(GetProcessHeap(), 0, valueW);
3627 #ifdef SONAME_LIBFONTCONFIG
3628 load_fontconfig_fonts();
3629 #elif defined(HAVE_CARBON_CARBON_H)
3633 /* then look in any directories that we've specified in the config file */
3634 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3635 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
3641 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
3643 len += sizeof(WCHAR);
3644 valueW = HeapAlloc( GetProcessHeap(), 0, len );
3645 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
3647 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
3648 valueA = HeapAlloc( GetProcessHeap(), 0, len );
3649 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
3650 TRACE( "got font path %s\n", debugstr_a(valueA) );
3655 LPSTR next = strchr( ptr, ':' );
3656 if (next) *next++ = 0;
3657 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
3658 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
3660 strcpy( unixname, home );
3661 strcat( unixname, ptr + 1 );
3662 ReadFontDir( unixname, TRUE );
3663 HeapFree( GetProcessHeap(), 0, unixname );
3666 ReadFontDir( ptr, TRUE );
3669 HeapFree( GetProcessHeap(), 0, valueA );
3671 HeapFree( GetProcessHeap(), 0, valueW );
3677 static BOOL move_to_front(const WCHAR *name)
3679 Family *family, *cursor2;
3680 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
3682 if(!strcmpiW(family->FamilyName, name))
3684 list_remove(&family->entry);
3685 list_add_head(&font_list, &family->entry);
3692 static BOOL set_default(const WCHAR **name_list)
3696 if (move_to_front(*name_list)) return TRUE;
3703 static void reorder_font_list(void)
3705 set_default( default_serif_list );
3706 set_default( default_fixed_list );
3707 set_default( default_sans_list );
3710 /*************************************************************
3713 * Initialize FreeType library and create a list of available faces
3715 BOOL WineEngInit(void)
3717 HKEY hkey_font_cache;
3721 /* update locale dependent font info in registry */
3724 if(!init_freetype()) return FALSE;
3726 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
3728 ERR("Failed to create font mutex\n");
3731 WaitForSingleObject(font_mutex, INFINITE);
3733 create_font_cache_key(&hkey_font_cache, &disposition);
3735 if(disposition == REG_CREATED_NEW_KEY)
3738 load_font_list_from_cache(hkey_font_cache);
3740 RegCloseKey(hkey_font_cache);
3742 reorder_font_list();
3749 if(disposition == REG_CREATED_NEW_KEY)
3750 update_reg_entries();
3752 init_system_links();
3754 ReleaseMutex(font_mutex);
3759 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
3762 TT_HoriHeader *pHori;
3766 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3767 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3769 if(height == 0) height = 16;
3771 /* Calc. height of EM square:
3773 * For +ve lfHeight we have
3774 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3775 * Re-arranging gives:
3776 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3778 * For -ve lfHeight we have
3780 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3781 * with il = winAscent + winDescent - units_per_em]
3786 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
3787 ppem = MulDiv(ft_face->units_per_EM, height,
3788 pHori->Ascender - pHori->Descender);
3790 ppem = MulDiv(ft_face->units_per_EM, height,
3791 pOS2->usWinAscent + pOS2->usWinDescent);
3799 static struct font_mapping *map_font_file( const char *name )
3801 struct font_mapping *mapping;
3805 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
3806 if (fstat( fd, &st ) == -1) goto error;
3808 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
3810 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
3812 mapping->refcount++;
3817 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
3820 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
3823 if (mapping->data == MAP_FAILED)
3825 HeapFree( GetProcessHeap(), 0, mapping );
3828 mapping->refcount = 1;
3829 mapping->dev = st.st_dev;
3830 mapping->ino = st.st_ino;
3831 mapping->size = st.st_size;
3832 list_add_tail( &mappings_list, &mapping->entry );
3840 static void unmap_font_file( struct font_mapping *mapping )
3842 if (!--mapping->refcount)
3844 list_remove( &mapping->entry );
3845 munmap( mapping->data, mapping->size );
3846 HeapFree( GetProcessHeap(), 0, mapping );
3850 static LONG load_VDMX(GdiFont*, LONG);
3852 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
3859 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
3863 if (!(font->mapping = map_font_file( face->file )))
3865 WARN("failed to map %s\n", debugstr_a(face->file));
3868 data_ptr = font->mapping->data;
3869 data_size = font->mapping->size;
3873 data_ptr = face->font_data_ptr;
3874 data_size = face->font_data_size;
3877 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3879 ERR("FT_New_Face rets %d\n", err);
3883 /* set it here, as load_VDMX needs it */
3884 font->ft_face = ft_face;
3886 if(FT_IS_SCALABLE(ft_face)) {
3887 /* load the VDMX table if we have one */
3888 font->ppem = load_VDMX(font, height);
3890 font->ppem = calc_ppem_for_height(ft_face, height);
3891 TRACE("height %d => ppem %d\n", height, font->ppem);
3893 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3894 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3896 font->ppem = height;
3897 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3898 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3904 static int get_nearest_charset(const WCHAR *family_name, Face *face, int *cp)
3906 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3907 a single face with the requested charset. The idea is to check if
3908 the selected font supports the current ANSI codepage, if it does
3909 return the corresponding charset, else return the first charset */
3912 int acp = GetACP(), i;
3916 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3918 const SYSTEM_LINKS *font_link;
3920 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
3921 return csi.ciCharset;
3923 font_link = find_font_link(family_name);
3924 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
3925 return csi.ciCharset;
3928 for(i = 0; i < 32; i++) {
3930 if(face->fs.fsCsb[0] & fs0) {
3931 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
3933 return csi.ciCharset;
3936 FIXME("TCI failing on %x\n", fs0);
3940 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3941 face->fs.fsCsb[0], face->file);
3943 return DEFAULT_CHARSET;
3946 static GdiFont *alloc_font(void)
3948 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
3950 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
3951 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3953 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3954 ret->total_kern_pairs = (DWORD)-1;
3955 ret->kern_pairs = NULL;
3956 list_init(&ret->hfontlist);
3957 list_init(&ret->child_fonts);
3961 static void free_font(GdiFont *font)
3963 struct list *cursor, *cursor2;
3966 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
3968 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
3969 list_remove(cursor);
3971 free_font(child->font);
3972 HeapFree(GetProcessHeap(), 0, child);
3975 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->hfontlist)
3977 HFONTLIST *hfontlist = LIST_ENTRY(cursor, HFONTLIST, entry);
3978 DeleteObject(hfontlist->hfont);
3979 list_remove(&hfontlist->entry);
3980 HeapFree(GetProcessHeap(), 0, hfontlist);
3983 if (font->ft_face) pFT_Done_Face(font->ft_face);
3984 if (font->mapping) unmap_font_file( font->mapping );
3985 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
3986 HeapFree(GetProcessHeap(), 0, font->potm);
3987 HeapFree(GetProcessHeap(), 0, font->name);
3988 for (i = 0; i < font->gmsize; i++)
3989 HeapFree(GetProcessHeap(),0,font->gm[i]);
3990 HeapFree(GetProcessHeap(), 0, font->gm);
3991 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
3992 HeapFree(GetProcessHeap(), 0, font);
3996 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
3998 FT_Face ft_face = font->ft_face;
4002 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
4009 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
4011 /* make sure value of len is the value freetype says it needs */
4014 FT_ULong needed = 0;
4015 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
4016 if( !err && needed < len) len = needed;
4018 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
4021 TRACE("Can't find table %c%c%c%c\n",
4022 /* bytes were reversed */
4023 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
4024 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
4030 /*************************************************************
4033 * load the vdmx entry for the specified height
4036 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
4037 ( ( (FT_ULong)_x4 << 24 ) | \
4038 ( (FT_ULong)_x3 << 16 ) | \
4039 ( (FT_ULong)_x2 << 8 ) | \
4042 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
4057 static LONG load_VDMX(GdiFont *font, LONG height)
4061 BYTE devXRatio, devYRatio;
4062 USHORT numRecs, numRatios;
4063 DWORD result, offset = -1;
4067 result = get_font_data(font, MS_VDMX_TAG, 0, hdr, 6);
4069 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
4072 /* FIXME: need the real device aspect ratio */
4076 numRecs = GET_BE_WORD(hdr[1]);
4077 numRatios = GET_BE_WORD(hdr[2]);
4079 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
4080 for(i = 0; i < numRatios; i++) {
4083 offset = (3 * 2) + (i * sizeof(Ratios));
4084 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
4087 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
4089 if((ratio.xRatio == 0 &&
4090 ratio.yStartRatio == 0 &&
4091 ratio.yEndRatio == 0) ||
4092 (devXRatio == ratio.xRatio &&
4093 devYRatio >= ratio.yStartRatio &&
4094 devYRatio <= ratio.yEndRatio))
4096 offset = (3 * 2) + (numRatios * 4) + (i * 2);
4097 get_font_data(font, MS_VDMX_TAG, offset, &tmp, 2);
4098 offset = GET_BE_WORD(tmp);
4104 FIXME("No suitable ratio found\n");
4108 if(get_font_data(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
4110 BYTE startsz, endsz;
4113 recs = GET_BE_WORD(group.recs);
4114 startsz = group.startsz;
4115 endsz = group.endsz;
4117 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
4119 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
4120 result = get_font_data(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
4121 if(result == GDI_ERROR) {
4122 FIXME("Failed to retrieve vTable\n");
4127 for(i = 0; i < recs; i++) {
4128 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4129 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4130 ppem = GET_BE_WORD(vTable[i * 3]);
4132 if(yMax + -yMin == height) {
4135 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4138 if(yMax + -yMin > height) {
4141 goto end; /* failed */
4143 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4144 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4145 ppem = GET_BE_WORD(vTable[i * 3]);
4146 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4152 TRACE("ppem not found for height %d\n", height);
4156 HeapFree(GetProcessHeap(), 0, vTable);
4162 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
4164 if(font->font_desc.hash != fd->hash) return TRUE;
4165 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
4166 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
4167 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
4168 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
4171 static void calc_hash(FONT_DESC *pfd)
4173 DWORD hash = 0, *ptr, two_chars;
4177 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
4179 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
4181 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
4183 pwc = (WCHAR *)&two_chars;
4185 *pwc = toupperW(*pwc);
4187 *pwc = toupperW(*pwc);
4191 hash ^= !pfd->can_use_bitmap;
4196 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
4201 struct list *font_elem_ptr, *hfontlist_elem_ptr;
4205 fd.can_use_bitmap = can_use_bitmap;
4208 /* try the child list */
4209 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
4210 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4211 if(!fontcmp(ret, &fd)) {
4212 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4213 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
4214 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4215 if(hflist->hfont == hfont)
4221 /* try the in-use list */
4222 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
4223 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4224 if(!fontcmp(ret, &fd)) {
4225 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4226 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
4227 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4228 if(hflist->hfont == hfont)
4231 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
4232 hflist->hfont = hfont;
4233 list_add_head(&ret->hfontlist, &hflist->entry);
4238 /* then the unused list */
4239 font_elem_ptr = list_head(&unused_gdi_font_list);
4240 while(font_elem_ptr) {
4241 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4242 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4243 if(!fontcmp(ret, &fd)) {
4244 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4245 assert(list_empty(&ret->hfontlist));
4246 TRACE("Found %p in unused list\n", ret);
4247 list_remove(&ret->entry);
4248 list_add_head(&gdi_font_list, &ret->entry);
4249 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
4250 hflist->hfont = hfont;
4251 list_add_head(&ret->hfontlist, &hflist->entry);
4258 static void add_to_cache(GdiFont *font)
4260 static DWORD cache_num = 1;
4262 font->cache_num = cache_num++;
4263 list_add_head(&gdi_font_list, &font->entry);
4266 /*************************************************************
4267 * create_child_font_list
4269 static BOOL create_child_font_list(GdiFont *font)
4272 SYSTEM_LINKS *font_link;
4273 CHILD_FONT *font_link_entry, *new_child;
4277 psub = get_font_subst(&font_subst_list, font->name, -1);
4278 font_name = psub ? psub->to.name : font->name;
4279 font_link = find_font_link(font_name);
4280 if (font_link != NULL)
4282 TRACE("found entry in system list\n");
4283 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4285 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4286 new_child->face = font_link_entry->face;
4287 new_child->font = NULL;
4288 list_add_tail(&font->child_fonts, &new_child->entry);
4289 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
4294 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
4295 * Sans Serif. This is how asian windows get default fallbacks for fonts
4297 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
4298 font->charset != OEM_CHARSET &&
4299 strcmpiW(font_name,szDefaultFallbackLink) != 0)
4301 font_link = find_font_link(szDefaultFallbackLink);
4302 if (font_link != NULL)
4304 TRACE("found entry in default fallback list\n");
4305 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4307 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4308 new_child->face = font_link_entry->face;
4309 new_child->font = NULL;
4310 list_add_tail(&font->child_fonts, &new_child->entry);
4311 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
4320 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
4322 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
4324 if (pFT_Set_Charmap)
4327 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
4329 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
4331 for (i = 0; i < ft_face->num_charmaps; i++)
4333 if (ft_face->charmaps[i]->encoding == encoding)
4335 TRACE("found cmap with platform_id %u, encoding_id %u\n",
4336 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
4338 switch (ft_face->charmaps[i]->platform_id)
4341 cmap_def = ft_face->charmaps[i];
4343 case 0: /* Apple Unicode */
4344 cmap0 = ft_face->charmaps[i];
4346 case 1: /* Macintosh */
4347 cmap1 = ft_face->charmaps[i];
4350 cmap2 = ft_face->charmaps[i];
4352 case 3: /* Microsoft */
4353 cmap3 = ft_face->charmaps[i];
4358 if (cmap3) /* prefer Microsoft cmap table */
4359 ft_err = pFT_Set_Charmap(ft_face, cmap3);
4361 ft_err = pFT_Set_Charmap(ft_face, cmap1);
4363 ft_err = pFT_Set_Charmap(ft_face, cmap2);
4365 ft_err = pFT_Set_Charmap(ft_face, cmap0);
4367 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
4369 return ft_err == FT_Err_Ok;
4372 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
4376 /*************************************************************
4379 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
4380 LPCWSTR output, const DEVMODEW *devmode )
4382 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
4384 if (!physdev) return FALSE;
4385 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
4390 /*************************************************************
4393 static BOOL freetype_DeleteDC( PHYSDEV dev )
4395 struct freetype_physdev *physdev = get_freetype_dev( dev );
4396 HeapFree( GetProcessHeap(), 0, physdev );
4401 /*************************************************************
4402 * freetype_SelectFont
4404 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont )
4406 struct freetype_physdev *physdev = get_freetype_dev( dev );
4408 Face *face, *best, *best_bitmap;
4409 Family *family, *last_resort_family;
4410 const struct list *family_elem_ptr, *face_list, *face_elem_ptr;
4411 INT height, width = 0;
4412 unsigned int score = 0, new_score;
4413 signed int diff = 0, newdiff;
4414 BOOL bd, it, can_use_bitmap, want_vertical;
4419 FontSubst *psub = NULL;
4420 DC *dc = get_dc_ptr( dev->hdc );
4421 const SYSTEM_LINKS *font_link;
4423 if (!hfont) /* notification that the font has been changed by another driver */
4426 physdev->font = NULL;
4427 release_dc_ptr( dc );
4431 GetObjectW( hfont, sizeof(lf), &lf );
4432 lf.lfWidth = abs(lf.lfWidth);
4434 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
4436 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
4437 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
4438 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
4441 if(dc->GraphicsMode == GM_ADVANCED)
4443 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
4444 /* Try to avoid not necessary glyph transformations */
4445 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
4447 lf.lfHeight *= fabs(dcmat.eM11);
4448 lf.lfWidth *= fabs(dcmat.eM11);
4449 dcmat.eM11 = dcmat.eM22 = 1.0;
4454 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
4455 font scaling abilities. */
4456 dcmat.eM11 = dcmat.eM22 = 1.0;
4457 dcmat.eM21 = dcmat.eM12 = 0;
4458 if (dc->vport2WorldValid)
4460 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
4461 lf.lfOrientation = -lf.lfOrientation;
4462 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
4463 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
4467 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
4468 dcmat.eM21, dcmat.eM22);
4471 EnterCriticalSection( &freetype_cs );
4473 /* check the cache first */
4474 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4475 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
4479 if(list_empty(&font_list)) /* No fonts installed */
4481 TRACE("No fonts installed\n");
4485 TRACE("not in cache\n");
4488 ret->font_desc.matrix = dcmat;
4489 ret->font_desc.lf = lf;
4490 ret->font_desc.can_use_bitmap = can_use_bitmap;
4491 calc_hash(&ret->font_desc);
4492 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
4493 hflist->hfont = hfont;
4494 list_add_head(&ret->hfontlist, &hflist->entry);
4496 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4497 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4498 original value lfCharSet. Note this is a special case for
4499 Symbol and doesn't happen at least for "Wingdings*" */
4501 if(!strcmpiW(lf.lfFaceName, SymbolW))
4502 lf.lfCharSet = SYMBOL_CHARSET;
4504 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
4505 switch(lf.lfCharSet) {
4506 case DEFAULT_CHARSET:
4507 csi.fs.fsCsb[0] = 0;
4510 FIXME("Untranslated charset %d\n", lf.lfCharSet);
4511 csi.fs.fsCsb[0] = 0;
4517 if(lf.lfFaceName[0] != '\0') {
4518 CHILD_FONT *font_link_entry;
4519 LPWSTR FaceName = lf.lfFaceName;
4521 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
4524 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
4525 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
4526 if (psub->to.charset != -1)
4527 lf.lfCharSet = psub->to.charset;
4530 /* We want a match on name and charset or just name if
4531 charset was DEFAULT_CHARSET. If the latter then
4532 we fixup the returned charset later in get_nearest_charset
4533 where we'll either use the charset of the current ansi codepage
4534 or if that's unavailable the first charset that the font supports.
4536 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4537 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4538 if (!strcmpiW(family->FamilyName, FaceName) ||
4539 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
4541 font_link = find_font_link(family->FamilyName);
4542 face_list = get_face_list_from_family(family);
4543 LIST_FOR_EACH(face_elem_ptr, face_list) {
4544 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4545 if (!(face->scalable || can_use_bitmap))
4547 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4549 if (font_link != NULL &&
4550 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4552 if (!csi.fs.fsCsb[0])
4558 /* Search by full face name. */
4559 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4560 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4561 face_list = get_face_list_from_family(family);
4562 LIST_FOR_EACH(face_elem_ptr, face_list) {
4563 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4564 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
4565 (face->scalable || can_use_bitmap))
4567 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4569 font_link = find_font_link(family->FamilyName);
4570 if (font_link != NULL &&
4571 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4578 * Try check the SystemLink list first for a replacement font.
4579 * We may find good replacements there.
4581 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
4583 if(!strcmpiW(font_link->font_name, FaceName) ||
4584 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
4586 TRACE("found entry in system list\n");
4587 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4589 const SYSTEM_LINKS *links;
4591 face = font_link_entry->face;
4592 if (!(face->scalable || can_use_bitmap))
4594 family = face->family;
4595 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4597 links = find_font_link(family->FamilyName);
4598 if (links != NULL && csi.fs.fsCsb[0] & links->fs.fsCsb[0])
4605 psub = NULL; /* substitution is no more relevant */
4607 /* If requested charset was DEFAULT_CHARSET then try using charset
4608 corresponding to the current ansi codepage */
4609 if (!csi.fs.fsCsb[0])
4612 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
4613 FIXME("TCI failed on codepage %d\n", acp);
4614 csi.fs.fsCsb[0] = 0;
4616 lf.lfCharSet = csi.ciCharset;
4619 want_vertical = (lf.lfFaceName[0] == '@');
4621 /* Face families are in the top 4 bits of lfPitchAndFamily,
4622 so mask with 0xF0 before testing */
4624 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
4625 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
4626 strcpyW(lf.lfFaceName, defFixed);
4627 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
4628 strcpyW(lf.lfFaceName, defSerif);
4629 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
4630 strcpyW(lf.lfFaceName, defSans);
4632 strcpyW(lf.lfFaceName, defSans);
4633 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4634 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4635 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
4636 font_link = find_font_link(family->FamilyName);
4637 face_list = get_face_list_from_family(family);
4638 LIST_FOR_EACH(face_elem_ptr, face_list) {
4639 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4640 if (!(face->scalable || can_use_bitmap))
4642 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4644 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4650 last_resort_family = NULL;
4651 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4652 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4653 font_link = find_font_link(family->FamilyName);
4654 face_list = get_face_list_from_family(family);
4655 LIST_FOR_EACH(face_elem_ptr, face_list) {
4656 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4657 if(face->vertical == want_vertical &&
4658 (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4659 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]))) {
4662 if(can_use_bitmap && !last_resort_family)
4663 last_resort_family = family;
4668 if(last_resort_family) {
4669 family = last_resort_family;
4670 csi.fs.fsCsb[0] = 0;
4674 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4675 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4676 face_list = get_face_list_from_family(family);
4677 LIST_FOR_EACH(face_elem_ptr, face_list) {
4678 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4679 if(face->scalable && face->vertical == want_vertical) {
4680 csi.fs.fsCsb[0] = 0;
4681 WARN("just using first face for now\n");
4684 if(can_use_bitmap && !last_resort_family)
4685 last_resort_family = family;
4688 if(!last_resort_family) {
4689 FIXME("can't find a single appropriate font - bailing\n");
4695 WARN("could only find a bitmap font - this will probably look awful!\n");
4696 family = last_resort_family;
4697 csi.fs.fsCsb[0] = 0;
4700 it = lf.lfItalic ? 1 : 0;
4701 bd = lf.lfWeight > 550 ? 1 : 0;
4703 height = lf.lfHeight;
4705 face = best = best_bitmap = NULL;
4706 font_link = find_font_link(family->FamilyName);
4707 face_list = get_face_list_from_family(family);
4708 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
4710 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4711 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]) ||
4716 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
4717 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
4718 new_score = (italic ^ it) + (bold ^ bd);
4719 if(!best || new_score <= score)
4721 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4722 italic, bold, it, bd);
4725 if(best->scalable && score == 0) break;
4729 newdiff = height - (signed int)(best->size.height);
4731 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
4732 if(!best_bitmap || new_score < score ||
4733 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
4735 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
4738 if(score == 0 && diff == 0) break;
4745 face = best->scalable ? best : best_bitmap;
4746 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
4747 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
4750 height = lf.lfHeight;
4754 if(csi.fs.fsCsb[0]) {
4755 ret->charset = lf.lfCharSet;
4756 ret->codepage = csi.ciACP;
4759 ret->charset = get_nearest_charset(family->FamilyName, face, &ret->codepage);
4761 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
4762 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
4764 ret->aveWidth = height ? lf.lfWidth : 0;
4766 if(!face->scalable) {
4767 /* Windows uses integer scaling factors for bitmap fonts */
4768 INT scale, scaled_height;
4769 GdiFont *cachedfont;
4771 /* FIXME: rotation of bitmap fonts is ignored */
4772 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
4774 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
4775 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4776 dcmat.eM11 = dcmat.eM22 = 1.0;
4777 /* As we changed the matrix, we need to search the cache for the font again,
4778 * otherwise we might explode the cache. */
4779 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4780 TRACE("Found cached font after non-scalable matrix rescale!\n");
4785 calc_hash(&ret->font_desc);
4787 if (height != 0) height = diff;
4788 height += face->size.height;
4790 scale = (height + face->size.height - 1) / face->size.height;
4791 scaled_height = scale * face->size.height;
4792 /* Only jump to the next height if the difference <= 25% original height */
4793 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
4794 /* The jump between unscaled and doubled is delayed by 1 */
4795 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
4796 ret->scale_y = scale;
4798 width = face->size.x_ppem >> 6;
4799 height = face->size.y_ppem >> 6;
4803 TRACE("font scale y: %f\n", ret->scale_y);
4805 ret->ft_face = OpenFontFace(ret, face, width, height);
4814 ret->ntmFlags = face->ntmFlags;
4816 if (ret->charset == SYMBOL_CHARSET &&
4817 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
4820 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
4824 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
4827 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
4828 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
4829 ret->underline = lf.lfUnderline ? 0xff : 0;
4830 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
4831 create_child_font_list(ret);
4833 if (face->vertical) /* We need to try to load the GSUB table */
4835 int length = get_font_data(ret, GSUB_TAG , 0, NULL, 0);
4836 if (length != GDI_ERROR)
4838 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
4839 get_font_data(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
4840 TRACE("Loaded GSUB table of %i bytes\n",length);
4844 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
4851 physdev->font = ret;
4853 LeaveCriticalSection( &freetype_cs );
4854 release_dc_ptr( dc );
4855 return ret ? hfont : 0;
4858 static void dump_gdi_font_list(void)
4861 struct list *elem_ptr;
4863 TRACE("---------- gdiFont Cache ----------\n");
4864 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
4865 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4866 TRACE("gdiFont=%p %s %d\n",
4867 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4870 TRACE("---------- Unused gdiFont Cache ----------\n");
4871 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
4872 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4873 TRACE("gdiFont=%p %s %d\n",
4874 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4877 TRACE("---------- Child gdiFont Cache ----------\n");
4878 LIST_FOR_EACH(elem_ptr, &child_font_list) {
4879 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4880 TRACE("gdiFont=%p %s %d\n",
4881 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4885 /*************************************************************
4886 * WineEngDestroyFontInstance
4888 * free the gdiFont associated with this handle
4891 BOOL WineEngDestroyFontInstance(HFONT handle)
4896 struct list *font_elem_ptr, *hfontlist_elem_ptr;
4900 EnterCriticalSection( &freetype_cs );
4902 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
4904 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4905 while(hfontlist_elem_ptr) {
4906 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4907 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4908 if(hflist->hfont == handle) {
4909 TRACE("removing child font %p from child list\n", gdiFont);
4910 list_remove(&gdiFont->entry);
4911 LeaveCriticalSection( &freetype_cs );
4917 TRACE("destroying hfont=%p\n", handle);
4919 dump_gdi_font_list();
4921 font_elem_ptr = list_head(&gdi_font_list);
4922 while(font_elem_ptr) {
4923 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4924 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
4926 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4927 while(hfontlist_elem_ptr) {
4928 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4929 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4930 if(hflist->hfont == handle) {
4931 list_remove(&hflist->entry);
4932 HeapFree(GetProcessHeap(), 0, hflist);
4936 if(list_empty(&gdiFont->hfontlist)) {
4937 TRACE("Moving to Unused list\n");
4938 list_remove(&gdiFont->entry);
4939 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
4944 font_elem_ptr = list_head(&unused_gdi_font_list);
4945 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
4946 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4947 while(font_elem_ptr) {
4948 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4949 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4950 TRACE("freeing %p\n", gdiFont);
4951 list_remove(&gdiFont->entry);
4954 LeaveCriticalSection( &freetype_cs );
4958 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
4965 id += IDS_FIRST_SCRIPT;
4966 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
4967 if (!rsrc) return 0;
4968 hMem = LoadResource( gdi32_module, rsrc );
4969 if (!hMem) return 0;
4971 p = LockResource( hMem );
4973 while (id--) p += *p + 1;
4975 i = min(LF_FACESIZE - 1, *p);
4976 memcpy(buffer, p + 1, i * sizeof(WCHAR));
4982 /***************************************************
4983 * create_enum_charset_list
4985 * This function creates charset enumeration list because in DEFAULT_CHARSET
4986 * case, the ANSI codepage's charset takes precedence over other charsets.
4987 * This function works as a filter other than DEFAULT_CHARSET case.
4989 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
4994 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
4995 csi.fs.fsCsb[0] != 0) {
4996 list->element[n].mask = csi.fs.fsCsb[0];
4997 list->element[n].charset = csi.ciCharset;
4998 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5001 else { /* charset is DEFAULT_CHARSET or invalid. */
5004 /* Set the current codepage's charset as the first element. */
5006 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
5007 csi.fs.fsCsb[0] != 0) {
5008 list->element[n].mask = csi.fs.fsCsb[0];
5009 list->element[n].charset = csi.ciCharset;
5010 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5014 /* Fill out left elements. */
5015 for (i = 0; i < 32; i++) {
5017 fs.fsCsb[0] = 1L << i;
5019 if (n > 0 && fs.fsCsb[0] == list->element[0].mask)
5020 continue; /* skip, already added. */
5021 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
5022 continue; /* skip, this is an invalid fsCsb bit. */
5024 list->element[n].mask = fs.fsCsb[0];
5025 list->element[n].charset = csi.ciCharset;
5026 load_script_name( i, list->element[n].name );
5035 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
5036 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
5041 if (face->cached_enum_data)
5044 *pelf = face->cached_enum_data->elf;
5045 *pntm = face->cached_enum_data->ntm;
5046 *ptype = face->cached_enum_data->type;
5050 font = alloc_font();
5052 if(face->scalable) {
5056 height = face->size.y_ppem >> 6;
5057 width = face->size.x_ppem >> 6;
5059 font->scale_y = 1.0;
5061 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
5067 font->name = strdupW(face->family->FamilyName);
5068 font->ntmFlags = face->ntmFlags;
5070 if (get_outline_text_metrics(font))
5072 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
5074 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
5075 pntm->ntmTm.ntmCellHeight = font->ntmCellHeight;
5076 pntm->ntmTm.ntmAvgWidth = font->ntmAvgWidth;
5078 lstrcpynW(pelf->elfLogFont.lfFaceName,
5079 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
5081 lstrcpynW(pelf->elfFullName,
5082 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
5084 lstrcpynW(pelf->elfStyle,
5085 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
5090 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
5092 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
5093 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
5094 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
5096 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
5098 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
5100 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
5101 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
5104 pntm->ntmTm.ntmFlags = face->ntmFlags;
5105 pntm->ntmFontSig = face->fs;
5107 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
5109 pelf->elfLogFont.lfEscapement = 0;
5110 pelf->elfLogFont.lfOrientation = 0;
5111 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
5112 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
5113 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
5114 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
5115 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
5116 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
5117 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
5118 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
5119 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
5120 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
5121 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
5124 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
5125 *ptype |= TRUETYPE_FONTTYPE;
5126 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
5127 *ptype |= DEVICE_FONTTYPE;
5128 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
5129 *ptype |= RASTER_FONTTYPE;
5131 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
5132 if (face->cached_enum_data)
5134 face->cached_enum_data->elf = *pelf;
5135 face->cached_enum_data->ntm = *pntm;
5136 face->cached_enum_data->type = *ptype;
5142 static BOOL family_matches(Family *family, const LOGFONTW *lf)
5144 const struct list *face_list, *face_elem_ptr;
5146 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
5148 face_list = get_face_list_from_family(family);
5149 LIST_FOR_EACH(face_elem_ptr, face_list)
5151 Face *face = LIST_ENTRY(face_elem_ptr, Face, entry);
5153 if (face->FullName && !strcmpiW(lf->lfFaceName, face->FullName)) return TRUE;
5159 static BOOL face_matches(const WCHAR *family_name, Face *face, const LOGFONTW *lf)
5161 if (!strcmpiW(lf->lfFaceName, family_name)) return TRUE;
5163 return (face->FullName && !strcmpiW(lf->lfFaceName, face->FullName));
5166 static BOOL enum_face_charsets(const Family *family, Face *face, struct enum_charset_list *list,
5167 FONTENUMPROCW proc, LPARAM lparam)
5170 NEWTEXTMETRICEXW ntm;
5174 GetEnumStructs(face, &elf, &ntm, &type);
5175 for(i = 0; i < list->total; i++) {
5176 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
5177 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
5178 load_script_name( IDS_OEM_DOS, elf.elfScript );
5179 i = list->total; /* break out of loop after enumeration */
5180 } else if(!(face->fs.fsCsb[0] & list->element[i].mask))
5183 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
5184 strcpyW(elf.elfScript, list->element[i].name);
5185 if (!elf.elfScript[0])
5186 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
5188 /* Font Replacement */
5189 if (family != face->family)
5191 strcpyW(elf.elfLogFont.lfFaceName, family->FamilyName);
5193 strcpyW(elf.elfFullName, face->FullName);
5195 strcpyW(elf.elfFullName, family->FamilyName);
5197 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
5198 debugstr_w(elf.elfLogFont.lfFaceName),
5199 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
5200 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
5201 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
5202 ntm.ntmTm.ntmFlags);
5203 /* release section before callback (FIXME) */
5204 LeaveCriticalSection( &freetype_cs );
5205 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
5206 EnterCriticalSection( &freetype_cs );
5211 /*************************************************************
5212 * freetype_EnumFonts
5214 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
5218 const struct list *family_elem_ptr, *face_list, *face_elem_ptr;
5220 struct enum_charset_list enum_charsets;
5224 lf.lfCharSet = DEFAULT_CHARSET;
5225 lf.lfPitchAndFamily = 0;
5226 lf.lfFaceName[0] = 0;
5230 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
5232 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
5235 EnterCriticalSection( &freetype_cs );
5236 if(plf->lfFaceName[0]) {
5238 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
5241 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
5242 debugstr_w(psub->to.name));
5244 strcpyW(lf.lfFaceName, psub->to.name);
5248 LIST_FOR_EACH(family_elem_ptr, &font_list) {
5249 family = LIST_ENTRY(family_elem_ptr, Family, entry);
5250 if(family_matches(family, plf)) {
5251 face_list = get_face_list_from_family(family);
5252 LIST_FOR_EACH(face_elem_ptr, face_list) {
5253 face = LIST_ENTRY(face_elem_ptr, Face, entry);
5254 if (!face_matches(family->FamilyName, face, plf)) continue;
5255 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
5260 LIST_FOR_EACH(family_elem_ptr, &font_list) {
5261 family = LIST_ENTRY(family_elem_ptr, Family, entry);
5262 face_list = get_face_list_from_family(family);
5263 face_elem_ptr = list_head(face_list);
5264 face = LIST_ENTRY(face_elem_ptr, Face, entry);
5265 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
5268 LeaveCriticalSection( &freetype_cs );
5272 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
5274 pt->x.value = vec->x >> 6;
5275 pt->x.fract = (vec->x & 0x3f) << 10;
5276 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
5277 pt->y.value = vec->y >> 6;
5278 pt->y.fract = (vec->y & 0x3f) << 10;
5279 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
5283 /***************************************************
5284 * According to the MSDN documentation on WideCharToMultiByte,
5285 * certain codepages cannot set the default_used parameter.
5286 * This returns TRUE if the codepage can set that parameter, false else
5287 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
5289 static BOOL codepage_sets_default_used(UINT codepage)
5303 * GSUB Table handling functions
5306 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
5308 const GSUB_CoverageFormat1* cf1;
5312 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
5314 int count = GET_BE_WORD(cf1->GlyphCount);
5316 TRACE("Coverage Format 1, %i glyphs\n",count);
5317 for (i = 0; i < count; i++)
5318 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
5322 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
5324 const GSUB_CoverageFormat2* cf2;
5327 cf2 = (const GSUB_CoverageFormat2*)cf1;
5329 count = GET_BE_WORD(cf2->RangeCount);
5330 TRACE("Coverage Format 2, %i ranges\n",count);
5331 for (i = 0; i < count; i++)
5333 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
5335 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
5336 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
5338 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
5339 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
5345 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
5350 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
5352 const GSUB_ScriptList *script;
5353 const GSUB_Script *deflt = NULL;
5355 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
5357 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
5358 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
5360 const GSUB_Script *scr;
5363 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
5364 scr = (const GSUB_Script*)((const BYTE*)script + offset);
5366 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
5368 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
5374 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
5378 const GSUB_LangSys *Lang;
5380 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
5382 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
5384 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
5385 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5387 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
5390 offset = GET_BE_WORD(script->DefaultLangSys);
5393 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5399 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
5402 const GSUB_FeatureList *feature;
5403 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
5405 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
5406 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
5408 int index = GET_BE_WORD(lang->FeatureIndex[i]);
5409 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
5411 const GSUB_Feature *feat;
5412 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
5419 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
5423 const GSUB_LookupList *lookup;
5424 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
5426 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
5427 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
5429 const GSUB_LookupTable *look;
5430 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
5431 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
5432 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
5433 if (GET_BE_WORD(look->LookupType) != 1)
5434 FIXME("We only handle SubType 1\n");
5439 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
5441 const GSUB_SingleSubstFormat1 *ssf1;
5442 offset = GET_BE_WORD(look->SubTable[j]);
5443 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
5444 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
5446 int offset = GET_BE_WORD(ssf1->Coverage);
5447 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
5448 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
5450 TRACE(" Glyph 0x%x ->",glyph);
5451 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
5452 TRACE(" 0x%x\n",glyph);
5457 const GSUB_SingleSubstFormat2 *ssf2;
5461 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
5462 offset = GET_BE_WORD(ssf1->Coverage);
5463 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
5464 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
5465 TRACE(" Coverage index %i\n",index);
5468 TRACE(" Glyph is 0x%x ->",glyph);
5469 glyph = GET_BE_WORD(ssf2->Substitute[index]);
5470 TRACE("0x%x\n",glyph);
5479 static const char* get_opentype_script(const GdiFont *font)
5482 * I am not sure if this is the correct way to generate our script tag
5485 switch (font->charset)
5487 case ANSI_CHARSET: return "latn";
5488 case BALTIC_CHARSET: return "latn"; /* ?? */
5489 case CHINESEBIG5_CHARSET: return "hani";
5490 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
5491 case GB2312_CHARSET: return "hani";
5492 case GREEK_CHARSET: return "grek";
5493 case HANGUL_CHARSET: return "hang";
5494 case RUSSIAN_CHARSET: return "cyrl";
5495 case SHIFTJIS_CHARSET: return "kana";
5496 case TURKISH_CHARSET: return "latn"; /* ?? */
5497 case VIETNAMESE_CHARSET: return "latn";
5498 case JOHAB_CHARSET: return "latn"; /* ?? */
5499 case ARABIC_CHARSET: return "arab";
5500 case HEBREW_CHARSET: return "hebr";
5501 case THAI_CHARSET: return "thai";
5502 default: return "latn";
5506 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
5508 const GSUB_Header *header;
5509 const GSUB_Script *script;
5510 const GSUB_LangSys *language;
5511 const GSUB_Feature *feature;
5513 if (!font->GSUB_Table)
5516 header = font->GSUB_Table;
5518 script = GSUB_get_script_table(header, get_opentype_script(font));
5521 TRACE("Script not found\n");
5524 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
5527 TRACE("Language not found\n");
5530 feature = GSUB_get_feature(header, language, "vrt2");
5532 feature = GSUB_get_feature(header, language, "vert");
5535 TRACE("vrt2/vert feature not found\n");
5538 return GSUB_apply_feature(header, feature, glyph);
5541 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
5545 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
5546 WCHAR wc = (WCHAR)glyph;
5548 BOOL *default_used_pointer;
5551 default_used_pointer = NULL;
5552 default_used = FALSE;
5553 if (codepage_sets_default_used(font->codepage))
5554 default_used_pointer = &default_used;
5555 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
5558 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
5559 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
5563 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
5565 if (glyph < 0x100) glyph += 0xf000;
5566 /* there is a number of old pre-Unicode "broken" TTFs, which
5567 do have symbols at U+00XX instead of U+f0XX */
5568 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
5569 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
5571 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
5576 /*************************************************************
5577 * freetype_GetGlyphIndices
5579 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
5581 struct freetype_physdev *physdev = get_freetype_dev( dev );
5584 BOOL got_default = FALSE;
5588 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
5589 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
5592 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
5594 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
5599 EnterCriticalSection( &freetype_cs );
5601 for(i = 0; i < count; i++)
5603 pgi[i] = get_glyph_index(physdev->font, lpstr[i]);
5608 if (FT_IS_SFNT(physdev->font->ft_face))
5610 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(physdev->font->ft_face, ft_sfnt_os2);
5611 default_char = (pOS2->usDefaultChar ? get_glyph_index(physdev->font, pOS2->usDefaultChar) : 0);
5616 get_text_metrics(physdev->font, &textm);
5617 default_char = textm.tmDefaultChar;
5621 pgi[i] = default_char;
5624 LeaveCriticalSection( &freetype_cs );
5628 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
5630 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
5631 return !memcmp(matrix, &identity, sizeof(FMAT2));
5634 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
5636 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
5637 return !memcmp(matrix, &identity, sizeof(MAT2));
5640 static inline BYTE get_max_level( UINT format )
5644 case GGO_GRAY2_BITMAP: return 4;
5645 case GGO_GRAY4_BITMAP: return 16;
5646 case GGO_GRAY8_BITMAP: return 64;
5651 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5653 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
5654 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5657 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
5658 FT_Face ft_face = incoming_font->ft_face;
5659 GdiFont *font = incoming_font;
5660 FT_UInt glyph_index;
5661 DWORD width, height, pitch, needed = 0;
5662 FT_Bitmap ft_bitmap;
5664 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
5666 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
5667 double widthRatio = 1.0;
5668 FT_Matrix transMat = identityMat;
5669 FT_Matrix transMatUnrotated;
5670 BOOL needsTransform = FALSE;
5671 BOOL tategaki = (font->GSUB_Table != NULL);
5672 UINT original_index;
5674 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
5675 buflen, buf, lpmat);
5677 TRACE("font transform %f %f %f %f\n",
5678 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
5679 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
5681 if(format & GGO_GLYPH_INDEX) {
5682 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
5683 original_index = glyph;
5684 format &= ~GGO_GLYPH_INDEX;
5686 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
5687 ft_face = font->ft_face;
5688 original_index = glyph_index;
5691 if(format & GGO_UNHINTED) {
5692 load_flags |= FT_LOAD_NO_HINTING;
5693 format &= ~GGO_UNHINTED;
5696 /* tategaki never appears to happen to lower glyph index */
5697 if (glyph_index < TATEGAKI_LOWER_BOUND )
5700 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
5701 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
5702 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
5703 font->gmsize * sizeof(GM*));
5705 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
5706 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
5708 *lpgm = FONT_GM(font,original_index)->gm;
5709 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5710 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5711 lpgm->gmCellIncX, lpgm->gmCellIncY);
5712 return 1; /* FIXME */
5716 if (!font->gm[original_index / GM_BLOCK_SIZE])
5717 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
5719 /* Scaling factor */
5724 get_text_metrics(font, &tm);
5726 widthRatio = (double)font->aveWidth;
5727 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5730 widthRatio = font->scale_y;
5732 /* Scaling transform */
5733 if (widthRatio != 1.0 || font->scale_y != 1.0)
5736 scaleMat.xx = FT_FixedFromFloat(widthRatio);
5739 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
5741 pFT_Matrix_Multiply(&scaleMat, &transMat);
5742 needsTransform = TRUE;
5745 /* Slant transform */
5746 if (font->fake_italic) {
5749 slantMat.xx = (1 << 16);
5750 slantMat.xy = ((1 << 16) >> 2);
5752 slantMat.yy = (1 << 16);
5753 pFT_Matrix_Multiply(&slantMat, &transMat);
5754 needsTransform = TRUE;
5757 /* Rotation transform */
5758 transMatUnrotated = transMat;
5759 if(font->orientation && !tategaki) {
5760 FT_Matrix rotationMat;
5762 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
5763 pFT_Vector_Unit(&vecAngle, angle);
5764 rotationMat.xx = vecAngle.x;
5765 rotationMat.xy = -vecAngle.y;
5766 rotationMat.yx = -rotationMat.xy;
5767 rotationMat.yy = rotationMat.xx;
5769 pFT_Matrix_Multiply(&rotationMat, &transMat);
5770 needsTransform = TRUE;
5773 /* World transform */
5774 if (!is_identity_FMAT2(&font->font_desc.matrix))
5777 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
5778 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
5779 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
5780 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
5781 pFT_Matrix_Multiply(&worldMat, &transMat);
5782 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
5783 needsTransform = TRUE;
5786 /* Extra transformation specified by caller */
5787 if (!is_identity_MAT2(lpmat))
5790 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
5791 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
5792 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
5793 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
5794 pFT_Matrix_Multiply(&extraMat, &transMat);
5795 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
5796 needsTransform = TRUE;
5799 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
5800 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
5801 format == GGO_GRAY8_BITMAP))
5803 load_flags |= FT_LOAD_NO_BITMAP;
5806 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
5809 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
5813 if(!needsTransform) {
5814 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
5815 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
5816 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
5818 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
5819 bottom = (ft_face->glyph->metrics.horiBearingY -
5820 ft_face->glyph->metrics.height) & -64;
5821 lpgm->gmCellIncX = adv;
5822 lpgm->gmCellIncY = 0;
5829 for(xc = 0; xc < 2; xc++) {
5830 for(yc = 0; yc < 2; yc++) {
5831 vec.x = (ft_face->glyph->metrics.horiBearingX +
5832 xc * ft_face->glyph->metrics.width);
5833 vec.y = ft_face->glyph->metrics.horiBearingY -
5834 yc * ft_face->glyph->metrics.height;
5835 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
5836 pFT_Vector_Transform(&vec, &transMat);
5837 if(xc == 0 && yc == 0) {
5838 left = right = vec.x;
5839 top = bottom = vec.y;
5841 if(vec.x < left) left = vec.x;
5842 else if(vec.x > right) right = vec.x;
5843 if(vec.y < bottom) bottom = vec.y;
5844 else if(vec.y > top) top = vec.y;
5849 right = (right + 63) & -64;
5850 bottom = bottom & -64;
5851 top = (top + 63) & -64;
5853 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
5854 vec.x = ft_face->glyph->metrics.horiAdvance;
5856 pFT_Vector_Transform(&vec, &transMat);
5857 lpgm->gmCellIncX = (vec.x+63) >> 6;
5858 lpgm->gmCellIncY = -((vec.y+63) >> 6);
5860 vec.x = ft_face->glyph->metrics.horiAdvance;
5862 pFT_Vector_Transform(&vec, &transMatUnrotated);
5863 adv = (vec.x+63) >> 6;
5867 bbx = (right - left) >> 6;
5868 lpgm->gmBlackBoxX = (right - left) >> 6;
5869 lpgm->gmBlackBoxY = (top - bottom) >> 6;
5870 lpgm->gmptGlyphOrigin.x = left >> 6;
5871 lpgm->gmptGlyphOrigin.y = top >> 6;
5873 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5874 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5875 lpgm->gmCellIncX, lpgm->gmCellIncY);
5877 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
5878 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
5880 FONT_GM(font,original_index)->gm = *lpgm;
5881 FONT_GM(font,original_index)->adv = adv;
5882 FONT_GM(font,original_index)->lsb = lsb;
5883 FONT_GM(font,original_index)->bbx = bbx;
5884 FONT_GM(font,original_index)->init = TRUE;
5887 if(format == GGO_METRICS)
5889 return 1; /* FIXME */
5892 if(ft_face->glyph->format != ft_glyph_format_outline &&
5893 (format == GGO_NATIVE || format == GGO_BEZIER))
5895 TRACE("loaded a bitmap\n");
5901 width = lpgm->gmBlackBoxX;
5902 height = lpgm->gmBlackBoxY;
5903 pitch = ((width + 31) >> 5) << 2;
5904 needed = pitch * height;
5906 if(!buf || !buflen) break;
5908 switch(ft_face->glyph->format) {
5909 case ft_glyph_format_bitmap:
5911 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5912 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
5913 INT h = ft_face->glyph->bitmap.rows;
5915 memcpy(dst, src, w);
5916 src += ft_face->glyph->bitmap.pitch;
5922 case ft_glyph_format_outline:
5923 ft_bitmap.width = width;
5924 ft_bitmap.rows = height;
5925 ft_bitmap.pitch = pitch;
5926 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
5927 ft_bitmap.buffer = buf;
5930 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5932 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5934 /* Note: FreeType will only set 'black' bits for us. */
5935 memset(buf, 0, needed);
5936 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5940 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5945 case GGO_GRAY2_BITMAP:
5946 case GGO_GRAY4_BITMAP:
5947 case GGO_GRAY8_BITMAP:
5948 case WINE_GGO_GRAY16_BITMAP:
5950 unsigned int max_level, row, col;
5953 width = lpgm->gmBlackBoxX;
5954 height = lpgm->gmBlackBoxY;
5955 pitch = (width + 3) / 4 * 4;
5956 needed = pitch * height;
5958 if(!buf || !buflen) break;
5960 max_level = get_max_level( format );
5962 switch(ft_face->glyph->format) {
5963 case ft_glyph_format_bitmap:
5965 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5966 INT h = ft_face->glyph->bitmap.rows;
5968 memset( buf, 0, needed );
5970 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
5971 if (src[x / 8] & masks[x % 8]) dst[x] = max_level;
5972 src += ft_face->glyph->bitmap.pitch;
5977 case ft_glyph_format_outline:
5979 ft_bitmap.width = width;
5980 ft_bitmap.rows = height;
5981 ft_bitmap.pitch = pitch;
5982 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
5983 ft_bitmap.buffer = buf;
5986 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5988 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5990 memset(ft_bitmap.buffer, 0, buflen);
5992 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5994 if (max_level != 255)
5996 for (row = 0, start = buf; row < height; row++)
5998 for (col = 0, ptr = start; col < width; col++, ptr++)
5999 *ptr = (((int)*ptr) * max_level + 128) / 256;
6007 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
6013 case WINE_GGO_HRGB_BITMAP:
6014 case WINE_GGO_HBGR_BITMAP:
6015 case WINE_GGO_VRGB_BITMAP:
6016 case WINE_GGO_VBGR_BITMAP:
6017 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6019 switch (ft_face->glyph->format)
6021 case FT_GLYPH_FORMAT_BITMAP:
6026 width = lpgm->gmBlackBoxX;
6027 height = lpgm->gmBlackBoxY;
6029 needed = pitch * height;
6031 if (!buf || !buflen) break;
6033 memset(buf, 0, buflen);
6035 src = ft_face->glyph->bitmap.buffer;
6036 src_pitch = ft_face->glyph->bitmap.pitch;
6038 height = min( height, ft_face->glyph->bitmap.rows );
6041 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
6043 if ( src[x / 8] & masks[x % 8] )
6044 ((unsigned int *)dst)[x] = ~0u;
6053 case FT_GLYPH_FORMAT_OUTLINE:
6057 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
6058 INT x_shift, y_shift;
6060 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
6061 FT_Render_Mode render_mode =
6062 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
6063 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
6065 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
6067 if ( render_mode == FT_RENDER_MODE_LCD)
6069 lpgm->gmBlackBoxX += 2;
6070 lpgm->gmptGlyphOrigin.x -= 1;
6074 lpgm->gmBlackBoxY += 2;
6075 lpgm->gmptGlyphOrigin.y += 1;
6079 width = lpgm->gmBlackBoxX;
6080 height = lpgm->gmBlackBoxY;
6082 needed = pitch * height;
6084 if (!buf || !buflen) break;
6086 memset(buf, 0, buflen);
6088 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
6090 if ( needsTransform )
6091 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
6093 if ( pFT_Library_SetLcdFilter )
6094 pFT_Library_SetLcdFilter( library, lcdfilter );
6095 pFT_Render_Glyph (ft_face->glyph, render_mode);
6097 src = ft_face->glyph->bitmap.buffer;
6098 src_pitch = ft_face->glyph->bitmap.pitch;
6099 src_width = ft_face->glyph->bitmap.width;
6100 src_height = ft_face->glyph->bitmap.rows;
6102 if ( render_mode == FT_RENDER_MODE_LCD)
6110 rgb_interval = src_pitch;
6115 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
6116 if ( x_shift < 0 ) x_shift = 0;
6117 if ( x_shift + (src_width / hmul) > width )
6118 x_shift = width - (src_width / hmul);
6120 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
6121 if ( y_shift < 0 ) y_shift = 0;
6122 if ( y_shift + (src_height / vmul) > height )
6123 y_shift = height - (src_height / vmul);
6125 dst += x_shift + y_shift * ( pitch / 4 );
6126 while ( src_height )
6128 for ( x = 0; x < src_width / hmul; x++ )
6132 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
6133 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6134 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
6135 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6139 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
6140 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6141 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
6142 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6145 src += src_pitch * vmul;
6154 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
6166 int contour, point = 0, first_pt;
6167 FT_Outline *outline = &ft_face->glyph->outline;
6168 TTPOLYGONHEADER *pph;
6170 DWORD pph_start, cpfx, type;
6172 if(buflen == 0) buf = NULL;
6174 if (needsTransform && buf) {
6175 pFT_Outline_Transform(outline, &transMat);
6178 for(contour = 0; contour < outline->n_contours; contour++) {
6180 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6183 pph->dwType = TT_POLYGON_TYPE;
6184 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6186 needed += sizeof(*pph);
6188 while(point <= outline->contours[contour]) {
6189 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6190 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6191 TT_PRIM_LINE : TT_PRIM_QSPLINE;
6195 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6198 } while(point <= outline->contours[contour] &&
6199 (outline->tags[point] & FT_Curve_Tag_On) ==
6200 (outline->tags[point-1] & FT_Curve_Tag_On));
6201 /* At the end of a contour Windows adds the start point, but
6203 if(point > outline->contours[contour] &&
6204 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
6206 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
6208 } else if(point <= outline->contours[contour] &&
6209 outline->tags[point] & FT_Curve_Tag_On) {
6210 /* add closing pt for bezier */
6212 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6220 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6223 pph->cb = needed - pph_start;
6229 /* Convert the quadratic Beziers to cubic Beziers.
6230 The parametric eqn for a cubic Bezier is, from PLRM:
6231 r(t) = at^3 + bt^2 + ct + r0
6232 with the control points:
6237 A quadratic Bezier has the form:
6238 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6240 So equating powers of t leads to:
6241 r1 = 2/3 p1 + 1/3 p0
6242 r2 = 2/3 p1 + 1/3 p2
6243 and of course r0 = p0, r3 = p2
6246 int contour, point = 0, first_pt;
6247 FT_Outline *outline = &ft_face->glyph->outline;
6248 TTPOLYGONHEADER *pph;
6250 DWORD pph_start, cpfx, type;
6251 FT_Vector cubic_control[4];
6252 if(buflen == 0) buf = NULL;
6254 if (needsTransform && buf) {
6255 pFT_Outline_Transform(outline, &transMat);
6258 for(contour = 0; contour < outline->n_contours; contour++) {
6260 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6263 pph->dwType = TT_POLYGON_TYPE;
6264 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6266 needed += sizeof(*pph);
6268 while(point <= outline->contours[contour]) {
6269 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6270 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6271 TT_PRIM_LINE : TT_PRIM_CSPLINE;
6274 if(type == TT_PRIM_LINE) {
6276 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6280 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6283 /* FIXME: Possible optimization in endpoint calculation
6284 if there are two consecutive curves */
6285 cubic_control[0] = outline->points[point-1];
6286 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
6287 cubic_control[0].x += outline->points[point].x + 1;
6288 cubic_control[0].y += outline->points[point].y + 1;
6289 cubic_control[0].x >>= 1;
6290 cubic_control[0].y >>= 1;
6292 if(point+1 > outline->contours[contour])
6293 cubic_control[3] = outline->points[first_pt];
6295 cubic_control[3] = outline->points[point+1];
6296 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
6297 cubic_control[3].x += outline->points[point].x + 1;
6298 cubic_control[3].y += outline->points[point].y + 1;
6299 cubic_control[3].x >>= 1;
6300 cubic_control[3].y >>= 1;
6303 /* r1 = 1/3 p0 + 2/3 p1
6304 r2 = 1/3 p2 + 2/3 p1 */
6305 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
6306 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
6307 cubic_control[2] = cubic_control[1];
6308 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
6309 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
6310 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
6311 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
6313 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
6314 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
6315 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
6320 } while(point <= outline->contours[contour] &&
6321 (outline->tags[point] & FT_Curve_Tag_On) ==
6322 (outline->tags[point-1] & FT_Curve_Tag_On));
6323 /* At the end of a contour Windows adds the start point,
6324 but only for Beziers and we've already done that.
6326 if(point <= outline->contours[contour] &&
6327 outline->tags[point] & FT_Curve_Tag_On) {
6328 /* This is the closing pt of a bezier, but we've already
6329 added it, so just inc point and carry on */
6336 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6339 pph->cb = needed - pph_start;
6345 FIXME("Unsupported format %d\n", format);
6351 static BOOL get_bitmap_text_metrics(GdiFont *font)
6353 FT_Face ft_face = font->ft_face;
6354 FT_WinFNT_HeaderRec winfnt_header;
6355 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
6356 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
6357 font->potm->otmSize = size;
6359 #define TM font->potm->otmTextMetrics
6360 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
6362 TM.tmHeight = winfnt_header.pixel_height;
6363 TM.tmAscent = winfnt_header.ascent;
6364 TM.tmDescent = TM.tmHeight - TM.tmAscent;
6365 TM.tmInternalLeading = winfnt_header.internal_leading;
6366 TM.tmExternalLeading = winfnt_header.external_leading;
6367 TM.tmAveCharWidth = winfnt_header.avg_width;
6368 TM.tmMaxCharWidth = winfnt_header.max_width;
6369 TM.tmWeight = winfnt_header.weight;
6371 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
6372 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
6373 TM.tmFirstChar = winfnt_header.first_char;
6374 TM.tmLastChar = winfnt_header.last_char;
6375 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
6376 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
6377 TM.tmItalic = winfnt_header.italic;
6378 TM.tmUnderlined = font->underline;
6379 TM.tmStruckOut = font->strikeout;
6380 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
6381 TM.tmCharSet = winfnt_header.charset;
6385 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
6386 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
6387 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6388 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
6389 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
6390 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
6391 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
6392 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
6394 TM.tmDigitizedAspectX = 96; /* FIXME */
6395 TM.tmDigitizedAspectY = 96; /* FIXME */
6397 TM.tmLastChar = 255;
6398 TM.tmDefaultChar = 32;
6399 TM.tmBreakChar = 32;
6400 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
6401 TM.tmUnderlined = font->underline;
6402 TM.tmStruckOut = font->strikeout;
6403 /* NB inverted meaning of TMPF_FIXED_PITCH */
6404 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
6405 TM.tmCharSet = font->charset;
6413 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
6415 double scale_x, scale_y;
6419 scale_x = (double)font->aveWidth;
6420 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6423 scale_x = font->scale_y;
6425 scale_x *= fabs(font->font_desc.matrix.eM11);
6426 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6428 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6429 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6431 SCALE_Y(ptm->tmHeight);
6432 SCALE_Y(ptm->tmAscent);
6433 SCALE_Y(ptm->tmDescent);
6434 SCALE_Y(ptm->tmInternalLeading);
6435 SCALE_Y(ptm->tmExternalLeading);
6436 SCALE_Y(ptm->tmOverhang);
6438 SCALE_X(ptm->tmAveCharWidth);
6439 SCALE_X(ptm->tmMaxCharWidth);
6445 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
6447 double scale_x, scale_y;
6451 scale_x = (double)font->aveWidth;
6452 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6455 scale_x = font->scale_y;
6457 scale_x *= fabs(font->font_desc.matrix.eM11);
6458 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6460 scale_font_metrics(font, &potm->otmTextMetrics);
6462 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6463 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6465 SCALE_Y(potm->otmAscent);
6466 SCALE_Y(potm->otmDescent);
6467 SCALE_Y(potm->otmLineGap);
6468 SCALE_Y(potm->otmsCapEmHeight);
6469 SCALE_Y(potm->otmsXHeight);
6470 SCALE_Y(potm->otmrcFontBox.top);
6471 SCALE_Y(potm->otmrcFontBox.bottom);
6472 SCALE_X(potm->otmrcFontBox.left);
6473 SCALE_X(potm->otmrcFontBox.right);
6474 SCALE_Y(potm->otmMacAscent);
6475 SCALE_Y(potm->otmMacDescent);
6476 SCALE_Y(potm->otmMacLineGap);
6477 SCALE_X(potm->otmptSubscriptSize.x);
6478 SCALE_Y(potm->otmptSubscriptSize.y);
6479 SCALE_X(potm->otmptSubscriptOffset.x);
6480 SCALE_Y(potm->otmptSubscriptOffset.y);
6481 SCALE_X(potm->otmptSuperscriptSize.x);
6482 SCALE_Y(potm->otmptSuperscriptSize.y);
6483 SCALE_X(potm->otmptSuperscriptOffset.x);
6484 SCALE_Y(potm->otmptSuperscriptOffset.y);
6485 SCALE_Y(potm->otmsStrikeoutSize);
6486 SCALE_Y(potm->otmsStrikeoutPosition);
6487 SCALE_Y(potm->otmsUnderscoreSize);
6488 SCALE_Y(potm->otmsUnderscorePosition);
6494 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
6498 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
6500 /* Make sure that the font has sane width/height ratio */
6503 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
6505 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
6510 *ptm = font->potm->otmTextMetrics;
6511 scale_font_metrics(font, ptm);
6515 static BOOL face_has_symbol_charmap(FT_Face ft_face)
6519 for(i = 0; i < ft_face->num_charmaps; i++)
6521 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
6527 static BOOL get_outline_text_metrics(GdiFont *font)
6530 FT_Face ft_face = font->ft_face;
6531 UINT needed, lenfam, lensty, lenface, lenfull;
6533 TT_HoriHeader *pHori;
6534 TT_Postscript *pPost;
6535 FT_Fixed x_scale, y_scale;
6536 WCHAR *family_nameW, *style_nameW, *face_nameW, *full_nameW;
6538 INT ascent, descent;
6540 TRACE("font=%p\n", font);
6542 if(!FT_IS_SCALABLE(ft_face))
6545 needed = sizeof(*font->potm);
6547 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
6548 family_nameW = strdupW(font->name);
6550 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
6552 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
6553 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
6554 style_nameW, lensty/sizeof(WCHAR));
6556 face_nameW = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES );
6559 FIXME("failed to read face_nameW for font %s!\n", wine_dbgstr_w(font->name));
6560 face_nameW = strdupW(font->name);
6562 lenface = (strlenW(face_nameW) + 1) * sizeof(WCHAR);
6564 full_nameW = get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, TT_MS_LANGID_ENGLISH_UNITED_STATES );
6567 WCHAR fake_nameW[] = {'f','a','k','e',' ','n','a','m','e', 0};
6568 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w(font->name));
6569 full_nameW = strdupW(fake_nameW);
6571 lenfull = (strlenW(full_nameW) + 1) * sizeof(WCHAR);
6573 /* These names should be read from the TT name table */
6575 /* length of otmpFamilyName */
6578 /* length of otmpFaceName */
6581 /* length of otmpStyleName */
6584 /* length of otmpFullName */
6588 x_scale = ft_face->size->metrics.x_scale;
6589 y_scale = ft_face->size->metrics.y_scale;
6591 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
6593 FIXME("Can't find OS/2 table - not TT font?\n");
6597 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
6599 FIXME("Can't find HHEA table - not TT font?\n");
6603 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
6605 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",
6606 pOS2->usWinAscent, pOS2->usWinDescent,
6607 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
6608 pOS2->xAvgCharWidth,
6609 ft_face->ascender, ft_face->descender, ft_face->height,
6610 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
6611 ft_face->bbox.yMax, ft_face->bbox.yMin);
6613 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
6614 font->potm->otmSize = needed;
6616 #define TM font->potm->otmTextMetrics
6618 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
6619 ascent = pHori->Ascender;
6620 descent = -pHori->Descender;
6622 ascent = pOS2->usWinAscent;
6623 descent = pOS2->usWinDescent;
6626 font->ntmCellHeight = ascent + descent;
6627 font->ntmAvgWidth = pOS2->xAvgCharWidth;
6630 TM.tmAscent = font->yMax;
6631 TM.tmDescent = -font->yMin;
6632 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
6634 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
6635 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
6636 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
6637 - ft_face->units_per_EM, y_scale) + 32) >> 6;
6640 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6643 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6645 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
6646 ((ascent + descent) -
6647 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
6649 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
6650 if (TM.tmAveCharWidth == 0) {
6651 TM.tmAveCharWidth = 1;
6653 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
6654 TM.tmWeight = FW_REGULAR;
6655 if (font->fake_bold)
6656 TM.tmWeight = FW_BOLD;
6659 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
6661 if (pOS2->usWeightClass > FW_MEDIUM)
6662 TM.tmWeight = pOS2->usWeightClass;
6664 else if (pOS2->usWeightClass <= FW_MEDIUM)
6665 TM.tmWeight = pOS2->usWeightClass;
6668 TM.tmDigitizedAspectX = 96; /* FIXME */
6669 TM.tmDigitizedAspectY = 96; /* FIXME */
6670 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6671 * symbol range to 0 - f0ff
6674 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
6679 case 1257: /* Baltic */
6680 TM.tmLastChar = 0xf8fd;
6683 TM.tmLastChar = 0xf0ff;
6685 TM.tmBreakChar = 0x20;
6686 TM.tmDefaultChar = 0x1f;
6690 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
6691 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
6693 if(pOS2->usFirstCharIndex <= 1)
6694 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
6695 else if (pOS2->usFirstCharIndex > 0xff)
6696 TM.tmBreakChar = 0x20;
6698 TM.tmBreakChar = pOS2->usFirstCharIndex;
6699 TM.tmDefaultChar = TM.tmBreakChar - 1;
6701 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
6702 TM.tmUnderlined = font->underline;
6703 TM.tmStruckOut = font->strikeout;
6705 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6706 if(!FT_IS_FIXED_WIDTH(ft_face) &&
6707 (pOS2->version == 0xFFFFU ||
6708 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
6709 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
6711 TM.tmPitchAndFamily = 0;
6713 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
6715 case PAN_FAMILY_SCRIPT:
6716 TM.tmPitchAndFamily |= FF_SCRIPT;
6719 case PAN_FAMILY_DECORATIVE:
6720 TM.tmPitchAndFamily |= FF_DECORATIVE;
6725 case PAN_FAMILY_TEXT_DISPLAY:
6726 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
6727 /* which is clearly not what the panose spec says. */
6729 if(TM.tmPitchAndFamily == 0 || /* fixed */
6730 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
6731 TM.tmPitchAndFamily = FF_MODERN;
6734 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
6739 TM.tmPitchAndFamily |= FF_DONTCARE;
6742 case PAN_SERIF_COVE:
6743 case PAN_SERIF_OBTUSE_COVE:
6744 case PAN_SERIF_SQUARE_COVE:
6745 case PAN_SERIF_OBTUSE_SQUARE_COVE:
6746 case PAN_SERIF_SQUARE:
6747 case PAN_SERIF_THIN:
6748 case PAN_SERIF_BONE:
6749 case PAN_SERIF_EXAGGERATED:
6750 case PAN_SERIF_TRIANGLE:
6751 TM.tmPitchAndFamily |= FF_ROMAN;
6754 case PAN_SERIF_NORMAL_SANS:
6755 case PAN_SERIF_OBTUSE_SANS:
6756 case PAN_SERIF_PERP_SANS:
6757 case PAN_SERIF_FLARED:
6758 case PAN_SERIF_ROUNDED:
6759 TM.tmPitchAndFamily |= FF_SWISS;
6766 if(FT_IS_SCALABLE(ft_face))
6767 TM.tmPitchAndFamily |= TMPF_VECTOR;
6769 if(FT_IS_SFNT(ft_face))
6771 if (font->ntmFlags & NTM_PS_OPENTYPE)
6772 TM.tmPitchAndFamily |= TMPF_DEVICE;
6774 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
6777 TM.tmCharSet = font->charset;
6779 font->potm->otmFiller = 0;
6780 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
6781 font->potm->otmfsSelection = pOS2->fsSelection;
6782 font->potm->otmfsType = pOS2->fsType;
6783 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
6784 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
6785 font->potm->otmItalicAngle = 0; /* POST table */
6786 font->potm->otmEMSquare = ft_face->units_per_EM;
6787 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
6788 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
6789 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
6790 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
6791 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
6792 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
6793 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
6794 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
6795 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
6796 font->potm->otmMacAscent = TM.tmAscent;
6797 font->potm->otmMacDescent = -TM.tmDescent;
6798 font->potm->otmMacLineGap = font->potm->otmLineGap;
6799 font->potm->otmusMinimumPPEM = 0; /* TT Header */
6800 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
6801 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
6802 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
6803 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
6804 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
6805 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
6806 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
6807 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
6808 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
6809 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
6811 font->potm->otmsUnderscoreSize = 0;
6812 font->potm->otmsUnderscorePosition = 0;
6814 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
6815 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
6819 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
6820 cp = (char*)font->potm + sizeof(*font->potm);
6821 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
6822 strcpyW((WCHAR*)cp, family_nameW);
6824 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
6825 strcpyW((WCHAR*)cp, style_nameW);
6827 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
6828 strcpyW((WCHAR*)cp, face_nameW);
6830 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
6831 strcpyW((WCHAR*)cp, full_nameW);
6835 HeapFree(GetProcessHeap(), 0, style_nameW);
6836 HeapFree(GetProcessHeap(), 0, family_nameW);
6837 HeapFree(GetProcessHeap(), 0, face_nameW);
6838 HeapFree(GetProcessHeap(), 0, full_nameW);
6842 /*************************************************************
6843 * freetype_GetGlyphOutline
6845 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
6846 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
6848 struct freetype_physdev *physdev = get_freetype_dev( dev );
6853 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
6854 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
6858 EnterCriticalSection( &freetype_cs );
6859 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, buflen, buf, lpmat );
6860 LeaveCriticalSection( &freetype_cs );
6864 /*************************************************************
6865 * freetype_GetTextMetrics
6867 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
6869 struct freetype_physdev *physdev = get_freetype_dev( dev );
6874 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
6875 return dev->funcs->pGetTextMetrics( dev, metrics );
6879 EnterCriticalSection( &freetype_cs );
6880 ret = get_text_metrics( physdev->font, metrics );
6881 LeaveCriticalSection( &freetype_cs );
6885 /*************************************************************
6886 * freetype_GetOutlineTextMetrics
6888 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
6890 struct freetype_physdev *physdev = get_freetype_dev( dev );
6895 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
6896 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
6899 TRACE("font=%p\n", physdev->font);
6901 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
6904 EnterCriticalSection( &freetype_cs );
6906 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
6908 if(cbSize >= physdev->font->potm->otmSize)
6910 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
6911 scale_outline_font_metrics(physdev->font, potm);
6913 ret = physdev->font->potm->otmSize;
6915 LeaveCriticalSection( &freetype_cs );
6919 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
6921 HFONTLIST *hfontlist;
6922 child->font = alloc_font();
6923 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
6924 if(!child->font->ft_face)
6926 free_font(child->font);
6931 child->font->font_desc = font->font_desc;
6932 child->font->ntmFlags = child->face->ntmFlags;
6933 child->font->orientation = font->orientation;
6934 child->font->scale_y = font->scale_y;
6935 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
6936 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
6937 child->font->name = strdupW(child->face->family->FamilyName);
6938 list_add_head(&child->font->hfontlist, &hfontlist->entry);
6939 child->font->base_font = font;
6940 list_add_head(&child_font_list, &child->font->entry);
6941 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
6945 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
6948 CHILD_FONT *child_font;
6951 font = font->base_font;
6953 *linked_font = font;
6955 if((*glyph = get_glyph_index(font, c)))
6957 *glyph = get_GSUB_vert_glyph(font, *glyph);
6961 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
6963 if(!child_font->font)
6964 if(!load_child_font(font, child_font))
6967 if(!child_font->font->ft_face)
6969 g = get_glyph_index(child_font->font, c);
6970 g = get_GSUB_vert_glyph(child_font->font, g);
6974 *linked_font = child_font->font;
6981 /*************************************************************
6982 * freetype_GetCharWidth
6984 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
6986 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6989 FT_UInt glyph_index;
6990 GdiFont *linked_font;
6991 struct freetype_physdev *physdev = get_freetype_dev( dev );
6995 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
6996 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
6999 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
7002 EnterCriticalSection( &freetype_cs );
7003 for(c = firstChar; c <= lastChar; c++) {
7004 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
7005 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
7006 &gm, 0, NULL, &identity);
7007 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
7009 LeaveCriticalSection( &freetype_cs );
7013 /*************************************************************
7014 * freetype_GetCharABCWidths
7016 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
7018 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7021 FT_UInt glyph_index;
7022 GdiFont *linked_font;
7023 struct freetype_physdev *physdev = get_freetype_dev( dev );
7027 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
7028 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
7031 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
7034 EnterCriticalSection( &freetype_cs );
7036 for(c = firstChar; c <= lastChar; c++) {
7037 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
7038 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
7039 &gm, 0, NULL, &identity);
7040 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
7041 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
7042 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
7043 FONT_GM(linked_font,glyph_index)->bbx;
7045 LeaveCriticalSection( &freetype_cs );
7049 /*************************************************************
7050 * freetype_GetCharABCWidthsI
7052 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
7054 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7057 FT_UInt glyph_index;
7058 GdiFont *linked_font;
7059 struct freetype_physdev *physdev = get_freetype_dev( dev );
7063 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
7064 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
7067 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
7071 EnterCriticalSection( &freetype_cs );
7073 get_glyph_index_linked(physdev->font, 'a', &linked_font, &glyph_index);
7075 for(c = firstChar; c < firstChar+count; c++) {
7076 get_glyph_outline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
7077 &gm, 0, NULL, &identity);
7078 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
7079 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
7080 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
7081 - FONT_GM(linked_font,c)->bbx;
7084 for(c = 0; c < count; c++) {
7085 get_glyph_outline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
7086 &gm, 0, NULL, &identity);
7087 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
7088 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
7089 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
7090 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
7093 LeaveCriticalSection( &freetype_cs );
7097 /*************************************************************
7098 * freetype_GetTextExtentExPoint
7100 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count,
7101 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
7103 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7108 FT_UInt glyph_index;
7109 GdiFont *linked_font;
7110 struct freetype_physdev *physdev = get_freetype_dev( dev );
7114 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
7115 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, max_ext, pnfit, dxs, size );
7118 TRACE("%p, %s, %d, %d, %p\n", physdev->font, debugstr_wn(wstr, count), count, max_ext, size);
7121 EnterCriticalSection( &freetype_cs );
7124 get_text_metrics( physdev->font, &tm );
7125 size->cy = tm.tmHeight;
7127 for(idx = 0; idx < count; idx++) {
7128 get_glyph_index_linked( physdev->font, wstr[idx], &linked_font, &glyph_index );
7129 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
7130 &gm, 0, NULL, &identity);
7131 size->cx += FONT_GM(linked_font,glyph_index)->adv;
7133 if (! pnfit || ext <= max_ext) {
7143 LeaveCriticalSection( &freetype_cs );
7144 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
7148 /*************************************************************
7149 * freetype_GetTextExtentExPointI
7151 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count,
7152 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size )
7154 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7159 struct freetype_physdev *physdev = get_freetype_dev( dev );
7163 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
7164 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, max_ext, pnfit, dxs, size );
7167 TRACE("%p, %p, %d, %d, %p\n", physdev->font, indices, count, max_ext, size);
7170 EnterCriticalSection( &freetype_cs );
7173 get_text_metrics(physdev->font, &tm);
7174 size->cy = tm.tmHeight;
7176 for(idx = 0; idx < count; idx++) {
7177 get_glyph_outline(physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &identity);
7178 size->cx += FONT_GM(physdev->font,indices[idx])->adv;
7180 if (! pnfit || ext <= max_ext) {
7190 LeaveCriticalSection( &freetype_cs );
7191 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
7195 /*************************************************************
7196 * freetype_GetFontData
7198 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
7200 struct freetype_physdev *physdev = get_freetype_dev( dev );
7204 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
7205 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
7208 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
7209 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
7210 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
7212 return get_font_data( physdev->font, table, offset, buf, cbData );
7215 /*************************************************************
7216 * freetype_GetTextFace
7218 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
7221 struct freetype_physdev *physdev = get_freetype_dev( dev );
7225 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
7226 return dev->funcs->pGetTextFace( dev, count, str );
7229 n = strlenW(physdev->font->name) + 1;
7232 lstrcpynW(str, physdev->font->name, count);
7238 /*************************************************************
7239 * freetype_GetTextCharsetInfo
7241 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
7243 struct freetype_physdev *physdev = get_freetype_dev( dev );
7247 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
7248 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
7250 if (fs) *fs = physdev->font->fs;
7251 return physdev->font->charset;
7254 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
7256 GdiFont *font = dc->gdiFont, *linked_font;
7257 struct list *first_hfont;
7261 EnterCriticalSection( &freetype_cs );
7262 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
7263 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
7264 if(font == linked_font)
7265 *new_hfont = dc->hFont;
7268 first_hfont = list_head(&linked_font->hfontlist);
7269 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
7271 LeaveCriticalSection( &freetype_cs );
7275 /* Retrieve a list of supported Unicode ranges for a given font.
7276 * Can be called with NULL gs to calculate the buffer size. Returns
7277 * the number of ranges found.
7279 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
7281 DWORD num_ranges = 0;
7283 if (face->charmap->encoding == FT_ENCODING_UNICODE)
7286 FT_ULong char_code, char_code_prev;
7289 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
7291 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
7292 face->num_glyphs, glyph_code, char_code);
7294 if (!glyph_code) return 0;
7298 gs->ranges[0].wcLow = (USHORT)char_code;
7299 gs->ranges[0].cGlyphs = 0;
7300 gs->cGlyphsSupported = 0;
7306 if (char_code < char_code_prev)
7308 ERR("expected increasing char code from FT_Get_Next_Char\n");
7311 if (char_code - char_code_prev > 1)
7316 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
7317 gs->ranges[num_ranges - 1].cGlyphs = 1;
7318 gs->cGlyphsSupported++;
7323 gs->ranges[num_ranges - 1].cGlyphs++;
7324 gs->cGlyphsSupported++;
7326 char_code_prev = char_code;
7327 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
7331 FIXME("encoding %u not supported\n", face->charmap->encoding);
7336 /*************************************************************
7337 * freetype_GetFontUnicodeRanges
7339 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
7341 struct freetype_physdev *physdev = get_freetype_dev( dev );
7342 DWORD size, num_ranges;
7346 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
7347 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
7350 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
7351 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
7354 glyphset->cbThis = size;
7355 glyphset->cRanges = num_ranges;
7356 glyphset->flAccel = 0;
7361 /*************************************************************
7362 * freetype_FontIsLinked
7364 static BOOL freetype_FontIsLinked( PHYSDEV dev )
7366 struct freetype_physdev *physdev = get_freetype_dev( dev );
7371 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
7372 return dev->funcs->pFontIsLinked( dev );
7376 EnterCriticalSection( &freetype_cs );
7377 ret = !list_empty(&physdev->font->child_fonts);
7378 LeaveCriticalSection( &freetype_cs );
7382 static BOOL is_hinting_enabled(void)
7384 /* Use the >= 2.2.0 function if available */
7385 if(pFT_Get_TrueType_Engine_Type)
7387 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
7388 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
7390 #ifdef FT_DRIVER_HAS_HINTER
7395 /* otherwise if we've been compiled with < 2.2.0 headers
7396 use the internal macro */
7397 mod = pFT_Get_Module(library, "truetype");
7398 if(mod && FT_DRIVER_HAS_HINTER(mod))
7406 static BOOL is_subpixel_rendering_enabled( void )
7408 #ifdef HAVE_FREETYPE_FTLCDFIL_H
7409 return pFT_Library_SetLcdFilter &&
7410 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
7416 /*************************************************************************
7417 * GetRasterizerCaps (GDI32.@)
7419 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7421 static int hinting = -1;
7422 static int subpixel = -1;
7426 hinting = is_hinting_enabled();
7427 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
7430 if ( subpixel == -1 )
7432 subpixel = is_subpixel_rendering_enabled();
7433 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
7436 lprs->nSize = sizeof(RASTERIZER_STATUS);
7437 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
7439 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
7440 lprs->nLanguageID = 0;
7444 /*************************************************************
7445 * freetype_GdiRealizationInfo
7447 static BOOL freetype_GdiRealizationInfo( PHYSDEV dev, void *ptr )
7449 struct freetype_physdev *physdev = get_freetype_dev( dev );
7450 realization_info_t *info = ptr;
7454 dev = GET_NEXT_PHYSDEV( dev, pGdiRealizationInfo );
7455 return dev->funcs->pGdiRealizationInfo( dev, ptr );
7458 FIXME("(%p, %p): stub!\n", physdev->font, info);
7461 if(FT_IS_SCALABLE(physdev->font->ft_face))
7464 info->cache_num = physdev->font->cache_num;
7465 info->unknown2 = -1;
7469 /*************************************************************************
7470 * Kerning support for TrueType fonts
7472 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
7474 struct TT_kern_table
7480 struct TT_kern_subtable
7489 USHORT horizontal : 1;
7491 USHORT cross_stream: 1;
7492 USHORT override : 1;
7493 USHORT reserved1 : 4;
7499 struct TT_format0_kern_subtable
7503 USHORT entrySelector;
7514 static DWORD parse_format0_kern_subtable(GdiFont *font,
7515 const struct TT_format0_kern_subtable *tt_f0_ks,
7516 const USHORT *glyph_to_char,
7517 KERNINGPAIR *kern_pair, DWORD cPairs)
7520 const struct TT_kern_pair *tt_kern_pair;
7522 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
7524 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
7526 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7527 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
7528 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
7530 if (!kern_pair || !cPairs)
7533 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
7535 nPairs = min(nPairs, cPairs);
7537 for (i = 0; i < nPairs; i++)
7539 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
7540 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
7541 /* this algorithm appears to better match what Windows does */
7542 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
7543 if (kern_pair->iKernAmount < 0)
7545 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
7546 kern_pair->iKernAmount -= font->ppem;
7548 else if (kern_pair->iKernAmount > 0)
7550 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
7551 kern_pair->iKernAmount += font->ppem;
7553 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
7555 TRACE("left %u right %u value %d\n",
7556 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
7560 TRACE("copied %u entries\n", nPairs);
7564 /*************************************************************
7565 * freetype_GetKerningPairs
7567 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
7571 const struct TT_kern_table *tt_kern_table;
7572 const struct TT_kern_subtable *tt_kern_subtable;
7574 USHORT *glyph_to_char;
7576 struct freetype_physdev *physdev = get_freetype_dev( dev );
7578 if (!(font = physdev->font))
7580 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
7581 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
7585 EnterCriticalSection( &freetype_cs );
7586 if (font->total_kern_pairs != (DWORD)-1)
7588 if (cPairs && kern_pair)
7590 cPairs = min(cPairs, font->total_kern_pairs);
7591 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7593 else cPairs = font->total_kern_pairs;
7595 LeaveCriticalSection( &freetype_cs );
7599 font->total_kern_pairs = 0;
7601 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
7603 if (length == GDI_ERROR)
7605 TRACE("no kerning data in the font\n");
7606 LeaveCriticalSection( &freetype_cs );
7610 buf = HeapAlloc(GetProcessHeap(), 0, length);
7613 WARN("Out of memory\n");
7614 LeaveCriticalSection( &freetype_cs );
7618 get_font_data(font, MS_KERN_TAG, 0, buf, length);
7620 /* build a glyph index to char code map */
7621 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
7624 WARN("Out of memory allocating a glyph index to char code map\n");
7625 HeapFree(GetProcessHeap(), 0, buf);
7626 LeaveCriticalSection( &freetype_cs );
7630 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
7636 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
7638 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7639 font->ft_face->num_glyphs, glyph_code, char_code);
7643 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7645 /* FIXME: This doesn't match what Windows does: it does some fancy
7646 * things with duplicate glyph index to char code mappings, while
7647 * we just avoid overriding existing entries.
7649 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
7650 glyph_to_char[glyph_code] = (USHORT)char_code;
7652 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
7659 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
7660 for (n = 0; n <= 65535; n++)
7661 glyph_to_char[n] = (USHORT)n;
7664 tt_kern_table = buf;
7665 nTables = GET_BE_WORD(tt_kern_table->nTables);
7666 TRACE("version %u, nTables %u\n",
7667 GET_BE_WORD(tt_kern_table->version), nTables);
7669 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
7671 for (i = 0; i < nTables; i++)
7673 struct TT_kern_subtable tt_kern_subtable_copy;
7675 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
7676 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
7677 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
7679 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7680 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
7681 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
7683 /* According to the TrueType specification this is the only format
7684 * that will be properly interpreted by Windows and OS/2
7686 if (tt_kern_subtable_copy.coverage.bits.format == 0)
7688 DWORD new_chunk, old_total = font->total_kern_pairs;
7690 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7691 glyph_to_char, NULL, 0);
7692 font->total_kern_pairs += new_chunk;
7694 if (!font->kern_pairs)
7695 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
7696 font->total_kern_pairs * sizeof(*font->kern_pairs));
7698 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
7699 font->total_kern_pairs * sizeof(*font->kern_pairs));
7701 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7702 glyph_to_char, font->kern_pairs + old_total, new_chunk);
7705 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
7707 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
7710 HeapFree(GetProcessHeap(), 0, glyph_to_char);
7711 HeapFree(GetProcessHeap(), 0, buf);
7713 if (cPairs && kern_pair)
7715 cPairs = min(cPairs, font->total_kern_pairs);
7716 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7718 else cPairs = font->total_kern_pairs;
7720 LeaveCriticalSection( &freetype_cs );
7724 static const struct gdi_dc_funcs freetype_funcs =
7726 NULL, /* pAbortDoc */
7727 NULL, /* pAbortPath */
7728 NULL, /* pAlphaBlend */
7729 NULL, /* pAngleArc */
7732 NULL, /* pBeginPath */
7733 NULL, /* pBlendImage */
7735 NULL, /* pCloseFigure */
7736 NULL, /* pCreateCompatibleDC */
7737 freetype_CreateDC, /* pCreateDC */
7738 freetype_DeleteDC, /* pDeleteDC */
7739 NULL, /* pDeleteObject */
7740 NULL, /* pDeviceCapabilities */
7741 NULL, /* pEllipse */
7743 NULL, /* pEndPage */
7744 NULL, /* pEndPath */
7745 freetype_EnumFonts, /* pEnumFonts */
7746 NULL, /* pEnumICMProfiles */
7747 NULL, /* pExcludeClipRect */
7748 NULL, /* pExtDeviceMode */
7749 NULL, /* pExtEscape */
7750 NULL, /* pExtFloodFill */
7751 NULL, /* pExtSelectClipRgn */
7752 NULL, /* pExtTextOut */
7753 NULL, /* pFillPath */
7754 NULL, /* pFillRgn */
7755 NULL, /* pFlattenPath */
7756 freetype_FontIsLinked, /* pFontIsLinked */
7757 NULL, /* pFrameRgn */
7758 NULL, /* pGdiComment */
7759 freetype_GdiRealizationInfo, /* pGdiRealizationInfo */
7760 NULL, /* pGetBoundsRect */
7761 freetype_GetCharABCWidths, /* pGetCharABCWidths */
7762 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
7763 freetype_GetCharWidth, /* pGetCharWidth */
7764 NULL, /* pGetDeviceCaps */
7765 NULL, /* pGetDeviceGammaRamp */
7766 freetype_GetFontData, /* pGetFontData */
7767 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
7768 freetype_GetGlyphIndices, /* pGetGlyphIndices */
7769 freetype_GetGlyphOutline, /* pGetGlyphOutline */
7770 NULL, /* pGetICMProfile */
7771 NULL, /* pGetImage */
7772 freetype_GetKerningPairs, /* pGetKerningPairs */
7773 NULL, /* pGetNearestColor */
7774 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
7775 NULL, /* pGetPixel */
7776 NULL, /* pGetSystemPaletteEntries */
7777 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
7778 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
7779 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
7780 freetype_GetTextFace, /* pGetTextFace */
7781 freetype_GetTextMetrics, /* pGetTextMetrics */
7782 NULL, /* pGradientFill */
7783 NULL, /* pIntersectClipRect */
7784 NULL, /* pInvertRgn */
7786 NULL, /* pModifyWorldTransform */
7788 NULL, /* pOffsetClipRgn */
7789 NULL, /* pOffsetViewportOrg */
7790 NULL, /* pOffsetWindowOrg */
7791 NULL, /* pPaintRgn */
7794 NULL, /* pPolyBezier */
7795 NULL, /* pPolyBezierTo */
7796 NULL, /* pPolyDraw */
7797 NULL, /* pPolyPolygon */
7798 NULL, /* pPolyPolyline */
7799 NULL, /* pPolygon */
7800 NULL, /* pPolyline */
7801 NULL, /* pPolylineTo */
7802 NULL, /* pPutImage */
7803 NULL, /* pRealizeDefaultPalette */
7804 NULL, /* pRealizePalette */
7805 NULL, /* pRectangle */
7806 NULL, /* pResetDC */
7807 NULL, /* pRestoreDC */
7808 NULL, /* pRoundRect */
7810 NULL, /* pScaleViewportExt */
7811 NULL, /* pScaleWindowExt */
7812 NULL, /* pSelectBitmap */
7813 NULL, /* pSelectBrush */
7814 NULL, /* pSelectClipPath */
7815 freetype_SelectFont, /* pSelectFont */
7816 NULL, /* pSelectPalette */
7817 NULL, /* pSelectPen */
7818 NULL, /* pSetArcDirection */
7819 NULL, /* pSetBkColor */
7820 NULL, /* pSetBkMode */
7821 NULL, /* pSetDCBrushColor */
7822 NULL, /* pSetDCPenColor */
7823 NULL, /* pSetDIBColorTable */
7824 NULL, /* pSetDIBitsToDevice */
7825 NULL, /* pSetDeviceClipping */
7826 NULL, /* pSetDeviceGammaRamp */
7827 NULL, /* pSetLayout */
7828 NULL, /* pSetMapMode */
7829 NULL, /* pSetMapperFlags */
7830 NULL, /* pSetPixel */
7831 NULL, /* pSetPolyFillMode */
7832 NULL, /* pSetROP2 */
7833 NULL, /* pSetRelAbs */
7834 NULL, /* pSetStretchBltMode */
7835 NULL, /* pSetTextAlign */
7836 NULL, /* pSetTextCharacterExtra */
7837 NULL, /* pSetTextColor */
7838 NULL, /* pSetTextJustification */
7839 NULL, /* pSetViewportExt */
7840 NULL, /* pSetViewportOrg */
7841 NULL, /* pSetWindowExt */
7842 NULL, /* pSetWindowOrg */
7843 NULL, /* pSetWorldTransform */
7844 NULL, /* pStartDoc */
7845 NULL, /* pStartPage */
7846 NULL, /* pStretchBlt */
7847 NULL, /* pStretchDIBits */
7848 NULL, /* pStrokeAndFillPath */
7849 NULL, /* pStrokePath */
7850 NULL, /* pSwapBuffers */
7851 NULL, /* pUnrealizePalette */
7852 NULL, /* pWidenPath */
7853 NULL, /* wine_get_wgl_driver */
7854 GDI_PRIORITY_FONT_DRV /* priority */
7857 #else /* HAVE_FREETYPE */
7859 /*************************************************************************/
7861 BOOL WineEngInit(void)
7865 BOOL WineEngDestroyFontInstance(HFONT hfont)
7870 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7872 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7876 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7878 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7882 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
7884 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
7888 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
7889 LPCWSTR font_file, LPCWSTR font_path )
7895 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
7900 /*************************************************************************
7901 * GetRasterizerCaps (GDI32.@)
7903 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7905 lprs->nSize = sizeof(RASTERIZER_STATUS);
7907 lprs->nLanguageID = 0;
7911 #endif /* HAVE_FREETYPE */