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 "gdi_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 style_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
= pFcPatternCreate();
1545 if (*cached
) return *cached
;
1546 pFcPatternAddString( pattern
, FC_FAMILY
, (const FcChar8
*)name
);
1547 pFcPatternAddString( pattern
, FC_NAMELANG
, (const FcChar8
*)"en-us" );
1548 pFcPatternAddString( pattern
, FC_PRGNAME
, (const FcChar8
*)"wine" );
1549 pFcConfigSubstitute( NULL
, pattern
, FcMatchPattern
);
1550 pFcDefaultSubstitute( pattern
);
1551 tmp
= pFcFontMatch( NULL
, pattern
, &result
);
1552 pFcPatternDestroy( pattern
);
1553 if (result
!= FcResultMatch
) pFcPatternDestroy( tmp
);
1554 else if ((ret
= InterlockedCompareExchangePointer( (void **)cached
, tmp
, NULL
))) pFcPatternDestroy( tmp
);
1559 static void fontconfig_add_font( FcPattern
*pattern
, DWORD flags
)
1561 const char *unix_name
, *format
;
1567 TRACE( "(%p %#x)\n", pattern
, flags
);
1569 if (pFcPatternGetString( pattern
, FC_FILE
, 0, (FcChar8
**)&unix_name
) != FcResultMatch
)
1572 if (pFcPatternGetBool( pattern
, FC_SCALABLE
, 0, &scalable
) != FcResultMatch
)
1575 if (pFcPatternGetString( pattern
, FC_FONTFORMAT
, 0, (FcChar8
**)&format
) != FcResultMatch
)
1577 TRACE( "ignoring unknown font format %s\n", debugstr_a(unix_name
) );
1581 if (!strcmp( format
, "Type 1" ))
1583 TRACE( "ignoring Type 1 font %s\n", debugstr_a(unix_name
) );
1587 if (!scalable
&& !(flags
& ADDFONT_ALLOW_BITMAP
))
1589 TRACE( "ignoring non-scalable font %s\n", debugstr_a(unix_name
) );
1593 if (!(aa_flags
= parse_aa_pattern( pattern
))) aa_flags
= default_aa_flags
;
1594 flags
|= ADDFONT_AA_FLAGS(aa_flags
);
1596 if (pFcPatternGetInteger( pattern
, FC_INDEX
, 0, &face_index
) != FcResultMatch
)
1599 dos_name
= get_dos_file_name( unix_name
);
1600 add_unix_face( unix_name
, dos_name
, NULL
, 0, face_index
, flags
, NULL
);
1601 RtlFreeHeap( GetProcessHeap(), 0, dos_name
);
1604 static void init_fontconfig(void)
1606 void *fc_handle
= dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
);
1610 TRACE("Wine cannot find the fontconfig library (%s).\n", SONAME_LIBFONTCONFIG
);
1614 #define LOAD_FUNCPTR(f) if((p##f = dlsym(fc_handle, #f)) == NULL){WARN("Can't find symbol %s\n", #f); return;}
1615 LOAD_FUNCPTR(FcConfigSubstitute
);
1616 LOAD_FUNCPTR(FcDefaultSubstitute
);
1617 LOAD_FUNCPTR(FcFontList
);
1618 LOAD_FUNCPTR(FcFontMatch
);
1619 LOAD_FUNCPTR(FcFontSetDestroy
);
1620 LOAD_FUNCPTR(FcInit
);
1621 LOAD_FUNCPTR(FcPatternAddString
);
1622 LOAD_FUNCPTR(FcPatternCreate
);
1623 LOAD_FUNCPTR(FcPatternDestroy
);
1624 LOAD_FUNCPTR(FcPatternGetBool
);
1625 LOAD_FUNCPTR(FcPatternGetInteger
);
1626 LOAD_FUNCPTR(FcPatternGetString
);
1627 LOAD_FUNCPTR(FcConfigGetFontDirs
);
1628 LOAD_FUNCPTR(FcConfigGetCurrent
);
1629 LOAD_FUNCPTR(FcCacheCopySet
);
1630 LOAD_FUNCPTR(FcCacheNumSubdir
);
1631 LOAD_FUNCPTR(FcCacheSubdir
);
1632 LOAD_FUNCPTR(FcDirCacheRead
);
1633 LOAD_FUNCPTR(FcDirCacheUnload
);
1634 LOAD_FUNCPTR(FcStrListCreate
);
1635 LOAD_FUNCPTR(FcStrListDone
);
1636 LOAD_FUNCPTR(FcStrListNext
);
1637 LOAD_FUNCPTR(FcStrSetAdd
);
1638 LOAD_FUNCPTR(FcStrSetCreate
);
1639 LOAD_FUNCPTR(FcStrSetDestroy
);
1640 LOAD_FUNCPTR(FcStrSetMember
);
1645 FcPattern
*pattern
= pFcPatternCreate();
1646 pFcConfigSubstitute( NULL
, pattern
, FcMatchFont
);
1647 default_aa_flags
= parse_aa_pattern( pattern
);
1648 pFcPatternDestroy( pattern
);
1650 if (!default_aa_flags
)
1652 FcPattern
*pattern
= pFcPatternCreate();
1653 pFcConfigSubstitute( NULL
, pattern
, FcMatchPattern
);
1654 default_aa_flags
= parse_aa_pattern( pattern
);
1655 pFcPatternDestroy( pattern
);
1658 TRACE( "enabled, default flags = %x\n", default_aa_flags
);
1659 fontconfig_enabled
= TRUE
;
1663 static void fontconfig_add_fonts_from_dir_list( FcConfig
*config
, FcStrList
*dir_list
, FcStrSet
*done_set
, DWORD flags
)
1666 FcFontSet
*font_set
= NULL
;
1667 FcStrList
*subdir_list
= NULL
;
1668 FcStrSet
*subdir_set
= NULL
;
1669 FcCache
*cache
= NULL
;
1672 TRACE( "(%p %p %p %#x)\n", config
, dir_list
, done_set
, flags
);
1674 while ((dir
= pFcStrListNext( dir_list
)))
1676 if (pFcStrSetMember( done_set
, dir
)) continue;
1678 TRACE( "adding fonts from %s\n", dir
);
1679 if (!(cache
= pFcDirCacheRead( dir
, FcFalse
, config
))) continue;
1681 if (!(font_set
= pFcCacheCopySet( cache
))) goto done
;
1682 for (i
= 0; i
< font_set
->nfont
; i
++)
1683 fontconfig_add_font( font_set
->fonts
[i
], flags
);
1684 pFcFontSetDestroy( font_set
);
1687 if (!(subdir_set
= pFcStrSetCreate())) goto done
;
1688 for (i
= 0; i
< pFcCacheNumSubdir( cache
); i
++)
1689 pFcStrSetAdd( subdir_set
, pFcCacheSubdir( cache
, i
) );
1690 pFcDirCacheUnload( cache
);
1693 if (!(subdir_list
= pFcStrListCreate( subdir_set
))) goto done
;
1694 pFcStrSetDestroy( subdir_set
);
1697 pFcStrSetAdd( done_set
, dir
);
1698 fontconfig_add_fonts_from_dir_list( config
, subdir_list
, done_set
, flags
);
1699 pFcStrListDone( subdir_list
);
1704 if (font_set
) pFcFontSetDestroy( font_set
);
1705 if (subdir_list
) pFcStrListDone( subdir_list
);
1706 if (subdir_set
) pFcStrSetDestroy( subdir_set
);
1707 if (cache
) pFcDirCacheUnload( cache
);
1710 static void load_fontconfig_fonts( void )
1712 FcStrList
*dir_list
= NULL
;
1713 FcStrSet
*done_set
= NULL
;
1716 if (!fontconfig_enabled
) return;
1717 if (!(config
= pFcConfigGetCurrent())) goto done
;
1718 if (!(done_set
= pFcStrSetCreate())) goto done
;
1719 if (!(dir_list
= pFcConfigGetFontDirs( config
))) goto done
;
1721 fontconfig_add_fonts_from_dir_list( config
, dir_list
, done_set
, ADDFONT_EXTERNAL_FONT
);
1724 if (dir_list
) pFcStrListDone( dir_list
);
1725 if (done_set
) pFcStrSetDestroy( done_set
);
1728 #elif defined(HAVE_CARBON_CARBON_H)
1730 static void load_mac_font_callback(const void *value
, void *context
)
1732 CFStringRef pathStr
= value
;
1736 len
= CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr
);
1737 path
= RtlAllocateHeap(GetProcessHeap(), 0, len
);
1738 if (path
&& CFStringGetFileSystemRepresentation(pathStr
, path
, len
))
1740 TRACE("font file %s\n", path
);
1741 AddFontToList(NULL
, path
, NULL
, 0, ADDFONT_EXTERNAL_FONT
);
1743 RtlFreeHeap(GetProcessHeap(), 0, path
);
1746 static void load_mac_fonts(void)
1748 CFStringRef removeDupesKey
;
1749 CFBooleanRef removeDupesValue
;
1750 CFDictionaryRef options
;
1751 CTFontCollectionRef col
;
1753 CFMutableSetRef paths
;
1756 removeDupesKey
= kCTFontCollectionRemoveDuplicatesOption
;
1757 removeDupesValue
= kCFBooleanTrue
;
1758 options
= CFDictionaryCreate(NULL
, (const void**)&removeDupesKey
, (const void**)&removeDupesValue
, 1,
1759 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1760 col
= CTFontCollectionCreateFromAvailableFonts(options
);
1761 if (options
) CFRelease(options
);
1764 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
1768 descs
= CTFontCollectionCreateMatchingFontDescriptors(col
);
1772 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
1776 paths
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
1779 WARN("CFSetCreateMutable failed\n");
1784 for (i
= 0; i
< CFArrayGetCount(descs
); i
++)
1786 CTFontDescriptorRef desc
;
1791 desc
= CFArrayGetValueAtIndex(descs
, i
);
1793 #if defined(MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
1794 url
= CTFontDescriptorCopyAttribute(desc
, kCTFontURLAttribute
);
1796 /* CTFontDescriptor doesn't support kCTFontURLAttribute prior to 10.6, so
1797 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
1804 font
= CTFontCreateWithFontDescriptor(desc
, 0, NULL
);
1805 if (!font
) continue;
1807 atsFont
= CTFontGetPlatformFont(font
, NULL
);
1814 status
= ATSFontGetFileReference(atsFont
, &fsref
);
1816 if (status
!= noErr
) continue;
1818 url
= CFURLCreateFromFSRef(NULL
, &fsref
);
1823 ext
= CFURLCopyPathExtension(url
);
1826 BOOL skip
= (CFStringCompare(ext
, CFSTR("pfa"), kCFCompareCaseInsensitive
) == kCFCompareEqualTo
||
1827 CFStringCompare(ext
, CFSTR("pfb"), kCFCompareCaseInsensitive
) == kCFCompareEqualTo
);
1836 path
= CFURLCopyFileSystemPath(url
, kCFURLPOSIXPathStyle
);
1838 if (!path
) continue;
1840 CFSetAddValue(paths
, path
);
1846 CFSetApplyFunction(paths
, load_mac_font_callback
, NULL
);
1853 static BOOL
init_freetype(void)
1855 ft_handle
= dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
);
1858 "Wine cannot find the FreeType font library. To enable Wine to\n"
1859 "use TrueType fonts please install a version of FreeType greater than\n"
1860 "or equal to 2.0.5.\n"
1861 "http://www.freetype.org\n");
1865 #define LOAD_FUNCPTR(f) if((p##f = dlsym(ft_handle, #f)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
1867 LOAD_FUNCPTR(FT_Done_Face
)
1868 LOAD_FUNCPTR(FT_Get_Char_Index
)
1869 LOAD_FUNCPTR(FT_Get_First_Char
)
1870 LOAD_FUNCPTR(FT_Get_Next_Char
)
1871 LOAD_FUNCPTR(FT_Get_Sfnt_Name
)
1872 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count
)
1873 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
1874 LOAD_FUNCPTR(FT_Get_WinFNT_Header
)
1875 LOAD_FUNCPTR(FT_Init_FreeType
)
1876 LOAD_FUNCPTR(FT_Library_Version
)
1877 LOAD_FUNCPTR(FT_Load_Glyph
)
1878 LOAD_FUNCPTR(FT_Load_Sfnt_Table
)
1879 LOAD_FUNCPTR(FT_Matrix_Multiply
)
1880 LOAD_FUNCPTR(FT_MulDiv
)
1881 #ifndef FT_MULFIX_INLINED
1882 LOAD_FUNCPTR(FT_MulFix
)
1884 LOAD_FUNCPTR(FT_New_Face
)
1885 LOAD_FUNCPTR(FT_New_Memory_Face
)
1886 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
1887 LOAD_FUNCPTR(FT_Outline_Get_CBox
)
1888 LOAD_FUNCPTR(FT_Outline_Transform
)
1889 LOAD_FUNCPTR(FT_Outline_Translate
)
1890 LOAD_FUNCPTR(FT_Render_Glyph
)
1891 LOAD_FUNCPTR(FT_Set_Charmap
)
1892 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
1893 LOAD_FUNCPTR(FT_Vector_Length
)
1894 LOAD_FUNCPTR(FT_Vector_Transform
)
1895 LOAD_FUNCPTR(FT_Vector_Unit
)
1897 /* Don't warn if these ones are missing */
1898 pFT_Outline_Embolden
= dlsym(ft_handle
, "FT_Outline_Embolden");
1899 pFT_Get_TrueType_Engine_Type
= dlsym(ft_handle
, "FT_Get_TrueType_Engine_Type");
1900 #ifdef FT_LCD_FILTER_H
1901 pFT_Library_SetLcdFilter
= dlsym(ft_handle
, "FT_Library_SetLcdFilter");
1903 pFT_Property_Set
= dlsym(ft_handle
, "FT_Property_Set");
1905 if(pFT_Init_FreeType(&library
) != 0) {
1906 ERR("Can't init FreeType library\n");
1911 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
1913 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
1914 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
1915 ((FT_Version
.minor
<< 8) & 0x00ff00) |
1916 ((FT_Version
.patch
) & 0x0000ff);
1918 /* In FreeType < 2.8.1 v40's FT_LOAD_TARGET_MONO has broken advance widths. */
1919 if (pFT_Property_Set
&& FT_SimpleVersion
< FT_VERSION_VALUE(2, 8, 1))
1921 FT_UInt interpreter_version
= 35;
1922 pFT_Property_Set( library
, "truetype", "interpreter-version", &interpreter_version
);
1925 #ifdef FT_LCD_FILTER_H
1926 if (pFT_Library_SetLcdFilter
)
1927 pFT_Library_SetLcdFilter( library
, FT_LCD_FILTER_DEFAULT
);
1934 "Wine cannot find certain functions that it needs inside the FreeType\n"
1935 "font library. To enable Wine to use TrueType fonts please upgrade\n"
1936 "FreeType to at least version 2.1.4.\n"
1937 "http://www.freetype.org\n");
1943 /*************************************************************
1944 * freetype_load_fonts
1946 static void CDECL
freetype_load_fonts(void)
1948 #ifdef SONAME_LIBFONTCONFIG
1949 load_fontconfig_fonts();
1950 #elif defined(HAVE_CARBON_CARBON_H)
1952 #elif defined(__ANDROID__)
1953 ReadFontDir("/system/fonts", TRUE
);
1957 /* Some fonts have large usWinDescent values, as a result of storing signed short
1958 in unsigned field. That's probably caused by sTypoDescent vs usWinDescent confusion in
1959 some font generation tools. */
1960 static inline USHORT
get_fixed_windescent(USHORT windescent
)
1962 return abs((SHORT
)windescent
);
1965 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
1968 TT_HoriHeader
*pHori
;
1971 const LONG MAX_PPEM
= (1 << 16) - 1;
1973 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
1974 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
1976 if(height
== 0) height
= 16;
1978 /* Calc. height of EM square:
1980 * For +ve lfHeight we have
1981 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
1982 * Re-arranging gives:
1983 * ppem = units_per_em * lfheight / (winAscent + winDescent)
1985 * For -ve lfHeight we have
1987 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
1988 * with il = winAscent + winDescent - units_per_em]
1993 USHORT windescent
= get_fixed_windescent(pOS2
->usWinDescent
);
1994 if(pOS2
->usWinAscent
+ windescent
== 0)
1995 ppem
= pFT_MulDiv(ft_face
->units_per_EM
, height
, pHori
->Ascender
- pHori
->Descender
);
1997 ppem
= pFT_MulDiv(ft_face
->units_per_EM
, height
, pOS2
->usWinAscent
+ windescent
);
1998 if(ppem
> MAX_PPEM
) {
1999 WARN("Ignoring too large height %d, ppem %d\n", height
, ppem
);
2003 else if(height
>= -MAX_PPEM
)
2006 WARN("Ignoring too large height %d\n", height
);
2013 static struct font_mapping
*map_font_file( const char *name
)
2015 struct font_mapping
*mapping
;
2019 if ((fd
= open( name
, O_RDONLY
)) == -1) return NULL
;
2020 if (fstat( fd
, &st
) == -1) goto error
;
2022 LIST_FOR_EACH_ENTRY( mapping
, &mappings_list
, struct font_mapping
, entry
)
2024 if (mapping
->dev
== st
.st_dev
&& mapping
->ino
== st
.st_ino
)
2026 mapping
->refcount
++;
2031 if (!(mapping
= RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*mapping
) )))
2034 mapping
->data
= mmap( NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0 );
2037 if (mapping
->data
== MAP_FAILED
)
2039 RtlFreeHeap( GetProcessHeap(), 0, mapping
);
2042 mapping
->refcount
= 1;
2043 mapping
->dev
= st
.st_dev
;
2044 mapping
->ino
= st
.st_ino
;
2045 mapping
->size
= st
.st_size
;
2046 list_add_tail( &mappings_list
, &mapping
->entry
);
2054 static void unmap_font_file( struct font_mapping
*mapping
)
2056 if (!--mapping
->refcount
)
2058 list_remove( &mapping
->entry
);
2059 munmap( mapping
->data
, mapping
->size
);
2060 RtlFreeHeap( GetProcessHeap(), 0, mapping
);
2064 static LONG
load_VDMX(struct gdi_font
*font
, LONG height
);
2066 /*************************************************************
2067 * freetype_destroy_font
2069 static void CDECL
freetype_destroy_font( struct gdi_font
*font
)
2071 struct font_private_data
*data
= font
->private;
2073 if (data
->ft_face
) pFT_Done_Face( data
->ft_face
);
2074 if (data
->mapping
) unmap_font_file( data
->mapping
);
2075 RtlFreeHeap( GetProcessHeap(), 0, data
);
2078 /*************************************************************
2079 * freetype_get_font_data
2081 static DWORD CDECL
freetype_get_font_data( struct gdi_font
*font
, DWORD table
, DWORD offset
,
2082 void *buf
, DWORD cbData
)
2084 FT_Face ft_face
= get_ft_face( font
);
2088 if (!FT_IS_SFNT(ft_face
)) return GDI_ERROR
;
2095 /* if font is a member of TTC, 'ttcf' tag allows reading from beginning of TTC file,
2096 0 tag means to read from start of collection member data. */
2097 if (font
->ttc_item_offset
)
2099 if (table
== MS_TTCF_TAG
)
2101 else if (table
== 0)
2102 offset
+= font
->ttc_item_offset
;
2105 /* make sure value of len is the value freetype says it needs */
2108 FT_ULong needed
= 0;
2109 err
= pFT_Load_Sfnt_Table(ft_face
, RtlUlongByteSwap(table
), offset
, NULL
, &needed
);
2110 if( !err
&& needed
< len
) len
= needed
;
2112 err
= pFT_Load_Sfnt_Table(ft_face
, RtlUlongByteSwap(table
), offset
, buf
, &len
);
2115 TRACE("Can't find table %s\n", debugstr_an((char*)&table
, 4));
2121 /*************************************************************
2124 * load the vdmx entry for the specified height
2154 static LONG
load_VDMX(struct gdi_font
*font
, LONG height
)
2158 BYTE devXRatio
, devYRatio
;
2159 USHORT numRecs
, numRatios
;
2160 DWORD result
, offset
= -1;
2164 result
= freetype_get_font_data(font
, MS_VDMX_TAG
, 0, &hdr
, sizeof(hdr
));
2166 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
2169 /* FIXME: need the real device aspect ratio */
2173 numRecs
= GET_BE_WORD(hdr
.numRecs
);
2174 numRatios
= GET_BE_WORD(hdr
.numRatios
);
2176 TRACE("version = %d numRecs = %d numRatios = %d\n", GET_BE_WORD(hdr
.version
), numRecs
, numRatios
);
2177 for(i
= 0; i
< numRatios
; i
++) {
2180 offset
= sizeof(hdr
) + (i
* sizeof(Ratios
));
2181 freetype_get_font_data(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
2184 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
2186 if (!ratio
.bCharSet
) continue;
2188 if((ratio
.xRatio
== 0 &&
2189 ratio
.yStartRatio
== 0 &&
2190 ratio
.yEndRatio
== 0) ||
2191 (devXRatio
== ratio
.xRatio
&&
2192 devYRatio
>= ratio
.yStartRatio
&&
2193 devYRatio
<= ratio
.yEndRatio
))
2197 offset
= sizeof(hdr
) + numRatios
* sizeof(ratio
) + i
* sizeof(group_offset
);
2198 freetype_get_font_data(font
, MS_VDMX_TAG
, offset
, &group_offset
, sizeof(group_offset
));
2199 offset
= GET_BE_WORD(group_offset
);
2204 if(offset
== -1) return 0;
2206 if(freetype_get_font_data(font
, MS_VDMX_TAG
, offset
, &group
, sizeof(group
)) != GDI_ERROR
) {
2208 BYTE startsz
, endsz
;
2211 recs
= GET_BE_WORD(group
.recs
);
2212 startsz
= group
.startsz
;
2213 endsz
= group
.endsz
;
2215 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
2217 vTable
= RtlAllocateHeap(GetProcessHeap(), 0, recs
* sizeof(VDMX_vTable
));
2218 result
= freetype_get_font_data(font
, MS_VDMX_TAG
, offset
+ sizeof(group
), vTable
, recs
* sizeof(VDMX_vTable
));
2219 if(result
== GDI_ERROR
) {
2220 FIXME("Failed to retrieve vTable\n");
2225 for(i
= 0; i
< recs
; i
++) {
2226 SHORT yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
2227 SHORT yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
2228 ppem
= GET_BE_WORD(vTable
[i
* 3]);
2230 if(yMax
+ -yMin
== height
) {
2233 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
2236 if(yMax
+ -yMin
> height
) {
2239 goto end
; /* failed */
2241 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
2242 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
2243 ppem
= GET_BE_WORD(vTable
[i
* 3]);
2244 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
2250 TRACE("ppem not found for height %d\n", height
);
2254 if(ppem
< startsz
|| ppem
> endsz
)
2260 for(i
= 0; i
< recs
; i
++) {
2262 yPelHeight
= GET_BE_WORD(vTable
[i
* 3]);
2264 if(yPelHeight
> ppem
)
2270 if(yPelHeight
== ppem
) {
2271 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
2272 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
2273 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem
, font
->yMax
, font
->yMin
);
2279 RtlFreeHeap(GetProcessHeap(), 0, vTable
);
2285 static BOOL
select_charmap(FT_Face ft_face
, FT_Encoding encoding
)
2287 FT_Error ft_err
= FT_Err_Invalid_CharMap_Handle
;
2288 FT_CharMap cmap0
, cmap1
, cmap2
, cmap3
, cmap_def
;
2291 cmap0
= cmap1
= cmap2
= cmap3
= cmap_def
= NULL
;
2293 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
2295 if (ft_face
->charmaps
[i
]->encoding
== encoding
)
2297 TRACE("found cmap with platform_id %u, encoding_id %u\n",
2298 ft_face
->charmaps
[i
]->platform_id
, ft_face
->charmaps
[i
]->encoding_id
);
2300 switch (ft_face
->charmaps
[i
]->platform_id
)
2303 cmap_def
= ft_face
->charmaps
[i
];
2305 case 0: /* Apple Unicode */
2306 cmap0
= ft_face
->charmaps
[i
];
2308 case 1: /* Macintosh */
2309 cmap1
= ft_face
->charmaps
[i
];
2312 cmap2
= ft_face
->charmaps
[i
];
2314 case 3: /* Microsoft */
2315 cmap3
= ft_face
->charmaps
[i
];
2320 if (cmap3
) /* prefer Microsoft cmap table */
2321 ft_err
= pFT_Set_Charmap(ft_face
, cmap3
);
2323 ft_err
= pFT_Set_Charmap(ft_face
, cmap1
);
2325 ft_err
= pFT_Set_Charmap(ft_face
, cmap2
);
2327 ft_err
= pFT_Set_Charmap(ft_face
, cmap0
);
2329 ft_err
= pFT_Set_Charmap(ft_face
, cmap_def
);
2332 return ft_err
== FT_Err_Ok
;
2336 static FT_Encoding
pick_charmap( FT_Face face
, int charset
)
2338 static const FT_Encoding regular_order
[] = { FT_ENCODING_UNICODE
, FT_ENCODING_APPLE_ROMAN
, FT_ENCODING_MS_SYMBOL
, 0 };
2339 static const FT_Encoding symbol_order
[] = { FT_ENCODING_MS_SYMBOL
, FT_ENCODING_UNICODE
, FT_ENCODING_APPLE_ROMAN
, 0 };
2340 const FT_Encoding
*encs
= regular_order
;
2342 if (charset
== SYMBOL_CHARSET
) encs
= symbol_order
;
2346 if (select_charmap( face
, *encs
)) break;
2350 if (!face
->charmap
&& face
->num_charmaps
)
2352 if (!pFT_Set_Charmap(face
, face
->charmaps
[0]))
2353 return face
->charmap
->encoding
;
2359 static BOOL
get_gasp_flags( struct gdi_font
*font
, WORD
*flags
)
2361 FT_Face ft_face
= get_ft_face( font
);
2363 WORD buf
[16]; /* Enough for seven ranges before we need to alloc */
2364 WORD
*alloced
= NULL
, *ptr
= buf
;
2365 WORD num_recs
, version
;
2369 size
= freetype_get_font_data( font
, MS_GASP_TAG
, 0, NULL
, 0 );
2370 if (size
== GDI_ERROR
) return FALSE
;
2371 if (size
< 4 * sizeof(WORD
)) return FALSE
;
2372 if (size
> sizeof(buf
))
2374 ptr
= alloced
= RtlAllocateHeap( GetProcessHeap(), 0, size
);
2375 if (!ptr
) return FALSE
;
2378 freetype_get_font_data( font
, MS_GASP_TAG
, 0, ptr
, size
);
2380 version
= GET_BE_WORD( *ptr
++ );
2381 num_recs
= GET_BE_WORD( *ptr
++ );
2383 if (version
> 1 || size
< (num_recs
* 2 + 2) * sizeof(WORD
))
2385 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version
, size
, num_recs
);
2391 *flags
= GET_BE_WORD( *(ptr
+ 1) );
2392 if (ft_face
->size
->metrics
.y_ppem
<= GET_BE_WORD( *ptr
)) break;
2395 TRACE( "got flags %04x for ppem %d\n", *flags
, ft_face
->size
->metrics
.y_ppem
);
2399 RtlFreeHeap( GetProcessHeap(), 0, alloced
);
2403 /*************************************************************
2404 * fontconfig_enum_family_fallbacks
2406 static BOOL CDECL
fontconfig_enum_family_fallbacks( DWORD pitch_and_family
, int index
,
2407 WCHAR buffer
[LF_FACESIZE
] )
2409 #ifdef SONAME_LIBFONTCONFIG
2414 if ((pitch_and_family
& FIXED_PITCH
) || (pitch_and_family
& 0xf0) == FF_MODERN
) pat
= create_family_pattern( "monospace", &pattern_fixed
);
2415 else if ((pitch_and_family
& 0xf0) == FF_ROMAN
) pat
= create_family_pattern( "serif", &pattern_serif
);
2416 else pat
= create_family_pattern( "sans", &pattern_sans
);
2418 if (!pat
) return FALSE
;
2419 if (pFcPatternGetString( pat
, FC_FAMILY
, index
, (FcChar8
**)&str
) != FcResultMatch
) return FALSE
;
2420 RtlUTF8ToUnicodeN( buffer
, (LF_FACESIZE
- 1) * sizeof(WCHAR
), &len
, str
, strlen(str
) );
2421 buffer
[len
/ sizeof(WCHAR
)] = 0;
2427 static DWORD
get_ttc_offset( FT_Face ft_face
, UINT face_index
)
2430 DWORD header
, offset
;
2432 /* see if it's a TTC */
2433 len
= sizeof(header
);
2434 if (pFT_Load_Sfnt_Table( ft_face
, 0, 0, (void *)&header
, &len
)) return 0;
2435 if (header
!= MS_TTCF_TAG
) return 0;
2437 len
= sizeof(offset
);
2438 if (pFT_Load_Sfnt_Table( ft_face
, 0, (3 + face_index
) * sizeof(DWORD
), (void *)&offset
, &len
))
2441 return GET_BE_DWORD( offset
);
2444 /*************************************************************
2445 * freetype_load_font
2447 static BOOL CDECL
freetype_load_font( struct gdi_font
*font
)
2449 struct font_private_data
*data
;
2450 INT width
= 0, height
;
2455 if (!(data
= RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*data
) ))) return FALSE
;
2456 font
->private = data
;
2460 char *filename
= get_unix_file_name( font
->file
);
2461 data
->mapping
= map_font_file( filename
);
2462 RtlFreeHeap( GetProcessHeap(), 0, filename
);
2465 WARN("failed to map %s\n", debugstr_w(font
->file
));
2468 data_ptr
= data
->mapping
->data
;
2469 data_size
= data
->mapping
->size
;
2473 data_ptr
= font
->data_ptr
;
2474 data_size
= font
->data_size
;
2477 if (pFT_New_Memory_Face( library
, data_ptr
, data_size
, font
->face_index
, &ft_face
)) return FALSE
;
2479 data
->ft_face
= ft_face
;
2480 font
->scalable
= FT_IS_SCALABLE( ft_face
);
2481 if (!font
->fs
.fsCsb
[0]) get_fontsig( ft_face
, &font
->fs
);
2482 if (!font
->ntmFlags
) font
->ntmFlags
= get_ntm_flags( ft_face
);
2483 if (!font
->aa_flags
) font
->aa_flags
= ADDFONT_AA_FLAGS( default_aa_flags
);
2484 if (!font
->otm
.otmpFamilyName
)
2486 font
->otm
.otmpFamilyName
= (char *)ft_face_get_family_name( ft_face
, system_lcid
);
2487 font
->otm
.otmpStyleName
= (char *)ft_face_get_style_name( ft_face
, system_lcid
);
2488 font
->otm
.otmpFaceName
= (char *)ft_face_get_full_name( ft_face
, system_lcid
);
2493 /* load the VDMX table if we have one */
2494 font
->ppem
= load_VDMX( font
, font
->lf
.lfHeight
);
2495 if (font
->ppem
== 0) font
->ppem
= calc_ppem_for_height( ft_face
, font
->lf
.lfHeight
);
2496 TRACE( "height %d => ppem %d\n", font
->lf
.lfHeight
, font
->ppem
);
2497 height
= font
->ppem
;
2498 font
->ttc_item_offset
= get_ttc_offset( ft_face
, font
->face_index
);
2499 font
->otm
.otmEMSquare
= ft_face
->units_per_EM
;
2503 struct bitmap_font_size size
;
2505 get_bitmap_size( ft_face
, &size
);
2506 width
= size
.x_ppem
>> 6;
2507 height
= size
.y_ppem
>> 6;
2508 font
->ppem
= height
;
2511 pFT_Set_Pixel_Sizes( ft_face
, width
, height
);
2512 pick_charmap( ft_face
, font
->charset
);
2517 /*************************************************************
2518 * freetype_get_aa_flags
2520 static UINT CDECL
freetype_get_aa_flags( struct gdi_font
*font
, UINT aa_flags
, BOOL antialias_fakes
)
2522 /* fixup the antialiasing flags for that font */
2525 case WINE_GGO_HRGB_BITMAP
:
2526 case WINE_GGO_HBGR_BITMAP
:
2527 case WINE_GGO_VRGB_BITMAP
:
2528 case WINE_GGO_VBGR_BITMAP
:
2529 if (is_subpixel_rendering_enabled()) break;
2530 aa_flags
= GGO_GRAY4_BITMAP
;
2532 case GGO_GRAY2_BITMAP
:
2533 case GGO_GRAY4_BITMAP
:
2534 case GGO_GRAY8_BITMAP
:
2535 case WINE_GGO_GRAY16_BITMAP
:
2536 if ((!antialias_fakes
|| (!font
->fake_bold
&& !font
->fake_italic
)) && is_hinting_enabled())
2539 if (get_gasp_flags( font
, &gasp_flags
) && !(gasp_flags
& GASP_DOGRAY
))
2541 TRACE( "font %s %d aa disabled by GASP\n",
2542 debugstr_w(font
->lf
.lfFaceName
), font
->lf
.lfHeight
);
2543 aa_flags
= GGO_BITMAP
;
2550 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
2552 pt
->x
.value
= vec
->x
>> 6;
2553 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
2554 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
2555 pt
->y
.value
= vec
->y
>> 6;
2556 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
2557 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
2560 static FT_UInt
get_glyph_index_symbol( struct gdi_font
*font
, UINT glyph
)
2562 FT_Face ft_face
= get_ft_face( font
);
2565 if (glyph
< 0x100) glyph
+= 0xf000;
2566 /* there are a number of old pre-Unicode "broken" TTFs, which
2567 do have symbols at U+00XX instead of U+f0XX */
2568 if (!(ret
= pFT_Get_Char_Index(ft_face
, glyph
)))
2569 ret
= pFT_Get_Char_Index(ft_face
, glyph
- 0xf000);
2574 /*************************************************************
2575 * freetype_get_glyph_index
2577 static BOOL CDECL
freetype_get_glyph_index( struct gdi_font
*font
, UINT
*glyph
, BOOL use_encoding
)
2579 FT_Face ft_face
= get_ft_face( font
);
2581 if (!use_encoding
^ (ft_face
->charmap
->encoding
== FT_ENCODING_NONE
)) return FALSE
;
2583 if (ft_face
->charmap
->encoding
== FT_ENCODING_MS_SYMBOL
)
2585 if (!(*glyph
= get_glyph_index_symbol( font
, *glyph
)))
2591 RtlUnicodeToMultiByteN( &ch
, 1, &len
, &wc
, sizeof(wc
) );
2592 if (len
) *glyph
= get_glyph_index_symbol( font
, (unsigned char)ch
);
2596 *glyph
= pFT_Get_Char_Index( ft_face
, *glyph
);
2600 /*************************************************************
2601 * freetype_get_default_glyph
2603 static UINT CDECL
freetype_get_default_glyph( struct gdi_font
*font
)
2605 FT_Face ft_face
= get_ft_face( font
);
2606 FT_WinFNT_HeaderRec winfnt
;
2609 if ((pOS2
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_os2
)))
2611 UINT glyph
= pOS2
->usDefaultChar
;
2612 if (glyph
) freetype_get_glyph_index( font
, &glyph
, TRUE
);
2615 if (!pFT_Get_WinFNT_Header( ft_face
, &winfnt
)) return winfnt
.default_char
+ winfnt
.first_char
;
2620 static inline BOOL
is_identity_FMAT2(const FMAT2
*matrix
)
2622 static const FMAT2 identity
= { 1.0, 0.0, 0.0, 1.0 };
2623 return !memcmp(matrix
, &identity
, sizeof(FMAT2
));
2626 static inline FT_Vector
normalize_vector(FT_Vector
*vec
)
2630 len
= pFT_Vector_Length(vec
);
2632 out
.x
= (vec
->x
<< 6) / len
;
2633 out
.y
= (vec
->y
<< 6) / len
;
2640 /* get_glyph_outline() glyph transform matrices index */
2648 static FT_Matrix
*get_transform_matrices( struct gdi_font
*font
, BOOL vertical
, const MAT2
*user_transform
,
2649 FT_Matrix matrices
[3] )
2651 static const FT_Matrix identity_mat
= { (1 << 16), 0, 0, (1 << 16) };
2652 BOOL needs_transform
= FALSE
;
2656 matrices
[matrix_unrotated
] = identity_mat
;
2658 /* Scaling factor */
2661 if (!freetype_set_outline_text_metrics( font
)) freetype_set_bitmap_text_metrics( font
);
2662 width_ratio
= (double)font
->aveWidth
;
2663 width_ratio
/= (double)font
->otm
.otmTextMetrics
.tmAveCharWidth
;
2666 width_ratio
= font
->scale_y
;
2668 /* Scaling transform */
2669 if (width_ratio
!= 1.0 || font
->scale_y
!= 1)
2671 FT_Matrix scale_mat
;
2672 scale_mat
.xx
= FT_FixedFromFloat( width_ratio
);
2675 scale_mat
.yy
= font
->scale_y
<< 16;
2677 pFT_Matrix_Multiply( &scale_mat
, &matrices
[matrix_unrotated
] );
2678 needs_transform
= TRUE
;
2681 /* Slant transform */
2682 if (font
->fake_italic
)
2684 FT_Matrix slant_mat
;
2685 slant_mat
.xx
= (1 << 16);
2686 slant_mat
.xy
= (1 << 16) >> 2;
2688 slant_mat
.yy
= (1 << 16);
2690 pFT_Matrix_Multiply( &slant_mat
, &matrices
[matrix_unrotated
] );
2691 needs_transform
= TRUE
;
2694 /* Rotation transform */
2695 matrices
[matrix_hori
] = matrices
[matrix_unrotated
];
2696 if (font
->scalable
&& font
->lf
.lfOrientation
% 3600)
2698 FT_Matrix rotation_mat
;
2701 pFT_Vector_Unit( &angle
, pFT_MulDiv( 1 << 16, font
->lf
.lfOrientation
, 10 ) );
2702 rotation_mat
.xx
= angle
.x
;
2703 rotation_mat
.xy
= -angle
.y
;
2704 rotation_mat
.yx
= angle
.y
;
2705 rotation_mat
.yy
= angle
.x
;
2706 pFT_Matrix_Multiply( &rotation_mat
, &matrices
[matrix_hori
] );
2707 needs_transform
= TRUE
;
2710 /* Vertical transform */
2711 matrices
[matrix_vert
] = matrices
[matrix_hori
];
2714 FT_Matrix vertical_mat
= { 0, -(1 << 16), 1 << 16, 0 }; /* 90 degrees rotation */
2716 pFT_Matrix_Multiply( &vertical_mat
, &matrices
[matrix_vert
] );
2717 needs_transform
= TRUE
;
2720 /* World transform */
2721 if (!is_identity_FMAT2( &font
->matrix
))
2723 FT_Matrix world_mat
;
2724 world_mat
.xx
= FT_FixedFromFloat( font
->matrix
.eM11
);
2725 world_mat
.xy
= -FT_FixedFromFloat( font
->matrix
.eM21
);
2726 world_mat
.yx
= -FT_FixedFromFloat( font
->matrix
.eM12
);
2727 world_mat
.yy
= FT_FixedFromFloat( font
->matrix
.eM22
);
2729 for (i
= 0; i
< 3; i
++)
2730 pFT_Matrix_Multiply( &world_mat
, &matrices
[i
] );
2731 needs_transform
= TRUE
;
2734 /* Extra transformation specified by caller */
2738 user_mat
.xx
= FT_FixedFromFIXED( user_transform
->eM11
);
2739 user_mat
.xy
= FT_FixedFromFIXED( user_transform
->eM21
);
2740 user_mat
.yx
= FT_FixedFromFIXED( user_transform
->eM12
);
2741 user_mat
.yy
= FT_FixedFromFIXED( user_transform
->eM22
);
2743 for (i
= 0; i
< 3; i
++)
2744 pFT_Matrix_Multiply( &user_mat
, &matrices
[i
] );
2745 needs_transform
= TRUE
;
2748 return needs_transform
? matrices
: NULL
;
2751 static BOOL
get_bold_glyph_outline(FT_GlyphSlot glyph
, LONG ppem
, FT_Glyph_Metrics
*metrics
)
2757 if(glyph
->format
!= FT_GLYPH_FORMAT_OUTLINE
)
2759 if(!pFT_Outline_Embolden
)
2762 strength
= pFT_MulDiv(ppem
, 1 << 6, 24);
2763 err
= pFT_Outline_Embolden(&glyph
->outline
, strength
);
2765 TRACE("FT_Ouline_Embolden returns %d\n", err
);
2769 pFT_Outline_Get_CBox(&glyph
->outline
, &bbox
);
2770 metrics
->width
= bbox
.xMax
- bbox
.xMin
;
2771 metrics
->height
= bbox
.yMax
- bbox
.yMin
;
2772 metrics
->horiBearingX
= bbox
.xMin
;
2773 metrics
->horiBearingY
= bbox
.yMax
;
2774 metrics
->vertBearingX
= metrics
->horiBearingX
- metrics
->horiAdvance
/ 2;
2775 metrics
->vertBearingY
= (metrics
->vertAdvance
- metrics
->height
) / 2;
2779 static inline BYTE
get_max_level( UINT format
)
2783 case GGO_GRAY2_BITMAP
: return 4;
2784 case GGO_GRAY4_BITMAP
: return 16;
2785 case GGO_GRAY8_BITMAP
: return 64;
2790 static FT_Vector
get_advance_metric( struct gdi_font
*font
, FT_Pos base_advance
,
2791 const FT_Matrix
*transMat
)
2794 FT_Fixed em_scale
= 0;
2795 BOOL fixed_pitch_full
= FALSE
;
2796 struct gdi_font
*incoming_font
= font
->base_font
? font
->base_font
: font
;
2798 adv
.x
= base_advance
;
2801 /* In fixed-pitch font, we adjust the fullwidth character advance so that
2802 they have double halfwidth character width. E.g. if the font is 19 ppem,
2803 we return 20 (not 19) for fullwidth characters as we return 10 for
2804 halfwidth characters. */
2805 if (freetype_set_outline_text_metrics(incoming_font
) &&
2806 !(incoming_font
->otm
.otmTextMetrics
.tmPitchAndFamily
& TMPF_FIXED_PITCH
)) {
2808 em_scale
= pFT_MulDiv(incoming_font
->ppem
, 1 << 16, get_ft_face(incoming_font
)->units_per_EM
);
2809 avg_advance
= pFT_MulFix(incoming_font
->ntmAvgWidth
, em_scale
);
2810 fixed_pitch_full
= (avg_advance
> 0 &&
2811 (base_advance
+ 63) >> 6 ==
2812 pFT_MulFix(incoming_font
->ntmAvgWidth
*2, em_scale
));
2813 if (fixed_pitch_full
&& !transMat
)
2814 adv
.x
= (avg_advance
* 2) << 6;
2818 pFT_Vector_Transform(&adv
, transMat
);
2819 if (fixed_pitch_full
&& adv
.y
== 0) {
2821 vec
.x
= incoming_font
->ntmAvgWidth
;
2823 pFT_Vector_Transform(&vec
, transMat
);
2824 adv
.x
= (pFT_MulFix(vec
.x
, em_scale
) * 2) << 6;
2828 if (font
->fake_bold
) {
2832 FT_Vector fake_bold_adv
, vec
= { 1 << 6, 0 };
2833 pFT_Vector_Transform(&vec
, transMat
);
2834 fake_bold_adv
= normalize_vector(&vec
);
2835 adv
.x
+= fake_bold_adv
.x
;
2836 adv
.y
+= fake_bold_adv
.y
;
2840 adv
.x
= (adv
.x
+ 63) & -64;
2841 adv
.y
= -((adv
.y
+ 63) & -64);
2845 static FT_BBox
get_transformed_bbox( const FT_Glyph_Metrics
*metrics
, const FT_Matrix
*matrices
)
2847 FT_BBox bbox
= { 0, 0, 0, 0 };
2851 bbox
.xMin
= (metrics
->horiBearingX
) & -64;
2852 bbox
.xMax
= (metrics
->horiBearingX
+ metrics
->width
+ 63) & -64;
2853 bbox
.yMax
= (metrics
->horiBearingY
+ 63) & -64;
2854 bbox
.yMin
= (metrics
->horiBearingY
- metrics
->height
) & -64;
2861 for (xc
= 0; xc
< 2; xc
++)
2863 for (yc
= 0; yc
< 2; yc
++)
2865 vec
.x
= metrics
->horiBearingX
+ xc
* metrics
->width
;
2866 vec
.y
= metrics
->horiBearingY
- yc
* metrics
->height
;
2867 TRACE( "Vec %ld, %ld\n", vec
.x
, vec
.y
);
2868 pFT_Vector_Transform( &vec
, &matrices
[matrix_vert
] );
2869 if (xc
== 0 && yc
== 0)
2871 bbox
.xMin
= bbox
.xMax
= vec
.x
;
2872 bbox
.yMin
= bbox
.yMax
= vec
.y
;
2876 if (vec
.x
< bbox
.xMin
) bbox
.xMin
= vec
.x
;
2877 else if (vec
.x
> bbox
.xMax
) bbox
.xMax
= vec
.x
;
2878 if (vec
.y
< bbox
.yMin
) bbox
.yMin
= vec
.y
;
2879 else if (vec
.y
> bbox
.yMax
) bbox
.yMax
= vec
.y
;
2883 bbox
.xMin
= bbox
.xMin
& -64;
2884 bbox
.xMax
= (bbox
.xMax
+ 63) & -64;
2885 bbox
.yMin
= bbox
.yMin
& -64;
2886 bbox
.yMax
= (bbox
.yMax
+ 63) & -64;
2887 TRACE( "transformed box: (%ld, %ld - %ld, %ld)\n", bbox
.xMin
, bbox
.yMax
, bbox
.xMax
, bbox
.yMin
);
2893 static void compute_metrics( struct gdi_font
*font
, FT_BBox bbox
, const FT_Glyph_Metrics
*metrics
,
2894 BOOL vertical
, BOOL vertical_metrics
, const FT_Matrix
*matrices
,
2895 GLYPHMETRICS
*gm
, ABC
*abc
)
2897 FT_Vector adv
, vec
, origin
;
2898 FT_Fixed base_advance
= vertical_metrics
? metrics
->vertAdvance
: metrics
->horiAdvance
;
2902 adv
= get_advance_metric( font
, base_advance
, NULL
);
2903 gm
->gmCellIncX
= adv
.x
>> 6;
2905 origin
.x
= bbox
.xMin
;
2906 origin
.y
= bbox
.yMax
;
2907 abc
->abcA
= origin
.x
>> 6;
2908 abc
->abcB
= (metrics
->width
+ 63) >> 6;
2914 if (vertical
&& freetype_set_outline_text_metrics( font
))
2916 if (vertical_metrics
)
2917 lsb
= metrics
->horiBearingY
+ metrics
->vertBearingY
;
2919 lsb
= metrics
->vertAdvance
+ (font
->otm
.otmDescent
<< 6);
2921 vec
.y
= font
->otm
.otmDescent
<< 6;
2922 TRACE( "Vec %ld,%ld\n", vec
.x
>>6, vec
.y
>>6 );
2923 pFT_Vector_Transform( &vec
, &matrices
[matrix_hori
] );
2924 origin
.x
= (vec
.x
+ bbox
.xMin
) & -64;
2925 origin
.y
= (vec
.y
+ bbox
.yMax
+ 63) & -64;
2926 lsb
-= metrics
->horiBearingY
;
2930 origin
.x
= bbox
.xMin
;
2931 origin
.y
= bbox
.yMax
;
2932 lsb
= metrics
->horiBearingX
;
2935 adv
= get_advance_metric( font
, base_advance
, &matrices
[matrix_hori
] );
2936 gm
->gmCellIncX
= adv
.x
>> 6;
2937 gm
->gmCellIncY
= adv
.y
>> 6;
2939 adv
= get_advance_metric( font
, base_advance
, &matrices
[matrix_unrotated
] );
2940 adv
.x
= pFT_Vector_Length( &adv
);
2945 pFT_Vector_Transform( &vec
, &matrices
[matrix_unrotated
] );
2946 if (lsb
> 0) abc
->abcA
= pFT_Vector_Length( &vec
) >> 6;
2947 else abc
->abcA
= -((pFT_Vector_Length( &vec
) + 63) >> 6);
2949 /* We use lsb again to avoid rounding errors */
2950 vec
.x
= lsb
+ (vertical
? metrics
->height
: metrics
->width
);
2952 pFT_Vector_Transform( &vec
, &matrices
[matrix_unrotated
] );
2953 abc
->abcB
= ((pFT_Vector_Length( &vec
) + 63) >> 6) - abc
->abcA
;
2955 if (!abc
->abcB
) abc
->abcB
= 1;
2956 abc
->abcC
= (adv
.x
>> 6) - abc
->abcA
- abc
->abcB
;
2958 gm
->gmptGlyphOrigin
.x
= origin
.x
>> 6;
2959 gm
->gmptGlyphOrigin
.y
= origin
.y
>> 6;
2960 gm
->gmBlackBoxX
= (bbox
.xMax
- bbox
.xMin
) >> 6;
2961 gm
->gmBlackBoxY
= (bbox
.yMax
- bbox
.yMin
) >> 6;
2962 if (!gm
->gmBlackBoxX
) gm
->gmBlackBoxX
= 1;
2963 if (!gm
->gmBlackBoxY
) gm
->gmBlackBoxY
= 1;
2965 TRACE( "gm: %u, %u, %s, %d, %d abc %d, %u, %d\n",
2966 gm
->gmBlackBoxX
, gm
->gmBlackBoxY
, wine_dbgstr_point(&gm
->gmptGlyphOrigin
),
2967 gm
->gmCellIncX
, gm
->gmCellIncY
, abc
->abcA
, abc
->abcB
, abc
->abcC
);
2971 static const BYTE masks
[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
2973 static DWORD
get_mono_glyph_bitmap( FT_GlyphSlot glyph
, FT_BBox bbox
,
2974 BOOL fake_bold
, const FT_Matrix
*matrices
,
2975 DWORD buflen
, BYTE
*buf
)
2977 DWORD width
= (bbox
.xMax
- bbox
.xMin
) >> 6;
2978 DWORD height
= (bbox
.yMax
- bbox
.yMin
) >> 6;
2979 DWORD pitch
= ((width
+ 31) >> 5) << 2;
2980 DWORD needed
= pitch
* height
;
2981 FT_Bitmap ft_bitmap
;
2985 if (!buf
|| !buflen
) return needed
;
2986 if (!needed
) return GDI_ERROR
; /* empty glyph */
2987 if (needed
> buflen
) return GDI_ERROR
;
2989 switch (glyph
->format
)
2991 case FT_GLYPH_FORMAT_BITMAP
:
2992 src
= glyph
->bitmap
.buffer
;
2994 w
= min( pitch
, (glyph
->bitmap
.width
+ 7) >> 3 );
2995 h
= min( height
, glyph
->bitmap
.rows
);
2999 memcpy( dst
, src
, w
);
3003 for (x
= 0; x
< w
; x
++)
3005 dst
[x
] = (dst
[x
] & 0x80) | (src
[x
] >> 1) | src
[x
];
3007 dst
[x
+ 1] = (src
[x
] & 0x01) << 7;
3010 src
+= glyph
->bitmap
.pitch
;
3015 case FT_GLYPH_FORMAT_OUTLINE
:
3016 ft_bitmap
.width
= width
;
3017 ft_bitmap
.rows
= height
;
3018 ft_bitmap
.pitch
= pitch
;
3019 ft_bitmap
.pixel_mode
= FT_PIXEL_MODE_MONO
;
3020 ft_bitmap
.buffer
= buf
;
3023 pFT_Outline_Transform( &glyph
->outline
, &matrices
[matrix_vert
] );
3024 pFT_Outline_Translate( &glyph
->outline
, -bbox
.xMin
, -bbox
.yMin
);
3026 /* Note: FreeType will only set 'black' bits for us. */
3027 memset( buf
, 0, buflen
);
3028 pFT_Outline_Get_Bitmap( library
, &glyph
->outline
, &ft_bitmap
);
3032 FIXME( "loaded glyph format %x\n", glyph
->format
);
3039 static DWORD
get_antialias_glyph_bitmap( FT_GlyphSlot glyph
, FT_BBox bbox
, UINT format
,
3040 BOOL fake_bold
, const FT_Matrix
*matrices
,
3041 DWORD buflen
, BYTE
*buf
)
3043 DWORD width
= (bbox
.xMax
- bbox
.xMin
) >> 6;
3044 DWORD height
= (bbox
.yMax
- bbox
.yMin
) >> 6;
3045 DWORD pitch
= (width
+ 3) / 4 * 4;
3046 DWORD needed
= pitch
* height
;
3047 FT_Bitmap ft_bitmap
;
3048 INT w
, h
, x
, max_level
;
3051 if (!buf
|| !buflen
) return needed
;
3052 if (!needed
) return GDI_ERROR
; /* empty glyph */
3053 if (needed
> buflen
) return GDI_ERROR
;
3055 max_level
= get_max_level( format
);
3057 switch (glyph
->format
)
3059 case FT_GLYPH_FORMAT_BITMAP
:
3060 src
= glyph
->bitmap
.buffer
;
3062 memset( buf
, 0, buflen
);
3064 w
= min( pitch
, glyph
->bitmap
.width
);
3065 h
= min( height
, glyph
->bitmap
.rows
);
3068 for (x
= 0; x
< w
; x
++)
3070 if (src
[x
/ 8] & masks
[x
% 8])
3073 if (fake_bold
&& x
+ 1 < pitch
) dst
[x
+ 1] = max_level
;
3076 src
+= glyph
->bitmap
.pitch
;
3081 case FT_GLYPH_FORMAT_OUTLINE
:
3082 ft_bitmap
.width
= width
;
3083 ft_bitmap
.rows
= height
;
3084 ft_bitmap
.pitch
= pitch
;
3085 ft_bitmap
.pixel_mode
= FT_PIXEL_MODE_GRAY
;
3086 ft_bitmap
.buffer
= buf
;
3089 pFT_Outline_Transform( &glyph
->outline
, &matrices
[matrix_vert
] );
3090 pFT_Outline_Translate( &glyph
->outline
, -bbox
.xMin
, -bbox
.yMin
);
3092 memset( buf
, 0, buflen
);
3093 pFT_Outline_Get_Bitmap( library
, &glyph
->outline
, &ft_bitmap
);
3095 if (max_level
!= 255)
3100 for (row
= 0, start
= buf
; row
< height
; row
++)
3102 for (col
= 0, ptr
= start
; col
< width
; col
++, ptr
++)
3103 *ptr
= (((int)*ptr
) * (max_level
+ 1)) / 256;
3110 FIXME("loaded glyph format %x\n", glyph
->format
);
3117 static DWORD
get_subpixel_glyph_bitmap( FT_GlyphSlot glyph
, FT_BBox bbox
, UINT format
,
3118 BOOL fake_bold
, const FT_Matrix
*matrices
,
3119 GLYPHMETRICS
*gm
, DWORD buflen
, BYTE
*buf
)
3121 DWORD width
= (bbox
.xMax
- bbox
.xMin
) >> 6;
3122 DWORD height
= (bbox
.yMax
- bbox
.yMin
) >> 6;
3123 DWORD pitch
, needed
= 0;
3127 switch (glyph
->format
)
3129 case FT_GLYPH_FORMAT_BITMAP
:
3131 needed
= pitch
* height
;
3133 if (!buf
|| !buflen
) break;
3134 if (!needed
) return GDI_ERROR
; /* empty glyph */
3135 if (needed
> buflen
) return GDI_ERROR
;
3137 src
= glyph
->bitmap
.buffer
;
3139 memset( buf
, 0, buflen
);
3141 w
= min( width
, glyph
->bitmap
.width
);
3142 h
= min( height
, glyph
->bitmap
.rows
);
3145 for (x
= 0; x
< w
; x
++)
3147 if ( src
[x
/ 8] & masks
[x
% 8] )
3149 ((unsigned int *)dst
)[x
] = ~0u;
3150 if (fake_bold
&& x
+ 1 < width
) ((unsigned int *)dst
)[x
+ 1] = ~0u;
3153 src
+= glyph
->bitmap
.pitch
;
3158 case FT_GLYPH_FORMAT_OUTLINE
:
3160 INT src_pitch
, src_width
, src_height
, x_shift
, y_shift
;
3161 INT sub_stride
, hmul
, vmul
;
3162 const INT
*sub_order
;
3163 const INT rgb_order
[3] = { 0, 1, 2 };
3164 const INT bgr_order
[3] = { 2, 1, 0 };
3165 FT_Render_Mode render_mode
=
3166 (format
== WINE_GGO_HRGB_BITMAP
||
3167 format
== WINE_GGO_HBGR_BITMAP
) ? FT_RENDER_MODE_LCD
: FT_RENDER_MODE_LCD_V
;
3169 if (!width
|| !height
) /* empty glyph */
3171 if (!buf
|| !buflen
) break;
3175 if ( render_mode
== FT_RENDER_MODE_LCD
)
3177 gm
->gmBlackBoxX
+= 2;
3178 gm
->gmptGlyphOrigin
.x
-= 1;
3179 bbox
.xMin
-= (1 << 6);
3183 gm
->gmBlackBoxY
+= 2;
3184 gm
->gmptGlyphOrigin
.y
+= 1;
3185 bbox
.yMax
+= (1 << 6);
3188 width
= gm
->gmBlackBoxX
;
3189 height
= gm
->gmBlackBoxY
;
3191 needed
= pitch
* height
;
3193 if (!buf
|| !buflen
) return needed
;
3194 if (needed
> buflen
) return GDI_ERROR
;
3197 pFT_Outline_Transform( &glyph
->outline
, &matrices
[matrix_vert
] );
3199 pFT_Render_Glyph( glyph
, render_mode
);
3201 src_pitch
= glyph
->bitmap
.pitch
;
3202 src_width
= glyph
->bitmap
.width
;
3203 src_height
= glyph
->bitmap
.rows
;
3204 src
= glyph
->bitmap
.buffer
;
3206 memset( buf
, 0, buflen
);
3208 sub_order
= (format
== WINE_GGO_HRGB_BITMAP
||
3209 format
== WINE_GGO_VRGB_BITMAP
) ? rgb_order
: bgr_order
;
3210 sub_stride
= render_mode
== FT_RENDER_MODE_LCD
? 1 : src_pitch
;
3211 hmul
= render_mode
== FT_RENDER_MODE_LCD
? 3 : 1;
3212 vmul
= render_mode
== FT_RENDER_MODE_LCD
? 1 : 3;
3214 x_shift
= glyph
->bitmap_left
- (bbox
.xMin
>> 6);
3217 src
+= hmul
* -x_shift
;
3218 src_width
-= hmul
* -x_shift
;
3220 else if ( x_shift
> 0 )
3222 dst
+= x_shift
* sizeof(unsigned int);
3226 y_shift
= (bbox
.yMax
>> 6) - glyph
->bitmap_top
;
3229 src
+= src_pitch
* vmul
* -y_shift
;
3230 src_height
-= vmul
* -y_shift
;
3232 else if ( y_shift
> 0 )
3234 dst
+= y_shift
* pitch
;
3238 w
= min( width
, src_width
/ hmul
);
3239 h
= min( height
, src_height
/ vmul
);
3242 for (x
= 0; x
< w
; x
++)
3244 ((unsigned int *)dst
)[x
] =
3245 ((unsigned int)src
[hmul
* x
+ sub_stride
* sub_order
[0]] << 16) |
3246 ((unsigned int)src
[hmul
* x
+ sub_stride
* sub_order
[1]] << 8) |
3247 ((unsigned int)src
[hmul
* x
+ sub_stride
* sub_order
[2]]);
3249 src
+= src_pitch
* vmul
;
3255 FIXME ( "loaded glyph format %x\n", glyph
->format
);
3262 static unsigned int get_native_glyph_outline(FT_Outline
*outline
, unsigned int buflen
, char *buf
)
3264 TTPOLYGONHEADER
*pph
;
3266 unsigned int needed
= 0, point
= 0, contour
, first_pt
;
3267 unsigned int pph_start
, cpfx
;
3270 for (contour
= 0; contour
< outline
->n_contours
; contour
++)
3272 /* Ignore contours containing one point */
3273 if (point
== outline
->contours
[contour
])
3280 pph
= (TTPOLYGONHEADER
*)(buf
+ needed
);
3284 pph
->dwType
= TT_POLYGON_TYPE
;
3285 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
3287 needed
+= sizeof(*pph
);
3289 while (point
<= outline
->contours
[contour
])
3291 ppc
= (TTPOLYCURVE
*)(buf
+ needed
);
3292 type
= outline
->tags
[point
] & FT_Curve_Tag_On
?
3293 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
3298 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
3301 } while (point
<= outline
->contours
[contour
] &&
3302 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
3303 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
3304 /* At the end of a contour Windows adds the start point, but
3306 if (point
> outline
->contours
[contour
] &&
3307 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
))
3310 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
3313 else if (point
<= outline
->contours
[contour
] &&
3314 outline
->tags
[point
] & FT_Curve_Tag_On
)
3316 /* add closing pt for bezier */
3318 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
3327 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
3330 pph
->cb
= needed
- pph_start
;
3335 static unsigned int get_bezier_glyph_outline(FT_Outline
*outline
, unsigned int buflen
, char *buf
)
3337 /* Convert the quadratic Beziers to cubic Beziers.
3338 The parametric eqn for a cubic Bezier is, from PLRM:
3339 r(t) = at^3 + bt^2 + ct + r0
3340 with the control points:
3345 A quadratic Bezier has the form:
3346 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3348 So equating powers of t leads to:
3349 r1 = 2/3 p1 + 1/3 p0
3350 r2 = 2/3 p1 + 1/3 p2
3351 and of course r0 = p0, r3 = p2
3353 int contour
, point
= 0, first_pt
;
3354 TTPOLYGONHEADER
*pph
;
3356 DWORD pph_start
, cpfx
, type
;
3357 FT_Vector cubic_control
[4];
3358 unsigned int needed
= 0;
3360 for (contour
= 0; contour
< outline
->n_contours
; contour
++)
3363 pph
= (TTPOLYGONHEADER
*)(buf
+ needed
);
3367 pph
->dwType
= TT_POLYGON_TYPE
;
3368 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
3370 needed
+= sizeof(*pph
);
3372 while (point
<= outline
->contours
[contour
])
3374 ppc
= (TTPOLYCURVE
*)(buf
+ needed
);
3375 type
= outline
->tags
[point
] & FT_Curve_Tag_On
?
3376 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
3380 if (type
== TT_PRIM_LINE
)
3383 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
3389 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
3392 /* FIXME: Possible optimization in endpoint calculation
3393 if there are two consecutive curves */
3394 cubic_control
[0] = outline
->points
[point
-1];
3395 if (!(outline
->tags
[point
-1] & FT_Curve_Tag_On
))
3397 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
3398 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
3399 cubic_control
[0].x
>>= 1;
3400 cubic_control
[0].y
>>= 1;
3402 if (point
+1 > outline
->contours
[contour
])
3403 cubic_control
[3] = outline
->points
[first_pt
];
3406 cubic_control
[3] = outline
->points
[point
+1];
3407 if (!(outline
->tags
[point
+1] & FT_Curve_Tag_On
))
3409 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
3410 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
3411 cubic_control
[3].x
>>= 1;
3412 cubic_control
[3].y
>>= 1;
3415 /* r1 = 1/3 p0 + 2/3 p1
3416 r2 = 1/3 p2 + 2/3 p1 */
3417 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
3418 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
3419 cubic_control
[2] = cubic_control
[1];
3420 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
3421 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
3422 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
3423 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
3426 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
3427 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
3428 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
3433 } while (point
<= outline
->contours
[contour
] &&
3434 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
3435 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
3436 /* At the end of a contour Windows adds the start point,
3437 but only for Beziers and we've already done that.
3439 if (point
<= outline
->contours
[contour
] &&
3440 outline
->tags
[point
] & FT_Curve_Tag_On
)
3442 /* This is the closing pt of a bezier, but we've already
3443 added it, so just inc point and carry on */
3451 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
3454 pph
->cb
= needed
- pph_start
;
3459 static FT_Int
get_load_flags( UINT format
)
3461 FT_Int load_flags
= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
3463 if (format
& GGO_UNHINTED
)
3464 return load_flags
| FT_LOAD_NO_HINTING
;
3466 switch (format
& ~GGO_GLYPH_INDEX
)
3469 load_flags
|= FT_LOAD_TARGET_MONO
;
3471 case GGO_GRAY2_BITMAP
:
3472 case GGO_GRAY4_BITMAP
:
3473 case GGO_GRAY8_BITMAP
:
3474 case WINE_GGO_GRAY16_BITMAP
:
3475 load_flags
|= FT_LOAD_TARGET_NORMAL
;
3477 case WINE_GGO_HRGB_BITMAP
:
3478 case WINE_GGO_HBGR_BITMAP
:
3479 load_flags
|= FT_LOAD_TARGET_LCD
;
3481 case WINE_GGO_VRGB_BITMAP
:
3482 case WINE_GGO_VBGR_BITMAP
:
3483 load_flags
|= FT_LOAD_TARGET_LCD_V
;
3490 /*************************************************************
3491 * freetype_get_glyph_outline
3493 static DWORD CDECL
freetype_get_glyph_outline( struct gdi_font
*font
, UINT glyph
, UINT format
,
3494 GLYPHMETRICS
*lpgm
, ABC
*abc
, DWORD buflen
, void *buf
,
3495 const MAT2
*lpmat
, BOOL tategaki
)
3497 struct gdi_font
*base_font
= font
->base_font
? font
->base_font
: font
;
3498 FT_Face ft_face
= get_ft_face( font
);
3499 FT_Glyph_Metrics metrics
;
3502 FT_Int load_flags
= get_load_flags(format
);
3503 FT_Matrix transform_matrices
[3], *matrices
= NULL
;
3504 BOOL vertical_metrics
;
3506 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
, buflen
, buf
, lpmat
);
3508 TRACE("font transform %f %f %f %f\n",
3509 font
->matrix
.eM11
, font
->matrix
.eM12
,
3510 font
->matrix
.eM21
, font
->matrix
.eM22
);
3512 format
&= ~GGO_UNHINTED
;
3514 matrices
= get_transform_matrices( font
, tategaki
, lpmat
, transform_matrices
);
3516 vertical_metrics
= (tategaki
&& FT_HAS_VERTICAL(ft_face
));
3517 /* there is a freetype bug where vertical metrics are only
3518 properly scaled and correct in 2.4.0 or greater */
3519 if (vertical_metrics
&& FT_SimpleVersion
< FT_VERSION_VALUE(2, 4, 0))
3520 vertical_metrics
= FALSE
;
3522 if (matrices
|| format
!= GGO_BITMAP
) load_flags
|= FT_LOAD_NO_BITMAP
;
3523 if (vertical_metrics
) load_flags
|= FT_LOAD_VERTICAL_LAYOUT
;
3525 err
= pFT_Load_Glyph(ft_face
, glyph
, load_flags
);
3526 if (err
&& !(load_flags
& FT_LOAD_NO_HINTING
))
3528 WARN("Failed to load glyph %#x, retrying without hinting. Error %#x.\n", glyph
, err
);
3529 load_flags
|= FT_LOAD_NO_HINTING
;
3530 err
= pFT_Load_Glyph(ft_face
, glyph
, load_flags
);
3534 WARN("Failed to load glyph %#x, error %#x.\n", glyph
, err
);
3538 metrics
= ft_face
->glyph
->metrics
;
3539 if(font
->fake_bold
) {
3540 if (!get_bold_glyph_outline(ft_face
->glyph
, font
->ppem
, &metrics
) && metrics
.width
)
3541 metrics
.width
+= 1 << 6;
3544 /* Some poorly-created fonts contain glyphs that exceed the boundaries set
3545 * by the text metrics. The proper behavior is to clip the glyph metrics to
3546 * fit within the maximums specified in the text metrics. */
3547 if (freetype_set_outline_text_metrics(base_font
) ||
3548 freetype_set_bitmap_text_metrics(base_font
)) {
3549 TEXTMETRICW
*ptm
= &base_font
->otm
.otmTextMetrics
;
3550 INT top
= min( metrics
.horiBearingY
, ptm
->tmAscent
<< 6 );
3551 INT bottom
= max( metrics
.horiBearingY
- metrics
.height
, -(ptm
->tmDescent
<< 6) );
3552 metrics
.horiBearingY
= top
;
3553 metrics
.height
= top
- bottom
;
3555 /* TODO: Are we supposed to clip the width as well...? */
3556 /* metrics.width = min( metrics.width, ptm->tmMaxCharWidth << 6 ); */
3559 bbox
= get_transformed_bbox( &metrics
, matrices
);
3560 compute_metrics( font
, bbox
, &metrics
, tategaki
, vertical_metrics
, matrices
, lpgm
, abc
);
3565 return 1; /* FIXME */
3568 return get_mono_glyph_bitmap( ft_face
->glyph
, bbox
, font
->fake_bold
,
3569 matrices
, buflen
, buf
);
3571 case GGO_GRAY2_BITMAP
:
3572 case GGO_GRAY4_BITMAP
:
3573 case GGO_GRAY8_BITMAP
:
3574 case WINE_GGO_GRAY16_BITMAP
:
3575 return get_antialias_glyph_bitmap( ft_face
->glyph
, bbox
, format
, font
->fake_bold
,
3576 matrices
, buflen
, buf
);
3578 case WINE_GGO_HRGB_BITMAP
:
3579 case WINE_GGO_HBGR_BITMAP
:
3580 case WINE_GGO_VRGB_BITMAP
:
3581 case WINE_GGO_VBGR_BITMAP
:
3582 return get_subpixel_glyph_bitmap( ft_face
->glyph
, bbox
, format
, font
->fake_bold
,
3583 matrices
, lpgm
, buflen
, buf
);
3586 if (ft_face
->glyph
->format
== ft_glyph_format_outline
)
3588 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
3591 if (buflen
== 0) buf
= NULL
;
3593 if (matrices
&& buf
)
3594 pFT_Outline_Transform( outline
, &matrices
[matrix_vert
] );
3596 needed
= get_native_glyph_outline(outline
, buflen
, NULL
);
3598 if (!buf
|| !buflen
) return needed
;
3599 if (needed
> buflen
) return GDI_ERROR
;
3600 return get_native_glyph_outline(outline
, buflen
, buf
);
3602 TRACE("loaded a bitmap\n");
3606 if (ft_face
->glyph
->format
== ft_glyph_format_outline
)
3608 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
3611 if (buflen
== 0) buf
= NULL
;
3613 if (matrices
&& buf
)
3614 pFT_Outline_Transform( outline
, &matrices
[matrix_vert
] );
3616 needed
= get_bezier_glyph_outline(outline
, buflen
, NULL
);
3618 if (!buf
|| !buflen
) return needed
;
3619 if (needed
> buflen
) return GDI_ERROR
;
3620 return get_bezier_glyph_outline(outline
, buflen
, buf
);
3622 TRACE("loaded a bitmap\n");
3626 FIXME("Unsupported format %d\n", format
);
3631 /*************************************************************
3632 * freetype_set_bitmap_text_metrics
3634 static BOOL CDECL
freetype_set_bitmap_text_metrics( struct gdi_font
*font
)
3636 FT_Face ft_face
= get_ft_face( font
);
3637 FT_WinFNT_HeaderRec winfnt_header
;
3639 if (font
->otm
.otmSize
) return TRUE
; /* already set */
3640 font
->otm
.otmSize
= offsetof( OUTLINETEXTMETRICW
, otmFiller
);
3642 #define TM font->otm.otmTextMetrics
3643 if(!pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
3645 TM
.tmHeight
= winfnt_header
.pixel_height
;
3646 TM
.tmAscent
= winfnt_header
.ascent
;
3647 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
3648 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
3649 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
3650 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
3651 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
3652 TM
.tmWeight
= winfnt_header
.weight
;
3654 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
3655 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
3656 TM
.tmFirstChar
= winfnt_header
.first_char
;
3657 TM
.tmLastChar
= winfnt_header
.last_char
;
3658 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
3659 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
3660 TM
.tmItalic
= winfnt_header
.italic
;
3661 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
3662 TM
.tmCharSet
= winfnt_header
.charset
;
3666 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
3667 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
3668 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
3669 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
3670 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
3671 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
3672 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
3673 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
3675 TM
.tmDigitizedAspectX
= 96; /* FIXME */
3676 TM
.tmDigitizedAspectY
= 96; /* FIXME */
3678 TM
.tmLastChar
= 255;
3679 TM
.tmDefaultChar
= 32;
3680 TM
.tmBreakChar
= 32;
3681 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
3682 /* NB inverted meaning of TMPF_FIXED_PITCH */
3683 TM
.tmPitchAndFamily
= FT_IS_FIXED_WIDTH(ft_face
) ? 0 : TMPF_FIXED_PITCH
;
3684 TM
.tmCharSet
= font
->charset
;
3686 TM
.tmUnderlined
= font
->lf
.lfUnderline
? 0xff : 0;
3687 TM
.tmStruckOut
= font
->lf
.lfStrikeOut
? 0xff : 0;
3690 TM
.tmWeight
= FW_BOLD
;
3697 static BOOL
face_has_symbol_charmap(FT_Face ft_face
)
3701 for(i
= 0; i
< ft_face
->num_charmaps
; i
++)
3703 if(ft_face
->charmaps
[i
]->encoding
== FT_ENCODING_MS_SYMBOL
)
3709 /*************************************************************
3710 * freetype_set_outline_text_metrics
3712 static BOOL CDECL
freetype_set_outline_text_metrics( struct gdi_font
*font
)
3714 FT_Face ft_face
= get_ft_face( font
);
3717 TT_HoriHeader
*pHori
;
3718 TT_Postscript
*pPost
;
3720 INT ascent
, descent
;
3723 TRACE("font=%p\n", font
);
3725 if (!font
->scalable
) return FALSE
;
3726 if (font
->otm
.otmSize
) return TRUE
; /* already set */
3728 /* note: we store actual pointers in the names instead of offsets,
3729 they are fixed up when returned to the app */
3730 if (!(font
->otm
.otmpFullName
= (char *)get_face_name( ft_face
, TT_NAME_ID_UNIQUE_ID
, system_lcid
)))
3732 static const WCHAR fake_nameW
[] = {'f','a','k','e',' ','n','a','m','e', 0};
3733 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w((WCHAR
*)font
->otm
.otmpFamilyName
));
3734 font
->otm
.otmpFullName
= (char *)strdupW(fake_nameW
);
3736 needed
= sizeof(font
->otm
) + (lstrlenW( (WCHAR
*)font
->otm
.otmpFamilyName
) + 1 +
3737 lstrlenW( (WCHAR
*)font
->otm
.otmpStyleName
) + 1 +
3738 lstrlenW( (WCHAR
*)font
->otm
.otmpFaceName
) + 1 +
3739 lstrlenW( (WCHAR
*)font
->otm
.otmpFullName
) + 1) * sizeof(WCHAR
);
3741 em_scale
= (FT_Fixed
)pFT_MulDiv(font
->ppem
, 1 << 16, ft_face
->units_per_EM
);
3743 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
3745 FIXME("Can't find OS/2 table - not TT font?\n");
3749 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
3751 FIXME("Can't find HHEA table - not TT font?\n");
3755 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
3757 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",
3758 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
3759 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
3760 pOS2
->xAvgCharWidth
,
3761 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
3762 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
3763 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
3765 font
->otm
.otmSize
= needed
;
3767 #define TM font->otm.otmTextMetrics
3769 windescent
= get_fixed_windescent(pOS2
->usWinDescent
);
3770 if(pOS2
->usWinAscent
+ windescent
== 0) {
3771 ascent
= pHori
->Ascender
;
3772 descent
= -pHori
->Descender
;
3774 ascent
= pOS2
->usWinAscent
;
3775 descent
= windescent
;
3778 font
->ntmAvgWidth
= pOS2
->xAvgCharWidth
;
3780 #define SCALE_X(x) (pFT_MulFix(x, em_scale))
3781 #define SCALE_Y(y) (pFT_MulFix(y, em_scale))
3784 TM
.tmAscent
= font
->yMax
;
3785 TM
.tmDescent
= -font
->yMin
;
3786 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
3788 TM
.tmAscent
= SCALE_Y(ascent
);
3789 TM
.tmDescent
= SCALE_Y(descent
);
3790 TM
.tmInternalLeading
= SCALE_Y(ascent
+ descent
- ft_face
->units_per_EM
);
3793 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
3796 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
3798 TM
.tmExternalLeading
= max(0, SCALE_Y(pHori
->Line_Gap
-
3799 ((ascent
+ descent
) -
3800 (pHori
->Ascender
- pHori
->Descender
))));
3802 TM
.tmAveCharWidth
= SCALE_X(pOS2
->xAvgCharWidth
);
3803 if (TM
.tmAveCharWidth
== 0) {
3804 TM
.tmAveCharWidth
= 1;
3806 TM
.tmMaxCharWidth
= SCALE_X(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
);
3807 TM
.tmWeight
= FW_REGULAR
;
3808 if (font
->fake_bold
)
3809 TM
.tmWeight
= FW_BOLD
;
3812 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)
3814 if (pOS2
->usWeightClass
> FW_MEDIUM
)
3815 TM
.tmWeight
= pOS2
->usWeightClass
;
3817 else if (pOS2
->usWeightClass
<= FW_MEDIUM
)
3818 TM
.tmWeight
= pOS2
->usWeightClass
;
3821 TM
.tmDigitizedAspectX
= 96; /* FIXME */
3822 TM
.tmDigitizedAspectY
= 96; /* FIXME */
3823 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
3824 * symbol range to 0 - f0ff
3827 if (face_has_symbol_charmap(ft_face
) || (pOS2
->usFirstCharIndex
>= 0xf000 && pOS2
->usFirstCharIndex
< 0xf100))
3830 switch (PRIMARYLANGID(system_lcid
))
3833 TM
.tmLastChar
= 0xf896;
3837 case LANG_LITHUANIAN
:
3838 TM
.tmLastChar
= 0xf8fd;
3841 TM
.tmLastChar
= 0xf0ff;
3843 TM
.tmBreakChar
= 0x20;
3844 TM
.tmDefaultChar
= 0x1f;
3848 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
; /* Should be the first char in the cmap */
3849 TM
.tmLastChar
= pOS2
->usLastCharIndex
; /* Should be min(cmap_last, os2_last) */
3851 if(pOS2
->usFirstCharIndex
<= 1)
3852 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
+ 2;
3853 else if (pOS2
->usFirstCharIndex
> 0xff)
3854 TM
.tmBreakChar
= 0x20;
3856 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
;
3857 TM
.tmDefaultChar
= TM
.tmBreakChar
- 1;
3859 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
3860 TM
.tmUnderlined
= font
->lf
.lfUnderline
? 255 : 0;
3861 TM
.tmStruckOut
= font
->lf
.lfStrikeOut
? 255 : 0;
3863 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
3864 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
3865 (pOS2
->version
== 0xFFFFU
||
3866 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
3867 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
3869 TM
.tmPitchAndFamily
= 0;
3871 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
])
3873 case PAN_FAMILY_SCRIPT
:
3874 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
3877 case PAN_FAMILY_DECORATIVE
:
3878 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
3883 case PAN_FAMILY_TEXT_DISPLAY
:
3884 case PAN_FAMILY_PICTORIAL
: /* symbol fonts get treated as if they were text */
3885 /* which is clearly not what the panose spec says. */
3887 if(TM
.tmPitchAndFamily
== 0 || /* fixed */
3888 pOS2
->panose
[PAN_PROPORTION_INDEX
] == PAN_PROP_MONOSPACED
)
3889 TM
.tmPitchAndFamily
= FF_MODERN
;
3892 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
])
3897 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
3900 case PAN_SERIF_COVE
:
3901 case PAN_SERIF_OBTUSE_COVE
:
3902 case PAN_SERIF_SQUARE_COVE
:
3903 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
3904 case PAN_SERIF_SQUARE
:
3905 case PAN_SERIF_THIN
:
3906 case PAN_SERIF_BONE
:
3907 case PAN_SERIF_EXAGGERATED
:
3908 case PAN_SERIF_TRIANGLE
:
3909 TM
.tmPitchAndFamily
|= FF_ROMAN
;
3912 case PAN_SERIF_NORMAL_SANS
:
3913 case PAN_SERIF_OBTUSE_SANS
:
3914 case PAN_SERIF_PERP_SANS
:
3915 case PAN_SERIF_FLARED
:
3916 case PAN_SERIF_ROUNDED
:
3917 TM
.tmPitchAndFamily
|= FF_SWISS
;
3924 if(FT_IS_SCALABLE(ft_face
))
3925 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
3927 if(FT_IS_SFNT(ft_face
))
3929 if (font
->ntmFlags
& NTM_PS_OPENTYPE
)
3930 TM
.tmPitchAndFamily
|= TMPF_DEVICE
;
3932 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
3935 TM
.tmCharSet
= font
->charset
;
3937 font
->otm
.otmFiller
= 0;
3938 memcpy(&font
->otm
.otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
3939 font
->otm
.otmfsSelection
= pOS2
->fsSelection
;
3940 if (font
->fake_italic
)
3941 font
->otm
.otmfsSelection
|= 1;
3942 if (font
->fake_bold
)
3943 font
->otm
.otmfsSelection
|= 1 << 5;
3944 /* Only return valid bits that define embedding and subsetting restrictions */
3945 font
->otm
.otmfsType
= pOS2
->fsType
& 0x30e;
3946 font
->otm
.otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
3947 font
->otm
.otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
3948 font
->otm
.otmItalicAngle
= 0; /* POST table */
3949 font
->otm
.otmAscent
= SCALE_Y(pOS2
->sTypoAscender
);
3950 font
->otm
.otmDescent
= SCALE_Y(pOS2
->sTypoDescender
);
3951 font
->otm
.otmLineGap
= SCALE_Y(pOS2
->sTypoLineGap
);
3952 font
->otm
.otmsCapEmHeight
= SCALE_Y(pOS2
->sCapHeight
);
3953 font
->otm
.otmsXHeight
= SCALE_Y(pOS2
->sxHeight
);
3954 font
->otm
.otmrcFontBox
.left
= SCALE_X(ft_face
->bbox
.xMin
);
3955 font
->otm
.otmrcFontBox
.right
= SCALE_X(ft_face
->bbox
.xMax
);
3956 font
->otm
.otmrcFontBox
.top
= SCALE_Y(ft_face
->bbox
.yMax
);
3957 font
->otm
.otmrcFontBox
.bottom
= SCALE_Y(ft_face
->bbox
.yMin
);
3958 font
->otm
.otmMacAscent
= TM
.tmAscent
;
3959 font
->otm
.otmMacDescent
= -TM
.tmDescent
;
3960 font
->otm
.otmMacLineGap
= SCALE_Y(pHori
->Line_Gap
);
3961 font
->otm
.otmusMinimumPPEM
= 0; /* TT Header */
3962 font
->otm
.otmptSubscriptSize
.x
= SCALE_X(pOS2
->ySubscriptXSize
);
3963 font
->otm
.otmptSubscriptSize
.y
= SCALE_Y(pOS2
->ySubscriptYSize
);
3964 font
->otm
.otmptSubscriptOffset
.x
= SCALE_X(pOS2
->ySubscriptXOffset
);
3965 font
->otm
.otmptSubscriptOffset
.y
= SCALE_Y(pOS2
->ySubscriptYOffset
);
3966 font
->otm
.otmptSuperscriptSize
.x
= SCALE_X(pOS2
->ySuperscriptXSize
);
3967 font
->otm
.otmptSuperscriptSize
.y
= SCALE_Y(pOS2
->ySuperscriptYSize
);
3968 font
->otm
.otmptSuperscriptOffset
.x
= SCALE_X(pOS2
->ySuperscriptXOffset
);
3969 font
->otm
.otmptSuperscriptOffset
.y
= SCALE_Y(pOS2
->ySuperscriptYOffset
);
3970 font
->otm
.otmsStrikeoutSize
= SCALE_Y(pOS2
->yStrikeoutSize
);
3971 font
->otm
.otmsStrikeoutPosition
= SCALE_Y(pOS2
->yStrikeoutPosition
);
3973 font
->otm
.otmsUnderscoreSize
= 0;
3974 font
->otm
.otmsUnderscorePosition
= 0;
3976 font
->otm
.otmsUnderscoreSize
= SCALE_Y(pPost
->underlineThickness
);
3977 font
->otm
.otmsUnderscorePosition
= SCALE_Y(pPost
->underlinePosition
);
3985 /*************************************************************
3986 * freetype_get_char_width_info
3988 static BOOL CDECL
freetype_get_char_width_info( struct gdi_font
*font
, struct char_width_info
*info
)
3990 FT_Face ft_face
= get_ft_face( font
);
3991 TT_HoriHeader
*pHori
;
3993 TRACE("%p, %p\n", font
, info
);
3995 if ((pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
)))
3997 FT_Fixed em_scale
= pFT_MulDiv(font
->ppem
, 1 << 16, ft_face
->units_per_EM
);
3998 info
->lsb
= (SHORT
)pFT_MulFix(pHori
->min_Left_Side_Bearing
, em_scale
);
3999 info
->rsb
= (SHORT
)pFT_MulFix(pHori
->min_Right_Side_Bearing
, em_scale
);
4006 /*************************************************************
4007 * freetype_get_unicode_ranges
4009 * Retrieve a list of supported Unicode ranges for a given font.
4010 * Can be called with NULL gs to calculate the buffer size. Returns
4011 * the number of ranges found.
4013 static DWORD CDECL
freetype_get_unicode_ranges( struct gdi_font
*font
, GLYPHSET
*gs
)
4015 FT_Face ft_face
= get_ft_face( font
);
4016 DWORD num_ranges
= 0;
4018 if (ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
4021 FT_ULong char_code
, char_code_prev
;
4024 char_code_prev
= char_code
= pFT_Get_First_Char(ft_face
, &glyph_code
);
4026 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
4027 ft_face
->num_glyphs
, glyph_code
, char_code
);
4029 if (!glyph_code
) return 0;
4033 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
4034 gs
->ranges
[0].cGlyphs
= 0;
4035 gs
->cGlyphsSupported
= 0;
4041 if (char_code
< char_code_prev
)
4043 ERR("expected increasing char code from FT_Get_Next_Char\n");
4046 if (char_code
- char_code_prev
> 1)
4051 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
4052 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
4053 gs
->cGlyphsSupported
++;
4058 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
4059 gs
->cGlyphsSupported
++;
4061 char_code_prev
= char_code
;
4062 char_code
= pFT_Get_Next_Char(ft_face
, char_code
, &glyph_code
);
4067 DWORD encoding
= RtlUlongByteSwap(ft_face
->charmap
->encoding
);
4068 FIXME("encoding %s not supported\n", debugstr_an((char *)&encoding
, 4));
4074 /*************************************************************************
4075 * Kerning support for TrueType fonts
4078 struct TT_kern_table
4084 struct TT_kern_subtable
4093 USHORT horizontal
: 1;
4095 USHORT cross_stream
: 1;
4096 USHORT override
: 1;
4097 USHORT reserved1
: 4;
4103 struct TT_format0_kern_subtable
4107 USHORT entrySelector
;
4118 static DWORD
parse_format0_kern_subtable(struct gdi_font
*font
,
4119 const struct TT_format0_kern_subtable
*tt_f0_ks
,
4120 const USHORT
*glyph_to_char
,
4121 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
4123 FT_Face ft_face
= get_ft_face( font
);
4125 const struct TT_kern_pair
*tt_kern_pair
;
4127 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, ft_face
->units_per_EM
);
4129 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
4131 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
4132 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
4133 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
4135 if (!kern_pair
|| !cPairs
)
4138 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
4140 nPairs
= min(nPairs
, cPairs
);
4142 for (i
= 0; i
< nPairs
; i
++)
4144 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
4145 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
4146 /* this algorithm appears to better match what Windows does */
4147 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
4148 if (kern_pair
->iKernAmount
< 0)
4150 kern_pair
->iKernAmount
-= ft_face
->units_per_EM
/ 2;
4151 kern_pair
->iKernAmount
-= font
->ppem
;
4153 else if (kern_pair
->iKernAmount
> 0)
4155 kern_pair
->iKernAmount
+= ft_face
->units_per_EM
/ 2;
4156 kern_pair
->iKernAmount
+= font
->ppem
;
4158 kern_pair
->iKernAmount
/= ft_face
->units_per_EM
;
4160 TRACE("left %u right %u value %d\n",
4161 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
4165 TRACE("copied %u entries\n", nPairs
);
4169 /*************************************************************
4170 * freetype_get_kerning_pairs
4172 static DWORD CDECL
freetype_get_kerning_pairs( struct gdi_font
*font
, KERNINGPAIR
**pairs
)
4174 FT_Face ft_face
= get_ft_face( font
);
4175 DWORD length
, count
= 0;
4177 const struct TT_kern_table
*tt_kern_table
;
4178 const struct TT_kern_subtable
*tt_kern_subtable
;
4180 USHORT
*glyph_to_char
;
4182 length
= freetype_get_font_data(font
, MS_KERN_TAG
, 0, NULL
, 0);
4184 if (length
== GDI_ERROR
)
4186 TRACE("no kerning data in the font\n");
4190 buf
= RtlAllocateHeap(GetProcessHeap(), 0, length
);
4193 freetype_get_font_data(font
, MS_KERN_TAG
, 0, buf
, length
);
4195 /* build a glyph index to char code map */
4196 glyph_to_char
= RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(USHORT
) * 65536);
4199 RtlFreeHeap(GetProcessHeap(), 0, buf
);
4203 if (ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
4209 char_code
= pFT_Get_First_Char(ft_face
, &glyph_code
);
4211 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
4212 ft_face
->num_glyphs
, glyph_code
, char_code
);
4216 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
4218 /* FIXME: This doesn't match what Windows does: it does some fancy
4219 * things with duplicate glyph index to char code mappings, while
4220 * we just avoid overriding existing entries.
4222 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
4223 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
4225 char_code
= pFT_Get_Next_Char(ft_face
, char_code
, &glyph_code
);
4230 DWORD encoding
= RtlUlongByteSwap(ft_face
->charmap
->encoding
);
4233 FIXME("encoding %s not supported\n", debugstr_an((char *)&encoding
, 4));
4234 for (n
= 0; n
<= 65535; n
++)
4235 glyph_to_char
[n
] = (USHORT
)n
;
4238 tt_kern_table
= buf
;
4239 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
4240 TRACE("version %u, nTables %u\n",
4241 GET_BE_WORD(tt_kern_table
->version
), nTables
);
4243 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
4245 for (i
= 0; i
< nTables
; i
++)
4247 struct TT_kern_subtable tt_kern_subtable_copy
;
4249 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
4250 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
4251 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
4253 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
4254 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
4255 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
4257 /* According to the TrueType specification this is the only format
4258 * that will be properly interpreted by Windows and OS/2
4260 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
4262 DWORD new_chunk
, old_total
= count
;
4264 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
4265 glyph_to_char
, NULL
, 0);
4269 *pairs
= RtlAllocateHeap(GetProcessHeap(), 0, count
* sizeof(**pairs
));
4271 *pairs
= RtlReAllocateHeap(GetProcessHeap(), 0, *pairs
, count
* sizeof(**pairs
));
4273 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
4274 glyph_to_char
, *pairs
+ old_total
, new_chunk
);
4277 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
4279 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
4282 RtlFreeHeap(GetProcessHeap(), 0, glyph_to_char
);
4283 RtlFreeHeap(GetProcessHeap(), 0, buf
);
4287 static const struct font_backend_funcs font_funcs
=
4289 freetype_load_fonts
,
4290 fontconfig_enum_family_fallbacks
,
4292 freetype_add_mem_font
,
4294 freetype_get_font_data
,
4295 freetype_get_aa_flags
,
4296 freetype_get_glyph_index
,
4297 freetype_get_default_glyph
,
4298 freetype_get_glyph_outline
,
4299 freetype_get_unicode_ranges
,
4300 freetype_get_char_width_info
,
4301 freetype_set_outline_text_metrics
,
4302 freetype_set_bitmap_text_metrics
,
4303 freetype_get_kerning_pairs
,
4304 freetype_destroy_font
4307 static NTSTATUS
init_freetype_lib( HMODULE module
, DWORD reason
, const void *ptr_in
, void *ptr_out
)
4309 callback_funcs
= ptr_in
;
4310 if (!init_freetype()) return STATUS_DLL_NOT_FOUND
;
4311 #ifdef SONAME_LIBFONTCONFIG
4314 NtQueryDefaultLocale( FALSE
, &system_lcid
);
4315 *(const struct font_backend_funcs
**)ptr_out
= &font_funcs
;
4316 return STATUS_SUCCESS
;
4319 #else /* HAVE_FREETYPE */
4321 static NTSTATUS
init_freetype_lib( HMODULE module
, DWORD reason
, const void *ptr_in
, void *ptr_out
)
4323 return STATUS_DLL_NOT_FOUND
;
4326 #endif /* HAVE_FREETYPE */
4328 NTSTATUS CDECL
__wine_init_unix_lib( HMODULE module
, DWORD reason
, const void *ptr_in
, void *ptr_out
)
4330 if (reason
!= DLL_PROCESS_ATTACH
) return STATUS_SUCCESS
;
4332 if (ptr_in
) return init_freetype_lib( module
, reason
, ptr_in
, ptr_out
);
4333 else return init_opengl_lib( module
, reason
, ptr_in
, ptr_out
);