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(FcConfigSubstitute);
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(FcPatternGetInteger);
205 MAKE_FUNCPTR(FcPatternGetString);
211 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
212 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
213 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
216 #ifndef ft_encoding_none
217 #define FT_ENCODING_NONE ft_encoding_none
219 #ifndef ft_encoding_ms_symbol
220 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
222 #ifndef ft_encoding_unicode
223 #define FT_ENCODING_UNICODE ft_encoding_unicode
225 #ifndef ft_encoding_apple_roman
226 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
229 #ifdef WORDS_BIGENDIAN
230 #define GET_BE_WORD(x) (x)
232 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
235 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
242 FT_Short internal_leading;
245 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
246 So to let this compile on older versions of FreeType we'll define the
247 new structure here. */
249 FT_Short height, width;
250 FT_Pos size, x_ppem, y_ppem;
256 NEWTEXTMETRICEXW ntm;
260 typedef struct tagFace {
266 DWORD font_data_size;
270 FT_Fixed font_version;
273 Bitmap_Size size; /* set if face is a bitmap */
274 BOOL external; /* TRUE if we should manually add this font to the registry */
276 struct tagFamily *family;
277 /* Cached data for Enum */
278 struct enum_data *cached_enum_data;
281 typedef struct tagFamily {
286 struct list *replacement;
291 ABC abc; /* metrics of the unrotated char */
307 typedef struct tagGdiFont GdiFont;
317 struct list unused_entry;
318 unsigned int refcount;
321 OUTLINETEXTMETRICW *potm;
322 DWORD total_kern_pairs;
323 KERNINGPAIR *kern_pairs;
324 struct list child_fonts;
326 /* the following members can be accessed without locking, they are never modified after creation */
328 struct font_mapping *mapping;
344 UINT ntmCellHeight, ntmAvgWidth;
353 const WCHAR *font_name;
358 struct enum_charset_element {
361 WCHAR name[LF_FACESIZE];
364 struct enum_charset_list {
366 struct enum_charset_element element[32];
369 #define GM_BLOCK_SIZE 128
370 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
372 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
373 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
374 static unsigned int unused_font_count;
375 #define UNUSED_CACHE_SIZE 10
376 static struct list system_links = LIST_INIT(system_links);
378 static struct list font_subst_list = LIST_INIT(font_subst_list);
380 static struct list font_list = LIST_INIT(font_list);
382 struct freetype_physdev
384 struct gdi_physdev dev;
388 static inline struct freetype_physdev *get_freetype_dev( PHYSDEV dev )
390 return (struct freetype_physdev *)dev;
393 static const struct gdi_dc_funcs freetype_funcs;
395 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
396 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
397 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
399 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
400 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
401 'W','i','n','d','o','w','s','\\',
402 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
403 'F','o','n','t','s','\0'};
405 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
406 'W','i','n','d','o','w','s',' ','N','T','\\',
407 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
408 'F','o','n','t','s','\0'};
410 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
411 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
412 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
413 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
415 static const WCHAR * const SystemFontValues[] = {
422 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
423 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
425 /* Interesting and well-known (frequently-assumed!) font names */
426 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
427 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 };
428 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
429 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
430 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
431 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
432 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
433 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
435 static const WCHAR arial[] = {'A','r','i','a','l',0};
436 static const WCHAR bitstream_vera_sans[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
437 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};
438 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};
439 static const WCHAR courier_new[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
440 static const WCHAR liberation_mono[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
441 static const WCHAR liberation_sans[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
442 static const WCHAR liberation_serif[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
443 static const WCHAR times_new_roman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
444 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
446 static const WCHAR *default_serif_list[] =
450 bitstream_vera_serif,
454 static const WCHAR *default_fixed_list[] =
458 bitstream_vera_sans_mono,
462 static const WCHAR *default_sans_list[] =
475 typedef struct tagFontSubst {
481 /* Registry font cache key and value names */
482 static const WCHAR wine_fonts_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
483 'F','o','n','t','s',0};
484 static const WCHAR wine_fonts_cache_key[] = {'C','a','c','h','e',0};
485 static const WCHAR english_name_value[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
486 static const WCHAR face_index_value[] = {'I','n','d','e','x',0};
487 static const WCHAR face_ntmflags_value[] = {'N','t','m','f','l','a','g','s',0};
488 static const WCHAR face_version_value[] = {'V','e','r','s','i','o','n',0};
489 static const WCHAR face_vertical_value[] = {'V','e','r','t','i','c','a','l',0};
490 static const WCHAR face_height_value[] = {'H','e','i','g','h','t',0};
491 static const WCHAR face_width_value[] = {'W','i','d','t','h',0};
492 static const WCHAR face_size_value[] = {'S','i','z','e',0};
493 static const WCHAR face_x_ppem_value[] = {'X','p','p','e','m',0};
494 static const WCHAR face_y_ppem_value[] = {'Y','p','p','e','m',0};
495 static const WCHAR face_aa_value[] = {'A','n','t','i','a','l','i','a','s','i','n','g',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_file_name_value[] = {'F','i','l','e',' ','N','a','m','e','\0'};
499 static const WCHAR face_full_name_value[] = {'F','u','l','l',' ','N','a','m','e','\0'};
512 static struct list mappings_list = LIST_INIT( mappings_list );
514 static UINT default_aa_flags;
516 static CRITICAL_SECTION freetype_cs;
517 static CRITICAL_SECTION_DEBUG critsect_debug =
520 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
521 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
523 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
525 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
527 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
528 static BOOL use_default_fallback = FALSE;
530 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
531 static BOOL get_outline_text_metrics(GdiFont *font);
532 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm);
534 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
535 'W','i','n','d','o','w','s',' ','N','T','\\',
536 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
537 'S','y','s','t','e','m','L','i','n','k',0};
539 static const WCHAR internal_system_link[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
540 'F','o','n','t','L','i','n','k','\\',
541 'S','y','s','t','e','m','L','i','n','k',0};
543 /****************************************
544 * Notes on .fon files
546 * The fonts System, FixedSys and Terminal are special. There are typically multiple
547 * versions installed for different resolutions and codepages. Windows stores which one to use
548 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
550 * FIXEDFON.FON FixedSys
552 * OEMFONT.FON Terminal
553 * LogPixels Current dpi set by the display control panel applet
554 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
555 * also has a LogPixels value that appears to mirror this)
557 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
558 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
559 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
560 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
561 * so that makes sense.
563 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
564 * to be mapped into the registry on Windows 2000 at least).
567 * ega80woa.fon=ega80850.fon
568 * ega40woa.fon=ega40850.fon
569 * cga80woa.fon=cga80850.fon
570 * cga40woa.fon=cga40850.fon
573 /* These are all structures needed for the GSUB table */
575 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
576 #define TATEGAKI_LOWER_BOUND 0x02F1
592 GSUB_ScriptRecord ScriptRecord[1];
598 } GSUB_LangSysRecord;
603 GSUB_LangSysRecord LangSysRecord[1];
607 WORD LookupOrder; /* Reserved */
608 WORD ReqFeatureIndex;
610 WORD FeatureIndex[1];
616 } GSUB_FeatureRecord;
620 GSUB_FeatureRecord FeatureRecord[1];
624 WORD FeatureParams; /* Reserved */
626 WORD LookupListIndex[1];
645 } GSUB_CoverageFormat1;
650 WORD StartCoverageIndex;
656 GSUB_RangeRecord RangeRecord[1];
657 } GSUB_CoverageFormat2;
660 WORD SubstFormat; /* = 1 */
663 } GSUB_SingleSubstFormat1;
666 WORD SubstFormat; /* = 2 */
670 }GSUB_SingleSubstFormat2;
672 #ifdef HAVE_CARBON_CARBON_H
673 static char *find_cache_dir(void)
677 static char cached_path[MAX_PATH];
678 static const char *wine = "/Wine", *fonts = "/Fonts";
680 if(*cached_path) return cached_path;
682 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
685 WARN("can't create cached data folder\n");
688 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
691 WARN("can't create cached data path\n");
695 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
697 ERR("Could not create full path\n");
701 strcat(cached_path, wine);
703 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
705 WARN("Couldn't mkdir %s\n", cached_path);
709 strcat(cached_path, fonts);
710 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
712 WARN("Couldn't mkdir %s\n", cached_path);
719 /******************************************************************
722 * Extracts individual TrueType font files from a Mac suitcase font
723 * and saves them into the user's caches directory (see
725 * Returns a NULL terminated array of filenames.
727 * We do this because they are apps that try to read ttf files
728 * themselves and they don't like Mac suitcase files.
730 static char **expand_mac_font(const char *path)
737 const char *filename;
741 unsigned int size, max_size;
744 TRACE("path %s\n", path);
746 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
749 WARN("failed to get ref\n");
753 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
756 TRACE("no data fork, so trying resource fork\n");
757 res_ref = FSOpenResFile(&ref, fsRdPerm);
760 TRACE("unable to open resource fork\n");
767 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
770 CloseResFile(res_ref);
774 out_dir = find_cache_dir();
776 filename = strrchr(path, '/');
777 if(!filename) filename = path;
780 /* output filename has the form out_dir/filename_%04x.ttf */
781 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
788 unsigned short *num_faces_ptr, num_faces, face;
791 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
793 fond = Get1IndResource(fond_res, idx);
795 TRACE("got fond resource %d\n", idx);
798 fam_rec = *(FamRec**)fond;
799 num_faces_ptr = (unsigned short *)(fam_rec + 1);
800 num_faces = GET_BE_WORD(*num_faces_ptr);
802 assoc = (AsscEntry*)(num_faces_ptr + 1);
803 TRACE("num faces %04x\n", num_faces);
804 for(face = 0; face < num_faces; face++, assoc++)
807 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
808 unsigned short size, font_id;
811 size = GET_BE_WORD(assoc->fontSize);
812 font_id = GET_BE_WORD(assoc->fontID);
815 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
819 TRACE("trying to load sfnt id %04x\n", font_id);
820 sfnt = GetResource(sfnt_res, font_id);
823 TRACE("can't get sfnt resource %04x\n", font_id);
827 output = HeapAlloc(GetProcessHeap(), 0, output_len);
832 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
834 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
835 if(fd != -1 || errno == EEXIST)
839 unsigned char *sfnt_data;
842 sfnt_data = *(unsigned char**)sfnt;
843 write(fd, sfnt_data, GetHandleSize(sfnt));
847 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
850 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
852 ret.array[ret.size++] = output;
856 WARN("unable to create %s\n", output);
857 HeapFree(GetProcessHeap(), 0, output);
860 ReleaseResource(sfnt);
863 ReleaseResource(fond);
866 CloseResFile(res_ref);
871 #endif /* HAVE_CARBON_CARBON_H */
873 static inline BOOL is_win9x(void)
875 return GetVersion() & 0x80000000;
878 This function builds an FT_Fixed from a double. It fails if the absolute
879 value of the float number is greater than 32768.
881 static inline FT_Fixed FT_FixedFromFloat(double f)
887 This function builds an FT_Fixed from a FIXED. It simply put f.value
888 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
890 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
892 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
895 static BOOL is_hinting_enabled(void)
897 static int enabled = -1;
901 /* Use the >= 2.2.0 function if available */
902 if (pFT_Get_TrueType_Engine_Type)
904 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
905 enabled = (type == FT_TRUETYPE_ENGINE_TYPE_PATENTED);
907 #ifdef FT_DRIVER_HAS_HINTER
910 /* otherwise if we've been compiled with < 2.2.0 headers use the internal macro */
911 FT_Module mod = pFT_Get_Module(library, "truetype");
912 enabled = (mod && FT_DRIVER_HAS_HINTER(mod));
915 else enabled = FALSE;
916 TRACE("hinting is %senabled\n", enabled ? "" : "NOT ");
921 static BOOL is_subpixel_rendering_enabled( void )
923 #ifdef HAVE_FREETYPE_FTLCDFIL_H
924 static int enabled = -1;
927 enabled = (pFT_Library_SetLcdFilter &&
928 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature);
929 TRACE("subpixel rendering is %senabled\n", enabled ? "" : "NOT ");
938 static const struct list *get_face_list_from_family(const Family *family)
940 if (!list_empty(&family->faces))
941 return &family->faces;
943 return family->replacement;
946 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
952 TRACE("looking for file %s name %s\n", debugstr_w(file_name), debugstr_w(face_name));
954 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
956 const struct list *face_list;
957 if(face_name && strcmpiW(face_name, family->FamilyName))
959 face_list = get_face_list_from_family(family);
960 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
964 file = strrchrW(face->file, '/');
969 if(!strcmpiW(file, file_name)) return face;
975 static Family *find_family_from_name(const WCHAR *name)
979 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
981 if(!strcmpiW(family->FamilyName, name))
988 static Family *find_family_from_any_name(const WCHAR *name)
992 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
994 if(!strcmpiW(family->FamilyName, name))
996 if(family->EnglishName && !strcmpiW(family->EnglishName, name))
1003 static void DumpSubstList(void)
1007 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
1009 if(psub->from.charset != -1 || psub->to.charset != -1)
1010 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
1011 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
1013 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
1014 debugstr_w(psub->to.name));
1019 static LPWSTR strdupW(LPCWSTR p)
1022 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
1023 ret = HeapAlloc(GetProcessHeap(), 0, len);
1024 memcpy(ret, p, len);
1028 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
1033 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
1035 if(!strcmpiW(element->from.name, from_name) &&
1036 (element->from.charset == from_charset ||
1037 element->from.charset == -1))
1044 #define ADD_FONT_SUBST_FORCE 1
1046 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
1048 FontSubst *from_exist, *to_exist;
1050 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
1052 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
1054 list_remove(&from_exist->entry);
1055 HeapFree(GetProcessHeap(), 0, from_exist->from.name);
1056 HeapFree(GetProcessHeap(), 0, from_exist->to.name);
1057 HeapFree(GetProcessHeap(), 0, from_exist);
1063 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
1067 HeapFree(GetProcessHeap(), 0, subst->to.name);
1068 subst->to.name = strdupW(to_exist->to.name);
1071 list_add_tail(subst_list, &subst->entry);
1076 HeapFree(GetProcessHeap(), 0, subst->from.name);
1077 HeapFree(GetProcessHeap(), 0, subst->to.name);
1078 HeapFree(GetProcessHeap(), 0, subst);
1082 static WCHAR *towstr(UINT cp, const char *str)
1087 len = MultiByteToWideChar(cp, 0, str, -1, NULL, 0);
1088 wstr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1089 MultiByteToWideChar(cp, 0, str, -1, wstr, len);
1093 static char *strWtoA(UINT cp, const WCHAR *str)
1095 int len = WideCharToMultiByte( cp, 0, str, -1, NULL, 0, NULL, NULL );
1096 char *ret = HeapAlloc( GetProcessHeap(), 0, len );
1097 WideCharToMultiByte( cp, 0, str, -1, ret, len, NULL, NULL );
1101 static void split_subst_info(NameCs *nc, LPSTR str)
1103 CHAR *p = strrchr(str, ',');
1107 nc->charset = strtol(p+1, NULL, 10);
1110 nc->name = towstr(CP_ACP, str);
1113 static void LoadSubstList(void)
1117 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1121 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1122 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1123 &hkey) == ERROR_SUCCESS) {
1125 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1126 &valuelen, &datalen, NULL, NULL);
1128 valuelen++; /* returned value doesn't include room for '\0' */
1129 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1130 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1134 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1135 &dlen) == ERROR_SUCCESS) {
1136 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1138 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1139 split_subst_info(&psub->from, value);
1140 split_subst_info(&psub->to, data);
1142 /* Win 2000 doesn't allow mapping between different charsets
1143 or mapping of DEFAULT_CHARSET */
1144 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1145 psub->to.charset == DEFAULT_CHARSET) {
1146 HeapFree(GetProcessHeap(), 0, psub->to.name);
1147 HeapFree(GetProcessHeap(), 0, psub->from.name);
1148 HeapFree(GetProcessHeap(), 0, psub);
1150 add_font_subst(&font_subst_list, psub, 0);
1152 /* reset dlen and vlen */
1156 HeapFree(GetProcessHeap(), 0, data);
1157 HeapFree(GetProcessHeap(), 0, value);
1163 /*****************************************************************
1164 * get_name_table_entry
1166 * Supply the platform, encoding, language and name ids in req
1167 * and if the name exists the function will fill in the string
1168 * and string_len members. The string is owned by FreeType so
1169 * don't free it. Returns TRUE if the name is found else FALSE.
1171 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1174 FT_UInt num_names, name_index;
1176 if(FT_IS_SFNT(ft_face))
1178 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1180 for(name_index = 0; name_index < num_names; name_index++)
1182 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1184 if((name.platform_id == req->platform_id) &&
1185 ((name.encoding_id == TT_MS_ID_UNICODE_CS) || (name.encoding_id == TT_MS_ID_SYMBOL_CS)) &&
1186 (name.language_id == req->language_id) &&
1187 (name.name_id == req->name_id))
1189 req->string = name.string;
1190 req->string_len = name.string_len;
1197 req->string_len = 0;
1201 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, FT_UShort language_id)
1206 name.platform_id = TT_PLATFORM_MICROSOFT;
1207 name.language_id = language_id;
1208 name.name_id = name_id;
1210 if(get_name_table_entry(ft_face, &name))
1214 /* String is not nul terminated and string_len is a byte length. */
1215 ret = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1216 for(i = 0; i < name.string_len / 2; i++)
1218 WORD *tmp = (WORD *)&name.string[i * 2];
1219 ret[i] = GET_BE_WORD(*tmp);
1222 TRACE("Got localised name %s\n", debugstr_w(ret));
1228 static inline BOOL faces_equal( const Face *f1, const Face *f2 )
1230 if (strcmpiW( f1->StyleName, f2->StyleName )) return FALSE;
1231 if (f1->scalable) return TRUE;
1232 if (f1->size.y_ppem != f2->size.y_ppem) return FALSE;
1233 return !memcmp( &f1->fs, &f2->fs, sizeof(f1->fs) );
1236 static inline void free_face( Face *face )
1238 HeapFree( GetProcessHeap(), 0, face->file );
1239 HeapFree( GetProcessHeap(), 0, face->StyleName );
1240 HeapFree( GetProcessHeap(), 0, face->FullName );
1241 HeapFree( GetProcessHeap(), 0, face->cached_enum_data );
1242 HeapFree( GetProcessHeap(), 0, face );
1245 static inline void free_family( Family *family )
1247 Face *face, *cursor2;
1249 LIST_FOR_EACH_ENTRY_SAFE( face, cursor2, &family->faces, Face, entry )
1251 list_remove( &face->entry );
1254 HeapFree( GetProcessHeap(), 0, family->FamilyName );
1255 HeapFree( GetProcessHeap(), 0, family->EnglishName );
1256 HeapFree( GetProcessHeap(), 0, family );
1259 static inline int style_order(const Face *face)
1261 switch (face->ntmFlags & (NTM_REGULAR | NTM_BOLD | NTM_ITALIC))
1269 case NTM_BOLD | NTM_ITALIC:
1272 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1273 debugstr_w(face->family->FamilyName),
1274 debugstr_w(face->StyleName),
1280 static BOOL insert_face_in_family_list( Face *face, Family *family )
1284 LIST_FOR_EACH_ENTRY( cursor, &family->faces, Face, entry )
1286 if (faces_equal( face, cursor ))
1288 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1289 debugstr_w(family->FamilyName), debugstr_w(face->StyleName),
1290 cursor->font_version, face->font_version);
1292 if (face->font_version <= cursor->font_version)
1294 TRACE("Original font %s is newer so skipping %s\n",
1295 debugstr_w(cursor->file), debugstr_w(face->file));
1300 TRACE("Replacing original %s with %s\n",
1301 debugstr_w(cursor->file), debugstr_w(face->file));
1302 list_add_before( &cursor->entry, &face->entry );
1303 face->family = family;
1304 list_remove( &cursor->entry);
1305 free_face( cursor );
1310 TRACE("Adding new %s\n", debugstr_w(face->file));
1312 if (style_order( face ) < style_order( cursor )) break;
1315 list_add_before( &cursor->entry, &face->entry );
1316 face->family = family;
1320 /****************************************************************
1321 * NB This function stores the ptrs to the strings to save copying.
1322 * Don't free them after calling.
1324 static Family *create_family( WCHAR *name, WCHAR *english_name )
1326 Family * const family = HeapAlloc( GetProcessHeap(), 0, sizeof(*family) );
1327 family->FamilyName = name;
1328 family->EnglishName = english_name;
1329 list_init( &family->faces );
1330 family->replacement = &family->faces;
1335 static LONG reg_load_dword(HKEY hkey, const WCHAR *value, DWORD *data)
1337 DWORD type, size = sizeof(DWORD);
1339 if (RegQueryValueExW(hkey, value, NULL, &type, (BYTE *)data, &size) ||
1340 type != REG_DWORD || size != sizeof(DWORD))
1343 return ERROR_BAD_CONFIGURATION;
1345 return ERROR_SUCCESS;
1348 static inline LONG reg_save_dword(HKEY hkey, const WCHAR *value, DWORD data)
1350 return RegSetValueExW(hkey, value, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD));
1353 static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family, void *buffer, DWORD buffer_size)
1355 DWORD needed, strike_index = 0;
1358 /* If we have a File Name key then this is a real font, not just the parent
1359 key of a bunch of non-scalable strikes */
1360 needed = buffer_size;
1361 if (RegQueryValueExW(hkey_face, face_file_name_value, NULL, NULL, buffer, &needed) == ERROR_SUCCESS)
1364 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1365 face->cached_enum_data = NULL;
1367 face->file = strdupW( buffer );
1368 face->StyleName = strdupW(face_name);
1370 needed = buffer_size;
1371 if(RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, buffer, &needed) == ERROR_SUCCESS)
1372 face->FullName = strdupW( buffer );
1374 face->FullName = NULL;
1376 reg_load_dword(hkey_face, face_index_value, (DWORD*)&face->face_index);
1377 reg_load_dword(hkey_face, face_ntmflags_value, &face->ntmFlags);
1378 reg_load_dword(hkey_face, face_version_value, (DWORD*)&face->font_version);
1379 reg_load_dword(hkey_face, face_vertical_value, (DWORD*)&face->vertical);
1380 reg_load_dword(hkey_face, face_aa_value, (DWORD*)&face->aa_flags);
1382 needed = sizeof(face->fs);
1383 RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
1385 if(reg_load_dword(hkey_face, face_height_value, (DWORD*)&face->size.height) != ERROR_SUCCESS)
1387 face->scalable = TRUE;
1388 memset(&face->size, 0, sizeof(face->size));
1392 face->scalable = FALSE;
1393 reg_load_dword(hkey_face, face_width_value, (DWORD*)&face->size.width);
1394 reg_load_dword(hkey_face, face_size_value, (DWORD*)&face->size.size);
1395 reg_load_dword(hkey_face, face_x_ppem_value, (DWORD*)&face->size.x_ppem);
1396 reg_load_dword(hkey_face, face_y_ppem_value, (DWORD*)&face->size.y_ppem);
1397 reg_load_dword(hkey_face, face_internal_leading_value, (DWORD*)&face->size.internal_leading);
1399 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1400 face->size.height, face->size.width, face->size.size >> 6,
1401 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1404 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1405 face->fs.fsCsb[0], face->fs.fsCsb[1],
1406 face->fs.fsUsb[0], face->fs.fsUsb[1],
1407 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1409 insert_face_in_family_list(face, family);
1411 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
1414 /* load bitmap strikes */
1416 needed = buffer_size;
1417 while (!RegEnumKeyExW(hkey_face, strike_index++, buffer, &needed, NULL, NULL, NULL, NULL))
1419 if (!RegOpenKeyExW(hkey_face, buffer, 0, KEY_ALL_ACCESS, &hkey_strike))
1421 load_face(hkey_strike, face_name, family, buffer, buffer_size);
1422 RegCloseKey(hkey_strike);
1424 needed = buffer_size;
1428 static void load_font_list_from_cache(HKEY hkey_font_cache)
1430 DWORD size, family_index = 0;
1435 size = sizeof(buffer);
1436 while (!RegEnumKeyExW(hkey_font_cache, family_index++, buffer, &size, NULL, NULL, NULL, NULL))
1438 WCHAR *english_family = NULL;
1439 WCHAR *family_name = strdupW( buffer );
1440 DWORD face_index = 0;
1442 RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
1443 TRACE("opened family key %s\n", debugstr_w(family_name));
1444 size = sizeof(buffer);
1445 if (!RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE *)buffer, &size))
1446 english_family = strdupW( buffer );
1448 family = create_family(family_name, english_family);
1449 list_add_tail(&font_list, &family->entry);
1453 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1454 subst->from.name = strdupW(english_family);
1455 subst->from.charset = -1;
1456 subst->to.name = strdupW(family_name);
1457 subst->to.charset = -1;
1458 add_font_subst(&font_subst_list, subst, 0);
1461 size = sizeof(buffer);
1462 while (!RegEnumKeyExW(hkey_family, face_index++, buffer, &size, NULL, NULL, NULL, NULL))
1464 WCHAR *face_name = strdupW( buffer );
1467 if (!RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face))
1469 load_face(hkey_face, face_name, family, buffer, sizeof(buffer));
1470 RegCloseKey(hkey_face);
1472 HeapFree( GetProcessHeap(), 0, face_name );
1473 size = sizeof(buffer);
1475 RegCloseKey(hkey_family);
1476 size = sizeof(buffer);
1480 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1483 HKEY hkey_wine_fonts;
1485 /* We don't want to create the fonts key as volatile, so open this first */
1486 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1487 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1488 if(ret != ERROR_SUCCESS)
1490 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1494 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1495 KEY_ALL_ACCESS, NULL, hkey, disposition);
1496 RegCloseKey(hkey_wine_fonts);
1500 static void add_face_to_cache(Face *face)
1502 HKEY hkey_font_cache, hkey_family, hkey_face;
1503 WCHAR *face_key_name;
1505 create_font_cache_key(&hkey_font_cache, NULL);
1507 RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0,
1508 NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL);
1509 if(face->family->EnglishName)
1510 RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName,
1511 (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR));
1514 face_key_name = face->StyleName;
1517 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1518 face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1519 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1521 RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
1524 HeapFree(GetProcessHeap(), 0, face_key_name);
1526 RegSetValueExW(hkey_face, face_file_name_value, 0, REG_SZ, (BYTE *)face->file,
1527 (strlenW(face->file) + 1) * sizeof(WCHAR));
1529 RegSetValueExW(hkey_face, face_full_name_value, 0, REG_SZ, (BYTE*)face->FullName,
1530 (strlenW(face->FullName) + 1) * sizeof(WCHAR));
1532 reg_save_dword(hkey_face, face_index_value, face->face_index);
1533 reg_save_dword(hkey_face, face_ntmflags_value, face->ntmFlags);
1534 reg_save_dword(hkey_face, face_version_value, face->font_version);
1535 if (face->vertical) reg_save_dword(hkey_face, face_vertical_value, face->vertical);
1536 if (face->aa_flags) reg_save_dword(hkey_face, face_aa_value, face->aa_flags);
1538 RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs));
1542 reg_save_dword(hkey_face, face_height_value, face->size.height);
1543 reg_save_dword(hkey_face, face_width_value, face->size.width);
1544 reg_save_dword(hkey_face, face_size_value, face->size.size);
1545 reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem);
1546 reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem);
1547 reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading);
1549 RegCloseKey(hkey_face);
1550 RegCloseKey(hkey_family);
1551 RegCloseKey(hkey_font_cache);
1554 static WCHAR *prepend_at(WCHAR *family)
1561 str = HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR) * (strlenW(family) + 2));
1563 strcpyW(str + 1, family);
1564 HeapFree(GetProcessHeap(), 0, family);
1568 static void get_family_names( FT_Face ft_face, WCHAR **name, WCHAR **english, BOOL vertical )
1570 *english = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1571 if (!*english) *english = towstr( CP_ACP, ft_face->family_name );
1573 *name = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, GetSystemDefaultLCID() );
1579 else if (!strcmpiW( *name, *english ))
1581 HeapFree( GetProcessHeap(), 0, *english );
1587 *name = prepend_at( *name );
1588 *english = prepend_at( *english );
1592 static Family *get_family( FT_Face ft_face, BOOL vertical )
1595 WCHAR *name, *english_name;
1597 get_family_names( ft_face, &name, &english_name, vertical );
1599 family = find_family_from_name( name );
1603 family = create_family( name, english_name );
1604 list_add_tail( &font_list, &family->entry );
1608 FontSubst *subst = HeapAlloc( GetProcessHeap(), 0, sizeof(*subst) );
1609 subst->from.name = strdupW( english_name );
1610 subst->from.charset = -1;
1611 subst->to.name = strdupW( name );
1612 subst->to.charset = -1;
1613 add_font_subst( &font_subst_list, subst, 0 );
1618 HeapFree( GetProcessHeap(), 0, name );
1619 HeapFree( GetProcessHeap(), 0, english_name );
1625 static inline FT_Fixed get_font_version( FT_Face ft_face )
1627 FT_Fixed version = 0;
1630 header = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head );
1631 if (header) version = header->Font_Revision;
1636 static inline DWORD get_ntm_flags( FT_Face ft_face )
1639 FT_ULong table_size = 0;
1641 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) flags |= NTM_ITALIC;
1642 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD) flags |= NTM_BOLD;
1643 if (flags == 0) flags = NTM_REGULAR;
1645 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL, &table_size ))
1646 flags |= NTM_PS_OPENTYPE;
1651 static inline int get_bitmap_internal_leading( FT_Face ft_face )
1653 int internal_leading = 0;
1654 FT_WinFNT_HeaderRec winfnt_header;
1656 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1657 internal_leading = winfnt_header.internal_leading;
1659 return internal_leading;
1662 static inline void get_fontsig( FT_Face ft_face, FONTSIGNATURE *fs )
1667 FT_WinFNT_HeaderRec winfnt_header;
1670 memset( fs, 0, sizeof(*fs) );
1672 os2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 );
1675 fs->fsUsb[0] = os2->ulUnicodeRange1;
1676 fs->fsUsb[1] = os2->ulUnicodeRange2;
1677 fs->fsUsb[2] = os2->ulUnicodeRange3;
1678 fs->fsUsb[3] = os2->ulUnicodeRange4;
1680 if (os2->version == 0)
1682 if (pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
1683 fs->fsCsb[0] = FS_LATIN1;
1685 fs->fsCsb[0] = FS_SYMBOL;
1689 fs->fsCsb[0] = os2->ulCodePageRange1;
1690 fs->fsCsb[1] = os2->ulCodePageRange2;
1695 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1697 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1698 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1699 if (TranslateCharsetInfo( (DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET ))
1704 if (fs->fsCsb[0] == 0)
1706 /* let's see if we can find any interesting cmaps */
1707 for (i = 0; i < ft_face->num_charmaps; i++)
1709 switch (ft_face->charmaps[i]->encoding)
1711 case FT_ENCODING_UNICODE:
1712 case FT_ENCODING_APPLE_ROMAN:
1713 fs->fsCsb[0] |= FS_LATIN1;
1715 case FT_ENCODING_MS_SYMBOL:
1716 fs->fsCsb[0] |= FS_SYMBOL;
1725 #define ADDFONT_EXTERNAL_FONT 0x01
1726 #define ADDFONT_FORCE_BITMAP 0x02
1727 #define ADDFONT_ADD_TO_CACHE 0x04
1728 #define ADDFONT_AA_FLAGS(flags) ((flags) << 16)
1730 static Face *create_face( FT_Face ft_face, FT_Long face_index, const char *file, void *font_data_ptr, DWORD font_data_size,
1731 DWORD flags, BOOL vertical, DWORD aa_flags )
1733 Face *face = HeapAlloc( GetProcessHeap(), 0, sizeof(*face) );
1734 My_FT_Bitmap_Size *size = (My_FT_Bitmap_Size *)ft_face->available_sizes;
1736 face->StyleName = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
1737 if (!face->StyleName)
1738 face->StyleName = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1739 if (!face->StyleName)
1741 face->StyleName = towstr( CP_ACP, ft_face->style_name );
1744 face->FullName = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
1745 if (!face->FullName)
1746 face->FullName = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1748 face->FullName = prepend_at( face->FullName );
1752 face->file = towstr( CP_UNIXCP, file );
1753 face->font_data_ptr = NULL;
1754 face->font_data_size = 0;
1759 face->font_data_ptr = font_data_ptr;
1760 face->font_data_size = font_data_size;
1763 face->face_index = face_index;
1764 get_fontsig( ft_face, &face->fs );
1765 face->ntmFlags = get_ntm_flags( ft_face );
1766 face->font_version = get_font_version( ft_face );
1768 if (FT_IS_SCALABLE( ft_face ))
1770 memset( &face->size, 0, sizeof(face->size) );
1771 face->scalable = TRUE;
1775 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1776 size->height, size->width, size->size >> 6,
1777 size->x_ppem >> 6, size->y_ppem >> 6);
1778 face->size.height = size->height;
1779 face->size.width = size->width;
1780 face->size.size = size->size;
1781 face->size.x_ppem = size->x_ppem;
1782 face->size.y_ppem = size->y_ppem;
1783 face->size.internal_leading = get_bitmap_internal_leading( ft_face );
1784 face->scalable = FALSE;
1787 face->vertical = vertical;
1788 face->external = (flags & ADDFONT_EXTERNAL_FONT) != 0;
1789 face->aa_flags = aa_flags;
1790 face->family = NULL;
1791 face->cached_enum_data = NULL;
1793 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1794 face->fs.fsCsb[0], face->fs.fsCsb[1],
1795 face->fs.fsUsb[0], face->fs.fsUsb[1],
1796 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1801 static void AddFaceToList(FT_Face ft_face, const char *file, void *font_data_ptr, DWORD font_data_size,
1802 FT_Long face_index, DWORD flags, BOOL vertical, DWORD aa_flags )
1807 face = create_face( ft_face, face_index, file, font_data_ptr, font_data_size, flags, vertical, aa_flags );
1808 family = get_family( ft_face, vertical );
1809 if (!insert_face_in_family_list( face, family ))
1815 if (flags & ADDFONT_ADD_TO_CACHE)
1816 add_face_to_cache( face );
1818 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1819 debugstr_w(face->StyleName));
1822 static FT_Face new_ft_face( const char *file, void *font_data_ptr, DWORD font_data_size,
1823 FT_Long face_index, BOOL allow_bitmap )
1831 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1832 err = pFT_New_Face(library, file, face_index, &ft_face);
1836 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1837 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1842 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1846 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1847 if (!FT_IS_SCALABLE( ft_face ) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0)))
1849 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1853 if (!FT_IS_SFNT( ft_face ))
1855 if (FT_IS_SCALABLE( ft_face ) || !allow_bitmap )
1857 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1863 if (!(pOS2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 )) ||
1864 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_hhea ) ||
1865 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head ))
1867 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1868 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1872 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1873 we don't want to load these. */
1874 if (!memcmp( pOS2->achVendID, "Wine", sizeof(pOS2->achVendID) ))
1878 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len ))
1880 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1886 if (!ft_face->family_name || !ft_face->style_name)
1888 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1894 pFT_Done_Face( ft_face );
1898 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, DWORD flags)
1901 FT_Long face_index = 0, num_faces;
1903 DWORD aa_flags = HIWORD( flags );
1905 if (!aa_flags) aa_flags = default_aa_flags;
1907 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1908 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1910 #ifdef HAVE_CARBON_CARBON_H
1913 char **mac_list = expand_mac_font(file);
1916 BOOL had_one = FALSE;
1918 for(cursor = mac_list; *cursor; cursor++)
1921 AddFontToList(*cursor, NULL, 0, flags);
1922 HeapFree(GetProcessHeap(), 0, *cursor);
1924 HeapFree(GetProcessHeap(), 0, mac_list);
1929 #endif /* HAVE_CARBON_CARBON_H */
1932 ft_face = new_ft_face( file, font_data_ptr, font_data_size, face_index, flags & ADDFONT_FORCE_BITMAP );
1933 if (!ft_face) return 0;
1935 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1937 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1938 pFT_Done_Face(ft_face);
1942 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags, FALSE, aa_flags);
1945 if (FT_HAS_VERTICAL(ft_face))
1947 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags, TRUE, aa_flags);
1951 num_faces = ft_face->num_faces;
1952 pFT_Done_Face(ft_face);
1953 } while(num_faces > ++face_index);
1957 static void DumpFontList(void)
1962 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
1963 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1964 LIST_FOR_EACH_ENTRY( face, &family->faces, Face, entry ) {
1965 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1967 TRACE(" %d", face->size.height);
1974 /***********************************************************
1975 * The replacement list is a way to map an entire font
1976 * family onto another family. For example adding
1978 * [HKCU\Software\Wine\Fonts\Replacements]
1979 * "Wingdings"="Winedings"
1981 * would enumerate the Winedings font both as Winedings and
1982 * Wingdings. However if a real Wingdings font is present the
1983 * replacement does not take place.
1986 static void LoadReplaceList(void)
1989 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1993 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1994 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1996 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1997 &valuelen, &datalen, NULL, NULL);
1999 valuelen++; /* returned value doesn't include room for '\0' */
2000 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2001 data = HeapAlloc(GetProcessHeap(), 0, datalen);
2005 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
2006 &dlen) == ERROR_SUCCESS) {
2007 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
2008 /* "NewName"="Oldname" */
2009 if(!find_family_from_any_name(value))
2011 Family * const family = find_family_from_any_name(data);
2014 Family * const new_family = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family));
2015 if (new_family != NULL)
2017 TRACE("mapping %s to %s\n", debugstr_w(data), debugstr_w(value));
2018 new_family->FamilyName = strdupW(value);
2019 new_family->EnglishName = NULL;
2020 list_init(&new_family->faces);
2021 new_family->replacement = &family->faces;
2022 list_add_tail(&font_list, &new_family->entry);
2027 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(data));
2032 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value));
2034 /* reset dlen and vlen */
2038 HeapFree(GetProcessHeap(), 0, data);
2039 HeapFree(GetProcessHeap(), 0, value);
2044 static const WCHAR *font_links_list[] =
2046 Lucida_Sans_Unicode,
2047 Microsoft_Sans_Serif,
2051 static const struct font_links_defaults_list
2053 /* Keyed off substitution for "MS Shell Dlg" */
2054 const WCHAR *shelldlg;
2055 /* Maximum of four substitutes, plus terminating NULL pointer */
2056 const WCHAR *substitutes[5];
2057 } font_links_defaults_list[] =
2059 /* Non East-Asian */
2060 { Tahoma, /* FIXME unverified ordering */
2061 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2063 /* Below lists are courtesy of
2064 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2068 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2070 /* Chinese Simplified */
2072 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2076 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2078 /* Chinese Traditional */
2080 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2085 static SYSTEM_LINKS *find_font_link(const WCHAR *name)
2087 SYSTEM_LINKS *font_link;
2089 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2091 if(!strcmpiW(font_link->font_name, name))
2098 static void populate_system_links(const WCHAR *name, const WCHAR *const *values)
2109 SYSTEM_LINKS *font_link;
2111 psub = get_font_subst(&font_subst_list, name, -1);
2112 /* Don't store fonts that are only substitutes for other fonts */
2115 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name));
2119 font_link = find_font_link(name);
2120 if (font_link == NULL)
2122 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2123 font_link->font_name = strdupW(name);
2124 list_init(&font_link->links);
2125 list_add_tail(&system_links, &font_link->entry);
2128 memset(&font_link->fs, 0, sizeof font_link->fs);
2129 for (i = 0; values[i] != NULL; i++)
2131 const struct list *face_list;
2132 CHILD_FONT *child_font;
2135 if (!strcmpiW(name,value))
2137 psub = get_font_subst(&font_subst_list, value, -1);
2139 value = psub->to.name;
2140 family = find_family_from_name(value);
2144 /* Use first extant filename for this Family */
2145 face_list = get_face_list_from_family(family);
2146 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
2150 file = strrchrW(face->file, '/');
2159 face = find_face_from_filename(file, value);
2162 TRACE("Unable to find file %s face name %s\n", debugstr_w(file), debugstr_w(value));
2166 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2167 child_font->face = face;
2168 child_font->font = NULL;
2169 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2170 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2171 TRACE("Adding file %s index %ld\n", debugstr_w(child_font->face->file),
2172 child_font->face->face_index);
2173 list_add_tail(&font_link->links, &child_font->entry);
2175 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(file));
2181 /*************************************************************
2184 static BOOL init_system_links(void)
2188 DWORD type, max_val, max_data, val_len, data_len, index;
2189 WCHAR *value, *data;
2190 WCHAR *entry, *next;
2191 SYSTEM_LINKS *font_link, *system_font_link;
2192 CHILD_FONT *child_font;
2193 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
2194 static const WCHAR System[] = {'S','y','s','t','e','m',0};
2195 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2200 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
2202 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
2203 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
2204 data = HeapAlloc(GetProcessHeap(), 0, max_data);
2205 val_len = max_val + 1;
2206 data_len = max_data;
2208 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
2210 psub = get_font_subst(&font_subst_list, value, -1);
2211 /* Don't store fonts that are only substitutes for other fonts */
2214 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
2217 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2218 font_link->font_name = strdupW(value);
2219 memset(&font_link->fs, 0, sizeof font_link->fs);
2220 list_init(&font_link->links);
2221 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
2224 CHILD_FONT *child_font;
2226 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
2228 next = entry + strlenW(entry) + 1;
2230 face_name = strchrW(entry, ',');
2234 while(isspaceW(*face_name))
2237 psub = get_font_subst(&font_subst_list, face_name, -1);
2239 face_name = psub->to.name;
2241 face = find_face_from_filename(entry, face_name);
2244 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
2248 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2249 child_font->face = face;
2250 child_font->font = NULL;
2251 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2252 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2253 TRACE("Adding file %s index %ld\n",
2254 debugstr_w(child_font->face->file), child_font->face->face_index);
2255 list_add_tail(&font_link->links, &child_font->entry);
2257 list_add_tail(&system_links, &font_link->entry);
2259 val_len = max_val + 1;
2260 data_len = max_data;
2263 HeapFree(GetProcessHeap(), 0, value);
2264 HeapFree(GetProcessHeap(), 0, data);
2269 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2271 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2275 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2277 const FontSubst *psub2;
2278 psub2 = get_font_subst(&font_subst_list, font_links_defaults_list[i].shelldlg, -1);
2280 if ((!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name) || (psub2 && !strcmpiW(psub2->to.name,psub->to.name))))
2282 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2283 populate_system_links(font_links_list[j], font_links_defaults_list[i].substitutes);
2285 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2286 populate_system_links(psub->to.name, font_links_defaults_list[i].substitutes);
2288 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2290 populate_system_links(font_links_defaults_list[i].substitutes[0], NULL);
2296 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2299 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2300 system_font_link->font_name = strdupW(System);
2301 memset(&system_font_link->fs, 0, sizeof system_font_link->fs);
2302 list_init(&system_font_link->links);
2304 face = find_face_from_filename(tahoma_ttf, Tahoma);
2307 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2308 child_font->face = face;
2309 child_font->font = NULL;
2310 system_font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2311 system_font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2312 TRACE("Found Tahoma in %s index %ld\n",
2313 debugstr_w(child_font->face->file), child_font->face->face_index);
2314 list_add_tail(&system_font_link->links, &child_font->entry);
2316 font_link = find_font_link(Tahoma);
2317 if (font_link != NULL)
2319 CHILD_FONT *font_link_entry;
2320 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2322 CHILD_FONT *new_child;
2323 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2324 new_child->face = font_link_entry->face;
2325 new_child->font = NULL;
2326 system_font_link->fs.fsCsb[0] |= font_link_entry->face->fs.fsCsb[0];
2327 system_font_link->fs.fsCsb[1] |= font_link_entry->face->fs.fsCsb[1];
2328 list_add_tail(&system_font_link->links, &new_child->entry);
2331 list_add_tail(&system_links, &system_font_link->entry);
2335 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2338 struct dirent *dent;
2339 char path[MAX_PATH];
2341 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2343 dir = opendir(dirname);
2345 WARN("Can't open directory %s\n", debugstr_a(dirname));
2348 while((dent = readdir(dir)) != NULL) {
2349 struct stat statbuf;
2351 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2354 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2356 sprintf(path, "%s/%s", dirname, dent->d_name);
2358 if(stat(path, &statbuf) == -1)
2360 WARN("Can't stat %s\n", debugstr_a(path));
2363 if(S_ISDIR(statbuf.st_mode))
2364 ReadFontDir(path, external_fonts);
2367 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2368 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2369 AddFontToList(path, NULL, 0, addfont_flags);
2376 #ifdef SONAME_LIBFONTCONFIG
2378 static BOOL fontconfig_enabled;
2380 static UINT parse_aa_pattern( FcPattern *pattern )
2386 if (pFcPatternGetBool( pattern, FC_ANTIALIAS, 0, &antialias ) == FcResultMatch)
2387 aa_flags = antialias ? GGO_GRAY4_BITMAP : GGO_BITMAP;
2389 if (pFcPatternGetInteger( pattern, FC_RGBA, 0, &rgba ) == FcResultMatch)
2393 case FC_RGBA_RGB: aa_flags = WINE_GGO_HRGB_BITMAP; break;
2394 case FC_RGBA_BGR: aa_flags = WINE_GGO_HBGR_BITMAP; break;
2395 case FC_RGBA_VRGB: aa_flags = WINE_GGO_VRGB_BITMAP; break;
2396 case FC_RGBA_VBGR: aa_flags = WINE_GGO_VBGR_BITMAP; break;
2397 case FC_RGBA_NONE: aa_flags = GGO_GRAY4_BITMAP; break;
2403 static void init_fontconfig(void)
2405 void *fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2409 TRACE("Wine cannot find the fontconfig library (%s).\n", SONAME_LIBFONTCONFIG);
2413 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); return;}
2414 LOAD_FUNCPTR(FcConfigSubstitute);
2415 LOAD_FUNCPTR(FcFontList);
2416 LOAD_FUNCPTR(FcFontSetDestroy);
2417 LOAD_FUNCPTR(FcInit);
2418 LOAD_FUNCPTR(FcObjectSetAdd);
2419 LOAD_FUNCPTR(FcObjectSetCreate);
2420 LOAD_FUNCPTR(FcObjectSetDestroy);
2421 LOAD_FUNCPTR(FcPatternCreate);
2422 LOAD_FUNCPTR(FcPatternDestroy);
2423 LOAD_FUNCPTR(FcPatternGetBool);
2424 LOAD_FUNCPTR(FcPatternGetInteger);
2425 LOAD_FUNCPTR(FcPatternGetString);
2430 FcPattern *pattern = pFcPatternCreate();
2431 pFcConfigSubstitute( NULL, pattern, FcMatchFont );
2432 default_aa_flags = parse_aa_pattern( pattern );
2433 pFcPatternDestroy( pattern );
2434 TRACE( "enabled, default flags = %x\n", default_aa_flags );
2435 fontconfig_enabled = TRUE;
2439 static void load_fontconfig_fonts(void)
2448 if (!fontconfig_enabled) return;
2450 pat = pFcPatternCreate();
2451 os = pFcObjectSetCreate();
2452 pFcObjectSetAdd(os, FC_FILE);
2453 pFcObjectSetAdd(os, FC_SCALABLE);
2454 pFcObjectSetAdd(os, FC_ANTIALIAS);
2455 pFcObjectSetAdd(os, FC_RGBA);
2456 fontset = pFcFontList(NULL, pat, os);
2457 if(!fontset) return;
2458 for(i = 0; i < fontset->nfont; i++) {
2462 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2465 pFcConfigSubstitute( NULL, fontset->fonts[i], FcMatchFont );
2467 /* We're just interested in OT/TT fonts for now, so this hack just
2468 picks up the scalable fonts without extensions .pf[ab] to save time
2469 loading every other font */
2471 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2473 TRACE("not scalable\n");
2477 aa_flags = parse_aa_pattern( fontset->fonts[i] );
2478 TRACE("fontconfig: %s aa %x\n", file, aa_flags);
2480 len = strlen( file );
2481 if(len < 4) continue;
2482 ext = &file[ len - 3 ];
2483 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2484 AddFontToList(file, NULL, 0,
2485 ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE | ADDFONT_AA_FLAGS(aa_flags) );
2487 pFcFontSetDestroy(fontset);
2488 pFcObjectSetDestroy(os);
2489 pFcPatternDestroy(pat);
2492 #elif defined(HAVE_CARBON_CARBON_H)
2494 static void load_mac_font_callback(const void *value, void *context)
2496 CFStringRef pathStr = value;
2500 len = CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr);
2501 path = HeapAlloc(GetProcessHeap(), 0, len);
2502 if (path && CFStringGetFileSystemRepresentation(pathStr, path, len))
2504 TRACE("font file %s\n", path);
2505 AddFontToList(path, NULL, 0, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2507 HeapFree(GetProcessHeap(), 0, path);
2510 static void load_mac_fonts(void)
2512 CFStringRef removeDupesKey;
2513 CFBooleanRef removeDupesValue;
2514 CFDictionaryRef options;
2515 CTFontCollectionRef col;
2517 CFMutableSetRef paths;
2520 removeDupesKey = kCTFontCollectionRemoveDuplicatesOption;
2521 removeDupesValue = kCFBooleanTrue;
2522 options = CFDictionaryCreate(NULL, (const void**)&removeDupesKey, (const void**)&removeDupesValue, 1,
2523 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2524 col = CTFontCollectionCreateFromAvailableFonts(options);
2525 if (options) CFRelease(options);
2528 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
2532 descs = CTFontCollectionCreateMatchingFontDescriptors(col);
2536 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
2540 paths = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
2543 WARN("CFSetCreateMutable failed\n");
2548 for (i = 0; i < CFArrayGetCount(descs); i++)
2550 CTFontDescriptorRef desc;
2559 desc = CFArrayGetValueAtIndex(descs, i);
2561 /* CTFontDescriptor doesn't support kCTFontURLAttribute until 10.6, so
2562 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
2563 font = CTFontCreateWithFontDescriptor(desc, 0, NULL);
2564 if (!font) continue;
2566 atsFont = CTFontGetPlatformFont(font, NULL);
2573 status = ATSFontGetFileReference(atsFont, &fsref);
2575 if (status != noErr) continue;
2577 url = CFURLCreateFromFSRef(NULL, &fsref);
2580 ext = CFURLCopyPathExtension(url);
2583 BOOL skip = (CFStringCompare(ext, CFSTR("pfa"), kCFCompareCaseInsensitive) == kCFCompareEqualTo ||
2584 CFStringCompare(ext, CFSTR("pfb"), kCFCompareCaseInsensitive) == kCFCompareEqualTo);
2593 path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
2595 if (!path) continue;
2597 CFSetAddValue(paths, path);
2603 CFSetApplyFunction(paths, load_mac_font_callback, NULL);
2609 static BOOL load_font_from_data_dir(LPCWSTR file)
2612 const char *data_dir = wine_get_data_dir();
2614 if (!data_dir) data_dir = wine_get_build_dir();
2621 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
2623 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
2625 strcpy(unix_name, data_dir);
2626 strcat(unix_name, "/fonts/");
2628 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
2630 EnterCriticalSection( &freetype_cs );
2631 ret = AddFontToList(unix_name, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2632 LeaveCriticalSection( &freetype_cs );
2633 HeapFree(GetProcessHeap(), 0, unix_name);
2638 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
2640 static const WCHAR slashW[] = {'\\','\0'};
2642 WCHAR windowsdir[MAX_PATH];
2645 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2646 strcatW(windowsdir, fontsW);
2647 strcatW(windowsdir, slashW);
2648 strcatW(windowsdir, file);
2649 if ((unixname = wine_get_unix_file_name(windowsdir))) {
2650 EnterCriticalSection( &freetype_cs );
2651 ret = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP);
2652 LeaveCriticalSection( &freetype_cs );
2653 HeapFree(GetProcessHeap(), 0, unixname);
2658 static void load_system_fonts(void)
2661 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
2662 const WCHAR * const *value;
2664 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2667 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
2668 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2669 strcatW(windowsdir, fontsW);
2670 for(value = SystemFontValues; *value; value++) {
2671 dlen = sizeof(data);
2672 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
2676 sprintfW(pathW, fmtW, windowsdir, data);
2677 if((unixname = wine_get_unix_file_name(pathW))) {
2678 added = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2679 HeapFree(GetProcessHeap(), 0, unixname);
2682 load_font_from_data_dir(data);
2689 /*************************************************************
2691 * This adds registry entries for any externally loaded fonts
2692 * (fonts from fontconfig or FontDirs). It also deletes entries
2693 * of no longer existing fonts.
2696 static void update_reg_entries(void)
2698 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2704 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2706 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2707 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2708 ERR("Can't create Windows font reg key\n");
2712 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2713 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2714 ERR("Can't create Windows font reg key\n");
2718 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
2719 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
2720 ERR("Can't create external font reg key\n");
2724 /* enumerate the fonts and add external ones to the two keys */
2726 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
2727 LIST_FOR_EACH_ENTRY( face, &family->faces, Face, entry ) {
2729 if(!face->external) continue;
2733 len = strlenW(face->FullName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2734 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2735 strcpyW(valueW, face->FullName);
2739 len = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2740 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2741 strcpyW(valueW, family->FamilyName);
2744 buffer = strWtoA( CP_UNIXCP, face->file );
2745 path = wine_get_dos_file_name( buffer );
2746 HeapFree( GetProcessHeap(), 0, buffer );
2750 else if ((file = strrchrW(face->file, '/')))
2755 len = strlenW(file) + 1;
2756 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2757 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2758 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2760 HeapFree(GetProcessHeap(), 0, path);
2761 HeapFree(GetProcessHeap(), 0, valueW);
2765 if(external_key) RegCloseKey(external_key);
2766 if(win9x_key) RegCloseKey(win9x_key);
2767 if(winnt_key) RegCloseKey(winnt_key);
2771 static void delete_external_font_keys(void)
2773 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2774 DWORD dlen, vlen, datalen, valuelen, i, type;
2778 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2779 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2780 ERR("Can't create Windows font reg key\n");
2784 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2785 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2786 ERR("Can't create Windows font reg key\n");
2790 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2791 ERR("Can't create external font reg key\n");
2795 /* Delete all external fonts added last time */
2797 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2798 &valuelen, &datalen, NULL, NULL);
2799 valuelen++; /* returned value doesn't include room for '\0' */
2800 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2801 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2803 dlen = datalen * sizeof(WCHAR);
2806 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2807 &dlen) == ERROR_SUCCESS) {
2809 RegDeleteValueW(winnt_key, valueW);
2810 RegDeleteValueW(win9x_key, valueW);
2811 /* reset dlen and vlen */
2815 HeapFree(GetProcessHeap(), 0, data);
2816 HeapFree(GetProcessHeap(), 0, valueW);
2818 /* Delete the old external fonts key */
2819 RegCloseKey(external_key);
2820 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2823 if(win9x_key) RegCloseKey(win9x_key);
2824 if(winnt_key) RegCloseKey(winnt_key);
2827 /*************************************************************
2828 * WineEngAddFontResourceEx
2831 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2837 if (ft_handle) /* do it only if we have freetype up and running */
2842 FIXME("Ignoring flags %x\n", flags);
2844 if((unixname = wine_get_unix_file_name(file)))
2846 DWORD addfont_flags = ADDFONT_FORCE_BITMAP;
2848 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
2849 EnterCriticalSection( &freetype_cs );
2850 ret = AddFontToList(unixname, NULL, 0, addfont_flags);
2851 LeaveCriticalSection( &freetype_cs );
2852 HeapFree(GetProcessHeap(), 0, unixname);
2854 if (!ret && !strchrW(file, '\\')) {
2855 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2856 ret = load_font_from_winfonts_dir(file);
2858 /* Try in datadir/fonts (or builddir/fonts),
2859 * needed for Magic the Gathering Online
2861 ret = load_font_from_data_dir(file);
2868 /*************************************************************
2869 * WineEngAddFontMemResourceEx
2872 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2876 if (ft_handle) /* do it only if we have freetype up and running */
2878 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2880 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2881 memcpy(pFontCopy, pbFont, cbFont);
2883 EnterCriticalSection( &freetype_cs );
2884 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, ADDFONT_FORCE_BITMAP);
2885 LeaveCriticalSection( &freetype_cs );
2889 TRACE("AddFontToList failed\n");
2890 HeapFree(GetProcessHeap(), 0, pFontCopy);
2893 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2894 * For now return something unique but quite random
2896 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2897 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2904 /*************************************************************
2905 * WineEngRemoveFontResourceEx
2908 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2911 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
2915 static char *get_ttf_file_name( LPCWSTR font_file, LPCWSTR font_path )
2921 if (!font_file) return NULL;
2923 file_len = strlenW( font_file );
2925 if (font_path && font_path[0])
2927 int path_len = strlenW( font_path );
2928 fullname = HeapAlloc( GetProcessHeap(), 0, (file_len + path_len + 2) * sizeof(WCHAR) );
2929 if (!fullname) return NULL;
2930 memcpy( fullname, font_path, path_len * sizeof(WCHAR) );
2931 fullname[path_len] = '\\';
2932 memcpy( fullname + path_len + 1, font_file, (file_len + 1) * sizeof(WCHAR) );
2936 int len = GetFullPathNameW( font_file, 0, NULL, NULL );
2937 if (!len) return NULL;
2938 fullname = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
2939 if (!fullname) return NULL;
2940 GetFullPathNameW( font_file, len, fullname, NULL );
2943 unix_name = wine_get_unix_file_name( fullname );
2944 HeapFree( GetProcessHeap(), 0, fullname );
2948 #include <pshpack1.h>
2951 WORD num_of_resources;
2955 CHAR dfCopyright[60];
2961 WORD dfInternalLeading;
2962 WORD dfExternalLeading;
2970 BYTE dfPitchAndFamily;
2981 CHAR szFaceName[LF_FACESIZE];
2984 #include <poppack.h>
2986 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
2987 NEWTEXTMETRICEXW *pntm, LPDWORD ptype);
2989 static BOOL get_fontdir( const char *unix_name, struct fontdir *fd )
2991 FT_Face ft_face = new_ft_face( unix_name, NULL, 0, 0, FALSE );
2994 WCHAR *name, *english_name;
2996 NEWTEXTMETRICEXW ntm;
2999 if (!ft_face) return FALSE;
3000 face = create_face( ft_face, 0, unix_name, NULL, 0, 0, FALSE, 0 );
3001 get_family_names( ft_face, &name, &english_name, FALSE );
3002 family = create_family( name, english_name );
3003 insert_face_in_family_list( face, family );
3004 pFT_Done_Face( ft_face );
3006 GetEnumStructs( face, &elf, &ntm, &type );
3007 free_family( family );
3009 if ((type & TRUETYPE_FONTTYPE) == 0) return FALSE;
3011 memset( fd, 0, sizeof(*fd) );
3013 fd->num_of_resources = 1;
3015 fd->dfVersion = 0x200;
3016 fd->dfSize = sizeof(*fd);
3017 strcpy( fd->dfCopyright, "Wine fontdir" );
3018 fd->dfType = 0x4003; /* 0x0080 set if private */
3019 fd->dfPoints = ntm.ntmTm.ntmSizeEM;
3021 fd->dfHorizRes = 72;
3022 fd->dfAscent = ntm.ntmTm.tmAscent;
3023 fd->dfInternalLeading = ntm.ntmTm.tmInternalLeading;
3024 fd->dfExternalLeading = ntm.ntmTm.tmExternalLeading;
3025 fd->dfItalic = ntm.ntmTm.tmItalic;
3026 fd->dfUnderline = ntm.ntmTm.tmUnderlined;
3027 fd->dfStrikeOut = ntm.ntmTm.tmStruckOut;
3028 fd->dfWeight = ntm.ntmTm.tmWeight;
3029 fd->dfCharSet = ntm.ntmTm.tmCharSet;
3031 fd->dfPixHeight = ntm.ntmTm.tmHeight;
3032 fd->dfPitchAndFamily = ntm.ntmTm.tmPitchAndFamily;
3033 fd->dfAvgWidth = ntm.ntmTm.tmAveCharWidth;
3034 fd->dfMaxWidth = ntm.ntmTm.tmMaxCharWidth;
3035 fd->dfFirstChar = ntm.ntmTm.tmFirstChar;
3036 fd->dfLastChar = ntm.ntmTm.tmLastChar;
3037 fd->dfDefaultChar = ntm.ntmTm.tmDefaultChar;
3038 fd->dfBreakChar = ntm.ntmTm.tmBreakChar;
3039 fd->dfWidthBytes = 0;
3041 fd->dfFace = FIELD_OFFSET( struct fontdir, szFaceName );
3043 WideCharToMultiByte( CP_ACP, 0, elf.elfLogFont.lfFaceName, -1, fd->szFaceName, LF_FACESIZE, NULL, NULL );
3048 #define NE_FFLAGS_LIBMODULE 0x8000
3049 #define NE_OSFLAGS_WINDOWS 0x02
3051 static const char dos_string[0x40] = "This is a TrueType resource file";
3052 static const char FONTRES[] = {'F','O','N','T','R','E','S',':'};
3054 #include <pshpack2.h>
3075 struct ne_typeinfo fontdir_type;
3076 struct ne_nameinfo fontdir_name;
3077 struct ne_typeinfo scalable_type;
3078 struct ne_nameinfo scalable_name;
3080 BYTE fontdir_res_name[8];
3083 #include <poppack.h>
3085 static BOOL create_fot( const WCHAR *resource, const WCHAR *font_file, const struct fontdir *fontdir )
3089 DWORD size, written;
3091 BYTE import_name_len, res_name_len, non_res_name_len, font_file_len;
3092 char *font_fileA, *last_part, *ext;
3093 IMAGE_DOS_HEADER dos;
3094 IMAGE_OS2_HEADER ne =
3096 IMAGE_OS2_SIGNATURE, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE, 0,
3098 0, sizeof(ne), sizeof(ne), 0, 0, 0, 0,
3099 0, 4, 2, NE_OSFLAGS_WINDOWS, 0, 0, 0, 0, 0x300
3101 struct rsrc_tab rsrc_tab =
3105 { 0, 0, 0x0c50, 0x2c, 0 },
3107 { 0, 0, 0x0c50, 0x8001, 0 },
3109 { 7,'F','O','N','T','D','I','R'}
3112 memset( &dos, 0, sizeof(dos) );
3113 dos.e_magic = IMAGE_DOS_SIGNATURE;
3114 dos.e_lfanew = sizeof(dos) + sizeof(dos_string);
3116 /* import name is last part\0, resident name is last part without extension
3117 non-resident name is "FONTRES:" + lfFaceName */
3119 font_file_len = WideCharToMultiByte( CP_ACP, 0, font_file, -1, NULL, 0, NULL, NULL );
3120 font_fileA = HeapAlloc( GetProcessHeap(), 0, font_file_len );
3121 WideCharToMultiByte( CP_ACP, 0, font_file, -1, font_fileA, font_file_len, NULL, NULL );
3123 last_part = strrchr( font_fileA, '\\' );
3124 if (last_part) last_part++;
3125 else last_part = font_fileA;
3126 import_name_len = strlen( last_part ) + 1;
3128 ext = strchr( last_part, '.' );
3129 if (ext) res_name_len = ext - last_part;
3130 else res_name_len = import_name_len - 1;
3132 non_res_name_len = sizeof( FONTRES ) + strlen( fontdir->szFaceName );
3134 ne.ne_cbnrestab = 1 + non_res_name_len + 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
3135 ne.ne_restab = ne.ne_rsrctab + sizeof(rsrc_tab);
3136 ne.ne_modtab = ne.ne_imptab = ne.ne_restab + 1 + res_name_len + 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
3137 ne.ne_enttab = ne.ne_imptab + 1 + import_name_len; /* len + string */
3139 ne.ne_nrestab = ne.ne_enttab + ne.ne_cbenttab + 2 + dos.e_lfanew; /* there are 2 bytes of 0 after entry tab */
3141 rsrc_tab.scalable_name.off = (ne.ne_nrestab + ne.ne_cbnrestab + 0xf) >> 4;
3142 rsrc_tab.scalable_name.len = (font_file_len + 0xf) >> 4;
3143 rsrc_tab.fontdir_name.off = rsrc_tab.scalable_name.off + rsrc_tab.scalable_name.len;
3144 rsrc_tab.fontdir_name.len = (fontdir->dfSize + 0xf) >> 4;
3146 size = (rsrc_tab.fontdir_name.off + rsrc_tab.fontdir_name.len) << 4;
3147 start = ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
3151 HeapFree( GetProcessHeap(), 0, font_fileA );
3155 memcpy( ptr, &dos, sizeof(dos) );
3156 memcpy( ptr + sizeof(dos), dos_string, sizeof(dos_string) );
3157 memcpy( ptr + dos.e_lfanew, &ne, sizeof(ne) );
3159 ptr = start + dos.e_lfanew + ne.ne_rsrctab;
3160 memcpy( ptr, &rsrc_tab, sizeof(rsrc_tab) );
3162 ptr = start + dos.e_lfanew + ne.ne_restab;
3163 *ptr++ = res_name_len;
3164 memcpy( ptr, last_part, res_name_len );
3166 ptr = start + dos.e_lfanew + ne.ne_imptab;
3167 *ptr++ = import_name_len;
3168 memcpy( ptr, last_part, import_name_len );
3170 ptr = start + ne.ne_nrestab;
3171 *ptr++ = non_res_name_len;
3172 memcpy( ptr, FONTRES, sizeof(FONTRES) );
3173 memcpy( ptr + sizeof(FONTRES), fontdir->szFaceName, strlen( fontdir->szFaceName ) );
3175 ptr = start + (rsrc_tab.scalable_name.off << 4);
3176 memcpy( ptr, font_fileA, font_file_len );
3178 ptr = start + (rsrc_tab.fontdir_name.off << 4);
3179 memcpy( ptr, fontdir, fontdir->dfSize );
3181 file = CreateFileW( resource, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
3182 if (file != INVALID_HANDLE_VALUE)
3184 if (WriteFile( file, start, size, &written, NULL ) && written == size)
3186 CloseHandle( file );
3189 HeapFree( GetProcessHeap(), 0, start );
3190 HeapFree( GetProcessHeap(), 0, font_fileA );
3195 /*************************************************************
3196 * WineEngCreateScalableFontResource
3199 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
3200 LPCWSTR font_file, LPCWSTR font_path )
3202 char *unix_name = get_ttf_file_name( font_file, font_path );
3203 struct fontdir fontdir;
3206 if (!unix_name || !get_fontdir( unix_name, &fontdir ))
3207 SetLastError( ERROR_INVALID_PARAMETER );
3210 if (hidden) fontdir.dfType |= 0x80;
3211 ret = create_fot( resource, font_file, &fontdir );
3214 HeapFree( GetProcessHeap(), 0, unix_name );
3218 static const struct nls_update_font_list
3220 UINT ansi_cp, oem_cp;
3221 const char *oem, *fixed, *system;
3222 const char *courier, *serif, *small, *sserif_96, *sserif_120;
3223 /* these are for font substitutes */
3224 const char *shelldlg, *tmsrmn;
3225 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
3229 const char *from, *to;
3230 } arial_0, courier_new_0, times_new_roman_0;
3231 } nls_update_font_list[] =
3233 /* Latin 1 (United States) */
3234 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
3235 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3236 "Tahoma","Times New Roman",
3237 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3240 /* Latin 1 (Multilingual) */
3241 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
3242 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3243 "Tahoma","Times New Roman", /* FIXME unverified */
3244 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3247 /* Eastern Europe */
3248 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
3249 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
3250 "Tahoma","Times New Roman", /* FIXME unverified */
3251 "Fixedsys,238", "System,238",
3252 "Courier New,238", "MS Serif,238", "Small Fonts,238",
3253 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
3254 { "Arial CE,0", "Arial,238" },
3255 { "Courier New CE,0", "Courier New,238" },
3256 { "Times New Roman CE,0", "Times New Roman,238" }
3259 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
3260 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
3261 "Tahoma","Times New Roman", /* FIXME unverified */
3262 "Fixedsys,204", "System,204",
3263 "Courier New,204", "MS Serif,204", "Small Fonts,204",
3264 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
3265 { "Arial Cyr,0", "Arial,204" },
3266 { "Courier New Cyr,0", "Courier New,204" },
3267 { "Times New Roman Cyr,0", "Times New Roman,204" }
3270 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
3271 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
3272 "Tahoma","Times New Roman", /* FIXME unverified */
3273 "Fixedsys,161", "System,161",
3274 "Courier New,161", "MS Serif,161", "Small Fonts,161",
3275 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
3276 { "Arial Greek,0", "Arial,161" },
3277 { "Courier New Greek,0", "Courier New,161" },
3278 { "Times New Roman Greek,0", "Times New Roman,161" }
3281 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
3282 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
3283 "Tahoma","Times New Roman", /* FIXME unverified */
3284 "Fixedsys,162", "System,162",
3285 "Courier New,162", "MS Serif,162", "Small Fonts,162",
3286 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
3287 { "Arial Tur,0", "Arial,162" },
3288 { "Courier New Tur,0", "Courier New,162" },
3289 { "Times New Roman Tur,0", "Times New Roman,162" }
3292 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
3293 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
3294 "Tahoma","Times New Roman", /* FIXME unverified */
3295 "Fixedsys,177", "System,177",
3296 "Courier New,177", "MS Serif,177", "Small Fonts,177",
3297 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
3301 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
3302 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
3303 "Tahoma","Times New Roman", /* FIXME unverified */
3304 "Fixedsys,178", "System,178",
3305 "Courier New,178", "MS Serif,178", "Small Fonts,178",
3306 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
3310 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
3311 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
3312 "Tahoma","Times New Roman", /* FIXME unverified */
3313 "Fixedsys,186", "System,186",
3314 "Courier New,186", "MS Serif,186", "Small Fonts,186",
3315 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
3316 { "Arial Baltic,0", "Arial,186" },
3317 { "Courier New Baltic,0", "Courier New,186" },
3318 { "Times New Roman Baltic,0", "Times New Roman,186" }
3321 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
3322 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3323 "Tahoma","Times New Roman", /* FIXME unverified */
3324 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3328 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
3329 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
3330 "Tahoma","Times New Roman", /* FIXME unverified */
3331 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3335 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
3336 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
3337 "MS UI Gothic","MS Serif",
3338 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3341 /* Chinese Simplified */
3342 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
3343 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3344 "SimSun", "NSimSun",
3345 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3349 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
3350 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3352 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3355 /* Chinese Traditional */
3356 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
3357 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3358 "PMingLiU", "MingLiU",
3359 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3364 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
3366 return ( ansi_cp == 932 /* CP932 for Japanese */
3367 || ansi_cp == 936 /* CP936 for Chinese Simplified */
3368 || ansi_cp == 949 /* CP949 for Korean */
3369 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
3372 static inline HKEY create_fonts_NT_registry_key(void)
3376 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
3377 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3381 static inline HKEY create_fonts_9x_registry_key(void)
3385 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
3386 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3390 static inline HKEY create_config_fonts_registry_key(void)
3394 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
3395 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3399 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl, int dpi)
3401 const char *sserif = (dpi <= 108) ? fl->sserif_96 : fl->sserif_120;
3403 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
3404 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
3405 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)sserif, strlen(sserif)+1);
3406 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
3409 static void set_value_key(HKEY hkey, const char *name, const char *value)
3412 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
3414 RegDeleteValueA(hkey, name);
3417 static void update_font_info(void)
3419 static const WCHAR logpixels[] = { 'L','o','g','P','i','x','e','l','s',0 };
3420 char buf[40], cpbuf[40];
3423 UINT i, ansi_cp = 0, oem_cp = 0;
3424 DWORD screen_dpi = 96, font_dpi = 0;
3427 if (RegOpenKeyA(HKEY_LOCAL_MACHINE,
3428 "System\\CurrentControlSet\\Hardware Profiles\\Current\\Software\\Fonts",
3429 &hkey) == ERROR_SUCCESS)
3431 reg_load_dword(hkey, logpixels, &screen_dpi);
3435 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
3438 reg_load_dword(hkey, logpixels, &font_dpi);
3440 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3441 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
3442 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3443 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
3444 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
3446 /* Setup Default_Fallback usage for DBCS ANSI codepages */
3447 if (is_dbcs_ansi_cp(ansi_cp))
3448 use_default_fallback = TRUE;
3451 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
3453 if (!strcmp( buf, cpbuf ) && screen_dpi == font_dpi) /* already set correctly */
3458 TRACE("updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
3459 buf, font_dpi, ansi_cp, oem_cp, screen_dpi);
3461 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
3462 ansi_cp, oem_cp, screen_dpi);
3464 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
3465 RegSetValueExW(hkey, logpixels, 0, REG_DWORD, (const BYTE *)&screen_dpi, sizeof(screen_dpi));
3468 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
3472 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
3473 nls_update_font_list[i].oem_cp == oem_cp)
3475 hkey = create_config_fonts_registry_key();
3476 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
3477 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
3478 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
3481 hkey = create_fonts_NT_registry_key();
3482 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3485 hkey = create_fonts_9x_registry_key();
3486 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3489 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3491 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
3492 strlen(nls_update_font_list[i].shelldlg)+1);
3493 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
3494 strlen(nls_update_font_list[i].tmsrmn)+1);
3496 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
3497 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
3498 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
3499 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
3500 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
3501 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
3502 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
3503 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
3505 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
3506 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
3507 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
3515 /* Delete the FontSubstitutes from other locales */
3516 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3518 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
3519 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
3520 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
3526 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
3529 static BOOL init_freetype(void)
3531 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
3534 "Wine cannot find the FreeType font library. To enable Wine to\n"
3535 "use TrueType fonts please install a version of FreeType greater than\n"
3536 "or equal to 2.0.5.\n"
3537 "http://www.freetype.org\n");
3541 #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;}
3543 LOAD_FUNCPTR(FT_Done_Face)
3544 LOAD_FUNCPTR(FT_Get_Char_Index)
3545 LOAD_FUNCPTR(FT_Get_First_Char)
3546 LOAD_FUNCPTR(FT_Get_Module)
3547 LOAD_FUNCPTR(FT_Get_Next_Char)
3548 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
3549 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
3550 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
3551 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
3552 LOAD_FUNCPTR(FT_Init_FreeType)
3553 LOAD_FUNCPTR(FT_Library_Version)
3554 LOAD_FUNCPTR(FT_Load_Glyph)
3555 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
3556 LOAD_FUNCPTR(FT_Matrix_Multiply)
3557 #ifndef FT_MULFIX_INLINED
3558 LOAD_FUNCPTR(FT_MulFix)
3560 LOAD_FUNCPTR(FT_New_Face)
3561 LOAD_FUNCPTR(FT_New_Memory_Face)
3562 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
3563 LOAD_FUNCPTR(FT_Outline_Transform)
3564 LOAD_FUNCPTR(FT_Outline_Translate)
3565 LOAD_FUNCPTR(FT_Render_Glyph)
3566 LOAD_FUNCPTR(FT_Select_Charmap)
3567 LOAD_FUNCPTR(FT_Set_Charmap)
3568 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
3569 LOAD_FUNCPTR(FT_Vector_Transform)
3570 LOAD_FUNCPTR(FT_Vector_Unit)
3572 /* Don't warn if these ones are missing */
3573 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
3574 #ifdef HAVE_FREETYPE_FTLCDFIL_H
3575 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
3578 if(pFT_Init_FreeType(&library) != 0) {
3579 ERR("Can't init FreeType library\n");
3580 wine_dlclose(ft_handle, NULL, 0);
3584 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
3586 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
3587 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
3588 ((FT_Version.minor << 8) & 0x00ff00) |
3589 ((FT_Version.patch ) & 0x0000ff);
3591 font_driver = &freetype_funcs;
3596 "Wine cannot find certain functions that it needs inside the FreeType\n"
3597 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3598 "FreeType to at least version 2.1.4.\n"
3599 "http://www.freetype.org\n");
3600 wine_dlclose(ft_handle, NULL, 0);
3605 static void init_font_list(void)
3607 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
3608 static const WCHAR pathW[] = {'P','a','t','h',0};
3610 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
3611 WCHAR windowsdir[MAX_PATH];
3613 const char *data_dir;
3615 #ifdef SONAME_LIBFONTCONFIG
3619 delete_external_font_keys();
3621 /* load the system bitmap fonts */
3622 load_system_fonts();
3624 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3625 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3626 strcatW(windowsdir, fontsW);
3627 if((unixname = wine_get_unix_file_name(windowsdir)))
3629 ReadFontDir(unixname, FALSE);
3630 HeapFree(GetProcessHeap(), 0, unixname);
3633 /* load the system truetype fonts */
3634 data_dir = wine_get_data_dir();
3635 if (!data_dir) data_dir = wine_get_build_dir();
3636 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
3638 strcpy(unixname, data_dir);
3639 strcat(unixname, "/fonts/");
3640 ReadFontDir(unixname, TRUE);
3641 HeapFree(GetProcessHeap(), 0, unixname);
3644 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3645 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3646 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3648 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
3649 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
3650 &hkey) == ERROR_SUCCESS)
3652 LPWSTR data, valueW;
3653 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3654 &valuelen, &datalen, NULL, NULL);
3656 valuelen++; /* returned value doesn't include room for '\0' */
3657 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3658 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3661 dlen = datalen * sizeof(WCHAR);
3663 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
3664 &dlen) == ERROR_SUCCESS)
3666 if(data[0] && (data[1] == ':'))
3668 if((unixname = wine_get_unix_file_name(data)))
3670 AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3671 HeapFree(GetProcessHeap(), 0, unixname);
3674 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
3676 WCHAR pathW[MAX_PATH];
3677 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3680 sprintfW(pathW, fmtW, windowsdir, data);
3681 if((unixname = wine_get_unix_file_name(pathW)))
3683 added = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3684 HeapFree(GetProcessHeap(), 0, unixname);
3687 load_font_from_data_dir(data);
3689 /* reset dlen and vlen */
3694 HeapFree(GetProcessHeap(), 0, data);
3695 HeapFree(GetProcessHeap(), 0, valueW);
3699 #ifdef SONAME_LIBFONTCONFIG
3700 load_fontconfig_fonts();
3701 #elif defined(HAVE_CARBON_CARBON_H)
3705 /* then look in any directories that we've specified in the config file */
3706 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3707 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
3713 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
3715 len += sizeof(WCHAR);
3716 valueW = HeapAlloc( GetProcessHeap(), 0, len );
3717 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
3719 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
3720 valueA = HeapAlloc( GetProcessHeap(), 0, len );
3721 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
3722 TRACE( "got font path %s\n", debugstr_a(valueA) );
3727 LPSTR next = strchr( ptr, ':' );
3728 if (next) *next++ = 0;
3729 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
3730 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
3732 strcpy( unixname, home );
3733 strcat( unixname, ptr + 1 );
3734 ReadFontDir( unixname, TRUE );
3735 HeapFree( GetProcessHeap(), 0, unixname );
3738 ReadFontDir( ptr, TRUE );
3741 HeapFree( GetProcessHeap(), 0, valueA );
3743 HeapFree( GetProcessHeap(), 0, valueW );
3749 static BOOL move_to_front(const WCHAR *name)
3751 Family *family, *cursor2;
3752 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
3754 if(!strcmpiW(family->FamilyName, name))
3756 list_remove(&family->entry);
3757 list_add_head(&font_list, &family->entry);
3764 static BOOL set_default(const WCHAR **name_list)
3768 if (move_to_front(*name_list)) return TRUE;
3775 static void reorder_font_list(void)
3777 set_default( default_serif_list );
3778 set_default( default_fixed_list );
3779 set_default( default_sans_list );
3782 /*************************************************************
3785 * Initialize FreeType library and create a list of available faces
3787 BOOL WineEngInit(void)
3789 HKEY hkey_font_cache;
3793 /* update locale dependent font info in registry */
3796 if(!init_freetype()) return FALSE;
3798 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
3800 ERR("Failed to create font mutex\n");
3803 WaitForSingleObject(font_mutex, INFINITE);
3805 create_font_cache_key(&hkey_font_cache, &disposition);
3807 if(disposition == REG_CREATED_NEW_KEY)
3810 load_font_list_from_cache(hkey_font_cache);
3812 RegCloseKey(hkey_font_cache);
3814 reorder_font_list();
3821 if(disposition == REG_CREATED_NEW_KEY)
3822 update_reg_entries();
3824 init_system_links();
3826 ReleaseMutex(font_mutex);
3831 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
3834 TT_HoriHeader *pHori;
3838 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3839 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3841 if(height == 0) height = 16;
3843 /* Calc. height of EM square:
3845 * For +ve lfHeight we have
3846 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3847 * Re-arranging gives:
3848 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3850 * For -ve lfHeight we have
3852 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3853 * with il = winAscent + winDescent - units_per_em]
3858 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
3859 ppem = MulDiv(ft_face->units_per_EM, height,
3860 pHori->Ascender - pHori->Descender);
3862 ppem = MulDiv(ft_face->units_per_EM, height,
3863 pOS2->usWinAscent + pOS2->usWinDescent);
3871 static struct font_mapping *map_font_file( const char *name )
3873 struct font_mapping *mapping;
3877 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
3878 if (fstat( fd, &st ) == -1) goto error;
3880 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
3882 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
3884 mapping->refcount++;
3889 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
3892 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
3895 if (mapping->data == MAP_FAILED)
3897 HeapFree( GetProcessHeap(), 0, mapping );
3900 mapping->refcount = 1;
3901 mapping->dev = st.st_dev;
3902 mapping->ino = st.st_ino;
3903 mapping->size = st.st_size;
3904 list_add_tail( &mappings_list, &mapping->entry );
3912 static void unmap_font_file( struct font_mapping *mapping )
3914 if (!--mapping->refcount)
3916 list_remove( &mapping->entry );
3917 munmap( mapping->data, mapping->size );
3918 HeapFree( GetProcessHeap(), 0, mapping );
3922 static LONG load_VDMX(GdiFont*, LONG);
3924 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
3931 TRACE("%s/%p, %ld, %d x %d\n", debugstr_w(face->file), face->font_data_ptr, face->face_index, width, height);
3935 char *filename = strWtoA( CP_UNIXCP, face->file );
3936 font->mapping = map_font_file( filename );
3937 HeapFree( GetProcessHeap(), 0, filename );
3940 WARN("failed to map %s\n", debugstr_w(face->file));
3943 data_ptr = font->mapping->data;
3944 data_size = font->mapping->size;
3948 data_ptr = face->font_data_ptr;
3949 data_size = face->font_data_size;
3952 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3954 ERR("FT_New_Face rets %d\n", err);
3958 /* set it here, as load_VDMX needs it */
3959 font->ft_face = ft_face;
3961 if(FT_IS_SCALABLE(ft_face)) {
3962 /* load the VDMX table if we have one */
3963 font->ppem = load_VDMX(font, height);
3965 font->ppem = calc_ppem_for_height(ft_face, height);
3966 TRACE("height %d => ppem %d\n", height, font->ppem);
3968 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3969 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3971 font->ppem = height;
3972 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3973 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3979 static int get_nearest_charset(const WCHAR *family_name, Face *face, int *cp)
3981 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3982 a single face with the requested charset. The idea is to check if
3983 the selected font supports the current ANSI codepage, if it does
3984 return the corresponding charset, else return the first charset */
3987 int acp = GetACP(), i;
3991 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3993 const SYSTEM_LINKS *font_link;
3995 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
3996 return csi.ciCharset;
3998 font_link = find_font_link(family_name);
3999 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4000 return csi.ciCharset;
4003 for(i = 0; i < 32; i++) {
4005 if(face->fs.fsCsb[0] & fs0) {
4006 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
4008 return csi.ciCharset;
4011 FIXME("TCI failing on %x\n", fs0);
4015 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
4016 face->fs.fsCsb[0], debugstr_w(face->file));
4018 return DEFAULT_CHARSET;
4021 static GdiFont *alloc_font(void)
4023 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
4026 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
4027 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4029 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4030 ret->total_kern_pairs = (DWORD)-1;
4031 ret->kern_pairs = NULL;
4032 list_init(&ret->child_fonts);
4036 static void free_font(GdiFont *font)
4038 CHILD_FONT *child, *child_next;
4041 LIST_FOR_EACH_ENTRY_SAFE( child, child_next, &font->child_fonts, CHILD_FONT, entry )
4043 list_remove(&child->entry);
4045 free_font(child->font);
4046 HeapFree(GetProcessHeap(), 0, child);
4049 if (font->ft_face) pFT_Done_Face(font->ft_face);
4050 if (font->mapping) unmap_font_file( font->mapping );
4051 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
4052 HeapFree(GetProcessHeap(), 0, font->potm);
4053 HeapFree(GetProcessHeap(), 0, font->name);
4054 for (i = 0; i < font->gmsize; i++)
4055 HeapFree(GetProcessHeap(),0,font->gm[i]);
4056 HeapFree(GetProcessHeap(), 0, font->gm);
4057 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
4058 HeapFree(GetProcessHeap(), 0, font);
4062 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
4064 FT_Face ft_face = font->ft_face;
4068 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
4075 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
4077 /* make sure value of len is the value freetype says it needs */
4080 FT_ULong needed = 0;
4081 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
4082 if( !err && needed < len) len = needed;
4084 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
4087 TRACE("Can't find table %c%c%c%c\n",
4088 /* bytes were reversed */
4089 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
4090 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
4096 /*************************************************************
4099 * load the vdmx entry for the specified height
4102 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
4103 ( ( (FT_ULong)_x4 << 24 ) | \
4104 ( (FT_ULong)_x3 << 16 ) | \
4105 ( (FT_ULong)_x2 << 8 ) | \
4108 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
4123 static LONG load_VDMX(GdiFont *font, LONG height)
4127 BYTE devXRatio, devYRatio;
4128 USHORT numRecs, numRatios;
4129 DWORD result, offset = -1;
4133 result = get_font_data(font, MS_VDMX_TAG, 0, hdr, 6);
4135 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
4138 /* FIXME: need the real device aspect ratio */
4142 numRecs = GET_BE_WORD(hdr[1]);
4143 numRatios = GET_BE_WORD(hdr[2]);
4145 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
4146 for(i = 0; i < numRatios; i++) {
4149 offset = (3 * 2) + (i * sizeof(Ratios));
4150 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
4153 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
4155 if((ratio.xRatio == 0 &&
4156 ratio.yStartRatio == 0 &&
4157 ratio.yEndRatio == 0) ||
4158 (devXRatio == ratio.xRatio &&
4159 devYRatio >= ratio.yStartRatio &&
4160 devYRatio <= ratio.yEndRatio))
4162 offset = (3 * 2) + (numRatios * 4) + (i * 2);
4163 get_font_data(font, MS_VDMX_TAG, offset, &tmp, 2);
4164 offset = GET_BE_WORD(tmp);
4170 FIXME("No suitable ratio found\n");
4174 if(get_font_data(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
4176 BYTE startsz, endsz;
4179 recs = GET_BE_WORD(group.recs);
4180 startsz = group.startsz;
4181 endsz = group.endsz;
4183 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
4185 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
4186 result = get_font_data(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
4187 if(result == GDI_ERROR) {
4188 FIXME("Failed to retrieve vTable\n");
4193 for(i = 0; i < recs; i++) {
4194 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4195 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4196 ppem = GET_BE_WORD(vTable[i * 3]);
4198 if(yMax + -yMin == height) {
4201 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4204 if(yMax + -yMin > height) {
4207 goto end; /* failed */
4209 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4210 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4211 ppem = GET_BE_WORD(vTable[i * 3]);
4212 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4218 TRACE("ppem not found for height %d\n", height);
4222 HeapFree(GetProcessHeap(), 0, vTable);
4228 static void dump_gdi_font_list(void)
4232 TRACE("---------- Font Cache ----------\n");
4233 LIST_FOR_EACH_ENTRY( font, &gdi_font_list, struct tagGdiFont, entry )
4234 TRACE("font=%p ref=%u %s %d\n", font, font->refcount,
4235 debugstr_w(font->font_desc.lf.lfFaceName), font->font_desc.lf.lfHeight);
4238 static void grab_font( GdiFont *font )
4240 if (!font->refcount++)
4242 list_remove( &font->unused_entry );
4243 unused_font_count--;
4247 static void release_font( GdiFont *font )
4250 if (!--font->refcount)
4252 TRACE( "font %p\n", font );
4254 /* add it to the unused list */
4255 list_add_head( &unused_gdi_font_list, &font->unused_entry );
4256 if (unused_font_count > UNUSED_CACHE_SIZE)
4258 font = LIST_ENTRY( list_tail( &unused_gdi_font_list ), struct tagGdiFont, unused_entry );
4259 TRACE( "freeing %p\n", font );
4260 list_remove( &font->entry );
4261 list_remove( &font->unused_entry );
4264 else unused_font_count++;
4266 if (TRACE_ON(font)) dump_gdi_font_list();
4270 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
4272 if(font->font_desc.hash != fd->hash) return TRUE;
4273 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
4274 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
4275 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
4276 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
4279 static void calc_hash(FONT_DESC *pfd)
4281 DWORD hash = 0, *ptr, two_chars;
4285 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
4287 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
4289 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
4291 pwc = (WCHAR *)&two_chars;
4293 *pwc = toupperW(*pwc);
4295 *pwc = toupperW(*pwc);
4299 hash ^= !pfd->can_use_bitmap;
4304 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
4311 fd.can_use_bitmap = can_use_bitmap;
4314 /* try the in-use list */
4315 LIST_FOR_EACH_ENTRY( ret, &gdi_font_list, struct tagGdiFont, entry )
4317 if(fontcmp(ret, &fd)) continue;
4318 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4319 list_remove( &ret->entry );
4320 list_add_head( &gdi_font_list, &ret->entry );
4327 static void add_to_cache(GdiFont *font)
4329 static DWORD cache_num = 1;
4331 font->cache_num = cache_num++;
4332 list_add_head(&gdi_font_list, &font->entry);
4333 TRACE( "font %p\n", font );
4336 /*************************************************************
4337 * create_child_font_list
4339 static BOOL create_child_font_list(GdiFont *font)
4342 SYSTEM_LINKS *font_link;
4343 CHILD_FONT *font_link_entry, *new_child;
4347 psub = get_font_subst(&font_subst_list, font->name, -1);
4348 font_name = psub ? psub->to.name : font->name;
4349 font_link = find_font_link(font_name);
4350 if (font_link != NULL)
4352 TRACE("found entry in system list\n");
4353 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4355 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4356 new_child->face = font_link_entry->face;
4357 new_child->font = NULL;
4358 list_add_tail(&font->child_fonts, &new_child->entry);
4359 TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index);
4364 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
4365 * Sans Serif. This is how asian windows get default fallbacks for fonts
4367 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
4368 font->charset != OEM_CHARSET &&
4369 strcmpiW(font_name,szDefaultFallbackLink) != 0)
4371 font_link = find_font_link(szDefaultFallbackLink);
4372 if (font_link != NULL)
4374 TRACE("found entry in default fallback list\n");
4375 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4377 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4378 new_child->face = font_link_entry->face;
4379 new_child->font = NULL;
4380 list_add_tail(&font->child_fonts, &new_child->entry);
4381 TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index);
4390 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
4392 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
4394 if (pFT_Set_Charmap)
4397 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
4399 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
4401 for (i = 0; i < ft_face->num_charmaps; i++)
4403 if (ft_face->charmaps[i]->encoding == encoding)
4405 TRACE("found cmap with platform_id %u, encoding_id %u\n",
4406 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
4408 switch (ft_face->charmaps[i]->platform_id)
4411 cmap_def = ft_face->charmaps[i];
4413 case 0: /* Apple Unicode */
4414 cmap0 = ft_face->charmaps[i];
4416 case 1: /* Macintosh */
4417 cmap1 = ft_face->charmaps[i];
4420 cmap2 = ft_face->charmaps[i];
4422 case 3: /* Microsoft */
4423 cmap3 = ft_face->charmaps[i];
4428 if (cmap3) /* prefer Microsoft cmap table */
4429 ft_err = pFT_Set_Charmap(ft_face, cmap3);
4431 ft_err = pFT_Set_Charmap(ft_face, cmap1);
4433 ft_err = pFT_Set_Charmap(ft_face, cmap2);
4435 ft_err = pFT_Set_Charmap(ft_face, cmap0);
4437 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
4439 return ft_err == FT_Err_Ok;
4442 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
4446 /*************************************************************
4449 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
4450 LPCWSTR output, const DEVMODEW *devmode )
4452 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
4454 if (!physdev) return FALSE;
4455 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
4460 /*************************************************************
4463 static BOOL freetype_DeleteDC( PHYSDEV dev )
4465 struct freetype_physdev *physdev = get_freetype_dev( dev );
4466 release_font( physdev->font );
4467 HeapFree( GetProcessHeap(), 0, physdev );
4471 static FT_Encoding pick_charmap( FT_Face face, int charset )
4473 static const FT_Encoding regular_order[] = { FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, FT_ENCODING_MS_SYMBOL, 0 };
4474 static const FT_Encoding symbol_order[] = { FT_ENCODING_MS_SYMBOL, FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, 0 };
4475 const FT_Encoding *encs = regular_order;
4477 if (charset == SYMBOL_CHARSET) encs = symbol_order;
4481 if (select_charmap( face, *encs )) break;
4487 #define GASP_GRIDFIT 0x01
4488 #define GASP_DOGRAY 0x02
4489 #define GASP_TAG MS_MAKE_TAG('g','a','s','p')
4491 static BOOL get_gasp_flags( GdiFont *font, WORD *flags )
4494 WORD buf[16]; /* Enough for seven ranges before we need to alloc */
4495 WORD *alloced = NULL, *ptr = buf;
4496 WORD num_recs, version;
4500 size = get_font_data( font, GASP_TAG, 0, NULL, 0 );
4501 if (size == GDI_ERROR) return FALSE;
4502 if (size < 4 * sizeof(WORD)) return FALSE;
4503 if (size > sizeof(buf))
4505 ptr = alloced = HeapAlloc( GetProcessHeap(), 0, size );
4506 if (!ptr) return FALSE;
4509 get_font_data( font, GASP_TAG, 0, ptr, size );
4511 version = GET_BE_WORD( *ptr++ );
4512 num_recs = GET_BE_WORD( *ptr++ );
4514 if (version > 1 || size < (num_recs * 2 + 2) * sizeof(WORD))
4516 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version, size, num_recs );
4522 *flags = GET_BE_WORD( *(ptr + 1) );
4523 if (font->ft_face->size->metrics.y_ppem <= GET_BE_WORD( *ptr )) break;
4526 TRACE( "got flags %04x for ppem %d\n", *flags, font->ft_face->size->metrics.y_ppem );
4530 HeapFree( GetProcessHeap(), 0, alloced );
4534 /*************************************************************
4535 * freetype_SelectFont
4537 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont, UINT *aa_flags )
4539 struct freetype_physdev *physdev = get_freetype_dev( dev );
4541 Face *face, *best, *best_bitmap;
4542 Family *family, *last_resort_family;
4543 const struct list *face_list;
4544 INT height, width = 0;
4545 unsigned int score = 0, new_score;
4546 signed int diff = 0, newdiff;
4547 BOOL bd, it, can_use_bitmap, want_vertical;
4551 FontSubst *psub = NULL;
4552 DC *dc = get_dc_ptr( dev->hdc );
4553 const SYSTEM_LINKS *font_link;
4555 if (!hfont) /* notification that the font has been changed by another driver */
4557 release_font( physdev->font );
4558 physdev->font = NULL;
4559 release_dc_ptr( dc );
4563 GetObjectW( hfont, sizeof(lf), &lf );
4564 lf.lfWidth = abs(lf.lfWidth);
4566 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
4568 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
4569 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
4570 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
4573 if(dc->GraphicsMode == GM_ADVANCED)
4575 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
4576 /* Try to avoid not necessary glyph transformations */
4577 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
4579 lf.lfHeight *= fabs(dcmat.eM11);
4580 lf.lfWidth *= fabs(dcmat.eM11);
4581 dcmat.eM11 = dcmat.eM22 = dcmat.eM11 < 0 ? -1 : 1;
4586 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
4587 font scaling abilities. */
4588 dcmat.eM11 = dcmat.eM22 = 1.0;
4589 dcmat.eM21 = dcmat.eM12 = 0;
4590 lf.lfOrientation = lf.lfEscapement;
4591 if (dc->vport2WorldValid)
4593 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
4594 lf.lfOrientation = -lf.lfOrientation;
4595 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
4596 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
4600 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
4601 dcmat.eM21, dcmat.eM22);
4604 EnterCriticalSection( &freetype_cs );
4606 /* check the cache first */
4607 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4608 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
4612 TRACE("not in cache\n");
4615 ret->font_desc.matrix = dcmat;
4616 ret->font_desc.lf = lf;
4617 ret->font_desc.can_use_bitmap = can_use_bitmap;
4618 calc_hash(&ret->font_desc);
4620 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4621 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4622 original value lfCharSet. Note this is a special case for
4623 Symbol and doesn't happen at least for "Wingdings*" */
4625 if(!strcmpiW(lf.lfFaceName, SymbolW))
4626 lf.lfCharSet = SYMBOL_CHARSET;
4628 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
4629 switch(lf.lfCharSet) {
4630 case DEFAULT_CHARSET:
4631 csi.fs.fsCsb[0] = 0;
4634 FIXME("Untranslated charset %d\n", lf.lfCharSet);
4635 csi.fs.fsCsb[0] = 0;
4641 if(lf.lfFaceName[0] != '\0') {
4642 CHILD_FONT *font_link_entry;
4643 LPWSTR FaceName = lf.lfFaceName;
4645 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
4648 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
4649 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
4650 if (psub->to.charset != -1)
4651 lf.lfCharSet = psub->to.charset;
4654 /* We want a match on name and charset or just name if
4655 charset was DEFAULT_CHARSET. If the latter then
4656 we fixup the returned charset later in get_nearest_charset
4657 where we'll either use the charset of the current ansi codepage
4658 or if that's unavailable the first charset that the font supports.
4660 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
4661 if (!strcmpiW(family->FamilyName, FaceName) ||
4662 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
4664 font_link = find_font_link(family->FamilyName);
4665 face_list = get_face_list_from_family(family);
4666 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
4667 if (!(face->scalable || can_use_bitmap))
4669 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4671 if (font_link != NULL &&
4672 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4674 if (!csi.fs.fsCsb[0])
4680 /* Search by full face name. */
4681 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
4682 face_list = get_face_list_from_family(family);
4683 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
4684 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
4685 (face->scalable || can_use_bitmap))
4687 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4689 font_link = find_font_link(family->FamilyName);
4690 if (font_link != NULL &&
4691 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4698 * Try check the SystemLink list first for a replacement font.
4699 * We may find good replacements there.
4701 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
4703 if(!strcmpiW(font_link->font_name, FaceName) ||
4704 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
4706 TRACE("found entry in system list\n");
4707 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4709 const SYSTEM_LINKS *links;
4711 face = font_link_entry->face;
4712 if (!(face->scalable || can_use_bitmap))
4714 family = face->family;
4715 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4717 links = find_font_link(family->FamilyName);
4718 if (links != NULL && csi.fs.fsCsb[0] & links->fs.fsCsb[0])
4725 psub = NULL; /* substitution is no more relevant */
4727 /* If requested charset was DEFAULT_CHARSET then try using charset
4728 corresponding to the current ansi codepage */
4729 if (!csi.fs.fsCsb[0])
4732 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
4733 FIXME("TCI failed on codepage %d\n", acp);
4734 csi.fs.fsCsb[0] = 0;
4736 lf.lfCharSet = csi.ciCharset;
4739 want_vertical = (lf.lfFaceName[0] == '@');
4741 /* Face families are in the top 4 bits of lfPitchAndFamily,
4742 so mask with 0xF0 before testing */
4744 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
4745 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
4746 strcpyW(lf.lfFaceName, defFixed);
4747 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
4748 strcpyW(lf.lfFaceName, defSerif);
4749 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
4750 strcpyW(lf.lfFaceName, defSans);
4752 strcpyW(lf.lfFaceName, defSans);
4753 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
4754 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
4755 font_link = find_font_link(family->FamilyName);
4756 face_list = get_face_list_from_family(family);
4757 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
4758 if (!(face->scalable || can_use_bitmap))
4760 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4762 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4768 last_resort_family = NULL;
4769 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
4770 font_link = find_font_link(family->FamilyName);
4771 face_list = get_face_list_from_family(family);
4772 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
4773 if(face->vertical == want_vertical &&
4774 (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4775 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]))) {
4778 if(can_use_bitmap && !last_resort_family)
4779 last_resort_family = family;
4784 if(last_resort_family) {
4785 family = last_resort_family;
4786 csi.fs.fsCsb[0] = 0;
4790 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
4791 face_list = get_face_list_from_family(family);
4792 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
4793 if(face->scalable && face->vertical == want_vertical) {
4794 csi.fs.fsCsb[0] = 0;
4795 WARN("just using first face for now\n");
4798 if(can_use_bitmap && !last_resort_family)
4799 last_resort_family = family;
4802 if(!last_resort_family) {
4803 FIXME("can't find a single appropriate font - bailing\n");
4809 WARN("could only find a bitmap font - this will probably look awful!\n");
4810 family = last_resort_family;
4811 csi.fs.fsCsb[0] = 0;
4814 it = lf.lfItalic ? 1 : 0;
4815 bd = lf.lfWeight > 550 ? 1 : 0;
4817 height = lf.lfHeight;
4819 face = best = best_bitmap = NULL;
4820 font_link = find_font_link(family->FamilyName);
4821 face_list = get_face_list_from_family(family);
4822 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
4824 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4825 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]) ||
4830 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
4831 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
4832 new_score = (italic ^ it) + (bold ^ bd);
4833 if(!best || new_score <= score)
4835 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4836 italic, bold, it, bd);
4839 if(best->scalable && score == 0) break;
4843 newdiff = height - (signed int)(best->size.height);
4845 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
4846 if(!best_bitmap || new_score < score ||
4847 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
4849 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
4852 if(score == 0 && diff == 0) break;
4859 face = best->scalable ? best : best_bitmap;
4860 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
4861 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
4864 height = lf.lfHeight;
4868 if(csi.fs.fsCsb[0]) {
4869 ret->charset = lf.lfCharSet;
4870 ret->codepage = csi.ciACP;
4873 ret->charset = get_nearest_charset(family->FamilyName, face, &ret->codepage);
4875 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
4876 debugstr_w(face->StyleName), debugstr_w(face->file), face->font_data_ptr, face->face_index);
4878 ret->aveWidth = height ? lf.lfWidth : 0;
4880 if(!face->scalable) {
4881 /* Windows uses integer scaling factors for bitmap fonts */
4882 INT scale, scaled_height;
4883 GdiFont *cachedfont;
4885 /* FIXME: rotation of bitmap fonts is ignored */
4886 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
4888 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
4889 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4890 dcmat.eM11 = dcmat.eM22 = 1.0;
4891 /* As we changed the matrix, we need to search the cache for the font again,
4892 * otherwise we might explode the cache. */
4893 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4894 TRACE("Found cached font after non-scalable matrix rescale!\n");
4899 calc_hash(&ret->font_desc);
4901 if (height != 0) height = diff;
4902 height += face->size.height;
4904 scale = (height + face->size.height - 1) / face->size.height;
4905 scaled_height = scale * face->size.height;
4906 /* Only jump to the next height if the difference <= 25% original height */
4907 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
4908 /* The jump between unscaled and doubled is delayed by 1 */
4909 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
4910 ret->scale_y = scale;
4912 width = face->size.x_ppem >> 6;
4913 height = face->size.y_ppem >> 6;
4917 TRACE("font scale y: %f\n", ret->scale_y);
4919 ret->ft_face = OpenFontFace(ret, face, width, height);
4928 ret->ntmFlags = face->ntmFlags;
4930 pick_charmap( ret->ft_face, ret->charset );
4932 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
4933 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
4934 ret->underline = lf.lfUnderline ? 0xff : 0;
4935 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
4936 create_child_font_list(ret);
4938 if (face->vertical) /* We need to try to load the GSUB table */
4940 int length = get_font_data(ret, GSUB_TAG , 0, NULL, 0);
4941 if (length != GDI_ERROR)
4943 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
4944 get_font_data(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
4945 TRACE("Loaded GSUB table of %i bytes\n",length);
4948 ret->aa_flags = face->aa_flags;
4950 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
4956 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSelectFont );
4958 switch (lf.lfQuality)
4960 case NONANTIALIASED_QUALITY:
4961 case ANTIALIASED_QUALITY:
4962 next->funcs->pSelectFont( dev, hfont, aa_flags );
4964 case CLEARTYPE_QUALITY:
4965 case CLEARTYPE_NATURAL_QUALITY:
4967 if (!*aa_flags) *aa_flags = ret->aa_flags;
4968 next->funcs->pSelectFont( dev, hfont, aa_flags );
4970 /* fixup the antialiasing flags for that font */
4973 case WINE_GGO_HRGB_BITMAP:
4974 case WINE_GGO_HBGR_BITMAP:
4975 case WINE_GGO_VRGB_BITMAP:
4976 case WINE_GGO_VBGR_BITMAP:
4977 if (is_subpixel_rendering_enabled()) break;
4978 *aa_flags = GGO_GRAY4_BITMAP;
4980 case GGO_GRAY2_BITMAP:
4981 case GGO_GRAY4_BITMAP:
4982 case GGO_GRAY8_BITMAP:
4983 case WINE_GGO_GRAY16_BITMAP:
4984 if (is_hinting_enabled())
4987 if (get_gasp_flags( ret, &gasp_flags ) && !(gasp_flags & GASP_DOGRAY))
4989 TRACE( "font %s %d aa disabled by GASP\n",
4990 debugstr_w(lf.lfFaceName), lf.lfHeight );
4991 *aa_flags = GGO_BITMAP;
4996 TRACE( "%p %s %d aa %x\n", hfont, debugstr_w(lf.lfFaceName), lf.lfHeight, *aa_flags );
4997 release_font( physdev->font );
4998 physdev->font = ret;
5000 LeaveCriticalSection( &freetype_cs );
5001 release_dc_ptr( dc );
5002 return ret ? hfont : 0;
5005 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
5012 id += IDS_FIRST_SCRIPT;
5013 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
5014 if (!rsrc) return 0;
5015 hMem = LoadResource( gdi32_module, rsrc );
5016 if (!hMem) return 0;
5018 p = LockResource( hMem );
5020 while (id--) p += *p + 1;
5022 i = min(LF_FACESIZE - 1, *p);
5023 memcpy(buffer, p + 1, i * sizeof(WCHAR));
5029 /***************************************************
5030 * create_enum_charset_list
5032 * This function creates charset enumeration list because in DEFAULT_CHARSET
5033 * case, the ANSI codepage's charset takes precedence over other charsets.
5034 * This function works as a filter other than DEFAULT_CHARSET case.
5036 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
5041 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
5042 csi.fs.fsCsb[0] != 0) {
5043 list->element[n].mask = csi.fs.fsCsb[0];
5044 list->element[n].charset = csi.ciCharset;
5045 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5048 else { /* charset is DEFAULT_CHARSET or invalid. */
5052 /* Set the current codepage's charset as the first element. */
5054 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
5055 csi.fs.fsCsb[0] != 0) {
5056 list->element[n].mask = csi.fs.fsCsb[0];
5057 list->element[n].charset = csi.ciCharset;
5058 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5059 mask |= csi.fs.fsCsb[0];
5063 /* Fill out left elements. */
5064 for (i = 0; i < 32; i++) {
5066 fs.fsCsb[0] = 1L << i;
5068 if (fs.fsCsb[0] & mask)
5069 continue; /* skip, already added. */
5070 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
5071 continue; /* skip, this is an invalid fsCsb bit. */
5073 list->element[n].mask = fs.fsCsb[0];
5074 list->element[n].charset = csi.ciCharset;
5075 load_script_name( i, list->element[n].name );
5076 mask |= fs.fsCsb[0];
5080 /* add catch all mask for remaining bits */
5083 list->element[n].mask = ~mask;
5084 list->element[n].charset = DEFAULT_CHARSET;
5085 load_script_name( IDS_OTHER - IDS_FIRST_SCRIPT, list->element[n].name );
5094 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
5095 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
5100 if (face->cached_enum_data)
5103 *pelf = face->cached_enum_data->elf;
5104 *pntm = face->cached_enum_data->ntm;
5105 *ptype = face->cached_enum_data->type;
5109 font = alloc_font();
5111 if(face->scalable) {
5115 height = face->size.y_ppem >> 6;
5116 width = face->size.x_ppem >> 6;
5118 font->scale_y = 1.0;
5120 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
5126 font->name = strdupW(face->family->FamilyName);
5127 font->ntmFlags = face->ntmFlags;
5129 if (get_outline_text_metrics(font))
5131 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
5133 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
5134 pntm->ntmTm.ntmCellHeight = font->ntmCellHeight;
5135 pntm->ntmTm.ntmAvgWidth = font->ntmAvgWidth;
5137 lstrcpynW(pelf->elfLogFont.lfFaceName,
5138 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
5140 lstrcpynW(pelf->elfFullName,
5141 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
5143 lstrcpynW(pelf->elfStyle,
5144 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
5149 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
5151 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
5152 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
5153 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
5155 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
5157 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
5159 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
5160 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
5163 pntm->ntmTm.ntmFlags = face->ntmFlags;
5164 pntm->ntmFontSig = face->fs;
5166 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
5168 pelf->elfLogFont.lfEscapement = 0;
5169 pelf->elfLogFont.lfOrientation = 0;
5170 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
5171 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
5172 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
5173 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
5174 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
5175 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
5176 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
5177 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
5178 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
5179 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
5180 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
5183 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
5184 *ptype |= TRUETYPE_FONTTYPE;
5185 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
5186 *ptype |= DEVICE_FONTTYPE;
5187 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
5188 *ptype |= RASTER_FONTTYPE;
5190 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
5191 if (face->cached_enum_data)
5193 face->cached_enum_data->elf = *pelf;
5194 face->cached_enum_data->ntm = *pntm;
5195 face->cached_enum_data->type = *ptype;
5201 static BOOL family_matches(Family *family, const LOGFONTW *lf)
5204 const struct list *face_list;
5206 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
5208 face_list = get_face_list_from_family(family);
5209 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
5210 if (face->FullName && !strcmpiW(lf->lfFaceName, face->FullName)) return TRUE;
5215 static BOOL face_matches(const WCHAR *family_name, Face *face, const LOGFONTW *lf)
5217 if (!strcmpiW(lf->lfFaceName, family_name)) return TRUE;
5219 return (face->FullName && !strcmpiW(lf->lfFaceName, face->FullName));
5222 static BOOL enum_face_charsets(const Family *family, Face *face, struct enum_charset_list *list,
5223 FONTENUMPROCW proc, LPARAM lparam)
5226 NEWTEXTMETRICEXW ntm;
5230 GetEnumStructs(face, &elf, &ntm, &type);
5231 for(i = 0; i < list->total; i++) {
5232 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
5233 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
5234 load_script_name( IDS_OEM_DOS - IDS_FIRST_SCRIPT, elf.elfScript );
5235 i = list->total; /* break out of loop after enumeration */
5239 if(!(face->fs.fsCsb[0] & list->element[i].mask)) continue;
5240 /* use the DEFAULT_CHARSET case only if no other charset is present */
5241 if (list->element[i].charset == DEFAULT_CHARSET &&
5242 (face->fs.fsCsb[0] & ~list->element[i].mask)) continue;
5243 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
5244 strcpyW(elf.elfScript, list->element[i].name);
5245 if (!elf.elfScript[0])
5246 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
5248 /* Font Replacement */
5249 if (family != face->family)
5251 strcpyW(elf.elfLogFont.lfFaceName, family->FamilyName);
5253 strcpyW(elf.elfFullName, face->FullName);
5255 strcpyW(elf.elfFullName, family->FamilyName);
5257 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
5258 debugstr_w(elf.elfLogFont.lfFaceName),
5259 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
5260 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
5261 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
5262 ntm.ntmTm.ntmFlags);
5263 /* release section before callback (FIXME) */
5264 LeaveCriticalSection( &freetype_cs );
5265 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
5266 EnterCriticalSection( &freetype_cs );
5271 /*************************************************************
5272 * freetype_EnumFonts
5274 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
5278 const struct list *face_list;
5280 struct enum_charset_list enum_charsets;
5284 lf.lfCharSet = DEFAULT_CHARSET;
5285 lf.lfPitchAndFamily = 0;
5286 lf.lfFaceName[0] = 0;
5290 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
5292 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
5295 EnterCriticalSection( &freetype_cs );
5296 if(plf->lfFaceName[0]) {
5298 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
5301 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
5302 debugstr_w(psub->to.name));
5304 strcpyW(lf.lfFaceName, psub->to.name);
5308 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5309 if (!family_matches(family, plf)) continue;
5310 face_list = get_face_list_from_family(family);
5311 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5312 if (!face_matches(family->FamilyName, face, plf)) continue;
5313 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
5317 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5318 face_list = get_face_list_from_family(family);
5319 face = LIST_ENTRY(list_head(face_list), Face, entry);
5320 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
5323 LeaveCriticalSection( &freetype_cs );
5327 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
5329 pt->x.value = vec->x >> 6;
5330 pt->x.fract = (vec->x & 0x3f) << 10;
5331 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
5332 pt->y.value = vec->y >> 6;
5333 pt->y.fract = (vec->y & 0x3f) << 10;
5334 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
5338 /***************************************************
5339 * According to the MSDN documentation on WideCharToMultiByte,
5340 * certain codepages cannot set the default_used parameter.
5341 * This returns TRUE if the codepage can set that parameter, false else
5342 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
5344 static BOOL codepage_sets_default_used(UINT codepage)
5358 * GSUB Table handling functions
5361 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
5363 const GSUB_CoverageFormat1* cf1;
5367 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
5369 int count = GET_BE_WORD(cf1->GlyphCount);
5371 TRACE("Coverage Format 1, %i glyphs\n",count);
5372 for (i = 0; i < count; i++)
5373 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
5377 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
5379 const GSUB_CoverageFormat2* cf2;
5382 cf2 = (const GSUB_CoverageFormat2*)cf1;
5384 count = GET_BE_WORD(cf2->RangeCount);
5385 TRACE("Coverage Format 2, %i ranges\n",count);
5386 for (i = 0; i < count; i++)
5388 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
5390 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
5391 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
5393 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
5394 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
5400 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
5405 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
5407 const GSUB_ScriptList *script;
5408 const GSUB_Script *deflt = NULL;
5410 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
5412 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
5413 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
5415 const GSUB_Script *scr;
5418 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
5419 scr = (const GSUB_Script*)((const BYTE*)script + offset);
5421 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
5423 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
5429 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
5433 const GSUB_LangSys *Lang;
5435 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
5437 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
5439 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
5440 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5442 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
5445 offset = GET_BE_WORD(script->DefaultLangSys);
5448 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5454 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
5457 const GSUB_FeatureList *feature;
5458 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
5460 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
5461 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
5463 int index = GET_BE_WORD(lang->FeatureIndex[i]);
5464 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
5466 const GSUB_Feature *feat;
5467 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
5474 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
5478 const GSUB_LookupList *lookup;
5479 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
5481 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
5482 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
5484 const GSUB_LookupTable *look;
5485 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
5486 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
5487 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
5488 if (GET_BE_WORD(look->LookupType) != 1)
5489 FIXME("We only handle SubType 1\n");
5494 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
5496 const GSUB_SingleSubstFormat1 *ssf1;
5497 offset = GET_BE_WORD(look->SubTable[j]);
5498 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
5499 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
5501 int offset = GET_BE_WORD(ssf1->Coverage);
5502 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
5503 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
5505 TRACE(" Glyph 0x%x ->",glyph);
5506 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
5507 TRACE(" 0x%x\n",glyph);
5512 const GSUB_SingleSubstFormat2 *ssf2;
5516 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
5517 offset = GET_BE_WORD(ssf1->Coverage);
5518 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
5519 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
5520 TRACE(" Coverage index %i\n",index);
5523 TRACE(" Glyph is 0x%x ->",glyph);
5524 glyph = GET_BE_WORD(ssf2->Substitute[index]);
5525 TRACE("0x%x\n",glyph);
5534 static const char* get_opentype_script(const GdiFont *font)
5537 * I am not sure if this is the correct way to generate our script tag
5540 switch (font->charset)
5542 case ANSI_CHARSET: return "latn";
5543 case BALTIC_CHARSET: return "latn"; /* ?? */
5544 case CHINESEBIG5_CHARSET: return "hani";
5545 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
5546 case GB2312_CHARSET: return "hani";
5547 case GREEK_CHARSET: return "grek";
5548 case HANGUL_CHARSET: return "hang";
5549 case RUSSIAN_CHARSET: return "cyrl";
5550 case SHIFTJIS_CHARSET: return "kana";
5551 case TURKISH_CHARSET: return "latn"; /* ?? */
5552 case VIETNAMESE_CHARSET: return "latn";
5553 case JOHAB_CHARSET: return "latn"; /* ?? */
5554 case ARABIC_CHARSET: return "arab";
5555 case HEBREW_CHARSET: return "hebr";
5556 case THAI_CHARSET: return "thai";
5557 default: return "latn";
5561 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
5563 const GSUB_Header *header;
5564 const GSUB_Script *script;
5565 const GSUB_LangSys *language;
5566 const GSUB_Feature *feature;
5568 if (!font->GSUB_Table)
5571 header = font->GSUB_Table;
5573 script = GSUB_get_script_table(header, get_opentype_script(font));
5576 TRACE("Script not found\n");
5579 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
5582 TRACE("Language not found\n");
5585 feature = GSUB_get_feature(header, language, "vrt2");
5587 feature = GSUB_get_feature(header, language, "vert");
5590 TRACE("vrt2/vert feature not found\n");
5593 return GSUB_apply_feature(header, feature, glyph);
5596 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
5600 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
5601 WCHAR wc = (WCHAR)glyph;
5603 BOOL *default_used_pointer;
5606 default_used_pointer = NULL;
5607 default_used = FALSE;
5608 if (codepage_sets_default_used(font->codepage))
5609 default_used_pointer = &default_used;
5610 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
5612 if (font->codepage == CP_SYMBOL && wc < 0x100)
5613 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)wc);
5618 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
5619 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
5623 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
5625 if (glyph < 0x100) glyph += 0xf000;
5626 /* there is a number of old pre-Unicode "broken" TTFs, which
5627 do have symbols at U+00XX instead of U+f0XX */
5628 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
5629 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
5631 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
5636 /*************************************************************
5637 * freetype_GetGlyphIndices
5639 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
5641 struct freetype_physdev *physdev = get_freetype_dev( dev );
5644 BOOL got_default = FALSE;
5648 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
5649 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
5652 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
5654 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
5659 EnterCriticalSection( &freetype_cs );
5661 for(i = 0; i < count; i++)
5663 pgi[i] = get_glyph_index(physdev->font, lpstr[i]);
5668 if (FT_IS_SFNT(physdev->font->ft_face))
5670 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(physdev->font->ft_face, ft_sfnt_os2);
5671 default_char = (pOS2->usDefaultChar ? get_glyph_index(physdev->font, pOS2->usDefaultChar) : 0);
5676 get_text_metrics(physdev->font, &textm);
5677 default_char = textm.tmDefaultChar;
5681 pgi[i] = default_char;
5684 LeaveCriticalSection( &freetype_cs );
5688 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
5690 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
5691 return !memcmp(matrix, &identity, sizeof(FMAT2));
5694 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
5696 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
5697 return !memcmp(matrix, &identity, sizeof(MAT2));
5700 static inline BYTE get_max_level( UINT format )
5704 case GGO_GRAY2_BITMAP: return 4;
5705 case GGO_GRAY4_BITMAP: return 16;
5706 case GGO_GRAY8_BITMAP: return 64;
5711 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5713 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
5714 LPGLYPHMETRICS lpgm, ABC *abc, DWORD buflen, LPVOID buf,
5717 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
5718 FT_Face ft_face = incoming_font->ft_face;
5719 GdiFont *font = incoming_font;
5720 FT_UInt glyph_index;
5721 DWORD width, height, pitch, needed = 0;
5722 FT_Bitmap ft_bitmap;
5724 INT left, right, top = 0, bottom = 0, adv;
5726 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
5727 double widthRatio = 1.0;
5728 FT_Matrix transMat = identityMat;
5729 FT_Matrix transMatUnrotated;
5730 BOOL needsTransform = FALSE;
5731 BOOL tategaki = (font->GSUB_Table != NULL);
5732 UINT original_index;
5734 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
5735 buflen, buf, lpmat);
5737 TRACE("font transform %f %f %f %f\n",
5738 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
5739 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
5741 if(format & GGO_GLYPH_INDEX) {
5742 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
5743 original_index = glyph;
5744 format &= ~GGO_GLYPH_INDEX;
5746 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
5747 ft_face = font->ft_face;
5748 original_index = glyph_index;
5751 if(format & GGO_UNHINTED) {
5752 load_flags |= FT_LOAD_NO_HINTING;
5753 format &= ~GGO_UNHINTED;
5756 /* tategaki never appears to happen to lower glyph index */
5757 if (glyph_index < TATEGAKI_LOWER_BOUND )
5760 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
5761 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
5762 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
5763 font->gmsize * sizeof(GM*));
5765 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
5766 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
5768 *lpgm = FONT_GM(font,original_index)->gm;
5769 *abc = FONT_GM(font,original_index)->abc;
5770 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5771 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5772 lpgm->gmCellIncX, lpgm->gmCellIncY);
5773 return 1; /* FIXME */
5777 if (!font->gm[original_index / GM_BLOCK_SIZE])
5778 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
5780 /* Scaling factor */
5785 get_text_metrics(font, &tm);
5787 widthRatio = (double)font->aveWidth;
5788 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5791 widthRatio = font->scale_y;
5793 /* Scaling transform */
5794 if (widthRatio != 1.0 || font->scale_y != 1.0)
5797 scaleMat.xx = FT_FixedFromFloat(widthRatio);
5800 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
5802 pFT_Matrix_Multiply(&scaleMat, &transMat);
5803 needsTransform = TRUE;
5806 /* Slant transform */
5807 if (font->fake_italic) {
5810 slantMat.xx = (1 << 16);
5811 slantMat.xy = ((1 << 16) >> 2);
5813 slantMat.yy = (1 << 16);
5814 pFT_Matrix_Multiply(&slantMat, &transMat);
5815 needsTransform = TRUE;
5818 /* Rotation transform */
5819 transMatUnrotated = transMat;
5820 if(font->orientation && !tategaki) {
5821 FT_Matrix rotationMat;
5823 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
5824 pFT_Vector_Unit(&vecAngle, angle);
5825 rotationMat.xx = vecAngle.x;
5826 rotationMat.xy = -vecAngle.y;
5827 rotationMat.yx = -rotationMat.xy;
5828 rotationMat.yy = rotationMat.xx;
5830 pFT_Matrix_Multiply(&rotationMat, &transMat);
5831 needsTransform = TRUE;
5834 /* World transform */
5835 if (!is_identity_FMAT2(&font->font_desc.matrix))
5838 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
5839 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
5840 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
5841 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
5842 pFT_Matrix_Multiply(&worldMat, &transMat);
5843 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
5844 needsTransform = TRUE;
5847 /* Extra transformation specified by caller */
5848 if (!is_identity_MAT2(lpmat))
5851 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
5852 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
5853 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
5854 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
5855 pFT_Matrix_Multiply(&extraMat, &transMat);
5856 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
5857 needsTransform = TRUE;
5860 if (needsTransform || format != GGO_BITMAP) load_flags |= FT_LOAD_NO_BITMAP;
5862 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
5865 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
5869 if(!needsTransform) {
5870 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
5871 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
5872 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
5874 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
5875 bottom = (ft_face->glyph->metrics.horiBearingY -
5876 ft_face->glyph->metrics.height) & -64;
5877 lpgm->gmCellIncX = adv;
5878 lpgm->gmCellIncY = 0;
5885 for(xc = 0; xc < 2; xc++) {
5886 for(yc = 0; yc < 2; yc++) {
5887 vec.x = (ft_face->glyph->metrics.horiBearingX +
5888 xc * ft_face->glyph->metrics.width);
5889 vec.y = ft_face->glyph->metrics.horiBearingY -
5890 yc * ft_face->glyph->metrics.height;
5891 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
5892 pFT_Vector_Transform(&vec, &transMat);
5893 if(xc == 0 && yc == 0) {
5894 left = right = vec.x;
5895 top = bottom = vec.y;
5897 if(vec.x < left) left = vec.x;
5898 else if(vec.x > right) right = vec.x;
5899 if(vec.y < bottom) bottom = vec.y;
5900 else if(vec.y > top) top = vec.y;
5905 right = (right + 63) & -64;
5906 bottom = bottom & -64;
5907 top = (top + 63) & -64;
5909 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
5910 vec.x = ft_face->glyph->metrics.horiAdvance;
5912 pFT_Vector_Transform(&vec, &transMat);
5913 lpgm->gmCellIncX = (vec.x+63) >> 6;
5914 lpgm->gmCellIncY = -((vec.y+63) >> 6);
5916 vec.x = ft_face->glyph->metrics.horiAdvance;
5918 pFT_Vector_Transform(&vec, &transMatUnrotated);
5919 adv = (vec.x+63) >> 6;
5922 lpgm->gmBlackBoxX = (right - left) >> 6;
5923 lpgm->gmBlackBoxY = (top - bottom) >> 6;
5924 lpgm->gmptGlyphOrigin.x = left >> 6;
5925 lpgm->gmptGlyphOrigin.y = top >> 6;
5926 abc->abcA = left >> 6;
5927 abc->abcB = (right - left) >> 6;
5928 abc->abcC = adv - abc->abcA - abc->abcB;
5930 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5931 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5932 lpgm->gmCellIncX, lpgm->gmCellIncY);
5934 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
5935 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
5937 FONT_GM(font,original_index)->gm = *lpgm;
5938 FONT_GM(font,original_index)->abc = *abc;
5939 FONT_GM(font,original_index)->init = TRUE;
5942 if(format == GGO_METRICS)
5944 return 1; /* FIXME */
5947 if(ft_face->glyph->format != ft_glyph_format_outline &&
5948 (format == GGO_NATIVE || format == GGO_BEZIER))
5950 TRACE("loaded a bitmap\n");
5956 width = lpgm->gmBlackBoxX;
5957 height = lpgm->gmBlackBoxY;
5958 pitch = ((width + 31) >> 5) << 2;
5959 needed = pitch * height;
5961 if(!buf || !buflen) break;
5963 switch(ft_face->glyph->format) {
5964 case ft_glyph_format_bitmap:
5966 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5967 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
5968 INT h = ft_face->glyph->bitmap.rows;
5970 memcpy(dst, src, w);
5971 src += ft_face->glyph->bitmap.pitch;
5977 case ft_glyph_format_outline:
5978 ft_bitmap.width = width;
5979 ft_bitmap.rows = height;
5980 ft_bitmap.pitch = pitch;
5981 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
5982 ft_bitmap.buffer = buf;
5985 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5987 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5989 /* Note: FreeType will only set 'black' bits for us. */
5990 memset(buf, 0, needed);
5991 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5995 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
6000 case GGO_GRAY2_BITMAP:
6001 case GGO_GRAY4_BITMAP:
6002 case GGO_GRAY8_BITMAP:
6003 case WINE_GGO_GRAY16_BITMAP:
6005 unsigned int max_level, row, col;
6008 width = lpgm->gmBlackBoxX;
6009 height = lpgm->gmBlackBoxY;
6010 pitch = (width + 3) / 4 * 4;
6011 needed = pitch * height;
6013 if(!buf || !buflen) break;
6015 max_level = get_max_level( format );
6017 switch(ft_face->glyph->format) {
6018 case ft_glyph_format_bitmap:
6020 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
6021 INT h = ft_face->glyph->bitmap.rows;
6023 memset( buf, 0, needed );
6025 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
6026 if (src[x / 8] & masks[x % 8]) dst[x] = max_level;
6027 src += ft_face->glyph->bitmap.pitch;
6032 case ft_glyph_format_outline:
6034 ft_bitmap.width = width;
6035 ft_bitmap.rows = height;
6036 ft_bitmap.pitch = pitch;
6037 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
6038 ft_bitmap.buffer = buf;
6041 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
6043 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
6045 memset(ft_bitmap.buffer, 0, buflen);
6047 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
6049 if (max_level != 255)
6051 for (row = 0, start = buf; row < height; row++)
6053 for (col = 0, ptr = start; col < width; col++, ptr++)
6054 *ptr = (((int)*ptr) * (max_level + 1)) / 256;
6062 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
6068 case WINE_GGO_HRGB_BITMAP:
6069 case WINE_GGO_HBGR_BITMAP:
6070 case WINE_GGO_VRGB_BITMAP:
6071 case WINE_GGO_VBGR_BITMAP:
6072 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6074 switch (ft_face->glyph->format)
6076 case FT_GLYPH_FORMAT_BITMAP:
6081 width = lpgm->gmBlackBoxX;
6082 height = lpgm->gmBlackBoxY;
6084 needed = pitch * height;
6086 if (!buf || !buflen) break;
6088 memset(buf, 0, buflen);
6090 src = ft_face->glyph->bitmap.buffer;
6091 src_pitch = ft_face->glyph->bitmap.pitch;
6093 height = min( height, ft_face->glyph->bitmap.rows );
6096 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
6098 if ( src[x / 8] & masks[x % 8] )
6099 ((unsigned int *)dst)[x] = ~0u;
6108 case FT_GLYPH_FORMAT_OUTLINE:
6112 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
6113 INT x_shift, y_shift;
6115 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
6116 FT_Render_Mode render_mode =
6117 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
6118 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
6120 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
6122 if ( render_mode == FT_RENDER_MODE_LCD)
6124 lpgm->gmBlackBoxX += 2;
6125 lpgm->gmptGlyphOrigin.x -= 1;
6129 lpgm->gmBlackBoxY += 2;
6130 lpgm->gmptGlyphOrigin.y += 1;
6134 width = lpgm->gmBlackBoxX;
6135 height = lpgm->gmBlackBoxY;
6137 needed = pitch * height;
6139 if (!buf || !buflen) break;
6141 memset(buf, 0, buflen);
6143 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
6145 if ( needsTransform )
6146 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
6148 if ( pFT_Library_SetLcdFilter )
6149 pFT_Library_SetLcdFilter( library, lcdfilter );
6150 pFT_Render_Glyph (ft_face->glyph, render_mode);
6152 src = ft_face->glyph->bitmap.buffer;
6153 src_pitch = ft_face->glyph->bitmap.pitch;
6154 src_width = ft_face->glyph->bitmap.width;
6155 src_height = ft_face->glyph->bitmap.rows;
6157 if ( render_mode == FT_RENDER_MODE_LCD)
6165 rgb_interval = src_pitch;
6170 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
6171 if ( x_shift < 0 ) x_shift = 0;
6172 if ( x_shift + (src_width / hmul) > width )
6173 x_shift = width - (src_width / hmul);
6175 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
6176 if ( y_shift < 0 ) y_shift = 0;
6177 if ( y_shift + (src_height / vmul) > height )
6178 y_shift = height - (src_height / vmul);
6180 dst += x_shift + y_shift * ( pitch / 4 );
6181 while ( src_height )
6183 for ( x = 0; x < src_width / hmul; x++ )
6187 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
6188 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6189 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
6190 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6194 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
6195 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6196 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
6197 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6200 src += src_pitch * vmul;
6209 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
6221 int contour, point = 0, first_pt;
6222 FT_Outline *outline = &ft_face->glyph->outline;
6223 TTPOLYGONHEADER *pph;
6225 DWORD pph_start, cpfx, type;
6227 if(buflen == 0) buf = NULL;
6229 if (needsTransform && buf) {
6230 pFT_Outline_Transform(outline, &transMat);
6233 for(contour = 0; contour < outline->n_contours; contour++) {
6234 /* Ignore contours containing one point */
6235 if(point == outline->contours[contour]) {
6241 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6244 pph->dwType = TT_POLYGON_TYPE;
6245 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6247 needed += sizeof(*pph);
6249 while(point <= outline->contours[contour]) {
6250 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6251 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6252 TT_PRIM_LINE : TT_PRIM_QSPLINE;
6256 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6259 } while(point <= outline->contours[contour] &&
6260 (outline->tags[point] & FT_Curve_Tag_On) ==
6261 (outline->tags[point-1] & FT_Curve_Tag_On));
6262 /* At the end of a contour Windows adds the start point, but
6264 if(point > outline->contours[contour] &&
6265 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
6267 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
6269 } else if(point <= outline->contours[contour] &&
6270 outline->tags[point] & FT_Curve_Tag_On) {
6271 /* add closing pt for bezier */
6273 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6281 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6284 pph->cb = needed - pph_start;
6290 /* Convert the quadratic Beziers to cubic Beziers.
6291 The parametric eqn for a cubic Bezier is, from PLRM:
6292 r(t) = at^3 + bt^2 + ct + r0
6293 with the control points:
6298 A quadratic Bezier has the form:
6299 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6301 So equating powers of t leads to:
6302 r1 = 2/3 p1 + 1/3 p0
6303 r2 = 2/3 p1 + 1/3 p2
6304 and of course r0 = p0, r3 = p2
6307 int contour, point = 0, first_pt;
6308 FT_Outline *outline = &ft_face->glyph->outline;
6309 TTPOLYGONHEADER *pph;
6311 DWORD pph_start, cpfx, type;
6312 FT_Vector cubic_control[4];
6313 if(buflen == 0) buf = NULL;
6315 if (needsTransform && buf) {
6316 pFT_Outline_Transform(outline, &transMat);
6319 for(contour = 0; contour < outline->n_contours; contour++) {
6321 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6324 pph->dwType = TT_POLYGON_TYPE;
6325 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6327 needed += sizeof(*pph);
6329 while(point <= outline->contours[contour]) {
6330 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6331 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6332 TT_PRIM_LINE : TT_PRIM_CSPLINE;
6335 if(type == TT_PRIM_LINE) {
6337 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6341 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6344 /* FIXME: Possible optimization in endpoint calculation
6345 if there are two consecutive curves */
6346 cubic_control[0] = outline->points[point-1];
6347 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
6348 cubic_control[0].x += outline->points[point].x + 1;
6349 cubic_control[0].y += outline->points[point].y + 1;
6350 cubic_control[0].x >>= 1;
6351 cubic_control[0].y >>= 1;
6353 if(point+1 > outline->contours[contour])
6354 cubic_control[3] = outline->points[first_pt];
6356 cubic_control[3] = outline->points[point+1];
6357 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
6358 cubic_control[3].x += outline->points[point].x + 1;
6359 cubic_control[3].y += outline->points[point].y + 1;
6360 cubic_control[3].x >>= 1;
6361 cubic_control[3].y >>= 1;
6364 /* r1 = 1/3 p0 + 2/3 p1
6365 r2 = 1/3 p2 + 2/3 p1 */
6366 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
6367 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
6368 cubic_control[2] = cubic_control[1];
6369 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
6370 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
6371 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
6372 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
6374 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
6375 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
6376 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
6381 } while(point <= outline->contours[contour] &&
6382 (outline->tags[point] & FT_Curve_Tag_On) ==
6383 (outline->tags[point-1] & FT_Curve_Tag_On));
6384 /* At the end of a contour Windows adds the start point,
6385 but only for Beziers and we've already done that.
6387 if(point <= outline->contours[contour] &&
6388 outline->tags[point] & FT_Curve_Tag_On) {
6389 /* This is the closing pt of a bezier, but we've already
6390 added it, so just inc point and carry on */
6397 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6400 pph->cb = needed - pph_start;
6406 FIXME("Unsupported format %d\n", format);
6412 static BOOL get_bitmap_text_metrics(GdiFont *font)
6414 FT_Face ft_face = font->ft_face;
6415 FT_WinFNT_HeaderRec winfnt_header;
6416 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
6417 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
6418 font->potm->otmSize = size;
6420 #define TM font->potm->otmTextMetrics
6421 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
6423 TM.tmHeight = winfnt_header.pixel_height;
6424 TM.tmAscent = winfnt_header.ascent;
6425 TM.tmDescent = TM.tmHeight - TM.tmAscent;
6426 TM.tmInternalLeading = winfnt_header.internal_leading;
6427 TM.tmExternalLeading = winfnt_header.external_leading;
6428 TM.tmAveCharWidth = winfnt_header.avg_width;
6429 TM.tmMaxCharWidth = winfnt_header.max_width;
6430 TM.tmWeight = winfnt_header.weight;
6432 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
6433 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
6434 TM.tmFirstChar = winfnt_header.first_char;
6435 TM.tmLastChar = winfnt_header.last_char;
6436 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
6437 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
6438 TM.tmItalic = winfnt_header.italic;
6439 TM.tmUnderlined = font->underline;
6440 TM.tmStruckOut = font->strikeout;
6441 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
6442 TM.tmCharSet = winfnt_header.charset;
6446 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
6447 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
6448 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6449 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
6450 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
6451 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
6452 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
6453 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
6455 TM.tmDigitizedAspectX = 96; /* FIXME */
6456 TM.tmDigitizedAspectY = 96; /* FIXME */
6458 TM.tmLastChar = 255;
6459 TM.tmDefaultChar = 32;
6460 TM.tmBreakChar = 32;
6461 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
6462 TM.tmUnderlined = font->underline;
6463 TM.tmStruckOut = font->strikeout;
6464 /* NB inverted meaning of TMPF_FIXED_PITCH */
6465 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
6466 TM.tmCharSet = font->charset;
6474 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
6476 double scale_x, scale_y;
6480 scale_x = (double)font->aveWidth;
6481 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6484 scale_x = font->scale_y;
6486 scale_x *= fabs(font->font_desc.matrix.eM11);
6487 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6489 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6490 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6492 SCALE_Y(ptm->tmHeight);
6493 SCALE_Y(ptm->tmAscent);
6494 SCALE_Y(ptm->tmDescent);
6495 SCALE_Y(ptm->tmInternalLeading);
6496 SCALE_Y(ptm->tmExternalLeading);
6497 SCALE_Y(ptm->tmOverhang);
6499 SCALE_X(ptm->tmAveCharWidth);
6500 SCALE_X(ptm->tmMaxCharWidth);
6506 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
6508 double scale_x, scale_y;
6512 scale_x = (double)font->aveWidth;
6513 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6516 scale_x = font->scale_y;
6518 scale_x *= fabs(font->font_desc.matrix.eM11);
6519 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6521 scale_font_metrics(font, &potm->otmTextMetrics);
6523 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6524 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6526 SCALE_Y(potm->otmAscent);
6527 SCALE_Y(potm->otmDescent);
6528 SCALE_Y(potm->otmLineGap);
6529 SCALE_Y(potm->otmsCapEmHeight);
6530 SCALE_Y(potm->otmsXHeight);
6531 SCALE_Y(potm->otmrcFontBox.top);
6532 SCALE_Y(potm->otmrcFontBox.bottom);
6533 SCALE_X(potm->otmrcFontBox.left);
6534 SCALE_X(potm->otmrcFontBox.right);
6535 SCALE_Y(potm->otmMacAscent);
6536 SCALE_Y(potm->otmMacDescent);
6537 SCALE_Y(potm->otmMacLineGap);
6538 SCALE_X(potm->otmptSubscriptSize.x);
6539 SCALE_Y(potm->otmptSubscriptSize.y);
6540 SCALE_X(potm->otmptSubscriptOffset.x);
6541 SCALE_Y(potm->otmptSubscriptOffset.y);
6542 SCALE_X(potm->otmptSuperscriptSize.x);
6543 SCALE_Y(potm->otmptSuperscriptSize.y);
6544 SCALE_X(potm->otmptSuperscriptOffset.x);
6545 SCALE_Y(potm->otmptSuperscriptOffset.y);
6546 SCALE_Y(potm->otmsStrikeoutSize);
6547 SCALE_Y(potm->otmsStrikeoutPosition);
6548 SCALE_Y(potm->otmsUnderscoreSize);
6549 SCALE_Y(potm->otmsUnderscorePosition);
6555 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
6559 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
6561 /* Make sure that the font has sane width/height ratio */
6564 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
6566 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
6571 *ptm = font->potm->otmTextMetrics;
6572 scale_font_metrics(font, ptm);
6576 static BOOL face_has_symbol_charmap(FT_Face ft_face)
6580 for(i = 0; i < ft_face->num_charmaps; i++)
6582 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
6588 static BOOL get_outline_text_metrics(GdiFont *font)
6591 FT_Face ft_face = font->ft_face;
6592 UINT needed, lenfam, lensty, lenface, lenfull;
6594 TT_HoriHeader *pHori;
6595 TT_Postscript *pPost;
6596 FT_Fixed x_scale, y_scale;
6597 WCHAR *family_nameW, *style_nameW, *face_nameW, *full_nameW;
6599 INT ascent, descent;
6601 TRACE("font=%p\n", font);
6603 if(!FT_IS_SCALABLE(ft_face))
6606 needed = sizeof(*font->potm);
6608 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
6609 family_nameW = strdupW(font->name);
6611 style_nameW = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
6613 style_nameW = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
6616 FIXME("failed to read style_nameW for font %s!\n", wine_dbgstr_w(font->name));
6617 style_nameW = towstr( CP_ACP, ft_face->style_name );
6619 lensty = (strlenW(style_nameW) + 1) * sizeof(WCHAR);
6621 face_nameW = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
6623 face_nameW = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES );
6626 FIXME("failed to read face_nameW for font %s!\n", wine_dbgstr_w(font->name));
6627 face_nameW = strdupW(font->name);
6629 if (font->name[0] == '@') face_nameW = prepend_at( face_nameW );
6630 lenface = (strlenW(face_nameW) + 1) * sizeof(WCHAR);
6632 full_nameW = get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, GetSystemDefaultLangID() );
6634 full_nameW = get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, TT_MS_LANGID_ENGLISH_UNITED_STATES );
6637 WCHAR fake_nameW[] = {'f','a','k','e',' ','n','a','m','e', 0};
6638 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w(font->name));
6639 full_nameW = strdupW(fake_nameW);
6641 lenfull = (strlenW(full_nameW) + 1) * sizeof(WCHAR);
6643 /* These names should be read from the TT name table */
6645 /* length of otmpFamilyName */
6648 /* length of otmpFaceName */
6651 /* length of otmpStyleName */
6654 /* length of otmpFullName */
6658 x_scale = ft_face->size->metrics.x_scale;
6659 y_scale = ft_face->size->metrics.y_scale;
6661 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
6663 FIXME("Can't find OS/2 table - not TT font?\n");
6667 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
6669 FIXME("Can't find HHEA table - not TT font?\n");
6673 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
6675 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",
6676 pOS2->usWinAscent, pOS2->usWinDescent,
6677 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
6678 pOS2->xAvgCharWidth,
6679 ft_face->ascender, ft_face->descender, ft_face->height,
6680 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
6681 ft_face->bbox.yMax, ft_face->bbox.yMin);
6683 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
6684 font->potm->otmSize = needed;
6686 #define TM font->potm->otmTextMetrics
6688 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
6689 ascent = pHori->Ascender;
6690 descent = -pHori->Descender;
6692 ascent = pOS2->usWinAscent;
6693 descent = pOS2->usWinDescent;
6696 font->ntmCellHeight = ascent + descent;
6697 font->ntmAvgWidth = pOS2->xAvgCharWidth;
6700 TM.tmAscent = font->yMax;
6701 TM.tmDescent = -font->yMin;
6702 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
6704 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
6705 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
6706 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
6707 - ft_face->units_per_EM, y_scale) + 32) >> 6;
6710 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6713 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6715 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
6716 ((ascent + descent) -
6717 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
6719 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
6720 if (TM.tmAveCharWidth == 0) {
6721 TM.tmAveCharWidth = 1;
6723 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
6724 TM.tmWeight = FW_REGULAR;
6725 if (font->fake_bold)
6726 TM.tmWeight = FW_BOLD;
6729 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
6731 if (pOS2->usWeightClass > FW_MEDIUM)
6732 TM.tmWeight = pOS2->usWeightClass;
6734 else if (pOS2->usWeightClass <= FW_MEDIUM)
6735 TM.tmWeight = pOS2->usWeightClass;
6738 TM.tmDigitizedAspectX = 96; /* FIXME */
6739 TM.tmDigitizedAspectY = 96; /* FIXME */
6740 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6741 * symbol range to 0 - f0ff
6744 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
6749 case 1257: /* Baltic */
6750 TM.tmLastChar = 0xf8fd;
6753 TM.tmLastChar = 0xf0ff;
6755 TM.tmBreakChar = 0x20;
6756 TM.tmDefaultChar = 0x1f;
6760 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
6761 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
6763 if(pOS2->usFirstCharIndex <= 1)
6764 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
6765 else if (pOS2->usFirstCharIndex > 0xff)
6766 TM.tmBreakChar = 0x20;
6768 TM.tmBreakChar = pOS2->usFirstCharIndex;
6769 TM.tmDefaultChar = TM.tmBreakChar - 1;
6771 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
6772 TM.tmUnderlined = font->underline;
6773 TM.tmStruckOut = font->strikeout;
6775 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6776 if(!FT_IS_FIXED_WIDTH(ft_face) &&
6777 (pOS2->version == 0xFFFFU ||
6778 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
6779 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
6781 TM.tmPitchAndFamily = 0;
6783 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
6785 case PAN_FAMILY_SCRIPT:
6786 TM.tmPitchAndFamily |= FF_SCRIPT;
6789 case PAN_FAMILY_DECORATIVE:
6790 TM.tmPitchAndFamily |= FF_DECORATIVE;
6795 case PAN_FAMILY_TEXT_DISPLAY:
6796 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
6797 /* which is clearly not what the panose spec says. */
6799 if(TM.tmPitchAndFamily == 0 || /* fixed */
6800 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
6801 TM.tmPitchAndFamily = FF_MODERN;
6804 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
6809 TM.tmPitchAndFamily |= FF_DONTCARE;
6812 case PAN_SERIF_COVE:
6813 case PAN_SERIF_OBTUSE_COVE:
6814 case PAN_SERIF_SQUARE_COVE:
6815 case PAN_SERIF_OBTUSE_SQUARE_COVE:
6816 case PAN_SERIF_SQUARE:
6817 case PAN_SERIF_THIN:
6818 case PAN_SERIF_BONE:
6819 case PAN_SERIF_EXAGGERATED:
6820 case PAN_SERIF_TRIANGLE:
6821 TM.tmPitchAndFamily |= FF_ROMAN;
6824 case PAN_SERIF_NORMAL_SANS:
6825 case PAN_SERIF_OBTUSE_SANS:
6826 case PAN_SERIF_PERP_SANS:
6827 case PAN_SERIF_FLARED:
6828 case PAN_SERIF_ROUNDED:
6829 TM.tmPitchAndFamily |= FF_SWISS;
6836 if(FT_IS_SCALABLE(ft_face))
6837 TM.tmPitchAndFamily |= TMPF_VECTOR;
6839 if(FT_IS_SFNT(ft_face))
6841 if (font->ntmFlags & NTM_PS_OPENTYPE)
6842 TM.tmPitchAndFamily |= TMPF_DEVICE;
6844 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
6847 TM.tmCharSet = font->charset;
6849 font->potm->otmFiller = 0;
6850 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
6851 font->potm->otmfsSelection = pOS2->fsSelection;
6852 font->potm->otmfsType = pOS2->fsType;
6853 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
6854 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
6855 font->potm->otmItalicAngle = 0; /* POST table */
6856 font->potm->otmEMSquare = ft_face->units_per_EM;
6857 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
6858 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
6859 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
6860 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
6861 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
6862 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
6863 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
6864 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
6865 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
6866 font->potm->otmMacAscent = TM.tmAscent;
6867 font->potm->otmMacDescent = -TM.tmDescent;
6868 font->potm->otmMacLineGap = font->potm->otmLineGap;
6869 font->potm->otmusMinimumPPEM = 0; /* TT Header */
6870 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
6871 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
6872 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
6873 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
6874 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
6875 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
6876 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
6877 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
6878 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
6879 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
6881 font->potm->otmsUnderscoreSize = 0;
6882 font->potm->otmsUnderscorePosition = 0;
6884 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
6885 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
6889 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
6890 cp = (char*)font->potm + sizeof(*font->potm);
6891 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
6892 strcpyW((WCHAR*)cp, family_nameW);
6894 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
6895 strcpyW((WCHAR*)cp, style_nameW);
6897 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
6898 strcpyW((WCHAR*)cp, face_nameW);
6900 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
6901 strcpyW((WCHAR*)cp, full_nameW);
6905 HeapFree(GetProcessHeap(), 0, style_nameW);
6906 HeapFree(GetProcessHeap(), 0, family_nameW);
6907 HeapFree(GetProcessHeap(), 0, face_nameW);
6908 HeapFree(GetProcessHeap(), 0, full_nameW);
6912 /*************************************************************
6913 * freetype_GetGlyphOutline
6915 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
6916 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
6918 struct freetype_physdev *physdev = get_freetype_dev( dev );
6924 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
6925 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
6929 EnterCriticalSection( &freetype_cs );
6930 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, &abc, buflen, buf, lpmat );
6931 LeaveCriticalSection( &freetype_cs );
6935 /*************************************************************
6936 * freetype_GetTextMetrics
6938 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
6940 struct freetype_physdev *physdev = get_freetype_dev( dev );
6945 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
6946 return dev->funcs->pGetTextMetrics( dev, metrics );
6950 EnterCriticalSection( &freetype_cs );
6951 ret = get_text_metrics( physdev->font, metrics );
6952 LeaveCriticalSection( &freetype_cs );
6956 /*************************************************************
6957 * freetype_GetOutlineTextMetrics
6959 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
6961 struct freetype_physdev *physdev = get_freetype_dev( dev );
6966 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
6967 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
6970 TRACE("font=%p\n", physdev->font);
6972 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
6975 EnterCriticalSection( &freetype_cs );
6977 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
6979 if(cbSize >= physdev->font->potm->otmSize)
6981 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
6982 scale_outline_font_metrics(physdev->font, potm);
6984 ret = physdev->font->potm->otmSize;
6986 LeaveCriticalSection( &freetype_cs );
6990 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
6992 child->font = alloc_font();
6993 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
6994 if(!child->font->ft_face)
6996 free_font(child->font);
7001 child->font->font_desc = font->font_desc;
7002 child->font->ntmFlags = child->face->ntmFlags;
7003 child->font->orientation = font->orientation;
7004 child->font->scale_y = font->scale_y;
7005 child->font->name = strdupW(child->face->family->FamilyName);
7006 child->font->base_font = font;
7007 TRACE("created child font %p for base %p\n", child->font, font);
7011 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
7014 CHILD_FONT *child_font;
7017 font = font->base_font;
7019 *linked_font = font;
7021 if((*glyph = get_glyph_index(font, c)))
7023 *glyph = get_GSUB_vert_glyph(font, *glyph);
7027 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
7029 if(!child_font->font)
7030 if(!load_child_font(font, child_font))
7033 if(!child_font->font->ft_face)
7035 g = get_glyph_index(child_font->font, c);
7036 g = get_GSUB_vert_glyph(child_font->font, g);
7040 *linked_font = child_font->font;
7047 /*************************************************************
7048 * freetype_GetCharWidth
7050 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
7052 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7056 struct freetype_physdev *physdev = get_freetype_dev( dev );
7060 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
7061 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
7064 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
7067 EnterCriticalSection( &freetype_cs );
7068 for(c = firstChar; c <= lastChar; c++) {
7069 get_glyph_outline( physdev->font, c, GGO_METRICS, &gm, &abc, 0, NULL, &identity );
7070 buffer[c - firstChar] = abc.abcA + abc.abcB + abc.abcC;
7072 LeaveCriticalSection( &freetype_cs );
7076 /*************************************************************
7077 * freetype_GetCharABCWidths
7079 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
7081 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7084 struct freetype_physdev *physdev = get_freetype_dev( dev );
7088 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
7089 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
7092 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
7095 EnterCriticalSection( &freetype_cs );
7097 for(c = firstChar; c <= lastChar; c++, buffer++)
7098 get_glyph_outline( physdev->font, c, GGO_METRICS, &gm, buffer, 0, NULL, &identity );
7100 LeaveCriticalSection( &freetype_cs );
7104 /*************************************************************
7105 * freetype_GetCharABCWidthsI
7107 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
7109 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7112 struct freetype_physdev *physdev = get_freetype_dev( dev );
7116 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
7117 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
7120 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
7124 EnterCriticalSection( &freetype_cs );
7126 for(c = 0; c < count; c++, buffer++)
7127 get_glyph_outline( physdev->font, pgi ? pgi[c] : firstChar + c, GGO_METRICS | GGO_GLYPH_INDEX,
7128 &gm, buffer, 0, NULL, &identity );
7130 LeaveCriticalSection( &freetype_cs );
7134 /*************************************************************
7135 * freetype_GetTextExtentExPoint
7137 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count,
7138 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
7140 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7146 struct freetype_physdev *physdev = get_freetype_dev( dev );
7150 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
7151 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, max_ext, pnfit, dxs, size );
7154 TRACE("%p, %s, %d, %d, %p\n", physdev->font, debugstr_wn(wstr, count), count, max_ext, size);
7157 EnterCriticalSection( &freetype_cs );
7160 get_text_metrics( physdev->font, &tm );
7161 size->cy = tm.tmHeight;
7163 for(idx = 0; idx < count; idx++) {
7164 get_glyph_outline( physdev->font, wstr[idx], GGO_METRICS, &gm, &abc, 0, NULL, &identity );
7165 size->cx += abc.abcA + abc.abcB + abc.abcC;
7167 if (! pnfit || ext <= max_ext) {
7177 LeaveCriticalSection( &freetype_cs );
7178 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
7182 /*************************************************************
7183 * freetype_GetTextExtentExPointI
7185 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count,
7186 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size )
7188 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7194 struct freetype_physdev *physdev = get_freetype_dev( dev );
7198 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
7199 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, max_ext, pnfit, dxs, size );
7202 TRACE("%p, %p, %d, %d, %p\n", physdev->font, indices, count, max_ext, size);
7205 EnterCriticalSection( &freetype_cs );
7208 get_text_metrics(physdev->font, &tm);
7209 size->cy = tm.tmHeight;
7211 for(idx = 0; idx < count; idx++) {
7212 get_glyph_outline( physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX,
7213 &gm, &abc, 0, NULL, &identity );
7214 size->cx += abc.abcA + abc.abcB + abc.abcC;
7216 if (! pnfit || ext <= max_ext) {
7226 LeaveCriticalSection( &freetype_cs );
7227 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
7231 /*************************************************************
7232 * freetype_GetFontData
7234 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
7236 struct freetype_physdev *physdev = get_freetype_dev( dev );
7240 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
7241 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
7244 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
7245 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
7246 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
7248 return get_font_data( physdev->font, table, offset, buf, cbData );
7251 /*************************************************************
7252 * freetype_GetTextFace
7254 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
7257 struct freetype_physdev *physdev = get_freetype_dev( dev );
7261 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
7262 return dev->funcs->pGetTextFace( dev, count, str );
7265 n = strlenW(physdev->font->name) + 1;
7268 lstrcpynW(str, physdev->font->name, count);
7274 /*************************************************************
7275 * freetype_GetTextCharsetInfo
7277 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
7279 struct freetype_physdev *physdev = get_freetype_dev( dev );
7283 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
7284 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
7286 if (fs) *fs = physdev->font->fs;
7287 return physdev->font->charset;
7290 /* Retrieve a list of supported Unicode ranges for a given font.
7291 * Can be called with NULL gs to calculate the buffer size. Returns
7292 * the number of ranges found.
7294 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
7296 DWORD num_ranges = 0;
7298 if (face->charmap->encoding == FT_ENCODING_UNICODE)
7301 FT_ULong char_code, char_code_prev;
7304 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
7306 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
7307 face->num_glyphs, glyph_code, char_code);
7309 if (!glyph_code) return 0;
7313 gs->ranges[0].wcLow = (USHORT)char_code;
7314 gs->ranges[0].cGlyphs = 0;
7315 gs->cGlyphsSupported = 0;
7321 if (char_code < char_code_prev)
7323 ERR("expected increasing char code from FT_Get_Next_Char\n");
7326 if (char_code - char_code_prev > 1)
7331 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
7332 gs->ranges[num_ranges - 1].cGlyphs = 1;
7333 gs->cGlyphsSupported++;
7338 gs->ranges[num_ranges - 1].cGlyphs++;
7339 gs->cGlyphsSupported++;
7341 char_code_prev = char_code;
7342 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
7346 FIXME("encoding %u not supported\n", face->charmap->encoding);
7351 /*************************************************************
7352 * freetype_GetFontUnicodeRanges
7354 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
7356 struct freetype_physdev *physdev = get_freetype_dev( dev );
7357 DWORD size, num_ranges;
7361 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
7362 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
7365 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
7366 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
7369 glyphset->cbThis = size;
7370 glyphset->cRanges = num_ranges;
7371 glyphset->flAccel = 0;
7376 /*************************************************************
7377 * freetype_FontIsLinked
7379 static BOOL freetype_FontIsLinked( PHYSDEV dev )
7381 struct freetype_physdev *physdev = get_freetype_dev( dev );
7386 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
7387 return dev->funcs->pFontIsLinked( dev );
7391 EnterCriticalSection( &freetype_cs );
7392 ret = !list_empty(&physdev->font->child_fonts);
7393 LeaveCriticalSection( &freetype_cs );
7397 /*************************************************************************
7398 * GetRasterizerCaps (GDI32.@)
7400 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7402 lprs->nSize = sizeof(RASTERIZER_STATUS);
7403 lprs->wFlags = TT_AVAILABLE | TT_ENABLED;
7404 lprs->nLanguageID = 0;
7408 /*************************************************************
7409 * freetype_GdiRealizationInfo
7411 static BOOL freetype_GdiRealizationInfo( PHYSDEV dev, void *ptr )
7413 struct freetype_physdev *physdev = get_freetype_dev( dev );
7414 realization_info_t *info = ptr;
7418 dev = GET_NEXT_PHYSDEV( dev, pGdiRealizationInfo );
7419 return dev->funcs->pGdiRealizationInfo( dev, ptr );
7422 FIXME("(%p, %p): stub!\n", physdev->font, info);
7425 if(FT_IS_SCALABLE(physdev->font->ft_face))
7428 info->cache_num = physdev->font->cache_num;
7429 info->unknown2 = -1;
7433 /*************************************************************************
7434 * Kerning support for TrueType fonts
7436 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
7438 struct TT_kern_table
7444 struct TT_kern_subtable
7453 USHORT horizontal : 1;
7455 USHORT cross_stream: 1;
7456 USHORT override : 1;
7457 USHORT reserved1 : 4;
7463 struct TT_format0_kern_subtable
7467 USHORT entrySelector;
7478 static DWORD parse_format0_kern_subtable(GdiFont *font,
7479 const struct TT_format0_kern_subtable *tt_f0_ks,
7480 const USHORT *glyph_to_char,
7481 KERNINGPAIR *kern_pair, DWORD cPairs)
7484 const struct TT_kern_pair *tt_kern_pair;
7486 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
7488 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
7490 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7491 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
7492 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
7494 if (!kern_pair || !cPairs)
7497 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
7499 nPairs = min(nPairs, cPairs);
7501 for (i = 0; i < nPairs; i++)
7503 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
7504 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
7505 /* this algorithm appears to better match what Windows does */
7506 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
7507 if (kern_pair->iKernAmount < 0)
7509 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
7510 kern_pair->iKernAmount -= font->ppem;
7512 else if (kern_pair->iKernAmount > 0)
7514 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
7515 kern_pair->iKernAmount += font->ppem;
7517 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
7519 TRACE("left %u right %u value %d\n",
7520 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
7524 TRACE("copied %u entries\n", nPairs);
7528 /*************************************************************
7529 * freetype_GetKerningPairs
7531 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
7535 const struct TT_kern_table *tt_kern_table;
7536 const struct TT_kern_subtable *tt_kern_subtable;
7538 USHORT *glyph_to_char;
7540 struct freetype_physdev *physdev = get_freetype_dev( dev );
7542 if (!(font = physdev->font))
7544 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
7545 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
7549 EnterCriticalSection( &freetype_cs );
7550 if (font->total_kern_pairs != (DWORD)-1)
7552 if (cPairs && kern_pair)
7554 cPairs = min(cPairs, font->total_kern_pairs);
7555 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7557 else cPairs = font->total_kern_pairs;
7559 LeaveCriticalSection( &freetype_cs );
7563 font->total_kern_pairs = 0;
7565 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
7567 if (length == GDI_ERROR)
7569 TRACE("no kerning data in the font\n");
7570 LeaveCriticalSection( &freetype_cs );
7574 buf = HeapAlloc(GetProcessHeap(), 0, length);
7577 WARN("Out of memory\n");
7578 LeaveCriticalSection( &freetype_cs );
7582 get_font_data(font, MS_KERN_TAG, 0, buf, length);
7584 /* build a glyph index to char code map */
7585 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
7588 WARN("Out of memory allocating a glyph index to char code map\n");
7589 HeapFree(GetProcessHeap(), 0, buf);
7590 LeaveCriticalSection( &freetype_cs );
7594 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
7600 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
7602 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7603 font->ft_face->num_glyphs, glyph_code, char_code);
7607 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7609 /* FIXME: This doesn't match what Windows does: it does some fancy
7610 * things with duplicate glyph index to char code mappings, while
7611 * we just avoid overriding existing entries.
7613 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
7614 glyph_to_char[glyph_code] = (USHORT)char_code;
7616 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
7623 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
7624 for (n = 0; n <= 65535; n++)
7625 glyph_to_char[n] = (USHORT)n;
7628 tt_kern_table = buf;
7629 nTables = GET_BE_WORD(tt_kern_table->nTables);
7630 TRACE("version %u, nTables %u\n",
7631 GET_BE_WORD(tt_kern_table->version), nTables);
7633 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
7635 for (i = 0; i < nTables; i++)
7637 struct TT_kern_subtable tt_kern_subtable_copy;
7639 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
7640 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
7641 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
7643 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7644 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
7645 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
7647 /* According to the TrueType specification this is the only format
7648 * that will be properly interpreted by Windows and OS/2
7650 if (tt_kern_subtable_copy.coverage.bits.format == 0)
7652 DWORD new_chunk, old_total = font->total_kern_pairs;
7654 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7655 glyph_to_char, NULL, 0);
7656 font->total_kern_pairs += new_chunk;
7658 if (!font->kern_pairs)
7659 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
7660 font->total_kern_pairs * sizeof(*font->kern_pairs));
7662 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
7663 font->total_kern_pairs * sizeof(*font->kern_pairs));
7665 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7666 glyph_to_char, font->kern_pairs + old_total, new_chunk);
7669 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
7671 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
7674 HeapFree(GetProcessHeap(), 0, glyph_to_char);
7675 HeapFree(GetProcessHeap(), 0, buf);
7677 if (cPairs && kern_pair)
7679 cPairs = min(cPairs, font->total_kern_pairs);
7680 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7682 else cPairs = font->total_kern_pairs;
7684 LeaveCriticalSection( &freetype_cs );
7688 static const struct gdi_dc_funcs freetype_funcs =
7690 NULL, /* pAbortDoc */
7691 NULL, /* pAbortPath */
7692 NULL, /* pAlphaBlend */
7693 NULL, /* pAngleArc */
7696 NULL, /* pBeginPath */
7697 NULL, /* pBlendImage */
7699 NULL, /* pCloseFigure */
7700 NULL, /* pCreateCompatibleDC */
7701 freetype_CreateDC, /* pCreateDC */
7702 freetype_DeleteDC, /* pDeleteDC */
7703 NULL, /* pDeleteObject */
7704 NULL, /* pDeviceCapabilities */
7705 NULL, /* pEllipse */
7707 NULL, /* pEndPage */
7708 NULL, /* pEndPath */
7709 freetype_EnumFonts, /* pEnumFonts */
7710 NULL, /* pEnumICMProfiles */
7711 NULL, /* pExcludeClipRect */
7712 NULL, /* pExtDeviceMode */
7713 NULL, /* pExtEscape */
7714 NULL, /* pExtFloodFill */
7715 NULL, /* pExtSelectClipRgn */
7716 NULL, /* pExtTextOut */
7717 NULL, /* pFillPath */
7718 NULL, /* pFillRgn */
7719 NULL, /* pFlattenPath */
7720 freetype_FontIsLinked, /* pFontIsLinked */
7721 NULL, /* pFrameRgn */
7722 NULL, /* pGdiComment */
7723 freetype_GdiRealizationInfo, /* pGdiRealizationInfo */
7724 NULL, /* pGetBoundsRect */
7725 freetype_GetCharABCWidths, /* pGetCharABCWidths */
7726 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
7727 freetype_GetCharWidth, /* pGetCharWidth */
7728 NULL, /* pGetDeviceCaps */
7729 NULL, /* pGetDeviceGammaRamp */
7730 freetype_GetFontData, /* pGetFontData */
7731 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
7732 freetype_GetGlyphIndices, /* pGetGlyphIndices */
7733 freetype_GetGlyphOutline, /* pGetGlyphOutline */
7734 NULL, /* pGetICMProfile */
7735 NULL, /* pGetImage */
7736 freetype_GetKerningPairs, /* pGetKerningPairs */
7737 NULL, /* pGetNearestColor */
7738 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
7739 NULL, /* pGetPixel */
7740 NULL, /* pGetSystemPaletteEntries */
7741 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
7742 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
7743 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
7744 freetype_GetTextFace, /* pGetTextFace */
7745 freetype_GetTextMetrics, /* pGetTextMetrics */
7746 NULL, /* pGradientFill */
7747 NULL, /* pIntersectClipRect */
7748 NULL, /* pInvertRgn */
7750 NULL, /* pModifyWorldTransform */
7752 NULL, /* pOffsetClipRgn */
7753 NULL, /* pOffsetViewportOrg */
7754 NULL, /* pOffsetWindowOrg */
7755 NULL, /* pPaintRgn */
7758 NULL, /* pPolyBezier */
7759 NULL, /* pPolyBezierTo */
7760 NULL, /* pPolyDraw */
7761 NULL, /* pPolyPolygon */
7762 NULL, /* pPolyPolyline */
7763 NULL, /* pPolygon */
7764 NULL, /* pPolyline */
7765 NULL, /* pPolylineTo */
7766 NULL, /* pPutImage */
7767 NULL, /* pRealizeDefaultPalette */
7768 NULL, /* pRealizePalette */
7769 NULL, /* pRectangle */
7770 NULL, /* pResetDC */
7771 NULL, /* pRestoreDC */
7772 NULL, /* pRoundRect */
7774 NULL, /* pScaleViewportExt */
7775 NULL, /* pScaleWindowExt */
7776 NULL, /* pSelectBitmap */
7777 NULL, /* pSelectBrush */
7778 NULL, /* pSelectClipPath */
7779 freetype_SelectFont, /* pSelectFont */
7780 NULL, /* pSelectPalette */
7781 NULL, /* pSelectPen */
7782 NULL, /* pSetArcDirection */
7783 NULL, /* pSetBkColor */
7784 NULL, /* pSetBkMode */
7785 NULL, /* pSetDCBrushColor */
7786 NULL, /* pSetDCPenColor */
7787 NULL, /* pSetDIBColorTable */
7788 NULL, /* pSetDIBitsToDevice */
7789 NULL, /* pSetDeviceClipping */
7790 NULL, /* pSetDeviceGammaRamp */
7791 NULL, /* pSetLayout */
7792 NULL, /* pSetMapMode */
7793 NULL, /* pSetMapperFlags */
7794 NULL, /* pSetPixel */
7795 NULL, /* pSetPolyFillMode */
7796 NULL, /* pSetROP2 */
7797 NULL, /* pSetRelAbs */
7798 NULL, /* pSetStretchBltMode */
7799 NULL, /* pSetTextAlign */
7800 NULL, /* pSetTextCharacterExtra */
7801 NULL, /* pSetTextColor */
7802 NULL, /* pSetTextJustification */
7803 NULL, /* pSetViewportExt */
7804 NULL, /* pSetViewportOrg */
7805 NULL, /* pSetWindowExt */
7806 NULL, /* pSetWindowOrg */
7807 NULL, /* pSetWorldTransform */
7808 NULL, /* pStartDoc */
7809 NULL, /* pStartPage */
7810 NULL, /* pStretchBlt */
7811 NULL, /* pStretchDIBits */
7812 NULL, /* pStrokeAndFillPath */
7813 NULL, /* pStrokePath */
7814 NULL, /* pUnrealizePalette */
7815 NULL, /* pWidenPath */
7816 NULL, /* wine_get_wgl_driver */
7817 GDI_PRIORITY_FONT_DRV /* priority */
7820 #else /* HAVE_FREETYPE */
7822 /*************************************************************************/
7824 BOOL WineEngInit(void)
7829 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7831 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7835 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7837 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7841 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
7843 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
7847 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
7848 LPCWSTR font_file, LPCWSTR font_path )
7854 /*************************************************************************
7855 * GetRasterizerCaps (GDI32.@)
7857 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7859 lprs->nSize = sizeof(RASTERIZER_STATUS);
7861 lprs->nLanguageID = 0;
7865 #endif /* HAVE_FREETYPE */