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
29 #include "wine/port.h"
33 #ifdef HAVE_SYS_STAT_H
34 # include <sys/stat.h>
36 #ifdef HAVE_SYS_MMAN_H
37 # include <sys/mman.h>
46 #ifdef HAVE_CARBON_CARBON_H
47 #define LoadResource __carbon_LoadResource
48 #define CompareString __carbon_CompareString
49 #define GetCurrentThread __carbon_GetCurrentThread
50 #define GetCurrentProcess __carbon_GetCurrentProcess
51 #define AnimatePalette __carbon_AnimatePalette
52 #define EqualRgn __carbon_EqualRgn
53 #define FillRgn __carbon_FillRgn
54 #define FrameRgn __carbon_FrameRgn
55 #define GetPixel __carbon_GetPixel
56 #define InvertRgn __carbon_InvertRgn
57 #define LineTo __carbon_LineTo
58 #define OffsetRgn __carbon_OffsetRgn
59 #define PaintRgn __carbon_PaintRgn
60 #define Polygon __carbon_Polygon
61 #define ResizePalette __carbon_ResizePalette
62 #define SetRectRgn __carbon_SetRectRgn
63 #include <Carbon/Carbon.h>
66 #undef GetCurrentThread
68 #undef GetCurrentProcess
81 #endif /* HAVE_CARBON_CARBON_H */
83 #ifdef HAVE_FT2BUILD_H
85 #include FT_FREETYPE_H
88 #include FT_TRUETYPE_TABLES_H
89 #include FT_SFNT_NAMES_H
90 #include FT_TRUETYPE_IDS_H
92 #include FT_TRIGONOMETRY_H
94 #include FT_WINFONTS_H
95 #ifdef FT_LCD_FILTER_H
96 #include FT_LCD_FILTER_H
98 #endif /* HAVE_FT2BUILD_H */
100 #include "ntstatus.h"
101 #define WIN32_NO_STATUS
104 #include "winternl.h"
105 #include "winerror.h"
108 #include "ntgdi_private.h"
109 #include "wine/debug.h"
110 #include "wine/list.h"
112 #include "resource.h"
116 WINE_DEFAULT_DEBUG_CHANNEL(font
);
118 #ifndef HAVE_FT_TRUETYPEENGINETYPE
121 FT_TRUETYPE_ENGINE_TYPE_NONE
= 0,
122 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED
,
123 FT_TRUETYPE_ENGINE_TYPE_PATENTED
124 } FT_TrueTypeEngineType
;
127 static FT_Library library
= 0;
134 static FT_Version_t FT_Version
;
135 static DWORD FT_SimpleVersion
;
136 #define FT_VERSION_VALUE(major, minor, patch) (((major) << 16) | ((minor) << 8) | (patch))
138 static void *ft_handle
= NULL
;
140 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
141 MAKE_FUNCPTR(FT_Done_Face
);
142 MAKE_FUNCPTR(FT_Get_Char_Index
);
143 MAKE_FUNCPTR(FT_Get_First_Char
);
144 MAKE_FUNCPTR(FT_Get_Next_Char
);
145 MAKE_FUNCPTR(FT_Get_Sfnt_Name
);
146 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count
);
147 MAKE_FUNCPTR(FT_Get_Sfnt_Table
);
148 MAKE_FUNCPTR(FT_Get_WinFNT_Header
);
149 MAKE_FUNCPTR(FT_Init_FreeType
);
150 MAKE_FUNCPTR(FT_Library_Version
);
151 MAKE_FUNCPTR(FT_Load_Glyph
);
152 MAKE_FUNCPTR(FT_Load_Sfnt_Table
);
153 MAKE_FUNCPTR(FT_Matrix_Multiply
);
154 MAKE_FUNCPTR(FT_MulDiv
);
155 #ifdef FT_MULFIX_INLINED
156 #define pFT_MulFix FT_MULFIX_INLINED
158 MAKE_FUNCPTR(FT_MulFix
);
160 MAKE_FUNCPTR(FT_New_Face
);
161 MAKE_FUNCPTR(FT_New_Memory_Face
);
162 MAKE_FUNCPTR(FT_Outline_Get_Bitmap
);
163 MAKE_FUNCPTR(FT_Outline_Get_CBox
);
164 MAKE_FUNCPTR(FT_Outline_Transform
);
165 MAKE_FUNCPTR(FT_Outline_Translate
);
166 MAKE_FUNCPTR(FT_Render_Glyph
);
167 MAKE_FUNCPTR(FT_Set_Charmap
);
168 MAKE_FUNCPTR(FT_Set_Pixel_Sizes
);
169 MAKE_FUNCPTR(FT_Vector_Length
);
170 MAKE_FUNCPTR(FT_Vector_Transform
);
171 MAKE_FUNCPTR(FT_Vector_Unit
);
172 static FT_Error (*pFT_Outline_Embolden
)(FT_Outline
*, FT_Pos
);
173 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type
)(FT_Library
);
174 #ifdef FT_LCD_FILTER_H
175 static FT_Error (*pFT_Library_SetLcdFilter
)(FT_Library
, FT_LcdFilter
);
177 static FT_Error (*pFT_Property_Set
)(FT_Library
, const FT_String
*, const FT_String
*, const void *);
179 #ifdef SONAME_LIBFONTCONFIG
180 #include <fontconfig/fontconfig.h>
181 MAKE_FUNCPTR(FcConfigSubstitute
);
182 MAKE_FUNCPTR(FcDefaultSubstitute
);
183 MAKE_FUNCPTR(FcFontList
);
184 MAKE_FUNCPTR(FcFontMatch
);
185 MAKE_FUNCPTR(FcFontSetDestroy
);
186 MAKE_FUNCPTR(FcInit
);
187 MAKE_FUNCPTR(FcPatternAddString
);
188 MAKE_FUNCPTR(FcPatternCreate
);
189 MAKE_FUNCPTR(FcPatternDestroy
);
190 MAKE_FUNCPTR(FcPatternGetBool
);
191 MAKE_FUNCPTR(FcPatternGetInteger
);
192 MAKE_FUNCPTR(FcPatternGetString
);
193 MAKE_FUNCPTR(FcConfigGetFontDirs
);
194 MAKE_FUNCPTR(FcConfigGetCurrent
);
195 MAKE_FUNCPTR(FcCacheCopySet
);
196 MAKE_FUNCPTR(FcCacheNumSubdir
);
197 MAKE_FUNCPTR(FcCacheSubdir
);
198 MAKE_FUNCPTR(FcDirCacheRead
);
199 MAKE_FUNCPTR(FcDirCacheUnload
);
200 MAKE_FUNCPTR(FcStrListCreate
);
201 MAKE_FUNCPTR(FcStrListDone
);
202 MAKE_FUNCPTR(FcStrListNext
);
203 MAKE_FUNCPTR(FcStrSetAdd
);
204 MAKE_FUNCPTR(FcStrSetCreate
);
205 MAKE_FUNCPTR(FcStrSetDestroy
);
206 MAKE_FUNCPTR(FcStrSetMember
);
208 #define FC_NAMELANG "namelang"
211 #define FC_PRGNAME "prgname"
213 #endif /* SONAME_LIBFONTCONFIG */
218 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
219 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
220 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
223 #ifndef ft_encoding_none
224 #define FT_ENCODING_NONE ft_encoding_none
226 #ifndef ft_encoding_ms_symbol
227 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
229 #ifndef ft_encoding_unicode
230 #define FT_ENCODING_UNICODE ft_encoding_unicode
232 #ifndef ft_encoding_apple_roman
233 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
236 #ifdef WORDS_BIGENDIAN
237 #define GET_BE_WORD(x) (x)
238 #define GET_BE_DWORD(x) (x)
240 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
241 #define GET_BE_DWORD(x) RtlUlongByteSwap(x)
245 #define GASP_GRIDFIT 0x01
246 #define GASP_DOGRAY 0x02
248 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
249 So to let this compile on older versions of FreeType we'll define the
250 new structure here. */
252 FT_Short height
, width
;
253 FT_Pos size
, x_ppem
, y_ppem
;
256 struct font_private_data
259 struct font_mapping
*mapping
;
262 static inline FT_Face
get_ft_face( struct gdi_font
*font
)
264 return ((struct font_private_data
*)font
->private)->ft_face
;
267 static const struct font_callback_funcs
*callback_funcs
;
279 static struct list mappings_list
= LIST_INIT( mappings_list
);
281 static UINT default_aa_flags
;
282 static LCID system_lcid
;
284 static BOOL CDECL
freetype_set_outline_text_metrics( struct gdi_font
*font
);
285 static BOOL CDECL
freetype_set_bitmap_text_metrics( struct gdi_font
*font
);
287 /****************************************
288 * Notes on .fon files
290 * The fonts System, FixedSys and Terminal are special. There are typically multiple
291 * versions installed for different resolutions and codepages. Windows stores which one to use
292 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
294 * FIXEDFON.FON FixedSys
296 * OEMFONT.FON Terminal
297 * LogPixels Current dpi set by the display control panel applet
298 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
299 * also has a LogPixels value that appears to mirror this)
301 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
302 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
303 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
304 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
305 * so that makes sense.
307 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
308 * to be mapped into the registry on Windows 2000 at least).
311 * ega80woa.fon=ega80850.fon
312 * ega40woa.fon=ega40850.fon
313 * cga80woa.fon=cga80850.fon
314 * cga40woa.fon=cga40850.fon
317 #ifdef HAVE_CARBON_CARBON_H
318 static char *find_cache_dir(void)
322 static char cached_path
[MAX_PATH
];
323 static const char *wine
= "/Wine", *fonts
= "/Fonts";
325 if(*cached_path
) return cached_path
;
327 err
= FSFindFolder(kUserDomain
, kCachedDataFolderType
, kCreateFolder
, &ref
);
330 WARN("can't create cached data folder\n");
333 err
= FSRefMakePath(&ref
, (unsigned char*)cached_path
, sizeof(cached_path
));
336 WARN("can't create cached data path\n");
340 if(strlen(cached_path
) + strlen(wine
) + strlen(fonts
) + 1 > sizeof(cached_path
))
342 ERR("Could not create full path\n");
346 strcat(cached_path
, wine
);
348 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
350 WARN("Couldn't mkdir %s\n", cached_path
);
354 strcat(cached_path
, fonts
);
355 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
357 WARN("Couldn't mkdir %s\n", cached_path
);
364 /******************************************************************
367 * Extracts individual TrueType font files from a Mac suitcase font
368 * and saves them into the user's caches directory (see
370 * Returns a NULL terminated array of filenames.
372 * We do this because they are apps that try to read ttf files
373 * themselves and they don't like Mac suitcase files.
375 static char **expand_mac_font(const char *path
)
378 ResFileRefNum res_ref
;
382 const char *filename
;
386 unsigned int size
, max_size
;
389 TRACE("path %s\n", path
);
391 s
= FSPathMakeRef((unsigned char*)path
, &ref
, FALSE
);
394 WARN("failed to get ref\n");
398 s
= FSOpenResourceFile(&ref
, 0, NULL
, fsRdPerm
, &res_ref
);
401 TRACE("no data fork, so trying resource fork\n");
402 res_ref
= FSOpenResFile(&ref
, fsRdPerm
);
405 TRACE("unable to open resource fork\n");
412 ret
.array
= RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.max_size
* sizeof(*ret
.array
));
415 CloseResFile(res_ref
);
419 out_dir
= find_cache_dir();
421 filename
= strrchr(path
, '/');
422 if(!filename
) filename
= path
;
425 /* output filename has the form out_dir/filename_%04x.ttf */
426 output_len
= strlen(out_dir
) + 1 + strlen(filename
) + 5 + 5;
433 unsigned short *num_faces_ptr
, num_faces
, face
;
436 ResType fond_res
= FT_MAKE_TAG('F','O','N','D');
438 fond
= Get1IndResource(fond_res
, idx
);
440 TRACE("got fond resource %d\n", idx
);
443 fam_rec
= *(FamRec
**)fond
;
444 num_faces_ptr
= (unsigned short *)(fam_rec
+ 1);
445 num_faces
= GET_BE_WORD(*num_faces_ptr
);
447 assoc
= (AsscEntry
*)(num_faces_ptr
+ 1);
448 TRACE("num faces %04x\n", num_faces
);
449 for(face
= 0; face
< num_faces
; face
++, assoc
++)
452 ResType sfnt_res
= FT_MAKE_TAG('s','f','n','t');
453 unsigned short size
, font_id
;
456 size
= GET_BE_WORD(assoc
->fontSize
);
457 font_id
= GET_BE_WORD(assoc
->fontID
);
460 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id
, size
);
464 TRACE("trying to load sfnt id %04x\n", font_id
);
465 sfnt
= GetResource(sfnt_res
, font_id
);
468 TRACE("can't get sfnt resource %04x\n", font_id
);
472 output
= RtlAllocateHeap(GetProcessHeap(), 0, output_len
);
477 sprintf(output
, "%s/%s_%04x.ttf", out_dir
, filename
, font_id
);
479 fd
= open(output
, O_CREAT
| O_EXCL
| O_WRONLY
, 0600);
480 if(fd
!= -1 || errno
== EEXIST
)
484 unsigned char *sfnt_data
;
487 sfnt_data
= *(unsigned char**)sfnt
;
488 write(fd
, sfnt_data
, GetHandleSize(sfnt
));
492 if(ret
.size
>= ret
.max_size
- 1) /* Always want the last element to be NULL */
495 ret
.array
= RtlReAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.array
, ret
.max_size
* sizeof(*ret
.array
));
497 ret
.array
[ret
.size
++] = output
;
501 WARN("unable to create %s\n", output
);
502 RtlFreeHeap(GetProcessHeap(), 0, output
);
505 ReleaseResource(sfnt
);
508 ReleaseResource(fond
);
511 CloseResFile(res_ref
);
516 #endif /* HAVE_CARBON_CARBON_H */
519 This function builds an FT_Fixed from a double. It fails if the absolute
520 value of the float number is greater than 32768.
522 static inline FT_Fixed
FT_FixedFromFloat(double f
)
528 This function builds an FT_Fixed from a FIXED. It simply put f.value
529 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
531 static inline FT_Fixed
FT_FixedFromFIXED(FIXED f
)
533 return (FT_Fixed
)((int)f
.value
<< 16 | (unsigned int)f
.fract
);
536 static BOOL
is_hinting_enabled(void)
538 static int enabled
= -1;
542 /* Use the >= 2.2.0 function if available */
543 if (pFT_Get_TrueType_Engine_Type
)
545 FT_TrueTypeEngineType type
= pFT_Get_TrueType_Engine_Type(library
);
546 enabled
= (type
== FT_TRUETYPE_ENGINE_TYPE_PATENTED
);
548 else enabled
= FALSE
;
549 TRACE("hinting is %senabled\n", enabled
? "" : "NOT ");
554 static BOOL
is_subpixel_rendering_enabled( void )
556 static int enabled
= -1;
559 /* FreeType >= 2.8.1 offers LCD-optimezed rendering without lcd filters. */
560 if (FT_SimpleVersion
>= FT_VERSION_VALUE(2, 8, 1))
562 #ifdef FT_LCD_FILTER_H
563 else if (pFT_Library_SetLcdFilter
&&
564 pFT_Library_SetLcdFilter( NULL
, 0 ) != FT_Err_Unimplemented_Feature
)
567 else enabled
= FALSE
;
569 TRACE("subpixel rendering is %senabled\n", enabled
? "" : "NOT ");
575 static LPWSTR
strdupW(LPCWSTR p
)
578 DWORD len
= (lstrlenW(p
) + 1) * sizeof(WCHAR
);
579 ret
= RtlAllocateHeap(GetProcessHeap(), 0, len
);
584 static WCHAR
*towstr(const char *str
)
586 DWORD len
= strlen(str
) + 1;
587 WCHAR
*wstr
= RtlAllocateHeap( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
588 RtlMultiByteToUnicodeN( wstr
, len
* sizeof(WCHAR
), &len
, str
, len
);
593 static const LANGID mac_langid_table
[] =
595 MAKELANGID(LANG_ENGLISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ENGLISH */
596 MAKELANGID(LANG_FRENCH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FRENCH */
597 MAKELANGID(LANG_GERMAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GERMAN */
598 MAKELANGID(LANG_ITALIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ITALIAN */
599 MAKELANGID(LANG_DUTCH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_DUTCH */
600 MAKELANGID(LANG_SWEDISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SWEDISH */
601 MAKELANGID(LANG_SPANISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SPANISH */
602 MAKELANGID(LANG_DANISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_DANISH */
603 MAKELANGID(LANG_PORTUGUESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PORTUGUESE */
604 MAKELANGID(LANG_NORWEGIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_NORWEGIAN */
605 MAKELANGID(LANG_HEBREW
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HEBREW */
606 MAKELANGID(LANG_JAPANESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_JAPANESE */
607 MAKELANGID(LANG_ARABIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ARABIC */
608 MAKELANGID(LANG_FINNISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FINNISH */
609 MAKELANGID(LANG_GREEK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GREEK */
610 MAKELANGID(LANG_ICELANDIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ICELANDIC */
611 MAKELANGID(LANG_MALTESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALTESE */
612 MAKELANGID(LANG_TURKISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TURKISH */
613 MAKELANGID(LANG_CROATIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CROATIAN */
614 MAKELANGID(LANG_CHINESE_TRADITIONAL
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CHINESE_TRADITIONAL */
615 MAKELANGID(LANG_URDU
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_URDU */
616 MAKELANGID(LANG_HINDI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HINDI */
617 MAKELANGID(LANG_THAI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_THAI */
618 MAKELANGID(LANG_KOREAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KOREAN */
619 MAKELANGID(LANG_LITHUANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LITHUANIAN */
620 MAKELANGID(LANG_POLISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_POLISH */
621 MAKELANGID(LANG_HUNGARIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HUNGARIAN */
622 MAKELANGID(LANG_ESTONIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ESTONIAN */
623 MAKELANGID(LANG_LATVIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LETTISH */
624 MAKELANGID(LANG_SAMI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SAAMISK */
625 MAKELANGID(LANG_FAEROESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FAEROESE */
626 MAKELANGID(LANG_FARSI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FARSI */
627 MAKELANGID(LANG_RUSSIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_RUSSIAN */
628 MAKELANGID(LANG_CHINESE_SIMPLIFIED
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CHINESE_SIMPLIFIED */
629 MAKELANGID(LANG_DUTCH
,SUBLANG_DUTCH_BELGIAN
), /* TT_MAC_LANGID_FLEMISH */
630 MAKELANGID(LANG_IRISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_IRISH */
631 MAKELANGID(LANG_ALBANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ALBANIAN */
632 MAKELANGID(LANG_ROMANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ROMANIAN */
633 MAKELANGID(LANG_CZECH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CZECH */
634 MAKELANGID(LANG_SLOVAK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SLOVAK */
635 MAKELANGID(LANG_SLOVENIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SLOVENIAN */
636 0, /* TT_MAC_LANGID_YIDDISH */
637 MAKELANGID(LANG_SERBIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SERBIAN */
638 MAKELANGID(LANG_MACEDONIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MACEDONIAN */
639 MAKELANGID(LANG_BULGARIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BULGARIAN */
640 MAKELANGID(LANG_UKRAINIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UKRAINIAN */
641 MAKELANGID(LANG_BELARUSIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BYELORUSSIAN */
642 MAKELANGID(LANG_UZBEK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UZBEK */
643 MAKELANGID(LANG_KAZAK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KAZAKH */
644 MAKELANGID(LANG_AZERI
,SUBLANG_AZERI_CYRILLIC
), /* TT_MAC_LANGID_AZERBAIJANI */
645 0, /* TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT */
646 MAKELANGID(LANG_ARMENIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ARMENIAN */
647 MAKELANGID(LANG_GEORGIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GEORGIAN */
648 0, /* TT_MAC_LANGID_MOLDAVIAN */
649 MAKELANGID(LANG_KYRGYZ
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KIRGHIZ */
650 MAKELANGID(LANG_TAJIK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TAJIKI */
651 MAKELANGID(LANG_TURKMEN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TURKMEN */
652 MAKELANGID(LANG_MONGOLIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MONGOLIAN */
653 MAKELANGID(LANG_MONGOLIAN
,SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA
), /* TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT */
654 MAKELANGID(LANG_PASHTO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PASHTO */
655 0, /* TT_MAC_LANGID_KURDISH */
656 MAKELANGID(LANG_KASHMIRI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KASHMIRI */
657 MAKELANGID(LANG_SINDHI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SINDHI */
658 MAKELANGID(LANG_TIBETAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TIBETAN */
659 MAKELANGID(LANG_NEPALI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_NEPALI */
660 MAKELANGID(LANG_SANSKRIT
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SANSKRIT */
661 MAKELANGID(LANG_MARATHI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MARATHI */
662 MAKELANGID(LANG_BENGALI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BENGALI */
663 MAKELANGID(LANG_ASSAMESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ASSAMESE */
664 MAKELANGID(LANG_GUJARATI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GUJARATI */
665 MAKELANGID(LANG_PUNJABI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PUNJABI */
666 MAKELANGID(LANG_ORIYA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ORIYA */
667 MAKELANGID(LANG_MALAYALAM
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAYALAM */
668 MAKELANGID(LANG_KANNADA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KANNADA */
669 MAKELANGID(LANG_TAMIL
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TAMIL */
670 MAKELANGID(LANG_TELUGU
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TELUGU */
671 MAKELANGID(LANG_SINHALESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SINHALESE */
672 0, /* TT_MAC_LANGID_BURMESE */
673 MAKELANGID(LANG_KHMER
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KHMER */
674 MAKELANGID(LANG_LAO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LAO */
675 MAKELANGID(LANG_VIETNAMESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_VIETNAMESE */
676 MAKELANGID(LANG_INDONESIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_INDONESIAN */
677 0, /* TT_MAC_LANGID_TAGALOG */
678 MAKELANGID(LANG_MALAY
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAY_ROMAN_SCRIPT */
679 0, /* TT_MAC_LANGID_MALAY_ARABIC_SCRIPT */
680 MAKELANGID(LANG_AMHARIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_AMHARIC */
681 MAKELANGID(LANG_TIGRIGNA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TIGRINYA */
682 0, /* TT_MAC_LANGID_GALLA */
683 0, /* TT_MAC_LANGID_SOMALI */
684 MAKELANGID(LANG_SWAHILI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SWAHILI */
685 0, /* TT_MAC_LANGID_RUANDA */
686 0, /* TT_MAC_LANGID_RUNDI */
687 0, /* TT_MAC_LANGID_CHEWA */
688 MAKELANGID(LANG_MALAGASY
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAGASY */
689 MAKELANGID(LANG_ESPERANTO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ESPERANTO */
690 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 95-111 */
691 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 112-127 */
692 MAKELANGID(LANG_WELSH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_WELSH */
693 MAKELANGID(LANG_BASQUE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BASQUE */
694 MAKELANGID(LANG_CATALAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CATALAN */
695 0, /* TT_MAC_LANGID_LATIN */
696 MAKELANGID(LANG_QUECHUA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_QUECHUA */
697 0, /* TT_MAC_LANGID_GUARANI */
698 0, /* TT_MAC_LANGID_AYMARA */
699 MAKELANGID(LANG_TATAR
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TATAR */
700 MAKELANGID(LANG_UIGHUR
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UIGHUR */
701 0, /* TT_MAC_LANGID_DZONGKHA */
702 0, /* TT_MAC_LANGID_JAVANESE */
703 0, /* TT_MAC_LANGID_SUNDANESE */
704 MAKELANGID(LANG_GALICIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GALICIAN */
705 MAKELANGID(LANG_AFRIKAANS
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_AFRIKAANS */
706 MAKELANGID(LANG_BRETON
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BRETON */
707 MAKELANGID(LANG_INUKTITUT
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_INUKTITUT */
708 MAKELANGID(LANG_SCOTTISH_GAELIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SCOTTISH_GAELIC */
709 MAKELANGID(LANG_MANX_GAELIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MANX_GAELIC */
710 MAKELANGID(LANG_IRISH
,SUBLANG_IRISH_IRELAND
), /* TT_MAC_LANGID_IRISH_GAELIC */
711 0, /* TT_MAC_LANGID_TONGAN */
712 0, /* TT_MAC_LANGID_GREEK_POLYTONIC */
713 MAKELANGID(LANG_GREENLANDIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GREELANDIC */
714 MAKELANGID(LANG_AZERI
,SUBLANG_AZERI_LATIN
), /* TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT */
717 static CPTABLEINFO
*get_cptable( WORD cp
)
719 static CPTABLEINFO tables
[100];
724 for (i
= 0; i
< ARRAY_SIZE(tables
) && tables
[i
].CodePage
; i
++)
725 if (tables
[i
].CodePage
== cp
) return &tables
[i
];
726 if (NtGetNlsSectionPtr( 11, cp
, NULL
, (void **)&ptr
, &size
)) return NULL
;
727 if (i
== ARRAY_SIZE(tables
)) ERR( "too many code pages\n" );
728 RtlInitCodePageTable( ptr
, &tables
[i
] );
732 static CPTABLEINFO
*get_mac_code_page( const FT_SfntName
*name
)
734 int id
= name
->encoding_id
;
736 if (name
->encoding_id
== TT_MAC_ID_SIMPLIFIED_CHINESE
) id
= 8; /* special case */
737 return get_cptable( 10000 + id
);
740 static int match_name_table_language( const FT_SfntName
*name
, LANGID lang
)
745 switch (name
->platform_id
)
747 case TT_PLATFORM_MICROSOFT
:
748 res
+= 5; /* prefer the Microsoft name */
749 switch (name
->encoding_id
)
751 case TT_MS_ID_UNICODE_CS
:
752 case TT_MS_ID_SYMBOL_CS
:
753 name_lang
= name
->language_id
;
759 case TT_PLATFORM_MACINTOSH
:
760 if (!get_mac_code_page( name
)) return 0;
761 if (name
->language_id
>= ARRAY_SIZE( mac_langid_table
)) return 0;
762 name_lang
= mac_langid_table
[name
->language_id
];
764 case TT_PLATFORM_APPLE_UNICODE
:
765 res
+= 2; /* prefer Unicode encodings */
766 switch (name
->encoding_id
)
768 case TT_APPLE_ID_DEFAULT
:
769 case TT_APPLE_ID_ISO_10646
:
770 case TT_APPLE_ID_UNICODE_2_0
:
771 if (name
->language_id
>= ARRAY_SIZE( mac_langid_table
)) return 0;
772 name_lang
= mac_langid_table
[name
->language_id
];
781 if (name_lang
== lang
) res
+= 30;
782 else if (PRIMARYLANGID( name_lang
) == PRIMARYLANGID( lang
)) res
+= 20;
783 else if (name_lang
== MAKELANGID( LANG_ENGLISH
, SUBLANG_DEFAULT
)) res
+= 10;
784 else if (lang
== MAKELANGID( LANG_NEUTRAL
, SUBLANG_NEUTRAL
)) res
+= 5 * (0x100000 - name_lang
);
788 static WCHAR
*copy_name_table_string( const FT_SfntName
*name
)
794 switch (name
->platform_id
)
796 case TT_PLATFORM_APPLE_UNICODE
:
797 case TT_PLATFORM_MICROSOFT
:
798 ret
= RtlAllocateHeap( GetProcessHeap(), 0, name
->string_len
+ sizeof(WCHAR
) );
799 for (i
= 0; i
< name
->string_len
/ 2; i
++)
800 ret
[i
] = (name
->string
[i
* 2] << 8) | name
->string
[i
* 2 + 1];
803 case TT_PLATFORM_MACINTOSH
:
804 if (!(cp
= get_mac_code_page( name
))) return NULL
;
805 ret
= RtlAllocateHeap( GetProcessHeap(), 0, (name
->string_len
+ 1) * sizeof(WCHAR
) );
806 RtlCustomCPToUnicodeN( cp
, ret
, name
->string_len
* sizeof(WCHAR
), &i
,
807 (char *)name
->string
, name
->string_len
);
808 ret
[i
/ sizeof(WCHAR
)] = 0;
814 static WCHAR
*get_face_name(FT_Face ft_face
, FT_UShort name_id
, LANGID language_id
)
817 FT_UInt num_names
, name_index
;
818 int res
, best_lang
= 0, best_index
= -1;
820 if (!FT_IS_SFNT(ft_face
)) return NULL
;
822 num_names
= pFT_Get_Sfnt_Name_Count( ft_face
);
824 for (name_index
= 0; name_index
< num_names
; name_index
++)
826 if (pFT_Get_Sfnt_Name( ft_face
, name_index
, &name
)) continue;
827 if (name
.name_id
!= name_id
) continue;
828 res
= match_name_table_language( &name
, language_id
);
832 best_index
= name_index
;
836 if (best_index
!= -1 && !pFT_Get_Sfnt_Name( ft_face
, best_index
, &name
))
838 WCHAR
*ret
= copy_name_table_string( &name
);
839 TRACE( "name %u found platform %u lang %04x %s\n",
840 name_id
, name
.platform_id
, name
.language_id
, debugstr_w( ret
));
846 static WCHAR
*ft_face_get_family_name( FT_Face ft_face
, LANGID langid
)
850 if ((family_name
= get_face_name( ft_face
, TT_NAME_ID_FONT_FAMILY
, langid
)))
853 return towstr( ft_face
->family_name
);
856 static WCHAR
*ft_face_get_style_name( FT_Face ft_face
, LANGID langid
)
860 if ((style_name
= get_face_name( ft_face
, TT_NAME_ID_FONT_SUBFAMILY
, langid
)))
863 return towstr( ft_face
->style_name
);
866 static WCHAR
*ft_face_get_full_name( FT_Face ft_face
, LANGID langid
)
868 static const WCHAR space_w
[] = {' ',0};
869 WCHAR
*full_name
, *style_name
;
872 if ((full_name
= get_face_name( ft_face
, TT_NAME_ID_FULL_NAME
, langid
)))
875 full_name
= ft_face_get_family_name( ft_face
, langid
);
876 style_name
= ft_face_get_style_name( ft_face
, langid
);
878 length
= lstrlenW( full_name
) + lstrlenW( space_w
) + lstrlenW( style_name
) + 1;
879 full_name
= RtlReAllocateHeap( GetProcessHeap(), 0, full_name
, length
* sizeof(WCHAR
) );
881 lstrcatW( full_name
, space_w
);
882 lstrcatW( full_name
, style_name
);
883 RtlFreeHeap( GetProcessHeap(), 0, style_name
);
885 WARN( "full name not found, using %s instead\n", debugstr_w(full_name
) );
889 static inline FT_Fixed
get_font_version( FT_Face ft_face
)
891 FT_Fixed version
= 0;
894 header
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_head
);
895 if (header
) version
= header
->Font_Revision
;
900 static inline DWORD
get_ntm_flags( FT_Face ft_face
)
903 FT_ULong table_size
= 0;
904 FT_WinFNT_HeaderRec winfnt_header
;
906 if (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) flags
|= NTM_ITALIC
;
907 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
) flags
|= NTM_BOLD
;
909 /* fixup the flag for our fake-bold implementation. */
910 if (!FT_IS_SCALABLE( ft_face
) &&
911 !pFT_Get_WinFNT_Header( ft_face
, &winfnt_header
) &&
912 winfnt_header
.weight
> FW_NORMAL
)
915 if (flags
== 0) flags
= NTM_REGULAR
;
917 if (!pFT_Load_Sfnt_Table( ft_face
, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL
, &table_size
))
918 flags
|= NTM_PS_OPENTYPE
;
923 static inline void get_bitmap_size( FT_Face ft_face
, struct bitmap_font_size
*face_size
)
925 My_FT_Bitmap_Size
*size
;
926 FT_WinFNT_HeaderRec winfnt_header
;
928 size
= (My_FT_Bitmap_Size
*)ft_face
->available_sizes
;
929 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
930 size
->height
, size
->width
, size
->size
>> 6,
931 size
->x_ppem
>> 6, size
->y_ppem
>> 6);
932 face_size
->height
= size
->height
;
933 face_size
->width
= size
->width
;
934 face_size
->size
= size
->size
;
935 face_size
->x_ppem
= size
->x_ppem
;
936 face_size
->y_ppem
= size
->y_ppem
;
938 if (!pFT_Get_WinFNT_Header( ft_face
, &winfnt_header
)) {
939 face_size
->internal_leading
= winfnt_header
.internal_leading
;
940 if (winfnt_header
.external_leading
> 0 &&
941 (face_size
->height
==
942 winfnt_header
.pixel_height
+ winfnt_header
.external_leading
))
943 face_size
->height
= winfnt_header
.pixel_height
;
947 static inline void get_fontsig( FT_Face ft_face
, FONTSIGNATURE
*fs
)
950 FT_WinFNT_HeaderRec winfnt_header
;
953 memset( fs
, 0, sizeof(*fs
) );
955 os2
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_os2
);
958 fs
->fsUsb
[0] = os2
->ulUnicodeRange1
;
959 fs
->fsUsb
[1] = os2
->ulUnicodeRange2
;
960 fs
->fsUsb
[2] = os2
->ulUnicodeRange3
;
961 fs
->fsUsb
[3] = os2
->ulUnicodeRange4
;
963 if (os2
->version
== 0)
965 if (os2
->usFirstCharIndex
>= 0xf000 && os2
->usFirstCharIndex
< 0xf100)
966 fs
->fsCsb
[0] = FS_SYMBOL
;
968 fs
->fsCsb
[0] = FS_LATIN1
;
972 fs
->fsCsb
[0] = os2
->ulCodePageRange1
;
973 fs
->fsCsb
[1] = os2
->ulCodePageRange2
;
978 if (!pFT_Get_WinFNT_Header( ft_face
, &winfnt_header
))
980 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header
.pixel_height
, winfnt_header
.charset
,
981 winfnt_header
.vertical_resolution
,winfnt_header
.horizontal_resolution
, winfnt_header
.nominal_point_size
);
982 switch (winfnt_header
.charset
)
984 case ANSI_CHARSET
: fs
->fsCsb
[0] = FS_LATIN1
; break;
985 case EASTEUROPE_CHARSET
: fs
->fsCsb
[0] = FS_LATIN2
; break;
986 case RUSSIAN_CHARSET
: fs
->fsCsb
[0] = FS_CYRILLIC
; break;
987 case GREEK_CHARSET
: fs
->fsCsb
[0] = FS_GREEK
; break;
988 case TURKISH_CHARSET
: fs
->fsCsb
[0] = FS_TURKISH
; break;
989 case HEBREW_CHARSET
: fs
->fsCsb
[0] = FS_HEBREW
; break;
990 case ARABIC_CHARSET
: fs
->fsCsb
[0] = FS_ARABIC
; break;
991 case BALTIC_CHARSET
: fs
->fsCsb
[0] = FS_BALTIC
; break;
992 case VIETNAMESE_CHARSET
: fs
->fsCsb
[0] = FS_VIETNAMESE
; break;
993 case THAI_CHARSET
: fs
->fsCsb
[0] = FS_THAI
; break;
994 case SHIFTJIS_CHARSET
: fs
->fsCsb
[0] = FS_JISJAPAN
; break;
995 case GB2312_CHARSET
: fs
->fsCsb
[0] = FS_CHINESESIMP
; break;
996 case HANGEUL_CHARSET
: fs
->fsCsb
[0] = FS_WANSUNG
; break;
997 case CHINESEBIG5_CHARSET
: fs
->fsCsb
[0] = FS_CHINESETRAD
; break;
998 case JOHAB_CHARSET
: fs
->fsCsb
[0] = FS_JOHAB
; break;
999 case SYMBOL_CHARSET
: fs
->fsCsb
[0] = FS_SYMBOL
; break;
1004 if (fs
->fsCsb
[0] == 0)
1006 /* let's see if we can find any interesting cmaps */
1007 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
1009 switch (ft_face
->charmaps
[i
]->encoding
)
1011 case FT_ENCODING_UNICODE
:
1012 case FT_ENCODING_APPLE_ROMAN
:
1013 fs
->fsCsb
[0] |= FS_LATIN1
;
1015 case FT_ENCODING_MS_SYMBOL
:
1016 fs
->fsCsb
[0] |= FS_SYMBOL
;
1025 static FT_Face
new_ft_face( const char *file
, void *font_data_ptr
, DWORD font_data_size
,
1026 FT_Long face_index
, BOOL allow_bitmap
)
1034 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
1035 err
= pFT_New_Face(library
, file
, face_index
, &ft_face
);
1039 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr
, font_data_size
, face_index
);
1040 err
= pFT_New_Memory_Face(library
, font_data_ptr
, font_data_size
, face_index
, &ft_face
);
1045 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file
), font_data_ptr
, err
);
1049 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1050 if (!FT_IS_SCALABLE( ft_face
) && FT_SimpleVersion
< FT_VERSION_VALUE(2, 1, 9))
1052 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1056 if (!FT_IS_SFNT( ft_face
))
1058 if (FT_IS_SCALABLE( ft_face
) || !allow_bitmap
)
1060 WARN("Ignoring font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1066 if (!(pOS2
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_os2
)) ||
1067 !pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_hhea
) ||
1068 !pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_head
))
1070 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1071 "Skipping this font.\n", debugstr_a(file
), font_data_ptr
);
1075 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1076 we don't want to load these. */
1077 if (!memcmp( pOS2
->achVendID
, "Wine", sizeof(pOS2
->achVendID
) ))
1081 if (!pFT_Load_Sfnt_Table( ft_face
, FT_MAKE_TAG('E','B','S','C'), 0, NULL
, &len
))
1083 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file
));
1089 if (!ft_face
->family_name
|| !ft_face
->style_name
)
1091 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file
), font_data_ptr
);
1097 pFT_Done_Face( ft_face
);
1101 struct family_names_data
1103 LANGID primary_langid
;
1104 struct opentype_name family_name
;
1105 struct opentype_name second_name
;
1110 static BOOL
search_family_names_callback( LANGID langid
, struct opentype_name
*name
, void *user
)
1112 struct family_names_data
*data
= user
;
1114 if (langid
== MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
))
1116 data
->english_seen
= TRUE
;
1117 if (data
->primary_langid
== langid
) data
->primary_seen
= TRUE
;
1119 if (!data
->family_name
.bytes
) data
->family_name
= *name
;
1120 else if (data
->primary_langid
!= langid
) data
->second_name
= *name
;
1122 else if (data
->primary_langid
== langid
)
1124 data
->primary_seen
= TRUE
;
1125 if (!data
->second_name
.bytes
) data
->second_name
= data
->family_name
;
1126 data
->family_name
= *name
;
1128 else if (!data
->second_name
.bytes
) data
->second_name
= *name
;
1130 if (data
->family_name
.bytes
&& data
->second_name
.bytes
&& data
->primary_seen
&& data
->english_seen
)
1135 struct face_name_data
1137 LANGID primary_langid
;
1138 struct opentype_name face_name
;
1141 static BOOL
search_face_name_callback( LANGID langid
, struct opentype_name
*name
, void *user
)
1143 struct face_name_data
*data
= user
;
1145 if (langid
== data
->primary_langid
|| (langid
== MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
) && !data
->face_name
.bytes
))
1146 data
->face_name
= *name
;
1148 return langid
== data
->primary_langid
;
1151 static WCHAR
*decode_opentype_name( struct opentype_name
*name
)
1156 if (!name
->codepage
)
1158 len
= min( ARRAY_SIZE(buffer
), name
->length
/ sizeof(WCHAR
) );
1159 while (len
--) buffer
[len
] = GET_BE_WORD( ((WORD
*)name
->bytes
)[len
] );
1160 len
= min( ARRAY_SIZE(buffer
), name
->length
/ sizeof(WCHAR
) );
1164 CPTABLEINFO
*cptable
= get_cptable( name
->codepage
);
1165 if (!cptable
) return NULL
;
1166 RtlCustomCPToUnicodeN( cptable
, buffer
, sizeof(buffer
), &len
, name
->bytes
, name
->length
);
1167 len
/= sizeof(WCHAR
);
1170 buffer
[ARRAY_SIZE(buffer
) - 1] = 0;
1171 if (len
== ARRAY_SIZE(buffer
)) WARN("Truncated font name %s -> %s\n", debugstr_an(name
->bytes
, name
->length
), debugstr_w(buffer
));
1172 else buffer
[len
] = 0;
1174 return strdupW( buffer
);
1189 struct bitmap_font_size size
;
1192 static struct unix_face
*unix_face_create( const char *unix_name
, void *data_ptr
, DWORD data_size
,
1193 UINT face_index
, DWORD flags
)
1195 static const WCHAR space_w
[] = {' ',0};
1197 const struct ttc_sfnt_v1
*ttc_sfnt_v1
;
1198 const struct tt_name_v0
*tt_name_v0
;
1199 struct unix_face
*This
;
1204 TRACE( "unix_name %s, face_index %u, data_ptr %p, data_size %u, flags %#x\n",
1205 unix_name
, face_index
, data_ptr
, data_size
, flags
);
1209 if ((fd
= open( unix_name
, O_RDONLY
)) == -1) return NULL
;
1210 if (fstat( fd
, &st
) == -1)
1215 data_size
= st
.st_size
;
1216 data_ptr
= mmap( NULL
, data_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0 );
1218 if (data_ptr
== MAP_FAILED
) return NULL
;
1221 if (!(This
= RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*This
) ))) goto done
;
1223 if (opentype_get_ttc_sfnt_v1( data_ptr
, data_size
, face_index
, &face_count
, &ttc_sfnt_v1
) &&
1224 opentype_get_tt_name_v0( data_ptr
, data_size
, ttc_sfnt_v1
, &tt_name_v0
) &&
1225 opentype_get_properties( data_ptr
, data_size
, ttc_sfnt_v1
, &This
->font_version
,
1226 &This
->fs
, &This
->ntm_flags
))
1228 struct family_names_data family_names
;
1229 struct face_name_data style_name
;
1230 struct face_name_data full_name
;
1231 LANGID primary_langid
= system_lcid
;
1233 This
->scalable
= TRUE
;
1234 This
->num_faces
= face_count
;
1236 memset( &family_names
, 0, sizeof(family_names
) );
1237 family_names
.primary_langid
= primary_langid
;
1238 opentype_enum_family_names( tt_name_v0
, search_family_names_callback
, &family_names
);
1239 This
->family_name
= decode_opentype_name( &family_names
.family_name
);
1240 This
->second_name
= decode_opentype_name( &family_names
.second_name
);
1242 memset( &style_name
, 0, sizeof(style_name
) );
1243 style_name
.primary_langid
= primary_langid
;
1244 opentype_enum_style_names( tt_name_v0
, search_face_name_callback
, &style_name
);
1245 This
->style_name
= decode_opentype_name( &style_name
.face_name
);
1247 memset( &full_name
, 0, sizeof(full_name
) );
1248 full_name
.primary_langid
= primary_langid
;
1249 opentype_enum_full_names( tt_name_v0
, search_face_name_callback
, &full_name
);
1250 This
->full_name
= decode_opentype_name( &full_name
.face_name
);
1252 TRACE( "parsed font names family_name %s, second_name %s, primary_seen %d, english_seen %d, "
1253 "full_name %s, style_name %s\n",
1254 debugstr_w(This
->family_name
), debugstr_w(This
->second_name
),
1255 family_names
.primary_seen
, family_names
.english_seen
,
1256 debugstr_w(This
->full_name
), debugstr_w(This
->style_name
) );
1258 if (!This
->full_name
&& This
->family_name
&& This
->style_name
)
1260 length
= lstrlenW( This
->family_name
) + lstrlenW( space_w
) + lstrlenW( This
->style_name
) + 1;
1261 This
->full_name
= RtlAllocateHeap( GetProcessHeap(), 0, length
* sizeof(WCHAR
) );
1262 lstrcpyW( This
->full_name
, This
->family_name
);
1263 lstrcatW( This
->full_name
, space_w
);
1264 lstrcatW( This
->full_name
, This
->style_name
);
1265 WARN( "full name not found, using %s instead\n", debugstr_w(This
->full_name
) );
1268 else if ((This
->ft_face
= new_ft_face( unix_name
, data_ptr
, data_size
, face_index
, flags
& ADDFONT_ALLOW_BITMAP
)))
1270 WARN( "unable to parse font, falling back to FreeType\n" );
1271 This
->scalable
= FT_IS_SCALABLE( This
->ft_face
);
1272 This
->num_faces
= This
->ft_face
->num_faces
;
1274 This
->family_name
= ft_face_get_family_name( This
->ft_face
, system_lcid
);
1275 This
->second_name
= ft_face_get_family_name( This
->ft_face
, MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
) );
1277 /* try to find another secondary name, preferring the lowest langids */
1278 if (!RtlCompareUnicodeStrings( This
->family_name
, lstrlenW( This
->family_name
),
1279 This
->second_name
, lstrlenW( This
->second_name
), TRUE
))
1281 RtlFreeHeap( GetProcessHeap(), 0, This
->second_name
);
1282 This
->second_name
= ft_face_get_family_name( This
->ft_face
, MAKELANGID(LANG_NEUTRAL
, SUBLANG_NEUTRAL
) );
1283 if (!RtlCompareUnicodeStrings( This
->family_name
, lstrlenW( This
->family_name
),
1284 This
->second_name
, lstrlenW( This
->second_name
), TRUE
))
1286 RtlFreeHeap( GetProcessHeap(), 0, This
->second_name
);
1287 This
->second_name
= NULL
;
1291 This
->style_name
= ft_face_get_style_name( This
->ft_face
, system_lcid
);
1292 This
->full_name
= ft_face_get_full_name( This
->ft_face
, system_lcid
);
1294 This
->ntm_flags
= get_ntm_flags( This
->ft_face
);
1295 This
->font_version
= get_font_version( This
->ft_face
);
1296 if (!This
->scalable
) get_bitmap_size( This
->ft_face
, &This
->size
);
1297 get_fontsig( This
->ft_face
, &This
->fs
);
1301 RtlFreeHeap( GetProcessHeap(), 0, This
);
1306 if (unix_name
) munmap( data_ptr
, data_size
);
1310 static void unix_face_destroy( struct unix_face
*This
)
1312 if (This
->ft_face
) pFT_Done_Face( This
->ft_face
);
1313 RtlFreeHeap( GetProcessHeap(), 0, This
->full_name
);
1314 RtlFreeHeap( GetProcessHeap(), 0, This
->style_name
);
1315 RtlFreeHeap( GetProcessHeap(), 0, This
->second_name
);
1316 RtlFreeHeap( GetProcessHeap(), 0, This
->family_name
);
1317 RtlFreeHeap( GetProcessHeap(), 0, This
);
1320 static int add_unix_face( const char *unix_name
, const WCHAR
*file
, void *data_ptr
, SIZE_T data_size
,
1321 DWORD face_index
, DWORD flags
, DWORD
*num_faces
)
1323 struct unix_face
*unix_face
;
1326 if (num_faces
) *num_faces
= 0;
1328 if (!(unix_face
= unix_face_create( unix_name
, data_ptr
, data_size
, face_index
, flags
)))
1331 if (unix_face
->family_name
[0] == '.') /* Ignore fonts with names beginning with a dot */
1333 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(unix_name
));
1334 unix_face_destroy( unix_face
);
1338 if (!HIWORD( flags
)) flags
|= ADDFONT_AA_FLAGS( default_aa_flags
);
1340 ret
= callback_funcs
->add_gdi_face( unix_face
->family_name
, unix_face
->second_name
, unix_face
->style_name
, unix_face
->full_name
,
1341 file
, data_ptr
, data_size
, face_index
, unix_face
->fs
, unix_face
->ntm_flags
,
1342 unix_face
->font_version
, flags
, unix_face
->scalable
? NULL
: &unix_face
->size
);
1344 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n", unix_face
->fs
.fsCsb
[0], unix_face
->fs
.fsCsb
[1],
1345 unix_face
->fs
.fsUsb
[0], unix_face
->fs
.fsUsb
[1], unix_face
->fs
.fsUsb
[2], unix_face
->fs
.fsUsb
[3]);
1347 if (num_faces
) *num_faces
= unix_face
->num_faces
;
1348 unix_face_destroy( unix_face
);
1352 static WCHAR
*get_dos_file_name( LPCSTR str
)
1355 SIZE_T len
= strlen(str
) + 1;
1357 len
+= 8; /* \??\unix prefix */
1358 if (!(buffer
= RtlAllocateHeap( GetProcessHeap(), 0, len
* sizeof(WCHAR
) ))) return NULL
;
1359 if (wine_unix_to_nt_file_name( str
, buffer
, &len
))
1361 RtlFreeHeap( GetProcessHeap(), 0, buffer
);
1364 if (buffer
[5] == ':')
1366 /* get rid of the \??\ prefix */
1367 /* FIXME: should implement RtlNtPathNameToDosPathName and use that instead */
1368 memmove( buffer
, buffer
+ 4, (len
- 4) * sizeof(WCHAR
) );
1370 else buffer
[1] = '\\';
1374 static char *get_unix_file_name( LPCWSTR dosW
)
1376 UNICODE_STRING nt_name
;
1381 if (!RtlDosPathNameToNtPathName_U( dosW
, &nt_name
, NULL
, NULL
)) return NULL
;
1384 if (!(buffer
= RtlAllocateHeap( GetProcessHeap(), 0, size
)))
1386 RtlFreeUnicodeString( &nt_name
);
1389 status
= wine_nt_to_unix_file_name( &nt_name
, buffer
, &size
, FILE_OPEN_IF
);
1390 if (status
!= STATUS_BUFFER_TOO_SMALL
) break;
1391 RtlFreeHeap( GetProcessHeap(), 0, buffer
);
1393 RtlFreeUnicodeString( &nt_name
);
1394 if (status
&& status
!= STATUS_NO_SUCH_FILE
)
1396 RtlFreeHeap( GetProcessHeap(), 0, buffer
);
1397 RtlSetLastWin32ErrorAndNtStatusFromNtStatus( status
);
1403 static INT
AddFontToList(const WCHAR
*dos_name
, const char *unix_name
, void *font_data_ptr
,
1404 DWORD font_data_size
, DWORD flags
)
1406 DWORD face_index
= 0, num_faces
;
1408 WCHAR
*filename
= NULL
;
1410 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1411 assert(unix_name
|| !(flags
& ADDFONT_EXTERNAL_FONT
));
1413 #ifdef HAVE_CARBON_CARBON_H
1416 char **mac_list
= expand_mac_font(unix_name
);
1419 BOOL had_one
= FALSE
;
1421 for(cursor
= mac_list
; *cursor
; cursor
++)
1424 AddFontToList(NULL
, *cursor
, NULL
, 0, flags
);
1425 RtlFreeHeap(GetProcessHeap(), 0, *cursor
);
1427 RtlFreeHeap(GetProcessHeap(), 0, mac_list
);
1432 #endif /* HAVE_CARBON_CARBON_H */
1434 if (!dos_name
&& unix_name
) dos_name
= filename
= get_dos_file_name( unix_name
);
1437 ret
+= add_unix_face( unix_name
, dos_name
, font_data_ptr
, font_data_size
, face_index
, flags
, &num_faces
);
1438 while (num_faces
> ++face_index
);
1440 RtlFreeHeap( GetProcessHeap(), 0, filename
);
1444 /*************************************************************
1447 static INT CDECL
freetype_add_font( const WCHAR
*file
, DWORD flags
)
1450 char *unixname
= get_unix_file_name( file
);
1454 ret
= AddFontToList( file
, unixname
, NULL
, 0, flags
);
1455 RtlFreeHeap( GetProcessHeap(), 0, unixname
);
1460 /*************************************************************
1461 * freetype_add_mem_font
1463 static INT CDECL
freetype_add_mem_font( void *ptr
, SIZE_T size
, DWORD flags
)
1465 return AddFontToList( NULL
, NULL
, ptr
, size
, flags
);
1469 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
1472 struct dirent
*dent
;
1473 char path
[MAX_PATH
];
1475 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
1477 dir
= opendir(dirname
);
1479 WARN("Can't open directory %s\n", debugstr_a(dirname
));
1482 while((dent
= readdir(dir
)) != NULL
) {
1483 struct stat statbuf
;
1485 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
1488 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
1490 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
1492 if(stat(path
, &statbuf
) == -1)
1494 WARN("Can't stat %s\n", debugstr_a(path
));
1497 if(S_ISDIR(statbuf
.st_mode
))
1498 ReadFontDir(path
, external_fonts
);
1501 DWORD addfont_flags
= 0;
1502 if(external_fonts
) addfont_flags
|= ADDFONT_EXTERNAL_FONT
;
1503 AddFontToList(NULL
, path
, NULL
, 0, addfont_flags
);
1511 #ifdef SONAME_LIBFONTCONFIG
1513 static BOOL fontconfig_enabled
;
1514 static FcPattern
*pattern_serif
;
1515 static FcPattern
*pattern_fixed
;
1516 static FcPattern
*pattern_sans
;
1518 static UINT
parse_aa_pattern( FcPattern
*pattern
)
1524 if (pFcPatternGetBool( pattern
, FC_ANTIALIAS
, 0, &antialias
) == FcResultMatch
)
1525 aa_flags
= antialias
? GGO_GRAY4_BITMAP
: GGO_BITMAP
;
1527 if (pFcPatternGetInteger( pattern
, FC_RGBA
, 0, &rgba
) == FcResultMatch
)
1531 case FC_RGBA_RGB
: aa_flags
= WINE_GGO_HRGB_BITMAP
; break;
1532 case FC_RGBA_BGR
: aa_flags
= WINE_GGO_HBGR_BITMAP
; break;
1533 case FC_RGBA_VRGB
: aa_flags
= WINE_GGO_VRGB_BITMAP
; break;
1534 case FC_RGBA_VBGR
: aa_flags
= WINE_GGO_VBGR_BITMAP
; break;
1535 case FC_RGBA_NONE
: aa_flags
= aa_flags
? aa_flags
: GGO_GRAY4_BITMAP
; break;
1541 static FcPattern
*create_family_pattern( const char *name
, FcPattern
**cached
)
1543 FcPattern
*ret
= NULL
, *tmp
, *pattern
;
1545 if (*cached
) return *cached
;
1546 pattern
= pFcPatternCreate();
1547 pFcPatternAddString( pattern
, FC_FAMILY
, (const FcChar8
*)name
);
1548 pFcPatternAddString( pattern
, FC_NAMELANG
, (const FcChar8
*)"en-us" );
1549 pFcPatternAddString( pattern
, FC_PRGNAME
, (const FcChar8
*)"wine" );
1550 pFcConfigSubstitute( NULL
, pattern
, FcMatchPattern
);
1551 pFcDefaultSubstitute( pattern
);
1552 tmp
= pFcFontMatch( NULL
, pattern
, &result
);
1553 pFcPatternDestroy( pattern
);
1554 if (result
!= FcResultMatch
) pFcPatternDestroy( tmp
);
1555 else if ((ret
= InterlockedCompareExchangePointer( (void **)cached
, tmp
, NULL
))) pFcPatternDestroy( tmp
);
1560 static void fontconfig_add_font( FcPattern
*pattern
, DWORD flags
)
1562 const char *unix_name
, *format
;
1568 TRACE( "(%p %#x)\n", pattern
, flags
);
1570 if (pFcPatternGetString( pattern
, FC_FILE
, 0, (FcChar8
**)&unix_name
) != FcResultMatch
)
1573 if (pFcPatternGetBool( pattern
, FC_SCALABLE
, 0, &scalable
) != FcResultMatch
)
1576 if (pFcPatternGetString( pattern
, FC_FONTFORMAT
, 0, (FcChar8
**)&format
) != FcResultMatch
)
1578 TRACE( "ignoring unknown font format %s\n", debugstr_a(unix_name
) );
1582 if (!strcmp( format
, "Type 1" ))
1584 TRACE( "ignoring Type 1 font %s\n", debugstr_a(unix_name
) );
1588 if (!scalable
&& !(flags
& ADDFONT_ALLOW_BITMAP
))
1590 TRACE( "ignoring non-scalable font %s\n", debugstr_a(unix_name
) );
1594 if (!(aa_flags
= parse_aa_pattern( pattern
))) aa_flags
= default_aa_flags
;
1595 flags
|= ADDFONT_AA_FLAGS(aa_flags
);
1597 if (pFcPatternGetInteger( pattern
, FC_INDEX
, 0, &face_index
) != FcResultMatch
)
1600 dos_name
= get_dos_file_name( unix_name
);
1601 add_unix_face( unix_name
, dos_name
, NULL
, 0, face_index
, flags
, NULL
);
1602 RtlFreeHeap( GetProcessHeap(), 0, dos_name
);
1605 static void init_fontconfig(void)
1607 void *fc_handle
= dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
);
1611 TRACE("Wine cannot find the fontconfig library (%s).\n", SONAME_LIBFONTCONFIG
);
1615 #define LOAD_FUNCPTR(f) if((p##f = dlsym(fc_handle, #f)) == NULL){WARN("Can't find symbol %s\n", #f); return;}
1616 LOAD_FUNCPTR(FcConfigSubstitute
);
1617 LOAD_FUNCPTR(FcDefaultSubstitute
);
1618 LOAD_FUNCPTR(FcFontList
);
1619 LOAD_FUNCPTR(FcFontMatch
);
1620 LOAD_FUNCPTR(FcFontSetDestroy
);
1621 LOAD_FUNCPTR(FcInit
);
1622 LOAD_FUNCPTR(FcPatternAddString
);
1623 LOAD_FUNCPTR(FcPatternCreate
);
1624 LOAD_FUNCPTR(FcPatternDestroy
);
1625 LOAD_FUNCPTR(FcPatternGetBool
);
1626 LOAD_FUNCPTR(FcPatternGetInteger
);
1627 LOAD_FUNCPTR(FcPatternGetString
);
1628 LOAD_FUNCPTR(FcConfigGetFontDirs
);
1629 LOAD_FUNCPTR(FcConfigGetCurrent
);
1630 LOAD_FUNCPTR(FcCacheCopySet
);
1631 LOAD_FUNCPTR(FcCacheNumSubdir
);
1632 LOAD_FUNCPTR(FcCacheSubdir
);
1633 LOAD_FUNCPTR(FcDirCacheRead
);
1634 LOAD_FUNCPTR(FcDirCacheUnload
);
1635 LOAD_FUNCPTR(FcStrListCreate
);
1636 LOAD_FUNCPTR(FcStrListDone
);
1637 LOAD_FUNCPTR(FcStrListNext
);
1638 LOAD_FUNCPTR(FcStrSetAdd
);
1639 LOAD_FUNCPTR(FcStrSetCreate
);
1640 LOAD_FUNCPTR(FcStrSetDestroy
);
1641 LOAD_FUNCPTR(FcStrSetMember
);
1646 FcPattern
*pattern
= pFcPatternCreate();
1647 pFcConfigSubstitute( NULL
, pattern
, FcMatchFont
);
1648 default_aa_flags
= parse_aa_pattern( pattern
);
1649 pFcPatternDestroy( pattern
);
1651 if (!default_aa_flags
)
1653 FcPattern
*pattern
= pFcPatternCreate();
1654 pFcConfigSubstitute( NULL
, pattern
, FcMatchPattern
);
1655 default_aa_flags
= parse_aa_pattern( pattern
);
1656 pFcPatternDestroy( pattern
);
1659 TRACE( "enabled, default flags = %x\n", default_aa_flags
);
1660 fontconfig_enabled
= TRUE
;
1664 static void fontconfig_add_fonts_from_dir_list( FcConfig
*config
, FcStrList
*dir_list
, FcStrSet
*done_set
, DWORD flags
)
1667 FcFontSet
*font_set
= NULL
;
1668 FcStrList
*subdir_list
= NULL
;
1669 FcStrSet
*subdir_set
= NULL
;
1670 FcCache
*cache
= NULL
;
1673 TRACE( "(%p %p %p %#x)\n", config
, dir_list
, done_set
, flags
);
1675 while ((dir
= pFcStrListNext( dir_list
)))
1677 if (pFcStrSetMember( done_set
, dir
)) continue;
1679 TRACE( "adding fonts from %s\n", dir
);
1680 if (!(cache
= pFcDirCacheRead( dir
, FcFalse
, config
))) continue;
1682 if (!(font_set
= pFcCacheCopySet( cache
))) goto done
;
1683 for (i
= 0; i
< font_set
->nfont
; i
++)
1684 fontconfig_add_font( font_set
->fonts
[i
], flags
);
1685 pFcFontSetDestroy( font_set
);
1688 if (!(subdir_set
= pFcStrSetCreate())) goto done
;
1689 for (i
= 0; i
< pFcCacheNumSubdir( cache
); i
++)
1690 pFcStrSetAdd( subdir_set
, pFcCacheSubdir( cache
, i
) );
1691 pFcDirCacheUnload( cache
);
1694 if (!(subdir_list
= pFcStrListCreate( subdir_set
))) goto done
;
1695 pFcStrSetDestroy( subdir_set
);
1698 pFcStrSetAdd( done_set
, dir
);
1699 fontconfig_add_fonts_from_dir_list( config
, subdir_list
, done_set
, flags
);
1700 pFcStrListDone( subdir_list
);
1705 if (subdir_set
) pFcStrSetDestroy( subdir_set
);
1706 if (cache
) pFcDirCacheUnload( cache
);
1709 static void load_fontconfig_fonts( void )
1711 FcStrList
*dir_list
= NULL
;
1712 FcStrSet
*done_set
= NULL
;
1715 if (!fontconfig_enabled
) return;
1716 if (!(config
= pFcConfigGetCurrent())) goto done
;
1717 if (!(done_set
= pFcStrSetCreate())) goto done
;
1718 if (!(dir_list
= pFcConfigGetFontDirs( config
))) goto done
;
1720 fontconfig_add_fonts_from_dir_list( config
, dir_list
, done_set
, ADDFONT_EXTERNAL_FONT
);
1723 if (dir_list
) pFcStrListDone( dir_list
);
1724 if (done_set
) pFcStrSetDestroy( done_set
);
1727 #elif defined(HAVE_CARBON_CARBON_H)
1729 static void load_mac_font_callback(const void *value
, void *context
)
1731 CFStringRef pathStr
= value
;
1735 len
= CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr
);
1736 path
= RtlAllocateHeap(GetProcessHeap(), 0, len
);
1737 if (path
&& CFStringGetFileSystemRepresentation(pathStr
, path
, len
))
1739 TRACE("font file %s\n", path
);
1740 AddFontToList(NULL
, path
, NULL
, 0, ADDFONT_EXTERNAL_FONT
);
1742 RtlFreeHeap(GetProcessHeap(), 0, path
);
1745 static void load_mac_fonts(void)
1747 CFStringRef removeDupesKey
;
1748 CFBooleanRef removeDupesValue
;
1749 CFDictionaryRef options
;
1750 CTFontCollectionRef col
;
1752 CFMutableSetRef paths
;
1755 removeDupesKey
= kCTFontCollectionRemoveDuplicatesOption
;
1756 removeDupesValue
= kCFBooleanTrue
;
1757 options
= CFDictionaryCreate(NULL
, (const void**)&removeDupesKey
, (const void**)&removeDupesValue
, 1,
1758 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1759 col
= CTFontCollectionCreateFromAvailableFonts(options
);
1760 if (options
) CFRelease(options
);
1763 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
1767 descs
= CTFontCollectionCreateMatchingFontDescriptors(col
);
1771 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
1775 paths
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
1778 WARN("CFSetCreateMutable failed\n");
1783 for (i
= 0; i
< CFArrayGetCount(descs
); i
++)
1785 CTFontDescriptorRef desc
;
1790 desc
= CFArrayGetValueAtIndex(descs
, i
);
1792 #if defined(MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
1793 url
= CTFontDescriptorCopyAttribute(desc
, kCTFontURLAttribute
);
1795 /* CTFontDescriptor doesn't support kCTFontURLAttribute prior to 10.6, so
1796 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
1803 font
= CTFontCreateWithFontDescriptor(desc
, 0, NULL
);
1804 if (!font
) continue;
1806 atsFont
= CTFontGetPlatformFont(font
, NULL
);
1813 status
= ATSFontGetFileReference(atsFont
, &fsref
);
1815 if (status
!= noErr
) continue;
1817 url
= CFURLCreateFromFSRef(NULL
, &fsref
);
1822 ext
= CFURLCopyPathExtension(url
);
1825 BOOL skip
= (CFStringCompare(ext
, CFSTR("pfa"), kCFCompareCaseInsensitive
) == kCFCompareEqualTo
||
1826 CFStringCompare(ext
, CFSTR("pfb"), kCFCompareCaseInsensitive
) == kCFCompareEqualTo
);
1835 path
= CFURLCopyFileSystemPath(url
, kCFURLPOSIXPathStyle
);
1837 if (!path
) continue;
1839 CFSetAddValue(paths
, path
);
1845 CFSetApplyFunction(paths
, load_mac_font_callback
, NULL
);
1852 static BOOL
init_freetype(void)
1854 ft_handle
= dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
);
1857 "Wine cannot find the FreeType font library. To enable Wine to\n"
1858 "use TrueType fonts please install a version of FreeType greater than\n"
1859 "or equal to 2.0.5.\n"
1860 "http://www.freetype.org\n");
1864 #define LOAD_FUNCPTR(f) if((p##f = dlsym(ft_handle, #f)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
1866 LOAD_FUNCPTR(FT_Done_Face
)
1867 LOAD_FUNCPTR(FT_Get_Char_Index
)
1868 LOAD_FUNCPTR(FT_Get_First_Char
)
1869 LOAD_FUNCPTR(FT_Get_Next_Char
)
1870 LOAD_FUNCPTR(FT_Get_Sfnt_Name
)
1871 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count
)
1872 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
1873 LOAD_FUNCPTR(FT_Get_WinFNT_Header
)
1874 LOAD_FUNCPTR(FT_Init_FreeType
)
1875 LOAD_FUNCPTR(FT_Library_Version
)
1876 LOAD_FUNCPTR(FT_Load_Glyph
)
1877 LOAD_FUNCPTR(FT_Load_Sfnt_Table
)
1878 LOAD_FUNCPTR(FT_Matrix_Multiply
)
1879 LOAD_FUNCPTR(FT_MulDiv
)
1880 #ifndef FT_MULFIX_INLINED
1881 LOAD_FUNCPTR(FT_MulFix
)
1883 LOAD_FUNCPTR(FT_New_Face
)
1884 LOAD_FUNCPTR(FT_New_Memory_Face
)
1885 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
1886 LOAD_FUNCPTR(FT_Outline_Get_CBox
)
1887 LOAD_FUNCPTR(FT_Outline_Transform
)
1888 LOAD_FUNCPTR(FT_Outline_Translate
)
1889 LOAD_FUNCPTR(FT_Render_Glyph
)
1890 LOAD_FUNCPTR(FT_Set_Charmap
)
1891 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
1892 LOAD_FUNCPTR(FT_Vector_Length
)
1893 LOAD_FUNCPTR(FT_Vector_Transform
)
1894 LOAD_FUNCPTR(FT_Vector_Unit
)
1896 /* Don't warn if these ones are missing */
1897 pFT_Outline_Embolden
= dlsym(ft_handle
, "FT_Outline_Embolden");
1898 pFT_Get_TrueType_Engine_Type
= dlsym(ft_handle
, "FT_Get_TrueType_Engine_Type");
1899 #ifdef FT_LCD_FILTER_H
1900 pFT_Library_SetLcdFilter
= dlsym(ft_handle
, "FT_Library_SetLcdFilter");
1902 pFT_Property_Set
= dlsym(ft_handle
, "FT_Property_Set");
1904 if(pFT_Init_FreeType(&library
) != 0) {
1905 ERR("Can't init FreeType library\n");
1910 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
1912 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
1913 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
1914 ((FT_Version
.minor
<< 8) & 0x00ff00) |
1915 ((FT_Version
.patch
) & 0x0000ff);
1917 /* In FreeType < 2.8.1 v40's FT_LOAD_TARGET_MONO has broken advance widths. */
1918 if (pFT_Property_Set
&& FT_SimpleVersion
< FT_VERSION_VALUE(2, 8, 1))
1920 FT_UInt interpreter_version
= 35;
1921 pFT_Property_Set( library
, "truetype", "interpreter-version", &interpreter_version
);
1924 #ifdef FT_LCD_FILTER_H
1925 if (pFT_Library_SetLcdFilter
)
1926 pFT_Library_SetLcdFilter( library
, FT_LCD_FILTER_DEFAULT
);
1933 "Wine cannot find certain functions that it needs inside the FreeType\n"
1934 "font library. To enable Wine to use TrueType fonts please upgrade\n"
1935 "FreeType to at least version 2.1.4.\n"
1936 "http://www.freetype.org\n");
1942 /*************************************************************
1943 * freetype_load_fonts
1945 static void CDECL
freetype_load_fonts(void)
1947 #ifdef SONAME_LIBFONTCONFIG
1948 load_fontconfig_fonts();
1949 #elif defined(HAVE_CARBON_CARBON_H)
1951 #elif defined(__ANDROID__)
1952 ReadFontDir("/system/fonts", TRUE
);
1956 /* Some fonts have large usWinDescent values, as a result of storing signed short
1957 in unsigned field. That's probably caused by sTypoDescent vs usWinDescent confusion in
1958 some font generation tools. */
1959 static inline USHORT
get_fixed_windescent(USHORT windescent
)
1961 return abs((SHORT
)windescent
);
1964 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
1967 TT_HoriHeader
*pHori
;
1970 const LONG MAX_PPEM
= (1 << 16) - 1;
1972 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
1973 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
1975 if(height
== 0) height
= 16;
1977 /* Calc. height of EM square:
1979 * For +ve lfHeight we have
1980 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
1981 * Re-arranging gives:
1982 * ppem = units_per_em * lfheight / (winAscent + winDescent)
1984 * For -ve lfHeight we have
1986 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
1987 * with il = winAscent + winDescent - units_per_em]
1992 USHORT windescent
= get_fixed_windescent(pOS2
->usWinDescent
);
1993 if(pOS2
->usWinAscent
+ windescent
== 0)
1994 ppem
= pFT_MulDiv(ft_face
->units_per_EM
, height
, pHori
->Ascender
- pHori
->Descender
);
1996 ppem
= pFT_MulDiv(ft_face
->units_per_EM
, height
, pOS2
->usWinAscent
+ windescent
);
1997 if(ppem
> MAX_PPEM
) {
1998 WARN("Ignoring too large height %d, ppem %d\n", height
, ppem
);
2002 else if(height
>= -MAX_PPEM
)
2005 WARN("Ignoring too large height %d\n", height
);
2012 static struct font_mapping
*map_font_file( const char *name
)
2014 struct font_mapping
*mapping
;
2018 if ((fd
= open( name
, O_RDONLY
)) == -1) return NULL
;
2019 if (fstat( fd
, &st
) == -1) goto error
;
2021 LIST_FOR_EACH_ENTRY( mapping
, &mappings_list
, struct font_mapping
, entry
)
2023 if (mapping
->dev
== st
.st_dev
&& mapping
->ino
== st
.st_ino
)
2025 mapping
->refcount
++;
2030 if (!(mapping
= RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*mapping
) )))
2033 mapping
->data
= mmap( NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0 );
2036 if (mapping
->data
== MAP_FAILED
)
2038 RtlFreeHeap( GetProcessHeap(), 0, mapping
);
2041 mapping
->refcount
= 1;
2042 mapping
->dev
= st
.st_dev
;
2043 mapping
->ino
= st
.st_ino
;
2044 mapping
->size
= st
.st_size
;
2045 list_add_tail( &mappings_list
, &mapping
->entry
);
2053 static void unmap_font_file( struct font_mapping
*mapping
)
2055 if (!--mapping
->refcount
)
2057 list_remove( &mapping
->entry
);
2058 munmap( mapping
->data
, mapping
->size
);
2059 RtlFreeHeap( GetProcessHeap(), 0, mapping
);
2063 static LONG
load_VDMX(struct gdi_font
*font
, LONG height
);
2065 /*************************************************************
2066 * freetype_destroy_font
2068 static void CDECL
freetype_destroy_font( struct gdi_font
*font
)
2070 struct font_private_data
*data
= font
->private;
2072 if (data
->ft_face
) pFT_Done_Face( data
->ft_face
);
2073 if (data
->mapping
) unmap_font_file( data
->mapping
);
2074 RtlFreeHeap( GetProcessHeap(), 0, data
);
2077 /*************************************************************
2078 * freetype_get_font_data
2080 static DWORD CDECL
freetype_get_font_data( struct gdi_font
*font
, DWORD table
, DWORD offset
,
2081 void *buf
, DWORD cbData
)
2083 FT_Face ft_face
= get_ft_face( font
);
2087 if (!FT_IS_SFNT(ft_face
)) return GDI_ERROR
;
2094 /* if font is a member of TTC, 'ttcf' tag allows reading from beginning of TTC file,
2095 0 tag means to read from start of collection member data. */
2096 if (font
->ttc_item_offset
)
2098 if (table
== MS_TTCF_TAG
)
2100 else if (table
== 0)
2101 offset
+= font
->ttc_item_offset
;
2104 /* make sure value of len is the value freetype says it needs */
2107 FT_ULong needed
= 0;
2108 err
= pFT_Load_Sfnt_Table(ft_face
, RtlUlongByteSwap(table
), offset
, NULL
, &needed
);
2109 if( !err
&& needed
< len
) len
= needed
;
2111 err
= pFT_Load_Sfnt_Table(ft_face
, RtlUlongByteSwap(table
), offset
, buf
, &len
);
2114 TRACE("Can't find table %s\n", debugstr_an((char*)&table
, 4));
2120 /*************************************************************
2123 * load the vdmx entry for the specified height
2153 static LONG
load_VDMX(struct gdi_font
*font
, LONG height
)
2157 BYTE devXRatio
, devYRatio
;
2158 USHORT numRecs
, numRatios
;
2159 DWORD result
, offset
= -1;
2163 result
= freetype_get_font_data(font
, MS_VDMX_TAG
, 0, &hdr
, sizeof(hdr
));
2165 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
2168 /* FIXME: need the real device aspect ratio */
2172 numRecs
= GET_BE_WORD(hdr
.numRecs
);
2173 numRatios
= GET_BE_WORD(hdr
.numRatios
);
2175 TRACE("version = %d numRecs = %d numRatios = %d\n", GET_BE_WORD(hdr
.version
), numRecs
, numRatios
);
2176 for(i
= 0; i
< numRatios
; i
++) {
2179 offset
= sizeof(hdr
) + (i
* sizeof(Ratios
));
2180 freetype_get_font_data(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
2183 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
2185 if (!ratio
.bCharSet
) continue;
2187 if((ratio
.xRatio
== 0 &&
2188 ratio
.yStartRatio
== 0 &&
2189 ratio
.yEndRatio
== 0) ||
2190 (devXRatio
== ratio
.xRatio
&&
2191 devYRatio
>= ratio
.yStartRatio
&&
2192 devYRatio
<= ratio
.yEndRatio
))
2196 offset
= sizeof(hdr
) + numRatios
* sizeof(ratio
) + i
* sizeof(group_offset
);
2197 freetype_get_font_data(font
, MS_VDMX_TAG
, offset
, &group_offset
, sizeof(group_offset
));
2198 offset
= GET_BE_WORD(group_offset
);
2203 if(offset
== -1) return 0;
2205 if(freetype_get_font_data(font
, MS_VDMX_TAG
, offset
, &group
, sizeof(group
)) != GDI_ERROR
) {
2207 BYTE startsz
, endsz
;
2210 recs
= GET_BE_WORD(group
.recs
);
2211 startsz
= group
.startsz
;
2212 endsz
= group
.endsz
;
2214 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
2216 vTable
= RtlAllocateHeap(GetProcessHeap(), 0, recs
* sizeof(VDMX_vTable
));
2217 result
= freetype_get_font_data(font
, MS_VDMX_TAG
, offset
+ sizeof(group
), vTable
, recs
* sizeof(VDMX_vTable
));
2218 if(result
== GDI_ERROR
) {
2219 FIXME("Failed to retrieve vTable\n");
2224 for(i
= 0; i
< recs
; i
++) {
2225 SHORT yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
2226 SHORT yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
2227 ppem
= GET_BE_WORD(vTable
[i
* 3]);
2229 if(yMax
+ -yMin
== height
) {
2232 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
2235 if(yMax
+ -yMin
> height
) {
2238 goto end
; /* failed */
2240 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
2241 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
2242 ppem
= GET_BE_WORD(vTable
[i
* 3]);
2243 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
2249 TRACE("ppem not found for height %d\n", height
);
2253 if(ppem
< startsz
|| ppem
> endsz
)
2259 for(i
= 0; i
< recs
; i
++) {
2261 yPelHeight
= GET_BE_WORD(vTable
[i
* 3]);
2263 if(yPelHeight
> ppem
)
2269 if(yPelHeight
== ppem
) {
2270 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
2271 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
2272 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem
, font
->yMax
, font
->yMin
);
2278 RtlFreeHeap(GetProcessHeap(), 0, vTable
);
2284 static BOOL
select_charmap(FT_Face ft_face
, FT_Encoding encoding
)
2286 FT_Error ft_err
= FT_Err_Invalid_CharMap_Handle
;
2287 FT_CharMap cmap0
, cmap1
, cmap2
, cmap3
, cmap_def
;
2290 cmap0
= cmap1
= cmap2
= cmap3
= cmap_def
= NULL
;
2292 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
2294 if (ft_face
->charmaps
[i
]->encoding
== encoding
)
2296 TRACE("found cmap with platform_id %u, encoding_id %u\n",
2297 ft_face
->charmaps
[i
]->platform_id
, ft_face
->charmaps
[i
]->encoding_id
);
2299 switch (ft_face
->charmaps
[i
]->platform_id
)
2302 cmap_def
= ft_face
->charmaps
[i
];
2304 case 0: /* Apple Unicode */
2305 cmap0
= ft_face
->charmaps
[i
];
2307 case 1: /* Macintosh */
2308 cmap1
= ft_face
->charmaps
[i
];
2311 cmap2
= ft_face
->charmaps
[i
];
2313 case 3: /* Microsoft */
2314 cmap3
= ft_face
->charmaps
[i
];
2319 if (cmap3
) /* prefer Microsoft cmap table */
2320 ft_err
= pFT_Set_Charmap(ft_face
, cmap3
);
2322 ft_err
= pFT_Set_Charmap(ft_face
, cmap1
);
2324 ft_err
= pFT_Set_Charmap(ft_face
, cmap2
);
2326 ft_err
= pFT_Set_Charmap(ft_face
, cmap0
);
2328 ft_err
= pFT_Set_Charmap(ft_face
, cmap_def
);
2331 return ft_err
== FT_Err_Ok
;
2335 static FT_Encoding
pick_charmap( FT_Face face
, int charset
)
2337 static const FT_Encoding regular_order
[] = { FT_ENCODING_UNICODE
, FT_ENCODING_APPLE_ROMAN
, FT_ENCODING_MS_SYMBOL
, 0 };
2338 static const FT_Encoding symbol_order
[] = { FT_ENCODING_MS_SYMBOL
, FT_ENCODING_UNICODE
, FT_ENCODING_APPLE_ROMAN
, 0 };
2339 const FT_Encoding
*encs
= regular_order
;
2341 if (charset
== SYMBOL_CHARSET
) encs
= symbol_order
;
2345 if (select_charmap( face
, *encs
)) break;
2349 if (!face
->charmap
&& face
->num_charmaps
)
2351 if (!pFT_Set_Charmap(face
, face
->charmaps
[0]))
2352 return face
->charmap
->encoding
;
2358 static BOOL
get_gasp_flags( struct gdi_font
*font
, WORD
*flags
)
2360 FT_Face ft_face
= get_ft_face( font
);
2362 WORD buf
[16]; /* Enough for seven ranges before we need to alloc */
2363 WORD
*alloced
= NULL
, *ptr
= buf
;
2364 WORD num_recs
, version
;
2368 size
= freetype_get_font_data( font
, MS_GASP_TAG
, 0, NULL
, 0 );
2369 if (size
== GDI_ERROR
) return FALSE
;
2370 if (size
< 4 * sizeof(WORD
)) return FALSE
;
2371 if (size
> sizeof(buf
))
2373 ptr
= alloced
= RtlAllocateHeap( GetProcessHeap(), 0, size
);
2374 if (!ptr
) return FALSE
;
2377 freetype_get_font_data( font
, MS_GASP_TAG
, 0, ptr
, size
);
2379 version
= GET_BE_WORD( *ptr
++ );
2380 num_recs
= GET_BE_WORD( *ptr
++ );
2382 if (version
> 1 || size
< (num_recs
* 2 + 2) * sizeof(WORD
))
2384 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version
, size
, num_recs
);
2390 *flags
= GET_BE_WORD( *(ptr
+ 1) );
2391 if (ft_face
->size
->metrics
.y_ppem
<= GET_BE_WORD( *ptr
)) break;
2394 TRACE( "got flags %04x for ppem %d\n", *flags
, ft_face
->size
->metrics
.y_ppem
);
2398 RtlFreeHeap( GetProcessHeap(), 0, alloced
);
2402 /*************************************************************
2403 * fontconfig_enum_family_fallbacks
2405 static BOOL CDECL
fontconfig_enum_family_fallbacks( DWORD pitch_and_family
, int index
,
2406 WCHAR buffer
[LF_FACESIZE
] )
2408 #ifdef SONAME_LIBFONTCONFIG
2413 if ((pitch_and_family
& FIXED_PITCH
) || (pitch_and_family
& 0xf0) == FF_MODERN
) pat
= create_family_pattern( "monospace", &pattern_fixed
);
2414 else if ((pitch_and_family
& 0xf0) == FF_ROMAN
) pat
= create_family_pattern( "serif", &pattern_serif
);
2415 else pat
= create_family_pattern( "sans", &pattern_sans
);
2417 if (!pat
) return FALSE
;
2418 if (pFcPatternGetString( pat
, FC_FAMILY
, index
, (FcChar8
**)&str
) != FcResultMatch
) return FALSE
;
2419 RtlUTF8ToUnicodeN( buffer
, (LF_FACESIZE
- 1) * sizeof(WCHAR
), &len
, str
, strlen(str
) );
2420 buffer
[len
/ sizeof(WCHAR
)] = 0;
2426 static DWORD
get_ttc_offset( FT_Face ft_face
, UINT face_index
)
2429 DWORD header
, offset
;
2431 /* see if it's a TTC */
2432 len
= sizeof(header
);
2433 if (pFT_Load_Sfnt_Table( ft_face
, 0, 0, (void *)&header
, &len
)) return 0;
2434 if (header
!= MS_TTCF_TAG
) return 0;
2436 len
= sizeof(offset
);
2437 if (pFT_Load_Sfnt_Table( ft_face
, 0, (3 + face_index
) * sizeof(DWORD
), (void *)&offset
, &len
))
2440 return GET_BE_DWORD( offset
);
2443 /*************************************************************
2444 * freetype_load_font
2446 static BOOL CDECL
freetype_load_font( struct gdi_font
*font
)
2448 struct font_private_data
*data
;
2449 INT width
= 0, height
;
2454 if (!(data
= RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*data
) ))) return FALSE
;
2455 font
->private = data
;
2459 char *filename
= get_unix_file_name( font
->file
);
2460 data
->mapping
= map_font_file( filename
);
2461 RtlFreeHeap( GetProcessHeap(), 0, filename
);
2464 WARN("failed to map %s\n", debugstr_w(font
->file
));
2467 data_ptr
= data
->mapping
->data
;
2468 data_size
= data
->mapping
->size
;
2472 data_ptr
= font
->data_ptr
;
2473 data_size
= font
->data_size
;
2476 if (pFT_New_Memory_Face( library
, data_ptr
, data_size
, font
->face_index
, &ft_face
)) return FALSE
;
2478 data
->ft_face
= ft_face
;
2479 font
->scalable
= FT_IS_SCALABLE( ft_face
);
2480 if (!font
->fs
.fsCsb
[0]) get_fontsig( ft_face
, &font
->fs
);
2481 if (!font
->ntmFlags
) font
->ntmFlags
= get_ntm_flags( ft_face
);
2482 if (!font
->aa_flags
) font
->aa_flags
= ADDFONT_AA_FLAGS( default_aa_flags
);
2483 if (!font
->otm
.otmpFamilyName
)
2485 font
->otm
.otmpFamilyName
= (char *)ft_face_get_family_name( ft_face
, system_lcid
);
2486 font
->otm
.otmpStyleName
= (char *)ft_face_get_style_name( ft_face
, system_lcid
);
2487 font
->otm
.otmpFaceName
= (char *)ft_face_get_full_name( ft_face
, system_lcid
);
2492 /* load the VDMX table if we have one */
2493 font
->ppem
= load_VDMX( font
, font
->lf
.lfHeight
);
2494 if (font
->ppem
== 0) font
->ppem
= calc_ppem_for_height( ft_face
, font
->lf
.lfHeight
);
2495 TRACE( "height %d => ppem %d\n", font
->lf
.lfHeight
, font
->ppem
);
2496 height
= font
->ppem
;
2497 font
->ttc_item_offset
= get_ttc_offset( ft_face
, font
->face_index
);
2498 font
->otm
.otmEMSquare
= ft_face
->units_per_EM
;
2502 struct bitmap_font_size size
;
2504 get_bitmap_size( ft_face
, &size
);
2505 width
= size
.x_ppem
>> 6;
2506 height
= size
.y_ppem
>> 6;
2507 font
->ppem
= height
;
2510 pFT_Set_Pixel_Sizes( ft_face
, width
, height
);
2511 pick_charmap( ft_face
, font
->charset
);
2516 /*************************************************************
2517 * freetype_get_aa_flags
2519 static UINT CDECL
freetype_get_aa_flags( struct gdi_font
*font
, UINT aa_flags
, BOOL antialias_fakes
)
2521 /* fixup the antialiasing flags for that font */
2524 case WINE_GGO_HRGB_BITMAP
:
2525 case WINE_GGO_HBGR_BITMAP
:
2526 case WINE_GGO_VRGB_BITMAP
:
2527 case WINE_GGO_VBGR_BITMAP
:
2528 if (is_subpixel_rendering_enabled()) break;
2529 aa_flags
= GGO_GRAY4_BITMAP
;
2531 case GGO_GRAY2_BITMAP
:
2532 case GGO_GRAY4_BITMAP
:
2533 case GGO_GRAY8_BITMAP
:
2534 case WINE_GGO_GRAY16_BITMAP
:
2535 if ((!antialias_fakes
|| (!font
->fake_bold
&& !font
->fake_italic
)) && is_hinting_enabled())
2538 if (get_gasp_flags( font
, &gasp_flags
) && !(gasp_flags
& GASP_DOGRAY
))
2540 TRACE( "font %s %d aa disabled by GASP\n",
2541 debugstr_w(font
->lf
.lfFaceName
), font
->lf
.lfHeight
);
2542 aa_flags
= GGO_BITMAP
;
2549 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
2551 pt
->x
.value
= vec
->x
>> 6;
2552 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
2553 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
2554 pt
->y
.value
= vec
->y
>> 6;
2555 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
2556 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
2559 static FT_UInt
get_glyph_index_symbol( struct gdi_font
*font
, UINT glyph
)
2561 FT_Face ft_face
= get_ft_face( font
);
2564 if (glyph
< 0x100) glyph
+= 0xf000;
2565 /* there are a number of old pre-Unicode "broken" TTFs, which
2566 do have symbols at U+00XX instead of U+f0XX */
2567 if (!(ret
= pFT_Get_Char_Index(ft_face
, glyph
)))
2568 ret
= pFT_Get_Char_Index(ft_face
, glyph
- 0xf000);
2573 /*************************************************************
2574 * freetype_get_glyph_index
2576 static BOOL CDECL
freetype_get_glyph_index( struct gdi_font
*font
, UINT
*glyph
, BOOL use_encoding
)
2578 FT_Face ft_face
= get_ft_face( font
);
2580 if (!use_encoding
^ (ft_face
->charmap
->encoding
== FT_ENCODING_NONE
)) return FALSE
;
2582 if (ft_face
->charmap
->encoding
== FT_ENCODING_MS_SYMBOL
)
2584 if (!(*glyph
= get_glyph_index_symbol( font
, *glyph
)))
2590 RtlUnicodeToMultiByteN( &ch
, 1, &len
, &wc
, sizeof(wc
) );
2591 if (len
) *glyph
= get_glyph_index_symbol( font
, (unsigned char)ch
);
2595 *glyph
= pFT_Get_Char_Index( ft_face
, *glyph
);
2599 /*************************************************************
2600 * freetype_get_default_glyph
2602 static UINT CDECL
freetype_get_default_glyph( struct gdi_font
*font
)
2604 FT_Face ft_face
= get_ft_face( font
);
2605 FT_WinFNT_HeaderRec winfnt
;
2608 if ((pOS2
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_os2
)))
2610 UINT glyph
= pOS2
->usDefaultChar
;
2611 if (glyph
) freetype_get_glyph_index( font
, &glyph
, TRUE
);
2614 if (!pFT_Get_WinFNT_Header( ft_face
, &winfnt
)) return winfnt
.default_char
+ winfnt
.first_char
;
2619 static inline BOOL
is_identity_FMAT2(const FMAT2
*matrix
)
2621 static const FMAT2 identity
= { 1.0, 0.0, 0.0, 1.0 };
2622 return !memcmp(matrix
, &identity
, sizeof(FMAT2
));
2625 static inline FT_Vector
normalize_vector(FT_Vector
*vec
)
2629 len
= pFT_Vector_Length(vec
);
2631 out
.x
= (vec
->x
<< 6) / len
;
2632 out
.y
= (vec
->y
<< 6) / len
;
2639 /* get_glyph_outline() glyph transform matrices index */
2647 static FT_Matrix
*get_transform_matrices( struct gdi_font
*font
, BOOL vertical
, const MAT2
*user_transform
,
2648 FT_Matrix matrices
[3] )
2650 static const FT_Matrix identity_mat
= { (1 << 16), 0, 0, (1 << 16) };
2651 BOOL needs_transform
= FALSE
;
2655 matrices
[matrix_unrotated
] = identity_mat
;
2657 /* Scaling factor */
2660 if (!freetype_set_outline_text_metrics( font
)) freetype_set_bitmap_text_metrics( font
);
2661 width_ratio
= (double)font
->aveWidth
;
2662 width_ratio
/= (double)font
->otm
.otmTextMetrics
.tmAveCharWidth
;
2665 width_ratio
= font
->scale_y
;
2667 /* Scaling transform */
2668 if (width_ratio
!= 1.0 || font
->scale_y
!= 1)
2670 FT_Matrix scale_mat
;
2671 scale_mat
.xx
= FT_FixedFromFloat( width_ratio
);
2674 scale_mat
.yy
= font
->scale_y
<< 16;
2676 pFT_Matrix_Multiply( &scale_mat
, &matrices
[matrix_unrotated
] );
2677 needs_transform
= TRUE
;
2680 /* Slant transform */
2681 if (font
->fake_italic
)
2683 FT_Matrix slant_mat
;
2684 slant_mat
.xx
= (1 << 16);
2685 slant_mat
.xy
= (1 << 16) >> 2;
2687 slant_mat
.yy
= (1 << 16);
2689 pFT_Matrix_Multiply( &slant_mat
, &matrices
[matrix_unrotated
] );
2690 needs_transform
= TRUE
;
2693 /* Rotation transform */
2694 matrices
[matrix_hori
] = matrices
[matrix_unrotated
];
2695 if (font
->scalable
&& font
->lf
.lfOrientation
% 3600)
2697 FT_Matrix rotation_mat
;
2700 pFT_Vector_Unit( &angle
, pFT_MulDiv( 1 << 16, font
->lf
.lfOrientation
, 10 ) );
2701 rotation_mat
.xx
= angle
.x
;
2702 rotation_mat
.xy
= -angle
.y
;
2703 rotation_mat
.yx
= angle
.y
;
2704 rotation_mat
.yy
= angle
.x
;
2705 pFT_Matrix_Multiply( &rotation_mat
, &matrices
[matrix_hori
] );
2706 needs_transform
= TRUE
;
2709 /* Vertical transform */
2710 matrices
[matrix_vert
] = matrices
[matrix_hori
];
2713 FT_Matrix vertical_mat
= { 0, -(1 << 16), 1 << 16, 0 }; /* 90 degrees rotation */
2715 pFT_Matrix_Multiply( &vertical_mat
, &matrices
[matrix_vert
] );
2716 needs_transform
= TRUE
;
2719 /* World transform */
2720 if (!is_identity_FMAT2( &font
->matrix
))
2722 FT_Matrix world_mat
;
2723 world_mat
.xx
= FT_FixedFromFloat( font
->matrix
.eM11
);
2724 world_mat
.xy
= -FT_FixedFromFloat( font
->matrix
.eM21
);
2725 world_mat
.yx
= -FT_FixedFromFloat( font
->matrix
.eM12
);
2726 world_mat
.yy
= FT_FixedFromFloat( font
->matrix
.eM22
);
2728 for (i
= 0; i
< 3; i
++)
2729 pFT_Matrix_Multiply( &world_mat
, &matrices
[i
] );
2730 needs_transform
= TRUE
;
2733 /* Extra transformation specified by caller */
2737 user_mat
.xx
= FT_FixedFromFIXED( user_transform
->eM11
);
2738 user_mat
.xy
= FT_FixedFromFIXED( user_transform
->eM21
);
2739 user_mat
.yx
= FT_FixedFromFIXED( user_transform
->eM12
);
2740 user_mat
.yy
= FT_FixedFromFIXED( user_transform
->eM22
);
2742 for (i
= 0; i
< 3; i
++)
2743 pFT_Matrix_Multiply( &user_mat
, &matrices
[i
] );
2744 needs_transform
= TRUE
;
2747 return needs_transform
? matrices
: NULL
;
2750 static BOOL
get_bold_glyph_outline(FT_GlyphSlot glyph
, LONG ppem
, FT_Glyph_Metrics
*metrics
)
2756 if(glyph
->format
!= FT_GLYPH_FORMAT_OUTLINE
)
2758 if(!pFT_Outline_Embolden
)
2761 strength
= pFT_MulDiv(ppem
, 1 << 6, 24);
2762 err
= pFT_Outline_Embolden(&glyph
->outline
, strength
);
2764 TRACE("FT_Ouline_Embolden returns %d\n", err
);
2768 pFT_Outline_Get_CBox(&glyph
->outline
, &bbox
);
2769 metrics
->width
= bbox
.xMax
- bbox
.xMin
;
2770 metrics
->height
= bbox
.yMax
- bbox
.yMin
;
2771 metrics
->horiBearingX
= bbox
.xMin
;
2772 metrics
->horiBearingY
= bbox
.yMax
;
2773 metrics
->vertBearingX
= metrics
->horiBearingX
- metrics
->horiAdvance
/ 2;
2774 metrics
->vertBearingY
= (metrics
->vertAdvance
- metrics
->height
) / 2;
2778 static inline BYTE
get_max_level( UINT format
)
2782 case GGO_GRAY2_BITMAP
: return 4;
2783 case GGO_GRAY4_BITMAP
: return 16;
2784 case GGO_GRAY8_BITMAP
: return 64;
2789 static FT_Vector
get_advance_metric( struct gdi_font
*font
, FT_Pos base_advance
,
2790 const FT_Matrix
*transMat
)
2793 FT_Fixed em_scale
= 0;
2794 BOOL fixed_pitch_full
= FALSE
;
2795 struct gdi_font
*incoming_font
= font
->base_font
? font
->base_font
: font
;
2797 adv
.x
= base_advance
;
2800 /* In fixed-pitch font, we adjust the fullwidth character advance so that
2801 they have double halfwidth character width. E.g. if the font is 19 ppem,
2802 we return 20 (not 19) for fullwidth characters as we return 10 for
2803 halfwidth characters. */
2804 if (freetype_set_outline_text_metrics(incoming_font
) &&
2805 !(incoming_font
->otm
.otmTextMetrics
.tmPitchAndFamily
& TMPF_FIXED_PITCH
)) {
2807 em_scale
= pFT_MulDiv(incoming_font
->ppem
, 1 << 16, get_ft_face(incoming_font
)->units_per_EM
);
2808 avg_advance
= pFT_MulFix(incoming_font
->ntmAvgWidth
, em_scale
);
2809 fixed_pitch_full
= (avg_advance
> 0 &&
2810 (base_advance
+ 63) >> 6 ==
2811 pFT_MulFix(incoming_font
->ntmAvgWidth
*2, em_scale
));
2812 if (fixed_pitch_full
&& !transMat
)
2813 adv
.x
= (avg_advance
* 2) << 6;
2817 pFT_Vector_Transform(&adv
, transMat
);
2818 if (fixed_pitch_full
&& adv
.y
== 0) {
2820 vec
.x
= incoming_font
->ntmAvgWidth
;
2822 pFT_Vector_Transform(&vec
, transMat
);
2823 adv
.x
= (pFT_MulFix(vec
.x
, em_scale
) * 2) << 6;
2827 if (font
->fake_bold
) {
2831 FT_Vector fake_bold_adv
, vec
= { 1 << 6, 0 };
2832 pFT_Vector_Transform(&vec
, transMat
);
2833 fake_bold_adv
= normalize_vector(&vec
);
2834 adv
.x
+= fake_bold_adv
.x
;
2835 adv
.y
+= fake_bold_adv
.y
;
2839 adv
.x
= (adv
.x
+ 63) & -64;
2840 adv
.y
= -((adv
.y
+ 63) & -64);
2844 static FT_BBox
get_transformed_bbox( const FT_Glyph_Metrics
*metrics
, const FT_Matrix
*matrices
)
2846 FT_BBox bbox
= { 0, 0, 0, 0 };
2850 bbox
.xMin
= (metrics
->horiBearingX
) & -64;
2851 bbox
.xMax
= (metrics
->horiBearingX
+ metrics
->width
+ 63) & -64;
2852 bbox
.yMax
= (metrics
->horiBearingY
+ 63) & -64;
2853 bbox
.yMin
= (metrics
->horiBearingY
- metrics
->height
) & -64;
2860 for (xc
= 0; xc
< 2; xc
++)
2862 for (yc
= 0; yc
< 2; yc
++)
2864 vec
.x
= metrics
->horiBearingX
+ xc
* metrics
->width
;
2865 vec
.y
= metrics
->horiBearingY
- yc
* metrics
->height
;
2866 TRACE( "Vec %ld, %ld\n", vec
.x
, vec
.y
);
2867 pFT_Vector_Transform( &vec
, &matrices
[matrix_vert
] );
2868 if (xc
== 0 && yc
== 0)
2870 bbox
.xMin
= bbox
.xMax
= vec
.x
;
2871 bbox
.yMin
= bbox
.yMax
= vec
.y
;
2875 if (vec
.x
< bbox
.xMin
) bbox
.xMin
= vec
.x
;
2876 else if (vec
.x
> bbox
.xMax
) bbox
.xMax
= vec
.x
;
2877 if (vec
.y
< bbox
.yMin
) bbox
.yMin
= vec
.y
;
2878 else if (vec
.y
> bbox
.yMax
) bbox
.yMax
= vec
.y
;
2882 bbox
.xMin
= bbox
.xMin
& -64;
2883 bbox
.xMax
= (bbox
.xMax
+ 63) & -64;
2884 bbox
.yMin
= bbox
.yMin
& -64;
2885 bbox
.yMax
= (bbox
.yMax
+ 63) & -64;
2886 TRACE( "transformed box: (%ld, %ld - %ld, %ld)\n", bbox
.xMin
, bbox
.yMax
, bbox
.xMax
, bbox
.yMin
);
2892 static void compute_metrics( struct gdi_font
*font
, FT_BBox bbox
, const FT_Glyph_Metrics
*metrics
,
2893 BOOL vertical
, BOOL vertical_metrics
, const FT_Matrix
*matrices
,
2894 GLYPHMETRICS
*gm
, ABC
*abc
)
2896 FT_Vector adv
, vec
, origin
;
2897 FT_Fixed base_advance
= vertical_metrics
? metrics
->vertAdvance
: metrics
->horiAdvance
;
2901 adv
= get_advance_metric( font
, base_advance
, NULL
);
2902 gm
->gmCellIncX
= adv
.x
>> 6;
2904 origin
.x
= bbox
.xMin
;
2905 origin
.y
= bbox
.yMax
;
2906 abc
->abcA
= origin
.x
>> 6;
2907 abc
->abcB
= (metrics
->width
+ 63) >> 6;
2913 if (vertical
&& freetype_set_outline_text_metrics( font
))
2915 if (vertical_metrics
)
2916 lsb
= metrics
->horiBearingY
+ metrics
->vertBearingY
;
2918 lsb
= metrics
->vertAdvance
+ (font
->otm
.otmDescent
<< 6);
2920 vec
.y
= font
->otm
.otmDescent
<< 6;
2921 TRACE( "Vec %ld,%ld\n", vec
.x
>>6, vec
.y
>>6 );
2922 pFT_Vector_Transform( &vec
, &matrices
[matrix_hori
] );
2923 origin
.x
= (vec
.x
+ bbox
.xMin
) & -64;
2924 origin
.y
= (vec
.y
+ bbox
.yMax
+ 63) & -64;
2925 lsb
-= metrics
->horiBearingY
;
2929 origin
.x
= bbox
.xMin
;
2930 origin
.y
= bbox
.yMax
;
2931 lsb
= metrics
->horiBearingX
;
2934 adv
= get_advance_metric( font
, base_advance
, &matrices
[matrix_hori
] );
2935 gm
->gmCellIncX
= adv
.x
>> 6;
2936 gm
->gmCellIncY
= adv
.y
>> 6;
2938 adv
= get_advance_metric( font
, base_advance
, &matrices
[matrix_unrotated
] );
2939 adv
.x
= pFT_Vector_Length( &adv
);
2944 pFT_Vector_Transform( &vec
, &matrices
[matrix_unrotated
] );
2945 if (lsb
> 0) abc
->abcA
= pFT_Vector_Length( &vec
) >> 6;
2946 else abc
->abcA
= -((pFT_Vector_Length( &vec
) + 63) >> 6);
2948 /* We use lsb again to avoid rounding errors */
2949 vec
.x
= lsb
+ (vertical
? metrics
->height
: metrics
->width
);
2951 pFT_Vector_Transform( &vec
, &matrices
[matrix_unrotated
] );
2952 abc
->abcB
= ((pFT_Vector_Length( &vec
) + 63) >> 6) - abc
->abcA
;
2954 if (!abc
->abcB
) abc
->abcB
= 1;
2955 abc
->abcC
= (adv
.x
>> 6) - abc
->abcA
- abc
->abcB
;
2957 gm
->gmptGlyphOrigin
.x
= origin
.x
>> 6;
2958 gm
->gmptGlyphOrigin
.y
= origin
.y
>> 6;
2959 gm
->gmBlackBoxX
= (bbox
.xMax
- bbox
.xMin
) >> 6;
2960 gm
->gmBlackBoxY
= (bbox
.yMax
- bbox
.yMin
) >> 6;
2961 if (!gm
->gmBlackBoxX
) gm
->gmBlackBoxX
= 1;
2962 if (!gm
->gmBlackBoxY
) gm
->gmBlackBoxY
= 1;
2964 TRACE( "gm: %u, %u, %s, %d, %d abc %d, %u, %d\n",
2965 gm
->gmBlackBoxX
, gm
->gmBlackBoxY
, wine_dbgstr_point(&gm
->gmptGlyphOrigin
),
2966 gm
->gmCellIncX
, gm
->gmCellIncY
, abc
->abcA
, abc
->abcB
, abc
->abcC
);
2970 static const BYTE masks
[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
2972 static DWORD
get_mono_glyph_bitmap( FT_GlyphSlot glyph
, FT_BBox bbox
,
2973 BOOL fake_bold
, const FT_Matrix
*matrices
,
2974 DWORD buflen
, BYTE
*buf
)
2976 DWORD width
= (bbox
.xMax
- bbox
.xMin
) >> 6;
2977 DWORD height
= (bbox
.yMax
- bbox
.yMin
) >> 6;
2978 DWORD pitch
= ((width
+ 31) >> 5) << 2;
2979 DWORD needed
= pitch
* height
;
2980 FT_Bitmap ft_bitmap
;
2984 if (!buf
|| !buflen
) return needed
;
2985 if (!needed
) return GDI_ERROR
; /* empty glyph */
2986 if (needed
> buflen
) return GDI_ERROR
;
2988 switch (glyph
->format
)
2990 case FT_GLYPH_FORMAT_BITMAP
:
2991 src
= glyph
->bitmap
.buffer
;
2993 w
= min( pitch
, (glyph
->bitmap
.width
+ 7) >> 3 );
2994 h
= min( height
, glyph
->bitmap
.rows
);
2998 memcpy( dst
, src
, w
);
3002 for (x
= 0; x
< w
; x
++)
3004 dst
[x
] = (dst
[x
] & 0x80) | (src
[x
] >> 1) | src
[x
];
3006 dst
[x
+ 1] = (src
[x
] & 0x01) << 7;
3009 src
+= glyph
->bitmap
.pitch
;
3014 case FT_GLYPH_FORMAT_OUTLINE
:
3015 ft_bitmap
.width
= width
;
3016 ft_bitmap
.rows
= height
;
3017 ft_bitmap
.pitch
= pitch
;
3018 ft_bitmap
.pixel_mode
= FT_PIXEL_MODE_MONO
;
3019 ft_bitmap
.buffer
= buf
;
3022 pFT_Outline_Transform( &glyph
->outline
, &matrices
[matrix_vert
] );
3023 pFT_Outline_Translate( &glyph
->outline
, -bbox
.xMin
, -bbox
.yMin
);
3025 /* Note: FreeType will only set 'black' bits for us. */
3026 memset( buf
, 0, buflen
);
3027 pFT_Outline_Get_Bitmap( library
, &glyph
->outline
, &ft_bitmap
);
3031 FIXME( "loaded glyph format %x\n", glyph
->format
);
3038 static DWORD
get_antialias_glyph_bitmap( FT_GlyphSlot glyph
, FT_BBox bbox
, UINT format
,
3039 BOOL fake_bold
, const FT_Matrix
*matrices
,
3040 DWORD buflen
, BYTE
*buf
)
3042 DWORD width
= (bbox
.xMax
- bbox
.xMin
) >> 6;
3043 DWORD height
= (bbox
.yMax
- bbox
.yMin
) >> 6;
3044 DWORD pitch
= (width
+ 3) / 4 * 4;
3045 DWORD needed
= pitch
* height
;
3046 FT_Bitmap ft_bitmap
;
3047 INT w
, h
, x
, max_level
;
3050 if (!buf
|| !buflen
) return needed
;
3051 if (!needed
) return GDI_ERROR
; /* empty glyph */
3052 if (needed
> buflen
) return GDI_ERROR
;
3054 max_level
= get_max_level( format
);
3056 switch (glyph
->format
)
3058 case FT_GLYPH_FORMAT_BITMAP
:
3059 src
= glyph
->bitmap
.buffer
;
3061 memset( buf
, 0, buflen
);
3063 w
= min( pitch
, glyph
->bitmap
.width
);
3064 h
= min( height
, glyph
->bitmap
.rows
);
3067 for (x
= 0; x
< w
; x
++)
3069 if (src
[x
/ 8] & masks
[x
% 8])
3072 if (fake_bold
&& x
+ 1 < pitch
) dst
[x
+ 1] = max_level
;
3075 src
+= glyph
->bitmap
.pitch
;
3080 case FT_GLYPH_FORMAT_OUTLINE
:
3081 ft_bitmap
.width
= width
;
3082 ft_bitmap
.rows
= height
;
3083 ft_bitmap
.pitch
= pitch
;
3084 ft_bitmap
.pixel_mode
= FT_PIXEL_MODE_GRAY
;
3085 ft_bitmap
.buffer
= buf
;
3088 pFT_Outline_Transform( &glyph
->outline
, &matrices
[matrix_vert
] );
3089 pFT_Outline_Translate( &glyph
->outline
, -bbox
.xMin
, -bbox
.yMin
);
3091 memset( buf
, 0, buflen
);
3092 pFT_Outline_Get_Bitmap( library
, &glyph
->outline
, &ft_bitmap
);
3094 if (max_level
!= 255)
3099 for (row
= 0, start
= buf
; row
< height
; row
++)
3101 for (col
= 0, ptr
= start
; col
< width
; col
++, ptr
++)
3102 *ptr
= (((int)*ptr
) * (max_level
+ 1)) / 256;
3109 FIXME("loaded glyph format %x\n", glyph
->format
);
3116 static DWORD
get_subpixel_glyph_bitmap( FT_GlyphSlot glyph
, FT_BBox bbox
, UINT format
,
3117 BOOL fake_bold
, const FT_Matrix
*matrices
,
3118 GLYPHMETRICS
*gm
, DWORD buflen
, BYTE
*buf
)
3120 DWORD width
= (bbox
.xMax
- bbox
.xMin
) >> 6;
3121 DWORD height
= (bbox
.yMax
- bbox
.yMin
) >> 6;
3122 DWORD pitch
, needed
= 0;
3126 switch (glyph
->format
)
3128 case FT_GLYPH_FORMAT_BITMAP
:
3130 needed
= pitch
* height
;
3132 if (!buf
|| !buflen
) break;
3133 if (!needed
) return GDI_ERROR
; /* empty glyph */
3134 if (needed
> buflen
) return GDI_ERROR
;
3136 src
= glyph
->bitmap
.buffer
;
3138 memset( buf
, 0, buflen
);
3140 w
= min( width
, glyph
->bitmap
.width
);
3141 h
= min( height
, glyph
->bitmap
.rows
);
3144 for (x
= 0; x
< w
; x
++)
3146 if ( src
[x
/ 8] & masks
[x
% 8] )
3148 ((unsigned int *)dst
)[x
] = ~0u;
3149 if (fake_bold
&& x
+ 1 < width
) ((unsigned int *)dst
)[x
+ 1] = ~0u;
3152 src
+= glyph
->bitmap
.pitch
;
3157 case FT_GLYPH_FORMAT_OUTLINE
:
3159 INT src_pitch
, src_width
, src_height
, x_shift
, y_shift
;
3160 INT sub_stride
, hmul
, vmul
;
3161 const INT
*sub_order
;
3162 const INT rgb_order
[3] = { 0, 1, 2 };
3163 const INT bgr_order
[3] = { 2, 1, 0 };
3164 FT_Render_Mode render_mode
=
3165 (format
== WINE_GGO_HRGB_BITMAP
||
3166 format
== WINE_GGO_HBGR_BITMAP
) ? FT_RENDER_MODE_LCD
: FT_RENDER_MODE_LCD_V
;
3168 if (!width
|| !height
) /* empty glyph */
3170 if (!buf
|| !buflen
) break;
3174 if ( render_mode
== FT_RENDER_MODE_LCD
)
3176 gm
->gmBlackBoxX
+= 2;
3177 gm
->gmptGlyphOrigin
.x
-= 1;
3178 bbox
.xMin
-= (1 << 6);
3182 gm
->gmBlackBoxY
+= 2;
3183 gm
->gmptGlyphOrigin
.y
+= 1;
3184 bbox
.yMax
+= (1 << 6);
3187 width
= gm
->gmBlackBoxX
;
3188 height
= gm
->gmBlackBoxY
;
3190 needed
= pitch
* height
;
3192 if (!buf
|| !buflen
) return needed
;
3193 if (needed
> buflen
) return GDI_ERROR
;
3196 pFT_Outline_Transform( &glyph
->outline
, &matrices
[matrix_vert
] );
3198 pFT_Render_Glyph( glyph
, render_mode
);
3200 src_pitch
= glyph
->bitmap
.pitch
;
3201 src_width
= glyph
->bitmap
.width
;
3202 src_height
= glyph
->bitmap
.rows
;
3203 src
= glyph
->bitmap
.buffer
;
3205 memset( buf
, 0, buflen
);
3207 sub_order
= (format
== WINE_GGO_HRGB_BITMAP
||
3208 format
== WINE_GGO_VRGB_BITMAP
) ? rgb_order
: bgr_order
;
3209 sub_stride
= render_mode
== FT_RENDER_MODE_LCD
? 1 : src_pitch
;
3210 hmul
= render_mode
== FT_RENDER_MODE_LCD
? 3 : 1;
3211 vmul
= render_mode
== FT_RENDER_MODE_LCD
? 1 : 3;
3213 x_shift
= glyph
->bitmap_left
- (bbox
.xMin
>> 6);
3216 src
+= hmul
* -x_shift
;
3217 src_width
-= hmul
* -x_shift
;
3219 else if ( x_shift
> 0 )
3221 dst
+= x_shift
* sizeof(unsigned int);
3225 y_shift
= (bbox
.yMax
>> 6) - glyph
->bitmap_top
;
3228 src
+= src_pitch
* vmul
* -y_shift
;
3229 src_height
-= vmul
* -y_shift
;
3231 else if ( y_shift
> 0 )
3233 dst
+= y_shift
* pitch
;
3237 w
= min( width
, src_width
/ hmul
);
3238 h
= min( height
, src_height
/ vmul
);
3241 for (x
= 0; x
< w
; x
++)
3243 ((unsigned int *)dst
)[x
] =
3244 ((unsigned int)src
[hmul
* x
+ sub_stride
* sub_order
[0]] << 16) |
3245 ((unsigned int)src
[hmul
* x
+ sub_stride
* sub_order
[1]] << 8) |
3246 ((unsigned int)src
[hmul
* x
+ sub_stride
* sub_order
[2]]);
3248 src
+= src_pitch
* vmul
;
3254 FIXME ( "loaded glyph format %x\n", glyph
->format
);
3261 static unsigned int get_native_glyph_outline(FT_Outline
*outline
, unsigned int buflen
, char *buf
)
3263 TTPOLYGONHEADER
*pph
;
3265 unsigned int needed
= 0, point
= 0, contour
, first_pt
;
3266 unsigned int pph_start
, cpfx
;
3269 for (contour
= 0; contour
< outline
->n_contours
; contour
++)
3271 /* Ignore contours containing one point */
3272 if (point
== outline
->contours
[contour
])
3279 pph
= (TTPOLYGONHEADER
*)(buf
+ needed
);
3283 pph
->dwType
= TT_POLYGON_TYPE
;
3284 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
3286 needed
+= sizeof(*pph
);
3288 while (point
<= outline
->contours
[contour
])
3290 ppc
= (TTPOLYCURVE
*)(buf
+ needed
);
3291 type
= outline
->tags
[point
] & FT_Curve_Tag_On
?
3292 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
3297 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
3300 } while (point
<= outline
->contours
[contour
] &&
3301 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
3302 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
3303 /* At the end of a contour Windows adds the start point, but
3305 if (point
> outline
->contours
[contour
] &&
3306 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
))
3309 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
3312 else if (point
<= outline
->contours
[contour
] &&
3313 outline
->tags
[point
] & FT_Curve_Tag_On
)
3315 /* add closing pt for bezier */
3317 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
3326 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
3329 pph
->cb
= needed
- pph_start
;
3334 static unsigned int get_bezier_glyph_outline(FT_Outline
*outline
, unsigned int buflen
, char *buf
)
3336 /* Convert the quadratic Beziers to cubic Beziers.
3337 The parametric eqn for a cubic Bezier is, from PLRM:
3338 r(t) = at^3 + bt^2 + ct + r0
3339 with the control points:
3344 A quadratic Bezier has the form:
3345 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3347 So equating powers of t leads to:
3348 r1 = 2/3 p1 + 1/3 p0
3349 r2 = 2/3 p1 + 1/3 p2
3350 and of course r0 = p0, r3 = p2
3352 int contour
, point
= 0, first_pt
;
3353 TTPOLYGONHEADER
*pph
;
3355 DWORD pph_start
, cpfx
, type
;
3356 FT_Vector cubic_control
[4];
3357 unsigned int needed
= 0;
3359 for (contour
= 0; contour
< outline
->n_contours
; contour
++)
3362 pph
= (TTPOLYGONHEADER
*)(buf
+ needed
);
3366 pph
->dwType
= TT_POLYGON_TYPE
;
3367 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
3369 needed
+= sizeof(*pph
);
3371 while (point
<= outline
->contours
[contour
])
3373 ppc
= (TTPOLYCURVE
*)(buf
+ needed
);
3374 type
= outline
->tags
[point
] & FT_Curve_Tag_On
?
3375 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
3379 if (type
== TT_PRIM_LINE
)
3382 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
3388 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
3391 /* FIXME: Possible optimization in endpoint calculation
3392 if there are two consecutive curves */
3393 cubic_control
[0] = outline
->points
[point
-1];
3394 if (!(outline
->tags
[point
-1] & FT_Curve_Tag_On
))
3396 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
3397 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
3398 cubic_control
[0].x
>>= 1;
3399 cubic_control
[0].y
>>= 1;
3401 if (point
+1 > outline
->contours
[contour
])
3402 cubic_control
[3] = outline
->points
[first_pt
];
3405 cubic_control
[3] = outline
->points
[point
+1];
3406 if (!(outline
->tags
[point
+1] & FT_Curve_Tag_On
))
3408 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
3409 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
3410 cubic_control
[3].x
>>= 1;
3411 cubic_control
[3].y
>>= 1;
3414 /* r1 = 1/3 p0 + 2/3 p1
3415 r2 = 1/3 p2 + 2/3 p1 */
3416 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
3417 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
3418 cubic_control
[2] = cubic_control
[1];
3419 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
3420 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
3421 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
3422 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
3425 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
3426 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
3427 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
3432 } while (point
<= outline
->contours
[contour
] &&
3433 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
3434 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
3435 /* At the end of a contour Windows adds the start point,
3436 but only for Beziers and we've already done that.
3438 if (point
<= outline
->contours
[contour
] &&
3439 outline
->tags
[point
] & FT_Curve_Tag_On
)
3441 /* This is the closing pt of a bezier, but we've already
3442 added it, so just inc point and carry on */
3450 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
3453 pph
->cb
= needed
- pph_start
;
3458 static FT_Int
get_load_flags( UINT format
)
3460 FT_Int load_flags
= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
3462 if (format
& GGO_UNHINTED
)
3463 return load_flags
| FT_LOAD_NO_HINTING
;
3465 switch (format
& ~GGO_GLYPH_INDEX
)
3468 load_flags
|= FT_LOAD_TARGET_MONO
;
3470 case GGO_GRAY2_BITMAP
:
3471 case GGO_GRAY4_BITMAP
:
3472 case GGO_GRAY8_BITMAP
:
3473 case WINE_GGO_GRAY16_BITMAP
:
3474 load_flags
|= FT_LOAD_TARGET_NORMAL
;
3476 case WINE_GGO_HRGB_BITMAP
:
3477 case WINE_GGO_HBGR_BITMAP
:
3478 load_flags
|= FT_LOAD_TARGET_LCD
;
3480 case WINE_GGO_VRGB_BITMAP
:
3481 case WINE_GGO_VBGR_BITMAP
:
3482 load_flags
|= FT_LOAD_TARGET_LCD_V
;
3489 /*************************************************************
3490 * freetype_get_glyph_outline
3492 static DWORD CDECL
freetype_get_glyph_outline( struct gdi_font
*font
, UINT glyph
, UINT format
,
3493 GLYPHMETRICS
*lpgm
, ABC
*abc
, DWORD buflen
, void *buf
,
3494 const MAT2
*lpmat
, BOOL tategaki
)
3496 struct gdi_font
*base_font
= font
->base_font
? font
->base_font
: font
;
3497 FT_Face ft_face
= get_ft_face( font
);
3498 FT_Glyph_Metrics metrics
;
3501 FT_Int load_flags
= get_load_flags(format
);
3502 FT_Matrix transform_matrices
[3], *matrices
= NULL
;
3503 BOOL vertical_metrics
;
3505 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
, buflen
, buf
, lpmat
);
3507 TRACE("font transform %f %f %f %f\n",
3508 font
->matrix
.eM11
, font
->matrix
.eM12
,
3509 font
->matrix
.eM21
, font
->matrix
.eM22
);
3511 format
&= ~GGO_UNHINTED
;
3513 matrices
= get_transform_matrices( font
, tategaki
, lpmat
, transform_matrices
);
3515 vertical_metrics
= (tategaki
&& FT_HAS_VERTICAL(ft_face
));
3516 /* there is a freetype bug where vertical metrics are only
3517 properly scaled and correct in 2.4.0 or greater */
3518 if (vertical_metrics
&& FT_SimpleVersion
< FT_VERSION_VALUE(2, 4, 0))
3519 vertical_metrics
= FALSE
;
3521 if (matrices
|| format
!= GGO_BITMAP
) load_flags
|= FT_LOAD_NO_BITMAP
;
3522 if (vertical_metrics
) load_flags
|= FT_LOAD_VERTICAL_LAYOUT
;
3524 err
= pFT_Load_Glyph(ft_face
, glyph
, load_flags
);
3525 if (err
&& !(load_flags
& FT_LOAD_NO_HINTING
))
3527 WARN("Failed to load glyph %#x, retrying without hinting. Error %#x.\n", glyph
, err
);
3528 load_flags
|= FT_LOAD_NO_HINTING
;
3529 err
= pFT_Load_Glyph(ft_face
, glyph
, load_flags
);
3533 WARN("Failed to load glyph %#x, error %#x.\n", glyph
, err
);
3537 metrics
= ft_face
->glyph
->metrics
;
3538 if(font
->fake_bold
) {
3539 if (!get_bold_glyph_outline(ft_face
->glyph
, font
->ppem
, &metrics
) && metrics
.width
)
3540 metrics
.width
+= 1 << 6;
3543 /* Some poorly-created fonts contain glyphs that exceed the boundaries set
3544 * by the text metrics. The proper behavior is to clip the glyph metrics to
3545 * fit within the maximums specified in the text metrics. */
3546 if (freetype_set_outline_text_metrics(base_font
) ||
3547 freetype_set_bitmap_text_metrics(base_font
)) {
3548 TEXTMETRICW
*ptm
= &base_font
->otm
.otmTextMetrics
;
3549 INT top
= min( metrics
.horiBearingY
, ptm
->tmAscent
<< 6 );
3550 INT bottom
= max( metrics
.horiBearingY
- metrics
.height
, -(ptm
->tmDescent
<< 6) );
3551 metrics
.horiBearingY
= top
;
3552 metrics
.height
= top
- bottom
;
3554 /* TODO: Are we supposed to clip the width as well...? */
3555 /* metrics.width = min( metrics.width, ptm->tmMaxCharWidth << 6 ); */
3558 bbox
= get_transformed_bbox( &metrics
, matrices
);
3559 compute_metrics( font
, bbox
, &metrics
, tategaki
, vertical_metrics
, matrices
, lpgm
, abc
);
3564 return 1; /* FIXME */
3567 return get_mono_glyph_bitmap( ft_face
->glyph
, bbox
, font
->fake_bold
,
3568 matrices
, buflen
, buf
);
3570 case GGO_GRAY2_BITMAP
:
3571 case GGO_GRAY4_BITMAP
:
3572 case GGO_GRAY8_BITMAP
:
3573 case WINE_GGO_GRAY16_BITMAP
:
3574 return get_antialias_glyph_bitmap( ft_face
->glyph
, bbox
, format
, font
->fake_bold
,
3575 matrices
, buflen
, buf
);
3577 case WINE_GGO_HRGB_BITMAP
:
3578 case WINE_GGO_HBGR_BITMAP
:
3579 case WINE_GGO_VRGB_BITMAP
:
3580 case WINE_GGO_VBGR_BITMAP
:
3581 return get_subpixel_glyph_bitmap( ft_face
->glyph
, bbox
, format
, font
->fake_bold
,
3582 matrices
, lpgm
, buflen
, buf
);
3585 if (ft_face
->glyph
->format
== ft_glyph_format_outline
)
3587 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
3590 if (buflen
== 0) buf
= NULL
;
3592 if (matrices
&& buf
)
3593 pFT_Outline_Transform( outline
, &matrices
[matrix_vert
] );
3595 needed
= get_native_glyph_outline(outline
, buflen
, NULL
);
3597 if (!buf
|| !buflen
) return needed
;
3598 if (needed
> buflen
) return GDI_ERROR
;
3599 return get_native_glyph_outline(outline
, buflen
, buf
);
3601 TRACE("loaded a bitmap\n");
3605 if (ft_face
->glyph
->format
== ft_glyph_format_outline
)
3607 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
3610 if (buflen
== 0) buf
= NULL
;
3612 if (matrices
&& buf
)
3613 pFT_Outline_Transform( outline
, &matrices
[matrix_vert
] );
3615 needed
= get_bezier_glyph_outline(outline
, buflen
, NULL
);
3617 if (!buf
|| !buflen
) return needed
;
3618 if (needed
> buflen
) return GDI_ERROR
;
3619 return get_bezier_glyph_outline(outline
, buflen
, buf
);
3621 TRACE("loaded a bitmap\n");
3625 FIXME("Unsupported format %d\n", format
);
3630 /*************************************************************
3631 * freetype_set_bitmap_text_metrics
3633 static BOOL CDECL
freetype_set_bitmap_text_metrics( struct gdi_font
*font
)
3635 FT_Face ft_face
= get_ft_face( font
);
3636 FT_WinFNT_HeaderRec winfnt_header
;
3638 if (font
->otm
.otmSize
) return TRUE
; /* already set */
3639 font
->otm
.otmSize
= offsetof( OUTLINETEXTMETRICW
, otmFiller
);
3641 #define TM font->otm.otmTextMetrics
3642 if(!pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
3644 TM
.tmHeight
= winfnt_header
.pixel_height
;
3645 TM
.tmAscent
= winfnt_header
.ascent
;
3646 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
3647 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
3648 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
3649 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
3650 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
3651 TM
.tmWeight
= winfnt_header
.weight
;
3653 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
3654 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
3655 TM
.tmFirstChar
= winfnt_header
.first_char
;
3656 TM
.tmLastChar
= winfnt_header
.last_char
;
3657 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
3658 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
3659 TM
.tmItalic
= winfnt_header
.italic
;
3660 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
3661 TM
.tmCharSet
= winfnt_header
.charset
;
3665 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
3666 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
3667 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
3668 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
3669 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
3670 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
3671 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
3672 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
3674 TM
.tmDigitizedAspectX
= 96; /* FIXME */
3675 TM
.tmDigitizedAspectY
= 96; /* FIXME */
3677 TM
.tmLastChar
= 255;
3678 TM
.tmDefaultChar
= 32;
3679 TM
.tmBreakChar
= 32;
3680 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
3681 /* NB inverted meaning of TMPF_FIXED_PITCH */
3682 TM
.tmPitchAndFamily
= FT_IS_FIXED_WIDTH(ft_face
) ? 0 : TMPF_FIXED_PITCH
;
3683 TM
.tmCharSet
= font
->charset
;
3685 TM
.tmUnderlined
= font
->lf
.lfUnderline
? 0xff : 0;
3686 TM
.tmStruckOut
= font
->lf
.lfStrikeOut
? 0xff : 0;
3689 TM
.tmWeight
= FW_BOLD
;
3696 static BOOL
face_has_symbol_charmap(FT_Face ft_face
)
3700 for(i
= 0; i
< ft_face
->num_charmaps
; i
++)
3702 if(ft_face
->charmaps
[i
]->encoding
== FT_ENCODING_MS_SYMBOL
)
3708 /*************************************************************
3709 * freetype_set_outline_text_metrics
3711 static BOOL CDECL
freetype_set_outline_text_metrics( struct gdi_font
*font
)
3713 FT_Face ft_face
= get_ft_face( font
);
3716 TT_HoriHeader
*pHori
;
3717 TT_Postscript
*pPost
;
3719 INT ascent
, descent
;
3722 TRACE("font=%p\n", font
);
3724 if (!font
->scalable
) return FALSE
;
3725 if (font
->otm
.otmSize
) return TRUE
; /* already set */
3727 /* note: we store actual pointers in the names instead of offsets,
3728 they are fixed up when returned to the app */
3729 if (!(font
->otm
.otmpFullName
= (char *)get_face_name( ft_face
, TT_NAME_ID_UNIQUE_ID
, system_lcid
)))
3731 static const WCHAR fake_nameW
[] = {'f','a','k','e',' ','n','a','m','e', 0};
3732 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w((WCHAR
*)font
->otm
.otmpFamilyName
));
3733 font
->otm
.otmpFullName
= (char *)strdupW(fake_nameW
);
3735 needed
= sizeof(font
->otm
) + (lstrlenW( (WCHAR
*)font
->otm
.otmpFamilyName
) + 1 +
3736 lstrlenW( (WCHAR
*)font
->otm
.otmpStyleName
) + 1 +
3737 lstrlenW( (WCHAR
*)font
->otm
.otmpFaceName
) + 1 +
3738 lstrlenW( (WCHAR
*)font
->otm
.otmpFullName
) + 1) * sizeof(WCHAR
);
3740 em_scale
= (FT_Fixed
)pFT_MulDiv(font
->ppem
, 1 << 16, ft_face
->units_per_EM
);
3742 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
3744 FIXME("Can't find OS/2 table - not TT font?\n");
3748 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
3750 FIXME("Can't find HHEA table - not TT font?\n");
3754 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
3756 TRACE("OS/2 winA = %u winD = %u 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",
3757 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
3758 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
3759 pOS2
->xAvgCharWidth
,
3760 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
3761 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
3762 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
3764 font
->otm
.otmSize
= needed
;
3766 #define TM font->otm.otmTextMetrics
3768 windescent
= get_fixed_windescent(pOS2
->usWinDescent
);
3769 if(pOS2
->usWinAscent
+ windescent
== 0) {
3770 ascent
= pHori
->Ascender
;
3771 descent
= -pHori
->Descender
;
3773 ascent
= pOS2
->usWinAscent
;
3774 descent
= windescent
;
3777 font
->ntmAvgWidth
= pOS2
->xAvgCharWidth
;
3779 #define SCALE_X(x) (pFT_MulFix(x, em_scale))
3780 #define SCALE_Y(y) (pFT_MulFix(y, em_scale))
3783 TM
.tmAscent
= font
->yMax
;
3784 TM
.tmDescent
= -font
->yMin
;
3785 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
3787 TM
.tmAscent
= SCALE_Y(ascent
);
3788 TM
.tmDescent
= SCALE_Y(descent
);
3789 TM
.tmInternalLeading
= SCALE_Y(ascent
+ descent
- ft_face
->units_per_EM
);
3792 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
3795 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
3797 TM
.tmExternalLeading
= max(0, SCALE_Y(pHori
->Line_Gap
-
3798 ((ascent
+ descent
) -
3799 (pHori
->Ascender
- pHori
->Descender
))));
3801 TM
.tmAveCharWidth
= SCALE_X(pOS2
->xAvgCharWidth
);
3802 if (TM
.tmAveCharWidth
== 0) {
3803 TM
.tmAveCharWidth
= 1;
3805 TM
.tmMaxCharWidth
= SCALE_X(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
);
3806 TM
.tmWeight
= FW_REGULAR
;
3807 if (font
->fake_bold
)
3808 TM
.tmWeight
= FW_BOLD
;
3811 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)
3813 if (pOS2
->usWeightClass
> FW_MEDIUM
)
3814 TM
.tmWeight
= pOS2
->usWeightClass
;
3816 else if (pOS2
->usWeightClass
<= FW_MEDIUM
)
3817 TM
.tmWeight
= pOS2
->usWeightClass
;
3820 TM
.tmDigitizedAspectX
= 96; /* FIXME */
3821 TM
.tmDigitizedAspectY
= 96; /* FIXME */
3822 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
3823 * symbol range to 0 - f0ff
3826 if (face_has_symbol_charmap(ft_face
) || (pOS2
->usFirstCharIndex
>= 0xf000 && pOS2
->usFirstCharIndex
< 0xf100))
3829 switch (PRIMARYLANGID(system_lcid
))
3832 TM
.tmLastChar
= 0xf896;
3836 case LANG_LITHUANIAN
:
3837 TM
.tmLastChar
= 0xf8fd;
3840 TM
.tmLastChar
= 0xf0ff;
3842 TM
.tmBreakChar
= 0x20;
3843 TM
.tmDefaultChar
= 0x1f;
3847 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
; /* Should be the first char in the cmap */
3848 TM
.tmLastChar
= pOS2
->usLastCharIndex
; /* Should be min(cmap_last, os2_last) */
3850 if(pOS2
->usFirstCharIndex
<= 1)
3851 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
+ 2;
3852 else if (pOS2
->usFirstCharIndex
> 0xff)
3853 TM
.tmBreakChar
= 0x20;
3855 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
;
3856 TM
.tmDefaultChar
= TM
.tmBreakChar
- 1;
3858 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
3859 TM
.tmUnderlined
= font
->lf
.lfUnderline
? 255 : 0;
3860 TM
.tmStruckOut
= font
->lf
.lfStrikeOut
? 255 : 0;
3862 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
3863 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
3864 (pOS2
->version
== 0xFFFFU
||
3865 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
3866 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
3868 TM
.tmPitchAndFamily
= 0;
3870 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
])
3872 case PAN_FAMILY_SCRIPT
:
3873 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
3876 case PAN_FAMILY_DECORATIVE
:
3877 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
3882 case PAN_FAMILY_TEXT_DISPLAY
:
3883 case PAN_FAMILY_PICTORIAL
: /* symbol fonts get treated as if they were text */
3884 /* which is clearly not what the panose spec says. */
3886 if(TM
.tmPitchAndFamily
== 0 || /* fixed */
3887 pOS2
->panose
[PAN_PROPORTION_INDEX
] == PAN_PROP_MONOSPACED
)
3888 TM
.tmPitchAndFamily
= FF_MODERN
;
3891 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
])
3896 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
3899 case PAN_SERIF_COVE
:
3900 case PAN_SERIF_OBTUSE_COVE
:
3901 case PAN_SERIF_SQUARE_COVE
:
3902 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
3903 case PAN_SERIF_SQUARE
:
3904 case PAN_SERIF_THIN
:
3905 case PAN_SERIF_BONE
:
3906 case PAN_SERIF_EXAGGERATED
:
3907 case PAN_SERIF_TRIANGLE
:
3908 TM
.tmPitchAndFamily
|= FF_ROMAN
;
3911 case PAN_SERIF_NORMAL_SANS
:
3912 case PAN_SERIF_OBTUSE_SANS
:
3913 case PAN_SERIF_PERP_SANS
:
3914 case PAN_SERIF_FLARED
:
3915 case PAN_SERIF_ROUNDED
:
3916 TM
.tmPitchAndFamily
|= FF_SWISS
;
3923 if(FT_IS_SCALABLE(ft_face
))
3924 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
3926 if(FT_IS_SFNT(ft_face
))
3928 if (font
->ntmFlags
& NTM_PS_OPENTYPE
)
3929 TM
.tmPitchAndFamily
|= TMPF_DEVICE
;
3931 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
3934 TM
.tmCharSet
= font
->charset
;
3936 font
->otm
.otmFiller
= 0;
3937 memcpy(&font
->otm
.otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
3938 font
->otm
.otmfsSelection
= pOS2
->fsSelection
;
3939 if (font
->fake_italic
)
3940 font
->otm
.otmfsSelection
|= 1;
3941 if (font
->fake_bold
)
3942 font
->otm
.otmfsSelection
|= 1 << 5;
3943 /* Only return valid bits that define embedding and subsetting restrictions */
3944 font
->otm
.otmfsType
= pOS2
->fsType
& 0x30e;
3945 font
->otm
.otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
3946 font
->otm
.otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
3947 font
->otm
.otmItalicAngle
= 0; /* POST table */
3948 font
->otm
.otmAscent
= SCALE_Y(pOS2
->sTypoAscender
);
3949 font
->otm
.otmDescent
= SCALE_Y(pOS2
->sTypoDescender
);
3950 font
->otm
.otmLineGap
= SCALE_Y(pOS2
->sTypoLineGap
);
3951 font
->otm
.otmsCapEmHeight
= SCALE_Y(pOS2
->sCapHeight
);
3952 font
->otm
.otmsXHeight
= SCALE_Y(pOS2
->sxHeight
);
3953 font
->otm
.otmrcFontBox
.left
= SCALE_X(ft_face
->bbox
.xMin
);
3954 font
->otm
.otmrcFontBox
.right
= SCALE_X(ft_face
->bbox
.xMax
);
3955 font
->otm
.otmrcFontBox
.top
= SCALE_Y(ft_face
->bbox
.yMax
);
3956 font
->otm
.otmrcFontBox
.bottom
= SCALE_Y(ft_face
->bbox
.yMin
);
3957 font
->otm
.otmMacAscent
= TM
.tmAscent
;
3958 font
->otm
.otmMacDescent
= -TM
.tmDescent
;
3959 font
->otm
.otmMacLineGap
= SCALE_Y(pHori
->Line_Gap
);
3960 font
->otm
.otmusMinimumPPEM
= 0; /* TT Header */
3961 font
->otm
.otmptSubscriptSize
.x
= SCALE_X(pOS2
->ySubscriptXSize
);
3962 font
->otm
.otmptSubscriptSize
.y
= SCALE_Y(pOS2
->ySubscriptYSize
);
3963 font
->otm
.otmptSubscriptOffset
.x
= SCALE_X(pOS2
->ySubscriptXOffset
);
3964 font
->otm
.otmptSubscriptOffset
.y
= SCALE_Y(pOS2
->ySubscriptYOffset
);
3965 font
->otm
.otmptSuperscriptSize
.x
= SCALE_X(pOS2
->ySuperscriptXSize
);
3966 font
->otm
.otmptSuperscriptSize
.y
= SCALE_Y(pOS2
->ySuperscriptYSize
);
3967 font
->otm
.otmptSuperscriptOffset
.x
= SCALE_X(pOS2
->ySuperscriptXOffset
);
3968 font
->otm
.otmptSuperscriptOffset
.y
= SCALE_Y(pOS2
->ySuperscriptYOffset
);
3969 font
->otm
.otmsStrikeoutSize
= SCALE_Y(pOS2
->yStrikeoutSize
);
3970 font
->otm
.otmsStrikeoutPosition
= SCALE_Y(pOS2
->yStrikeoutPosition
);
3972 font
->otm
.otmsUnderscoreSize
= 0;
3973 font
->otm
.otmsUnderscorePosition
= 0;
3975 font
->otm
.otmsUnderscoreSize
= SCALE_Y(pPost
->underlineThickness
);
3976 font
->otm
.otmsUnderscorePosition
= SCALE_Y(pPost
->underlinePosition
);
3984 /*************************************************************
3985 * freetype_get_char_width_info
3987 static BOOL CDECL
freetype_get_char_width_info( struct gdi_font
*font
, struct char_width_info
*info
)
3989 FT_Face ft_face
= get_ft_face( font
);
3990 TT_HoriHeader
*pHori
;
3992 TRACE("%p, %p\n", font
, info
);
3994 if ((pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
)))
3996 FT_Fixed em_scale
= pFT_MulDiv(font
->ppem
, 1 << 16, ft_face
->units_per_EM
);
3997 info
->lsb
= (SHORT
)pFT_MulFix(pHori
->min_Left_Side_Bearing
, em_scale
);
3998 info
->rsb
= (SHORT
)pFT_MulFix(pHori
->min_Right_Side_Bearing
, em_scale
);
4005 /*************************************************************
4006 * freetype_get_unicode_ranges
4008 * Retrieve a list of supported Unicode ranges for a given font.
4009 * Can be called with NULL gs to calculate the buffer size. Returns
4010 * the number of ranges found.
4012 static DWORD CDECL
freetype_get_unicode_ranges( struct gdi_font
*font
, GLYPHSET
*gs
)
4014 FT_Face ft_face
= get_ft_face( font
);
4015 DWORD num_ranges
= 0;
4017 if (ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
4020 FT_ULong char_code
, char_code_prev
;
4023 char_code_prev
= char_code
= pFT_Get_First_Char(ft_face
, &glyph_code
);
4025 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
4026 ft_face
->num_glyphs
, glyph_code
, char_code
);
4028 if (!glyph_code
) return 0;
4032 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
4033 gs
->ranges
[0].cGlyphs
= 0;
4034 gs
->cGlyphsSupported
= 0;
4040 if (char_code
< char_code_prev
)
4042 ERR("expected increasing char code from FT_Get_Next_Char\n");
4045 if (char_code
- char_code_prev
> 1)
4050 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
4051 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
4052 gs
->cGlyphsSupported
++;
4057 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
4058 gs
->cGlyphsSupported
++;
4060 char_code_prev
= char_code
;
4061 char_code
= pFT_Get_Next_Char(ft_face
, char_code
, &glyph_code
);
4066 DWORD encoding
= RtlUlongByteSwap(ft_face
->charmap
->encoding
);
4067 FIXME("encoding %s not supported\n", debugstr_an((char *)&encoding
, 4));
4073 /*************************************************************************
4074 * Kerning support for TrueType fonts
4077 struct TT_kern_table
4083 struct TT_kern_subtable
4092 USHORT horizontal
: 1;
4094 USHORT cross_stream
: 1;
4095 USHORT override
: 1;
4096 USHORT reserved1
: 4;
4102 struct TT_format0_kern_subtable
4106 USHORT entrySelector
;
4117 static DWORD
parse_format0_kern_subtable(struct gdi_font
*font
,
4118 const struct TT_format0_kern_subtable
*tt_f0_ks
,
4119 const USHORT
*glyph_to_char
,
4120 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
4122 FT_Face ft_face
= get_ft_face( font
);
4124 const struct TT_kern_pair
*tt_kern_pair
;
4126 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, ft_face
->units_per_EM
);
4128 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
4130 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
4131 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
4132 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
4134 if (!kern_pair
|| !cPairs
)
4137 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
4139 nPairs
= min(nPairs
, cPairs
);
4141 for (i
= 0; i
< nPairs
; i
++)
4143 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
4144 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
4145 /* this algorithm appears to better match what Windows does */
4146 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
4147 if (kern_pair
->iKernAmount
< 0)
4149 kern_pair
->iKernAmount
-= ft_face
->units_per_EM
/ 2;
4150 kern_pair
->iKernAmount
-= font
->ppem
;
4152 else if (kern_pair
->iKernAmount
> 0)
4154 kern_pair
->iKernAmount
+= ft_face
->units_per_EM
/ 2;
4155 kern_pair
->iKernAmount
+= font
->ppem
;
4157 kern_pair
->iKernAmount
/= ft_face
->units_per_EM
;
4159 TRACE("left %u right %u value %d\n",
4160 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
4164 TRACE("copied %u entries\n", nPairs
);
4168 /*************************************************************
4169 * freetype_get_kerning_pairs
4171 static DWORD CDECL
freetype_get_kerning_pairs( struct gdi_font
*font
, KERNINGPAIR
**pairs
)
4173 FT_Face ft_face
= get_ft_face( font
);
4174 DWORD length
, count
= 0;
4176 const struct TT_kern_table
*tt_kern_table
;
4177 const struct TT_kern_subtable
*tt_kern_subtable
;
4179 USHORT
*glyph_to_char
;
4181 length
= freetype_get_font_data(font
, MS_KERN_TAG
, 0, NULL
, 0);
4183 if (length
== GDI_ERROR
)
4185 TRACE("no kerning data in the font\n");
4189 buf
= RtlAllocateHeap(GetProcessHeap(), 0, length
);
4192 freetype_get_font_data(font
, MS_KERN_TAG
, 0, buf
, length
);
4194 /* build a glyph index to char code map */
4195 glyph_to_char
= RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(USHORT
) * 65536);
4198 RtlFreeHeap(GetProcessHeap(), 0, buf
);
4202 if (ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
4208 char_code
= pFT_Get_First_Char(ft_face
, &glyph_code
);
4210 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
4211 ft_face
->num_glyphs
, glyph_code
, char_code
);
4215 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
4217 /* FIXME: This doesn't match what Windows does: it does some fancy
4218 * things with duplicate glyph index to char code mappings, while
4219 * we just avoid overriding existing entries.
4221 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
4222 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
4224 char_code
= pFT_Get_Next_Char(ft_face
, char_code
, &glyph_code
);
4229 DWORD encoding
= RtlUlongByteSwap(ft_face
->charmap
->encoding
);
4232 FIXME("encoding %s not supported\n", debugstr_an((char *)&encoding
, 4));
4233 for (n
= 0; n
<= 65535; n
++)
4234 glyph_to_char
[n
] = (USHORT
)n
;
4237 tt_kern_table
= buf
;
4238 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
4239 TRACE("version %u, nTables %u\n",
4240 GET_BE_WORD(tt_kern_table
->version
), nTables
);
4242 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
4244 for (i
= 0; i
< nTables
; i
++)
4246 struct TT_kern_subtable tt_kern_subtable_copy
;
4248 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
4249 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
4250 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
4252 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
4253 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
4254 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
4256 /* According to the TrueType specification this is the only format
4257 * that will be properly interpreted by Windows and OS/2
4259 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
4261 DWORD new_chunk
, old_total
= count
;
4263 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
4264 glyph_to_char
, NULL
, 0);
4268 *pairs
= RtlAllocateHeap(GetProcessHeap(), 0, count
* sizeof(**pairs
));
4270 *pairs
= RtlReAllocateHeap(GetProcessHeap(), 0, *pairs
, count
* sizeof(**pairs
));
4272 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
4273 glyph_to_char
, *pairs
+ old_total
, new_chunk
);
4276 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
4278 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
4281 RtlFreeHeap(GetProcessHeap(), 0, glyph_to_char
);
4282 RtlFreeHeap(GetProcessHeap(), 0, buf
);
4286 static const struct font_backend_funcs font_funcs
=
4288 freetype_load_fonts
,
4289 fontconfig_enum_family_fallbacks
,
4291 freetype_add_mem_font
,
4293 freetype_get_font_data
,
4294 freetype_get_aa_flags
,
4295 freetype_get_glyph_index
,
4296 freetype_get_default_glyph
,
4297 freetype_get_glyph_outline
,
4298 freetype_get_unicode_ranges
,
4299 freetype_get_char_width_info
,
4300 freetype_set_outline_text_metrics
,
4301 freetype_set_bitmap_text_metrics
,
4302 freetype_get_kerning_pairs
,
4303 freetype_destroy_font
4306 static NTSTATUS
init_freetype_lib( HMODULE module
, DWORD reason
, const void *ptr_in
, void *ptr_out
)
4308 callback_funcs
= ptr_in
;
4309 if (!init_freetype()) return STATUS_DLL_NOT_FOUND
;
4310 #ifdef SONAME_LIBFONTCONFIG
4313 NtQueryDefaultLocale( FALSE
, &system_lcid
);
4314 *(const struct font_backend_funcs
**)ptr_out
= &font_funcs
;
4315 return STATUS_SUCCESS
;
4318 #else /* HAVE_FREETYPE */
4320 static NTSTATUS
init_freetype_lib( HMODULE module
, DWORD reason
, const void *ptr_in
, void *ptr_out
)
4322 return STATUS_DLL_NOT_FOUND
;
4325 #endif /* HAVE_FREETYPE */
4327 NTSTATUS CDECL
__wine_init_unix_lib( HMODULE module
, DWORD reason
, const void *ptr_in
, void *ptr_out
)
4329 if (reason
!= DLL_PROCESS_ATTACH
) return STATUS_SUCCESS
;
4331 if (ptr_in
) return init_freetype_lib( module
, reason
, ptr_in
, ptr_out
);
4332 else return init_opengl_lib( module
, reason
, ptr_in
, ptr_out
);