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 /****************************************
536 * Notes on .fon files
538 * The fonts System, FixedSys and Terminal are special. There are typically multiple
539 * versions installed for different resolutions and codepages. Windows stores which one to use
540 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
542 * FIXEDFON.FON FixedSys
544 * OEMFONT.FON Terminal
545 * LogPixels Current dpi set by the display control panel applet
546 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
547 * also has a LogPixels value that appears to mirror this)
549 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
550 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
551 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
552 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
553 * so that makes sense.
555 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
556 * to be mapped into the registry on Windows 2000 at least).
559 * ega80woa.fon=ega80850.fon
560 * ega40woa.fon=ega40850.fon
561 * cga80woa.fon=cga80850.fon
562 * cga40woa.fon=cga40850.fon
565 /* These are all structures needed for the GSUB table */
567 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
568 #define TATEGAKI_LOWER_BOUND 0x02F1
584 GSUB_ScriptRecord ScriptRecord[1];
590 } GSUB_LangSysRecord;
595 GSUB_LangSysRecord LangSysRecord[1];
599 WORD LookupOrder; /* Reserved */
600 WORD ReqFeatureIndex;
602 WORD FeatureIndex[1];
608 } GSUB_FeatureRecord;
612 GSUB_FeatureRecord FeatureRecord[1];
616 WORD FeatureParams; /* Reserved */
618 WORD LookupListIndex[1];
637 } GSUB_CoverageFormat1;
642 WORD StartCoverageIndex;
648 GSUB_RangeRecord RangeRecord[1];
649 } GSUB_CoverageFormat2;
652 WORD SubstFormat; /* = 1 */
655 } GSUB_SingleSubstFormat1;
658 WORD SubstFormat; /* = 2 */
662 }GSUB_SingleSubstFormat2;
664 #ifdef HAVE_CARBON_CARBON_H
665 static char *find_cache_dir(void)
669 static char cached_path[MAX_PATH];
670 static const char *wine = "/Wine", *fonts = "/Fonts";
672 if(*cached_path) return cached_path;
674 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
677 WARN("can't create cached data folder\n");
680 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
683 WARN("can't create cached data path\n");
687 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
689 ERR("Could not create full path\n");
693 strcat(cached_path, wine);
695 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
697 WARN("Couldn't mkdir %s\n", cached_path);
701 strcat(cached_path, fonts);
702 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
704 WARN("Couldn't mkdir %s\n", cached_path);
711 /******************************************************************
714 * Extracts individual TrueType font files from a Mac suitcase font
715 * and saves them into the user's caches directory (see
717 * Returns a NULL terminated array of filenames.
719 * We do this because they are apps that try to read ttf files
720 * themselves and they don't like Mac suitcase files.
722 static char **expand_mac_font(const char *path)
729 const char *filename;
733 unsigned int size, max_size;
736 TRACE("path %s\n", path);
738 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
741 WARN("failed to get ref\n");
745 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
748 TRACE("no data fork, so trying resource fork\n");
749 res_ref = FSOpenResFile(&ref, fsRdPerm);
752 TRACE("unable to open resource fork\n");
759 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
762 CloseResFile(res_ref);
766 out_dir = find_cache_dir();
768 filename = strrchr(path, '/');
769 if(!filename) filename = path;
772 /* output filename has the form out_dir/filename_%04x.ttf */
773 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
780 unsigned short *num_faces_ptr, num_faces, face;
783 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
785 fond = Get1IndResource(fond_res, idx);
787 TRACE("got fond resource %d\n", idx);
790 fam_rec = *(FamRec**)fond;
791 num_faces_ptr = (unsigned short *)(fam_rec + 1);
792 num_faces = GET_BE_WORD(*num_faces_ptr);
794 assoc = (AsscEntry*)(num_faces_ptr + 1);
795 TRACE("num faces %04x\n", num_faces);
796 for(face = 0; face < num_faces; face++, assoc++)
799 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
800 unsigned short size, font_id;
803 size = GET_BE_WORD(assoc->fontSize);
804 font_id = GET_BE_WORD(assoc->fontID);
807 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
811 TRACE("trying to load sfnt id %04x\n", font_id);
812 sfnt = GetResource(sfnt_res, font_id);
815 TRACE("can't get sfnt resource %04x\n", font_id);
819 output = HeapAlloc(GetProcessHeap(), 0, output_len);
824 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
826 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
827 if(fd != -1 || errno == EEXIST)
831 unsigned char *sfnt_data;
834 sfnt_data = *(unsigned char**)sfnt;
835 write(fd, sfnt_data, GetHandleSize(sfnt));
839 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
842 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
844 ret.array[ret.size++] = output;
848 WARN("unable to create %s\n", output);
849 HeapFree(GetProcessHeap(), 0, output);
852 ReleaseResource(sfnt);
855 ReleaseResource(fond);
858 CloseResFile(res_ref);
863 #endif /* HAVE_CARBON_CARBON_H */
865 static inline BOOL is_win9x(void)
867 return GetVersion() & 0x80000000;
870 This function builds an FT_Fixed from a double. It fails if the absolute
871 value of the float number is greater than 32768.
873 static inline FT_Fixed FT_FixedFromFloat(double f)
879 This function builds an FT_Fixed from a FIXED. It simply put f.value
880 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
882 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
884 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
888 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
893 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
894 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
896 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
897 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
899 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
901 if(face_name && strcmpiW(face_name, family->FamilyName))
903 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
907 file = strrchr(face->file, '/');
912 if(!strcasecmp(file, file_nameA))
914 HeapFree(GetProcessHeap(), 0, file_nameA);
919 HeapFree(GetProcessHeap(), 0, file_nameA);
923 static Family *find_family_from_name(const WCHAR *name)
927 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
929 if(!strcmpiW(family->FamilyName, name))
936 static void DumpSubstList(void)
940 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
942 if(psub->from.charset != -1 || psub->to.charset != -1)
943 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
944 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
946 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
947 debugstr_w(psub->to.name));
952 static LPWSTR strdupW(LPCWSTR p)
955 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
956 ret = HeapAlloc(GetProcessHeap(), 0, len);
961 static LPSTR strdupA(LPCSTR p)
964 DWORD len = (strlen(p) + 1);
965 ret = HeapAlloc(GetProcessHeap(), 0, len);
970 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
975 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
977 if(!strcmpiW(element->from.name, from_name) &&
978 (element->from.charset == from_charset ||
979 element->from.charset == -1))
986 #define ADD_FONT_SUBST_FORCE 1
988 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
990 FontSubst *from_exist, *to_exist;
992 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
994 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
996 list_remove(&from_exist->entry);
997 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
998 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
999 HeapFree(GetProcessHeap(), 0, from_exist);
1005 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
1009 HeapFree(GetProcessHeap(), 0, subst->to.name);
1010 subst->to.name = strdupW(to_exist->to.name);
1013 list_add_tail(subst_list, &subst->entry);
1018 HeapFree(GetProcessHeap(), 0, subst->from.name);
1019 HeapFree(GetProcessHeap(), 0, subst->to.name);
1020 HeapFree(GetProcessHeap(), 0, subst);
1024 static WCHAR *towstr(UINT cp, const char *str)
1029 len = MultiByteToWideChar(cp, 0, str, -1, NULL, 0);
1030 wstr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1031 MultiByteToWideChar(cp, 0, str, -1, wstr, len);
1035 static void split_subst_info(NameCs *nc, LPSTR str)
1037 CHAR *p = strrchr(str, ',');
1041 nc->charset = strtol(p+1, NULL, 10);
1044 nc->name = towstr(CP_ACP, str);
1047 static void LoadSubstList(void)
1051 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1055 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1056 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1057 &hkey) == ERROR_SUCCESS) {
1059 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1060 &valuelen, &datalen, NULL, NULL);
1062 valuelen++; /* returned value doesn't include room for '\0' */
1063 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1064 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1068 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1069 &dlen) == ERROR_SUCCESS) {
1070 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1072 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1073 split_subst_info(&psub->from, value);
1074 split_subst_info(&psub->to, data);
1076 /* Win 2000 doesn't allow mapping between different charsets
1077 or mapping of DEFAULT_CHARSET */
1078 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1079 psub->to.charset == DEFAULT_CHARSET) {
1080 HeapFree(GetProcessHeap(), 0, psub->to.name);
1081 HeapFree(GetProcessHeap(), 0, psub->from.name);
1082 HeapFree(GetProcessHeap(), 0, psub);
1084 add_font_subst(&font_subst_list, psub, 0);
1086 /* reset dlen and vlen */
1090 HeapFree(GetProcessHeap(), 0, data);
1091 HeapFree(GetProcessHeap(), 0, value);
1097 /*****************************************************************
1098 * get_name_table_entry
1100 * Supply the platform, encoding, language and name ids in req
1101 * and if the name exists the function will fill in the string
1102 * and string_len members. The string is owned by FreeType so
1103 * don't free it. Returns TRUE if the name is found else FALSE.
1105 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1108 FT_UInt num_names, name_index;
1110 if(FT_IS_SFNT(ft_face))
1112 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1114 for(name_index = 0; name_index < num_names; name_index++)
1116 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1118 if((name.platform_id == req->platform_id) &&
1119 (name.encoding_id == req->encoding_id) &&
1120 (name.language_id == req->language_id) &&
1121 (name.name_id == req->name_id))
1123 req->string = name.string;
1124 req->string_len = name.string_len;
1131 req->string_len = 0;
1135 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, FT_UShort language_id)
1140 name.platform_id = TT_PLATFORM_MICROSOFT;
1141 name.encoding_id = TT_MS_ID_UNICODE_CS;
1142 name.language_id = language_id;
1143 name.name_id = name_id;
1145 if(get_name_table_entry(ft_face, &name))
1149 /* String is not nul terminated and string_len is a byte length. */
1150 ret = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1151 for(i = 0; i < name.string_len / 2; i++)
1153 WORD *tmp = (WORD *)&name.string[i * 2];
1154 ret[i] = GET_BE_WORD(*tmp);
1157 TRACE("Got localised name %s\n", debugstr_w(ret));
1163 static LONG reg_load_dword(HKEY hkey, const WCHAR *value, DWORD *data)
1166 LONG r = RegQueryValueExW(hkey, value, NULL, &type, NULL, &needed);
1167 if(r != ERROR_SUCCESS) return r;
1168 if(type != REG_DWORD || needed != sizeof(DWORD)) return ERROR_BAD_CONFIGURATION;
1169 return RegQueryValueExW(hkey, value, NULL, &type, (BYTE*)data, &needed);
1172 static inline LONG reg_save_dword(HKEY hkey, const WCHAR *value, DWORD data)
1174 return RegSetValueExW(hkey, value, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD));
1177 static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family)
1180 DWORD num_strikes, max_strike_key_len;
1182 /* If we have a File Name key then this is a real font, not just the parent
1183 key of a bunch of non-scalable strikes */
1184 if(RegQueryValueExA(hkey_face, "File Name", NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1188 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1189 face->cached_enum_data = NULL;
1191 face->file = HeapAlloc(GetProcessHeap(), 0, needed);
1192 RegQueryValueExA(hkey_face, "File Name", NULL, NULL, (BYTE*)face->file, &needed);
1194 face->StyleName = strdupW(face_name);
1195 face->family = family;
1197 if(RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, NULL, &needed) == ERROR_SUCCESS)
1199 WCHAR *fullName = HeapAlloc(GetProcessHeap(), 0, needed);
1200 RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, (BYTE*)fullName, &needed);
1201 face->FullName = fullName;
1204 face->FullName = NULL;
1206 reg_load_dword(hkey_face, face_index_value, (DWORD*)&face->face_index);
1207 reg_load_dword(hkey_face, face_italic_value, &italic);
1208 reg_load_dword(hkey_face, face_bold_value, &bold);
1209 reg_load_dword(hkey_face, face_version_value, (DWORD*)&face->font_version);
1210 reg_load_dword(hkey_face, face_external_value, (DWORD*)&face->external);
1212 needed = sizeof(face->fs);
1213 RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
1214 memset(&face->fs_links, 0, sizeof(face->fs_links));
1216 if(reg_load_dword(hkey_face, face_height_value, (DWORD*)&face->size.height) != ERROR_SUCCESS)
1218 face->scalable = TRUE;
1219 memset(&face->size, 0, sizeof(face->size));
1223 face->scalable = FALSE;
1224 reg_load_dword(hkey_face, face_width_value, (DWORD*)&face->size.width);
1225 reg_load_dword(hkey_face, face_size_value, (DWORD*)&face->size.size);
1226 reg_load_dword(hkey_face, face_x_ppem_value, (DWORD*)&face->size.x_ppem);
1227 reg_load_dword(hkey_face, face_y_ppem_value, (DWORD*)&face->size.y_ppem);
1228 reg_load_dword(hkey_face, face_internal_leading_value, (DWORD*)&face->size.internal_leading);
1230 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1231 face->size.height, face->size.width, face->size.size >> 6,
1232 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1236 if (italic) face->ntmFlags |= NTM_ITALIC;
1237 if (bold) face->ntmFlags |= NTM_BOLD;
1238 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1240 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1241 face->fs.fsCsb[0], face->fs.fsCsb[1],
1242 face->fs.fsUsb[0], face->fs.fsUsb[1],
1243 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1245 if(!italic && !bold)
1246 list_add_head(&family->faces, &face->entry);
1248 list_add_tail(&family->faces, &face->entry);
1250 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
1253 /* do we have any bitmap strikes? */
1254 RegQueryInfoKeyW(hkey_face, NULL, NULL, NULL, &num_strikes, &max_strike_key_len, NULL, NULL,
1255 NULL, NULL, NULL, NULL);
1256 if(num_strikes != 0)
1258 WCHAR strike_name[10];
1259 DWORD strike_index = 0;
1261 needed = sizeof(strike_name) / sizeof(WCHAR);
1262 while(RegEnumKeyExW(hkey_face, strike_index++, strike_name, &needed,
1263 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1266 RegOpenKeyExW(hkey_face, strike_name, 0, KEY_ALL_ACCESS, &hkey_strike);
1267 load_face(hkey_strike, face_name, family);
1268 RegCloseKey(hkey_strike);
1269 needed = sizeof(strike_name) / sizeof(WCHAR);
1274 static void load_font_list_from_cache(HKEY hkey_font_cache)
1276 DWORD max_family_key_len, size;
1278 DWORD family_index = 0;
1282 RegQueryInfoKeyW(hkey_font_cache, NULL, NULL, NULL, NULL, &max_family_key_len, NULL, NULL,
1283 NULL, NULL, NULL, NULL);
1284 family_name = HeapAlloc(GetProcessHeap(), 0, (max_family_key_len + 1) * sizeof(WCHAR));
1286 size = max_family_key_len + 1;
1287 while(RegEnumKeyExW(hkey_font_cache, family_index++, family_name, &size,
1288 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1290 WCHAR *english_family = NULL;
1291 DWORD face_index = 0;
1293 DWORD max_face_key_len;
1295 RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
1296 TRACE("opened family key %s\n", debugstr_w(family_name));
1297 if(RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, NULL, &size) == ERROR_SUCCESS)
1299 english_family = HeapAlloc(GetProcessHeap(), 0, size);
1300 RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE*)english_family, &size);
1303 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1304 family->FamilyName = strdupW(family_name);
1305 family->EnglishName = english_family;
1306 list_init(&family->faces);
1307 list_add_tail(&font_list, &family->entry);
1311 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1312 subst->from.name = strdupW(english_family);
1313 subst->from.charset = -1;
1314 subst->to.name = strdupW(family_name);
1315 subst->to.charset = -1;
1316 add_font_subst(&font_subst_list, subst, 0);
1319 RegQueryInfoKeyW(hkey_family, NULL, NULL, NULL, NULL, &max_face_key_len, NULL, NULL,
1320 NULL, NULL, NULL, NULL);
1322 face_name = HeapAlloc(GetProcessHeap(), 0, (max_face_key_len + 1) * sizeof(WCHAR));
1323 size = max_face_key_len + 1;
1324 while(RegEnumKeyExW(hkey_family, face_index++, face_name, &size,
1325 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1329 RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face);
1330 load_face(hkey_face, face_name, family);
1331 RegCloseKey(hkey_face);
1332 size = max_face_key_len + 1;
1334 HeapFree(GetProcessHeap(), 0, face_name);
1335 RegCloseKey(hkey_family);
1336 size = max_family_key_len + 1;
1339 HeapFree(GetProcessHeap(), 0, family_name);
1342 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1345 HKEY hkey_wine_fonts;
1347 /* We don't want to create the fonts key as volatile, so open this first */
1348 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1349 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1350 if(ret != ERROR_SUCCESS)
1352 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1356 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1357 KEY_ALL_ACCESS, NULL, hkey, disposition);
1358 RegCloseKey(hkey_wine_fonts);
1362 static void add_face_to_cache(Face *face)
1364 HKEY hkey_font_cache, hkey_family, hkey_face;
1365 WCHAR *face_key_name;
1367 create_font_cache_key(&hkey_font_cache, NULL);
1369 RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0,
1370 NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL);
1371 if(face->family->EnglishName)
1372 RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName,
1373 (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR));
1376 face_key_name = face->StyleName;
1379 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1380 face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1381 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1383 RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
1386 HeapFree(GetProcessHeap(), 0, face_key_name);
1388 RegSetValueExA(hkey_face, "File Name", 0, REG_BINARY, (BYTE*)face->file, strlen(face->file) + 1);
1390 RegSetValueExW(hkey_face, face_full_name_value, 0, REG_SZ, (BYTE*)face->FullName,
1391 (strlenW(face->FullName) + 1) * sizeof(WCHAR));
1393 reg_save_dword(hkey_face, face_index_value, face->face_index);
1394 reg_save_dword(hkey_face, face_italic_value, (face->ntmFlags & NTM_ITALIC) != 0);
1395 reg_save_dword(hkey_face, face_bold_value, (face->ntmFlags & NTM_BOLD) != 0);
1396 reg_save_dword(hkey_face, face_version_value, face->font_version);
1397 reg_save_dword(hkey_face, face_external_value, face->external);
1399 RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs));
1403 reg_save_dword(hkey_face, face_height_value, face->size.height);
1404 reg_save_dword(hkey_face, face_width_value, face->size.width);
1405 reg_save_dword(hkey_face, face_size_value, face->size.size);
1406 reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem);
1407 reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem);
1408 reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading);
1410 RegCloseKey(hkey_face);
1411 RegCloseKey(hkey_family);
1412 RegCloseKey(hkey_font_cache);
1415 static inline int TestStyles(DWORD flags, DWORD styles)
1417 return (flags & styles) == styles;
1420 static int StyleOrdering(Face *face)
1422 if (TestStyles(face->ntmFlags, NTM_BOLD | NTM_ITALIC))
1424 if (TestStyles(face->ntmFlags, NTM_ITALIC))
1426 if (TestStyles(face->ntmFlags, NTM_BOLD))
1428 if (TestStyles(face->ntmFlags, NTM_REGULAR))
1431 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1432 debugstr_w(face->family->FamilyName),
1433 debugstr_w(face->StyleName),
1439 /* Add a style of face to a font family using an ordering of the list such
1440 that regular fonts come before bold and italic, and single styles come
1441 before compound styles. */
1442 static void AddFaceToFamily(Face *face, Family *family)
1446 LIST_FOR_EACH( entry, &family->faces )
1448 Face *ent = LIST_ENTRY(entry, Face, entry);
1449 if (StyleOrdering(face) < StyleOrdering(ent)) break;
1451 list_add_before( entry, &face->entry );
1454 static WCHAR *prepend_at(WCHAR *family)
1461 str = HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR) * (strlenW(family) + 2));
1463 strcpyW(str + 1, family);
1464 HeapFree(GetProcessHeap(), 0, family);
1468 #define ADDFONT_EXTERNAL_FONT 0x01
1469 #define ADDFONT_FORCE_BITMAP 0x02
1470 #define ADDFONT_ADD_TO_CACHE 0x04
1472 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)
1481 WCHAR *english_family, *localised_family;
1483 struct list *face_elem_ptr;
1484 FT_WinFNT_HeaderRec winfnt_header;
1485 int internal_leading;
1487 My_FT_Bitmap_Size *size = NULL;
1490 if(!FT_IS_SCALABLE(ft_face))
1491 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1495 english_family = towstr(CP_ACP, fake_family);
1496 localised_family = NULL;
1500 english_family = get_face_name(ft_face, TT_NAME_ID_FONT_FAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES);
1501 if (!english_family)
1502 english_family = towstr(CP_ACP, ft_face->family_name);
1504 localised_family = get_face_name(ft_face, TT_NAME_ID_FONT_FAMILY, GetUserDefaultLCID());
1505 if (localised_family && !strcmpiW(localised_family, english_family))
1507 HeapFree(GetProcessHeap(), 0, localised_family);
1508 localised_family = NULL;
1514 english_family = prepend_at(english_family);
1515 localised_family = prepend_at(localised_family);
1518 family = find_family_from_name(localised_family ? localised_family : english_family);
1520 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1521 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1522 family->EnglishName = localised_family ? strdupW(english_family) : NULL;
1523 list_init(&family->faces);
1524 list_add_tail(&font_list, &family->entry);
1526 if(localised_family) {
1527 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1528 subst->from.name = strdupW(english_family);
1529 subst->from.charset = -1;
1530 subst->to.name = strdupW(localised_family);
1531 subst->to.charset = -1;
1532 add_font_subst(&font_subst_list, subst, 0);
1535 HeapFree(GetProcessHeap(), 0, localised_family);
1536 HeapFree(GetProcessHeap(), 0, english_family);
1538 StyleW = towstr(CP_ACP, ft_face->style_name);
1540 internal_leading = 0;
1541 memset(&fs, 0, sizeof(fs));
1543 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1545 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1546 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1547 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1548 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1549 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1550 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1551 if(pOS2->version == 0) {
1554 if(pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
1555 fs.fsCsb[0] |= FS_LATIN1;
1557 fs.fsCsb[0] |= FS_SYMBOL;
1560 else if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1562 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1563 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1564 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1566 internal_leading = winfnt_header.internal_leading;
1569 pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head);
1570 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1571 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1572 if(!strcmpiW(face->StyleName, StyleW) &&
1573 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1574 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1575 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1576 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1579 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1580 HeapFree(GetProcessHeap(), 0, StyleW);
1583 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1584 TRACE("Original font is newer so skipping this one\n");
1585 HeapFree(GetProcessHeap(), 0, StyleW);
1588 TRACE("Replacing original with this one\n");
1589 list_remove(&face->entry);
1590 HeapFree(GetProcessHeap(), 0, face->file);
1591 HeapFree(GetProcessHeap(), 0, face->StyleName);
1592 HeapFree(GetProcessHeap(), 0, face->FullName);
1593 HeapFree(GetProcessHeap(), 0, face);
1598 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1599 face->cached_enum_data = NULL;
1600 face->StyleName = StyleW;
1601 face->FullName = get_face_name(ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES);
1604 face->file = strdupA(file);
1605 face->font_data_ptr = NULL;
1606 face->font_data_size = 0;
1611 face->font_data_ptr = font_data_ptr;
1612 face->font_data_size = font_data_size;
1614 face->face_index = face_index;
1616 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC)
1617 face->ntmFlags |= NTM_ITALIC;
1618 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
1619 face->ntmFlags |= NTM_BOLD;
1620 if (face->ntmFlags == 0) face->ntmFlags = NTM_REGULAR;
1621 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1622 face->family = family;
1623 face->vertical = vertical;
1624 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1626 memset(&face->fs_links, 0, sizeof(face->fs_links));
1628 if(FT_IS_SCALABLE(ft_face)) {
1629 memset(&face->size, 0, sizeof(face->size));
1630 face->scalable = TRUE;
1632 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1633 size->height, size->width, size->size >> 6,
1634 size->x_ppem >> 6, size->y_ppem >> 6);
1635 face->size.height = size->height;
1636 face->size.width = size->width;
1637 face->size.size = size->size;
1638 face->size.x_ppem = size->x_ppem;
1639 face->size.y_ppem = size->y_ppem;
1640 face->size.internal_leading = internal_leading;
1641 face->scalable = FALSE;
1644 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1646 if (!pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1648 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1649 face->ntmFlags |= NTM_PS_OPENTYPE;
1652 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1653 face->fs.fsCsb[0], face->fs.fsCsb[1],
1654 face->fs.fsUsb[0], face->fs.fsUsb[1],
1655 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1657 if(face->fs.fsCsb[0] == 0)
1661 /* let's see if we can find any interesting cmaps */
1662 for(i = 0; i < ft_face->num_charmaps; i++) {
1663 switch(ft_face->charmaps[i]->encoding) {
1664 case FT_ENCODING_UNICODE:
1665 case FT_ENCODING_APPLE_ROMAN:
1666 face->fs.fsCsb[0] |= FS_LATIN1;
1668 case FT_ENCODING_MS_SYMBOL:
1669 face->fs.fsCsb[0] |= FS_SYMBOL;
1677 if(flags & ADDFONT_ADD_TO_CACHE)
1678 add_face_to_cache(face);
1680 AddFaceToFamily(face, family);
1682 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1684 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1685 debugstr_w(StyleW));
1688 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1692 TT_Header *pHeader = NULL;
1693 WCHAR *localised_family;
1695 FT_Long face_index = 0, num_faces;
1698 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1699 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1701 #ifdef HAVE_CARBON_CARBON_H
1702 if(file && !fake_family)
1704 char **mac_list = expand_mac_font(file);
1707 BOOL had_one = FALSE;
1709 for(cursor = mac_list; *cursor; cursor++)
1712 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1713 HeapFree(GetProcessHeap(), 0, *cursor);
1715 HeapFree(GetProcessHeap(), 0, mac_list);
1720 #endif /* HAVE_CARBON_CARBON_H */
1725 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1726 err = pFT_New_Face(library, file, face_index, &ft_face);
1729 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1730 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1734 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1738 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*/
1739 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1740 pFT_Done_Face(ft_face);
1744 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1745 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1746 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1747 pFT_Done_Face(ft_face);
1751 if(FT_IS_SFNT(ft_face))
1753 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1754 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1755 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1757 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1758 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1759 pFT_Done_Face(ft_face);
1763 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1764 we don't want to load these. */
1765 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1769 if(!pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1771 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1772 pFT_Done_Face(ft_face);
1778 if(!ft_face->family_name || !ft_face->style_name) {
1779 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1780 pFT_Done_Face(ft_face);
1784 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1786 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1787 pFT_Done_Face(ft_face);
1793 localised_family = get_face_name(ft_face, TT_NAME_ID_FONT_FAMILY, GetUserDefaultLCID());
1794 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1796 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1797 HeapFree(GetProcessHeap(), 0, localised_family);
1798 num_faces = ft_face->num_faces;
1799 pFT_Done_Face(ft_face);
1802 HeapFree(GetProcessHeap(), 0, localised_family);
1805 AddFaceToList(ft_face, fake_family, file, font_data_ptr, font_data_size, face_index, flags, FALSE);
1808 if (FT_HAS_VERTICAL(ft_face))
1810 AddFaceToList(ft_face, fake_family, file, font_data_ptr, font_data_size, face_index, flags, TRUE);
1814 num_faces = ft_face->num_faces;
1815 pFT_Done_Face(ft_face);
1816 } while(num_faces > ++face_index);
1820 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1822 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1825 static void DumpFontList(void)
1829 struct list *family_elem_ptr, *face_elem_ptr;
1831 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1832 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1833 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1834 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1835 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1836 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1838 TRACE(" %d", face->size.height);
1845 /***********************************************************
1846 * The replacement list is a way to map an entire font
1847 * family onto another family. For example adding
1849 * [HKCU\Software\Wine\Fonts\Replacements]
1850 * "Wingdings"="Winedings"
1852 * would enumerate the Winedings font both as Winedings and
1853 * Wingdings. However if a real Wingdings font is present the
1854 * replacement does not take place.
1857 static void LoadReplaceList(void)
1860 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1865 struct list *family_elem_ptr, *face_elem_ptr;
1868 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1869 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1871 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1872 &valuelen, &datalen, NULL, NULL);
1874 valuelen++; /* returned value doesn't include room for '\0' */
1875 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1876 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1880 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1881 &dlen) == ERROR_SUCCESS) {
1882 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1883 /* "NewName"="Oldname" */
1884 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1886 if(!find_family_from_name(value))
1888 /* Find the old family and hence all of the font files
1890 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1891 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1892 if(!strcmpiW(family->FamilyName, data)) {
1893 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1894 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1895 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1896 debugstr_w(face->StyleName), familyA);
1897 /* Now add a new entry with the new family name */
1898 AddFontToList(face->file, face->font_data_ptr, face->font_data_size,
1899 familyA, family->FamilyName,
1900 ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1906 /* reset dlen and vlen */
1910 HeapFree(GetProcessHeap(), 0, data);
1911 HeapFree(GetProcessHeap(), 0, value);
1916 /*************************************************************
1919 static BOOL init_system_links(void)
1923 DWORD type, max_val, max_data, val_len, data_len, index;
1924 WCHAR *value, *data;
1925 WCHAR *entry, *next;
1926 SYSTEM_LINKS *font_link, *system_font_link;
1927 CHILD_FONT *child_font;
1928 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1929 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1935 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1937 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1938 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1939 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1940 val_len = max_val + 1;
1941 data_len = max_data;
1943 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1945 memset(&fs, 0, sizeof(fs));
1946 psub = get_font_subst(&font_subst_list, value, -1);
1947 /* Don't store fonts that are only substitutes for other fonts */
1950 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
1953 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1954 font_link->font_name = strdupW(value);
1955 list_init(&font_link->links);
1956 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1959 CHILD_FONT *child_font;
1961 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
1963 next = entry + strlenW(entry) + 1;
1965 face_name = strchrW(entry, ',');
1969 while(isspaceW(*face_name))
1972 psub = get_font_subst(&font_subst_list, face_name, -1);
1974 face_name = psub->to.name;
1976 face = find_face_from_filename(entry, face_name);
1979 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1983 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1984 child_font->face = face;
1985 child_font->font = NULL;
1986 fs.fsCsb[0] |= face->fs.fsCsb[0];
1987 fs.fsCsb[1] |= face->fs.fsCsb[1];
1988 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1989 list_add_tail(&font_link->links, &child_font->entry);
1991 family = find_family_from_name(font_link->font_name);
1994 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1996 face->fs_links = fs;
1999 list_add_tail(&system_links, &font_link->entry);
2001 val_len = max_val + 1;
2002 data_len = max_data;
2005 HeapFree(GetProcessHeap(), 0, value);
2006 HeapFree(GetProcessHeap(), 0, data);
2010 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2013 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2014 system_font_link->font_name = strdupW(System);
2015 list_init(&system_font_link->links);
2017 face = find_face_from_filename(tahoma_ttf, Tahoma);
2020 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2021 child_font->face = face;
2022 child_font->font = NULL;
2023 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
2024 list_add_tail(&system_font_link->links, &child_font->entry);
2026 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2028 if(!strcmpiW(font_link->font_name, Tahoma))
2030 CHILD_FONT *font_link_entry;
2031 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2033 CHILD_FONT *new_child;
2034 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2035 new_child->face = font_link_entry->face;
2036 new_child->font = NULL;
2037 list_add_tail(&system_font_link->links, &new_child->entry);
2042 list_add_tail(&system_links, &system_font_link->entry);
2046 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2049 struct dirent *dent;
2050 char path[MAX_PATH];
2052 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2054 dir = opendir(dirname);
2056 WARN("Can't open directory %s\n", debugstr_a(dirname));
2059 while((dent = readdir(dir)) != NULL) {
2060 struct stat statbuf;
2062 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2065 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2067 sprintf(path, "%s/%s", dirname, dent->d_name);
2069 if(stat(path, &statbuf) == -1)
2071 WARN("Can't stat %s\n", debugstr_a(path));
2074 if(S_ISDIR(statbuf.st_mode))
2075 ReadFontDir(path, external_fonts);
2078 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2079 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2080 AddFontFileToList(path, NULL, NULL, addfont_flags);
2087 static void load_fontconfig_fonts(void)
2089 #ifdef SONAME_LIBFONTCONFIG
2090 void *fc_handle = NULL;
2099 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2101 TRACE("Wine cannot find the fontconfig library (%s).\n",
2102 SONAME_LIBFONTCONFIG);
2105 #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;}
2106 LOAD_FUNCPTR(FcConfigGetCurrent);
2107 LOAD_FUNCPTR(FcFontList);
2108 LOAD_FUNCPTR(FcFontSetDestroy);
2109 LOAD_FUNCPTR(FcInit);
2110 LOAD_FUNCPTR(FcObjectSetAdd);
2111 LOAD_FUNCPTR(FcObjectSetCreate);
2112 LOAD_FUNCPTR(FcObjectSetDestroy);
2113 LOAD_FUNCPTR(FcPatternCreate);
2114 LOAD_FUNCPTR(FcPatternDestroy);
2115 LOAD_FUNCPTR(FcPatternGetBool);
2116 LOAD_FUNCPTR(FcPatternGetString);
2119 if(!pFcInit()) return;
2121 config = pFcConfigGetCurrent();
2122 pat = pFcPatternCreate();
2123 os = pFcObjectSetCreate();
2124 pFcObjectSetAdd(os, FC_FILE);
2125 pFcObjectSetAdd(os, FC_SCALABLE);
2126 fontset = pFcFontList(config, pat, os);
2127 if(!fontset) return;
2128 for(i = 0; i < fontset->nfont; i++) {
2131 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2133 TRACE("fontconfig: %s\n", file);
2135 /* We're just interested in OT/TT fonts for now, so this hack just
2136 picks up the scalable fonts without extensions .pf[ab] to save time
2137 loading every other font */
2139 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2141 TRACE("not scalable\n");
2145 len = strlen( file );
2146 if(len < 4) continue;
2147 ext = &file[ len - 3 ];
2148 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2149 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2151 pFcFontSetDestroy(fontset);
2152 pFcObjectSetDestroy(os);
2153 pFcPatternDestroy(pat);
2159 static BOOL load_font_from_data_dir(LPCWSTR file)
2162 const char *data_dir = wine_get_data_dir();
2164 if (!data_dir) data_dir = wine_get_build_dir();
2171 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
2173 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
2175 strcpy(unix_name, data_dir);
2176 strcat(unix_name, "/fonts/");
2178 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
2180 EnterCriticalSection( &freetype_cs );
2181 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2182 LeaveCriticalSection( &freetype_cs );
2183 HeapFree(GetProcessHeap(), 0, unix_name);
2188 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
2190 static const WCHAR slashW[] = {'\\','\0'};
2192 WCHAR windowsdir[MAX_PATH];
2195 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2196 strcatW(windowsdir, fontsW);
2197 strcatW(windowsdir, slashW);
2198 strcatW(windowsdir, file);
2199 if ((unixname = wine_get_unix_file_name(windowsdir))) {
2200 EnterCriticalSection( &freetype_cs );
2201 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2202 LeaveCriticalSection( &freetype_cs );
2203 HeapFree(GetProcessHeap(), 0, unixname);
2208 static void load_system_fonts(void)
2211 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
2212 const WCHAR * const *value;
2214 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2217 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
2218 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2219 strcatW(windowsdir, fontsW);
2220 for(value = SystemFontValues; *value; value++) {
2221 dlen = sizeof(data);
2222 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
2226 sprintfW(pathW, fmtW, windowsdir, data);
2227 if((unixname = wine_get_unix_file_name(pathW))) {
2228 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2229 HeapFree(GetProcessHeap(), 0, unixname);
2232 load_font_from_data_dir(data);
2239 /*************************************************************
2241 * This adds registry entries for any externally loaded fonts
2242 * (fonts from fontconfig or FontDirs). It also deletes entries
2243 * of no longer existing fonts.
2246 static void update_reg_entries(void)
2248 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2253 struct list *family_elem_ptr, *face_elem_ptr;
2255 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2256 static const WCHAR spaceW[] = {' ', '\0'};
2259 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2260 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2261 ERR("Can't create Windows font reg key\n");
2265 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2266 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2267 ERR("Can't create Windows font reg key\n");
2271 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
2272 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
2273 ERR("Can't create external font reg key\n");
2277 /* enumerate the fonts and add external ones to the two keys */
2279 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2280 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2281 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2282 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2283 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2284 if(!face->external) continue;
2286 if (!(face->ntmFlags & NTM_REGULAR))
2287 len = len_fam + strlenW(face->StyleName) + 1;
2288 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2289 strcpyW(valueW, family->FamilyName);
2290 if(len != len_fam) {
2291 strcatW(valueW, spaceW);
2292 strcatW(valueW, face->StyleName);
2294 strcatW(valueW, TrueType);
2296 file = wine_get_dos_file_name(face->file);
2298 len = strlenW(file) + 1;
2301 if((path = strrchr(face->file, '/')) == NULL)
2305 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
2307 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2308 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
2310 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2311 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2312 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2314 HeapFree(GetProcessHeap(), 0, file);
2315 HeapFree(GetProcessHeap(), 0, valueW);
2319 if(external_key) RegCloseKey(external_key);
2320 if(win9x_key) RegCloseKey(win9x_key);
2321 if(winnt_key) RegCloseKey(winnt_key);
2325 static void delete_external_font_keys(void)
2327 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2328 DWORD dlen, vlen, datalen, valuelen, i, type;
2332 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2333 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2334 ERR("Can't create Windows font reg key\n");
2338 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2339 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2340 ERR("Can't create Windows font reg key\n");
2344 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2345 ERR("Can't create external font reg key\n");
2349 /* Delete all external fonts added last time */
2351 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2352 &valuelen, &datalen, NULL, NULL);
2353 valuelen++; /* returned value doesn't include room for '\0' */
2354 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2355 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2357 dlen = datalen * sizeof(WCHAR);
2360 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2361 &dlen) == ERROR_SUCCESS) {
2363 RegDeleteValueW(winnt_key, valueW);
2364 RegDeleteValueW(win9x_key, valueW);
2365 /* reset dlen and vlen */
2369 HeapFree(GetProcessHeap(), 0, data);
2370 HeapFree(GetProcessHeap(), 0, valueW);
2372 /* Delete the old external fonts key */
2373 RegCloseKey(external_key);
2374 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2377 if(win9x_key) RegCloseKey(win9x_key);
2378 if(winnt_key) RegCloseKey(winnt_key);
2381 /*************************************************************
2382 * WineEngAddFontResourceEx
2385 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2391 if (ft_handle) /* do it only if we have freetype up and running */
2396 FIXME("Ignoring flags %x\n", flags);
2398 if((unixname = wine_get_unix_file_name(file)))
2400 DWORD addfont_flags = ADDFONT_FORCE_BITMAP;
2402 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
2403 EnterCriticalSection( &freetype_cs );
2404 ret = AddFontFileToList(unixname, NULL, NULL, addfont_flags);
2405 LeaveCriticalSection( &freetype_cs );
2406 HeapFree(GetProcessHeap(), 0, unixname);
2408 if (!ret && !strchrW(file, '\\')) {
2409 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2410 ret = load_font_from_winfonts_dir(file);
2412 /* Try in datadir/fonts (or builddir/fonts),
2413 * needed for Magic the Gathering Online
2415 ret = load_font_from_data_dir(file);
2422 /*************************************************************
2423 * WineEngAddFontMemResourceEx
2426 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2430 if (ft_handle) /* do it only if we have freetype up and running */
2432 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2434 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2435 memcpy(pFontCopy, pbFont, cbFont);
2437 EnterCriticalSection( &freetype_cs );
2438 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
2439 LeaveCriticalSection( &freetype_cs );
2443 TRACE("AddFontToList failed\n");
2444 HeapFree(GetProcessHeap(), 0, pFontCopy);
2447 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2448 * For now return something unique but quite random
2450 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2451 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2458 /*************************************************************
2459 * WineEngRemoveFontResourceEx
2462 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2465 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
2469 static const struct nls_update_font_list
2471 UINT ansi_cp, oem_cp;
2472 const char *oem, *fixed, *system;
2473 const char *courier, *serif, *small, *sserif;
2474 /* these are for font substitutes */
2475 const char *shelldlg, *tmsrmn;
2476 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
2480 const char *from, *to;
2481 } arial_0, courier_new_0, times_new_roman_0;
2482 } nls_update_font_list[] =
2484 /* Latin 1 (United States) */
2485 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
2486 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2487 "Tahoma","Times New Roman",
2488 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2491 /* Latin 1 (Multilingual) */
2492 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
2493 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2494 "Tahoma","Times New Roman", /* FIXME unverified */
2495 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2498 /* Eastern Europe */
2499 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
2500 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
2501 "Tahoma","Times New Roman", /* FIXME unverified */
2502 "Fixedsys,238", "System,238",
2503 "Courier New,238", "MS Serif,238", "Small Fonts,238",
2504 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
2505 { "Arial CE,0", "Arial,238" },
2506 { "Courier New CE,0", "Courier New,238" },
2507 { "Times New Roman CE,0", "Times New Roman,238" }
2510 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
2511 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
2512 "Tahoma","Times New Roman", /* FIXME unverified */
2513 "Fixedsys,204", "System,204",
2514 "Courier New,204", "MS Serif,204", "Small Fonts,204",
2515 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
2516 { "Arial Cyr,0", "Arial,204" },
2517 { "Courier New Cyr,0", "Courier New,204" },
2518 { "Times New Roman Cyr,0", "Times New Roman,204" }
2521 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
2522 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
2523 "Tahoma","Times New Roman", /* FIXME unverified */
2524 "Fixedsys,161", "System,161",
2525 "Courier New,161", "MS Serif,161", "Small Fonts,161",
2526 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
2527 { "Arial Greek,0", "Arial,161" },
2528 { "Courier New Greek,0", "Courier New,161" },
2529 { "Times New Roman Greek,0", "Times New Roman,161" }
2532 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
2533 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
2534 "Tahoma","Times New Roman", /* FIXME unverified */
2535 "Fixedsys,162", "System,162",
2536 "Courier New,162", "MS Serif,162", "Small Fonts,162",
2537 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
2538 { "Arial Tur,0", "Arial,162" },
2539 { "Courier New Tur,0", "Courier New,162" },
2540 { "Times New Roman Tur,0", "Times New Roman,162" }
2543 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
2544 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
2545 "Tahoma","Times New Roman", /* FIXME unverified */
2546 "Fixedsys,177", "System,177",
2547 "Courier New,177", "MS Serif,177", "Small Fonts,177",
2548 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
2552 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
2553 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
2554 "Tahoma","Times New Roman", /* FIXME unverified */
2555 "Fixedsys,178", "System,178",
2556 "Courier New,178", "MS Serif,178", "Small Fonts,178",
2557 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
2561 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
2562 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
2563 "Tahoma","Times New Roman", /* FIXME unverified */
2564 "Fixedsys,186", "System,186",
2565 "Courier New,186", "MS Serif,186", "Small Fonts,186",
2566 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
2567 { "Arial Baltic,0", "Arial,186" },
2568 { "Courier New Baltic,0", "Courier New,186" },
2569 { "Times New Roman Baltic,0", "Times New Roman,186" }
2572 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
2573 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2574 "Tahoma","Times New Roman", /* FIXME unverified */
2575 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2579 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
2580 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
2581 "Tahoma","Times New Roman", /* FIXME unverified */
2582 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2586 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
2587 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
2588 "MS UI Gothic","MS Serif",
2589 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2592 /* Chinese Simplified */
2593 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
2594 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2595 "SimSun", "NSimSun",
2596 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2600 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
2601 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2603 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2606 /* Chinese Traditional */
2607 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2608 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2609 "PMingLiU", "MingLiU",
2610 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2615 static const WCHAR *font_links_list[] =
2617 Lucida_Sans_Unicode,
2618 Microsoft_Sans_Serif,
2622 static const struct font_links_defaults_list
2624 /* Keyed off substitution for "MS Shell Dlg" */
2625 const WCHAR *shelldlg;
2626 /* Maximum of four substitutes, plus terminating NULL pointer */
2627 const WCHAR *substitutes[5];
2628 } font_links_defaults_list[] =
2630 /* Non East-Asian */
2631 { Tahoma, /* FIXME unverified ordering */
2632 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2634 /* Below lists are courtesy of
2635 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2639 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2641 /* Chinese Simplified */
2643 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2647 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2649 /* Chinese Traditional */
2651 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2655 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
2657 return ( ansi_cp == 932 /* CP932 for Japanese */
2658 || ansi_cp == 936 /* CP936 for Chinese Simplified */
2659 || ansi_cp == 949 /* CP949 for Korean */
2660 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
2663 static inline HKEY create_fonts_NT_registry_key(void)
2667 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2668 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2672 static inline HKEY create_fonts_9x_registry_key(void)
2676 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2677 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2681 static inline HKEY create_config_fonts_registry_key(void)
2685 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2686 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2690 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2692 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2693 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2694 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2695 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2698 static void set_value_key(HKEY hkey, const char *name, const char *value)
2701 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
2703 RegDeleteValueA(hkey, name);
2706 static void update_font_info(void)
2708 char buf[40], cpbuf[40];
2711 UINT i, ansi_cp = 0, oem_cp = 0;
2714 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2717 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2718 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2719 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2720 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2721 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2723 /* Setup Default_Fallback usage for DBCS ANSI codepages */
2724 if (is_dbcs_ansi_cp(ansi_cp))
2725 use_default_fallback = TRUE;
2728 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2730 if (!strcmp( buf, cpbuf )) /* already set correctly */
2735 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2737 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2739 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2742 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2746 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2747 nls_update_font_list[i].oem_cp == oem_cp)
2749 hkey = create_config_fonts_registry_key();
2750 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2751 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2752 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2755 hkey = create_fonts_NT_registry_key();
2756 add_font_list(hkey, &nls_update_font_list[i]);
2759 hkey = create_fonts_9x_registry_key();
2760 add_font_list(hkey, &nls_update_font_list[i]);
2763 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2765 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2766 strlen(nls_update_font_list[i].shelldlg)+1);
2767 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2768 strlen(nls_update_font_list[i].tmsrmn)+1);
2770 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
2771 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
2772 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
2773 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
2774 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
2775 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
2776 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
2777 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
2779 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
2780 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
2781 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
2789 /* Delete the FontSubstitutes from other locales */
2790 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2792 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
2793 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
2794 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
2800 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2802 /* Clear out system links */
2803 RegDeleteKeyW(HKEY_LOCAL_MACHINE, system_link);
2806 static void populate_system_links(HKEY hkey, const WCHAR *name, const WCHAR *const *values)
2815 WCHAR buff[MAX_PATH];
2819 static const WCHAR comma[] = {',',0};
2821 RegDeleteValueW(hkey, name);
2826 for (i = 0; values[i] != NULL; i++)
2829 if (!strcmpiW(name,value))
2831 psub = get_font_subst(&font_subst_list, value, -1);
2833 value = psub->to.name;
2834 family = find_family_from_name(value);
2838 /* Use first extant filename for this Family */
2839 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2843 file = strrchr(face->file, '/');
2852 fileW = towstr(CP_UNIXCP, file);
2853 entryLen = strlenW(fileW) + 1 + strlenW(value) + 1;
2854 if (sizeof(buff)-(data-buff) < entryLen + 1)
2856 WARN("creating SystemLink for %s, ran out of buffer space\n", debugstr_w(name));
2857 HeapFree(GetProcessHeap(), 0, fileW);
2860 strcpyW(data, fileW);
2861 strcatW(data, comma);
2862 strcatW(data, value);
2864 TRACE("added SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(fileW));
2865 HeapFree(GetProcessHeap(), 0, fileW);
2871 RegSetValueExW(hkey, name, 0, REG_MULTI_SZ, (BYTE*)buff, (data-buff) * sizeof(WCHAR));
2873 TRACE("no SystemLink fonts found for %s\n", debugstr_w(name));
2875 TRACE("removed SystemLink for %s\n", debugstr_w(name));
2878 static void update_system_links(void)
2886 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2888 if (!RegCreateKeyExW(HKEY_LOCAL_MACHINE, system_link, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, &disposition))
2890 if (disposition == REG_OPENED_EXISTING_KEY)
2892 TRACE("SystemLink key already exists, doing nothing\n");
2897 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2899 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2904 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2906 if (!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name))
2908 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2909 populate_system_links(hkey, font_links_list[j], font_links_defaults_list[i].substitutes);
2911 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2912 populate_system_links(hkey, psub->to.name, font_links_defaults_list[i].substitutes);
2915 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2917 populate_system_links(hkey, font_links_defaults_list[i].substitutes[0], NULL);
2922 WARN("there is no SystemLink default list for MS Shell Dlg %s\n", debugstr_w(psub->to.name));
2924 WARN("failed to create SystemLink key\n");
2928 static BOOL init_freetype(void)
2930 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2933 "Wine cannot find the FreeType font library. To enable Wine to\n"
2934 "use TrueType fonts please install a version of FreeType greater than\n"
2935 "or equal to 2.0.5.\n"
2936 "http://www.freetype.org\n");
2940 #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;}
2942 LOAD_FUNCPTR(FT_Done_Face)
2943 LOAD_FUNCPTR(FT_Get_Char_Index)
2944 LOAD_FUNCPTR(FT_Get_First_Char)
2945 LOAD_FUNCPTR(FT_Get_Module)
2946 LOAD_FUNCPTR(FT_Get_Next_Char)
2947 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2948 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2949 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2950 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
2951 LOAD_FUNCPTR(FT_Init_FreeType)
2952 LOAD_FUNCPTR(FT_Library_Version)
2953 LOAD_FUNCPTR(FT_Load_Glyph)
2954 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
2955 LOAD_FUNCPTR(FT_Matrix_Multiply)
2956 #ifndef FT_MULFIX_INLINED
2957 LOAD_FUNCPTR(FT_MulFix)
2959 LOAD_FUNCPTR(FT_New_Face)
2960 LOAD_FUNCPTR(FT_New_Memory_Face)
2961 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2962 LOAD_FUNCPTR(FT_Outline_Transform)
2963 LOAD_FUNCPTR(FT_Outline_Translate)
2964 LOAD_FUNCPTR(FT_Render_Glyph)
2965 LOAD_FUNCPTR(FT_Select_Charmap)
2966 LOAD_FUNCPTR(FT_Set_Charmap)
2967 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2968 LOAD_FUNCPTR(FT_Vector_Transform)
2969 LOAD_FUNCPTR(FT_Vector_Unit)
2971 /* Don't warn if these ones are missing */
2972 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2973 #ifdef HAVE_FREETYPE_FTLCDFIL_H
2974 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
2977 if(pFT_Init_FreeType(&library) != 0) {
2978 ERR("Can't init FreeType library\n");
2979 wine_dlclose(ft_handle, NULL, 0);
2983 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2985 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2986 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2987 ((FT_Version.minor << 8) & 0x00ff00) |
2988 ((FT_Version.patch ) & 0x0000ff);
2990 font_driver = &freetype_funcs;
2995 "Wine cannot find certain functions that it needs inside the FreeType\n"
2996 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2997 "FreeType to at least version 2.1.4.\n"
2998 "http://www.freetype.org\n");
2999 wine_dlclose(ft_handle, NULL, 0);
3004 static void init_font_list(void)
3006 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
3007 static const WCHAR pathW[] = {'P','a','t','h',0};
3009 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
3010 WCHAR windowsdir[MAX_PATH];
3012 const char *data_dir;
3014 delete_external_font_keys();
3016 /* load the system bitmap fonts */
3017 load_system_fonts();
3019 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3020 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3021 strcatW(windowsdir, fontsW);
3022 if((unixname = wine_get_unix_file_name(windowsdir)))
3024 ReadFontDir(unixname, FALSE);
3025 HeapFree(GetProcessHeap(), 0, unixname);
3028 /* load the system truetype fonts */
3029 data_dir = wine_get_data_dir();
3030 if (!data_dir) data_dir = wine_get_build_dir();
3031 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
3033 strcpy(unixname, data_dir);
3034 strcat(unixname, "/fonts/");
3035 ReadFontDir(unixname, TRUE);
3036 HeapFree(GetProcessHeap(), 0, unixname);
3039 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3040 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3041 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3043 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
3044 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
3045 &hkey) == ERROR_SUCCESS)
3047 LPWSTR data, valueW;
3048 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3049 &valuelen, &datalen, NULL, NULL);
3051 valuelen++; /* returned value doesn't include room for '\0' */
3052 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3053 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3056 dlen = datalen * sizeof(WCHAR);
3058 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
3059 &dlen) == ERROR_SUCCESS)
3061 if(data[0] && (data[1] == ':'))
3063 if((unixname = wine_get_unix_file_name(data)))
3065 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3066 HeapFree(GetProcessHeap(), 0, unixname);
3069 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
3071 WCHAR pathW[MAX_PATH];
3072 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3075 sprintfW(pathW, fmtW, windowsdir, data);
3076 if((unixname = wine_get_unix_file_name(pathW)))
3078 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3079 HeapFree(GetProcessHeap(), 0, unixname);
3082 load_font_from_data_dir(data);
3084 /* reset dlen and vlen */
3089 HeapFree(GetProcessHeap(), 0, data);
3090 HeapFree(GetProcessHeap(), 0, valueW);
3094 load_fontconfig_fonts();
3096 /* then look in any directories that we've specified in the config file */
3097 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3098 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
3104 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
3106 len += sizeof(WCHAR);
3107 valueW = HeapAlloc( GetProcessHeap(), 0, len );
3108 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
3110 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
3111 valueA = HeapAlloc( GetProcessHeap(), 0, len );
3112 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
3113 TRACE( "got font path %s\n", debugstr_a(valueA) );
3118 LPSTR next = strchr( ptr, ':' );
3119 if (next) *next++ = 0;
3120 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
3121 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
3123 strcpy( unixname, home );
3124 strcat( unixname, ptr + 1 );
3125 ReadFontDir( unixname, TRUE );
3126 HeapFree( GetProcessHeap(), 0, unixname );
3129 ReadFontDir( ptr, TRUE );
3132 HeapFree( GetProcessHeap(), 0, valueA );
3134 HeapFree( GetProcessHeap(), 0, valueW );
3140 static BOOL move_to_front(const WCHAR *name)
3142 Family *family, *cursor2;
3143 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
3145 if(!strcmpiW(family->FamilyName, name))
3147 list_remove(&family->entry);
3148 list_add_head(&font_list, &family->entry);
3155 static BOOL set_default(const WCHAR **name_list)
3159 if (move_to_front(*name_list)) return TRUE;
3166 static void reorder_font_list(void)
3168 set_default( default_serif_list );
3169 set_default( default_fixed_list );
3170 set_default( default_sans_list );
3173 /*************************************************************
3176 * Initialize FreeType library and create a list of available faces
3178 BOOL WineEngInit(void)
3180 HKEY hkey_font_cache;
3184 /* update locale dependent font info in registry */
3187 if(!init_freetype()) return FALSE;
3189 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
3191 ERR("Failed to create font mutex\n");
3194 WaitForSingleObject(font_mutex, INFINITE);
3196 create_font_cache_key(&hkey_font_cache, &disposition);
3198 if(disposition == REG_CREATED_NEW_KEY)
3201 load_font_list_from_cache(hkey_font_cache);
3203 RegCloseKey(hkey_font_cache);
3205 reorder_font_list();
3212 if(disposition == REG_CREATED_NEW_KEY)
3213 update_reg_entries();
3215 update_system_links();
3216 init_system_links();
3218 ReleaseMutex(font_mutex);
3223 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
3226 TT_HoriHeader *pHori;
3230 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3231 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3233 if(height == 0) height = 16;
3235 /* Calc. height of EM square:
3237 * For +ve lfHeight we have
3238 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3239 * Re-arranging gives:
3240 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3242 * For -ve lfHeight we have
3244 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3245 * with il = winAscent + winDescent - units_per_em]
3250 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
3251 ppem = MulDiv(ft_face->units_per_EM, height,
3252 pHori->Ascender - pHori->Descender);
3254 ppem = MulDiv(ft_face->units_per_EM, height,
3255 pOS2->usWinAscent + pOS2->usWinDescent);
3263 static struct font_mapping *map_font_file( const char *name )
3265 struct font_mapping *mapping;
3269 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
3270 if (fstat( fd, &st ) == -1) goto error;
3272 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
3274 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
3276 mapping->refcount++;
3281 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
3284 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
3287 if (mapping->data == MAP_FAILED)
3289 HeapFree( GetProcessHeap(), 0, mapping );
3292 mapping->refcount = 1;
3293 mapping->dev = st.st_dev;
3294 mapping->ino = st.st_ino;
3295 mapping->size = st.st_size;
3296 list_add_tail( &mappings_list, &mapping->entry );
3304 static void unmap_font_file( struct font_mapping *mapping )
3306 if (!--mapping->refcount)
3308 list_remove( &mapping->entry );
3309 munmap( mapping->data, mapping->size );
3310 HeapFree( GetProcessHeap(), 0, mapping );
3314 static LONG load_VDMX(GdiFont*, LONG);
3316 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
3323 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
3327 if (!(font->mapping = map_font_file( face->file )))
3329 WARN("failed to map %s\n", debugstr_a(face->file));
3332 data_ptr = font->mapping->data;
3333 data_size = font->mapping->size;
3337 data_ptr = face->font_data_ptr;
3338 data_size = face->font_data_size;
3341 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3343 ERR("FT_New_Face rets %d\n", err);
3347 /* set it here, as load_VDMX needs it */
3348 font->ft_face = ft_face;
3350 if(FT_IS_SCALABLE(ft_face)) {
3351 /* load the VDMX table if we have one */
3352 font->ppem = load_VDMX(font, height);
3354 font->ppem = calc_ppem_for_height(ft_face, height);
3355 TRACE("height %d => ppem %d\n", height, font->ppem);
3357 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3358 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3360 font->ppem = height;
3361 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3362 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3368 static int get_nearest_charset(Face *face, int *cp)
3370 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3371 a single face with the requested charset. The idea is to check if
3372 the selected font supports the current ANSI codepage, if it does
3373 return the corresponding charset, else return the first charset */
3376 int acp = GetACP(), i;
3380 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
3381 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3382 return csi.ciCharset;
3384 for(i = 0; i < 32; i++) {
3386 if(face->fs.fsCsb[0] & fs0) {
3387 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
3389 return csi.ciCharset;
3392 FIXME("TCI failing on %x\n", fs0);
3396 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
3397 face->fs.fsCsb[0], face->file);
3399 return DEFAULT_CHARSET;
3402 static GdiFont *alloc_font(void)
3404 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
3406 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
3407 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3409 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
3410 ret->total_kern_pairs = (DWORD)-1;
3411 ret->kern_pairs = NULL;
3412 list_init(&ret->hfontlist);
3413 list_init(&ret->child_fonts);
3417 static void free_font(GdiFont *font)
3419 struct list *cursor, *cursor2;
3422 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
3424 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
3425 list_remove(cursor);
3427 free_font(child->font);
3428 HeapFree(GetProcessHeap(), 0, child);
3431 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->hfontlist)
3433 HFONTLIST *hfontlist = LIST_ENTRY(cursor, HFONTLIST, entry);
3434 DeleteObject(hfontlist->hfont);
3435 list_remove(&hfontlist->entry);
3436 HeapFree(GetProcessHeap(), 0, hfontlist);
3439 if (font->ft_face) pFT_Done_Face(font->ft_face);
3440 if (font->mapping) unmap_font_file( font->mapping );
3441 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
3442 HeapFree(GetProcessHeap(), 0, font->potm);
3443 HeapFree(GetProcessHeap(), 0, font->name);
3444 for (i = 0; i < font->gmsize; i++)
3445 HeapFree(GetProcessHeap(),0,font->gm[i]);
3446 HeapFree(GetProcessHeap(), 0, font->gm);
3447 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
3448 HeapFree(GetProcessHeap(), 0, font);
3452 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
3454 FT_Face ft_face = font->ft_face;
3458 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
3465 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
3467 /* make sure value of len is the value freetype says it needs */
3470 FT_ULong needed = 0;
3471 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
3472 if( !err && needed < len) len = needed;
3474 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
3477 TRACE("Can't find table %c%c%c%c\n",
3478 /* bytes were reversed */
3479 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
3480 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
3486 /*************************************************************
3489 * load the vdmx entry for the specified height
3492 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
3493 ( ( (FT_ULong)_x4 << 24 ) | \
3494 ( (FT_ULong)_x3 << 16 ) | \
3495 ( (FT_ULong)_x2 << 8 ) | \
3498 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
3513 static LONG load_VDMX(GdiFont *font, LONG height)
3517 BYTE devXRatio, devYRatio;
3518 USHORT numRecs, numRatios;
3519 DWORD result, offset = -1;
3523 result = get_font_data(font, MS_VDMX_TAG, 0, hdr, 6);
3525 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
3528 /* FIXME: need the real device aspect ratio */
3532 numRecs = GET_BE_WORD(hdr[1]);
3533 numRatios = GET_BE_WORD(hdr[2]);
3535 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
3536 for(i = 0; i < numRatios; i++) {
3539 offset = (3 * 2) + (i * sizeof(Ratios));
3540 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
3543 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
3545 if((ratio.xRatio == 0 &&
3546 ratio.yStartRatio == 0 &&
3547 ratio.yEndRatio == 0) ||
3548 (devXRatio == ratio.xRatio &&
3549 devYRatio >= ratio.yStartRatio &&
3550 devYRatio <= ratio.yEndRatio))
3552 offset = (3 * 2) + (numRatios * 4) + (i * 2);
3553 get_font_data(font, MS_VDMX_TAG, offset, &tmp, 2);
3554 offset = GET_BE_WORD(tmp);
3560 FIXME("No suitable ratio found\n");
3564 if(get_font_data(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
3566 BYTE startsz, endsz;
3569 recs = GET_BE_WORD(group.recs);
3570 startsz = group.startsz;
3571 endsz = group.endsz;
3573 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
3575 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
3576 result = get_font_data(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
3577 if(result == GDI_ERROR) {
3578 FIXME("Failed to retrieve vTable\n");
3583 for(i = 0; i < recs; i++) {
3584 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3585 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3586 ppem = GET_BE_WORD(vTable[i * 3]);
3588 if(yMax + -yMin == height) {
3591 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3594 if(yMax + -yMin > height) {
3597 goto end; /* failed */
3599 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
3600 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
3601 ppem = GET_BE_WORD(vTable[i * 3]);
3602 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
3608 TRACE("ppem not found for height %d\n", height);
3612 HeapFree(GetProcessHeap(), 0, vTable);
3618 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
3620 if(font->font_desc.hash != fd->hash) return TRUE;
3621 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
3622 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
3623 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
3624 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
3627 static void calc_hash(FONT_DESC *pfd)
3629 DWORD hash = 0, *ptr, two_chars;
3633 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
3635 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
3637 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
3639 pwc = (WCHAR *)&two_chars;
3641 *pwc = toupperW(*pwc);
3643 *pwc = toupperW(*pwc);
3647 hash ^= !pfd->can_use_bitmap;
3652 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
3657 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3661 fd.can_use_bitmap = can_use_bitmap;
3664 /* try the child list */
3665 LIST_FOR_EACH(font_elem_ptr, &child_font_list) {
3666 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3667 if(!fontcmp(ret, &fd)) {
3668 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3669 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3670 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3671 if(hflist->hfont == hfont)
3677 /* try the in-use list */
3678 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
3679 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3680 if(!fontcmp(ret, &fd)) {
3681 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3682 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
3683 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3684 if(hflist->hfont == hfont)
3687 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3688 hflist->hfont = hfont;
3689 list_add_head(&ret->hfontlist, &hflist->entry);
3694 /* then the unused list */
3695 font_elem_ptr = list_head(&unused_gdi_font_list);
3696 while(font_elem_ptr) {
3697 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3698 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3699 if(!fontcmp(ret, &fd)) {
3700 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
3701 assert(list_empty(&ret->hfontlist));
3702 TRACE("Found %p in unused list\n", ret);
3703 list_remove(&ret->entry);
3704 list_add_head(&gdi_font_list, &ret->entry);
3705 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3706 hflist->hfont = hfont;
3707 list_add_head(&ret->hfontlist, &hflist->entry);
3714 static void add_to_cache(GdiFont *font)
3716 static DWORD cache_num = 1;
3718 font->cache_num = cache_num++;
3719 list_add_head(&gdi_font_list, &font->entry);
3722 /*************************************************************
3723 * create_child_font_list
3725 static BOOL create_child_font_list(GdiFont *font)
3728 SYSTEM_LINKS *font_link;
3729 CHILD_FONT *font_link_entry, *new_child;
3733 psub = get_font_subst(&font_subst_list, font->name, -1);
3734 font_name = psub ? psub->to.name : font->name;
3735 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3737 if(!strcmpiW(font_link->font_name, font_name))
3739 TRACE("found entry in system list\n");
3740 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3742 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3743 new_child->face = font_link_entry->face;
3744 new_child->font = NULL;
3745 list_add_tail(&font->child_fonts, &new_child->entry);
3746 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3753 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
3754 * Sans Serif. This is how asian windows get default fallbacks for fonts
3756 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
3757 font->charset != OEM_CHARSET &&
3758 strcmpiW(font_name,szDefaultFallbackLink) != 0)
3759 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3761 if(!strcmpiW(font_link->font_name,szDefaultFallbackLink))
3763 TRACE("found entry in default fallback list\n");
3764 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3766 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
3767 new_child->face = font_link_entry->face;
3768 new_child->font = NULL;
3769 list_add_tail(&font->child_fonts, &new_child->entry);
3770 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
3780 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
3782 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
3784 if (pFT_Set_Charmap)
3787 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
3789 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
3791 for (i = 0; i < ft_face->num_charmaps; i++)
3793 if (ft_face->charmaps[i]->encoding == encoding)
3795 TRACE("found cmap with platform_id %u, encoding_id %u\n",
3796 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
3798 switch (ft_face->charmaps[i]->platform_id)
3801 cmap_def = ft_face->charmaps[i];
3803 case 0: /* Apple Unicode */
3804 cmap0 = ft_face->charmaps[i];
3806 case 1: /* Macintosh */
3807 cmap1 = ft_face->charmaps[i];
3810 cmap2 = ft_face->charmaps[i];
3812 case 3: /* Microsoft */
3813 cmap3 = ft_face->charmaps[i];
3818 if (cmap3) /* prefer Microsoft cmap table */
3819 ft_err = pFT_Set_Charmap(ft_face, cmap3);
3821 ft_err = pFT_Set_Charmap(ft_face, cmap1);
3823 ft_err = pFT_Set_Charmap(ft_face, cmap2);
3825 ft_err = pFT_Set_Charmap(ft_face, cmap0);
3827 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
3829 return ft_err == FT_Err_Ok;
3832 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
3836 /*************************************************************
3839 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
3840 LPCWSTR output, const DEVMODEW *devmode )
3842 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
3844 if (!physdev) return FALSE;
3845 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
3850 /*************************************************************
3853 static BOOL freetype_DeleteDC( PHYSDEV dev )
3855 struct freetype_physdev *physdev = get_freetype_dev( dev );
3856 HeapFree( GetProcessHeap(), 0, physdev );
3861 /*************************************************************
3862 * freetype_SelectFont
3864 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont )
3866 struct freetype_physdev *physdev = get_freetype_dev( dev );
3868 Face *face, *best, *best_bitmap;
3869 Family *family, *last_resort_family;
3870 struct list *family_elem_ptr, *face_elem_ptr;
3871 INT height, width = 0;
3872 unsigned int score = 0, new_score;
3873 signed int diff = 0, newdiff;
3874 BOOL bd, it, can_use_bitmap;
3879 FontSubst *psub = NULL;
3880 DC *dc = get_dc_ptr( dev->hdc );
3882 if (!hfont) /* notification that the font has been changed by another driver */
3885 physdev->font = NULL;
3886 release_dc_ptr( dc );
3890 GetObjectW( hfont, sizeof(lf), &lf );
3891 lf.lfWidth = abs(lf.lfWidth);
3893 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
3895 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
3896 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
3897 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
3900 if(dc->GraphicsMode == GM_ADVANCED)
3901 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
3904 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
3905 font scaling abilities. */
3906 dcmat.eM11 = dcmat.eM22 = dc->vport2WorldValid ? fabs(dc->xformWorld2Vport.eM22) : 1.0;
3907 dcmat.eM21 = dcmat.eM12 = 0;
3910 /* Try to avoid not necessary glyph transformations */
3911 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
3913 lf.lfHeight *= fabs(dcmat.eM11);
3914 lf.lfWidth *= fabs(dcmat.eM11);
3915 dcmat.eM11 = dcmat.eM22 = 1.0;
3918 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
3919 dcmat.eM21, dcmat.eM22);
3922 EnterCriticalSection( &freetype_cs );
3924 /* check the cache first */
3925 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
3926 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
3930 if(list_empty(&font_list)) /* No fonts installed */
3932 TRACE("No fonts installed\n");
3936 TRACE("not in cache\n");
3939 ret->font_desc.matrix = dcmat;
3940 ret->font_desc.lf = lf;
3941 ret->font_desc.can_use_bitmap = can_use_bitmap;
3942 calc_hash(&ret->font_desc);
3943 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
3944 hflist->hfont = hfont;
3945 list_add_head(&ret->hfontlist, &hflist->entry);
3947 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
3948 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
3949 original value lfCharSet. Note this is a special case for
3950 Symbol and doesn't happen at least for "Wingdings*" */
3952 if(!strcmpiW(lf.lfFaceName, SymbolW))
3953 lf.lfCharSet = SYMBOL_CHARSET;
3955 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
3956 switch(lf.lfCharSet) {
3957 case DEFAULT_CHARSET:
3958 csi.fs.fsCsb[0] = 0;
3961 FIXME("Untranslated charset %d\n", lf.lfCharSet);
3962 csi.fs.fsCsb[0] = 0;
3968 if(lf.lfFaceName[0] != '\0') {
3969 SYSTEM_LINKS *font_link;
3970 CHILD_FONT *font_link_entry;
3971 LPWSTR FaceName = lf.lfFaceName;
3973 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
3976 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
3977 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
3978 if (psub->to.charset != -1)
3979 lf.lfCharSet = psub->to.charset;
3982 /* We want a match on name and charset or just name if
3983 charset was DEFAULT_CHARSET. If the latter then
3984 we fixup the returned charset later in get_nearest_charset
3985 where we'll either use the charset of the current ansi codepage
3986 or if that's unavailable the first charset that the font supports.
3988 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3989 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3990 if (!strcmpiW(family->FamilyName, FaceName) ||
3991 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
3993 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3994 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3995 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3996 if(face->scalable || can_use_bitmap)
4002 /* Search by full face name. */
4003 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4004 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4005 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4006 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4007 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
4008 ((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0]))
4010 if(face->scalable || can_use_bitmap)
4017 * Try check the SystemLink list first for a replacement font.
4018 * We may find good replacements there.
4020 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
4022 if(!strcmpiW(font_link->font_name, FaceName) ||
4023 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
4025 TRACE("found entry in system list\n");
4026 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4028 face = font_link_entry->face;
4029 family = face->family;
4030 if(csi.fs.fsCsb[0] &
4031 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
4033 if(face->scalable || can_use_bitmap)
4041 psub = NULL; /* substitution is no more relevant */
4043 /* If requested charset was DEFAULT_CHARSET then try using charset
4044 corresponding to the current ansi codepage */
4045 if (!csi.fs.fsCsb[0])
4048 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
4049 FIXME("TCI failed on codepage %d\n", acp);
4050 csi.fs.fsCsb[0] = 0;
4052 lf.lfCharSet = csi.ciCharset;
4055 /* Face families are in the top 4 bits of lfPitchAndFamily,
4056 so mask with 0xF0 before testing */
4058 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
4059 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
4060 strcpyW(lf.lfFaceName, defFixed);
4061 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
4062 strcpyW(lf.lfFaceName, defSerif);
4063 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
4064 strcpyW(lf.lfFaceName, defSans);
4066 strcpyW(lf.lfFaceName, defSans);
4067 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4068 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4069 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
4070 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4071 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4072 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
4073 if(face->scalable || can_use_bitmap)
4079 last_resort_family = NULL;
4080 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4081 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4082 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4083 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4084 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
4087 if(can_use_bitmap && !last_resort_family)
4088 last_resort_family = family;
4093 if(last_resort_family) {
4094 family = last_resort_family;
4095 csi.fs.fsCsb[0] = 0;
4099 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4100 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4101 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4102 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4103 if(face->scalable) {
4104 csi.fs.fsCsb[0] = 0;
4105 WARN("just using first face for now\n");
4108 if(can_use_bitmap && !last_resort_family)
4109 last_resort_family = family;
4112 if(!last_resort_family) {
4113 FIXME("can't find a single appropriate font - bailing\n");
4119 WARN("could only find a bitmap font - this will probably look awful!\n");
4120 family = last_resort_family;
4121 csi.fs.fsCsb[0] = 0;
4124 it = lf.lfItalic ? 1 : 0;
4125 bd = lf.lfWeight > 550 ? 1 : 0;
4127 height = lf.lfHeight;
4129 face = best = best_bitmap = NULL;
4130 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
4132 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
4136 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
4137 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
4138 new_score = (italic ^ it) + (bold ^ bd);
4139 if(!best || new_score <= score)
4141 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4142 italic, bold, it, bd);
4145 if(best->scalable && score == 0) break;
4149 newdiff = height - (signed int)(best->size.height);
4151 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
4152 if(!best_bitmap || new_score < score ||
4153 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
4155 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
4158 if(score == 0 && diff == 0) break;
4165 face = best->scalable ? best : best_bitmap;
4166 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
4167 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
4170 height = lf.lfHeight;
4174 if(csi.fs.fsCsb[0]) {
4175 ret->charset = lf.lfCharSet;
4176 ret->codepage = csi.ciACP;
4179 ret->charset = get_nearest_charset(face, &ret->codepage);
4181 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
4182 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
4184 ret->aveWidth = height ? lf.lfWidth : 0;
4186 if(!face->scalable) {
4187 /* Windows uses integer scaling factors for bitmap fonts */
4188 INT scale, scaled_height;
4189 GdiFont *cachedfont;
4191 /* FIXME: rotation of bitmap fonts is ignored */
4192 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
4194 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
4195 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4196 dcmat.eM11 = dcmat.eM22 = 1.0;
4197 /* As we changed the matrix, we need to search the cache for the font again,
4198 * otherwise we might explode the cache. */
4199 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4200 TRACE("Found cached font after non-scalable matrix rescale!\n");
4205 calc_hash(&ret->font_desc);
4207 if (height != 0) height = diff;
4208 height += face->size.height;
4210 scale = (height + face->size.height - 1) / face->size.height;
4211 scaled_height = scale * face->size.height;
4212 /* Only jump to the next height if the difference <= 25% original height */
4213 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
4214 /* The jump between unscaled and doubled is delayed by 1 */
4215 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
4216 ret->scale_y = scale;
4218 width = face->size.x_ppem >> 6;
4219 height = face->size.y_ppem >> 6;
4223 TRACE("font scale y: %f\n", ret->scale_y);
4225 ret->ft_face = OpenFontFace(ret, face, width, height);
4234 ret->ntmFlags = face->ntmFlags;
4236 if (ret->charset == SYMBOL_CHARSET &&
4237 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
4240 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
4244 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
4247 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
4248 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
4249 ret->underline = lf.lfUnderline ? 0xff : 0;
4250 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
4251 create_child_font_list(ret);
4253 if (face->vertical) /* We need to try to load the GSUB table */
4255 int length = get_font_data(ret, GSUB_TAG , 0, NULL, 0);
4256 if (length != GDI_ERROR)
4258 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
4259 get_font_data(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
4260 TRACE("Loaded GSUB table of %i bytes\n",length);
4264 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
4271 physdev->font = ret;
4273 LeaveCriticalSection( &freetype_cs );
4274 release_dc_ptr( dc );
4275 return ret ? hfont : 0;
4278 static void dump_gdi_font_list(void)
4281 struct list *elem_ptr;
4283 TRACE("---------- gdiFont Cache ----------\n");
4284 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
4285 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4286 TRACE("gdiFont=%p %s %d\n",
4287 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4290 TRACE("---------- Unused gdiFont Cache ----------\n");
4291 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
4292 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4293 TRACE("gdiFont=%p %s %d\n",
4294 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4297 TRACE("---------- Child gdiFont Cache ----------\n");
4298 LIST_FOR_EACH(elem_ptr, &child_font_list) {
4299 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
4300 TRACE("gdiFont=%p %s %d\n",
4301 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
4305 /*************************************************************
4306 * WineEngDestroyFontInstance
4308 * free the gdiFont associated with this handle
4311 BOOL WineEngDestroyFontInstance(HFONT handle)
4316 struct list *font_elem_ptr, *hfontlist_elem_ptr;
4320 EnterCriticalSection( &freetype_cs );
4322 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
4324 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4325 while(hfontlist_elem_ptr) {
4326 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4327 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4328 if(hflist->hfont == handle) {
4329 TRACE("removing child font %p from child list\n", gdiFont);
4330 list_remove(&gdiFont->entry);
4331 LeaveCriticalSection( &freetype_cs );
4337 TRACE("destroying hfont=%p\n", handle);
4339 dump_gdi_font_list();
4341 font_elem_ptr = list_head(&gdi_font_list);
4342 while(font_elem_ptr) {
4343 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4344 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
4346 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
4347 while(hfontlist_elem_ptr) {
4348 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
4349 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
4350 if(hflist->hfont == handle) {
4351 list_remove(&hflist->entry);
4352 HeapFree(GetProcessHeap(), 0, hflist);
4356 if(list_empty(&gdiFont->hfontlist)) {
4357 TRACE("Moving to Unused list\n");
4358 list_remove(&gdiFont->entry);
4359 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
4364 font_elem_ptr = list_head(&unused_gdi_font_list);
4365 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
4366 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4367 while(font_elem_ptr) {
4368 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
4369 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
4370 TRACE("freeing %p\n", gdiFont);
4371 list_remove(&gdiFont->entry);
4374 LeaveCriticalSection( &freetype_cs );
4378 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
4385 id += IDS_FIRST_SCRIPT;
4386 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
4387 if (!rsrc) return 0;
4388 hMem = LoadResource( gdi32_module, rsrc );
4389 if (!hMem) return 0;
4391 p = LockResource( hMem );
4393 while (id--) p += *p + 1;
4395 i = min(LF_FACESIZE - 1, *p);
4396 memcpy(buffer, p + 1, i * sizeof(WCHAR));
4402 /***************************************************
4403 * create_enum_charset_list
4405 * This function creates charset enumeration list because in DEFAULT_CHARSET
4406 * case, the ANSI codepage's charset takes precedence over other charsets.
4407 * This function works as a filter other than DEFAULT_CHARSET case.
4409 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
4414 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
4415 csi.fs.fsCsb[0] != 0) {
4416 list->element[n].mask = csi.fs.fsCsb[0];
4417 list->element[n].charset = csi.ciCharset;
4418 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
4421 else { /* charset is DEFAULT_CHARSET or invalid. */
4424 /* Set the current codepage's charset as the first element. */
4426 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
4427 csi.fs.fsCsb[0] != 0) {
4428 list->element[n].mask = csi.fs.fsCsb[0];
4429 list->element[n].charset = csi.ciCharset;
4430 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
4434 /* Fill out left elements. */
4435 for (i = 0; i < 32; i++) {
4437 fs.fsCsb[0] = 1L << i;
4439 if (n > 0 && fs.fsCsb[0] == list->element[0].mask)
4440 continue; /* skip, already added. */
4441 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
4442 continue; /* skip, this is an invalid fsCsb bit. */
4444 list->element[n].mask = fs.fsCsb[0];
4445 list->element[n].charset = csi.ciCharset;
4446 load_script_name( i, list->element[n].name );
4455 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
4456 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
4461 if (face->cached_enum_data)
4464 *pelf = face->cached_enum_data->elf;
4465 *pntm = face->cached_enum_data->ntm;
4466 *ptype = face->cached_enum_data->type;
4470 font = alloc_font();
4472 if(face->scalable) {
4473 height = -2048; /* 2048 is the most common em size */
4476 height = face->size.y_ppem >> 6;
4477 width = face->size.x_ppem >> 6;
4479 font->scale_y = 1.0;
4481 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
4487 font->name = strdupW(face->family->FamilyName);
4488 font->ntmFlags = face->ntmFlags;
4490 if (get_outline_text_metrics(font))
4492 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
4494 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
4496 lstrcpynW(pelf->elfLogFont.lfFaceName,
4497 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
4499 lstrcpynW(pelf->elfFullName,
4500 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFullName),
4502 lstrcpynW(pelf->elfStyle,
4503 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
4508 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
4510 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
4512 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
4514 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
4516 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
4517 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
4520 pntm->ntmTm.ntmFlags = face->ntmFlags;
4521 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
4522 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
4523 pntm->ntmFontSig = face->fs;
4525 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
4527 pelf->elfLogFont.lfEscapement = 0;
4528 pelf->elfLogFont.lfOrientation = 0;
4529 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
4530 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
4531 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
4532 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
4533 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
4534 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
4535 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
4536 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
4537 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
4538 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
4539 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
4542 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
4543 *ptype |= TRUETYPE_FONTTYPE;
4544 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
4545 *ptype |= DEVICE_FONTTYPE;
4546 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
4547 *ptype |= RASTER_FONTTYPE;
4549 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
4550 if (face->cached_enum_data)
4552 face->cached_enum_data->elf = *pelf;
4553 face->cached_enum_data->ntm = *pntm;
4554 face->cached_enum_data->type = *ptype;
4560 static BOOL family_matches(Family *family, const LOGFONTW *lf)
4562 struct list *face_elem_ptr;
4564 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
4566 LIST_FOR_EACH(face_elem_ptr, &family->faces)
4568 static const WCHAR spaceW[] = { ' ',0 };
4569 WCHAR full_family_name[LF_FULLFACESIZE];
4570 Face *face = LIST_ENTRY(face_elem_ptr, Face, entry);
4572 if (strlenW(family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4574 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4575 debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
4579 strcpyW(full_family_name, family->FamilyName);
4580 strcatW(full_family_name, spaceW);
4581 strcatW(full_family_name, face->StyleName);
4582 if (!strcmpiW(lf->lfFaceName, full_family_name)) return TRUE;
4588 static BOOL face_matches(Face *face, const LOGFONTW *lf)
4590 static const WCHAR spaceW[] = { ' ',0 };
4591 WCHAR full_family_name[LF_FULLFACESIZE];
4593 if (!strcmpiW(lf->lfFaceName, face->family->FamilyName)) return TRUE;
4595 if (strlenW(face->family->FamilyName) + strlenW(face->StyleName) + 2 > LF_FULLFACESIZE)
4597 FIXME("Length of %s + %s + 2 is longer than LF_FULLFACESIZE\n",
4598 debugstr_w(face->family->FamilyName), debugstr_w(face->StyleName));
4602 strcpyW(full_family_name, face->family->FamilyName);
4603 strcatW(full_family_name, spaceW);
4604 strcatW(full_family_name, face->StyleName);
4605 return !strcmpiW(lf->lfFaceName, full_family_name);
4608 static BOOL enum_face_charsets(Face *face, struct enum_charset_list *list,
4609 FONTENUMPROCW proc, LPARAM lparam)
4612 NEWTEXTMETRICEXW ntm;
4616 GetEnumStructs(face, &elf, &ntm, &type);
4617 for(i = 0; i < list->total; i++) {
4618 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
4619 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
4620 load_script_name( IDS_OEM_DOS, elf.elfScript );
4621 i = list->total; /* break out of loop after enumeration */
4622 } else if(!(face->fs.fsCsb[0] & list->element[i].mask))
4625 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
4626 strcpyW(elf.elfScript, list->element[i].name);
4627 if (!elf.elfScript[0])
4628 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
4630 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
4631 debugstr_w(elf.elfLogFont.lfFaceName),
4632 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
4633 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
4634 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
4635 ntm.ntmTm.ntmFlags);
4636 /* release section before callback (FIXME) */
4637 LeaveCriticalSection( &freetype_cs );
4638 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
4639 EnterCriticalSection( &freetype_cs );
4644 /*************************************************************
4645 * freetype_EnumFonts
4647 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
4651 struct list *family_elem_ptr, *face_elem_ptr;
4653 struct enum_charset_list enum_charsets;
4657 lf.lfCharSet = DEFAULT_CHARSET;
4658 lf.lfPitchAndFamily = 0;
4659 lf.lfFaceName[0] = 0;
4663 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
4665 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
4668 EnterCriticalSection( &freetype_cs );
4669 if(plf->lfFaceName[0]) {
4671 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
4674 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
4675 debugstr_w(psub->to.name));
4677 strcpyW(lf.lfFaceName, psub->to.name);
4681 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4682 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4683 if(family_matches(family, plf)) {
4684 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
4685 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4686 if (!face_matches(face, plf)) continue;
4687 if (!enum_face_charsets(face, &enum_charsets, proc, lparam)) return FALSE;
4692 LIST_FOR_EACH(family_elem_ptr, &font_list) {
4693 family = LIST_ENTRY(family_elem_ptr, Family, entry);
4694 face_elem_ptr = list_head(&family->faces);
4695 face = LIST_ENTRY(face_elem_ptr, Face, entry);
4696 if (!enum_face_charsets(face, &enum_charsets, proc, lparam)) return FALSE;
4699 LeaveCriticalSection( &freetype_cs );
4703 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
4705 pt->x.value = vec->x >> 6;
4706 pt->x.fract = (vec->x & 0x3f) << 10;
4707 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
4708 pt->y.value = vec->y >> 6;
4709 pt->y.fract = (vec->y & 0x3f) << 10;
4710 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
4714 /***************************************************
4715 * According to the MSDN documentation on WideCharToMultiByte,
4716 * certain codepages cannot set the default_used parameter.
4717 * This returns TRUE if the codepage can set that parameter, false else
4718 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
4720 static BOOL codepage_sets_default_used(UINT codepage)
4734 * GSUB Table handling functions
4737 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
4739 const GSUB_CoverageFormat1* cf1;
4743 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
4745 int count = GET_BE_WORD(cf1->GlyphCount);
4747 TRACE("Coverage Format 1, %i glyphs\n",count);
4748 for (i = 0; i < count; i++)
4749 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
4753 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
4755 const GSUB_CoverageFormat2* cf2;
4758 cf2 = (const GSUB_CoverageFormat2*)cf1;
4760 count = GET_BE_WORD(cf2->RangeCount);
4761 TRACE("Coverage Format 2, %i ranges\n",count);
4762 for (i = 0; i < count; i++)
4764 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
4766 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
4767 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
4769 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
4770 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
4776 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
4781 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
4783 const GSUB_ScriptList *script;
4784 const GSUB_Script *deflt = NULL;
4786 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
4788 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
4789 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
4791 const GSUB_Script *scr;
4794 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
4795 scr = (const GSUB_Script*)((const BYTE*)script + offset);
4797 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
4799 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
4805 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
4809 const GSUB_LangSys *Lang;
4811 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
4813 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
4815 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
4816 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4818 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
4821 offset = GET_BE_WORD(script->DefaultLangSys);
4824 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
4830 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
4833 const GSUB_FeatureList *feature;
4834 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
4836 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
4837 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
4839 int index = GET_BE_WORD(lang->FeatureIndex[i]);
4840 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
4842 const GSUB_Feature *feat;
4843 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
4850 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
4854 const GSUB_LookupList *lookup;
4855 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
4857 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
4858 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
4860 const GSUB_LookupTable *look;
4861 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
4862 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
4863 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
4864 if (GET_BE_WORD(look->LookupType) != 1)
4865 FIXME("We only handle SubType 1\n");
4870 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
4872 const GSUB_SingleSubstFormat1 *ssf1;
4873 offset = GET_BE_WORD(look->SubTable[j]);
4874 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
4875 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
4877 int offset = GET_BE_WORD(ssf1->Coverage);
4878 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
4879 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
4881 TRACE(" Glyph 0x%x ->",glyph);
4882 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
4883 TRACE(" 0x%x\n",glyph);
4888 const GSUB_SingleSubstFormat2 *ssf2;
4892 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
4893 offset = GET_BE_WORD(ssf1->Coverage);
4894 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
4895 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
4896 TRACE(" Coverage index %i\n",index);
4899 TRACE(" Glyph is 0x%x ->",glyph);
4900 glyph = GET_BE_WORD(ssf2->Substitute[index]);
4901 TRACE("0x%x\n",glyph);
4910 static const char* get_opentype_script(const GdiFont *font)
4913 * I am not sure if this is the correct way to generate our script tag
4916 switch (font->charset)
4918 case ANSI_CHARSET: return "latn";
4919 case BALTIC_CHARSET: return "latn"; /* ?? */
4920 case CHINESEBIG5_CHARSET: return "hani";
4921 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
4922 case GB2312_CHARSET: return "hani";
4923 case GREEK_CHARSET: return "grek";
4924 case HANGUL_CHARSET: return "hang";
4925 case RUSSIAN_CHARSET: return "cyrl";
4926 case SHIFTJIS_CHARSET: return "kana";
4927 case TURKISH_CHARSET: return "latn"; /* ?? */
4928 case VIETNAMESE_CHARSET: return "latn";
4929 case JOHAB_CHARSET: return "latn"; /* ?? */
4930 case ARABIC_CHARSET: return "arab";
4931 case HEBREW_CHARSET: return "hebr";
4932 case THAI_CHARSET: return "thai";
4933 default: return "latn";
4937 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
4939 const GSUB_Header *header;
4940 const GSUB_Script *script;
4941 const GSUB_LangSys *language;
4942 const GSUB_Feature *feature;
4944 if (!font->GSUB_Table)
4947 header = font->GSUB_Table;
4949 script = GSUB_get_script_table(header, get_opentype_script(font));
4952 TRACE("Script not found\n");
4955 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
4958 TRACE("Language not found\n");
4961 feature = GSUB_get_feature(header, language, "vrt2");
4963 feature = GSUB_get_feature(header, language, "vert");
4966 TRACE("vrt2/vert feature not found\n");
4969 return GSUB_apply_feature(header, feature, glyph);
4972 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
4976 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
4977 WCHAR wc = (WCHAR)glyph;
4979 BOOL *default_used_pointer;
4982 default_used_pointer = NULL;
4983 default_used = FALSE;
4984 if (codepage_sets_default_used(font->codepage))
4985 default_used_pointer = &default_used;
4986 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
4989 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
4990 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
4994 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
4996 if (glyph < 0x100) glyph += 0xf000;
4997 /* there is a number of old pre-Unicode "broken" TTFs, which
4998 do have symbols at U+00XX instead of U+f0XX */
4999 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
5000 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
5002 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
5007 /*************************************************************
5008 * freetype_GetGlyphIndices
5010 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
5012 struct freetype_physdev *physdev = get_freetype_dev( dev );
5015 BOOL got_default = FALSE;
5019 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
5020 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
5023 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
5025 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
5030 EnterCriticalSection( &freetype_cs );
5032 for(i = 0; i < count; i++)
5034 pgi[i] = get_glyph_index(physdev->font, lpstr[i]);
5039 if (FT_IS_SFNT(physdev->font->ft_face))
5041 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(physdev->font->ft_face, ft_sfnt_os2);
5042 default_char = (pOS2->usDefaultChar ? get_glyph_index(physdev->font, pOS2->usDefaultChar) : 0);
5047 get_text_metrics(physdev->font, &textm);
5048 default_char = textm.tmDefaultChar;
5052 pgi[i] = default_char;
5055 LeaveCriticalSection( &freetype_cs );
5059 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
5061 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
5062 return !memcmp(matrix, &identity, sizeof(FMAT2));
5065 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
5067 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
5068 return !memcmp(matrix, &identity, sizeof(MAT2));
5071 static inline BYTE get_max_level( UINT format )
5075 case GGO_GRAY2_BITMAP: return 4;
5076 case GGO_GRAY4_BITMAP: return 16;
5077 case GGO_GRAY8_BITMAP: return 64;
5082 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5084 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
5085 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5088 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
5089 FT_Face ft_face = incoming_font->ft_face;
5090 GdiFont *font = incoming_font;
5091 FT_UInt glyph_index;
5092 DWORD width, height, pitch, needed = 0;
5093 FT_Bitmap ft_bitmap;
5095 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
5097 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
5098 double widthRatio = 1.0;
5099 FT_Matrix transMat = identityMat;
5100 FT_Matrix transMatUnrotated;
5101 BOOL needsTransform = FALSE;
5102 BOOL tategaki = (font->GSUB_Table != NULL);
5103 UINT original_index;
5105 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
5106 buflen, buf, lpmat);
5108 TRACE("font transform %f %f %f %f\n",
5109 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
5110 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
5112 if(format & GGO_GLYPH_INDEX) {
5113 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
5114 original_index = glyph;
5115 format &= ~GGO_GLYPH_INDEX;
5117 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
5118 ft_face = font->ft_face;
5119 original_index = glyph_index;
5122 if(format & GGO_UNHINTED) {
5123 load_flags |= FT_LOAD_NO_HINTING;
5124 format &= ~GGO_UNHINTED;
5127 /* tategaki never appears to happen to lower glyph index */
5128 if (glyph_index < TATEGAKI_LOWER_BOUND )
5131 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
5132 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
5133 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
5134 font->gmsize * sizeof(GM*));
5136 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
5137 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
5139 *lpgm = FONT_GM(font,original_index)->gm;
5140 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5141 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5142 lpgm->gmCellIncX, lpgm->gmCellIncY);
5143 return 1; /* FIXME */
5147 if (!font->gm[original_index / GM_BLOCK_SIZE])
5148 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
5150 /* Scaling factor */
5155 get_text_metrics(font, &tm);
5157 widthRatio = (double)font->aveWidth;
5158 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5161 widthRatio = font->scale_y;
5163 /* Scaling transform */
5164 if (widthRatio != 1.0 || font->scale_y != 1.0)
5167 scaleMat.xx = FT_FixedFromFloat(widthRatio);
5170 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
5172 pFT_Matrix_Multiply(&scaleMat, &transMat);
5173 needsTransform = TRUE;
5176 /* Slant transform */
5177 if (font->fake_italic) {
5180 slantMat.xx = (1 << 16);
5181 slantMat.xy = ((1 << 16) >> 2);
5183 slantMat.yy = (1 << 16);
5184 pFT_Matrix_Multiply(&slantMat, &transMat);
5185 needsTransform = TRUE;
5188 /* Rotation transform */
5189 transMatUnrotated = transMat;
5190 if(font->orientation && !tategaki) {
5191 FT_Matrix rotationMat;
5193 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
5194 pFT_Vector_Unit(&vecAngle, angle);
5195 rotationMat.xx = vecAngle.x;
5196 rotationMat.xy = -vecAngle.y;
5197 rotationMat.yx = -rotationMat.xy;
5198 rotationMat.yy = rotationMat.xx;
5200 pFT_Matrix_Multiply(&rotationMat, &transMat);
5201 needsTransform = TRUE;
5204 /* World transform */
5205 if (!is_identity_FMAT2(&font->font_desc.matrix))
5208 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
5209 worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
5210 worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
5211 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
5212 pFT_Matrix_Multiply(&worldMat, &transMat);
5213 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
5214 needsTransform = TRUE;
5217 /* Extra transformation specified by caller */
5218 if (!is_identity_MAT2(lpmat))
5221 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
5222 extraMat.xy = FT_FixedFromFIXED(lpmat->eM12);
5223 extraMat.yx = FT_FixedFromFIXED(lpmat->eM21);
5224 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
5225 pFT_Matrix_Multiply(&extraMat, &transMat);
5226 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
5227 needsTransform = TRUE;
5230 if (needsTransform || (format == GGO_NATIVE || format == GGO_BEZIER ||
5231 format == GGO_GRAY2_BITMAP || format == GGO_GRAY4_BITMAP ||
5232 format == GGO_GRAY8_BITMAP))
5234 load_flags |= FT_LOAD_NO_BITMAP;
5237 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
5240 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
5244 if(!needsTransform) {
5245 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
5246 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
5247 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
5249 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
5250 bottom = (ft_face->glyph->metrics.horiBearingY -
5251 ft_face->glyph->metrics.height) & -64;
5252 lpgm->gmCellIncX = adv;
5253 lpgm->gmCellIncY = 0;
5260 for(xc = 0; xc < 2; xc++) {
5261 for(yc = 0; yc < 2; yc++) {
5262 vec.x = (ft_face->glyph->metrics.horiBearingX +
5263 xc * ft_face->glyph->metrics.width);
5264 vec.y = ft_face->glyph->metrics.horiBearingY -
5265 yc * ft_face->glyph->metrics.height;
5266 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
5267 pFT_Vector_Transform(&vec, &transMat);
5268 if(xc == 0 && yc == 0) {
5269 left = right = vec.x;
5270 top = bottom = vec.y;
5272 if(vec.x < left) left = vec.x;
5273 else if(vec.x > right) right = vec.x;
5274 if(vec.y < bottom) bottom = vec.y;
5275 else if(vec.y > top) top = vec.y;
5280 right = (right + 63) & -64;
5281 bottom = bottom & -64;
5282 top = (top + 63) & -64;
5284 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
5285 vec.x = ft_face->glyph->metrics.horiAdvance;
5287 pFT_Vector_Transform(&vec, &transMat);
5288 lpgm->gmCellIncX = (vec.x+63) >> 6;
5289 lpgm->gmCellIncY = -((vec.y+63) >> 6);
5291 vec.x = ft_face->glyph->metrics.horiAdvance;
5293 pFT_Vector_Transform(&vec, &transMatUnrotated);
5294 adv = (vec.x+63) >> 6;
5298 bbx = (right - left) >> 6;
5299 lpgm->gmBlackBoxX = (right - left) >> 6;
5300 lpgm->gmBlackBoxY = (top - bottom) >> 6;
5301 lpgm->gmptGlyphOrigin.x = left >> 6;
5302 lpgm->gmptGlyphOrigin.y = top >> 6;
5304 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5305 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5306 lpgm->gmCellIncX, lpgm->gmCellIncY);
5308 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
5309 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
5311 FONT_GM(font,original_index)->gm = *lpgm;
5312 FONT_GM(font,original_index)->adv = adv;
5313 FONT_GM(font,original_index)->lsb = lsb;
5314 FONT_GM(font,original_index)->bbx = bbx;
5315 FONT_GM(font,original_index)->init = TRUE;
5318 if(format == GGO_METRICS)
5320 return 1; /* FIXME */
5323 if(ft_face->glyph->format != ft_glyph_format_outline &&
5324 (format == GGO_NATIVE || format == GGO_BEZIER))
5326 TRACE("loaded a bitmap\n");
5332 width = lpgm->gmBlackBoxX;
5333 height = lpgm->gmBlackBoxY;
5334 pitch = ((width + 31) >> 5) << 2;
5335 needed = pitch * height;
5337 if(!buf || !buflen) break;
5339 switch(ft_face->glyph->format) {
5340 case ft_glyph_format_bitmap:
5342 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5343 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
5344 INT h = ft_face->glyph->bitmap.rows;
5346 memcpy(dst, src, w);
5347 src += ft_face->glyph->bitmap.pitch;
5353 case ft_glyph_format_outline:
5354 ft_bitmap.width = width;
5355 ft_bitmap.rows = height;
5356 ft_bitmap.pitch = pitch;
5357 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
5358 ft_bitmap.buffer = buf;
5361 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5363 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5365 /* Note: FreeType will only set 'black' bits for us. */
5366 memset(buf, 0, needed);
5367 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5371 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5376 case GGO_GRAY2_BITMAP:
5377 case GGO_GRAY4_BITMAP:
5378 case GGO_GRAY8_BITMAP:
5379 case WINE_GGO_GRAY16_BITMAP:
5381 unsigned int max_level, row, col;
5384 width = lpgm->gmBlackBoxX;
5385 height = lpgm->gmBlackBoxY;
5386 pitch = (width + 3) / 4 * 4;
5387 needed = pitch * height;
5389 if(!buf || !buflen) break;
5391 max_level = get_max_level( format );
5393 switch(ft_face->glyph->format) {
5394 case ft_glyph_format_bitmap:
5396 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5397 INT h = ft_face->glyph->bitmap.rows;
5399 memset( buf, 0, needed );
5401 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
5402 if (src[x / 8] & masks[x % 8]) dst[x] = max_level;
5403 src += ft_face->glyph->bitmap.pitch;
5408 case ft_glyph_format_outline:
5410 ft_bitmap.width = width;
5411 ft_bitmap.rows = height;
5412 ft_bitmap.pitch = pitch;
5413 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
5414 ft_bitmap.buffer = buf;
5417 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
5419 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
5421 memset(ft_bitmap.buffer, 0, buflen);
5423 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
5425 if (max_level != 255)
5427 for (row = 0, start = buf; row < height; row++)
5429 for (col = 0, ptr = start; col < width; col++, ptr++)
5430 *ptr = (((int)*ptr) * max_level + 128) / 256;
5438 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
5444 case WINE_GGO_HRGB_BITMAP:
5445 case WINE_GGO_HBGR_BITMAP:
5446 case WINE_GGO_VRGB_BITMAP:
5447 case WINE_GGO_VBGR_BITMAP:
5448 #ifdef HAVE_FREETYPE_FTLCDFIL_H
5450 switch (ft_face->glyph->format)
5452 case FT_GLYPH_FORMAT_BITMAP:
5457 width = lpgm->gmBlackBoxX;
5458 height = lpgm->gmBlackBoxY;
5460 needed = pitch * height;
5462 if (!buf || !buflen) break;
5464 memset(buf, 0, buflen);
5466 src = ft_face->glyph->bitmap.buffer;
5467 src_pitch = ft_face->glyph->bitmap.pitch;
5469 height = min( height, ft_face->glyph->bitmap.rows );
5472 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
5474 if ( src[x / 8] & masks[x % 8] )
5475 ((unsigned int *)dst)[x] = ~0u;
5484 case FT_GLYPH_FORMAT_OUTLINE:
5488 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
5489 INT x_shift, y_shift;
5491 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
5492 FT_Render_Mode render_mode =
5493 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
5494 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
5496 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
5498 if ( render_mode == FT_RENDER_MODE_LCD)
5500 lpgm->gmBlackBoxX += 2;
5501 lpgm->gmptGlyphOrigin.x -= 1;
5505 lpgm->gmBlackBoxY += 2;
5506 lpgm->gmptGlyphOrigin.y += 1;
5510 width = lpgm->gmBlackBoxX;
5511 height = lpgm->gmBlackBoxY;
5513 needed = pitch * height;
5515 if (!buf || !buflen) break;
5517 memset(buf, 0, buflen);
5519 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
5521 if ( needsTransform )
5522 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
5524 if ( pFT_Library_SetLcdFilter )
5525 pFT_Library_SetLcdFilter( library, lcdfilter );
5526 pFT_Render_Glyph (ft_face->glyph, render_mode);
5528 src = ft_face->glyph->bitmap.buffer;
5529 src_pitch = ft_face->glyph->bitmap.pitch;
5530 src_width = ft_face->glyph->bitmap.width;
5531 src_height = ft_face->glyph->bitmap.rows;
5533 if ( render_mode == FT_RENDER_MODE_LCD)
5541 rgb_interval = src_pitch;
5546 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
5547 if ( x_shift < 0 ) x_shift = 0;
5548 if ( x_shift + (src_width / hmul) > width )
5549 x_shift = width - (src_width / hmul);
5551 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
5552 if ( y_shift < 0 ) y_shift = 0;
5553 if ( y_shift + (src_height / vmul) > height )
5554 y_shift = height - (src_height / vmul);
5556 dst += x_shift + y_shift * ( pitch / 4 );
5557 while ( src_height )
5559 for ( x = 0; x < src_width / hmul; x++ )
5563 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
5564 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5565 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
5566 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5570 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
5571 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
5572 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
5573 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
5576 src += src_pitch * vmul;
5585 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
5597 int contour, point = 0, first_pt;
5598 FT_Outline *outline = &ft_face->glyph->outline;
5599 TTPOLYGONHEADER *pph;
5601 DWORD pph_start, cpfx, type;
5603 if(buflen == 0) buf = NULL;
5605 if (needsTransform && buf) {
5606 pFT_Outline_Transform(outline, &transMat);
5609 for(contour = 0; contour < outline->n_contours; contour++) {
5611 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5614 pph->dwType = TT_POLYGON_TYPE;
5615 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5617 needed += sizeof(*pph);
5619 while(point <= outline->contours[contour]) {
5620 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5621 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5622 TT_PRIM_LINE : TT_PRIM_QSPLINE;
5626 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5629 } while(point <= outline->contours[contour] &&
5630 (outline->tags[point] & FT_Curve_Tag_On) ==
5631 (outline->tags[point-1] & FT_Curve_Tag_On));
5632 /* At the end of a contour Windows adds the start point, but
5634 if(point > outline->contours[contour] &&
5635 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
5637 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
5639 } else if(point <= outline->contours[contour] &&
5640 outline->tags[point] & FT_Curve_Tag_On) {
5641 /* add closing pt for bezier */
5643 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5651 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5654 pph->cb = needed - pph_start;
5660 /* Convert the quadratic Beziers to cubic Beziers.
5661 The parametric eqn for a cubic Bezier is, from PLRM:
5662 r(t) = at^3 + bt^2 + ct + r0
5663 with the control points:
5668 A quadratic Bezier has the form:
5669 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
5671 So equating powers of t leads to:
5672 r1 = 2/3 p1 + 1/3 p0
5673 r2 = 2/3 p1 + 1/3 p2
5674 and of course r0 = p0, r3 = p2
5677 int contour, point = 0, first_pt;
5678 FT_Outline *outline = &ft_face->glyph->outline;
5679 TTPOLYGONHEADER *pph;
5681 DWORD pph_start, cpfx, type;
5682 FT_Vector cubic_control[4];
5683 if(buflen == 0) buf = NULL;
5685 if (needsTransform && buf) {
5686 pFT_Outline_Transform(outline, &transMat);
5689 for(contour = 0; contour < outline->n_contours; contour++) {
5691 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
5694 pph->dwType = TT_POLYGON_TYPE;
5695 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
5697 needed += sizeof(*pph);
5699 while(point <= outline->contours[contour]) {
5700 ppc = (TTPOLYCURVE *)((char *)buf + needed);
5701 type = (outline->tags[point] & FT_Curve_Tag_On) ?
5702 TT_PRIM_LINE : TT_PRIM_CSPLINE;
5705 if(type == TT_PRIM_LINE) {
5707 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
5711 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
5714 /* FIXME: Possible optimization in endpoint calculation
5715 if there are two consecutive curves */
5716 cubic_control[0] = outline->points[point-1];
5717 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
5718 cubic_control[0].x += outline->points[point].x + 1;
5719 cubic_control[0].y += outline->points[point].y + 1;
5720 cubic_control[0].x >>= 1;
5721 cubic_control[0].y >>= 1;
5723 if(point+1 > outline->contours[contour])
5724 cubic_control[3] = outline->points[first_pt];
5726 cubic_control[3] = outline->points[point+1];
5727 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
5728 cubic_control[3].x += outline->points[point].x + 1;
5729 cubic_control[3].y += outline->points[point].y + 1;
5730 cubic_control[3].x >>= 1;
5731 cubic_control[3].y >>= 1;
5734 /* r1 = 1/3 p0 + 2/3 p1
5735 r2 = 1/3 p2 + 2/3 p1 */
5736 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
5737 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
5738 cubic_control[2] = cubic_control[1];
5739 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
5740 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
5741 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
5742 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
5744 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
5745 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
5746 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
5751 } while(point <= outline->contours[contour] &&
5752 (outline->tags[point] & FT_Curve_Tag_On) ==
5753 (outline->tags[point-1] & FT_Curve_Tag_On));
5754 /* At the end of a contour Windows adds the start point,
5755 but only for Beziers and we've already done that.
5757 if(point <= outline->contours[contour] &&
5758 outline->tags[point] & FT_Curve_Tag_On) {
5759 /* This is the closing pt of a bezier, but we've already
5760 added it, so just inc point and carry on */
5767 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
5770 pph->cb = needed - pph_start;
5776 FIXME("Unsupported format %d\n", format);
5782 static BOOL get_bitmap_text_metrics(GdiFont *font)
5784 FT_Face ft_face = font->ft_face;
5785 FT_WinFNT_HeaderRec winfnt_header;
5786 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
5787 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
5788 font->potm->otmSize = size;
5790 #define TM font->potm->otmTextMetrics
5791 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
5793 TM.tmHeight = winfnt_header.pixel_height;
5794 TM.tmAscent = winfnt_header.ascent;
5795 TM.tmDescent = TM.tmHeight - TM.tmAscent;
5796 TM.tmInternalLeading = winfnt_header.internal_leading;
5797 TM.tmExternalLeading = winfnt_header.external_leading;
5798 TM.tmAveCharWidth = winfnt_header.avg_width;
5799 TM.tmMaxCharWidth = winfnt_header.max_width;
5800 TM.tmWeight = winfnt_header.weight;
5802 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
5803 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
5804 TM.tmFirstChar = winfnt_header.first_char;
5805 TM.tmLastChar = winfnt_header.last_char;
5806 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
5807 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
5808 TM.tmItalic = winfnt_header.italic;
5809 TM.tmUnderlined = font->underline;
5810 TM.tmStruckOut = font->strikeout;
5811 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
5812 TM.tmCharSet = winfnt_header.charset;
5816 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
5817 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
5818 TM.tmHeight = TM.tmAscent + TM.tmDescent;
5819 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
5820 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
5821 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
5822 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
5823 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
5825 TM.tmDigitizedAspectX = 96; /* FIXME */
5826 TM.tmDigitizedAspectY = 96; /* FIXME */
5828 TM.tmLastChar = 255;
5829 TM.tmDefaultChar = 32;
5830 TM.tmBreakChar = 32;
5831 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
5832 TM.tmUnderlined = font->underline;
5833 TM.tmStruckOut = font->strikeout;
5834 /* NB inverted meaning of TMPF_FIXED_PITCH */
5835 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
5836 TM.tmCharSet = font->charset;
5844 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
5846 double scale_x, scale_y;
5850 scale_x = (double)font->aveWidth;
5851 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5854 scale_x = font->scale_y;
5856 scale_x *= fabs(font->font_desc.matrix.eM11);
5857 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5859 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5860 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5862 SCALE_Y(ptm->tmHeight);
5863 SCALE_Y(ptm->tmAscent);
5864 SCALE_Y(ptm->tmDescent);
5865 SCALE_Y(ptm->tmInternalLeading);
5866 SCALE_Y(ptm->tmExternalLeading);
5867 SCALE_Y(ptm->tmOverhang);
5869 SCALE_X(ptm->tmAveCharWidth);
5870 SCALE_X(ptm->tmMaxCharWidth);
5876 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
5878 double scale_x, scale_y;
5882 scale_x = (double)font->aveWidth;
5883 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5886 scale_x = font->scale_y;
5888 scale_x *= fabs(font->font_desc.matrix.eM11);
5889 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
5891 scale_font_metrics(font, &potm->otmTextMetrics);
5893 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
5894 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
5896 SCALE_Y(potm->otmAscent);
5897 SCALE_Y(potm->otmDescent);
5898 SCALE_Y(potm->otmLineGap);
5899 SCALE_Y(potm->otmsCapEmHeight);
5900 SCALE_Y(potm->otmsXHeight);
5901 SCALE_Y(potm->otmrcFontBox.top);
5902 SCALE_Y(potm->otmrcFontBox.bottom);
5903 SCALE_X(potm->otmrcFontBox.left);
5904 SCALE_X(potm->otmrcFontBox.right);
5905 SCALE_Y(potm->otmMacAscent);
5906 SCALE_Y(potm->otmMacDescent);
5907 SCALE_Y(potm->otmMacLineGap);
5908 SCALE_X(potm->otmptSubscriptSize.x);
5909 SCALE_Y(potm->otmptSubscriptSize.y);
5910 SCALE_X(potm->otmptSubscriptOffset.x);
5911 SCALE_Y(potm->otmptSubscriptOffset.y);
5912 SCALE_X(potm->otmptSuperscriptSize.x);
5913 SCALE_Y(potm->otmptSuperscriptSize.y);
5914 SCALE_X(potm->otmptSuperscriptOffset.x);
5915 SCALE_Y(potm->otmptSuperscriptOffset.y);
5916 SCALE_Y(potm->otmsStrikeoutSize);
5917 SCALE_Y(potm->otmsStrikeoutPosition);
5918 SCALE_Y(potm->otmsUnderscoreSize);
5919 SCALE_Y(potm->otmsUnderscorePosition);
5925 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
5929 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
5931 /* Make sure that the font has sane width/height ratio */
5934 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
5936 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
5941 *ptm = font->potm->otmTextMetrics;
5942 scale_font_metrics(font, ptm);
5946 static BOOL face_has_symbol_charmap(FT_Face ft_face)
5950 for(i = 0; i < ft_face->num_charmaps; i++)
5952 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
5958 static BOOL get_outline_text_metrics(GdiFont *font)
5961 FT_Face ft_face = font->ft_face;
5962 UINT needed, lenfam, lensty;
5964 TT_HoriHeader *pHori;
5965 TT_Postscript *pPost;
5966 FT_Fixed x_scale, y_scale;
5967 WCHAR *family_nameW, *style_nameW;
5968 static const WCHAR spaceW[] = {' ', '\0'};
5970 INT ascent, descent;
5972 TRACE("font=%p\n", font);
5974 if(!FT_IS_SCALABLE(ft_face))
5977 needed = sizeof(*font->potm);
5979 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
5980 family_nameW = strdupW(font->name);
5982 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
5984 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
5985 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
5986 style_nameW, lensty/sizeof(WCHAR));
5988 /* These names should be read from the TT name table */
5990 /* length of otmpFamilyName */
5993 /* length of otmpFaceName */
5994 if ((ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) == 0) {
5995 needed += lenfam; /* just the family name */
5997 needed += lenfam + lensty; /* family + " " + style */
6000 /* length of otmpStyleName */
6003 /* length of otmpFullName */
6004 needed += lenfam + lensty;
6007 x_scale = ft_face->size->metrics.x_scale;
6008 y_scale = ft_face->size->metrics.y_scale;
6010 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
6012 FIXME("Can't find OS/2 table - not TT font?\n");
6016 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
6018 FIXME("Can't find HHEA table - not TT font?\n");
6022 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
6024 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",
6025 pOS2->usWinAscent, pOS2->usWinDescent,
6026 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
6027 ft_face->ascender, ft_face->descender, ft_face->height,
6028 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
6029 ft_face->bbox.yMax, ft_face->bbox.yMin);
6031 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
6032 font->potm->otmSize = needed;
6034 #define TM font->potm->otmTextMetrics
6036 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
6037 ascent = pHori->Ascender;
6038 descent = -pHori->Descender;
6040 ascent = pOS2->usWinAscent;
6041 descent = pOS2->usWinDescent;
6045 TM.tmAscent = font->yMax;
6046 TM.tmDescent = -font->yMin;
6047 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
6049 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
6050 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
6051 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
6052 - ft_face->units_per_EM, y_scale) + 32) >> 6;
6055 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6058 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6060 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
6061 ((ascent + descent) -
6062 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
6064 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
6065 if (TM.tmAveCharWidth == 0) {
6066 TM.tmAveCharWidth = 1;
6068 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
6069 TM.tmWeight = FW_REGULAR;
6070 if (font->fake_bold)
6071 TM.tmWeight = FW_BOLD;
6074 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
6076 if (pOS2->usWeightClass > FW_MEDIUM)
6077 TM.tmWeight = pOS2->usWeightClass;
6079 else if (pOS2->usWeightClass <= FW_MEDIUM)
6080 TM.tmWeight = pOS2->usWeightClass;
6083 TM.tmDigitizedAspectX = 300;
6084 TM.tmDigitizedAspectY = 300;
6085 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6086 * symbol range to 0 - f0ff
6089 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
6094 case 1257: /* Baltic */
6095 TM.tmLastChar = 0xf8fd;
6098 TM.tmLastChar = 0xf0ff;
6100 TM.tmBreakChar = 0x20;
6101 TM.tmDefaultChar = 0x1f;
6105 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
6106 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
6108 if(pOS2->usFirstCharIndex <= 1)
6109 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
6110 else if (pOS2->usFirstCharIndex > 0xff)
6111 TM.tmBreakChar = 0x20;
6113 TM.tmBreakChar = pOS2->usFirstCharIndex;
6114 TM.tmDefaultChar = TM.tmBreakChar - 1;
6116 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
6117 TM.tmUnderlined = font->underline;
6118 TM.tmStruckOut = font->strikeout;
6120 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6121 if(!FT_IS_FIXED_WIDTH(ft_face) &&
6122 (pOS2->version == 0xFFFFU ||
6123 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
6124 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
6126 TM.tmPitchAndFamily = 0;
6128 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
6130 case PAN_FAMILY_SCRIPT:
6131 TM.tmPitchAndFamily |= FF_SCRIPT;
6134 case PAN_FAMILY_DECORATIVE:
6135 TM.tmPitchAndFamily |= FF_DECORATIVE;
6140 case PAN_FAMILY_TEXT_DISPLAY:
6141 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
6142 /* which is clearly not what the panose spec says. */
6144 if(TM.tmPitchAndFamily == 0 || /* fixed */
6145 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
6146 TM.tmPitchAndFamily = FF_MODERN;
6149 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
6154 TM.tmPitchAndFamily |= FF_DONTCARE;
6157 case PAN_SERIF_COVE:
6158 case PAN_SERIF_OBTUSE_COVE:
6159 case PAN_SERIF_SQUARE_COVE:
6160 case PAN_SERIF_OBTUSE_SQUARE_COVE:
6161 case PAN_SERIF_SQUARE:
6162 case PAN_SERIF_THIN:
6163 case PAN_SERIF_BONE:
6164 case PAN_SERIF_EXAGGERATED:
6165 case PAN_SERIF_TRIANGLE:
6166 TM.tmPitchAndFamily |= FF_ROMAN;
6169 case PAN_SERIF_NORMAL_SANS:
6170 case PAN_SERIF_OBTUSE_SANS:
6171 case PAN_SERIF_PERP_SANS:
6172 case PAN_SERIF_FLARED:
6173 case PAN_SERIF_ROUNDED:
6174 TM.tmPitchAndFamily |= FF_SWISS;
6181 if(FT_IS_SCALABLE(ft_face))
6182 TM.tmPitchAndFamily |= TMPF_VECTOR;
6184 if(FT_IS_SFNT(ft_face))
6186 if (font->ntmFlags & NTM_PS_OPENTYPE)
6187 TM.tmPitchAndFamily |= TMPF_DEVICE;
6189 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
6192 TM.tmCharSet = font->charset;
6194 font->potm->otmFiller = 0;
6195 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
6196 font->potm->otmfsSelection = pOS2->fsSelection;
6197 font->potm->otmfsType = pOS2->fsType;
6198 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
6199 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
6200 font->potm->otmItalicAngle = 0; /* POST table */
6201 font->potm->otmEMSquare = ft_face->units_per_EM;
6202 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
6203 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
6204 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
6205 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
6206 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
6207 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
6208 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
6209 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
6210 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
6211 font->potm->otmMacAscent = TM.tmAscent;
6212 font->potm->otmMacDescent = -TM.tmDescent;
6213 font->potm->otmMacLineGap = font->potm->otmLineGap;
6214 font->potm->otmusMinimumPPEM = 0; /* TT Header */
6215 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
6216 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
6217 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
6218 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
6219 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
6220 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
6221 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
6222 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
6223 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
6224 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
6226 font->potm->otmsUnderscoreSize = 0;
6227 font->potm->otmsUnderscorePosition = 0;
6229 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
6230 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
6234 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
6235 cp = (char*)font->potm + sizeof(*font->potm);
6236 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
6237 strcpyW((WCHAR*)cp, family_nameW);
6239 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
6240 strcpyW((WCHAR*)cp, style_nameW);
6242 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
6243 strcpyW((WCHAR*)cp, family_nameW);
6244 if (ft_face->style_flags & (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) {
6245 strcatW((WCHAR*)cp, spaceW);
6246 strcatW((WCHAR*)cp, style_nameW);
6247 cp += lenfam + lensty;
6250 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
6251 strcpyW((WCHAR*)cp, family_nameW);
6252 strcatW((WCHAR*)cp, spaceW);
6253 strcatW((WCHAR*)cp, style_nameW);
6257 HeapFree(GetProcessHeap(), 0, style_nameW);
6258 HeapFree(GetProcessHeap(), 0, family_nameW);
6262 /*************************************************************
6263 * freetype_GetGlyphOutline
6265 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
6266 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
6268 struct freetype_physdev *physdev = get_freetype_dev( dev );
6273 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
6274 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
6278 EnterCriticalSection( &freetype_cs );
6279 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, buflen, buf, lpmat );
6280 LeaveCriticalSection( &freetype_cs );
6284 /*************************************************************
6285 * freetype_GetTextMetrics
6287 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
6289 struct freetype_physdev *physdev = get_freetype_dev( dev );
6294 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
6295 return dev->funcs->pGetTextMetrics( dev, metrics );
6299 EnterCriticalSection( &freetype_cs );
6300 ret = get_text_metrics( physdev->font, metrics );
6301 LeaveCriticalSection( &freetype_cs );
6305 /*************************************************************
6306 * freetype_GetOutlineTextMetrics
6308 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
6310 struct freetype_physdev *physdev = get_freetype_dev( dev );
6315 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
6316 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
6319 TRACE("font=%p\n", physdev->font);
6321 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
6324 EnterCriticalSection( &freetype_cs );
6326 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
6328 if(cbSize >= physdev->font->potm->otmSize)
6330 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
6331 scale_outline_font_metrics(physdev->font, potm);
6333 ret = physdev->font->potm->otmSize;
6335 LeaveCriticalSection( &freetype_cs );
6339 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
6341 HFONTLIST *hfontlist;
6342 child->font = alloc_font();
6343 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
6344 if(!child->font->ft_face)
6346 free_font(child->font);
6351 child->font->font_desc = font->font_desc;
6352 child->font->ntmFlags = child->face->ntmFlags;
6353 child->font->orientation = font->orientation;
6354 child->font->scale_y = font->scale_y;
6355 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
6356 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
6357 child->font->name = strdupW(child->face->family->FamilyName);
6358 list_add_head(&child->font->hfontlist, &hfontlist->entry);
6359 child->font->base_font = font;
6360 list_add_head(&child_font_list, &child->font->entry);
6361 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
6365 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
6368 CHILD_FONT *child_font;
6371 font = font->base_font;
6373 *linked_font = font;
6375 if((*glyph = get_glyph_index(font, c)))
6377 *glyph = get_GSUB_vert_glyph(font, *glyph);
6381 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
6383 if(!child_font->font)
6384 if(!load_child_font(font, child_font))
6387 if(!child_font->font->ft_face)
6389 g = get_glyph_index(child_font->font, c);
6390 g = get_GSUB_vert_glyph(child_font->font, g);
6394 *linked_font = child_font->font;
6401 /*************************************************************
6402 * freetype_GetCharWidth
6404 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
6406 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6409 FT_UInt glyph_index;
6410 GdiFont *linked_font;
6411 struct freetype_physdev *physdev = get_freetype_dev( dev );
6415 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
6416 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
6419 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
6422 EnterCriticalSection( &freetype_cs );
6423 for(c = firstChar; c <= lastChar; c++) {
6424 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
6425 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6426 &gm, 0, NULL, &identity);
6427 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
6429 LeaveCriticalSection( &freetype_cs );
6433 /*************************************************************
6434 * freetype_GetCharABCWidths
6436 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
6438 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6441 FT_UInt glyph_index;
6442 GdiFont *linked_font;
6443 struct freetype_physdev *physdev = get_freetype_dev( dev );
6447 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
6448 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
6451 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
6454 EnterCriticalSection( &freetype_cs );
6456 for(c = firstChar; c <= lastChar; c++) {
6457 get_glyph_index_linked(physdev->font, c, &linked_font, &glyph_index);
6458 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6459 &gm, 0, NULL, &identity);
6460 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
6461 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
6462 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
6463 FONT_GM(linked_font,glyph_index)->bbx;
6465 LeaveCriticalSection( &freetype_cs );
6469 /*************************************************************
6470 * freetype_GetCharABCWidthsI
6472 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
6474 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6477 FT_UInt glyph_index;
6478 GdiFont *linked_font;
6479 struct freetype_physdev *physdev = get_freetype_dev( dev );
6483 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
6484 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
6487 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
6491 EnterCriticalSection( &freetype_cs );
6493 get_glyph_index_linked(physdev->font, 'a', &linked_font, &glyph_index);
6495 for(c = firstChar; c < firstChar+count; c++) {
6496 get_glyph_outline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
6497 &gm, 0, NULL, &identity);
6498 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
6499 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
6500 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
6501 - FONT_GM(linked_font,c)->bbx;
6504 for(c = 0; c < count; c++) {
6505 get_glyph_outline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
6506 &gm, 0, NULL, &identity);
6507 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
6508 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
6509 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
6510 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
6513 LeaveCriticalSection( &freetype_cs );
6517 /*************************************************************
6518 * freetype_GetTextExtentExPoint
6520 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count,
6521 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
6523 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6528 FT_UInt glyph_index;
6529 GdiFont *linked_font;
6530 struct freetype_physdev *physdev = get_freetype_dev( dev );
6534 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
6535 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, max_ext, pnfit, dxs, size );
6538 TRACE("%p, %s, %d, %d, %p\n", physdev->font, debugstr_wn(wstr, count), count, max_ext, size);
6541 EnterCriticalSection( &freetype_cs );
6544 get_text_metrics( physdev->font, &tm );
6545 size->cy = tm.tmHeight;
6547 for(idx = 0; idx < count; idx++) {
6548 get_glyph_index_linked( physdev->font, wstr[idx], &linked_font, &glyph_index );
6549 get_glyph_outline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
6550 &gm, 0, NULL, &identity);
6551 size->cx += FONT_GM(linked_font,glyph_index)->adv;
6553 if (! pnfit || ext <= max_ext) {
6563 LeaveCriticalSection( &freetype_cs );
6564 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6568 /*************************************************************
6569 * freetype_GetTextExtentExPointI
6571 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count,
6572 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size )
6574 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
6579 struct freetype_physdev *physdev = get_freetype_dev( dev );
6583 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
6584 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, max_ext, pnfit, dxs, size );
6587 TRACE("%p, %p, %d, %d, %p\n", physdev->font, indices, count, max_ext, size);
6590 EnterCriticalSection( &freetype_cs );
6593 get_text_metrics(physdev->font, &tm);
6594 size->cy = tm.tmHeight;
6596 for(idx = 0; idx < count; idx++) {
6597 get_glyph_outline(physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &identity);
6598 size->cx += FONT_GM(physdev->font,indices[idx])->adv;
6600 if (! pnfit || ext <= max_ext) {
6610 LeaveCriticalSection( &freetype_cs );
6611 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
6615 /*************************************************************
6616 * freetype_GetFontData
6618 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
6620 struct freetype_physdev *physdev = get_freetype_dev( dev );
6624 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
6625 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
6628 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
6629 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
6630 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
6632 return get_font_data( physdev->font, table, offset, buf, cbData );
6635 /*************************************************************
6636 * freetype_GetTextFace
6638 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
6641 struct freetype_physdev *physdev = get_freetype_dev( dev );
6645 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
6646 return dev->funcs->pGetTextFace( dev, count, str );
6649 n = strlenW(physdev->font->name) + 1;
6652 lstrcpynW(str, physdev->font->name, count);
6658 /*************************************************************
6659 * freetype_GetTextCharsetInfo
6661 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
6663 struct freetype_physdev *physdev = get_freetype_dev( dev );
6667 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
6668 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
6670 if (fs) *fs = physdev->font->fs;
6671 return physdev->font->charset;
6674 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
6676 GdiFont *font = dc->gdiFont, *linked_font;
6677 struct list *first_hfont;
6681 EnterCriticalSection( &freetype_cs );
6682 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
6683 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
6684 if(font == linked_font)
6685 *new_hfont = dc->hFont;
6688 first_hfont = list_head(&linked_font->hfontlist);
6689 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
6691 LeaveCriticalSection( &freetype_cs );
6695 /* Retrieve a list of supported Unicode ranges for a given font.
6696 * Can be called with NULL gs to calculate the buffer size. Returns
6697 * the number of ranges found.
6699 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
6701 DWORD num_ranges = 0;
6703 if (face->charmap->encoding == FT_ENCODING_UNICODE)
6706 FT_ULong char_code, char_code_prev;
6709 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
6711 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
6712 face->num_glyphs, glyph_code, char_code);
6714 if (!glyph_code) return 0;
6718 gs->ranges[0].wcLow = (USHORT)char_code;
6719 gs->ranges[0].cGlyphs = 0;
6720 gs->cGlyphsSupported = 0;
6726 if (char_code < char_code_prev)
6728 ERR("expected increasing char code from FT_Get_Next_Char\n");
6731 if (char_code - char_code_prev > 1)
6736 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
6737 gs->ranges[num_ranges - 1].cGlyphs = 1;
6738 gs->cGlyphsSupported++;
6743 gs->ranges[num_ranges - 1].cGlyphs++;
6744 gs->cGlyphsSupported++;
6746 char_code_prev = char_code;
6747 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
6751 FIXME("encoding %u not supported\n", face->charmap->encoding);
6756 /*************************************************************
6757 * freetype_GetFontUnicodeRanges
6759 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
6761 struct freetype_physdev *physdev = get_freetype_dev( dev );
6762 DWORD size, num_ranges;
6766 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
6767 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
6770 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
6771 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
6774 glyphset->cbThis = size;
6775 glyphset->cRanges = num_ranges;
6776 glyphset->flAccel = 0;
6781 /*************************************************************
6782 * freetype_FontIsLinked
6784 static BOOL freetype_FontIsLinked( PHYSDEV dev )
6786 struct freetype_physdev *physdev = get_freetype_dev( dev );
6791 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
6792 return dev->funcs->pFontIsLinked( dev );
6796 EnterCriticalSection( &freetype_cs );
6797 ret = !list_empty(&physdev->font->child_fonts);
6798 LeaveCriticalSection( &freetype_cs );
6802 static BOOL is_hinting_enabled(void)
6804 /* Use the >= 2.2.0 function if available */
6805 if(pFT_Get_TrueType_Engine_Type)
6807 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
6808 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
6810 #ifdef FT_DRIVER_HAS_HINTER
6815 /* otherwise if we've been compiled with < 2.2.0 headers
6816 use the internal macro */
6817 mod = pFT_Get_Module(library, "truetype");
6818 if(mod && FT_DRIVER_HAS_HINTER(mod))
6826 static BOOL is_subpixel_rendering_enabled( void )
6828 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6829 return pFT_Library_SetLcdFilter &&
6830 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature;
6836 /*************************************************************************
6837 * GetRasterizerCaps (GDI32.@)
6839 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
6841 static int hinting = -1;
6842 static int subpixel = -1;
6846 hinting = is_hinting_enabled();
6847 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
6850 if ( subpixel == -1 )
6852 subpixel = is_subpixel_rendering_enabled();
6853 TRACE("subpixel rendering is %senabled\n", subpixel ? "" : "NOT ");
6856 lprs->nSize = sizeof(RASTERIZER_STATUS);
6857 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
6859 lprs->wFlags |= WINE_TT_SUBPIXEL_RENDERING_ENABLED;
6860 lprs->nLanguageID = 0;
6864 /*************************************************************
6865 * freetype_GdiRealizationInfo
6867 static BOOL freetype_GdiRealizationInfo( PHYSDEV dev, void *ptr )
6869 struct freetype_physdev *physdev = get_freetype_dev( dev );
6870 realization_info_t *info = ptr;
6874 dev = GET_NEXT_PHYSDEV( dev, pGdiRealizationInfo );
6875 return dev->funcs->pGdiRealizationInfo( dev, ptr );
6878 FIXME("(%p, %p): stub!\n", physdev->font, info);
6881 if(FT_IS_SCALABLE(physdev->font->ft_face))
6884 info->cache_num = physdev->font->cache_num;
6885 info->unknown2 = -1;
6889 /*************************************************************************
6890 * Kerning support for TrueType fonts
6892 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
6894 struct TT_kern_table
6900 struct TT_kern_subtable
6909 USHORT horizontal : 1;
6911 USHORT cross_stream: 1;
6912 USHORT override : 1;
6913 USHORT reserved1 : 4;
6919 struct TT_format0_kern_subtable
6923 USHORT entrySelector;
6934 static DWORD parse_format0_kern_subtable(GdiFont *font,
6935 const struct TT_format0_kern_subtable *tt_f0_ks,
6936 const USHORT *glyph_to_char,
6937 KERNINGPAIR *kern_pair, DWORD cPairs)
6940 const struct TT_kern_pair *tt_kern_pair;
6942 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
6944 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
6946 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
6947 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
6948 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
6950 if (!kern_pair || !cPairs)
6953 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
6955 nPairs = min(nPairs, cPairs);
6957 for (i = 0; i < nPairs; i++)
6959 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
6960 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
6961 /* this algorithm appears to better match what Windows does */
6962 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
6963 if (kern_pair->iKernAmount < 0)
6965 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
6966 kern_pair->iKernAmount -= font->ppem;
6968 else if (kern_pair->iKernAmount > 0)
6970 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
6971 kern_pair->iKernAmount += font->ppem;
6973 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
6975 TRACE("left %u right %u value %d\n",
6976 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
6980 TRACE("copied %u entries\n", nPairs);
6984 /*************************************************************
6985 * freetype_GetKerningPairs
6987 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
6991 const struct TT_kern_table *tt_kern_table;
6992 const struct TT_kern_subtable *tt_kern_subtable;
6994 USHORT *glyph_to_char;
6996 struct freetype_physdev *physdev = get_freetype_dev( dev );
6998 if (!(font = physdev->font))
7000 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
7001 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
7005 EnterCriticalSection( &freetype_cs );
7006 if (font->total_kern_pairs != (DWORD)-1)
7008 if (cPairs && kern_pair)
7010 cPairs = min(cPairs, font->total_kern_pairs);
7011 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7013 else cPairs = font->total_kern_pairs;
7015 LeaveCriticalSection( &freetype_cs );
7019 font->total_kern_pairs = 0;
7021 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
7023 if (length == GDI_ERROR)
7025 TRACE("no kerning data in the font\n");
7026 LeaveCriticalSection( &freetype_cs );
7030 buf = HeapAlloc(GetProcessHeap(), 0, length);
7033 WARN("Out of memory\n");
7034 LeaveCriticalSection( &freetype_cs );
7038 get_font_data(font, MS_KERN_TAG, 0, buf, length);
7040 /* build a glyph index to char code map */
7041 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
7044 WARN("Out of memory allocating a glyph index to char code map\n");
7045 HeapFree(GetProcessHeap(), 0, buf);
7046 LeaveCriticalSection( &freetype_cs );
7050 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
7056 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
7058 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7059 font->ft_face->num_glyphs, glyph_code, char_code);
7063 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7065 /* FIXME: This doesn't match what Windows does: it does some fancy
7066 * things with duplicate glyph index to char code mappings, while
7067 * we just avoid overriding existing entries.
7069 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
7070 glyph_to_char[glyph_code] = (USHORT)char_code;
7072 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
7079 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
7080 for (n = 0; n <= 65535; n++)
7081 glyph_to_char[n] = (USHORT)n;
7084 tt_kern_table = buf;
7085 nTables = GET_BE_WORD(tt_kern_table->nTables);
7086 TRACE("version %u, nTables %u\n",
7087 GET_BE_WORD(tt_kern_table->version), nTables);
7089 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
7091 for (i = 0; i < nTables; i++)
7093 struct TT_kern_subtable tt_kern_subtable_copy;
7095 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
7096 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
7097 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
7099 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7100 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
7101 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
7103 /* According to the TrueType specification this is the only format
7104 * that will be properly interpreted by Windows and OS/2
7106 if (tt_kern_subtable_copy.coverage.bits.format == 0)
7108 DWORD new_chunk, old_total = font->total_kern_pairs;
7110 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7111 glyph_to_char, NULL, 0);
7112 font->total_kern_pairs += new_chunk;
7114 if (!font->kern_pairs)
7115 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
7116 font->total_kern_pairs * sizeof(*font->kern_pairs));
7118 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
7119 font->total_kern_pairs * sizeof(*font->kern_pairs));
7121 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7122 glyph_to_char, font->kern_pairs + old_total, new_chunk);
7125 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
7127 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
7130 HeapFree(GetProcessHeap(), 0, glyph_to_char);
7131 HeapFree(GetProcessHeap(), 0, buf);
7133 if (cPairs && kern_pair)
7135 cPairs = min(cPairs, font->total_kern_pairs);
7136 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7138 else cPairs = font->total_kern_pairs;
7140 LeaveCriticalSection( &freetype_cs );
7144 static const struct gdi_dc_funcs freetype_funcs =
7146 NULL, /* pAbortDoc */
7147 NULL, /* pAbortPath */
7148 NULL, /* pAlphaBlend */
7149 NULL, /* pAngleArc */
7152 NULL, /* pBeginPath */
7153 NULL, /* pBlendImage */
7154 NULL, /* pChoosePixelFormat */
7156 NULL, /* pCloseFigure */
7157 NULL, /* pCopyBitmap */
7158 NULL, /* pCreateBitmap */
7159 NULL, /* pCreateCompatibleDC */
7160 freetype_CreateDC, /* pCreateDC */
7161 NULL, /* pCreateDIBSection */
7162 NULL, /* pDeleteBitmap */
7163 freetype_DeleteDC, /* pDeleteDC */
7164 NULL, /* pDeleteObject */
7165 NULL, /* pDescribePixelFormat */
7166 NULL, /* pDeviceCapabilities */
7167 NULL, /* pEllipse */
7169 NULL, /* pEndPage */
7170 NULL, /* pEndPath */
7171 freetype_EnumFonts, /* pEnumFonts */
7172 NULL, /* pEnumICMProfiles */
7173 NULL, /* pExcludeClipRect */
7174 NULL, /* pExtDeviceMode */
7175 NULL, /* pExtEscape */
7176 NULL, /* pExtFloodFill */
7177 NULL, /* pExtSelectClipRgn */
7178 NULL, /* pExtTextOut */
7179 NULL, /* pFillPath */
7180 NULL, /* pFillRgn */
7181 NULL, /* pFlattenPath */
7182 freetype_FontIsLinked, /* pFontIsLinked */
7183 NULL, /* pFrameRgn */
7184 NULL, /* pGdiComment */
7185 freetype_GdiRealizationInfo, /* pGdiRealizationInfo */
7186 freetype_GetCharABCWidths, /* pGetCharABCWidths */
7187 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
7188 freetype_GetCharWidth, /* pGetCharWidth */
7189 NULL, /* pGetDeviceCaps */
7190 NULL, /* pGetDeviceGammaRamp */
7191 freetype_GetFontData, /* pGetFontData */
7192 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
7193 freetype_GetGlyphIndices, /* pGetGlyphIndices */
7194 freetype_GetGlyphOutline, /* pGetGlyphOutline */
7195 NULL, /* pGetICMProfile */
7196 NULL, /* pGetImage */
7197 freetype_GetKerningPairs, /* pGetKerningPairs */
7198 NULL, /* pGetNearestColor */
7199 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
7200 NULL, /* pGetPixel */
7201 NULL, /* pGetPixelFormat */
7202 NULL, /* pGetSystemPaletteEntries */
7203 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
7204 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
7205 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
7206 freetype_GetTextFace, /* pGetTextFace */
7207 freetype_GetTextMetrics, /* pGetTextMetrics */
7208 NULL, /* pGradientFill */
7209 NULL, /* pIntersectClipRect */
7210 NULL, /* pInvertRgn */
7212 NULL, /* pModifyWorldTransform */
7214 NULL, /* pOffsetClipRgn */
7215 NULL, /* pOffsetViewportOrg */
7216 NULL, /* pOffsetWindowOrg */
7217 NULL, /* pPaintRgn */
7220 NULL, /* pPolyBezier */
7221 NULL, /* pPolyBezierTo */
7222 NULL, /* pPolyDraw */
7223 NULL, /* pPolyPolygon */
7224 NULL, /* pPolyPolyline */
7225 NULL, /* pPolygon */
7226 NULL, /* pPolyline */
7227 NULL, /* pPolylineTo */
7228 NULL, /* pPutImage */
7229 NULL, /* pRealizeDefaultPalette */
7230 NULL, /* pRealizePalette */
7231 NULL, /* pRectangle */
7232 NULL, /* pResetDC */
7233 NULL, /* pRestoreDC */
7234 NULL, /* pRoundRect */
7236 NULL, /* pScaleViewportExt */
7237 NULL, /* pScaleWindowExt */
7238 NULL, /* pSelectBitmap */
7239 NULL, /* pSelectBrush */
7240 NULL, /* pSelectClipPath */
7241 freetype_SelectFont, /* pSelectFont */
7242 NULL, /* pSelectPalette */
7243 NULL, /* pSelectPen */
7244 NULL, /* pSetArcDirection */
7245 NULL, /* pSetBkColor */
7246 NULL, /* pSetBkMode */
7247 NULL, /* pSetDCBrushColor */
7248 NULL, /* pSetDCPenColor */
7249 NULL, /* pSetDIBColorTable */
7250 NULL, /* pSetDIBitsToDevice */
7251 NULL, /* pSetDeviceClipping */
7252 NULL, /* pSetDeviceGammaRamp */
7253 NULL, /* pSetLayout */
7254 NULL, /* pSetMapMode */
7255 NULL, /* pSetMapperFlags */
7256 NULL, /* pSetPixel */
7257 NULL, /* pSetPixelFormat */
7258 NULL, /* pSetPolyFillMode */
7259 NULL, /* pSetROP2 */
7260 NULL, /* pSetRelAbs */
7261 NULL, /* pSetStretchBltMode */
7262 NULL, /* pSetTextAlign */
7263 NULL, /* pSetTextCharacterExtra */
7264 NULL, /* pSetTextColor */
7265 NULL, /* pSetTextJustification */
7266 NULL, /* pSetViewportExt */
7267 NULL, /* pSetViewportOrg */
7268 NULL, /* pSetWindowExt */
7269 NULL, /* pSetWindowOrg */
7270 NULL, /* pSetWorldTransform */
7271 NULL, /* pStartDoc */
7272 NULL, /* pStartPage */
7273 NULL, /* pStretchBlt */
7274 NULL, /* pStretchDIBits */
7275 NULL, /* pStrokeAndFillPath */
7276 NULL, /* pStrokePath */
7277 NULL, /* pSwapBuffers */
7278 NULL, /* pUnrealizePalette */
7279 NULL, /* pWidenPath */
7280 /* OpenGL not supported */
7283 #else /* HAVE_FREETYPE */
7285 /*************************************************************************/
7287 BOOL WineEngInit(void)
7291 BOOL WineEngDestroyFontInstance(HFONT hfont)
7296 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7298 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7302 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7304 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7308 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
7310 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
7314 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
7319 /*************************************************************************
7320 * GetRasterizerCaps (GDI32.@)
7322 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7324 lprs->nSize = sizeof(RASTERIZER_STATUS);
7326 lprs->nLanguageID = 0;
7330 #endif /* HAVE_FREETYPE */