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_mac_code_page( const FT_SfntName
*name
)
719 static CPTABLEINFO tables
[100];
720 int id
= name
->encoding_id
;
724 if (name
->encoding_id
== TT_MAC_ID_SIMPLIFIED_CHINESE
) id
= 8; /* special case */
725 if (id
>= ARRAY_SIZE(tables
)) return NULL
;
726 if (!tables
[id
].CodePage
)
728 if (NtGetNlsSectionPtr( 11, 10000 + id
, NULL
, (void **)&ptr
, &size
)) return NULL
;
729 RtlInitCodePageTable( ptr
, &tables
[id
] );
734 static int match_name_table_language( const FT_SfntName
*name
, LANGID lang
)
739 switch (name
->platform_id
)
741 case TT_PLATFORM_MICROSOFT
:
742 res
+= 5; /* prefer the Microsoft name */
743 switch (name
->encoding_id
)
745 case TT_MS_ID_UNICODE_CS
:
746 case TT_MS_ID_SYMBOL_CS
:
747 name_lang
= name
->language_id
;
753 case TT_PLATFORM_MACINTOSH
:
754 if (!get_mac_code_page( name
)) return 0;
755 if (name
->language_id
>= ARRAY_SIZE( mac_langid_table
)) return 0;
756 name_lang
= mac_langid_table
[name
->language_id
];
758 case TT_PLATFORM_APPLE_UNICODE
:
759 res
+= 2; /* prefer Unicode encodings */
760 switch (name
->encoding_id
)
762 case TT_APPLE_ID_DEFAULT
:
763 case TT_APPLE_ID_ISO_10646
:
764 case TT_APPLE_ID_UNICODE_2_0
:
765 if (name
->language_id
>= ARRAY_SIZE( mac_langid_table
)) return 0;
766 name_lang
= mac_langid_table
[name
->language_id
];
775 if (name_lang
== lang
) res
+= 30;
776 else if (PRIMARYLANGID( name_lang
) == PRIMARYLANGID( lang
)) res
+= 20;
777 else if (name_lang
== MAKELANGID( LANG_ENGLISH
, SUBLANG_DEFAULT
)) res
+= 10;
778 else if (lang
== MAKELANGID( LANG_NEUTRAL
, SUBLANG_NEUTRAL
)) res
+= 5 * (0x100000 - name_lang
);
782 static WCHAR
*copy_name_table_string( const FT_SfntName
*name
)
788 switch (name
->platform_id
)
790 case TT_PLATFORM_APPLE_UNICODE
:
791 case TT_PLATFORM_MICROSOFT
:
792 ret
= RtlAllocateHeap( GetProcessHeap(), 0, name
->string_len
+ sizeof(WCHAR
) );
793 for (i
= 0; i
< name
->string_len
/ 2; i
++)
794 ret
[i
] = (name
->string
[i
* 2] << 8) | name
->string
[i
* 2 + 1];
797 case TT_PLATFORM_MACINTOSH
:
798 if (!(cp
= get_mac_code_page( name
))) return NULL
;
799 ret
= RtlAllocateHeap( GetProcessHeap(), 0, (name
->string_len
+ 1) * sizeof(WCHAR
) );
800 RtlCustomCPToUnicodeN( cp
, ret
, name
->string_len
* sizeof(WCHAR
), &i
,
801 (char *)name
->string
, name
->string_len
);
802 ret
[i
/ sizeof(WCHAR
)] = 0;
808 static WCHAR
*get_face_name(FT_Face ft_face
, FT_UShort name_id
, LANGID language_id
)
811 FT_UInt num_names
, name_index
;
812 int res
, best_lang
= 0, best_index
= -1;
814 if (!FT_IS_SFNT(ft_face
)) return NULL
;
816 num_names
= pFT_Get_Sfnt_Name_Count( ft_face
);
818 for (name_index
= 0; name_index
< num_names
; name_index
++)
820 if (pFT_Get_Sfnt_Name( ft_face
, name_index
, &name
)) continue;
821 if (name
.name_id
!= name_id
) continue;
822 res
= match_name_table_language( &name
, language_id
);
826 best_index
= name_index
;
830 if (best_index
!= -1 && !pFT_Get_Sfnt_Name( ft_face
, best_index
, &name
))
832 WCHAR
*ret
= copy_name_table_string( &name
);
833 TRACE( "name %u found platform %u lang %04x %s\n",
834 name_id
, name
.platform_id
, name
.language_id
, debugstr_w( ret
));
840 static WCHAR
*ft_face_get_family_name( FT_Face ft_face
, LANGID langid
)
844 if ((family_name
= get_face_name( ft_face
, TT_NAME_ID_FONT_FAMILY
, langid
)))
847 return towstr( ft_face
->family_name
);
850 static WCHAR
*ft_face_get_style_name( FT_Face ft_face
, LANGID langid
)
854 if ((style_name
= get_face_name( ft_face
, TT_NAME_ID_FONT_SUBFAMILY
, langid
)))
857 return towstr( ft_face
->style_name
);
860 static WCHAR
*ft_face_get_full_name( FT_Face ft_face
, LANGID langid
)
862 static const WCHAR space_w
[] = {' ',0};
863 WCHAR
*full_name
, *style_name
;
866 if ((full_name
= get_face_name( ft_face
, TT_NAME_ID_FULL_NAME
, langid
)))
869 full_name
= ft_face_get_family_name( ft_face
, langid
);
870 style_name
= ft_face_get_style_name( ft_face
, langid
);
872 length
= lstrlenW( full_name
) + lstrlenW( space_w
) + lstrlenW( style_name
) + 1;
873 full_name
= RtlReAllocateHeap( GetProcessHeap(), 0, full_name
, length
* sizeof(WCHAR
) );
875 lstrcatW( full_name
, space_w
);
876 lstrcatW( full_name
, style_name
);
877 RtlFreeHeap( GetProcessHeap(), 0, style_name
);
879 WARN( "full name not found, using %s instead\n", debugstr_w(full_name
) );
883 static inline FT_Fixed
get_font_version( FT_Face ft_face
)
885 FT_Fixed version
= 0;
888 header
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_head
);
889 if (header
) version
= header
->Font_Revision
;
894 static inline DWORD
get_ntm_flags( FT_Face ft_face
)
897 FT_ULong table_size
= 0;
898 FT_WinFNT_HeaderRec winfnt_header
;
900 if (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) flags
|= NTM_ITALIC
;
901 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
) flags
|= NTM_BOLD
;
903 /* fixup the flag for our fake-bold implementation. */
904 if (!FT_IS_SCALABLE( ft_face
) &&
905 !pFT_Get_WinFNT_Header( ft_face
, &winfnt_header
) &&
906 winfnt_header
.weight
> FW_NORMAL
)
909 if (flags
== 0) flags
= NTM_REGULAR
;
911 if (!pFT_Load_Sfnt_Table( ft_face
, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL
, &table_size
))
912 flags
|= NTM_PS_OPENTYPE
;
917 static inline void get_bitmap_size( FT_Face ft_face
, struct bitmap_font_size
*face_size
)
919 My_FT_Bitmap_Size
*size
;
920 FT_WinFNT_HeaderRec winfnt_header
;
922 size
= (My_FT_Bitmap_Size
*)ft_face
->available_sizes
;
923 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
924 size
->height
, size
->width
, size
->size
>> 6,
925 size
->x_ppem
>> 6, size
->y_ppem
>> 6);
926 face_size
->height
= size
->height
;
927 face_size
->width
= size
->width
;
928 face_size
->size
= size
->size
;
929 face_size
->x_ppem
= size
->x_ppem
;
930 face_size
->y_ppem
= size
->y_ppem
;
932 if (!pFT_Get_WinFNT_Header( ft_face
, &winfnt_header
)) {
933 face_size
->internal_leading
= winfnt_header
.internal_leading
;
934 if (winfnt_header
.external_leading
> 0 &&
935 (face_size
->height
==
936 winfnt_header
.pixel_height
+ winfnt_header
.external_leading
))
937 face_size
->height
= winfnt_header
.pixel_height
;
941 static inline void get_fontsig( FT_Face ft_face
, FONTSIGNATURE
*fs
)
944 FT_WinFNT_HeaderRec winfnt_header
;
947 memset( fs
, 0, sizeof(*fs
) );
949 os2
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_os2
);
952 fs
->fsUsb
[0] = os2
->ulUnicodeRange1
;
953 fs
->fsUsb
[1] = os2
->ulUnicodeRange2
;
954 fs
->fsUsb
[2] = os2
->ulUnicodeRange3
;
955 fs
->fsUsb
[3] = os2
->ulUnicodeRange4
;
957 if (os2
->version
== 0)
959 if (os2
->usFirstCharIndex
>= 0xf000 && os2
->usFirstCharIndex
< 0xf100)
960 fs
->fsCsb
[0] = FS_SYMBOL
;
962 fs
->fsCsb
[0] = FS_LATIN1
;
966 fs
->fsCsb
[0] = os2
->ulCodePageRange1
;
967 fs
->fsCsb
[1] = os2
->ulCodePageRange2
;
972 if (!pFT_Get_WinFNT_Header( ft_face
, &winfnt_header
))
974 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header
.pixel_height
, winfnt_header
.charset
,
975 winfnt_header
.vertical_resolution
,winfnt_header
.horizontal_resolution
, winfnt_header
.nominal_point_size
);
976 switch (winfnt_header
.charset
)
978 case ANSI_CHARSET
: fs
->fsCsb
[0] = FS_LATIN1
; break;
979 case EASTEUROPE_CHARSET
: fs
->fsCsb
[0] = FS_LATIN2
; break;
980 case RUSSIAN_CHARSET
: fs
->fsCsb
[0] = FS_CYRILLIC
; break;
981 case GREEK_CHARSET
: fs
->fsCsb
[0] = FS_GREEK
; break;
982 case TURKISH_CHARSET
: fs
->fsCsb
[0] = FS_TURKISH
; break;
983 case HEBREW_CHARSET
: fs
->fsCsb
[0] = FS_HEBREW
; break;
984 case ARABIC_CHARSET
: fs
->fsCsb
[0] = FS_ARABIC
; break;
985 case BALTIC_CHARSET
: fs
->fsCsb
[0] = FS_BALTIC
; break;
986 case VIETNAMESE_CHARSET
: fs
->fsCsb
[0] = FS_VIETNAMESE
; break;
987 case THAI_CHARSET
: fs
->fsCsb
[0] = FS_THAI
; break;
988 case SHIFTJIS_CHARSET
: fs
->fsCsb
[0] = FS_JISJAPAN
; break;
989 case GB2312_CHARSET
: fs
->fsCsb
[0] = FS_CHINESESIMP
; break;
990 case HANGEUL_CHARSET
: fs
->fsCsb
[0] = FS_WANSUNG
; break;
991 case CHINESEBIG5_CHARSET
: fs
->fsCsb
[0] = FS_CHINESETRAD
; break;
992 case JOHAB_CHARSET
: fs
->fsCsb
[0] = FS_JOHAB
; break;
993 case SYMBOL_CHARSET
: fs
->fsCsb
[0] = FS_SYMBOL
; break;
998 if (fs
->fsCsb
[0] == 0)
1000 /* let's see if we can find any interesting cmaps */
1001 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
1003 switch (ft_face
->charmaps
[i
]->encoding
)
1005 case FT_ENCODING_UNICODE
:
1006 case FT_ENCODING_APPLE_ROMAN
:
1007 fs
->fsCsb
[0] |= FS_LATIN1
;
1009 case FT_ENCODING_MS_SYMBOL
:
1010 fs
->fsCsb
[0] |= FS_SYMBOL
;
1019 static FT_Face
new_ft_face( const char *file
, void *font_data_ptr
, DWORD font_data_size
,
1020 FT_Long face_index
, BOOL allow_bitmap
)
1028 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
1029 err
= pFT_New_Face(library
, file
, face_index
, &ft_face
);
1033 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr
, font_data_size
, face_index
);
1034 err
= pFT_New_Memory_Face(library
, font_data_ptr
, font_data_size
, face_index
, &ft_face
);
1039 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file
), font_data_ptr
, err
);
1043 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1044 if (!FT_IS_SCALABLE( ft_face
) && FT_SimpleVersion
< FT_VERSION_VALUE(2, 1, 9))
1046 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1050 if (!FT_IS_SFNT( ft_face
))
1052 if (FT_IS_SCALABLE( ft_face
) || !allow_bitmap
)
1054 WARN("Ignoring font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1060 if (!(pOS2
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_os2
)) ||
1061 !pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_hhea
) ||
1062 !pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_head
))
1064 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1065 "Skipping this font.\n", debugstr_a(file
), font_data_ptr
);
1069 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1070 we don't want to load these. */
1071 if (!memcmp( pOS2
->achVendID
, "Wine", sizeof(pOS2
->achVendID
) ))
1075 if (!pFT_Load_Sfnt_Table( ft_face
, FT_MAKE_TAG('E','B','S','C'), 0, NULL
, &len
))
1077 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file
));
1083 if (!ft_face
->family_name
|| !ft_face
->style_name
)
1085 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file
), font_data_ptr
);
1091 pFT_Done_Face( ft_face
);
1095 static int add_unix_face( const char *unix_name
, const WCHAR
*file
, void *data_ptr
, SIZE_T data_size
,
1096 DWORD face_index
, DWORD flags
, DWORD
*num_faces
)
1098 struct bitmap_font_size size
;
1101 WCHAR
*family_name
, *second_name
, *style_name
, *full_name
;
1104 if (num_faces
) *num_faces
= 0;
1106 if (!(ft_face
= new_ft_face( unix_name
, data_ptr
, data_size
, face_index
, flags
& ADDFONT_ALLOW_BITMAP
)))
1109 if (ft_face
->family_name
[0] == '.') /* Ignore fonts with names beginning with a dot */
1111 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(unix_name
));
1112 pFT_Done_Face( ft_face
);
1116 family_name
= ft_face_get_family_name( ft_face
, system_lcid
);
1117 second_name
= ft_face_get_family_name( ft_face
, MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
) );
1118 style_name
= ft_face_get_style_name( ft_face
, system_lcid
);
1119 full_name
= ft_face_get_full_name( ft_face
, system_lcid
);
1121 /* try to find another secondary name, preferring the lowest langids */
1122 if (!RtlCompareUnicodeStrings( family_name
, lstrlenW(family_name
),
1123 second_name
, lstrlenW(second_name
), TRUE
))
1125 RtlFreeHeap( GetProcessHeap(), 0, second_name
);
1126 second_name
= ft_face_get_family_name( ft_face
, MAKELANGID(LANG_NEUTRAL
, SUBLANG_NEUTRAL
) );
1127 if (!RtlCompareUnicodeStrings( family_name
, lstrlenW(family_name
),
1128 second_name
, lstrlenW(second_name
), TRUE
))
1130 RtlFreeHeap( GetProcessHeap(), 0, second_name
);
1135 get_fontsig( ft_face
, &fs
);
1136 if (!FT_IS_SCALABLE( ft_face
)) get_bitmap_size( ft_face
, &size
);
1137 if (!HIWORD( flags
)) flags
|= ADDFONT_AA_FLAGS( default_aa_flags
);
1139 ret
= callback_funcs
->add_gdi_face( family_name
, second_name
, style_name
, full_name
, file
,
1140 data_ptr
, data_size
, face_index
, fs
, get_ntm_flags( ft_face
),
1141 get_font_version( ft_face
), flags
,
1142 FT_IS_SCALABLE(ft_face
) ? NULL
: &size
);
1144 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1145 fs
.fsCsb
[0], fs
.fsCsb
[1], fs
.fsUsb
[0], fs
.fsUsb
[1], fs
.fsUsb
[2], fs
.fsUsb
[3]);
1147 RtlFreeHeap( GetProcessHeap(), 0, family_name
);
1148 RtlFreeHeap( GetProcessHeap(), 0, second_name
);
1149 RtlFreeHeap( GetProcessHeap(), 0, style_name
);
1150 RtlFreeHeap( GetProcessHeap(), 0, full_name
);
1152 if (num_faces
) *num_faces
= ft_face
->num_faces
;
1153 pFT_Done_Face( ft_face
);
1157 static WCHAR
*get_dos_file_name( LPCSTR str
)
1160 SIZE_T len
= strlen(str
) + 1;
1162 len
+= 8; /* \??\unix prefix */
1163 if (!(buffer
= RtlAllocateHeap( GetProcessHeap(), 0, len
* sizeof(WCHAR
) ))) return NULL
;
1164 if (wine_unix_to_nt_file_name( str
, buffer
, &len
))
1166 RtlFreeHeap( GetProcessHeap(), 0, buffer
);
1169 if (buffer
[5] == ':')
1171 /* get rid of the \??\ prefix */
1172 /* FIXME: should implement RtlNtPathNameToDosPathName and use that instead */
1173 memmove( buffer
, buffer
+ 4, (len
- 4) * sizeof(WCHAR
) );
1175 else buffer
[1] = '\\';
1179 static char *get_unix_file_name( LPCWSTR dosW
)
1181 UNICODE_STRING nt_name
;
1186 if (!RtlDosPathNameToNtPathName_U( dosW
, &nt_name
, NULL
, NULL
)) return NULL
;
1189 if (!(buffer
= RtlAllocateHeap( GetProcessHeap(), 0, size
)))
1191 RtlFreeUnicodeString( &nt_name
);
1194 status
= wine_nt_to_unix_file_name( &nt_name
, buffer
, &size
, FILE_OPEN_IF
);
1195 if (status
!= STATUS_BUFFER_TOO_SMALL
) break;
1196 RtlFreeHeap( GetProcessHeap(), 0, buffer
);
1198 RtlFreeUnicodeString( &nt_name
);
1199 if (status
&& status
!= STATUS_NO_SUCH_FILE
)
1201 RtlFreeHeap( GetProcessHeap(), 0, buffer
);
1202 RtlSetLastWin32ErrorAndNtStatusFromNtStatus( status
);
1208 static INT
AddFontToList(const WCHAR
*dos_name
, const char *unix_name
, void *font_data_ptr
,
1209 DWORD font_data_size
, DWORD flags
)
1211 DWORD face_index
= 0, num_faces
;
1213 WCHAR
*filename
= NULL
;
1215 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1216 assert(unix_name
|| !(flags
& ADDFONT_EXTERNAL_FONT
));
1218 #ifdef HAVE_CARBON_CARBON_H
1221 char **mac_list
= expand_mac_font(unix_name
);
1224 BOOL had_one
= FALSE
;
1226 for(cursor
= mac_list
; *cursor
; cursor
++)
1229 AddFontToList(NULL
, *cursor
, NULL
, 0, flags
);
1230 RtlFreeHeap(GetProcessHeap(), 0, *cursor
);
1232 RtlFreeHeap(GetProcessHeap(), 0, mac_list
);
1237 #endif /* HAVE_CARBON_CARBON_H */
1239 if (!dos_name
&& unix_name
) dos_name
= filename
= get_dos_file_name( unix_name
);
1242 ret
+= add_unix_face( unix_name
, dos_name
, font_data_ptr
, font_data_size
, face_index
, flags
, &num_faces
);
1243 while (num_faces
> ++face_index
);
1245 RtlFreeHeap( GetProcessHeap(), 0, filename
);
1249 /*************************************************************
1252 static INT CDECL
freetype_add_font( const WCHAR
*file
, DWORD flags
)
1255 char *unixname
= get_unix_file_name( file
);
1259 ret
= AddFontToList( file
, unixname
, NULL
, 0, flags
);
1260 RtlFreeHeap( GetProcessHeap(), 0, unixname
);
1265 /*************************************************************
1266 * freetype_add_mem_font
1268 static INT CDECL
freetype_add_mem_font( void *ptr
, SIZE_T size
, DWORD flags
)
1270 return AddFontToList( NULL
, NULL
, ptr
, size
, flags
);
1274 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
1277 struct dirent
*dent
;
1278 char path
[MAX_PATH
];
1280 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
1282 dir
= opendir(dirname
);
1284 WARN("Can't open directory %s\n", debugstr_a(dirname
));
1287 while((dent
= readdir(dir
)) != NULL
) {
1288 struct stat statbuf
;
1290 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
1293 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
1295 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
1297 if(stat(path
, &statbuf
) == -1)
1299 WARN("Can't stat %s\n", debugstr_a(path
));
1302 if(S_ISDIR(statbuf
.st_mode
))
1303 ReadFontDir(path
, external_fonts
);
1306 DWORD addfont_flags
= ADDFONT_ADD_TO_CACHE
;
1307 if(external_fonts
) addfont_flags
|= ADDFONT_EXTERNAL_FONT
;
1308 AddFontToList(NULL
, path
, NULL
, 0, addfont_flags
);
1316 #ifdef SONAME_LIBFONTCONFIG
1318 static BOOL fontconfig_enabled
;
1319 static FcPattern
*pattern_serif
;
1320 static FcPattern
*pattern_fixed
;
1321 static FcPattern
*pattern_sans
;
1323 static UINT
parse_aa_pattern( FcPattern
*pattern
)
1329 if (pFcPatternGetBool( pattern
, FC_ANTIALIAS
, 0, &antialias
) == FcResultMatch
)
1330 aa_flags
= antialias
? GGO_GRAY4_BITMAP
: GGO_BITMAP
;
1332 if (pFcPatternGetInteger( pattern
, FC_RGBA
, 0, &rgba
) == FcResultMatch
)
1336 case FC_RGBA_RGB
: aa_flags
= WINE_GGO_HRGB_BITMAP
; break;
1337 case FC_RGBA_BGR
: aa_flags
= WINE_GGO_HBGR_BITMAP
; break;
1338 case FC_RGBA_VRGB
: aa_flags
= WINE_GGO_VRGB_BITMAP
; break;
1339 case FC_RGBA_VBGR
: aa_flags
= WINE_GGO_VBGR_BITMAP
; break;
1340 case FC_RGBA_NONE
: aa_flags
= aa_flags
? aa_flags
: GGO_GRAY4_BITMAP
; break;
1346 static FcPattern
*create_family_pattern( const char *name
)
1348 FcPattern
*ret
, *pattern
= pFcPatternCreate();
1351 pFcPatternAddString( pattern
, FC_FAMILY
, (const FcChar8
*)name
);
1352 pFcPatternAddString( pattern
, FC_NAMELANG
, (const FcChar8
*)"en-us" );
1353 pFcPatternAddString( pattern
, FC_PRGNAME
, (const FcChar8
*)"wine" );
1354 pFcConfigSubstitute( NULL
, pattern
, FcMatchPattern
);
1355 pFcDefaultSubstitute( pattern
);
1356 ret
= pFcFontMatch( NULL
, pattern
, &result
);
1357 pFcPatternDestroy( pattern
);
1358 if (ret
&& result
== FcResultMatch
) return ret
;
1359 pFcPatternDestroy( ret
);
1363 static void fontconfig_add_font( FcPattern
*pattern
, DWORD flags
)
1365 const char *unix_name
, *format
;
1371 TRACE( "(%p %#x)\n", pattern
, flags
);
1373 if (pFcPatternGetString( pattern
, FC_FILE
, 0, (FcChar8
**)&unix_name
) != FcResultMatch
)
1376 if (pFcPatternGetBool( pattern
, FC_SCALABLE
, 0, &scalable
) != FcResultMatch
)
1379 if (pFcPatternGetString( pattern
, FC_FONTFORMAT
, 0, (FcChar8
**)&format
) != FcResultMatch
)
1381 TRACE( "ignoring unknown font format %s\n", debugstr_a(unix_name
) );
1385 if (!strcmp( format
, "Type 1" ))
1387 TRACE( "ignoring Type 1 font %s\n", debugstr_a(unix_name
) );
1391 if (!scalable
&& !(flags
& ADDFONT_ALLOW_BITMAP
))
1393 TRACE( "ignoring non-scalable font %s\n", debugstr_a(unix_name
) );
1397 if (!(aa_flags
= parse_aa_pattern( pattern
))) aa_flags
= default_aa_flags
;
1398 flags
|= ADDFONT_AA_FLAGS(aa_flags
);
1400 if (pFcPatternGetInteger( pattern
, FC_INDEX
, 0, &face_index
) != FcResultMatch
)
1403 dos_name
= get_dos_file_name( unix_name
);
1404 add_unix_face( unix_name
, dos_name
, NULL
, 0, face_index
, flags
, NULL
);
1405 RtlFreeHeap( GetProcessHeap(), 0, dos_name
);
1408 static void init_fontconfig(void)
1410 void *fc_handle
= dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
);
1414 TRACE("Wine cannot find the fontconfig library (%s).\n", SONAME_LIBFONTCONFIG
);
1418 #define LOAD_FUNCPTR(f) if((p##f = dlsym(fc_handle, #f)) == NULL){WARN("Can't find symbol %s\n", #f); return;}
1419 LOAD_FUNCPTR(FcConfigSubstitute
);
1420 LOAD_FUNCPTR(FcDefaultSubstitute
);
1421 LOAD_FUNCPTR(FcFontList
);
1422 LOAD_FUNCPTR(FcFontMatch
);
1423 LOAD_FUNCPTR(FcFontSetDestroy
);
1424 LOAD_FUNCPTR(FcInit
);
1425 LOAD_FUNCPTR(FcPatternAddString
);
1426 LOAD_FUNCPTR(FcPatternCreate
);
1427 LOAD_FUNCPTR(FcPatternDestroy
);
1428 LOAD_FUNCPTR(FcPatternGetBool
);
1429 LOAD_FUNCPTR(FcPatternGetInteger
);
1430 LOAD_FUNCPTR(FcPatternGetString
);
1431 LOAD_FUNCPTR(FcConfigGetFontDirs
);
1432 LOAD_FUNCPTR(FcConfigGetCurrent
);
1433 LOAD_FUNCPTR(FcCacheCopySet
);
1434 LOAD_FUNCPTR(FcCacheNumSubdir
);
1435 LOAD_FUNCPTR(FcCacheSubdir
);
1436 LOAD_FUNCPTR(FcDirCacheRead
);
1437 LOAD_FUNCPTR(FcDirCacheUnload
);
1438 LOAD_FUNCPTR(FcStrListCreate
);
1439 LOAD_FUNCPTR(FcStrListDone
);
1440 LOAD_FUNCPTR(FcStrListNext
);
1441 LOAD_FUNCPTR(FcStrSetAdd
);
1442 LOAD_FUNCPTR(FcStrSetCreate
);
1443 LOAD_FUNCPTR(FcStrSetDestroy
);
1444 LOAD_FUNCPTR(FcStrSetMember
);
1449 FcPattern
*pattern
= pFcPatternCreate();
1450 pFcConfigSubstitute( NULL
, pattern
, FcMatchFont
);
1451 default_aa_flags
= parse_aa_pattern( pattern
);
1452 pFcPatternDestroy( pattern
);
1454 if (!default_aa_flags
)
1456 FcPattern
*pattern
= pFcPatternCreate();
1457 pFcConfigSubstitute( NULL
, pattern
, FcMatchPattern
);
1458 default_aa_flags
= parse_aa_pattern( pattern
);
1459 pFcPatternDestroy( pattern
);
1461 pattern_serif
= create_family_pattern( "serif" );
1462 pattern_fixed
= create_family_pattern( "monospace" );
1463 pattern_sans
= create_family_pattern( "sans" );
1465 TRACE( "enabled, default flags = %x\n", default_aa_flags
);
1466 fontconfig_enabled
= TRUE
;
1470 static void fontconfig_add_fonts_from_dir_list( FcConfig
*config
, FcStrList
*dir_list
, FcStrSet
*done_set
, DWORD flags
)
1473 FcFontSet
*font_set
;
1474 FcStrList
*subdir_list
= NULL
;
1475 FcStrSet
*subdir_set
= NULL
;
1476 FcCache
*cache
= NULL
;
1479 TRACE( "(%p %p %p %#x)\n", config
, dir_list
, done_set
, flags
);
1481 while ((dir
= pFcStrListNext( dir_list
)))
1483 if (pFcStrSetMember( done_set
, dir
)) continue;
1485 TRACE( "adding fonts from %s\n", dir
);
1486 if (!(cache
= pFcDirCacheRead( dir
, FcFalse
, config
))) continue;
1488 if (!(font_set
= pFcCacheCopySet( cache
))) goto done
;
1489 for (i
= 0; i
< font_set
->nfont
; i
++)
1490 fontconfig_add_font( font_set
->fonts
[i
], flags
);
1491 pFcFontSetDestroy( font_set
);
1494 if (!(subdir_set
= pFcStrSetCreate())) goto done
;
1495 for (i
= 0; i
< pFcCacheNumSubdir( cache
); i
++)
1496 pFcStrSetAdd( subdir_set
, pFcCacheSubdir( cache
, i
) );
1497 pFcDirCacheUnload( cache
);
1500 if (!(subdir_list
= pFcStrListCreate( subdir_set
))) goto done
;
1501 pFcStrSetDestroy( subdir_set
);
1504 pFcStrSetAdd( done_set
, dir
);
1505 fontconfig_add_fonts_from_dir_list( config
, subdir_list
, done_set
, flags
);
1506 pFcStrListDone( subdir_list
);
1511 if (font_set
) pFcFontSetDestroy( font_set
);
1512 if (subdir_list
) pFcStrListDone( subdir_list
);
1513 if (subdir_set
) pFcStrSetDestroy( subdir_set
);
1514 if (cache
) pFcDirCacheUnload( cache
);
1517 static void load_fontconfig_fonts( void )
1519 FcStrList
*dir_list
= NULL
;
1520 FcStrSet
*done_set
= NULL
;
1523 if (!fontconfig_enabled
) return;
1524 if (!(config
= pFcConfigGetCurrent())) goto done
;
1525 if (!(done_set
= pFcStrSetCreate())) goto done
;
1526 if (!(dir_list
= pFcConfigGetFontDirs( config
))) goto done
;
1528 fontconfig_add_fonts_from_dir_list( config
, dir_list
, done_set
, ADDFONT_EXTERNAL_FONT
| ADDFONT_ADD_TO_CACHE
);
1531 if (dir_list
) pFcStrListDone( dir_list
);
1532 if (done_set
) pFcStrSetDestroy( done_set
);
1535 #elif defined(HAVE_CARBON_CARBON_H)
1537 static void load_mac_font_callback(const void *value
, void *context
)
1539 CFStringRef pathStr
= value
;
1543 len
= CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr
);
1544 path
= RtlAllocateHeap(GetProcessHeap(), 0, len
);
1545 if (path
&& CFStringGetFileSystemRepresentation(pathStr
, path
, len
))
1547 TRACE("font file %s\n", path
);
1548 AddFontToList(NULL
, path
, NULL
, 0, ADDFONT_EXTERNAL_FONT
| ADDFONT_ADD_TO_CACHE
);
1550 RtlFreeHeap(GetProcessHeap(), 0, path
);
1553 static void load_mac_fonts(void)
1555 CFStringRef removeDupesKey
;
1556 CFBooleanRef removeDupesValue
;
1557 CFDictionaryRef options
;
1558 CTFontCollectionRef col
;
1560 CFMutableSetRef paths
;
1563 removeDupesKey
= kCTFontCollectionRemoveDuplicatesOption
;
1564 removeDupesValue
= kCFBooleanTrue
;
1565 options
= CFDictionaryCreate(NULL
, (const void**)&removeDupesKey
, (const void**)&removeDupesValue
, 1,
1566 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1567 col
= CTFontCollectionCreateFromAvailableFonts(options
);
1568 if (options
) CFRelease(options
);
1571 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
1575 descs
= CTFontCollectionCreateMatchingFontDescriptors(col
);
1579 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
1583 paths
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
1586 WARN("CFSetCreateMutable failed\n");
1591 for (i
= 0; i
< CFArrayGetCount(descs
); i
++)
1593 CTFontDescriptorRef desc
;
1598 desc
= CFArrayGetValueAtIndex(descs
, i
);
1600 #if defined(MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
1601 url
= CTFontDescriptorCopyAttribute(desc
, kCTFontURLAttribute
);
1603 /* CTFontDescriptor doesn't support kCTFontURLAttribute prior to 10.6, so
1604 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
1611 font
= CTFontCreateWithFontDescriptor(desc
, 0, NULL
);
1612 if (!font
) continue;
1614 atsFont
= CTFontGetPlatformFont(font
, NULL
);
1621 status
= ATSFontGetFileReference(atsFont
, &fsref
);
1623 if (status
!= noErr
) continue;
1625 url
= CFURLCreateFromFSRef(NULL
, &fsref
);
1630 ext
= CFURLCopyPathExtension(url
);
1633 BOOL skip
= (CFStringCompare(ext
, CFSTR("pfa"), kCFCompareCaseInsensitive
) == kCFCompareEqualTo
||
1634 CFStringCompare(ext
, CFSTR("pfb"), kCFCompareCaseInsensitive
) == kCFCompareEqualTo
);
1643 path
= CFURLCopyFileSystemPath(url
, kCFURLPOSIXPathStyle
);
1645 if (!path
) continue;
1647 CFSetAddValue(paths
, path
);
1653 CFSetApplyFunction(paths
, load_mac_font_callback
, NULL
);
1660 static BOOL
init_freetype(void)
1662 ft_handle
= dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
);
1665 "Wine cannot find the FreeType font library. To enable Wine to\n"
1666 "use TrueType fonts please install a version of FreeType greater than\n"
1667 "or equal to 2.0.5.\n"
1668 "http://www.freetype.org\n");
1672 #define LOAD_FUNCPTR(f) if((p##f = dlsym(ft_handle, #f)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
1674 LOAD_FUNCPTR(FT_Done_Face
)
1675 LOAD_FUNCPTR(FT_Get_Char_Index
)
1676 LOAD_FUNCPTR(FT_Get_First_Char
)
1677 LOAD_FUNCPTR(FT_Get_Next_Char
)
1678 LOAD_FUNCPTR(FT_Get_Sfnt_Name
)
1679 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count
)
1680 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
1681 LOAD_FUNCPTR(FT_Get_WinFNT_Header
)
1682 LOAD_FUNCPTR(FT_Init_FreeType
)
1683 LOAD_FUNCPTR(FT_Library_Version
)
1684 LOAD_FUNCPTR(FT_Load_Glyph
)
1685 LOAD_FUNCPTR(FT_Load_Sfnt_Table
)
1686 LOAD_FUNCPTR(FT_Matrix_Multiply
)
1687 LOAD_FUNCPTR(FT_MulDiv
)
1688 #ifndef FT_MULFIX_INLINED
1689 LOAD_FUNCPTR(FT_MulFix
)
1691 LOAD_FUNCPTR(FT_New_Face
)
1692 LOAD_FUNCPTR(FT_New_Memory_Face
)
1693 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
1694 LOAD_FUNCPTR(FT_Outline_Get_CBox
)
1695 LOAD_FUNCPTR(FT_Outline_Transform
)
1696 LOAD_FUNCPTR(FT_Outline_Translate
)
1697 LOAD_FUNCPTR(FT_Render_Glyph
)
1698 LOAD_FUNCPTR(FT_Set_Charmap
)
1699 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
1700 LOAD_FUNCPTR(FT_Vector_Length
)
1701 LOAD_FUNCPTR(FT_Vector_Transform
)
1702 LOAD_FUNCPTR(FT_Vector_Unit
)
1704 /* Don't warn if these ones are missing */
1705 pFT_Outline_Embolden
= dlsym(ft_handle
, "FT_Outline_Embolden");
1706 pFT_Get_TrueType_Engine_Type
= dlsym(ft_handle
, "FT_Get_TrueType_Engine_Type");
1707 #ifdef FT_LCD_FILTER_H
1708 pFT_Library_SetLcdFilter
= dlsym(ft_handle
, "FT_Library_SetLcdFilter");
1710 pFT_Property_Set
= dlsym(ft_handle
, "FT_Property_Set");
1712 if(pFT_Init_FreeType(&library
) != 0) {
1713 ERR("Can't init FreeType library\n");
1718 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
1720 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
1721 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
1722 ((FT_Version
.minor
<< 8) & 0x00ff00) |
1723 ((FT_Version
.patch
) & 0x0000ff);
1725 /* In FreeType < 2.8.1 v40's FT_LOAD_TARGET_MONO has broken advance widths. */
1726 if (pFT_Property_Set
&& FT_SimpleVersion
< FT_VERSION_VALUE(2, 8, 1))
1728 FT_UInt interpreter_version
= 35;
1729 pFT_Property_Set( library
, "truetype", "interpreter-version", &interpreter_version
);
1736 "Wine cannot find certain functions that it needs inside the FreeType\n"
1737 "font library. To enable Wine to use TrueType fonts please upgrade\n"
1738 "FreeType to at least version 2.1.4.\n"
1739 "http://www.freetype.org\n");
1745 /*************************************************************
1746 * freetype_load_fonts
1748 static void CDECL
freetype_load_fonts(void)
1750 #ifdef SONAME_LIBFONTCONFIG
1751 load_fontconfig_fonts();
1752 #elif defined(HAVE_CARBON_CARBON_H)
1754 #elif defined(__ANDROID__)
1755 ReadFontDir("/system/fonts", TRUE
);
1759 /* Some fonts have large usWinDescent values, as a result of storing signed short
1760 in unsigned field. That's probably caused by sTypoDescent vs usWinDescent confusion in
1761 some font generation tools. */
1762 static inline USHORT
get_fixed_windescent(USHORT windescent
)
1764 return abs((SHORT
)windescent
);
1767 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
1770 TT_HoriHeader
*pHori
;
1773 const LONG MAX_PPEM
= (1 << 16) - 1;
1775 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
1776 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
1778 if(height
== 0) height
= 16;
1780 /* Calc. height of EM square:
1782 * For +ve lfHeight we have
1783 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
1784 * Re-arranging gives:
1785 * ppem = units_per_em * lfheight / (winAscent + winDescent)
1787 * For -ve lfHeight we have
1789 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
1790 * with il = winAscent + winDescent - units_per_em]
1795 USHORT windescent
= get_fixed_windescent(pOS2
->usWinDescent
);
1796 if(pOS2
->usWinAscent
+ windescent
== 0)
1797 ppem
= pFT_MulDiv(ft_face
->units_per_EM
, height
, pHori
->Ascender
- pHori
->Descender
);
1799 ppem
= pFT_MulDiv(ft_face
->units_per_EM
, height
, pOS2
->usWinAscent
+ windescent
);
1800 if(ppem
> MAX_PPEM
) {
1801 WARN("Ignoring too large height %d, ppem %d\n", height
, ppem
);
1805 else if(height
>= -MAX_PPEM
)
1808 WARN("Ignoring too large height %d\n", height
);
1815 static struct font_mapping
*map_font_file( const char *name
)
1817 struct font_mapping
*mapping
;
1821 if ((fd
= open( name
, O_RDONLY
)) == -1) return NULL
;
1822 if (fstat( fd
, &st
) == -1) goto error
;
1824 LIST_FOR_EACH_ENTRY( mapping
, &mappings_list
, struct font_mapping
, entry
)
1826 if (mapping
->dev
== st
.st_dev
&& mapping
->ino
== st
.st_ino
)
1828 mapping
->refcount
++;
1833 if (!(mapping
= RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*mapping
) )))
1836 mapping
->data
= mmap( NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0 );
1839 if (mapping
->data
== MAP_FAILED
)
1841 RtlFreeHeap( GetProcessHeap(), 0, mapping
);
1844 mapping
->refcount
= 1;
1845 mapping
->dev
= st
.st_dev
;
1846 mapping
->ino
= st
.st_ino
;
1847 mapping
->size
= st
.st_size
;
1848 list_add_tail( &mappings_list
, &mapping
->entry
);
1856 static void unmap_font_file( struct font_mapping
*mapping
)
1858 if (!--mapping
->refcount
)
1860 list_remove( &mapping
->entry
);
1861 munmap( mapping
->data
, mapping
->size
);
1862 RtlFreeHeap( GetProcessHeap(), 0, mapping
);
1866 static LONG
load_VDMX(struct gdi_font
*font
, LONG height
);
1868 /*************************************************************
1869 * freetype_destroy_font
1871 static void CDECL
freetype_destroy_font( struct gdi_font
*font
)
1873 struct font_private_data
*data
= font
->private;
1875 if (data
->ft_face
) pFT_Done_Face( data
->ft_face
);
1876 if (data
->mapping
) unmap_font_file( data
->mapping
);
1877 RtlFreeHeap( GetProcessHeap(), 0, data
);
1880 /*************************************************************
1881 * freetype_get_font_data
1883 static DWORD CDECL
freetype_get_font_data( struct gdi_font
*font
, DWORD table
, DWORD offset
,
1884 void *buf
, DWORD cbData
)
1886 FT_Face ft_face
= get_ft_face( font
);
1890 if (!FT_IS_SFNT(ft_face
)) return GDI_ERROR
;
1897 /* if font is a member of TTC, 'ttcf' tag allows reading from beginning of TTC file,
1898 0 tag means to read from start of collection member data. */
1899 if (font
->ttc_item_offset
)
1901 if (table
== MS_TTCF_TAG
)
1903 else if (table
== 0)
1904 offset
+= font
->ttc_item_offset
;
1907 /* make sure value of len is the value freetype says it needs */
1910 FT_ULong needed
= 0;
1911 err
= pFT_Load_Sfnt_Table(ft_face
, RtlUlongByteSwap(table
), offset
, NULL
, &needed
);
1912 if( !err
&& needed
< len
) len
= needed
;
1914 err
= pFT_Load_Sfnt_Table(ft_face
, RtlUlongByteSwap(table
), offset
, buf
, &len
);
1917 TRACE("Can't find table %s\n", debugstr_an((char*)&table
, 4));
1923 /*************************************************************
1926 * load the vdmx entry for the specified height
1956 static LONG
load_VDMX(struct gdi_font
*font
, LONG height
)
1960 BYTE devXRatio
, devYRatio
;
1961 USHORT numRecs
, numRatios
;
1962 DWORD result
, offset
= -1;
1966 result
= freetype_get_font_data(font
, MS_VDMX_TAG
, 0, &hdr
, sizeof(hdr
));
1968 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
1971 /* FIXME: need the real device aspect ratio */
1975 numRecs
= GET_BE_WORD(hdr
.numRecs
);
1976 numRatios
= GET_BE_WORD(hdr
.numRatios
);
1978 TRACE("version = %d numRecs = %d numRatios = %d\n", GET_BE_WORD(hdr
.version
), numRecs
, numRatios
);
1979 for(i
= 0; i
< numRatios
; i
++) {
1982 offset
= sizeof(hdr
) + (i
* sizeof(Ratios
));
1983 freetype_get_font_data(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
1986 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
1988 if (!ratio
.bCharSet
) continue;
1990 if((ratio
.xRatio
== 0 &&
1991 ratio
.yStartRatio
== 0 &&
1992 ratio
.yEndRatio
== 0) ||
1993 (devXRatio
== ratio
.xRatio
&&
1994 devYRatio
>= ratio
.yStartRatio
&&
1995 devYRatio
<= ratio
.yEndRatio
))
1999 offset
= sizeof(hdr
) + numRatios
* sizeof(ratio
) + i
* sizeof(group_offset
);
2000 freetype_get_font_data(font
, MS_VDMX_TAG
, offset
, &group_offset
, sizeof(group_offset
));
2001 offset
= GET_BE_WORD(group_offset
);
2006 if(offset
== -1) return 0;
2008 if(freetype_get_font_data(font
, MS_VDMX_TAG
, offset
, &group
, sizeof(group
)) != GDI_ERROR
) {
2010 BYTE startsz
, endsz
;
2013 recs
= GET_BE_WORD(group
.recs
);
2014 startsz
= group
.startsz
;
2015 endsz
= group
.endsz
;
2017 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
2019 vTable
= RtlAllocateHeap(GetProcessHeap(), 0, recs
* sizeof(VDMX_vTable
));
2020 result
= freetype_get_font_data(font
, MS_VDMX_TAG
, offset
+ sizeof(group
), vTable
, recs
* sizeof(VDMX_vTable
));
2021 if(result
== GDI_ERROR
) {
2022 FIXME("Failed to retrieve vTable\n");
2027 for(i
= 0; i
< recs
; i
++) {
2028 SHORT yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
2029 SHORT yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
2030 ppem
= GET_BE_WORD(vTable
[i
* 3]);
2032 if(yMax
+ -yMin
== height
) {
2035 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
2038 if(yMax
+ -yMin
> height
) {
2041 goto end
; /* failed */
2043 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
2044 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
2045 ppem
= GET_BE_WORD(vTable
[i
* 3]);
2046 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
2052 TRACE("ppem not found for height %d\n", height
);
2056 if(ppem
< startsz
|| ppem
> endsz
)
2062 for(i
= 0; i
< recs
; i
++) {
2064 yPelHeight
= GET_BE_WORD(vTable
[i
* 3]);
2066 if(yPelHeight
> ppem
)
2072 if(yPelHeight
== ppem
) {
2073 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
2074 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
2075 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem
, font
->yMax
, font
->yMin
);
2081 RtlFreeHeap(GetProcessHeap(), 0, vTable
);
2087 static BOOL
select_charmap(FT_Face ft_face
, FT_Encoding encoding
)
2089 FT_Error ft_err
= FT_Err_Invalid_CharMap_Handle
;
2090 FT_CharMap cmap0
, cmap1
, cmap2
, cmap3
, cmap_def
;
2093 cmap0
= cmap1
= cmap2
= cmap3
= cmap_def
= NULL
;
2095 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
2097 if (ft_face
->charmaps
[i
]->encoding
== encoding
)
2099 TRACE("found cmap with platform_id %u, encoding_id %u\n",
2100 ft_face
->charmaps
[i
]->platform_id
, ft_face
->charmaps
[i
]->encoding_id
);
2102 switch (ft_face
->charmaps
[i
]->platform_id
)
2105 cmap_def
= ft_face
->charmaps
[i
];
2107 case 0: /* Apple Unicode */
2108 cmap0
= ft_face
->charmaps
[i
];
2110 case 1: /* Macintosh */
2111 cmap1
= ft_face
->charmaps
[i
];
2114 cmap2
= ft_face
->charmaps
[i
];
2116 case 3: /* Microsoft */
2117 cmap3
= ft_face
->charmaps
[i
];
2122 if (cmap3
) /* prefer Microsoft cmap table */
2123 ft_err
= pFT_Set_Charmap(ft_face
, cmap3
);
2125 ft_err
= pFT_Set_Charmap(ft_face
, cmap1
);
2127 ft_err
= pFT_Set_Charmap(ft_face
, cmap2
);
2129 ft_err
= pFT_Set_Charmap(ft_face
, cmap0
);
2131 ft_err
= pFT_Set_Charmap(ft_face
, cmap_def
);
2134 return ft_err
== FT_Err_Ok
;
2138 static FT_Encoding
pick_charmap( FT_Face face
, int charset
)
2140 static const FT_Encoding regular_order
[] = { FT_ENCODING_UNICODE
, FT_ENCODING_APPLE_ROMAN
, FT_ENCODING_MS_SYMBOL
, 0 };
2141 static const FT_Encoding symbol_order
[] = { FT_ENCODING_MS_SYMBOL
, FT_ENCODING_UNICODE
, FT_ENCODING_APPLE_ROMAN
, 0 };
2142 const FT_Encoding
*encs
= regular_order
;
2144 if (charset
== SYMBOL_CHARSET
) encs
= symbol_order
;
2148 if (select_charmap( face
, *encs
)) break;
2152 if (!face
->charmap
&& face
->num_charmaps
)
2154 if (!pFT_Set_Charmap(face
, face
->charmaps
[0]))
2155 return face
->charmap
->encoding
;
2161 static BOOL
get_gasp_flags( struct gdi_font
*font
, WORD
*flags
)
2163 FT_Face ft_face
= get_ft_face( font
);
2165 WORD buf
[16]; /* Enough for seven ranges before we need to alloc */
2166 WORD
*alloced
= NULL
, *ptr
= buf
;
2167 WORD num_recs
, version
;
2171 size
= freetype_get_font_data( font
, MS_GASP_TAG
, 0, NULL
, 0 );
2172 if (size
== GDI_ERROR
) return FALSE
;
2173 if (size
< 4 * sizeof(WORD
)) return FALSE
;
2174 if (size
> sizeof(buf
))
2176 ptr
= alloced
= RtlAllocateHeap( GetProcessHeap(), 0, size
);
2177 if (!ptr
) return FALSE
;
2180 freetype_get_font_data( font
, MS_GASP_TAG
, 0, ptr
, size
);
2182 version
= GET_BE_WORD( *ptr
++ );
2183 num_recs
= GET_BE_WORD( *ptr
++ );
2185 if (version
> 1 || size
< (num_recs
* 2 + 2) * sizeof(WORD
))
2187 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version
, size
, num_recs
);
2193 *flags
= GET_BE_WORD( *(ptr
+ 1) );
2194 if (ft_face
->size
->metrics
.y_ppem
<= GET_BE_WORD( *ptr
)) break;
2197 TRACE( "got flags %04x for ppem %d\n", *flags
, ft_face
->size
->metrics
.y_ppem
);
2201 RtlFreeHeap( GetProcessHeap(), 0, alloced
);
2205 /*************************************************************
2206 * fontconfig_enum_family_fallbacks
2208 static BOOL CDECL
fontconfig_enum_family_fallbacks( DWORD pitch_and_family
, int index
,
2209 WCHAR buffer
[LF_FACESIZE
] )
2211 #ifdef SONAME_LIBFONTCONFIG
2216 if ((pitch_and_family
& FIXED_PITCH
) || (pitch_and_family
& 0xf0) == FF_MODERN
) pat
= pattern_fixed
;
2217 else if ((pitch_and_family
& 0xf0) == FF_ROMAN
) pat
= pattern_serif
;
2218 else pat
= pattern_sans
;
2220 if (!pat
) return FALSE
;
2221 if (pFcPatternGetString( pat
, FC_FAMILY
, index
, (FcChar8
**)&str
) != FcResultMatch
) return FALSE
;
2222 RtlUTF8ToUnicodeN( buffer
, (LF_FACESIZE
- 1) * sizeof(WCHAR
), &len
, str
, strlen(str
) );
2223 buffer
[len
/ sizeof(WCHAR
)] = 0;
2229 static DWORD
get_ttc_offset( FT_Face ft_face
, UINT face_index
)
2232 DWORD header
, offset
;
2234 /* see if it's a TTC */
2235 len
= sizeof(header
);
2236 if (pFT_Load_Sfnt_Table( ft_face
, 0, 0, (void *)&header
, &len
)) return 0;
2237 if (header
!= MS_TTCF_TAG
) return 0;
2239 len
= sizeof(offset
);
2240 if (pFT_Load_Sfnt_Table( ft_face
, 0, (3 + face_index
) * sizeof(DWORD
), (void *)&offset
, &len
))
2243 return GET_BE_DWORD( offset
);
2246 /*************************************************************
2247 * freetype_load_font
2249 static BOOL CDECL
freetype_load_font( struct gdi_font
*font
)
2251 struct font_private_data
*data
;
2252 INT width
= 0, height
;
2257 if (!(data
= RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*data
) ))) return FALSE
;
2258 font
->private = data
;
2262 char *filename
= get_unix_file_name( font
->file
);
2263 data
->mapping
= map_font_file( filename
);
2264 RtlFreeHeap( GetProcessHeap(), 0, filename
);
2267 WARN("failed to map %s\n", debugstr_w(font
->file
));
2270 data_ptr
= data
->mapping
->data
;
2271 data_size
= data
->mapping
->size
;
2275 data_ptr
= font
->data_ptr
;
2276 data_size
= font
->data_size
;
2279 if (pFT_New_Memory_Face( library
, data_ptr
, data_size
, font
->face_index
, &ft_face
)) return FALSE
;
2281 data
->ft_face
= ft_face
;
2282 font
->scalable
= FT_IS_SCALABLE( ft_face
);
2283 if (!font
->fs
.fsCsb
[0]) get_fontsig( ft_face
, &font
->fs
);
2284 if (!font
->ntmFlags
) font
->ntmFlags
= get_ntm_flags( ft_face
);
2285 if (!font
->aa_flags
) font
->aa_flags
= ADDFONT_AA_FLAGS( default_aa_flags
);
2286 if (!font
->otm
.otmpFamilyName
)
2288 font
->otm
.otmpFamilyName
= (char *)ft_face_get_family_name( ft_face
, system_lcid
);
2289 font
->otm
.otmpStyleName
= (char *)ft_face_get_style_name( ft_face
, system_lcid
);
2290 font
->otm
.otmpFaceName
= (char *)ft_face_get_full_name( ft_face
, system_lcid
);
2295 /* load the VDMX table if we have one */
2296 font
->ppem
= load_VDMX( font
, font
->lf
.lfHeight
);
2297 if (font
->ppem
== 0) font
->ppem
= calc_ppem_for_height( ft_face
, font
->lf
.lfHeight
);
2298 TRACE( "height %d => ppem %d\n", font
->lf
.lfHeight
, font
->ppem
);
2299 height
= font
->ppem
;
2300 font
->ttc_item_offset
= get_ttc_offset( ft_face
, font
->face_index
);
2304 struct bitmap_font_size size
;
2306 get_bitmap_size( ft_face
, &size
);
2307 width
= size
.x_ppem
>> 6;
2308 height
= size
.y_ppem
>> 6;
2309 font
->ppem
= height
;
2312 pFT_Set_Pixel_Sizes( ft_face
, width
, height
);
2313 pick_charmap( ft_face
, font
->charset
);
2318 /*************************************************************
2319 * freetype_get_aa_flags
2321 static UINT CDECL
freetype_get_aa_flags( struct gdi_font
*font
, UINT aa_flags
, BOOL antialias_fakes
)
2323 /* fixup the antialiasing flags for that font */
2326 case WINE_GGO_HRGB_BITMAP
:
2327 case WINE_GGO_HBGR_BITMAP
:
2328 case WINE_GGO_VRGB_BITMAP
:
2329 case WINE_GGO_VBGR_BITMAP
:
2330 if (is_subpixel_rendering_enabled()) break;
2331 aa_flags
= GGO_GRAY4_BITMAP
;
2333 case GGO_GRAY2_BITMAP
:
2334 case GGO_GRAY4_BITMAP
:
2335 case GGO_GRAY8_BITMAP
:
2336 case WINE_GGO_GRAY16_BITMAP
:
2337 if ((!antialias_fakes
|| (!font
->fake_bold
&& !font
->fake_italic
)) && is_hinting_enabled())
2340 if (get_gasp_flags( font
, &gasp_flags
) && !(gasp_flags
& GASP_DOGRAY
))
2342 TRACE( "font %s %d aa disabled by GASP\n",
2343 debugstr_w(font
->lf
.lfFaceName
), font
->lf
.lfHeight
);
2344 aa_flags
= GGO_BITMAP
;
2351 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
2353 pt
->x
.value
= vec
->x
>> 6;
2354 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
2355 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
2356 pt
->y
.value
= vec
->y
>> 6;
2357 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
2358 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
2361 static FT_UInt
get_glyph_index_symbol( struct gdi_font
*font
, UINT glyph
)
2363 FT_Face ft_face
= get_ft_face( font
);
2366 if (glyph
< 0x100) glyph
+= 0xf000;
2367 /* there are a number of old pre-Unicode "broken" TTFs, which
2368 do have symbols at U+00XX instead of U+f0XX */
2369 if (!(ret
= pFT_Get_Char_Index(ft_face
, glyph
)))
2370 ret
= pFT_Get_Char_Index(ft_face
, glyph
- 0xf000);
2375 /*************************************************************
2376 * freetype_get_glyph_index
2378 static BOOL CDECL
freetype_get_glyph_index( struct gdi_font
*font
, UINT
*glyph
, BOOL use_encoding
)
2380 FT_Face ft_face
= get_ft_face( font
);
2382 if (!use_encoding
^ (ft_face
->charmap
->encoding
== FT_ENCODING_NONE
)) return FALSE
;
2384 if (ft_face
->charmap
->encoding
== FT_ENCODING_MS_SYMBOL
)
2386 if (!(*glyph
= get_glyph_index_symbol( font
, *glyph
)))
2392 RtlUnicodeToMultiByteN( &ch
, 1, &len
, &wc
, sizeof(wc
) );
2393 if (len
) *glyph
= get_glyph_index_symbol( font
, (unsigned char)ch
);
2397 *glyph
= pFT_Get_Char_Index( ft_face
, *glyph
);
2401 /*************************************************************
2402 * freetype_get_default_glyph
2404 static UINT CDECL
freetype_get_default_glyph( struct gdi_font
*font
)
2406 FT_Face ft_face
= get_ft_face( font
);
2407 FT_WinFNT_HeaderRec winfnt
;
2410 if ((pOS2
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_os2
)))
2412 UINT glyph
= pOS2
->usDefaultChar
;
2413 freetype_get_glyph_index( font
, &glyph
, TRUE
);
2416 if (!pFT_Get_WinFNT_Header( ft_face
, &winfnt
)) return winfnt
.default_char
+ winfnt
.first_char
;
2421 static inline BOOL
is_identity_FMAT2(const FMAT2
*matrix
)
2423 static const FMAT2 identity
= { 1.0, 0.0, 0.0, 1.0 };
2424 return !memcmp(matrix
, &identity
, sizeof(FMAT2
));
2427 static inline FT_Vector
normalize_vector(FT_Vector
*vec
)
2431 len
= pFT_Vector_Length(vec
);
2433 out
.x
= (vec
->x
<< 6) / len
;
2434 out
.y
= (vec
->y
<< 6) / len
;
2441 /* get_glyph_outline() glyph transform matrices index */
2449 static BOOL
get_transform_matrices( struct gdi_font
*font
, BOOL vertical
, const MAT2
*user_transform
,
2450 FT_Matrix matrices
[3] )
2452 static const FT_Matrix identity_mat
= { (1 << 16), 0, 0, (1 << 16) };
2453 BOOL needs_transform
= FALSE
;
2457 matrices
[matrix_unrotated
] = identity_mat
;
2459 /* Scaling factor */
2462 if (!freetype_set_outline_text_metrics( font
)) freetype_set_bitmap_text_metrics( font
);
2463 width_ratio
= (double)font
->aveWidth
;
2464 width_ratio
/= (double)font
->otm
.otmTextMetrics
.tmAveCharWidth
;
2467 width_ratio
= font
->scale_y
;
2469 /* Scaling transform */
2470 if (width_ratio
!= 1.0 || font
->scale_y
!= 1)
2472 FT_Matrix scale_mat
;
2473 scale_mat
.xx
= FT_FixedFromFloat( width_ratio
);
2476 scale_mat
.yy
= font
->scale_y
<< 16;
2478 pFT_Matrix_Multiply( &scale_mat
, &matrices
[matrix_unrotated
] );
2479 needs_transform
= TRUE
;
2482 /* Slant transform */
2483 if (font
->fake_italic
)
2485 FT_Matrix slant_mat
;
2486 slant_mat
.xx
= (1 << 16);
2487 slant_mat
.xy
= (1 << 16) >> 2;
2489 slant_mat
.yy
= (1 << 16);
2491 pFT_Matrix_Multiply( &slant_mat
, &matrices
[matrix_unrotated
] );
2492 needs_transform
= TRUE
;
2495 /* Rotation transform */
2496 matrices
[matrix_hori
] = matrices
[matrix_unrotated
];
2497 if (font
->scalable
&& font
->lf
.lfOrientation
% 3600)
2499 FT_Matrix rotation_mat
;
2502 pFT_Vector_Unit( &angle
, pFT_MulDiv( 1 << 16, font
->lf
.lfOrientation
, 10 ) );
2503 rotation_mat
.xx
= angle
.x
;
2504 rotation_mat
.xy
= -angle
.y
;
2505 rotation_mat
.yx
= angle
.y
;
2506 rotation_mat
.yy
= angle
.x
;
2507 pFT_Matrix_Multiply( &rotation_mat
, &matrices
[matrix_hori
] );
2508 needs_transform
= TRUE
;
2511 /* Vertical transform */
2512 matrices
[matrix_vert
] = matrices
[matrix_hori
];
2515 FT_Matrix vertical_mat
= { 0, -(1 << 16), 1 << 16, 0 }; /* 90 degrees rotation */
2517 pFT_Matrix_Multiply( &vertical_mat
, &matrices
[matrix_vert
] );
2518 needs_transform
= TRUE
;
2521 /* World transform */
2522 if (!is_identity_FMAT2( &font
->matrix
))
2524 FT_Matrix world_mat
;
2525 world_mat
.xx
= FT_FixedFromFloat( font
->matrix
.eM11
);
2526 world_mat
.xy
= -FT_FixedFromFloat( font
->matrix
.eM21
);
2527 world_mat
.yx
= -FT_FixedFromFloat( font
->matrix
.eM12
);
2528 world_mat
.yy
= FT_FixedFromFloat( font
->matrix
.eM22
);
2530 for (i
= 0; i
< 3; i
++)
2531 pFT_Matrix_Multiply( &world_mat
, &matrices
[i
] );
2532 needs_transform
= TRUE
;
2535 /* Extra transformation specified by caller */
2539 user_mat
.xx
= FT_FixedFromFIXED( user_transform
->eM11
);
2540 user_mat
.xy
= FT_FixedFromFIXED( user_transform
->eM21
);
2541 user_mat
.yx
= FT_FixedFromFIXED( user_transform
->eM12
);
2542 user_mat
.yy
= FT_FixedFromFIXED( user_transform
->eM22
);
2544 for (i
= 0; i
< 3; i
++)
2545 pFT_Matrix_Multiply( &user_mat
, &matrices
[i
] );
2546 needs_transform
= TRUE
;
2549 return needs_transform
;
2552 static BOOL
get_bold_glyph_outline(FT_GlyphSlot glyph
, LONG ppem
, FT_Glyph_Metrics
*metrics
)
2558 if(glyph
->format
!= FT_GLYPH_FORMAT_OUTLINE
)
2560 if(!pFT_Outline_Embolden
)
2563 strength
= pFT_MulDiv(ppem
, 1 << 6, 24);
2564 err
= pFT_Outline_Embolden(&glyph
->outline
, strength
);
2566 TRACE("FT_Ouline_Embolden returns %d\n", err
);
2570 pFT_Outline_Get_CBox(&glyph
->outline
, &bbox
);
2571 metrics
->width
= bbox
.xMax
- bbox
.xMin
;
2572 metrics
->height
= bbox
.yMax
- bbox
.yMin
;
2573 metrics
->horiBearingX
= bbox
.xMin
;
2574 metrics
->horiBearingY
= bbox
.yMax
;
2575 metrics
->vertBearingX
= metrics
->horiBearingX
- metrics
->horiAdvance
/ 2;
2576 metrics
->vertBearingY
= (metrics
->vertAdvance
- metrics
->height
) / 2;
2580 static inline BYTE
get_max_level( UINT format
)
2584 case GGO_GRAY2_BITMAP
: return 4;
2585 case GGO_GRAY4_BITMAP
: return 16;
2586 case GGO_GRAY8_BITMAP
: return 64;
2591 static FT_Vector
get_advance_metric(struct gdi_font
*incoming_font
, struct gdi_font
*font
,
2592 const FT_Glyph_Metrics
*metrics
,
2593 const FT_Matrix
*transMat
, BOOL vertical_metrics
)
2596 FT_Fixed base_advance
, em_scale
= 0;
2597 BOOL fixed_pitch_full
= FALSE
;
2599 if (vertical_metrics
)
2600 base_advance
= metrics
->vertAdvance
;
2602 base_advance
= metrics
->horiAdvance
;
2604 adv
.x
= base_advance
;
2607 /* In fixed-pitch font, we adjust the fullwidth character advance so that
2608 they have double halfwidth character width. E.g. if the font is 19 ppem,
2609 we return 20 (not 19) for fullwidth characters as we return 10 for
2610 halfwidth characters. */
2611 if (freetype_set_outline_text_metrics(incoming_font
) &&
2612 !(incoming_font
->otm
.otmTextMetrics
.tmPitchAndFamily
& TMPF_FIXED_PITCH
)) {
2614 em_scale
= pFT_MulDiv(incoming_font
->ppem
, 1 << 16, get_ft_face(incoming_font
)->units_per_EM
);
2615 avg_advance
= pFT_MulFix(incoming_font
->ntmAvgWidth
, em_scale
);
2616 fixed_pitch_full
= (avg_advance
> 0 &&
2617 (base_advance
+ 63) >> 6 ==
2618 pFT_MulFix(incoming_font
->ntmAvgWidth
*2, em_scale
));
2619 if (fixed_pitch_full
&& !transMat
)
2620 adv
.x
= (avg_advance
* 2) << 6;
2624 pFT_Vector_Transform(&adv
, transMat
);
2625 if (fixed_pitch_full
&& adv
.y
== 0) {
2627 vec
.x
= incoming_font
->ntmAvgWidth
;
2629 pFT_Vector_Transform(&vec
, transMat
);
2630 adv
.x
= (pFT_MulFix(vec
.x
, em_scale
) * 2) << 6;
2634 if (font
->fake_bold
) {
2638 FT_Vector fake_bold_adv
, vec
= { 1 << 6, 0 };
2639 pFT_Vector_Transform(&vec
, transMat
);
2640 fake_bold_adv
= normalize_vector(&vec
);
2641 adv
.x
+= fake_bold_adv
.x
;
2642 adv
.y
+= fake_bold_adv
.y
;
2646 adv
.x
= (adv
.x
+ 63) & -64;
2647 adv
.y
= -((adv
.y
+ 63) & -64);
2651 static FT_BBox
get_transformed_bbox( const FT_Glyph_Metrics
*metrics
,
2652 BOOL needs_transform
, const FT_Matrix metrices
[3] )
2654 FT_BBox bbox
= { 0, 0, 0, 0 };
2656 if (!needs_transform
)
2658 bbox
.xMin
= (metrics
->horiBearingX
) & -64;
2659 bbox
.xMax
= (metrics
->horiBearingX
+ metrics
->width
+ 63) & -64;
2660 bbox
.yMax
= (metrics
->horiBearingY
+ 63) & -64;
2661 bbox
.yMin
= (metrics
->horiBearingY
- metrics
->height
) & -64;
2668 for (xc
= 0; xc
< 2; xc
++)
2670 for (yc
= 0; yc
< 2; yc
++)
2672 vec
.x
= metrics
->horiBearingX
+ xc
* metrics
->width
;
2673 vec
.y
= metrics
->horiBearingY
- yc
* metrics
->height
;
2674 TRACE( "Vec %ld,i %ld\n", vec
.x
, vec
.y
);
2675 pFT_Vector_Transform( &vec
, &metrices
[matrix_vert
] );
2676 if (xc
== 0 && yc
== 0)
2678 bbox
.xMin
= bbox
.xMax
= vec
.x
;
2679 bbox
.yMin
= bbox
.yMax
= vec
.y
;
2683 if (vec
.x
< bbox
.xMin
) bbox
.xMin
= vec
.x
;
2684 else if (vec
.x
> bbox
.xMax
) bbox
.xMax
= vec
.x
;
2685 if (vec
.y
< bbox
.yMin
) bbox
.yMin
= vec
.y
;
2686 else if (vec
.y
> bbox
.yMax
) bbox
.yMax
= vec
.y
;
2690 bbox
.xMin
= bbox
.xMin
& -64;
2691 bbox
.xMax
= (bbox
.xMax
+ 63) & -64;
2692 bbox
.yMin
= bbox
.yMin
& -64;
2693 bbox
.yMax
= (bbox
.yMax
+ 63) & -64;
2694 TRACE( "transformed box: (%ld, %ld - %ld, %ld)\n", bbox
.xMin
, bbox
.yMax
, bbox
.xMax
, bbox
.yMin
);
2700 static void compute_metrics( struct gdi_font
*incoming_font
, struct gdi_font
*font
,
2701 FT_BBox bbox
, const FT_Glyph_Metrics
*metrics
,
2702 BOOL vertical
, BOOL vertical_metrics
,
2703 BOOL needs_transform
, const FT_Matrix matrices
[3],
2704 GLYPHMETRICS
*gm
, ABC
*abc
)
2706 FT_Vector adv
, vec
, origin
;
2708 if (!needs_transform
)
2710 adv
= get_advance_metric( incoming_font
, font
, metrics
, NULL
, vertical_metrics
);
2711 gm
->gmCellIncX
= adv
.x
>> 6;
2713 origin
.x
= bbox
.xMin
;
2714 origin
.y
= bbox
.yMax
;
2715 abc
->abcA
= origin
.x
>> 6;
2716 abc
->abcB
= (metrics
->width
+ 63) >> 6;
2722 if (vertical
&& freetype_set_outline_text_metrics( font
))
2724 if (vertical_metrics
)
2725 lsb
= metrics
->horiBearingY
+ metrics
->vertBearingY
;
2727 lsb
= metrics
->vertAdvance
+ (font
->otm
.otmDescent
<< 6);
2729 vec
.y
= font
->otm
.otmDescent
<< 6;
2730 TRACE( "Vec %ld,%ld\n", vec
.x
>>6, vec
.y
>>6 );
2731 pFT_Vector_Transform( &vec
, &matrices
[matrix_hori
] );
2732 origin
.x
= (vec
.x
+ bbox
.xMin
) & -64;
2733 origin
.y
= (vec
.y
+ bbox
.yMax
+ 63) & -64;
2734 lsb
-= metrics
->horiBearingY
;
2738 origin
.x
= bbox
.xMin
;
2739 origin
.y
= bbox
.yMax
;
2740 lsb
= metrics
->horiBearingX
;
2743 adv
= get_advance_metric( incoming_font
, font
, metrics
, &matrices
[matrix_hori
],
2745 gm
->gmCellIncX
= adv
.x
>> 6;
2746 gm
->gmCellIncY
= adv
.y
>> 6;
2748 adv
= get_advance_metric( incoming_font
, font
, metrics
, &matrices
[matrix_unrotated
],
2750 adv
.x
= pFT_Vector_Length( &adv
);
2755 pFT_Vector_Transform( &vec
, &matrices
[matrix_unrotated
] );
2756 if (lsb
> 0) abc
->abcA
= pFT_Vector_Length( &vec
) >> 6;
2757 else abc
->abcA
= -((pFT_Vector_Length( &vec
) + 63) >> 6);
2759 /* We use lsb again to avoid rounding errors */
2760 vec
.x
= lsb
+ (vertical
? metrics
->height
: metrics
->width
);
2762 pFT_Vector_Transform( &vec
, &matrices
[matrix_unrotated
] );
2763 abc
->abcB
= ((pFT_Vector_Length( &vec
) + 63) >> 6) - abc
->abcA
;
2765 if (!abc
->abcB
) abc
->abcB
= 1;
2766 abc
->abcC
= (adv
.x
>> 6) - abc
->abcA
- abc
->abcB
;
2768 gm
->gmptGlyphOrigin
.x
= origin
.x
>> 6;
2769 gm
->gmptGlyphOrigin
.y
= origin
.y
>> 6;
2770 gm
->gmBlackBoxX
= (bbox
.xMax
- bbox
.xMin
) >> 6;
2771 gm
->gmBlackBoxY
= (bbox
.yMax
- bbox
.yMin
) >> 6;
2772 if (!gm
->gmBlackBoxX
) gm
->gmBlackBoxX
= 1;
2773 if (!gm
->gmBlackBoxY
) gm
->gmBlackBoxY
= 1;
2775 TRACE( "gm: %u, %u, %s, %d, %d abc %d, %u, %d\n",
2776 gm
->gmBlackBoxX
, gm
->gmBlackBoxY
, wine_dbgstr_point(&gm
->gmptGlyphOrigin
),
2777 gm
->gmCellIncX
, gm
->gmCellIncY
, abc
->abcA
, abc
->abcB
, abc
->abcC
);
2781 static const BYTE masks
[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
2783 static DWORD
get_mono_glyph_bitmap( FT_GlyphSlot glyph
, FT_BBox bbox
,
2784 BOOL fake_bold
, BOOL needs_transform
, FT_Matrix matrices
[3],
2785 DWORD buflen
, BYTE
*buf
)
2787 DWORD width
= (bbox
.xMax
- bbox
.xMin
) >> 6;
2788 DWORD height
= (bbox
.yMax
- bbox
.yMin
) >> 6;
2789 DWORD pitch
= ((width
+ 31) >> 5) << 2;
2790 DWORD needed
= pitch
* height
;
2791 FT_Bitmap ft_bitmap
;
2795 if (!buf
|| !buflen
) return needed
;
2796 if (!needed
) return GDI_ERROR
; /* empty glyph */
2797 if (needed
> buflen
) return GDI_ERROR
;
2799 switch (glyph
->format
)
2801 case FT_GLYPH_FORMAT_BITMAP
:
2802 src
= glyph
->bitmap
.buffer
;
2804 w
= min( pitch
, (glyph
->bitmap
.width
+ 7) >> 3 );
2805 h
= min( height
, glyph
->bitmap
.rows
);
2809 memcpy( dst
, src
, w
);
2813 for (x
= 0; x
< w
; x
++)
2815 dst
[x
] = (dst
[x
] & 0x80) | (src
[x
] >> 1) | src
[x
];
2817 dst
[x
+ 1] = (src
[x
] & 0x01) << 7;
2820 src
+= glyph
->bitmap
.pitch
;
2825 case FT_GLYPH_FORMAT_OUTLINE
:
2826 ft_bitmap
.width
= width
;
2827 ft_bitmap
.rows
= height
;
2828 ft_bitmap
.pitch
= pitch
;
2829 ft_bitmap
.pixel_mode
= FT_PIXEL_MODE_MONO
;
2830 ft_bitmap
.buffer
= buf
;
2832 if (needs_transform
)
2833 pFT_Outline_Transform( &glyph
->outline
, &matrices
[matrix_vert
] );
2834 pFT_Outline_Translate( &glyph
->outline
, -bbox
.xMin
, -bbox
.yMin
);
2836 /* Note: FreeType will only set 'black' bits for us. */
2837 memset( buf
, 0, buflen
);
2838 pFT_Outline_Get_Bitmap( library
, &glyph
->outline
, &ft_bitmap
);
2842 FIXME( "loaded glyph format %x\n", glyph
->format
);
2849 static DWORD
get_antialias_glyph_bitmap( FT_GlyphSlot glyph
, FT_BBox bbox
, UINT format
,
2850 BOOL fake_bold
, BOOL needs_transform
, FT_Matrix matrices
[3],
2851 DWORD buflen
, BYTE
*buf
)
2853 DWORD width
= (bbox
.xMax
- bbox
.xMin
) >> 6;
2854 DWORD height
= (bbox
.yMax
- bbox
.yMin
) >> 6;
2855 DWORD pitch
= (width
+ 3) / 4 * 4;
2856 DWORD needed
= pitch
* height
;
2857 FT_Bitmap ft_bitmap
;
2858 INT w
, h
, x
, max_level
;
2861 if (!buf
|| !buflen
) return needed
;
2862 if (!needed
) return GDI_ERROR
; /* empty glyph */
2863 if (needed
> buflen
) return GDI_ERROR
;
2865 max_level
= get_max_level( format
);
2867 switch (glyph
->format
)
2869 case FT_GLYPH_FORMAT_BITMAP
:
2870 src
= glyph
->bitmap
.buffer
;
2872 memset( buf
, 0, buflen
);
2874 w
= min( pitch
, glyph
->bitmap
.width
);
2875 h
= min( height
, glyph
->bitmap
.rows
);
2878 for (x
= 0; x
< w
; x
++)
2880 if (src
[x
/ 8] & masks
[x
% 8])
2883 if (fake_bold
&& x
+ 1 < pitch
) dst
[x
+ 1] = max_level
;
2886 src
+= glyph
->bitmap
.pitch
;
2891 case FT_GLYPH_FORMAT_OUTLINE
:
2892 ft_bitmap
.width
= width
;
2893 ft_bitmap
.rows
= height
;
2894 ft_bitmap
.pitch
= pitch
;
2895 ft_bitmap
.pixel_mode
= FT_PIXEL_MODE_GRAY
;
2896 ft_bitmap
.buffer
= buf
;
2898 if (needs_transform
)
2899 pFT_Outline_Transform( &glyph
->outline
, &matrices
[matrix_vert
] );
2900 pFT_Outline_Translate( &glyph
->outline
, -bbox
.xMin
, -bbox
.yMin
);
2902 memset( buf
, 0, buflen
);
2903 pFT_Outline_Get_Bitmap( library
, &glyph
->outline
, &ft_bitmap
);
2905 if (max_level
!= 255)
2910 for (row
= 0, start
= buf
; row
< height
; row
++)
2912 for (col
= 0, ptr
= start
; col
< width
; col
++, ptr
++)
2913 *ptr
= (((int)*ptr
) * (max_level
+ 1)) / 256;
2920 FIXME("loaded glyph format %x\n", glyph
->format
);
2927 static DWORD
get_subpixel_glyph_bitmap( FT_GlyphSlot glyph
, FT_BBox bbox
, UINT format
,
2928 BOOL fake_bold
, BOOL needs_transform
, FT_Matrix matrices
[3],
2929 GLYPHMETRICS
*gm
, DWORD buflen
, BYTE
*buf
)
2931 DWORD width
= (bbox
.xMax
- bbox
.xMin
) >> 6;
2932 DWORD height
= (bbox
.yMax
- bbox
.yMin
) >> 6;
2933 DWORD pitch
, needed
= 0;
2937 switch (glyph
->format
)
2939 case FT_GLYPH_FORMAT_BITMAP
:
2941 needed
= pitch
* height
;
2943 if (!buf
|| !buflen
) break;
2944 if (!needed
) return GDI_ERROR
; /* empty glyph */
2945 if (needed
> buflen
) return GDI_ERROR
;
2947 src
= glyph
->bitmap
.buffer
;
2949 memset( buf
, 0, buflen
);
2951 w
= min( width
, glyph
->bitmap
.width
);
2952 h
= min( height
, glyph
->bitmap
.rows
);
2955 for (x
= 0; x
< w
; x
++)
2957 if ( src
[x
/ 8] & masks
[x
% 8] )
2959 ((unsigned int *)dst
)[x
] = ~0u;
2960 if (fake_bold
&& x
+ 1 < width
) ((unsigned int *)dst
)[x
+ 1] = ~0u;
2963 src
+= glyph
->bitmap
.pitch
;
2968 case FT_GLYPH_FORMAT_OUTLINE
:
2970 INT src_pitch
, src_width
, src_height
, x_shift
, y_shift
;
2971 INT sub_stride
, hmul
, vmul
;
2972 const INT
*sub_order
;
2973 const INT rgb_order
[3] = { 0, 1, 2 };
2974 const INT bgr_order
[3] = { 2, 1, 0 };
2975 FT_Render_Mode render_mode
=
2976 (format
== WINE_GGO_HRGB_BITMAP
||
2977 format
== WINE_GGO_HBGR_BITMAP
) ? FT_RENDER_MODE_LCD
: FT_RENDER_MODE_LCD_V
;
2979 if (!width
|| !height
) /* empty glyph */
2981 if (!buf
|| !buflen
) break;
2985 if ( render_mode
== FT_RENDER_MODE_LCD
)
2987 gm
->gmBlackBoxX
+= 2;
2988 gm
->gmptGlyphOrigin
.x
-= 1;
2989 bbox
.xMin
-= (1 << 6);
2993 gm
->gmBlackBoxY
+= 2;
2994 gm
->gmptGlyphOrigin
.y
+= 1;
2995 bbox
.yMax
+= (1 << 6);
2998 width
= gm
->gmBlackBoxX
;
2999 height
= gm
->gmBlackBoxY
;
3001 needed
= pitch
* height
;
3003 if (!buf
|| !buflen
) return needed
;
3004 if (needed
> buflen
) return GDI_ERROR
;
3006 if (needs_transform
)
3007 pFT_Outline_Transform( &glyph
->outline
, &matrices
[matrix_vert
] );
3009 #ifdef FT_LCD_FILTER_H
3010 if (pFT_Library_SetLcdFilter
)
3011 pFT_Library_SetLcdFilter( library
, FT_LCD_FILTER_DEFAULT
);
3013 pFT_Render_Glyph( glyph
, render_mode
);
3015 src_pitch
= glyph
->bitmap
.pitch
;
3016 src_width
= glyph
->bitmap
.width
;
3017 src_height
= glyph
->bitmap
.rows
;
3018 src
= glyph
->bitmap
.buffer
;
3020 memset( buf
, 0, buflen
);
3022 sub_order
= (format
== WINE_GGO_HRGB_BITMAP
||
3023 format
== WINE_GGO_VRGB_BITMAP
) ? rgb_order
: bgr_order
;
3024 sub_stride
= render_mode
== FT_RENDER_MODE_LCD
? 1 : src_pitch
;
3025 hmul
= render_mode
== FT_RENDER_MODE_LCD
? 3 : 1;
3026 vmul
= render_mode
== FT_RENDER_MODE_LCD
? 1 : 3;
3028 x_shift
= glyph
->bitmap_left
- (bbox
.xMin
>> 6);
3031 src
+= hmul
* -x_shift
;
3032 src_width
-= hmul
* -x_shift
;
3034 else if ( x_shift
> 0 )
3036 dst
+= x_shift
* sizeof(unsigned int);
3040 y_shift
= (bbox
.yMax
>> 6) - glyph
->bitmap_top
;
3043 src
+= src_pitch
* vmul
* -y_shift
;
3044 src_height
-= vmul
* -y_shift
;
3046 else if ( y_shift
> 0 )
3048 dst
+= y_shift
* pitch
;
3052 w
= min( width
, src_width
/ hmul
);
3053 h
= min( height
, src_height
/ vmul
);
3056 for (x
= 0; x
< w
; x
++)
3058 ((unsigned int *)dst
)[x
] =
3059 ((unsigned int)src
[hmul
* x
+ sub_stride
* sub_order
[0]] << 16) |
3060 ((unsigned int)src
[hmul
* x
+ sub_stride
* sub_order
[1]] << 8) |
3061 ((unsigned int)src
[hmul
* x
+ sub_stride
* sub_order
[2]]);
3063 src
+= src_pitch
* vmul
;
3069 FIXME ( "loaded glyph format %x\n", glyph
->format
);
3076 static unsigned int get_native_glyph_outline(FT_Outline
*outline
, unsigned int buflen
, char *buf
)
3078 TTPOLYGONHEADER
*pph
;
3080 unsigned int needed
= 0, point
= 0, contour
, first_pt
;
3081 unsigned int pph_start
, cpfx
;
3084 for (contour
= 0; contour
< outline
->n_contours
; contour
++)
3086 /* Ignore contours containing one point */
3087 if (point
== outline
->contours
[contour
])
3094 pph
= (TTPOLYGONHEADER
*)(buf
+ needed
);
3098 pph
->dwType
= TT_POLYGON_TYPE
;
3099 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
3101 needed
+= sizeof(*pph
);
3103 while (point
<= outline
->contours
[contour
])
3105 ppc
= (TTPOLYCURVE
*)(buf
+ needed
);
3106 type
= outline
->tags
[point
] & FT_Curve_Tag_On
?
3107 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
3112 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
3115 } while (point
<= outline
->contours
[contour
] &&
3116 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
3117 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
3118 /* At the end of a contour Windows adds the start point, but
3120 if (point
> outline
->contours
[contour
] &&
3121 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
))
3124 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
3127 else if (point
<= outline
->contours
[contour
] &&
3128 outline
->tags
[point
] & FT_Curve_Tag_On
)
3130 /* add closing pt for bezier */
3132 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
3141 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
3144 pph
->cb
= needed
- pph_start
;
3149 static unsigned int get_bezier_glyph_outline(FT_Outline
*outline
, unsigned int buflen
, char *buf
)
3151 /* Convert the quadratic Beziers to cubic Beziers.
3152 The parametric eqn for a cubic Bezier is, from PLRM:
3153 r(t) = at^3 + bt^2 + ct + r0
3154 with the control points:
3159 A quadratic Bezier has the form:
3160 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3162 So equating powers of t leads to:
3163 r1 = 2/3 p1 + 1/3 p0
3164 r2 = 2/3 p1 + 1/3 p2
3165 and of course r0 = p0, r3 = p2
3167 int contour
, point
= 0, first_pt
;
3168 TTPOLYGONHEADER
*pph
;
3170 DWORD pph_start
, cpfx
, type
;
3171 FT_Vector cubic_control
[4];
3172 unsigned int needed
= 0;
3174 for (contour
= 0; contour
< outline
->n_contours
; contour
++)
3177 pph
= (TTPOLYGONHEADER
*)(buf
+ needed
);
3181 pph
->dwType
= TT_POLYGON_TYPE
;
3182 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
3184 needed
+= sizeof(*pph
);
3186 while (point
<= outline
->contours
[contour
])
3188 ppc
= (TTPOLYCURVE
*)(buf
+ needed
);
3189 type
= outline
->tags
[point
] & FT_Curve_Tag_On
?
3190 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
3194 if (type
== TT_PRIM_LINE
)
3197 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
3203 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
3206 /* FIXME: Possible optimization in endpoint calculation
3207 if there are two consecutive curves */
3208 cubic_control
[0] = outline
->points
[point
-1];
3209 if (!(outline
->tags
[point
-1] & FT_Curve_Tag_On
))
3211 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
3212 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
3213 cubic_control
[0].x
>>= 1;
3214 cubic_control
[0].y
>>= 1;
3216 if (point
+1 > outline
->contours
[contour
])
3217 cubic_control
[3] = outline
->points
[first_pt
];
3220 cubic_control
[3] = outline
->points
[point
+1];
3221 if (!(outline
->tags
[point
+1] & FT_Curve_Tag_On
))
3223 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
3224 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
3225 cubic_control
[3].x
>>= 1;
3226 cubic_control
[3].y
>>= 1;
3229 /* r1 = 1/3 p0 + 2/3 p1
3230 r2 = 1/3 p2 + 2/3 p1 */
3231 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
3232 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
3233 cubic_control
[2] = cubic_control
[1];
3234 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
3235 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
3236 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
3237 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
3240 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
3241 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
3242 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
3247 } while (point
<= outline
->contours
[contour
] &&
3248 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
3249 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
3250 /* At the end of a contour Windows adds the start point,
3251 but only for Beziers and we've already done that.
3253 if (point
<= outline
->contours
[contour
] &&
3254 outline
->tags
[point
] & FT_Curve_Tag_On
)
3256 /* This is the closing pt of a bezier, but we've already
3257 added it, so just inc point and carry on */
3265 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
3268 pph
->cb
= needed
- pph_start
;
3273 static FT_Int
get_load_flags( UINT format
)
3275 FT_Int load_flags
= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
3277 if (format
& GGO_UNHINTED
)
3278 return load_flags
| FT_LOAD_NO_HINTING
;
3280 switch (format
& ~GGO_GLYPH_INDEX
)
3283 load_flags
|= FT_LOAD_TARGET_MONO
;
3285 case GGO_GRAY2_BITMAP
:
3286 case GGO_GRAY4_BITMAP
:
3287 case GGO_GRAY8_BITMAP
:
3288 case WINE_GGO_GRAY16_BITMAP
:
3289 load_flags
|= FT_LOAD_TARGET_NORMAL
;
3291 case WINE_GGO_HRGB_BITMAP
:
3292 case WINE_GGO_HBGR_BITMAP
:
3293 load_flags
|= FT_LOAD_TARGET_LCD
;
3295 case WINE_GGO_VRGB_BITMAP
:
3296 case WINE_GGO_VBGR_BITMAP
:
3297 load_flags
|= FT_LOAD_TARGET_LCD_V
;
3304 /*************************************************************
3305 * freetype_get_glyph_outline
3307 static DWORD CDECL
freetype_get_glyph_outline( struct gdi_font
*font
, UINT glyph
, UINT format
,
3308 GLYPHMETRICS
*lpgm
, ABC
*abc
, DWORD buflen
, void *buf
,
3309 const MAT2
*lpmat
, BOOL tategaki
)
3311 struct gdi_font
*base_font
= font
->base_font
? font
->base_font
: font
;
3312 FT_Face ft_face
= get_ft_face( font
);
3313 FT_Glyph_Metrics metrics
;
3316 FT_Int load_flags
= get_load_flags(format
);
3317 FT_Matrix matrices
[3];
3318 BOOL needsTransform
= FALSE
;
3319 BOOL vertical_metrics
;
3321 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
, buflen
, buf
, lpmat
);
3323 TRACE("font transform %f %f %f %f\n",
3324 font
->matrix
.eM11
, font
->matrix
.eM12
,
3325 font
->matrix
.eM21
, font
->matrix
.eM22
);
3327 needsTransform
= get_transform_matrices( font
, tategaki
, lpmat
, matrices
);
3329 vertical_metrics
= (tategaki
&& FT_HAS_VERTICAL(ft_face
));
3330 /* there is a freetype bug where vertical metrics are only
3331 properly scaled and correct in 2.4.0 or greater */
3332 if (vertical_metrics
&& FT_SimpleVersion
< FT_VERSION_VALUE(2, 4, 0))
3333 vertical_metrics
= FALSE
;
3335 if (needsTransform
|| format
!= GGO_BITMAP
) load_flags
|= FT_LOAD_NO_BITMAP
;
3336 if (vertical_metrics
) load_flags
|= FT_LOAD_VERTICAL_LAYOUT
;
3338 err
= pFT_Load_Glyph(ft_face
, glyph
, load_flags
);
3339 if (err
&& !(load_flags
& FT_LOAD_NO_HINTING
))
3341 WARN("Failed to load glyph %#x, retrying without hinting. Error %#x.\n", glyph
, err
);
3342 load_flags
|= FT_LOAD_NO_HINTING
;
3343 err
= pFT_Load_Glyph(ft_face
, glyph
, load_flags
);
3347 WARN("Failed to load glyph %#x, error %#x.\n", glyph
, err
);
3351 metrics
= ft_face
->glyph
->metrics
;
3352 if(font
->fake_bold
) {
3353 if (!get_bold_glyph_outline(ft_face
->glyph
, font
->ppem
, &metrics
) && metrics
.width
)
3354 metrics
.width
+= 1 << 6;
3357 /* Some poorly-created fonts contain glyphs that exceed the boundaries set
3358 * by the text metrics. The proper behavior is to clip the glyph metrics to
3359 * fit within the maximums specified in the text metrics. */
3360 if (freetype_set_outline_text_metrics(base_font
) ||
3361 freetype_set_bitmap_text_metrics(base_font
)) {
3362 TEXTMETRICW
*ptm
= &base_font
->otm
.otmTextMetrics
;
3363 INT top
= min( metrics
.horiBearingY
, ptm
->tmAscent
<< 6 );
3364 INT bottom
= max( metrics
.horiBearingY
- metrics
.height
, -(ptm
->tmDescent
<< 6) );
3365 metrics
.horiBearingY
= top
;
3366 metrics
.height
= top
- bottom
;
3368 /* TODO: Are we supposed to clip the width as well...? */
3369 /* metrics.width = min( metrics.width, ptm->tmMaxCharWidth << 6 ); */
3372 bbox
= get_transformed_bbox( &metrics
, needsTransform
, matrices
);
3373 compute_metrics( base_font
, font
, bbox
, &metrics
, tategaki
,
3374 vertical_metrics
, needsTransform
, matrices
, lpgm
, abc
);
3379 return 1; /* FIXME */
3382 return get_mono_glyph_bitmap( ft_face
->glyph
, bbox
, font
->fake_bold
,
3383 needsTransform
, matrices
, buflen
, buf
);
3385 case GGO_GRAY2_BITMAP
:
3386 case GGO_GRAY4_BITMAP
:
3387 case GGO_GRAY8_BITMAP
:
3388 case WINE_GGO_GRAY16_BITMAP
:
3389 return get_antialias_glyph_bitmap( ft_face
->glyph
, bbox
, format
, font
->fake_bold
,
3390 needsTransform
, matrices
, buflen
, buf
);
3392 case WINE_GGO_HRGB_BITMAP
:
3393 case WINE_GGO_HBGR_BITMAP
:
3394 case WINE_GGO_VRGB_BITMAP
:
3395 case WINE_GGO_VBGR_BITMAP
:
3396 return get_subpixel_glyph_bitmap( ft_face
->glyph
, bbox
, format
, font
->fake_bold
,
3397 needsTransform
, matrices
, lpgm
, buflen
, buf
);
3400 if (ft_face
->glyph
->format
== ft_glyph_format_outline
)
3402 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
3405 if (buflen
== 0) buf
= NULL
;
3407 if (needsTransform
&& buf
)
3408 pFT_Outline_Transform( outline
, &matrices
[matrix_vert
] );
3410 needed
= get_native_glyph_outline(outline
, buflen
, NULL
);
3412 if (!buf
|| !buflen
) return needed
;
3413 if (needed
> buflen
) return GDI_ERROR
;
3414 return get_native_glyph_outline(outline
, buflen
, buf
);
3416 TRACE("loaded a bitmap\n");
3420 if (ft_face
->glyph
->format
== ft_glyph_format_outline
)
3422 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
3425 if (buflen
== 0) buf
= NULL
;
3427 if (needsTransform
&& buf
)
3428 pFT_Outline_Transform( outline
, &matrices
[matrix_vert
] );
3430 needed
= get_bezier_glyph_outline(outline
, buflen
, NULL
);
3432 if (!buf
|| !buflen
) return needed
;
3433 if (needed
> buflen
) return GDI_ERROR
;
3434 return get_bezier_glyph_outline(outline
, buflen
, buf
);
3436 TRACE("loaded a bitmap\n");
3440 FIXME("Unsupported format %d\n", format
);
3445 /*************************************************************
3446 * freetype_set_bitmap_text_metrics
3448 static BOOL CDECL
freetype_set_bitmap_text_metrics( struct gdi_font
*font
)
3450 FT_Face ft_face
= get_ft_face( font
);
3451 FT_WinFNT_HeaderRec winfnt_header
;
3453 if (font
->otm
.otmSize
) return TRUE
; /* already set */
3454 font
->otm
.otmSize
= offsetof( OUTLINETEXTMETRICW
, otmFiller
);
3456 #define TM font->otm.otmTextMetrics
3457 if(!pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
3459 TM
.tmHeight
= winfnt_header
.pixel_height
;
3460 TM
.tmAscent
= winfnt_header
.ascent
;
3461 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
3462 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
3463 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
3464 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
3465 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
3466 TM
.tmWeight
= winfnt_header
.weight
;
3468 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
3469 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
3470 TM
.tmFirstChar
= winfnt_header
.first_char
;
3471 TM
.tmLastChar
= winfnt_header
.last_char
;
3472 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
3473 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
3474 TM
.tmItalic
= winfnt_header
.italic
;
3475 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
3476 TM
.tmCharSet
= winfnt_header
.charset
;
3480 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
3481 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
3482 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
3483 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
3484 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
3485 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
3486 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
3487 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
3489 TM
.tmDigitizedAspectX
= 96; /* FIXME */
3490 TM
.tmDigitizedAspectY
= 96; /* FIXME */
3492 TM
.tmLastChar
= 255;
3493 TM
.tmDefaultChar
= 32;
3494 TM
.tmBreakChar
= 32;
3495 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
3496 /* NB inverted meaning of TMPF_FIXED_PITCH */
3497 TM
.tmPitchAndFamily
= FT_IS_FIXED_WIDTH(ft_face
) ? 0 : TMPF_FIXED_PITCH
;
3498 TM
.tmCharSet
= font
->charset
;
3500 TM
.tmUnderlined
= font
->lf
.lfUnderline
? 0xff : 0;
3501 TM
.tmStruckOut
= font
->lf
.lfStrikeOut
? 0xff : 0;
3504 TM
.tmWeight
= FW_BOLD
;
3511 static BOOL
face_has_symbol_charmap(FT_Face ft_face
)
3515 for(i
= 0; i
< ft_face
->num_charmaps
; i
++)
3517 if(ft_face
->charmaps
[i
]->encoding
== FT_ENCODING_MS_SYMBOL
)
3523 /*************************************************************
3524 * freetype_set_outline_text_metrics
3526 static BOOL CDECL
freetype_set_outline_text_metrics( struct gdi_font
*font
)
3528 FT_Face ft_face
= get_ft_face( font
);
3531 TT_HoriHeader
*pHori
;
3532 TT_Postscript
*pPost
;
3534 INT ascent
, descent
;
3537 TRACE("font=%p\n", font
);
3539 if (!font
->scalable
) return FALSE
;
3540 if (font
->otm
.otmSize
) return TRUE
; /* already set */
3542 /* note: we store actual pointers in the names instead of offsets,
3543 they are fixed up when returned to the app */
3544 if (!(font
->otm
.otmpFullName
= (char *)get_face_name( ft_face
, TT_NAME_ID_UNIQUE_ID
, system_lcid
)))
3546 static const WCHAR fake_nameW
[] = {'f','a','k','e',' ','n','a','m','e', 0};
3547 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w((WCHAR
*)font
->otm
.otmpFamilyName
));
3548 font
->otm
.otmpFullName
= (char *)strdupW(fake_nameW
);
3550 needed
= sizeof(font
->otm
) + (lstrlenW( (WCHAR
*)font
->otm
.otmpFamilyName
) + 1 +
3551 lstrlenW( (WCHAR
*)font
->otm
.otmpStyleName
) + 1 +
3552 lstrlenW( (WCHAR
*)font
->otm
.otmpFaceName
) + 1 +
3553 lstrlenW( (WCHAR
*)font
->otm
.otmpFullName
) + 1) * sizeof(WCHAR
);
3555 em_scale
= (FT_Fixed
)pFT_MulDiv(font
->ppem
, 1 << 16, ft_face
->units_per_EM
);
3557 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
3559 FIXME("Can't find OS/2 table - not TT font?\n");
3563 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
3565 FIXME("Can't find HHEA table - not TT font?\n");
3569 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
3571 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",
3572 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
3573 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
3574 pOS2
->xAvgCharWidth
,
3575 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
3576 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
3577 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
3579 font
->otm
.otmSize
= needed
;
3581 #define TM font->otm.otmTextMetrics
3583 windescent
= get_fixed_windescent(pOS2
->usWinDescent
);
3584 if(pOS2
->usWinAscent
+ windescent
== 0) {
3585 ascent
= pHori
->Ascender
;
3586 descent
= -pHori
->Descender
;
3588 ascent
= pOS2
->usWinAscent
;
3589 descent
= windescent
;
3592 font
->ntmCellHeight
= ascent
+ descent
;
3593 font
->ntmAvgWidth
= pOS2
->xAvgCharWidth
;
3595 #define SCALE_X(x) (pFT_MulFix(x, em_scale))
3596 #define SCALE_Y(y) (pFT_MulFix(y, em_scale))
3599 TM
.tmAscent
= font
->yMax
;
3600 TM
.tmDescent
= -font
->yMin
;
3601 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
3603 TM
.tmAscent
= SCALE_Y(ascent
);
3604 TM
.tmDescent
= SCALE_Y(descent
);
3605 TM
.tmInternalLeading
= SCALE_Y(ascent
+ descent
- ft_face
->units_per_EM
);
3608 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
3611 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
3613 TM
.tmExternalLeading
= max(0, SCALE_Y(pHori
->Line_Gap
-
3614 ((ascent
+ descent
) -
3615 (pHori
->Ascender
- pHori
->Descender
))));
3617 TM
.tmAveCharWidth
= SCALE_X(pOS2
->xAvgCharWidth
);
3618 if (TM
.tmAveCharWidth
== 0) {
3619 TM
.tmAveCharWidth
= 1;
3621 TM
.tmMaxCharWidth
= SCALE_X(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
);
3622 TM
.tmWeight
= FW_REGULAR
;
3623 if (font
->fake_bold
)
3624 TM
.tmWeight
= FW_BOLD
;
3627 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)
3629 if (pOS2
->usWeightClass
> FW_MEDIUM
)
3630 TM
.tmWeight
= pOS2
->usWeightClass
;
3632 else if (pOS2
->usWeightClass
<= FW_MEDIUM
)
3633 TM
.tmWeight
= pOS2
->usWeightClass
;
3636 TM
.tmDigitizedAspectX
= 96; /* FIXME */
3637 TM
.tmDigitizedAspectY
= 96; /* FIXME */
3638 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
3639 * symbol range to 0 - f0ff
3642 if (face_has_symbol_charmap(ft_face
) || (pOS2
->usFirstCharIndex
>= 0xf000 && pOS2
->usFirstCharIndex
< 0xf100))
3645 switch (PRIMARYLANGID(system_lcid
))
3648 TM
.tmLastChar
= 0xf896;
3652 case LANG_LITHUANIAN
:
3653 TM
.tmLastChar
= 0xf8fd;
3656 TM
.tmLastChar
= 0xf0ff;
3658 TM
.tmBreakChar
= 0x20;
3659 TM
.tmDefaultChar
= 0x1f;
3663 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
; /* Should be the first char in the cmap */
3664 TM
.tmLastChar
= pOS2
->usLastCharIndex
; /* Should be min(cmap_last, os2_last) */
3666 if(pOS2
->usFirstCharIndex
<= 1)
3667 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
+ 2;
3668 else if (pOS2
->usFirstCharIndex
> 0xff)
3669 TM
.tmBreakChar
= 0x20;
3671 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
;
3672 TM
.tmDefaultChar
= TM
.tmBreakChar
- 1;
3674 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
3675 TM
.tmUnderlined
= font
->lf
.lfUnderline
? 255 : 0;
3676 TM
.tmStruckOut
= font
->lf
.lfStrikeOut
? 255 : 0;
3678 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
3679 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
3680 (pOS2
->version
== 0xFFFFU
||
3681 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
3682 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
3684 TM
.tmPitchAndFamily
= 0;
3686 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
])
3688 case PAN_FAMILY_SCRIPT
:
3689 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
3692 case PAN_FAMILY_DECORATIVE
:
3693 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
3698 case PAN_FAMILY_TEXT_DISPLAY
:
3699 case PAN_FAMILY_PICTORIAL
: /* symbol fonts get treated as if they were text */
3700 /* which is clearly not what the panose spec says. */
3702 if(TM
.tmPitchAndFamily
== 0 || /* fixed */
3703 pOS2
->panose
[PAN_PROPORTION_INDEX
] == PAN_PROP_MONOSPACED
)
3704 TM
.tmPitchAndFamily
= FF_MODERN
;
3707 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
])
3712 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
3715 case PAN_SERIF_COVE
:
3716 case PAN_SERIF_OBTUSE_COVE
:
3717 case PAN_SERIF_SQUARE_COVE
:
3718 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
3719 case PAN_SERIF_SQUARE
:
3720 case PAN_SERIF_THIN
:
3721 case PAN_SERIF_BONE
:
3722 case PAN_SERIF_EXAGGERATED
:
3723 case PAN_SERIF_TRIANGLE
:
3724 TM
.tmPitchAndFamily
|= FF_ROMAN
;
3727 case PAN_SERIF_NORMAL_SANS
:
3728 case PAN_SERIF_OBTUSE_SANS
:
3729 case PAN_SERIF_PERP_SANS
:
3730 case PAN_SERIF_FLARED
:
3731 case PAN_SERIF_ROUNDED
:
3732 TM
.tmPitchAndFamily
|= FF_SWISS
;
3739 if(FT_IS_SCALABLE(ft_face
))
3740 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
3742 if(FT_IS_SFNT(ft_face
))
3744 if (font
->ntmFlags
& NTM_PS_OPENTYPE
)
3745 TM
.tmPitchAndFamily
|= TMPF_DEVICE
;
3747 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
3750 TM
.tmCharSet
= font
->charset
;
3752 font
->otm
.otmFiller
= 0;
3753 memcpy(&font
->otm
.otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
3754 font
->otm
.otmfsSelection
= pOS2
->fsSelection
;
3755 if (font
->fake_italic
)
3756 font
->otm
.otmfsSelection
|= 1;
3757 if (font
->fake_bold
)
3758 font
->otm
.otmfsSelection
|= 1 << 5;
3759 /* Only return valid bits that define embedding and subsetting restrictions */
3760 font
->otm
.otmfsType
= pOS2
->fsType
& 0x30e;
3761 font
->otm
.otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
3762 font
->otm
.otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
3763 font
->otm
.otmItalicAngle
= 0; /* POST table */
3764 font
->otm
.otmEMSquare
= ft_face
->units_per_EM
;
3765 font
->otm
.otmAscent
= SCALE_Y(pOS2
->sTypoAscender
);
3766 font
->otm
.otmDescent
= SCALE_Y(pOS2
->sTypoDescender
);
3767 font
->otm
.otmLineGap
= SCALE_Y(pOS2
->sTypoLineGap
);
3768 font
->otm
.otmsCapEmHeight
= SCALE_Y(pOS2
->sCapHeight
);
3769 font
->otm
.otmsXHeight
= SCALE_Y(pOS2
->sxHeight
);
3770 font
->otm
.otmrcFontBox
.left
= SCALE_X(ft_face
->bbox
.xMin
);
3771 font
->otm
.otmrcFontBox
.right
= SCALE_X(ft_face
->bbox
.xMax
);
3772 font
->otm
.otmrcFontBox
.top
= SCALE_Y(ft_face
->bbox
.yMax
);
3773 font
->otm
.otmrcFontBox
.bottom
= SCALE_Y(ft_face
->bbox
.yMin
);
3774 font
->otm
.otmMacAscent
= TM
.tmAscent
;
3775 font
->otm
.otmMacDescent
= -TM
.tmDescent
;
3776 font
->otm
.otmMacLineGap
= SCALE_Y(pHori
->Line_Gap
);
3777 font
->otm
.otmusMinimumPPEM
= 0; /* TT Header */
3778 font
->otm
.otmptSubscriptSize
.x
= SCALE_X(pOS2
->ySubscriptXSize
);
3779 font
->otm
.otmptSubscriptSize
.y
= SCALE_Y(pOS2
->ySubscriptYSize
);
3780 font
->otm
.otmptSubscriptOffset
.x
= SCALE_X(pOS2
->ySubscriptXOffset
);
3781 font
->otm
.otmptSubscriptOffset
.y
= SCALE_Y(pOS2
->ySubscriptYOffset
);
3782 font
->otm
.otmptSuperscriptSize
.x
= SCALE_X(pOS2
->ySuperscriptXSize
);
3783 font
->otm
.otmptSuperscriptSize
.y
= SCALE_Y(pOS2
->ySuperscriptYSize
);
3784 font
->otm
.otmptSuperscriptOffset
.x
= SCALE_X(pOS2
->ySuperscriptXOffset
);
3785 font
->otm
.otmptSuperscriptOffset
.y
= SCALE_Y(pOS2
->ySuperscriptYOffset
);
3786 font
->otm
.otmsStrikeoutSize
= SCALE_Y(pOS2
->yStrikeoutSize
);
3787 font
->otm
.otmsStrikeoutPosition
= SCALE_Y(pOS2
->yStrikeoutPosition
);
3789 font
->otm
.otmsUnderscoreSize
= 0;
3790 font
->otm
.otmsUnderscorePosition
= 0;
3792 font
->otm
.otmsUnderscoreSize
= SCALE_Y(pPost
->underlineThickness
);
3793 font
->otm
.otmsUnderscorePosition
= SCALE_Y(pPost
->underlinePosition
);
3801 /*************************************************************
3802 * freetype_get_char_width_info
3804 static BOOL CDECL
freetype_get_char_width_info( struct gdi_font
*font
, struct char_width_info
*info
)
3806 FT_Face ft_face
= get_ft_face( font
);
3807 TT_HoriHeader
*pHori
;
3809 TRACE("%p, %p\n", font
, info
);
3811 if ((pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
)))
3813 FT_Fixed em_scale
= pFT_MulDiv(font
->ppem
, 1 << 16, ft_face
->units_per_EM
);
3814 info
->lsb
= (SHORT
)pFT_MulFix(pHori
->min_Left_Side_Bearing
, em_scale
);
3815 info
->rsb
= (SHORT
)pFT_MulFix(pHori
->min_Right_Side_Bearing
, em_scale
);
3822 /*************************************************************
3823 * freetype_get_unicode_ranges
3825 * Retrieve a list of supported Unicode ranges for a given font.
3826 * Can be called with NULL gs to calculate the buffer size. Returns
3827 * the number of ranges found.
3829 static DWORD CDECL
freetype_get_unicode_ranges( struct gdi_font
*font
, GLYPHSET
*gs
)
3831 FT_Face ft_face
= get_ft_face( font
);
3832 DWORD num_ranges
= 0;
3834 if (ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
3837 FT_ULong char_code
, char_code_prev
;
3840 char_code_prev
= char_code
= pFT_Get_First_Char(ft_face
, &glyph_code
);
3842 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
3843 ft_face
->num_glyphs
, glyph_code
, char_code
);
3845 if (!glyph_code
) return 0;
3849 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
3850 gs
->ranges
[0].cGlyphs
= 0;
3851 gs
->cGlyphsSupported
= 0;
3857 if (char_code
< char_code_prev
)
3859 ERR("expected increasing char code from FT_Get_Next_Char\n");
3862 if (char_code
- char_code_prev
> 1)
3867 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
3868 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
3869 gs
->cGlyphsSupported
++;
3874 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
3875 gs
->cGlyphsSupported
++;
3877 char_code_prev
= char_code
;
3878 char_code
= pFT_Get_Next_Char(ft_face
, char_code
, &glyph_code
);
3883 DWORD encoding
= RtlUlongByteSwap(ft_face
->charmap
->encoding
);
3884 FIXME("encoding %s not supported\n", debugstr_an((char *)&encoding
, 4));
3890 /*************************************************************************
3891 * Kerning support for TrueType fonts
3894 struct TT_kern_table
3900 struct TT_kern_subtable
3909 USHORT horizontal
: 1;
3911 USHORT cross_stream
: 1;
3912 USHORT override
: 1;
3913 USHORT reserved1
: 4;
3919 struct TT_format0_kern_subtable
3923 USHORT entrySelector
;
3934 static DWORD
parse_format0_kern_subtable(struct gdi_font
*font
,
3935 const struct TT_format0_kern_subtable
*tt_f0_ks
,
3936 const USHORT
*glyph_to_char
,
3937 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
3939 FT_Face ft_face
= get_ft_face( font
);
3941 const struct TT_kern_pair
*tt_kern_pair
;
3943 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, ft_face
->units_per_EM
);
3945 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
3947 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
3948 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
3949 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
3951 if (!kern_pair
|| !cPairs
)
3954 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
3956 nPairs
= min(nPairs
, cPairs
);
3958 for (i
= 0; i
< nPairs
; i
++)
3960 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
3961 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
3962 /* this algorithm appears to better match what Windows does */
3963 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
3964 if (kern_pair
->iKernAmount
< 0)
3966 kern_pair
->iKernAmount
-= ft_face
->units_per_EM
/ 2;
3967 kern_pair
->iKernAmount
-= font
->ppem
;
3969 else if (kern_pair
->iKernAmount
> 0)
3971 kern_pair
->iKernAmount
+= ft_face
->units_per_EM
/ 2;
3972 kern_pair
->iKernAmount
+= font
->ppem
;
3974 kern_pair
->iKernAmount
/= ft_face
->units_per_EM
;
3976 TRACE("left %u right %u value %d\n",
3977 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
3981 TRACE("copied %u entries\n", nPairs
);
3985 /*************************************************************
3986 * freetype_get_kerning_pairs
3988 static DWORD CDECL
freetype_get_kerning_pairs( struct gdi_font
*font
, KERNINGPAIR
**pairs
)
3990 FT_Face ft_face
= get_ft_face( font
);
3991 DWORD length
, count
= 0;
3993 const struct TT_kern_table
*tt_kern_table
;
3994 const struct TT_kern_subtable
*tt_kern_subtable
;
3996 USHORT
*glyph_to_char
;
3998 length
= freetype_get_font_data(font
, MS_KERN_TAG
, 0, NULL
, 0);
4000 if (length
== GDI_ERROR
)
4002 TRACE("no kerning data in the font\n");
4006 buf
= RtlAllocateHeap(GetProcessHeap(), 0, length
);
4009 freetype_get_font_data(font
, MS_KERN_TAG
, 0, buf
, length
);
4011 /* build a glyph index to char code map */
4012 glyph_to_char
= RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(USHORT
) * 65536);
4015 RtlFreeHeap(GetProcessHeap(), 0, buf
);
4019 if (ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
4025 char_code
= pFT_Get_First_Char(ft_face
, &glyph_code
);
4027 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
4028 ft_face
->num_glyphs
, glyph_code
, char_code
);
4032 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
4034 /* FIXME: This doesn't match what Windows does: it does some fancy
4035 * things with duplicate glyph index to char code mappings, while
4036 * we just avoid overriding existing entries.
4038 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
4039 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
4041 char_code
= pFT_Get_Next_Char(ft_face
, char_code
, &glyph_code
);
4046 DWORD encoding
= RtlUlongByteSwap(ft_face
->charmap
->encoding
);
4049 FIXME("encoding %s not supported\n", debugstr_an((char *)&encoding
, 4));
4050 for (n
= 0; n
<= 65535; n
++)
4051 glyph_to_char
[n
] = (USHORT
)n
;
4054 tt_kern_table
= buf
;
4055 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
4056 TRACE("version %u, nTables %u\n",
4057 GET_BE_WORD(tt_kern_table
->version
), nTables
);
4059 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
4061 for (i
= 0; i
< nTables
; i
++)
4063 struct TT_kern_subtable tt_kern_subtable_copy
;
4065 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
4066 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
4067 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
4069 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
4070 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
4071 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
4073 /* According to the TrueType specification this is the only format
4074 * that will be properly interpreted by Windows and OS/2
4076 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
4078 DWORD new_chunk
, old_total
= count
;
4080 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
4081 glyph_to_char
, NULL
, 0);
4085 *pairs
= RtlAllocateHeap(GetProcessHeap(), 0, count
* sizeof(**pairs
));
4087 *pairs
= RtlReAllocateHeap(GetProcessHeap(), 0, *pairs
, count
* sizeof(**pairs
));
4089 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
4090 glyph_to_char
, *pairs
+ old_total
, new_chunk
);
4093 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
4095 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
4098 RtlFreeHeap(GetProcessHeap(), 0, glyph_to_char
);
4099 RtlFreeHeap(GetProcessHeap(), 0, buf
);
4103 static const struct font_backend_funcs font_funcs
=
4105 freetype_load_fonts
,
4106 fontconfig_enum_family_fallbacks
,
4108 freetype_add_mem_font
,
4110 freetype_get_font_data
,
4111 freetype_get_aa_flags
,
4112 freetype_get_glyph_index
,
4113 freetype_get_default_glyph
,
4114 freetype_get_glyph_outline
,
4115 freetype_get_unicode_ranges
,
4116 freetype_get_char_width_info
,
4117 freetype_set_outline_text_metrics
,
4118 freetype_set_bitmap_text_metrics
,
4119 freetype_get_kerning_pairs
,
4120 freetype_destroy_font
4123 static NTSTATUS
init_freetype_lib( HMODULE module
, DWORD reason
, const void *ptr_in
, void *ptr_out
)
4125 callback_funcs
= ptr_in
;
4126 if (!init_freetype()) return STATUS_DLL_NOT_FOUND
;
4127 #ifdef SONAME_LIBFONTCONFIG
4130 NtQueryDefaultLocale( FALSE
, &system_lcid
);
4131 *(const struct font_backend_funcs
**)ptr_out
= &font_funcs
;
4132 return STATUS_SUCCESS
;
4135 #else /* HAVE_FREETYPE */
4137 static NTSTATUS
init_freetype_lib( HMODULE module
, DWORD reason
, const void *ptr_in
, void *ptr_out
)
4139 return STATUS_DLL_NOT_FOUND
;
4142 #endif /* HAVE_FREETYPE */
4144 NTSTATUS CDECL
__wine_init_unix_lib( HMODULE module
, DWORD reason
, const void *ptr_in
, void *ptr_out
)
4146 if (reason
!= DLL_PROCESS_ATTACH
) return STATUS_SUCCESS
;
4148 if (ptr_in
) return init_freetype_lib( module
, reason
, ptr_in
, ptr_out
);
4149 else return init_opengl_lib( module
, reason
, ptr_in
, ptr_out
);