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
32 #include <sys/types.h>
43 #ifdef HAVE_CARBON_CARBON_H
44 #define LoadResource __carbon_LoadResource
45 #define CheckMenuItem __carbon_CheckMenuItem
46 #define CompareString __carbon_CompareString
47 #define GetCurrentThread __carbon_GetCurrentThread
48 #define GetCurrentProcess __carbon_GetCurrentProcess
49 #define AnimatePalette __carbon_AnimatePalette
50 #define DeleteMenu __carbon_DeleteMenu
51 #define DrawMenu __carbon_DrawMenu
52 #define DrawMenuBar __carbon_DrawMenuBar
53 #define EnableMenuItem __carbon_EnableMenuItem
54 #define EqualRgn __carbon_EqualRgn
55 #define FillRgn __carbon_FillRgn
56 #define FrameRgn __carbon_FrameRgn
57 #define GetMenu __carbon_GetMenu
58 #define GetPixel __carbon_GetPixel
59 #define InvertRgn __carbon_InvertRgn
60 #define IsWindowVisible __carbon_IsWindowVisible
61 #define LineTo __carbon_LineTo
62 #define MoveWindow __carbon_MoveWindow
63 #define OffsetRgn __carbon_OffsetRgn
64 #define PaintRgn __carbon_PaintRgn
65 #define Polygon __carbon_Polygon
66 #define ResizePalette __carbon_ResizePalette
67 #define SetRectRgn __carbon_SetRectRgn
68 #define ShowWindow __carbon_ShowWindow
69 #include <Carbon/Carbon.h>
72 #undef GetCurrentThread
74 #undef GetCurrentProcess
87 #undef IsWindowVisible
96 #endif /* HAVE_CARBON_CARBON_H */
98 #ifdef HAVE_FT2BUILD_H
100 #include FT_FREETYPE_H
103 #include FT_TRUETYPE_TABLES_H
104 #include FT_SFNT_NAMES_H
105 #include FT_TRUETYPE_IDS_H
106 #include FT_OUTLINE_H
107 #include FT_TRIGONOMETRY_H
109 #include FT_WINFONTS_H
110 #ifdef FT_LCD_FILTER_H
111 #include FT_LCD_FILTER_H
113 #endif /* HAVE_FT2BUILD_H */
115 #include "ntstatus.h"
116 #define WIN32_NO_STATUS
119 #include "winternl.h"
120 #include "winerror.h"
123 #include "ntgdi_private.h"
124 #include "wine/debug.h"
125 #include "wine/list.h"
129 WINE_DEFAULT_DEBUG_CHANNEL(font
);
131 #ifndef HAVE_FT_TRUETYPEENGINETYPE
134 FT_TRUETYPE_ENGINE_TYPE_NONE
= 0,
135 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED
,
136 FT_TRUETYPE_ENGINE_TYPE_PATENTED
137 } FT_TrueTypeEngineType
;
140 static FT_Library library
= 0;
147 static FT_Version_t FT_Version
;
148 static DWORD FT_SimpleVersion
;
149 #define FT_VERSION_VALUE(major, minor, patch) (((major) << 16) | ((minor) << 8) | (patch))
151 static void *ft_handle
= NULL
;
153 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
154 MAKE_FUNCPTR(FT_Done_Face
);
155 MAKE_FUNCPTR(FT_Get_Char_Index
);
156 MAKE_FUNCPTR(FT_Get_First_Char
);
157 MAKE_FUNCPTR(FT_Get_Next_Char
);
158 MAKE_FUNCPTR(FT_Get_Sfnt_Name
);
159 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count
);
160 MAKE_FUNCPTR(FT_Get_Sfnt_Table
);
161 MAKE_FUNCPTR(FT_Get_WinFNT_Header
);
162 MAKE_FUNCPTR(FT_Init_FreeType
);
163 MAKE_FUNCPTR(FT_Library_Version
);
164 MAKE_FUNCPTR(FT_Load_Glyph
);
165 MAKE_FUNCPTR(FT_Load_Sfnt_Table
);
166 MAKE_FUNCPTR(FT_Matrix_Multiply
);
167 MAKE_FUNCPTR(FT_MulDiv
);
168 #ifdef FT_MULFIX_INLINED
169 #define pFT_MulFix FT_MULFIX_INLINED
171 MAKE_FUNCPTR(FT_MulFix
);
173 MAKE_FUNCPTR(FT_New_Face
);
174 MAKE_FUNCPTR(FT_New_Memory_Face
);
175 MAKE_FUNCPTR(FT_Outline_Get_Bitmap
);
176 MAKE_FUNCPTR(FT_Outline_Get_CBox
);
177 MAKE_FUNCPTR(FT_Outline_Transform
);
178 MAKE_FUNCPTR(FT_Outline_Translate
);
179 MAKE_FUNCPTR(FT_Render_Glyph
);
180 MAKE_FUNCPTR(FT_Set_Charmap
);
181 MAKE_FUNCPTR(FT_Set_Pixel_Sizes
);
182 MAKE_FUNCPTR(FT_Vector_Length
);
183 MAKE_FUNCPTR(FT_Vector_Transform
);
184 MAKE_FUNCPTR(FT_Vector_Unit
);
185 static FT_Error (*pFT_Outline_Embolden
)(FT_Outline
*, FT_Pos
);
186 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type
)(FT_Library
);
187 #ifdef FT_LCD_FILTER_H
188 static FT_Error (*pFT_Library_SetLcdFilter
)(FT_Library
, FT_LcdFilter
);
190 static FT_Error (*pFT_Property_Set
)(FT_Library
, const FT_String
*, const FT_String
*, const void *);
192 #ifdef SONAME_LIBFONTCONFIG
193 #include <fontconfig/fontconfig.h>
194 MAKE_FUNCPTR(FcConfigSubstitute
);
195 MAKE_FUNCPTR(FcDefaultSubstitute
);
196 MAKE_FUNCPTR(FcFontList
);
197 MAKE_FUNCPTR(FcFontMatch
);
198 MAKE_FUNCPTR(FcFontSetDestroy
);
199 MAKE_FUNCPTR(FcInit
);
200 MAKE_FUNCPTR(FcPatternAddString
);
201 MAKE_FUNCPTR(FcPatternCreate
);
202 MAKE_FUNCPTR(FcPatternDestroy
);
203 MAKE_FUNCPTR(FcPatternGetBool
);
204 MAKE_FUNCPTR(FcPatternGetInteger
);
205 MAKE_FUNCPTR(FcPatternGetString
);
206 MAKE_FUNCPTR(FcConfigGetFontDirs
);
207 MAKE_FUNCPTR(FcConfigGetCurrent
);
208 MAKE_FUNCPTR(FcCacheCopySet
);
209 MAKE_FUNCPTR(FcCacheNumSubdir
);
210 MAKE_FUNCPTR(FcCacheSubdir
);
211 MAKE_FUNCPTR(FcDirCacheRead
);
212 MAKE_FUNCPTR(FcDirCacheUnload
);
213 MAKE_FUNCPTR(FcStrListCreate
);
214 MAKE_FUNCPTR(FcStrListDone
);
215 MAKE_FUNCPTR(FcStrListNext
);
216 MAKE_FUNCPTR(FcStrSetAdd
);
217 MAKE_FUNCPTR(FcStrSetCreate
);
218 MAKE_FUNCPTR(FcStrSetDestroy
);
219 MAKE_FUNCPTR(FcStrSetMember
);
221 #define FC_NAMELANG "namelang"
224 #define FC_PRGNAME "prgname"
226 #endif /* SONAME_LIBFONTCONFIG */
231 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
232 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
233 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
236 #ifndef ft_encoding_none
237 #define FT_ENCODING_NONE ft_encoding_none
239 #ifndef ft_encoding_ms_symbol
240 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
242 #ifndef ft_encoding_unicode
243 #define FT_ENCODING_UNICODE ft_encoding_unicode
245 #ifndef ft_encoding_apple_roman
246 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
249 #ifdef WORDS_BIGENDIAN
250 #define GET_BE_WORD(x) (x)
251 #define GET_BE_DWORD(x) (x)
253 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
254 #define GET_BE_DWORD(x) RtlUlongByteSwap(x)
258 #define GASP_GRIDFIT 0x01
259 #define GASP_DOGRAY 0x02
261 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
262 So to let this compile on older versions of FreeType we'll define the
263 new structure here. */
265 FT_Short height
, width
;
266 FT_Pos size
, x_ppem
, y_ppem
;
269 struct font_private_data
272 struct font_mapping
*mapping
;
275 static inline FT_Face
get_ft_face( struct gdi_font
*font
)
277 return ((struct font_private_data
*)font
->private)->ft_face
;
290 static struct list mappings_list
= LIST_INIT( mappings_list
);
292 static UINT default_aa_flags
;
293 static LCID system_lcid
;
295 static BOOL
freetype_set_outline_text_metrics( struct gdi_font
*font
);
296 static BOOL
freetype_set_bitmap_text_metrics( struct gdi_font
*font
);
298 /****************************************
299 * Notes on .fon files
301 * The fonts System, FixedSys and Terminal are special. There are typically multiple
302 * versions installed for different resolutions and codepages. Windows stores which one to use
303 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
305 * FIXEDFON.FON FixedSys
307 * OEMFONT.FON Terminal
308 * LogPixels Current dpi set by the display control panel applet
309 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
310 * also has a LogPixels value that appears to mirror this)
312 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
313 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
314 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
315 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
316 * so that makes sense.
318 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
319 * to be mapped into the registry on Windows 2000 at least).
322 * ega80woa.fon=ega80850.fon
323 * ega40woa.fon=ega40850.fon
324 * cga80woa.fon=cga80850.fon
325 * cga40woa.fon=cga40850.fon
328 #ifdef HAVE_CARBON_CARBON_H
329 static char *find_cache_dir(void)
333 static char cached_path
[MAX_PATH
];
334 static const char *wine
= "/Wine", *fonts
= "/Fonts";
336 if(*cached_path
) return cached_path
;
338 err
= FSFindFolder(kUserDomain
, kCachedDataFolderType
, kCreateFolder
, &ref
);
341 WARN("can't create cached data folder\n");
344 err
= FSRefMakePath(&ref
, (unsigned char*)cached_path
, sizeof(cached_path
));
347 WARN("can't create cached data path\n");
351 if(strlen(cached_path
) + strlen(wine
) + strlen(fonts
) + 1 > sizeof(cached_path
))
353 ERR("Could not create full path\n");
357 strcat(cached_path
, wine
);
359 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
361 WARN("Couldn't mkdir %s\n", cached_path
);
365 strcat(cached_path
, fonts
);
366 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
368 WARN("Couldn't mkdir %s\n", cached_path
);
375 /******************************************************************
378 * Extracts individual TrueType font files from a Mac suitcase font
379 * and saves them into the user's caches directory (see
381 * Returns a NULL terminated array of filenames.
383 * We do this because they are apps that try to read ttf files
384 * themselves and they don't like Mac suitcase files.
386 static char **expand_mac_font(const char *path
)
389 ResFileRefNum res_ref
;
393 const char *filename
;
397 unsigned int size
, max_size
;
400 TRACE("path %s\n", path
);
402 s
= FSPathMakeRef((unsigned char*)path
, &ref
, FALSE
);
405 WARN("failed to get ref\n");
409 s
= FSOpenResourceFile(&ref
, 0, NULL
, fsRdPerm
, &res_ref
);
412 TRACE("no data fork, so trying resource fork\n");
413 res_ref
= FSOpenResFile(&ref
, fsRdPerm
);
416 TRACE("unable to open resource fork\n");
423 ret
.array
= calloc( ret
.max_size
, sizeof(*ret
.array
) );
426 CloseResFile(res_ref
);
430 out_dir
= find_cache_dir();
432 filename
= strrchr(path
, '/');
433 if(!filename
) filename
= path
;
436 /* output filename has the form out_dir/filename_%04x.ttf */
437 output_len
= strlen(out_dir
) + 1 + strlen(filename
) + 5 + 5;
444 unsigned short *num_faces_ptr
, num_faces
, face
;
447 ResType fond_res
= FT_MAKE_TAG('F','O','N','D');
449 fond
= Get1IndResource(fond_res
, idx
);
451 TRACE("got fond resource %d\n", idx
);
454 fam_rec
= *(FamRec
**)fond
;
455 num_faces_ptr
= (unsigned short *)(fam_rec
+ 1);
456 num_faces
= GET_BE_WORD(*num_faces_ptr
);
458 assoc
= (AsscEntry
*)(num_faces_ptr
+ 1);
459 TRACE("num faces %04x\n", num_faces
);
460 for(face
= 0; face
< num_faces
; face
++, assoc
++)
463 ResType sfnt_res
= FT_MAKE_TAG('s','f','n','t');
464 unsigned short size
, font_id
;
467 size
= GET_BE_WORD(assoc
->fontSize
);
468 font_id
= GET_BE_WORD(assoc
->fontID
);
471 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id
, size
);
475 TRACE("trying to load sfnt id %04x\n", font_id
);
476 sfnt
= GetResource(sfnt_res
, font_id
);
479 TRACE("can't get sfnt resource %04x\n", font_id
);
483 output
= malloc( output_len
);
488 sprintf(output
, "%s/%s_%04x.ttf", out_dir
, filename
, font_id
);
490 fd
= open(output
, O_CREAT
| O_EXCL
| O_WRONLY
, 0600);
491 if(fd
!= -1 || errno
== EEXIST
)
495 unsigned char *sfnt_data
;
498 sfnt_data
= *(unsigned char**)sfnt
;
499 write(fd
, sfnt_data
, GetHandleSize(sfnt
));
503 if(ret
.size
>= ret
.max_size
- 1) /* Always want the last element to be NULL */
505 ret
.array
= realloc( ret
.array
, ret
.max_size
* sizeof(*ret
.array
) * 2 );
506 memset( ret
.array
+ ret
.max_size
, 0, ret
.max_size
* sizeof(*ret
.array
) );
509 ret
.array
[ret
.size
++] = output
;
513 WARN("unable to create %s\n", output
);
517 ReleaseResource(sfnt
);
520 ReleaseResource(fond
);
523 CloseResFile(res_ref
);
528 #endif /* HAVE_CARBON_CARBON_H */
531 This function builds an FT_Fixed from a double. It fails if the absolute
532 value of the float number is greater than 32768.
534 static inline FT_Fixed
FT_FixedFromFloat(double f
)
540 This function builds an FT_Fixed from a FIXED. It simply put f.value
541 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
543 static inline FT_Fixed
FT_FixedFromFIXED(FIXED f
)
545 return (FT_Fixed
)((int)f
.value
<< 16 | (unsigned int)f
.fract
);
548 static BOOL
is_hinting_enabled(void)
550 static int enabled
= -1;
554 /* Use the >= 2.2.0 function if available */
555 if (pFT_Get_TrueType_Engine_Type
)
557 FT_TrueTypeEngineType type
= pFT_Get_TrueType_Engine_Type(library
);
558 enabled
= (type
== FT_TRUETYPE_ENGINE_TYPE_PATENTED
);
560 else enabled
= FALSE
;
561 TRACE("hinting is %senabled\n", enabled
? "" : "NOT ");
566 static BOOL
is_subpixel_rendering_enabled( void )
568 static int enabled
= -1;
571 /* FreeType >= 2.8.1 offers LCD-optimezed rendering without lcd filters. */
572 if (FT_SimpleVersion
>= FT_VERSION_VALUE(2, 8, 1))
574 #ifdef FT_LCD_FILTER_H
575 else if (pFT_Library_SetLcdFilter
&&
576 pFT_Library_SetLcdFilter( NULL
, 0 ) != FT_Err_Unimplemented_Feature
)
579 else enabled
= FALSE
;
581 TRACE("subpixel rendering is %senabled\n", enabled
? "" : "NOT ");
587 static LPWSTR
strdupW(LPCWSTR p
)
590 DWORD len
= (lstrlenW(p
) + 1) * sizeof(WCHAR
);
596 static WCHAR
*towstr(const char *str
)
598 DWORD len
= strlen(str
) + 1;
599 WCHAR
*wstr
= malloc( len
* sizeof(WCHAR
) );
600 win32u_mbtowc( NULL
, wstr
, len
* sizeof(WCHAR
), str
, len
);
605 static const LANGID mac_langid_table
[] =
607 MAKELANGID(LANG_ENGLISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ENGLISH */
608 MAKELANGID(LANG_FRENCH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FRENCH */
609 MAKELANGID(LANG_GERMAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GERMAN */
610 MAKELANGID(LANG_ITALIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ITALIAN */
611 MAKELANGID(LANG_DUTCH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_DUTCH */
612 MAKELANGID(LANG_SWEDISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SWEDISH */
613 MAKELANGID(LANG_SPANISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SPANISH */
614 MAKELANGID(LANG_DANISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_DANISH */
615 MAKELANGID(LANG_PORTUGUESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PORTUGUESE */
616 MAKELANGID(LANG_NORWEGIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_NORWEGIAN */
617 MAKELANGID(LANG_HEBREW
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HEBREW */
618 MAKELANGID(LANG_JAPANESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_JAPANESE */
619 MAKELANGID(LANG_ARABIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ARABIC */
620 MAKELANGID(LANG_FINNISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FINNISH */
621 MAKELANGID(LANG_GREEK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GREEK */
622 MAKELANGID(LANG_ICELANDIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ICELANDIC */
623 MAKELANGID(LANG_MALTESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALTESE */
624 MAKELANGID(LANG_TURKISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TURKISH */
625 MAKELANGID(LANG_CROATIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CROATIAN */
626 MAKELANGID(LANG_CHINESE_TRADITIONAL
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CHINESE_TRADITIONAL */
627 MAKELANGID(LANG_URDU
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_URDU */
628 MAKELANGID(LANG_HINDI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HINDI */
629 MAKELANGID(LANG_THAI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_THAI */
630 MAKELANGID(LANG_KOREAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KOREAN */
631 MAKELANGID(LANG_LITHUANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LITHUANIAN */
632 MAKELANGID(LANG_POLISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_POLISH */
633 MAKELANGID(LANG_HUNGARIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HUNGARIAN */
634 MAKELANGID(LANG_ESTONIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ESTONIAN */
635 MAKELANGID(LANG_LATVIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LETTISH */
636 MAKELANGID(LANG_SAMI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SAAMISK */
637 MAKELANGID(LANG_FAEROESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FAEROESE */
638 MAKELANGID(LANG_FARSI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FARSI */
639 MAKELANGID(LANG_RUSSIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_RUSSIAN */
640 MAKELANGID(LANG_CHINESE_SIMPLIFIED
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CHINESE_SIMPLIFIED */
641 MAKELANGID(LANG_DUTCH
,SUBLANG_DUTCH_BELGIAN
), /* TT_MAC_LANGID_FLEMISH */
642 MAKELANGID(LANG_IRISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_IRISH */
643 MAKELANGID(LANG_ALBANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ALBANIAN */
644 MAKELANGID(LANG_ROMANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ROMANIAN */
645 MAKELANGID(LANG_CZECH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CZECH */
646 MAKELANGID(LANG_SLOVAK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SLOVAK */
647 MAKELANGID(LANG_SLOVENIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SLOVENIAN */
648 0, /* TT_MAC_LANGID_YIDDISH */
649 MAKELANGID(LANG_SERBIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SERBIAN */
650 MAKELANGID(LANG_MACEDONIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MACEDONIAN */
651 MAKELANGID(LANG_BULGARIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BULGARIAN */
652 MAKELANGID(LANG_UKRAINIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UKRAINIAN */
653 MAKELANGID(LANG_BELARUSIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BYELORUSSIAN */
654 MAKELANGID(LANG_UZBEK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UZBEK */
655 MAKELANGID(LANG_KAZAK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KAZAKH */
656 MAKELANGID(LANG_AZERI
,SUBLANG_AZERI_CYRILLIC
), /* TT_MAC_LANGID_AZERBAIJANI */
657 0, /* TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT */
658 MAKELANGID(LANG_ARMENIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ARMENIAN */
659 MAKELANGID(LANG_GEORGIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GEORGIAN */
660 0, /* TT_MAC_LANGID_MOLDAVIAN */
661 MAKELANGID(LANG_KYRGYZ
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KIRGHIZ */
662 MAKELANGID(LANG_TAJIK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TAJIKI */
663 MAKELANGID(LANG_TURKMEN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TURKMEN */
664 MAKELANGID(LANG_MONGOLIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MONGOLIAN */
665 MAKELANGID(LANG_MONGOLIAN
,SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA
), /* TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT */
666 MAKELANGID(LANG_PASHTO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PASHTO */
667 0, /* TT_MAC_LANGID_KURDISH */
668 MAKELANGID(LANG_KASHMIRI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KASHMIRI */
669 MAKELANGID(LANG_SINDHI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SINDHI */
670 MAKELANGID(LANG_TIBETAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TIBETAN */
671 MAKELANGID(LANG_NEPALI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_NEPALI */
672 MAKELANGID(LANG_SANSKRIT
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SANSKRIT */
673 MAKELANGID(LANG_MARATHI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MARATHI */
674 MAKELANGID(LANG_BENGALI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BENGALI */
675 MAKELANGID(LANG_ASSAMESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ASSAMESE */
676 MAKELANGID(LANG_GUJARATI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GUJARATI */
677 MAKELANGID(LANG_PUNJABI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PUNJABI */
678 MAKELANGID(LANG_ORIYA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ORIYA */
679 MAKELANGID(LANG_MALAYALAM
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAYALAM */
680 MAKELANGID(LANG_KANNADA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KANNADA */
681 MAKELANGID(LANG_TAMIL
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TAMIL */
682 MAKELANGID(LANG_TELUGU
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TELUGU */
683 MAKELANGID(LANG_SINHALESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SINHALESE */
684 0, /* TT_MAC_LANGID_BURMESE */
685 MAKELANGID(LANG_KHMER
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KHMER */
686 MAKELANGID(LANG_LAO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LAO */
687 MAKELANGID(LANG_VIETNAMESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_VIETNAMESE */
688 MAKELANGID(LANG_INDONESIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_INDONESIAN */
689 0, /* TT_MAC_LANGID_TAGALOG */
690 MAKELANGID(LANG_MALAY
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAY_ROMAN_SCRIPT */
691 0, /* TT_MAC_LANGID_MALAY_ARABIC_SCRIPT */
692 MAKELANGID(LANG_AMHARIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_AMHARIC */
693 MAKELANGID(LANG_TIGRIGNA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TIGRINYA */
694 0, /* TT_MAC_LANGID_GALLA */
695 0, /* TT_MAC_LANGID_SOMALI */
696 MAKELANGID(LANG_SWAHILI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SWAHILI */
697 0, /* TT_MAC_LANGID_RUANDA */
698 0, /* TT_MAC_LANGID_RUNDI */
699 0, /* TT_MAC_LANGID_CHEWA */
700 MAKELANGID(LANG_MALAGASY
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAGASY */
701 MAKELANGID(LANG_ESPERANTO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ESPERANTO */
702 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 95-111 */
703 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 112-127 */
704 MAKELANGID(LANG_WELSH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_WELSH */
705 MAKELANGID(LANG_BASQUE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BASQUE */
706 MAKELANGID(LANG_CATALAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CATALAN */
707 0, /* TT_MAC_LANGID_LATIN */
708 MAKELANGID(LANG_QUECHUA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_QUECHUA */
709 0, /* TT_MAC_LANGID_GUARANI */
710 0, /* TT_MAC_LANGID_AYMARA */
711 MAKELANGID(LANG_TATAR
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TATAR */
712 MAKELANGID(LANG_UIGHUR
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UIGHUR */
713 0, /* TT_MAC_LANGID_DZONGKHA */
714 0, /* TT_MAC_LANGID_JAVANESE */
715 0, /* TT_MAC_LANGID_SUNDANESE */
716 MAKELANGID(LANG_GALICIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GALICIAN */
717 MAKELANGID(LANG_AFRIKAANS
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_AFRIKAANS */
718 MAKELANGID(LANG_BRETON
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BRETON */
719 MAKELANGID(LANG_INUKTITUT
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_INUKTITUT */
720 MAKELANGID(LANG_SCOTTISH_GAELIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SCOTTISH_GAELIC */
721 MAKELANGID(LANG_MANX_GAELIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MANX_GAELIC */
722 MAKELANGID(LANG_IRISH
,SUBLANG_IRISH_IRELAND
), /* TT_MAC_LANGID_IRISH_GAELIC */
723 0, /* TT_MAC_LANGID_TONGAN */
724 0, /* TT_MAC_LANGID_GREEK_POLYTONIC */
725 MAKELANGID(LANG_GREENLANDIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GREELANDIC */
726 MAKELANGID(LANG_AZERI
,SUBLANG_AZERI_LATIN
), /* TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT */
729 static CPTABLEINFO
*get_mac_code_page( const FT_SfntName
*name
)
731 int id
= name
->encoding_id
;
733 if (name
->encoding_id
== TT_MAC_ID_SIMPLIFIED_CHINESE
) id
= 8; /* special case */
734 return get_cptable( 10000 + id
);
737 static int match_name_table_language( const FT_SfntName
*name
, LANGID lang
)
742 switch (name
->platform_id
)
744 case TT_PLATFORM_MICROSOFT
:
745 res
+= 5; /* prefer the Microsoft name */
746 switch (name
->encoding_id
)
748 case TT_MS_ID_UNICODE_CS
:
749 case TT_MS_ID_SYMBOL_CS
:
750 name_lang
= name
->language_id
;
756 case TT_PLATFORM_MACINTOSH
:
757 if (!get_mac_code_page( name
)) return 0;
758 if (name
->language_id
>= ARRAY_SIZE( mac_langid_table
)) return 0;
759 name_lang
= mac_langid_table
[name
->language_id
];
761 case TT_PLATFORM_APPLE_UNICODE
:
762 res
+= 2; /* prefer Unicode encodings */
763 switch (name
->encoding_id
)
765 case TT_APPLE_ID_DEFAULT
:
766 case TT_APPLE_ID_ISO_10646
:
767 case TT_APPLE_ID_UNICODE_2_0
:
768 if (name
->language_id
>= ARRAY_SIZE( mac_langid_table
)) return 0;
769 name_lang
= mac_langid_table
[name
->language_id
];
778 if (name_lang
== lang
) res
+= 30;
779 else if (PRIMARYLANGID( name_lang
) == PRIMARYLANGID( lang
)) res
+= 20;
780 else if (name_lang
== MAKELANGID( LANG_ENGLISH
, SUBLANG_DEFAULT
)) res
+= 10;
781 else if (lang
== MAKELANGID( LANG_NEUTRAL
, SUBLANG_NEUTRAL
)) res
+= 5 * (0x100000 - name_lang
);
785 static WCHAR
*copy_name_table_string( const FT_SfntName
*name
)
791 switch (name
->platform_id
)
793 case TT_PLATFORM_APPLE_UNICODE
:
794 case TT_PLATFORM_MICROSOFT
:
795 ret
= malloc( name
->string_len
+ sizeof(WCHAR
) );
796 for (i
= 0; i
< name
->string_len
/ 2; i
++)
797 ret
[i
] = (name
->string
[i
* 2] << 8) | name
->string
[i
* 2 + 1];
800 case TT_PLATFORM_MACINTOSH
:
801 if (!(cp
= get_mac_code_page( name
))) return NULL
;
802 ret
= malloc( (name
->string_len
+ 1) * sizeof(WCHAR
) );
803 i
= win32u_mbtowc( cp
, ret
, name
->string_len
* sizeof(WCHAR
),
804 (char *)name
->string
, name
->string_len
);
805 ret
[i
/ sizeof(WCHAR
)] = 0;
811 static WCHAR
*get_face_name(FT_Face ft_face
, FT_UShort name_id
, LANGID language_id
)
814 FT_UInt num_names
, name_index
;
815 int res
, best_lang
= 0, best_index
= -1;
817 if (!FT_IS_SFNT(ft_face
)) return NULL
;
819 num_names
= pFT_Get_Sfnt_Name_Count( ft_face
);
821 for (name_index
= 0; name_index
< num_names
; name_index
++)
823 if (pFT_Get_Sfnt_Name( ft_face
, name_index
, &name
)) continue;
824 if (name
.name_id
!= name_id
) continue;
825 res
= match_name_table_language( &name
, language_id
);
829 best_index
= name_index
;
833 if (best_index
!= -1 && !pFT_Get_Sfnt_Name( ft_face
, best_index
, &name
))
835 WCHAR
*ret
= copy_name_table_string( &name
);
836 TRACE( "name %u found platform %u lang %04x %s\n",
837 name_id
, name
.platform_id
, name
.language_id
, debugstr_w( ret
));
843 static WCHAR
*ft_face_get_family_name( FT_Face ft_face
, LANGID langid
)
847 if ((family_name
= get_face_name( ft_face
, TT_NAME_ID_FONT_FAMILY
, langid
)))
850 return towstr( ft_face
->family_name
);
853 static WCHAR
*ft_face_get_style_name( FT_Face ft_face
, LANGID langid
)
857 if ((style_name
= get_face_name( ft_face
, TT_NAME_ID_FONT_SUBFAMILY
, langid
)))
860 return towstr( ft_face
->style_name
);
863 static WCHAR
*ft_face_get_full_name( FT_Face ft_face
, LANGID langid
)
865 static const WCHAR space_w
[] = {' ',0};
866 WCHAR
*full_name
, *style_name
;
869 if ((full_name
= get_face_name( ft_face
, TT_NAME_ID_FULL_NAME
, langid
)))
872 full_name
= ft_face_get_family_name( ft_face
, langid
);
873 style_name
= ft_face_get_style_name( ft_face
, langid
);
875 length
= lstrlenW( full_name
) + lstrlenW( space_w
) + lstrlenW( style_name
) + 1;
876 full_name
= realloc( full_name
, length
* sizeof(WCHAR
) );
878 lstrcatW( full_name
, space_w
);
879 lstrcatW( full_name
, style_name
);
882 WARN( "full name not found, using %s instead\n", debugstr_w(full_name
) );
886 static inline FT_Fixed
get_font_version( FT_Face ft_face
)
888 FT_Fixed version
= 0;
891 header
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_head
);
892 if (header
) version
= header
->Font_Revision
;
897 static inline DWORD
get_ntm_flags( FT_Face ft_face
)
900 FT_ULong table_size
= 0;
901 FT_WinFNT_HeaderRec winfnt_header
;
903 if (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) flags
|= NTM_ITALIC
;
904 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
) flags
|= NTM_BOLD
;
906 /* fixup the flag for our fake-bold implementation. */
907 if (!FT_IS_SCALABLE( ft_face
) &&
908 !pFT_Get_WinFNT_Header( ft_face
, &winfnt_header
) &&
909 winfnt_header
.weight
> FW_NORMAL
)
912 if (flags
== 0) flags
= NTM_REGULAR
;
914 if (!pFT_Load_Sfnt_Table( ft_face
, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL
, &table_size
))
915 flags
|= NTM_PS_OPENTYPE
;
920 static inline void get_bitmap_size( FT_Face ft_face
, struct bitmap_font_size
*face_size
)
922 My_FT_Bitmap_Size
*size
;
923 FT_WinFNT_HeaderRec winfnt_header
;
925 size
= (My_FT_Bitmap_Size
*)ft_face
->available_sizes
;
926 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
927 size
->height
, size
->width
, size
->size
>> 6,
928 size
->x_ppem
>> 6, size
->y_ppem
>> 6);
929 face_size
->height
= size
->height
;
930 face_size
->width
= size
->width
;
931 face_size
->size
= size
->size
;
932 face_size
->x_ppem
= size
->x_ppem
;
933 face_size
->y_ppem
= size
->y_ppem
;
935 if (!pFT_Get_WinFNT_Header( ft_face
, &winfnt_header
)) {
936 face_size
->internal_leading
= winfnt_header
.internal_leading
;
937 if (winfnt_header
.external_leading
> 0 &&
938 (face_size
->height
==
939 winfnt_header
.pixel_height
+ winfnt_header
.external_leading
))
940 face_size
->height
= winfnt_header
.pixel_height
;
944 static inline void get_fontsig( FT_Face ft_face
, FONTSIGNATURE
*fs
)
947 FT_WinFNT_HeaderRec winfnt_header
;
950 memset( fs
, 0, sizeof(*fs
) );
952 os2
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_os2
);
955 fs
->fsUsb
[0] = os2
->ulUnicodeRange1
;
956 fs
->fsUsb
[1] = os2
->ulUnicodeRange2
;
957 fs
->fsUsb
[2] = os2
->ulUnicodeRange3
;
958 fs
->fsUsb
[3] = os2
->ulUnicodeRange4
;
960 if (os2
->version
== 0)
962 if (os2
->usFirstCharIndex
>= 0xf000 && os2
->usFirstCharIndex
< 0xf100)
963 fs
->fsCsb
[0] = FS_SYMBOL
;
965 fs
->fsCsb
[0] = FS_LATIN1
;
969 fs
->fsCsb
[0] = os2
->ulCodePageRange1
;
970 fs
->fsCsb
[1] = os2
->ulCodePageRange2
;
975 if (!pFT_Get_WinFNT_Header( ft_face
, &winfnt_header
))
977 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header
.pixel_height
, winfnt_header
.charset
,
978 winfnt_header
.vertical_resolution
,winfnt_header
.horizontal_resolution
, winfnt_header
.nominal_point_size
);
979 switch (winfnt_header
.charset
)
981 case ANSI_CHARSET
: fs
->fsCsb
[0] = FS_LATIN1
; break;
982 case EASTEUROPE_CHARSET
: fs
->fsCsb
[0] = FS_LATIN2
; break;
983 case RUSSIAN_CHARSET
: fs
->fsCsb
[0] = FS_CYRILLIC
; break;
984 case GREEK_CHARSET
: fs
->fsCsb
[0] = FS_GREEK
; break;
985 case TURKISH_CHARSET
: fs
->fsCsb
[0] = FS_TURKISH
; break;
986 case HEBREW_CHARSET
: fs
->fsCsb
[0] = FS_HEBREW
; break;
987 case ARABIC_CHARSET
: fs
->fsCsb
[0] = FS_ARABIC
; break;
988 case BALTIC_CHARSET
: fs
->fsCsb
[0] = FS_BALTIC
; break;
989 case VIETNAMESE_CHARSET
: fs
->fsCsb
[0] = FS_VIETNAMESE
; break;
990 case THAI_CHARSET
: fs
->fsCsb
[0] = FS_THAI
; break;
991 case SHIFTJIS_CHARSET
: fs
->fsCsb
[0] = FS_JISJAPAN
; break;
992 case GB2312_CHARSET
: fs
->fsCsb
[0] = FS_CHINESESIMP
; break;
993 case HANGEUL_CHARSET
: fs
->fsCsb
[0] = FS_WANSUNG
; break;
994 case CHINESEBIG5_CHARSET
: fs
->fsCsb
[0] = FS_CHINESETRAD
; break;
995 case JOHAB_CHARSET
: fs
->fsCsb
[0] = FS_JOHAB
; break;
996 case SYMBOL_CHARSET
: fs
->fsCsb
[0] = FS_SYMBOL
; break;
1001 if (fs
->fsCsb
[0] == 0)
1003 /* let's see if we can find any interesting cmaps */
1004 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
1006 switch (ft_face
->charmaps
[i
]->encoding
)
1008 case FT_ENCODING_UNICODE
:
1009 case FT_ENCODING_APPLE_ROMAN
:
1010 fs
->fsCsb
[0] |= FS_LATIN1
;
1012 case FT_ENCODING_MS_SYMBOL
:
1013 fs
->fsCsb
[0] |= FS_SYMBOL
;
1022 static FT_Face
new_ft_face( const char *file
, void *font_data_ptr
, DWORD font_data_size
,
1023 FT_Long face_index
, BOOL allow_bitmap
)
1031 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
1032 err
= pFT_New_Face(library
, file
, face_index
, &ft_face
);
1036 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr
, font_data_size
, face_index
);
1037 err
= pFT_New_Memory_Face(library
, font_data_ptr
, font_data_size
, face_index
, &ft_face
);
1042 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file
), font_data_ptr
, err
);
1046 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1047 if (!FT_IS_SCALABLE( ft_face
) && FT_SimpleVersion
< FT_VERSION_VALUE(2, 1, 9))
1049 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1053 if (!FT_IS_SFNT( ft_face
))
1055 if (FT_IS_SCALABLE( ft_face
) || !allow_bitmap
)
1057 WARN("Ignoring font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1063 if (!(pOS2
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_os2
)) ||
1064 !pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_hhea
) ||
1065 !pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_head
))
1067 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1068 "Skipping this font.\n", debugstr_a(file
), font_data_ptr
);
1072 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1073 we don't want to load these. */
1074 if (!memcmp( pOS2
->achVendID
, "Wine", sizeof(pOS2
->achVendID
) ))
1078 if (!pFT_Load_Sfnt_Table( ft_face
, FT_MAKE_TAG('E','B','S','C'), 0, NULL
, &len
))
1080 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file
));
1086 if (!ft_face
->family_name
|| !ft_face
->style_name
)
1088 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file
), font_data_ptr
);
1094 pFT_Done_Face( ft_face
);
1098 struct family_names_data
1100 LANGID primary_langid
;
1101 struct opentype_name family_name
;
1102 struct opentype_name second_name
;
1107 static BOOL
search_family_names_callback( LANGID langid
, struct opentype_name
*name
, void *user
)
1109 struct family_names_data
*data
= user
;
1111 if (langid
== MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
))
1113 data
->english_seen
= TRUE
;
1114 if (data
->primary_langid
== langid
) data
->primary_seen
= TRUE
;
1116 if (!data
->family_name
.bytes
) data
->family_name
= *name
;
1117 else if (data
->primary_langid
!= langid
) data
->second_name
= *name
;
1119 else if (data
->primary_langid
== langid
)
1121 data
->primary_seen
= TRUE
;
1122 if (!data
->second_name
.bytes
) data
->second_name
= data
->family_name
;
1123 data
->family_name
= *name
;
1125 else if (!data
->second_name
.bytes
) data
->second_name
= *name
;
1127 if (data
->family_name
.bytes
&& data
->second_name
.bytes
&& data
->primary_seen
&& data
->english_seen
)
1132 struct face_name_data
1134 LANGID primary_langid
;
1135 struct opentype_name face_name
;
1138 static BOOL
search_face_name_callback( LANGID langid
, struct opentype_name
*name
, void *user
)
1140 struct face_name_data
*data
= user
;
1142 if (langid
== data
->primary_langid
|| (langid
== MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
) && !data
->face_name
.bytes
))
1143 data
->face_name
= *name
;
1145 return langid
== data
->primary_langid
;
1148 static WCHAR
*decode_opentype_name( struct opentype_name
*name
)
1153 if (!name
->codepage
)
1155 len
= min( ARRAY_SIZE(buffer
), name
->length
/ sizeof(WCHAR
) );
1156 while (len
--) buffer
[len
] = GET_BE_WORD( ((WORD
*)name
->bytes
)[len
] );
1157 len
= min( ARRAY_SIZE(buffer
), name
->length
/ sizeof(WCHAR
) );
1161 CPTABLEINFO
*cptable
= get_cptable( name
->codepage
);
1162 if (!cptable
) return NULL
;
1163 len
= win32u_mbtowc( cptable
, buffer
, sizeof(buffer
), name
->bytes
, name
->length
);
1164 len
/= sizeof(WCHAR
);
1167 buffer
[ARRAY_SIZE(buffer
) - 1] = 0;
1168 if (len
== ARRAY_SIZE(buffer
)) WARN("Truncated font name %s -> %s\n", debugstr_an(name
->bytes
, name
->length
), debugstr_w(buffer
));
1169 else buffer
[len
] = 0;
1171 return strdupW( buffer
);
1186 struct bitmap_font_size size
;
1189 static struct unix_face
*unix_face_create( const char *unix_name
, void *data_ptr
, DWORD data_size
,
1190 UINT face_index
, DWORD flags
)
1192 static const WCHAR space_w
[] = {' ',0};
1194 const struct ttc_sfnt_v1
*ttc_sfnt_v1
;
1195 const struct tt_name_v0
*tt_name_v0
;
1196 struct unix_face
*This
;
1201 TRACE( "unix_name %s, face_index %u, data_ptr %p, data_size %u, flags %#x\n",
1202 unix_name
, face_index
, data_ptr
, data_size
, flags
);
1206 if ((fd
= open( unix_name
, O_RDONLY
)) == -1) return NULL
;
1207 if (fstat( fd
, &st
) == -1)
1212 data_size
= st
.st_size
;
1213 data_ptr
= mmap( NULL
, data_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0 );
1215 if (data_ptr
== MAP_FAILED
) return NULL
;
1218 if (!(This
= calloc( 1, sizeof(*This
) ))) goto done
;
1220 if (opentype_get_ttc_sfnt_v1( data_ptr
, data_size
, face_index
, &face_count
, &ttc_sfnt_v1
) &&
1221 opentype_get_tt_name_v0( data_ptr
, data_size
, ttc_sfnt_v1
, &tt_name_v0
) &&
1222 opentype_get_properties( data_ptr
, data_size
, ttc_sfnt_v1
, &This
->font_version
,
1223 &This
->fs
, &This
->ntm_flags
))
1225 struct family_names_data family_names
;
1226 struct face_name_data style_name
;
1227 struct face_name_data full_name
;
1228 LANGID primary_langid
= system_lcid
;
1230 This
->scalable
= TRUE
;
1231 This
->num_faces
= face_count
;
1233 memset( &family_names
, 0, sizeof(family_names
) );
1234 family_names
.primary_langid
= primary_langid
;
1235 opentype_enum_family_names( tt_name_v0
, search_family_names_callback
, &family_names
);
1236 This
->family_name
= decode_opentype_name( &family_names
.family_name
);
1237 This
->second_name
= decode_opentype_name( &family_names
.second_name
);
1239 memset( &style_name
, 0, sizeof(style_name
) );
1240 style_name
.primary_langid
= primary_langid
;
1241 opentype_enum_style_names( tt_name_v0
, search_face_name_callback
, &style_name
);
1242 This
->style_name
= decode_opentype_name( &style_name
.face_name
);
1244 memset( &full_name
, 0, sizeof(full_name
) );
1245 full_name
.primary_langid
= primary_langid
;
1246 opentype_enum_full_names( tt_name_v0
, search_face_name_callback
, &full_name
);
1247 This
->full_name
= decode_opentype_name( &full_name
.face_name
);
1249 TRACE( "parsed font names family_name %s, second_name %s, primary_seen %d, english_seen %d, "
1250 "full_name %s, style_name %s\n",
1251 debugstr_w(This
->family_name
), debugstr_w(This
->second_name
),
1252 family_names
.primary_seen
, family_names
.english_seen
,
1253 debugstr_w(This
->full_name
), debugstr_w(This
->style_name
) );
1255 if (!This
->full_name
&& This
->family_name
&& This
->style_name
)
1257 length
= lstrlenW( This
->family_name
) + lstrlenW( space_w
) + lstrlenW( This
->style_name
) + 1;
1258 This
->full_name
= malloc( length
* sizeof(WCHAR
) );
1259 lstrcpyW( This
->full_name
, This
->family_name
);
1260 lstrcatW( This
->full_name
, space_w
);
1261 lstrcatW( This
->full_name
, This
->style_name
);
1262 WARN( "full name not found, using %s instead\n", debugstr_w(This
->full_name
) );
1265 else if ((This
->ft_face
= new_ft_face( unix_name
, data_ptr
, data_size
, face_index
, flags
& ADDFONT_ALLOW_BITMAP
)))
1267 WARN( "unable to parse font, falling back to FreeType\n" );
1268 This
->scalable
= FT_IS_SCALABLE( This
->ft_face
);
1269 This
->num_faces
= This
->ft_face
->num_faces
;
1271 This
->family_name
= ft_face_get_family_name( This
->ft_face
, system_lcid
);
1272 This
->second_name
= ft_face_get_family_name( This
->ft_face
, MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
) );
1274 /* try to find another secondary name, preferring the lowest langids */
1275 if (!wcsicmp( This
->family_name
, This
->second_name
))
1277 free( This
->second_name
);
1278 This
->second_name
= ft_face_get_family_name( This
->ft_face
, MAKELANGID(LANG_NEUTRAL
, SUBLANG_NEUTRAL
) );
1279 if (!wcsicmp( This
->family_name
, This
->second_name
))
1281 free( This
->second_name
);
1282 This
->second_name
= NULL
;
1286 This
->style_name
= ft_face_get_style_name( This
->ft_face
, system_lcid
);
1287 This
->full_name
= ft_face_get_full_name( This
->ft_face
, system_lcid
);
1289 This
->ntm_flags
= get_ntm_flags( This
->ft_face
);
1290 This
->font_version
= get_font_version( This
->ft_face
);
1291 if (!This
->scalable
) get_bitmap_size( This
->ft_face
, &This
->size
);
1292 get_fontsig( This
->ft_face
, &This
->fs
);
1301 if (unix_name
) munmap( data_ptr
, data_size
);
1305 static void unix_face_destroy( struct unix_face
*This
)
1307 if (This
->ft_face
) pFT_Done_Face( This
->ft_face
);
1308 free( This
->full_name
);
1309 free( This
->style_name
);
1310 free( This
->second_name
);
1311 free( This
->family_name
);
1315 static int add_unix_face( const char *unix_name
, const WCHAR
*file
, void *data_ptr
, SIZE_T data_size
,
1316 DWORD face_index
, DWORD flags
, DWORD
*num_faces
)
1318 struct unix_face
*unix_face
;
1321 if (num_faces
) *num_faces
= 0;
1323 if (!(unix_face
= unix_face_create( unix_name
, data_ptr
, data_size
, face_index
, flags
)))
1326 if (unix_face
->family_name
[0] == '.') /* Ignore fonts with names beginning with a dot */
1328 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(unix_name
));
1329 unix_face_destroy( unix_face
);
1333 if (!HIWORD( flags
)) flags
|= ADDFONT_AA_FLAGS( default_aa_flags
);
1335 ret
= add_gdi_face( unix_face
->family_name
, unix_face
->second_name
, unix_face
->style_name
, unix_face
->full_name
,
1336 file
, data_ptr
, data_size
, face_index
, unix_face
->fs
, unix_face
->ntm_flags
,
1337 unix_face
->font_version
, flags
, unix_face
->scalable
? NULL
: &unix_face
->size
);
1339 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n", unix_face
->fs
.fsCsb
[0], unix_face
->fs
.fsCsb
[1],
1340 unix_face
->fs
.fsUsb
[0], unix_face
->fs
.fsUsb
[1], unix_face
->fs
.fsUsb
[2], unix_face
->fs
.fsUsb
[3]);
1342 if (num_faces
) *num_faces
= unix_face
->num_faces
;
1343 unix_face_destroy( unix_face
);
1347 static WCHAR
*get_dos_file_name( LPCSTR str
)
1350 ULONG len
= strlen(str
) + 1;
1352 len
+= 8; /* \??\unix prefix */
1353 if (!(buffer
= malloc( len
* sizeof(WCHAR
) ))) return NULL
;
1354 if (wine_unix_to_nt_file_name( str
, buffer
, &len
))
1362 static char *get_unix_file_name( LPCWSTR path
)
1364 UNICODE_STRING nt_name
;
1365 OBJECT_ATTRIBUTES attr
;
1370 nt_name
.Buffer
= (WCHAR
*)path
;
1371 nt_name
.MaximumLength
= nt_name
.Length
= lstrlenW( path
) * sizeof(WCHAR
);
1372 InitializeObjectAttributes( &attr
, &nt_name
, 0, 0, NULL
);
1375 if (!(buffer
= malloc( size
))) return NULL
;
1376 status
= wine_nt_to_unix_file_name( &attr
, buffer
, &size
, FILE_OPEN_IF
);
1377 if (status
!= STATUS_BUFFER_TOO_SMALL
) break;
1380 if (status
&& status
!= STATUS_NO_SUCH_FILE
)
1388 static INT
AddFontToList(const WCHAR
*dos_name
, const char *unix_name
, void *font_data_ptr
,
1389 DWORD font_data_size
, DWORD flags
)
1391 DWORD face_index
= 0, num_faces
;
1393 WCHAR
*filename
= NULL
;
1395 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1396 assert(unix_name
|| !(flags
& ADDFONT_EXTERNAL_FONT
));
1398 #ifdef HAVE_CARBON_CARBON_H
1401 char **mac_list
= expand_mac_font(unix_name
);
1404 BOOL had_one
= FALSE
;
1406 for(cursor
= mac_list
; *cursor
; cursor
++)
1409 AddFontToList(NULL
, *cursor
, NULL
, 0, flags
);
1417 #endif /* HAVE_CARBON_CARBON_H */
1419 if (!dos_name
&& unix_name
) dos_name
= filename
= get_dos_file_name( unix_name
);
1422 ret
+= add_unix_face( unix_name
, dos_name
, font_data_ptr
, font_data_size
, face_index
, flags
, &num_faces
);
1423 while (num_faces
> ++face_index
);
1429 /*************************************************************
1432 static INT
freetype_add_font( const WCHAR
*file
, DWORD flags
)
1435 char *unixname
= get_unix_file_name( file
);
1439 ret
= AddFontToList( file
, unixname
, NULL
, 0, flags
);
1445 /*************************************************************
1446 * freetype_add_mem_font
1448 static INT
freetype_add_mem_font( void *ptr
, SIZE_T size
, DWORD flags
)
1450 return AddFontToList( NULL
, NULL
, ptr
, size
, flags
);
1454 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
1457 struct dirent
*dent
;
1458 char path
[MAX_PATH
];
1460 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
1462 dir
= opendir(dirname
);
1464 WARN("Can't open directory %s\n", debugstr_a(dirname
));
1467 while((dent
= readdir(dir
)) != NULL
) {
1468 struct stat statbuf
;
1470 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
1473 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
1475 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
1477 if(stat(path
, &statbuf
) == -1)
1479 WARN("Can't stat %s\n", debugstr_a(path
));
1482 if(S_ISDIR(statbuf
.st_mode
))
1483 ReadFontDir(path
, external_fonts
);
1486 DWORD addfont_flags
= 0;
1487 if(external_fonts
) addfont_flags
|= ADDFONT_EXTERNAL_FONT
;
1488 AddFontToList(NULL
, path
, NULL
, 0, addfont_flags
);
1496 #ifdef SONAME_LIBFONTCONFIG
1498 static BOOL fontconfig_enabled
;
1499 static FcPattern
*pattern_serif
;
1500 static FcPattern
*pattern_fixed
;
1501 static FcPattern
*pattern_sans
;
1503 static UINT
parse_aa_pattern( FcPattern
*pattern
)
1509 if (pFcPatternGetBool( pattern
, FC_ANTIALIAS
, 0, &antialias
) == FcResultMatch
)
1510 aa_flags
= antialias
? GGO_GRAY4_BITMAP
: GGO_BITMAP
;
1512 if (pFcPatternGetInteger( pattern
, FC_RGBA
, 0, &rgba
) == FcResultMatch
)
1516 case FC_RGBA_RGB
: aa_flags
= WINE_GGO_HRGB_BITMAP
; break;
1517 case FC_RGBA_BGR
: aa_flags
= WINE_GGO_HBGR_BITMAP
; break;
1518 case FC_RGBA_VRGB
: aa_flags
= WINE_GGO_VRGB_BITMAP
; break;
1519 case FC_RGBA_VBGR
: aa_flags
= WINE_GGO_VBGR_BITMAP
; break;
1520 case FC_RGBA_NONE
: aa_flags
= aa_flags
? aa_flags
: GGO_GRAY4_BITMAP
; break;
1526 static FcPattern
*create_family_pattern( const char *name
, FcPattern
**cached
)
1528 FcPattern
*ret
= NULL
, *tmp
, *pattern
;
1530 if (*cached
) return *cached
;
1531 pattern
= pFcPatternCreate();
1532 pFcPatternAddString( pattern
, FC_FAMILY
, (const FcChar8
*)name
);
1533 pFcPatternAddString( pattern
, FC_NAMELANG
, (const FcChar8
*)"en-us" );
1534 pFcPatternAddString( pattern
, FC_PRGNAME
, (const FcChar8
*)"wine" );
1535 pFcConfigSubstitute( NULL
, pattern
, FcMatchPattern
);
1536 pFcDefaultSubstitute( pattern
);
1537 tmp
= pFcFontMatch( NULL
, pattern
, &result
);
1538 pFcPatternDestroy( pattern
);
1539 if (result
!= FcResultMatch
) pFcPatternDestroy( tmp
);
1540 else if ((ret
= InterlockedCompareExchangePointer( (void **)cached
, tmp
, NULL
))) pFcPatternDestroy( tmp
);
1545 static void fontconfig_add_font( FcPattern
*pattern
, DWORD flags
)
1547 const char *unix_name
, *format
;
1553 TRACE( "(%p %#x)\n", pattern
, flags
);
1555 if (pFcPatternGetString( pattern
, FC_FILE
, 0, (FcChar8
**)&unix_name
) != FcResultMatch
)
1558 if (pFcPatternGetBool( pattern
, FC_SCALABLE
, 0, &scalable
) != FcResultMatch
)
1561 if (pFcPatternGetString( pattern
, FC_FONTFORMAT
, 0, (FcChar8
**)&format
) != FcResultMatch
)
1563 TRACE( "ignoring unknown font format %s\n", debugstr_a(unix_name
) );
1567 if (!strcmp( format
, "Type 1" ))
1569 TRACE( "ignoring Type 1 font %s\n", debugstr_a(unix_name
) );
1573 if (!scalable
&& !(flags
& ADDFONT_ALLOW_BITMAP
))
1575 TRACE( "ignoring non-scalable font %s\n", debugstr_a(unix_name
) );
1579 if (!(aa_flags
= parse_aa_pattern( pattern
))) aa_flags
= default_aa_flags
;
1580 flags
|= ADDFONT_AA_FLAGS(aa_flags
);
1582 if (pFcPatternGetInteger( pattern
, FC_INDEX
, 0, &face_index
) != FcResultMatch
)
1585 dos_name
= get_dos_file_name( unix_name
);
1586 add_unix_face( unix_name
, dos_name
, NULL
, 0, face_index
, flags
, NULL
);
1590 static void init_fontconfig(void)
1592 void *fc_handle
= dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
);
1596 TRACE("Wine cannot find the fontconfig library (%s).\n", SONAME_LIBFONTCONFIG
);
1600 #define LOAD_FUNCPTR(f) if((p##f = dlsym(fc_handle, #f)) == NULL){WARN("Can't find symbol %s\n", #f); return;}
1601 LOAD_FUNCPTR(FcConfigSubstitute
);
1602 LOAD_FUNCPTR(FcDefaultSubstitute
);
1603 LOAD_FUNCPTR(FcFontList
);
1604 LOAD_FUNCPTR(FcFontMatch
);
1605 LOAD_FUNCPTR(FcFontSetDestroy
);
1606 LOAD_FUNCPTR(FcInit
);
1607 LOAD_FUNCPTR(FcPatternAddString
);
1608 LOAD_FUNCPTR(FcPatternCreate
);
1609 LOAD_FUNCPTR(FcPatternDestroy
);
1610 LOAD_FUNCPTR(FcPatternGetBool
);
1611 LOAD_FUNCPTR(FcPatternGetInteger
);
1612 LOAD_FUNCPTR(FcPatternGetString
);
1613 LOAD_FUNCPTR(FcConfigGetFontDirs
);
1614 LOAD_FUNCPTR(FcConfigGetCurrent
);
1615 LOAD_FUNCPTR(FcCacheCopySet
);
1616 LOAD_FUNCPTR(FcCacheNumSubdir
);
1617 LOAD_FUNCPTR(FcCacheSubdir
);
1618 LOAD_FUNCPTR(FcDirCacheRead
);
1619 LOAD_FUNCPTR(FcDirCacheUnload
);
1620 LOAD_FUNCPTR(FcStrListCreate
);
1621 LOAD_FUNCPTR(FcStrListDone
);
1622 LOAD_FUNCPTR(FcStrListNext
);
1623 LOAD_FUNCPTR(FcStrSetAdd
);
1624 LOAD_FUNCPTR(FcStrSetCreate
);
1625 LOAD_FUNCPTR(FcStrSetDestroy
);
1626 LOAD_FUNCPTR(FcStrSetMember
);
1631 FcPattern
*pattern
= pFcPatternCreate();
1632 pFcConfigSubstitute( NULL
, pattern
, FcMatchFont
);
1633 default_aa_flags
= parse_aa_pattern( pattern
);
1634 pFcPatternDestroy( pattern
);
1636 if (!default_aa_flags
)
1638 FcPattern
*pattern
= pFcPatternCreate();
1639 pFcConfigSubstitute( NULL
, pattern
, FcMatchPattern
);
1640 default_aa_flags
= parse_aa_pattern( pattern
);
1641 pFcPatternDestroy( pattern
);
1644 TRACE( "enabled, default flags = %x\n", default_aa_flags
);
1645 fontconfig_enabled
= TRUE
;
1649 static void fontconfig_add_fonts_from_dir_list( FcConfig
*config
, FcStrList
*dir_list
, FcStrSet
*done_set
, DWORD flags
)
1652 FcFontSet
*font_set
= NULL
;
1653 FcStrList
*subdir_list
= NULL
;
1654 FcStrSet
*subdir_set
= NULL
;
1655 FcCache
*cache
= NULL
;
1658 TRACE( "(%p %p %p %#x)\n", config
, dir_list
, done_set
, flags
);
1660 while ((dir
= pFcStrListNext( dir_list
)))
1662 if (pFcStrSetMember( done_set
, dir
)) continue;
1664 TRACE( "adding fonts from %s\n", dir
);
1665 if (!(cache
= pFcDirCacheRead( dir
, FcFalse
, config
))) continue;
1667 if (!(font_set
= pFcCacheCopySet( cache
))) goto done
;
1668 for (i
= 0; i
< font_set
->nfont
; i
++)
1669 fontconfig_add_font( font_set
->fonts
[i
], flags
);
1670 pFcFontSetDestroy( font_set
);
1673 if (!(subdir_set
= pFcStrSetCreate())) goto done
;
1674 for (i
= 0; i
< pFcCacheNumSubdir( cache
); i
++)
1675 pFcStrSetAdd( subdir_set
, pFcCacheSubdir( cache
, i
) );
1676 pFcDirCacheUnload( cache
);
1679 if (!(subdir_list
= pFcStrListCreate( subdir_set
))) goto done
;
1680 pFcStrSetDestroy( subdir_set
);
1683 pFcStrSetAdd( done_set
, dir
);
1684 fontconfig_add_fonts_from_dir_list( config
, subdir_list
, done_set
, flags
);
1685 pFcStrListDone( subdir_list
);
1690 if (subdir_set
) pFcStrSetDestroy( subdir_set
);
1691 if (cache
) pFcDirCacheUnload( cache
);
1694 static void load_fontconfig_fonts( void )
1696 FcStrList
*dir_list
= NULL
;
1697 FcStrSet
*done_set
= NULL
;
1700 if (!fontconfig_enabled
) return;
1701 if (!(config
= pFcConfigGetCurrent())) goto done
;
1702 if (!(done_set
= pFcStrSetCreate())) goto done
;
1703 if (!(dir_list
= pFcConfigGetFontDirs( config
))) goto done
;
1705 fontconfig_add_fonts_from_dir_list( config
, dir_list
, done_set
, ADDFONT_EXTERNAL_FONT
);
1708 if (dir_list
) pFcStrListDone( dir_list
);
1709 if (done_set
) pFcStrSetDestroy( done_set
);
1712 #elif defined(HAVE_CARBON_CARBON_H)
1714 static void load_mac_font_callback(const void *value
, void *context
)
1716 CFStringRef pathStr
= value
;
1720 len
= CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr
);
1721 path
= malloc( len
);
1722 if (path
&& CFStringGetFileSystemRepresentation(pathStr
, path
, len
))
1724 TRACE("font file %s\n", path
);
1725 AddFontToList(NULL
, path
, NULL
, 0, ADDFONT_EXTERNAL_FONT
);
1730 static void load_mac_fonts(void)
1732 CFStringRef removeDupesKey
;
1733 CFBooleanRef removeDupesValue
;
1734 CFDictionaryRef options
;
1735 CTFontCollectionRef col
;
1737 CFMutableSetRef paths
;
1740 removeDupesKey
= kCTFontCollectionRemoveDuplicatesOption
;
1741 removeDupesValue
= kCFBooleanTrue
;
1742 options
= CFDictionaryCreate(NULL
, (const void**)&removeDupesKey
, (const void**)&removeDupesValue
, 1,
1743 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1744 col
= CTFontCollectionCreateFromAvailableFonts(options
);
1745 if (options
) CFRelease(options
);
1748 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
1752 descs
= CTFontCollectionCreateMatchingFontDescriptors(col
);
1756 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
1760 paths
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
1763 WARN("CFSetCreateMutable failed\n");
1768 for (i
= 0; i
< CFArrayGetCount(descs
); i
++)
1770 CTFontDescriptorRef desc
;
1775 desc
= CFArrayGetValueAtIndex(descs
, i
);
1776 url
= CTFontDescriptorCopyAttribute(desc
, kCTFontURLAttribute
);
1779 ext
= CFURLCopyPathExtension(url
);
1782 BOOL skip
= (CFStringCompare(ext
, CFSTR("pfa"), kCFCompareCaseInsensitive
) == kCFCompareEqualTo
||
1783 CFStringCompare(ext
, CFSTR("pfb"), kCFCompareCaseInsensitive
) == kCFCompareEqualTo
);
1792 path
= CFURLCopyFileSystemPath(url
, kCFURLPOSIXPathStyle
);
1794 if (!path
) continue;
1796 CFSetAddValue(paths
, path
);
1802 CFSetApplyFunction(paths
, load_mac_font_callback
, NULL
);
1809 static BOOL
init_freetype(void)
1811 ft_handle
= dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
);
1814 "Wine cannot find the FreeType font library. To enable Wine to\n"
1815 "use TrueType fonts please install a version of FreeType greater than\n"
1816 "or equal to 2.0.5.\n"
1817 "http://www.freetype.org\n");
1821 #define LOAD_FUNCPTR(f) if((p##f = dlsym(ft_handle, #f)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
1823 LOAD_FUNCPTR(FT_Done_Face
)
1824 LOAD_FUNCPTR(FT_Get_Char_Index
)
1825 LOAD_FUNCPTR(FT_Get_First_Char
)
1826 LOAD_FUNCPTR(FT_Get_Next_Char
)
1827 LOAD_FUNCPTR(FT_Get_Sfnt_Name
)
1828 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count
)
1829 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
1830 LOAD_FUNCPTR(FT_Get_WinFNT_Header
)
1831 LOAD_FUNCPTR(FT_Init_FreeType
)
1832 LOAD_FUNCPTR(FT_Library_Version
)
1833 LOAD_FUNCPTR(FT_Load_Glyph
)
1834 LOAD_FUNCPTR(FT_Load_Sfnt_Table
)
1835 LOAD_FUNCPTR(FT_Matrix_Multiply
)
1836 LOAD_FUNCPTR(FT_MulDiv
)
1837 #ifndef FT_MULFIX_INLINED
1838 LOAD_FUNCPTR(FT_MulFix
)
1840 LOAD_FUNCPTR(FT_New_Face
)
1841 LOAD_FUNCPTR(FT_New_Memory_Face
)
1842 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
1843 LOAD_FUNCPTR(FT_Outline_Get_CBox
)
1844 LOAD_FUNCPTR(FT_Outline_Transform
)
1845 LOAD_FUNCPTR(FT_Outline_Translate
)
1846 LOAD_FUNCPTR(FT_Render_Glyph
)
1847 LOAD_FUNCPTR(FT_Set_Charmap
)
1848 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
1849 LOAD_FUNCPTR(FT_Vector_Length
)
1850 LOAD_FUNCPTR(FT_Vector_Transform
)
1851 LOAD_FUNCPTR(FT_Vector_Unit
)
1853 /* Don't warn if these ones are missing */
1854 pFT_Outline_Embolden
= dlsym(ft_handle
, "FT_Outline_Embolden");
1855 pFT_Get_TrueType_Engine_Type
= dlsym(ft_handle
, "FT_Get_TrueType_Engine_Type");
1856 #ifdef FT_LCD_FILTER_H
1857 pFT_Library_SetLcdFilter
= dlsym(ft_handle
, "FT_Library_SetLcdFilter");
1859 pFT_Property_Set
= dlsym(ft_handle
, "FT_Property_Set");
1861 if(pFT_Init_FreeType(&library
) != 0) {
1862 ERR("Can't init FreeType library\n");
1867 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
1869 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
1870 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
1871 ((FT_Version
.minor
<< 8) & 0x00ff00) |
1872 ((FT_Version
.patch
) & 0x0000ff);
1874 /* In FreeType < 2.8.1 v40's FT_LOAD_TARGET_MONO has broken advance widths. */
1875 if (pFT_Property_Set
&& FT_SimpleVersion
< FT_VERSION_VALUE(2, 8, 1))
1877 FT_UInt interpreter_version
= 35;
1878 pFT_Property_Set( library
, "truetype", "interpreter-version", &interpreter_version
);
1881 #ifdef FT_LCD_FILTER_H
1882 if (pFT_Library_SetLcdFilter
)
1883 pFT_Library_SetLcdFilter( library
, FT_LCD_FILTER_DEFAULT
);
1890 "Wine cannot find certain functions that it needs inside the FreeType\n"
1891 "font library. To enable Wine to use TrueType fonts please upgrade\n"
1892 "FreeType to at least version 2.1.4.\n"
1893 "http://www.freetype.org\n");
1899 /*************************************************************
1900 * freetype_load_fonts
1902 static void freetype_load_fonts(void)
1904 #ifdef SONAME_LIBFONTCONFIG
1905 load_fontconfig_fonts();
1906 #elif defined(HAVE_CARBON_CARBON_H)
1908 #elif defined(__ANDROID__)
1909 ReadFontDir("/system/fonts", TRUE
);
1913 /* Some fonts have large usWinDescent values, as a result of storing signed short
1914 in unsigned field. That's probably caused by sTypoDescent vs usWinDescent confusion in
1915 some font generation tools. */
1916 static inline USHORT
get_fixed_windescent(USHORT windescent
)
1918 return abs((SHORT
)windescent
);
1921 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
1924 TT_HoriHeader
*pHori
;
1927 const LONG MAX_PPEM
= (1 << 16) - 1;
1929 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
1930 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
1932 if(height
== 0) height
= 16;
1934 /* Calc. height of EM square:
1936 * For +ve lfHeight we have
1937 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
1938 * Re-arranging gives:
1939 * ppem = units_per_em * lfheight / (winAscent + winDescent)
1941 * For -ve lfHeight we have
1943 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
1944 * with il = winAscent + winDescent - units_per_em]
1949 USHORT windescent
= get_fixed_windescent(pOS2
->usWinDescent
);
1950 if(pOS2
->usWinAscent
+ windescent
== 0)
1951 ppem
= pFT_MulDiv(ft_face
->units_per_EM
, height
, pHori
->Ascender
- pHori
->Descender
);
1953 ppem
= pFT_MulDiv(ft_face
->units_per_EM
, height
, pOS2
->usWinAscent
+ windescent
);
1954 if(ppem
> MAX_PPEM
) {
1955 WARN("Ignoring too large height %d, ppem %d\n", height
, ppem
);
1959 else if(height
>= -MAX_PPEM
)
1962 WARN("Ignoring too large height %d\n", height
);
1969 static struct font_mapping
*map_font_file( const char *name
)
1971 struct font_mapping
*mapping
;
1975 if ((fd
= open( name
, O_RDONLY
)) == -1) return NULL
;
1976 if (fstat( fd
, &st
) == -1) goto error
;
1978 LIST_FOR_EACH_ENTRY( mapping
, &mappings_list
, struct font_mapping
, entry
)
1980 if (mapping
->dev
== st
.st_dev
&& mapping
->ino
== st
.st_ino
)
1982 mapping
->refcount
++;
1987 if (!(mapping
= malloc( sizeof(*mapping
) )))
1990 mapping
->data
= mmap( NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0 );
1993 if (mapping
->data
== MAP_FAILED
)
1998 mapping
->refcount
= 1;
1999 mapping
->dev
= st
.st_dev
;
2000 mapping
->ino
= st
.st_ino
;
2001 mapping
->size
= st
.st_size
;
2002 list_add_tail( &mappings_list
, &mapping
->entry
);
2010 static void unmap_font_file( struct font_mapping
*mapping
)
2012 if (!--mapping
->refcount
)
2014 list_remove( &mapping
->entry
);
2015 munmap( mapping
->data
, mapping
->size
);
2020 static LONG
load_VDMX(struct gdi_font
*font
, LONG height
);
2022 /*************************************************************
2023 * freetype_destroy_font
2025 static void freetype_destroy_font( struct gdi_font
*font
)
2027 struct font_private_data
*data
= font
->private;
2029 if (data
->ft_face
) pFT_Done_Face( data
->ft_face
);
2030 if (data
->mapping
) unmap_font_file( data
->mapping
);
2034 /*************************************************************
2035 * freetype_get_font_data
2037 static DWORD
freetype_get_font_data( struct gdi_font
*font
, DWORD table
, DWORD offset
,
2038 void *buf
, DWORD cbData
)
2040 FT_Face ft_face
= get_ft_face( font
);
2044 if (!FT_IS_SFNT(ft_face
)) return GDI_ERROR
;
2051 /* if font is a member of TTC, 'ttcf' tag allows reading from beginning of TTC file,
2052 0 tag means to read from start of collection member data. */
2053 if (font
->ttc_item_offset
)
2055 if (table
== MS_TTCF_TAG
)
2057 else if (table
== 0)
2058 offset
+= font
->ttc_item_offset
;
2061 /* make sure value of len is the value freetype says it needs */
2064 FT_ULong needed
= 0;
2065 err
= pFT_Load_Sfnt_Table(ft_face
, RtlUlongByteSwap(table
), offset
, NULL
, &needed
);
2066 if( !err
&& needed
< len
) len
= needed
;
2068 err
= pFT_Load_Sfnt_Table(ft_face
, RtlUlongByteSwap(table
), offset
, buf
, &len
);
2071 TRACE("Can't find table %s\n", debugstr_an((char*)&table
, 4));
2077 /*************************************************************
2080 * load the vdmx entry for the specified height
2110 static LONG
load_VDMX(struct gdi_font
*font
, LONG height
)
2114 BYTE devXRatio
, devYRatio
;
2115 USHORT numRecs
, numRatios
;
2116 DWORD result
, offset
= -1;
2120 result
= freetype_get_font_data(font
, MS_VDMX_TAG
, 0, &hdr
, sizeof(hdr
));
2122 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
2125 /* FIXME: need the real device aspect ratio */
2129 numRecs
= GET_BE_WORD(hdr
.numRecs
);
2130 numRatios
= GET_BE_WORD(hdr
.numRatios
);
2132 TRACE("version = %d numRecs = %d numRatios = %d\n", GET_BE_WORD(hdr
.version
), numRecs
, numRatios
);
2133 for(i
= 0; i
< numRatios
; i
++) {
2136 offset
= sizeof(hdr
) + (i
* sizeof(Ratios
));
2137 freetype_get_font_data(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
2140 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
2142 if (!ratio
.bCharSet
) continue;
2144 if((ratio
.xRatio
== 0 &&
2145 ratio
.yStartRatio
== 0 &&
2146 ratio
.yEndRatio
== 0) ||
2147 (devXRatio
== ratio
.xRatio
&&
2148 devYRatio
>= ratio
.yStartRatio
&&
2149 devYRatio
<= ratio
.yEndRatio
))
2153 offset
= sizeof(hdr
) + numRatios
* sizeof(ratio
) + i
* sizeof(group_offset
);
2154 freetype_get_font_data(font
, MS_VDMX_TAG
, offset
, &group_offset
, sizeof(group_offset
));
2155 offset
= GET_BE_WORD(group_offset
);
2160 if(offset
== -1) return 0;
2162 if(freetype_get_font_data(font
, MS_VDMX_TAG
, offset
, &group
, sizeof(group
)) != GDI_ERROR
) {
2164 BYTE startsz
, endsz
;
2167 recs
= GET_BE_WORD(group
.recs
);
2168 startsz
= group
.startsz
;
2169 endsz
= group
.endsz
;
2171 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
2173 vTable
= malloc( recs
* sizeof(VDMX_vTable
) );
2174 result
= freetype_get_font_data(font
, MS_VDMX_TAG
, offset
+ sizeof(group
), vTable
, recs
* sizeof(VDMX_vTable
));
2175 if(result
== GDI_ERROR
) {
2176 FIXME("Failed to retrieve vTable\n");
2181 for(i
= 0; i
< recs
; i
++) {
2182 SHORT yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
2183 SHORT yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
2184 ppem
= GET_BE_WORD(vTable
[i
* 3]);
2186 if(yMax
+ -yMin
== height
) {
2189 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
2192 if(yMax
+ -yMin
> height
) {
2195 goto end
; /* failed */
2197 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
2198 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
2199 ppem
= GET_BE_WORD(vTable
[i
* 3]);
2200 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
2206 TRACE("ppem not found for height %d\n", height
);
2210 if(ppem
< startsz
|| ppem
> endsz
)
2216 for(i
= 0; i
< recs
; i
++) {
2218 yPelHeight
= GET_BE_WORD(vTable
[i
* 3]);
2220 if(yPelHeight
> ppem
)
2226 if(yPelHeight
== ppem
) {
2227 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
2228 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
2229 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem
, font
->yMax
, font
->yMin
);
2241 static BOOL
select_charmap(FT_Face ft_face
, FT_Encoding encoding
)
2243 FT_Error ft_err
= FT_Err_Invalid_CharMap_Handle
;
2244 FT_CharMap cmap0
, cmap1
, cmap2
, cmap3
, cmap_def
;
2247 cmap0
= cmap1
= cmap2
= cmap3
= cmap_def
= NULL
;
2249 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
2251 if (ft_face
->charmaps
[i
]->encoding
== encoding
)
2253 TRACE("found cmap with platform_id %u, encoding_id %u\n",
2254 ft_face
->charmaps
[i
]->platform_id
, ft_face
->charmaps
[i
]->encoding_id
);
2256 switch (ft_face
->charmaps
[i
]->platform_id
)
2259 cmap_def
= ft_face
->charmaps
[i
];
2261 case 0: /* Apple Unicode */
2262 cmap0
= ft_face
->charmaps
[i
];
2264 case 1: /* Macintosh */
2265 cmap1
= ft_face
->charmaps
[i
];
2268 cmap2
= ft_face
->charmaps
[i
];
2270 case 3: /* Microsoft */
2271 cmap3
= ft_face
->charmaps
[i
];
2276 if (cmap3
) /* prefer Microsoft cmap table */
2277 ft_err
= pFT_Set_Charmap(ft_face
, cmap3
);
2279 ft_err
= pFT_Set_Charmap(ft_face
, cmap1
);
2281 ft_err
= pFT_Set_Charmap(ft_face
, cmap2
);
2283 ft_err
= pFT_Set_Charmap(ft_face
, cmap0
);
2285 ft_err
= pFT_Set_Charmap(ft_face
, cmap_def
);
2288 return ft_err
== FT_Err_Ok
;
2292 static FT_Encoding
pick_charmap( FT_Face face
, int charset
)
2294 static const FT_Encoding regular_order
[] = { FT_ENCODING_UNICODE
, FT_ENCODING_APPLE_ROMAN
, FT_ENCODING_MS_SYMBOL
, 0 };
2295 static const FT_Encoding symbol_order
[] = { FT_ENCODING_MS_SYMBOL
, FT_ENCODING_UNICODE
, FT_ENCODING_APPLE_ROMAN
, 0 };
2296 const FT_Encoding
*encs
= regular_order
;
2298 if (charset
== SYMBOL_CHARSET
) encs
= symbol_order
;
2302 if (select_charmap( face
, *encs
)) break;
2306 if (!face
->charmap
&& face
->num_charmaps
)
2308 if (!pFT_Set_Charmap(face
, face
->charmaps
[0]))
2309 return face
->charmap
->encoding
;
2315 static BOOL
get_gasp_flags( struct gdi_font
*font
, WORD
*flags
)
2317 FT_Face ft_face
= get_ft_face( font
);
2319 WORD buf
[16]; /* Enough for seven ranges before we need to alloc */
2320 WORD
*alloced
= NULL
, *ptr
= buf
;
2321 WORD num_recs
, version
;
2325 size
= freetype_get_font_data( font
, MS_GASP_TAG
, 0, NULL
, 0 );
2326 if (size
== GDI_ERROR
) return FALSE
;
2327 if (size
< 4 * sizeof(WORD
)) return FALSE
;
2328 if (size
> sizeof(buf
))
2330 ptr
= alloced
= malloc( size
);
2331 if (!ptr
) return FALSE
;
2334 freetype_get_font_data( font
, MS_GASP_TAG
, 0, ptr
, size
);
2336 version
= GET_BE_WORD( *ptr
++ );
2337 num_recs
= GET_BE_WORD( *ptr
++ );
2339 if (version
> 1 || size
< (num_recs
* 2 + 2) * sizeof(WORD
))
2341 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version
, size
, num_recs
);
2347 *flags
= GET_BE_WORD( *(ptr
+ 1) );
2348 if (ft_face
->size
->metrics
.y_ppem
<= GET_BE_WORD( *ptr
)) break;
2351 TRACE( "got flags %04x for ppem %d\n", *flags
, ft_face
->size
->metrics
.y_ppem
);
2359 /*************************************************************
2360 * fontconfig_enum_family_fallbacks
2362 static BOOL
fontconfig_enum_family_fallbacks( DWORD pitch_and_family
, int index
,
2363 WCHAR buffer
[LF_FACESIZE
] )
2365 #ifdef SONAME_LIBFONTCONFIG
2370 if ((pitch_and_family
& FIXED_PITCH
) || (pitch_and_family
& 0xf0) == FF_MODERN
) pat
= create_family_pattern( "monospace", &pattern_fixed
);
2371 else if ((pitch_and_family
& 0xf0) == FF_ROMAN
) pat
= create_family_pattern( "serif", &pattern_serif
);
2372 else pat
= create_family_pattern( "sans", &pattern_sans
);
2374 if (!pat
) return FALSE
;
2375 if (pFcPatternGetString( pat
, FC_FAMILY
, index
, (FcChar8
**)&str
) != FcResultMatch
) return FALSE
;
2376 RtlUTF8ToUnicodeN( buffer
, (LF_FACESIZE
- 1) * sizeof(WCHAR
), &len
, str
, strlen(str
) );
2377 buffer
[len
/ sizeof(WCHAR
)] = 0;
2383 static DWORD
get_ttc_offset( FT_Face ft_face
, UINT face_index
)
2386 DWORD header
, offset
;
2388 /* see if it's a TTC */
2389 len
= sizeof(header
);
2390 if (pFT_Load_Sfnt_Table( ft_face
, 0, 0, (void *)&header
, &len
)) return 0;
2391 if (header
!= MS_TTCF_TAG
) return 0;
2393 len
= sizeof(offset
);
2394 if (pFT_Load_Sfnt_Table( ft_face
, 0, (3 + face_index
) * sizeof(DWORD
), (void *)&offset
, &len
))
2397 return GET_BE_DWORD( offset
);
2400 /*************************************************************
2401 * freetype_load_font
2403 static BOOL
freetype_load_font( struct gdi_font
*font
)
2405 struct font_private_data
*data
;
2406 INT width
= 0, height
;
2411 if (!(data
= calloc( 1, sizeof(*data
) ))) return FALSE
;
2412 font
->private = data
;
2416 char *filename
= get_unix_file_name( font
->file
);
2417 data
->mapping
= map_font_file( filename
);
2421 WARN("failed to map %s\n", debugstr_w(font
->file
));
2424 data_ptr
= data
->mapping
->data
;
2425 data_size
= data
->mapping
->size
;
2429 data_ptr
= font
->data_ptr
;
2430 data_size
= font
->data_size
;
2433 if (pFT_New_Memory_Face( library
, data_ptr
, data_size
, font
->face_index
, &ft_face
)) return FALSE
;
2435 data
->ft_face
= ft_face
;
2436 font
->scalable
= FT_IS_SCALABLE( ft_face
);
2437 if (!font
->fs
.fsCsb
[0]) get_fontsig( ft_face
, &font
->fs
);
2438 if (!font
->ntmFlags
) font
->ntmFlags
= get_ntm_flags( ft_face
);
2439 if (!font
->aa_flags
) font
->aa_flags
= ADDFONT_AA_FLAGS( default_aa_flags
);
2440 if (!font
->otm
.otmpFamilyName
)
2442 font
->otm
.otmpFamilyName
= (char *)ft_face_get_family_name( ft_face
, system_lcid
);
2443 font
->otm
.otmpStyleName
= (char *)ft_face_get_style_name( ft_face
, system_lcid
);
2444 font
->otm
.otmpFaceName
= (char *)ft_face_get_full_name( ft_face
, system_lcid
);
2449 /* load the VDMX table if we have one */
2450 font
->ppem
= load_VDMX( font
, font
->lf
.lfHeight
);
2451 if (font
->ppem
== 0) font
->ppem
= calc_ppem_for_height( ft_face
, font
->lf
.lfHeight
);
2452 TRACE( "height %d => ppem %d\n", font
->lf
.lfHeight
, font
->ppem
);
2453 height
= font
->ppem
;
2454 font
->ttc_item_offset
= get_ttc_offset( ft_face
, font
->face_index
);
2455 font
->otm
.otmEMSquare
= ft_face
->units_per_EM
;
2459 struct bitmap_font_size size
;
2461 get_bitmap_size( ft_face
, &size
);
2462 width
= size
.x_ppem
>> 6;
2463 height
= size
.y_ppem
>> 6;
2464 font
->ppem
= height
;
2467 pFT_Set_Pixel_Sizes( ft_face
, width
, height
);
2468 pick_charmap( ft_face
, font
->charset
);
2473 /*************************************************************
2474 * freetype_get_aa_flags
2476 static UINT
freetype_get_aa_flags( struct gdi_font
*font
, UINT aa_flags
, BOOL antialias_fakes
)
2478 /* fixup the antialiasing flags for that font */
2481 case WINE_GGO_HRGB_BITMAP
:
2482 case WINE_GGO_HBGR_BITMAP
:
2483 case WINE_GGO_VRGB_BITMAP
:
2484 case WINE_GGO_VBGR_BITMAP
:
2485 if (is_subpixel_rendering_enabled()) break;
2486 aa_flags
= GGO_GRAY4_BITMAP
;
2488 case GGO_GRAY2_BITMAP
:
2489 case GGO_GRAY4_BITMAP
:
2490 case GGO_GRAY8_BITMAP
:
2491 case WINE_GGO_GRAY16_BITMAP
:
2492 if ((!antialias_fakes
|| (!font
->fake_bold
&& !font
->fake_italic
)) && is_hinting_enabled())
2495 if (get_gasp_flags( font
, &gasp_flags
) && !(gasp_flags
& GASP_DOGRAY
))
2497 TRACE( "font %s %d aa disabled by GASP\n",
2498 debugstr_w(font
->lf
.lfFaceName
), font
->lf
.lfHeight
);
2499 aa_flags
= GGO_BITMAP
;
2506 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
2508 pt
->x
.value
= vec
->x
>> 6;
2509 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
2510 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
2511 pt
->y
.value
= vec
->y
>> 6;
2512 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
2513 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
2516 static FT_UInt
get_glyph_index_symbol( struct gdi_font
*font
, UINT glyph
)
2518 FT_Face ft_face
= get_ft_face( font
);
2521 if (glyph
< 0x100) glyph
+= 0xf000;
2522 /* there are a number of old pre-Unicode "broken" TTFs, which
2523 do have symbols at U+00XX instead of U+f0XX */
2524 if (!(ret
= pFT_Get_Char_Index(ft_face
, glyph
)))
2525 ret
= pFT_Get_Char_Index(ft_face
, glyph
- 0xf000);
2530 /*************************************************************
2531 * freetype_get_glyph_index
2533 static BOOL
freetype_get_glyph_index( struct gdi_font
*font
, UINT
*glyph
, BOOL use_encoding
)
2535 FT_Face ft_face
= get_ft_face( font
);
2537 if (!use_encoding
^ (ft_face
->charmap
->encoding
== FT_ENCODING_NONE
)) return FALSE
;
2539 if (ft_face
->charmap
->encoding
== FT_ENCODING_MS_SYMBOL
)
2541 if (!(*glyph
= get_glyph_index_symbol( font
, *glyph
)))
2547 len
= win32u_wctomb( NULL
, &ch
, 1, &wc
, sizeof(wc
) );
2548 if (len
) *glyph
= get_glyph_index_symbol( font
, (unsigned char)ch
);
2552 *glyph
= pFT_Get_Char_Index( ft_face
, *glyph
);
2556 /*************************************************************
2557 * freetype_get_default_glyph
2559 static UINT
freetype_get_default_glyph( struct gdi_font
*font
)
2561 FT_Face ft_face
= get_ft_face( font
);
2562 FT_WinFNT_HeaderRec winfnt
;
2565 if ((pOS2
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_os2
)))
2567 UINT glyph
= pOS2
->usDefaultChar
;
2568 if (glyph
) freetype_get_glyph_index( font
, &glyph
, TRUE
);
2571 if (!pFT_Get_WinFNT_Header( ft_face
, &winfnt
)) return winfnt
.default_char
+ winfnt
.first_char
;
2576 static inline BOOL
is_identity_FMAT2(const FMAT2
*matrix
)
2578 static const FMAT2 identity
= { 1.0, 0.0, 0.0, 1.0 };
2579 return !memcmp(matrix
, &identity
, sizeof(FMAT2
));
2582 static inline FT_Vector
normalize_vector(FT_Vector
*vec
)
2586 len
= pFT_Vector_Length(vec
);
2588 out
.x
= (vec
->x
<< 6) / len
;
2589 out
.y
= (vec
->y
<< 6) / len
;
2596 /* get_glyph_outline() glyph transform matrices index */
2604 static FT_Matrix
*get_transform_matrices( struct gdi_font
*font
, BOOL vertical
, const MAT2
*user_transform
,
2605 FT_Matrix matrices
[3] )
2607 static const FT_Matrix identity_mat
= { (1 << 16), 0, 0, (1 << 16) };
2608 BOOL needs_transform
= FALSE
;
2612 matrices
[matrix_unrotated
] = identity_mat
;
2614 /* Scaling factor */
2617 if (!freetype_set_outline_text_metrics( font
)) freetype_set_bitmap_text_metrics( font
);
2618 width_ratio
= (double)font
->aveWidth
;
2619 width_ratio
/= (double)font
->otm
.otmTextMetrics
.tmAveCharWidth
;
2622 width_ratio
= font
->scale_y
;
2624 /* Scaling transform */
2625 if (width_ratio
!= 1.0 || font
->scale_y
!= 1)
2627 FT_Matrix scale_mat
;
2628 scale_mat
.xx
= FT_FixedFromFloat( width_ratio
);
2631 scale_mat
.yy
= font
->scale_y
<< 16;
2633 pFT_Matrix_Multiply( &scale_mat
, &matrices
[matrix_unrotated
] );
2634 needs_transform
= TRUE
;
2637 /* Slant transform */
2638 if (font
->fake_italic
)
2640 FT_Matrix slant_mat
;
2641 slant_mat
.xx
= (1 << 16);
2642 slant_mat
.xy
= (1 << 16) >> 2;
2644 slant_mat
.yy
= (1 << 16);
2646 pFT_Matrix_Multiply( &slant_mat
, &matrices
[matrix_unrotated
] );
2647 needs_transform
= TRUE
;
2650 /* Rotation transform */
2651 matrices
[matrix_hori
] = matrices
[matrix_unrotated
];
2652 if (font
->scalable
&& font
->lf
.lfOrientation
% 3600)
2654 FT_Matrix rotation_mat
;
2657 pFT_Vector_Unit( &angle
, pFT_MulDiv( 1 << 16, font
->lf
.lfOrientation
, 10 ) );
2658 rotation_mat
.xx
= angle
.x
;
2659 rotation_mat
.xy
= -angle
.y
;
2660 rotation_mat
.yx
= angle
.y
;
2661 rotation_mat
.yy
= angle
.x
;
2662 pFT_Matrix_Multiply( &rotation_mat
, &matrices
[matrix_hori
] );
2663 needs_transform
= TRUE
;
2666 /* Vertical transform */
2667 matrices
[matrix_vert
] = matrices
[matrix_hori
];
2670 FT_Matrix vertical_mat
= { 0, -(1 << 16), 1 << 16, 0 }; /* 90 degrees rotation */
2672 pFT_Matrix_Multiply( &vertical_mat
, &matrices
[matrix_vert
] );
2673 needs_transform
= TRUE
;
2676 /* World transform */
2677 if (!is_identity_FMAT2( &font
->matrix
))
2679 FT_Matrix world_mat
;
2680 world_mat
.xx
= FT_FixedFromFloat( font
->matrix
.eM11
);
2681 world_mat
.xy
= -FT_FixedFromFloat( font
->matrix
.eM21
);
2682 world_mat
.yx
= -FT_FixedFromFloat( font
->matrix
.eM12
);
2683 world_mat
.yy
= FT_FixedFromFloat( font
->matrix
.eM22
);
2685 for (i
= 0; i
< 3; i
++)
2686 pFT_Matrix_Multiply( &world_mat
, &matrices
[i
] );
2687 needs_transform
= TRUE
;
2690 /* Extra transformation specified by caller */
2694 user_mat
.xx
= FT_FixedFromFIXED( user_transform
->eM11
);
2695 user_mat
.xy
= FT_FixedFromFIXED( user_transform
->eM21
);
2696 user_mat
.yx
= FT_FixedFromFIXED( user_transform
->eM12
);
2697 user_mat
.yy
= FT_FixedFromFIXED( user_transform
->eM22
);
2699 for (i
= 0; i
< 3; i
++)
2700 pFT_Matrix_Multiply( &user_mat
, &matrices
[i
] );
2701 needs_transform
= TRUE
;
2704 return needs_transform
? matrices
: NULL
;
2707 static BOOL
get_bold_glyph_outline(FT_GlyphSlot glyph
, LONG ppem
, FT_Glyph_Metrics
*metrics
)
2713 if(glyph
->format
!= FT_GLYPH_FORMAT_OUTLINE
)
2715 if(!pFT_Outline_Embolden
)
2718 strength
= pFT_MulDiv(ppem
, 1 << 6, 24);
2719 err
= pFT_Outline_Embolden(&glyph
->outline
, strength
);
2721 TRACE("FT_Ouline_Embolden returns %d\n", err
);
2725 pFT_Outline_Get_CBox(&glyph
->outline
, &bbox
);
2726 metrics
->width
= bbox
.xMax
- bbox
.xMin
;
2727 metrics
->height
= bbox
.yMax
- bbox
.yMin
;
2728 metrics
->horiBearingX
= bbox
.xMin
;
2729 metrics
->horiBearingY
= bbox
.yMax
;
2730 metrics
->vertBearingX
= metrics
->horiBearingX
- metrics
->horiAdvance
/ 2;
2731 metrics
->vertBearingY
= (metrics
->vertAdvance
- metrics
->height
) / 2;
2735 static inline BYTE
get_max_level( UINT format
)
2739 case GGO_GRAY2_BITMAP
: return 4;
2740 case GGO_GRAY4_BITMAP
: return 16;
2741 case GGO_GRAY8_BITMAP
: return 64;
2746 static FT_Vector
get_advance_metric( struct gdi_font
*font
, FT_Pos base_advance
,
2747 const FT_Matrix
*transMat
)
2750 FT_Fixed em_scale
= 0;
2751 BOOL fixed_pitch_full
= FALSE
;
2752 struct gdi_font
*incoming_font
= font
->base_font
? font
->base_font
: font
;
2754 adv
.x
= base_advance
;
2757 /* In fixed-pitch font, we adjust the fullwidth character advance so that
2758 they have double halfwidth character width. E.g. if the font is 19 ppem,
2759 we return 20 (not 19) for fullwidth characters as we return 10 for
2760 halfwidth characters. */
2761 if (freetype_set_outline_text_metrics(incoming_font
) &&
2762 !(incoming_font
->otm
.otmTextMetrics
.tmPitchAndFamily
& TMPF_FIXED_PITCH
)) {
2764 em_scale
= pFT_MulDiv(incoming_font
->ppem
, 1 << 16, get_ft_face(incoming_font
)->units_per_EM
);
2765 avg_advance
= pFT_MulFix(incoming_font
->ntmAvgWidth
, em_scale
);
2766 fixed_pitch_full
= (avg_advance
> 0 &&
2767 (base_advance
+ 63) >> 6 ==
2768 pFT_MulFix(incoming_font
->ntmAvgWidth
*2, em_scale
));
2769 if (fixed_pitch_full
&& !transMat
)
2770 adv
.x
= (avg_advance
* 2) << 6;
2774 pFT_Vector_Transform(&adv
, transMat
);
2775 if (fixed_pitch_full
&& adv
.y
== 0) {
2777 vec
.x
= incoming_font
->ntmAvgWidth
;
2779 pFT_Vector_Transform(&vec
, transMat
);
2780 adv
.x
= (pFT_MulFix(vec
.x
, em_scale
) * 2) << 6;
2784 if (font
->fake_bold
) {
2788 FT_Vector fake_bold_adv
, vec
= { 1 << 6, 0 };
2789 pFT_Vector_Transform(&vec
, transMat
);
2790 fake_bold_adv
= normalize_vector(&vec
);
2791 adv
.x
+= fake_bold_adv
.x
;
2792 adv
.y
+= fake_bold_adv
.y
;
2796 adv
.x
= (adv
.x
+ 63) & -64;
2797 adv
.y
= -((adv
.y
+ 63) & -64);
2801 static FT_BBox
get_transformed_bbox( const FT_Glyph_Metrics
*metrics
, const FT_Matrix
*matrices
)
2803 FT_BBox bbox
= { 0, 0, 0, 0 };
2807 bbox
.xMin
= (metrics
->horiBearingX
) & -64;
2808 bbox
.xMax
= (metrics
->horiBearingX
+ metrics
->width
+ 63) & -64;
2809 bbox
.yMax
= (metrics
->horiBearingY
+ 63) & -64;
2810 bbox
.yMin
= (metrics
->horiBearingY
- metrics
->height
) & -64;
2817 for (xc
= 0; xc
< 2; xc
++)
2819 for (yc
= 0; yc
< 2; yc
++)
2821 vec
.x
= metrics
->horiBearingX
+ xc
* metrics
->width
;
2822 vec
.y
= metrics
->horiBearingY
- yc
* metrics
->height
;
2823 TRACE( "Vec %ld, %ld\n", vec
.x
, vec
.y
);
2824 pFT_Vector_Transform( &vec
, &matrices
[matrix_vert
] );
2825 if (xc
== 0 && yc
== 0)
2827 bbox
.xMin
= bbox
.xMax
= vec
.x
;
2828 bbox
.yMin
= bbox
.yMax
= vec
.y
;
2832 if (vec
.x
< bbox
.xMin
) bbox
.xMin
= vec
.x
;
2833 else if (vec
.x
> bbox
.xMax
) bbox
.xMax
= vec
.x
;
2834 if (vec
.y
< bbox
.yMin
) bbox
.yMin
= vec
.y
;
2835 else if (vec
.y
> bbox
.yMax
) bbox
.yMax
= vec
.y
;
2839 bbox
.xMin
= bbox
.xMin
& -64;
2840 bbox
.xMax
= (bbox
.xMax
+ 63) & -64;
2841 bbox
.yMin
= bbox
.yMin
& -64;
2842 bbox
.yMax
= (bbox
.yMax
+ 63) & -64;
2843 TRACE( "transformed box: (%ld, %ld - %ld, %ld)\n", bbox
.xMin
, bbox
.yMax
, bbox
.xMax
, bbox
.yMin
);
2849 static void compute_metrics( struct gdi_font
*font
, FT_BBox bbox
, const FT_Glyph_Metrics
*metrics
,
2850 BOOL vertical
, BOOL vertical_metrics
, const FT_Matrix
*matrices
,
2851 GLYPHMETRICS
*gm
, ABC
*abc
)
2853 FT_Vector adv
, vec
, origin
;
2854 FT_Fixed base_advance
= vertical_metrics
? metrics
->vertAdvance
: metrics
->horiAdvance
;
2858 adv
= get_advance_metric( font
, base_advance
, NULL
);
2859 gm
->gmCellIncX
= adv
.x
>> 6;
2861 origin
.x
= bbox
.xMin
;
2862 origin
.y
= bbox
.yMax
;
2863 abc
->abcA
= origin
.x
>> 6;
2864 abc
->abcB
= (metrics
->width
+ 63) >> 6;
2870 if (vertical
&& freetype_set_outline_text_metrics( font
))
2872 if (vertical_metrics
)
2873 lsb
= metrics
->horiBearingY
+ metrics
->vertBearingY
;
2875 lsb
= metrics
->vertAdvance
+ (font
->otm
.otmDescent
<< 6);
2877 vec
.y
= font
->otm
.otmDescent
<< 6;
2878 TRACE( "Vec %ld,%ld\n", vec
.x
>>6, vec
.y
>>6 );
2879 pFT_Vector_Transform( &vec
, &matrices
[matrix_hori
] );
2880 origin
.x
= (vec
.x
+ bbox
.xMin
) & -64;
2881 origin
.y
= (vec
.y
+ bbox
.yMax
+ 63) & -64;
2882 lsb
-= metrics
->horiBearingY
;
2886 origin
.x
= bbox
.xMin
;
2887 origin
.y
= bbox
.yMax
;
2888 lsb
= metrics
->horiBearingX
;
2891 adv
= get_advance_metric( font
, base_advance
, &matrices
[matrix_hori
] );
2892 gm
->gmCellIncX
= adv
.x
>> 6;
2893 gm
->gmCellIncY
= adv
.y
>> 6;
2895 adv
= get_advance_metric( font
, base_advance
, &matrices
[matrix_unrotated
] );
2896 adv
.x
= pFT_Vector_Length( &adv
);
2901 pFT_Vector_Transform( &vec
, &matrices
[matrix_unrotated
] );
2902 if (lsb
> 0) abc
->abcA
= pFT_Vector_Length( &vec
) >> 6;
2903 else abc
->abcA
= -((pFT_Vector_Length( &vec
) + 63) >> 6);
2905 /* We use lsb again to avoid rounding errors */
2906 vec
.x
= lsb
+ (vertical
? metrics
->height
: metrics
->width
);
2908 pFT_Vector_Transform( &vec
, &matrices
[matrix_unrotated
] );
2909 abc
->abcB
= ((pFT_Vector_Length( &vec
) + 63) >> 6) - abc
->abcA
;
2911 if (!abc
->abcB
) abc
->abcB
= 1;
2912 abc
->abcC
= (adv
.x
>> 6) - abc
->abcA
- abc
->abcB
;
2914 gm
->gmptGlyphOrigin
.x
= origin
.x
>> 6;
2915 gm
->gmptGlyphOrigin
.y
= origin
.y
>> 6;
2916 gm
->gmBlackBoxX
= (bbox
.xMax
- bbox
.xMin
) >> 6;
2917 gm
->gmBlackBoxY
= (bbox
.yMax
- bbox
.yMin
) >> 6;
2918 if (!gm
->gmBlackBoxX
) gm
->gmBlackBoxX
= 1;
2919 if (!gm
->gmBlackBoxY
) gm
->gmBlackBoxY
= 1;
2921 TRACE( "gm: %u, %u, %s, %d, %d abc %d, %u, %d\n",
2922 gm
->gmBlackBoxX
, gm
->gmBlackBoxY
, wine_dbgstr_point(&gm
->gmptGlyphOrigin
),
2923 gm
->gmCellIncX
, gm
->gmCellIncY
, abc
->abcA
, abc
->abcB
, abc
->abcC
);
2927 static const BYTE masks
[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
2929 static DWORD
get_mono_glyph_bitmap( FT_GlyphSlot glyph
, FT_BBox bbox
,
2930 BOOL fake_bold
, const FT_Matrix
*matrices
,
2931 DWORD buflen
, BYTE
*buf
)
2933 DWORD width
= (bbox
.xMax
- bbox
.xMin
) >> 6;
2934 DWORD height
= (bbox
.yMax
- bbox
.yMin
) >> 6;
2935 DWORD pitch
= ((width
+ 31) >> 5) << 2;
2936 DWORD needed
= pitch
* height
;
2937 FT_Bitmap ft_bitmap
;
2941 if (!buf
|| !buflen
) return needed
;
2942 if (!needed
) return GDI_ERROR
; /* empty glyph */
2943 if (needed
> buflen
) return GDI_ERROR
;
2945 switch (glyph
->format
)
2947 case FT_GLYPH_FORMAT_BITMAP
:
2948 src
= glyph
->bitmap
.buffer
;
2950 w
= min( pitch
, (glyph
->bitmap
.width
+ 7) >> 3 );
2951 h
= min( height
, glyph
->bitmap
.rows
);
2955 memcpy( dst
, src
, w
);
2959 for (x
= 0; x
< w
; x
++)
2961 dst
[x
] = (dst
[x
] & 0x80) | (src
[x
] >> 1) | src
[x
];
2963 dst
[x
+ 1] = (src
[x
] & 0x01) << 7;
2966 src
+= glyph
->bitmap
.pitch
;
2971 case FT_GLYPH_FORMAT_OUTLINE
:
2972 ft_bitmap
.width
= width
;
2973 ft_bitmap
.rows
= height
;
2974 ft_bitmap
.pitch
= pitch
;
2975 ft_bitmap
.pixel_mode
= FT_PIXEL_MODE_MONO
;
2976 ft_bitmap
.buffer
= buf
;
2979 pFT_Outline_Transform( &glyph
->outline
, &matrices
[matrix_vert
] );
2980 pFT_Outline_Translate( &glyph
->outline
, -bbox
.xMin
, -bbox
.yMin
);
2982 /* Note: FreeType will only set 'black' bits for us. */
2983 memset( buf
, 0, buflen
);
2984 pFT_Outline_Get_Bitmap( library
, &glyph
->outline
, &ft_bitmap
);
2988 FIXME( "loaded glyph format %x\n", glyph
->format
);
2995 static DWORD
get_antialias_glyph_bitmap( FT_GlyphSlot glyph
, FT_BBox bbox
, UINT format
,
2996 BOOL fake_bold
, const FT_Matrix
*matrices
,
2997 DWORD buflen
, BYTE
*buf
)
2999 DWORD width
= (bbox
.xMax
- bbox
.xMin
) >> 6;
3000 DWORD height
= (bbox
.yMax
- bbox
.yMin
) >> 6;
3001 DWORD pitch
= (width
+ 3) / 4 * 4;
3002 DWORD needed
= pitch
* height
;
3003 FT_Bitmap ft_bitmap
;
3004 INT w
, h
, x
, max_level
;
3007 if (!buf
|| !buflen
) return needed
;
3008 if (!needed
) return GDI_ERROR
; /* empty glyph */
3009 if (needed
> buflen
) return GDI_ERROR
;
3011 max_level
= get_max_level( format
);
3013 switch (glyph
->format
)
3015 case FT_GLYPH_FORMAT_BITMAP
:
3016 src
= glyph
->bitmap
.buffer
;
3018 memset( buf
, 0, buflen
);
3020 w
= min( pitch
, glyph
->bitmap
.width
);
3021 h
= min( height
, glyph
->bitmap
.rows
);
3024 for (x
= 0; x
< w
; x
++)
3026 if (src
[x
/ 8] & masks
[x
% 8])
3029 if (fake_bold
&& x
+ 1 < pitch
) dst
[x
+ 1] = max_level
;
3032 src
+= glyph
->bitmap
.pitch
;
3037 case FT_GLYPH_FORMAT_OUTLINE
:
3038 ft_bitmap
.width
= width
;
3039 ft_bitmap
.rows
= height
;
3040 ft_bitmap
.pitch
= pitch
;
3041 ft_bitmap
.pixel_mode
= FT_PIXEL_MODE_GRAY
;
3042 ft_bitmap
.buffer
= buf
;
3045 pFT_Outline_Transform( &glyph
->outline
, &matrices
[matrix_vert
] );
3046 pFT_Outline_Translate( &glyph
->outline
, -bbox
.xMin
, -bbox
.yMin
);
3048 memset( buf
, 0, buflen
);
3049 pFT_Outline_Get_Bitmap( library
, &glyph
->outline
, &ft_bitmap
);
3051 if (max_level
!= 255)
3056 for (row
= 0, start
= buf
; row
< height
; row
++)
3058 for (col
= 0, ptr
= start
; col
< width
; col
++, ptr
++)
3059 *ptr
= (((int)*ptr
) * (max_level
+ 1)) / 256;
3066 FIXME("loaded glyph format %x\n", glyph
->format
);
3073 static DWORD
get_subpixel_glyph_bitmap( FT_GlyphSlot glyph
, FT_BBox bbox
, UINT format
,
3074 BOOL fake_bold
, const FT_Matrix
*matrices
,
3075 GLYPHMETRICS
*gm
, DWORD buflen
, BYTE
*buf
)
3077 DWORD width
= (bbox
.xMax
- bbox
.xMin
) >> 6;
3078 DWORD height
= (bbox
.yMax
- bbox
.yMin
) >> 6;
3079 DWORD pitch
, needed
= 0;
3083 switch (glyph
->format
)
3085 case FT_GLYPH_FORMAT_BITMAP
:
3087 needed
= pitch
* height
;
3089 if (!buf
|| !buflen
) break;
3090 if (!needed
) return GDI_ERROR
; /* empty glyph */
3091 if (needed
> buflen
) return GDI_ERROR
;
3093 src
= glyph
->bitmap
.buffer
;
3095 memset( buf
, 0, buflen
);
3097 w
= min( width
, glyph
->bitmap
.width
);
3098 h
= min( height
, glyph
->bitmap
.rows
);
3101 for (x
= 0; x
< w
; x
++)
3103 if ( src
[x
/ 8] & masks
[x
% 8] )
3105 ((unsigned int *)dst
)[x
] = ~0u;
3106 if (fake_bold
&& x
+ 1 < width
) ((unsigned int *)dst
)[x
+ 1] = ~0u;
3109 src
+= glyph
->bitmap
.pitch
;
3114 case FT_GLYPH_FORMAT_OUTLINE
:
3116 INT src_pitch
, src_width
, src_height
, x_shift
, y_shift
;
3117 INT sub_stride
, hmul
, vmul
;
3118 const INT
*sub_order
;
3119 const INT rgb_order
[3] = { 0, 1, 2 };
3120 const INT bgr_order
[3] = { 2, 1, 0 };
3121 FT_Render_Mode render_mode
=
3122 (format
== WINE_GGO_HRGB_BITMAP
||
3123 format
== WINE_GGO_HBGR_BITMAP
) ? FT_RENDER_MODE_LCD
: FT_RENDER_MODE_LCD_V
;
3125 if (!width
|| !height
) /* empty glyph */
3127 if (!buf
|| !buflen
) break;
3131 if ( render_mode
== FT_RENDER_MODE_LCD
)
3133 gm
->gmBlackBoxX
+= 2;
3134 gm
->gmptGlyphOrigin
.x
-= 1;
3135 bbox
.xMin
-= (1 << 6);
3139 gm
->gmBlackBoxY
+= 2;
3140 gm
->gmptGlyphOrigin
.y
+= 1;
3141 bbox
.yMax
+= (1 << 6);
3144 width
= gm
->gmBlackBoxX
;
3145 height
= gm
->gmBlackBoxY
;
3147 needed
= pitch
* height
;
3149 if (!buf
|| !buflen
) return needed
;
3150 if (needed
> buflen
) return GDI_ERROR
;
3153 pFT_Outline_Transform( &glyph
->outline
, &matrices
[matrix_vert
] );
3155 pFT_Render_Glyph( glyph
, render_mode
);
3157 src_pitch
= glyph
->bitmap
.pitch
;
3158 src_width
= glyph
->bitmap
.width
;
3159 src_height
= glyph
->bitmap
.rows
;
3160 src
= glyph
->bitmap
.buffer
;
3162 memset( buf
, 0, buflen
);
3164 sub_order
= (format
== WINE_GGO_HRGB_BITMAP
||
3165 format
== WINE_GGO_VRGB_BITMAP
) ? rgb_order
: bgr_order
;
3166 sub_stride
= render_mode
== FT_RENDER_MODE_LCD
? 1 : src_pitch
;
3167 hmul
= render_mode
== FT_RENDER_MODE_LCD
? 3 : 1;
3168 vmul
= render_mode
== FT_RENDER_MODE_LCD
? 1 : 3;
3170 x_shift
= glyph
->bitmap_left
- (bbox
.xMin
>> 6);
3173 src
+= hmul
* -x_shift
;
3174 src_width
-= hmul
* -x_shift
;
3176 else if ( x_shift
> 0 )
3178 dst
+= x_shift
* sizeof(unsigned int);
3182 y_shift
= (bbox
.yMax
>> 6) - glyph
->bitmap_top
;
3185 src
+= src_pitch
* vmul
* -y_shift
;
3186 src_height
-= vmul
* -y_shift
;
3188 else if ( y_shift
> 0 )
3190 dst
+= y_shift
* pitch
;
3194 w
= min( width
, src_width
/ hmul
);
3195 h
= min( height
, src_height
/ vmul
);
3198 for (x
= 0; x
< w
; x
++)
3200 ((unsigned int *)dst
)[x
] =
3201 ((unsigned int)src
[hmul
* x
+ sub_stride
* sub_order
[0]] << 16) |
3202 ((unsigned int)src
[hmul
* x
+ sub_stride
* sub_order
[1]] << 8) |
3203 ((unsigned int)src
[hmul
* x
+ sub_stride
* sub_order
[2]]);
3205 src
+= src_pitch
* vmul
;
3211 FIXME ( "loaded glyph format %x\n", glyph
->format
);
3218 static unsigned int get_native_glyph_outline(FT_Outline
*outline
, unsigned int buflen
, char *buf
)
3220 TTPOLYGONHEADER
*pph
;
3222 unsigned int needed
= 0, point
= 0, contour
, first_pt
;
3223 unsigned int pph_start
, cpfx
;
3226 for (contour
= 0; contour
< outline
->n_contours
; contour
++)
3228 /* Ignore contours containing one point */
3229 if (point
== outline
->contours
[contour
])
3236 pph
= (TTPOLYGONHEADER
*)(buf
+ needed
);
3240 pph
->dwType
= TT_POLYGON_TYPE
;
3241 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
3243 needed
+= sizeof(*pph
);
3245 while (point
<= outline
->contours
[contour
])
3247 ppc
= (TTPOLYCURVE
*)(buf
+ needed
);
3248 type
= outline
->tags
[point
] & FT_Curve_Tag_On
?
3249 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
3254 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
3257 } while (point
<= outline
->contours
[contour
] &&
3258 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
3259 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
3260 /* At the end of a contour Windows adds the start point, but
3262 if (point
> outline
->contours
[contour
] &&
3263 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
))
3266 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
3269 else if (point
<= outline
->contours
[contour
] &&
3270 outline
->tags
[point
] & FT_Curve_Tag_On
)
3272 /* add closing pt for bezier */
3274 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
3283 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
3286 pph
->cb
= needed
- pph_start
;
3291 static unsigned int get_bezier_glyph_outline(FT_Outline
*outline
, unsigned int buflen
, char *buf
)
3293 /* Convert the quadratic Beziers to cubic Beziers.
3294 The parametric eqn for a cubic Bezier is, from PLRM:
3295 r(t) = at^3 + bt^2 + ct + r0
3296 with the control points:
3301 A quadratic Bezier has the form:
3302 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3304 So equating powers of t leads to:
3305 r1 = 2/3 p1 + 1/3 p0
3306 r2 = 2/3 p1 + 1/3 p2
3307 and of course r0 = p0, r3 = p2
3309 int contour
, point
= 0, first_pt
;
3310 TTPOLYGONHEADER
*pph
;
3312 DWORD pph_start
, cpfx
, type
;
3313 FT_Vector cubic_control
[4];
3314 unsigned int needed
= 0;
3316 for (contour
= 0; contour
< outline
->n_contours
; contour
++)
3319 pph
= (TTPOLYGONHEADER
*)(buf
+ needed
);
3323 pph
->dwType
= TT_POLYGON_TYPE
;
3324 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
3326 needed
+= sizeof(*pph
);
3328 while (point
<= outline
->contours
[contour
])
3330 ppc
= (TTPOLYCURVE
*)(buf
+ needed
);
3331 type
= outline
->tags
[point
] & FT_Curve_Tag_On
?
3332 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
3336 if (type
== TT_PRIM_LINE
)
3339 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
3345 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
3348 /* FIXME: Possible optimization in endpoint calculation
3349 if there are two consecutive curves */
3350 cubic_control
[0] = outline
->points
[point
-1];
3351 if (!(outline
->tags
[point
-1] & FT_Curve_Tag_On
))
3353 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
3354 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
3355 cubic_control
[0].x
>>= 1;
3356 cubic_control
[0].y
>>= 1;
3358 if (point
+1 > outline
->contours
[contour
])
3359 cubic_control
[3] = outline
->points
[first_pt
];
3362 cubic_control
[3] = outline
->points
[point
+1];
3363 if (!(outline
->tags
[point
+1] & FT_Curve_Tag_On
))
3365 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
3366 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
3367 cubic_control
[3].x
>>= 1;
3368 cubic_control
[3].y
>>= 1;
3371 /* r1 = 1/3 p0 + 2/3 p1
3372 r2 = 1/3 p2 + 2/3 p1 */
3373 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
3374 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
3375 cubic_control
[2] = cubic_control
[1];
3376 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
3377 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
3378 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
3379 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
3382 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
3383 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
3384 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
3389 } while (point
<= outline
->contours
[contour
] &&
3390 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
3391 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
3392 /* At the end of a contour Windows adds the start point,
3393 but only for Beziers and we've already done that.
3395 if (point
<= outline
->contours
[contour
] &&
3396 outline
->tags
[point
] & FT_Curve_Tag_On
)
3398 /* This is the closing pt of a bezier, but we've already
3399 added it, so just inc point and carry on */
3407 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
3410 pph
->cb
= needed
- pph_start
;
3415 static FT_Int
get_load_flags( UINT format
)
3417 FT_Int load_flags
= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
3419 if (format
& GGO_UNHINTED
)
3420 return load_flags
| FT_LOAD_NO_HINTING
;
3422 switch (format
& ~GGO_GLYPH_INDEX
)
3425 load_flags
|= FT_LOAD_TARGET_MONO
;
3427 case GGO_GRAY2_BITMAP
:
3428 case GGO_GRAY4_BITMAP
:
3429 case GGO_GRAY8_BITMAP
:
3430 case WINE_GGO_GRAY16_BITMAP
:
3431 load_flags
|= FT_LOAD_TARGET_NORMAL
;
3433 case WINE_GGO_HRGB_BITMAP
:
3434 case WINE_GGO_HBGR_BITMAP
:
3435 load_flags
|= FT_LOAD_TARGET_LCD
;
3437 case WINE_GGO_VRGB_BITMAP
:
3438 case WINE_GGO_VBGR_BITMAP
:
3439 load_flags
|= FT_LOAD_TARGET_LCD_V
;
3446 /*************************************************************
3447 * freetype_get_glyph_outline
3449 static DWORD
freetype_get_glyph_outline( struct gdi_font
*font
, UINT glyph
, UINT format
,
3450 GLYPHMETRICS
*lpgm
, ABC
*abc
, DWORD buflen
, void *buf
,
3451 const MAT2
*lpmat
, BOOL tategaki
)
3453 struct gdi_font
*base_font
= font
->base_font
? font
->base_font
: font
;
3454 FT_Face ft_face
= get_ft_face( font
);
3455 FT_Glyph_Metrics metrics
;
3458 FT_Int load_flags
= get_load_flags(format
);
3459 FT_Matrix transform_matrices
[3], *matrices
= NULL
;
3460 BOOL vertical_metrics
;
3462 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
, buflen
, buf
, lpmat
);
3464 TRACE("font transform %f %f %f %f\n",
3465 font
->matrix
.eM11
, font
->matrix
.eM12
,
3466 font
->matrix
.eM21
, font
->matrix
.eM22
);
3468 format
&= ~GGO_UNHINTED
;
3470 matrices
= get_transform_matrices( font
, tategaki
, lpmat
, transform_matrices
);
3472 vertical_metrics
= (tategaki
&& FT_HAS_VERTICAL(ft_face
));
3473 /* there is a freetype bug where vertical metrics are only
3474 properly scaled and correct in 2.4.0 or greater */
3475 if (vertical_metrics
&& FT_SimpleVersion
< FT_VERSION_VALUE(2, 4, 0))
3476 vertical_metrics
= FALSE
;
3478 if (matrices
|| format
!= GGO_BITMAP
) load_flags
|= FT_LOAD_NO_BITMAP
;
3479 if (vertical_metrics
) load_flags
|= FT_LOAD_VERTICAL_LAYOUT
;
3481 err
= pFT_Load_Glyph(ft_face
, glyph
, load_flags
);
3482 if (err
&& !(load_flags
& FT_LOAD_NO_HINTING
))
3484 WARN("Failed to load glyph %#x, retrying without hinting. Error %#x.\n", glyph
, err
);
3485 load_flags
|= FT_LOAD_NO_HINTING
;
3486 err
= pFT_Load_Glyph(ft_face
, glyph
, load_flags
);
3490 WARN("Failed to load glyph %#x, error %#x.\n", glyph
, err
);
3494 metrics
= ft_face
->glyph
->metrics
;
3495 if(font
->fake_bold
) {
3496 if (!get_bold_glyph_outline(ft_face
->glyph
, font
->ppem
, &metrics
) && metrics
.width
)
3497 metrics
.width
+= 1 << 6;
3500 /* Some poorly-created fonts contain glyphs that exceed the boundaries set
3501 * by the text metrics. The proper behavior is to clip the glyph metrics to
3502 * fit within the maximums specified in the text metrics. */
3503 if (freetype_set_outline_text_metrics(base_font
) ||
3504 freetype_set_bitmap_text_metrics(base_font
)) {
3505 TEXTMETRICW
*ptm
= &base_font
->otm
.otmTextMetrics
;
3506 INT top
= min( metrics
.horiBearingY
, ptm
->tmAscent
<< 6 );
3507 INT bottom
= max( metrics
.horiBearingY
- metrics
.height
, -(ptm
->tmDescent
<< 6) );
3508 metrics
.horiBearingY
= top
;
3509 metrics
.height
= top
- bottom
;
3511 /* TODO: Are we supposed to clip the width as well...? */
3512 /* metrics.width = min( metrics.width, ptm->tmMaxCharWidth << 6 ); */
3515 bbox
= get_transformed_bbox( &metrics
, matrices
);
3516 compute_metrics( font
, bbox
, &metrics
, tategaki
, vertical_metrics
, matrices
, lpgm
, abc
);
3521 return 1; /* FIXME */
3524 return get_mono_glyph_bitmap( ft_face
->glyph
, bbox
, font
->fake_bold
,
3525 matrices
, buflen
, buf
);
3527 case GGO_GRAY2_BITMAP
:
3528 case GGO_GRAY4_BITMAP
:
3529 case GGO_GRAY8_BITMAP
:
3530 case WINE_GGO_GRAY16_BITMAP
:
3531 return get_antialias_glyph_bitmap( ft_face
->glyph
, bbox
, format
, font
->fake_bold
,
3532 matrices
, buflen
, buf
);
3534 case WINE_GGO_HRGB_BITMAP
:
3535 case WINE_GGO_HBGR_BITMAP
:
3536 case WINE_GGO_VRGB_BITMAP
:
3537 case WINE_GGO_VBGR_BITMAP
:
3538 return get_subpixel_glyph_bitmap( ft_face
->glyph
, bbox
, format
, font
->fake_bold
,
3539 matrices
, lpgm
, buflen
, buf
);
3542 if (ft_face
->glyph
->format
== ft_glyph_format_outline
)
3544 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
3547 if (buflen
== 0) buf
= NULL
;
3549 if (matrices
&& buf
)
3550 pFT_Outline_Transform( outline
, &matrices
[matrix_vert
] );
3552 needed
= get_native_glyph_outline(outline
, buflen
, NULL
);
3554 if (!buf
|| !buflen
) return needed
;
3555 if (needed
> buflen
) return GDI_ERROR
;
3556 return get_native_glyph_outline(outline
, buflen
, buf
);
3558 TRACE("loaded a bitmap\n");
3562 if (ft_face
->glyph
->format
== ft_glyph_format_outline
)
3564 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
3567 if (buflen
== 0) buf
= NULL
;
3569 if (matrices
&& buf
)
3570 pFT_Outline_Transform( outline
, &matrices
[matrix_vert
] );
3572 needed
= get_bezier_glyph_outline(outline
, buflen
, NULL
);
3574 if (!buf
|| !buflen
) return needed
;
3575 if (needed
> buflen
) return GDI_ERROR
;
3576 return get_bezier_glyph_outline(outline
, buflen
, buf
);
3578 TRACE("loaded a bitmap\n");
3582 FIXME("Unsupported format %d\n", format
);
3587 /*************************************************************
3588 * freetype_set_bitmap_text_metrics
3590 static BOOL
freetype_set_bitmap_text_metrics( struct gdi_font
*font
)
3592 FT_Face ft_face
= get_ft_face( font
);
3593 FT_WinFNT_HeaderRec winfnt_header
;
3595 if (font
->otm
.otmSize
) return TRUE
; /* already set */
3596 font
->otm
.otmSize
= offsetof( OUTLINETEXTMETRICW
, otmFiller
);
3598 #define TM font->otm.otmTextMetrics
3599 if(!pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
3601 TM
.tmHeight
= winfnt_header
.pixel_height
;
3602 TM
.tmAscent
= winfnt_header
.ascent
;
3603 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
3604 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
3605 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
3606 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
3607 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
3608 TM
.tmWeight
= winfnt_header
.weight
;
3610 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
3611 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
3612 TM
.tmFirstChar
= winfnt_header
.first_char
;
3613 TM
.tmLastChar
= winfnt_header
.last_char
;
3614 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
3615 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
3616 TM
.tmItalic
= winfnt_header
.italic
;
3617 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
3618 TM
.tmCharSet
= winfnt_header
.charset
;
3622 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
3623 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
3624 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
3625 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
3626 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
3627 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
3628 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
3629 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
3631 TM
.tmDigitizedAspectX
= 96; /* FIXME */
3632 TM
.tmDigitizedAspectY
= 96; /* FIXME */
3634 TM
.tmLastChar
= 255;
3635 TM
.tmDefaultChar
= 32;
3636 TM
.tmBreakChar
= 32;
3637 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
3638 /* NB inverted meaning of TMPF_FIXED_PITCH */
3639 TM
.tmPitchAndFamily
= FT_IS_FIXED_WIDTH(ft_face
) ? 0 : TMPF_FIXED_PITCH
;
3640 TM
.tmCharSet
= font
->charset
;
3642 TM
.tmUnderlined
= font
->lf
.lfUnderline
? 0xff : 0;
3643 TM
.tmStruckOut
= font
->lf
.lfStrikeOut
? 0xff : 0;
3646 TM
.tmWeight
= FW_BOLD
;
3653 static BOOL
face_has_symbol_charmap(FT_Face ft_face
)
3657 for(i
= 0; i
< ft_face
->num_charmaps
; i
++)
3659 if(ft_face
->charmaps
[i
]->encoding
== FT_ENCODING_MS_SYMBOL
)
3665 /*************************************************************
3666 * freetype_set_outline_text_metrics
3668 static BOOL
freetype_set_outline_text_metrics( struct gdi_font
*font
)
3670 FT_Face ft_face
= get_ft_face( font
);
3673 TT_HoriHeader
*pHori
;
3674 TT_Postscript
*pPost
;
3676 INT ascent
, descent
;
3679 TRACE("font=%p\n", font
);
3681 if (!font
->scalable
) return FALSE
;
3682 if (font
->otm
.otmSize
) return TRUE
; /* already set */
3684 /* note: we store actual pointers in the names instead of offsets,
3685 they are fixed up when returned to the app */
3686 if (!(font
->otm
.otmpFullName
= (char *)get_face_name( ft_face
, TT_NAME_ID_UNIQUE_ID
, system_lcid
)))
3688 static const WCHAR fake_nameW
[] = {'f','a','k','e',' ','n','a','m','e', 0};
3689 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w((WCHAR
*)font
->otm
.otmpFamilyName
));
3690 font
->otm
.otmpFullName
= (char *)strdupW(fake_nameW
);
3692 needed
= sizeof(font
->otm
) + (lstrlenW( (WCHAR
*)font
->otm
.otmpFamilyName
) + 1 +
3693 lstrlenW( (WCHAR
*)font
->otm
.otmpStyleName
) + 1 +
3694 lstrlenW( (WCHAR
*)font
->otm
.otmpFaceName
) + 1 +
3695 lstrlenW( (WCHAR
*)font
->otm
.otmpFullName
) + 1) * sizeof(WCHAR
);
3697 em_scale
= (FT_Fixed
)pFT_MulDiv(font
->ppem
, 1 << 16, ft_face
->units_per_EM
);
3699 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
3701 FIXME("Can't find OS/2 table - not TT font?\n");
3705 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
3707 FIXME("Can't find HHEA table - not TT font?\n");
3711 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
3713 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",
3714 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
3715 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
3716 pOS2
->xAvgCharWidth
,
3717 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
3718 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
3719 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
3721 font
->otm
.otmSize
= needed
;
3723 #define TM font->otm.otmTextMetrics
3725 windescent
= get_fixed_windescent(pOS2
->usWinDescent
);
3726 if(pOS2
->usWinAscent
+ windescent
== 0) {
3727 ascent
= pHori
->Ascender
;
3728 descent
= -pHori
->Descender
;
3730 ascent
= pOS2
->usWinAscent
;
3731 descent
= windescent
;
3734 font
->ntmAvgWidth
= pOS2
->xAvgCharWidth
;
3736 #define SCALE_X(x) (pFT_MulFix(x, em_scale))
3737 #define SCALE_Y(y) (pFT_MulFix(y, em_scale))
3740 TM
.tmAscent
= font
->yMax
;
3741 TM
.tmDescent
= -font
->yMin
;
3742 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
3744 TM
.tmAscent
= SCALE_Y(ascent
);
3745 TM
.tmDescent
= SCALE_Y(descent
);
3746 TM
.tmInternalLeading
= SCALE_Y(ascent
+ descent
- ft_face
->units_per_EM
);
3749 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
3752 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
3754 TM
.tmExternalLeading
= max(0, SCALE_Y(pHori
->Line_Gap
-
3755 ((ascent
+ descent
) -
3756 (pHori
->Ascender
- pHori
->Descender
))));
3758 TM
.tmAveCharWidth
= SCALE_X(pOS2
->xAvgCharWidth
);
3759 if (TM
.tmAveCharWidth
== 0) {
3760 TM
.tmAveCharWidth
= 1;
3762 TM
.tmMaxCharWidth
= SCALE_X(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
);
3763 TM
.tmWeight
= FW_REGULAR
;
3764 if (font
->fake_bold
)
3765 TM
.tmWeight
= FW_BOLD
;
3768 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)
3770 if (pOS2
->usWeightClass
> FW_MEDIUM
)
3771 TM
.tmWeight
= pOS2
->usWeightClass
;
3773 else if (pOS2
->usWeightClass
<= FW_MEDIUM
)
3774 TM
.tmWeight
= pOS2
->usWeightClass
;
3777 TM
.tmDigitizedAspectX
= 96; /* FIXME */
3778 TM
.tmDigitizedAspectY
= 96; /* FIXME */
3779 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
3780 * symbol range to 0 - f0ff
3783 if (face_has_symbol_charmap(ft_face
) || (pOS2
->usFirstCharIndex
>= 0xf000 && pOS2
->usFirstCharIndex
< 0xf100))
3786 switch (PRIMARYLANGID(system_lcid
))
3789 TM
.tmLastChar
= 0xf896;
3793 case LANG_LITHUANIAN
:
3794 TM
.tmLastChar
= 0xf8fd;
3797 TM
.tmLastChar
= 0xf0ff;
3799 TM
.tmBreakChar
= 0x20;
3800 TM
.tmDefaultChar
= 0x1f;
3804 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
; /* Should be the first char in the cmap */
3805 TM
.tmLastChar
= pOS2
->usLastCharIndex
; /* Should be min(cmap_last, os2_last) */
3807 if(pOS2
->usFirstCharIndex
<= 1)
3808 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
+ 2;
3809 else if (pOS2
->usFirstCharIndex
> 0xff)
3810 TM
.tmBreakChar
= 0x20;
3812 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
;
3813 TM
.tmDefaultChar
= TM
.tmBreakChar
- 1;
3815 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
3816 TM
.tmUnderlined
= font
->lf
.lfUnderline
? 255 : 0;
3817 TM
.tmStruckOut
= font
->lf
.lfStrikeOut
? 255 : 0;
3819 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
3820 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
3821 (pOS2
->version
== 0xFFFFU
||
3822 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
3823 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
3825 TM
.tmPitchAndFamily
= 0;
3827 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
])
3829 case PAN_FAMILY_SCRIPT
:
3830 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
3833 case PAN_FAMILY_DECORATIVE
:
3834 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
3839 case PAN_FAMILY_TEXT_DISPLAY
:
3840 case PAN_FAMILY_PICTORIAL
: /* symbol fonts get treated as if they were text */
3841 /* which is clearly not what the panose spec says. */
3843 if(TM
.tmPitchAndFamily
== 0 || /* fixed */
3844 pOS2
->panose
[PAN_PROPORTION_INDEX
] == PAN_PROP_MONOSPACED
)
3845 TM
.tmPitchAndFamily
= FF_MODERN
;
3848 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
])
3853 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
3856 case PAN_SERIF_COVE
:
3857 case PAN_SERIF_OBTUSE_COVE
:
3858 case PAN_SERIF_SQUARE_COVE
:
3859 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
3860 case PAN_SERIF_SQUARE
:
3861 case PAN_SERIF_THIN
:
3862 case PAN_SERIF_BONE
:
3863 case PAN_SERIF_EXAGGERATED
:
3864 case PAN_SERIF_TRIANGLE
:
3865 TM
.tmPitchAndFamily
|= FF_ROMAN
;
3868 case PAN_SERIF_NORMAL_SANS
:
3869 case PAN_SERIF_OBTUSE_SANS
:
3870 case PAN_SERIF_PERP_SANS
:
3871 case PAN_SERIF_FLARED
:
3872 case PAN_SERIF_ROUNDED
:
3873 TM
.tmPitchAndFamily
|= FF_SWISS
;
3880 if(FT_IS_SCALABLE(ft_face
))
3881 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
3883 if(FT_IS_SFNT(ft_face
))
3885 if (font
->ntmFlags
& NTM_PS_OPENTYPE
)
3886 TM
.tmPitchAndFamily
|= TMPF_DEVICE
;
3888 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
3891 TM
.tmCharSet
= font
->charset
;
3893 font
->otm
.otmFiller
= 0;
3894 memcpy(&font
->otm
.otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
3895 font
->otm
.otmfsSelection
= pOS2
->fsSelection
;
3896 if (font
->fake_italic
)
3897 font
->otm
.otmfsSelection
|= 1;
3898 if (font
->fake_bold
)
3899 font
->otm
.otmfsSelection
|= 1 << 5;
3900 /* Only return valid bits that define embedding and subsetting restrictions */
3901 font
->otm
.otmfsType
= pOS2
->fsType
& 0x30e;
3902 font
->otm
.otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
3903 font
->otm
.otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
3904 font
->otm
.otmItalicAngle
= 0; /* POST table */
3905 font
->otm
.otmAscent
= SCALE_Y(pOS2
->sTypoAscender
);
3906 font
->otm
.otmDescent
= SCALE_Y(pOS2
->sTypoDescender
);
3907 font
->otm
.otmLineGap
= SCALE_Y(pOS2
->sTypoLineGap
);
3908 font
->otm
.otmsCapEmHeight
= SCALE_Y(pOS2
->sCapHeight
);
3909 font
->otm
.otmsXHeight
= SCALE_Y(pOS2
->sxHeight
);
3910 font
->otm
.otmrcFontBox
.left
= SCALE_X(ft_face
->bbox
.xMin
);
3911 font
->otm
.otmrcFontBox
.right
= SCALE_X(ft_face
->bbox
.xMax
);
3912 font
->otm
.otmrcFontBox
.top
= SCALE_Y(ft_face
->bbox
.yMax
);
3913 font
->otm
.otmrcFontBox
.bottom
= SCALE_Y(ft_face
->bbox
.yMin
);
3914 font
->otm
.otmMacAscent
= TM
.tmAscent
;
3915 font
->otm
.otmMacDescent
= -TM
.tmDescent
;
3916 font
->otm
.otmMacLineGap
= SCALE_Y(pHori
->Line_Gap
);
3917 font
->otm
.otmusMinimumPPEM
= 0; /* TT Header */
3918 font
->otm
.otmptSubscriptSize
.x
= SCALE_X(pOS2
->ySubscriptXSize
);
3919 font
->otm
.otmptSubscriptSize
.y
= SCALE_Y(pOS2
->ySubscriptYSize
);
3920 font
->otm
.otmptSubscriptOffset
.x
= SCALE_X(pOS2
->ySubscriptXOffset
);
3921 font
->otm
.otmptSubscriptOffset
.y
= SCALE_Y(pOS2
->ySubscriptYOffset
);
3922 font
->otm
.otmptSuperscriptSize
.x
= SCALE_X(pOS2
->ySuperscriptXSize
);
3923 font
->otm
.otmptSuperscriptSize
.y
= SCALE_Y(pOS2
->ySuperscriptYSize
);
3924 font
->otm
.otmptSuperscriptOffset
.x
= SCALE_X(pOS2
->ySuperscriptXOffset
);
3925 font
->otm
.otmptSuperscriptOffset
.y
= SCALE_Y(pOS2
->ySuperscriptYOffset
);
3926 font
->otm
.otmsStrikeoutSize
= SCALE_Y(pOS2
->yStrikeoutSize
);
3927 font
->otm
.otmsStrikeoutPosition
= SCALE_Y(pOS2
->yStrikeoutPosition
);
3929 font
->otm
.otmsUnderscoreSize
= 0;
3930 font
->otm
.otmsUnderscorePosition
= 0;
3932 font
->otm
.otmsUnderscoreSize
= SCALE_Y(pPost
->underlineThickness
);
3933 font
->otm
.otmsUnderscorePosition
= SCALE_Y(pPost
->underlinePosition
);
3941 /*************************************************************
3942 * freetype_get_char_width_info
3944 static BOOL
freetype_get_char_width_info( struct gdi_font
*font
, struct char_width_info
*info
)
3946 FT_Face ft_face
= get_ft_face( font
);
3947 TT_HoriHeader
*pHori
;
3949 TRACE("%p, %p\n", font
, info
);
3951 if ((pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
)))
3953 FT_Fixed em_scale
= pFT_MulDiv(font
->ppem
, 1 << 16, ft_face
->units_per_EM
);
3954 info
->lsb
= (SHORT
)pFT_MulFix(pHori
->min_Left_Side_Bearing
, em_scale
);
3955 info
->rsb
= (SHORT
)pFT_MulFix(pHori
->min_Right_Side_Bearing
, em_scale
);
3962 /*************************************************************
3963 * freetype_get_unicode_ranges
3965 * Retrieve a list of supported Unicode ranges for a given font.
3966 * Can be called with NULL gs to calculate the buffer size. Returns
3967 * the number of ranges found.
3969 static DWORD
freetype_get_unicode_ranges( struct gdi_font
*font
, GLYPHSET
*gs
)
3971 FT_Face ft_face
= get_ft_face( font
);
3972 DWORD num_ranges
= 0;
3974 if (ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
3977 FT_ULong char_code
, char_code_prev
;
3980 char_code_prev
= char_code
= pFT_Get_First_Char(ft_face
, &glyph_code
);
3982 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
3983 ft_face
->num_glyphs
, glyph_code
, char_code
);
3985 if (!glyph_code
) return 0;
3989 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
3990 gs
->ranges
[0].cGlyphs
= 0;
3991 gs
->cGlyphsSupported
= 0;
3997 if (char_code
< char_code_prev
)
3999 ERR("expected increasing char code from FT_Get_Next_Char\n");
4002 if (char_code
- char_code_prev
> 1)
4007 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
4008 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
4009 gs
->cGlyphsSupported
++;
4014 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
4015 gs
->cGlyphsSupported
++;
4017 char_code_prev
= char_code
;
4018 char_code
= pFT_Get_Next_Char(ft_face
, char_code
, &glyph_code
);
4023 DWORD encoding
= RtlUlongByteSwap(ft_face
->charmap
->encoding
);
4024 FIXME("encoding %s not supported\n", debugstr_an((char *)&encoding
, 4));
4030 /*************************************************************************
4031 * Kerning support for TrueType fonts
4034 struct TT_kern_table
4040 struct TT_kern_subtable
4049 USHORT horizontal
: 1;
4051 USHORT cross_stream
: 1;
4052 USHORT override
: 1;
4053 USHORT reserved1
: 4;
4059 struct TT_format0_kern_subtable
4063 USHORT entrySelector
;
4074 static DWORD
parse_format0_kern_subtable(struct gdi_font
*font
,
4075 const struct TT_format0_kern_subtable
*tt_f0_ks
,
4076 const USHORT
*glyph_to_char
,
4077 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
4079 FT_Face ft_face
= get_ft_face( font
);
4081 const struct TT_kern_pair
*tt_kern_pair
;
4083 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, ft_face
->units_per_EM
);
4085 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
4087 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
4088 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
4089 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
4091 if (!kern_pair
|| !cPairs
)
4094 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
4096 nPairs
= min(nPairs
, cPairs
);
4098 for (i
= 0; i
< nPairs
; i
++)
4100 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
4101 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
4102 /* this algorithm appears to better match what Windows does */
4103 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
4104 if (kern_pair
->iKernAmount
< 0)
4106 kern_pair
->iKernAmount
-= ft_face
->units_per_EM
/ 2;
4107 kern_pair
->iKernAmount
-= font
->ppem
;
4109 else if (kern_pair
->iKernAmount
> 0)
4111 kern_pair
->iKernAmount
+= ft_face
->units_per_EM
/ 2;
4112 kern_pair
->iKernAmount
+= font
->ppem
;
4114 kern_pair
->iKernAmount
/= ft_face
->units_per_EM
;
4116 TRACE("left %u right %u value %d\n",
4117 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
4121 TRACE("copied %u entries\n", nPairs
);
4125 /*************************************************************
4126 * freetype_get_kerning_pairs
4128 static DWORD
freetype_get_kerning_pairs( struct gdi_font
*font
, KERNINGPAIR
**pairs
)
4130 FT_Face ft_face
= get_ft_face( font
);
4131 DWORD length
, count
= 0;
4133 const struct TT_kern_table
*tt_kern_table
;
4134 const struct TT_kern_subtable
*tt_kern_subtable
;
4136 USHORT
*glyph_to_char
;
4138 length
= freetype_get_font_data(font
, MS_KERN_TAG
, 0, NULL
, 0);
4140 if (length
== GDI_ERROR
)
4142 TRACE("no kerning data in the font\n");
4146 buf
= malloc( length
);
4149 freetype_get_font_data(font
, MS_KERN_TAG
, 0, buf
, length
);
4151 /* build a glyph index to char code map */
4152 glyph_to_char
= calloc( sizeof(USHORT
), 65536 );
4159 if (ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
4165 char_code
= pFT_Get_First_Char(ft_face
, &glyph_code
);
4167 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
4168 ft_face
->num_glyphs
, glyph_code
, char_code
);
4172 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
4174 /* FIXME: This doesn't match what Windows does: it does some fancy
4175 * things with duplicate glyph index to char code mappings, while
4176 * we just avoid overriding existing entries.
4178 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
4179 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
4181 char_code
= pFT_Get_Next_Char(ft_face
, char_code
, &glyph_code
);
4186 DWORD encoding
= RtlUlongByteSwap(ft_face
->charmap
->encoding
);
4189 FIXME("encoding %s not supported\n", debugstr_an((char *)&encoding
, 4));
4190 for (n
= 0; n
<= 65535; n
++)
4191 glyph_to_char
[n
] = (USHORT
)n
;
4194 tt_kern_table
= buf
;
4195 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
4196 TRACE("version %u, nTables %u\n",
4197 GET_BE_WORD(tt_kern_table
->version
), nTables
);
4199 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
4201 for (i
= 0; i
< nTables
; i
++)
4203 struct TT_kern_subtable tt_kern_subtable_copy
;
4205 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
4206 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
4207 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
4209 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
4210 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
4211 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
4213 /* According to the TrueType specification this is the only format
4214 * that will be properly interpreted by Windows and OS/2
4216 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
4218 DWORD new_chunk
, old_total
= count
;
4220 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
4221 glyph_to_char
, NULL
, 0);
4224 *pairs
= realloc( *pairs
, count
* sizeof(**pairs
));
4226 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
4227 glyph_to_char
, *pairs
+ old_total
, new_chunk
);
4230 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
4232 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
4235 free( glyph_to_char
);
4240 static const struct font_backend_funcs font_funcs
=
4242 freetype_load_fonts
,
4243 fontconfig_enum_family_fallbacks
,
4245 freetype_add_mem_font
,
4247 freetype_get_font_data
,
4248 freetype_get_aa_flags
,
4249 freetype_get_glyph_index
,
4250 freetype_get_default_glyph
,
4251 freetype_get_glyph_outline
,
4252 freetype_get_unicode_ranges
,
4253 freetype_get_char_width_info
,
4254 freetype_set_outline_text_metrics
,
4255 freetype_set_bitmap_text_metrics
,
4256 freetype_get_kerning_pairs
,
4257 freetype_destroy_font
4260 const struct font_backend_funcs
*init_freetype_lib(void)
4262 if (!init_freetype()) return NULL
;
4263 #ifdef SONAME_LIBFONTCONFIG
4266 NtQueryDefaultLocale( FALSE
, &system_lcid
);
4270 #else /* HAVE_FREETYPE */
4272 const struct font_backend_funcs
*init_freetype_lib(void)
4277 #endif /* HAVE_FREETYPE */