2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
5 * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
7 * This file contains the WineEng* functions.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "wine/port.h"
29 #ifdef HAVE_SYS_STAT_H
30 # include <sys/stat.h>
32 #ifdef HAVE_SYS_MMAN_H
33 # include <sys/mman.h>
42 #ifdef HAVE_CARBON_CARBON_H
43 #define LoadResource __carbon_LoadResource
44 #define CompareString __carbon_CompareString
45 #define GetCurrentThread __carbon_GetCurrentThread
46 #define GetCurrentProcess __carbon_GetCurrentProcess
47 #define AnimatePalette __carbon_AnimatePalette
48 #define EqualRgn __carbon_EqualRgn
49 #define FillRgn __carbon_FillRgn
50 #define FrameRgn __carbon_FrameRgn
51 #define GetPixel __carbon_GetPixel
52 #define InvertRgn __carbon_InvertRgn
53 #define LineTo __carbon_LineTo
54 #define OffsetRgn __carbon_OffsetRgn
55 #define PaintRgn __carbon_PaintRgn
56 #define Polygon __carbon_Polygon
57 #define ResizePalette __carbon_ResizePalette
58 #define SetRectRgn __carbon_SetRectRgn
59 #include <Carbon/Carbon.h>
62 #undef GetCurrentThread
65 #undef GetCurrentProcess
78 #endif /* HAVE_CARBON_CARBON_H */
86 #include "gdi_private.h"
87 #include "wine/library.h"
88 #include "wine/unicode.h"
89 #include "wine/debug.h"
90 #include "wine/list.h"
94 WINE_DEFAULT_DEBUG_CHANNEL(font);
98 #ifdef HAVE_FT2BUILD_H
101 #ifdef HAVE_FREETYPE_FREETYPE_H
102 #include <freetype/freetype.h>
104 #ifdef HAVE_FREETYPE_FTGLYPH_H
105 #include <freetype/ftglyph.h>
107 #ifdef HAVE_FREETYPE_TTTABLES_H
108 #include <freetype/tttables.h>
110 #ifdef HAVE_FREETYPE_FTTYPES_H
111 #include <freetype/fttypes.h>
113 #ifdef HAVE_FREETYPE_FTSNAMES_H
114 #include <freetype/ftsnames.h>
116 #ifdef HAVE_FREETYPE_TTNAMEID_H
117 #include <freetype/ttnameid.h>
119 #ifdef HAVE_FREETYPE_FTOUTLN_H
120 #include <freetype/ftoutln.h>
122 #ifdef HAVE_FREETYPE_FTTRIGON_H
123 #include <freetype/fttrigon.h>
125 #ifdef HAVE_FREETYPE_FTWINFNT_H
126 #include <freetype/ftwinfnt.h>
128 #ifdef HAVE_FREETYPE_FTMODAPI_H
129 #include <freetype/ftmodapi.h>
131 #ifdef HAVE_FREETYPE_FTLCDFIL_H
132 #include <freetype/ftlcdfil.h>
135 #ifndef HAVE_FT_TRUETYPEENGINETYPE
138 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
139 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
140 FT_TRUETYPE_ENGINE_TYPE_PATENTED
141 } FT_TrueTypeEngineType;
144 static FT_Library library = 0;
151 static FT_Version_t FT_Version;
152 static DWORD FT_SimpleVersion;
154 static void *ft_handle = NULL;
156 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
157 MAKE_FUNCPTR(FT_Done_Face);
158 MAKE_FUNCPTR(FT_Get_Char_Index);
159 MAKE_FUNCPTR(FT_Get_First_Char);
160 MAKE_FUNCPTR(FT_Get_Module);
161 MAKE_FUNCPTR(FT_Get_Next_Char);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
163 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
164 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
165 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
166 MAKE_FUNCPTR(FT_Init_FreeType);
167 MAKE_FUNCPTR(FT_Library_Version);
168 MAKE_FUNCPTR(FT_Load_Glyph);
169 MAKE_FUNCPTR(FT_Load_Sfnt_Table);
170 MAKE_FUNCPTR(FT_Matrix_Multiply);
171 #ifdef FT_MULFIX_INLINED
172 #define pFT_MulFix FT_MULFIX_INLINED
174 MAKE_FUNCPTR(FT_MulFix);
176 MAKE_FUNCPTR(FT_New_Face);
177 MAKE_FUNCPTR(FT_New_Memory_Face);
178 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
179 MAKE_FUNCPTR(FT_Outline_Transform);
180 MAKE_FUNCPTR(FT_Outline_Translate);
181 MAKE_FUNCPTR(FT_Render_Glyph);
182 MAKE_FUNCPTR(FT_Select_Charmap);
183 MAKE_FUNCPTR(FT_Set_Charmap);
184 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
185 MAKE_FUNCPTR(FT_Vector_Transform);
186 MAKE_FUNCPTR(FT_Vector_Unit);
187 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
188 #ifdef HAVE_FREETYPE_FTLCDFIL_H
189 static FT_Error (*pFT_Library_SetLcdFilter)(FT_Library, FT_LcdFilter);
192 #ifdef SONAME_LIBFONTCONFIG
193 #include <fontconfig/fontconfig.h>
194 MAKE_FUNCPTR(FcConfigSubstitute);
195 MAKE_FUNCPTR(FcFontList);
196 MAKE_FUNCPTR(FcFontSetDestroy);
197 MAKE_FUNCPTR(FcInit);
198 MAKE_FUNCPTR(FcObjectSetAdd);
199 MAKE_FUNCPTR(FcObjectSetCreate);
200 MAKE_FUNCPTR(FcObjectSetDestroy);
201 MAKE_FUNCPTR(FcPatternCreate);
202 MAKE_FUNCPTR(FcPatternDestroy);
203 MAKE_FUNCPTR(FcPatternGetBool);
204 MAKE_FUNCPTR(FcPatternGetInteger);
205 MAKE_FUNCPTR(FcPatternGetString);
211 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
212 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
213 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
216 #ifndef ft_encoding_none
217 #define FT_ENCODING_NONE ft_encoding_none
219 #ifndef ft_encoding_ms_symbol
220 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
222 #ifndef ft_encoding_unicode
223 #define FT_ENCODING_UNICODE ft_encoding_unicode
225 #ifndef ft_encoding_apple_roman
226 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
229 #ifdef WORDS_BIGENDIAN
230 #define GET_BE_WORD(x) (x)
232 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
235 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
242 FT_Short internal_leading;
245 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
246 So to let this compile on older versions of FreeType we'll define the
247 new structure here. */
249 FT_Short height, width;
250 FT_Pos size, x_ppem, y_ppem;
256 NEWTEXTMETRICEXW ntm;
260 typedef struct tagFace {
262 unsigned int refcount;
267 DWORD font_data_size;
271 FT_Fixed font_version;
274 Bitmap_Size size; /* set if face is a bitmap */
275 BOOL external; /* TRUE if we should manually add this font to the registry */
277 struct tagFamily *family;
278 /* Cached data for Enum */
279 struct enum_data *cached_enum_data;
282 typedef struct tagFamily {
284 unsigned int refcount;
288 struct list *replacement;
293 ABC abc; /* metrics of the unrotated char */
309 typedef struct tagGdiFont GdiFont;
319 struct list unused_entry;
320 unsigned int refcount;
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;
346 UINT ntmCellHeight, ntmAvgWidth;
355 const WCHAR *font_name;
360 struct enum_charset_element {
363 WCHAR name[LF_FACESIZE];
366 struct enum_charset_list {
368 struct enum_charset_element element[32];
371 #define GM_BLOCK_SIZE 128
372 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
374 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
375 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
376 static unsigned int unused_font_count;
377 #define UNUSED_CACHE_SIZE 10
378 static struct list system_links = LIST_INIT(system_links);
380 static struct list font_subst_list = LIST_INIT(font_subst_list);
382 static struct list font_list = LIST_INIT(font_list);
384 struct freetype_physdev
386 struct gdi_physdev dev;
390 static inline struct freetype_physdev *get_freetype_dev( PHYSDEV dev )
392 return (struct freetype_physdev *)dev;
395 static const struct gdi_dc_funcs freetype_funcs;
397 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
398 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
399 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
401 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
402 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
403 'W','i','n','d','o','w','s','\\',
404 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
405 'F','o','n','t','s','\0'};
407 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
408 'W','i','n','d','o','w','s',' ','N','T','\\',
409 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
410 'F','o','n','t','s','\0'};
412 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
413 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
414 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
415 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
417 static const WCHAR * const SystemFontValues[] = {
424 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
425 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
427 /* Interesting and well-known (frequently-assumed!) font names */
428 static const WCHAR Lucida_Sans_Unicode[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
429 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 };
430 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
431 static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
432 static const WCHAR SimSun[] = {'S','i','m','S','u','n',0};
433 static const WCHAR Gulim[] = {'G','u','l','i','m',0};
434 static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0};
435 static const WCHAR Batang[] = {'B','a','t','a','n','g',0};
437 static const WCHAR arial[] = {'A','r','i','a','l',0};
438 static const WCHAR bitstream_vera_sans[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
439 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};
440 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};
441 static const WCHAR courier_new[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
442 static const WCHAR liberation_mono[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
443 static const WCHAR liberation_sans[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
444 static const WCHAR liberation_serif[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
445 static const WCHAR times_new_roman[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
446 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
448 static const WCHAR *default_serif_list[] =
452 bitstream_vera_serif,
456 static const WCHAR *default_fixed_list[] =
460 bitstream_vera_sans_mono,
464 static const WCHAR *default_sans_list[] =
477 typedef struct tagFontSubst {
483 /* Registry font cache key and value names */
484 static const WCHAR wine_fonts_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
485 'F','o','n','t','s',0};
486 static const WCHAR wine_fonts_cache_key[] = {'C','a','c','h','e',0};
487 static const WCHAR english_name_value[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
488 static const WCHAR face_index_value[] = {'I','n','d','e','x',0};
489 static const WCHAR face_ntmflags_value[] = {'N','t','m','f','l','a','g','s',0};
490 static const WCHAR face_version_value[] = {'V','e','r','s','i','o','n',0};
491 static const WCHAR face_vertical_value[] = {'V','e','r','t','i','c','a','l',0};
492 static const WCHAR face_height_value[] = {'H','e','i','g','h','t',0};
493 static const WCHAR face_width_value[] = {'W','i','d','t','h',0};
494 static const WCHAR face_size_value[] = {'S','i','z','e',0};
495 static const WCHAR face_x_ppem_value[] = {'X','p','p','e','m',0};
496 static const WCHAR face_y_ppem_value[] = {'Y','p','p','e','m',0};
497 static const WCHAR face_aa_value[] = {'A','n','t','i','a','l','i','a','s','i','n','g',0};
498 static const WCHAR face_internal_leading_value[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
499 static const WCHAR face_font_sig_value[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
500 static const WCHAR face_file_name_value[] = {'F','i','l','e',' ','N','a','m','e','\0'};
501 static const WCHAR face_full_name_value[] = {'F','u','l','l',' ','N','a','m','e','\0'};
514 static struct list mappings_list = LIST_INIT( mappings_list );
516 static UINT default_aa_flags;
518 static CRITICAL_SECTION freetype_cs;
519 static CRITICAL_SECTION_DEBUG critsect_debug =
522 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
523 0, 0, { (DWORD_PTR)(__FILE__ ": freetype_cs") }
525 static CRITICAL_SECTION freetype_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
527 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
529 static const WCHAR szDefaultFallbackLink[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
530 static BOOL use_default_fallback = FALSE;
532 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
533 static BOOL get_outline_text_metrics(GdiFont *font);
534 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm);
536 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
537 'W','i','n','d','o','w','s',' ','N','T','\\',
538 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
539 'S','y','s','t','e','m','L','i','n','k',0};
541 static const WCHAR internal_system_link[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
542 'F','o','n','t','L','i','n','k','\\',
543 'S','y','s','t','e','m','L','i','n','k',0};
545 /****************************************
546 * Notes on .fon files
548 * The fonts System, FixedSys and Terminal are special. There are typically multiple
549 * versions installed for different resolutions and codepages. Windows stores which one to use
550 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
552 * FIXEDFON.FON FixedSys
554 * OEMFONT.FON Terminal
555 * LogPixels Current dpi set by the display control panel applet
556 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
557 * also has a LogPixels value that appears to mirror this)
559 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
560 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
561 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
562 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
563 * so that makes sense.
565 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
566 * to be mapped into the registry on Windows 2000 at least).
569 * ega80woa.fon=ega80850.fon
570 * ega40woa.fon=ega40850.fon
571 * cga80woa.fon=cga80850.fon
572 * cga40woa.fon=cga40850.fon
575 /* These are all structures needed for the GSUB table */
577 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
578 #define TATEGAKI_LOWER_BOUND 0x02F1
594 GSUB_ScriptRecord ScriptRecord[1];
600 } GSUB_LangSysRecord;
605 GSUB_LangSysRecord LangSysRecord[1];
609 WORD LookupOrder; /* Reserved */
610 WORD ReqFeatureIndex;
612 WORD FeatureIndex[1];
618 } GSUB_FeatureRecord;
622 GSUB_FeatureRecord FeatureRecord[1];
626 WORD FeatureParams; /* Reserved */
628 WORD LookupListIndex[1];
647 } GSUB_CoverageFormat1;
652 WORD StartCoverageIndex;
658 GSUB_RangeRecord RangeRecord[1];
659 } GSUB_CoverageFormat2;
662 WORD SubstFormat; /* = 1 */
665 } GSUB_SingleSubstFormat1;
668 WORD SubstFormat; /* = 2 */
672 }GSUB_SingleSubstFormat2;
674 #ifdef HAVE_CARBON_CARBON_H
675 static char *find_cache_dir(void)
679 static char cached_path[MAX_PATH];
680 static const char *wine = "/Wine", *fonts = "/Fonts";
682 if(*cached_path) return cached_path;
684 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
687 WARN("can't create cached data folder\n");
690 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
693 WARN("can't create cached data path\n");
697 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
699 ERR("Could not create full path\n");
703 strcat(cached_path, wine);
705 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
707 WARN("Couldn't mkdir %s\n", cached_path);
711 strcat(cached_path, fonts);
712 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
714 WARN("Couldn't mkdir %s\n", cached_path);
721 /******************************************************************
724 * Extracts individual TrueType font files from a Mac suitcase font
725 * and saves them into the user's caches directory (see
727 * Returns a NULL terminated array of filenames.
729 * We do this because they are apps that try to read ttf files
730 * themselves and they don't like Mac suitcase files.
732 static char **expand_mac_font(const char *path)
739 const char *filename;
743 unsigned int size, max_size;
746 TRACE("path %s\n", path);
748 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
751 WARN("failed to get ref\n");
755 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
758 TRACE("no data fork, so trying resource fork\n");
759 res_ref = FSOpenResFile(&ref, fsRdPerm);
762 TRACE("unable to open resource fork\n");
769 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
772 CloseResFile(res_ref);
776 out_dir = find_cache_dir();
778 filename = strrchr(path, '/');
779 if(!filename) filename = path;
782 /* output filename has the form out_dir/filename_%04x.ttf */
783 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
790 unsigned short *num_faces_ptr, num_faces, face;
793 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
795 fond = Get1IndResource(fond_res, idx);
797 TRACE("got fond resource %d\n", idx);
800 fam_rec = *(FamRec**)fond;
801 num_faces_ptr = (unsigned short *)(fam_rec + 1);
802 num_faces = GET_BE_WORD(*num_faces_ptr);
804 assoc = (AsscEntry*)(num_faces_ptr + 1);
805 TRACE("num faces %04x\n", num_faces);
806 for(face = 0; face < num_faces; face++, assoc++)
809 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
810 unsigned short size, font_id;
813 size = GET_BE_WORD(assoc->fontSize);
814 font_id = GET_BE_WORD(assoc->fontID);
817 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
821 TRACE("trying to load sfnt id %04x\n", font_id);
822 sfnt = GetResource(sfnt_res, font_id);
825 TRACE("can't get sfnt resource %04x\n", font_id);
829 output = HeapAlloc(GetProcessHeap(), 0, output_len);
834 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
836 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
837 if(fd != -1 || errno == EEXIST)
841 unsigned char *sfnt_data;
844 sfnt_data = *(unsigned char**)sfnt;
845 write(fd, sfnt_data, GetHandleSize(sfnt));
849 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
852 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
854 ret.array[ret.size++] = output;
858 WARN("unable to create %s\n", output);
859 HeapFree(GetProcessHeap(), 0, output);
862 ReleaseResource(sfnt);
865 ReleaseResource(fond);
868 CloseResFile(res_ref);
873 #endif /* HAVE_CARBON_CARBON_H */
875 static inline BOOL is_win9x(void)
877 return GetVersion() & 0x80000000;
880 This function builds an FT_Fixed from a double. It fails if the absolute
881 value of the float number is greater than 32768.
883 static inline FT_Fixed FT_FixedFromFloat(double f)
889 This function builds an FT_Fixed from a FIXED. It simply put f.value
890 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
892 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
894 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
897 static BOOL is_hinting_enabled(void)
899 static int enabled = -1;
903 /* Use the >= 2.2.0 function if available */
904 if (pFT_Get_TrueType_Engine_Type)
906 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
907 enabled = (type == FT_TRUETYPE_ENGINE_TYPE_PATENTED);
909 #ifdef FT_DRIVER_HAS_HINTER
912 /* otherwise if we've been compiled with < 2.2.0 headers use the internal macro */
913 FT_Module mod = pFT_Get_Module(library, "truetype");
914 enabled = (mod && FT_DRIVER_HAS_HINTER(mod));
917 else enabled = FALSE;
918 TRACE("hinting is %senabled\n", enabled ? "" : "NOT ");
923 static BOOL is_subpixel_rendering_enabled( void )
925 #ifdef HAVE_FREETYPE_FTLCDFIL_H
926 static int enabled = -1;
929 enabled = (pFT_Library_SetLcdFilter &&
930 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature);
931 TRACE("subpixel rendering is %senabled\n", enabled ? "" : "NOT ");
940 static const struct list *get_face_list_from_family(const Family *family)
942 if (!list_empty(&family->faces))
943 return &family->faces;
945 return family->replacement;
948 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
954 TRACE("looking for file %s name %s\n", debugstr_w(file_name), debugstr_w(face_name));
956 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
958 const struct list *face_list;
959 if(face_name && strcmpiW(face_name, family->FamilyName))
961 face_list = get_face_list_from_family(family);
962 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
966 file = strrchrW(face->file, '/');
971 if(strcmpiW(file, file_name)) continue;
979 static Family *find_family_from_name(const WCHAR *name)
983 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
985 if(!strcmpiW(family->FamilyName, name))
992 static Family *find_family_from_any_name(const WCHAR *name)
996 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
998 if(!strcmpiW(family->FamilyName, name))
1000 if(family->EnglishName && !strcmpiW(family->EnglishName, name))
1007 static void DumpSubstList(void)
1011 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
1013 if(psub->from.charset != -1 || psub->to.charset != -1)
1014 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
1015 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
1017 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
1018 debugstr_w(psub->to.name));
1023 static LPWSTR strdupW(LPCWSTR p)
1026 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
1027 ret = HeapAlloc(GetProcessHeap(), 0, len);
1028 memcpy(ret, p, len);
1032 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
1037 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
1039 if(!strcmpiW(element->from.name, from_name) &&
1040 (element->from.charset == from_charset ||
1041 element->from.charset == -1))
1048 #define ADD_FONT_SUBST_FORCE 1
1050 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
1052 FontSubst *from_exist, *to_exist;
1054 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
1056 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
1058 list_remove(&from_exist->entry);
1059 HeapFree(GetProcessHeap(), 0, from_exist->from.name);
1060 HeapFree(GetProcessHeap(), 0, from_exist->to.name);
1061 HeapFree(GetProcessHeap(), 0, from_exist);
1067 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
1071 HeapFree(GetProcessHeap(), 0, subst->to.name);
1072 subst->to.name = strdupW(to_exist->to.name);
1075 list_add_tail(subst_list, &subst->entry);
1080 HeapFree(GetProcessHeap(), 0, subst->from.name);
1081 HeapFree(GetProcessHeap(), 0, subst->to.name);
1082 HeapFree(GetProcessHeap(), 0, subst);
1086 static WCHAR *towstr(UINT cp, const char *str)
1091 len = MultiByteToWideChar(cp, 0, str, -1, NULL, 0);
1092 wstr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1093 MultiByteToWideChar(cp, 0, str, -1, wstr, len);
1097 static char *strWtoA(UINT cp, const WCHAR *str)
1099 int len = WideCharToMultiByte( cp, 0, str, -1, NULL, 0, NULL, NULL );
1100 char *ret = HeapAlloc( GetProcessHeap(), 0, len );
1101 WideCharToMultiByte( cp, 0, str, -1, ret, len, NULL, NULL );
1105 static void split_subst_info(NameCs *nc, LPSTR str)
1107 CHAR *p = strrchr(str, ',');
1111 nc->charset = strtol(p+1, NULL, 10);
1114 nc->name = towstr(CP_ACP, str);
1117 static void LoadSubstList(void)
1121 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1125 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1126 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1127 &hkey) == ERROR_SUCCESS) {
1129 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1130 &valuelen, &datalen, NULL, NULL);
1132 valuelen++; /* returned value doesn't include room for '\0' */
1133 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
1134 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1138 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1139 &dlen) == ERROR_SUCCESS) {
1140 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
1142 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
1143 split_subst_info(&psub->from, value);
1144 split_subst_info(&psub->to, data);
1146 /* Win 2000 doesn't allow mapping between different charsets
1147 or mapping of DEFAULT_CHARSET */
1148 if ((psub->from.charset && psub->to.charset != psub->from.charset) ||
1149 psub->to.charset == DEFAULT_CHARSET) {
1150 HeapFree(GetProcessHeap(), 0, psub->to.name);
1151 HeapFree(GetProcessHeap(), 0, psub->from.name);
1152 HeapFree(GetProcessHeap(), 0, psub);
1154 add_font_subst(&font_subst_list, psub, 0);
1156 /* reset dlen and vlen */
1160 HeapFree(GetProcessHeap(), 0, data);
1161 HeapFree(GetProcessHeap(), 0, value);
1167 /*****************************************************************
1168 * get_name_table_entry
1170 * Supply the platform, encoding, language and name ids in req
1171 * and if the name exists the function will fill in the string
1172 * and string_len members. The string is owned by FreeType so
1173 * don't free it. Returns TRUE if the name is found else FALSE.
1175 static BOOL get_name_table_entry(FT_Face ft_face, FT_SfntName *req)
1178 FT_UInt num_names, name_index;
1180 if(FT_IS_SFNT(ft_face))
1182 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
1184 for(name_index = 0; name_index < num_names; name_index++)
1186 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
1188 if((name.platform_id == req->platform_id) &&
1189 ((name.encoding_id == TT_MS_ID_UNICODE_CS) || (name.encoding_id == TT_MS_ID_SYMBOL_CS)) &&
1190 (name.language_id == req->language_id) &&
1191 (name.name_id == req->name_id))
1193 req->string = name.string;
1194 req->string_len = name.string_len;
1201 req->string_len = 0;
1205 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, FT_UShort language_id)
1210 name.platform_id = TT_PLATFORM_MICROSOFT;
1211 name.language_id = language_id;
1212 name.name_id = name_id;
1214 if(get_name_table_entry(ft_face, &name))
1218 /* String is not nul terminated and string_len is a byte length. */
1219 ret = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
1220 for(i = 0; i < name.string_len / 2; i++)
1222 WORD *tmp = (WORD *)&name.string[i * 2];
1223 ret[i] = GET_BE_WORD(*tmp);
1226 TRACE("Got localised name %s\n", debugstr_w(ret));
1232 static inline BOOL faces_equal( const Face *f1, const Face *f2 )
1234 if (strcmpiW( f1->StyleName, f2->StyleName )) return FALSE;
1235 if (f1->scalable) return TRUE;
1236 if (f1->size.y_ppem != f2->size.y_ppem) return FALSE;
1237 return !memcmp( &f1->fs, &f2->fs, sizeof(f1->fs) );
1240 static void release_family( Family *family )
1242 if (--family->refcount) return;
1243 assert( list_empty( &family->faces ));
1244 list_remove( &family->entry );
1245 HeapFree( GetProcessHeap(), 0, family->FamilyName );
1246 HeapFree( GetProcessHeap(), 0, family->EnglishName );
1247 HeapFree( GetProcessHeap(), 0, family );
1250 static void release_face( Face *face )
1252 if (--face->refcount) return;
1255 list_remove( &face->entry );
1256 release_family( face->family );
1258 HeapFree( GetProcessHeap(), 0, face->file );
1259 HeapFree( GetProcessHeap(), 0, face->StyleName );
1260 HeapFree( GetProcessHeap(), 0, face->FullName );
1261 HeapFree( GetProcessHeap(), 0, face->cached_enum_data );
1262 HeapFree( GetProcessHeap(), 0, face );
1265 static inline int style_order(const Face *face)
1267 switch (face->ntmFlags & (NTM_REGULAR | NTM_BOLD | NTM_ITALIC))
1275 case NTM_BOLD | NTM_ITALIC:
1278 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1279 debugstr_w(face->family->FamilyName),
1280 debugstr_w(face->StyleName),
1286 static BOOL insert_face_in_family_list( Face *face, Family *family )
1290 LIST_FOR_EACH_ENTRY( cursor, &family->faces, Face, entry )
1292 if (faces_equal( face, cursor ))
1294 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1295 debugstr_w(family->FamilyName), debugstr_w(face->StyleName),
1296 cursor->font_version, face->font_version);
1298 if (face->font_version <= cursor->font_version)
1300 TRACE("Original font %s is newer so skipping %s\n",
1301 debugstr_w(cursor->file), debugstr_w(face->file));
1306 TRACE("Replacing original %s with %s\n",
1307 debugstr_w(cursor->file), debugstr_w(face->file));
1308 list_add_before( &cursor->entry, &face->entry );
1309 face->family = family;
1312 release_face( cursor );
1317 TRACE("Adding new %s\n", debugstr_w(face->file));
1319 if (style_order( face ) < style_order( cursor )) break;
1322 list_add_before( &cursor->entry, &face->entry );
1323 face->family = family;
1329 /****************************************************************
1330 * NB This function stores the ptrs to the strings to save copying.
1331 * Don't free them after calling.
1333 static Family *create_family( WCHAR *name, WCHAR *english_name )
1335 Family * const family = HeapAlloc( GetProcessHeap(), 0, sizeof(*family) );
1336 family->refcount = 1;
1337 family->FamilyName = name;
1338 family->EnglishName = english_name;
1339 list_init( &family->faces );
1340 family->replacement = &family->faces;
1341 list_add_tail( &font_list, &family->entry );
1346 static LONG reg_load_dword(HKEY hkey, const WCHAR *value, DWORD *data)
1348 DWORD type, size = sizeof(DWORD);
1350 if (RegQueryValueExW(hkey, value, NULL, &type, (BYTE *)data, &size) ||
1351 type != REG_DWORD || size != sizeof(DWORD))
1354 return ERROR_BAD_CONFIGURATION;
1356 return ERROR_SUCCESS;
1359 static inline LONG reg_save_dword(HKEY hkey, const WCHAR *value, DWORD data)
1361 return RegSetValueExW(hkey, value, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD));
1364 static void load_face(HKEY hkey_face, WCHAR *face_name, Family *family, void *buffer, DWORD buffer_size)
1366 DWORD needed, strike_index = 0;
1369 /* If we have a File Name key then this is a real font, not just the parent
1370 key of a bunch of non-scalable strikes */
1371 needed = buffer_size;
1372 if (RegQueryValueExW(hkey_face, face_file_name_value, NULL, NULL, buffer, &needed) == ERROR_SUCCESS)
1375 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1376 face->cached_enum_data = NULL;
1377 face->family = NULL;
1380 face->file = strdupW( buffer );
1381 face->StyleName = strdupW(face_name);
1383 needed = buffer_size;
1384 if(RegQueryValueExW(hkey_face, face_full_name_value, NULL, NULL, buffer, &needed) == ERROR_SUCCESS)
1385 face->FullName = strdupW( buffer );
1387 face->FullName = NULL;
1389 reg_load_dword(hkey_face, face_index_value, (DWORD*)&face->face_index);
1390 reg_load_dword(hkey_face, face_ntmflags_value, &face->ntmFlags);
1391 reg_load_dword(hkey_face, face_version_value, (DWORD*)&face->font_version);
1392 reg_load_dword(hkey_face, face_vertical_value, (DWORD*)&face->vertical);
1393 reg_load_dword(hkey_face, face_aa_value, (DWORD*)&face->aa_flags);
1395 needed = sizeof(face->fs);
1396 RegQueryValueExW(hkey_face, face_font_sig_value, NULL, NULL, (BYTE*)&face->fs, &needed);
1398 if(reg_load_dword(hkey_face, face_height_value, (DWORD*)&face->size.height) != ERROR_SUCCESS)
1400 face->scalable = TRUE;
1401 memset(&face->size, 0, sizeof(face->size));
1405 face->scalable = FALSE;
1406 reg_load_dword(hkey_face, face_width_value, (DWORD*)&face->size.width);
1407 reg_load_dword(hkey_face, face_size_value, (DWORD*)&face->size.size);
1408 reg_load_dword(hkey_face, face_x_ppem_value, (DWORD*)&face->size.x_ppem);
1409 reg_load_dword(hkey_face, face_y_ppem_value, (DWORD*)&face->size.y_ppem);
1410 reg_load_dword(hkey_face, face_internal_leading_value, (DWORD*)&face->size.internal_leading);
1412 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1413 face->size.height, face->size.width, face->size.size >> 6,
1414 face->size.x_ppem >> 6, face->size.y_ppem >> 6);
1417 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1418 face->fs.fsCsb[0], face->fs.fsCsb[1],
1419 face->fs.fsUsb[0], face->fs.fsUsb[1],
1420 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1422 if (insert_face_in_family_list(face, family))
1423 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName));
1425 release_face( face );
1428 /* load bitmap strikes */
1430 needed = buffer_size;
1431 while (!RegEnumKeyExW(hkey_face, strike_index++, buffer, &needed, NULL, NULL, NULL, NULL))
1433 if (!RegOpenKeyExW(hkey_face, buffer, 0, KEY_ALL_ACCESS, &hkey_strike))
1435 load_face(hkey_strike, face_name, family, buffer, buffer_size);
1436 RegCloseKey(hkey_strike);
1438 needed = buffer_size;
1442 static void load_font_list_from_cache(HKEY hkey_font_cache)
1444 DWORD size, family_index = 0;
1449 size = sizeof(buffer);
1450 while (!RegEnumKeyExW(hkey_font_cache, family_index++, buffer, &size, NULL, NULL, NULL, NULL))
1452 WCHAR *english_family = NULL;
1453 WCHAR *family_name = strdupW( buffer );
1454 DWORD face_index = 0;
1456 RegOpenKeyExW(hkey_font_cache, family_name, 0, KEY_ALL_ACCESS, &hkey_family);
1457 TRACE("opened family key %s\n", debugstr_w(family_name));
1458 size = sizeof(buffer);
1459 if (!RegQueryValueExW(hkey_family, english_name_value, NULL, NULL, (BYTE *)buffer, &size))
1460 english_family = strdupW( buffer );
1462 family = create_family(family_name, english_family);
1466 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1467 subst->from.name = strdupW(english_family);
1468 subst->from.charset = -1;
1469 subst->to.name = strdupW(family_name);
1470 subst->to.charset = -1;
1471 add_font_subst(&font_subst_list, subst, 0);
1474 size = sizeof(buffer);
1475 while (!RegEnumKeyExW(hkey_family, face_index++, buffer, &size, NULL, NULL, NULL, NULL))
1477 WCHAR *face_name = strdupW( buffer );
1480 if (!RegOpenKeyExW(hkey_family, face_name, 0, KEY_ALL_ACCESS, &hkey_face))
1482 load_face(hkey_face, face_name, family, buffer, sizeof(buffer));
1483 RegCloseKey(hkey_face);
1485 HeapFree( GetProcessHeap(), 0, face_name );
1486 size = sizeof(buffer);
1488 RegCloseKey(hkey_family);
1489 release_family( family );
1490 size = sizeof(buffer);
1494 static LONG create_font_cache_key(HKEY *hkey, DWORD *disposition)
1497 HKEY hkey_wine_fonts;
1499 /* We don't want to create the fonts key as volatile, so open this first */
1500 ret = RegCreateKeyExW(HKEY_CURRENT_USER, wine_fonts_key, 0, NULL, 0,
1501 KEY_ALL_ACCESS, NULL, &hkey_wine_fonts, NULL);
1502 if(ret != ERROR_SUCCESS)
1504 WARN("Can't create %s\n", debugstr_w(wine_fonts_key));
1508 ret = RegCreateKeyExW(hkey_wine_fonts, wine_fonts_cache_key, 0, NULL, REG_OPTION_VOLATILE,
1509 KEY_ALL_ACCESS, NULL, hkey, disposition);
1510 RegCloseKey(hkey_wine_fonts);
1514 static void add_face_to_cache(Face *face)
1516 HKEY hkey_font_cache, hkey_family, hkey_face;
1517 WCHAR *face_key_name;
1519 create_font_cache_key(&hkey_font_cache, NULL);
1521 RegCreateKeyExW(hkey_font_cache, face->family->FamilyName, 0,
1522 NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey_family, NULL);
1523 if(face->family->EnglishName)
1524 RegSetValueExW(hkey_family, english_name_value, 0, REG_SZ, (BYTE*)face->family->EnglishName,
1525 (strlenW(face->family->EnglishName) + 1) * sizeof(WCHAR));
1528 face_key_name = face->StyleName;
1531 static const WCHAR fmtW[] = {'%','s','\\','%','d',0};
1532 face_key_name = HeapAlloc(GetProcessHeap(), 0, (strlenW(face->StyleName) + 10) * sizeof(WCHAR));
1533 sprintfW(face_key_name, fmtW, face->StyleName, face->size.y_ppem);
1535 RegCreateKeyExW(hkey_family, face_key_name, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL,
1538 HeapFree(GetProcessHeap(), 0, face_key_name);
1540 RegSetValueExW(hkey_face, face_file_name_value, 0, REG_SZ, (BYTE *)face->file,
1541 (strlenW(face->file) + 1) * sizeof(WCHAR));
1543 RegSetValueExW(hkey_face, face_full_name_value, 0, REG_SZ, (BYTE*)face->FullName,
1544 (strlenW(face->FullName) + 1) * sizeof(WCHAR));
1546 reg_save_dword(hkey_face, face_index_value, face->face_index);
1547 reg_save_dword(hkey_face, face_ntmflags_value, face->ntmFlags);
1548 reg_save_dword(hkey_face, face_version_value, face->font_version);
1549 if (face->vertical) reg_save_dword(hkey_face, face_vertical_value, face->vertical);
1550 if (face->aa_flags) reg_save_dword(hkey_face, face_aa_value, face->aa_flags);
1552 RegSetValueExW(hkey_face, face_font_sig_value, 0, REG_BINARY, (BYTE*)&face->fs, sizeof(face->fs));
1556 reg_save_dword(hkey_face, face_height_value, face->size.height);
1557 reg_save_dword(hkey_face, face_width_value, face->size.width);
1558 reg_save_dword(hkey_face, face_size_value, face->size.size);
1559 reg_save_dword(hkey_face, face_x_ppem_value, face->size.x_ppem);
1560 reg_save_dword(hkey_face, face_y_ppem_value, face->size.y_ppem);
1561 reg_save_dword(hkey_face, face_internal_leading_value, face->size.internal_leading);
1563 RegCloseKey(hkey_face);
1564 RegCloseKey(hkey_family);
1565 RegCloseKey(hkey_font_cache);
1568 static WCHAR *prepend_at(WCHAR *family)
1575 str = HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR) * (strlenW(family) + 2));
1577 strcpyW(str + 1, family);
1578 HeapFree(GetProcessHeap(), 0, family);
1582 static void get_family_names( FT_Face ft_face, WCHAR **name, WCHAR **english, BOOL vertical )
1584 *english = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1585 if (!*english) *english = towstr( CP_ACP, ft_face->family_name );
1587 *name = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, GetSystemDefaultLCID() );
1593 else if (!strcmpiW( *name, *english ))
1595 HeapFree( GetProcessHeap(), 0, *english );
1601 *name = prepend_at( *name );
1602 *english = prepend_at( *english );
1606 static Family *get_family( FT_Face ft_face, BOOL vertical )
1609 WCHAR *name, *english_name;
1611 get_family_names( ft_face, &name, &english_name, vertical );
1613 family = find_family_from_name( name );
1617 family = create_family( name, english_name );
1620 FontSubst *subst = HeapAlloc( GetProcessHeap(), 0, sizeof(*subst) );
1621 subst->from.name = strdupW( english_name );
1622 subst->from.charset = -1;
1623 subst->to.name = strdupW( name );
1624 subst->to.charset = -1;
1625 add_font_subst( &font_subst_list, subst, 0 );
1630 HeapFree( GetProcessHeap(), 0, name );
1631 HeapFree( GetProcessHeap(), 0, english_name );
1638 static inline FT_Fixed get_font_version( FT_Face ft_face )
1640 FT_Fixed version = 0;
1643 header = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head );
1644 if (header) version = header->Font_Revision;
1649 static inline DWORD get_ntm_flags( FT_Face ft_face )
1652 FT_ULong table_size = 0;
1654 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) flags |= NTM_ITALIC;
1655 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD) flags |= NTM_BOLD;
1656 if (flags == 0) flags = NTM_REGULAR;
1658 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL, &table_size ))
1659 flags |= NTM_PS_OPENTYPE;
1664 static inline int get_bitmap_internal_leading( FT_Face ft_face )
1666 int internal_leading = 0;
1667 FT_WinFNT_HeaderRec winfnt_header;
1669 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1670 internal_leading = winfnt_header.internal_leading;
1672 return internal_leading;
1675 static inline void get_fontsig( FT_Face ft_face, FONTSIGNATURE *fs )
1680 FT_WinFNT_HeaderRec winfnt_header;
1683 memset( fs, 0, sizeof(*fs) );
1685 os2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 );
1688 fs->fsUsb[0] = os2->ulUnicodeRange1;
1689 fs->fsUsb[1] = os2->ulUnicodeRange2;
1690 fs->fsUsb[2] = os2->ulUnicodeRange3;
1691 fs->fsUsb[3] = os2->ulUnicodeRange4;
1693 if (os2->version == 0)
1695 if (pFT_Get_First_Char( ft_face, &dummy ) < 0x100)
1696 fs->fsCsb[0] = FS_LATIN1;
1698 fs->fsCsb[0] = FS_SYMBOL;
1702 fs->fsCsb[0] = os2->ulCodePageRange1;
1703 fs->fsCsb[1] = os2->ulCodePageRange2;
1708 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
1710 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1711 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1712 if (TranslateCharsetInfo( (DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET ))
1717 if (fs->fsCsb[0] == 0)
1719 /* let's see if we can find any interesting cmaps */
1720 for (i = 0; i < ft_face->num_charmaps; i++)
1722 switch (ft_face->charmaps[i]->encoding)
1724 case FT_ENCODING_UNICODE:
1725 case FT_ENCODING_APPLE_ROMAN:
1726 fs->fsCsb[0] |= FS_LATIN1;
1728 case FT_ENCODING_MS_SYMBOL:
1729 fs->fsCsb[0] |= FS_SYMBOL;
1738 #define ADDFONT_EXTERNAL_FONT 0x01
1739 #define ADDFONT_FORCE_BITMAP 0x02
1740 #define ADDFONT_ADD_TO_CACHE 0x04
1741 #define ADDFONT_AA_FLAGS(flags) ((flags) << 16)
1743 static Face *create_face( FT_Face ft_face, FT_Long face_index, const char *file, void *font_data_ptr, DWORD font_data_size,
1744 DWORD flags, BOOL vertical, DWORD aa_flags )
1746 Face *face = HeapAlloc( GetProcessHeap(), 0, sizeof(*face) );
1747 My_FT_Bitmap_Size *size = (My_FT_Bitmap_Size *)ft_face->available_sizes;
1750 face->StyleName = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
1751 if (!face->StyleName)
1752 face->StyleName = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1753 if (!face->StyleName)
1755 face->StyleName = towstr( CP_ACP, ft_face->style_name );
1758 face->FullName = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
1759 if (!face->FullName)
1760 face->FullName = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES );
1762 face->FullName = prepend_at( face->FullName );
1766 face->file = towstr( CP_UNIXCP, file );
1767 face->font_data_ptr = NULL;
1768 face->font_data_size = 0;
1773 face->font_data_ptr = font_data_ptr;
1774 face->font_data_size = font_data_size;
1777 face->face_index = face_index;
1778 get_fontsig( ft_face, &face->fs );
1779 face->ntmFlags = get_ntm_flags( ft_face );
1780 face->font_version = get_font_version( ft_face );
1782 if (FT_IS_SCALABLE( ft_face ))
1784 memset( &face->size, 0, sizeof(face->size) );
1785 face->scalable = TRUE;
1789 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1790 size->height, size->width, size->size >> 6,
1791 size->x_ppem >> 6, size->y_ppem >> 6);
1792 face->size.height = size->height;
1793 face->size.width = size->width;
1794 face->size.size = size->size;
1795 face->size.x_ppem = size->x_ppem;
1796 face->size.y_ppem = size->y_ppem;
1797 face->size.internal_leading = get_bitmap_internal_leading( ft_face );
1798 face->scalable = FALSE;
1801 face->vertical = vertical;
1802 face->external = (flags & ADDFONT_EXTERNAL_FONT) != 0;
1803 face->aa_flags = aa_flags;
1804 face->family = NULL;
1805 face->cached_enum_data = NULL;
1807 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1808 face->fs.fsCsb[0], face->fs.fsCsb[1],
1809 face->fs.fsUsb[0], face->fs.fsUsb[1],
1810 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1815 static void AddFaceToList(FT_Face ft_face, const char *file, void *font_data_ptr, DWORD font_data_size,
1816 FT_Long face_index, DWORD flags, BOOL vertical, DWORD aa_flags )
1821 face = create_face( ft_face, face_index, file, font_data_ptr, font_data_size, flags, vertical, aa_flags );
1822 family = get_family( ft_face, vertical );
1823 if (insert_face_in_family_list( face, family ))
1825 if (flags & ADDFONT_ADD_TO_CACHE)
1826 add_face_to_cache( face );
1828 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1829 debugstr_w(face->StyleName));
1831 release_face( face );
1832 release_family( family );
1835 static FT_Face new_ft_face( const char *file, void *font_data_ptr, DWORD font_data_size,
1836 FT_Long face_index, BOOL allow_bitmap )
1844 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1845 err = pFT_New_Face(library, file, face_index, &ft_face);
1849 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1850 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1855 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1859 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1860 if (!FT_IS_SCALABLE( ft_face ) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0)))
1862 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1866 if (!FT_IS_SFNT( ft_face ))
1868 if (FT_IS_SCALABLE( ft_face ) || !allow_bitmap )
1870 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1876 if (!(pOS2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 )) ||
1877 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_hhea ) ||
1878 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head ))
1880 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1881 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1885 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1886 we don't want to load these. */
1887 if (!memcmp( pOS2->achVendID, "Wine", sizeof(pOS2->achVendID) ))
1891 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len ))
1893 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1899 if (!ft_face->family_name || !ft_face->style_name)
1901 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1907 pFT_Done_Face( ft_face );
1911 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, DWORD flags)
1914 FT_Long face_index = 0, num_faces;
1916 DWORD aa_flags = HIWORD( flags );
1918 if (!aa_flags) aa_flags = default_aa_flags;
1920 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1921 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1923 #ifdef HAVE_CARBON_CARBON_H
1926 char **mac_list = expand_mac_font(file);
1929 BOOL had_one = FALSE;
1931 for(cursor = mac_list; *cursor; cursor++)
1934 AddFontToList(*cursor, NULL, 0, flags);
1935 HeapFree(GetProcessHeap(), 0, *cursor);
1937 HeapFree(GetProcessHeap(), 0, mac_list);
1942 #endif /* HAVE_CARBON_CARBON_H */
1945 ft_face = new_ft_face( file, font_data_ptr, font_data_size, face_index, flags & ADDFONT_FORCE_BITMAP );
1946 if (!ft_face) return 0;
1948 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1950 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file));
1951 pFT_Done_Face(ft_face);
1955 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags, FALSE, aa_flags);
1958 if (FT_HAS_VERTICAL(ft_face))
1960 AddFaceToList(ft_face, file, font_data_ptr, font_data_size, face_index, flags, TRUE, aa_flags);
1964 num_faces = ft_face->num_faces;
1965 pFT_Done_Face(ft_face);
1966 } while(num_faces > ++face_index);
1970 static void DumpFontList(void)
1975 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
1976 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1977 LIST_FOR_EACH_ENTRY( face, &family->faces, Face, entry ) {
1978 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1980 TRACE(" %d", face->size.height);
1987 /***********************************************************
1988 * The replacement list is a way to map an entire font
1989 * family onto another family. For example adding
1991 * [HKCU\Software\Wine\Fonts\Replacements]
1992 * "Wingdings"="Winedings"
1994 * would enumerate the Winedings font both as Winedings and
1995 * Wingdings. However if a real Wingdings font is present the
1996 * replacement does not take place.
1999 static void LoadReplaceList(void)
2002 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2006 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
2007 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
2009 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2010 &valuelen, &datalen, NULL, NULL);
2012 valuelen++; /* returned value doesn't include room for '\0' */
2013 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2014 data = HeapAlloc(GetProcessHeap(), 0, datalen);
2018 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
2019 &dlen) == ERROR_SUCCESS) {
2020 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
2021 /* "NewName"="Oldname" */
2022 if(!find_family_from_any_name(value))
2024 Family * const family = find_family_from_any_name(data);
2027 Family * const new_family = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family));
2028 if (new_family != NULL)
2030 TRACE("mapping %s to %s\n", debugstr_w(data), debugstr_w(value));
2031 new_family->FamilyName = strdupW(value);
2032 new_family->EnglishName = NULL;
2033 list_init(&new_family->faces);
2034 new_family->replacement = &family->faces;
2035 list_add_tail(&font_list, &new_family->entry);
2040 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(data));
2045 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value));
2047 /* reset dlen and vlen */
2051 HeapFree(GetProcessHeap(), 0, data);
2052 HeapFree(GetProcessHeap(), 0, value);
2057 static const WCHAR *font_links_list[] =
2059 Lucida_Sans_Unicode,
2060 Microsoft_Sans_Serif,
2064 static const struct font_links_defaults_list
2066 /* Keyed off substitution for "MS Shell Dlg" */
2067 const WCHAR *shelldlg;
2068 /* Maximum of four substitutes, plus terminating NULL pointer */
2069 const WCHAR *substitutes[5];
2070 } font_links_defaults_list[] =
2072 /* Non East-Asian */
2073 { Tahoma, /* FIXME unverified ordering */
2074 { MS_UI_Gothic, SimSun, Gulim, PMingLiU, NULL }
2076 /* Below lists are courtesy of
2077 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2081 { MS_UI_Gothic, PMingLiU, SimSun, Gulim, NULL }
2083 /* Chinese Simplified */
2085 { SimSun, PMingLiU, MS_UI_Gothic, Batang, NULL }
2089 { Gulim, PMingLiU, MS_UI_Gothic, SimSun, NULL }
2091 /* Chinese Traditional */
2093 { PMingLiU, SimSun, MS_UI_Gothic, Batang, NULL }
2098 static SYSTEM_LINKS *find_font_link(const WCHAR *name)
2100 SYSTEM_LINKS *font_link;
2102 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2104 if(!strcmpiW(font_link->font_name, name))
2111 static void populate_system_links(const WCHAR *name, const WCHAR *const *values)
2122 SYSTEM_LINKS *font_link;
2124 psub = get_font_subst(&font_subst_list, name, -1);
2125 /* Don't store fonts that are only substitutes for other fonts */
2128 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name));
2132 font_link = find_font_link(name);
2133 if (font_link == NULL)
2135 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2136 font_link->font_name = strdupW(name);
2137 list_init(&font_link->links);
2138 list_add_tail(&system_links, &font_link->entry);
2141 memset(&font_link->fs, 0, sizeof font_link->fs);
2142 for (i = 0; values[i] != NULL; i++)
2144 const struct list *face_list;
2145 CHILD_FONT *child_font;
2148 if (!strcmpiW(name,value))
2150 psub = get_font_subst(&font_subst_list, value, -1);
2152 value = psub->to.name;
2153 family = find_family_from_name(value);
2157 /* Use first extant filename for this Family */
2158 face_list = get_face_list_from_family(family);
2159 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
2163 file = strrchrW(face->file, '/');
2172 face = find_face_from_filename(file, value);
2175 TRACE("Unable to find file %s face name %s\n", debugstr_w(file), debugstr_w(value));
2179 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2180 child_font->face = face;
2181 child_font->font = NULL;
2182 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2183 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2184 TRACE("Adding file %s index %ld\n", debugstr_w(child_font->face->file),
2185 child_font->face->face_index);
2186 list_add_tail(&font_link->links, &child_font->entry);
2188 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name), debugstr_w(value),debugstr_w(file));
2194 /*************************************************************
2197 static BOOL init_system_links(void)
2201 DWORD type, max_val, max_data, val_len, data_len, index;
2202 WCHAR *value, *data;
2203 WCHAR *entry, *next;
2204 SYSTEM_LINKS *font_link, *system_font_link;
2205 CHILD_FONT *child_font;
2206 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
2207 static const WCHAR System[] = {'S','y','s','t','e','m',0};
2208 static const WCHAR MS_Shell_Dlg[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2213 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
2215 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
2216 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
2217 data = HeapAlloc(GetProcessHeap(), 0, max_data);
2218 val_len = max_val + 1;
2219 data_len = max_data;
2221 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
2223 psub = get_font_subst(&font_subst_list, value, -1);
2224 /* Don't store fonts that are only substitutes for other fonts */
2227 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value));
2230 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
2231 font_link->font_name = strdupW(value);
2232 memset(&font_link->fs, 0, sizeof font_link->fs);
2233 list_init(&font_link->links);
2234 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
2237 CHILD_FONT *child_font;
2239 TRACE("%s: %s\n", debugstr_w(value), debugstr_w(entry));
2241 next = entry + strlenW(entry) + 1;
2243 face_name = strchrW(entry, ',');
2247 while(isspaceW(*face_name))
2250 psub = get_font_subst(&font_subst_list, face_name, -1);
2252 face_name = psub->to.name;
2254 face = find_face_from_filename(entry, face_name);
2257 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
2261 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2262 child_font->face = face;
2263 child_font->font = NULL;
2264 font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2265 font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2266 TRACE("Adding file %s index %ld\n",
2267 debugstr_w(child_font->face->file), child_font->face->face_index);
2268 list_add_tail(&font_link->links, &child_font->entry);
2270 list_add_tail(&system_links, &font_link->entry);
2272 val_len = max_val + 1;
2273 data_len = max_data;
2276 HeapFree(GetProcessHeap(), 0, value);
2277 HeapFree(GetProcessHeap(), 0, data);
2282 psub = get_font_subst(&font_subst_list, MS_Shell_Dlg, -1);
2284 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2288 for (i = 0; i < sizeof(font_links_defaults_list)/sizeof(font_links_defaults_list[0]); i++)
2290 const FontSubst *psub2;
2291 psub2 = get_font_subst(&font_subst_list, font_links_defaults_list[i].shelldlg, -1);
2293 if ((!strcmpiW(font_links_defaults_list[i].shelldlg, psub->to.name) || (psub2 && !strcmpiW(psub2->to.name,psub->to.name))))
2295 for (j = 0; j < sizeof(font_links_list)/sizeof(font_links_list[0]); j++)
2296 populate_system_links(font_links_list[j], font_links_defaults_list[i].substitutes);
2298 if (!strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2299 populate_system_links(psub->to.name, font_links_defaults_list[i].substitutes);
2301 else if (strcmpiW(psub->to.name, font_links_defaults_list[i].substitutes[0]))
2303 populate_system_links(font_links_defaults_list[i].substitutes[0], NULL);
2309 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2312 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
2313 system_font_link->font_name = strdupW(System);
2314 memset(&system_font_link->fs, 0, sizeof system_font_link->fs);
2315 list_init(&system_font_link->links);
2317 face = find_face_from_filename(tahoma_ttf, Tahoma);
2320 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
2321 child_font->face = face;
2322 child_font->font = NULL;
2323 system_font_link->fs.fsCsb[0] |= face->fs.fsCsb[0];
2324 system_font_link->fs.fsCsb[1] |= face->fs.fsCsb[1];
2325 TRACE("Found Tahoma in %s index %ld\n",
2326 debugstr_w(child_font->face->file), child_font->face->face_index);
2327 list_add_tail(&system_font_link->links, &child_font->entry);
2329 font_link = find_font_link(Tahoma);
2330 if (font_link != NULL)
2332 CHILD_FONT *font_link_entry;
2333 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2335 CHILD_FONT *new_child;
2336 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2337 new_child->face = font_link_entry->face;
2338 new_child->font = NULL;
2339 new_child->face->refcount++;
2340 system_font_link->fs.fsCsb[0] |= font_link_entry->face->fs.fsCsb[0];
2341 system_font_link->fs.fsCsb[1] |= font_link_entry->face->fs.fsCsb[1];
2342 list_add_tail(&system_font_link->links, &new_child->entry);
2345 list_add_tail(&system_links, &system_font_link->entry);
2349 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
2352 struct dirent *dent;
2353 char path[MAX_PATH];
2355 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
2357 dir = opendir(dirname);
2359 WARN("Can't open directory %s\n", debugstr_a(dirname));
2362 while((dent = readdir(dir)) != NULL) {
2363 struct stat statbuf;
2365 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2368 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
2370 sprintf(path, "%s/%s", dirname, dent->d_name);
2372 if(stat(path, &statbuf) == -1)
2374 WARN("Can't stat %s\n", debugstr_a(path));
2377 if(S_ISDIR(statbuf.st_mode))
2378 ReadFontDir(path, external_fonts);
2381 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
2382 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
2383 AddFontToList(path, NULL, 0, addfont_flags);
2390 #ifdef SONAME_LIBFONTCONFIG
2392 static BOOL fontconfig_enabled;
2394 static UINT parse_aa_pattern( FcPattern *pattern )
2400 if (pFcPatternGetBool( pattern, FC_ANTIALIAS, 0, &antialias ) == FcResultMatch)
2401 aa_flags = antialias ? GGO_GRAY4_BITMAP : GGO_BITMAP;
2403 if (pFcPatternGetInteger( pattern, FC_RGBA, 0, &rgba ) == FcResultMatch)
2407 case FC_RGBA_RGB: aa_flags = WINE_GGO_HRGB_BITMAP; break;
2408 case FC_RGBA_BGR: aa_flags = WINE_GGO_HBGR_BITMAP; break;
2409 case FC_RGBA_VRGB: aa_flags = WINE_GGO_VRGB_BITMAP; break;
2410 case FC_RGBA_VBGR: aa_flags = WINE_GGO_VBGR_BITMAP; break;
2411 case FC_RGBA_NONE: aa_flags = GGO_GRAY4_BITMAP; break;
2417 static void init_fontconfig(void)
2419 void *fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
2423 TRACE("Wine cannot find the fontconfig library (%s).\n", SONAME_LIBFONTCONFIG);
2427 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); return;}
2428 LOAD_FUNCPTR(FcConfigSubstitute);
2429 LOAD_FUNCPTR(FcFontList);
2430 LOAD_FUNCPTR(FcFontSetDestroy);
2431 LOAD_FUNCPTR(FcInit);
2432 LOAD_FUNCPTR(FcObjectSetAdd);
2433 LOAD_FUNCPTR(FcObjectSetCreate);
2434 LOAD_FUNCPTR(FcObjectSetDestroy);
2435 LOAD_FUNCPTR(FcPatternCreate);
2436 LOAD_FUNCPTR(FcPatternDestroy);
2437 LOAD_FUNCPTR(FcPatternGetBool);
2438 LOAD_FUNCPTR(FcPatternGetInteger);
2439 LOAD_FUNCPTR(FcPatternGetString);
2444 FcPattern *pattern = pFcPatternCreate();
2445 pFcConfigSubstitute( NULL, pattern, FcMatchFont );
2446 default_aa_flags = parse_aa_pattern( pattern );
2447 pFcPatternDestroy( pattern );
2448 TRACE( "enabled, default flags = %x\n", default_aa_flags );
2449 fontconfig_enabled = TRUE;
2453 static void load_fontconfig_fonts(void)
2462 if (!fontconfig_enabled) return;
2464 pat = pFcPatternCreate();
2465 os = pFcObjectSetCreate();
2466 pFcObjectSetAdd(os, FC_FILE);
2467 pFcObjectSetAdd(os, FC_SCALABLE);
2468 pFcObjectSetAdd(os, FC_ANTIALIAS);
2469 pFcObjectSetAdd(os, FC_RGBA);
2470 fontset = pFcFontList(NULL, pat, os);
2471 if(!fontset) return;
2472 for(i = 0; i < fontset->nfont; i++) {
2476 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
2479 pFcConfigSubstitute( NULL, fontset->fonts[i], FcMatchFont );
2481 /* We're just interested in OT/TT fonts for now, so this hack just
2482 picks up the scalable fonts without extensions .pf[ab] to save time
2483 loading every other font */
2485 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
2487 TRACE("not scalable\n");
2491 aa_flags = parse_aa_pattern( fontset->fonts[i] );
2492 TRACE("fontconfig: %s aa %x\n", file, aa_flags);
2494 len = strlen( file );
2495 if(len < 4) continue;
2496 ext = &file[ len - 3 ];
2497 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
2498 AddFontToList(file, NULL, 0,
2499 ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE | ADDFONT_AA_FLAGS(aa_flags) );
2501 pFcFontSetDestroy(fontset);
2502 pFcObjectSetDestroy(os);
2503 pFcPatternDestroy(pat);
2506 #elif defined(HAVE_CARBON_CARBON_H)
2508 static void load_mac_font_callback(const void *value, void *context)
2510 CFStringRef pathStr = value;
2514 len = CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr);
2515 path = HeapAlloc(GetProcessHeap(), 0, len);
2516 if (path && CFStringGetFileSystemRepresentation(pathStr, path, len))
2518 TRACE("font file %s\n", path);
2519 AddFontToList(path, NULL, 0, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
2521 HeapFree(GetProcessHeap(), 0, path);
2524 static void load_mac_fonts(void)
2526 CFStringRef removeDupesKey;
2527 CFBooleanRef removeDupesValue;
2528 CFDictionaryRef options;
2529 CTFontCollectionRef col;
2531 CFMutableSetRef paths;
2534 removeDupesKey = kCTFontCollectionRemoveDuplicatesOption;
2535 removeDupesValue = kCFBooleanTrue;
2536 options = CFDictionaryCreate(NULL, (const void**)&removeDupesKey, (const void**)&removeDupesValue, 1,
2537 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2538 col = CTFontCollectionCreateFromAvailableFonts(options);
2539 if (options) CFRelease(options);
2542 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
2546 descs = CTFontCollectionCreateMatchingFontDescriptors(col);
2550 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
2554 paths = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
2557 WARN("CFSetCreateMutable failed\n");
2562 for (i = 0; i < CFArrayGetCount(descs); i++)
2564 CTFontDescriptorRef desc;
2573 desc = CFArrayGetValueAtIndex(descs, i);
2575 /* CTFontDescriptor doesn't support kCTFontURLAttribute until 10.6, so
2576 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
2577 font = CTFontCreateWithFontDescriptor(desc, 0, NULL);
2578 if (!font) continue;
2580 atsFont = CTFontGetPlatformFont(font, NULL);
2587 status = ATSFontGetFileReference(atsFont, &fsref);
2589 if (status != noErr) continue;
2591 url = CFURLCreateFromFSRef(NULL, &fsref);
2594 ext = CFURLCopyPathExtension(url);
2597 BOOL skip = (CFStringCompare(ext, CFSTR("pfa"), kCFCompareCaseInsensitive) == kCFCompareEqualTo ||
2598 CFStringCompare(ext, CFSTR("pfb"), kCFCompareCaseInsensitive) == kCFCompareEqualTo);
2607 path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
2609 if (!path) continue;
2611 CFSetAddValue(paths, path);
2617 CFSetApplyFunction(paths, load_mac_font_callback, NULL);
2623 static BOOL load_font_from_data_dir(LPCWSTR file)
2626 const char *data_dir = wine_get_data_dir();
2628 if (!data_dir) data_dir = wine_get_build_dir();
2635 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
2637 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
2639 strcpy(unix_name, data_dir);
2640 strcat(unix_name, "/fonts/");
2642 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
2644 EnterCriticalSection( &freetype_cs );
2645 ret = AddFontToList(unix_name, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2646 LeaveCriticalSection( &freetype_cs );
2647 HeapFree(GetProcessHeap(), 0, unix_name);
2652 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
2654 static const WCHAR slashW[] = {'\\','\0'};
2656 WCHAR windowsdir[MAX_PATH];
2659 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2660 strcatW(windowsdir, fontsW);
2661 strcatW(windowsdir, slashW);
2662 strcatW(windowsdir, file);
2663 if ((unixname = wine_get_unix_file_name(windowsdir))) {
2664 EnterCriticalSection( &freetype_cs );
2665 ret = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP);
2666 LeaveCriticalSection( &freetype_cs );
2667 HeapFree(GetProcessHeap(), 0, unixname);
2672 static void load_system_fonts(void)
2675 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
2676 const WCHAR * const *value;
2678 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2681 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
2682 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2683 strcatW(windowsdir, fontsW);
2684 for(value = SystemFontValues; *value; value++) {
2685 dlen = sizeof(data);
2686 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
2690 sprintfW(pathW, fmtW, windowsdir, data);
2691 if((unixname = wine_get_unix_file_name(pathW))) {
2692 added = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
2693 HeapFree(GetProcessHeap(), 0, unixname);
2696 load_font_from_data_dir(data);
2703 /*************************************************************
2705 * This adds registry entries for any externally loaded fonts
2706 * (fonts from fontconfig or FontDirs). It also deletes entries
2707 * of no longer existing fonts.
2710 static void update_reg_entries(void)
2712 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2718 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2720 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2721 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2722 ERR("Can't create Windows font reg key\n");
2726 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2727 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2728 ERR("Can't create Windows font reg key\n");
2732 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
2733 0, NULL, 0, KEY_ALL_ACCESS, NULL, &external_key, NULL) != ERROR_SUCCESS) {
2734 ERR("Can't create external font reg key\n");
2738 /* enumerate the fonts and add external ones to the two keys */
2740 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
2741 LIST_FOR_EACH_ENTRY( face, &family->faces, Face, entry ) {
2743 if(!face->external) continue;
2747 len = strlenW(face->FullName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2748 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2749 strcpyW(valueW, face->FullName);
2753 len = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
2754 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2755 strcpyW(valueW, family->FamilyName);
2758 buffer = strWtoA( CP_UNIXCP, face->file );
2759 path = wine_get_dos_file_name( buffer );
2760 HeapFree( GetProcessHeap(), 0, buffer );
2764 else if ((file = strrchrW(face->file, '/')))
2769 len = strlenW(file) + 1;
2770 RegSetValueExW(winnt_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2771 RegSetValueExW(win9x_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2772 RegSetValueExW(external_key, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
2774 HeapFree(GetProcessHeap(), 0, path);
2775 HeapFree(GetProcessHeap(), 0, valueW);
2779 if(external_key) RegCloseKey(external_key);
2780 if(win9x_key) RegCloseKey(win9x_key);
2781 if(winnt_key) RegCloseKey(winnt_key);
2785 static void delete_external_font_keys(void)
2787 HKEY winnt_key = 0, win9x_key = 0, external_key = 0;
2788 DWORD dlen, vlen, datalen, valuelen, i, type;
2792 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key,
2793 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winnt_key, NULL) != ERROR_SUCCESS) {
2794 ERR("Can't create Windows font reg key\n");
2798 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key,
2799 0, NULL, 0, KEY_ALL_ACCESS, NULL, &win9x_key, NULL) != ERROR_SUCCESS) {
2800 ERR("Can't create Windows font reg key\n");
2804 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &external_key) != ERROR_SUCCESS) {
2805 ERR("Can't create external font reg key\n");
2809 /* Delete all external fonts added last time */
2811 RegQueryInfoKeyW(external_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2812 &valuelen, &datalen, NULL, NULL);
2813 valuelen++; /* returned value doesn't include room for '\0' */
2814 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2815 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2817 dlen = datalen * sizeof(WCHAR);
2820 while(RegEnumValueW(external_key, i++, valueW, &vlen, NULL, &type, data,
2821 &dlen) == ERROR_SUCCESS) {
2823 RegDeleteValueW(winnt_key, valueW);
2824 RegDeleteValueW(win9x_key, valueW);
2825 /* reset dlen and vlen */
2829 HeapFree(GetProcessHeap(), 0, data);
2830 HeapFree(GetProcessHeap(), 0, valueW);
2832 /* Delete the old external fonts key */
2833 RegCloseKey(external_key);
2834 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
2837 if(win9x_key) RegCloseKey(win9x_key);
2838 if(winnt_key) RegCloseKey(winnt_key);
2841 /*************************************************************
2842 * WineEngAddFontResourceEx
2845 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2851 if (ft_handle) /* do it only if we have freetype up and running */
2856 FIXME("Ignoring flags %x\n", flags);
2858 if((unixname = wine_get_unix_file_name(file)))
2860 DWORD addfont_flags = ADDFONT_FORCE_BITMAP;
2862 if(!(flags & FR_PRIVATE)) addfont_flags |= ADDFONT_ADD_TO_CACHE;
2863 EnterCriticalSection( &freetype_cs );
2864 ret = AddFontToList(unixname, NULL, 0, addfont_flags);
2865 LeaveCriticalSection( &freetype_cs );
2866 HeapFree(GetProcessHeap(), 0, unixname);
2868 if (!ret && !strchrW(file, '\\')) {
2869 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
2870 ret = load_font_from_winfonts_dir(file);
2872 /* Try in datadir/fonts (or builddir/fonts),
2873 * needed for Magic the Gathering Online
2875 ret = load_font_from_data_dir(file);
2882 /*************************************************************
2883 * WineEngAddFontMemResourceEx
2886 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
2890 if (ft_handle) /* do it only if we have freetype up and running */
2892 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
2894 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
2895 memcpy(pFontCopy, pbFont, cbFont);
2897 EnterCriticalSection( &freetype_cs );
2898 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, ADDFONT_FORCE_BITMAP);
2899 LeaveCriticalSection( &freetype_cs );
2903 TRACE("AddFontToList failed\n");
2904 HeapFree(GetProcessHeap(), 0, pFontCopy);
2907 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
2908 * For now return something unique but quite random
2910 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
2911 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
2918 /*************************************************************
2919 * WineEngRemoveFontResourceEx
2922 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2925 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
2929 static char *get_ttf_file_name( LPCWSTR font_file, LPCWSTR font_path )
2935 if (!font_file) return NULL;
2937 file_len = strlenW( font_file );
2939 if (font_path && font_path[0])
2941 int path_len = strlenW( font_path );
2942 fullname = HeapAlloc( GetProcessHeap(), 0, (file_len + path_len + 2) * sizeof(WCHAR) );
2943 if (!fullname) return NULL;
2944 memcpy( fullname, font_path, path_len * sizeof(WCHAR) );
2945 fullname[path_len] = '\\';
2946 memcpy( fullname + path_len + 1, font_file, (file_len + 1) * sizeof(WCHAR) );
2950 int len = GetFullPathNameW( font_file, 0, NULL, NULL );
2951 if (!len) return NULL;
2952 fullname = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
2953 if (!fullname) return NULL;
2954 GetFullPathNameW( font_file, len, fullname, NULL );
2957 unix_name = wine_get_unix_file_name( fullname );
2958 HeapFree( GetProcessHeap(), 0, fullname );
2962 #include <pshpack1.h>
2965 WORD num_of_resources;
2969 CHAR dfCopyright[60];
2975 WORD dfInternalLeading;
2976 WORD dfExternalLeading;
2984 BYTE dfPitchAndFamily;
2995 CHAR szFaceName[LF_FACESIZE];
2998 #include <poppack.h>
3000 static void GetEnumStructs(Face *face, const WCHAR *family_name, LPENUMLOGFONTEXW pelf,
3001 NEWTEXTMETRICEXW *pntm, LPDWORD ptype);
3003 static BOOL get_fontdir( const char *unix_name, struct fontdir *fd )
3005 FT_Face ft_face = new_ft_face( unix_name, NULL, 0, 0, FALSE );
3007 WCHAR *name, *english_name;
3009 NEWTEXTMETRICEXW ntm;
3012 if (!ft_face) return FALSE;
3013 face = create_face( ft_face, 0, unix_name, NULL, 0, 0, FALSE, 0 );
3014 get_family_names( ft_face, &name, &english_name, FALSE );
3015 pFT_Done_Face( ft_face );
3017 GetEnumStructs( face, name, &elf, &ntm, &type );
3018 release_face( face );
3019 HeapFree( GetProcessHeap(), 0, name );
3020 HeapFree( GetProcessHeap(), 0, english_name );
3022 if ((type & TRUETYPE_FONTTYPE) == 0) return FALSE;
3024 memset( fd, 0, sizeof(*fd) );
3026 fd->num_of_resources = 1;
3028 fd->dfVersion = 0x200;
3029 fd->dfSize = sizeof(*fd);
3030 strcpy( fd->dfCopyright, "Wine fontdir" );
3031 fd->dfType = 0x4003; /* 0x0080 set if private */
3032 fd->dfPoints = ntm.ntmTm.ntmSizeEM;
3034 fd->dfHorizRes = 72;
3035 fd->dfAscent = ntm.ntmTm.tmAscent;
3036 fd->dfInternalLeading = ntm.ntmTm.tmInternalLeading;
3037 fd->dfExternalLeading = ntm.ntmTm.tmExternalLeading;
3038 fd->dfItalic = ntm.ntmTm.tmItalic;
3039 fd->dfUnderline = ntm.ntmTm.tmUnderlined;
3040 fd->dfStrikeOut = ntm.ntmTm.tmStruckOut;
3041 fd->dfWeight = ntm.ntmTm.tmWeight;
3042 fd->dfCharSet = ntm.ntmTm.tmCharSet;
3044 fd->dfPixHeight = ntm.ntmTm.tmHeight;
3045 fd->dfPitchAndFamily = ntm.ntmTm.tmPitchAndFamily;
3046 fd->dfAvgWidth = ntm.ntmTm.tmAveCharWidth;
3047 fd->dfMaxWidth = ntm.ntmTm.tmMaxCharWidth;
3048 fd->dfFirstChar = ntm.ntmTm.tmFirstChar;
3049 fd->dfLastChar = ntm.ntmTm.tmLastChar;
3050 fd->dfDefaultChar = ntm.ntmTm.tmDefaultChar;
3051 fd->dfBreakChar = ntm.ntmTm.tmBreakChar;
3052 fd->dfWidthBytes = 0;
3054 fd->dfFace = FIELD_OFFSET( struct fontdir, szFaceName );
3056 WideCharToMultiByte( CP_ACP, 0, elf.elfLogFont.lfFaceName, -1, fd->szFaceName, LF_FACESIZE, NULL, NULL );
3061 #define NE_FFLAGS_LIBMODULE 0x8000
3062 #define NE_OSFLAGS_WINDOWS 0x02
3064 static const char dos_string[0x40] = "This is a TrueType resource file";
3065 static const char FONTRES[] = {'F','O','N','T','R','E','S',':'};
3067 #include <pshpack2.h>
3088 struct ne_typeinfo fontdir_type;
3089 struct ne_nameinfo fontdir_name;
3090 struct ne_typeinfo scalable_type;
3091 struct ne_nameinfo scalable_name;
3093 BYTE fontdir_res_name[8];
3096 #include <poppack.h>
3098 static BOOL create_fot( const WCHAR *resource, const WCHAR *font_file, const struct fontdir *fontdir )
3102 DWORD size, written;
3104 BYTE import_name_len, res_name_len, non_res_name_len, font_file_len;
3105 char *font_fileA, *last_part, *ext;
3106 IMAGE_DOS_HEADER dos;
3107 IMAGE_OS2_HEADER ne =
3109 IMAGE_OS2_SIGNATURE, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE, 0,
3111 0, sizeof(ne), sizeof(ne), 0, 0, 0, 0,
3112 0, 4, 2, NE_OSFLAGS_WINDOWS, 0, 0, 0, 0, 0x300
3114 struct rsrc_tab rsrc_tab =
3118 { 0, 0, 0x0c50, 0x2c, 0 },
3120 { 0, 0, 0x0c50, 0x8001, 0 },
3122 { 7,'F','O','N','T','D','I','R'}
3125 memset( &dos, 0, sizeof(dos) );
3126 dos.e_magic = IMAGE_DOS_SIGNATURE;
3127 dos.e_lfanew = sizeof(dos) + sizeof(dos_string);
3129 /* import name is last part\0, resident name is last part without extension
3130 non-resident name is "FONTRES:" + lfFaceName */
3132 font_file_len = WideCharToMultiByte( CP_ACP, 0, font_file, -1, NULL, 0, NULL, NULL );
3133 font_fileA = HeapAlloc( GetProcessHeap(), 0, font_file_len );
3134 WideCharToMultiByte( CP_ACP, 0, font_file, -1, font_fileA, font_file_len, NULL, NULL );
3136 last_part = strrchr( font_fileA, '\\' );
3137 if (last_part) last_part++;
3138 else last_part = font_fileA;
3139 import_name_len = strlen( last_part ) + 1;
3141 ext = strchr( last_part, '.' );
3142 if (ext) res_name_len = ext - last_part;
3143 else res_name_len = import_name_len - 1;
3145 non_res_name_len = sizeof( FONTRES ) + strlen( fontdir->szFaceName );
3147 ne.ne_cbnrestab = 1 + non_res_name_len + 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
3148 ne.ne_restab = ne.ne_rsrctab + sizeof(rsrc_tab);
3149 ne.ne_modtab = ne.ne_imptab = ne.ne_restab + 1 + res_name_len + 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
3150 ne.ne_enttab = ne.ne_imptab + 1 + import_name_len; /* len + string */
3152 ne.ne_nrestab = ne.ne_enttab + ne.ne_cbenttab + 2 + dos.e_lfanew; /* there are 2 bytes of 0 after entry tab */
3154 rsrc_tab.scalable_name.off = (ne.ne_nrestab + ne.ne_cbnrestab + 0xf) >> 4;
3155 rsrc_tab.scalable_name.len = (font_file_len + 0xf) >> 4;
3156 rsrc_tab.fontdir_name.off = rsrc_tab.scalable_name.off + rsrc_tab.scalable_name.len;
3157 rsrc_tab.fontdir_name.len = (fontdir->dfSize + 0xf) >> 4;
3159 size = (rsrc_tab.fontdir_name.off + rsrc_tab.fontdir_name.len) << 4;
3160 start = ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
3164 HeapFree( GetProcessHeap(), 0, font_fileA );
3168 memcpy( ptr, &dos, sizeof(dos) );
3169 memcpy( ptr + sizeof(dos), dos_string, sizeof(dos_string) );
3170 memcpy( ptr + dos.e_lfanew, &ne, sizeof(ne) );
3172 ptr = start + dos.e_lfanew + ne.ne_rsrctab;
3173 memcpy( ptr, &rsrc_tab, sizeof(rsrc_tab) );
3175 ptr = start + dos.e_lfanew + ne.ne_restab;
3176 *ptr++ = res_name_len;
3177 memcpy( ptr, last_part, res_name_len );
3179 ptr = start + dos.e_lfanew + ne.ne_imptab;
3180 *ptr++ = import_name_len;
3181 memcpy( ptr, last_part, import_name_len );
3183 ptr = start + ne.ne_nrestab;
3184 *ptr++ = non_res_name_len;
3185 memcpy( ptr, FONTRES, sizeof(FONTRES) );
3186 memcpy( ptr + sizeof(FONTRES), fontdir->szFaceName, strlen( fontdir->szFaceName ) );
3188 ptr = start + (rsrc_tab.scalable_name.off << 4);
3189 memcpy( ptr, font_fileA, font_file_len );
3191 ptr = start + (rsrc_tab.fontdir_name.off << 4);
3192 memcpy( ptr, fontdir, fontdir->dfSize );
3194 file = CreateFileW( resource, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
3195 if (file != INVALID_HANDLE_VALUE)
3197 if (WriteFile( file, start, size, &written, NULL ) && written == size)
3199 CloseHandle( file );
3202 HeapFree( GetProcessHeap(), 0, start );
3203 HeapFree( GetProcessHeap(), 0, font_fileA );
3208 /*************************************************************
3209 * WineEngCreateScalableFontResource
3212 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
3213 LPCWSTR font_file, LPCWSTR font_path )
3215 char *unix_name = get_ttf_file_name( font_file, font_path );
3216 struct fontdir fontdir;
3219 if (!unix_name || !get_fontdir( unix_name, &fontdir ))
3220 SetLastError( ERROR_INVALID_PARAMETER );
3223 if (hidden) fontdir.dfType |= 0x80;
3224 ret = create_fot( resource, font_file, &fontdir );
3227 HeapFree( GetProcessHeap(), 0, unix_name );
3231 static const struct nls_update_font_list
3233 UINT ansi_cp, oem_cp;
3234 const char *oem, *fixed, *system;
3235 const char *courier, *serif, *small, *sserif_96, *sserif_120;
3236 /* these are for font substitutes */
3237 const char *shelldlg, *tmsrmn;
3238 const char *fixed_0, *system_0, *courier_0, *serif_0, *small_0, *sserif_0,
3242 const char *from, *to;
3243 } arial_0, courier_new_0, times_new_roman_0;
3244 } nls_update_font_list[] =
3246 /* Latin 1 (United States) */
3247 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
3248 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3249 "Tahoma","Times New Roman",
3250 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3253 /* Latin 1 (Multilingual) */
3254 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
3255 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3256 "Tahoma","Times New Roman", /* FIXME unverified */
3257 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3260 /* Eastern Europe */
3261 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
3262 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
3263 "Tahoma","Times New Roman", /* FIXME unverified */
3264 "Fixedsys,238", "System,238",
3265 "Courier New,238", "MS Serif,238", "Small Fonts,238",
3266 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
3267 { "Arial CE,0", "Arial,238" },
3268 { "Courier New CE,0", "Courier New,238" },
3269 { "Times New Roman CE,0", "Times New Roman,238" }
3272 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
3273 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
3274 "Tahoma","Times New Roman", /* FIXME unverified */
3275 "Fixedsys,204", "System,204",
3276 "Courier New,204", "MS Serif,204", "Small Fonts,204",
3277 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
3278 { "Arial Cyr,0", "Arial,204" },
3279 { "Courier New Cyr,0", "Courier New,204" },
3280 { "Times New Roman Cyr,0", "Times New Roman,204" }
3283 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
3284 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
3285 "Tahoma","Times New Roman", /* FIXME unverified */
3286 "Fixedsys,161", "System,161",
3287 "Courier New,161", "MS Serif,161", "Small Fonts,161",
3288 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
3289 { "Arial Greek,0", "Arial,161" },
3290 { "Courier New Greek,0", "Courier New,161" },
3291 { "Times New Roman Greek,0", "Times New Roman,161" }
3294 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
3295 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
3296 "Tahoma","Times New Roman", /* FIXME unverified */
3297 "Fixedsys,162", "System,162",
3298 "Courier New,162", "MS Serif,162", "Small Fonts,162",
3299 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
3300 { "Arial Tur,0", "Arial,162" },
3301 { "Courier New Tur,0", "Courier New,162" },
3302 { "Times New Roman Tur,0", "Times New Roman,162" }
3305 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
3306 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
3307 "Tahoma","Times New Roman", /* FIXME unverified */
3308 "Fixedsys,177", "System,177",
3309 "Courier New,177", "MS Serif,177", "Small Fonts,177",
3310 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
3314 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
3315 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
3316 "Tahoma","Times New Roman", /* FIXME unverified */
3317 "Fixedsys,178", "System,178",
3318 "Courier New,178", "MS Serif,178", "Small Fonts,178",
3319 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
3323 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
3324 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
3325 "Tahoma","Times New Roman", /* FIXME unverified */
3326 "Fixedsys,186", "System,186",
3327 "Courier New,186", "MS Serif,186", "Small Fonts,186",
3328 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
3329 { "Arial Baltic,0", "Arial,186" },
3330 { "Courier New Baltic,0", "Courier New,186" },
3331 { "Times New Roman Baltic,0", "Times New Roman,186" }
3334 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
3335 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3336 "Tahoma","Times New Roman", /* FIXME unverified */
3337 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3341 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
3342 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
3343 "Tahoma","Times New Roman", /* FIXME unverified */
3344 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3348 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
3349 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
3350 "MS UI Gothic","MS Serif",
3351 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3354 /* Chinese Simplified */
3355 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
3356 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3357 "SimSun", "NSimSun",
3358 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3362 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
3363 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3365 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3368 /* Chinese Traditional */
3369 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
3370 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3371 "PMingLiU", "MingLiU",
3372 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3377 static inline BOOL is_dbcs_ansi_cp(UINT ansi_cp)
3379 return ( ansi_cp == 932 /* CP932 for Japanese */
3380 || ansi_cp == 936 /* CP936 for Chinese Simplified */
3381 || ansi_cp == 949 /* CP949 for Korean */
3382 || ansi_cp == 950 ); /* CP950 for Chinese Traditional */
3385 static inline HKEY create_fonts_NT_registry_key(void)
3389 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
3390 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3394 static inline HKEY create_fonts_9x_registry_key(void)
3398 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
3399 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3403 static inline HKEY create_config_fonts_registry_key(void)
3407 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
3408 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
3412 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl, int dpi)
3414 const char *sserif = (dpi <= 108) ? fl->sserif_96 : fl->sserif_120;
3416 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
3417 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
3418 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)sserif, strlen(sserif)+1);
3419 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
3422 static void set_value_key(HKEY hkey, const char *name, const char *value)
3425 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
3427 RegDeleteValueA(hkey, name);
3430 static void update_font_info(void)
3432 static const WCHAR logpixels[] = { 'L','o','g','P','i','x','e','l','s',0 };
3433 char buf[40], cpbuf[40];
3436 UINT i, ansi_cp = 0, oem_cp = 0;
3437 DWORD screen_dpi = 96, font_dpi = 0;
3440 if (RegOpenKeyA(HKEY_LOCAL_MACHINE,
3441 "System\\CurrentControlSet\\Hardware Profiles\\Current\\Software\\Fonts",
3442 &hkey) == ERROR_SUCCESS)
3444 reg_load_dword(hkey, logpixels, &screen_dpi);
3448 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
3451 reg_load_dword(hkey, logpixels, &font_dpi);
3453 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3454 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
3455 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
3456 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
3457 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
3459 /* Setup Default_Fallback usage for DBCS ANSI codepages */
3460 if (is_dbcs_ansi_cp(ansi_cp))
3461 use_default_fallback = TRUE;
3464 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
3466 if (!strcmp( buf, cpbuf ) && screen_dpi == font_dpi) /* already set correctly */
3471 TRACE("updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
3472 buf, font_dpi, ansi_cp, oem_cp, screen_dpi);
3474 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
3475 ansi_cp, oem_cp, screen_dpi);
3477 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
3478 RegSetValueExW(hkey, logpixels, 0, REG_DWORD, (const BYTE *)&screen_dpi, sizeof(screen_dpi));
3481 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
3485 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
3486 nls_update_font_list[i].oem_cp == oem_cp)
3488 hkey = create_config_fonts_registry_key();
3489 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
3490 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
3491 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
3494 hkey = create_fonts_NT_registry_key();
3495 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3498 hkey = create_fonts_9x_registry_key();
3499 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
3502 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3504 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
3505 strlen(nls_update_font_list[i].shelldlg)+1);
3506 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
3507 strlen(nls_update_font_list[i].tmsrmn)+1);
3509 set_value_key(hkey, "Fixedsys,0", nls_update_font_list[i].fixed_0);
3510 set_value_key(hkey, "System,0", nls_update_font_list[i].system_0);
3511 set_value_key(hkey, "Courier,0", nls_update_font_list[i].courier_0);
3512 set_value_key(hkey, "MS Serif,0", nls_update_font_list[i].serif_0);
3513 set_value_key(hkey, "Small Fonts,0", nls_update_font_list[i].small_0);
3514 set_value_key(hkey, "MS Sans Serif,0", nls_update_font_list[i].sserif_0);
3515 set_value_key(hkey, "Helv,0", nls_update_font_list[i].helv_0);
3516 set_value_key(hkey, "Tms Rmn,0", nls_update_font_list[i].tmsrmn_0);
3518 set_value_key(hkey, nls_update_font_list[i].arial_0.from, nls_update_font_list[i].arial_0.to);
3519 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, nls_update_font_list[i].courier_new_0.to);
3520 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, nls_update_font_list[i].times_new_roman_0.to);
3528 /* Delete the FontSubstitutes from other locales */
3529 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
3531 set_value_key(hkey, nls_update_font_list[i].arial_0.from, NULL);
3532 set_value_key(hkey, nls_update_font_list[i].courier_new_0.from, NULL);
3533 set_value_key(hkey, nls_update_font_list[i].times_new_roman_0.from, NULL);
3539 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
3542 static BOOL init_freetype(void)
3544 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
3547 "Wine cannot find the FreeType font library. To enable Wine to\n"
3548 "use TrueType fonts please install a version of FreeType greater than\n"
3549 "or equal to 2.0.5.\n"
3550 "http://www.freetype.org\n");
3554 #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;}
3556 LOAD_FUNCPTR(FT_Done_Face)
3557 LOAD_FUNCPTR(FT_Get_Char_Index)
3558 LOAD_FUNCPTR(FT_Get_First_Char)
3559 LOAD_FUNCPTR(FT_Get_Module)
3560 LOAD_FUNCPTR(FT_Get_Next_Char)
3561 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
3562 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
3563 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
3564 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
3565 LOAD_FUNCPTR(FT_Init_FreeType)
3566 LOAD_FUNCPTR(FT_Library_Version)
3567 LOAD_FUNCPTR(FT_Load_Glyph)
3568 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
3569 LOAD_FUNCPTR(FT_Matrix_Multiply)
3570 #ifndef FT_MULFIX_INLINED
3571 LOAD_FUNCPTR(FT_MulFix)
3573 LOAD_FUNCPTR(FT_New_Face)
3574 LOAD_FUNCPTR(FT_New_Memory_Face)
3575 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
3576 LOAD_FUNCPTR(FT_Outline_Transform)
3577 LOAD_FUNCPTR(FT_Outline_Translate)
3578 LOAD_FUNCPTR(FT_Render_Glyph)
3579 LOAD_FUNCPTR(FT_Select_Charmap)
3580 LOAD_FUNCPTR(FT_Set_Charmap)
3581 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
3582 LOAD_FUNCPTR(FT_Vector_Transform)
3583 LOAD_FUNCPTR(FT_Vector_Unit)
3585 /* Don't warn if these ones are missing */
3586 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
3587 #ifdef HAVE_FREETYPE_FTLCDFIL_H
3588 pFT_Library_SetLcdFilter = wine_dlsym(ft_handle, "FT_Library_SetLcdFilter", NULL, 0);
3591 if(pFT_Init_FreeType(&library) != 0) {
3592 ERR("Can't init FreeType library\n");
3593 wine_dlclose(ft_handle, NULL, 0);
3597 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
3599 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
3600 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
3601 ((FT_Version.minor << 8) & 0x00ff00) |
3602 ((FT_Version.patch ) & 0x0000ff);
3604 font_driver = &freetype_funcs;
3609 "Wine cannot find certain functions that it needs inside the FreeType\n"
3610 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3611 "FreeType to at least version 2.1.4.\n"
3612 "http://www.freetype.org\n");
3613 wine_dlclose(ft_handle, NULL, 0);
3618 static void init_font_list(void)
3620 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
3621 static const WCHAR pathW[] = {'P','a','t','h',0};
3623 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
3624 WCHAR windowsdir[MAX_PATH];
3626 const char *data_dir;
3628 #ifdef SONAME_LIBFONTCONFIG
3632 delete_external_font_keys();
3634 /* load the system bitmap fonts */
3635 load_system_fonts();
3637 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3638 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
3639 strcatW(windowsdir, fontsW);
3640 if((unixname = wine_get_unix_file_name(windowsdir)))
3642 ReadFontDir(unixname, FALSE);
3643 HeapFree(GetProcessHeap(), 0, unixname);
3646 /* load the system truetype fonts */
3647 data_dir = wine_get_data_dir();
3648 if (!data_dir) data_dir = wine_get_build_dir();
3649 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/"))))
3651 strcpy(unixname, data_dir);
3652 strcat(unixname, "/fonts/");
3653 ReadFontDir(unixname, TRUE);
3654 HeapFree(GetProcessHeap(), 0, unixname);
3657 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3658 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3659 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3661 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
3662 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
3663 &hkey) == ERROR_SUCCESS)
3665 LPWSTR data, valueW;
3666 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3667 &valuelen, &datalen, NULL, NULL);
3669 valuelen++; /* returned value doesn't include room for '\0' */
3670 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
3671 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
3674 dlen = datalen * sizeof(WCHAR);
3676 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, (LPBYTE)data,
3677 &dlen) == ERROR_SUCCESS)
3679 if(data[0] && (data[1] == ':'))
3681 if((unixname = wine_get_unix_file_name(data)))
3683 AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3684 HeapFree(GetProcessHeap(), 0, unixname);
3687 else if(dlen / 2 >= 6 && !strcmpiW(data + dlen / 2 - 5, dot_fonW))
3689 WCHAR pathW[MAX_PATH];
3690 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
3693 sprintfW(pathW, fmtW, windowsdir, data);
3694 if((unixname = wine_get_unix_file_name(pathW)))
3696 added = AddFontToList(unixname, NULL, 0, ADDFONT_FORCE_BITMAP | ADDFONT_ADD_TO_CACHE);
3697 HeapFree(GetProcessHeap(), 0, unixname);
3700 load_font_from_data_dir(data);
3702 /* reset dlen and vlen */
3707 HeapFree(GetProcessHeap(), 0, data);
3708 HeapFree(GetProcessHeap(), 0, valueW);
3712 #ifdef SONAME_LIBFONTCONFIG
3713 load_fontconfig_fonts();
3714 #elif defined(HAVE_CARBON_CARBON_H)
3718 /* then look in any directories that we've specified in the config file */
3719 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
3720 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
3726 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
3728 len += sizeof(WCHAR);
3729 valueW = HeapAlloc( GetProcessHeap(), 0, len );
3730 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
3732 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
3733 valueA = HeapAlloc( GetProcessHeap(), 0, len );
3734 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
3735 TRACE( "got font path %s\n", debugstr_a(valueA) );
3740 LPSTR next = strchr( ptr, ':' );
3741 if (next) *next++ = 0;
3742 if (ptr[0] == '~' && ptr[1] == '/' && (home = getenv( "HOME" )) &&
3743 (unixname = HeapAlloc( GetProcessHeap(), 0, strlen(ptr) + strlen(home) )))
3745 strcpy( unixname, home );
3746 strcat( unixname, ptr + 1 );
3747 ReadFontDir( unixname, TRUE );
3748 HeapFree( GetProcessHeap(), 0, unixname );
3751 ReadFontDir( ptr, TRUE );
3754 HeapFree( GetProcessHeap(), 0, valueA );
3756 HeapFree( GetProcessHeap(), 0, valueW );
3762 static BOOL move_to_front(const WCHAR *name)
3764 Family *family, *cursor2;
3765 LIST_FOR_EACH_ENTRY_SAFE(family, cursor2, &font_list, Family, entry)
3767 if(!strcmpiW(family->FamilyName, name))
3769 list_remove(&family->entry);
3770 list_add_head(&font_list, &family->entry);
3777 static BOOL set_default(const WCHAR **name_list)
3781 if (move_to_front(*name_list)) return TRUE;
3788 static void reorder_font_list(void)
3790 set_default( default_serif_list );
3791 set_default( default_fixed_list );
3792 set_default( default_sans_list );
3795 /*************************************************************
3798 * Initialize FreeType library and create a list of available faces
3800 BOOL WineEngInit(void)
3802 HKEY hkey_font_cache;
3806 /* update locale dependent font info in registry */
3809 if(!init_freetype()) return FALSE;
3811 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL)
3813 ERR("Failed to create font mutex\n");
3816 WaitForSingleObject(font_mutex, INFINITE);
3818 create_font_cache_key(&hkey_font_cache, &disposition);
3820 if(disposition == REG_CREATED_NEW_KEY)
3823 load_font_list_from_cache(hkey_font_cache);
3825 RegCloseKey(hkey_font_cache);
3827 reorder_font_list();
3834 if(disposition == REG_CREATED_NEW_KEY)
3835 update_reg_entries();
3837 init_system_links();
3839 ReleaseMutex(font_mutex);
3844 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
3847 TT_HoriHeader *pHori;
3851 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3852 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3854 if(height == 0) height = 16;
3856 /* Calc. height of EM square:
3858 * For +ve lfHeight we have
3859 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
3860 * Re-arranging gives:
3861 * ppem = units_per_em * lfheight / (winAscent + winDescent)
3863 * For -ve lfHeight we have
3865 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
3866 * with il = winAscent + winDescent - units_per_em]
3871 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
3872 ppem = MulDiv(ft_face->units_per_EM, height,
3873 pHori->Ascender - pHori->Descender);
3875 ppem = MulDiv(ft_face->units_per_EM, height,
3876 pOS2->usWinAscent + pOS2->usWinDescent);
3884 static struct font_mapping *map_font_file( const char *name )
3886 struct font_mapping *mapping;
3890 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
3891 if (fstat( fd, &st ) == -1) goto error;
3893 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
3895 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
3897 mapping->refcount++;
3902 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
3905 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
3908 if (mapping->data == MAP_FAILED)
3910 HeapFree( GetProcessHeap(), 0, mapping );
3913 mapping->refcount = 1;
3914 mapping->dev = st.st_dev;
3915 mapping->ino = st.st_ino;
3916 mapping->size = st.st_size;
3917 list_add_tail( &mappings_list, &mapping->entry );
3925 static void unmap_font_file( struct font_mapping *mapping )
3927 if (!--mapping->refcount)
3929 list_remove( &mapping->entry );
3930 munmap( mapping->data, mapping->size );
3931 HeapFree( GetProcessHeap(), 0, mapping );
3935 static LONG load_VDMX(GdiFont*, LONG);
3937 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
3944 TRACE("%s/%p, %ld, %d x %d\n", debugstr_w(face->file), face->font_data_ptr, face->face_index, width, height);
3948 char *filename = strWtoA( CP_UNIXCP, face->file );
3949 font->mapping = map_font_file( filename );
3950 HeapFree( GetProcessHeap(), 0, filename );
3953 WARN("failed to map %s\n", debugstr_w(face->file));
3956 data_ptr = font->mapping->data;
3957 data_size = font->mapping->size;
3961 data_ptr = face->font_data_ptr;
3962 data_size = face->font_data_size;
3965 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
3967 ERR("FT_New_Face rets %d\n", err);
3971 /* set it here, as load_VDMX needs it */
3972 font->ft_face = ft_face;
3974 if(FT_IS_SCALABLE(ft_face)) {
3975 /* load the VDMX table if we have one */
3976 font->ppem = load_VDMX(font, height);
3978 font->ppem = calc_ppem_for_height(ft_face, height);
3979 TRACE("height %d => ppem %d\n", height, font->ppem);
3981 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
3982 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
3984 font->ppem = height;
3985 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
3986 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
3992 static int get_nearest_charset(const WCHAR *family_name, Face *face, int *cp)
3994 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
3995 a single face with the requested charset. The idea is to check if
3996 the selected font supports the current ANSI codepage, if it does
3997 return the corresponding charset, else return the first charset */
4000 int acp = GetACP(), i;
4004 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
4006 const SYSTEM_LINKS *font_link;
4008 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4009 return csi.ciCharset;
4011 font_link = find_font_link(family_name);
4012 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4013 return csi.ciCharset;
4016 for(i = 0; i < 32; i++) {
4018 if(face->fs.fsCsb[0] & fs0) {
4019 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
4021 return csi.ciCharset;
4024 FIXME("TCI failing on %x\n", fs0);
4028 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
4029 face->fs.fsCsb[0], debugstr_w(face->file));
4031 return DEFAULT_CHARSET;
4034 static GdiFont *alloc_font(void)
4036 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
4039 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
4040 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
4042 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4043 ret->total_kern_pairs = (DWORD)-1;
4044 ret->kern_pairs = NULL;
4045 list_init(&ret->child_fonts);
4049 static void free_font(GdiFont *font)
4051 CHILD_FONT *child, *child_next;
4054 LIST_FOR_EACH_ENTRY_SAFE( child, child_next, &font->child_fonts, CHILD_FONT, entry )
4056 list_remove(&child->entry);
4058 free_font(child->font);
4059 release_face( child->face );
4060 HeapFree(GetProcessHeap(), 0, child);
4063 if (font->ft_face) pFT_Done_Face(font->ft_face);
4064 if (font->mapping) unmap_font_file( font->mapping );
4065 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
4066 HeapFree(GetProcessHeap(), 0, font->potm);
4067 HeapFree(GetProcessHeap(), 0, font->name);
4068 for (i = 0; i < font->gmsize; i++)
4069 HeapFree(GetProcessHeap(),0,font->gm[i]);
4070 HeapFree(GetProcessHeap(), 0, font->gm);
4071 HeapFree(GetProcessHeap(), 0, font->GSUB_Table);
4072 HeapFree(GetProcessHeap(), 0, font);
4076 static DWORD get_font_data( GdiFont *font, DWORD table, DWORD offset, LPVOID buf, DWORD cbData)
4078 FT_Face ft_face = font->ft_face;
4082 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
4089 table = RtlUlongByteSwap( table ); /* MS tags differ in endianness from FT ones */
4091 /* make sure value of len is the value freetype says it needs */
4094 FT_ULong needed = 0;
4095 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
4096 if( !err && needed < len) len = needed;
4098 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
4101 TRACE("Can't find table %c%c%c%c\n",
4102 /* bytes were reversed */
4103 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
4104 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
4110 /*************************************************************
4113 * load the vdmx entry for the specified height
4116 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
4117 ( ( (FT_ULong)_x4 << 24 ) | \
4118 ( (FT_ULong)_x3 << 16 ) | \
4119 ( (FT_ULong)_x2 << 8 ) | \
4122 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
4137 static LONG load_VDMX(GdiFont *font, LONG height)
4141 BYTE devXRatio, devYRatio;
4142 USHORT numRecs, numRatios;
4143 DWORD result, offset = -1;
4147 result = get_font_data(font, MS_VDMX_TAG, 0, hdr, 6);
4149 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
4152 /* FIXME: need the real device aspect ratio */
4156 numRecs = GET_BE_WORD(hdr[1]);
4157 numRatios = GET_BE_WORD(hdr[2]);
4159 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
4160 for(i = 0; i < numRatios; i++) {
4163 offset = (3 * 2) + (i * sizeof(Ratios));
4164 get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
4167 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
4169 if((ratio.xRatio == 0 &&
4170 ratio.yStartRatio == 0 &&
4171 ratio.yEndRatio == 0) ||
4172 (devXRatio == ratio.xRatio &&
4173 devYRatio >= ratio.yStartRatio &&
4174 devYRatio <= ratio.yEndRatio))
4176 offset = (3 * 2) + (numRatios * 4) + (i * 2);
4177 get_font_data(font, MS_VDMX_TAG, offset, &tmp, 2);
4178 offset = GET_BE_WORD(tmp);
4184 FIXME("No suitable ratio found\n");
4188 if(get_font_data(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
4190 BYTE startsz, endsz;
4193 recs = GET_BE_WORD(group.recs);
4194 startsz = group.startsz;
4195 endsz = group.endsz;
4197 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
4199 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
4200 result = get_font_data(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
4201 if(result == GDI_ERROR) {
4202 FIXME("Failed to retrieve vTable\n");
4207 for(i = 0; i < recs; i++) {
4208 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4209 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4210 ppem = GET_BE_WORD(vTable[i * 3]);
4212 if(yMax + -yMin == height) {
4215 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4218 if(yMax + -yMin > height) {
4221 goto end; /* failed */
4223 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
4224 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
4225 ppem = GET_BE_WORD(vTable[i * 3]);
4226 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
4232 TRACE("ppem not found for height %d\n", height);
4236 HeapFree(GetProcessHeap(), 0, vTable);
4242 static void dump_gdi_font_list(void)
4246 TRACE("---------- Font Cache ----------\n");
4247 LIST_FOR_EACH_ENTRY( font, &gdi_font_list, struct tagGdiFont, entry )
4248 TRACE("font=%p ref=%u %s %d\n", font, font->refcount,
4249 debugstr_w(font->font_desc.lf.lfFaceName), font->font_desc.lf.lfHeight);
4252 static void grab_font( GdiFont *font )
4254 if (!font->refcount++)
4256 list_remove( &font->unused_entry );
4257 unused_font_count--;
4261 static void release_font( GdiFont *font )
4264 if (!--font->refcount)
4266 TRACE( "font %p\n", font );
4268 /* add it to the unused list */
4269 list_add_head( &unused_gdi_font_list, &font->unused_entry );
4270 if (unused_font_count > UNUSED_CACHE_SIZE)
4272 font = LIST_ENTRY( list_tail( &unused_gdi_font_list ), struct tagGdiFont, unused_entry );
4273 TRACE( "freeing %p\n", font );
4274 list_remove( &font->entry );
4275 list_remove( &font->unused_entry );
4278 else unused_font_count++;
4280 if (TRACE_ON(font)) dump_gdi_font_list();
4284 static BOOL fontcmp(const GdiFont *font, FONT_DESC *fd)
4286 if(font->font_desc.hash != fd->hash) return TRUE;
4287 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
4288 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
4289 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
4290 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
4293 static void calc_hash(FONT_DESC *pfd)
4295 DWORD hash = 0, *ptr, two_chars;
4299 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
4301 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
4303 for(i = 0, ptr = (DWORD*)pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
4305 pwc = (WCHAR *)&two_chars;
4307 *pwc = toupperW(*pwc);
4309 *pwc = toupperW(*pwc);
4313 hash ^= !pfd->can_use_bitmap;
4318 static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pmat, BOOL can_use_bitmap)
4325 fd.can_use_bitmap = can_use_bitmap;
4328 /* try the in-use list */
4329 LIST_FOR_EACH_ENTRY( ret, &gdi_font_list, struct tagGdiFont, entry )
4331 if(fontcmp(ret, &fd)) continue;
4332 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
4333 list_remove( &ret->entry );
4334 list_add_head( &gdi_font_list, &ret->entry );
4341 static void add_to_cache(GdiFont *font)
4343 static DWORD cache_num = 1;
4345 font->cache_num = cache_num++;
4346 list_add_head(&gdi_font_list, &font->entry);
4347 TRACE( "font %p\n", font );
4350 /*************************************************************
4351 * create_child_font_list
4353 static BOOL create_child_font_list(GdiFont *font)
4356 SYSTEM_LINKS *font_link;
4357 CHILD_FONT *font_link_entry, *new_child;
4361 psub = get_font_subst(&font_subst_list, font->name, -1);
4362 font_name = psub ? psub->to.name : font->name;
4363 font_link = find_font_link(font_name);
4364 if (font_link != NULL)
4366 TRACE("found entry in system list\n");
4367 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4369 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4370 new_child->face = font_link_entry->face;
4371 new_child->font = NULL;
4372 new_child->face->refcount++;
4373 list_add_tail(&font->child_fonts, &new_child->entry);
4374 TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index);
4379 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
4380 * Sans Serif. This is how asian windows get default fallbacks for fonts
4382 if (use_default_fallback && font->charset != SYMBOL_CHARSET &&
4383 font->charset != OEM_CHARSET &&
4384 strcmpiW(font_name,szDefaultFallbackLink) != 0)
4386 font_link = find_font_link(szDefaultFallbackLink);
4387 if (font_link != NULL)
4389 TRACE("found entry in default fallback list\n");
4390 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4392 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
4393 new_child->face = font_link_entry->face;
4394 new_child->font = NULL;
4395 new_child->face->refcount++;
4396 list_add_tail(&font->child_fonts, &new_child->entry);
4397 TRACE("font %s %ld\n", debugstr_w(new_child->face->file), new_child->face->face_index);
4406 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
4408 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
4410 if (pFT_Set_Charmap)
4413 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
4415 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
4417 for (i = 0; i < ft_face->num_charmaps; i++)
4419 if (ft_face->charmaps[i]->encoding == encoding)
4421 TRACE("found cmap with platform_id %u, encoding_id %u\n",
4422 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
4424 switch (ft_face->charmaps[i]->platform_id)
4427 cmap_def = ft_face->charmaps[i];
4429 case 0: /* Apple Unicode */
4430 cmap0 = ft_face->charmaps[i];
4432 case 1: /* Macintosh */
4433 cmap1 = ft_face->charmaps[i];
4436 cmap2 = ft_face->charmaps[i];
4438 case 3: /* Microsoft */
4439 cmap3 = ft_face->charmaps[i];
4444 if (cmap3) /* prefer Microsoft cmap table */
4445 ft_err = pFT_Set_Charmap(ft_face, cmap3);
4447 ft_err = pFT_Set_Charmap(ft_face, cmap1);
4449 ft_err = pFT_Set_Charmap(ft_face, cmap2);
4451 ft_err = pFT_Set_Charmap(ft_face, cmap0);
4453 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
4455 return ft_err == FT_Err_Ok;
4458 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
4462 /*************************************************************
4465 static BOOL freetype_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
4466 LPCWSTR output, const DEVMODEW *devmode )
4468 struct freetype_physdev *physdev = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physdev) );
4470 if (!physdev) return FALSE;
4471 push_dc_driver( dev, &physdev->dev, &freetype_funcs );
4476 /*************************************************************
4479 static BOOL freetype_DeleteDC( PHYSDEV dev )
4481 struct freetype_physdev *physdev = get_freetype_dev( dev );
4482 release_font( physdev->font );
4483 HeapFree( GetProcessHeap(), 0, physdev );
4487 static FT_Encoding pick_charmap( FT_Face face, int charset )
4489 static const FT_Encoding regular_order[] = { FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, FT_ENCODING_MS_SYMBOL, 0 };
4490 static const FT_Encoding symbol_order[] = { FT_ENCODING_MS_SYMBOL, FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, 0 };
4491 const FT_Encoding *encs = regular_order;
4493 if (charset == SYMBOL_CHARSET) encs = symbol_order;
4497 if (select_charmap( face, *encs )) break;
4503 #define GASP_GRIDFIT 0x01
4504 #define GASP_DOGRAY 0x02
4505 #define GASP_TAG MS_MAKE_TAG('g','a','s','p')
4507 static BOOL get_gasp_flags( GdiFont *font, WORD *flags )
4510 WORD buf[16]; /* Enough for seven ranges before we need to alloc */
4511 WORD *alloced = NULL, *ptr = buf;
4512 WORD num_recs, version;
4516 size = get_font_data( font, GASP_TAG, 0, NULL, 0 );
4517 if (size == GDI_ERROR) return FALSE;
4518 if (size < 4 * sizeof(WORD)) return FALSE;
4519 if (size > sizeof(buf))
4521 ptr = alloced = HeapAlloc( GetProcessHeap(), 0, size );
4522 if (!ptr) return FALSE;
4525 get_font_data( font, GASP_TAG, 0, ptr, size );
4527 version = GET_BE_WORD( *ptr++ );
4528 num_recs = GET_BE_WORD( *ptr++ );
4530 if (version > 1 || size < (num_recs * 2 + 2) * sizeof(WORD))
4532 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version, size, num_recs );
4538 *flags = GET_BE_WORD( *(ptr + 1) );
4539 if (font->ft_face->size->metrics.y_ppem <= GET_BE_WORD( *ptr )) break;
4542 TRACE( "got flags %04x for ppem %d\n", *flags, font->ft_face->size->metrics.y_ppem );
4546 HeapFree( GetProcessHeap(), 0, alloced );
4550 /*************************************************************
4551 * freetype_SelectFont
4553 static HFONT freetype_SelectFont( PHYSDEV dev, HFONT hfont, UINT *aa_flags )
4555 struct freetype_physdev *physdev = get_freetype_dev( dev );
4557 Face *face, *best, *best_bitmap;
4558 Family *family, *last_resort_family;
4559 const struct list *face_list;
4560 INT height, width = 0;
4561 unsigned int score = 0, new_score;
4562 signed int diff = 0, newdiff;
4563 BOOL bd, it, can_use_bitmap, want_vertical;
4567 FontSubst *psub = NULL;
4568 DC *dc = get_dc_ptr( dev->hdc );
4569 const SYSTEM_LINKS *font_link;
4571 if (!hfont) /* notification that the font has been changed by another driver */
4573 release_font( physdev->font );
4574 physdev->font = NULL;
4575 release_dc_ptr( dc );
4579 GetObjectW( hfont, sizeof(lf), &lf );
4580 lf.lfWidth = abs(lf.lfWidth);
4582 can_use_bitmap = GetDeviceCaps(dev->hdc, TEXTCAPS) & TC_RA_ABLE;
4584 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
4585 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
4586 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
4589 if(dc->GraphicsMode == GM_ADVANCED)
4591 memcpy(&dcmat, &dc->xformWorld2Vport, sizeof(FMAT2));
4592 /* Try to avoid not necessary glyph transformations */
4593 if (dcmat.eM21 == 0.0 && dcmat.eM12 == 0.0 && dcmat.eM11 == dcmat.eM22)
4595 lf.lfHeight *= fabs(dcmat.eM11);
4596 lf.lfWidth *= fabs(dcmat.eM11);
4597 dcmat.eM11 = dcmat.eM22 = dcmat.eM11 < 0 ? -1 : 1;
4602 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
4603 font scaling abilities. */
4604 dcmat.eM11 = dcmat.eM22 = 1.0;
4605 dcmat.eM21 = dcmat.eM12 = 0;
4606 lf.lfOrientation = lf.lfEscapement;
4607 if (dc->vport2WorldValid)
4609 if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < 0)
4610 lf.lfOrientation = -lf.lfOrientation;
4611 lf.lfHeight *= fabs(dc->xformWorld2Vport.eM22);
4612 lf.lfWidth *= fabs(dc->xformWorld2Vport.eM22);
4616 TRACE("DC transform %f %f %f %f\n", dcmat.eM11, dcmat.eM12,
4617 dcmat.eM21, dcmat.eM22);
4620 EnterCriticalSection( &freetype_cs );
4622 /* check the cache first */
4623 if((ret = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4624 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
4628 TRACE("not in cache\n");
4631 ret->font_desc.matrix = dcmat;
4632 ret->font_desc.lf = lf;
4633 ret->font_desc.can_use_bitmap = can_use_bitmap;
4634 calc_hash(&ret->font_desc);
4636 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
4637 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
4638 original value lfCharSet. Note this is a special case for
4639 Symbol and doesn't happen at least for "Wingdings*" */
4641 if(!strcmpiW(lf.lfFaceName, SymbolW))
4642 lf.lfCharSet = SYMBOL_CHARSET;
4644 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
4645 switch(lf.lfCharSet) {
4646 case DEFAULT_CHARSET:
4647 csi.fs.fsCsb[0] = 0;
4650 FIXME("Untranslated charset %d\n", lf.lfCharSet);
4651 csi.fs.fsCsb[0] = 0;
4657 if(lf.lfFaceName[0] != '\0') {
4658 CHILD_FONT *font_link_entry;
4659 LPWSTR FaceName = lf.lfFaceName;
4661 psub = get_font_subst(&font_subst_list, FaceName, lf.lfCharSet);
4664 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName), lf.lfCharSet,
4665 debugstr_w(psub->to.name), (psub->to.charset != -1) ? psub->to.charset : lf.lfCharSet);
4666 if (psub->to.charset != -1)
4667 lf.lfCharSet = psub->to.charset;
4670 /* We want a match on name and charset or just name if
4671 charset was DEFAULT_CHARSET. If the latter then
4672 we fixup the returned charset later in get_nearest_charset
4673 where we'll either use the charset of the current ansi codepage
4674 or if that's unavailable the first charset that the font supports.
4676 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
4677 if (!strcmpiW(family->FamilyName, FaceName) ||
4678 (psub && !strcmpiW(family->FamilyName, psub->to.name)))
4680 font_link = find_font_link(family->FamilyName);
4681 face_list = get_face_list_from_family(family);
4682 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
4683 if (!(face->scalable || can_use_bitmap))
4685 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4687 if (font_link != NULL &&
4688 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4690 if (!csi.fs.fsCsb[0])
4696 /* Search by full face name. */
4697 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
4698 face_list = get_face_list_from_family(family);
4699 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
4700 if(face->FullName && !strcmpiW(face->FullName, FaceName) &&
4701 (face->scalable || can_use_bitmap))
4703 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4705 font_link = find_font_link(family->FamilyName);
4706 if (font_link != NULL &&
4707 csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4714 * Try check the SystemLink list first for a replacement font.
4715 * We may find good replacements there.
4717 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
4719 if(!strcmpiW(font_link->font_name, FaceName) ||
4720 (psub && !strcmpiW(font_link->font_name,psub->to.name)))
4722 TRACE("found entry in system list\n");
4723 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
4725 const SYSTEM_LINKS *links;
4727 face = font_link_entry->face;
4728 if (!(face->scalable || can_use_bitmap))
4730 family = face->family;
4731 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] || !csi.fs.fsCsb[0])
4733 links = find_font_link(family->FamilyName);
4734 if (links != NULL && csi.fs.fsCsb[0] & links->fs.fsCsb[0])
4741 psub = NULL; /* substitution is no more relevant */
4743 /* If requested charset was DEFAULT_CHARSET then try using charset
4744 corresponding to the current ansi codepage */
4745 if (!csi.fs.fsCsb[0])
4748 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
4749 FIXME("TCI failed on codepage %d\n", acp);
4750 csi.fs.fsCsb[0] = 0;
4752 lf.lfCharSet = csi.ciCharset;
4755 want_vertical = (lf.lfFaceName[0] == '@');
4757 /* Face families are in the top 4 bits of lfPitchAndFamily,
4758 so mask with 0xF0 before testing */
4760 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
4761 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
4762 strcpyW(lf.lfFaceName, defFixed);
4763 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
4764 strcpyW(lf.lfFaceName, defSerif);
4765 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
4766 strcpyW(lf.lfFaceName, defSans);
4768 strcpyW(lf.lfFaceName, defSans);
4769 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
4770 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
4771 font_link = find_font_link(family->FamilyName);
4772 face_list = get_face_list_from_family(family);
4773 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
4774 if (!(face->scalable || can_use_bitmap))
4776 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0])
4778 if (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0])
4784 last_resort_family = NULL;
4785 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
4786 font_link = find_font_link(family->FamilyName);
4787 face_list = get_face_list_from_family(family);
4788 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
4789 if(face->vertical == want_vertical &&
4790 (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4791 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]))) {
4794 if(can_use_bitmap && !last_resort_family)
4795 last_resort_family = family;
4800 if(last_resort_family) {
4801 family = last_resort_family;
4802 csi.fs.fsCsb[0] = 0;
4806 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
4807 face_list = get_face_list_from_family(family);
4808 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
4809 if(face->scalable && face->vertical == want_vertical) {
4810 csi.fs.fsCsb[0] = 0;
4811 WARN("just using first face for now\n");
4814 if(can_use_bitmap && !last_resort_family)
4815 last_resort_family = family;
4818 if(!last_resort_family) {
4819 FIXME("can't find a single appropriate font - bailing\n");
4825 WARN("could only find a bitmap font - this will probably look awful!\n");
4826 family = last_resort_family;
4827 csi.fs.fsCsb[0] = 0;
4830 it = lf.lfItalic ? 1 : 0;
4831 bd = lf.lfWeight > 550 ? 1 : 0;
4833 height = lf.lfHeight;
4835 face = best = best_bitmap = NULL;
4836 font_link = find_font_link(family->FamilyName);
4837 face_list = get_face_list_from_family(family);
4838 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
4840 if (csi.fs.fsCsb[0] & face->fs.fsCsb[0] ||
4841 (font_link != NULL && csi.fs.fsCsb[0] & font_link->fs.fsCsb[0]) ||
4846 italic = (face->ntmFlags & NTM_ITALIC) ? 1 : 0;
4847 bold = (face->ntmFlags & NTM_BOLD) ? 1 : 0;
4848 new_score = (italic ^ it) + (bold ^ bd);
4849 if(!best || new_score <= score)
4851 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
4852 italic, bold, it, bd);
4855 if(best->scalable && score == 0) break;
4859 newdiff = height - (signed int)(best->size.height);
4861 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
4862 if(!best_bitmap || new_score < score ||
4863 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
4865 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
4868 if(score == 0 && diff == 0) break;
4875 face = best->scalable ? best : best_bitmap;
4876 ret->fake_italic = (it && !(face->ntmFlags & NTM_ITALIC));
4877 ret->fake_bold = (bd && !(face->ntmFlags & NTM_BOLD));
4880 height = lf.lfHeight;
4884 if(csi.fs.fsCsb[0]) {
4885 ret->charset = lf.lfCharSet;
4886 ret->codepage = csi.ciACP;
4889 ret->charset = get_nearest_charset(family->FamilyName, face, &ret->codepage);
4891 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
4892 debugstr_w(face->StyleName), debugstr_w(face->file), face->font_data_ptr, face->face_index);
4894 ret->aveWidth = height ? lf.lfWidth : 0;
4896 if(!face->scalable) {
4897 /* Windows uses integer scaling factors for bitmap fonts */
4898 INT scale, scaled_height;
4899 GdiFont *cachedfont;
4901 /* FIXME: rotation of bitmap fonts is ignored */
4902 height = abs(GDI_ROUND( (double)height * ret->font_desc.matrix.eM22 ));
4904 ret->aveWidth = (double)ret->aveWidth * ret->font_desc.matrix.eM11;
4905 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
4906 dcmat.eM11 = dcmat.eM22 = 1.0;
4907 /* As we changed the matrix, we need to search the cache for the font again,
4908 * otherwise we might explode the cache. */
4909 if((cachedfont = find_in_cache(hfont, &lf, &dcmat, can_use_bitmap)) != NULL) {
4910 TRACE("Found cached font after non-scalable matrix rescale!\n");
4915 calc_hash(&ret->font_desc);
4917 if (height != 0) height = diff;
4918 height += face->size.height;
4920 scale = (height + face->size.height - 1) / face->size.height;
4921 scaled_height = scale * face->size.height;
4922 /* Only jump to the next height if the difference <= 25% original height */
4923 if (scale > 2 && scaled_height - height > face->size.height / 4) scale--;
4924 /* The jump between unscaled and doubled is delayed by 1 */
4925 else if (scale == 2 && scaled_height - height > (face->size.height / 4 - 1)) scale--;
4926 ret->scale_y = scale;
4928 width = face->size.x_ppem >> 6;
4929 height = face->size.y_ppem >> 6;
4933 TRACE("font scale y: %f\n", ret->scale_y);
4935 ret->ft_face = OpenFontFace(ret, face, width, height);
4944 ret->ntmFlags = face->ntmFlags;
4946 pick_charmap( ret->ft_face, ret->charset );
4948 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
4949 ret->name = psub ? strdupW(psub->from.name) : strdupW(family->FamilyName);
4950 ret->underline = lf.lfUnderline ? 0xff : 0;
4951 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
4952 create_child_font_list(ret);
4954 if (face->vertical) /* We need to try to load the GSUB table */
4956 int length = get_font_data(ret, GSUB_TAG , 0, NULL, 0);
4957 if (length != GDI_ERROR)
4959 ret->GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
4960 get_font_data(ret, GSUB_TAG , 0, ret->GSUB_Table, length);
4961 TRACE("Loaded GSUB table of %i bytes\n",length);
4964 ret->aa_flags = face->aa_flags;
4966 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
4972 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSelectFont );
4974 switch (lf.lfQuality)
4976 case NONANTIALIASED_QUALITY:
4977 case ANTIALIASED_QUALITY:
4978 next->funcs->pSelectFont( dev, hfont, aa_flags );
4980 case CLEARTYPE_QUALITY:
4981 case CLEARTYPE_NATURAL_QUALITY:
4983 if (!*aa_flags) *aa_flags = ret->aa_flags;
4984 next->funcs->pSelectFont( dev, hfont, aa_flags );
4986 /* fixup the antialiasing flags for that font */
4989 case WINE_GGO_HRGB_BITMAP:
4990 case WINE_GGO_HBGR_BITMAP:
4991 case WINE_GGO_VRGB_BITMAP:
4992 case WINE_GGO_VBGR_BITMAP:
4993 if (is_subpixel_rendering_enabled()) break;
4994 *aa_flags = GGO_GRAY4_BITMAP;
4996 case GGO_GRAY2_BITMAP:
4997 case GGO_GRAY4_BITMAP:
4998 case GGO_GRAY8_BITMAP:
4999 case WINE_GGO_GRAY16_BITMAP:
5000 if (is_hinting_enabled())
5003 if (get_gasp_flags( ret, &gasp_flags ) && !(gasp_flags & GASP_DOGRAY))
5005 TRACE( "font %s %d aa disabled by GASP\n",
5006 debugstr_w(lf.lfFaceName), lf.lfHeight );
5007 *aa_flags = GGO_BITMAP;
5012 TRACE( "%p %s %d aa %x\n", hfont, debugstr_w(lf.lfFaceName), lf.lfHeight, *aa_flags );
5013 release_font( physdev->font );
5014 physdev->font = ret;
5016 LeaveCriticalSection( &freetype_cs );
5017 release_dc_ptr( dc );
5018 return ret ? hfont : 0;
5021 static INT load_script_name( UINT id, WCHAR buffer[LF_FACESIZE] )
5028 id += IDS_FIRST_SCRIPT;
5029 rsrc = FindResourceW( gdi32_module, (LPCWSTR)(ULONG_PTR)((id >> 4) + 1), (LPCWSTR)6 /*RT_STRING*/ );
5030 if (!rsrc) return 0;
5031 hMem = LoadResource( gdi32_module, rsrc );
5032 if (!hMem) return 0;
5034 p = LockResource( hMem );
5036 while (id--) p += *p + 1;
5038 i = min(LF_FACESIZE - 1, *p);
5039 memcpy(buffer, p + 1, i * sizeof(WCHAR));
5045 /***************************************************
5046 * create_enum_charset_list
5048 * This function creates charset enumeration list because in DEFAULT_CHARSET
5049 * case, the ANSI codepage's charset takes precedence over other charsets.
5050 * This function works as a filter other than DEFAULT_CHARSET case.
5052 static DWORD create_enum_charset_list(DWORD charset, struct enum_charset_list *list)
5057 if (TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET) &&
5058 csi.fs.fsCsb[0] != 0) {
5059 list->element[n].mask = csi.fs.fsCsb[0];
5060 list->element[n].charset = csi.ciCharset;
5061 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5064 else { /* charset is DEFAULT_CHARSET or invalid. */
5068 /* Set the current codepage's charset as the first element. */
5070 if (TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE) &&
5071 csi.fs.fsCsb[0] != 0) {
5072 list->element[n].mask = csi.fs.fsCsb[0];
5073 list->element[n].charset = csi.ciCharset;
5074 load_script_name( ffs(csi.fs.fsCsb[0]) - 1, list->element[n].name );
5075 mask |= csi.fs.fsCsb[0];
5079 /* Fill out left elements. */
5080 for (i = 0; i < 32; i++) {
5082 fs.fsCsb[0] = 1L << i;
5084 if (fs.fsCsb[0] & mask)
5085 continue; /* skip, already added. */
5086 if (!TranslateCharsetInfo(fs.fsCsb, &csi, TCI_SRCFONTSIG))
5087 continue; /* skip, this is an invalid fsCsb bit. */
5089 list->element[n].mask = fs.fsCsb[0];
5090 list->element[n].charset = csi.ciCharset;
5091 load_script_name( i, list->element[n].name );
5092 mask |= fs.fsCsb[0];
5096 /* add catch all mask for remaining bits */
5099 list->element[n].mask = ~mask;
5100 list->element[n].charset = DEFAULT_CHARSET;
5101 load_script_name( IDS_OTHER - IDS_FIRST_SCRIPT, list->element[n].name );
5110 static void GetEnumStructs(Face *face, const WCHAR *family_name, LPENUMLOGFONTEXW pelf,
5111 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
5116 if (face->cached_enum_data)
5119 *pelf = face->cached_enum_data->elf;
5120 *pntm = face->cached_enum_data->ntm;
5121 *ptype = face->cached_enum_data->type;
5125 font = alloc_font();
5127 if(face->scalable) {
5131 height = face->size.y_ppem >> 6;
5132 width = face->size.x_ppem >> 6;
5134 font->scale_y = 1.0;
5136 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
5142 font->name = strdupW( family_name );
5143 font->ntmFlags = face->ntmFlags;
5145 if (get_outline_text_metrics(font))
5147 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
5149 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
5150 pntm->ntmTm.ntmCellHeight = font->ntmCellHeight;
5151 pntm->ntmTm.ntmAvgWidth = font->ntmAvgWidth;
5153 lstrcpynW(pelf->elfLogFont.lfFaceName,
5154 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
5156 lstrcpynW(pelf->elfFullName,
5157 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
5159 lstrcpynW(pelf->elfStyle,
5160 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
5165 get_text_metrics(font, (TEXTMETRICW *)&pntm->ntmTm);
5167 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
5168 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
5169 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
5171 lstrcpynW(pelf->elfLogFont.lfFaceName, family_name, LF_FACESIZE);
5173 lstrcpynW(pelf->elfFullName, face->FullName, LF_FULLFACESIZE);
5175 lstrcpynW(pelf->elfFullName, family_name, LF_FULLFACESIZE);
5176 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
5179 pntm->ntmTm.ntmFlags = face->ntmFlags;
5180 pntm->ntmFontSig = face->fs;
5182 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
5184 pelf->elfLogFont.lfEscapement = 0;
5185 pelf->elfLogFont.lfOrientation = 0;
5186 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
5187 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
5188 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
5189 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
5190 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
5191 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
5192 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
5193 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
5194 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
5195 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
5196 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
5199 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
5200 *ptype |= TRUETYPE_FONTTYPE;
5201 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
5202 *ptype |= DEVICE_FONTTYPE;
5203 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
5204 *ptype |= RASTER_FONTTYPE;
5206 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
5207 if (face->cached_enum_data)
5209 face->cached_enum_data->elf = *pelf;
5210 face->cached_enum_data->ntm = *pntm;
5211 face->cached_enum_data->type = *ptype;
5217 static BOOL family_matches(Family *family, const LOGFONTW *lf)
5220 const struct list *face_list;
5222 if (!strcmpiW(lf->lfFaceName, family->FamilyName)) return TRUE;
5224 face_list = get_face_list_from_family(family);
5225 LIST_FOR_EACH_ENTRY(face, face_list, Face, entry)
5226 if (face->FullName && !strcmpiW(lf->lfFaceName, face->FullName)) return TRUE;
5231 static BOOL face_matches(const WCHAR *family_name, Face *face, const LOGFONTW *lf)
5233 if (!strcmpiW(lf->lfFaceName, family_name)) return TRUE;
5235 return (face->FullName && !strcmpiW(lf->lfFaceName, face->FullName));
5238 static BOOL enum_face_charsets(const Family *family, Face *face, struct enum_charset_list *list,
5239 FONTENUMPROCW proc, LPARAM lparam)
5242 NEWTEXTMETRICEXW ntm;
5246 GetEnumStructs(face, face->family->FamilyName, &elf, &ntm, &type);
5247 for(i = 0; i < list->total; i++) {
5248 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
5249 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
5250 load_script_name( IDS_OEM_DOS - IDS_FIRST_SCRIPT, elf.elfScript );
5251 i = list->total; /* break out of loop after enumeration */
5255 if(!(face->fs.fsCsb[0] & list->element[i].mask)) continue;
5256 /* use the DEFAULT_CHARSET case only if no other charset is present */
5257 if (list->element[i].charset == DEFAULT_CHARSET &&
5258 (face->fs.fsCsb[0] & ~list->element[i].mask)) continue;
5259 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = list->element[i].charset;
5260 strcpyW(elf.elfScript, list->element[i].name);
5261 if (!elf.elfScript[0])
5262 FIXME("Unknown elfscript for bit %d\n", ffs(list->element[i].mask) - 1);
5264 /* Font Replacement */
5265 if (family != face->family)
5267 strcpyW(elf.elfLogFont.lfFaceName, family->FamilyName);
5269 strcpyW(elf.elfFullName, face->FullName);
5271 strcpyW(elf.elfFullName, family->FamilyName);
5273 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
5274 debugstr_w(elf.elfLogFont.lfFaceName),
5275 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
5276 elf.elfLogFont.lfCharSet, type, debugstr_w(elf.elfScript),
5277 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
5278 ntm.ntmTm.ntmFlags);
5279 /* release section before callback (FIXME) */
5280 LeaveCriticalSection( &freetype_cs );
5281 if (!proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam)) return FALSE;
5282 EnterCriticalSection( &freetype_cs );
5287 /*************************************************************
5288 * freetype_EnumFonts
5290 static BOOL freetype_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam )
5294 const struct list *face_list;
5296 struct enum_charset_list enum_charsets;
5300 lf.lfCharSet = DEFAULT_CHARSET;
5301 lf.lfPitchAndFamily = 0;
5302 lf.lfFaceName[0] = 0;
5306 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
5308 create_enum_charset_list(plf->lfCharSet, &enum_charsets);
5311 EnterCriticalSection( &freetype_cs );
5312 if(plf->lfFaceName[0]) {
5314 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
5317 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
5318 debugstr_w(psub->to.name));
5320 strcpyW(lf.lfFaceName, psub->to.name);
5324 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5325 if (!family_matches(family, plf)) continue;
5326 face_list = get_face_list_from_family(family);
5327 LIST_FOR_EACH_ENTRY( face, face_list, Face, entry ) {
5328 if (!face_matches(family->FamilyName, face, plf)) continue;
5329 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
5333 LIST_FOR_EACH_ENTRY( family, &font_list, Family, entry ) {
5334 face_list = get_face_list_from_family(family);
5335 face = LIST_ENTRY(list_head(face_list), Face, entry);
5336 if (!enum_face_charsets(family, face, &enum_charsets, proc, lparam)) return FALSE;
5339 LeaveCriticalSection( &freetype_cs );
5343 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
5345 pt->x.value = vec->x >> 6;
5346 pt->x.fract = (vec->x & 0x3f) << 10;
5347 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
5348 pt->y.value = vec->y >> 6;
5349 pt->y.fract = (vec->y & 0x3f) << 10;
5350 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
5354 /***************************************************
5355 * According to the MSDN documentation on WideCharToMultiByte,
5356 * certain codepages cannot set the default_used parameter.
5357 * This returns TRUE if the codepage can set that parameter, false else
5358 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
5360 static BOOL codepage_sets_default_used(UINT codepage)
5374 * GSUB Table handling functions
5377 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
5379 const GSUB_CoverageFormat1* cf1;
5383 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
5385 int count = GET_BE_WORD(cf1->GlyphCount);
5387 TRACE("Coverage Format 1, %i glyphs\n",count);
5388 for (i = 0; i < count; i++)
5389 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
5393 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
5395 const GSUB_CoverageFormat2* cf2;
5398 cf2 = (const GSUB_CoverageFormat2*)cf1;
5400 count = GET_BE_WORD(cf2->RangeCount);
5401 TRACE("Coverage Format 2, %i ranges\n",count);
5402 for (i = 0; i < count; i++)
5404 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
5406 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
5407 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
5409 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
5410 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
5416 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
5421 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
5423 const GSUB_ScriptList *script;
5424 const GSUB_Script *deflt = NULL;
5426 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
5428 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
5429 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
5431 const GSUB_Script *scr;
5434 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
5435 scr = (const GSUB_Script*)((const BYTE*)script + offset);
5437 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
5439 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
5445 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
5449 const GSUB_LangSys *Lang;
5451 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
5453 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
5455 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
5456 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5458 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
5461 offset = GET_BE_WORD(script->DefaultLangSys);
5464 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
5470 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
5473 const GSUB_FeatureList *feature;
5474 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
5476 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
5477 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
5479 int index = GET_BE_WORD(lang->FeatureIndex[i]);
5480 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
5482 const GSUB_Feature *feat;
5483 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
5490 static FT_UInt GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, UINT glyph)
5494 const GSUB_LookupList *lookup;
5495 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
5497 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
5498 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
5500 const GSUB_LookupTable *look;
5501 offset = GET_BE_WORD(lookup->Lookup[GET_BE_WORD(feature->LookupListIndex[i])]);
5502 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
5503 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
5504 if (GET_BE_WORD(look->LookupType) != 1)
5505 FIXME("We only handle SubType 1\n");
5510 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
5512 const GSUB_SingleSubstFormat1 *ssf1;
5513 offset = GET_BE_WORD(look->SubTable[j]);
5514 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
5515 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
5517 int offset = GET_BE_WORD(ssf1->Coverage);
5518 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
5519 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyph) != -1)
5521 TRACE(" Glyph 0x%x ->",glyph);
5522 glyph += GET_BE_WORD(ssf1->DeltaGlyphID);
5523 TRACE(" 0x%x\n",glyph);
5528 const GSUB_SingleSubstFormat2 *ssf2;
5532 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
5533 offset = GET_BE_WORD(ssf1->Coverage);
5534 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
5535 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyph);
5536 TRACE(" Coverage index %i\n",index);
5539 TRACE(" Glyph is 0x%x ->",glyph);
5540 glyph = GET_BE_WORD(ssf2->Substitute[index]);
5541 TRACE("0x%x\n",glyph);
5550 static const char* get_opentype_script(const GdiFont *font)
5553 * I am not sure if this is the correct way to generate our script tag
5556 switch (font->charset)
5558 case ANSI_CHARSET: return "latn";
5559 case BALTIC_CHARSET: return "latn"; /* ?? */
5560 case CHINESEBIG5_CHARSET: return "hani";
5561 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
5562 case GB2312_CHARSET: return "hani";
5563 case GREEK_CHARSET: return "grek";
5564 case HANGUL_CHARSET: return "hang";
5565 case RUSSIAN_CHARSET: return "cyrl";
5566 case SHIFTJIS_CHARSET: return "kana";
5567 case TURKISH_CHARSET: return "latn"; /* ?? */
5568 case VIETNAMESE_CHARSET: return "latn";
5569 case JOHAB_CHARSET: return "latn"; /* ?? */
5570 case ARABIC_CHARSET: return "arab";
5571 case HEBREW_CHARSET: return "hebr";
5572 case THAI_CHARSET: return "thai";
5573 default: return "latn";
5577 static FT_UInt get_GSUB_vert_glyph(const GdiFont *font, UINT glyph)
5579 const GSUB_Header *header;
5580 const GSUB_Script *script;
5581 const GSUB_LangSys *language;
5582 const GSUB_Feature *feature;
5584 if (!font->GSUB_Table)
5587 header = font->GSUB_Table;
5589 script = GSUB_get_script_table(header, get_opentype_script(font));
5592 TRACE("Script not found\n");
5595 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
5598 TRACE("Language not found\n");
5601 feature = GSUB_get_feature(header, language, "vrt2");
5603 feature = GSUB_get_feature(header, language, "vert");
5606 TRACE("vrt2/vert feature not found\n");
5609 return GSUB_apply_feature(header, feature, glyph);
5612 static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
5616 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
5617 WCHAR wc = (WCHAR)glyph;
5619 BOOL *default_used_pointer;
5622 default_used_pointer = NULL;
5623 default_used = FALSE;
5624 if (codepage_sets_default_used(font->codepage))
5625 default_used_pointer = &default_used;
5626 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
5628 if (font->codepage == CP_SYMBOL && wc < 0x100)
5629 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)wc);
5634 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
5635 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
5639 if(font->ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
5641 if (glyph < 0x100) glyph += 0xf000;
5642 /* there is a number of old pre-Unicode "broken" TTFs, which
5643 do have symbols at U+00XX instead of U+f0XX */
5644 if (!(glyphId = pFT_Get_Char_Index(font->ft_face, glyph)))
5645 glyphId = pFT_Get_Char_Index(font->ft_face, glyph-0xf000);
5647 else glyphId = pFT_Get_Char_Index(font->ft_face, glyph);
5652 /*************************************************************
5653 * freetype_GetGlyphIndices
5655 static DWORD freetype_GetGlyphIndices( PHYSDEV dev, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags )
5657 struct freetype_physdev *physdev = get_freetype_dev( dev );
5660 BOOL got_default = FALSE;
5664 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphIndices );
5665 return dev->funcs->pGetGlyphIndices( dev, lpstr, count, pgi, flags );
5668 if (flags & GGI_MARK_NONEXISTING_GLYPHS)
5670 default_char = 0xffff; /* XP would use 0x1f for bitmap fonts */
5675 EnterCriticalSection( &freetype_cs );
5677 for(i = 0; i < count; i++)
5679 pgi[i] = get_glyph_index(physdev->font, lpstr[i]);
5684 if (FT_IS_SFNT(physdev->font->ft_face))
5686 TT_OS2 *pOS2 = pFT_Get_Sfnt_Table(physdev->font->ft_face, ft_sfnt_os2);
5687 default_char = (pOS2->usDefaultChar ? get_glyph_index(physdev->font, pOS2->usDefaultChar) : 0);
5692 get_text_metrics(physdev->font, &textm);
5693 default_char = textm.tmDefaultChar;
5697 pgi[i] = default_char;
5700 LeaveCriticalSection( &freetype_cs );
5704 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
5706 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
5707 return !memcmp(matrix, &identity, sizeof(FMAT2));
5710 static inline BOOL is_identity_MAT2(const MAT2 *matrix)
5712 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
5713 return !memcmp(matrix, &identity, sizeof(MAT2));
5716 static inline BYTE get_max_level( UINT format )
5720 case GGO_GRAY2_BITMAP: return 4;
5721 case GGO_GRAY4_BITMAP: return 16;
5722 case GGO_GRAY8_BITMAP: return 64;
5727 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5729 static DWORD get_glyph_outline(GdiFont *incoming_font, UINT glyph, UINT format,
5730 LPGLYPHMETRICS lpgm, ABC *abc, DWORD buflen, LPVOID buf,
5733 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
5734 FT_Face ft_face = incoming_font->ft_face;
5735 GdiFont *font = incoming_font;
5736 FT_UInt glyph_index;
5737 DWORD width, height, pitch, needed = 0;
5738 FT_Bitmap ft_bitmap;
5740 INT left, right, top = 0, bottom = 0, adv;
5742 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
5743 double widthRatio = 1.0;
5744 FT_Matrix transMat = identityMat;
5745 FT_Matrix transMatUnrotated;
5746 BOOL needsTransform = FALSE;
5747 BOOL tategaki = (font->GSUB_Table != NULL);
5748 UINT original_index;
5750 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
5751 buflen, buf, lpmat);
5753 TRACE("font transform %f %f %f %f\n",
5754 font->font_desc.matrix.eM11, font->font_desc.matrix.eM12,
5755 font->font_desc.matrix.eM21, font->font_desc.matrix.eM22);
5757 if(format & GGO_GLYPH_INDEX) {
5758 glyph_index = get_GSUB_vert_glyph(incoming_font,glyph);
5759 original_index = glyph;
5760 format &= ~GGO_GLYPH_INDEX;
5762 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
5763 ft_face = font->ft_face;
5764 original_index = glyph_index;
5767 if(format & GGO_UNHINTED) {
5768 load_flags |= FT_LOAD_NO_HINTING;
5769 format &= ~GGO_UNHINTED;
5772 /* tategaki never appears to happen to lower glyph index */
5773 if (glyph_index < TATEGAKI_LOWER_BOUND )
5776 if(original_index >= font->gmsize * GM_BLOCK_SIZE) {
5777 font->gmsize = (original_index / GM_BLOCK_SIZE + 1);
5778 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
5779 font->gmsize * sizeof(GM*));
5781 if (format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL &&
5782 FONT_GM(font,original_index)->init && is_identity_MAT2(lpmat))
5784 *lpgm = FONT_GM(font,original_index)->gm;
5785 *abc = FONT_GM(font,original_index)->abc;
5786 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5787 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5788 lpgm->gmCellIncX, lpgm->gmCellIncY);
5789 return 1; /* FIXME */
5793 if (!font->gm[original_index / GM_BLOCK_SIZE])
5794 font->gm[original_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
5796 /* Scaling factor */
5801 get_text_metrics(font, &tm);
5803 widthRatio = (double)font->aveWidth;
5804 widthRatio /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
5807 widthRatio = font->scale_y;
5809 /* Scaling transform */
5810 if (widthRatio != 1.0 || font->scale_y != 1.0)
5813 scaleMat.xx = FT_FixedFromFloat(widthRatio);
5816 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
5818 pFT_Matrix_Multiply(&scaleMat, &transMat);
5819 needsTransform = TRUE;
5822 /* Slant transform */
5823 if (font->fake_italic) {
5826 slantMat.xx = (1 << 16);
5827 slantMat.xy = ((1 << 16) >> 2);
5829 slantMat.yy = (1 << 16);
5830 pFT_Matrix_Multiply(&slantMat, &transMat);
5831 needsTransform = TRUE;
5834 /* Rotation transform */
5835 transMatUnrotated = transMat;
5836 if(font->orientation && !tategaki) {
5837 FT_Matrix rotationMat;
5839 angle = FT_FixedFromFloat((double)font->orientation / 10.0);
5840 pFT_Vector_Unit(&vecAngle, angle);
5841 rotationMat.xx = vecAngle.x;
5842 rotationMat.xy = -vecAngle.y;
5843 rotationMat.yx = -rotationMat.xy;
5844 rotationMat.yy = rotationMat.xx;
5846 pFT_Matrix_Multiply(&rotationMat, &transMat);
5847 needsTransform = TRUE;
5850 /* World transform */
5851 if (!is_identity_FMAT2(&font->font_desc.matrix))
5854 worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
5855 worldMat.xy = -FT_FixedFromFloat(font->font_desc.matrix.eM21);
5856 worldMat.yx = -FT_FixedFromFloat(font->font_desc.matrix.eM12);
5857 worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
5858 pFT_Matrix_Multiply(&worldMat, &transMat);
5859 pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);
5860 needsTransform = TRUE;
5863 /* Extra transformation specified by caller */
5864 if (!is_identity_MAT2(lpmat))
5867 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
5868 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
5869 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
5870 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
5871 pFT_Matrix_Multiply(&extraMat, &transMat);
5872 pFT_Matrix_Multiply(&extraMat, &transMatUnrotated);
5873 needsTransform = TRUE;
5876 if (needsTransform || format != GGO_BITMAP) load_flags |= FT_LOAD_NO_BITMAP;
5878 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
5881 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
5885 if(!needsTransform) {
5886 left = (INT)(ft_face->glyph->metrics.horiBearingX) & -64;
5887 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) + 63) & -64;
5888 adv = (INT)(ft_face->glyph->metrics.horiAdvance + 63) >> 6;
5890 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
5891 bottom = (ft_face->glyph->metrics.horiBearingY -
5892 ft_face->glyph->metrics.height) & -64;
5893 lpgm->gmCellIncX = adv;
5894 lpgm->gmCellIncY = 0;
5901 for(xc = 0; xc < 2; xc++) {
5902 for(yc = 0; yc < 2; yc++) {
5903 vec.x = (ft_face->glyph->metrics.horiBearingX +
5904 xc * ft_face->glyph->metrics.width);
5905 vec.y = ft_face->glyph->metrics.horiBearingY -
5906 yc * ft_face->glyph->metrics.height;
5907 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
5908 pFT_Vector_Transform(&vec, &transMat);
5909 if(xc == 0 && yc == 0) {
5910 left = right = vec.x;
5911 top = bottom = vec.y;
5913 if(vec.x < left) left = vec.x;
5914 else if(vec.x > right) right = vec.x;
5915 if(vec.y < bottom) bottom = vec.y;
5916 else if(vec.y > top) top = vec.y;
5921 right = (right + 63) & -64;
5922 bottom = bottom & -64;
5923 top = (top + 63) & -64;
5925 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
5926 vec.x = ft_face->glyph->metrics.horiAdvance;
5928 pFT_Vector_Transform(&vec, &transMat);
5929 lpgm->gmCellIncX = (vec.x+63) >> 6;
5930 lpgm->gmCellIncY = -((vec.y+63) >> 6);
5932 vec.x = ft_face->glyph->metrics.horiAdvance;
5934 pFT_Vector_Transform(&vec, &transMatUnrotated);
5935 adv = (vec.x+63) >> 6;
5938 lpgm->gmBlackBoxX = (right - left) >> 6;
5939 lpgm->gmBlackBoxY = (top - bottom) >> 6;
5940 lpgm->gmptGlyphOrigin.x = left >> 6;
5941 lpgm->gmptGlyphOrigin.y = top >> 6;
5942 abc->abcA = left >> 6;
5943 abc->abcB = (right - left) >> 6;
5944 abc->abcC = adv - abc->abcA - abc->abcB;
5946 TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
5947 wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
5948 lpgm->gmCellIncX, lpgm->gmCellIncY);
5950 if ((format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP) &&
5951 is_identity_MAT2(lpmat)) /* don't cache custom transforms */
5953 FONT_GM(font,original_index)->gm = *lpgm;
5954 FONT_GM(font,original_index)->abc = *abc;
5955 FONT_GM(font,original_index)->init = TRUE;
5958 if(format == GGO_METRICS)
5960 return 1; /* FIXME */
5963 if(ft_face->glyph->format != ft_glyph_format_outline &&
5964 (format == GGO_NATIVE || format == GGO_BEZIER))
5966 TRACE("loaded a bitmap\n");
5972 width = lpgm->gmBlackBoxX;
5973 height = lpgm->gmBlackBoxY;
5974 pitch = ((width + 31) >> 5) << 2;
5975 needed = pitch * height;
5977 if(!buf || !buflen) break;
5979 switch(ft_face->glyph->format) {
5980 case ft_glyph_format_bitmap:
5982 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
5983 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
5984 INT h = ft_face->glyph->bitmap.rows;
5986 memcpy(dst, src, w);
5987 src += ft_face->glyph->bitmap.pitch;
5993 case ft_glyph_format_outline:
5994 ft_bitmap.width = width;
5995 ft_bitmap.rows = height;
5996 ft_bitmap.pitch = pitch;
5997 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
5998 ft_bitmap.buffer = buf;
6001 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
6003 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
6005 /* Note: FreeType will only set 'black' bits for us. */
6006 memset(buf, 0, needed);
6007 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
6011 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
6016 case GGO_GRAY2_BITMAP:
6017 case GGO_GRAY4_BITMAP:
6018 case GGO_GRAY8_BITMAP:
6019 case WINE_GGO_GRAY16_BITMAP:
6021 unsigned int max_level, row, col;
6024 width = lpgm->gmBlackBoxX;
6025 height = lpgm->gmBlackBoxY;
6026 pitch = (width + 3) / 4 * 4;
6027 needed = pitch * height;
6029 if(!buf || !buflen) break;
6031 max_level = get_max_level( format );
6033 switch(ft_face->glyph->format) {
6034 case ft_glyph_format_bitmap:
6036 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
6037 INT h = ft_face->glyph->bitmap.rows;
6039 memset( buf, 0, needed );
6041 for(x = 0; x < pitch && x < ft_face->glyph->bitmap.width; x++)
6042 if (src[x / 8] & masks[x % 8]) dst[x] = max_level;
6043 src += ft_face->glyph->bitmap.pitch;
6048 case ft_glyph_format_outline:
6050 ft_bitmap.width = width;
6051 ft_bitmap.rows = height;
6052 ft_bitmap.pitch = pitch;
6053 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
6054 ft_bitmap.buffer = buf;
6057 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
6059 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
6061 memset(ft_bitmap.buffer, 0, buflen);
6063 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
6065 if (max_level != 255)
6067 for (row = 0, start = buf; row < height; row++)
6069 for (col = 0, ptr = start; col < width; col++, ptr++)
6070 *ptr = (((int)*ptr) * (max_level + 1)) / 256;
6078 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
6084 case WINE_GGO_HRGB_BITMAP:
6085 case WINE_GGO_HBGR_BITMAP:
6086 case WINE_GGO_VRGB_BITMAP:
6087 case WINE_GGO_VBGR_BITMAP:
6088 #ifdef HAVE_FREETYPE_FTLCDFIL_H
6090 switch (ft_face->glyph->format)
6092 case FT_GLYPH_FORMAT_BITMAP:
6097 width = lpgm->gmBlackBoxX;
6098 height = lpgm->gmBlackBoxY;
6100 needed = pitch * height;
6102 if (!buf || !buflen) break;
6104 memset(buf, 0, buflen);
6106 src = ft_face->glyph->bitmap.buffer;
6107 src_pitch = ft_face->glyph->bitmap.pitch;
6109 height = min( height, ft_face->glyph->bitmap.rows );
6112 for (x = 0; x < width && x < ft_face->glyph->bitmap.width; x++)
6114 if ( src[x / 8] & masks[x % 8] )
6115 ((unsigned int *)dst)[x] = ~0u;
6124 case FT_GLYPH_FORMAT_OUTLINE:
6128 INT x, src_pitch, src_width, src_height, rgb_interval, hmul, vmul;
6129 INT x_shift, y_shift;
6131 FT_LcdFilter lcdfilter = FT_LCD_FILTER_DEFAULT;
6132 FT_Render_Mode render_mode =
6133 (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_HBGR_BITMAP)?
6134 FT_RENDER_MODE_LCD: FT_RENDER_MODE_LCD_V;
6136 if ( lcdfilter == FT_LCD_FILTER_DEFAULT || lcdfilter == FT_LCD_FILTER_LIGHT )
6138 if ( render_mode == FT_RENDER_MODE_LCD)
6140 lpgm->gmBlackBoxX += 2;
6141 lpgm->gmptGlyphOrigin.x -= 1;
6145 lpgm->gmBlackBoxY += 2;
6146 lpgm->gmptGlyphOrigin.y += 1;
6150 width = lpgm->gmBlackBoxX;
6151 height = lpgm->gmBlackBoxY;
6153 needed = pitch * height;
6155 if (!buf || !buflen) break;
6157 memset(buf, 0, buflen);
6159 rgb = (format == WINE_GGO_HRGB_BITMAP || format == WINE_GGO_VRGB_BITMAP);
6161 if ( needsTransform )
6162 pFT_Outline_Transform (&ft_face->glyph->outline, &transMat);
6164 if ( pFT_Library_SetLcdFilter )
6165 pFT_Library_SetLcdFilter( library, lcdfilter );
6166 pFT_Render_Glyph (ft_face->glyph, render_mode);
6168 src = ft_face->glyph->bitmap.buffer;
6169 src_pitch = ft_face->glyph->bitmap.pitch;
6170 src_width = ft_face->glyph->bitmap.width;
6171 src_height = ft_face->glyph->bitmap.rows;
6173 if ( render_mode == FT_RENDER_MODE_LCD)
6181 rgb_interval = src_pitch;
6186 x_shift = ft_face->glyph->bitmap_left - lpgm->gmptGlyphOrigin.x;
6187 if ( x_shift < 0 ) x_shift = 0;
6188 if ( x_shift + (src_width / hmul) > width )
6189 x_shift = width - (src_width / hmul);
6191 y_shift = lpgm->gmptGlyphOrigin.y - ft_face->glyph->bitmap_top;
6192 if ( y_shift < 0 ) y_shift = 0;
6193 if ( y_shift + (src_height / vmul) > height )
6194 y_shift = height - (src_height / vmul);
6196 dst += x_shift + y_shift * ( pitch / 4 );
6197 while ( src_height )
6199 for ( x = 0; x < src_width / hmul; x++ )
6203 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 0] << 16) |
6204 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6205 ((unsigned int)src[hmul * x + rgb_interval * 2] << 0) |
6206 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6210 dst[x] = ((unsigned int)src[hmul * x + rgb_interval * 2] << 16) |
6211 ((unsigned int)src[hmul * x + rgb_interval * 1] << 8) |
6212 ((unsigned int)src[hmul * x + rgb_interval * 0] << 0) |
6213 ((unsigned int)src[hmul * x + rgb_interval * 1] << 24) ;
6216 src += src_pitch * vmul;
6225 FIXME ("loaded glyph format %x\n", ft_face->glyph->format);
6237 int contour, point = 0, first_pt;
6238 FT_Outline *outline = &ft_face->glyph->outline;
6239 TTPOLYGONHEADER *pph;
6241 DWORD pph_start, cpfx, type;
6243 if(buflen == 0) buf = NULL;
6245 if (needsTransform && buf) {
6246 pFT_Outline_Transform(outline, &transMat);
6249 for(contour = 0; contour < outline->n_contours; contour++) {
6250 /* Ignore contours containing one point */
6251 if(point == outline->contours[contour]) {
6257 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6260 pph->dwType = TT_POLYGON_TYPE;
6261 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6263 needed += sizeof(*pph);
6265 while(point <= outline->contours[contour]) {
6266 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6267 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6268 TT_PRIM_LINE : TT_PRIM_QSPLINE;
6272 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6275 } while(point <= outline->contours[contour] &&
6276 (outline->tags[point] & FT_Curve_Tag_On) ==
6277 (outline->tags[point-1] & FT_Curve_Tag_On));
6278 /* At the end of a contour Windows adds the start point, but
6280 if(point > outline->contours[contour] &&
6281 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
6283 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
6285 } else if(point <= outline->contours[contour] &&
6286 outline->tags[point] & FT_Curve_Tag_On) {
6287 /* add closing pt for bezier */
6289 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6297 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6300 pph->cb = needed - pph_start;
6306 /* Convert the quadratic Beziers to cubic Beziers.
6307 The parametric eqn for a cubic Bezier is, from PLRM:
6308 r(t) = at^3 + bt^2 + ct + r0
6309 with the control points:
6314 A quadratic Bezier has the form:
6315 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6317 So equating powers of t leads to:
6318 r1 = 2/3 p1 + 1/3 p0
6319 r2 = 2/3 p1 + 1/3 p2
6320 and of course r0 = p0, r3 = p2
6323 int contour, point = 0, first_pt;
6324 FT_Outline *outline = &ft_face->glyph->outline;
6325 TTPOLYGONHEADER *pph;
6327 DWORD pph_start, cpfx, type;
6328 FT_Vector cubic_control[4];
6329 if(buflen == 0) buf = NULL;
6331 if (needsTransform && buf) {
6332 pFT_Outline_Transform(outline, &transMat);
6335 for(contour = 0; contour < outline->n_contours; contour++) {
6337 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
6340 pph->dwType = TT_POLYGON_TYPE;
6341 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
6343 needed += sizeof(*pph);
6345 while(point <= outline->contours[contour]) {
6346 ppc = (TTPOLYCURVE *)((char *)buf + needed);
6347 type = (outline->tags[point] & FT_Curve_Tag_On) ?
6348 TT_PRIM_LINE : TT_PRIM_CSPLINE;
6351 if(type == TT_PRIM_LINE) {
6353 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
6357 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6360 /* FIXME: Possible optimization in endpoint calculation
6361 if there are two consecutive curves */
6362 cubic_control[0] = outline->points[point-1];
6363 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
6364 cubic_control[0].x += outline->points[point].x + 1;
6365 cubic_control[0].y += outline->points[point].y + 1;
6366 cubic_control[0].x >>= 1;
6367 cubic_control[0].y >>= 1;
6369 if(point+1 > outline->contours[contour])
6370 cubic_control[3] = outline->points[first_pt];
6372 cubic_control[3] = outline->points[point+1];
6373 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
6374 cubic_control[3].x += outline->points[point].x + 1;
6375 cubic_control[3].y += outline->points[point].y + 1;
6376 cubic_control[3].x >>= 1;
6377 cubic_control[3].y >>= 1;
6380 /* r1 = 1/3 p0 + 2/3 p1
6381 r2 = 1/3 p2 + 2/3 p1 */
6382 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
6383 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
6384 cubic_control[2] = cubic_control[1];
6385 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
6386 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
6387 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
6388 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
6390 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
6391 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
6392 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
6397 } while(point <= outline->contours[contour] &&
6398 (outline->tags[point] & FT_Curve_Tag_On) ==
6399 (outline->tags[point-1] & FT_Curve_Tag_On));
6400 /* At the end of a contour Windows adds the start point,
6401 but only for Beziers and we've already done that.
6403 if(point <= outline->contours[contour] &&
6404 outline->tags[point] & FT_Curve_Tag_On) {
6405 /* This is the closing pt of a bezier, but we've already
6406 added it, so just inc point and carry on */
6413 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
6416 pph->cb = needed - pph_start;
6422 FIXME("Unsupported format %d\n", format);
6428 static BOOL get_bitmap_text_metrics(GdiFont *font)
6430 FT_Face ft_face = font->ft_face;
6431 FT_WinFNT_HeaderRec winfnt_header;
6432 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
6433 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
6434 font->potm->otmSize = size;
6436 #define TM font->potm->otmTextMetrics
6437 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
6439 TM.tmHeight = winfnt_header.pixel_height;
6440 TM.tmAscent = winfnt_header.ascent;
6441 TM.tmDescent = TM.tmHeight - TM.tmAscent;
6442 TM.tmInternalLeading = winfnt_header.internal_leading;
6443 TM.tmExternalLeading = winfnt_header.external_leading;
6444 TM.tmAveCharWidth = winfnt_header.avg_width;
6445 TM.tmMaxCharWidth = winfnt_header.max_width;
6446 TM.tmWeight = winfnt_header.weight;
6448 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
6449 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
6450 TM.tmFirstChar = winfnt_header.first_char;
6451 TM.tmLastChar = winfnt_header.last_char;
6452 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
6453 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
6454 TM.tmItalic = winfnt_header.italic;
6455 TM.tmUnderlined = font->underline;
6456 TM.tmStruckOut = font->strikeout;
6457 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
6458 TM.tmCharSet = winfnt_header.charset;
6462 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
6463 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
6464 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6465 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
6466 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
6467 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
6468 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
6469 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
6471 TM.tmDigitizedAspectX = 96; /* FIXME */
6472 TM.tmDigitizedAspectY = 96; /* FIXME */
6474 TM.tmLastChar = 255;
6475 TM.tmDefaultChar = 32;
6476 TM.tmBreakChar = 32;
6477 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
6478 TM.tmUnderlined = font->underline;
6479 TM.tmStruckOut = font->strikeout;
6480 /* NB inverted meaning of TMPF_FIXED_PITCH */
6481 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
6482 TM.tmCharSet = font->charset;
6490 static void scale_font_metrics(const GdiFont *font, LPTEXTMETRICW ptm)
6492 double scale_x, scale_y;
6496 scale_x = (double)font->aveWidth;
6497 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6500 scale_x = font->scale_y;
6502 scale_x *= fabs(font->font_desc.matrix.eM11);
6503 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6505 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6506 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6508 SCALE_Y(ptm->tmHeight);
6509 SCALE_Y(ptm->tmAscent);
6510 SCALE_Y(ptm->tmDescent);
6511 SCALE_Y(ptm->tmInternalLeading);
6512 SCALE_Y(ptm->tmExternalLeading);
6513 SCALE_Y(ptm->tmOverhang);
6515 SCALE_X(ptm->tmAveCharWidth);
6516 SCALE_X(ptm->tmMaxCharWidth);
6522 static void scale_outline_font_metrics(const GdiFont *font, OUTLINETEXTMETRICW *potm)
6524 double scale_x, scale_y;
6528 scale_x = (double)font->aveWidth;
6529 scale_x /= (double)font->potm->otmTextMetrics.tmAveCharWidth;
6532 scale_x = font->scale_y;
6534 scale_x *= fabs(font->font_desc.matrix.eM11);
6535 scale_y = font->scale_y * fabs(font->font_desc.matrix.eM22);
6537 scale_font_metrics(font, &potm->otmTextMetrics);
6539 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
6540 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
6542 SCALE_Y(potm->otmAscent);
6543 SCALE_Y(potm->otmDescent);
6544 SCALE_Y(potm->otmLineGap);
6545 SCALE_Y(potm->otmsCapEmHeight);
6546 SCALE_Y(potm->otmsXHeight);
6547 SCALE_Y(potm->otmrcFontBox.top);
6548 SCALE_Y(potm->otmrcFontBox.bottom);
6549 SCALE_X(potm->otmrcFontBox.left);
6550 SCALE_X(potm->otmrcFontBox.right);
6551 SCALE_Y(potm->otmMacAscent);
6552 SCALE_Y(potm->otmMacDescent);
6553 SCALE_Y(potm->otmMacLineGap);
6554 SCALE_X(potm->otmptSubscriptSize.x);
6555 SCALE_Y(potm->otmptSubscriptSize.y);
6556 SCALE_X(potm->otmptSubscriptOffset.x);
6557 SCALE_Y(potm->otmptSubscriptOffset.y);
6558 SCALE_X(potm->otmptSuperscriptSize.x);
6559 SCALE_Y(potm->otmptSuperscriptSize.y);
6560 SCALE_X(potm->otmptSuperscriptOffset.x);
6561 SCALE_Y(potm->otmptSuperscriptOffset.y);
6562 SCALE_Y(potm->otmsStrikeoutSize);
6563 SCALE_Y(potm->otmsStrikeoutPosition);
6564 SCALE_Y(potm->otmsUnderscoreSize);
6565 SCALE_Y(potm->otmsUnderscorePosition);
6571 static BOOL get_text_metrics(GdiFont *font, LPTEXTMETRICW ptm)
6575 if (!get_outline_text_metrics(font) && !get_bitmap_text_metrics(font)) return FALSE;
6577 /* Make sure that the font has sane width/height ratio */
6580 if ((font->aveWidth + font->potm->otmTextMetrics.tmHeight - 1) / font->potm->otmTextMetrics.tmHeight > 100)
6582 WARN("Ignoring too large font->aveWidth %d\n", font->aveWidth);
6587 *ptm = font->potm->otmTextMetrics;
6588 scale_font_metrics(font, ptm);
6592 static BOOL face_has_symbol_charmap(FT_Face ft_face)
6596 for(i = 0; i < ft_face->num_charmaps; i++)
6598 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
6604 static BOOL get_outline_text_metrics(GdiFont *font)
6607 FT_Face ft_face = font->ft_face;
6608 UINT needed, lenfam, lensty, lenface, lenfull;
6610 TT_HoriHeader *pHori;
6611 TT_Postscript *pPost;
6612 FT_Fixed x_scale, y_scale;
6613 WCHAR *family_nameW, *style_nameW, *face_nameW, *full_nameW;
6615 INT ascent, descent;
6617 TRACE("font=%p\n", font);
6619 if(!FT_IS_SCALABLE(ft_face))
6622 needed = sizeof(*font->potm);
6624 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
6625 family_nameW = strdupW(font->name);
6627 style_nameW = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, GetSystemDefaultLangID() );
6629 style_nameW = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, TT_MS_LANGID_ENGLISH_UNITED_STATES );
6632 FIXME("failed to read style_nameW for font %s!\n", wine_dbgstr_w(font->name));
6633 style_nameW = towstr( CP_ACP, ft_face->style_name );
6635 lensty = (strlenW(style_nameW) + 1) * sizeof(WCHAR);
6637 face_nameW = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, GetSystemDefaultLangID() );
6639 face_nameW = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, TT_MS_LANGID_ENGLISH_UNITED_STATES );
6642 FIXME("failed to read face_nameW for font %s!\n", wine_dbgstr_w(font->name));
6643 face_nameW = strdupW(font->name);
6645 if (font->name[0] == '@') face_nameW = prepend_at( face_nameW );
6646 lenface = (strlenW(face_nameW) + 1) * sizeof(WCHAR);
6648 full_nameW = get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, GetSystemDefaultLangID() );
6650 full_nameW = get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, TT_MS_LANGID_ENGLISH_UNITED_STATES );
6653 WCHAR fake_nameW[] = {'f','a','k','e',' ','n','a','m','e', 0};
6654 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w(font->name));
6655 full_nameW = strdupW(fake_nameW);
6657 lenfull = (strlenW(full_nameW) + 1) * sizeof(WCHAR);
6659 /* These names should be read from the TT name table */
6661 /* length of otmpFamilyName */
6664 /* length of otmpFaceName */
6667 /* length of otmpStyleName */
6670 /* length of otmpFullName */
6674 x_scale = ft_face->size->metrics.x_scale;
6675 y_scale = ft_face->size->metrics.y_scale;
6677 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
6679 FIXME("Can't find OS/2 table - not TT font?\n");
6683 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
6685 FIXME("Can't find HHEA table - not TT font?\n");
6689 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
6691 TRACE("OS/2 winA = %d winD = %d typoA = %d typoD = %d typoLG = %d avgW %d FT_Face a = %d, d = %d, h = %d: HORZ a = %d, d = %d lg = %d maxY = %ld minY = %ld\n",
6692 pOS2->usWinAscent, pOS2->usWinDescent,
6693 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
6694 pOS2->xAvgCharWidth,
6695 ft_face->ascender, ft_face->descender, ft_face->height,
6696 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
6697 ft_face->bbox.yMax, ft_face->bbox.yMin);
6699 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
6700 font->potm->otmSize = needed;
6702 #define TM font->potm->otmTextMetrics
6704 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
6705 ascent = pHori->Ascender;
6706 descent = -pHori->Descender;
6708 ascent = pOS2->usWinAscent;
6709 descent = pOS2->usWinDescent;
6712 font->ntmCellHeight = ascent + descent;
6713 font->ntmAvgWidth = pOS2->xAvgCharWidth;
6716 TM.tmAscent = font->yMax;
6717 TM.tmDescent = -font->yMin;
6718 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
6720 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
6721 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
6722 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
6723 - ft_face->units_per_EM, y_scale) + 32) >> 6;
6726 TM.tmHeight = TM.tmAscent + TM.tmDescent;
6729 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
6731 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
6732 ((ascent + descent) -
6733 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
6735 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
6736 if (TM.tmAveCharWidth == 0) {
6737 TM.tmAveCharWidth = 1;
6739 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
6740 TM.tmWeight = FW_REGULAR;
6741 if (font->fake_bold)
6742 TM.tmWeight = FW_BOLD;
6745 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
6747 if (pOS2->usWeightClass > FW_MEDIUM)
6748 TM.tmWeight = pOS2->usWeightClass;
6750 else if (pOS2->usWeightClass <= FW_MEDIUM)
6751 TM.tmWeight = pOS2->usWeightClass;
6754 TM.tmDigitizedAspectX = 96; /* FIXME */
6755 TM.tmDigitizedAspectY = 96; /* FIXME */
6756 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
6757 * symbol range to 0 - f0ff
6760 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
6765 case 1257: /* Baltic */
6766 TM.tmLastChar = 0xf8fd;
6769 TM.tmLastChar = 0xf0ff;
6771 TM.tmBreakChar = 0x20;
6772 TM.tmDefaultChar = 0x1f;
6776 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
6777 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
6779 if(pOS2->usFirstCharIndex <= 1)
6780 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
6781 else if (pOS2->usFirstCharIndex > 0xff)
6782 TM.tmBreakChar = 0x20;
6784 TM.tmBreakChar = pOS2->usFirstCharIndex;
6785 TM.tmDefaultChar = TM.tmBreakChar - 1;
6787 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
6788 TM.tmUnderlined = font->underline;
6789 TM.tmStruckOut = font->strikeout;
6791 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
6792 if(!FT_IS_FIXED_WIDTH(ft_face) &&
6793 (pOS2->version == 0xFFFFU ||
6794 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
6795 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
6797 TM.tmPitchAndFamily = 0;
6799 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
6801 case PAN_FAMILY_SCRIPT:
6802 TM.tmPitchAndFamily |= FF_SCRIPT;
6805 case PAN_FAMILY_DECORATIVE:
6806 TM.tmPitchAndFamily |= FF_DECORATIVE;
6811 case PAN_FAMILY_TEXT_DISPLAY:
6812 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
6813 /* which is clearly not what the panose spec says. */
6815 if(TM.tmPitchAndFamily == 0 || /* fixed */
6816 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
6817 TM.tmPitchAndFamily = FF_MODERN;
6820 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
6825 TM.tmPitchAndFamily |= FF_DONTCARE;
6828 case PAN_SERIF_COVE:
6829 case PAN_SERIF_OBTUSE_COVE:
6830 case PAN_SERIF_SQUARE_COVE:
6831 case PAN_SERIF_OBTUSE_SQUARE_COVE:
6832 case PAN_SERIF_SQUARE:
6833 case PAN_SERIF_THIN:
6834 case PAN_SERIF_BONE:
6835 case PAN_SERIF_EXAGGERATED:
6836 case PAN_SERIF_TRIANGLE:
6837 TM.tmPitchAndFamily |= FF_ROMAN;
6840 case PAN_SERIF_NORMAL_SANS:
6841 case PAN_SERIF_OBTUSE_SANS:
6842 case PAN_SERIF_PERP_SANS:
6843 case PAN_SERIF_FLARED:
6844 case PAN_SERIF_ROUNDED:
6845 TM.tmPitchAndFamily |= FF_SWISS;
6852 if(FT_IS_SCALABLE(ft_face))
6853 TM.tmPitchAndFamily |= TMPF_VECTOR;
6855 if(FT_IS_SFNT(ft_face))
6857 if (font->ntmFlags & NTM_PS_OPENTYPE)
6858 TM.tmPitchAndFamily |= TMPF_DEVICE;
6860 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
6863 TM.tmCharSet = font->charset;
6865 font->potm->otmFiller = 0;
6866 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
6867 font->potm->otmfsSelection = pOS2->fsSelection;
6868 font->potm->otmfsType = pOS2->fsType;
6869 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
6870 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
6871 font->potm->otmItalicAngle = 0; /* POST table */
6872 font->potm->otmEMSquare = ft_face->units_per_EM;
6873 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
6874 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
6875 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
6876 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
6877 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
6878 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
6879 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
6880 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
6881 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
6882 font->potm->otmMacAscent = TM.tmAscent;
6883 font->potm->otmMacDescent = -TM.tmDescent;
6884 font->potm->otmMacLineGap = font->potm->otmLineGap;
6885 font->potm->otmusMinimumPPEM = 0; /* TT Header */
6886 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
6887 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
6888 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
6889 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
6890 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
6891 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
6892 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
6893 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
6894 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
6895 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
6897 font->potm->otmsUnderscoreSize = 0;
6898 font->potm->otmsUnderscorePosition = 0;
6900 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
6901 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
6905 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
6906 cp = (char*)font->potm + sizeof(*font->potm);
6907 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
6908 strcpyW((WCHAR*)cp, family_nameW);
6910 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
6911 strcpyW((WCHAR*)cp, style_nameW);
6913 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
6914 strcpyW((WCHAR*)cp, face_nameW);
6916 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
6917 strcpyW((WCHAR*)cp, full_nameW);
6921 HeapFree(GetProcessHeap(), 0, style_nameW);
6922 HeapFree(GetProcessHeap(), 0, family_nameW);
6923 HeapFree(GetProcessHeap(), 0, face_nameW);
6924 HeapFree(GetProcessHeap(), 0, full_nameW);
6928 /*************************************************************
6929 * freetype_GetGlyphOutline
6931 static DWORD freetype_GetGlyphOutline( PHYSDEV dev, UINT glyph, UINT format,
6932 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf, const MAT2 *lpmat )
6934 struct freetype_physdev *physdev = get_freetype_dev( dev );
6940 dev = GET_NEXT_PHYSDEV( dev, pGetGlyphOutline );
6941 return dev->funcs->pGetGlyphOutline( dev, glyph, format, lpgm, buflen, buf, lpmat );
6945 EnterCriticalSection( &freetype_cs );
6946 ret = get_glyph_outline( physdev->font, glyph, format, lpgm, &abc, buflen, buf, lpmat );
6947 LeaveCriticalSection( &freetype_cs );
6951 /*************************************************************
6952 * freetype_GetTextMetrics
6954 static BOOL freetype_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
6956 struct freetype_physdev *physdev = get_freetype_dev( dev );
6961 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
6962 return dev->funcs->pGetTextMetrics( dev, metrics );
6966 EnterCriticalSection( &freetype_cs );
6967 ret = get_text_metrics( physdev->font, metrics );
6968 LeaveCriticalSection( &freetype_cs );
6972 /*************************************************************
6973 * freetype_GetOutlineTextMetrics
6975 static UINT freetype_GetOutlineTextMetrics( PHYSDEV dev, UINT cbSize, OUTLINETEXTMETRICW *potm )
6977 struct freetype_physdev *physdev = get_freetype_dev( dev );
6982 dev = GET_NEXT_PHYSDEV( dev, pGetOutlineTextMetrics );
6983 return dev->funcs->pGetOutlineTextMetrics( dev, cbSize, potm );
6986 TRACE("font=%p\n", physdev->font);
6988 if (!FT_IS_SCALABLE( physdev->font->ft_face )) return 0;
6991 EnterCriticalSection( &freetype_cs );
6993 if (physdev->font->potm || get_outline_text_metrics( physdev->font ))
6995 if(cbSize >= physdev->font->potm->otmSize)
6997 memcpy(potm, physdev->font->potm, physdev->font->potm->otmSize);
6998 scale_outline_font_metrics(physdev->font, potm);
7000 ret = physdev->font->potm->otmSize;
7002 LeaveCriticalSection( &freetype_cs );
7006 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
7008 child->font = alloc_font();
7009 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
7010 if(!child->font->ft_face)
7012 free_font(child->font);
7017 child->font->font_desc = font->font_desc;
7018 child->font->ntmFlags = child->face->ntmFlags;
7019 child->font->orientation = font->orientation;
7020 child->font->scale_y = font->scale_y;
7021 child->font->name = strdupW(child->face->family->FamilyName);
7022 child->font->base_font = font;
7023 TRACE("created child font %p for base %p\n", child->font, font);
7027 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
7030 CHILD_FONT *child_font;
7033 font = font->base_font;
7035 *linked_font = font;
7037 if((*glyph = get_glyph_index(font, c)))
7039 *glyph = get_GSUB_vert_glyph(font, *glyph);
7043 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
7045 if(!child_font->font)
7046 if(!load_child_font(font, child_font))
7049 if(!child_font->font->ft_face)
7051 g = get_glyph_index(child_font->font, c);
7052 g = get_GSUB_vert_glyph(child_font->font, g);
7056 *linked_font = child_font->font;
7063 /*************************************************************
7064 * freetype_GetCharWidth
7066 static BOOL freetype_GetCharWidth( PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer )
7068 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7072 struct freetype_physdev *physdev = get_freetype_dev( dev );
7076 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
7077 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
7080 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
7083 EnterCriticalSection( &freetype_cs );
7084 for(c = firstChar; c <= lastChar; c++) {
7085 get_glyph_outline( physdev->font, c, GGO_METRICS, &gm, &abc, 0, NULL, &identity );
7086 buffer[c - firstChar] = abc.abcA + abc.abcB + abc.abcC;
7088 LeaveCriticalSection( &freetype_cs );
7092 /*************************************************************
7093 * freetype_GetCharABCWidths
7095 static BOOL freetype_GetCharABCWidths( PHYSDEV dev, UINT firstChar, UINT lastChar, LPABC buffer )
7097 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7100 struct freetype_physdev *physdev = get_freetype_dev( dev );
7104 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidths );
7105 return dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, buffer );
7108 TRACE("%p, %d, %d, %p\n", physdev->font, firstChar, lastChar, buffer);
7111 EnterCriticalSection( &freetype_cs );
7113 for(c = firstChar; c <= lastChar; c++, buffer++)
7114 get_glyph_outline( physdev->font, c, GGO_METRICS, &gm, buffer, 0, NULL, &identity );
7116 LeaveCriticalSection( &freetype_cs );
7120 /*************************************************************
7121 * freetype_GetCharABCWidthsI
7123 static BOOL freetype_GetCharABCWidthsI( PHYSDEV dev, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer )
7125 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7128 struct freetype_physdev *physdev = get_freetype_dev( dev );
7132 dev = GET_NEXT_PHYSDEV( dev, pGetCharABCWidthsI );
7133 return dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, buffer );
7136 if(!FT_HAS_HORIZONTAL(physdev->font->ft_face))
7140 EnterCriticalSection( &freetype_cs );
7142 for(c = 0; c < count; c++, buffer++)
7143 get_glyph_outline( physdev->font, pgi ? pgi[c] : firstChar + c, GGO_METRICS | GGO_GLYPH_INDEX,
7144 &gm, buffer, 0, NULL, &identity );
7146 LeaveCriticalSection( &freetype_cs );
7150 /*************************************************************
7151 * freetype_GetTextExtentExPoint
7153 static BOOL freetype_GetTextExtentExPoint( PHYSDEV dev, LPCWSTR wstr, INT count, LPINT dxs )
7155 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7159 struct freetype_physdev *physdev = get_freetype_dev( dev );
7163 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
7164 return dev->funcs->pGetTextExtentExPoint( dev, wstr, count, dxs );
7167 TRACE("%p, %s, %d\n", physdev->font, debugstr_wn(wstr, count), count);
7170 EnterCriticalSection( &freetype_cs );
7172 for (idx = pos = 0; idx < count; idx++)
7174 get_glyph_outline( physdev->font, wstr[idx], GGO_METRICS, &gm, &abc, 0, NULL, &identity );
7175 pos += abc.abcA + abc.abcB + abc.abcC;
7179 LeaveCriticalSection( &freetype_cs );
7183 /*************************************************************
7184 * freetype_GetTextExtentExPointI
7186 static BOOL freetype_GetTextExtentExPointI( PHYSDEV dev, const WORD *indices, INT count, LPINT dxs )
7188 static const MAT2 identity = { {0,1},{0,0},{0,0},{0,1} };
7192 struct freetype_physdev *physdev = get_freetype_dev( dev );
7196 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPointI );
7197 return dev->funcs->pGetTextExtentExPointI( dev, indices, count, dxs );
7200 TRACE("%p, %p, %d\n", physdev->font, indices, count);
7203 EnterCriticalSection( &freetype_cs );
7205 for (idx = pos = 0; idx < count; idx++)
7207 get_glyph_outline( physdev->font, indices[idx], GGO_METRICS | GGO_GLYPH_INDEX,
7208 &gm, &abc, 0, NULL, &identity );
7209 pos += abc.abcA + abc.abcB + abc.abcC;
7213 LeaveCriticalSection( &freetype_cs );
7217 /*************************************************************
7218 * freetype_GetFontData
7220 static DWORD freetype_GetFontData( PHYSDEV dev, DWORD table, DWORD offset, LPVOID buf, DWORD cbData )
7222 struct freetype_physdev *physdev = get_freetype_dev( dev );
7226 dev = GET_NEXT_PHYSDEV( dev, pGetFontData );
7227 return dev->funcs->pGetFontData( dev, table, offset, buf, cbData );
7230 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
7231 physdev->font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
7232 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
7234 return get_font_data( physdev->font, table, offset, buf, cbData );
7237 /*************************************************************
7238 * freetype_GetTextFace
7240 static INT freetype_GetTextFace( PHYSDEV dev, INT count, LPWSTR str )
7243 struct freetype_physdev *physdev = get_freetype_dev( dev );
7247 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
7248 return dev->funcs->pGetTextFace( dev, count, str );
7251 n = strlenW(physdev->font->name) + 1;
7254 lstrcpynW(str, physdev->font->name, count);
7260 /*************************************************************
7261 * freetype_GetTextCharsetInfo
7263 static UINT freetype_GetTextCharsetInfo( PHYSDEV dev, LPFONTSIGNATURE fs, DWORD flags )
7265 struct freetype_physdev *physdev = get_freetype_dev( dev );
7269 dev = GET_NEXT_PHYSDEV( dev, pGetTextCharsetInfo );
7270 return dev->funcs->pGetTextCharsetInfo( dev, fs, flags );
7272 if (fs) *fs = physdev->font->fs;
7273 return physdev->font->charset;
7276 /* Retrieve a list of supported Unicode ranges for a given font.
7277 * Can be called with NULL gs to calculate the buffer size. Returns
7278 * the number of ranges found.
7280 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
7282 DWORD num_ranges = 0;
7284 if (face->charmap->encoding == FT_ENCODING_UNICODE)
7287 FT_ULong char_code, char_code_prev;
7290 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
7292 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
7293 face->num_glyphs, glyph_code, char_code);
7295 if (!glyph_code) return 0;
7299 gs->ranges[0].wcLow = (USHORT)char_code;
7300 gs->ranges[0].cGlyphs = 0;
7301 gs->cGlyphsSupported = 0;
7307 if (char_code < char_code_prev)
7309 ERR("expected increasing char code from FT_Get_Next_Char\n");
7312 if (char_code - char_code_prev > 1)
7317 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
7318 gs->ranges[num_ranges - 1].cGlyphs = 1;
7319 gs->cGlyphsSupported++;
7324 gs->ranges[num_ranges - 1].cGlyphs++;
7325 gs->cGlyphsSupported++;
7327 char_code_prev = char_code;
7328 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
7332 FIXME("encoding %u not supported\n", face->charmap->encoding);
7337 /*************************************************************
7338 * freetype_GetFontUnicodeRanges
7340 static DWORD freetype_GetFontUnicodeRanges( PHYSDEV dev, LPGLYPHSET glyphset )
7342 struct freetype_physdev *physdev = get_freetype_dev( dev );
7343 DWORD size, num_ranges;
7347 dev = GET_NEXT_PHYSDEV( dev, pGetFontUnicodeRanges );
7348 return dev->funcs->pGetFontUnicodeRanges( dev, glyphset );
7351 num_ranges = get_font_unicode_ranges(physdev->font->ft_face, glyphset);
7352 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
7355 glyphset->cbThis = size;
7356 glyphset->cRanges = num_ranges;
7357 glyphset->flAccel = 0;
7362 /*************************************************************
7363 * freetype_FontIsLinked
7365 static BOOL freetype_FontIsLinked( PHYSDEV dev )
7367 struct freetype_physdev *physdev = get_freetype_dev( dev );
7372 dev = GET_NEXT_PHYSDEV( dev, pFontIsLinked );
7373 return dev->funcs->pFontIsLinked( dev );
7377 EnterCriticalSection( &freetype_cs );
7378 ret = !list_empty(&physdev->font->child_fonts);
7379 LeaveCriticalSection( &freetype_cs );
7383 /*************************************************************************
7384 * GetRasterizerCaps (GDI32.@)
7386 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7388 lprs->nSize = sizeof(RASTERIZER_STATUS);
7389 lprs->wFlags = TT_AVAILABLE | TT_ENABLED;
7390 lprs->nLanguageID = 0;
7394 /*************************************************************
7395 * freetype_GdiRealizationInfo
7397 static BOOL freetype_GdiRealizationInfo( PHYSDEV dev, void *ptr )
7399 struct freetype_physdev *physdev = get_freetype_dev( dev );
7400 realization_info_t *info = ptr;
7404 dev = GET_NEXT_PHYSDEV( dev, pGdiRealizationInfo );
7405 return dev->funcs->pGdiRealizationInfo( dev, ptr );
7408 FIXME("(%p, %p): stub!\n", physdev->font, info);
7411 if(FT_IS_SCALABLE(physdev->font->ft_face))
7414 info->cache_num = physdev->font->cache_num;
7415 info->unknown2 = -1;
7419 /*************************************************************************
7420 * Kerning support for TrueType fonts
7422 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
7424 struct TT_kern_table
7430 struct TT_kern_subtable
7439 USHORT horizontal : 1;
7441 USHORT cross_stream: 1;
7442 USHORT override : 1;
7443 USHORT reserved1 : 4;
7449 struct TT_format0_kern_subtable
7453 USHORT entrySelector;
7464 static DWORD parse_format0_kern_subtable(GdiFont *font,
7465 const struct TT_format0_kern_subtable *tt_f0_ks,
7466 const USHORT *glyph_to_char,
7467 KERNINGPAIR *kern_pair, DWORD cPairs)
7470 const struct TT_kern_pair *tt_kern_pair;
7472 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
7474 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
7476 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
7477 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
7478 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
7480 if (!kern_pair || !cPairs)
7483 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
7485 nPairs = min(nPairs, cPairs);
7487 for (i = 0; i < nPairs; i++)
7489 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
7490 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
7491 /* this algorithm appears to better match what Windows does */
7492 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
7493 if (kern_pair->iKernAmount < 0)
7495 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
7496 kern_pair->iKernAmount -= font->ppem;
7498 else if (kern_pair->iKernAmount > 0)
7500 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
7501 kern_pair->iKernAmount += font->ppem;
7503 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
7505 TRACE("left %u right %u value %d\n",
7506 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
7510 TRACE("copied %u entries\n", nPairs);
7514 /*************************************************************
7515 * freetype_GetKerningPairs
7517 static DWORD freetype_GetKerningPairs( PHYSDEV dev, DWORD cPairs, KERNINGPAIR *kern_pair )
7521 const struct TT_kern_table *tt_kern_table;
7522 const struct TT_kern_subtable *tt_kern_subtable;
7524 USHORT *glyph_to_char;
7526 struct freetype_physdev *physdev = get_freetype_dev( dev );
7528 if (!(font = physdev->font))
7530 dev = GET_NEXT_PHYSDEV( dev, pGetKerningPairs );
7531 return dev->funcs->pGetKerningPairs( dev, cPairs, kern_pair );
7535 EnterCriticalSection( &freetype_cs );
7536 if (font->total_kern_pairs != (DWORD)-1)
7538 if (cPairs && kern_pair)
7540 cPairs = min(cPairs, font->total_kern_pairs);
7541 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7543 else cPairs = font->total_kern_pairs;
7545 LeaveCriticalSection( &freetype_cs );
7549 font->total_kern_pairs = 0;
7551 length = get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
7553 if (length == GDI_ERROR)
7555 TRACE("no kerning data in the font\n");
7556 LeaveCriticalSection( &freetype_cs );
7560 buf = HeapAlloc(GetProcessHeap(), 0, length);
7563 WARN("Out of memory\n");
7564 LeaveCriticalSection( &freetype_cs );
7568 get_font_data(font, MS_KERN_TAG, 0, buf, length);
7570 /* build a glyph index to char code map */
7571 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
7574 WARN("Out of memory allocating a glyph index to char code map\n");
7575 HeapFree(GetProcessHeap(), 0, buf);
7576 LeaveCriticalSection( &freetype_cs );
7580 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE)
7586 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
7588 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
7589 font->ft_face->num_glyphs, glyph_code, char_code);
7593 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
7595 /* FIXME: This doesn't match what Windows does: it does some fancy
7596 * things with duplicate glyph index to char code mappings, while
7597 * we just avoid overriding existing entries.
7599 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
7600 glyph_to_char[glyph_code] = (USHORT)char_code;
7602 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
7609 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
7610 for (n = 0; n <= 65535; n++)
7611 glyph_to_char[n] = (USHORT)n;
7614 tt_kern_table = buf;
7615 nTables = GET_BE_WORD(tt_kern_table->nTables);
7616 TRACE("version %u, nTables %u\n",
7617 GET_BE_WORD(tt_kern_table->version), nTables);
7619 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
7621 for (i = 0; i < nTables; i++)
7623 struct TT_kern_subtable tt_kern_subtable_copy;
7625 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
7626 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
7627 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
7629 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
7630 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
7631 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
7633 /* According to the TrueType specification this is the only format
7634 * that will be properly interpreted by Windows and OS/2
7636 if (tt_kern_subtable_copy.coverage.bits.format == 0)
7638 DWORD new_chunk, old_total = font->total_kern_pairs;
7640 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7641 glyph_to_char, NULL, 0);
7642 font->total_kern_pairs += new_chunk;
7644 if (!font->kern_pairs)
7645 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
7646 font->total_kern_pairs * sizeof(*font->kern_pairs));
7648 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
7649 font->total_kern_pairs * sizeof(*font->kern_pairs));
7651 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
7652 glyph_to_char, font->kern_pairs + old_total, new_chunk);
7655 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
7657 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
7660 HeapFree(GetProcessHeap(), 0, glyph_to_char);
7661 HeapFree(GetProcessHeap(), 0, buf);
7663 if (cPairs && kern_pair)
7665 cPairs = min(cPairs, font->total_kern_pairs);
7666 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
7668 else cPairs = font->total_kern_pairs;
7670 LeaveCriticalSection( &freetype_cs );
7674 static const struct gdi_dc_funcs freetype_funcs =
7676 NULL, /* pAbortDoc */
7677 NULL, /* pAbortPath */
7678 NULL, /* pAlphaBlend */
7679 NULL, /* pAngleArc */
7682 NULL, /* pBeginPath */
7683 NULL, /* pBlendImage */
7685 NULL, /* pCloseFigure */
7686 NULL, /* pCreateCompatibleDC */
7687 freetype_CreateDC, /* pCreateDC */
7688 freetype_DeleteDC, /* pDeleteDC */
7689 NULL, /* pDeleteObject */
7690 NULL, /* pDeviceCapabilities */
7691 NULL, /* pEllipse */
7693 NULL, /* pEndPage */
7694 NULL, /* pEndPath */
7695 freetype_EnumFonts, /* pEnumFonts */
7696 NULL, /* pEnumICMProfiles */
7697 NULL, /* pExcludeClipRect */
7698 NULL, /* pExtDeviceMode */
7699 NULL, /* pExtEscape */
7700 NULL, /* pExtFloodFill */
7701 NULL, /* pExtSelectClipRgn */
7702 NULL, /* pExtTextOut */
7703 NULL, /* pFillPath */
7704 NULL, /* pFillRgn */
7705 NULL, /* pFlattenPath */
7706 freetype_FontIsLinked, /* pFontIsLinked */
7707 NULL, /* pFrameRgn */
7708 NULL, /* pGdiComment */
7709 freetype_GdiRealizationInfo, /* pGdiRealizationInfo */
7710 NULL, /* pGetBoundsRect */
7711 freetype_GetCharABCWidths, /* pGetCharABCWidths */
7712 freetype_GetCharABCWidthsI, /* pGetCharABCWidthsI */
7713 freetype_GetCharWidth, /* pGetCharWidth */
7714 NULL, /* pGetDeviceCaps */
7715 NULL, /* pGetDeviceGammaRamp */
7716 freetype_GetFontData, /* pGetFontData */
7717 freetype_GetFontUnicodeRanges, /* pGetFontUnicodeRanges */
7718 freetype_GetGlyphIndices, /* pGetGlyphIndices */
7719 freetype_GetGlyphOutline, /* pGetGlyphOutline */
7720 NULL, /* pGetICMProfile */
7721 NULL, /* pGetImage */
7722 freetype_GetKerningPairs, /* pGetKerningPairs */
7723 NULL, /* pGetNearestColor */
7724 freetype_GetOutlineTextMetrics, /* pGetOutlineTextMetrics */
7725 NULL, /* pGetPixel */
7726 NULL, /* pGetSystemPaletteEntries */
7727 freetype_GetTextCharsetInfo, /* pGetTextCharsetInfo */
7728 freetype_GetTextExtentExPoint, /* pGetTextExtentExPoint */
7729 freetype_GetTextExtentExPointI, /* pGetTextExtentExPointI */
7730 freetype_GetTextFace, /* pGetTextFace */
7731 freetype_GetTextMetrics, /* pGetTextMetrics */
7732 NULL, /* pGradientFill */
7733 NULL, /* pIntersectClipRect */
7734 NULL, /* pInvertRgn */
7736 NULL, /* pModifyWorldTransform */
7738 NULL, /* pOffsetClipRgn */
7739 NULL, /* pOffsetViewportOrg */
7740 NULL, /* pOffsetWindowOrg */
7741 NULL, /* pPaintRgn */
7744 NULL, /* pPolyBezier */
7745 NULL, /* pPolyBezierTo */
7746 NULL, /* pPolyDraw */
7747 NULL, /* pPolyPolygon */
7748 NULL, /* pPolyPolyline */
7749 NULL, /* pPolygon */
7750 NULL, /* pPolyline */
7751 NULL, /* pPolylineTo */
7752 NULL, /* pPutImage */
7753 NULL, /* pRealizeDefaultPalette */
7754 NULL, /* pRealizePalette */
7755 NULL, /* pRectangle */
7756 NULL, /* pResetDC */
7757 NULL, /* pRestoreDC */
7758 NULL, /* pRoundRect */
7760 NULL, /* pScaleViewportExt */
7761 NULL, /* pScaleWindowExt */
7762 NULL, /* pSelectBitmap */
7763 NULL, /* pSelectBrush */
7764 NULL, /* pSelectClipPath */
7765 freetype_SelectFont, /* pSelectFont */
7766 NULL, /* pSelectPalette */
7767 NULL, /* pSelectPen */
7768 NULL, /* pSetArcDirection */
7769 NULL, /* pSetBkColor */
7770 NULL, /* pSetBkMode */
7771 NULL, /* pSetDCBrushColor */
7772 NULL, /* pSetDCPenColor */
7773 NULL, /* pSetDIBColorTable */
7774 NULL, /* pSetDIBitsToDevice */
7775 NULL, /* pSetDeviceClipping */
7776 NULL, /* pSetDeviceGammaRamp */
7777 NULL, /* pSetLayout */
7778 NULL, /* pSetMapMode */
7779 NULL, /* pSetMapperFlags */
7780 NULL, /* pSetPixel */
7781 NULL, /* pSetPolyFillMode */
7782 NULL, /* pSetROP2 */
7783 NULL, /* pSetRelAbs */
7784 NULL, /* pSetStretchBltMode */
7785 NULL, /* pSetTextAlign */
7786 NULL, /* pSetTextCharacterExtra */
7787 NULL, /* pSetTextColor */
7788 NULL, /* pSetTextJustification */
7789 NULL, /* pSetViewportExt */
7790 NULL, /* pSetViewportOrg */
7791 NULL, /* pSetWindowExt */
7792 NULL, /* pSetWindowOrg */
7793 NULL, /* pSetWorldTransform */
7794 NULL, /* pStartDoc */
7795 NULL, /* pStartPage */
7796 NULL, /* pStretchBlt */
7797 NULL, /* pStretchDIBits */
7798 NULL, /* pStrokeAndFillPath */
7799 NULL, /* pStrokePath */
7800 NULL, /* pUnrealizePalette */
7801 NULL, /* pWidenPath */
7802 NULL, /* wine_get_wgl_driver */
7803 GDI_PRIORITY_FONT_DRV /* priority */
7806 #else /* HAVE_FREETYPE */
7808 /*************************************************************************/
7810 BOOL WineEngInit(void)
7815 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7817 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7821 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
7823 FIXME("(%s, %x, %p): stub\n", debugstr_w(file), flags, pdv);
7827 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
7829 FIXME("(%p, %u, %p, %p): stub\n", pbFont, cbFont, pdv, pcFonts);
7833 BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource,
7834 LPCWSTR font_file, LPCWSTR font_path )
7840 /*************************************************************************
7841 * GetRasterizerCaps (GDI32.@)
7843 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
7845 lprs->nSize = sizeof(RASTERIZER_STATUS);
7847 lprs->nLanguageID = 0;
7851 #endif /* HAVE_FREETYPE */