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;
268 FONTSIGNATURE fs_links;
270 FT_Fixed font_version;
273 Bitmap_Size size; /* set if face is a bitmap */
274 BOOL external; /* TRUE if we should manually add this font to the registry */
275 struct tagFamily *family;
276 /* Cached data for Enum */
277 struct enum_data *cached_enum_data;
280 typedef struct tagFamily {
282 const WCHAR *FamilyName;
283 const WCHAR *EnglishName;
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;
357 struct enum_charset_element {
360 WCHAR name[LF_FACESIZE];
363 struct enum_charset_list {
365 struct enum_charset_element element[32];
368 #define GM_BLOCK_SIZE 128
369 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
371 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
372 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
373 #define UNUSED_CACHE_SIZE 10
374 static struct list child_font_list = LIST_INIT(child_font_list);
375 static struct list system_links = LIST_INIT(system_links);
377 static struct list font_subst_list = LIST_INIT(font_subst_list);
379 static struct list font_list = LIST_INIT(font_list);
381 struct freetype_physdev
383 struct gdi_physdev dev;
387 static inline struct freetype_physdev *get_freetype_dev( PHYSDEV dev )
389 return (struct freetype_physdev *)dev;
392 static const struct gdi_dc_funcs freetype_funcs;
394 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
395 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
396 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
398 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
399 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
400 'W','i','n','d','o','w','s','\\',
401 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
402 'F','o','n','t','s','\0'};
404 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
405 'W','i','n','d','o','w','s',' ','N','T','\\',
406 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
407 'F','o','n','t','s','\0'};
409 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
410 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
411 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
412 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
414 static const WCHAR * const SystemFontValues[] = {
421 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
422 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
424 /* Interesting and well-known (frequently-assumed!) font names */
425 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
426 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 };
427 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
428 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
429 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
430 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
431 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
432 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
434 static const WCHAR arial[] = {'A','r','i','a','l',0};
435 static const WCHAR bitstream_vera_sans[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
436 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};
437 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};
438 static const WCHAR courier_new[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
439 static const WCHAR liberation_mono[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
440 static const WCHAR liberation_sans[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
441 static const WCHAR liberation_serif[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
442 static const WCHAR times_new_roman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
443 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
445 static const WCHAR *default_serif_list[] =
449 bitstream_vera_serif,
453 static const WCHAR *default_fixed_list[] =
457 bitstream_vera_sans_mono,
461 static const WCHAR *default_sans_list[] =
474 typedef struct tagFontSubst {
480 /* Registry font cache key and value names */
481 static const WCHAR wine_fonts_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
482 'F','o','n','t','s',0};
483 static const WCHAR wine_fonts_cache_key[] = {'C','a','c','h','e',0};
484 static const WCHAR english_name_value[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
485 static const WCHAR face_index_value[] = {'I','n','d','e','x',0};
486 static const WCHAR face_italic_value[] = {'I','t','a','l','i','c',0};
487 static const WCHAR face_bold_value[] = {'B','o','l','d',0};
488 static const WCHAR face_version_value[] = {'V','e','r','s','i','o','n',0};
489 static const WCHAR face_external_value[] = {'E','x','t','e','r','n','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 Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
897 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
898 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
900 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
901 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
903 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
905 if(face_name && strcmpiW(face_name, family->FamilyName))
907 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
911 file = strrchr(face->file, '/');
916 if(!strcasecmp(file, file_nameA))
918 HeapFree(GetProcessHeap(), 0, file_nameA);
923 HeapFree(GetProcessHeap(), 0, file_nameA);
927 static Family *find_family_from_name(const WCHAR *name)
931 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
933 if(!strcmpiW(family->FamilyName, name))
940 static void DumpSubstList(void)
944 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
946 if(psub->from.charset != -1 || psub->to.charset != -1)
947 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
948 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
950 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
951 debugstr_w(psub->to.name));
956 static LPWSTR strdupW(LPCWSTR p)
959 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
960 ret = HeapAlloc(GetProcessHeap(), 0, len);
965 static LPSTR strdupA(LPCSTR p)
968 DWORD len = (strlen(p) + 1);
969 ret = HeapAlloc(GetProcessHeap(), 0, len);
974 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
979 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
981 if(!strcmpiW(element->from.name, from_name) &&
982 (element->from.charset == from_charset ||
983 element->from.charset == -1))
990 #define ADD_FONT_SUBST_FORCE 1
992 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
994 FontSubst *from_exist, *to_exist;
996 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
998 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
1000 list_remove(&from_exist->entry);
1001 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
1002 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
1003 HeapFree(GetProcessHeap(), 0, from_exist);
1009 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
1013 HeapFree(GetProcessHeap(), 0, subst->to.name);
1014 subst->to.name = strdupW(to_exist->to.name);
1017 list_add_tail(subst_list, &subst->entry);
1022 HeapFree(GetProcessHeap(), 0, subst->from.name);
1023 HeapFree(GetProcessHeap(), 0, subst->to.name);
1024 HeapFree(GetProcessHeap(), 0, subst);
1028 static WCHAR *towstr(UINT cp, const char *str)
1033 len = MultiByteToWideChar(cp, 0, str, -1, NULL, 0);
1034 wstr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1035 MultiByteToWideChar(cp, 0, str, -1, wstr, len);
1039 static void split_subst_info(NameCs *nc, LPSTR str)
1041 CHAR *p = strrchr(str, ',');
1045 nc->charset = strtol(p+1, NULL, 10);
1048 nc->name = towstr(CP_ACP, str);
1051 static void LoadSubstList(void)
1055 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1059 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1060 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1061 &hkey) == ERROR_SUCCESS) {
1063 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1064 &valuelen, &datalen, NULL, NULL);
1066 valuelen++; /* returned value doesn't include room for '\0' */
1067 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1068 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1072 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1073 &dlen) == ERROR_SUCCESS) {
1074 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1076 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1077 split_subst_info(&psub->from, value);
1078 split_subst_info(&psub->to, data);
1080 /* Win 2000 doesn't allow mapping between different charsets
1081 or mapping of DEFAULT_CHARSET */
1082 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1083 psub->to.charset == DEFAULT_CHARSET) {
1084 HeapFree(GetProcessHeap(), 0, psub->to.name);
1085 HeapFree(GetProcessHeap(), 0, psub->from.name);
1086 HeapFree(GetProcessHeap(), 0, psub);
1088 add_font_subst(&font_subst_list, psub, 0);
1090 /* reset dlen and vlen */
1094 HeapFree(GetProcessHeap(), 0, data);
1095 HeapFree(GetProcessHeap(), 0, value);
1101 /*****************************************************************
1102 * get_name_table_entry
1104 * Supply the platform, encoding, language and name ids in req
1105 * and if the name exists the function will fill in the string
1106 * and string_len members. The string is owned by FreeType so
1107 * don't free it. Returns TRUE if the name is found else FALSE.
1109 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1112 FT_UInt num_names, name_index;
1114 if(FT_IS_SFNT(ft_face))
1116 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1118 for(name_index = 0; name_index < num_names; name_index++)
1120 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1122 if((name.platform_id == req->platform_id) &&
1123 (name.encoding_id == req->encoding_id) &&
1124 (name.language_id == req->language_id) &&
1125 (name.name_id == req->name_id))
1127 req->string = name.string;
1128 req->string_len = name.string_len;
1135 req->string_len = 0;
1139 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, FT_UShort language_id)
1144 name.platform_id = TT_PLATFORM_MICROSOFT;
1145 name.encoding_id = TT_MS_ID_UNICODE_CS;
1146 name.language_id = language_id;
1147 name.name_id = name_id;
1149 if(get_name_table_entry(ft_face, &name))
1153 /* String is not nul terminated and string_len is a byte length. */
1154 ret = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1155 for(i = 0; i < name.string_len / 2; i++)
1157 WORD *tmp = (WORD *)&name.string[i * 2];
1158 ret[i] = GET_BE_WORD(*tmp);
1161 TRACE("Got localised name %s\n", debugstr_w(ret));
1167 static LONG reg_load_dword(HKEY hkey, const WCHAR *value, DWORD *data)
1170 LONG r = RegQueryValueExW(hkey, value, NULL, &type, NULL, &needed);
1171 if(r != ERROR_SUCCESS) return r;
1172 if(type != REG_DWORD || needed != sizeof(DWORD)) return ERROR_BAD_CONFIGURATION;
1173 return RegQueryValueExW(hkey, value, NULL, &type, (BYTE*)data, &needed);
1176 static inline LONG reg_save_dword(HKEY hkey, const WCHAR *value, DWORD data)
1178 return RegSetValueExW(hkey, value, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD));
1181 static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family)
1184 DWORD num_strikes, max_strike_key_len;
1186 /* If we have a File Name key then this is a real font, not just the parent
1187 key of a bunch of non-scalable strikes */
1188 if(RegQueryValueExA(hkey_face, "File Name", NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1192 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1193 face->cached_enum_data = NULL;
1195 face->file = HeapAlloc(GetProcessHeap(), 0, needed);
1196 RegQueryValueExA(hkey_face, "File Name", NULL, NULL, (BYTE*)face->file, &needed);
1198 face->StyleName = strdupW(face_name);
1199 face->family = family;
1201 if(RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1203 WCHAR *fullName = HeapAlloc(GetProcessHeap(), 0, needed);
1204 RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, (BYTE*)fullName, &needed);
1205 face->FullName = fullName;
1208 face->FullName = NULL;
1210 reg_load_dword(hkey_face, face_index_value, (DWORD*)&face->face_index);
1211 reg_load_dword(hkey_face, face_italic_value, &italic);
1212 reg_load_dword(hkey_face, face_bold_value, &bold);
1213 reg_load_dword(hkey_face, face_version_value, (DWORD*)&face->font_version);
1214 reg_load_dword(hkey_face, face_external_value, (DWORD*)&face->external);
1216 needed = sizeof(face->fs);
1217 RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
1218 memset(&face->fs_links, 0, sizeof(face->fs_links));
1220 if(reg_load_dword(hkey_face, face_height_value, (DWORD*)&face->size.height) != ERROR_SUCCESS)
1222 face->scalable = TRUE;
1223 memset(&face->size, 0, sizeof(face->size));
1227 face->scalable = FALSE;
1228 reg_load_dword(hkey_face, face_width_value, (DWORD*)&face->size.width);
1229 reg_load_dword(hkey_face, face_size_value, (DWORD*)&face->size.size);
1230 reg_load_dword(hkey_face, face_x_ppem_value, (DWORD*)&face->size.x_ppem);
1231 reg_load_dword(hkey_face, face_y_ppem_value, (DWORD*)&face->size.y_ppem);
1232 reg_load_dword(hkey_face, face_internal_leading_value, (DWORD*)&face->size.internal_leading);
1234 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1235 face->size.height, face->size.width, face->size.size >> 6,
1236 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1240 if (italic) face->ntmFlags |= NTM_ITALIC;
1241 if (bold) face->ntmFlags |= NTM_BOLD;
1242 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1244 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1245 face->fs.fsCsb[0], face->fs.fsCsb[1],
1246 face->fs.fsUsb[0], face->fs.fsUsb[1],
1247 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1249 if(!italic && !bold)
1250 list_add_head(&family->faces, &face->entry);
1252 list_add_tail(&family->faces, &face->entry);
1254 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
1257 /* do we have any bitmap strikes? */
1258 RegQueryInfoKeyW(hkey_face, NULL, NULL, NULL, &num_strikes, &max_strike_key_len, NULL, NULL,
1259 NULL, NULL, NULL, NULL);
1260 if(num_strikes != 0)
1262 WCHAR strike_name[10];
1263 DWORD strike_index = 0;
1265 needed = sizeof(strike_name) / sizeof(WCHAR);
1266 while(RegEnumKeyExW(hkey_face, strike_index++, strike_name, &needed,
1267 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1270 RegOpenKeyExW(hkey_face, strike_name, 0, KEY_ALL_ACCESS, &hkey_strike);
1271 load_face(hkey_strike, face_name, family);
1272 RegCloseKey(hkey_strike);
1273 needed = sizeof(strike_name) / sizeof(WCHAR);
1278 static void load_font_list_from_cache(HKEY hkey_font_cache)
1280 DWORD max_family_key_len, size;
1282 DWORD family_index = 0;
1286 RegQueryInfoKeyW(hkey_font_cache, NULL, NULL, NULL, NULL, &max_family_key_len, NULL, NULL,
1287 NULL, NULL, NULL, NULL);
1288 family_name = HeapAlloc(GetProcessHeap(), 0, (max_family_key_len + 1) * sizeof(WCHAR));
1290 size = max_family_key_len + 1;
1291 while(RegEnumKeyExW(hkey_font_cache, family_index++, family_name, &size,
1292 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1294 WCHAR *english_family = NULL;
1295 DWORD face_index = 0;
1297 DWORD max_face_key_len;
1299 RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
1300 TRACE("opened family key %s\n", debugstr_w(family_name));
1301 if(RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, NULL, &size) == ERROR_SUCCESS)
1303 english_family = HeapAlloc(GetProcessHeap(), 0, size);
1304 RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE*)english_family, &size);
1307 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1308 family->FamilyName = strdupW(family_name);
1309 family->EnglishName = english_family;
1310 list_init(&family->faces);
1311 list_add_tail(&font_list, &family->entry);
1315 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1316 subst->from.name = strdupW(english_family);
1317 subst->from.charset = -1;
1318 subst->to.name = strdupW(family_name);
1319 subst->to.charset = -1;
1320 add_font_subst(&font_subst_list, subst, 0);
1323 RegQueryInfoKeyW(hkey_family, NULL, NULL, NULL, NULL, &max_face_key_len, NULL, NULL,
1324 NULL, NULL, NULL, NULL);
1326 face_name = HeapAlloc(GetProcessHeap(), 0, (max_face_key_len + 1) * sizeof(WCHAR));
1327 size = max_face_key_len + 1;
1328 while(RegEnumKeyExW(hkey_family, face_index++, face_name, &size,
1329 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1333 RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face);
1334 load_face(hkey_face, face_name, family);
1335 RegCloseKey(hkey_face);
1336 size = max_face_key_len + 1;
1338 HeapFree(GetProcessHeap(), 0, face_name);
1339 RegCloseKey(hkey_family);
1340 size = max_family_key_len + 1;
1343 HeapFree(GetProcessHeap(), 0, family_name);
1346 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1349 HKEY hkey_wine_fonts;
1351 /* We don't want to create the fonts key as volatile, so open this first */
1352 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1353 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1354 if(ret != ERROR_SUCCESS)
1356 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1360 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1361 KEY_ALL_ACCESS, NULL, hkey, disposition);
1362 RegCloseKey(hkey_wine_fonts);
1366 static void add_face_to_cache(Face *face)
1368 HKEY hkey_font_cache, hkey_family, hkey_face;
1369 WCHAR *face_key_name;
1371 create_font_cache_key(&hkey_font_cache, NULL);
1373 RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0,
1374 NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL);
1375 if(face->family->EnglishName)
1376 RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName,
1377 (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR));
1380 face_key_name = face->StyleName;
1383 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1384 face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1385 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1387 RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
1390 HeapFree(GetProcessHeap(), 0, face_key_name);
1392 RegSetValueExA(hkey_face, "File Name", 0, REG_BINARY, (BYTE*)face->file, strlen(face->file) + 1);
1394 RegSetValueExW(hkey_face, face_full_name_value, 0, REG_SZ, (BYTE*)face->FullName,
1395 (strlenW(face->FullName) + 1) * sizeof(WCHAR));
1397 reg_save_dword(hkey_face, face_index_value, face->face_index);
1398 reg_save_dword(hkey_face, face_italic_value, (face->ntmFlags & NTM_ITALIC) != 0);
1399 reg_save_dword(hkey_face, face_bold_value, (face->ntmFlags & NTM_BOLD) != 0);
1400 reg_save_dword(hkey_face, face_version_value, face->font_version);
1401 reg_save_dword(hkey_face, face_external_value, face->external);
1403 RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs));
1407 reg_save_dword(hkey_face, face_height_value, face->size.height);
1408 reg_save_dword(hkey_face, face_width_value, face->size.width);
1409 reg_save_dword(hkey_face, face_size_value, face->size.size);
1410 reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem);
1411 reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem);
1412 reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading);
1414 RegCloseKey(hkey_face);
1415 RegCloseKey(hkey_family);
1416 RegCloseKey(hkey_font_cache);
1419 static inline int TestStyles(DWORD flags, DWORD styles)
1421 return (flags & styles) == styles;
1424 static int StyleOrdering(Face *face)
1426 if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1428 if (TestStyles(face->ntmFlags, NTM_ITALIC))
1430 if (TestStyles(face->ntmFlags, NTM_BOLD))
1432 if (TestStyles(face->ntmFlags, NTM_REGULAR))
1435 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1436 debugstr_w(face->family->FamilyName),
1437 debugstr_w(face->StyleName),
1443 /* Add a style of face to a font family using an ordering of the list such
1444 that regular fonts come before bold and italic, and single styles come
1445 before compound styles. */
1446 static void AddFaceToFamily(Face *face, Family *family)
1450 LIST_FOR_EACH( entry, &family->faces )
1452 Face *ent = LIST_ENTRY(entry, Face, entry);
1453 if (StyleOrdering(face) < StyleOrdering(ent)) break;
1455 list_add_before( entry, &face->entry );
1458 static WCHAR *prepend_at(WCHAR *family)
1465 str = HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR) * (strlenW(family) + 2));
1467 strcpyW(str + 1, family);
1468 HeapFree(GetProcessHeap(), 0, family);
1472 #define ADDFONT_EXTERNAL_FONT 0x01
1473 #define ADDFONT_FORCE_BITMAP 0x02
1474 #define ADDFONT_ADD_TO_CACHE 0x04
1476 static void AddFaceToList(FT_Face ft_face, char *fake_family, const char *file, void *font_data_ptr, DWORD font_data_size, FT_Long face_index, DWORD flags, BOOL vertical)
1485 WCHAR *english_family, *localised_family;
1487 struct list *face_elem_ptr;
1488 FT_WinFNT_HeaderRec winfnt_header;
1489 int internal_leading;
1491 My_FT_Bitmap_Size *size = NULL;
1494 if(!FT_IS_SCALABLE(ft_face))
1495 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1499 english_family = towstr(CP_ACP, fake_family);
1500 localised_family = NULL;
1504 english_family = get_face_name(ft_face, TT_NAME_ID_FONT_FAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES);
1505 if (!english_family)
1506 english_family = towstr(CP_ACP, ft_face->family_name);
1508 localised_family = get_face_name(ft_face, TT_NAME_ID_FONT_FAMILY, GetUserDefaultLCID());
1509 if (localised_family && !strcmpiW(localised_family, english_family))
1511 HeapFree(GetProcessHeap(), 0, localised_family);
1512 localised_family = NULL;
1518 english_family = prepend_at(english_family);
1519 localised_family = prepend_at(localised_family);
1522 family = find_family_from_name(localised_family ? localised_family : english_family);
1524 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1525 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1526 family->EnglishName = localised_family ? strdupW(english_family) : NULL;
1527 list_init(&family->faces);
1528 list_add_tail(&font_list, &family->entry);
1530 if(localised_family) {
1531 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1532 subst->from.name = strdupW(english_family);
1533 subst->from.charset = -1;
1534 subst->to.name = strdupW(localised_family);
1535 subst->to.charset = -1;
1536 add_font_subst(&font_subst_list, subst, 0);
1539 HeapFree(GetProcessHeap(), 0, localised_family);
1540 HeapFree(GetProcessHeap(), 0, english_family);
1542 StyleW = towstr(CP_ACP, ft_face->style_name);
1544 internal_leading = 0;
1545 memset(&fs, 0, sizeof(fs));
1547 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1549 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1550 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1551 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1552 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1553 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1554 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1555 if(pOS2->version == 0) {
1558 if(pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
1559 fs.fsCsb[0] |= FS_LATIN1;
1561 fs.fsCsb[0] |= FS_SYMBOL;
1564 else if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1566 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1567 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1568 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1570 internal_leading = winfnt_header.internal_leading;
1573 pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head);
1574 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1575 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1576 if(!strcmpiW(face->StyleName, StyleW) &&
1577 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1578 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1579 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1580 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1583 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1584 HeapFree(GetProcessHeap(), 0, StyleW);
1587 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1588 TRACE("Original font is newer so skipping this one\n");
1589 HeapFree(GetProcessHeap(), 0, StyleW);
1592 TRACE("Replacing original with this one\n");
1593 list_remove(&face->entry);
1594 HeapFree(GetProcessHeap(), 0, face->file);
1595 HeapFree(GetProcessHeap(), 0, face->StyleName);
1596 HeapFree(GetProcessHeap(), 0, face->FullName);
1597 HeapFree(GetProcessHeap(), 0, face);
1602 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1603 face->cached_enum_data = NULL;
1604 face->StyleName = StyleW;
1605 face->FullName = get_face_name(ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES);
1608 face->file = strdupA(file);
1609 face->font_data_ptr = NULL;
1610 face->font_data_size = 0;
1615 face->font_data_ptr = font_data_ptr;
1616 face->font_data_size = font_data_size;
1618 face->face_index = face_index;
1620 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1621 face->ntmFlags |= NTM_ITALIC;
1622 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1623 face->ntmFlags |= NTM_BOLD;
1624 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1625 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1626 face->family = family;
1627 face->vertical = vertical;
1628 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1630 memset(&face->fs_links, 0, sizeof(face->fs_links));
1632 if(FT_IS_SCALABLE(ft_face)) {
1633 memset(&face->size, 0, sizeof(face->size));
1634 face->scalable = TRUE;
1636 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1637 size->height, size->width, size->size >> 6,
1638 size->x_ppem >> 6, size->y_ppem >> 6);
1639 face->size.height = size->height;
1640 face->size.width = size->width;
1641 face->size.size = size->size;
1642 face->size.x_ppem = size->x_ppem;
1643 face->size.y_ppem = size->y_ppem;
1644 face->size.internal_leading = internal_leading;
1645 face->scalable = FALSE;
1648 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1650 if (!pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1652 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1653 face->ntmFlags |= NTM_PS_OPENTYPE;
1656 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1657 face->fs.fsCsb[0], face->fs.fsCsb[1],
1658 face->fs.fsUsb[0], face->fs.fsUsb[1],
1659 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1661 if(face->fs.fsCsb[0] == 0)
1665 /* let's see if we can find any interesting cmaps */
1666 for(i = 0; i < ft_face->num_charmaps; i++) {
1667 switch(ft_face->charmaps[i]->encoding) {
1668 case FT_ENCODING_UNICODE:
1669 case FT_ENCODING_APPLE_ROMAN:
1670 face->fs.fsCsb[0] |= FS_LATIN1;
1672 case FT_ENCODING_MS_SYMBOL:
1673 face->fs.fsCsb[0] |= FS_SYMBOL;
1681 if(flags & ADDFONT_ADD_TO_CACHE)
1682 add_face_to_cache(face);
1684 AddFaceToFamily(face, family);
1686 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1688 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1689 debugstr_w(StyleW));
1692 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1696 TT_Header *pHeader = NULL;
1697 WCHAR *localised_family;
1699 FT_Long face_index = 0, num_faces;
1702 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1703 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1705 #ifdef HAVE_CARBON_CARBON_H
1706 if(file && !fake_family)
1708 char **mac_list = expand_mac_font(file);
1711 BOOL had_one = FALSE;
1713 for(cursor = mac_list; *cursor; cursor++)
1716 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1717 HeapFree(GetProcessHeap(), 0, *cursor);
1719 HeapFree(GetProcessHeap(), 0, mac_list);
1724 #endif /* HAVE_CARBON_CARBON_H */
1729 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1730 err = pFT_New_Face(library, file, face_index, &ft_face);
1733 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1734 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1738 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1742 if(!FT_IS_SFNT(ft_face) && (FT_IS_SCALABLE(ft_face) || !(flags & ADDFONT_FORCE_BITMAP))) { /* for now we'll accept TT/OT or bitmap fonts*/
1743 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1744 pFT_Done_Face(ft_face);
1748 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1749 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1750 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1751 pFT_Done_Face(ft_face);
1755 if(FT_IS_SFNT(ft_face))
1757 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1758 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1759 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1761 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1762 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1763 pFT_Done_Face(ft_face);
1767 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1768 we don't want to load these. */
1769 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1773 if(!pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1775 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1776 pFT_Done_Face(ft_face);
1782 if(!ft_face->family_name || !ft_face->style_name) {
1783 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1784 pFT_Done_Face(ft_face);
1788 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1790 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1791 pFT_Done_Face(ft_face);
1797 localised_family = get_face_name(ft_face, TT_NAME_ID_FONT_FAMILY, GetUserDefaultLCID());
1798 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1800 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1801 HeapFree(GetProcessHeap(), 0, localised_family);
1802 num_faces = ft_face->num_faces;
1803 pFT_Done_Face(ft_face);
1806 HeapFree(GetProcessHeap(), 0, localised_family);
1809 AddFaceToList(ft_face, fake_family, file, font_data_ptr, font_data_size, face_index, flags, FALSE);
1812 if (FT_HAS_VERTICAL(ft_face))
1814 AddFaceToList(ft_face, fake_family, file, font_data_ptr, font_data_size, face_index, flags, TRUE);
1818 num_faces = ft_face->num_faces;
1819 pFT_Done_Face(ft_face);
1820 } while(num_faces > ++face_index);
1824 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1826 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1829 static void DumpFontList(void)
1833 struct list *family_elem_ptr, *face_elem_ptr;
1835 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1836 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1837 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1838 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1839 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1840 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1842 TRACE(" %d", face->size.height);
1849 /***********************************************************
1850 * The replacement list is a way to map an entire font
1851 * family onto another family. For example adding
1853 * [HKCU\Software\Wine\Fonts\Replacements]
1854 * "Wingdings"="Winedings"
1856 * would enumerate the Winedings font both as Winedings and
1857 * Wingdings. However if a real Wingdings font is present the
1858 * replacement does not take place.
1861 static void LoadReplaceList(void)
1864 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1869 struct list *family_elem_ptr, *face_elem_ptr;
1872 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1873 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1875 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1876 &valuelen, &datalen, NULL, NULL);
1878 valuelen++; /* returned value doesn't include room for '\0' */
1879 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1880 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1884 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1885 &dlen) == ERROR_SUCCESS) {
1886 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1887 /* "NewName"="Oldname" */
1888 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1890 if(!find_family_from_name(value))
1892 /* Find the old family and hence all of the font files
1894 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1895 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1896 if(!strcmpiW(family->FamilyName, data)) {
1897 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1898 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1899 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1900 debugstr_w(face->StyleName), familyA);
1901 /* Now add a new entry with the new family name */
1902 AddFontToList(face->file, face->font_data_ptr, face->font_data_size,
1903 familyA, family->FamilyName,
1904 ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1910 /* reset dlen and vlen */
1914 HeapFree(GetProcessHeap(), 0, data);
1915 HeapFree(GetProcessHeap(), 0, value);
1920 /*************************************************************
1923 static BOOL init_system_links(void)
1927 DWORD type, max_val, max_data, val_len, data_len, index;
1928 WCHAR *value, *data;
1929 WCHAR *entry, *next;
1930 SYSTEM_LINKS *font_link, *system_font_link;
1931 CHILD_FONT *child_font;
1932 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1933 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1939 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1941 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1942 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1943 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1944 val_len = max_val + 1;
1945 data_len = max_data;
1947 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1949 memset(&fs, 0, sizeof(fs));
1950 psub = get_font_subst(&font_subst_list, value, -1);
1951 /* Don't store fonts that are only substitutes for other fonts */
1954 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
1957 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1958 font_link->font_name = strdupW(value);
1959 list_init(&font_link->links);
1960 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1963 CHILD_FONT *child_font;
1965 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
1967 next = entry + strlenW(entry) + 1;
1969 face_name = strchrW(entry, ',');
1973 while(isspaceW(*face_name))
1976 psub = get_font_subst(&font_subst_list, face_name, -1);
1978 face_name = psub->to.name;
1980 face = find_face_from_filename(entry, face_name);
1983 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1987 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1988 child_font->face = face;
1989 child_font->font = NULL;
1990 fs.fsCsb[0] |= face->fs.fsCsb[0];
1991 fs.fsCsb[1] |= face->fs.fsCsb[1];
1992 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1993 list_add_tail(&font_link->links, &child_font->entry);
1995 family = find_family_from_name(font_link->font_name);
1998 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2000 face->fs_links = fs;
2003 list_add_tail(&system_links, &font_link->entry);
2005 val_len = max_val + 1;
2006 data_len = max_data;
2009 HeapFree(GetProcessHeap(), 0, value);
2010 HeapFree(GetProcessHeap(), 0, data);
2014 if(RegOpenKeyW(HKEY_CURRENT_USER, internal_system_link, &hkey) == ERROR_SUCCESS)
2016 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
2017 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
2018 data = HeapAlloc(GetProcessHeap(), 0, max_data);
2019 val_len = max_val + 1;
2020 data_len = max_data;
2022 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
2024 BOOL existing = FALSE;
2025 memset(&fs, 0, sizeof(fs));
2026 psub = get_font_subst(&font_subst_list, value, -1);
2027 /* Don't store fonts that are only substitutes for other fonts */
2030 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
2034 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2036 if(!strcmpiW(font_link->font_name, value))
2045 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2046 font_link->font_name = strdupW(value);
2047 list_init(&font_link->links);
2050 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
2053 CHILD_FONT *child_font;
2055 TRACE("Internal entry %s: %s\n", debugstr_w(value), debugstr_w(entry));
2057 next = entry + strlenW(entry) + 1;
2059 face_name = strchrW(entry, ',');
2063 while(isspaceW(*face_name))
2066 psub = get_font_subst(&font_subst_list, face_name, -1);
2068 face_name = psub->to.name;
2070 face = find_face_from_filename(entry, face_name);
2073 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
2077 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2078 child_font->face = face;
2079 child_font->font = NULL;
2080 fs.fsCsb[0] |= face->fs.fsCsb[0];
2081 fs.fsCsb[1] |= face->fs.fsCsb[1];
2082 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
2083 list_add_tail(&font_link->links, &child_font->entry);
2085 family = find_family_from_name(font_link->font_name);
2088 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2090 face->fs_links = fs;
2094 list_add_tail(&system_links, &font_link->entry);
2096 val_len = max_val + 1;
2097 data_len = max_data;
2100 HeapFree(GetProcessHeap(), 0, value);
2101 HeapFree(GetProcessHeap(), 0, data);
2105 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2108 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2109 system_font_link->font_name = strdupW(System);
2110 list_init(&system_font_link->links);
2112 face = find_face_from_filename(tahoma_ttf, Tahoma);
2115 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2116 child_font->face = face;
2117 child_font->font = NULL;
2118 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
2119 list_add_tail(&system_font_link->links, &child_font->entry);
2121 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2123 if(!strcmpiW(font_link->font_name, Tahoma))
2125 CHILD_FONT *font_link_entry;
2126 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2128 CHILD_FONT *new_child;
2129 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2130 new_child->face = font_link_entry->face;
2131 new_child->font = NULL;
2132 list_add_tail(&system_font_link->links, &new_child->entry);
2137 list_add_tail(&system_links, &system_font_link->entry);
2141 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2144 struct dirent *dent;
2145 char path[MAX_PATH];
2147 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2149 dir = opendir(dirname);
2151 WARN("Can't open directory %s\n", debugstr_a(dirname));
2154 while((dent = readdir(dir)) != NULL) {
2155 struct stat statbuf;
2157 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2160 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2162 sprintf(path, "%s/%s", dirname, dent->d_name);
2164 if(stat(path, &statbuf) == -1)
2166 WARN("Can't stat %s\n", debugstr_a(path));
2169 if(S_ISDIR(statbuf.st_mode))
2170 ReadFontDir(path, external_fonts);
2173 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2174 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2175 AddFontFileToList(path, NULL, NULL, addfont_flags);
2182 static void load_fontconfig_fonts(void)
2184 #ifdef SONAME_LIBFONTCONFIG
2185 void *fc_handle = NULL;
2194 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2196 TRACE("Wine cannot find the fontconfig library (%s).\n",
2197 SONAME_LIBFONTCONFIG);
2200 #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;}
2201 LOAD_FUNCPTR(FcConfigGetCurrent);
2202 LOAD_FUNCPTR(FcFontList);
2203 LOAD_FUNCPTR(FcFontSetDestroy);
2204 LOAD_FUNCPTR(FcInit);
2205 LOAD_FUNCPTR(FcObjectSetAdd);
2206 LOAD_FUNCPTR(FcObjectSetCreate);
2207 LOAD_FUNCPTR(FcObjectSetDestroy);
2208 LOAD_FUNCPTR(FcPatternCreate);
2209 LOAD_FUNCPTR(FcPatternDestroy);
2210 LOAD_FUNCPTR(FcPatternGetBool);
2211 LOAD_FUNCPTR(FcPatternGetString);
2214 if(!pFcInit()) return;
2216 config = pFcConfigGetCurrent();
2217 pat = pFcPatternCreate();
2218 os = pFcObjectSetCreate();
2219 pFcObjectSetAdd(os, FC_FILE);
2220 pFcObjectSetAdd(os, FC_SCALABLE);
2221 fontset = pFcFontList(config, pat, os);
2222 if(!fontset) return;
2223 for(i = 0; i < fontset->nfont; i++) {
2226 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2228 TRACE("fontconfig: %s\n", file);
2230 /* We're just interested in OT/TT fonts for now, so this hack just
2231 picks up the scalable fonts without extensions .pf[ab] to save time
2232 loading every other font */
2234 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2236 TRACE("not scalable\n");
2240 len = strlen( file );
2241 if(len < 4) continue;
2242 ext = &file[ len - 3 ];
2243 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2244 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2246 pFcFontSetDestroy(fontset);
2247 pFcObjectSetDestroy(os);
2248 pFcPatternDestroy(pat);
2254 static BOOL load_font_from_data_dir(LPCWSTR file)
2257 const char *data_dir = wine_get_data_dir();
2259 if (!data_dir) data_dir = wine_get_build_dir();
2266 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
2268 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
2270 strcpy(unix_name, data_dir);
2271 strcat(unix_name, "/fonts/");
2273 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
2275 EnterCriticalSection( &freetype_cs );
2276 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2277 LeaveCriticalSection( &freetype_cs );
2278 HeapFree(GetProcessHeap(), 0, unix_name);
2283 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
2285 static const WCHAR slashW[] = {'\\','\0'};
2287 WCHAR windowsdir[MAX_PATH];
2290 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2291 strcatW(windowsdir, fontsW);
2292 strcatW(windowsdir, slashW);
2293 strcatW(windowsdir, file);
2294 if ((unixname = wine_get_unix_file_name(windowsdir))) {
2295 EnterCriticalSection( &freetype_cs );
2296 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2297 LeaveCriticalSection( &freetype_cs );
2298 HeapFree(GetProcessHeap(), 0, unixname);
2303 static void load_system_fonts(void)
2306 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
2307 const WCHAR * const *value;
2309 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2312 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
2313 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2314 strcatW(windowsdir, fontsW);
2315 for(value = SystemFontValues; *value; value++) {
2316 dlen = sizeof(data);
2317 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
2321 sprintfW(pathW, fmtW, windowsdir, data);
2322 if((unixname = wine_get_unix_file_name(pathW))) {
2323 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2324 HeapFree(GetProcessHeap(), 0, unixname);
2327 load_font_from_data_dir(data);
2334 /*************************************************************
2336 * This adds registry entries for any externally loaded fonts
2337 * (fonts from fontconfig or FontDirs). It also deletes entries
2338 * of no longer existing fonts.
2341 static void update_reg_entries(void)
2343 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2348 struct list *family_elem_ptr, *face_elem_ptr;
2350 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2351 static const WCHAR spaceW[] = {' ', '\0'};
2354 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2355 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2356 ERR("Can't create Windows font reg key\n");
2360 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2361 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2362 ERR("Can't create Windows font reg key\n");
2366 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
2367 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
2368 ERR("Can't create external font reg key\n");
2372 /* enumerate the fonts and add external ones to the two keys */
2374 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2375 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2376 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2377 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2378 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2379 if(!face->external) continue;
2381 if (!(face->ntmFlags & NTM_REGULAR))
2382 len = len_fam + strlenW(face->StyleName) + 1;
2383 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2384 strcpyW(valueW, family->FamilyName);
2385 if(len != len_fam) {
2386 strcatW(valueW, spaceW);
2387 strcatW(valueW, face->StyleName);
2389 strcatW(valueW, TrueType);
2391 file = wine_get_dos_file_name(face->file);
2393 len = strlenW(file) + 1;
2396 if((path = strrchr(face->file, '/')) == NULL)
2400 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
2402 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2403 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2405 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2406 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2407 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2409 HeapFree(GetProcessHeap(), 0, file);
2410 HeapFree(GetProcessHeap(), 0, valueW);
2414 if(external_key) RegCloseKey(external_key);
2415 if(win9x_key) RegCloseKey(win9x_key);
2416 if(winnt_key) RegCloseKey(winnt_key);
2420 static void delete_external_font_keys(void)
2422 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2423 DWORD dlen, vlen, datalen, valuelen, i, type;
2427 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2428 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2429 ERR("Can't create Windows font reg key\n");
2433 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2434 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2435 ERR("Can't create Windows font reg key\n");
2439 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2440 ERR("Can't create external font reg key\n");
2444 /* Delete all external fonts added last time */
2446 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2447 &valuelen, &datalen, NULL, NULL);
2448 valuelen++; /* returned value doesn't include room for '\0' */
2449 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2450 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2452 dlen = datalen * sizeof(WCHAR);
2455 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2456 &dlen) == ERROR_SUCCESS) {
2458 RegDeleteValueW(winnt_key, valueW);
2459 RegDeleteValueW(win9x_key, valueW);
2460 /* reset dlen and vlen */
2464 HeapFree(GetProcessHeap(), 0, data);
2465 HeapFree(GetProcessHeap(), 0, valueW);
2467 /* Delete the old external fonts key */
2468 RegCloseKey(external_key);
2469 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2472 if(win9x_key) RegCloseKey(win9x_key);
2473 if(winnt_key) RegCloseKey(winnt_key);
2476 /*************************************************************
2477 * WineEngAddFontResourceEx
2480 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2486 if (ft_handle) /* do it only if we have freetype up and running */
2491 FIXME("Ignoring flags %x\n", flags);
2493 if((unixname = wine_get_unix_file_name(file)))
2495 DWORD addfont_flags = ADDFONT_FORCE_BITMAP;
2497 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
2498 EnterCriticalSection( &freetype_cs );
2499 ret = AddFontFileToList(unixname, NULL, NULL, addfont_flags);
2500 LeaveCriticalSection( &freetype_cs );
2501 HeapFree(GetProcessHeap(), 0, unixname);
2503 if (!ret && !strchrW(file, '\\')) {
2504 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2505 ret = load_font_from_winfonts_dir(file);
2507 /* Try in datadir/fonts (or builddir/fonts),
2508 * needed for Magic the Gathering Online
2510 ret = load_font_from_data_dir(file);
2517 /*************************************************************
2518 * WineEngAddFontMemResourceEx
2521 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2525 if (ft_handle) /* do it only if we have freetype up and running */
2527 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2529 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2530 memcpy(pFontCopy, pbFont, cbFont);
2532 EnterCriticalSection( &freetype_cs );
2533 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
2534 LeaveCriticalSection( &freetype_cs );
2538 TRACE("AddFontToList failed\n");
2539 HeapFree(GetProcessHeap(), 0, pFontCopy);
2542 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2543 * For now return something unique but quite random
2545 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2546 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2553 /*************************************************************
2554 * WineEngRemoveFontResourceEx
2557 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2560 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
2564 static const struct nls_update_font_list
2566 UINT ansi_cp, oem_cp;
2567 const char *oem, *fixed, *system;
2568 const char *courier, *serif, *small, *sserif;
2569 /* these are for font substitutes */
2570 const char *shelldlg, *tmsrmn;
2571 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2575 const char *from, *to;
2576 } arial_0, courier_new_0, times_new_roman_0;
2577 } nls_update_font_list[] =
2579 /* Latin 1 (United States) */
2580 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2581 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2582 "Tahoma","Times New Roman",
2583 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2586 /* Latin 1 (Multilingual) */
2587 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2588 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2589 "Tahoma","Times New Roman", /* FIXME unverified */
2590 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2593 /* Eastern Europe */
2594 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2595 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2596 "Tahoma","Times New Roman", /* FIXME unverified */
2597 "Fixedsys,238", "System,238",
2598 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2599 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2600 { "Arial CE,0", "Arial,238" },
2601 { "Courier New CE,0", "Courier New,238" },
2602 { "Times New Roman CE,0", "Times New Roman,238" }
2605 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2606 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2607 "Tahoma","Times New Roman", /* FIXME unverified */
2608 "Fixedsys,204", "System,204",
2609 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2610 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2611 { "Arial Cyr,0", "Arial,204" },
2612 { "Courier New Cyr,0", "Courier New,204" },
2613 { "Times New Roman Cyr,0", "Times New Roman,204" }
2616 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2617 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2618 "Tahoma","Times New Roman", /* FIXME unverified */
2619 "Fixedsys,161", "System,161",
2620 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2621 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2622 { "Arial Greek,0", "Arial,161" },
2623 { "Courier New Greek,0", "Courier New,161" },
2624 { "Times New Roman Greek,0", "Times New Roman,161" }
2627 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2628 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2629 "Tahoma","Times New Roman", /* FIXME unverified */
2630 "Fixedsys,162", "System,162",
2631 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2632 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2633 { "Arial Tur,0", "Arial,162" },
2634 { "Courier New Tur,0", "Courier New,162" },
2635 { "Times New Roman Tur,0", "Times New Roman,162" }
2638 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2639 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2640 "Tahoma","Times New Roman", /* FIXME unverified */
2641 "Fixedsys,177", "System,177",
2642 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2643 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2647 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2648 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2649 "Tahoma","Times New Roman", /* FIXME unverified */
2650 "Fixedsys,178", "System,178",
2651 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2652 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2656 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2657 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2658 "Tahoma","Times New Roman", /* FIXME unverified */
2659 "Fixedsys,186", "System,186",
2660 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2661 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2662 { "Arial Baltic,0", "Arial,186" },
2663 { "Courier New Baltic,0", "Courier New,186" },
2664 { "Times New Roman Baltic,0", "Times New Roman,186" }
2667 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2668 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2669 "Tahoma","Times New Roman", /* FIXME unverified */
2670 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2674 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2675 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2676 "Tahoma","Times New Roman", /* FIXME unverified */
2677 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2681 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2682 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2683 "MS UI Gothic","MS Serif",
2684 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2687 /* Chinese Simplified */
2688 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2689 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2690 "SimSun", "NSimSun",
2691 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2695 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2696 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2698 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2701 /* Chinese Traditional */
2702 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2703 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2704 "PMingLiU", "MingLiU",
2705 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2710 static const WCHAR *font_links_list[] =
2712 Lucida_Sans_Unicode,
2713 Microsoft_Sans_Serif,
2717 static const struct font_links_defaults_list
2719 /* Keyed off substitution for "MS Shell Dlg" */
2720 const WCHAR *shelldlg;
2721 /* Maximum of four substitutes, plus terminating NULL pointer */
2722 const WCHAR *substitutes[5];
2723 } font_links_defaults_list[] =
2725 /* Non East-Asian */
2726 { Tahoma, /* FIXME unverified ordering */
2727 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2729 /* Below lists are courtesy of
2730 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2734 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2736 /* Chinese Simplified */
2738 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2742 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2744 /* Chinese Traditional */
2746 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2750 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2752 return ( ansi_cp == 932 /* CP932 for Japanese */
2753 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2754 || ansi_cp == 949 /* CP949 for Korean */
2755 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2758 static inline HKEY create_fonts_NT_registry_key(void)
2762 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2763 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2767 static inline HKEY create_fonts_9x_registry_key(void)
2771 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2772 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2776 static inline HKEY create_config_fonts_registry_key(void)
2780 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2781 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2785 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2787 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2788 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2789 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2790 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2793 static void set_value_key(HKEY hkey, const char *name, const char *value)
2796 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2798 RegDeleteValueA(hkey, name);
2801 static void update_font_info(void)
2803 char buf[40], cpbuf[40];
2806 UINT i, ansi_cp = 0, oem_cp = 0;
2809 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2812 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2813 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2814 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2815 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2816 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2818 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2819 if (is_dbcs_ansi_cp(ansi_cp))
2820 use_default_fallback = TRUE;
2823 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2825 if (!strcmp( buf, cpbuf )) /* already set correctly */
2830 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2832 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2834 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2837 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2841 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2842 nls_update_font_list[i].oem_cp == oem_cp)
2844 hkey = create_config_fonts_registry_key();
2845 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2846 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2847 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2850 hkey = create_fonts_NT_registry_key();
2851 add_font_list(hkey, &nls_update_font_list[i]);
2854 hkey = create_fonts_9x_registry_key();
2855 add_font_list(hkey, &nls_update_font_list[i]);
2858 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2860 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2861 strlen(nls_update_font_list[i].shelldlg)+1);
2862 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2863 strlen(nls_update_font_list[i].tmsrmn)+1);
2865 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2866 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2867 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2868 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2869 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2870 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2871 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2872 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2874 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2875 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2876 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2884 /* Delete the FontSubstitutes from other locales */
2885 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2887 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2888 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2889 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2895 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2898 static void populate_system_links(HKEY hkey, const WCHAR *name, const WCHAR *const *values)
2907 WCHAR buff[MAX_PATH];
2911 static const WCHAR comma[] = {',',0};
2913 RegDeleteValueW(hkey, name);
2918 for (i = 0; values[i] != NULL; i++)
2921 if (!strcmpiW(name,value))
2923 psub = get_font_subst(&font_subst_list, value, -1);
2925 value = psub->to.name;
2926 family = find_family_from_name(value);
2930 /* Use first extant filename for this Family */
2931 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2935 file = strrchr(face->file, '/');
2944 fileW = towstr(CP_UNIXCP, file);
2945 entryLen = strlenW(fileW) + 1 + strlenW(value) + 1;
2946 if (sizeof(buff)-(data-buff) < entryLen + 1)
2948 WARN("creating SystemLink for %s, ran out of buffer space\n", debugstr_w(name));
2949 HeapFree(GetProcessHeap(), 0, fileW);
2952 strcpyW(data, fileW);
2953 strcatW(data, comma);
2954 strcatW(data, value);
2956 TRACE("added SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(fileW));
2957 HeapFree(GetProcessHeap(), 0, fileW);
2963 RegSetValueExW(hkey, name, 0, REG_MULTI_SZ, (BYTE*)buff, (data-buff) * sizeof(WCHAR));
2965 TRACE("no SystemLink fonts found for %s\n", debugstr_w(name));
2967 TRACE("removed SystemLink for %s\n", debugstr_w(name));
2970 static void update_system_links(void)
2978 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2980 if (!RegCreateKeyExW(HKEY_CURRENT_USER, internal_system_link, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, &disposition))
2982 if (disposition == REG_OPENED_EXISTING_KEY)
2984 TRACE("SystemLink key already exists, doing nothing\n");
2989 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2991 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2996 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2998 const FontSubst *psub2;
2999 psub2 = get_font_subst(&font_subst_list, font_links_defaults_list[i].shelldlg, -1);
3001 if ((!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name) || (psub2 && !strcmpiW(psub2->to.name,psub->to.name))))
3003 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
3004 populate_system_links(hkey, font_links_list[j], font_links_defaults_list[i].substitutes);
3006 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
3007 populate_system_links(hkey, psub->to.name, font_links_defaults_list[i].substitutes);
3010 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
3012 populate_system_links(hkey, font_links_defaults_list[i].substitutes[0], NULL);
3017 WARN("there is no SystemLink default list for MS Shell Dlg %s\n", debugstr_w(psub->to.name));
3019 WARN("failed to create Internal SystemLink key\n");
3023 static BOOL init_freetype(void)
3025 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
3028 "Wine cannot find the FreeType font library. To enable Wine to\n"
3029 "use TrueType fonts please install a version of FreeType greater than\n"
3030 "or equal to 2.0.5.\n"
3031 "http://www.freetype.org\n");
3035 #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;}
3037 LOAD_FUNCPTR(FT_Done_Face)
3038 LOAD_FUNCPTR(FT_Get_Char_Index)
3039 LOAD_FUNCPTR(FT_Get_First_Char)
3040 LOAD_FUNCPTR(FT_Get_Module)
3041 LOAD_FUNCPTR(FT_Get_Next_Char)
3042 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
3043 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
3044 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
3045 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
3046 LOAD_FUNCPTR(FT_Init_FreeType)
3047 LOAD_FUNCPTR(FT_Library_Version)
3048 LOAD_FUNCPTR(FT_Load_Glyph)
3049 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
3050 LOAD_FUNCPTR(FT_Matrix_Multiply)
3051 #ifndef FT_MULFIX_INLINED
3052 LOAD_FUNCPTR(FT_MulFix)
3054 LOAD_FUNCPTR(FT_New_Face)
3055 LOAD_FUNCPTR(FT_New_Memory_Face)
3056 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
3057 LOAD_FUNCPTR(FT_Outline_Transform)
3058 LOAD_FUNCPTR(FT_Outline_Translate)
3059 LOAD_FUNCPTR(FT_Render_Glyph)
3060 LOAD_FUNCPTR(FT_Select_Charmap)
3061 LOAD_FUNCPTR(FT_Set_Charmap)
3062 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
3063 LOAD_FUNCPTR(FT_Vector_Transform)
3064 LOAD_FUNCPTR(FT_Vector_Unit)
3066 /* Don't warn if these ones are missing */
3067 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
3068 #ifdef HAVE_FREETYPE_FTLCDFIL_H
3069 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
3072 if(pFT_Init_FreeType(&library) != 0) {
3073 ERR("Can't init FreeType library\n");
3074 wine_dlclose(ft_handle, NULL, 0);
3078 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
3080 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
3081 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
3082 ((FT_Version.minor << 8) & 0x00ff00) |
3083 ((FT_Version.patch ) & 0x0000ff);
3085 font_driver = &freetype_funcs;
3090 "Wine cannot find certain functions that it needs inside the FreeType\n"
3091 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3092 "FreeType to at least version 2.1.4.\n"
3093 "http://www.freetype.org\n");
3094 wine_dlclose(ft_handle, NULL, 0);
3099 static void init_font_list(void)
3101 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
3102 static const WCHAR pathW[] = {'P','a','t','h',0};
3104 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
3105 WCHAR windowsdir[MAX_PATH];
3107 const char *data_dir;
3109 delete_external_font_keys();
3111 /* load the system bitmap fonts */
3112 load_system_fonts();
3114 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3115 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3116 strcatW(windowsdir, fontsW);
3117 if((unixname = wine_get_unix_file_name(windowsdir)))
3119 ReadFontDir(unixname, FALSE);
3120 HeapFree(GetProcessHeap(), 0, unixname);
3123 /* load the system truetype fonts */
3124 data_dir = wine_get_data_dir();
3125 if (!data_dir) data_dir = wine_get_build_dir();
3126 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
3128 strcpy(unixname, data_dir);
3129 strcat(unixname, "/fonts/");
3130 ReadFontDir(unixname, TRUE);
3131 HeapFree(GetProcessHeap(), 0, unixname);
3134 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3135 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3136 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3138 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
3139 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
3140 &hkey) == ERROR_SUCCESS)
3142 LPWSTR data, valueW;
3143 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3144 &valuelen, &datalen, NULL, NULL);
3146 valuelen++; /* returned value doesn't include room for '\0' */
3147 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3148 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3151 dlen = datalen * sizeof(WCHAR);
3153 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
3154 &dlen) == ERROR_SUCCESS)
3156 if(data[0] && (data[1] == ':'))
3158 if((unixname = wine_get_unix_file_name(data)))
3160 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3161 HeapFree(GetProcessHeap(), 0, unixname);
3164 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
3166 WCHAR pathW[MAX_PATH];
3167 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3170 sprintfW(pathW, fmtW, windowsdir, data);
3171 if((unixname = wine_get_unix_file_name(pathW)))
3173 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3174 HeapFree(GetProcessHeap(), 0, unixname);
3177 load_font_from_data_dir(data);
3179 /* reset dlen and vlen */
3184 HeapFree(GetProcessHeap(), 0, data);
3185 HeapFree(GetProcessHeap(), 0, valueW);
3189 load_fontconfig_fonts();
3191 /* then look in any directories that we've specified in the config file */
3192 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3193 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
3199 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
3201 len += sizeof(WCHAR);
3202 valueW = HeapAlloc( GetProcessHeap(), 0, len );
3203 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
3205 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
3206 valueA = HeapAlloc( GetProcessHeap(), 0, len );
3207 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
3208 TRACE( "got font path %s\n", debugstr_a(valueA) );
3213 LPSTR next = strchr( ptr, ':' );
3214 if (next) *next++ = 0;
3215 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
3216 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
3218 strcpy( unixname, home );
3219 strcat( unixname, ptr + 1 );
3220 ReadFontDir( unixname, TRUE );
3221 HeapFree( GetProcessHeap(), 0, unixname );
3224 ReadFontDir( ptr, TRUE );
3227 HeapFree( GetProcessHeap(), 0, valueA );
3229 HeapFree( GetProcessHeap(), 0, valueW );
3235 static BOOL move_to_front(const WCHAR *name)
3237 Family *family, *cursor2;
3238 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
3240 if(!strcmpiW(family->FamilyName, name))
3242 list_remove(&family->entry);
3243 list_add_head(&font_list, &family->entry);
3250 static BOOL set_default(const WCHAR **name_list)
3254 if (move_to_front(*name_list)) return TRUE;
3261 static void reorder_font_list(void)
3263 set_default( default_serif_list );
3264 set_default( default_fixed_list );
3265 set_default( default_sans_list );
3268 /*************************************************************
3271 * Initialize FreeType library and create a list of available faces
3273 BOOL WineEngInit(void)
3275 HKEY hkey_font_cache;
3279 /* update locale dependent font info in registry */
3282 if(!init_freetype()) return FALSE;
3284 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
3286 ERR("Failed to create font mutex\n");
3289 WaitForSingleObject(font_mutex, INFINITE);
3291 create_font_cache_key(&hkey_font_cache, &disposition);
3293 if(disposition == REG_CREATED_NEW_KEY)
3296 load_font_list_from_cache(hkey_font_cache);
3298 RegCloseKey(hkey_font_cache);
3300 reorder_font_list();
3307 if(disposition == REG_CREATED_NEW_KEY)
3308 update_reg_entries();
3310 update_system_links();
3311 init_system_links();
3313 ReleaseMutex(font_mutex);
3318 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
3321 TT_HoriHeader *pHori;
3325 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3326 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3328 if(height == 0) height = 16;
3330 /* Calc. height of EM square:
3332 * For +ve lfHeight we have
3333 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3334 * Re-arranging gives:
3335 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3337 * For -ve lfHeight we have
3339 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3340 * with il = winAscent + winDescent - units_per_em]
3345 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
3346 ppem = MulDiv(ft_face->units_per_EM, height,
3347 pHori->Ascender - pHori->Descender);
3349 ppem = MulDiv(ft_face->units_per_EM, height,
3350 pOS2->usWinAscent + pOS2->usWinDescent);
3358 static struct font_mapping *map_font_file( const char *name )
3360 struct font_mapping *mapping;
3364 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
3365 if (fstat( fd, &st ) == -1) goto error;
3367 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
3369 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
3371 mapping->refcount++;
3376 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
3379 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
3382 if (mapping->data == MAP_FAILED)
3384 HeapFree( GetProcessHeap(), 0, mapping );
3387 mapping->refcount = 1;
3388 mapping->dev = st.st_dev;
3389 mapping->ino = st.st_ino;
3390 mapping->size = st.st_size;
3391 list_add_tail( &mappings_list, &mapping->entry );
3399 static void unmap_font_file( struct font_mapping *mapping )
3401 if (!--mapping->refcount)
3403 list_remove( &mapping->entry );
3404 munmap( mapping->data, mapping->size );
3405 HeapFree( GetProcessHeap(), 0, mapping );
3409 static LONG load_VDMX(GdiFont*, LONG);
3411 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
3418 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
3422 if (!(font->mapping = map_font_file( face->file )))
3424 WARN("failed to map %s\n", debugstr_a(face->file));
3427 data_ptr = font->mapping->data;
3428 data_size = font->mapping->size;
3432 data_ptr = face->font_data_ptr;
3433 data_size = face->font_data_size;
3436 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3438 ERR("FT_New_Face rets %d\n", err);
3442 /* set it here, as load_VDMX needs it */
3443 font->ft_face = ft_face;
3445 if(FT_IS_SCALABLE(ft_face)) {
3446 /* load the VDMX table if we have one */
3447 font->ppem = load_VDMX(font, height);
3449 font->ppem = calc_ppem_for_height(ft_face, height);
3450 TRACE("height %d => ppem %d\n", height, font->ppem);
3452 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3453 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3455 font->ppem = height;
3456 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3457 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3463 static int get_nearest_charset(Face *face, int *cp)
3465 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3466 a single face with the requested charset. The idea is to check if
3467 the selected font supports the current ANSI codepage, if it does
3468 return the corresponding charset, else return the first charset */
3471 int acp = GetACP(), i;
3475 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3476 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3477 return csi.ciCharset;
3479 for(i = 0; i < 32; i++) {
3481 if(face->fs.fsCsb[0] & fs0) {
3482 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
3484 return csi.ciCharset;
3487 FIXME("TCI failing on %x\n", fs0);
3491 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3492 face->fs.fsCsb[0], face->file);
3494 return DEFAULT_CHARSET;
3497 static GdiFont *alloc_font(void)
3499 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
3501 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
3502 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3504 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3505 ret->total_kern_pairs = (DWORD)-1;
3506 ret->kern_pairs = NULL;
3507 list_init(&ret->hfontlist);
3508 list_init(&ret->child_fonts);
3512 static void free_font(GdiFont *font)
3514 struct list *cursor, *cursor2;
3517 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
3519 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
3520 list_remove(cursor);
3522 free_font(child->font);
3523 HeapFree(GetProcessHeap(), 0, child);
3526 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->hfontlist)
3528 HFONTLIST *hfontlist = LIST_ENTRY(cursor, HFONTLIST, entry);
3529 DeleteObject(hfontlist->hfont);
3530 list_remove(&hfontlist->entry);
3531 HeapFree(GetProcessHeap(), 0, hfontlist);
3534 if (font->ft_face) pFT_Done_Face(font->ft_face);
3535 if (font->mapping) unmap_font_file( font->mapping );
3536 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
3537 HeapFree(GetProcessHeap(), 0, font->potm);
3538 HeapFree(GetProcessHeap(), 0, font->name);
3539 for (i = 0; i < font->gmsize; i++)
3540 HeapFree(GetProcessHeap(),0,font->gm[i]);
3541 HeapFree(GetProcessHeap(), 0, font->gm);
3542 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
3543 HeapFree(GetProcessHeap(), 0, font);
3547 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
3549 FT_Face ft_face = font->ft_face;
3553 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
3560 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
3562 /* make sure value of len is the value freetype says it needs */
3565 FT_ULong needed = 0;
3566 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
3567 if( !err && needed < len) len = needed;
3569 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
3572 TRACE("Can't find table %c%c%c%c\n",
3573 /* bytes were reversed */
3574 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
3575 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
3581 /*************************************************************
3584 * load the vdmx entry for the specified height
3587 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3588 ( ( (FT_ULong)_x4 << 24 ) | \
3589 ( (FT_ULong)_x3 << 16 ) | \
3590 ( (FT_ULong)_x2 << 8 ) | \
3593 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3608 static LONG load_VDMX(GdiFont *font, LONG height)
3612 BYTE devXRatio, devYRatio;
3613 USHORT numRecs, numRatios;
3614 DWORD result, offset = -1;
3618 result = get_font_data(font, MS_VDMX_TAG, 0, hdr, 6);
3620 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
3623 /* FIXME: need the real device aspect ratio */
3627 numRecs = GET_BE_WORD(hdr[1]);
3628 numRatios = GET_BE_WORD(hdr[2]);
3630 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
3631 for(i = 0; i < numRatios; i++) {
3634 offset = (3 * 2) + (i * sizeof(Ratios));
3635 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
3638 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
3640 if((ratio.xRatio == 0 &&
3641 ratio.yStartRatio == 0 &&
3642 ratio.yEndRatio == 0) ||
3643 (devXRatio == ratio.xRatio &&
3644 devYRatio >= ratio.yStartRatio &&
3645 devYRatio <= ratio.yEndRatio))
3647 offset = (3 * 2) + (numRatios * 4) + (i * 2);
3648 get_font_data(font, MS_VDMX_TAG, offset, &tmp, 2);
3649 offset = GET_BE_WORD(tmp);
3655 FIXME("No suitable ratio found\n");
3659 if(get_font_data(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
3661 BYTE startsz, endsz;
3664 recs = GET_BE_WORD(group.recs);
3665 startsz = group.startsz;
3666 endsz = group.endsz;
3668 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
3670 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
3671 result = get_font_data(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
3672 if(result == GDI_ERROR) {
3673 FIXME("Failed to retrieve vTable\n");
3678 for(i = 0; i < recs; i++) {
3679 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3680 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3681 ppem = GET_BE_WORD(vTable[i * 3]);
3683 if(yMax + -yMin == height) {
3686 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3689 if(yMax + -yMin > height) {
3692 goto end; /* failed */
3694 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3695 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3696 ppem = GET_BE_WORD(vTable[i * 3]);
3697 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3703 TRACE("ppem not found for height %d\n", height);
3707 HeapFree(GetProcessHeap(), 0, vTable);
3713 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3715 if(font->font_desc.hash != fd->hash) return TRUE;
3716 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3717 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3718 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3719 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3722 static void calc_hash(FONT_DESC *pfd)
3724 DWORD hash = 0, *ptr, two_chars;
3728 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3730 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3732 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3734 pwc = (WCHAR *)&two_chars;
3736 *pwc = toupperW(*pwc);
3738 *pwc = toupperW(*pwc);
3742 hash ^= !pfd->can_use_bitmap;
3747 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3752 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3756 fd.can_use_bitmap = can_use_bitmap;
3759 /* try the child list */
3760 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
3761 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3762 if(!fontcmp(ret, &fd)) {
3763 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3764 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3765 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3766 if(hflist->hfont == hfont)
3772 /* try the in-use list */
3773 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3774 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3775 if(!fontcmp(ret, &fd)) {
3776 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3777 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3778 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3779 if(hflist->hfont == hfont)
3782 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3783 hflist->hfont = hfont;
3784 list_add_head(&ret->hfontlist, &hflist->entry);
3789 /* then the unused list */
3790 font_elem_ptr = list_head(&unused_gdi_font_list);
3791 while(font_elem_ptr) {
3792 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3793 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3794 if(!fontcmp(ret, &fd)) {
3795 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3796 assert(list_empty(&ret->hfontlist));
3797 TRACE("Found %p in unused list\n", ret);
3798 list_remove(&ret->entry);
3799 list_add_head(&gdi_font_list, &ret->entry);
3800 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3801 hflist->hfont = hfont;
3802 list_add_head(&ret->hfontlist, &hflist->entry);
3809 static void add_to_cache(GdiFont *font)
3811 static DWORD cache_num = 1;
3813 font->cache_num = cache_num++;
3814 list_add_head(&gdi_font_list, &font->entry);
3817 /*************************************************************
3818 * create_child_font_list
3820 static BOOL create_child_font_list(GdiFont *font)
3823 SYSTEM_LINKS *font_link;
3824 CHILD_FONT *font_link_entry, *new_child;
3828 psub = get_font_subst(&font_subst_list, font->name, -1);
3829 font_name = psub ? psub->to.name : font->name;
3830 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3832 if(!strcmpiW(font_link->font_name, font_name))
3834 TRACE("found entry in system list\n");
3835 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3837 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3838 new_child->face = font_link_entry->face;
3839 new_child->font = NULL;
3840 list_add_tail(&font->child_fonts, &new_child->entry);
3841 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3848 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3849 * Sans Serif. This is how asian windows get default fallbacks for fonts
3851 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3852 font->charset != OEM_CHARSET &&
3853 strcmpiW(font_name,szDefaultFallbackLink) != 0)
3854 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3856 if(!strcmpiW(font_link->font_name,szDefaultFallbackLink))
3858 TRACE("found entry in default fallback list\n");
3859 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3861 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3862 new_child->face = font_link_entry->face;
3863 new_child->font = NULL;
3864 list_add_tail(&font->child_fonts, &new_child->entry);
3865 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3875 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3877 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3879 if (pFT_Set_Charmap)
3882 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3884 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3886 for (i = 0; i < ft_face->num_charmaps; i++)
3888 if (ft_face->charmaps[i]->encoding == encoding)
3890 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3891 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3893 switch (ft_face->charmaps[i]->platform_id)
3896 cmap_def = ft_face->charmaps[i];
3898 case 0: /* Apple Unicode */
3899 cmap0 = ft_face->charmaps[i];
3901 case 1: /* Macintosh */
3902 cmap1 = ft_face->charmaps[i];
3905 cmap2 = ft_face->charmaps[i];
3907 case 3: /* Microsoft */
3908 cmap3 = ft_face->charmaps[i];
3913 if (cmap3) /* prefer Microsoft cmap table */
3914 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3916 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3918 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3920 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3922 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3924 return ft_err == FT_Err_Ok;
3927 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3931 /*************************************************************
3934 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
3935 LPCWSTR output, const DEVMODEW *devmode )
3937 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
3939 if (!physdev) return FALSE;
3940 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
3945 /*************************************************************
3948 static BOOL freetype_DeleteDC( PHYSDEV dev )
3950 struct freetype_physdev *physdev = get_freetype_dev( dev );
3951 HeapFree( GetProcessHeap(), 0, physdev );
3956 /*************************************************************
3957 * freetype_SelectFont
3959 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont )
3961 struct freetype_physdev *physdev = get_freetype_dev( dev );
3963 Face *face, *best, *best_bitmap;
3964 Family *family, *last_resort_family;
3965 struct list *family_elem_ptr, *face_elem_ptr;
3966 INT height, width = 0;
3967 unsigned int score = 0, new_score;
3968 signed int diff = 0, newdiff;
3969 BOOL bd, it, can_use_bitmap;
3974 FontSubst *psub = NULL;
3975 DC *dc = get_dc_ptr( dev->hdc );
3977 if (!hfont) /* notification that the font has been changed by another driver */
3980 physdev->font = NULL;
3981 release_dc_ptr( dc );
3985 GetObjectW( hfont, sizeof(lf), &lf );
3986 lf.lfWidth = abs(lf.lfWidth);
3988 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
3990 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3991 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3992 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3995 if(dc->GraphicsMode == GM_ADVANCED)
3996 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
3999 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
4000 font scaling abilities. */
4001 dcmat.eM11 = dcmat.eM22 = dc->vport2WorldValid ? fabs(dc->xformWorld2Vport.eM22) : 1.0;
4002 dcmat.eM21 = dcmat.eM12 = 0;
4005 /* Try to avoid not necessary glyph transformations */
4006 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
4008 lf.lfHeight *= fabs(dcmat.eM11);
4009 lf.lfWidth *= fabs(dcmat.eM11);
4010 dcmat.eM11 = dcmat.eM22 = 1.0;
4013 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
4014 dcmat.eM21, dcmat.eM22);
4017 EnterCriticalSection( &freetype_cs );
4019 /* check the cache first */
4020 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4021 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
4025 if(list_empty(&font_list)) /* No fonts installed */
4027 TRACE("No fonts installed\n");
4031 TRACE("not in cache\n");
4034 ret->font_desc.matrix = dcmat;
4035 ret->font_desc.lf = lf;
4036 ret->font_desc.can_use_bitmap = can_use_bitmap;
4037 calc_hash(&ret->font_desc);
4038 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
4039 hflist->hfont = hfont;
4040 list_add_head(&ret->hfontlist, &hflist->entry);
4042 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4043 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4044 original value lfCharSet. Note this is a special case for
4045 Symbol and doesn't happen at least for "Wingdings*" */
4047 if(!strcmpiW(lf.lfFaceName, SymbolW))
4048 lf.lfCharSet = SYMBOL_CHARSET;
4050 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
4051 switch(lf.lfCharSet) {
4052 case DEFAULT_CHARSET:
4053 csi.fs.fsCsb[0] = 0;
4056 FIXME("Untranslated charset %d\n", lf.lfCharSet);
4057 csi.fs.fsCsb[0] = 0;
4063 if(lf.lfFaceName[0] != '\0') {
4064 SYSTEM_LINKS *font_link;
4065 CHILD_FONT *font_link_entry;
4066 LPWSTR FaceName = lf.lfFaceName;
4068 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
4071 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
4072 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
4073 if (psub->to.charset != -1)
4074 lf.lfCharSet = psub->to.charset;
4077 /* We want a match on name and charset or just name if
4078 charset was DEFAULT_CHARSET. If the latter then
4079 we fixup the returned charset later in get_nearest_charset
4080 where we'll either use the charset of the current ansi codepage
4081 or if that's unavailable the first charset that the font supports.
4083 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4084 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4085 if (!strcmpiW(family->FamilyName, FaceName) ||
4086 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
4088 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4089 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4090 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
4091 if(face->scalable || can_use_bitmap)
4097 /* Search by full face name. */
4098 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4099 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4100 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4101 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4102 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
4103 ((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0]))
4105 if(face->scalable || can_use_bitmap)
4112 * Try check the SystemLink list first for a replacement font.
4113 * We may find good replacements there.
4115 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
4117 if(!strcmpiW(font_link->font_name, FaceName) ||
4118 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
4120 TRACE("found entry in system list\n");
4121 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4123 face = font_link_entry->face;
4124 family = face->family;
4125 if(csi.fs.fsCsb[0] &
4126 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
4128 if(face->scalable || can_use_bitmap)
4136 psub = NULL; /* substitution is no more relevant */
4138 /* If requested charset was DEFAULT_CHARSET then try using charset
4139 corresponding to the current ansi codepage */
4140 if (!csi.fs.fsCsb[0])
4143 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
4144 FIXME("TCI failed on codepage %d\n", acp);
4145 csi.fs.fsCsb[0] = 0;
4147 lf.lfCharSet = csi.ciCharset;
4150 /* Face families are in the top 4 bits of lfPitchAndFamily,
4151 so mask with 0xF0 before testing */
4153 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
4154 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
4155 strcpyW(lf.lfFaceName, defFixed);
4156 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
4157 strcpyW(lf.lfFaceName, defSerif);
4158 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
4159 strcpyW(lf.lfFaceName, defSans);
4161 strcpyW(lf.lfFaceName, defSans);
4162 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4163 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4164 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
4165 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4166 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4167 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
4168 if(face->scalable || can_use_bitmap)
4174 last_resort_family = NULL;
4175 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4176 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4177 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4178 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4179 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
4182 if(can_use_bitmap && !last_resort_family)
4183 last_resort_family = family;
4188 if(last_resort_family) {
4189 family = last_resort_family;
4190 csi.fs.fsCsb[0] = 0;
4194 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4195 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4196 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4197 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4198 if(face->scalable) {
4199 csi.fs.fsCsb[0] = 0;
4200 WARN("just using first face for now\n");
4203 if(can_use_bitmap && !last_resort_family)
4204 last_resort_family = family;
4207 if(!last_resort_family) {
4208 FIXME("can't find a single appropriate font - bailing\n");
4214 WARN("could only find a bitmap font - this will probably look awful!\n");
4215 family = last_resort_family;
4216 csi.fs.fsCsb[0] = 0;
4219 it = lf.lfItalic ? 1 : 0;
4220 bd = lf.lfWeight > 550 ? 1 : 0;
4222 height = lf.lfHeight;
4224 face = best = best_bitmap = NULL;
4225 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
4227 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
4231 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
4232 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
4233 new_score = (italic ^ it) + (bold ^ bd);
4234 if(!best || new_score <= score)
4236 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4237 italic, bold, it, bd);
4240 if(best->scalable && score == 0) break;
4244 newdiff = height - (signed int)(best->size.height);
4246 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
4247 if(!best_bitmap || new_score < score ||
4248 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
4250 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
4253 if(score == 0 && diff == 0) break;
4260 face = best->scalable ? best : best_bitmap;
4261 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
4262 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
4265 height = lf.lfHeight;
4269 if(csi.fs.fsCsb[0]) {
4270 ret->charset = lf.lfCharSet;
4271 ret->codepage = csi.ciACP;
4274 ret->charset = get_nearest_charset(face, &ret->codepage);
4276 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
4277 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
4279 ret->aveWidth = height ? lf.lfWidth : 0;
4281 if(!face->scalable) {
4282 /* Windows uses integer scaling factors for bitmap fonts */
4283 INT scale, scaled_height;
4284 GdiFont *cachedfont;
4286 /* FIXME: rotation of bitmap fonts is ignored */
4287 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
4289 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
4290 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4291 dcmat.eM11 = dcmat.eM22 = 1.0;
4292 /* As we changed the matrix, we need to search the cache for the font again,
4293 * otherwise we might explode the cache. */
4294 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4295 TRACE("Found cached font after non-scalable matrix rescale!\n");
4300 calc_hash(&ret->font_desc);
4302 if (height != 0) height = diff;
4303 height += face->size.height;
4305 scale = (height + face->size.height - 1) / face->size.height;
4306 scaled_height = scale * face->size.height;
4307 /* Only jump to the next height if the difference <= 25% original height */
4308 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
4309 /* The jump between unscaled and doubled is delayed by 1 */
4310 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
4311 ret->scale_y = scale;
4313 width = face->size.x_ppem >> 6;
4314 height = face->size.y_ppem >> 6;
4318 TRACE("font scale y: %f\n", ret->scale_y);
4320 ret->ft_face = OpenFontFace(ret, face, width, height);
4329 ret->ntmFlags = face->ntmFlags;
4331 if (ret->charset == SYMBOL_CHARSET &&
4332 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
4335 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
4339 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
4342 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
4343 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
4344 ret->underline = lf.lfUnderline ? 0xff : 0;
4345 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
4346 create_child_font_list(ret);
4348 if (face->vertical) /* We need to try to load the GSUB table */
4350 int length = get_font_data(ret, GSUB_TAG , 0, NULL, 0);
4351 if (length != GDI_ERROR)
4353 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
4354 get_font_data(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
4355 TRACE("Loaded GSUB table of %i bytes\n",length);
4359 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
4366 physdev->font = ret;
4368 LeaveCriticalSection( &freetype_cs );
4369 release_dc_ptr( dc );
4370 return ret ? hfont : 0;
4373 static void dump_gdi_font_list(void)
4376 struct list *elem_ptr;
4378 TRACE("---------- gdiFont Cache ----------\n");
4379 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
4380 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4381 TRACE("gdiFont=%p %s %d\n",
4382 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4385 TRACE("---------- Unused gdiFont Cache ----------\n");
4386 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
4387 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4388 TRACE("gdiFont=%p %s %d\n",
4389 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4392 TRACE("---------- Child gdiFont Cache ----------\n");
4393 LIST_FOR_EACH(elem_ptr, &child_font_list) {
4394 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4395 TRACE("gdiFont=%p %s %d\n",
4396 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4400 /*************************************************************
4401 * WineEngDestroyFontInstance
4403 * free the gdiFont associated with this handle
4406 BOOL WineEngDestroyFontInstance(HFONT handle)
4411 struct list *font_elem_ptr, *hfontlist_elem_ptr;
4415 EnterCriticalSection( &freetype_cs );
4417 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
4419 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4420 while(hfontlist_elem_ptr) {
4421 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4422 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4423 if(hflist->hfont == handle) {
4424 TRACE("removing child font %p from child list\n", gdiFont);
4425 list_remove(&gdiFont->entry);
4426 LeaveCriticalSection( &freetype_cs );
4432 TRACE("destroying hfont=%p\n", handle);
4434 dump_gdi_font_list();
4436 font_elem_ptr = list_head(&gdi_font_list);
4437 while(font_elem_ptr) {
4438 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4439 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
4441 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4442 while(hfontlist_elem_ptr) {
4443 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4444 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4445 if(hflist->hfont == handle) {
4446 list_remove(&hflist->entry);
4447 HeapFree(GetProcessHeap(), 0, hflist);
4451 if(list_empty(&gdiFont->hfontlist)) {
4452 TRACE("Moving to Unused list\n");
4453 list_remove(&gdiFont->entry);
4454 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
4459 font_elem_ptr = list_head(&unused_gdi_font_list);
4460 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
4461 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4462 while(font_elem_ptr) {
4463 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4464 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4465 TRACE("freeing %p\n", gdiFont);
4466 list_remove(&gdiFont->entry);
4469 LeaveCriticalSection( &freetype_cs );
4473 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
4480 id += IDS_FIRST_SCRIPT;
4481 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
4482 if (!rsrc) return 0;
4483 hMem = LoadResource( gdi32_module, rsrc );
4484 if (!hMem) return 0;
4486 p = LockResource( hMem );
4488 while (id--) p += *p + 1;
4490 i = min(LF_FACESIZE - 1, *p);
4491 memcpy(buffer, p + 1, i * sizeof(WCHAR));
4497 /***************************************************
4498 * create_enum_charset_list
4500 * This function creates charset enumeration list because in DEFAULT_CHARSET
4501 * case, the ANSI codepage's charset takes precedence over other charsets.
4502 * This function works as a filter other than DEFAULT_CHARSET case.
4504 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
4509 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
4510 csi.fs.fsCsb[0] != 0) {
4511 list->element[n].mask = csi.fs.fsCsb[0];
4512 list->element[n].charset = csi.ciCharset;
4513 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
4516 else { /* charset is DEFAULT_CHARSET or invalid. */
4519 /* Set the current codepage's charset as the first element. */
4521 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
4522 csi.fs.fsCsb[0] != 0) {
4523 list->element[n].mask = csi.fs.fsCsb[0];
4524 list->element[n].charset = csi.ciCharset;
4525 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
4529 /* Fill out left elements. */
4530 for (i = 0; i < 32; i++) {
4532 fs.fsCsb[0] = 1L << i;
4534 if (n > 0 && fs.fsCsb[0] == list->element[0].mask)
4535 continue; /* skip, already added. */
4536 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
4537 continue; /* skip, this is an invalid fsCsb bit. */
4539 list->element[n].mask = fs.fsCsb[0];
4540 list->element[n].charset = csi.ciCharset;
4541 load_script_name( i, list->element[n].name );
4550 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
4551 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
4556 if (face->cached_enum_data)
4559 *pelf = face->cached_enum_data->elf;
4560 *pntm = face->cached_enum_data->ntm;
4561 *ptype = face->cached_enum_data->type;
4565 font = alloc_font();
4567 if(face->scalable) {
4568 height = -2048; /* 2048 is the most common em size */
4571 height = face->size.y_ppem >> 6;
4572 width = face->size.x_ppem >> 6;
4574 font->scale_y = 1.0;
4576 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
4582 font->name = strdupW(face->family->FamilyName);
4583 font->ntmFlags = face->ntmFlags;
4585 if (get_outline_text_metrics(font))
4587 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
4589 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
4591 lstrcpynW(pelf->elfLogFont.lfFaceName,
4592 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
4594 lstrcpynW(pelf->elfFullName,
4595 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFullName),
4597 lstrcpynW(pelf->elfStyle,
4598 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
4603 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
4605 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
4607 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
4609 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
4611 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
4612 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
4615 pntm->ntmTm.ntmFlags = face->ntmFlags;
4616 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
4617 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
4618 pntm->ntmFontSig = face->fs;
4620 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
4622 pelf->elfLogFont.lfEscapement = 0;
4623 pelf->elfLogFont.lfOrientation = 0;
4624 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
4625 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
4626 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
4627 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
4628 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
4629 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
4630 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
4631 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
4632 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
4633 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
4634 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
4637 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
4638 *ptype |= TRUETYPE_FONTTYPE;
4639 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
4640 *ptype |= DEVICE_FONTTYPE;
4641 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
4642 *ptype |= RASTER_FONTTYPE;
4644 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
4645 if (face->cached_enum_data)
4647 face->cached_enum_data->elf = *pelf;
4648 face->cached_enum_data->ntm = *pntm;
4649 face->cached_enum_data->type = *ptype;
4655 static BOOL family_matches(Family *family, const LOGFONTW *lf)
4657 struct list *face_elem_ptr;
4659 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
4661 LIST_FOR_EACH(face_elem_ptr, &family->faces)
4663 static const WCHAR spaceW[] = { ' ',0 };
4664 WCHAR full_family_name[LF_FULLFACESIZE];
4665 Face *face = LIST_ENTRY(face_elem_ptr, Face, entry);
4667 if (strlenW(family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4669 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4670 debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
4674 strcpyW(full_family_name, family->FamilyName);
4675 strcatW(full_family_name, spaceW);
4676 strcatW(full_family_name, face->StyleName);
4677 if (!strcmpiW(lf->lfFaceName, full_family_name)) return TRUE;
4683 static BOOL face_matches(Face *face, const LOGFONTW *lf)
4685 static const WCHAR spaceW[] = { ' ',0 };
4686 WCHAR full_family_name[LF_FULLFACESIZE];
4688 if (!strcmpiW(lf->lfFaceName, face->family->FamilyName)) return TRUE;
4690 if (strlenW(face->family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4692 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4693 debugstr_w(face->family->FamilyName), debugstr_w(face->StyleName));
4697 strcpyW(full_family_name, face->family->FamilyName);
4698 strcatW(full_family_name, spaceW);
4699 strcatW(full_family_name, face->StyleName);
4700 return !strcmpiW(lf->lfFaceName, full_family_name);
4703 static BOOL enum_face_charsets(Face *face, struct enum_charset_list *list,
4704 FONTENUMPROCW proc, LPARAM lparam)
4707 NEWTEXTMETRICEXW ntm;
4711 GetEnumStructs(face, &elf, &ntm, &type);
4712 for(i = 0; i < list->total; i++) {
4713 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
4714 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
4715 load_script_name( IDS_OEM_DOS, elf.elfScript );
4716 i = list->total; /* break out of loop after enumeration */
4717 } else if(!(face->fs.fsCsb[0] & list->element[i].mask))
4720 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
4721 strcpyW(elf.elfScript, list->element[i].name);
4722 if (!elf.elfScript[0])
4723 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
4725 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4726 debugstr_w(elf.elfLogFont.lfFaceName),
4727 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
4728 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
4729 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
4730 ntm.ntmTm.ntmFlags);
4731 /* release section before callback (FIXME) */
4732 LeaveCriticalSection( &freetype_cs );
4733 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
4734 EnterCriticalSection( &freetype_cs );
4739 /*************************************************************
4740 * freetype_EnumFonts
4742 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
4746 struct list *family_elem_ptr, *face_elem_ptr;
4748 struct enum_charset_list enum_charsets;
4752 lf.lfCharSet = DEFAULT_CHARSET;
4753 lf.lfPitchAndFamily = 0;
4754 lf.lfFaceName[0] = 0;
4758 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
4760 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
4763 EnterCriticalSection( &freetype_cs );
4764 if(plf->lfFaceName[0]) {
4766 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
4769 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
4770 debugstr_w(psub->to.name));
4772 strcpyW(lf.lfFaceName, psub->to.name);
4776 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4777 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4778 if(family_matches(family, plf)) {
4779 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4780 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4781 if (!face_matches(face, plf)) continue;
4782 if (!enum_face_charsets(face, &enum_charsets, proc, lparam)) return FALSE;
4787 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4788 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4789 face_elem_ptr = list_head(&family->faces);
4790 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4791 if (!enum_face_charsets(face, &enum_charsets, proc, lparam)) return FALSE;
4794 LeaveCriticalSection( &freetype_cs );
4798 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
4800 pt->x.value = vec->x >> 6;
4801 pt->x.fract = (vec->x & 0x3f) << 10;
4802 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
4803 pt->y.value = vec->y >> 6;
4804 pt->y.fract = (vec->y & 0x3f) << 10;
4805 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
4809 /***************************************************
4810 * According to the MSDN documentation on WideCharToMultiByte,
4811 * certain codepages cannot set the default_used parameter.
4812 * This returns TRUE if the codepage can set that parameter, false else
4813 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4815 static BOOL codepage_sets_default_used(UINT codepage)
4829 * GSUB Table handling functions
4832 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
4834 const GSUB_CoverageFormat1* cf1;
4838 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
4840 int count = GET_BE_WORD(cf1->GlyphCount);
4842 TRACE("Coverage Format 1, %i glyphs\n",count);
4843 for (i = 0; i < count; i++)
4844 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
4848 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
4850 const GSUB_CoverageFormat2* cf2;
4853 cf2 = (const GSUB_CoverageFormat2*)cf1;
4855 count = GET_BE_WORD(cf2->RangeCount);
4856 TRACE("Coverage Format 2, %i ranges\n",count);
4857 for (i = 0; i < count; i++)
4859 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
4861 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
4862 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
4864 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4865 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4871 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4876 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4878 const GSUB_ScriptList *script;
4879 const GSUB_Script *deflt = NULL;
4881 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
4883 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4884 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4886 const GSUB_Script *scr;
4889 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4890 scr = (const GSUB_Script*)((const BYTE*)script + offset);
4892 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4894 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4900 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4904 const GSUB_LangSys *Lang;
4906 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4908 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4910 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4911 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4913 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4916 offset = GET_BE_WORD(script->DefaultLangSys);
4919 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4925 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4928 const GSUB_FeatureList *feature;
4929 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
4931 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4932 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4934 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4935 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4937 const GSUB_Feature *feat;
4938 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4945 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4949 const GSUB_LookupList *lookup;
4950 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
4952 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
4953 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
4955 const GSUB_LookupTable *look;
4956 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
4957 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
4958 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
4959 if (GET_BE_WORD(look->LookupType) != 1)
4960 FIXME("We only handle SubType 1\n");
4965 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
4967 const GSUB_SingleSubstFormat1 *ssf1;
4968 offset = GET_BE_WORD(look->SubTable[j]);
4969 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
4970 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
4972 int offset = GET_BE_WORD(ssf1->Coverage);
4973 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
4974 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
4976 TRACE(" Glyph 0x%x ->",glyph);
4977 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4978 TRACE(" 0x%x\n",glyph);
4983 const GSUB_SingleSubstFormat2 *ssf2;
4987 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
4988 offset = GET_BE_WORD(ssf1->Coverage);
4989 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4990 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
4991 TRACE(" Coverage index %i\n",index);
4994 TRACE(" Glyph is 0x%x ->",glyph);
4995 glyph = GET_BE_WORD(ssf2->Substitute[index]);
4996 TRACE("0x%x\n",glyph);
5005 static const char* get_opentype_script(const GdiFont *font)
5008 * I am not sure if this is the correct way to generate our script tag
5011 switch (font->charset)
5013 case ANSI_CHARSET: return "latn";
5014 case BALTIC_CHARSET: return "latn"; /* ?? */
5015 case CHINESEBIG5_CHARSET: return "hani";
5016 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
5017 case GB2312_CHARSET: return "hani";
5018 case GREEK_CHARSET: return "grek";
5019 case HANGUL_CHARSET: return "hang";
5020 case RUSSIAN_CHARSET: return "cyrl";
5021 case SHIFTJIS_CHARSET: return "kana";
5022 case TURKISH_CHARSET: return "latn"; /* ?? */
5023 case VIETNAMESE_CHARSET: return "latn";
5024 case JOHAB_CHARSET: return "latn"; /* ?? */
5025 case ARABIC_CHARSET: return "arab";
5026 case HEBREW_CHARSET: return "hebr";
5027 case THAI_CHARSET: return "thai";
5028 default: return "latn";
5032 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
5034 const GSUB_Header *header;
5035 const GSUB_Script *script;
5036 const GSUB_LangSys *language;
5037 const GSUB_Feature *feature;
5039 if (!font->GSUB_Table)
5042 header = font->GSUB_Table;
5044 script = GSUB_get_script_table(header, get_opentype_script(font));
5047 TRACE("Script not found\n");
5050 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
5053 TRACE("Language not found\n");
5056 feature = GSUB_get_feature(header, language, "vrt2");
5058 feature = GSUB_get_feature(header, language, "vert");
5061 TRACE("vrt2/vert feature not found\n");
5064 return GSUB_apply_feature(header, feature, glyph);
5067 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
5071 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
5072 WCHAR wc = (WCHAR)glyph;
5074 BOOL *default_used_pointer;
5077 default_used_pointer = NULL;
5078 default_used = FALSE;
5079 if (codepage_sets_default_used(font->codepage))
5080 default_used_pointer = &default_used;
5081 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
5084 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
5085 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
5089 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
5091 if (glyph < 0x100) glyph += 0xf000;
5092 /* there is a number of old pre-Unicode "broken" TTFs, which
5093 do have symbols at U+00XX instead of U+f0XX */
5094 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
5095 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
5097 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
5102 /*************************************************************
5103 * freetype_GetGlyphIndices
5105 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
5107 struct freetype_physdev *physdev = get_freetype_dev( dev );
5110 BOOL got_default = FALSE;
5114 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
5115 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
5118 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
5120 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
5125 EnterCriticalSection( &freetype_cs );
5127 for(i = 0; i < count; i++)
5129 pgi[i] = get_glyph_index(physdev->font, lpstr[i]);
5134 if (FT_IS_SFNT(physdev->font->ft_face))
5136 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(physdev->font->ft_face, ft_sfnt_os2);
5137 default_char = (pOS2->usDefaultChar ? get_glyph_index(physdev->font, pOS2->usDefaultChar) : 0);
5142 get_text_metrics(physdev->font, &textm);
5143 default_char = textm.tmDefaultChar;
5147 pgi[i] = default_char;
5150 LeaveCriticalSection( &freetype_cs );
5154 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
5156 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
5157 return !memcmp(matrix, &identity, sizeof(FMAT2));
5160 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
5162 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
5163 return !memcmp(matrix, &identity, sizeof(MAT2));
5166 static inline BYTE get_max_level( UINT format )
5170 case GGO_GRAY2_BITMAP: return 4;
5171 case GGO_GRAY4_BITMAP: return 16;
5172 case GGO_GRAY8_BITMAP: return 64;
5177 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5179 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
5180 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5183 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
5184 FT_Face ft_face = incoming_font->ft_face;
5185 GdiFont *font = incoming_font;
5186 FT_UInt glyph_index;
5187 DWORD width, height, pitch, needed = 0;
5188 FT_Bitmap ft_bitmap;
5190 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
5192 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
5193 double widthRatio = 1.0;
5194 FT_Matrix transMat = identityMat;
5195 FT_Matrix transMatUnrotated;
5196 BOOL needsTransform = FALSE;
5197 BOOL tategaki = (font->GSUB_Table != NULL);
5198 UINT original_index;
5200 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
5201 buflen, buf, lpmat);
5203 TRACE("font transform %f %f %f %f\n",
5204 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
5205 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
5207 if(format & GGO_GLYPH_INDEX) {
5208 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
5209 original_index = glyph;
5210 format &= ~GGO_GLYPH_INDEX;
5212 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
5213 ft_face = font->ft_face;
5214 original_index = glyph_index;
5217 if(format & GGO_UNHINTED) {
5218 load_flags |= FT_LOAD_NO_HINTING;
5219 format &= ~GGO_UNHINTED;
5222 /* tategaki never appears to happen to lower glyph index */
5223 if (glyph_index < TATEGAKI_LOWER_BOUND )
5226 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
5227 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
5228 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
5229 font->gmsize * sizeof(GM*));
5231 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
5232 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
5234 *lpgm = FONT_GM(font,original_index)->gm;
5235 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5236 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5237 lpgm->gmCellIncX, lpgm->gmCellIncY);
5238 return 1; /* FIXME */
5242 if (!font->gm[original_index / GM_BLOCK_SIZE])
5243 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
5245 /* Scaling factor */
5250 get_text_metrics(font, &tm);
5252 widthRatio = (double)font->aveWidth;
5253 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5256 widthRatio = font->scale_y;
5258 /* Scaling transform */
5259 if (widthRatio != 1.0 || font->scale_y != 1.0)
5262 scaleMat.xx = FT_FixedFromFloat(widthRatio);
5265 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
5267 pFT_Matrix_Multiply(&scaleMat, &transMat);
5268 needsTransform = TRUE;
5271 /* Slant transform */
5272 if (font->fake_italic) {
5275 slantMat.xx = (1 << 16);
5276 slantMat.xy = ((1 << 16) >> 2);
5278 slantMat.yy = (1 << 16);
5279 pFT_Matrix_Multiply(&slantMat, &transMat);
5280 needsTransform = TRUE;
5283 /* Rotation transform */
5284 transMatUnrotated = transMat;
5285 if(font->orientation && !tategaki) {
5286 FT_Matrix rotationMat;
5288 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
5289 pFT_Vector_Unit(&vecAngle, angle);
5290 rotationMat.xx = vecAngle.x;
5291 rotationMat.xy = -vecAngle.y;
5292 rotationMat.yx = -rotationMat.xy;
5293 rotationMat.yy = rotationMat.xx;
5295 pFT_Matrix_Multiply(&rotationMat, &transMat);
5296 needsTransform = TRUE;
5299 /* World transform */
5300 if (!is_identity_FMAT2(&font->font_desc.matrix))
5303 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
5304 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
5305 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
5306 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
5307 pFT_Matrix_Multiply(&worldMat, &transMat);
5308 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
5309 needsTransform = TRUE;
5312 /* Extra transformation specified by caller */
5313 if (!is_identity_MAT2(lpmat))
5316 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
5317 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
5318 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
5319 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
5320 pFT_Matrix_Multiply(&extraMat, &transMat);
5321 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
5322 needsTransform = TRUE;
5325 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
5326 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
5327 format == GGO_GRAY8_BITMAP))
5329 load_flags |= FT_LOAD_NO_BITMAP;
5332 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
5335 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
5339 if(!needsTransform) {
5340 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
5341 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
5342 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
5344 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
5345 bottom = (ft_face->glyph->metrics.horiBearingY -
5346 ft_face->glyph->metrics.height) & -64;
5347 lpgm->gmCellIncX = adv;
5348 lpgm->gmCellIncY = 0;
5355 for(xc = 0; xc < 2; xc++) {
5356 for(yc = 0; yc < 2; yc++) {
5357 vec.x = (ft_face->glyph->metrics.horiBearingX +
5358 xc * ft_face->glyph->metrics.width);
5359 vec.y = ft_face->glyph->metrics.horiBearingY -
5360 yc * ft_face->glyph->metrics.height;
5361 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
5362 pFT_Vector_Transform(&vec, &transMat);
5363 if(xc == 0 && yc == 0) {
5364 left = right = vec.x;
5365 top = bottom = vec.y;
5367 if(vec.x < left) left = vec.x;
5368 else if(vec.x > right) right = vec.x;
5369 if(vec.y < bottom) bottom = vec.y;
5370 else if(vec.y > top) top = vec.y;
5375 right = (right + 63) & -64;
5376 bottom = bottom & -64;
5377 top = (top + 63) & -64;
5379 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
5380 vec.x = ft_face->glyph->metrics.horiAdvance;
5382 pFT_Vector_Transform(&vec, &transMat);
5383 lpgm->gmCellIncX = (vec.x+63) >> 6;
5384 lpgm->gmCellIncY = -((vec.y+63) >> 6);
5386 vec.x = ft_face->glyph->metrics.horiAdvance;
5388 pFT_Vector_Transform(&vec, &transMatUnrotated);
5389 adv = (vec.x+63) >> 6;
5393 bbx = (right - left) >> 6;
5394 lpgm->gmBlackBoxX = (right - left) >> 6;
5395 lpgm->gmBlackBoxY = (top - bottom) >> 6;
5396 lpgm->gmptGlyphOrigin.x = left >> 6;
5397 lpgm->gmptGlyphOrigin.y = top >> 6;
5399 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5400 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5401 lpgm->gmCellIncX, lpgm->gmCellIncY);
5403 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
5404 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
5406 FONT_GM(font,original_index)->gm = *lpgm;
5407 FONT_GM(font,original_index)->adv = adv;
5408 FONT_GM(font,original_index)->lsb = lsb;
5409 FONT_GM(font,original_index)->bbx = bbx;
5410 FONT_GM(font,original_index)->init = TRUE;
5413 if(format == GGO_METRICS)
5415 return 1; /* FIXME */
5418 if(ft_face->glyph->format != ft_glyph_format_outline &&
5419 (format == GGO_NATIVE || format == GGO_BEZIER))
5421 TRACE("loaded a bitmap\n");
5427 width = lpgm->gmBlackBoxX;
5428 height = lpgm->gmBlackBoxY;
5429 pitch = ((width + 31) >> 5) << 2;
5430 needed = pitch * height;
5432 if(!buf || !buflen) break;
5434 switch(ft_face->glyph->format) {
5435 case ft_glyph_format_bitmap:
5437 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5438 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
5439 INT h = ft_face->glyph->bitmap.rows;
5441 memcpy(dst, src, w);
5442 src += ft_face->glyph->bitmap.pitch;
5448 case ft_glyph_format_outline:
5449 ft_bitmap.width = width;
5450 ft_bitmap.rows = height;
5451 ft_bitmap.pitch = pitch;
5452 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
5453 ft_bitmap.buffer = buf;
5456 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5458 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5460 /* Note: FreeType will only set 'black' bits for us. */
5461 memset(buf, 0, needed);
5462 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5466 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5471 case GGO_GRAY2_BITMAP:
5472 case GGO_GRAY4_BITMAP:
5473 case GGO_GRAY8_BITMAP:
5474 case WINE_GGO_GRAY16_BITMAP:
5476 unsigned int max_level, row, col;
5479 width = lpgm->gmBlackBoxX;
5480 height = lpgm->gmBlackBoxY;
5481 pitch = (width + 3) / 4 * 4;
5482 needed = pitch * height;
5484 if(!buf || !buflen) break;
5486 max_level = get_max_level( format );
5488 switch(ft_face->glyph->format) {
5489 case ft_glyph_format_bitmap:
5491 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5492 INT h = ft_face->glyph->bitmap.rows;
5494 memset( buf, 0, needed );
5496 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
5497 if (src[x / 8] & masks[x % 8]) dst[x] = max_level;
5498 src += ft_face->glyph->bitmap.pitch;
5503 case ft_glyph_format_outline:
5505 ft_bitmap.width = width;
5506 ft_bitmap.rows = height;
5507 ft_bitmap.pitch = pitch;
5508 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
5509 ft_bitmap.buffer = buf;
5512 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5514 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5516 memset(ft_bitmap.buffer, 0, buflen);
5518 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5520 if (max_level != 255)
5522 for (row = 0, start = buf; row < height; row++)
5524 for (col = 0, ptr = start; col < width; col++, ptr++)
5525 *ptr = (((int)*ptr) * max_level + 128) / 256;
5533 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5539 case WINE_GGO_HRGB_BITMAP:
5540 case WINE_GGO_HBGR_BITMAP:
5541 case WINE_GGO_VRGB_BITMAP:
5542 case WINE_GGO_VBGR_BITMAP:
5543 #ifdef HAVE_FREETYPE_FTLCDFIL_H
5545 switch (ft_face->glyph->format)
5547 case FT_GLYPH_FORMAT_BITMAP:
5552 width = lpgm->gmBlackBoxX;
5553 height = lpgm->gmBlackBoxY;
5555 needed = pitch * height;
5557 if (!buf || !buflen) break;
5559 memset(buf, 0, buflen);
5561 src = ft_face->glyph->bitmap.buffer;
5562 src_pitch = ft_face->glyph->bitmap.pitch;
5564 height = min( height, ft_face->glyph->bitmap.rows );
5567 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
5569 if ( src[x / 8] & masks[x % 8] )
5570 ((unsigned int *)dst)[x] = ~0u;
5579 case FT_GLYPH_FORMAT_OUTLINE:
5583 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
5584 INT x_shift, y_shift;
5586 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
5587 FT_Render_Mode render_mode =
5588 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
5589 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
5591 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
5593 if ( render_mode == FT_RENDER_MODE_LCD)
5595 lpgm->gmBlackBoxX += 2;
5596 lpgm->gmptGlyphOrigin.x -= 1;
5600 lpgm->gmBlackBoxY += 2;
5601 lpgm->gmptGlyphOrigin.y += 1;
5605 width = lpgm->gmBlackBoxX;
5606 height = lpgm->gmBlackBoxY;
5608 needed = pitch * height;
5610 if (!buf || !buflen) break;
5612 memset(buf, 0, buflen);
5614 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
5616 if ( needsTransform )
5617 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
5619 if ( pFT_Library_SetLcdFilter )
5620 pFT_Library_SetLcdFilter( library, lcdfilter );
5621 pFT_Render_Glyph (ft_face->glyph, render_mode);
5623 src = ft_face->glyph->bitmap.buffer;
5624 src_pitch = ft_face->glyph->bitmap.pitch;
5625 src_width = ft_face->glyph->bitmap.width;
5626 src_height = ft_face->glyph->bitmap.rows;
5628 if ( render_mode == FT_RENDER_MODE_LCD)
5636 rgb_interval = src_pitch;
5641 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
5642 if ( x_shift < 0 ) x_shift = 0;
5643 if ( x_shift + (src_width / hmul) > width )
5644 x_shift = width - (src_width / hmul);
5646 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
5647 if ( y_shift < 0 ) y_shift = 0;
5648 if ( y_shift + (src_height / vmul) > height )
5649 y_shift = height - (src_height / vmul);
5651 dst += x_shift + y_shift * ( pitch / 4 );
5652 while ( src_height )
5654 for ( x = 0; x < src_width / hmul; x++ )
5658 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
5659 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5660 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
5661 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5665 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
5666 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5667 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
5668 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5671 src += src_pitch * vmul;
5680 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
5692 int contour, point = 0, first_pt;
5693 FT_Outline *outline = &ft_face->glyph->outline;
5694 TTPOLYGONHEADER *pph;
5696 DWORD pph_start, cpfx, type;
5698 if(buflen == 0) buf = NULL;
5700 if (needsTransform && buf) {
5701 pFT_Outline_Transform(outline, &transMat);
5704 for(contour = 0; contour < outline->n_contours; contour++) {
5706 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5709 pph->dwType = TT_POLYGON_TYPE;
5710 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5712 needed += sizeof(*pph);
5714 while(point <= outline->contours[contour]) {
5715 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5716 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5717 TT_PRIM_LINE : TT_PRIM_QSPLINE;
5721 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5724 } while(point <= outline->contours[contour] &&
5725 (outline->tags[point] & FT_Curve_Tag_On) ==
5726 (outline->tags[point-1] & FT_Curve_Tag_On));
5727 /* At the end of a contour Windows adds the start point, but
5729 if(point > outline->contours[contour] &&
5730 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
5732 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
5734 } else if(point <= outline->contours[contour] &&
5735 outline->tags[point] & FT_Curve_Tag_On) {
5736 /* add closing pt for bezier */
5738 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5746 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5749 pph->cb = needed - pph_start;
5755 /* Convert the quadratic Beziers to cubic Beziers.
5756 The parametric eqn for a cubic Bezier is, from PLRM:
5757 r(t) = at^3 + bt^2 + ct + r0
5758 with the control points:
5763 A quadratic Bezier has the form:
5764 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5766 So equating powers of t leads to:
5767 r1 = 2/3 p1 + 1/3 p0
5768 r2 = 2/3 p1 + 1/3 p2
5769 and of course r0 = p0, r3 = p2
5772 int contour, point = 0, first_pt;
5773 FT_Outline *outline = &ft_face->glyph->outline;
5774 TTPOLYGONHEADER *pph;
5776 DWORD pph_start, cpfx, type;
5777 FT_Vector cubic_control[4];
5778 if(buflen == 0) buf = NULL;
5780 if (needsTransform && buf) {
5781 pFT_Outline_Transform(outline, &transMat);
5784 for(contour = 0; contour < outline->n_contours; contour++) {
5786 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5789 pph->dwType = TT_POLYGON_TYPE;
5790 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5792 needed += sizeof(*pph);
5794 while(point <= outline->contours[contour]) {
5795 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5796 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5797 TT_PRIM_LINE : TT_PRIM_CSPLINE;
5800 if(type == TT_PRIM_LINE) {
5802 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5806 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5809 /* FIXME: Possible optimization in endpoint calculation
5810 if there are two consecutive curves */
5811 cubic_control[0] = outline->points[point-1];
5812 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
5813 cubic_control[0].x += outline->points[point].x + 1;
5814 cubic_control[0].y += outline->points[point].y + 1;
5815 cubic_control[0].x >>= 1;
5816 cubic_control[0].y >>= 1;
5818 if(point+1 > outline->contours[contour])
5819 cubic_control[3] = outline->points[first_pt];
5821 cubic_control[3] = outline->points[point+1];
5822 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
5823 cubic_control[3].x += outline->points[point].x + 1;
5824 cubic_control[3].y += outline->points[point].y + 1;
5825 cubic_control[3].x >>= 1;
5826 cubic_control[3].y >>= 1;
5829 /* r1 = 1/3 p0 + 2/3 p1
5830 r2 = 1/3 p2 + 2/3 p1 */
5831 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
5832 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
5833 cubic_control[2] = cubic_control[1];
5834 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
5835 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
5836 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
5837 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
5839 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
5840 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
5841 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
5846 } while(point <= outline->contours[contour] &&
5847 (outline->tags[point] & FT_Curve_Tag_On) ==
5848 (outline->tags[point-1] & FT_Curve_Tag_On));
5849 /* At the end of a contour Windows adds the start point,
5850 but only for Beziers and we've already done that.
5852 if(point <= outline->contours[contour] &&
5853 outline->tags[point] & FT_Curve_Tag_On) {
5854 /* This is the closing pt of a bezier, but we've already
5855 added it, so just inc point and carry on */
5862 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5865 pph->cb = needed - pph_start;
5871 FIXME("Unsupported format %d\n", format);
5877 static BOOL get_bitmap_text_metrics(GdiFont *font)
5879 FT_Face ft_face = font->ft_face;
5880 FT_WinFNT_HeaderRec winfnt_header;
5881 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
5882 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
5883 font->potm->otmSize = size;
5885 #define TM font->potm->otmTextMetrics
5886 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
5888 TM.tmHeight = winfnt_header.pixel_height;
5889 TM.tmAscent = winfnt_header.ascent;
5890 TM.tmDescent = TM.tmHeight - TM.tmAscent;
5891 TM.tmInternalLeading = winfnt_header.internal_leading;
5892 TM.tmExternalLeading = winfnt_header.external_leading;
5893 TM.tmAveCharWidth = winfnt_header.avg_width;
5894 TM.tmMaxCharWidth = winfnt_header.max_width;
5895 TM.tmWeight = winfnt_header.weight;
5897 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
5898 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
5899 TM.tmFirstChar = winfnt_header.first_char;
5900 TM.tmLastChar = winfnt_header.last_char;
5901 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
5902 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
5903 TM.tmItalic = winfnt_header.italic;
5904 TM.tmUnderlined = font->underline;
5905 TM.tmStruckOut = font->strikeout;
5906 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
5907 TM.tmCharSet = winfnt_header.charset;
5911 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
5912 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
5913 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5914 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
5915 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
5916 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
5917 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
5918 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
5920 TM.tmDigitizedAspectX = 96; /* FIXME */
5921 TM.tmDigitizedAspectY = 96; /* FIXME */
5923 TM.tmLastChar = 255;
5924 TM.tmDefaultChar = 32;
5925 TM.tmBreakChar = 32;
5926 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
5927 TM.tmUnderlined = font->underline;
5928 TM.tmStruckOut = font->strikeout;
5929 /* NB inverted meaning of TMPF_FIXED_PITCH */
5930 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
5931 TM.tmCharSet = font->charset;
5939 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
5941 double scale_x, scale_y;
5945 scale_x = (double)font->aveWidth;
5946 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5949 scale_x = font->scale_y;
5951 scale_x *= fabs(font->font_desc.matrix.eM11);
5952 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5954 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5955 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5957 SCALE_Y(ptm->tmHeight);
5958 SCALE_Y(ptm->tmAscent);
5959 SCALE_Y(ptm->tmDescent);
5960 SCALE_Y(ptm->tmInternalLeading);
5961 SCALE_Y(ptm->tmExternalLeading);
5962 SCALE_Y(ptm->tmOverhang);
5964 SCALE_X(ptm->tmAveCharWidth);
5965 SCALE_X(ptm->tmMaxCharWidth);
5971 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
5973 double scale_x, scale_y;
5977 scale_x = (double)font->aveWidth;
5978 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5981 scale_x = font->scale_y;
5983 scale_x *= fabs(font->font_desc.matrix.eM11);
5984 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5986 scale_font_metrics(font, &potm->otmTextMetrics);
5988 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5989 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5991 SCALE_Y(potm->otmAscent);
5992 SCALE_Y(potm->otmDescent);
5993 SCALE_Y(potm->otmLineGap);
5994 SCALE_Y(potm->otmsCapEmHeight);
5995 SCALE_Y(potm->otmsXHeight);
5996 SCALE_Y(potm->otmrcFontBox.top);
5997 SCALE_Y(potm->otmrcFontBox.bottom);
5998 SCALE_X(potm->otmrcFontBox.left);
5999 SCALE_X(potm->otmrcFontBox.right);
6000 SCALE_Y(potm->otmMacAscent);
6001 SCALE_Y(potm->otmMacDescent);
6002 SCALE_Y(potm->otmMacLineGap);
6003 SCALE_X(potm->otmptSubscriptSize.x);
6004 SCALE_Y(potm->otmptSubscriptSize.y);
6005 SCALE_X(potm->otmptSubscriptOffset.x);
6006 SCALE_Y(potm->otmptSubscriptOffset.y);
6007 SCALE_X(potm->otmptSuperscriptSize.x);
6008 SCALE_Y(potm->otmptSuperscriptSize.y);
6009 SCALE_X(potm->otmptSuperscriptOffset.x);
6010 SCALE_Y(potm->otmptSuperscriptOffset.y);
6011 SCALE_Y(potm->otmsStrikeoutSize);
6012 SCALE_Y(potm->otmsStrikeoutPosition);
6013 SCALE_Y(potm->otmsUnderscoreSize);
6014 SCALE_Y(potm->otmsUnderscorePosition);
6020 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
6024 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
6026 /* Make sure that the font has sane width/height ratio */
6029 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
6031 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
6036 *ptm = font->potm->otmTextMetrics;
6037 scale_font_metrics(font, ptm);
6041 static BOOL face_has_symbol_charmap(FT_Face ft_face)
6045 for(i = 0; i < ft_face->num_charmaps; i++)
6047 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
6053 static BOOL get_outline_text_metrics(GdiFont *font)
6056 FT_Face ft_face = font->ft_face;
6057 UINT needed, lenfam, lensty;
6059 TT_HoriHeader *pHori;
6060 TT_Postscript *pPost;
6061 FT_Fixed x_scale, y_scale;
6062 WCHAR *family_nameW, *style_nameW;
6063 static const WCHAR spaceW[] = {' ', '\0'};
6065 INT ascent, descent;
6067 TRACE("font=%p\n", font);
6069 if(!FT_IS_SCALABLE(ft_face))
6072 needed = sizeof(*font->potm);
6074 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
6075 family_nameW = strdupW(font->name);
6077 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
6079 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
6080 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
6081 style_nameW, lensty/sizeof(WCHAR));
6083 /* These names should be read from the TT name table */
6085 /* length of otmpFamilyName */
6088 /* length of otmpFaceName */
6089 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
6090 needed += lenfam; /* just the family name */
6092 needed += lenfam + lensty; /* family + " " + style */
6095 /* length of otmpStyleName */
6098 /* length of otmpFullName */
6099 needed += lenfam + lensty;
6102 x_scale = ft_face->size->metrics.x_scale;
6103 y_scale = ft_face->size->metrics.y_scale;
6105 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
6107 FIXME("Can't find OS/2 table - not TT font?\n");
6111 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
6113 FIXME("Can't find HHEA table - not TT font?\n");
6117 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
6119 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",
6120 pOS2->usWinAscent, pOS2->usWinDescent,
6121 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
6122 ft_face->ascender, ft_face->descender, ft_face->height,
6123 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
6124 ft_face->bbox.yMax, ft_face->bbox.yMin);
6126 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
6127 font->potm->otmSize = needed;
6129 #define TM font->potm->otmTextMetrics
6131 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
6132 ascent = pHori->Ascender;
6133 descent = -pHori->Descender;
6135 ascent = pOS2->usWinAscent;
6136 descent = pOS2->usWinDescent;
6140 TM.tmAscent = font->yMax;
6141 TM.tmDescent = -font->yMin;
6142 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
6144 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
6145 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
6146 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
6147 - ft_face->units_per_EM, y_scale) + 32) >> 6;
6150 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6153 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6155 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
6156 ((ascent + descent) -
6157 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
6159 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
6160 if (TM.tmAveCharWidth == 0) {
6161 TM.tmAveCharWidth = 1;
6163 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
6164 TM.tmWeight = FW_REGULAR;
6165 if (font->fake_bold)
6166 TM.tmWeight = FW_BOLD;
6169 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
6171 if (pOS2->usWeightClass > FW_MEDIUM)
6172 TM.tmWeight = pOS2->usWeightClass;
6174 else if (pOS2->usWeightClass <= FW_MEDIUM)
6175 TM.tmWeight = pOS2->usWeightClass;
6178 TM.tmDigitizedAspectX = 300;
6179 TM.tmDigitizedAspectY = 300;
6180 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6181 * symbol range to 0 - f0ff
6184 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
6189 case 1257: /* Baltic */
6190 TM.tmLastChar = 0xf8fd;
6193 TM.tmLastChar = 0xf0ff;
6195 TM.tmBreakChar = 0x20;
6196 TM.tmDefaultChar = 0x1f;
6200 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
6201 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
6203 if(pOS2->usFirstCharIndex <= 1)
6204 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
6205 else if (pOS2->usFirstCharIndex > 0xff)
6206 TM.tmBreakChar = 0x20;
6208 TM.tmBreakChar = pOS2->usFirstCharIndex;
6209 TM.tmDefaultChar = TM.tmBreakChar - 1;
6211 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
6212 TM.tmUnderlined = font->underline;
6213 TM.tmStruckOut = font->strikeout;
6215 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6216 if(!FT_IS_FIXED_WIDTH(ft_face) &&
6217 (pOS2->version == 0xFFFFU ||
6218 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
6219 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
6221 TM.tmPitchAndFamily = 0;
6223 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
6225 case PAN_FAMILY_SCRIPT:
6226 TM.tmPitchAndFamily |= FF_SCRIPT;
6229 case PAN_FAMILY_DECORATIVE:
6230 TM.tmPitchAndFamily |= FF_DECORATIVE;
6235 case PAN_FAMILY_TEXT_DISPLAY:
6236 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
6237 /* which is clearly not what the panose spec says. */
6239 if(TM.tmPitchAndFamily == 0 || /* fixed */
6240 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
6241 TM.tmPitchAndFamily = FF_MODERN;
6244 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
6249 TM.tmPitchAndFamily |= FF_DONTCARE;
6252 case PAN_SERIF_COVE:
6253 case PAN_SERIF_OBTUSE_COVE:
6254 case PAN_SERIF_SQUARE_COVE:
6255 case PAN_SERIF_OBTUSE_SQUARE_COVE:
6256 case PAN_SERIF_SQUARE:
6257 case PAN_SERIF_THIN:
6258 case PAN_SERIF_BONE:
6259 case PAN_SERIF_EXAGGERATED:
6260 case PAN_SERIF_TRIANGLE:
6261 TM.tmPitchAndFamily |= FF_ROMAN;
6264 case PAN_SERIF_NORMAL_SANS:
6265 case PAN_SERIF_OBTUSE_SANS:
6266 case PAN_SERIF_PERP_SANS:
6267 case PAN_SERIF_FLARED:
6268 case PAN_SERIF_ROUNDED:
6269 TM.tmPitchAndFamily |= FF_SWISS;
6276 if(FT_IS_SCALABLE(ft_face))
6277 TM.tmPitchAndFamily |= TMPF_VECTOR;
6279 if(FT_IS_SFNT(ft_face))
6281 if (font->ntmFlags & NTM_PS_OPENTYPE)
6282 TM.tmPitchAndFamily |= TMPF_DEVICE;
6284 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
6287 TM.tmCharSet = font->charset;
6289 font->potm->otmFiller = 0;
6290 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
6291 font->potm->otmfsSelection = pOS2->fsSelection;
6292 font->potm->otmfsType = pOS2->fsType;
6293 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
6294 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
6295 font->potm->otmItalicAngle = 0; /* POST table */
6296 font->potm->otmEMSquare = ft_face->units_per_EM;
6297 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
6298 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
6299 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
6300 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
6301 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
6302 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
6303 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
6304 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
6305 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
6306 font->potm->otmMacAscent = TM.tmAscent;
6307 font->potm->otmMacDescent = -TM.tmDescent;
6308 font->potm->otmMacLineGap = font->potm->otmLineGap;
6309 font->potm->otmusMinimumPPEM = 0; /* TT Header */
6310 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
6311 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
6312 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
6313 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
6314 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
6315 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
6316 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
6317 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
6318 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
6319 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
6321 font->potm->otmsUnderscoreSize = 0;
6322 font->potm->otmsUnderscorePosition = 0;
6324 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
6325 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
6329 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
6330 cp = (char*)font->potm + sizeof(*font->potm);
6331 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
6332 strcpyW((WCHAR*)cp, family_nameW);
6334 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
6335 strcpyW((WCHAR*)cp, style_nameW);
6337 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
6338 strcpyW((WCHAR*)cp, family_nameW);
6339 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
6340 strcatW((WCHAR*)cp, spaceW);
6341 strcatW((WCHAR*)cp, style_nameW);
6342 cp += lenfam + lensty;
6345 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
6346 strcpyW((WCHAR*)cp, family_nameW);
6347 strcatW((WCHAR*)cp, spaceW);
6348 strcatW((WCHAR*)cp, style_nameW);
6352 HeapFree(GetProcessHeap(), 0, style_nameW);
6353 HeapFree(GetProcessHeap(), 0, family_nameW);
6357 /*************************************************************
6358 * freetype_GetGlyphOutline
6360 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
6361 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
6363 struct freetype_physdev *physdev = get_freetype_dev( dev );
6368 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
6369 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
6373 EnterCriticalSection( &freetype_cs );
6374 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, buflen, buf, lpmat );
6375 LeaveCriticalSection( &freetype_cs );
6379 /*************************************************************
6380 * freetype_GetTextMetrics
6382 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
6384 struct freetype_physdev *physdev = get_freetype_dev( dev );
6389 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
6390 return dev->funcs->pGetTextMetrics( dev, metrics );
6394 EnterCriticalSection( &freetype_cs );
6395 ret = get_text_metrics( physdev->font, metrics );
6396 LeaveCriticalSection( &freetype_cs );
6400 /*************************************************************
6401 * freetype_GetOutlineTextMetrics
6403 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
6405 struct freetype_physdev *physdev = get_freetype_dev( dev );
6410 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
6411 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
6414 TRACE("font=%p\n", physdev->font);
6416 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
6419 EnterCriticalSection( &freetype_cs );
6421 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
6423 if(cbSize >= physdev->font->potm->otmSize)
6425 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
6426 scale_outline_font_metrics(physdev->font, potm);
6428 ret = physdev->font->potm->otmSize;
6430 LeaveCriticalSection( &freetype_cs );
6434 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
6436 HFONTLIST *hfontlist;
6437 child->font = alloc_font();
6438 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
6439 if(!child->font->ft_face)
6441 free_font(child->font);
6446 child->font->font_desc = font->font_desc;
6447 child->font->ntmFlags = child->face->ntmFlags;
6448 child->font->orientation = font->orientation;
6449 child->font->scale_y = font->scale_y;
6450 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
6451 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
6452 child->font->name = strdupW(child->face->family->FamilyName);
6453 list_add_head(&child->font->hfontlist, &hfontlist->entry);
6454 child->font->base_font = font;
6455 list_add_head(&child_font_list, &child->font->entry);
6456 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
6460 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
6463 CHILD_FONT *child_font;
6466 font = font->base_font;
6468 *linked_font = font;
6470 if((*glyph = get_glyph_index(font, c)))
6472 *glyph = get_GSUB_vert_glyph(font, *glyph);
6476 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
6478 if(!child_font->font)
6479 if(!load_child_font(font, child_font))
6482 if(!child_font->font->ft_face)
6484 g = get_glyph_index(child_font->font, c);
6485 g = get_GSUB_vert_glyph(child_font->font, g);
6489 *linked_font = child_font->font;
6496 /*************************************************************
6497 * freetype_GetCharWidth
6499 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
6501 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6504 FT_UInt glyph_index;
6505 GdiFont *linked_font;
6506 struct freetype_physdev *physdev = get_freetype_dev( dev );
6510 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
6511 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
6514 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
6517 EnterCriticalSection( &freetype_cs );
6518 for(c = firstChar; c <= lastChar; c++) {
6519 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
6520 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6521 &gm, 0, NULL, &identity);
6522 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
6524 LeaveCriticalSection( &freetype_cs );
6528 /*************************************************************
6529 * freetype_GetCharABCWidths
6531 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
6533 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6536 FT_UInt glyph_index;
6537 GdiFont *linked_font;
6538 struct freetype_physdev *physdev = get_freetype_dev( dev );
6542 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
6543 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
6546 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
6549 EnterCriticalSection( &freetype_cs );
6551 for(c = firstChar; c <= lastChar; c++) {
6552 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
6553 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6554 &gm, 0, NULL, &identity);
6555 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
6556 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
6557 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
6558 FONT_GM(linked_font,glyph_index)->bbx;
6560 LeaveCriticalSection( &freetype_cs );
6564 /*************************************************************
6565 * freetype_GetCharABCWidthsI
6567 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
6569 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6572 FT_UInt glyph_index;
6573 GdiFont *linked_font;
6574 struct freetype_physdev *physdev = get_freetype_dev( dev );
6578 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
6579 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
6582 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
6586 EnterCriticalSection( &freetype_cs );
6588 get_glyph_index_linked(physdev->font, 'a', &linked_font, &glyph_index);
6590 for(c = firstChar; c < firstChar+count; c++) {
6591 get_glyph_outline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
6592 &gm, 0, NULL, &identity);
6593 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
6594 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
6595 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
6596 - FONT_GM(linked_font,c)->bbx;
6599 for(c = 0; c < count; c++) {
6600 get_glyph_outline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
6601 &gm, 0, NULL, &identity);
6602 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
6603 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
6604 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
6605 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
6608 LeaveCriticalSection( &freetype_cs );
6612 /*************************************************************
6613 * freetype_GetTextExtentExPoint
6615 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count,
6616 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6618 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6623 FT_UInt glyph_index;
6624 GdiFont *linked_font;
6625 struct freetype_physdev *physdev = get_freetype_dev( dev );
6629 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
6630 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, max_ext, pnfit, dxs, size );
6633 TRACE("%p, %s, %d, %d, %p\n", physdev->font, debugstr_wn(wstr, count), count, max_ext, size);
6636 EnterCriticalSection( &freetype_cs );
6639 get_text_metrics( physdev->font, &tm );
6640 size->cy = tm.tmHeight;
6642 for(idx = 0; idx < count; idx++) {
6643 get_glyph_index_linked( physdev->font, wstr[idx], &linked_font, &glyph_index );
6644 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6645 &gm, 0, NULL, &identity);
6646 size->cx += FONT_GM(linked_font,glyph_index)->adv;
6648 if (! pnfit || ext <= max_ext) {
6658 LeaveCriticalSection( &freetype_cs );
6659 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6663 /*************************************************************
6664 * freetype_GetTextExtentExPointI
6666 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count,
6667 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size )
6669 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6674 struct freetype_physdev *physdev = get_freetype_dev( dev );
6678 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
6679 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, max_ext, pnfit, dxs, size );
6682 TRACE("%p, %p, %d, %d, %p\n", physdev->font, indices, count, max_ext, size);
6685 EnterCriticalSection( &freetype_cs );
6688 get_text_metrics(physdev->font, &tm);
6689 size->cy = tm.tmHeight;
6691 for(idx = 0; idx < count; idx++) {
6692 get_glyph_outline(physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &identity);
6693 size->cx += FONT_GM(physdev->font,indices[idx])->adv;
6695 if (! pnfit || ext <= max_ext) {
6705 LeaveCriticalSection( &freetype_cs );
6706 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6710 /*************************************************************
6711 * freetype_GetFontData
6713 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
6715 struct freetype_physdev *physdev = get_freetype_dev( dev );
6719 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
6720 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
6723 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6724 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
6725 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
6727 return get_font_data( physdev->font, table, offset, buf, cbData );
6730 /*************************************************************
6731 * freetype_GetTextFace
6733 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
6736 struct freetype_physdev *physdev = get_freetype_dev( dev );
6740 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
6741 return dev->funcs->pGetTextFace( dev, count, str );
6744 n = strlenW(physdev->font->name) + 1;
6747 lstrcpynW(str, physdev->font->name, count);
6753 /*************************************************************
6754 * freetype_GetTextCharsetInfo
6756 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
6758 struct freetype_physdev *physdev = get_freetype_dev( dev );
6762 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
6763 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
6765 if (fs) *fs = physdev->font->fs;
6766 return physdev->font->charset;
6769 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6771 GdiFont *font = dc->gdiFont, *linked_font;
6772 struct list *first_hfont;
6776 EnterCriticalSection( &freetype_cs );
6777 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
6778 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
6779 if(font == linked_font)
6780 *new_hfont = dc->hFont;
6783 first_hfont = list_head(&linked_font->hfontlist);
6784 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
6786 LeaveCriticalSection( &freetype_cs );
6790 /* Retrieve a list of supported Unicode ranges for a given font.
6791 * Can be called with NULL gs to calculate the buffer size. Returns
6792 * the number of ranges found.
6794 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
6796 DWORD num_ranges = 0;
6798 if (face->charmap->encoding == FT_ENCODING_UNICODE)
6801 FT_ULong char_code, char_code_prev;
6804 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
6806 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6807 face->num_glyphs, glyph_code, char_code);
6809 if (!glyph_code) return 0;
6813 gs->ranges[0].wcLow = (USHORT)char_code;
6814 gs->ranges[0].cGlyphs = 0;
6815 gs->cGlyphsSupported = 0;
6821 if (char_code < char_code_prev)
6823 ERR("expected increasing char code from FT_Get_Next_Char\n");
6826 if (char_code - char_code_prev > 1)
6831 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
6832 gs->ranges[num_ranges - 1].cGlyphs = 1;
6833 gs->cGlyphsSupported++;
6838 gs->ranges[num_ranges - 1].cGlyphs++;
6839 gs->cGlyphsSupported++;
6841 char_code_prev = char_code;
6842 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
6846 FIXME("encoding %u not supported\n", face->charmap->encoding);
6851 /*************************************************************
6852 * freetype_GetFontUnicodeRanges
6854 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
6856 struct freetype_physdev *physdev = get_freetype_dev( dev );
6857 DWORD size, num_ranges;
6861 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
6862 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
6865 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
6866 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
6869 glyphset->cbThis = size;
6870 glyphset->cRanges = num_ranges;
6871 glyphset->flAccel = 0;
6876 /*************************************************************
6877 * freetype_FontIsLinked
6879 static BOOL freetype_FontIsLinked( PHYSDEV dev )
6881 struct freetype_physdev *physdev = get_freetype_dev( dev );
6886 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
6887 return dev->funcs->pFontIsLinked( dev );
6891 EnterCriticalSection( &freetype_cs );
6892 ret = !list_empty(&physdev->font->child_fonts);
6893 LeaveCriticalSection( &freetype_cs );
6897 static BOOL is_hinting_enabled(void)
6899 /* Use the >= 2.2.0 function if available */
6900 if(pFT_Get_TrueType_Engine_Type)
6902 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
6903 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
6905 #ifdef FT_DRIVER_HAS_HINTER
6910 /* otherwise if we've been compiled with < 2.2.0 headers
6911 use the internal macro */
6912 mod = pFT_Get_Module(library, "truetype");
6913 if(mod && FT_DRIVER_HAS_HINTER(mod))
6921 static BOOL is_subpixel_rendering_enabled( void )
6923 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6924 return pFT_Library_SetLcdFilter &&
6925 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
6931 /*************************************************************************
6932 * GetRasterizerCaps (GDI32.@)
6934 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6936 static int hinting = -1;
6937 static int subpixel = -1;
6941 hinting = is_hinting_enabled();
6942 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
6945 if ( subpixel == -1 )
6947 subpixel = is_subpixel_rendering_enabled();
6948 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
6951 lprs->nSize = sizeof(RASTERIZER_STATUS);
6952 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
6954 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
6955 lprs->nLanguageID = 0;
6959 /*************************************************************
6960 * freetype_GdiRealizationInfo
6962 static BOOL freetype_GdiRealizationInfo( PHYSDEV dev, void *ptr )
6964 struct freetype_physdev *physdev = get_freetype_dev( dev );
6965 realization_info_t *info = ptr;
6969 dev = GET_NEXT_PHYSDEV( dev, pGdiRealizationInfo );
6970 return dev->funcs->pGdiRealizationInfo( dev, ptr );
6973 FIXME("(%p, %p): stub!\n", physdev->font, info);
6976 if(FT_IS_SCALABLE(physdev->font->ft_face))
6979 info->cache_num = physdev->font->cache_num;
6980 info->unknown2 = -1;
6984 /*************************************************************************
6985 * Kerning support for TrueType fonts
6987 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
6989 struct TT_kern_table
6995 struct TT_kern_subtable
7004 USHORT horizontal : 1;
7006 USHORT cross_stream: 1;
7007 USHORT override : 1;
7008 USHORT reserved1 : 4;
7014 struct TT_format0_kern_subtable
7018 USHORT entrySelector;
7029 static DWORD parse_format0_kern_subtable(GdiFont *font,
7030 const struct TT_format0_kern_subtable *tt_f0_ks,
7031 const USHORT *glyph_to_char,
7032 KERNINGPAIR *kern_pair, DWORD cPairs)
7035 const struct TT_kern_pair *tt_kern_pair;
7037 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
7039 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
7041 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7042 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
7043 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
7045 if (!kern_pair || !cPairs)
7048 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
7050 nPairs = min(nPairs, cPairs);
7052 for (i = 0; i < nPairs; i++)
7054 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
7055 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
7056 /* this algorithm appears to better match what Windows does */
7057 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
7058 if (kern_pair->iKernAmount < 0)
7060 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
7061 kern_pair->iKernAmount -= font->ppem;
7063 else if (kern_pair->iKernAmount > 0)
7065 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
7066 kern_pair->iKernAmount += font->ppem;
7068 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
7070 TRACE("left %u right %u value %d\n",
7071 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
7075 TRACE("copied %u entries\n", nPairs);
7079 /*************************************************************
7080 * freetype_GetKerningPairs
7082 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
7086 const struct TT_kern_table *tt_kern_table;
7087 const struct TT_kern_subtable *tt_kern_subtable;
7089 USHORT *glyph_to_char;
7091 struct freetype_physdev *physdev = get_freetype_dev( dev );
7093 if (!(font = physdev->font))
7095 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
7096 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
7100 EnterCriticalSection( &freetype_cs );
7101 if (font->total_kern_pairs != (DWORD)-1)
7103 if (cPairs && kern_pair)
7105 cPairs = min(cPairs, font->total_kern_pairs);
7106 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7108 else cPairs = font->total_kern_pairs;
7110 LeaveCriticalSection( &freetype_cs );
7114 font->total_kern_pairs = 0;
7116 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
7118 if (length == GDI_ERROR)
7120 TRACE("no kerning data in the font\n");
7121 LeaveCriticalSection( &freetype_cs );
7125 buf = HeapAlloc(GetProcessHeap(), 0, length);
7128 WARN("Out of memory\n");
7129 LeaveCriticalSection( &freetype_cs );
7133 get_font_data(font, MS_KERN_TAG, 0, buf, length);
7135 /* build a glyph index to char code map */
7136 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
7139 WARN("Out of memory allocating a glyph index to char code map\n");
7140 HeapFree(GetProcessHeap(), 0, buf);
7141 LeaveCriticalSection( &freetype_cs );
7145 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
7151 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
7153 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7154 font->ft_face->num_glyphs, glyph_code, char_code);
7158 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7160 /* FIXME: This doesn't match what Windows does: it does some fancy
7161 * things with duplicate glyph index to char code mappings, while
7162 * we just avoid overriding existing entries.
7164 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
7165 glyph_to_char[glyph_code] = (USHORT)char_code;
7167 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
7174 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
7175 for (n = 0; n <= 65535; n++)
7176 glyph_to_char[n] = (USHORT)n;
7179 tt_kern_table = buf;
7180 nTables = GET_BE_WORD(tt_kern_table->nTables);
7181 TRACE("version %u, nTables %u\n",
7182 GET_BE_WORD(tt_kern_table->version), nTables);
7184 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
7186 for (i = 0; i < nTables; i++)
7188 struct TT_kern_subtable tt_kern_subtable_copy;
7190 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
7191 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
7192 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
7194 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7195 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
7196 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
7198 /* According to the TrueType specification this is the only format
7199 * that will be properly interpreted by Windows and OS/2
7201 if (tt_kern_subtable_copy.coverage.bits.format == 0)
7203 DWORD new_chunk, old_total = font->total_kern_pairs;
7205 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7206 glyph_to_char, NULL, 0);
7207 font->total_kern_pairs += new_chunk;
7209 if (!font->kern_pairs)
7210 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
7211 font->total_kern_pairs * sizeof(*font->kern_pairs));
7213 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
7214 font->total_kern_pairs * sizeof(*font->kern_pairs));
7216 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7217 glyph_to_char, font->kern_pairs + old_total, new_chunk);
7220 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
7222 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
7225 HeapFree(GetProcessHeap(), 0, glyph_to_char);
7226 HeapFree(GetProcessHeap(), 0, buf);
7228 if (cPairs && kern_pair)
7230 cPairs = min(cPairs, font->total_kern_pairs);
7231 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7233 else cPairs = font->total_kern_pairs;
7235 LeaveCriticalSection( &freetype_cs );
7239 static const struct gdi_dc_funcs freetype_funcs =
7241 NULL, /* pAbortDoc */
7242 NULL, /* pAbortPath */
7243 NULL, /* pAlphaBlend */
7244 NULL, /* pAngleArc */
7247 NULL, /* pBeginPath */
7248 NULL, /* pBlendImage */
7249 NULL, /* pChoosePixelFormat */
7251 NULL, /* pCloseFigure */
7252 NULL, /* pCopyBitmap */
7253 NULL, /* pCreateBitmap */
7254 NULL, /* pCreateCompatibleDC */
7255 freetype_CreateDC, /* pCreateDC */
7256 NULL, /* pDeleteBitmap */
7257 freetype_DeleteDC, /* pDeleteDC */
7258 NULL, /* pDeleteObject */
7259 NULL, /* pDescribePixelFormat */
7260 NULL, /* pDeviceCapabilities */
7261 NULL, /* pEllipse */
7263 NULL, /* pEndPage */
7264 NULL, /* pEndPath */
7265 freetype_EnumFonts, /* pEnumFonts */
7266 NULL, /* pEnumICMProfiles */
7267 NULL, /* pExcludeClipRect */
7268 NULL, /* pExtDeviceMode */
7269 NULL, /* pExtEscape */
7270 NULL, /* pExtFloodFill */
7271 NULL, /* pExtSelectClipRgn */
7272 NULL, /* pExtTextOut */
7273 NULL, /* pFillPath */
7274 NULL, /* pFillRgn */
7275 NULL, /* pFlattenPath */
7276 freetype_FontIsLinked, /* pFontIsLinked */
7277 NULL, /* pFrameRgn */
7278 NULL, /* pGdiComment */
7279 freetype_GdiRealizationInfo, /* pGdiRealizationInfo */
7280 freetype_GetCharABCWidths, /* pGetCharABCWidths */
7281 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
7282 freetype_GetCharWidth, /* pGetCharWidth */
7283 NULL, /* pGetDeviceCaps */
7284 NULL, /* pGetDeviceGammaRamp */
7285 freetype_GetFontData, /* pGetFontData */
7286 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
7287 freetype_GetGlyphIndices, /* pGetGlyphIndices */
7288 freetype_GetGlyphOutline, /* pGetGlyphOutline */
7289 NULL, /* pGetICMProfile */
7290 NULL, /* pGetImage */
7291 freetype_GetKerningPairs, /* pGetKerningPairs */
7292 NULL, /* pGetNearestColor */
7293 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
7294 NULL, /* pGetPixel */
7295 NULL, /* pGetPixelFormat */
7296 NULL, /* pGetSystemPaletteEntries */
7297 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
7298 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
7299 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
7300 freetype_GetTextFace, /* pGetTextFace */
7301 freetype_GetTextMetrics, /* pGetTextMetrics */
7302 NULL, /* pGradientFill */
7303 NULL, /* pIntersectClipRect */
7304 NULL, /* pInvertRgn */
7306 NULL, /* pModifyWorldTransform */
7308 NULL, /* pOffsetClipRgn */
7309 NULL, /* pOffsetViewportOrg */
7310 NULL, /* pOffsetWindowOrg */
7311 NULL, /* pPaintRgn */
7314 NULL, /* pPolyBezier */
7315 NULL, /* pPolyBezierTo */
7316 NULL, /* pPolyDraw */
7317 NULL, /* pPolyPolygon */
7318 NULL, /* pPolyPolyline */
7319 NULL, /* pPolygon */
7320 NULL, /* pPolyline */
7321 NULL, /* pPolylineTo */
7322 NULL, /* pPutImage */
7323 NULL, /* pRealizeDefaultPalette */
7324 NULL, /* pRealizePalette */
7325 NULL, /* pRectangle */
7326 NULL, /* pResetDC */
7327 NULL, /* pRestoreDC */
7328 NULL, /* pRoundRect */
7330 NULL, /* pScaleViewportExt */
7331 NULL, /* pScaleWindowExt */
7332 NULL, /* pSelectBitmap */
7333 NULL, /* pSelectBrush */
7334 NULL, /* pSelectClipPath */
7335 freetype_SelectFont, /* pSelectFont */
7336 NULL, /* pSelectPalette */
7337 NULL, /* pSelectPen */
7338 NULL, /* pSetArcDirection */
7339 NULL, /* pSetBkColor */
7340 NULL, /* pSetBkMode */
7341 NULL, /* pSetDCBrushColor */
7342 NULL, /* pSetDCPenColor */
7343 NULL, /* pSetDIBColorTable */
7344 NULL, /* pSetDIBitsToDevice */
7345 NULL, /* pSetDeviceClipping */
7346 NULL, /* pSetDeviceGammaRamp */
7347 NULL, /* pSetLayout */
7348 NULL, /* pSetMapMode */
7349 NULL, /* pSetMapperFlags */
7350 NULL, /* pSetPixel */
7351 NULL, /* pSetPixelFormat */
7352 NULL, /* pSetPolyFillMode */
7353 NULL, /* pSetROP2 */
7354 NULL, /* pSetRelAbs */
7355 NULL, /* pSetStretchBltMode */
7356 NULL, /* pSetTextAlign */
7357 NULL, /* pSetTextCharacterExtra */
7358 NULL, /* pSetTextColor */
7359 NULL, /* pSetTextJustification */
7360 NULL, /* pSetViewportExt */
7361 NULL, /* pSetViewportOrg */
7362 NULL, /* pSetWindowExt */
7363 NULL, /* pSetWindowOrg */
7364 NULL, /* pSetWorldTransform */
7365 NULL, /* pStartDoc */
7366 NULL, /* pStartPage */
7367 NULL, /* pStretchBlt */
7368 NULL, /* pStretchDIBits */
7369 NULL, /* pStrokeAndFillPath */
7370 NULL, /* pStrokePath */
7371 NULL, /* pSwapBuffers */
7372 NULL, /* pUnrealizePalette */
7373 NULL, /* pWidenPath */
7374 /* OpenGL not supported */
7377 #else /* HAVE_FREETYPE */
7379 /*************************************************************************/
7381 BOOL WineEngInit(void)
7385 BOOL WineEngDestroyFontInstance(HFONT hfont)
7390 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7392 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7396 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7398 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7402 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
7404 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
7408 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
7413 /*************************************************************************
7414 * GetRasterizerCaps (GDI32.@)
7416 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7418 lprs->nSize = sizeof(RASTERIZER_STATUS);
7420 lprs->nLanguageID = 0;
7424 #endif /* HAVE_FREETYPE */