2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
5 * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
7 * This file contains the WineEng* functions.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "wine/port.h"
29 #ifdef HAVE_SYS_STAT_H
30 # include <sys/stat.h>
32 #ifdef HAVE_SYS_MMAN_H
33 # include <sys/mman.h>
42 #ifdef HAVE_CARBON_CARBON_H
43 #define LoadResource __carbon_LoadResource
44 #define CompareString __carbon_CompareString
45 #define GetCurrentThread __carbon_GetCurrentThread
46 #define GetCurrentProcess __carbon_GetCurrentProcess
47 #define AnimatePalette __carbon_AnimatePalette
48 #define EqualRgn __carbon_EqualRgn
49 #define FillRgn __carbon_FillRgn
50 #define FrameRgn __carbon_FrameRgn
51 #define GetPixel __carbon_GetPixel
52 #define InvertRgn __carbon_InvertRgn
53 #define LineTo __carbon_LineTo
54 #define OffsetRgn __carbon_OffsetRgn
55 #define PaintRgn __carbon_PaintRgn
56 #define Polygon __carbon_Polygon
57 #define ResizePalette __carbon_ResizePalette
58 #define SetRectRgn __carbon_SetRectRgn
59 #include <Carbon/Carbon.h>
62 #undef GetCurrentThread
65 #undef GetCurrentProcess
78 #endif /* HAVE_CARBON_CARBON_H */
86 #include "gdi_private.h"
87 #include "wine/library.h"
88 #include "wine/unicode.h"
89 #include "wine/debug.h"
90 #include "wine/list.h"
94 WINE_DEFAULT_DEBUG_CHANNEL(font);
98 #ifdef HAVE_FT2BUILD_H
101 #ifdef HAVE_FREETYPE_FREETYPE_H
102 #include <freetype/freetype.h>
104 #ifdef HAVE_FREETYPE_FTGLYPH_H
105 #include <freetype/ftglyph.h>
107 #ifdef HAVE_FREETYPE_TTTABLES_H
108 #include <freetype/tttables.h>
110 #ifdef HAVE_FREETYPE_FTTYPES_H
111 #include <freetype/fttypes.h>
113 #ifdef HAVE_FREETYPE_FTSNAMES_H
114 #include <freetype/ftsnames.h>
116 #ifdef HAVE_FREETYPE_TTNAMEID_H
117 #include <freetype/ttnameid.h>
119 #ifdef HAVE_FREETYPE_FTOUTLN_H
120 #include <freetype/ftoutln.h>
122 #ifdef HAVE_FREETYPE_FTTRIGON_H
123 #include <freetype/fttrigon.h>
125 #ifdef HAVE_FREETYPE_FTWINFNT_H
126 #include <freetype/ftwinfnt.h>
128 #ifdef HAVE_FREETYPE_FTMODAPI_H
129 #include <freetype/ftmodapi.h>
131 #ifdef HAVE_FREETYPE_FTLCDFIL_H
132 #include <freetype/ftlcdfil.h>
135 #ifndef HAVE_FT_TRUETYPEENGINETYPE
138 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
139 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
140 FT_TRUETYPE_ENGINE_TYPE_PATENTED
141 } FT_TrueTypeEngineType;
144 static FT_Library library = 0;
151 static FT_Version_t FT_Version;
152 static DWORD FT_SimpleVersion;
154 static void *ft_handle = NULL;
156 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
157 MAKE_FUNCPTR(FT_Done_Face);
158 MAKE_FUNCPTR(FT_Get_Char_Index);
159 MAKE_FUNCPTR(FT_Get_First_Char);
160 MAKE_FUNCPTR(FT_Get_Module);
161 MAKE_FUNCPTR(FT_Get_Next_Char);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
163 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
164 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
165 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
166 MAKE_FUNCPTR(FT_Init_FreeType);
167 MAKE_FUNCPTR(FT_Library_Version);
168 MAKE_FUNCPTR(FT_Load_Glyph);
169 MAKE_FUNCPTR(FT_Load_Sfnt_Table);
170 MAKE_FUNCPTR(FT_Matrix_Multiply);
171 #ifdef FT_MULFIX_INLINED
172 #define pFT_MulFix FT_MULFIX_INLINED
174 MAKE_FUNCPTR(FT_MulFix);
176 MAKE_FUNCPTR(FT_New_Face);
177 MAKE_FUNCPTR(FT_New_Memory_Face);
178 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
179 MAKE_FUNCPTR(FT_Outline_Transform);
180 MAKE_FUNCPTR(FT_Outline_Translate);
181 MAKE_FUNCPTR(FT_Render_Glyph);
182 MAKE_FUNCPTR(FT_Select_Charmap);
183 MAKE_FUNCPTR(FT_Set_Charmap);
184 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
185 MAKE_FUNCPTR(FT_Vector_Transform);
186 MAKE_FUNCPTR(FT_Vector_Unit);
187 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
188 #ifdef HAVE_FREETYPE_FTLCDFIL_H
189 static FT_Error (*pFT_Library_SetLcdFilter)(FT_Library, FT_LcdFilter);
192 #ifdef SONAME_LIBFONTCONFIG
193 #include <fontconfig/fontconfig.h>
194 MAKE_FUNCPTR(FcConfigGetCurrent);
195 MAKE_FUNCPTR(FcFontList);
196 MAKE_FUNCPTR(FcFontSetDestroy);
197 MAKE_FUNCPTR(FcInit);
198 MAKE_FUNCPTR(FcObjectSetAdd);
199 MAKE_FUNCPTR(FcObjectSetCreate);
200 MAKE_FUNCPTR(FcObjectSetDestroy);
201 MAKE_FUNCPTR(FcPatternCreate);
202 MAKE_FUNCPTR(FcPatternDestroy);
203 MAKE_FUNCPTR(FcPatternGetBool);
204 MAKE_FUNCPTR(FcPatternGetString);
210 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
211 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
212 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
215 #ifndef ft_encoding_none
216 #define FT_ENCODING_NONE ft_encoding_none
218 #ifndef ft_encoding_ms_symbol
219 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
221 #ifndef ft_encoding_unicode
222 #define FT_ENCODING_UNICODE ft_encoding_unicode
224 #ifndef ft_encoding_apple_roman
225 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
228 #ifdef WORDS_BIGENDIAN
229 #define GET_BE_WORD(x) (x)
231 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
234 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
241 FT_Short internal_leading;
244 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
245 So to let this compile on older versions of FreeType we'll define the
246 new structure here. */
248 FT_Short height, width;
249 FT_Pos size, x_ppem, y_ppem;
255 NEWTEXTMETRICEXW ntm;
259 typedef struct tagFace {
265 DWORD font_data_size;
269 FT_Fixed font_version;
272 Bitmap_Size size; /* set if face is a bitmap */
273 BOOL external; /* TRUE if we should manually add this font to the registry */
274 struct tagFamily *family;
275 /* Cached data for Enum */
276 struct enum_data *cached_enum_data;
279 typedef struct tagFamily {
284 struct list *replacement;
289 INT adv; /* These three hold to widths of the unrotated chars */
307 typedef struct tagHFONTLIST {
322 struct list hfontlist;
323 OUTLINETEXTMETRICW *potm;
324 DWORD total_kern_pairs;
325 KERNINGPAIR *kern_pairs;
326 struct list child_fonts;
328 /* the following members can be accessed without locking, they are never modified after creation */
330 struct font_mapping *mapping;
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 #define UNUSED_CACHE_SIZE 10
375 static struct list child_font_list = LIST_INIT(child_font_list);
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_internal_leading_value[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
496 static const WCHAR face_font_sig_value[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
497 static const WCHAR face_full_name_value[] = {'F','u','l','l',' ','N','a','m','e','\0'};
510 static struct list mappings_list = LIST_INIT( mappings_list );
512 static CRITICAL_SECTION freetype_cs;
513 static CRITICAL_SECTION_DEBUG critsect_debug =
516 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
517 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
519 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
521 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
523 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
524 static BOOL use_default_fallback = FALSE;
526 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
527 static BOOL get_outline_text_metrics(GdiFont *font);
528 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm);
530 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
531 'W','i','n','d','o','w','s',' ','N','T','\\',
532 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
533 'S','y','s','t','e','m','L','i','n','k',0};
535 static const WCHAR internal_system_link[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
536 'F','o','n','t','L','i','n','k','\\',
537 'S','y','s','t','e','m','L','i','n','k',0};
539 /****************************************
540 * Notes on .fon files
542 * The fonts System, FixedSys and Terminal are special. There are typically multiple
543 * versions installed for different resolutions and codepages. Windows stores which one to use
544 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
546 * FIXEDFON.FON FixedSys
548 * OEMFONT.FON Terminal
549 * LogPixels Current dpi set by the display control panel applet
550 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
551 * also has a LogPixels value that appears to mirror this)
553 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
554 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
555 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
556 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
557 * so that makes sense.
559 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
560 * to be mapped into the registry on Windows 2000 at least).
563 * ega80woa.fon=ega80850.fon
564 * ega40woa.fon=ega40850.fon
565 * cga80woa.fon=cga80850.fon
566 * cga40woa.fon=cga40850.fon
569 /* These are all structures needed for the GSUB table */
571 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
572 #define TATEGAKI_LOWER_BOUND 0x02F1
588 GSUB_ScriptRecord ScriptRecord[1];
594 } GSUB_LangSysRecord;
599 GSUB_LangSysRecord LangSysRecord[1];
603 WORD LookupOrder; /* Reserved */
604 WORD ReqFeatureIndex;
606 WORD FeatureIndex[1];
612 } GSUB_FeatureRecord;
616 GSUB_FeatureRecord FeatureRecord[1];
620 WORD FeatureParams; /* Reserved */
622 WORD LookupListIndex[1];
641 } GSUB_CoverageFormat1;
646 WORD StartCoverageIndex;
652 GSUB_RangeRecord RangeRecord[1];
653 } GSUB_CoverageFormat2;
656 WORD SubstFormat; /* = 1 */
659 } GSUB_SingleSubstFormat1;
662 WORD SubstFormat; /* = 2 */
666 }GSUB_SingleSubstFormat2;
668 #ifdef HAVE_CARBON_CARBON_H
669 static char *find_cache_dir(void)
673 static char cached_path[MAX_PATH];
674 static const char *wine = "/Wine", *fonts = "/Fonts";
676 if(*cached_path) return cached_path;
678 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
681 WARN("can't create cached data folder\n");
684 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
687 WARN("can't create cached data path\n");
691 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
693 ERR("Could not create full path\n");
697 strcat(cached_path, wine);
699 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
701 WARN("Couldn't mkdir %s\n", cached_path);
705 strcat(cached_path, fonts);
706 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
708 WARN("Couldn't mkdir %s\n", cached_path);
715 /******************************************************************
718 * Extracts individual TrueType font files from a Mac suitcase font
719 * and saves them into the user's caches directory (see
721 * Returns a NULL terminated array of filenames.
723 * We do this because they are apps that try to read ttf files
724 * themselves and they don't like Mac suitcase files.
726 static char **expand_mac_font(const char *path)
733 const char *filename;
737 unsigned int size, max_size;
740 TRACE("path %s\n", path);
742 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
745 WARN("failed to get ref\n");
749 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
752 TRACE("no data fork, so trying resource fork\n");
753 res_ref = FSOpenResFile(&ref, fsRdPerm);
756 TRACE("unable to open resource fork\n");
763 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
766 CloseResFile(res_ref);
770 out_dir = find_cache_dir();
772 filename = strrchr(path, '/');
773 if(!filename) filename = path;
776 /* output filename has the form out_dir/filename_%04x.ttf */
777 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
784 unsigned short *num_faces_ptr, num_faces, face;
787 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
789 fond = Get1IndResource(fond_res, idx);
791 TRACE("got fond resource %d\n", idx);
794 fam_rec = *(FamRec**)fond;
795 num_faces_ptr = (unsigned short *)(fam_rec + 1);
796 num_faces = GET_BE_WORD(*num_faces_ptr);
798 assoc = (AsscEntry*)(num_faces_ptr + 1);
799 TRACE("num faces %04x\n", num_faces);
800 for(face = 0; face < num_faces; face++, assoc++)
803 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
804 unsigned short size, font_id;
807 size = GET_BE_WORD(assoc->fontSize);
808 font_id = GET_BE_WORD(assoc->fontID);
811 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
815 TRACE("trying to load sfnt id %04x\n", font_id);
816 sfnt = GetResource(sfnt_res, font_id);
819 TRACE("can't get sfnt resource %04x\n", font_id);
823 output = HeapAlloc(GetProcessHeap(), 0, output_len);
828 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
830 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
831 if(fd != -1 || errno == EEXIST)
835 unsigned char *sfnt_data;
838 sfnt_data = *(unsigned char**)sfnt;
839 write(fd, sfnt_data, GetHandleSize(sfnt));
843 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
846 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
848 ret.array[ret.size++] = output;
852 WARN("unable to create %s\n", output);
853 HeapFree(GetProcessHeap(), 0, output);
856 ReleaseResource(sfnt);
859 ReleaseResource(fond);
862 CloseResFile(res_ref);
867 #endif /* HAVE_CARBON_CARBON_H */
869 static inline BOOL is_win9x(void)
871 return GetVersion() & 0x80000000;
874 This function builds an FT_Fixed from a double. It fails if the absolute
875 value of the float number is greater than 32768.
877 static inline FT_Fixed FT_FixedFromFloat(double f)
883 This function builds an FT_Fixed from a FIXED. It simply put f.value
884 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
886 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
888 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
892 static const struct list *get_face_list_from_family(const Family *family)
894 if (!list_empty(&family->faces))
895 return &family->faces;
897 return family->replacement;
900 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
905 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
906 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
908 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
909 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
911 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
913 const struct list *face_list;
914 if(face_name && strcmpiW(face_name, family->FamilyName))
916 face_list = get_face_list_from_family(family);
917 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
921 file = strrchr(face->file, '/');
926 if(!strcasecmp(file, file_nameA))
928 HeapFree(GetProcessHeap(), 0, file_nameA);
933 HeapFree(GetProcessHeap(), 0, file_nameA);
937 static Family *find_family_from_name(const WCHAR *name)
941 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
943 if(!strcmpiW(family->FamilyName, name))
950 static Family *find_family_from_any_name(const WCHAR *name)
954 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
956 if(!strcmpiW(family->FamilyName, name))
958 if(family->EnglishName && !strcmpiW(family->EnglishName, name))
965 static void DumpSubstList(void)
969 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
971 if(psub->from.charset != -1 || psub->to.charset != -1)
972 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
973 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
975 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
976 debugstr_w(psub->to.name));
981 static LPWSTR strdupW(LPCWSTR p)
984 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
985 ret = HeapAlloc(GetProcessHeap(), 0, len);
990 static LPSTR strdupA(LPCSTR p)
993 DWORD len = (strlen(p) + 1);
994 ret = HeapAlloc(GetProcessHeap(), 0, len);
999 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
1004 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
1006 if(!strcmpiW(element->from.name, from_name) &&
1007 (element->from.charset == from_charset ||
1008 element->from.charset == -1))
1015 #define ADD_FONT_SUBST_FORCE 1
1017 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
1019 FontSubst *from_exist, *to_exist;
1021 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
1023 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
1025 list_remove(&from_exist->entry);
1026 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
1027 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
1028 HeapFree(GetProcessHeap(), 0, from_exist);
1034 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
1038 HeapFree(GetProcessHeap(), 0, subst->to.name);
1039 subst->to.name = strdupW(to_exist->to.name);
1042 list_add_tail(subst_list, &subst->entry);
1047 HeapFree(GetProcessHeap(), 0, subst->from.name);
1048 HeapFree(GetProcessHeap(), 0, subst->to.name);
1049 HeapFree(GetProcessHeap(), 0, subst);
1053 static WCHAR *towstr(UINT cp, const char *str)
1058 len = MultiByteToWideChar(cp, 0, str, -1, NULL, 0);
1059 wstr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1060 MultiByteToWideChar(cp, 0, str, -1, wstr, len);
1064 static void split_subst_info(NameCs *nc, LPSTR str)
1066 CHAR *p = strrchr(str, ',');
1070 nc->charset = strtol(p+1, NULL, 10);
1073 nc->name = towstr(CP_ACP, str);
1076 static void LoadSubstList(void)
1080 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1084 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1085 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1086 &hkey) == ERROR_SUCCESS) {
1088 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1089 &valuelen, &datalen, NULL, NULL);
1091 valuelen++; /* returned value doesn't include room for '\0' */
1092 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1093 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1097 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1098 &dlen) == ERROR_SUCCESS) {
1099 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1101 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1102 split_subst_info(&psub->from, value);
1103 split_subst_info(&psub->to, data);
1105 /* Win 2000 doesn't allow mapping between different charsets
1106 or mapping of DEFAULT_CHARSET */
1107 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1108 psub->to.charset == DEFAULT_CHARSET) {
1109 HeapFree(GetProcessHeap(), 0, psub->to.name);
1110 HeapFree(GetProcessHeap(), 0, psub->from.name);
1111 HeapFree(GetProcessHeap(), 0, psub);
1113 add_font_subst(&font_subst_list, psub, 0);
1115 /* reset dlen and vlen */
1119 HeapFree(GetProcessHeap(), 0, data);
1120 HeapFree(GetProcessHeap(), 0, value);
1126 /*****************************************************************
1127 * get_name_table_entry
1129 * Supply the platform, encoding, language and name ids in req
1130 * and if the name exists the function will fill in the string
1131 * and string_len members. The string is owned by FreeType so
1132 * don't free it. Returns TRUE if the name is found else FALSE.
1134 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1137 FT_UInt num_names, name_index;
1139 if(FT_IS_SFNT(ft_face))
1141 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1143 for(name_index = 0; name_index < num_names; name_index++)
1145 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1147 if((name.platform_id == req->platform_id) &&
1148 (name.encoding_id == req->encoding_id) &&
1149 (name.language_id == req->language_id) &&
1150 (name.name_id == req->name_id))
1152 req->string = name.string;
1153 req->string_len = name.string_len;
1160 req->string_len = 0;
1164 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, FT_UShort language_id)
1169 name.platform_id = TT_PLATFORM_MICROSOFT;
1170 name.encoding_id = TT_MS_ID_UNICODE_CS;
1171 name.language_id = language_id;
1172 name.name_id = name_id;
1174 if(get_name_table_entry(ft_face, &name))
1178 /* String is not nul terminated and string_len is a byte length. */
1179 ret = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1180 for(i = 0; i < name.string_len / 2; i++)
1182 WORD *tmp = (WORD *)&name.string[i * 2];
1183 ret[i] = GET_BE_WORD(*tmp);
1186 TRACE("Got localised name %s\n", debugstr_w(ret));
1192 static inline BOOL faces_equal( const Face *f1, const Face *f2 )
1194 if (strcmpiW( f1->StyleName, f2->StyleName )) return FALSE;
1195 if (f1->scalable) return TRUE;
1196 if (f2->size.y_ppem != f2->size.y_ppem) return FALSE;
1197 return !memcmp( &f1->fs, &f2->fs, sizeof(f1->fs) );
1200 static inline void free_face( Face *face )
1202 HeapFree( GetProcessHeap(), 0, face->file );
1203 HeapFree( GetProcessHeap(), 0, face->StyleName );
1204 HeapFree( GetProcessHeap(), 0, face->FullName );
1205 HeapFree( GetProcessHeap(), 0, face->cached_enum_data );
1206 HeapFree( GetProcessHeap(), 0, face );
1209 static inline void free_family( Family *family )
1211 Face *face, *cursor2;
1213 LIST_FOR_EACH_ENTRY_SAFE( face, cursor2, &family->faces, Face, entry )
1215 list_remove( &face->entry );
1218 HeapFree( GetProcessHeap(), 0, family->FamilyName );
1219 HeapFree( GetProcessHeap(), 0, family->EnglishName );
1220 HeapFree( GetProcessHeap(), 0, family );
1223 static inline int style_order(const Face *face)
1225 switch (face->ntmFlags & (NTM_REGULAR | NTM_BOLD | NTM_ITALIC))
1233 case NTM_BOLD | NTM_ITALIC:
1236 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1237 debugstr_w(face->family->FamilyName),
1238 debugstr_w(face->StyleName),
1244 static BOOL insert_face_in_family_list( Face *face, Family *family )
1248 LIST_FOR_EACH_ENTRY( cursor, &family->faces, Face, entry )
1250 if (faces_equal( face, cursor ))
1252 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1253 debugstr_w(family->FamilyName), debugstr_w(face->StyleName),
1254 cursor->font_version, face->font_version);
1256 if (face->font_version <= cursor->font_version)
1258 TRACE("Original font is newer so skipping this one\n");
1263 TRACE("Replacing original with this one\n");
1264 list_add_before( &cursor->entry, &face->entry );
1265 face->family = family;
1266 list_remove( &cursor->entry);
1267 free_face( cursor );
1272 if (style_order( face ) < style_order( cursor )) break;
1275 list_add_before( &cursor->entry, &face->entry );
1276 face->family = family;
1280 /****************************************************************
1281 * NB This function stores the ptrs to the strings to save copying.
1282 * Don't free them after calling.
1284 static Family *create_family( WCHAR *name, WCHAR *english_name )
1286 Family * const family = HeapAlloc( GetProcessHeap(), 0, sizeof(*family) );
1287 family->FamilyName = name;
1288 family->EnglishName = english_name;
1289 list_init( &family->faces );
1290 family->replacement = &family->faces;
1295 static LONG reg_load_dword(HKEY hkey, const WCHAR *value, DWORD *data)
1298 LONG r = RegQueryValueExW(hkey, value, NULL, &type, NULL, &needed);
1299 if(r != ERROR_SUCCESS) return r;
1300 if(type != REG_DWORD || needed != sizeof(DWORD)) return ERROR_BAD_CONFIGURATION;
1301 return RegQueryValueExW(hkey, value, NULL, &type, (BYTE*)data, &needed);
1304 static inline LONG reg_save_dword(HKEY hkey, const WCHAR *value, DWORD data)
1306 return RegSetValueExW(hkey, value, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD));
1309 static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family)
1312 DWORD num_strikes, max_strike_key_len;
1314 /* If we have a File Name key then this is a real font, not just the parent
1315 key of a bunch of non-scalable strikes */
1316 if(RegQueryValueExA(hkey_face, "File Name", NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1319 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1320 face->cached_enum_data = NULL;
1322 face->file = HeapAlloc(GetProcessHeap(), 0, needed);
1323 RegQueryValueExA(hkey_face, "File Name", NULL, NULL, (BYTE*)face->file, &needed);
1325 face->StyleName = strdupW(face_name);
1327 if(RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1329 WCHAR *fullName = HeapAlloc(GetProcessHeap(), 0, needed);
1330 RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, (BYTE*)fullName, &needed);
1331 face->FullName = fullName;
1334 face->FullName = NULL;
1336 reg_load_dword(hkey_face, face_index_value, (DWORD*)&face->face_index);
1337 reg_load_dword(hkey_face, face_ntmflags_value, &face->ntmFlags);
1338 reg_load_dword(hkey_face, face_version_value, (DWORD*)&face->font_version);
1339 reg_load_dword(hkey_face, face_vertical_value, (DWORD*)&face->vertical);
1341 needed = sizeof(face->fs);
1342 RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
1344 if(reg_load_dword(hkey_face, face_height_value, (DWORD*)&face->size.height) != ERROR_SUCCESS)
1346 face->scalable = TRUE;
1347 memset(&face->size, 0, sizeof(face->size));
1351 face->scalable = FALSE;
1352 reg_load_dword(hkey_face, face_width_value, (DWORD*)&face->size.width);
1353 reg_load_dword(hkey_face, face_size_value, (DWORD*)&face->size.size);
1354 reg_load_dword(hkey_face, face_x_ppem_value, (DWORD*)&face->size.x_ppem);
1355 reg_load_dword(hkey_face, face_y_ppem_value, (DWORD*)&face->size.y_ppem);
1356 reg_load_dword(hkey_face, face_internal_leading_value, (DWORD*)&face->size.internal_leading);
1358 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1359 face->size.height, face->size.width, face->size.size >> 6,
1360 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1363 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1364 face->fs.fsCsb[0], face->fs.fsCsb[1],
1365 face->fs.fsUsb[0], face->fs.fsUsb[1],
1366 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1368 insert_face_in_family_list(face, family);
1370 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
1373 /* do we have any bitmap strikes? */
1374 RegQueryInfoKeyW(hkey_face, NULL, NULL, NULL, &num_strikes, &max_strike_key_len, NULL, NULL,
1375 NULL, NULL, NULL, NULL);
1376 if(num_strikes != 0)
1378 WCHAR strike_name[10];
1379 DWORD strike_index = 0;
1381 needed = sizeof(strike_name) / sizeof(WCHAR);
1382 while(RegEnumKeyExW(hkey_face, strike_index++, strike_name, &needed,
1383 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1386 RegOpenKeyExW(hkey_face, strike_name, 0, KEY_ALL_ACCESS, &hkey_strike);
1387 load_face(hkey_strike, face_name, family);
1388 RegCloseKey(hkey_strike);
1389 needed = sizeof(strike_name) / sizeof(WCHAR);
1394 static void load_font_list_from_cache(HKEY hkey_font_cache)
1396 DWORD max_family_key_len, size;
1398 DWORD family_index = 0;
1402 RegQueryInfoKeyW(hkey_font_cache, NULL, NULL, NULL, NULL, &max_family_key_len, NULL, NULL,
1403 NULL, NULL, NULL, NULL);
1404 family_name = HeapAlloc(GetProcessHeap(), 0, (max_family_key_len + 1) * sizeof(WCHAR));
1406 size = max_family_key_len + 1;
1407 while(RegEnumKeyExW(hkey_font_cache, family_index++, family_name, &size,
1408 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1410 WCHAR *english_family = NULL;
1411 DWORD face_index = 0;
1413 DWORD max_face_key_len;
1415 RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
1416 TRACE("opened family key %s\n", debugstr_w(family_name));
1417 if(RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, NULL, &size) == ERROR_SUCCESS)
1419 english_family = HeapAlloc(GetProcessHeap(), 0, size);
1420 RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE*)english_family, &size);
1423 family = create_family(strdupW(family_name), english_family);
1424 list_add_tail(&font_list, &family->entry);
1428 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1429 subst->from.name = strdupW(english_family);
1430 subst->from.charset = -1;
1431 subst->to.name = strdupW(family_name);
1432 subst->to.charset = -1;
1433 add_font_subst(&font_subst_list, subst, 0);
1436 RegQueryInfoKeyW(hkey_family, NULL, NULL, NULL, NULL, &max_face_key_len, NULL, NULL,
1437 NULL, NULL, NULL, NULL);
1439 face_name = HeapAlloc(GetProcessHeap(), 0, (max_face_key_len + 1) * sizeof(WCHAR));
1440 size = max_face_key_len + 1;
1441 while(RegEnumKeyExW(hkey_family, face_index++, face_name, &size,
1442 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1446 RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face);
1447 load_face(hkey_face, face_name, family);
1448 RegCloseKey(hkey_face);
1449 size = max_face_key_len + 1;
1451 HeapFree(GetProcessHeap(), 0, face_name);
1452 RegCloseKey(hkey_family);
1453 size = max_family_key_len + 1;
1456 HeapFree(GetProcessHeap(), 0, family_name);
1459 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1462 HKEY hkey_wine_fonts;
1464 /* We don't want to create the fonts key as volatile, so open this first */
1465 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1466 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1467 if(ret != ERROR_SUCCESS)
1469 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1473 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1474 KEY_ALL_ACCESS, NULL, hkey, disposition);
1475 RegCloseKey(hkey_wine_fonts);
1479 static void add_face_to_cache(Face *face)
1481 HKEY hkey_font_cache, hkey_family, hkey_face;
1482 WCHAR *face_key_name;
1484 create_font_cache_key(&hkey_font_cache, NULL);
1486 RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0,
1487 NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL);
1488 if(face->family->EnglishName)
1489 RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName,
1490 (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR));
1493 face_key_name = face->StyleName;
1496 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1497 face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1498 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1500 RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
1503 HeapFree(GetProcessHeap(), 0, face_key_name);
1505 RegSetValueExA(hkey_face, "File Name", 0, REG_BINARY, (BYTE*)face->file, strlen(face->file) + 1);
1507 RegSetValueExW(hkey_face, face_full_name_value, 0, REG_SZ, (BYTE*)face->FullName,
1508 (strlenW(face->FullName) + 1) * sizeof(WCHAR));
1510 reg_save_dword(hkey_face, face_index_value, face->face_index);
1511 reg_save_dword(hkey_face, face_ntmflags_value, face->ntmFlags);
1512 reg_save_dword(hkey_face, face_version_value, face->font_version);
1513 reg_save_dword(hkey_face, face_vertical_value, face->vertical);
1515 RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs));
1519 reg_save_dword(hkey_face, face_height_value, face->size.height);
1520 reg_save_dword(hkey_face, face_width_value, face->size.width);
1521 reg_save_dword(hkey_face, face_size_value, face->size.size);
1522 reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem);
1523 reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem);
1524 reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading);
1526 RegCloseKey(hkey_face);
1527 RegCloseKey(hkey_family);
1528 RegCloseKey(hkey_font_cache);
1531 static WCHAR *prepend_at(WCHAR *family)
1538 str = HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR) * (strlenW(family) + 2));
1540 strcpyW(str + 1, family);
1541 HeapFree(GetProcessHeap(), 0, family);
1545 static void get_family_names( FT_Face ft_face, WCHAR **name, WCHAR **english, BOOL vertical )
1547 *english = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1548 if (!*english) *english = towstr( CP_ACP, ft_face->family_name );
1550 *name = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, GetUserDefaultLCID() );
1556 else if (!strcmpiW( *name, *english ))
1558 HeapFree( GetProcessHeap(), 0, *english );
1564 *name = prepend_at( *name );
1565 *english = prepend_at( *english );
1569 static Family *get_family( FT_Face ft_face, BOOL vertical )
1572 WCHAR *name, *english_name;
1574 get_family_names( ft_face, &name, &english_name, vertical );
1576 family = find_family_from_name( name );
1580 family = create_family( name, english_name );
1581 list_add_tail( &font_list, &family->entry );
1585 FontSubst *subst = HeapAlloc( GetProcessHeap(), 0, sizeof(*subst) );
1586 subst->from.name = strdupW( english_name );
1587 subst->from.charset = -1;
1588 subst->to.name = strdupW( name );
1589 subst->to.charset = -1;
1590 add_font_subst( &font_subst_list, subst, 0 );
1595 HeapFree( GetProcessHeap(), 0, name );
1596 HeapFree( GetProcessHeap(), 0, english_name );
1602 static inline FT_Fixed get_font_version( FT_Face ft_face )
1604 FT_Fixed version = 0;
1607 header = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head );
1608 if (header) version = header->Font_Revision;
1613 static inline DWORD get_ntm_flags( FT_Face ft_face )
1616 FT_ULong table_size = 0;
1618 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) flags |= NTM_ITALIC;
1619 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD) flags |= NTM_BOLD;
1620 if (flags == 0) flags = NTM_REGULAR;
1622 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL, &table_size ))
1623 flags |= NTM_PS_OPENTYPE;
1628 static inline int get_bitmap_internal_leading( FT_Face ft_face )
1630 int internal_leading = 0;
1631 FT_WinFNT_HeaderRec winfnt_header;
1633 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1634 internal_leading = winfnt_header.internal_leading;
1636 return internal_leading;
1639 static inline void get_fontsig( FT_Face ft_face, FONTSIGNATURE *fs )
1644 FT_WinFNT_HeaderRec winfnt_header;
1647 memset( fs, 0, sizeof(*fs) );
1649 os2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 );
1652 fs->fsUsb[0] = os2->ulUnicodeRange1;
1653 fs->fsUsb[1] = os2->ulUnicodeRange2;
1654 fs->fsUsb[2] = os2->ulUnicodeRange3;
1655 fs->fsUsb[3] = os2->ulUnicodeRange4;
1657 if (os2->version == 0)
1659 if (pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
1660 fs->fsCsb[0] = FS_LATIN1;
1662 fs->fsCsb[0] = FS_SYMBOL;
1666 fs->fsCsb[0] = os2->ulCodePageRange1;
1667 fs->fsCsb[1] = os2->ulCodePageRange2;
1672 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1674 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1675 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1676 if (TranslateCharsetInfo( (DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET ))
1681 if (fs->fsCsb[0] == 0)
1683 /* let's see if we can find any interesting cmaps */
1684 for (i = 0; i < ft_face->num_charmaps; i++)
1686 switch (ft_face->charmaps[i]->encoding)
1688 case FT_ENCODING_UNICODE:
1689 case FT_ENCODING_APPLE_ROMAN:
1690 fs->fsCsb[0] |= FS_LATIN1;
1692 case FT_ENCODING_MS_SYMBOL:
1693 fs->fsCsb[0] |= FS_SYMBOL;
1702 #define ADDFONT_EXTERNAL_FONT 0x01
1703 #define ADDFONT_FORCE_BITMAP 0x02
1704 #define ADDFONT_ADD_TO_CACHE 0x04
1706 static Face *create_face( FT_Face ft_face, FT_Long face_index, const char *file, void *font_data_ptr, DWORD font_data_size,
1707 DWORD flags, BOOL vertical )
1709 Face *face = HeapAlloc( GetProcessHeap(), 0, sizeof(*face) );
1710 My_FT_Bitmap_Size *size = (My_FT_Bitmap_Size *)ft_face->available_sizes;
1712 face->StyleName = towstr( CP_ACP, ft_face->style_name );
1713 face->FullName = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1716 face->file = strdupA( file );
1717 face->font_data_ptr = NULL;
1718 face->font_data_size = 0;
1723 face->font_data_ptr = font_data_ptr;
1724 face->font_data_size = font_data_size;
1727 face->face_index = face_index;
1728 get_fontsig( ft_face, &face->fs );
1729 face->ntmFlags = get_ntm_flags( ft_face );
1730 face->font_version = get_font_version( ft_face );
1732 if (FT_IS_SCALABLE( ft_face ))
1734 memset( &face->size, 0, sizeof(face->size) );
1735 face->scalable = TRUE;
1739 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1740 size->height, size->width, size->size >> 6,
1741 size->x_ppem >> 6, size->y_ppem >> 6);
1742 face->size.height = size->height;
1743 face->size.width = size->width;
1744 face->size.size = size->size;
1745 face->size.x_ppem = size->x_ppem;
1746 face->size.y_ppem = size->y_ppem;
1747 face->size.internal_leading = get_bitmap_internal_leading( ft_face );
1748 face->scalable = FALSE;
1751 face->vertical = vertical;
1752 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1753 face->family = NULL;
1754 face->cached_enum_data = NULL;
1756 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1757 face->fs.fsCsb[0], face->fs.fsCsb[1],
1758 face->fs.fsUsb[0], face->fs.fsUsb[1],
1759 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1764 static void AddFaceToList(FT_Face ft_face, const char *file, void *font_data_ptr, DWORD font_data_size,
1765 FT_Long face_index, DWORD flags, BOOL vertical)
1770 face = create_face( ft_face, face_index, file, font_data_ptr, font_data_size, flags, vertical );
1771 family = get_family( ft_face, vertical );
1772 if (!insert_face_in_family_list( face, family ))
1778 if (flags & ADDFONT_ADD_TO_CACHE)
1779 add_face_to_cache( face );
1781 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1782 debugstr_w(face->StyleName));
1785 static FT_Face new_ft_face( const char *file, void *font_data_ptr, DWORD font_data_size,
1786 FT_Long face_index, BOOL allow_bitmap )
1794 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1795 err = pFT_New_Face(library, file, face_index, &ft_face);
1799 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1800 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1805 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1809 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1810 if (!FT_IS_SCALABLE( ft_face ) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0)))
1812 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1816 if (!FT_IS_SFNT( ft_face ))
1818 if (FT_IS_SCALABLE( ft_face ) || !allow_bitmap )
1820 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1826 if (!(pOS2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 )) ||
1827 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_hhea ) ||
1828 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head ))
1830 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1831 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1835 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1836 we don't want to load these. */
1837 if (!memcmp( pOS2->achVendID, "Wine", sizeof(pOS2->achVendID) ))
1841 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len ))
1843 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1849 if (!ft_face->family_name || !ft_face->style_name)
1851 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1857 pFT_Done_Face( ft_face );
1861 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, DWORD flags)
1864 FT_Long face_index = 0, num_faces;
1867 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1868 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1870 #ifdef HAVE_CARBON_CARBON_H
1873 char **mac_list = expand_mac_font(file);
1876 BOOL had_one = FALSE;
1878 for(cursor = mac_list; *cursor; cursor++)
1881 AddFontToList(*cursor, NULL, 0, flags);
1882 HeapFree(GetProcessHeap(), 0, *cursor);
1884 HeapFree(GetProcessHeap(), 0, mac_list);
1889 #endif /* HAVE_CARBON_CARBON_H */
1892 ft_face = new_ft_face( file, font_data_ptr, font_data_size, face_index, flags & ADDFONT_FORCE_BITMAP );
1893 if (!ft_face) return 0;
1895 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1897 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1898 pFT_Done_Face(ft_face);
1902 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags, FALSE);
1905 if (FT_HAS_VERTICAL(ft_face))
1907 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags, TRUE);
1911 num_faces = ft_face->num_faces;
1912 pFT_Done_Face(ft_face);
1913 } while(num_faces > ++face_index);
1917 static void DumpFontList(void)
1921 struct list *family_elem_ptr, *face_elem_ptr;
1923 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1924 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1925 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1926 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1927 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1928 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1930 TRACE(" %d", face->size.height);
1937 /***********************************************************
1938 * The replacement list is a way to map an entire font
1939 * family onto another family. For example adding
1941 * [HKCU\Software\Wine\Fonts\Replacements]
1942 * "Wingdings"="Winedings"
1944 * would enumerate the Winedings font both as Winedings and
1945 * Wingdings. However if a real Wingdings font is present the
1946 * replacement does not take place.
1949 static void LoadReplaceList(void)
1952 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1957 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1958 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1960 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1961 &valuelen, &datalen, NULL, NULL);
1963 valuelen++; /* returned value doesn't include room for '\0' */
1964 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1965 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1969 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1970 &dlen) == ERROR_SUCCESS) {
1971 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1972 /* "NewName"="Oldname" */
1973 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1975 if(!find_family_from_any_name(value))
1977 Family * const family = find_family_from_any_name(data);
1980 Family * const new_family = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family));
1981 if (new_family != NULL)
1983 TRACE("mapping %s to %s\n", debugstr_w(data), debugstr_w(value));
1984 new_family->FamilyName = strdupW(value);
1985 new_family->EnglishName = NULL;
1986 list_init(&new_family->faces);
1987 new_family->replacement = &family->faces;
1988 list_add_tail(&font_list, &new_family->entry);
1993 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(data));
1998 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value));
2000 /* reset dlen and vlen */
2004 HeapFree(GetProcessHeap(), 0, data);
2005 HeapFree(GetProcessHeap(), 0, value);
2010 static const WCHAR *font_links_list[] =
2012 Lucida_Sans_Unicode,
2013 Microsoft_Sans_Serif,
2017 static const struct font_links_defaults_list
2019 /* Keyed off substitution for "MS Shell Dlg" */
2020 const WCHAR *shelldlg;
2021 /* Maximum of four substitutes, plus terminating NULL pointer */
2022 const WCHAR *substitutes[5];
2023 } font_links_defaults_list[] =
2025 /* Non East-Asian */
2026 { Tahoma, /* FIXME unverified ordering */
2027 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2029 /* Below lists are courtesy of
2030 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2034 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2036 /* Chinese Simplified */
2038 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2042 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2044 /* Chinese Traditional */
2046 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2051 static SYSTEM_LINKS *find_font_link(const WCHAR *name)
2053 SYSTEM_LINKS *font_link;
2055 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2057 if(!strcmpiW(font_link->font_name, name))
2064 static void populate_system_links(const WCHAR *name, const WCHAR *const *values)
2076 SYSTEM_LINKS *font_link;
2078 psub = get_font_subst(&font_subst_list, name, -1);
2079 /* Don't store fonts that are only substitutes for other fonts */
2082 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name));
2086 font_link = find_font_link(name);
2087 if (font_link == NULL)
2089 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2090 font_link->font_name = strdupW(name);
2091 list_init(&font_link->links);
2092 list_add_tail(&system_links, &font_link->entry);
2095 memset(&font_link->fs, 0, sizeof font_link->fs);
2096 for (i = 0; values[i] != NULL; i++)
2098 const struct list *face_list;
2099 CHILD_FONT *child_font;
2102 if (!strcmpiW(name,value))
2104 psub = get_font_subst(&font_subst_list, value, -1);
2106 value = psub->to.name;
2107 family = find_family_from_name(value);
2111 /* Use first extant filename for this Family */
2112 face_list = get_face_list_from_family(family);
2113 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
2117 file = strrchr(face->file, '/');
2126 fileW = towstr(CP_UNIXCP, file);
2128 face = find_face_from_filename(fileW, value);
2131 TRACE("Unable to find file %s face name %s\n", debugstr_w(fileW), debugstr_w(value));
2135 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2136 child_font->face = face;
2137 child_font->font = NULL;
2138 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2139 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2140 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
2141 list_add_tail(&font_link->links, &child_font->entry);
2143 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(fileW));
2144 HeapFree(GetProcessHeap(), 0, fileW);
2150 /*************************************************************
2153 static BOOL init_system_links(void)
2157 DWORD type, max_val, max_data, val_len, data_len, index;
2158 WCHAR *value, *data;
2159 WCHAR *entry, *next;
2160 SYSTEM_LINKS *font_link, *system_font_link;
2161 CHILD_FONT *child_font;
2162 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
2163 static const WCHAR System[] = {'S','y','s','t','e','m',0};
2164 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2169 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
2171 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
2172 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
2173 data = HeapAlloc(GetProcessHeap(), 0, max_data);
2174 val_len = max_val + 1;
2175 data_len = max_data;
2177 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
2179 psub = get_font_subst(&font_subst_list, value, -1);
2180 /* Don't store fonts that are only substitutes for other fonts */
2183 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
2186 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2187 font_link->font_name = strdupW(value);
2188 memset(&font_link->fs, 0, sizeof font_link->fs);
2189 list_init(&font_link->links);
2190 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
2193 CHILD_FONT *child_font;
2195 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
2197 next = entry + strlenW(entry) + 1;
2199 face_name = strchrW(entry, ',');
2203 while(isspaceW(*face_name))
2206 psub = get_font_subst(&font_subst_list, face_name, -1);
2208 face_name = psub->to.name;
2210 face = find_face_from_filename(entry, face_name);
2213 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
2217 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2218 child_font->face = face;
2219 child_font->font = NULL;
2220 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2221 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2222 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
2223 list_add_tail(&font_link->links, &child_font->entry);
2225 list_add_tail(&system_links, &font_link->entry);
2227 val_len = max_val + 1;
2228 data_len = max_data;
2231 HeapFree(GetProcessHeap(), 0, value);
2232 HeapFree(GetProcessHeap(), 0, data);
2237 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2239 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2243 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2245 const FontSubst *psub2;
2246 psub2 = get_font_subst(&font_subst_list, font_links_defaults_list[i].shelldlg, -1);
2248 if ((!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name) || (psub2 && !strcmpiW(psub2->to.name,psub->to.name))))
2250 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2251 populate_system_links(font_links_list[j], font_links_defaults_list[i].substitutes);
2253 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2254 populate_system_links(psub->to.name, font_links_defaults_list[i].substitutes);
2256 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2258 populate_system_links(font_links_defaults_list[i].substitutes[0], NULL);
2264 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2267 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2268 system_font_link->font_name = strdupW(System);
2269 memset(&system_font_link->fs, 0, sizeof system_font_link->fs);
2270 list_init(&system_font_link->links);
2272 face = find_face_from_filename(tahoma_ttf, Tahoma);
2275 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2276 child_font->face = face;
2277 child_font->font = NULL;
2278 system_font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2279 system_font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2280 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
2281 list_add_tail(&system_font_link->links, &child_font->entry);
2283 font_link = find_font_link(Tahoma);
2284 if (font_link != NULL)
2286 CHILD_FONT *font_link_entry;
2287 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2289 CHILD_FONT *new_child;
2290 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2291 new_child->face = font_link_entry->face;
2292 new_child->font = NULL;
2293 system_font_link->fs.fsCsb[0] |= font_link_entry->face->fs.fsCsb[0];
2294 system_font_link->fs.fsCsb[1] |= font_link_entry->face->fs.fsCsb[1];
2295 list_add_tail(&system_font_link->links, &new_child->entry);
2298 list_add_tail(&system_links, &system_font_link->entry);
2302 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2305 struct dirent *dent;
2306 char path[MAX_PATH];
2308 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2310 dir = opendir(dirname);
2312 WARN("Can't open directory %s\n", debugstr_a(dirname));
2315 while((dent = readdir(dir)) != NULL) {
2316 struct stat statbuf;
2318 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2321 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2323 sprintf(path, "%s/%s", dirname, dent->d_name);
2325 if(stat(path, &statbuf) == -1)
2327 WARN("Can't stat %s\n", debugstr_a(path));
2330 if(S_ISDIR(statbuf.st_mode))
2331 ReadFontDir(path, external_fonts);
2334 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2335 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2336 AddFontToList(path, NULL, 0, addfont_flags);
2343 static void load_fontconfig_fonts(void)
2345 #ifdef SONAME_LIBFONTCONFIG
2346 void *fc_handle = NULL;
2355 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2357 TRACE("Wine cannot find the fontconfig library (%s).\n",
2358 SONAME_LIBFONTCONFIG);
2361 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
2362 LOAD_FUNCPTR(FcConfigGetCurrent);
2363 LOAD_FUNCPTR(FcFontList);
2364 LOAD_FUNCPTR(FcFontSetDestroy);
2365 LOAD_FUNCPTR(FcInit);
2366 LOAD_FUNCPTR(FcObjectSetAdd);
2367 LOAD_FUNCPTR(FcObjectSetCreate);
2368 LOAD_FUNCPTR(FcObjectSetDestroy);
2369 LOAD_FUNCPTR(FcPatternCreate);
2370 LOAD_FUNCPTR(FcPatternDestroy);
2371 LOAD_FUNCPTR(FcPatternGetBool);
2372 LOAD_FUNCPTR(FcPatternGetString);
2375 if(!pFcInit()) return;
2377 config = pFcConfigGetCurrent();
2378 pat = pFcPatternCreate();
2379 os = pFcObjectSetCreate();
2380 pFcObjectSetAdd(os, FC_FILE);
2381 pFcObjectSetAdd(os, FC_SCALABLE);
2382 fontset = pFcFontList(config, pat, os);
2383 if(!fontset) return;
2384 for(i = 0; i < fontset->nfont; i++) {
2387 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2389 TRACE("fontconfig: %s\n", file);
2391 /* We're just interested in OT/TT fonts for now, so this hack just
2392 picks up the scalable fonts without extensions .pf[ab] to save time
2393 loading every other font */
2395 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2397 TRACE("not scalable\n");
2401 len = strlen( file );
2402 if(len < 4) continue;
2403 ext = &file[ len - 3 ];
2404 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2405 AddFontToList(file, NULL, 0, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2407 pFcFontSetDestroy(fontset);
2408 pFcObjectSetDestroy(os);
2409 pFcPatternDestroy(pat);
2415 static BOOL load_font_from_data_dir(LPCWSTR file)
2418 const char *data_dir = wine_get_data_dir();
2420 if (!data_dir) data_dir = wine_get_build_dir();
2427 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
2429 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
2431 strcpy(unix_name, data_dir);
2432 strcat(unix_name, "/fonts/");
2434 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
2436 EnterCriticalSection( &freetype_cs );
2437 ret = AddFontToList(unix_name, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2438 LeaveCriticalSection( &freetype_cs );
2439 HeapFree(GetProcessHeap(), 0, unix_name);
2444 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
2446 static const WCHAR slashW[] = {'\\','\0'};
2448 WCHAR windowsdir[MAX_PATH];
2451 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2452 strcatW(windowsdir, fontsW);
2453 strcatW(windowsdir, slashW);
2454 strcatW(windowsdir, file);
2455 if ((unixname = wine_get_unix_file_name(windowsdir))) {
2456 EnterCriticalSection( &freetype_cs );
2457 ret = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP);
2458 LeaveCriticalSection( &freetype_cs );
2459 HeapFree(GetProcessHeap(), 0, unixname);
2464 static void load_system_fonts(void)
2467 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
2468 const WCHAR * const *value;
2470 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2473 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
2474 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2475 strcatW(windowsdir, fontsW);
2476 for(value = SystemFontValues; *value; value++) {
2477 dlen = sizeof(data);
2478 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
2482 sprintfW(pathW, fmtW, windowsdir, data);
2483 if((unixname = wine_get_unix_file_name(pathW))) {
2484 added = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2485 HeapFree(GetProcessHeap(), 0, unixname);
2488 load_font_from_data_dir(data);
2495 /*************************************************************
2497 * This adds registry entries for any externally loaded fonts
2498 * (fonts from fontconfig or FontDirs). It also deletes entries
2499 * of no longer existing fonts.
2502 static void update_reg_entries(void)
2504 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2509 struct list *family_elem_ptr, *face_elem_ptr;
2511 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2512 static const WCHAR spaceW[] = {' ', '\0'};
2515 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2516 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2517 ERR("Can't create Windows font reg key\n");
2521 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2522 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2523 ERR("Can't create Windows font reg key\n");
2527 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
2528 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
2529 ERR("Can't create external font reg key\n");
2533 /* enumerate the fonts and add external ones to the two keys */
2535 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2536 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2537 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2538 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2539 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2540 if(!face->external) continue;
2542 if (!(face->ntmFlags & NTM_REGULAR))
2543 len = len_fam + strlenW(face->StyleName) + 1;
2544 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2545 strcpyW(valueW, family->FamilyName);
2546 if(len != len_fam) {
2547 strcatW(valueW, spaceW);
2548 strcatW(valueW, face->StyleName);
2550 strcatW(valueW, TrueType);
2552 file = wine_get_dos_file_name(face->file);
2554 len = strlenW(file) + 1;
2557 if((path = strrchr(face->file, '/')) == NULL)
2561 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
2563 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2564 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2566 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2567 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2568 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2570 HeapFree(GetProcessHeap(), 0, file);
2571 HeapFree(GetProcessHeap(), 0, valueW);
2575 if(external_key) RegCloseKey(external_key);
2576 if(win9x_key) RegCloseKey(win9x_key);
2577 if(winnt_key) RegCloseKey(winnt_key);
2581 static void delete_external_font_keys(void)
2583 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2584 DWORD dlen, vlen, datalen, valuelen, i, type;
2588 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2589 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2590 ERR("Can't create Windows font reg key\n");
2594 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2595 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2596 ERR("Can't create Windows font reg key\n");
2600 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2601 ERR("Can't create external font reg key\n");
2605 /* Delete all external fonts added last time */
2607 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2608 &valuelen, &datalen, NULL, NULL);
2609 valuelen++; /* returned value doesn't include room for '\0' */
2610 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2611 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2613 dlen = datalen * sizeof(WCHAR);
2616 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2617 &dlen) == ERROR_SUCCESS) {
2619 RegDeleteValueW(winnt_key, valueW);
2620 RegDeleteValueW(win9x_key, valueW);
2621 /* reset dlen and vlen */
2625 HeapFree(GetProcessHeap(), 0, data);
2626 HeapFree(GetProcessHeap(), 0, valueW);
2628 /* Delete the old external fonts key */
2629 RegCloseKey(external_key);
2630 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2633 if(win9x_key) RegCloseKey(win9x_key);
2634 if(winnt_key) RegCloseKey(winnt_key);
2637 /*************************************************************
2638 * WineEngAddFontResourceEx
2641 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2647 if (ft_handle) /* do it only if we have freetype up and running */
2652 FIXME("Ignoring flags %x\n", flags);
2654 if((unixname = wine_get_unix_file_name(file)))
2656 DWORD addfont_flags = ADDFONT_FORCE_BITMAP;
2658 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
2659 EnterCriticalSection( &freetype_cs );
2660 ret = AddFontToList(unixname, NULL, 0, addfont_flags);
2661 LeaveCriticalSection( &freetype_cs );
2662 HeapFree(GetProcessHeap(), 0, unixname);
2664 if (!ret && !strchrW(file, '\\')) {
2665 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2666 ret = load_font_from_winfonts_dir(file);
2668 /* Try in datadir/fonts (or builddir/fonts),
2669 * needed for Magic the Gathering Online
2671 ret = load_font_from_data_dir(file);
2678 /*************************************************************
2679 * WineEngAddFontMemResourceEx
2682 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2686 if (ft_handle) /* do it only if we have freetype up and running */
2688 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2690 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2691 memcpy(pFontCopy, pbFont, cbFont);
2693 EnterCriticalSection( &freetype_cs );
2694 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, ADDFONT_FORCE_BITMAP);
2695 LeaveCriticalSection( &freetype_cs );
2699 TRACE("AddFontToList failed\n");
2700 HeapFree(GetProcessHeap(), 0, pFontCopy);
2703 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2704 * For now return something unique but quite random
2706 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2707 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2714 /*************************************************************
2715 * WineEngRemoveFontResourceEx
2718 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2721 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
2725 static char *get_ttf_file_name( LPCWSTR font_file, LPCWSTR font_path )
2731 if (!font_file) return NULL;
2733 file_len = strlenW( font_file );
2735 if (font_path && font_path[0])
2737 int path_len = strlenW( font_path );
2738 fullname = HeapAlloc( GetProcessHeap(), 0, (file_len + path_len + 2) * sizeof(WCHAR) );
2739 if (!fullname) return NULL;
2740 memcpy( fullname, font_path, path_len * sizeof(WCHAR) );
2741 fullname[path_len] = '\\';
2742 memcpy( fullname + path_len + 1, font_file, (file_len + 1) * sizeof(WCHAR) );
2746 int len = GetFullPathNameW( font_file, 0, NULL, NULL );
2747 if (!len) return NULL;
2748 fullname = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
2749 if (!fullname) return NULL;
2750 GetFullPathNameW( font_file, len, fullname, NULL );
2753 unix_name = wine_get_unix_file_name( fullname );
2754 HeapFree( GetProcessHeap(), 0, fullname );
2758 #include <pshpack1.h>
2761 WORD num_of_resources;
2765 CHAR dfCopyright[60];
2771 WORD dfInternalLeading;
2772 WORD dfExternalLeading;
2780 BYTE dfPitchAndFamily;
2791 CHAR szFaceName[LF_FACESIZE];
2794 #include <poppack.h>
2796 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
2797 NEWTEXTMETRICEXW *pntm, LPDWORD ptype);
2799 static BOOL get_fontdir( const char *unix_name, struct fontdir *fd )
2801 FT_Face ft_face = new_ft_face( unix_name, NULL, 0, 0, FALSE );
2804 WCHAR *name, *english_name;
2806 NEWTEXTMETRICEXW ntm;
2809 if (!ft_face) return FALSE;
2810 face = create_face( ft_face, 0, unix_name, NULL, 0, 0, FALSE );
2811 get_family_names( ft_face, &name, &english_name, FALSE );
2812 family = create_family( name, english_name );
2813 insert_face_in_family_list( face, family );
2814 pFT_Done_Face( ft_face );
2816 GetEnumStructs( face, &elf, &ntm, &type );
2817 free_family( family );
2819 if ((type & TRUETYPE_FONTTYPE) == 0) return FALSE;
2821 memset( fd, 0, sizeof(*fd) );
2823 fd->num_of_resources = 1;
2825 fd->dfVersion = 0x200;
2826 fd->dfSize = sizeof(*fd);
2827 strcpy( fd->dfCopyright, "Wine fontdir" );
2828 fd->dfType = 0x4003; /* 0x0080 set if private */
2829 fd->dfPoints = ntm.ntmTm.ntmSizeEM;
2831 fd->dfHorizRes = 72;
2832 fd->dfAscent = ntm.ntmTm.tmAscent;
2833 fd->dfInternalLeading = ntm.ntmTm.tmInternalLeading;
2834 fd->dfExternalLeading = ntm.ntmTm.tmExternalLeading;
2835 fd->dfItalic = ntm.ntmTm.tmItalic;
2836 fd->dfUnderline = ntm.ntmTm.tmUnderlined;
2837 fd->dfStrikeOut = ntm.ntmTm.tmStruckOut;
2838 fd->dfWeight = ntm.ntmTm.tmWeight;
2839 fd->dfCharSet = ntm.ntmTm.tmCharSet;
2841 fd->dfPixHeight = ntm.ntmTm.tmHeight;
2842 fd->dfPitchAndFamily = ntm.ntmTm.tmPitchAndFamily;
2843 fd->dfAvgWidth = ntm.ntmTm.tmAveCharWidth;
2844 fd->dfMaxWidth = ntm.ntmTm.tmMaxCharWidth;
2845 fd->dfFirstChar = ntm.ntmTm.tmFirstChar;
2846 fd->dfLastChar = ntm.ntmTm.tmLastChar;
2847 fd->dfDefaultChar = ntm.ntmTm.tmDefaultChar;
2848 fd->dfBreakChar = ntm.ntmTm.tmBreakChar;
2849 fd->dfWidthBytes = 0;
2851 fd->dfFace = FIELD_OFFSET( struct fontdir, szFaceName );
2853 WideCharToMultiByte( CP_ACP, 0, elf.elfLogFont.lfFaceName, -1, fd->szFaceName, LF_FACESIZE, NULL, NULL );
2858 #define NE_FFLAGS_LIBMODULE 0x8000
2859 #define NE_OSFLAGS_WINDOWS 0x02
2861 static const char dos_string[0x40] = "This is a TrueType resource file";
2862 static const char FONTRES[] = {'F','O','N','T','R','E','S',':'};
2864 #include <pshpack2.h>
2885 struct ne_typeinfo fontdir_type;
2886 struct ne_nameinfo fontdir_name;
2887 struct ne_typeinfo scalable_type;
2888 struct ne_nameinfo scalable_name;
2890 BYTE fontdir_res_name[8];
2893 #include <poppack.h>
2895 static BOOL create_fot( const WCHAR *resource, const WCHAR *font_file, const struct fontdir *fontdir )
2899 DWORD size, written;
2901 BYTE import_name_len, res_name_len, non_res_name_len, font_file_len;
2902 char *font_fileA, *last_part, *ext;
2903 IMAGE_DOS_HEADER dos;
2904 IMAGE_OS2_HEADER ne =
2906 IMAGE_OS2_SIGNATURE, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE, 0,
2908 0, sizeof(ne), sizeof(ne), 0, 0, 0, 0,
2909 0, 4, 2, NE_OSFLAGS_WINDOWS, 0, 0, 0, 0, 0x300
2911 struct rsrc_tab rsrc_tab =
2915 { 0, 0, 0x0c50, 0x2c, 0 },
2917 { 0, 0, 0x0c50, 0x8001, 0 },
2919 { 7,'F','O','N','T','D','I','R'}
2922 memset( &dos, 0, sizeof(dos) );
2923 dos.e_magic = IMAGE_DOS_SIGNATURE;
2924 dos.e_lfanew = sizeof(dos) + sizeof(dos_string);
2926 /* import name is last part\0, resident name is last part without extension
2927 non-resident name is "FONTRES:" + lfFaceName */
2929 font_file_len = WideCharToMultiByte( CP_ACP, 0, font_file, -1, NULL, 0, NULL, NULL );
2930 font_fileA = HeapAlloc( GetProcessHeap(), 0, font_file_len );
2931 WideCharToMultiByte( CP_ACP, 0, font_file, -1, font_fileA, font_file_len, NULL, NULL );
2933 last_part = strrchr( font_fileA, '\\' );
2934 if (last_part) last_part++;
2935 else last_part = font_fileA;
2936 import_name_len = strlen( last_part ) + 1;
2938 ext = strchr( last_part, '.' );
2939 if (ext) res_name_len = ext - last_part;
2940 else res_name_len = import_name_len - 1;
2942 non_res_name_len = sizeof( FONTRES ) + strlen( fontdir->szFaceName );
2944 ne.ne_cbnrestab = 1 + non_res_name_len + 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
2945 ne.ne_restab = ne.ne_rsrctab + sizeof(rsrc_tab);
2946 ne.ne_modtab = ne.ne_imptab = ne.ne_restab + 1 + res_name_len + 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
2947 ne.ne_enttab = ne.ne_imptab + 1 + import_name_len; /* len + string */
2949 ne.ne_nrestab = ne.ne_enttab + ne.ne_cbenttab + 2 + dos.e_lfanew; /* there are 2 bytes of 0 after entry tab */
2951 rsrc_tab.scalable_name.off = (ne.ne_nrestab + ne.ne_cbnrestab + 0xf) >> 4;
2952 rsrc_tab.scalable_name.len = (font_file_len + 0xf) >> 4;
2953 rsrc_tab.fontdir_name.off = rsrc_tab.scalable_name.off + rsrc_tab.scalable_name.len;
2954 rsrc_tab.fontdir_name.len = (fontdir->dfSize + 0xf) >> 4;
2956 size = (rsrc_tab.fontdir_name.off + rsrc_tab.fontdir_name.len) << 4;
2957 start = ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
2961 HeapFree( GetProcessHeap(), 0, font_fileA );
2965 memcpy( ptr, &dos, sizeof(dos) );
2966 memcpy( ptr + sizeof(dos), dos_string, sizeof(dos_string) );
2967 memcpy( ptr + dos.e_lfanew, &ne, sizeof(ne) );
2969 ptr = start + dos.e_lfanew + ne.ne_rsrctab;
2970 memcpy( ptr, &rsrc_tab, sizeof(rsrc_tab) );
2972 ptr = start + dos.e_lfanew + ne.ne_restab;
2973 *ptr++ = res_name_len;
2974 memcpy( ptr, last_part, res_name_len );
2976 ptr = start + dos.e_lfanew + ne.ne_imptab;
2977 *ptr++ = import_name_len;
2978 memcpy( ptr, last_part, import_name_len );
2980 ptr = start + ne.ne_nrestab;
2981 *ptr++ = non_res_name_len;
2982 memcpy( ptr, FONTRES, sizeof(FONTRES) );
2983 memcpy( ptr + sizeof(FONTRES), fontdir->szFaceName, strlen( fontdir->szFaceName ) );
2985 ptr = start + (rsrc_tab.scalable_name.off << 4);
2986 memcpy( ptr, font_fileA, font_file_len );
2988 ptr = start + (rsrc_tab.fontdir_name.off << 4);
2989 memcpy( ptr, fontdir, fontdir->dfSize );
2991 file = CreateFileW( resource, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
2992 if (file != INVALID_HANDLE_VALUE)
2994 if (WriteFile( file, start, size, &written, NULL ) && written == size)
2996 CloseHandle( file );
2999 HeapFree( GetProcessHeap(), 0, start );
3000 HeapFree( GetProcessHeap(), 0, font_fileA );
3005 /*************************************************************
3006 * WineEngCreateScalableFontResource
3009 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
3010 LPCWSTR font_file, LPCWSTR font_path )
3012 char *unix_name = get_ttf_file_name( font_file, font_path );
3013 struct fontdir fontdir;
3016 if (!unix_name || !get_fontdir( unix_name, &fontdir ))
3017 SetLastError( ERROR_INVALID_PARAMETER );
3020 if (hidden) fontdir.dfType |= 0x80;
3021 ret = create_fot( resource, font_file, &fontdir );
3024 HeapFree( GetProcessHeap(), 0, unix_name );
3028 static const struct nls_update_font_list
3030 UINT ansi_cp, oem_cp;
3031 const char *oem, *fixed, *system;
3032 const char *courier, *serif, *small, *sserif;
3033 /* these are for font substitutes */
3034 const char *shelldlg, *tmsrmn;
3035 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
3039 const char *from, *to;
3040 } arial_0, courier_new_0, times_new_roman_0;
3041 } nls_update_font_list[] =
3043 /* Latin 1 (United States) */
3044 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
3045 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
3046 "Tahoma","Times New Roman",
3047 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3050 /* Latin 1 (Multilingual) */
3051 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
3052 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
3053 "Tahoma","Times New Roman", /* FIXME unverified */
3054 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3057 /* Eastern Europe */
3058 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
3059 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
3060 "Tahoma","Times New Roman", /* FIXME unverified */
3061 "Fixedsys,238", "System,238",
3062 "Courier New,238", "MS Serif,238", "Small Fonts,238",
3063 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
3064 { "Arial CE,0", "Arial,238" },
3065 { "Courier New CE,0", "Courier New,238" },
3066 { "Times New Roman CE,0", "Times New Roman,238" }
3069 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
3070 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
3071 "Tahoma","Times New Roman", /* FIXME unverified */
3072 "Fixedsys,204", "System,204",
3073 "Courier New,204", "MS Serif,204", "Small Fonts,204",
3074 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
3075 { "Arial Cyr,0", "Arial,204" },
3076 { "Courier New Cyr,0", "Courier New,204" },
3077 { "Times New Roman Cyr,0", "Times New Roman,204" }
3080 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
3081 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
3082 "Tahoma","Times New Roman", /* FIXME unverified */
3083 "Fixedsys,161", "System,161",
3084 "Courier New,161", "MS Serif,161", "Small Fonts,161",
3085 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
3086 { "Arial Greek,0", "Arial,161" },
3087 { "Courier New Greek,0", "Courier New,161" },
3088 { "Times New Roman Greek,0", "Times New Roman,161" }
3091 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
3092 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
3093 "Tahoma","Times New Roman", /* FIXME unverified */
3094 "Fixedsys,162", "System,162",
3095 "Courier New,162", "MS Serif,162", "Small Fonts,162",
3096 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
3097 { "Arial Tur,0", "Arial,162" },
3098 { "Courier New Tur,0", "Courier New,162" },
3099 { "Times New Roman Tur,0", "Times New Roman,162" }
3102 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
3103 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
3104 "Tahoma","Times New Roman", /* FIXME unverified */
3105 "Fixedsys,177", "System,177",
3106 "Courier New,177", "MS Serif,177", "Small Fonts,177",
3107 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
3111 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
3112 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
3113 "Tahoma","Times New Roman", /* FIXME unverified */
3114 "Fixedsys,178", "System,178",
3115 "Courier New,178", "MS Serif,178", "Small Fonts,178",
3116 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
3120 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
3121 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
3122 "Tahoma","Times New Roman", /* FIXME unverified */
3123 "Fixedsys,186", "System,186",
3124 "Courier New,186", "MS Serif,186", "Small Fonts,186",
3125 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
3126 { "Arial Baltic,0", "Arial,186" },
3127 { "Courier New Baltic,0", "Courier New,186" },
3128 { "Times New Roman Baltic,0", "Times New Roman,186" }
3131 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
3132 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
3133 "Tahoma","Times New Roman", /* FIXME unverified */
3134 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3138 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
3139 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
3140 "Tahoma","Times New Roman", /* FIXME unverified */
3141 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3145 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
3146 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
3147 "MS UI Gothic","MS Serif",
3148 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3151 /* Chinese Simplified */
3152 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
3153 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
3154 "SimSun", "NSimSun",
3155 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3159 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
3160 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
3162 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3165 /* Chinese Traditional */
3166 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
3167 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
3168 "PMingLiU", "MingLiU",
3169 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3174 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
3176 return ( ansi_cp == 932 /* CP932 for Japanese */
3177 || ansi_cp == 936 /* CP936 for Chinese Simplified */
3178 || ansi_cp == 949 /* CP949 for Korean */
3179 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
3182 static inline HKEY create_fonts_NT_registry_key(void)
3186 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
3187 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3191 static inline HKEY create_fonts_9x_registry_key(void)
3195 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
3196 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3200 static inline HKEY create_config_fonts_registry_key(void)
3204 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
3205 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3209 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
3211 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
3212 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
3213 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
3214 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
3217 static void set_value_key(HKEY hkey, const char *name, const char *value)
3220 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
3222 RegDeleteValueA(hkey, name);
3225 static void update_font_info(void)
3227 char buf[40], cpbuf[40];
3230 UINT i, ansi_cp = 0, oem_cp = 0;
3233 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
3236 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3237 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
3238 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3239 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
3240 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
3242 /* Setup Default_Fallback usage for DBCS ANSI codepages */
3243 if (is_dbcs_ansi_cp(ansi_cp))
3244 use_default_fallback = TRUE;
3247 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
3249 if (!strcmp( buf, cpbuf )) /* already set correctly */
3254 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
3256 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
3258 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
3261 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
3265 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
3266 nls_update_font_list[i].oem_cp == oem_cp)
3268 hkey = create_config_fonts_registry_key();
3269 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
3270 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
3271 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
3274 hkey = create_fonts_NT_registry_key();
3275 add_font_list(hkey, &nls_update_font_list[i]);
3278 hkey = create_fonts_9x_registry_key();
3279 add_font_list(hkey, &nls_update_font_list[i]);
3282 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3284 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
3285 strlen(nls_update_font_list[i].shelldlg)+1);
3286 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
3287 strlen(nls_update_font_list[i].tmsrmn)+1);
3289 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
3290 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
3291 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
3292 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
3293 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
3294 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
3295 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
3296 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
3298 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
3299 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
3300 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
3308 /* Delete the FontSubstitutes from other locales */
3309 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3311 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
3312 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
3313 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
3319 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
3322 static BOOL init_freetype(void)
3324 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
3327 "Wine cannot find the FreeType font library. To enable Wine to\n"
3328 "use TrueType fonts please install a version of FreeType greater than\n"
3329 "or equal to 2.0.5.\n"
3330 "http://www.freetype.org\n");
3334 #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;}
3336 LOAD_FUNCPTR(FT_Done_Face)
3337 LOAD_FUNCPTR(FT_Get_Char_Index)
3338 LOAD_FUNCPTR(FT_Get_First_Char)
3339 LOAD_FUNCPTR(FT_Get_Module)
3340 LOAD_FUNCPTR(FT_Get_Next_Char)
3341 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
3342 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
3343 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
3344 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
3345 LOAD_FUNCPTR(FT_Init_FreeType)
3346 LOAD_FUNCPTR(FT_Library_Version)
3347 LOAD_FUNCPTR(FT_Load_Glyph)
3348 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
3349 LOAD_FUNCPTR(FT_Matrix_Multiply)
3350 #ifndef FT_MULFIX_INLINED
3351 LOAD_FUNCPTR(FT_MulFix)
3353 LOAD_FUNCPTR(FT_New_Face)
3354 LOAD_FUNCPTR(FT_New_Memory_Face)
3355 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
3356 LOAD_FUNCPTR(FT_Outline_Transform)
3357 LOAD_FUNCPTR(FT_Outline_Translate)
3358 LOAD_FUNCPTR(FT_Render_Glyph)
3359 LOAD_FUNCPTR(FT_Select_Charmap)
3360 LOAD_FUNCPTR(FT_Set_Charmap)
3361 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
3362 LOAD_FUNCPTR(FT_Vector_Transform)
3363 LOAD_FUNCPTR(FT_Vector_Unit)
3365 /* Don't warn if these ones are missing */
3366 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
3367 #ifdef HAVE_FREETYPE_FTLCDFIL_H
3368 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
3371 if(pFT_Init_FreeType(&library) != 0) {
3372 ERR("Can't init FreeType library\n");
3373 wine_dlclose(ft_handle, NULL, 0);
3377 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
3379 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
3380 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
3381 ((FT_Version.minor << 8) & 0x00ff00) |
3382 ((FT_Version.patch ) & 0x0000ff);
3384 font_driver = &freetype_funcs;
3389 "Wine cannot find certain functions that it needs inside the FreeType\n"
3390 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3391 "FreeType to at least version 2.1.4.\n"
3392 "http://www.freetype.org\n");
3393 wine_dlclose(ft_handle, NULL, 0);
3398 static void init_font_list(void)
3400 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
3401 static const WCHAR pathW[] = {'P','a','t','h',0};
3403 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
3404 WCHAR windowsdir[MAX_PATH];
3407 const char *data_dir;
3409 delete_external_font_keys();
3411 /* load the system bitmap fonts */
3412 load_system_fonts();
3414 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3415 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3416 strcatW(windowsdir, fontsW);
3417 if((unixname = wine_get_unix_file_name(windowsdir)))
3419 ReadFontDir(unixname, FALSE);
3420 HeapFree(GetProcessHeap(), 0, unixname);
3423 /* load the system truetype fonts */
3424 data_dir = wine_get_data_dir();
3425 if (!data_dir) data_dir = wine_get_build_dir();
3426 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
3428 strcpy(unixname, data_dir);
3429 strcat(unixname, "/fonts/");
3430 ReadFontDir(unixname, TRUE);
3431 HeapFree(GetProcessHeap(), 0, unixname);
3434 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3435 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3436 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3438 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
3439 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
3440 &hkey) == ERROR_SUCCESS)
3442 LPWSTR data, valueW;
3443 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3444 &valuelen, &datalen, NULL, NULL);
3446 valuelen++; /* returned value doesn't include room for '\0' */
3447 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3448 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3451 dlen = datalen * sizeof(WCHAR);
3453 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
3454 &dlen) == ERROR_SUCCESS)
3456 if(data[0] && (data[1] == ':'))
3458 if((unixname = wine_get_unix_file_name(data)))
3460 AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3461 HeapFree(GetProcessHeap(), 0, unixname);
3464 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
3466 WCHAR pathW[MAX_PATH];
3467 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3470 sprintfW(pathW, fmtW, windowsdir, data);
3471 if((unixname = wine_get_unix_file_name(pathW)))
3473 added = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3474 HeapFree(GetProcessHeap(), 0, unixname);
3477 load_font_from_data_dir(data);
3479 /* reset dlen and vlen */
3484 HeapFree(GetProcessHeap(), 0, data);
3485 HeapFree(GetProcessHeap(), 0, valueW);
3489 load_fontconfig_fonts();
3491 /* then look in any directories that we've specified in the config file */
3492 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3493 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
3499 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
3501 len += sizeof(WCHAR);
3502 valueW = HeapAlloc( GetProcessHeap(), 0, len );
3503 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
3505 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
3506 valueA = HeapAlloc( GetProcessHeap(), 0, len );
3507 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
3508 TRACE( "got font path %s\n", debugstr_a(valueA) );
3512 LPSTR next = strchr( ptr, ':' );
3513 if (next) *next++ = 0;
3514 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
3515 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
3517 strcpy( unixname, home );
3518 strcat( unixname, ptr + 1 );
3519 ReadFontDir( unixname, TRUE );
3520 HeapFree( GetProcessHeap(), 0, unixname );
3523 ReadFontDir( ptr, TRUE );
3526 HeapFree( GetProcessHeap(), 0, valueA );
3528 HeapFree( GetProcessHeap(), 0, valueW );
3534 /* Mac default font locations. */
3535 ReadFontDir( "/Library/Fonts", TRUE );
3536 ReadFontDir( "/Network/Library/Fonts", TRUE );
3537 ReadFontDir( "/System/Library/Fonts", TRUE );
3538 if ((home = getenv( "HOME" )))
3540 unixname = HeapAlloc( GetProcessHeap(), 0, strlen(home)+15 );
3541 strcpy( unixname, home );
3542 strcat( unixname, "/Library/Fonts" );
3543 ReadFontDir( unixname, TRUE);
3544 HeapFree( GetProcessHeap(), 0, unixname );
3549 static BOOL move_to_front(const WCHAR *name)
3551 Family *family, *cursor2;
3552 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
3554 if(!strcmpiW(family->FamilyName, name))
3556 list_remove(&family->entry);
3557 list_add_head(&font_list, &family->entry);
3564 static BOOL set_default(const WCHAR **name_list)
3568 if (move_to_front(*name_list)) return TRUE;
3575 static void reorder_font_list(void)
3577 set_default( default_serif_list );
3578 set_default( default_fixed_list );
3579 set_default( default_sans_list );
3582 /*************************************************************
3585 * Initialize FreeType library and create a list of available faces
3587 BOOL WineEngInit(void)
3589 HKEY hkey_font_cache;
3593 /* update locale dependent font info in registry */
3596 if(!init_freetype()) return FALSE;
3598 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
3600 ERR("Failed to create font mutex\n");
3603 WaitForSingleObject(font_mutex, INFINITE);
3605 create_font_cache_key(&hkey_font_cache, &disposition);
3607 if(disposition == REG_CREATED_NEW_KEY)
3610 load_font_list_from_cache(hkey_font_cache);
3612 RegCloseKey(hkey_font_cache);
3614 reorder_font_list();
3621 if(disposition == REG_CREATED_NEW_KEY)
3622 update_reg_entries();
3624 init_system_links();
3626 ReleaseMutex(font_mutex);
3631 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
3634 TT_HoriHeader *pHori;
3638 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3639 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3641 if(height == 0) height = 16;
3643 /* Calc. height of EM square:
3645 * For +ve lfHeight we have
3646 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3647 * Re-arranging gives:
3648 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3650 * For -ve lfHeight we have
3652 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3653 * with il = winAscent + winDescent - units_per_em]
3658 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
3659 ppem = MulDiv(ft_face->units_per_EM, height,
3660 pHori->Ascender - pHori->Descender);
3662 ppem = MulDiv(ft_face->units_per_EM, height,
3663 pOS2->usWinAscent + pOS2->usWinDescent);
3671 static struct font_mapping *map_font_file( const char *name )
3673 struct font_mapping *mapping;
3677 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
3678 if (fstat( fd, &st ) == -1) goto error;
3680 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
3682 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
3684 mapping->refcount++;
3689 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
3692 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
3695 if (mapping->data == MAP_FAILED)
3697 HeapFree( GetProcessHeap(), 0, mapping );
3700 mapping->refcount = 1;
3701 mapping->dev = st.st_dev;
3702 mapping->ino = st.st_ino;
3703 mapping->size = st.st_size;
3704 list_add_tail( &mappings_list, &mapping->entry );
3712 static void unmap_font_file( struct font_mapping *mapping )
3714 if (!--mapping->refcount)
3716 list_remove( &mapping->entry );
3717 munmap( mapping->data, mapping->size );
3718 HeapFree( GetProcessHeap(), 0, mapping );
3722 static LONG load_VDMX(GdiFont*, LONG);
3724 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
3731 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
3735 if (!(font->mapping = map_font_file( face->file )))
3737 WARN("failed to map %s\n", debugstr_a(face->file));
3740 data_ptr = font->mapping->data;
3741 data_size = font->mapping->size;
3745 data_ptr = face->font_data_ptr;
3746 data_size = face->font_data_size;
3749 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3751 ERR("FT_New_Face rets %d\n", err);
3755 /* set it here, as load_VDMX needs it */
3756 font->ft_face = ft_face;
3758 if(FT_IS_SCALABLE(ft_face)) {
3759 /* load the VDMX table if we have one */
3760 font->ppem = load_VDMX(font, height);
3762 font->ppem = calc_ppem_for_height(ft_face, height);
3763 TRACE("height %d => ppem %d\n", height, font->ppem);
3765 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3766 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3768 font->ppem = height;
3769 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3770 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3776 static int get_nearest_charset(const WCHAR *family_name, Face *face, int *cp)
3778 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3779 a single face with the requested charset. The idea is to check if
3780 the selected font supports the current ANSI codepage, if it does
3781 return the corresponding charset, else return the first charset */
3784 int acp = GetACP(), i;
3788 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3790 const SYSTEM_LINKS *font_link;
3792 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
3793 return csi.ciCharset;
3795 font_link = find_font_link(family_name);
3796 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
3797 return csi.ciCharset;
3800 for(i = 0; i < 32; i++) {
3802 if(face->fs.fsCsb[0] & fs0) {
3803 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
3805 return csi.ciCharset;
3808 FIXME("TCI failing on %x\n", fs0);
3812 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3813 face->fs.fsCsb[0], face->file);
3815 return DEFAULT_CHARSET;
3818 static GdiFont *alloc_font(void)
3820 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
3822 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
3823 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3825 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3826 ret->total_kern_pairs = (DWORD)-1;
3827 ret->kern_pairs = NULL;
3828 list_init(&ret->hfontlist);
3829 list_init(&ret->child_fonts);
3833 static void free_font(GdiFont *font)
3835 struct list *cursor, *cursor2;
3838 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
3840 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
3841 list_remove(cursor);
3843 free_font(child->font);
3844 HeapFree(GetProcessHeap(), 0, child);
3847 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->hfontlist)
3849 HFONTLIST *hfontlist = LIST_ENTRY(cursor, HFONTLIST, entry);
3850 DeleteObject(hfontlist->hfont);
3851 list_remove(&hfontlist->entry);
3852 HeapFree(GetProcessHeap(), 0, hfontlist);
3855 if (font->ft_face) pFT_Done_Face(font->ft_face);
3856 if (font->mapping) unmap_font_file( font->mapping );
3857 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
3858 HeapFree(GetProcessHeap(), 0, font->potm);
3859 HeapFree(GetProcessHeap(), 0, font->name);
3860 for (i = 0; i < font->gmsize; i++)
3861 HeapFree(GetProcessHeap(),0,font->gm[i]);
3862 HeapFree(GetProcessHeap(), 0, font->gm);
3863 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
3864 HeapFree(GetProcessHeap(), 0, font);
3868 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
3870 FT_Face ft_face = font->ft_face;
3874 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
3881 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
3883 /* make sure value of len is the value freetype says it needs */
3886 FT_ULong needed = 0;
3887 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
3888 if( !err && needed < len) len = needed;
3890 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
3893 TRACE("Can't find table %c%c%c%c\n",
3894 /* bytes were reversed */
3895 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
3896 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
3902 /*************************************************************
3905 * load the vdmx entry for the specified height
3908 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3909 ( ( (FT_ULong)_x4 << 24 ) | \
3910 ( (FT_ULong)_x3 << 16 ) | \
3911 ( (FT_ULong)_x2 << 8 ) | \
3914 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3929 static LONG load_VDMX(GdiFont *font, LONG height)
3933 BYTE devXRatio, devYRatio;
3934 USHORT numRecs, numRatios;
3935 DWORD result, offset = -1;
3939 result = get_font_data(font, MS_VDMX_TAG, 0, hdr, 6);
3941 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
3944 /* FIXME: need the real device aspect ratio */
3948 numRecs = GET_BE_WORD(hdr[1]);
3949 numRatios = GET_BE_WORD(hdr[2]);
3951 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
3952 for(i = 0; i < numRatios; i++) {
3955 offset = (3 * 2) + (i * sizeof(Ratios));
3956 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
3959 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
3961 if((ratio.xRatio == 0 &&
3962 ratio.yStartRatio == 0 &&
3963 ratio.yEndRatio == 0) ||
3964 (devXRatio == ratio.xRatio &&
3965 devYRatio >= ratio.yStartRatio &&
3966 devYRatio <= ratio.yEndRatio))
3968 offset = (3 * 2) + (numRatios * 4) + (i * 2);
3969 get_font_data(font, MS_VDMX_TAG, offset, &tmp, 2);
3970 offset = GET_BE_WORD(tmp);
3976 FIXME("No suitable ratio found\n");
3980 if(get_font_data(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
3982 BYTE startsz, endsz;
3985 recs = GET_BE_WORD(group.recs);
3986 startsz = group.startsz;
3987 endsz = group.endsz;
3989 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
3991 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
3992 result = get_font_data(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
3993 if(result == GDI_ERROR) {
3994 FIXME("Failed to retrieve vTable\n");
3999 for(i = 0; i < recs; i++) {
4000 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4001 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4002 ppem = GET_BE_WORD(vTable[i * 3]);
4004 if(yMax + -yMin == height) {
4007 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4010 if(yMax + -yMin > height) {
4013 goto end; /* failed */
4015 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4016 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4017 ppem = GET_BE_WORD(vTable[i * 3]);
4018 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4024 TRACE("ppem not found for height %d\n", height);
4028 HeapFree(GetProcessHeap(), 0, vTable);
4034 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
4036 if(font->font_desc.hash != fd->hash) return TRUE;
4037 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
4038 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
4039 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
4040 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
4043 static void calc_hash(FONT_DESC *pfd)
4045 DWORD hash = 0, *ptr, two_chars;
4049 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
4051 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
4053 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
4055 pwc = (WCHAR *)&two_chars;
4057 *pwc = toupperW(*pwc);
4059 *pwc = toupperW(*pwc);
4063 hash ^= !pfd->can_use_bitmap;
4068 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
4073 struct list *font_elem_ptr, *hfontlist_elem_ptr;
4077 fd.can_use_bitmap = can_use_bitmap;
4080 /* try the child list */
4081 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
4082 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4083 if(!fontcmp(ret, &fd)) {
4084 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4085 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
4086 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4087 if(hflist->hfont == hfont)
4093 /* try the in-use list */
4094 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
4095 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4096 if(!fontcmp(ret, &fd)) {
4097 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4098 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
4099 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4100 if(hflist->hfont == hfont)
4103 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
4104 hflist->hfont = hfont;
4105 list_add_head(&ret->hfontlist, &hflist->entry);
4110 /* then the unused list */
4111 font_elem_ptr = list_head(&unused_gdi_font_list);
4112 while(font_elem_ptr) {
4113 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4114 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4115 if(!fontcmp(ret, &fd)) {
4116 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4117 assert(list_empty(&ret->hfontlist));
4118 TRACE("Found %p in unused list\n", ret);
4119 list_remove(&ret->entry);
4120 list_add_head(&gdi_font_list, &ret->entry);
4121 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
4122 hflist->hfont = hfont;
4123 list_add_head(&ret->hfontlist, &hflist->entry);
4130 static void add_to_cache(GdiFont *font)
4132 static DWORD cache_num = 1;
4134 font->cache_num = cache_num++;
4135 list_add_head(&gdi_font_list, &font->entry);
4138 /*************************************************************
4139 * create_child_font_list
4141 static BOOL create_child_font_list(GdiFont *font)
4144 SYSTEM_LINKS *font_link;
4145 CHILD_FONT *font_link_entry, *new_child;
4149 psub = get_font_subst(&font_subst_list, font->name, -1);
4150 font_name = psub ? psub->to.name : font->name;
4151 font_link = find_font_link(font_name);
4152 if (font_link != NULL)
4154 TRACE("found entry in system list\n");
4155 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4157 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4158 new_child->face = font_link_entry->face;
4159 new_child->font = NULL;
4160 list_add_tail(&font->child_fonts, &new_child->entry);
4161 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
4166 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
4167 * Sans Serif. This is how asian windows get default fallbacks for fonts
4169 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
4170 font->charset != OEM_CHARSET &&
4171 strcmpiW(font_name,szDefaultFallbackLink) != 0)
4173 font_link = find_font_link(szDefaultFallbackLink);
4174 if (font_link != NULL)
4176 TRACE("found entry in default fallback list\n");
4177 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4179 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4180 new_child->face = font_link_entry->face;
4181 new_child->font = NULL;
4182 list_add_tail(&font->child_fonts, &new_child->entry);
4183 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
4192 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
4194 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
4196 if (pFT_Set_Charmap)
4199 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
4201 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
4203 for (i = 0; i < ft_face->num_charmaps; i++)
4205 if (ft_face->charmaps[i]->encoding == encoding)
4207 TRACE("found cmap with platform_id %u, encoding_id %u\n",
4208 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
4210 switch (ft_face->charmaps[i]->platform_id)
4213 cmap_def = ft_face->charmaps[i];
4215 case 0: /* Apple Unicode */
4216 cmap0 = ft_face->charmaps[i];
4218 case 1: /* Macintosh */
4219 cmap1 = ft_face->charmaps[i];
4222 cmap2 = ft_face->charmaps[i];
4224 case 3: /* Microsoft */
4225 cmap3 = ft_face->charmaps[i];
4230 if (cmap3) /* prefer Microsoft cmap table */
4231 ft_err = pFT_Set_Charmap(ft_face, cmap3);
4233 ft_err = pFT_Set_Charmap(ft_face, cmap1);
4235 ft_err = pFT_Set_Charmap(ft_face, cmap2);
4237 ft_err = pFT_Set_Charmap(ft_face, cmap0);
4239 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
4241 return ft_err == FT_Err_Ok;
4244 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
4248 /*************************************************************
4251 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
4252 LPCWSTR output, const DEVMODEW *devmode )
4254 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
4256 if (!physdev) return FALSE;
4257 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
4262 /*************************************************************
4265 static BOOL freetype_DeleteDC( PHYSDEV dev )
4267 struct freetype_physdev *physdev = get_freetype_dev( dev );
4268 HeapFree( GetProcessHeap(), 0, physdev );
4273 /*************************************************************
4274 * freetype_SelectFont
4276 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont )
4278 struct freetype_physdev *physdev = get_freetype_dev( dev );
4280 Face *face, *best, *best_bitmap;
4281 Family *family, *last_resort_family;
4282 const struct list *family_elem_ptr, *face_list, *face_elem_ptr;
4283 INT height, width = 0;
4284 unsigned int score = 0, new_score;
4285 signed int diff = 0, newdiff;
4286 BOOL bd, it, can_use_bitmap, want_vertical;
4291 FontSubst *psub = NULL;
4292 DC *dc = get_dc_ptr( dev->hdc );
4293 const SYSTEM_LINKS *font_link;
4295 if (!hfont) /* notification that the font has been changed by another driver */
4298 physdev->font = NULL;
4299 release_dc_ptr( dc );
4303 GetObjectW( hfont, sizeof(lf), &lf );
4304 lf.lfWidth = abs(lf.lfWidth);
4306 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
4308 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
4309 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
4310 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
4313 if(dc->GraphicsMode == GM_ADVANCED)
4315 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
4316 /* Try to avoid not necessary glyph transformations */
4317 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
4319 lf.lfHeight *= fabs(dcmat.eM11);
4320 lf.lfWidth *= fabs(dcmat.eM11);
4321 dcmat.eM11 = dcmat.eM22 = 1.0;
4326 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
4327 font scaling abilities. */
4328 dcmat.eM11 = dcmat.eM22 = 1.0;
4329 dcmat.eM21 = dcmat.eM12 = 0;
4330 if (dc->vport2WorldValid)
4332 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
4333 lf.lfOrientation = -lf.lfOrientation;
4334 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
4335 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
4339 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
4340 dcmat.eM21, dcmat.eM22);
4343 EnterCriticalSection( &freetype_cs );
4345 /* check the cache first */
4346 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4347 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
4351 if(list_empty(&font_list)) /* No fonts installed */
4353 TRACE("No fonts installed\n");
4357 TRACE("not in cache\n");
4360 ret->font_desc.matrix = dcmat;
4361 ret->font_desc.lf = lf;
4362 ret->font_desc.can_use_bitmap = can_use_bitmap;
4363 calc_hash(&ret->font_desc);
4364 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
4365 hflist->hfont = hfont;
4366 list_add_head(&ret->hfontlist, &hflist->entry);
4368 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4369 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4370 original value lfCharSet. Note this is a special case for
4371 Symbol and doesn't happen at least for "Wingdings*" */
4373 if(!strcmpiW(lf.lfFaceName, SymbolW))
4374 lf.lfCharSet = SYMBOL_CHARSET;
4376 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
4377 switch(lf.lfCharSet) {
4378 case DEFAULT_CHARSET:
4379 csi.fs.fsCsb[0] = 0;
4382 FIXME("Untranslated charset %d\n", lf.lfCharSet);
4383 csi.fs.fsCsb[0] = 0;
4389 if(lf.lfFaceName[0] != '\0') {
4390 CHILD_FONT *font_link_entry;
4391 LPWSTR FaceName = lf.lfFaceName;
4393 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
4396 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
4397 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
4398 if (psub->to.charset != -1)
4399 lf.lfCharSet = psub->to.charset;
4402 /* We want a match on name and charset or just name if
4403 charset was DEFAULT_CHARSET. If the latter then
4404 we fixup the returned charset later in get_nearest_charset
4405 where we'll either use the charset of the current ansi codepage
4406 or if that's unavailable the first charset that the font supports.
4408 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4409 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4410 if (!strcmpiW(family->FamilyName, FaceName) ||
4411 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
4413 font_link = find_font_link(family->FamilyName);
4414 face_list = get_face_list_from_family(family);
4415 LIST_FOR_EACH(face_elem_ptr, face_list) {
4416 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4417 if (!(face->scalable || can_use_bitmap))
4419 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4421 if (font_link != NULL &&
4422 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4424 if (!csi.fs.fsCsb[0])
4430 /* Search by full face name. */
4431 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4432 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4433 face_list = get_face_list_from_family(family);
4434 LIST_FOR_EACH(face_elem_ptr, face_list) {
4435 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4436 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
4437 (face->scalable || can_use_bitmap))
4439 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4441 font_link = find_font_link(family->FamilyName);
4442 if (font_link != NULL &&
4443 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4450 * Try check the SystemLink list first for a replacement font.
4451 * We may find good replacements there.
4453 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
4455 if(!strcmpiW(font_link->font_name, FaceName) ||
4456 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
4458 TRACE("found entry in system list\n");
4459 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4461 const SYSTEM_LINKS *links;
4463 face = font_link_entry->face;
4464 if (!(face->scalable || can_use_bitmap))
4466 family = face->family;
4467 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4469 links = find_font_link(family->FamilyName);
4470 if (links != NULL && csi.fs.fsCsb[0] & links->fs.fsCsb[0])
4477 psub = NULL; /* substitution is no more relevant */
4479 /* If requested charset was DEFAULT_CHARSET then try using charset
4480 corresponding to the current ansi codepage */
4481 if (!csi.fs.fsCsb[0])
4484 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
4485 FIXME("TCI failed on codepage %d\n", acp);
4486 csi.fs.fsCsb[0] = 0;
4488 lf.lfCharSet = csi.ciCharset;
4491 want_vertical = (lf.lfFaceName[0] == '@');
4493 /* Face families are in the top 4 bits of lfPitchAndFamily,
4494 so mask with 0xF0 before testing */
4496 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
4497 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
4498 strcpyW(lf.lfFaceName, defFixed);
4499 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
4500 strcpyW(lf.lfFaceName, defSerif);
4501 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
4502 strcpyW(lf.lfFaceName, defSans);
4504 strcpyW(lf.lfFaceName, defSans);
4505 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4506 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4507 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
4508 font_link = find_font_link(family->FamilyName);
4509 face_list = get_face_list_from_family(family);
4510 LIST_FOR_EACH(face_elem_ptr, face_list) {
4511 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4512 if (!(face->scalable || can_use_bitmap))
4514 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4516 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4522 last_resort_family = NULL;
4523 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4524 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4525 font_link = find_font_link(family->FamilyName);
4526 face_list = get_face_list_from_family(family);
4527 LIST_FOR_EACH(face_elem_ptr, face_list) {
4528 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4529 if(face->vertical == want_vertical &&
4530 (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4531 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]))) {
4534 if(can_use_bitmap && !last_resort_family)
4535 last_resort_family = family;
4540 if(last_resort_family) {
4541 family = last_resort_family;
4542 csi.fs.fsCsb[0] = 0;
4546 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4547 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4548 face_list = get_face_list_from_family(family);
4549 LIST_FOR_EACH(face_elem_ptr, face_list) {
4550 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4551 if(face->scalable && face->vertical == want_vertical) {
4552 csi.fs.fsCsb[0] = 0;
4553 WARN("just using first face for now\n");
4556 if(can_use_bitmap && !last_resort_family)
4557 last_resort_family = family;
4560 if(!last_resort_family) {
4561 FIXME("can't find a single appropriate font - bailing\n");
4567 WARN("could only find a bitmap font - this will probably look awful!\n");
4568 family = last_resort_family;
4569 csi.fs.fsCsb[0] = 0;
4572 it = lf.lfItalic ? 1 : 0;
4573 bd = lf.lfWeight > 550 ? 1 : 0;
4575 height = lf.lfHeight;
4577 face = best = best_bitmap = NULL;
4578 font_link = find_font_link(family->FamilyName);
4579 face_list = get_face_list_from_family(family);
4580 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
4582 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4583 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]) ||
4588 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
4589 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
4590 new_score = (italic ^ it) + (bold ^ bd);
4591 if(!best || new_score <= score)
4593 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4594 italic, bold, it, bd);
4597 if(best->scalable && score == 0) break;
4601 newdiff = height - (signed int)(best->size.height);
4603 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
4604 if(!best_bitmap || new_score < score ||
4605 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
4607 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
4610 if(score == 0 && diff == 0) break;
4617 face = best->scalable ? best : best_bitmap;
4618 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
4619 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
4622 height = lf.lfHeight;
4626 if(csi.fs.fsCsb[0]) {
4627 ret->charset = lf.lfCharSet;
4628 ret->codepage = csi.ciACP;
4631 ret->charset = get_nearest_charset(family->FamilyName, face, &ret->codepage);
4633 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
4634 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
4636 ret->aveWidth = height ? lf.lfWidth : 0;
4638 if(!face->scalable) {
4639 /* Windows uses integer scaling factors for bitmap fonts */
4640 INT scale, scaled_height;
4641 GdiFont *cachedfont;
4643 /* FIXME: rotation of bitmap fonts is ignored */
4644 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
4646 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
4647 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4648 dcmat.eM11 = dcmat.eM22 = 1.0;
4649 /* As we changed the matrix, we need to search the cache for the font again,
4650 * otherwise we might explode the cache. */
4651 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4652 TRACE("Found cached font after non-scalable matrix rescale!\n");
4657 calc_hash(&ret->font_desc);
4659 if (height != 0) height = diff;
4660 height += face->size.height;
4662 scale = (height + face->size.height - 1) / face->size.height;
4663 scaled_height = scale * face->size.height;
4664 /* Only jump to the next height if the difference <= 25% original height */
4665 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
4666 /* The jump between unscaled and doubled is delayed by 1 */
4667 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
4668 ret->scale_y = scale;
4670 width = face->size.x_ppem >> 6;
4671 height = face->size.y_ppem >> 6;
4675 TRACE("font scale y: %f\n", ret->scale_y);
4677 ret->ft_face = OpenFontFace(ret, face, width, height);
4686 ret->ntmFlags = face->ntmFlags;
4688 if (ret->charset == SYMBOL_CHARSET &&
4689 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
4692 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
4696 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
4699 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
4700 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
4701 ret->underline = lf.lfUnderline ? 0xff : 0;
4702 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
4703 create_child_font_list(ret);
4705 if (face->vertical) /* We need to try to load the GSUB table */
4707 int length = get_font_data(ret, GSUB_TAG , 0, NULL, 0);
4708 if (length != GDI_ERROR)
4710 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
4711 get_font_data(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
4712 TRACE("Loaded GSUB table of %i bytes\n",length);
4716 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
4723 physdev->font = ret;
4725 LeaveCriticalSection( &freetype_cs );
4726 release_dc_ptr( dc );
4727 return ret ? hfont : 0;
4730 static void dump_gdi_font_list(void)
4733 struct list *elem_ptr;
4735 TRACE("---------- gdiFont Cache ----------\n");
4736 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
4737 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4738 TRACE("gdiFont=%p %s %d\n",
4739 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4742 TRACE("---------- Unused gdiFont Cache ----------\n");
4743 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
4744 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4745 TRACE("gdiFont=%p %s %d\n",
4746 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4749 TRACE("---------- Child gdiFont Cache ----------\n");
4750 LIST_FOR_EACH(elem_ptr, &child_font_list) {
4751 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4752 TRACE("gdiFont=%p %s %d\n",
4753 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4757 /*************************************************************
4758 * WineEngDestroyFontInstance
4760 * free the gdiFont associated with this handle
4763 BOOL WineEngDestroyFontInstance(HFONT handle)
4768 struct list *font_elem_ptr, *hfontlist_elem_ptr;
4772 EnterCriticalSection( &freetype_cs );
4774 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
4776 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4777 while(hfontlist_elem_ptr) {
4778 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4779 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4780 if(hflist->hfont == handle) {
4781 TRACE("removing child font %p from child list\n", gdiFont);
4782 list_remove(&gdiFont->entry);
4783 LeaveCriticalSection( &freetype_cs );
4789 TRACE("destroying hfont=%p\n", handle);
4791 dump_gdi_font_list();
4793 font_elem_ptr = list_head(&gdi_font_list);
4794 while(font_elem_ptr) {
4795 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4796 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
4798 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4799 while(hfontlist_elem_ptr) {
4800 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4801 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4802 if(hflist->hfont == handle) {
4803 list_remove(&hflist->entry);
4804 HeapFree(GetProcessHeap(), 0, hflist);
4808 if(list_empty(&gdiFont->hfontlist)) {
4809 TRACE("Moving to Unused list\n");
4810 list_remove(&gdiFont->entry);
4811 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
4816 font_elem_ptr = list_head(&unused_gdi_font_list);
4817 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
4818 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4819 while(font_elem_ptr) {
4820 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4821 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4822 TRACE("freeing %p\n", gdiFont);
4823 list_remove(&gdiFont->entry);
4826 LeaveCriticalSection( &freetype_cs );
4830 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
4837 id += IDS_FIRST_SCRIPT;
4838 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
4839 if (!rsrc) return 0;
4840 hMem = LoadResource( gdi32_module, rsrc );
4841 if (!hMem) return 0;
4843 p = LockResource( hMem );
4845 while (id--) p += *p + 1;
4847 i = min(LF_FACESIZE - 1, *p);
4848 memcpy(buffer, p + 1, i * sizeof(WCHAR));
4854 /***************************************************
4855 * create_enum_charset_list
4857 * This function creates charset enumeration list because in DEFAULT_CHARSET
4858 * case, the ANSI codepage's charset takes precedence over other charsets.
4859 * This function works as a filter other than DEFAULT_CHARSET case.
4861 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
4866 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
4867 csi.fs.fsCsb[0] != 0) {
4868 list->element[n].mask = csi.fs.fsCsb[0];
4869 list->element[n].charset = csi.ciCharset;
4870 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
4873 else { /* charset is DEFAULT_CHARSET or invalid. */
4876 /* Set the current codepage's charset as the first element. */
4878 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
4879 csi.fs.fsCsb[0] != 0) {
4880 list->element[n].mask = csi.fs.fsCsb[0];
4881 list->element[n].charset = csi.ciCharset;
4882 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
4886 /* Fill out left elements. */
4887 for (i = 0; i < 32; i++) {
4889 fs.fsCsb[0] = 1L << i;
4891 if (n > 0 && fs.fsCsb[0] == list->element[0].mask)
4892 continue; /* skip, already added. */
4893 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
4894 continue; /* skip, this is an invalid fsCsb bit. */
4896 list->element[n].mask = fs.fsCsb[0];
4897 list->element[n].charset = csi.ciCharset;
4898 load_script_name( i, list->element[n].name );
4907 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
4908 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
4913 if (face->cached_enum_data)
4916 *pelf = face->cached_enum_data->elf;
4917 *pntm = face->cached_enum_data->ntm;
4918 *ptype = face->cached_enum_data->type;
4922 font = alloc_font();
4924 if(face->scalable) {
4925 height = -2048; /* 2048 is the most common em size */
4928 height = face->size.y_ppem >> 6;
4929 width = face->size.x_ppem >> 6;
4931 font->scale_y = 1.0;
4933 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
4939 font->name = strdupW(face->family->FamilyName);
4940 font->ntmFlags = face->ntmFlags;
4942 if (get_outline_text_metrics(font))
4944 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
4946 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
4948 lstrcpynW(pelf->elfLogFont.lfFaceName,
4949 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
4951 lstrcpynW(pelf->elfFullName,
4952 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFullName),
4954 lstrcpynW(pelf->elfStyle,
4955 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
4960 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
4962 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
4964 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
4966 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
4968 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
4969 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
4972 pntm->ntmTm.ntmFlags = face->ntmFlags;
4973 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
4974 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
4975 pntm->ntmFontSig = face->fs;
4977 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
4979 pelf->elfLogFont.lfEscapement = 0;
4980 pelf->elfLogFont.lfOrientation = 0;
4981 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
4982 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
4983 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
4984 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
4985 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
4986 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
4987 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
4988 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
4989 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
4990 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
4991 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
4994 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
4995 *ptype |= TRUETYPE_FONTTYPE;
4996 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
4997 *ptype |= DEVICE_FONTTYPE;
4998 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
4999 *ptype |= RASTER_FONTTYPE;
5001 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
5002 if (face->cached_enum_data)
5004 face->cached_enum_data->elf = *pelf;
5005 face->cached_enum_data->ntm = *pntm;
5006 face->cached_enum_data->type = *ptype;
5012 static void create_full_name(WCHAR *full_name, const WCHAR *family_name, const WCHAR *style_name)
5014 static const WCHAR spaceW[] = { ' ', 0 };
5016 strcpyW(full_name, family_name);
5017 strcatW(full_name, spaceW);
5018 strcatW(full_name, style_name);
5021 static BOOL family_matches(Family *family, const LOGFONTW *lf)
5023 const struct list *face_list, *face_elem_ptr;
5025 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
5027 face_list = get_face_list_from_family(family);
5028 LIST_FOR_EACH(face_elem_ptr, face_list)
5030 WCHAR full_family_name[LF_FULLFACESIZE];
5031 Face *face = LIST_ENTRY(face_elem_ptr, Face, entry);
5033 if (strlenW(family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
5035 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
5036 debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
5040 create_full_name(full_family_name, family->FamilyName, face->StyleName);
5041 if (!strcmpiW(lf->lfFaceName, full_family_name)) return TRUE;
5047 static BOOL face_matches(const WCHAR *family_name, Face *face, const LOGFONTW *lf)
5049 WCHAR full_family_name[LF_FULLFACESIZE];
5051 if (!strcmpiW(lf->lfFaceName, family_name)) return TRUE;
5053 if (strlenW(family_name) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
5055 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
5056 debugstr_w(family_name), debugstr_w(face->StyleName));
5060 create_full_name(full_family_name, family_name, face->StyleName);
5061 return !strcmpiW(lf->lfFaceName, full_family_name);
5064 static BOOL enum_face_charsets(const Family *family, Face *face, struct enum_charset_list *list,
5065 FONTENUMPROCW proc, LPARAM lparam)
5068 NEWTEXTMETRICEXW ntm;
5072 GetEnumStructs(face, &elf, &ntm, &type);
5073 for(i = 0; i < list->total; i++) {
5074 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
5075 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
5076 load_script_name( IDS_OEM_DOS, elf.elfScript );
5077 i = list->total; /* break out of loop after enumeration */
5078 } else if(!(face->fs.fsCsb[0] & list->element[i].mask))
5081 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
5082 strcpyW(elf.elfScript, list->element[i].name);
5083 if (!elf.elfScript[0])
5084 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
5086 /* Font Replacement */
5087 if (family != face->family)
5089 strcpyW(elf.elfLogFont.lfFaceName, family->FamilyName);
5090 create_full_name(elf.elfFullName, family->FamilyName, face->StyleName);
5092 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
5093 debugstr_w(elf.elfLogFont.lfFaceName),
5094 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
5095 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
5096 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
5097 ntm.ntmTm.ntmFlags);
5098 /* release section before callback (FIXME) */
5099 LeaveCriticalSection( &freetype_cs );
5100 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
5101 EnterCriticalSection( &freetype_cs );
5106 /*************************************************************
5107 * freetype_EnumFonts
5109 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
5113 const struct list *family_elem_ptr, *face_list, *face_elem_ptr;
5115 struct enum_charset_list enum_charsets;
5119 lf.lfCharSet = DEFAULT_CHARSET;
5120 lf.lfPitchAndFamily = 0;
5121 lf.lfFaceName[0] = 0;
5125 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
5127 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
5130 EnterCriticalSection( &freetype_cs );
5131 if(plf->lfFaceName[0]) {
5133 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
5136 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
5137 debugstr_w(psub->to.name));
5139 strcpyW(lf.lfFaceName, psub->to.name);
5143 LIST_FOR_EACH(family_elem_ptr, &font_list) {
5144 family = LIST_ENTRY(family_elem_ptr, Family, entry);
5145 if(family_matches(family, plf)) {
5146 face_list = get_face_list_from_family(family);
5147 LIST_FOR_EACH(face_elem_ptr, face_list) {
5148 face = LIST_ENTRY(face_elem_ptr, Face, entry);
5149 if (!face_matches(family->FamilyName, face, plf)) continue;
5150 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
5155 LIST_FOR_EACH(family_elem_ptr, &font_list) {
5156 family = LIST_ENTRY(family_elem_ptr, Family, entry);
5157 face_list = get_face_list_from_family(family);
5158 face_elem_ptr = list_head(face_list);
5159 face = LIST_ENTRY(face_elem_ptr, Face, entry);
5160 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
5163 LeaveCriticalSection( &freetype_cs );
5167 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
5169 pt->x.value = vec->x >> 6;
5170 pt->x.fract = (vec->x & 0x3f) << 10;
5171 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
5172 pt->y.value = vec->y >> 6;
5173 pt->y.fract = (vec->y & 0x3f) << 10;
5174 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
5178 /***************************************************
5179 * According to the MSDN documentation on WideCharToMultiByte,
5180 * certain codepages cannot set the default_used parameter.
5181 * This returns TRUE if the codepage can set that parameter, false else
5182 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
5184 static BOOL codepage_sets_default_used(UINT codepage)
5198 * GSUB Table handling functions
5201 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
5203 const GSUB_CoverageFormat1* cf1;
5207 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
5209 int count = GET_BE_WORD(cf1->GlyphCount);
5211 TRACE("Coverage Format 1, %i glyphs\n",count);
5212 for (i = 0; i < count; i++)
5213 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
5217 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
5219 const GSUB_CoverageFormat2* cf2;
5222 cf2 = (const GSUB_CoverageFormat2*)cf1;
5224 count = GET_BE_WORD(cf2->RangeCount);
5225 TRACE("Coverage Format 2, %i ranges\n",count);
5226 for (i = 0; i < count; i++)
5228 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
5230 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
5231 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
5233 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
5234 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
5240 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
5245 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
5247 const GSUB_ScriptList *script;
5248 const GSUB_Script *deflt = NULL;
5250 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
5252 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
5253 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
5255 const GSUB_Script *scr;
5258 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
5259 scr = (const GSUB_Script*)((const BYTE*)script + offset);
5261 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
5263 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
5269 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
5273 const GSUB_LangSys *Lang;
5275 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
5277 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
5279 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
5280 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5282 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
5285 offset = GET_BE_WORD(script->DefaultLangSys);
5288 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5294 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
5297 const GSUB_FeatureList *feature;
5298 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
5300 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
5301 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
5303 int index = GET_BE_WORD(lang->FeatureIndex[i]);
5304 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
5306 const GSUB_Feature *feat;
5307 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
5314 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
5318 const GSUB_LookupList *lookup;
5319 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
5321 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
5322 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
5324 const GSUB_LookupTable *look;
5325 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
5326 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
5327 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
5328 if (GET_BE_WORD(look->LookupType) != 1)
5329 FIXME("We only handle SubType 1\n");
5334 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
5336 const GSUB_SingleSubstFormat1 *ssf1;
5337 offset = GET_BE_WORD(look->SubTable[j]);
5338 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
5339 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
5341 int offset = GET_BE_WORD(ssf1->Coverage);
5342 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
5343 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
5345 TRACE(" Glyph 0x%x ->",glyph);
5346 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
5347 TRACE(" 0x%x\n",glyph);
5352 const GSUB_SingleSubstFormat2 *ssf2;
5356 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
5357 offset = GET_BE_WORD(ssf1->Coverage);
5358 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
5359 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
5360 TRACE(" Coverage index %i\n",index);
5363 TRACE(" Glyph is 0x%x ->",glyph);
5364 glyph = GET_BE_WORD(ssf2->Substitute[index]);
5365 TRACE("0x%x\n",glyph);
5374 static const char* get_opentype_script(const GdiFont *font)
5377 * I am not sure if this is the correct way to generate our script tag
5380 switch (font->charset)
5382 case ANSI_CHARSET: return "latn";
5383 case BALTIC_CHARSET: return "latn"; /* ?? */
5384 case CHINESEBIG5_CHARSET: return "hani";
5385 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
5386 case GB2312_CHARSET: return "hani";
5387 case GREEK_CHARSET: return "grek";
5388 case HANGUL_CHARSET: return "hang";
5389 case RUSSIAN_CHARSET: return "cyrl";
5390 case SHIFTJIS_CHARSET: return "kana";
5391 case TURKISH_CHARSET: return "latn"; /* ?? */
5392 case VIETNAMESE_CHARSET: return "latn";
5393 case JOHAB_CHARSET: return "latn"; /* ?? */
5394 case ARABIC_CHARSET: return "arab";
5395 case HEBREW_CHARSET: return "hebr";
5396 case THAI_CHARSET: return "thai";
5397 default: return "latn";
5401 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
5403 const GSUB_Header *header;
5404 const GSUB_Script *script;
5405 const GSUB_LangSys *language;
5406 const GSUB_Feature *feature;
5408 if (!font->GSUB_Table)
5411 header = font->GSUB_Table;
5413 script = GSUB_get_script_table(header, get_opentype_script(font));
5416 TRACE("Script not found\n");
5419 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
5422 TRACE("Language not found\n");
5425 feature = GSUB_get_feature(header, language, "vrt2");
5427 feature = GSUB_get_feature(header, language, "vert");
5430 TRACE("vrt2/vert feature not found\n");
5433 return GSUB_apply_feature(header, feature, glyph);
5436 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
5440 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
5441 WCHAR wc = (WCHAR)glyph;
5443 BOOL *default_used_pointer;
5446 default_used_pointer = NULL;
5447 default_used = FALSE;
5448 if (codepage_sets_default_used(font->codepage))
5449 default_used_pointer = &default_used;
5450 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
5453 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
5454 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
5458 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
5460 if (glyph < 0x100) glyph += 0xf000;
5461 /* there is a number of old pre-Unicode "broken" TTFs, which
5462 do have symbols at U+00XX instead of U+f0XX */
5463 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
5464 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
5466 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
5471 /*************************************************************
5472 * freetype_GetGlyphIndices
5474 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
5476 struct freetype_physdev *physdev = get_freetype_dev( dev );
5479 BOOL got_default = FALSE;
5483 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
5484 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
5487 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
5489 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
5494 EnterCriticalSection( &freetype_cs );
5496 for(i = 0; i < count; i++)
5498 pgi[i] = get_glyph_index(physdev->font, lpstr[i]);
5503 if (FT_IS_SFNT(physdev->font->ft_face))
5505 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(physdev->font->ft_face, ft_sfnt_os2);
5506 default_char = (pOS2->usDefaultChar ? get_glyph_index(physdev->font, pOS2->usDefaultChar) : 0);
5511 get_text_metrics(physdev->font, &textm);
5512 default_char = textm.tmDefaultChar;
5516 pgi[i] = default_char;
5519 LeaveCriticalSection( &freetype_cs );
5523 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
5525 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
5526 return !memcmp(matrix, &identity, sizeof(FMAT2));
5529 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
5531 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
5532 return !memcmp(matrix, &identity, sizeof(MAT2));
5535 static inline BYTE get_max_level( UINT format )
5539 case GGO_GRAY2_BITMAP: return 4;
5540 case GGO_GRAY4_BITMAP: return 16;
5541 case GGO_GRAY8_BITMAP: return 64;
5546 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5548 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
5549 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5552 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
5553 FT_Face ft_face = incoming_font->ft_face;
5554 GdiFont *font = incoming_font;
5555 FT_UInt glyph_index;
5556 DWORD width, height, pitch, needed = 0;
5557 FT_Bitmap ft_bitmap;
5559 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
5561 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
5562 double widthRatio = 1.0;
5563 FT_Matrix transMat = identityMat;
5564 FT_Matrix transMatUnrotated;
5565 BOOL needsTransform = FALSE;
5566 BOOL tategaki = (font->GSUB_Table != NULL);
5567 UINT original_index;
5569 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
5570 buflen, buf, lpmat);
5572 TRACE("font transform %f %f %f %f\n",
5573 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
5574 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
5576 if(format & GGO_GLYPH_INDEX) {
5577 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
5578 original_index = glyph;
5579 format &= ~GGO_GLYPH_INDEX;
5581 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
5582 ft_face = font->ft_face;
5583 original_index = glyph_index;
5586 if(format & GGO_UNHINTED) {
5587 load_flags |= FT_LOAD_NO_HINTING;
5588 format &= ~GGO_UNHINTED;
5591 /* tategaki never appears to happen to lower glyph index */
5592 if (glyph_index < TATEGAKI_LOWER_BOUND )
5595 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
5596 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
5597 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
5598 font->gmsize * sizeof(GM*));
5600 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
5601 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
5603 *lpgm = FONT_GM(font,original_index)->gm;
5604 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5605 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5606 lpgm->gmCellIncX, lpgm->gmCellIncY);
5607 return 1; /* FIXME */
5611 if (!font->gm[original_index / GM_BLOCK_SIZE])
5612 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
5614 /* Scaling factor */
5619 get_text_metrics(font, &tm);
5621 widthRatio = (double)font->aveWidth;
5622 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5625 widthRatio = font->scale_y;
5627 /* Scaling transform */
5628 if (widthRatio != 1.0 || font->scale_y != 1.0)
5631 scaleMat.xx = FT_FixedFromFloat(widthRatio);
5634 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
5636 pFT_Matrix_Multiply(&scaleMat, &transMat);
5637 needsTransform = TRUE;
5640 /* Slant transform */
5641 if (font->fake_italic) {
5644 slantMat.xx = (1 << 16);
5645 slantMat.xy = ((1 << 16) >> 2);
5647 slantMat.yy = (1 << 16);
5648 pFT_Matrix_Multiply(&slantMat, &transMat);
5649 needsTransform = TRUE;
5652 /* Rotation transform */
5653 transMatUnrotated = transMat;
5654 if(font->orientation && !tategaki) {
5655 FT_Matrix rotationMat;
5657 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
5658 pFT_Vector_Unit(&vecAngle, angle);
5659 rotationMat.xx = vecAngle.x;
5660 rotationMat.xy = -vecAngle.y;
5661 rotationMat.yx = -rotationMat.xy;
5662 rotationMat.yy = rotationMat.xx;
5664 pFT_Matrix_Multiply(&rotationMat, &transMat);
5665 needsTransform = TRUE;
5668 /* World transform */
5669 if (!is_identity_FMAT2(&font->font_desc.matrix))
5672 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
5673 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
5674 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
5675 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
5676 pFT_Matrix_Multiply(&worldMat, &transMat);
5677 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
5678 needsTransform = TRUE;
5681 /* Extra transformation specified by caller */
5682 if (!is_identity_MAT2(lpmat))
5685 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
5686 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
5687 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
5688 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
5689 pFT_Matrix_Multiply(&extraMat, &transMat);
5690 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
5691 needsTransform = TRUE;
5694 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
5695 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
5696 format == GGO_GRAY8_BITMAP))
5698 load_flags |= FT_LOAD_NO_BITMAP;
5701 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
5704 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
5708 if(!needsTransform) {
5709 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
5710 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
5711 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
5713 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
5714 bottom = (ft_face->glyph->metrics.horiBearingY -
5715 ft_face->glyph->metrics.height) & -64;
5716 lpgm->gmCellIncX = adv;
5717 lpgm->gmCellIncY = 0;
5724 for(xc = 0; xc < 2; xc++) {
5725 for(yc = 0; yc < 2; yc++) {
5726 vec.x = (ft_face->glyph->metrics.horiBearingX +
5727 xc * ft_face->glyph->metrics.width);
5728 vec.y = ft_face->glyph->metrics.horiBearingY -
5729 yc * ft_face->glyph->metrics.height;
5730 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
5731 pFT_Vector_Transform(&vec, &transMat);
5732 if(xc == 0 && yc == 0) {
5733 left = right = vec.x;
5734 top = bottom = vec.y;
5736 if(vec.x < left) left = vec.x;
5737 else if(vec.x > right) right = vec.x;
5738 if(vec.y < bottom) bottom = vec.y;
5739 else if(vec.y > top) top = vec.y;
5744 right = (right + 63) & -64;
5745 bottom = bottom & -64;
5746 top = (top + 63) & -64;
5748 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
5749 vec.x = ft_face->glyph->metrics.horiAdvance;
5751 pFT_Vector_Transform(&vec, &transMat);
5752 lpgm->gmCellIncX = (vec.x+63) >> 6;
5753 lpgm->gmCellIncY = -((vec.y+63) >> 6);
5755 vec.x = ft_face->glyph->metrics.horiAdvance;
5757 pFT_Vector_Transform(&vec, &transMatUnrotated);
5758 adv = (vec.x+63) >> 6;
5762 bbx = (right - left) >> 6;
5763 lpgm->gmBlackBoxX = (right - left) >> 6;
5764 lpgm->gmBlackBoxY = (top - bottom) >> 6;
5765 lpgm->gmptGlyphOrigin.x = left >> 6;
5766 lpgm->gmptGlyphOrigin.y = top >> 6;
5768 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5769 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5770 lpgm->gmCellIncX, lpgm->gmCellIncY);
5772 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
5773 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
5775 FONT_GM(font,original_index)->gm = *lpgm;
5776 FONT_GM(font,original_index)->adv = adv;
5777 FONT_GM(font,original_index)->lsb = lsb;
5778 FONT_GM(font,original_index)->bbx = bbx;
5779 FONT_GM(font,original_index)->init = TRUE;
5782 if(format == GGO_METRICS)
5784 return 1; /* FIXME */
5787 if(ft_face->glyph->format != ft_glyph_format_outline &&
5788 (format == GGO_NATIVE || format == GGO_BEZIER))
5790 TRACE("loaded a bitmap\n");
5796 width = lpgm->gmBlackBoxX;
5797 height = lpgm->gmBlackBoxY;
5798 pitch = ((width + 31) >> 5) << 2;
5799 needed = pitch * height;
5801 if(!buf || !buflen) break;
5803 switch(ft_face->glyph->format) {
5804 case ft_glyph_format_bitmap:
5806 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5807 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
5808 INT h = ft_face->glyph->bitmap.rows;
5810 memcpy(dst, src, w);
5811 src += ft_face->glyph->bitmap.pitch;
5817 case ft_glyph_format_outline:
5818 ft_bitmap.width = width;
5819 ft_bitmap.rows = height;
5820 ft_bitmap.pitch = pitch;
5821 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
5822 ft_bitmap.buffer = buf;
5825 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5827 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5829 /* Note: FreeType will only set 'black' bits for us. */
5830 memset(buf, 0, needed);
5831 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5835 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5840 case GGO_GRAY2_BITMAP:
5841 case GGO_GRAY4_BITMAP:
5842 case GGO_GRAY8_BITMAP:
5843 case WINE_GGO_GRAY16_BITMAP:
5845 unsigned int max_level, row, col;
5848 width = lpgm->gmBlackBoxX;
5849 height = lpgm->gmBlackBoxY;
5850 pitch = (width + 3) / 4 * 4;
5851 needed = pitch * height;
5853 if(!buf || !buflen) break;
5855 max_level = get_max_level( format );
5857 switch(ft_face->glyph->format) {
5858 case ft_glyph_format_bitmap:
5860 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5861 INT h = ft_face->glyph->bitmap.rows;
5863 memset( buf, 0, needed );
5865 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
5866 if (src[x / 8] & masks[x % 8]) dst[x] = max_level;
5867 src += ft_face->glyph->bitmap.pitch;
5872 case ft_glyph_format_outline:
5874 ft_bitmap.width = width;
5875 ft_bitmap.rows = height;
5876 ft_bitmap.pitch = pitch;
5877 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
5878 ft_bitmap.buffer = buf;
5881 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5883 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5885 memset(ft_bitmap.buffer, 0, buflen);
5887 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5889 if (max_level != 255)
5891 for (row = 0, start = buf; row < height; row++)
5893 for (col = 0, ptr = start; col < width; col++, ptr++)
5894 *ptr = (((int)*ptr) * max_level + 128) / 256;
5902 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5908 case WINE_GGO_HRGB_BITMAP:
5909 case WINE_GGO_HBGR_BITMAP:
5910 case WINE_GGO_VRGB_BITMAP:
5911 case WINE_GGO_VBGR_BITMAP:
5912 #ifdef HAVE_FREETYPE_FTLCDFIL_H
5914 switch (ft_face->glyph->format)
5916 case FT_GLYPH_FORMAT_BITMAP:
5921 width = lpgm->gmBlackBoxX;
5922 height = lpgm->gmBlackBoxY;
5924 needed = pitch * height;
5926 if (!buf || !buflen) break;
5928 memset(buf, 0, buflen);
5930 src = ft_face->glyph->bitmap.buffer;
5931 src_pitch = ft_face->glyph->bitmap.pitch;
5933 height = min( height, ft_face->glyph->bitmap.rows );
5936 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
5938 if ( src[x / 8] & masks[x % 8] )
5939 ((unsigned int *)dst)[x] = ~0u;
5948 case FT_GLYPH_FORMAT_OUTLINE:
5952 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
5953 INT x_shift, y_shift;
5955 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
5956 FT_Render_Mode render_mode =
5957 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
5958 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
5960 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
5962 if ( render_mode == FT_RENDER_MODE_LCD)
5964 lpgm->gmBlackBoxX += 2;
5965 lpgm->gmptGlyphOrigin.x -= 1;
5969 lpgm->gmBlackBoxY += 2;
5970 lpgm->gmptGlyphOrigin.y += 1;
5974 width = lpgm->gmBlackBoxX;
5975 height = lpgm->gmBlackBoxY;
5977 needed = pitch * height;
5979 if (!buf || !buflen) break;
5981 memset(buf, 0, buflen);
5983 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
5985 if ( needsTransform )
5986 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
5988 if ( pFT_Library_SetLcdFilter )
5989 pFT_Library_SetLcdFilter( library, lcdfilter );
5990 pFT_Render_Glyph (ft_face->glyph, render_mode);
5992 src = ft_face->glyph->bitmap.buffer;
5993 src_pitch = ft_face->glyph->bitmap.pitch;
5994 src_width = ft_face->glyph->bitmap.width;
5995 src_height = ft_face->glyph->bitmap.rows;
5997 if ( render_mode == FT_RENDER_MODE_LCD)
6005 rgb_interval = src_pitch;
6010 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
6011 if ( x_shift < 0 ) x_shift = 0;
6012 if ( x_shift + (src_width / hmul) > width )
6013 x_shift = width - (src_width / hmul);
6015 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
6016 if ( y_shift < 0 ) y_shift = 0;
6017 if ( y_shift + (src_height / vmul) > height )
6018 y_shift = height - (src_height / vmul);
6020 dst += x_shift + y_shift * ( pitch / 4 );
6021 while ( src_height )
6023 for ( x = 0; x < src_width / hmul; x++ )
6027 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
6028 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6029 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
6030 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6034 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
6035 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6036 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
6037 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6040 src += src_pitch * vmul;
6049 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
6061 int contour, point = 0, first_pt;
6062 FT_Outline *outline = &ft_face->glyph->outline;
6063 TTPOLYGONHEADER *pph;
6065 DWORD pph_start, cpfx, type;
6067 if(buflen == 0) buf = NULL;
6069 if (needsTransform && buf) {
6070 pFT_Outline_Transform(outline, &transMat);
6073 for(contour = 0; contour < outline->n_contours; contour++) {
6075 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6078 pph->dwType = TT_POLYGON_TYPE;
6079 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6081 needed += sizeof(*pph);
6083 while(point <= outline->contours[contour]) {
6084 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6085 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6086 TT_PRIM_LINE : TT_PRIM_QSPLINE;
6090 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6093 } while(point <= outline->contours[contour] &&
6094 (outline->tags[point] & FT_Curve_Tag_On) ==
6095 (outline->tags[point-1] & FT_Curve_Tag_On));
6096 /* At the end of a contour Windows adds the start point, but
6098 if(point > outline->contours[contour] &&
6099 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
6101 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
6103 } else if(point <= outline->contours[contour] &&
6104 outline->tags[point] & FT_Curve_Tag_On) {
6105 /* add closing pt for bezier */
6107 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6115 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6118 pph->cb = needed - pph_start;
6124 /* Convert the quadratic Beziers to cubic Beziers.
6125 The parametric eqn for a cubic Bezier is, from PLRM:
6126 r(t) = at^3 + bt^2 + ct + r0
6127 with the control points:
6132 A quadratic Bezier has the form:
6133 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6135 So equating powers of t leads to:
6136 r1 = 2/3 p1 + 1/3 p0
6137 r2 = 2/3 p1 + 1/3 p2
6138 and of course r0 = p0, r3 = p2
6141 int contour, point = 0, first_pt;
6142 FT_Outline *outline = &ft_face->glyph->outline;
6143 TTPOLYGONHEADER *pph;
6145 DWORD pph_start, cpfx, type;
6146 FT_Vector cubic_control[4];
6147 if(buflen == 0) buf = NULL;
6149 if (needsTransform && buf) {
6150 pFT_Outline_Transform(outline, &transMat);
6153 for(contour = 0; contour < outline->n_contours; contour++) {
6155 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6158 pph->dwType = TT_POLYGON_TYPE;
6159 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6161 needed += sizeof(*pph);
6163 while(point <= outline->contours[contour]) {
6164 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6165 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6166 TT_PRIM_LINE : TT_PRIM_CSPLINE;
6169 if(type == TT_PRIM_LINE) {
6171 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6175 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6178 /* FIXME: Possible optimization in endpoint calculation
6179 if there are two consecutive curves */
6180 cubic_control[0] = outline->points[point-1];
6181 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
6182 cubic_control[0].x += outline->points[point].x + 1;
6183 cubic_control[0].y += outline->points[point].y + 1;
6184 cubic_control[0].x >>= 1;
6185 cubic_control[0].y >>= 1;
6187 if(point+1 > outline->contours[contour])
6188 cubic_control[3] = outline->points[first_pt];
6190 cubic_control[3] = outline->points[point+1];
6191 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
6192 cubic_control[3].x += outline->points[point].x + 1;
6193 cubic_control[3].y += outline->points[point].y + 1;
6194 cubic_control[3].x >>= 1;
6195 cubic_control[3].y >>= 1;
6198 /* r1 = 1/3 p0 + 2/3 p1
6199 r2 = 1/3 p2 + 2/3 p1 */
6200 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
6201 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
6202 cubic_control[2] = cubic_control[1];
6203 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
6204 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
6205 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
6206 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
6208 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
6209 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
6210 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
6215 } while(point <= outline->contours[contour] &&
6216 (outline->tags[point] & FT_Curve_Tag_On) ==
6217 (outline->tags[point-1] & FT_Curve_Tag_On));
6218 /* At the end of a contour Windows adds the start point,
6219 but only for Beziers and we've already done that.
6221 if(point <= outline->contours[contour] &&
6222 outline->tags[point] & FT_Curve_Tag_On) {
6223 /* This is the closing pt of a bezier, but we've already
6224 added it, so just inc point and carry on */
6231 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6234 pph->cb = needed - pph_start;
6240 FIXME("Unsupported format %d\n", format);
6246 static BOOL get_bitmap_text_metrics(GdiFont *font)
6248 FT_Face ft_face = font->ft_face;
6249 FT_WinFNT_HeaderRec winfnt_header;
6250 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
6251 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
6252 font->potm->otmSize = size;
6254 #define TM font->potm->otmTextMetrics
6255 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
6257 TM.tmHeight = winfnt_header.pixel_height;
6258 TM.tmAscent = winfnt_header.ascent;
6259 TM.tmDescent = TM.tmHeight - TM.tmAscent;
6260 TM.tmInternalLeading = winfnt_header.internal_leading;
6261 TM.tmExternalLeading = winfnt_header.external_leading;
6262 TM.tmAveCharWidth = winfnt_header.avg_width;
6263 TM.tmMaxCharWidth = winfnt_header.max_width;
6264 TM.tmWeight = winfnt_header.weight;
6266 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
6267 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
6268 TM.tmFirstChar = winfnt_header.first_char;
6269 TM.tmLastChar = winfnt_header.last_char;
6270 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
6271 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
6272 TM.tmItalic = winfnt_header.italic;
6273 TM.tmUnderlined = font->underline;
6274 TM.tmStruckOut = font->strikeout;
6275 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
6276 TM.tmCharSet = winfnt_header.charset;
6280 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
6281 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
6282 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6283 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
6284 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
6285 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
6286 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
6287 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
6289 TM.tmDigitizedAspectX = 96; /* FIXME */
6290 TM.tmDigitizedAspectY = 96; /* FIXME */
6292 TM.tmLastChar = 255;
6293 TM.tmDefaultChar = 32;
6294 TM.tmBreakChar = 32;
6295 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
6296 TM.tmUnderlined = font->underline;
6297 TM.tmStruckOut = font->strikeout;
6298 /* NB inverted meaning of TMPF_FIXED_PITCH */
6299 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
6300 TM.tmCharSet = font->charset;
6308 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
6310 double scale_x, scale_y;
6314 scale_x = (double)font->aveWidth;
6315 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6318 scale_x = font->scale_y;
6320 scale_x *= fabs(font->font_desc.matrix.eM11);
6321 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6323 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6324 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6326 SCALE_Y(ptm->tmHeight);
6327 SCALE_Y(ptm->tmAscent);
6328 SCALE_Y(ptm->tmDescent);
6329 SCALE_Y(ptm->tmInternalLeading);
6330 SCALE_Y(ptm->tmExternalLeading);
6331 SCALE_Y(ptm->tmOverhang);
6333 SCALE_X(ptm->tmAveCharWidth);
6334 SCALE_X(ptm->tmMaxCharWidth);
6340 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
6342 double scale_x, scale_y;
6346 scale_x = (double)font->aveWidth;
6347 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6350 scale_x = font->scale_y;
6352 scale_x *= fabs(font->font_desc.matrix.eM11);
6353 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6355 scale_font_metrics(font, &potm->otmTextMetrics);
6357 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6358 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6360 SCALE_Y(potm->otmAscent);
6361 SCALE_Y(potm->otmDescent);
6362 SCALE_Y(potm->otmLineGap);
6363 SCALE_Y(potm->otmsCapEmHeight);
6364 SCALE_Y(potm->otmsXHeight);
6365 SCALE_Y(potm->otmrcFontBox.top);
6366 SCALE_Y(potm->otmrcFontBox.bottom);
6367 SCALE_X(potm->otmrcFontBox.left);
6368 SCALE_X(potm->otmrcFontBox.right);
6369 SCALE_Y(potm->otmMacAscent);
6370 SCALE_Y(potm->otmMacDescent);
6371 SCALE_Y(potm->otmMacLineGap);
6372 SCALE_X(potm->otmptSubscriptSize.x);
6373 SCALE_Y(potm->otmptSubscriptSize.y);
6374 SCALE_X(potm->otmptSubscriptOffset.x);
6375 SCALE_Y(potm->otmptSubscriptOffset.y);
6376 SCALE_X(potm->otmptSuperscriptSize.x);
6377 SCALE_Y(potm->otmptSuperscriptSize.y);
6378 SCALE_X(potm->otmptSuperscriptOffset.x);
6379 SCALE_Y(potm->otmptSuperscriptOffset.y);
6380 SCALE_Y(potm->otmsStrikeoutSize);
6381 SCALE_Y(potm->otmsStrikeoutPosition);
6382 SCALE_Y(potm->otmsUnderscoreSize);
6383 SCALE_Y(potm->otmsUnderscorePosition);
6389 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
6393 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
6395 /* Make sure that the font has sane width/height ratio */
6398 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
6400 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
6405 *ptm = font->potm->otmTextMetrics;
6406 scale_font_metrics(font, ptm);
6410 static BOOL face_has_symbol_charmap(FT_Face ft_face)
6414 for(i = 0; i < ft_face->num_charmaps; i++)
6416 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
6422 static BOOL get_outline_text_metrics(GdiFont *font)
6425 FT_Face ft_face = font->ft_face;
6426 UINT needed, lenfam, lensty;
6428 TT_HoriHeader *pHori;
6429 TT_Postscript *pPost;
6430 FT_Fixed x_scale, y_scale;
6431 WCHAR *family_nameW, *style_nameW;
6432 static const WCHAR spaceW[] = {' ', '\0'};
6434 INT ascent, descent;
6436 TRACE("font=%p\n", font);
6438 if(!FT_IS_SCALABLE(ft_face))
6441 needed = sizeof(*font->potm);
6443 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
6444 family_nameW = strdupW(font->name);
6446 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
6448 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
6449 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
6450 style_nameW, lensty/sizeof(WCHAR));
6452 /* These names should be read from the TT name table */
6454 /* length of otmpFamilyName */
6457 /* length of otmpFaceName */
6458 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
6459 needed += lenfam; /* just the family name */
6461 needed += lenfam + lensty; /* family + " " + style */
6464 /* length of otmpStyleName */
6467 /* length of otmpFullName */
6468 needed += lenfam + lensty;
6471 x_scale = ft_face->size->metrics.x_scale;
6472 y_scale = ft_face->size->metrics.y_scale;
6474 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
6476 FIXME("Can't find OS/2 table - not TT font?\n");
6480 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
6482 FIXME("Can't find HHEA table - not TT font?\n");
6486 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
6488 TRACE("OS/2 winA = %d winD = %d typoA = %d typoD = %d typoLG = %d FT_Face a = %d, d = %d, h = %d: HORZ a = %d, d = %d lg = %d maxY = %ld minY = %ld\n",
6489 pOS2->usWinAscent, pOS2->usWinDescent,
6490 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
6491 ft_face->ascender, ft_face->descender, ft_face->height,
6492 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
6493 ft_face->bbox.yMax, ft_face->bbox.yMin);
6495 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
6496 font->potm->otmSize = needed;
6498 #define TM font->potm->otmTextMetrics
6500 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
6501 ascent = pHori->Ascender;
6502 descent = -pHori->Descender;
6504 ascent = pOS2->usWinAscent;
6505 descent = pOS2->usWinDescent;
6509 TM.tmAscent = font->yMax;
6510 TM.tmDescent = -font->yMin;
6511 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
6513 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
6514 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
6515 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
6516 - ft_face->units_per_EM, y_scale) + 32) >> 6;
6519 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6522 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6524 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
6525 ((ascent + descent) -
6526 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
6528 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
6529 if (TM.tmAveCharWidth == 0) {
6530 TM.tmAveCharWidth = 1;
6532 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
6533 TM.tmWeight = FW_REGULAR;
6534 if (font->fake_bold)
6535 TM.tmWeight = FW_BOLD;
6538 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
6540 if (pOS2->usWeightClass > FW_MEDIUM)
6541 TM.tmWeight = pOS2->usWeightClass;
6543 else if (pOS2->usWeightClass <= FW_MEDIUM)
6544 TM.tmWeight = pOS2->usWeightClass;
6547 TM.tmDigitizedAspectX = 300;
6548 TM.tmDigitizedAspectY = 300;
6549 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6550 * symbol range to 0 - f0ff
6553 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
6558 case 1257: /* Baltic */
6559 TM.tmLastChar = 0xf8fd;
6562 TM.tmLastChar = 0xf0ff;
6564 TM.tmBreakChar = 0x20;
6565 TM.tmDefaultChar = 0x1f;
6569 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
6570 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
6572 if(pOS2->usFirstCharIndex <= 1)
6573 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
6574 else if (pOS2->usFirstCharIndex > 0xff)
6575 TM.tmBreakChar = 0x20;
6577 TM.tmBreakChar = pOS2->usFirstCharIndex;
6578 TM.tmDefaultChar = TM.tmBreakChar - 1;
6580 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
6581 TM.tmUnderlined = font->underline;
6582 TM.tmStruckOut = font->strikeout;
6584 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6585 if(!FT_IS_FIXED_WIDTH(ft_face) &&
6586 (pOS2->version == 0xFFFFU ||
6587 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
6588 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
6590 TM.tmPitchAndFamily = 0;
6592 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
6594 case PAN_FAMILY_SCRIPT:
6595 TM.tmPitchAndFamily |= FF_SCRIPT;
6598 case PAN_FAMILY_DECORATIVE:
6599 TM.tmPitchAndFamily |= FF_DECORATIVE;
6604 case PAN_FAMILY_TEXT_DISPLAY:
6605 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
6606 /* which is clearly not what the panose spec says. */
6608 if(TM.tmPitchAndFamily == 0 || /* fixed */
6609 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
6610 TM.tmPitchAndFamily = FF_MODERN;
6613 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
6618 TM.tmPitchAndFamily |= FF_DONTCARE;
6621 case PAN_SERIF_COVE:
6622 case PAN_SERIF_OBTUSE_COVE:
6623 case PAN_SERIF_SQUARE_COVE:
6624 case PAN_SERIF_OBTUSE_SQUARE_COVE:
6625 case PAN_SERIF_SQUARE:
6626 case PAN_SERIF_THIN:
6627 case PAN_SERIF_BONE:
6628 case PAN_SERIF_EXAGGERATED:
6629 case PAN_SERIF_TRIANGLE:
6630 TM.tmPitchAndFamily |= FF_ROMAN;
6633 case PAN_SERIF_NORMAL_SANS:
6634 case PAN_SERIF_OBTUSE_SANS:
6635 case PAN_SERIF_PERP_SANS:
6636 case PAN_SERIF_FLARED:
6637 case PAN_SERIF_ROUNDED:
6638 TM.tmPitchAndFamily |= FF_SWISS;
6645 if(FT_IS_SCALABLE(ft_face))
6646 TM.tmPitchAndFamily |= TMPF_VECTOR;
6648 if(FT_IS_SFNT(ft_face))
6650 if (font->ntmFlags & NTM_PS_OPENTYPE)
6651 TM.tmPitchAndFamily |= TMPF_DEVICE;
6653 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
6656 TM.tmCharSet = font->charset;
6658 font->potm->otmFiller = 0;
6659 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
6660 font->potm->otmfsSelection = pOS2->fsSelection;
6661 font->potm->otmfsType = pOS2->fsType;
6662 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
6663 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
6664 font->potm->otmItalicAngle = 0; /* POST table */
6665 font->potm->otmEMSquare = ft_face->units_per_EM;
6666 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
6667 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
6668 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
6669 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
6670 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
6671 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
6672 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
6673 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
6674 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
6675 font->potm->otmMacAscent = TM.tmAscent;
6676 font->potm->otmMacDescent = -TM.tmDescent;
6677 font->potm->otmMacLineGap = font->potm->otmLineGap;
6678 font->potm->otmusMinimumPPEM = 0; /* TT Header */
6679 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
6680 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
6681 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
6682 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
6683 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
6684 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
6685 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
6686 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
6687 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
6688 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
6690 font->potm->otmsUnderscoreSize = 0;
6691 font->potm->otmsUnderscorePosition = 0;
6693 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
6694 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
6698 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
6699 cp = (char*)font->potm + sizeof(*font->potm);
6700 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
6701 strcpyW((WCHAR*)cp, family_nameW);
6703 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
6704 strcpyW((WCHAR*)cp, style_nameW);
6706 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
6707 strcpyW((WCHAR*)cp, family_nameW);
6708 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
6709 strcatW((WCHAR*)cp, spaceW);
6710 strcatW((WCHAR*)cp, style_nameW);
6711 cp += lenfam + lensty;
6714 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
6715 strcpyW((WCHAR*)cp, family_nameW);
6716 strcatW((WCHAR*)cp, spaceW);
6717 strcatW((WCHAR*)cp, style_nameW);
6721 HeapFree(GetProcessHeap(), 0, style_nameW);
6722 HeapFree(GetProcessHeap(), 0, family_nameW);
6726 /*************************************************************
6727 * freetype_GetGlyphOutline
6729 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
6730 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
6732 struct freetype_physdev *physdev = get_freetype_dev( dev );
6737 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
6738 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
6742 EnterCriticalSection( &freetype_cs );
6743 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, buflen, buf, lpmat );
6744 LeaveCriticalSection( &freetype_cs );
6748 /*************************************************************
6749 * freetype_GetTextMetrics
6751 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
6753 struct freetype_physdev *physdev = get_freetype_dev( dev );
6758 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
6759 return dev->funcs->pGetTextMetrics( dev, metrics );
6763 EnterCriticalSection( &freetype_cs );
6764 ret = get_text_metrics( physdev->font, metrics );
6765 LeaveCriticalSection( &freetype_cs );
6769 /*************************************************************
6770 * freetype_GetOutlineTextMetrics
6772 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
6774 struct freetype_physdev *physdev = get_freetype_dev( dev );
6779 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
6780 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
6783 TRACE("font=%p\n", physdev->font);
6785 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
6788 EnterCriticalSection( &freetype_cs );
6790 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
6792 if(cbSize >= physdev->font->potm->otmSize)
6794 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
6795 scale_outline_font_metrics(physdev->font, potm);
6797 ret = physdev->font->potm->otmSize;
6799 LeaveCriticalSection( &freetype_cs );
6803 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
6805 HFONTLIST *hfontlist;
6806 child->font = alloc_font();
6807 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
6808 if(!child->font->ft_face)
6810 free_font(child->font);
6815 child->font->font_desc = font->font_desc;
6816 child->font->ntmFlags = child->face->ntmFlags;
6817 child->font->orientation = font->orientation;
6818 child->font->scale_y = font->scale_y;
6819 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
6820 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
6821 child->font->name = strdupW(child->face->family->FamilyName);
6822 list_add_head(&child->font->hfontlist, &hfontlist->entry);
6823 child->font->base_font = font;
6824 list_add_head(&child_font_list, &child->font->entry);
6825 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
6829 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
6832 CHILD_FONT *child_font;
6835 font = font->base_font;
6837 *linked_font = font;
6839 if((*glyph = get_glyph_index(font, c)))
6841 *glyph = get_GSUB_vert_glyph(font, *glyph);
6845 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
6847 if(!child_font->font)
6848 if(!load_child_font(font, child_font))
6851 if(!child_font->font->ft_face)
6853 g = get_glyph_index(child_font->font, c);
6854 g = get_GSUB_vert_glyph(child_font->font, g);
6858 *linked_font = child_font->font;
6865 /*************************************************************
6866 * freetype_GetCharWidth
6868 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
6870 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6873 FT_UInt glyph_index;
6874 GdiFont *linked_font;
6875 struct freetype_physdev *physdev = get_freetype_dev( dev );
6879 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
6880 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
6883 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
6886 EnterCriticalSection( &freetype_cs );
6887 for(c = firstChar; c <= lastChar; c++) {
6888 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
6889 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6890 &gm, 0, NULL, &identity);
6891 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
6893 LeaveCriticalSection( &freetype_cs );
6897 /*************************************************************
6898 * freetype_GetCharABCWidths
6900 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
6902 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6905 FT_UInt glyph_index;
6906 GdiFont *linked_font;
6907 struct freetype_physdev *physdev = get_freetype_dev( dev );
6911 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
6912 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
6915 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
6918 EnterCriticalSection( &freetype_cs );
6920 for(c = firstChar; c <= lastChar; c++) {
6921 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
6922 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6923 &gm, 0, NULL, &identity);
6924 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
6925 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
6926 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
6927 FONT_GM(linked_font,glyph_index)->bbx;
6929 LeaveCriticalSection( &freetype_cs );
6933 /*************************************************************
6934 * freetype_GetCharABCWidthsI
6936 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
6938 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6941 FT_UInt glyph_index;
6942 GdiFont *linked_font;
6943 struct freetype_physdev *physdev = get_freetype_dev( dev );
6947 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
6948 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
6951 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
6955 EnterCriticalSection( &freetype_cs );
6957 get_glyph_index_linked(physdev->font, 'a', &linked_font, &glyph_index);
6959 for(c = firstChar; c < firstChar+count; c++) {
6960 get_glyph_outline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
6961 &gm, 0, NULL, &identity);
6962 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
6963 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
6964 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
6965 - FONT_GM(linked_font,c)->bbx;
6968 for(c = 0; c < count; c++) {
6969 get_glyph_outline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
6970 &gm, 0, NULL, &identity);
6971 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
6972 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
6973 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
6974 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
6977 LeaveCriticalSection( &freetype_cs );
6981 /*************************************************************
6982 * freetype_GetTextExtentExPoint
6984 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count,
6985 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6987 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6992 FT_UInt glyph_index;
6993 GdiFont *linked_font;
6994 struct freetype_physdev *physdev = get_freetype_dev( dev );
6998 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
6999 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, max_ext, pnfit, dxs, size );
7002 TRACE("%p, %s, %d, %d, %p\n", physdev->font, debugstr_wn(wstr, count), count, max_ext, size);
7005 EnterCriticalSection( &freetype_cs );
7008 get_text_metrics( physdev->font, &tm );
7009 size->cy = tm.tmHeight;
7011 for(idx = 0; idx < count; idx++) {
7012 get_glyph_index_linked( physdev->font, wstr[idx], &linked_font, &glyph_index );
7013 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
7014 &gm, 0, NULL, &identity);
7015 size->cx += FONT_GM(linked_font,glyph_index)->adv;
7017 if (! pnfit || ext <= max_ext) {
7027 LeaveCriticalSection( &freetype_cs );
7028 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
7032 /*************************************************************
7033 * freetype_GetTextExtentExPointI
7035 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count,
7036 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size )
7038 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7043 struct freetype_physdev *physdev = get_freetype_dev( dev );
7047 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
7048 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, max_ext, pnfit, dxs, size );
7051 TRACE("%p, %p, %d, %d, %p\n", physdev->font, indices, count, max_ext, size);
7054 EnterCriticalSection( &freetype_cs );
7057 get_text_metrics(physdev->font, &tm);
7058 size->cy = tm.tmHeight;
7060 for(idx = 0; idx < count; idx++) {
7061 get_glyph_outline(physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &identity);
7062 size->cx += FONT_GM(physdev->font,indices[idx])->adv;
7064 if (! pnfit || ext <= max_ext) {
7074 LeaveCriticalSection( &freetype_cs );
7075 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
7079 /*************************************************************
7080 * freetype_GetFontData
7082 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
7084 struct freetype_physdev *physdev = get_freetype_dev( dev );
7088 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
7089 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
7092 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
7093 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
7094 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
7096 return get_font_data( physdev->font, table, offset, buf, cbData );
7099 /*************************************************************
7100 * freetype_GetTextFace
7102 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
7105 struct freetype_physdev *physdev = get_freetype_dev( dev );
7109 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
7110 return dev->funcs->pGetTextFace( dev, count, str );
7113 n = strlenW(physdev->font->name) + 1;
7116 lstrcpynW(str, physdev->font->name, count);
7122 /*************************************************************
7123 * freetype_GetTextCharsetInfo
7125 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
7127 struct freetype_physdev *physdev = get_freetype_dev( dev );
7131 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
7132 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
7134 if (fs) *fs = physdev->font->fs;
7135 return physdev->font->charset;
7138 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
7140 GdiFont *font = dc->gdiFont, *linked_font;
7141 struct list *first_hfont;
7145 EnterCriticalSection( &freetype_cs );
7146 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
7147 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
7148 if(font == linked_font)
7149 *new_hfont = dc->hFont;
7152 first_hfont = list_head(&linked_font->hfontlist);
7153 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
7155 LeaveCriticalSection( &freetype_cs );
7159 /* Retrieve a list of supported Unicode ranges for a given font.
7160 * Can be called with NULL gs to calculate the buffer size. Returns
7161 * the number of ranges found.
7163 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
7165 DWORD num_ranges = 0;
7167 if (face->charmap->encoding == FT_ENCODING_UNICODE)
7170 FT_ULong char_code, char_code_prev;
7173 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
7175 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
7176 face->num_glyphs, glyph_code, char_code);
7178 if (!glyph_code) return 0;
7182 gs->ranges[0].wcLow = (USHORT)char_code;
7183 gs->ranges[0].cGlyphs = 0;
7184 gs->cGlyphsSupported = 0;
7190 if (char_code < char_code_prev)
7192 ERR("expected increasing char code from FT_Get_Next_Char\n");
7195 if (char_code - char_code_prev > 1)
7200 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
7201 gs->ranges[num_ranges - 1].cGlyphs = 1;
7202 gs->cGlyphsSupported++;
7207 gs->ranges[num_ranges - 1].cGlyphs++;
7208 gs->cGlyphsSupported++;
7210 char_code_prev = char_code;
7211 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
7215 FIXME("encoding %u not supported\n", face->charmap->encoding);
7220 /*************************************************************
7221 * freetype_GetFontUnicodeRanges
7223 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
7225 struct freetype_physdev *physdev = get_freetype_dev( dev );
7226 DWORD size, num_ranges;
7230 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
7231 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
7234 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
7235 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
7238 glyphset->cbThis = size;
7239 glyphset->cRanges = num_ranges;
7240 glyphset->flAccel = 0;
7245 /*************************************************************
7246 * freetype_FontIsLinked
7248 static BOOL freetype_FontIsLinked( PHYSDEV dev )
7250 struct freetype_physdev *physdev = get_freetype_dev( dev );
7255 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
7256 return dev->funcs->pFontIsLinked( dev );
7260 EnterCriticalSection( &freetype_cs );
7261 ret = !list_empty(&physdev->font->child_fonts);
7262 LeaveCriticalSection( &freetype_cs );
7266 static BOOL is_hinting_enabled(void)
7268 /* Use the >= 2.2.0 function if available */
7269 if(pFT_Get_TrueType_Engine_Type)
7271 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
7272 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
7274 #ifdef FT_DRIVER_HAS_HINTER
7279 /* otherwise if we've been compiled with < 2.2.0 headers
7280 use the internal macro */
7281 mod = pFT_Get_Module(library, "truetype");
7282 if(mod && FT_DRIVER_HAS_HINTER(mod))
7290 static BOOL is_subpixel_rendering_enabled( void )
7292 #ifdef HAVE_FREETYPE_FTLCDFIL_H
7293 return pFT_Library_SetLcdFilter &&
7294 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
7300 /*************************************************************************
7301 * GetRasterizerCaps (GDI32.@)
7303 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7305 static int hinting = -1;
7306 static int subpixel = -1;
7310 hinting = is_hinting_enabled();
7311 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
7314 if ( subpixel == -1 )
7316 subpixel = is_subpixel_rendering_enabled();
7317 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
7320 lprs->nSize = sizeof(RASTERIZER_STATUS);
7321 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
7323 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
7324 lprs->nLanguageID = 0;
7328 /*************************************************************
7329 * freetype_GdiRealizationInfo
7331 static BOOL freetype_GdiRealizationInfo( PHYSDEV dev, void *ptr )
7333 struct freetype_physdev *physdev = get_freetype_dev( dev );
7334 realization_info_t *info = ptr;
7338 dev = GET_NEXT_PHYSDEV( dev, pGdiRealizationInfo );
7339 return dev->funcs->pGdiRealizationInfo( dev, ptr );
7342 FIXME("(%p, %p): stub!\n", physdev->font, info);
7345 if(FT_IS_SCALABLE(physdev->font->ft_face))
7348 info->cache_num = physdev->font->cache_num;
7349 info->unknown2 = -1;
7353 /*************************************************************************
7354 * Kerning support for TrueType fonts
7356 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
7358 struct TT_kern_table
7364 struct TT_kern_subtable
7373 USHORT horizontal : 1;
7375 USHORT cross_stream: 1;
7376 USHORT override : 1;
7377 USHORT reserved1 : 4;
7383 struct TT_format0_kern_subtable
7387 USHORT entrySelector;
7398 static DWORD parse_format0_kern_subtable(GdiFont *font,
7399 const struct TT_format0_kern_subtable *tt_f0_ks,
7400 const USHORT *glyph_to_char,
7401 KERNINGPAIR *kern_pair, DWORD cPairs)
7404 const struct TT_kern_pair *tt_kern_pair;
7406 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
7408 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
7410 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7411 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
7412 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
7414 if (!kern_pair || !cPairs)
7417 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
7419 nPairs = min(nPairs, cPairs);
7421 for (i = 0; i < nPairs; i++)
7423 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
7424 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
7425 /* this algorithm appears to better match what Windows does */
7426 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
7427 if (kern_pair->iKernAmount < 0)
7429 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
7430 kern_pair->iKernAmount -= font->ppem;
7432 else if (kern_pair->iKernAmount > 0)
7434 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
7435 kern_pair->iKernAmount += font->ppem;
7437 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
7439 TRACE("left %u right %u value %d\n",
7440 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
7444 TRACE("copied %u entries\n", nPairs);
7448 /*************************************************************
7449 * freetype_GetKerningPairs
7451 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
7455 const struct TT_kern_table *tt_kern_table;
7456 const struct TT_kern_subtable *tt_kern_subtable;
7458 USHORT *glyph_to_char;
7460 struct freetype_physdev *physdev = get_freetype_dev( dev );
7462 if (!(font = physdev->font))
7464 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
7465 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
7469 EnterCriticalSection( &freetype_cs );
7470 if (font->total_kern_pairs != (DWORD)-1)
7472 if (cPairs && kern_pair)
7474 cPairs = min(cPairs, font->total_kern_pairs);
7475 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7477 else cPairs = font->total_kern_pairs;
7479 LeaveCriticalSection( &freetype_cs );
7483 font->total_kern_pairs = 0;
7485 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
7487 if (length == GDI_ERROR)
7489 TRACE("no kerning data in the font\n");
7490 LeaveCriticalSection( &freetype_cs );
7494 buf = HeapAlloc(GetProcessHeap(), 0, length);
7497 WARN("Out of memory\n");
7498 LeaveCriticalSection( &freetype_cs );
7502 get_font_data(font, MS_KERN_TAG, 0, buf, length);
7504 /* build a glyph index to char code map */
7505 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
7508 WARN("Out of memory allocating a glyph index to char code map\n");
7509 HeapFree(GetProcessHeap(), 0, buf);
7510 LeaveCriticalSection( &freetype_cs );
7514 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
7520 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
7522 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7523 font->ft_face->num_glyphs, glyph_code, char_code);
7527 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7529 /* FIXME: This doesn't match what Windows does: it does some fancy
7530 * things with duplicate glyph index to char code mappings, while
7531 * we just avoid overriding existing entries.
7533 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
7534 glyph_to_char[glyph_code] = (USHORT)char_code;
7536 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
7543 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
7544 for (n = 0; n <= 65535; n++)
7545 glyph_to_char[n] = (USHORT)n;
7548 tt_kern_table = buf;
7549 nTables = GET_BE_WORD(tt_kern_table->nTables);
7550 TRACE("version %u, nTables %u\n",
7551 GET_BE_WORD(tt_kern_table->version), nTables);
7553 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
7555 for (i = 0; i < nTables; i++)
7557 struct TT_kern_subtable tt_kern_subtable_copy;
7559 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
7560 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
7561 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
7563 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7564 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
7565 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
7567 /* According to the TrueType specification this is the only format
7568 * that will be properly interpreted by Windows and OS/2
7570 if (tt_kern_subtable_copy.coverage.bits.format == 0)
7572 DWORD new_chunk, old_total = font->total_kern_pairs;
7574 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7575 glyph_to_char, NULL, 0);
7576 font->total_kern_pairs += new_chunk;
7578 if (!font->kern_pairs)
7579 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
7580 font->total_kern_pairs * sizeof(*font->kern_pairs));
7582 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
7583 font->total_kern_pairs * sizeof(*font->kern_pairs));
7585 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7586 glyph_to_char, font->kern_pairs + old_total, new_chunk);
7589 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
7591 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
7594 HeapFree(GetProcessHeap(), 0, glyph_to_char);
7595 HeapFree(GetProcessHeap(), 0, buf);
7597 if (cPairs && kern_pair)
7599 cPairs = min(cPairs, font->total_kern_pairs);
7600 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7602 else cPairs = font->total_kern_pairs;
7604 LeaveCriticalSection( &freetype_cs );
7608 static const struct gdi_dc_funcs freetype_funcs =
7610 NULL, /* pAbortDoc */
7611 NULL, /* pAbortPath */
7612 NULL, /* pAlphaBlend */
7613 NULL, /* pAngleArc */
7616 NULL, /* pBeginPath */
7617 NULL, /* pBlendImage */
7618 NULL, /* pChoosePixelFormat */
7620 NULL, /* pCloseFigure */
7621 NULL, /* pCopyBitmap */
7622 NULL, /* pCreateBitmap */
7623 NULL, /* pCreateCompatibleDC */
7624 freetype_CreateDC, /* pCreateDC */
7625 NULL, /* pDeleteBitmap */
7626 freetype_DeleteDC, /* pDeleteDC */
7627 NULL, /* pDeleteObject */
7628 NULL, /* pDescribePixelFormat */
7629 NULL, /* pDeviceCapabilities */
7630 NULL, /* pEllipse */
7632 NULL, /* pEndPage */
7633 NULL, /* pEndPath */
7634 freetype_EnumFonts, /* pEnumFonts */
7635 NULL, /* pEnumICMProfiles */
7636 NULL, /* pExcludeClipRect */
7637 NULL, /* pExtDeviceMode */
7638 NULL, /* pExtEscape */
7639 NULL, /* pExtFloodFill */
7640 NULL, /* pExtSelectClipRgn */
7641 NULL, /* pExtTextOut */
7642 NULL, /* pFillPath */
7643 NULL, /* pFillRgn */
7644 NULL, /* pFlattenPath */
7645 freetype_FontIsLinked, /* pFontIsLinked */
7646 NULL, /* pFrameRgn */
7647 NULL, /* pGdiComment */
7648 freetype_GdiRealizationInfo, /* pGdiRealizationInfo */
7649 freetype_GetCharABCWidths, /* pGetCharABCWidths */
7650 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
7651 freetype_GetCharWidth, /* pGetCharWidth */
7652 NULL, /* pGetDeviceCaps */
7653 NULL, /* pGetDeviceGammaRamp */
7654 freetype_GetFontData, /* pGetFontData */
7655 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
7656 freetype_GetGlyphIndices, /* pGetGlyphIndices */
7657 freetype_GetGlyphOutline, /* pGetGlyphOutline */
7658 NULL, /* pGetICMProfile */
7659 NULL, /* pGetImage */
7660 freetype_GetKerningPairs, /* pGetKerningPairs */
7661 NULL, /* pGetNearestColor */
7662 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
7663 NULL, /* pGetPixel */
7664 NULL, /* pGetPixelFormat */
7665 NULL, /* pGetSystemPaletteEntries */
7666 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
7667 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
7668 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
7669 freetype_GetTextFace, /* pGetTextFace */
7670 freetype_GetTextMetrics, /* pGetTextMetrics */
7671 NULL, /* pGradientFill */
7672 NULL, /* pIntersectClipRect */
7673 NULL, /* pInvertRgn */
7675 NULL, /* pModifyWorldTransform */
7677 NULL, /* pOffsetClipRgn */
7678 NULL, /* pOffsetViewportOrg */
7679 NULL, /* pOffsetWindowOrg */
7680 NULL, /* pPaintRgn */
7683 NULL, /* pPolyBezier */
7684 NULL, /* pPolyBezierTo */
7685 NULL, /* pPolyDraw */
7686 NULL, /* pPolyPolygon */
7687 NULL, /* pPolyPolyline */
7688 NULL, /* pPolygon */
7689 NULL, /* pPolyline */
7690 NULL, /* pPolylineTo */
7691 NULL, /* pPutImage */
7692 NULL, /* pRealizeDefaultPalette */
7693 NULL, /* pRealizePalette */
7694 NULL, /* pRectangle */
7695 NULL, /* pResetDC */
7696 NULL, /* pRestoreDC */
7697 NULL, /* pRoundRect */
7699 NULL, /* pScaleViewportExt */
7700 NULL, /* pScaleWindowExt */
7701 NULL, /* pSelectBitmap */
7702 NULL, /* pSelectBrush */
7703 NULL, /* pSelectClipPath */
7704 freetype_SelectFont, /* pSelectFont */
7705 NULL, /* pSelectPalette */
7706 NULL, /* pSelectPen */
7707 NULL, /* pSetArcDirection */
7708 NULL, /* pSetBkColor */
7709 NULL, /* pSetBkMode */
7710 NULL, /* pSetDCBrushColor */
7711 NULL, /* pSetDCPenColor */
7712 NULL, /* pSetDIBColorTable */
7713 NULL, /* pSetDIBitsToDevice */
7714 NULL, /* pSetDeviceClipping */
7715 NULL, /* pSetDeviceGammaRamp */
7716 NULL, /* pSetLayout */
7717 NULL, /* pSetMapMode */
7718 NULL, /* pSetMapperFlags */
7719 NULL, /* pSetPixel */
7720 NULL, /* pSetPixelFormat */
7721 NULL, /* pSetPolyFillMode */
7722 NULL, /* pSetROP2 */
7723 NULL, /* pSetRelAbs */
7724 NULL, /* pSetStretchBltMode */
7725 NULL, /* pSetTextAlign */
7726 NULL, /* pSetTextCharacterExtra */
7727 NULL, /* pSetTextColor */
7728 NULL, /* pSetTextJustification */
7729 NULL, /* pSetViewportExt */
7730 NULL, /* pSetViewportOrg */
7731 NULL, /* pSetWindowExt */
7732 NULL, /* pSetWindowOrg */
7733 NULL, /* pSetWorldTransform */
7734 NULL, /* pStartDoc */
7735 NULL, /* pStartPage */
7736 NULL, /* pStretchBlt */
7737 NULL, /* pStretchDIBits */
7738 NULL, /* pStrokeAndFillPath */
7739 NULL, /* pStrokePath */
7740 NULL, /* pSwapBuffers */
7741 NULL, /* pUnrealizePalette */
7742 NULL, /* pWidenPath */
7743 /* OpenGL not supported */
7746 #else /* HAVE_FREETYPE */
7748 /*************************************************************************/
7750 BOOL WineEngInit(void)
7754 BOOL WineEngDestroyFontInstance(HFONT hfont)
7759 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7761 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7765 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7767 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7771 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
7773 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
7777 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
7778 LPCWSTR font_file, LPCWSTR font_path )
7784 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
7789 /*************************************************************************
7790 * GetRasterizerCaps (GDI32.@)
7792 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7794 lprs->nSize = sizeof(RASTERIZER_STATUS);
7796 lprs->nLanguageID = 0;
7800 #endif /* HAVE_FREETYPE */