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>
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 /* __APPLE__ */
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
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 /* __APPLE__ */
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 const LANGID mac_langid_table
[] =
589 MAKELANGID(LANG_ENGLISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ENGLISH */
590 MAKELANGID(LANG_FRENCH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FRENCH */
591 MAKELANGID(LANG_GERMAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GERMAN */
592 MAKELANGID(LANG_ITALIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ITALIAN */
593 MAKELANGID(LANG_DUTCH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_DUTCH */
594 MAKELANGID(LANG_SWEDISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SWEDISH */
595 MAKELANGID(LANG_SPANISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SPANISH */
596 MAKELANGID(LANG_DANISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_DANISH */
597 MAKELANGID(LANG_PORTUGUESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PORTUGUESE */
598 MAKELANGID(LANG_NORWEGIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_NORWEGIAN */
599 MAKELANGID(LANG_HEBREW
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HEBREW */
600 MAKELANGID(LANG_JAPANESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_JAPANESE */
601 MAKELANGID(LANG_ARABIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ARABIC */
602 MAKELANGID(LANG_FINNISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FINNISH */
603 MAKELANGID(LANG_GREEK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GREEK */
604 MAKELANGID(LANG_ICELANDIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ICELANDIC */
605 MAKELANGID(LANG_MALTESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALTESE */
606 MAKELANGID(LANG_TURKISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TURKISH */
607 MAKELANGID(LANG_CROATIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CROATIAN */
608 MAKELANGID(LANG_CHINESE_TRADITIONAL
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CHINESE_TRADITIONAL */
609 MAKELANGID(LANG_URDU
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_URDU */
610 MAKELANGID(LANG_HINDI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HINDI */
611 MAKELANGID(LANG_THAI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_THAI */
612 MAKELANGID(LANG_KOREAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KOREAN */
613 MAKELANGID(LANG_LITHUANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LITHUANIAN */
614 MAKELANGID(LANG_POLISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_POLISH */
615 MAKELANGID(LANG_HUNGARIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HUNGARIAN */
616 MAKELANGID(LANG_ESTONIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ESTONIAN */
617 MAKELANGID(LANG_LATVIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LETTISH */
618 MAKELANGID(LANG_SAMI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SAAMISK */
619 MAKELANGID(LANG_FAEROESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FAEROESE */
620 MAKELANGID(LANG_FARSI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FARSI */
621 MAKELANGID(LANG_RUSSIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_RUSSIAN */
622 MAKELANGID(LANG_CHINESE_SIMPLIFIED
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CHINESE_SIMPLIFIED */
623 MAKELANGID(LANG_DUTCH
,SUBLANG_DUTCH_BELGIAN
), /* TT_MAC_LANGID_FLEMISH */
624 MAKELANGID(LANG_IRISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_IRISH */
625 MAKELANGID(LANG_ALBANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ALBANIAN */
626 MAKELANGID(LANG_ROMANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ROMANIAN */
627 MAKELANGID(LANG_CZECH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CZECH */
628 MAKELANGID(LANG_SLOVAK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SLOVAK */
629 MAKELANGID(LANG_SLOVENIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SLOVENIAN */
630 0, /* TT_MAC_LANGID_YIDDISH */
631 MAKELANGID(LANG_SERBIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SERBIAN */
632 MAKELANGID(LANG_MACEDONIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MACEDONIAN */
633 MAKELANGID(LANG_BULGARIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BULGARIAN */
634 MAKELANGID(LANG_UKRAINIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UKRAINIAN */
635 MAKELANGID(LANG_BELARUSIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BYELORUSSIAN */
636 MAKELANGID(LANG_UZBEK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UZBEK */
637 MAKELANGID(LANG_KAZAK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KAZAKH */
638 MAKELANGID(LANG_AZERI
,SUBLANG_AZERI_CYRILLIC
), /* TT_MAC_LANGID_AZERBAIJANI */
639 0, /* TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT */
640 MAKELANGID(LANG_ARMENIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ARMENIAN */
641 MAKELANGID(LANG_GEORGIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GEORGIAN */
642 0, /* TT_MAC_LANGID_MOLDAVIAN */
643 MAKELANGID(LANG_KYRGYZ
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KIRGHIZ */
644 MAKELANGID(LANG_TAJIK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TAJIKI */
645 MAKELANGID(LANG_TURKMEN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TURKMEN */
646 MAKELANGID(LANG_MONGOLIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MONGOLIAN */
647 MAKELANGID(LANG_MONGOLIAN
,SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA
), /* TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT */
648 MAKELANGID(LANG_PASHTO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PASHTO */
649 0, /* TT_MAC_LANGID_KURDISH */
650 MAKELANGID(LANG_KASHMIRI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KASHMIRI */
651 MAKELANGID(LANG_SINDHI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SINDHI */
652 MAKELANGID(LANG_TIBETAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TIBETAN */
653 MAKELANGID(LANG_NEPALI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_NEPALI */
654 MAKELANGID(LANG_SANSKRIT
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SANSKRIT */
655 MAKELANGID(LANG_MARATHI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MARATHI */
656 MAKELANGID(LANG_BENGALI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BENGALI */
657 MAKELANGID(LANG_ASSAMESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ASSAMESE */
658 MAKELANGID(LANG_GUJARATI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GUJARATI */
659 MAKELANGID(LANG_PUNJABI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PUNJABI */
660 MAKELANGID(LANG_ORIYA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ORIYA */
661 MAKELANGID(LANG_MALAYALAM
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAYALAM */
662 MAKELANGID(LANG_KANNADA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KANNADA */
663 MAKELANGID(LANG_TAMIL
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TAMIL */
664 MAKELANGID(LANG_TELUGU
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TELUGU */
665 MAKELANGID(LANG_SINHALESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SINHALESE */
666 0, /* TT_MAC_LANGID_BURMESE */
667 MAKELANGID(LANG_KHMER
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KHMER */
668 MAKELANGID(LANG_LAO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LAO */
669 MAKELANGID(LANG_VIETNAMESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_VIETNAMESE */
670 MAKELANGID(LANG_INDONESIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_INDONESIAN */
671 0, /* TT_MAC_LANGID_TAGALOG */
672 MAKELANGID(LANG_MALAY
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAY_ROMAN_SCRIPT */
673 0, /* TT_MAC_LANGID_MALAY_ARABIC_SCRIPT */
674 MAKELANGID(LANG_AMHARIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_AMHARIC */
675 MAKELANGID(LANG_TIGRIGNA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TIGRINYA */
676 0, /* TT_MAC_LANGID_GALLA */
677 0, /* TT_MAC_LANGID_SOMALI */
678 MAKELANGID(LANG_SWAHILI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SWAHILI */
679 0, /* TT_MAC_LANGID_RUANDA */
680 0, /* TT_MAC_LANGID_RUNDI */
681 0, /* TT_MAC_LANGID_CHEWA */
682 0, /* TT_MAC_LANGID_MALAGASY */
683 0, /* TT_MAC_LANGID_ESPERANTO */
684 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 95-111 */
685 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 112-127 */
686 MAKELANGID(LANG_WELSH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_WELSH */
687 MAKELANGID(LANG_BASQUE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BASQUE */
688 MAKELANGID(LANG_CATALAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CATALAN */
689 0, /* TT_MAC_LANGID_LATIN */
690 MAKELANGID(LANG_QUECHUA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_QUECHUA */
691 0, /* TT_MAC_LANGID_GUARANI */
692 0, /* TT_MAC_LANGID_AYMARA */
693 MAKELANGID(LANG_TATAR
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TATAR */
694 MAKELANGID(LANG_UIGHUR
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UIGHUR */
695 0, /* TT_MAC_LANGID_DZONGKHA */
696 0, /* TT_MAC_LANGID_JAVANESE */
697 0, /* TT_MAC_LANGID_SUNDANESE */
698 MAKELANGID(LANG_GALICIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GALICIAN */
699 MAKELANGID(LANG_AFRIKAANS
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_AFRIKAANS */
700 MAKELANGID(LANG_BRETON
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BRETON */
701 MAKELANGID(LANG_INUKTITUT
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_INUKTITUT */
702 MAKELANGID(LANG_SCOTTISH_GAELIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SCOTTISH_GAELIC */
703 0, /* TT_MAC_LANGID_MANX_GAELIC */
704 MAKELANGID(LANG_IRISH
,SUBLANG_IRISH_IRELAND
), /* TT_MAC_LANGID_IRISH_GAELIC */
705 0, /* TT_MAC_LANGID_TONGAN */
706 0, /* TT_MAC_LANGID_GREEK_POLYTONIC */
707 MAKELANGID(LANG_GREENLANDIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GREELANDIC */
708 MAKELANGID(LANG_AZERI
,SUBLANG_AZERI_LATIN
), /* TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT */
711 static CPTABLEINFO
*get_mac_code_page( const FT_SfntName
*name
)
713 int id
= name
->encoding_id
;
715 if (name
->encoding_id
== TT_MAC_ID_SIMPLIFIED_CHINESE
) id
= 8; /* special case */
716 return get_cptable( 10000 + id
);
719 static int match_name_table_language( const FT_SfntName
*name
, LANGID lang
)
724 switch (name
->platform_id
)
726 case TT_PLATFORM_MICROSOFT
:
727 res
+= 5; /* prefer the Microsoft name */
728 switch (name
->encoding_id
)
730 case TT_MS_ID_UNICODE_CS
:
731 case TT_MS_ID_SYMBOL_CS
:
732 name_lang
= name
->language_id
;
738 case TT_PLATFORM_MACINTOSH
:
739 if (!get_mac_code_page( name
)) return 0;
740 if (name
->language_id
>= ARRAY_SIZE( mac_langid_table
)) return 0;
741 name_lang
= mac_langid_table
[name
->language_id
];
743 case TT_PLATFORM_APPLE_UNICODE
:
744 res
+= 2; /* prefer Unicode encodings */
745 switch (name
->encoding_id
)
747 case TT_APPLE_ID_DEFAULT
:
748 case TT_APPLE_ID_ISO_10646
:
749 case TT_APPLE_ID_UNICODE_2_0
:
750 if (name
->language_id
>= ARRAY_SIZE( mac_langid_table
)) return 0;
751 name_lang
= mac_langid_table
[name
->language_id
];
760 if (name_lang
== lang
) res
+= 30;
761 else if (PRIMARYLANGID( name_lang
) == PRIMARYLANGID( lang
)) res
+= 20;
762 else if (name_lang
== MAKELANGID( LANG_ENGLISH
, SUBLANG_DEFAULT
)) res
+= 10;
763 else if (lang
== MAKELANGID( LANG_NEUTRAL
, SUBLANG_NEUTRAL
)) res
+= 5 * (0x100000 - name_lang
);
767 static WCHAR
*copy_name_table_string( const FT_SfntName
*name
)
773 switch (name
->platform_id
)
775 case TT_PLATFORM_APPLE_UNICODE
:
776 case TT_PLATFORM_MICROSOFT
:
777 ret
= malloc( name
->string_len
+ sizeof(WCHAR
) );
778 for (i
= 0; i
< name
->string_len
/ 2; i
++)
779 ret
[i
] = (name
->string
[i
* 2] << 8) | name
->string
[i
* 2 + 1];
782 case TT_PLATFORM_MACINTOSH
:
783 if (!(cp
= get_mac_code_page( name
))) return NULL
;
784 ret
= malloc( (name
->string_len
+ 1) * sizeof(WCHAR
) );
785 i
= win32u_mbtowc( cp
, ret
, name
->string_len
, (char *)name
->string
, name
->string_len
);
792 static WCHAR
*get_face_name(FT_Face ft_face
, FT_UShort name_id
, LANGID language_id
)
795 FT_UInt num_names
, name_index
;
796 int res
, best_lang
= 0, best_index
= -1;
798 if (!FT_IS_SFNT(ft_face
)) return NULL
;
800 num_names
= pFT_Get_Sfnt_Name_Count( ft_face
);
802 for (name_index
= 0; name_index
< num_names
; name_index
++)
804 if (pFT_Get_Sfnt_Name( ft_face
, name_index
, &name
)) continue;
805 if (name
.name_id
!= name_id
) continue;
806 res
= match_name_table_language( &name
, language_id
);
810 best_index
= name_index
;
814 if (best_index
!= -1 && !pFT_Get_Sfnt_Name( ft_face
, best_index
, &name
))
816 WCHAR
*ret
= copy_name_table_string( &name
);
817 TRACE( "name %u found platform %u lang %04x %s\n",
818 name_id
, name
.platform_id
, name
.language_id
, debugstr_w( ret
));
824 static WCHAR
*ft_face_get_family_name( FT_Face ft_face
, LANGID langid
)
828 if ((family_name
= get_face_name( ft_face
, TT_NAME_ID_FONT_FAMILY
, langid
)))
831 return towstr( ft_face
->family_name
);
834 static WCHAR
*ft_face_get_style_name( FT_Face ft_face
, LANGID langid
)
838 if ((style_name
= get_face_name( ft_face
, TT_NAME_ID_FONT_SUBFAMILY
, langid
)))
841 return towstr( ft_face
->style_name
);
844 static WCHAR
*ft_face_get_full_name( FT_Face ft_face
, LANGID langid
)
846 static const WCHAR space_w
[] = {' ',0};
847 WCHAR
*full_name
, *style_name
;
850 if ((full_name
= get_face_name( ft_face
, TT_NAME_ID_FULL_NAME
, langid
)))
853 full_name
= ft_face_get_family_name( ft_face
, langid
);
854 style_name
= ft_face_get_style_name( ft_face
, langid
);
856 length
= lstrlenW( full_name
) + lstrlenW( space_w
) + lstrlenW( style_name
) + 1;
857 full_name
= realloc( full_name
, length
* sizeof(WCHAR
) );
859 lstrcatW( full_name
, space_w
);
860 lstrcatW( full_name
, style_name
);
863 WARN( "full name not found, using %s instead\n", debugstr_w(full_name
) );
867 static inline FT_Fixed
get_font_version( FT_Face ft_face
)
869 FT_Fixed version
= 0;
872 header
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_head
);
873 if (header
) version
= header
->Font_Revision
;
878 static inline DWORD
get_ntm_flags( FT_Face ft_face
)
881 FT_ULong table_size
= 0;
882 FT_WinFNT_HeaderRec winfnt_header
;
884 if (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) flags
|= NTM_ITALIC
;
885 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
) flags
|= NTM_BOLD
;
887 /* fixup the flag for our fake-bold implementation. */
888 if (!FT_IS_SCALABLE( ft_face
) &&
889 !pFT_Get_WinFNT_Header( ft_face
, &winfnt_header
) &&
890 winfnt_header
.weight
> FW_NORMAL
)
893 if (flags
== 0) flags
= NTM_REGULAR
;
895 if (!pFT_Load_Sfnt_Table( ft_face
, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL
, &table_size
))
896 flags
|= NTM_PS_OPENTYPE
;
901 static inline void get_bitmap_size( FT_Face ft_face
, struct bitmap_font_size
*face_size
)
903 My_FT_Bitmap_Size
*size
;
904 FT_WinFNT_HeaderRec winfnt_header
;
906 size
= (My_FT_Bitmap_Size
*)ft_face
->available_sizes
;
907 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
908 size
->height
, size
->width
, size
->size
>> 6,
909 size
->x_ppem
>> 6, size
->y_ppem
>> 6);
910 face_size
->height
= size
->height
;
911 face_size
->width
= size
->width
;
912 face_size
->size
= size
->size
;
913 face_size
->x_ppem
= size
->x_ppem
;
914 face_size
->y_ppem
= size
->y_ppem
;
916 if (!pFT_Get_WinFNT_Header( ft_face
, &winfnt_header
)) {
917 face_size
->internal_leading
= winfnt_header
.internal_leading
;
918 if (winfnt_header
.external_leading
> 0 &&
919 (face_size
->height
==
920 winfnt_header
.pixel_height
+ winfnt_header
.external_leading
))
921 face_size
->height
= winfnt_header
.pixel_height
;
925 static inline void get_fontsig( FT_Face ft_face
, FONTSIGNATURE
*fs
)
928 FT_WinFNT_HeaderRec winfnt_header
;
931 memset( fs
, 0, sizeof(*fs
) );
933 os2
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_os2
);
936 fs
->fsUsb
[0] = os2
->ulUnicodeRange1
;
937 fs
->fsUsb
[1] = os2
->ulUnicodeRange2
;
938 fs
->fsUsb
[2] = os2
->ulUnicodeRange3
;
939 fs
->fsUsb
[3] = os2
->ulUnicodeRange4
;
941 if (os2
->version
== 0)
943 if (os2
->usFirstCharIndex
>= 0xf000 && os2
->usFirstCharIndex
< 0xf100)
944 fs
->fsCsb
[0] = FS_SYMBOL
;
946 fs
->fsCsb
[0] = FS_LATIN1
;
950 fs
->fsCsb
[0] = os2
->ulCodePageRange1
;
951 fs
->fsCsb
[1] = os2
->ulCodePageRange2
;
956 if (!pFT_Get_WinFNT_Header( ft_face
, &winfnt_header
))
958 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header
.pixel_height
, winfnt_header
.charset
,
959 winfnt_header
.vertical_resolution
,winfnt_header
.horizontal_resolution
, winfnt_header
.nominal_point_size
);
960 switch (winfnt_header
.charset
)
962 case ANSI_CHARSET
: fs
->fsCsb
[0] = FS_LATIN1
; break;
963 case EASTEUROPE_CHARSET
: fs
->fsCsb
[0] = FS_LATIN2
; break;
964 case RUSSIAN_CHARSET
: fs
->fsCsb
[0] = FS_CYRILLIC
; break;
965 case GREEK_CHARSET
: fs
->fsCsb
[0] = FS_GREEK
; break;
966 case TURKISH_CHARSET
: fs
->fsCsb
[0] = FS_TURKISH
; break;
967 case HEBREW_CHARSET
: fs
->fsCsb
[0] = FS_HEBREW
; break;
968 case ARABIC_CHARSET
: fs
->fsCsb
[0] = FS_ARABIC
; break;
969 case BALTIC_CHARSET
: fs
->fsCsb
[0] = FS_BALTIC
; break;
970 case VIETNAMESE_CHARSET
: fs
->fsCsb
[0] = FS_VIETNAMESE
; break;
971 case THAI_CHARSET
: fs
->fsCsb
[0] = FS_THAI
; break;
972 case SHIFTJIS_CHARSET
: fs
->fsCsb
[0] = FS_JISJAPAN
; break;
973 case GB2312_CHARSET
: fs
->fsCsb
[0] = FS_CHINESESIMP
; break;
974 case HANGEUL_CHARSET
: fs
->fsCsb
[0] = FS_WANSUNG
; break;
975 case CHINESEBIG5_CHARSET
: fs
->fsCsb
[0] = FS_CHINESETRAD
; break;
976 case JOHAB_CHARSET
: fs
->fsCsb
[0] = FS_JOHAB
; break;
977 case SYMBOL_CHARSET
: fs
->fsCsb
[0] = FS_SYMBOL
; break;
982 if (fs
->fsCsb
[0] == 0)
984 /* let's see if we can find any interesting cmaps */
985 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
987 switch (ft_face
->charmaps
[i
]->encoding
)
989 case FT_ENCODING_UNICODE
:
990 case FT_ENCODING_APPLE_ROMAN
:
991 fs
->fsCsb
[0] |= FS_LATIN1
;
993 case FT_ENCODING_MS_SYMBOL
:
994 fs
->fsCsb
[0] |= FS_SYMBOL
;
1003 static FT_Face
new_ft_face( const char *file
, void *font_data_ptr
, UINT font_data_size
,
1004 FT_Long face_index
, BOOL allow_bitmap
)
1012 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
1013 err
= pFT_New_Face(library
, file
, face_index
, &ft_face
);
1017 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr
, font_data_size
, face_index
);
1018 err
= pFT_New_Memory_Face(library
, font_data_ptr
, font_data_size
, face_index
, &ft_face
);
1023 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file
), font_data_ptr
, err
);
1027 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1028 if (!FT_IS_SCALABLE( ft_face
) && FT_SimpleVersion
< FT_VERSION_VALUE(2, 1, 9))
1030 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1034 if (!FT_IS_SFNT( ft_face
))
1036 if (FT_IS_SCALABLE( ft_face
) || !allow_bitmap
)
1038 WARN("Ignoring font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1044 if (!(pOS2
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_os2
)) ||
1045 !pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_hhea
) ||
1046 !pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_head
))
1048 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1049 "Skipping this font.\n", debugstr_a(file
), font_data_ptr
);
1053 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1054 we don't want to load these. */
1055 if (!memcmp( pOS2
->achVendID
, "Wine", sizeof(pOS2
->achVendID
) ))
1059 if (!pFT_Load_Sfnt_Table( ft_face
, FT_MAKE_TAG('E','B','S','C'), 0, NULL
, &len
))
1061 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file
));
1067 if (!ft_face
->family_name
|| !ft_face
->style_name
)
1069 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file
), font_data_ptr
);
1075 pFT_Done_Face( ft_face
);
1079 struct family_names_data
1081 LANGID primary_langid
;
1082 struct opentype_name family_name
;
1083 struct opentype_name second_name
;
1088 static BOOL
search_family_names_callback( LANGID langid
, struct opentype_name
*name
, void *user
)
1090 struct family_names_data
*data
= user
;
1092 if (langid
== MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
))
1094 data
->english_seen
= TRUE
;
1095 if (data
->primary_langid
== langid
) data
->primary_seen
= TRUE
;
1097 if (!data
->family_name
.bytes
) data
->family_name
= *name
;
1098 else if (data
->primary_langid
!= langid
) data
->second_name
= *name
;
1100 else if (data
->primary_langid
== langid
)
1102 data
->primary_seen
= TRUE
;
1103 if (data
->family_name
.bytes
) data
->second_name
= data
->family_name
;
1104 data
->family_name
= *name
;
1106 else if (!data
->second_name
.bytes
) data
->second_name
= *name
;
1108 if (data
->family_name
.bytes
&& data
->second_name
.bytes
&& data
->primary_seen
&& data
->english_seen
)
1113 struct face_name_data
1115 LANGID primary_langid
;
1116 struct opentype_name face_name
;
1119 static BOOL
search_face_name_callback( LANGID langid
, struct opentype_name
*name
, void *user
)
1121 struct face_name_data
*data
= user
;
1123 if (langid
== data
->primary_langid
|| (langid
== MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
) && !data
->face_name
.bytes
))
1124 data
->face_name
= *name
;
1126 return langid
== data
->primary_langid
;
1129 static WCHAR
*decode_opentype_name( struct opentype_name
*name
)
1134 if (!name
->codepage
)
1136 len
= min( ARRAY_SIZE(buffer
), name
->length
/ sizeof(WCHAR
) );
1137 while (len
--) buffer
[len
] = GET_BE_WORD( ((WORD
*)name
->bytes
)[len
] );
1138 len
= min( ARRAY_SIZE(buffer
), name
->length
/ sizeof(WCHAR
) );
1142 CPTABLEINFO
*cptable
= get_cptable( name
->codepage
);
1143 if (!cptable
) return NULL
;
1144 len
= win32u_mbtowc( cptable
, buffer
, ARRAY_SIZE(buffer
), name
->bytes
, name
->length
);
1147 buffer
[ARRAY_SIZE(buffer
) - 1] = 0;
1148 if (len
== ARRAY_SIZE(buffer
)) WARN("Truncated font name %s -> %s\n", debugstr_an(name
->bytes
, name
->length
), debugstr_w(buffer
));
1149 else buffer
[len
] = 0;
1151 return wcsdup( buffer
);
1166 struct bitmap_font_size size
;
1169 static struct unix_face
*unix_face_create( const char *unix_name
, void *data_ptr
, UINT data_size
,
1170 UINT face_index
, UINT flags
)
1172 static const WCHAR space_w
[] = {' ',0};
1174 const struct ttc_sfnt_v1
*ttc_sfnt_v1
;
1175 const struct tt_name_v0
*tt_name_v0
;
1176 struct unix_face
*This
;
1181 TRACE( "unix_name %s, face_index %u, data_ptr %p, data_size %u, flags %#x\n",
1182 unix_name
, face_index
, data_ptr
, data_size
, flags
);
1186 if ((fd
= open( unix_name
, O_RDONLY
)) == -1) return NULL
;
1187 if (fstat( fd
, &st
) == -1)
1192 data_size
= st
.st_size
;
1193 data_ptr
= mmap( NULL
, data_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0 );
1195 if (data_ptr
== MAP_FAILED
) return NULL
;
1198 if (!(This
= calloc( 1, sizeof(*This
) ))) goto done
;
1200 if (opentype_get_ttc_sfnt_v1( data_ptr
, data_size
, face_index
, &face_count
, &ttc_sfnt_v1
) &&
1201 opentype_get_tt_name_v0( data_ptr
, data_size
, ttc_sfnt_v1
, &tt_name_v0
) &&
1202 opentype_get_properties( data_ptr
, data_size
, ttc_sfnt_v1
, &This
->font_version
,
1203 &This
->fs
, &This
->ntm_flags
))
1205 struct family_names_data family_names
;
1206 struct face_name_data style_name
;
1207 struct face_name_data full_name
;
1208 LANGID primary_langid
= system_lcid
;
1210 This
->scalable
= TRUE
;
1211 This
->num_faces
= face_count
;
1213 memset( &family_names
, 0, sizeof(family_names
) );
1214 family_names
.primary_langid
= primary_langid
;
1215 opentype_enum_family_names( tt_name_v0
, search_family_names_callback
, &family_names
);
1216 This
->family_name
= decode_opentype_name( &family_names
.family_name
);
1217 This
->second_name
= decode_opentype_name( &family_names
.second_name
);
1219 memset( &style_name
, 0, sizeof(style_name
) );
1220 style_name
.primary_langid
= primary_langid
;
1221 opentype_enum_style_names( tt_name_v0
, search_face_name_callback
, &style_name
);
1222 This
->style_name
= decode_opentype_name( &style_name
.face_name
);
1224 memset( &full_name
, 0, sizeof(full_name
) );
1225 full_name
.primary_langid
= primary_langid
;
1226 opentype_enum_full_names( tt_name_v0
, search_face_name_callback
, &full_name
);
1227 This
->full_name
= decode_opentype_name( &full_name
.face_name
);
1229 TRACE( "parsed font names family_name %s, second_name %s, primary_seen %d, english_seen %d, "
1230 "full_name %s, style_name %s\n",
1231 debugstr_w(This
->family_name
), debugstr_w(This
->second_name
),
1232 family_names
.primary_seen
, family_names
.english_seen
,
1233 debugstr_w(This
->full_name
), debugstr_w(This
->style_name
) );
1235 if (!This
->full_name
&& This
->family_name
&& This
->style_name
)
1237 length
= lstrlenW( This
->family_name
) + lstrlenW( space_w
) + lstrlenW( This
->style_name
) + 1;
1238 This
->full_name
= malloc( length
* sizeof(WCHAR
) );
1239 lstrcpyW( This
->full_name
, This
->family_name
);
1240 lstrcatW( This
->full_name
, space_w
);
1241 lstrcatW( This
->full_name
, This
->style_name
);
1242 WARN( "full name not found, using %s instead\n", debugstr_w(This
->full_name
) );
1245 else if ((This
->ft_face
= new_ft_face( unix_name
, data_ptr
, data_size
, face_index
, flags
& ADDFONT_ALLOW_BITMAP
)))
1247 WARN( "unable to parse font, falling back to FreeType\n" );
1248 This
->scalable
= FT_IS_SCALABLE( This
->ft_face
);
1249 This
->num_faces
= This
->ft_face
->num_faces
;
1251 This
->family_name
= ft_face_get_family_name( This
->ft_face
, system_lcid
);
1252 This
->second_name
= ft_face_get_family_name( This
->ft_face
, MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
) );
1254 /* try to find another secondary name, preferring the lowest langids */
1255 if (!wcsicmp( This
->family_name
, This
->second_name
))
1257 free( This
->second_name
);
1258 This
->second_name
= ft_face_get_family_name( This
->ft_face
, MAKELANGID(LANG_NEUTRAL
, SUBLANG_NEUTRAL
) );
1259 if (!wcsicmp( This
->family_name
, This
->second_name
))
1261 free( This
->second_name
);
1262 This
->second_name
= NULL
;
1266 This
->style_name
= ft_face_get_style_name( This
->ft_face
, system_lcid
);
1267 This
->full_name
= ft_face_get_full_name( This
->ft_face
, system_lcid
);
1269 This
->ntm_flags
= get_ntm_flags( This
->ft_face
);
1270 This
->font_version
= get_font_version( This
->ft_face
);
1271 if (!This
->scalable
) get_bitmap_size( This
->ft_face
, &This
->size
);
1272 get_fontsig( This
->ft_face
, &This
->fs
);
1281 if (unix_name
) munmap( data_ptr
, data_size
);
1285 static void unix_face_destroy( struct unix_face
*This
)
1287 if (This
->ft_face
) pFT_Done_Face( This
->ft_face
);
1288 free( This
->full_name
);
1289 free( This
->style_name
);
1290 free( This
->second_name
);
1291 free( This
->family_name
);
1295 static int add_unix_face( const char *unix_name
, const WCHAR
*file
, void *data_ptr
, SIZE_T data_size
,
1296 DWORD face_index
, DWORD flags
, DWORD
*num_faces
)
1298 struct unix_face
*unix_face
;
1301 if (num_faces
) *num_faces
= 0;
1303 if (!(unix_face
= unix_face_create( unix_name
, data_ptr
, data_size
, face_index
, flags
)))
1306 if (unix_face
->family_name
[0] == '.') /* Ignore fonts with names beginning with a dot */
1308 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(unix_name
));
1309 unix_face_destroy( unix_face
);
1313 if (!HIWORD( flags
)) flags
|= ADDFONT_AA_FLAGS( default_aa_flags
);
1315 ret
= add_gdi_face( unix_face
->family_name
, unix_face
->second_name
, unix_face
->style_name
, unix_face
->full_name
,
1316 file
, data_ptr
, data_size
, face_index
, unix_face
->fs
, unix_face
->ntm_flags
,
1317 unix_face
->font_version
, flags
, unix_face
->scalable
? NULL
: &unix_face
->size
);
1319 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1320 (int)unix_face
->fs
.fsCsb
[0], (int)unix_face
->fs
.fsCsb
[1],
1321 (int)unix_face
->fs
.fsUsb
[0], (int)unix_face
->fs
.fsUsb
[1],
1322 (int)unix_face
->fs
.fsUsb
[2], (int)unix_face
->fs
.fsUsb
[3]);
1324 if (num_faces
) *num_faces
= unix_face
->num_faces
;
1325 unix_face_destroy( unix_face
);
1329 static WCHAR
*get_dos_file_name( LPCSTR str
)
1332 ULONG len
= strlen(str
) + 1;
1334 len
+= 8; /* \??\unix prefix */
1335 if (!(buffer
= malloc( len
* sizeof(WCHAR
) ))) return NULL
;
1336 if (wine_unix_to_nt_file_name( str
, buffer
, &len
))
1344 static char *get_unix_file_name( LPCWSTR path
)
1346 UNICODE_STRING nt_name
;
1347 OBJECT_ATTRIBUTES attr
;
1352 nt_name
.Buffer
= (WCHAR
*)path
;
1353 nt_name
.MaximumLength
= nt_name
.Length
= lstrlenW( path
) * sizeof(WCHAR
);
1354 InitializeObjectAttributes( &attr
, &nt_name
, 0, 0, NULL
);
1357 if (!(buffer
= malloc( size
))) return NULL
;
1358 status
= wine_nt_to_unix_file_name( &attr
, buffer
, &size
, FILE_OPEN_IF
);
1359 if (status
!= STATUS_BUFFER_TOO_SMALL
) break;
1362 if (status
&& status
!= STATUS_NO_SUCH_FILE
)
1370 static INT
AddFontToList(const WCHAR
*dos_name
, const char *unix_name
, void *font_data_ptr
,
1371 UINT font_data_size
, UINT flags
)
1373 DWORD face_index
= 0, num_faces
;
1375 WCHAR
*filename
= NULL
;
1377 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1378 assert(unix_name
|| !(flags
& ADDFONT_EXTERNAL_FONT
));
1383 char **mac_list
= expand_mac_font(unix_name
);
1386 BOOL had_one
= FALSE
;
1388 for(cursor
= mac_list
; *cursor
; cursor
++)
1391 AddFontToList(NULL
, *cursor
, NULL
, 0, flags
);
1399 #endif /* __APPLE__ */
1401 if (!dos_name
&& unix_name
) dos_name
= filename
= get_dos_file_name( unix_name
);
1404 ret
+= add_unix_face( unix_name
, dos_name
, font_data_ptr
, font_data_size
, face_index
, flags
, &num_faces
);
1405 while (num_faces
> ++face_index
);
1411 /*************************************************************
1414 static INT
freetype_add_font( const WCHAR
*file
, UINT flags
)
1417 char *unixname
= get_unix_file_name( file
);
1421 ret
= AddFontToList( file
, unixname
, NULL
, 0, flags
);
1427 /*************************************************************
1428 * freetype_add_mem_font
1430 static INT
freetype_add_mem_font( void *ptr
, SIZE_T size
, UINT flags
)
1432 return AddFontToList( NULL
, NULL
, ptr
, size
, flags
);
1436 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
1439 struct dirent
*dent
;
1440 char path
[MAX_PATH
];
1442 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
1444 dir
= opendir(dirname
);
1446 WARN("Can't open directory %s\n", debugstr_a(dirname
));
1449 while((dent
= readdir(dir
)) != NULL
) {
1450 struct stat statbuf
;
1452 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
1455 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
1457 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
1459 if(stat(path
, &statbuf
) == -1)
1461 WARN("Can't stat %s\n", debugstr_a(path
));
1464 if(S_ISDIR(statbuf
.st_mode
))
1465 ReadFontDir(path
, external_fonts
);
1468 DWORD addfont_flags
= 0;
1469 if(external_fonts
) addfont_flags
|= ADDFONT_EXTERNAL_FONT
;
1470 AddFontToList(NULL
, path
, NULL
, 0, addfont_flags
);
1478 #ifdef SONAME_LIBFONTCONFIG
1480 static BOOL fontconfig_enabled
;
1481 static FcPattern
*pattern_serif
;
1482 static FcPattern
*pattern_fixed
;
1483 static FcPattern
*pattern_sans
;
1485 static UINT
parse_aa_pattern( FcPattern
*pattern
)
1491 if (pFcPatternGetBool( pattern
, FC_ANTIALIAS
, 0, &antialias
) == FcResultMatch
)
1492 aa_flags
= antialias
? GGO_GRAY4_BITMAP
: GGO_BITMAP
;
1494 if (pFcPatternGetInteger( pattern
, FC_RGBA
, 0, &rgba
) == FcResultMatch
)
1498 case FC_RGBA_RGB
: aa_flags
= WINE_GGO_HRGB_BITMAP
; break;
1499 case FC_RGBA_BGR
: aa_flags
= WINE_GGO_HBGR_BITMAP
; break;
1500 case FC_RGBA_VRGB
: aa_flags
= WINE_GGO_VRGB_BITMAP
; break;
1501 case FC_RGBA_VBGR
: aa_flags
= WINE_GGO_VBGR_BITMAP
; break;
1502 case FC_RGBA_NONE
: aa_flags
= aa_flags
? aa_flags
: GGO_GRAY4_BITMAP
; break;
1508 static FcPattern
*create_family_pattern( const char *name
, FcPattern
**cached
)
1510 FcPattern
*ret
= NULL
, *tmp
, *pattern
;
1512 if (*cached
) return *cached
;
1513 pattern
= pFcPatternCreate();
1514 pFcPatternAddString( pattern
, FC_FAMILY
, (const FcChar8
*)name
);
1515 pFcPatternAddString( pattern
, FC_NAMELANG
, (const FcChar8
*)"en-us" );
1516 pFcPatternAddString( pattern
, FC_PRGNAME
, (const FcChar8
*)"wine" );
1517 pFcConfigSubstitute( NULL
, pattern
, FcMatchPattern
);
1518 pFcDefaultSubstitute( pattern
);
1519 tmp
= pFcFontMatch( NULL
, pattern
, &result
);
1520 pFcPatternDestroy( pattern
);
1521 if (result
!= FcResultMatch
) pFcPatternDestroy( tmp
);
1522 else if ((ret
= InterlockedCompareExchangePointer( (void **)cached
, tmp
, NULL
))) pFcPatternDestroy( tmp
);
1527 static void fontconfig_add_font( FcPattern
*pattern
, UINT flags
)
1529 const char *unix_name
, *format
;
1535 TRACE( "(%p %#x)\n", pattern
, flags
);
1537 if (pFcPatternGetString( pattern
, FC_FILE
, 0, (FcChar8
**)&unix_name
) != FcResultMatch
)
1540 if (pFcPatternGetBool( pattern
, FC_SCALABLE
, 0, &scalable
) != FcResultMatch
)
1543 if (pFcPatternGetString( pattern
, FC_FONTFORMAT
, 0, (FcChar8
**)&format
) != FcResultMatch
)
1545 TRACE( "ignoring unknown font format %s\n", debugstr_a(unix_name
) );
1549 if (!strcmp( format
, "Type 1" ))
1551 TRACE( "ignoring Type 1 font %s\n", debugstr_a(unix_name
) );
1555 if (!scalable
&& !(flags
& ADDFONT_ALLOW_BITMAP
))
1557 TRACE( "ignoring non-scalable font %s\n", debugstr_a(unix_name
) );
1561 if (!(aa_flags
= parse_aa_pattern( pattern
))) aa_flags
= default_aa_flags
;
1562 flags
|= ADDFONT_AA_FLAGS(aa_flags
);
1564 if (pFcPatternGetInteger( pattern
, FC_INDEX
, 0, &face_index
) != FcResultMatch
)
1567 dos_name
= get_dos_file_name( unix_name
);
1568 add_unix_face( unix_name
, dos_name
, NULL
, 0, face_index
, flags
, NULL
);
1572 static void init_fontconfig(void)
1574 void *fc_handle
= dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
);
1578 TRACE("Wine cannot find the fontconfig library (%s).\n", SONAME_LIBFONTCONFIG
);
1582 #define LOAD_FUNCPTR(f) if((p##f = dlsym(fc_handle, #f)) == NULL){WARN("Can't find symbol %s\n", #f); return;}
1583 LOAD_FUNCPTR(FcConfigSubstitute
);
1584 LOAD_FUNCPTR(FcDefaultSubstitute
);
1585 LOAD_FUNCPTR(FcFontList
);
1586 LOAD_FUNCPTR(FcFontMatch
);
1587 LOAD_FUNCPTR(FcFontSetDestroy
);
1588 LOAD_FUNCPTR(FcInit
);
1589 LOAD_FUNCPTR(FcPatternAddString
);
1590 LOAD_FUNCPTR(FcPatternCreate
);
1591 LOAD_FUNCPTR(FcPatternDestroy
);
1592 LOAD_FUNCPTR(FcPatternGetBool
);
1593 LOAD_FUNCPTR(FcPatternGetInteger
);
1594 LOAD_FUNCPTR(FcPatternGetString
);
1595 LOAD_FUNCPTR(FcConfigGetFontDirs
);
1596 LOAD_FUNCPTR(FcConfigGetCurrent
);
1597 LOAD_FUNCPTR(FcCacheCopySet
);
1598 LOAD_FUNCPTR(FcCacheNumSubdir
);
1599 LOAD_FUNCPTR(FcCacheSubdir
);
1600 LOAD_FUNCPTR(FcDirCacheRead
);
1601 LOAD_FUNCPTR(FcDirCacheUnload
);
1602 LOAD_FUNCPTR(FcStrListCreate
);
1603 LOAD_FUNCPTR(FcStrListDone
);
1604 LOAD_FUNCPTR(FcStrListNext
);
1605 LOAD_FUNCPTR(FcStrSetAdd
);
1606 LOAD_FUNCPTR(FcStrSetCreate
);
1607 LOAD_FUNCPTR(FcStrSetDestroy
);
1608 LOAD_FUNCPTR(FcStrSetMember
);
1613 FcPattern
*pattern
= pFcPatternCreate();
1614 pFcConfigSubstitute( NULL
, pattern
, FcMatchFont
);
1615 default_aa_flags
= parse_aa_pattern( pattern
);
1616 pFcPatternDestroy( pattern
);
1618 if (!default_aa_flags
)
1620 FcPattern
*pattern
= pFcPatternCreate();
1621 pFcConfigSubstitute( NULL
, pattern
, FcMatchPattern
);
1622 default_aa_flags
= parse_aa_pattern( pattern
);
1623 pFcPatternDestroy( pattern
);
1626 TRACE( "enabled, default flags = %x\n", default_aa_flags
);
1627 fontconfig_enabled
= TRUE
;
1631 static void fontconfig_add_fonts_from_dir_list( FcConfig
*config
, FcStrList
*dir_list
, FcStrSet
*done_set
, UINT flags
)
1634 FcFontSet
*font_set
= NULL
;
1635 FcStrList
*subdir_list
= NULL
;
1636 FcStrSet
*subdir_set
= NULL
;
1637 FcCache
*cache
= NULL
;
1640 TRACE( "(%p %p %p %#x)\n", config
, dir_list
, done_set
, flags
);
1642 while ((dir
= pFcStrListNext( dir_list
)))
1644 if (pFcStrSetMember( done_set
, dir
)) continue;
1646 TRACE( "adding fonts from %s\n", dir
);
1647 if (!(cache
= pFcDirCacheRead( dir
, FcFalse
, config
))) continue;
1649 if (!(font_set
= pFcCacheCopySet( cache
))) goto done
;
1650 for (i
= 0; i
< font_set
->nfont
; i
++)
1651 fontconfig_add_font( font_set
->fonts
[i
], flags
);
1652 pFcFontSetDestroy( font_set
);
1655 if (!(subdir_set
= pFcStrSetCreate())) goto done
;
1656 for (i
= 0; i
< pFcCacheNumSubdir( cache
); i
++)
1657 pFcStrSetAdd( subdir_set
, pFcCacheSubdir( cache
, i
) );
1658 pFcDirCacheUnload( cache
);
1661 if (!(subdir_list
= pFcStrListCreate( subdir_set
))) goto done
;
1662 pFcStrSetDestroy( subdir_set
);
1665 pFcStrSetAdd( done_set
, dir
);
1666 fontconfig_add_fonts_from_dir_list( config
, subdir_list
, done_set
, flags
);
1667 pFcStrListDone( subdir_list
);
1672 if (subdir_set
) pFcStrSetDestroy( subdir_set
);
1673 if (cache
) pFcDirCacheUnload( cache
);
1676 static void load_fontconfig_fonts( void )
1678 FcStrList
*dir_list
= NULL
;
1679 FcStrSet
*done_set
= NULL
;
1682 if (!fontconfig_enabled
) return;
1683 if (!(config
= pFcConfigGetCurrent())) goto done
;
1684 if (!(done_set
= pFcStrSetCreate())) goto done
;
1685 if (!(dir_list
= pFcConfigGetFontDirs( config
))) goto done
;
1687 fontconfig_add_fonts_from_dir_list( config
, dir_list
, done_set
, ADDFONT_EXTERNAL_FONT
);
1690 if (dir_list
) pFcStrListDone( dir_list
);
1691 if (done_set
) pFcStrSetDestroy( done_set
);
1694 #elif defined(__APPLE__)
1696 static void load_mac_font_callback(const void *value
, void *context
)
1698 CFStringRef pathStr
= value
;
1702 len
= CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr
);
1703 path
= malloc( len
);
1704 if (path
&& CFStringGetFileSystemRepresentation(pathStr
, path
, len
))
1706 TRACE("font file %s\n", path
);
1707 AddFontToList(NULL
, path
, NULL
, 0, ADDFONT_EXTERNAL_FONT
);
1712 static void load_mac_fonts(void)
1714 CFStringRef removeDupesKey
;
1715 CFBooleanRef removeDupesValue
;
1716 CFDictionaryRef options
;
1717 CTFontCollectionRef col
;
1719 CFMutableSetRef paths
;
1722 removeDupesKey
= kCTFontCollectionRemoveDuplicatesOption
;
1723 removeDupesValue
= kCFBooleanTrue
;
1724 options
= CFDictionaryCreate(NULL
, (const void**)&removeDupesKey
, (const void**)&removeDupesValue
, 1,
1725 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1726 col
= CTFontCollectionCreateFromAvailableFonts(options
);
1727 if (options
) CFRelease(options
);
1730 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
1734 descs
= CTFontCollectionCreateMatchingFontDescriptors(col
);
1738 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
1742 paths
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
1745 WARN("CFSetCreateMutable failed\n");
1750 for (i
= 0; i
< CFArrayGetCount(descs
); i
++)
1752 CTFontDescriptorRef desc
;
1757 desc
= CFArrayGetValueAtIndex(descs
, i
);
1758 url
= CTFontDescriptorCopyAttribute(desc
, kCTFontURLAttribute
);
1761 ext
= CFURLCopyPathExtension(url
);
1764 BOOL skip
= (CFStringCompare(ext
, CFSTR("pfa"), kCFCompareCaseInsensitive
) == kCFCompareEqualTo
||
1765 CFStringCompare(ext
, CFSTR("pfb"), kCFCompareCaseInsensitive
) == kCFCompareEqualTo
);
1774 path
= CFURLCopyFileSystemPath(url
, kCFURLPOSIXPathStyle
);
1776 if (!path
) continue;
1778 CFSetAddValue(paths
, path
);
1784 CFSetApplyFunction(paths
, load_mac_font_callback
, NULL
);
1791 static BOOL
init_freetype(void)
1793 ft_handle
= dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
);
1796 "Wine cannot find the FreeType font library. To enable Wine to\n"
1797 "use TrueType fonts please install a version of FreeType greater than\n"
1798 "or equal to 2.0.5.\n"
1799 "http://www.freetype.org\n");
1803 #define LOAD_FUNCPTR(f) if((p##f = dlsym(ft_handle, #f)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
1805 LOAD_FUNCPTR(FT_Done_Face
)
1806 LOAD_FUNCPTR(FT_Get_Char_Index
)
1807 LOAD_FUNCPTR(FT_Get_First_Char
)
1808 LOAD_FUNCPTR(FT_Get_Next_Char
)
1809 LOAD_FUNCPTR(FT_Get_Sfnt_Name
)
1810 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count
)
1811 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
1812 LOAD_FUNCPTR(FT_Get_WinFNT_Header
)
1813 LOAD_FUNCPTR(FT_Init_FreeType
)
1814 LOAD_FUNCPTR(FT_Library_Version
)
1815 LOAD_FUNCPTR(FT_Load_Glyph
)
1816 LOAD_FUNCPTR(FT_Load_Sfnt_Table
)
1817 LOAD_FUNCPTR(FT_Matrix_Multiply
)
1818 LOAD_FUNCPTR(FT_MulDiv
)
1819 #ifndef FT_MULFIX_INLINED
1820 LOAD_FUNCPTR(FT_MulFix
)
1822 LOAD_FUNCPTR(FT_New_Face
)
1823 LOAD_FUNCPTR(FT_New_Memory_Face
)
1824 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
1825 LOAD_FUNCPTR(FT_Outline_Get_CBox
)
1826 LOAD_FUNCPTR(FT_Outline_Transform
)
1827 LOAD_FUNCPTR(FT_Outline_Translate
)
1828 LOAD_FUNCPTR(FT_Render_Glyph
)
1829 LOAD_FUNCPTR(FT_Set_Charmap
)
1830 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
1831 LOAD_FUNCPTR(FT_Vector_Length
)
1832 LOAD_FUNCPTR(FT_Vector_Transform
)
1833 LOAD_FUNCPTR(FT_Vector_Unit
)
1835 /* Don't warn if these ones are missing */
1836 pFT_Outline_Embolden
= dlsym(ft_handle
, "FT_Outline_Embolden");
1837 pFT_Get_TrueType_Engine_Type
= dlsym(ft_handle
, "FT_Get_TrueType_Engine_Type");
1838 #ifdef FT_LCD_FILTER_H
1839 pFT_Library_SetLcdFilter
= dlsym(ft_handle
, "FT_Library_SetLcdFilter");
1841 pFT_Property_Set
= dlsym(ft_handle
, "FT_Property_Set");
1843 if(pFT_Init_FreeType(&library
) != 0) {
1844 ERR("Can't init FreeType library\n");
1849 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
1851 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
1852 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
1853 ((FT_Version
.minor
<< 8) & 0x00ff00) |
1854 ((FT_Version
.patch
) & 0x0000ff);
1856 /* In FreeType < 2.8.1 v40's FT_LOAD_TARGET_MONO has broken advance widths. */
1857 if (pFT_Property_Set
&& FT_SimpleVersion
< FT_VERSION_VALUE(2, 8, 1))
1859 FT_UInt interpreter_version
= 35;
1860 pFT_Property_Set( library
, "truetype", "interpreter-version", &interpreter_version
);
1863 #ifdef FT_LCD_FILTER_H
1864 if (pFT_Library_SetLcdFilter
)
1865 pFT_Library_SetLcdFilter( library
, FT_LCD_FILTER_DEFAULT
);
1872 "Wine cannot find certain functions that it needs inside the FreeType\n"
1873 "font library. To enable Wine to use TrueType fonts please upgrade\n"
1874 "FreeType to at least version 2.1.4.\n"
1875 "http://www.freetype.org\n");
1881 /*************************************************************
1882 * freetype_load_fonts
1884 static void freetype_load_fonts(void)
1886 #ifdef SONAME_LIBFONTCONFIG
1887 load_fontconfig_fonts();
1888 #elif defined(__APPLE__)
1890 #elif defined(__ANDROID__)
1891 ReadFontDir("/system/fonts", TRUE
);
1895 /* Some fonts have large usWinDescent values, as a result of storing signed short
1896 in unsigned field. That's probably caused by sTypoDescent vs usWinDescent confusion in
1897 some font generation tools. */
1898 static inline USHORT
get_fixed_windescent(USHORT windescent
)
1900 return abs((SHORT
)windescent
);
1903 static int calc_ppem_for_height(FT_Face ft_face
, int height
)
1906 TT_HoriHeader
*pHori
;
1909 const int MAX_PPEM
= (1 << 16) - 1;
1911 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
1912 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
1914 if(height
== 0) height
= 16;
1916 /* Calc. height of EM square:
1918 * For +ve lfHeight we have
1919 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
1920 * Re-arranging gives:
1921 * ppem = units_per_em * lfheight / (winAscent + winDescent)
1923 * For -ve lfHeight we have
1925 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
1926 * with il = winAscent + winDescent - units_per_em]
1931 USHORT windescent
= get_fixed_windescent(pOS2
->usWinDescent
);
1934 if(pOS2
->usWinAscent
+ windescent
== 0)
1935 units
= pHori
->Ascender
- pHori
->Descender
;
1937 units
= pOS2
->usWinAscent
+ windescent
;
1938 ppem
= pFT_MulDiv(ft_face
->units_per_EM
, height
, units
);
1940 /* If rounding ends up getting a font exceeding height, choose a smaller ppem */
1941 if(ppem
> 1 && pFT_MulDiv(units
, ppem
, ft_face
->units_per_EM
) > height
)
1944 if(ppem
> MAX_PPEM
) {
1945 WARN("Ignoring too large height %d, ppem %d\n", height
, ppem
);
1949 else if(height
>= -MAX_PPEM
)
1952 WARN("Ignoring too large height %d\n", height
);
1959 static struct font_mapping
*map_font_file( const char *name
)
1961 struct font_mapping
*mapping
;
1965 if ((fd
= open( name
, O_RDONLY
)) == -1) return NULL
;
1966 if (fstat( fd
, &st
) == -1) goto error
;
1968 LIST_FOR_EACH_ENTRY( mapping
, &mappings_list
, struct font_mapping
, entry
)
1970 if (mapping
->dev
== st
.st_dev
&& mapping
->ino
== st
.st_ino
)
1972 mapping
->refcount
++;
1977 if (!(mapping
= malloc( sizeof(*mapping
) )))
1980 mapping
->data
= mmap( NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0 );
1983 if (mapping
->data
== MAP_FAILED
)
1988 mapping
->refcount
= 1;
1989 mapping
->dev
= st
.st_dev
;
1990 mapping
->ino
= st
.st_ino
;
1991 mapping
->size
= st
.st_size
;
1992 list_add_tail( &mappings_list
, &mapping
->entry
);
2000 static void unmap_font_file( struct font_mapping
*mapping
)
2002 if (!--mapping
->refcount
)
2004 list_remove( &mapping
->entry
);
2005 munmap( mapping
->data
, mapping
->size
);
2010 static int load_VDMX(struct gdi_font
*font
, int height
);
2012 /*************************************************************
2013 * freetype_destroy_font
2015 static void freetype_destroy_font( struct gdi_font
*font
)
2017 struct font_private_data
*data
= font
->private;
2019 if (data
->ft_face
) pFT_Done_Face( data
->ft_face
);
2020 if (data
->mapping
) unmap_font_file( data
->mapping
);
2024 /*************************************************************
2025 * freetype_get_font_data
2027 static UINT
freetype_get_font_data( struct gdi_font
*font
, UINT table
, UINT offset
,
2028 void *buf
, UINT cbData
)
2030 FT_Face ft_face
= get_ft_face( font
);
2034 if (!FT_IS_SFNT(ft_face
)) return GDI_ERROR
;
2041 /* if font is a member of TTC, 'ttcf' tag allows reading from beginning of TTC file,
2042 0 tag means to read from start of collection member data. */
2043 if (font
->ttc_item_offset
)
2045 if (table
== MS_TTCF_TAG
)
2047 else if (table
== 0)
2048 offset
+= font
->ttc_item_offset
;
2051 /* make sure value of len is the value freetype says it needs */
2054 FT_ULong needed
= 0;
2055 err
= pFT_Load_Sfnt_Table(ft_face
, RtlUlongByteSwap(table
), offset
, NULL
, &needed
);
2056 if( !err
&& needed
< len
) len
= needed
;
2058 err
= pFT_Load_Sfnt_Table(ft_face
, RtlUlongByteSwap(table
), offset
, buf
, &len
);
2061 TRACE("Can't find table %s\n", debugstr_an((char*)&table
, 4));
2067 /*************************************************************
2070 * load the vdmx entry for the specified height
2100 static int load_VDMX(struct gdi_font
*font
, int height
)
2104 BYTE devXRatio
, devYRatio
;
2105 USHORT numRecs
, numRatios
;
2106 UINT result
, offset
= -1;
2109 result
= freetype_get_font_data(font
, MS_VDMX_TAG
, 0, &hdr
, sizeof(hdr
));
2111 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
2114 /* FIXME: need the real device aspect ratio */
2118 numRecs
= GET_BE_WORD(hdr
.numRecs
);
2119 numRatios
= GET_BE_WORD(hdr
.numRatios
);
2121 TRACE("version = %d numRecs = %d numRatios = %d\n", GET_BE_WORD(hdr
.version
), numRecs
, numRatios
);
2122 for(i
= 0; i
< numRatios
; i
++) {
2125 offset
= sizeof(hdr
) + (i
* sizeof(Ratios
));
2126 freetype_get_font_data(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
2129 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
2131 if (!ratio
.bCharSet
) continue;
2133 if((ratio
.xRatio
== 0 &&
2134 ratio
.yStartRatio
== 0 &&
2135 ratio
.yEndRatio
== 0) ||
2136 (devXRatio
== ratio
.xRatio
&&
2137 devYRatio
>= ratio
.yStartRatio
&&
2138 devYRatio
<= ratio
.yEndRatio
))
2142 offset
= sizeof(hdr
) + numRatios
* sizeof(ratio
) + i
* sizeof(group_offset
);
2143 freetype_get_font_data(font
, MS_VDMX_TAG
, offset
, &group_offset
, sizeof(group_offset
));
2144 offset
= GET_BE_WORD(group_offset
);
2149 if(offset
== -1) return 0;
2151 if(freetype_get_font_data(font
, MS_VDMX_TAG
, offset
, &group
, sizeof(group
)) != GDI_ERROR
) {
2153 BYTE startsz
, endsz
;
2156 recs
= GET_BE_WORD(group
.recs
);
2157 startsz
= group
.startsz
;
2158 endsz
= group
.endsz
;
2160 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
2162 vTable
= malloc( recs
* sizeof(VDMX_vTable
) );
2163 result
= freetype_get_font_data(font
, MS_VDMX_TAG
, offset
+ sizeof(group
), vTable
, recs
* sizeof(VDMX_vTable
));
2164 if(result
== GDI_ERROR
) {
2165 FIXME("Failed to retrieve vTable\n");
2170 for(i
= 0; i
< recs
; i
++) {
2171 SHORT yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
2172 SHORT yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
2173 ppem
= GET_BE_WORD(vTable
[i
* 3]);
2175 if(yMax
+ -yMin
== height
) {
2178 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
2181 if(yMax
+ -yMin
> height
) {
2184 goto end
; /* failed */
2186 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
2187 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
2188 ppem
= GET_BE_WORD(vTable
[i
* 3]);
2189 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
2195 TRACE("ppem not found for height %d\n", height
);
2199 if(ppem
< startsz
|| ppem
> endsz
)
2205 for(i
= 0; i
< recs
; i
++) {
2207 yPelHeight
= GET_BE_WORD(vTable
[i
* 3]);
2209 if(yPelHeight
> ppem
)
2215 if(yPelHeight
== ppem
) {
2216 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
2217 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
2218 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem
, font
->yMax
, font
->yMin
);
2230 static BOOL
select_charmap(FT_Face ft_face
, FT_Encoding encoding
)
2232 FT_Error ft_err
= FT_Err_Invalid_CharMap_Handle
;
2233 FT_CharMap cmap0
, cmap1
, cmap2
, cmap3
, cmap_def
;
2236 cmap0
= cmap1
= cmap2
= cmap3
= cmap_def
= NULL
;
2238 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
2240 if (ft_face
->charmaps
[i
]->encoding
== encoding
)
2242 TRACE("found cmap with platform_id %u, encoding_id %u\n",
2243 ft_face
->charmaps
[i
]->platform_id
, ft_face
->charmaps
[i
]->encoding_id
);
2245 switch (ft_face
->charmaps
[i
]->platform_id
)
2248 cmap_def
= ft_face
->charmaps
[i
];
2250 case 0: /* Apple Unicode */
2251 cmap0
= ft_face
->charmaps
[i
];
2253 case 1: /* Macintosh */
2254 cmap1
= ft_face
->charmaps
[i
];
2257 cmap2
= ft_face
->charmaps
[i
];
2259 case 3: /* Microsoft */
2260 cmap3
= ft_face
->charmaps
[i
];
2265 if (cmap3
) /* prefer Microsoft cmap table */
2266 ft_err
= pFT_Set_Charmap(ft_face
, cmap3
);
2268 ft_err
= pFT_Set_Charmap(ft_face
, cmap1
);
2270 ft_err
= pFT_Set_Charmap(ft_face
, cmap2
);
2272 ft_err
= pFT_Set_Charmap(ft_face
, cmap0
);
2274 ft_err
= pFT_Set_Charmap(ft_face
, cmap_def
);
2277 return ft_err
== FT_Err_Ok
;
2281 static FT_Encoding
pick_charmap( FT_Face face
, int charset
)
2283 static const FT_Encoding regular_order
[] = { FT_ENCODING_UNICODE
, FT_ENCODING_APPLE_ROMAN
, FT_ENCODING_MS_SYMBOL
, 0 };
2284 static const FT_Encoding symbol_order
[] = { FT_ENCODING_MS_SYMBOL
, FT_ENCODING_UNICODE
, FT_ENCODING_APPLE_ROMAN
, 0 };
2285 const FT_Encoding
*encs
= regular_order
;
2287 if (charset
== SYMBOL_CHARSET
) encs
= symbol_order
;
2291 if (select_charmap( face
, *encs
)) break;
2295 if (!face
->charmap
&& face
->num_charmaps
)
2297 if (!pFT_Set_Charmap(face
, face
->charmaps
[0]))
2298 return face
->charmap
->encoding
;
2304 static BOOL
get_gasp_flags( struct gdi_font
*font
, WORD
*flags
)
2306 FT_Face ft_face
= get_ft_face( font
);
2308 WORD buf
[16]; /* Enough for seven ranges before we need to alloc */
2309 WORD
*alloced
= NULL
, *ptr
= buf
;
2310 WORD num_recs
, version
;
2314 size
= freetype_get_font_data( font
, MS_GASP_TAG
, 0, NULL
, 0 );
2315 if (size
== GDI_ERROR
) return FALSE
;
2316 if (size
< 4 * sizeof(WORD
)) return FALSE
;
2317 if (size
> sizeof(buf
))
2319 ptr
= alloced
= malloc( size
);
2320 if (!ptr
) return FALSE
;
2323 freetype_get_font_data( font
, MS_GASP_TAG
, 0, ptr
, size
);
2325 version
= GET_BE_WORD( *ptr
++ );
2326 num_recs
= GET_BE_WORD( *ptr
++ );
2328 if (version
> 1 || size
< (num_recs
* 2 + 2) * sizeof(WORD
))
2330 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version
, size
, num_recs
);
2336 *flags
= GET_BE_WORD( *(ptr
+ 1) );
2337 if (ft_face
->size
->metrics
.y_ppem
<= GET_BE_WORD( *ptr
)) break;
2340 TRACE( "got flags %04x for ppem %d\n", *flags
, ft_face
->size
->metrics
.y_ppem
);
2348 /*************************************************************
2349 * fontconfig_enum_family_fallbacks
2351 static BOOL
fontconfig_enum_family_fallbacks( UINT pitch_and_family
, int index
,
2352 WCHAR buffer
[LF_FACESIZE
] )
2354 #ifdef SONAME_LIBFONTCONFIG
2359 if ((pitch_and_family
& FIXED_PITCH
) || (pitch_and_family
& 0xf0) == FF_MODERN
) pat
= create_family_pattern( "monospace", &pattern_fixed
);
2360 else if ((pitch_and_family
& 0xf0) == FF_ROMAN
) pat
= create_family_pattern( "serif", &pattern_serif
);
2361 else pat
= create_family_pattern( "sans", &pattern_sans
);
2363 if (!pat
) return FALSE
;
2364 if (pFcPatternGetString( pat
, FC_FAMILY
, index
, (FcChar8
**)&str
) != FcResultMatch
) return FALSE
;
2365 RtlUTF8ToUnicodeN( buffer
, (LF_FACESIZE
- 1) * sizeof(WCHAR
), &len
, str
, strlen(str
) );
2366 buffer
[len
/ sizeof(WCHAR
)] = 0;
2372 static DWORD
get_ttc_offset( FT_Face ft_face
, UINT face_index
)
2375 DWORD header
, offset
;
2377 /* see if it's a TTC */
2378 len
= sizeof(header
);
2379 if (pFT_Load_Sfnt_Table( ft_face
, 0, 0, (void *)&header
, &len
)) return 0;
2380 if (header
!= MS_TTCF_TAG
) return 0;
2382 len
= sizeof(offset
);
2383 if (pFT_Load_Sfnt_Table( ft_face
, 0, (3 + face_index
) * sizeof(DWORD
), (void *)&offset
, &len
))
2386 return GET_BE_DWORD( offset
);
2389 /*************************************************************
2390 * freetype_load_font
2392 static BOOL
freetype_load_font( struct gdi_font
*font
)
2394 struct font_private_data
*data
;
2395 INT width
= 0, height
;
2400 if (!(data
= calloc( 1, sizeof(*data
) ))) return FALSE
;
2401 font
->private = data
;
2405 char *filename
= get_unix_file_name( font
->file
);
2406 data
->mapping
= map_font_file( filename
);
2410 WARN("failed to map %s\n", debugstr_w(font
->file
));
2413 data_ptr
= data
->mapping
->data
;
2414 data_size
= data
->mapping
->size
;
2418 data_ptr
= font
->data_ptr
;
2419 data_size
= font
->data_size
;
2422 if (pFT_New_Memory_Face( library
, data_ptr
, data_size
, font
->face_index
, &ft_face
)) return FALSE
;
2424 data
->ft_face
= ft_face
;
2425 font
->scalable
= FT_IS_SCALABLE( ft_face
);
2426 if (!font
->fs
.fsCsb
[0]) get_fontsig( ft_face
, &font
->fs
);
2427 if (!font
->ntmFlags
) font
->ntmFlags
= get_ntm_flags( ft_face
);
2428 if (!font
->aa_flags
) font
->aa_flags
= ADDFONT_AA_FLAGS( default_aa_flags
);
2429 if (!font
->otm
.otmpFamilyName
)
2431 font
->otm
.otmpFamilyName
= (char *)ft_face_get_family_name( ft_face
, system_lcid
);
2432 font
->otm
.otmpStyleName
= (char *)ft_face_get_style_name( ft_face
, system_lcid
);
2433 font
->otm
.otmpFaceName
= (char *)ft_face_get_full_name( ft_face
, system_lcid
);
2438 /* load the VDMX table if we have one */
2439 font
->ppem
= load_VDMX( font
, font
->lf
.lfHeight
);
2440 if (font
->ppem
== 0) font
->ppem
= calc_ppem_for_height( ft_face
, font
->lf
.lfHeight
);
2441 TRACE( "height %d => ppem %d\n", (int)font
->lf
.lfHeight
, font
->ppem
);
2442 height
= font
->ppem
;
2443 font
->ttc_item_offset
= get_ttc_offset( ft_face
, font
->face_index
);
2444 font
->otm
.otmEMSquare
= ft_face
->units_per_EM
;
2448 struct bitmap_font_size size
;
2450 get_bitmap_size( ft_face
, &size
);
2451 width
= size
.x_ppem
>> 6;
2452 height
= size
.y_ppem
>> 6;
2453 font
->ppem
= height
;
2456 pFT_Set_Pixel_Sizes( ft_face
, width
, height
);
2457 pick_charmap( ft_face
, font
->charset
);
2462 /*************************************************************
2463 * freetype_get_aa_flags
2465 static UINT
freetype_get_aa_flags( struct gdi_font
*font
, UINT aa_flags
, BOOL antialias_fakes
)
2467 /* fixup the antialiasing flags for that font */
2470 case WINE_GGO_HRGB_BITMAP
:
2471 case WINE_GGO_HBGR_BITMAP
:
2472 case WINE_GGO_VRGB_BITMAP
:
2473 case WINE_GGO_VBGR_BITMAP
:
2474 if (is_subpixel_rendering_enabled()) break;
2475 aa_flags
= GGO_GRAY4_BITMAP
;
2477 case GGO_GRAY2_BITMAP
:
2478 case GGO_GRAY4_BITMAP
:
2479 case GGO_GRAY8_BITMAP
:
2480 case WINE_GGO_GRAY16_BITMAP
:
2481 if ((!antialias_fakes
|| (!font
->fake_bold
&& !font
->fake_italic
)) && is_hinting_enabled())
2484 if (get_gasp_flags( font
, &gasp_flags
) && !(gasp_flags
& GASP_DOGRAY
))
2486 TRACE( "font %s %d aa disabled by GASP\n",
2487 debugstr_w(font
->lf
.lfFaceName
), (int)font
->lf
.lfHeight
);
2488 aa_flags
= GGO_BITMAP
;
2495 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
2497 pt
->x
.value
= vec
->x
>> 6;
2498 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
2499 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
2500 pt
->y
.value
= vec
->y
>> 6;
2501 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
2502 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
2505 static FT_UInt
get_glyph_index_symbol( struct gdi_font
*font
, UINT glyph
)
2507 FT_Face ft_face
= get_ft_face( font
);
2510 if (glyph
< 0x100) glyph
+= 0xf000;
2511 /* there are a number of old pre-Unicode "broken" TTFs, which
2512 do have symbols at U+00XX instead of U+f0XX */
2513 if (!(ret
= pFT_Get_Char_Index(ft_face
, glyph
)))
2514 ret
= pFT_Get_Char_Index(ft_face
, glyph
- 0xf000);
2519 /*************************************************************
2520 * freetype_get_glyph_index
2522 static BOOL
freetype_get_glyph_index( struct gdi_font
*font
, UINT
*glyph
, BOOL use_encoding
)
2524 FT_Face ft_face
= get_ft_face( font
);
2526 if (!use_encoding
^ (ft_face
->charmap
->encoding
== FT_ENCODING_NONE
)) return FALSE
;
2528 if (ft_face
->charmap
->encoding
== FT_ENCODING_MS_SYMBOL
)
2530 if (!(*glyph
= get_glyph_index_symbol( font
, *glyph
)))
2536 len
= win32u_wctomb( &ansi_cp
, &ch
, 1, &wc
, 1 );
2537 if (len
) *glyph
= get_glyph_index_symbol( font
, (unsigned char)ch
);
2541 *glyph
= pFT_Get_Char_Index( ft_face
, *glyph
);
2545 /*************************************************************
2546 * freetype_get_default_glyph
2548 static UINT
freetype_get_default_glyph( struct gdi_font
*font
)
2550 FT_Face ft_face
= get_ft_face( font
);
2551 FT_WinFNT_HeaderRec winfnt
;
2554 if ((pOS2
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_os2
)))
2556 UINT glyph
= pOS2
->usDefaultChar
;
2557 if (glyph
) freetype_get_glyph_index( font
, &glyph
, TRUE
);
2560 if (!pFT_Get_WinFNT_Header( ft_face
, &winfnt
)) return winfnt
.default_char
+ winfnt
.first_char
;
2565 static inline BOOL
is_identity_FMAT2(const FMAT2
*matrix
)
2567 static const FMAT2 identity
= { 1.0, 0.0, 0.0, 1.0 };
2568 return !memcmp(matrix
, &identity
, sizeof(FMAT2
));
2571 static inline FT_Vector
normalize_vector(FT_Vector
*vec
)
2575 len
= pFT_Vector_Length(vec
);
2577 out
.x
= (vec
->x
<< 6) / len
;
2578 out
.y
= (vec
->y
<< 6) / len
;
2585 /* get_glyph_outline() glyph transform matrices index */
2593 static FT_Matrix
*get_transform_matrices( struct gdi_font
*font
, BOOL vertical
, const MAT2
*user_transform
,
2594 FT_Matrix matrices
[3] )
2596 static const FT_Matrix identity_mat
= { (1 << 16), 0, 0, (1 << 16) };
2597 BOOL needs_transform
= FALSE
;
2601 matrices
[matrix_unrotated
] = identity_mat
;
2603 /* Scaling factor */
2606 if (!freetype_set_outline_text_metrics( font
)) freetype_set_bitmap_text_metrics( font
);
2607 width_ratio
= (double)font
->aveWidth
;
2608 width_ratio
/= (double)font
->otm
.otmTextMetrics
.tmAveCharWidth
;
2611 width_ratio
= font
->scale_y
;
2613 /* Scaling transform */
2614 if (width_ratio
!= 1.0 || font
->scale_y
!= 1)
2616 FT_Matrix scale_mat
;
2617 scale_mat
.xx
= FT_FixedFromFloat( width_ratio
);
2620 scale_mat
.yy
= font
->scale_y
<< 16;
2622 pFT_Matrix_Multiply( &scale_mat
, &matrices
[matrix_unrotated
] );
2623 needs_transform
= TRUE
;
2626 /* Slant transform */
2627 if (font
->fake_italic
)
2629 FT_Matrix slant_mat
;
2630 slant_mat
.xx
= (1 << 16);
2631 slant_mat
.xy
= (1 << 16) >> 2;
2633 slant_mat
.yy
= (1 << 16);
2635 pFT_Matrix_Multiply( &slant_mat
, &matrices
[matrix_unrotated
] );
2636 needs_transform
= TRUE
;
2639 /* Rotation transform */
2640 matrices
[matrix_hori
] = matrices
[matrix_unrotated
];
2641 if (font
->scalable
&& font
->lf
.lfOrientation
% 3600)
2643 FT_Matrix rotation_mat
;
2646 pFT_Vector_Unit( &angle
, pFT_MulDiv( 1 << 16, font
->lf
.lfOrientation
, 10 ) );
2647 rotation_mat
.xx
= angle
.x
;
2648 rotation_mat
.xy
= -angle
.y
;
2649 rotation_mat
.yx
= angle
.y
;
2650 rotation_mat
.yy
= angle
.x
;
2651 pFT_Matrix_Multiply( &rotation_mat
, &matrices
[matrix_hori
] );
2652 needs_transform
= TRUE
;
2655 /* Vertical transform */
2656 matrices
[matrix_vert
] = matrices
[matrix_hori
];
2659 FT_Matrix vertical_mat
= { 0, -(1 << 16), 1 << 16, 0 }; /* 90 degrees rotation */
2661 pFT_Matrix_Multiply( &vertical_mat
, &matrices
[matrix_vert
] );
2662 needs_transform
= TRUE
;
2665 /* World transform */
2666 if (!is_identity_FMAT2( &font
->matrix
))
2668 FT_Matrix world_mat
;
2669 world_mat
.xx
= FT_FixedFromFloat( font
->matrix
.eM11
);
2670 world_mat
.xy
= -FT_FixedFromFloat( font
->matrix
.eM21
);
2671 world_mat
.yx
= -FT_FixedFromFloat( font
->matrix
.eM12
);
2672 world_mat
.yy
= FT_FixedFromFloat( font
->matrix
.eM22
);
2674 for (i
= 0; i
< 3; i
++)
2675 pFT_Matrix_Multiply( &world_mat
, &matrices
[i
] );
2676 needs_transform
= TRUE
;
2679 /* Extra transformation specified by caller */
2683 user_mat
.xx
= FT_FixedFromFIXED( user_transform
->eM11
);
2684 user_mat
.xy
= FT_FixedFromFIXED( user_transform
->eM21
);
2685 user_mat
.yx
= FT_FixedFromFIXED( user_transform
->eM12
);
2686 user_mat
.yy
= FT_FixedFromFIXED( user_transform
->eM22
);
2688 for (i
= 0; i
< 3; i
++)
2689 pFT_Matrix_Multiply( &user_mat
, &matrices
[i
] );
2690 needs_transform
= TRUE
;
2693 return needs_transform
? matrices
: NULL
;
2696 static BOOL
get_bold_glyph_outline(FT_GlyphSlot glyph
, LONG ppem
, FT_Glyph_Metrics
*metrics
)
2702 if(glyph
->format
!= FT_GLYPH_FORMAT_OUTLINE
)
2704 if(!pFT_Outline_Embolden
)
2707 strength
= pFT_MulDiv(ppem
, 1 << 6, 24);
2708 err
= pFT_Outline_Embolden(&glyph
->outline
, strength
);
2710 TRACE("FT_Ouline_Embolden returns %d\n", err
);
2714 pFT_Outline_Get_CBox(&glyph
->outline
, &bbox
);
2715 metrics
->width
= bbox
.xMax
- bbox
.xMin
;
2716 metrics
->height
= bbox
.yMax
- bbox
.yMin
;
2717 metrics
->horiBearingX
= bbox
.xMin
;
2718 metrics
->horiBearingY
= bbox
.yMax
;
2719 metrics
->vertBearingX
= metrics
->horiBearingX
- metrics
->horiAdvance
/ 2;
2720 metrics
->vertBearingY
= (metrics
->vertAdvance
- metrics
->height
) / 2;
2724 static inline BYTE
get_max_level( UINT format
)
2728 case GGO_GRAY2_BITMAP
: return 4;
2729 case GGO_GRAY4_BITMAP
: return 16;
2730 case GGO_GRAY8_BITMAP
: return 64;
2735 static FT_Vector
get_advance_metric( struct gdi_font
*font
, FT_Pos base_advance
,
2736 const FT_Matrix
*transMat
)
2739 FT_Fixed em_scale
= 0;
2740 BOOL fixed_pitch_full
= FALSE
;
2741 struct gdi_font
*incoming_font
= font
->base_font
? font
->base_font
: font
;
2743 adv
.x
= base_advance
;
2746 /* In fixed-pitch font, we adjust the fullwidth character advance so that
2747 they have double halfwidth character width. E.g. if the font is 19 ppem,
2748 we return 20 (not 19) for fullwidth characters as we return 10 for
2749 halfwidth characters. */
2750 if (freetype_set_outline_text_metrics(incoming_font
) &&
2751 !(incoming_font
->otm
.otmTextMetrics
.tmPitchAndFamily
& TMPF_FIXED_PITCH
)) {
2753 em_scale
= pFT_MulDiv(incoming_font
->ppem
, 1 << 16, get_ft_face(incoming_font
)->units_per_EM
);
2754 avg_advance
= pFT_MulFix(incoming_font
->ntmAvgWidth
, em_scale
);
2755 fixed_pitch_full
= (avg_advance
> 0 &&
2756 (base_advance
+ 63) >> 6 ==
2757 pFT_MulFix(incoming_font
->ntmAvgWidth
*2, em_scale
));
2758 if (fixed_pitch_full
&& !transMat
)
2759 adv
.x
= (avg_advance
* 2) << 6;
2763 pFT_Vector_Transform(&adv
, transMat
);
2764 if (fixed_pitch_full
&& adv
.y
== 0) {
2766 vec
.x
= incoming_font
->ntmAvgWidth
;
2768 pFT_Vector_Transform(&vec
, transMat
);
2769 adv
.x
= (pFT_MulFix(vec
.x
, em_scale
) * 2) << 6;
2773 if (font
->fake_bold
) {
2777 FT_Vector fake_bold_adv
, vec
= { 1 << 6, 0 };
2778 pFT_Vector_Transform(&vec
, transMat
);
2779 fake_bold_adv
= normalize_vector(&vec
);
2780 adv
.x
+= fake_bold_adv
.x
;
2781 adv
.y
+= fake_bold_adv
.y
;
2785 adv
.x
= (adv
.x
+ 63) & -64;
2786 adv
.y
= -((adv
.y
+ 63) & -64);
2790 static FT_BBox
get_transformed_bbox( const FT_Glyph_Metrics
*metrics
, const FT_Matrix
*matrices
)
2792 FT_BBox bbox
= { 0, 0, 0, 0 };
2796 bbox
.xMin
= (metrics
->horiBearingX
) & -64;
2797 bbox
.xMax
= (metrics
->horiBearingX
+ metrics
->width
+ 63) & -64;
2798 bbox
.yMax
= (metrics
->horiBearingY
+ 63) & -64;
2799 bbox
.yMin
= (metrics
->horiBearingY
- metrics
->height
) & -64;
2806 for (xc
= 0; xc
< 2; xc
++)
2808 for (yc
= 0; yc
< 2; yc
++)
2810 vec
.x
= metrics
->horiBearingX
+ xc
* metrics
->width
;
2811 vec
.y
= metrics
->horiBearingY
- yc
* metrics
->height
;
2812 TRACE( "Vec %ld, %ld\n", vec
.x
, vec
.y
);
2813 pFT_Vector_Transform( &vec
, &matrices
[matrix_vert
] );
2814 if (xc
== 0 && yc
== 0)
2816 bbox
.xMin
= bbox
.xMax
= vec
.x
;
2817 bbox
.yMin
= bbox
.yMax
= vec
.y
;
2821 if (vec
.x
< bbox
.xMin
) bbox
.xMin
= vec
.x
;
2822 else if (vec
.x
> bbox
.xMax
) bbox
.xMax
= vec
.x
;
2823 if (vec
.y
< bbox
.yMin
) bbox
.yMin
= vec
.y
;
2824 else if (vec
.y
> bbox
.yMax
) bbox
.yMax
= vec
.y
;
2828 bbox
.xMin
= bbox
.xMin
& -64;
2829 bbox
.xMax
= (bbox
.xMax
+ 63) & -64;
2830 bbox
.yMin
= bbox
.yMin
& -64;
2831 bbox
.yMax
= (bbox
.yMax
+ 63) & -64;
2832 TRACE( "transformed box: (%ld, %ld - %ld, %ld)\n", bbox
.xMin
, bbox
.yMax
, bbox
.xMax
, bbox
.yMin
);
2838 static void compute_metrics( struct gdi_font
*font
, FT_BBox bbox
, const FT_Glyph_Metrics
*metrics
,
2839 BOOL vertical
, BOOL vertical_metrics
, const FT_Matrix
*matrices
,
2840 GLYPHMETRICS
*gm
, ABC
*abc
)
2842 FT_Vector adv
, vec
, origin
;
2843 FT_Fixed base_advance
= vertical_metrics
? metrics
->vertAdvance
: metrics
->horiAdvance
;
2847 adv
= get_advance_metric( font
, base_advance
, NULL
);
2848 gm
->gmCellIncX
= adv
.x
>> 6;
2850 origin
.x
= bbox
.xMin
;
2851 origin
.y
= bbox
.yMax
;
2852 abc
->abcA
= origin
.x
>> 6;
2853 abc
->abcB
= (metrics
->width
+ 63) >> 6;
2859 if (vertical
&& freetype_set_outline_text_metrics( font
))
2861 if (vertical_metrics
)
2862 lsb
= metrics
->horiBearingY
+ metrics
->vertBearingY
;
2864 lsb
= metrics
->vertAdvance
+ (font
->otm
.otmDescent
<< 6);
2866 vec
.y
= font
->otm
.otmDescent
<< 6;
2867 TRACE( "Vec %ld,%ld\n", vec
.x
>>6, vec
.y
>>6 );
2868 pFT_Vector_Transform( &vec
, &matrices
[matrix_hori
] );
2869 origin
.x
= (vec
.x
+ bbox
.xMin
) & -64;
2870 origin
.y
= (vec
.y
+ bbox
.yMax
+ 63) & -64;
2871 lsb
-= metrics
->horiBearingY
;
2875 origin
.x
= bbox
.xMin
;
2876 origin
.y
= bbox
.yMax
;
2877 lsb
= metrics
->horiBearingX
;
2880 adv
= get_advance_metric( font
, base_advance
, &matrices
[matrix_hori
] );
2881 gm
->gmCellIncX
= adv
.x
>> 6;
2882 gm
->gmCellIncY
= adv
.y
>> 6;
2884 adv
= get_advance_metric( font
, base_advance
, &matrices
[matrix_unrotated
] );
2885 adv
.x
= pFT_Vector_Length( &adv
);
2890 pFT_Vector_Transform( &vec
, &matrices
[matrix_unrotated
] );
2891 if (lsb
> 0) abc
->abcA
= pFT_Vector_Length( &vec
) >> 6;
2892 else abc
->abcA
= -((pFT_Vector_Length( &vec
) + 63) >> 6);
2894 /* We use lsb again to avoid rounding errors */
2895 vec
.x
= lsb
+ (vertical
? metrics
->height
: metrics
->width
);
2897 pFT_Vector_Transform( &vec
, &matrices
[matrix_unrotated
] );
2898 abc
->abcB
= ((pFT_Vector_Length( &vec
) + 63) >> 6) - abc
->abcA
;
2900 if (!abc
->abcB
) abc
->abcB
= 1;
2901 abc
->abcC
= (adv
.x
>> 6) - abc
->abcA
- abc
->abcB
;
2903 gm
->gmptGlyphOrigin
.x
= origin
.x
>> 6;
2904 gm
->gmptGlyphOrigin
.y
= origin
.y
>> 6;
2905 gm
->gmBlackBoxX
= (bbox
.xMax
- bbox
.xMin
) >> 6;
2906 gm
->gmBlackBoxY
= (bbox
.yMax
- bbox
.yMin
) >> 6;
2907 if (!gm
->gmBlackBoxX
) gm
->gmBlackBoxX
= 1;
2908 if (!gm
->gmBlackBoxY
) gm
->gmBlackBoxY
= 1;
2910 TRACE( "gm: %u, %u, %s, %d, %d abc %d, %u, %d\n",
2911 gm
->gmBlackBoxX
, gm
->gmBlackBoxY
, wine_dbgstr_point(&gm
->gmptGlyphOrigin
),
2912 gm
->gmCellIncX
, gm
->gmCellIncY
, abc
->abcA
, abc
->abcB
, abc
->abcC
);
2916 static const BYTE masks
[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
2918 static DWORD
get_mono_glyph_bitmap( FT_GlyphSlot glyph
, FT_BBox bbox
,
2919 BOOL fake_bold
, const FT_Matrix
*matrices
,
2920 DWORD buflen
, BYTE
*buf
)
2922 DWORD width
= (bbox
.xMax
- bbox
.xMin
) >> 6;
2923 DWORD height
= (bbox
.yMax
- bbox
.yMin
) >> 6;
2924 DWORD pitch
= ((width
+ 31) >> 5) << 2;
2925 DWORD needed
= pitch
* height
;
2926 FT_Bitmap ft_bitmap
;
2930 if (!buf
|| !buflen
) return needed
;
2931 if (!needed
) return GDI_ERROR
; /* empty glyph */
2932 if (needed
> buflen
) return GDI_ERROR
;
2934 switch (glyph
->format
)
2936 case FT_GLYPH_FORMAT_BITMAP
:
2937 src
= glyph
->bitmap
.buffer
;
2939 w
= min( pitch
, (glyph
->bitmap
.width
+ 7) >> 3 );
2940 h
= min( height
, glyph
->bitmap
.rows
);
2944 memcpy( dst
, src
, w
);
2948 for (x
= 0; x
< w
; x
++)
2950 dst
[x
] = (dst
[x
] & 0x80) | (src
[x
] >> 1) | src
[x
];
2952 dst
[x
+ 1] = (src
[x
] & 0x01) << 7;
2955 src
+= glyph
->bitmap
.pitch
;
2960 case FT_GLYPH_FORMAT_OUTLINE
:
2961 ft_bitmap
.width
= width
;
2962 ft_bitmap
.rows
= height
;
2963 ft_bitmap
.pitch
= pitch
;
2964 ft_bitmap
.pixel_mode
= FT_PIXEL_MODE_MONO
;
2965 ft_bitmap
.buffer
= buf
;
2968 pFT_Outline_Transform( &glyph
->outline
, &matrices
[matrix_vert
] );
2969 pFT_Outline_Translate( &glyph
->outline
, -bbox
.xMin
, -bbox
.yMin
);
2971 /* Note: FreeType will only set 'black' bits for us. */
2972 memset( buf
, 0, buflen
);
2973 pFT_Outline_Get_Bitmap( library
, &glyph
->outline
, &ft_bitmap
);
2977 FIXME( "loaded glyph format %x\n", glyph
->format
);
2984 static DWORD
get_antialias_glyph_bitmap( FT_GlyphSlot glyph
, FT_BBox bbox
, UINT format
,
2985 BOOL fake_bold
, const FT_Matrix
*matrices
,
2986 DWORD buflen
, BYTE
*buf
)
2988 DWORD width
= (bbox
.xMax
- bbox
.xMin
) >> 6;
2989 DWORD height
= (bbox
.yMax
- bbox
.yMin
) >> 6;
2990 DWORD pitch
= (width
+ 3) / 4 * 4;
2991 DWORD needed
= pitch
* height
;
2992 FT_Bitmap ft_bitmap
;
2993 INT w
, h
, x
, max_level
;
2996 if (!buf
|| !buflen
) return needed
;
2997 if (!needed
) return GDI_ERROR
; /* empty glyph */
2998 if (needed
> buflen
) return GDI_ERROR
;
3000 max_level
= get_max_level( format
);
3002 switch (glyph
->format
)
3004 case FT_GLYPH_FORMAT_BITMAP
:
3005 src
= glyph
->bitmap
.buffer
;
3007 memset( buf
, 0, buflen
);
3009 w
= min( pitch
, glyph
->bitmap
.width
);
3010 h
= min( height
, glyph
->bitmap
.rows
);
3013 for (x
= 0; x
< w
; x
++)
3015 if (src
[x
/ 8] & masks
[x
% 8])
3018 if (fake_bold
&& x
+ 1 < pitch
) dst
[x
+ 1] = max_level
;
3021 src
+= glyph
->bitmap
.pitch
;
3026 case FT_GLYPH_FORMAT_OUTLINE
:
3027 ft_bitmap
.width
= width
;
3028 ft_bitmap
.rows
= height
;
3029 ft_bitmap
.pitch
= pitch
;
3030 ft_bitmap
.pixel_mode
= FT_PIXEL_MODE_GRAY
;
3031 ft_bitmap
.buffer
= buf
;
3034 pFT_Outline_Transform( &glyph
->outline
, &matrices
[matrix_vert
] );
3035 pFT_Outline_Translate( &glyph
->outline
, -bbox
.xMin
, -bbox
.yMin
);
3037 memset( buf
, 0, buflen
);
3038 pFT_Outline_Get_Bitmap( library
, &glyph
->outline
, &ft_bitmap
);
3040 if (max_level
!= 255)
3045 for (row
= 0, start
= buf
; row
< height
; row
++)
3047 for (col
= 0, ptr
= start
; col
< width
; col
++, ptr
++)
3048 *ptr
= (((int)*ptr
) * (max_level
+ 1)) / 256;
3055 FIXME("loaded glyph format %x\n", glyph
->format
);
3062 static DWORD
get_subpixel_glyph_bitmap( FT_GlyphSlot glyph
, FT_BBox bbox
, UINT format
,
3063 BOOL fake_bold
, const FT_Matrix
*matrices
,
3064 GLYPHMETRICS
*gm
, DWORD buflen
, BYTE
*buf
)
3066 DWORD width
= (bbox
.xMax
- bbox
.xMin
) >> 6;
3067 DWORD height
= (bbox
.yMax
- bbox
.yMin
) >> 6;
3068 DWORD pitch
, needed
= 0;
3072 switch (glyph
->format
)
3074 case FT_GLYPH_FORMAT_BITMAP
:
3076 needed
= pitch
* height
;
3078 if (!buf
|| !buflen
) break;
3079 if (!needed
) return GDI_ERROR
; /* empty glyph */
3080 if (needed
> buflen
) return GDI_ERROR
;
3082 src
= glyph
->bitmap
.buffer
;
3084 memset( buf
, 0, buflen
);
3086 w
= min( width
, glyph
->bitmap
.width
);
3087 h
= min( height
, glyph
->bitmap
.rows
);
3090 for (x
= 0; x
< w
; x
++)
3092 if ( src
[x
/ 8] & masks
[x
% 8] )
3094 ((unsigned int *)dst
)[x
] = ~0u;
3095 if (fake_bold
&& x
+ 1 < width
) ((unsigned int *)dst
)[x
+ 1] = ~0u;
3098 src
+= glyph
->bitmap
.pitch
;
3103 case FT_GLYPH_FORMAT_OUTLINE
:
3105 INT src_pitch
, src_width
, src_height
, x_shift
, y_shift
;
3106 INT sub_stride
, hmul
, vmul
;
3107 const INT
*sub_order
;
3108 const INT rgb_order
[3] = { 0, 1, 2 };
3109 const INT bgr_order
[3] = { 2, 1, 0 };
3110 FT_Render_Mode render_mode
=
3111 (format
== WINE_GGO_HRGB_BITMAP
||
3112 format
== WINE_GGO_HBGR_BITMAP
) ? FT_RENDER_MODE_LCD
: FT_RENDER_MODE_LCD_V
;
3114 if (!width
|| !height
) /* empty glyph */
3116 if (!buf
|| !buflen
) break;
3120 if ( render_mode
== FT_RENDER_MODE_LCD
)
3122 gm
->gmBlackBoxX
+= 2;
3123 gm
->gmptGlyphOrigin
.x
-= 1;
3124 bbox
.xMin
-= (1 << 6);
3128 gm
->gmBlackBoxY
+= 2;
3129 gm
->gmptGlyphOrigin
.y
+= 1;
3130 bbox
.yMax
+= (1 << 6);
3133 width
= gm
->gmBlackBoxX
;
3134 height
= gm
->gmBlackBoxY
;
3136 needed
= pitch
* height
;
3138 if (!buf
|| !buflen
) return needed
;
3139 if (needed
> buflen
) return GDI_ERROR
;
3142 pFT_Outline_Transform( &glyph
->outline
, &matrices
[matrix_vert
] );
3144 pFT_Render_Glyph( glyph
, render_mode
);
3146 src_pitch
= glyph
->bitmap
.pitch
;
3147 src_width
= glyph
->bitmap
.width
;
3148 src_height
= glyph
->bitmap
.rows
;
3149 src
= glyph
->bitmap
.buffer
;
3151 memset( buf
, 0, buflen
);
3153 sub_order
= (format
== WINE_GGO_HRGB_BITMAP
||
3154 format
== WINE_GGO_VRGB_BITMAP
) ? rgb_order
: bgr_order
;
3155 sub_stride
= render_mode
== FT_RENDER_MODE_LCD
? 1 : src_pitch
;
3156 hmul
= render_mode
== FT_RENDER_MODE_LCD
? 3 : 1;
3157 vmul
= render_mode
== FT_RENDER_MODE_LCD
? 1 : 3;
3159 x_shift
= glyph
->bitmap_left
- (bbox
.xMin
>> 6);
3162 src
+= hmul
* -x_shift
;
3163 src_width
-= hmul
* -x_shift
;
3165 else if ( x_shift
> 0 )
3167 dst
+= x_shift
* sizeof(unsigned int);
3171 y_shift
= (bbox
.yMax
>> 6) - glyph
->bitmap_top
;
3174 src
+= src_pitch
* vmul
* -y_shift
;
3175 src_height
-= vmul
* -y_shift
;
3177 else if ( y_shift
> 0 )
3179 dst
+= y_shift
* pitch
;
3183 w
= min( width
, src_width
/ hmul
);
3184 h
= min( height
, src_height
/ vmul
);
3187 for (x
= 0; x
< w
; x
++)
3189 ((unsigned int *)dst
)[x
] =
3190 ((unsigned int)src
[hmul
* x
+ sub_stride
* sub_order
[0]] << 16) |
3191 ((unsigned int)src
[hmul
* x
+ sub_stride
* sub_order
[1]] << 8) |
3192 ((unsigned int)src
[hmul
* x
+ sub_stride
* sub_order
[2]]);
3194 src
+= src_pitch
* vmul
;
3200 FIXME ( "loaded glyph format %x\n", glyph
->format
);
3207 static unsigned int get_native_glyph_outline(FT_Outline
*outline
, unsigned int buflen
, char *buf
)
3209 TTPOLYGONHEADER
*pph
;
3211 unsigned int needed
= 0, point
= 0, contour
, first_pt
;
3212 unsigned int pph_start
, cpfx
;
3215 for (contour
= 0; contour
< outline
->n_contours
; contour
++)
3217 /* Ignore contours containing one point */
3218 if (point
== outline
->contours
[contour
])
3225 pph
= (TTPOLYGONHEADER
*)(buf
+ needed
);
3229 pph
->dwType
= TT_POLYGON_TYPE
;
3230 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
3232 needed
+= sizeof(*pph
);
3234 while (point
<= outline
->contours
[contour
])
3236 ppc
= (TTPOLYCURVE
*)(buf
+ needed
);
3237 type
= outline
->tags
[point
] & FT_Curve_Tag_On
?
3238 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
3243 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
3246 } while (point
<= outline
->contours
[contour
] &&
3247 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
3248 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
3249 /* At the end of a contour Windows adds the start point, but
3251 if (point
> outline
->contours
[contour
] &&
3252 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
))
3255 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
3258 else if (point
<= outline
->contours
[contour
] &&
3259 outline
->tags
[point
] & FT_Curve_Tag_On
)
3261 /* add closing pt for bezier */
3263 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
3272 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
3275 pph
->cb
= needed
- pph_start
;
3280 static unsigned int get_bezier_glyph_outline(FT_Outline
*outline
, unsigned int buflen
, char *buf
)
3282 /* Convert the quadratic Beziers to cubic Beziers.
3283 The parametric eqn for a cubic Bezier is, from PLRM:
3284 r(t) = at^3 + bt^2 + ct + r0
3285 with the control points:
3290 A quadratic Bezier has the form:
3291 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3293 So equating powers of t leads to:
3294 r1 = 2/3 p1 + 1/3 p0
3295 r2 = 2/3 p1 + 1/3 p2
3296 and of course r0 = p0, r3 = p2
3298 int contour
, point
= 0, first_pt
;
3299 TTPOLYGONHEADER
*pph
;
3301 DWORD pph_start
, cpfx
, type
;
3302 FT_Vector cubic_control
[4];
3303 unsigned int needed
= 0;
3305 for (contour
= 0; contour
< outline
->n_contours
; contour
++)
3308 pph
= (TTPOLYGONHEADER
*)(buf
+ needed
);
3312 pph
->dwType
= TT_POLYGON_TYPE
;
3313 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
3315 needed
+= sizeof(*pph
);
3317 while (point
<= outline
->contours
[contour
])
3319 ppc
= (TTPOLYCURVE
*)(buf
+ needed
);
3320 type
= outline
->tags
[point
] & FT_Curve_Tag_On
?
3321 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
3325 if (type
== TT_PRIM_LINE
)
3328 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
3334 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
3337 /* FIXME: Possible optimization in endpoint calculation
3338 if there are two consecutive curves */
3339 cubic_control
[0] = outline
->points
[point
-1];
3340 if (!(outline
->tags
[point
-1] & FT_Curve_Tag_On
))
3342 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
3343 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
3344 cubic_control
[0].x
>>= 1;
3345 cubic_control
[0].y
>>= 1;
3347 if (point
+1 > outline
->contours
[contour
])
3348 cubic_control
[3] = outline
->points
[first_pt
];
3351 cubic_control
[3] = outline
->points
[point
+1];
3352 if (!(outline
->tags
[point
+1] & FT_Curve_Tag_On
))
3354 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
3355 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
3356 cubic_control
[3].x
>>= 1;
3357 cubic_control
[3].y
>>= 1;
3360 /* r1 = 1/3 p0 + 2/3 p1
3361 r2 = 1/3 p2 + 2/3 p1 */
3362 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
3363 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
3364 cubic_control
[2] = cubic_control
[1];
3365 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
3366 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
3367 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
3368 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
3371 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
3372 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
3373 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
3378 } while (point
<= outline
->contours
[contour
] &&
3379 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
3380 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
3381 /* At the end of a contour Windows adds the start point,
3382 but only for Beziers and we've already done that.
3384 if (point
<= outline
->contours
[contour
] &&
3385 outline
->tags
[point
] & FT_Curve_Tag_On
)
3387 /* This is the closing pt of a bezier, but we've already
3388 added it, so just inc point and carry on */
3396 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
3399 pph
->cb
= needed
- pph_start
;
3404 static FT_Int
get_load_flags( UINT format
)
3406 FT_Int load_flags
= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
3408 if (format
& GGO_UNHINTED
)
3409 return load_flags
| FT_LOAD_NO_HINTING
;
3411 switch (format
& ~GGO_GLYPH_INDEX
)
3414 load_flags
|= FT_LOAD_TARGET_MONO
;
3416 case GGO_GRAY2_BITMAP
:
3417 case GGO_GRAY4_BITMAP
:
3418 case GGO_GRAY8_BITMAP
:
3419 case WINE_GGO_GRAY16_BITMAP
:
3420 load_flags
|= FT_LOAD_TARGET_NORMAL
;
3422 case WINE_GGO_HRGB_BITMAP
:
3423 case WINE_GGO_HBGR_BITMAP
:
3424 load_flags
|= FT_LOAD_TARGET_LCD
;
3426 case WINE_GGO_VRGB_BITMAP
:
3427 case WINE_GGO_VBGR_BITMAP
:
3428 load_flags
|= FT_LOAD_TARGET_LCD_V
;
3435 /*************************************************************
3436 * freetype_get_glyph_outline
3438 static UINT
freetype_get_glyph_outline( struct gdi_font
*font
, UINT glyph
, UINT format
,
3439 GLYPHMETRICS
*lpgm
, ABC
*abc
, UINT buflen
, void *buf
,
3440 const MAT2
*lpmat
, BOOL tategaki
)
3442 struct gdi_font
*base_font
= font
->base_font
? font
->base_font
: font
;
3443 FT_Face ft_face
= get_ft_face( font
);
3444 FT_Glyph_Metrics metrics
;
3447 FT_Int load_flags
= get_load_flags(format
);
3448 FT_Matrix transform_matrices
[3], *matrices
= NULL
;
3449 BOOL vertical_metrics
;
3451 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
, buflen
, buf
, lpmat
);
3453 TRACE("font transform %f %f %f %f\n",
3454 font
->matrix
.eM11
, font
->matrix
.eM12
,
3455 font
->matrix
.eM21
, font
->matrix
.eM22
);
3457 format
&= ~GGO_UNHINTED
;
3459 matrices
= get_transform_matrices( font
, tategaki
, lpmat
, transform_matrices
);
3461 vertical_metrics
= (tategaki
&& FT_HAS_VERTICAL(ft_face
));
3462 /* there is a freetype bug where vertical metrics are only
3463 properly scaled and correct in 2.4.0 or greater */
3464 if (vertical_metrics
&& FT_SimpleVersion
< FT_VERSION_VALUE(2, 4, 0))
3465 vertical_metrics
= FALSE
;
3467 if (matrices
|| format
!= GGO_BITMAP
) load_flags
|= FT_LOAD_NO_BITMAP
;
3468 if (vertical_metrics
) load_flags
|= FT_LOAD_VERTICAL_LAYOUT
;
3470 err
= pFT_Load_Glyph(ft_face
, glyph
, load_flags
);
3471 if (err
&& !(load_flags
& FT_LOAD_NO_HINTING
))
3473 WARN("Failed to load glyph %#x, retrying without hinting. Error %#x.\n", glyph
, err
);
3474 load_flags
|= FT_LOAD_NO_HINTING
;
3475 err
= pFT_Load_Glyph(ft_face
, glyph
, load_flags
);
3479 WARN("Failed to load glyph %#x, error %#x.\n", glyph
, err
);
3483 metrics
= ft_face
->glyph
->metrics
;
3484 if(font
->fake_bold
) {
3485 if (!get_bold_glyph_outline(ft_face
->glyph
, font
->ppem
, &metrics
) && metrics
.width
)
3486 metrics
.width
+= 1 << 6;
3489 /* Some poorly-created fonts contain glyphs that exceed the boundaries set
3490 * by the text metrics. The proper behavior is to clip the glyph metrics to
3491 * fit within the maximums specified in the text metrics. */
3492 if (freetype_set_outline_text_metrics(base_font
) ||
3493 freetype_set_bitmap_text_metrics(base_font
)) {
3494 TEXTMETRICW
*ptm
= &base_font
->otm
.otmTextMetrics
;
3495 INT top
= min( metrics
.horiBearingY
, ptm
->tmAscent
<< 6 );
3496 INT bottom
= max( metrics
.horiBearingY
- metrics
.height
, -(ptm
->tmDescent
<< 6) );
3497 metrics
.horiBearingY
= top
;
3498 metrics
.height
= top
- bottom
;
3500 /* TODO: Are we supposed to clip the width as well...? */
3501 /* metrics.width = min( metrics.width, ptm->tmMaxCharWidth << 6 ); */
3504 bbox
= get_transformed_bbox( &metrics
, matrices
);
3505 compute_metrics( font
, bbox
, &metrics
, tategaki
, vertical_metrics
, matrices
, lpgm
, abc
);
3510 return 1; /* FIXME */
3513 return get_mono_glyph_bitmap( ft_face
->glyph
, bbox
, font
->fake_bold
,
3514 matrices
, buflen
, buf
);
3516 case GGO_GRAY2_BITMAP
:
3517 case GGO_GRAY4_BITMAP
:
3518 case GGO_GRAY8_BITMAP
:
3519 case WINE_GGO_GRAY16_BITMAP
:
3520 return get_antialias_glyph_bitmap( ft_face
->glyph
, bbox
, format
, font
->fake_bold
,
3521 matrices
, buflen
, buf
);
3523 case WINE_GGO_HRGB_BITMAP
:
3524 case WINE_GGO_HBGR_BITMAP
:
3525 case WINE_GGO_VRGB_BITMAP
:
3526 case WINE_GGO_VBGR_BITMAP
:
3527 return get_subpixel_glyph_bitmap( ft_face
->glyph
, bbox
, format
, font
->fake_bold
,
3528 matrices
, lpgm
, buflen
, buf
);
3531 if (ft_face
->glyph
->format
== ft_glyph_format_outline
)
3533 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
3536 if (buflen
== 0) buf
= NULL
;
3538 if (matrices
&& buf
)
3539 pFT_Outline_Transform( outline
, &matrices
[matrix_vert
] );
3541 needed
= get_native_glyph_outline(outline
, buflen
, NULL
);
3543 if (!buf
|| !buflen
) return needed
;
3544 if (needed
> buflen
) return GDI_ERROR
;
3545 return get_native_glyph_outline(outline
, buflen
, buf
);
3547 TRACE("loaded a bitmap\n");
3551 if (ft_face
->glyph
->format
== ft_glyph_format_outline
)
3553 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
3556 if (buflen
== 0) buf
= NULL
;
3558 if (matrices
&& buf
)
3559 pFT_Outline_Transform( outline
, &matrices
[matrix_vert
] );
3561 needed
= get_bezier_glyph_outline(outline
, buflen
, NULL
);
3563 if (!buf
|| !buflen
) return needed
;
3564 if (needed
> buflen
) return GDI_ERROR
;
3565 return get_bezier_glyph_outline(outline
, buflen
, buf
);
3567 TRACE("loaded a bitmap\n");
3571 FIXME("Unsupported format %d\n", format
);
3576 /*************************************************************
3577 * freetype_set_bitmap_text_metrics
3579 static BOOL
freetype_set_bitmap_text_metrics( struct gdi_font
*font
)
3581 FT_Face ft_face
= get_ft_face( font
);
3582 FT_WinFNT_HeaderRec winfnt_header
;
3584 if (font
->otm
.otmSize
) return TRUE
; /* already set */
3585 font
->otm
.otmSize
= offsetof( OUTLINETEXTMETRICW
, otmFiller
);
3587 #define TM font->otm.otmTextMetrics
3588 if(!pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
3590 TM
.tmHeight
= winfnt_header
.pixel_height
;
3591 TM
.tmAscent
= winfnt_header
.ascent
;
3592 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
3593 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
3594 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
3595 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
3596 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
3597 TM
.tmWeight
= winfnt_header
.weight
;
3599 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
3600 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
3601 TM
.tmFirstChar
= winfnt_header
.first_char
;
3602 TM
.tmLastChar
= winfnt_header
.last_char
;
3603 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
3604 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
3605 TM
.tmItalic
= winfnt_header
.italic
;
3606 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
3607 TM
.tmCharSet
= winfnt_header
.charset
;
3611 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
3612 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
3613 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
3614 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
3615 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
3616 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
3617 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
3618 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
3620 TM
.tmDigitizedAspectX
= 96; /* FIXME */
3621 TM
.tmDigitizedAspectY
= 96; /* FIXME */
3623 TM
.tmLastChar
= 255;
3624 TM
.tmDefaultChar
= 32;
3625 TM
.tmBreakChar
= 32;
3626 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
3627 /* NB inverted meaning of TMPF_FIXED_PITCH */
3628 TM
.tmPitchAndFamily
= FT_IS_FIXED_WIDTH(ft_face
) ? 0 : TMPF_FIXED_PITCH
;
3629 TM
.tmCharSet
= font
->charset
;
3631 TM
.tmUnderlined
= font
->lf
.lfUnderline
? 0xff : 0;
3632 TM
.tmStruckOut
= font
->lf
.lfStrikeOut
? 0xff : 0;
3635 TM
.tmWeight
= FW_BOLD
;
3642 static BOOL
face_has_symbol_charmap(FT_Face ft_face
)
3646 for(i
= 0; i
< ft_face
->num_charmaps
; i
++)
3648 if(ft_face
->charmaps
[i
]->encoding
== FT_ENCODING_MS_SYMBOL
)
3654 /*************************************************************
3655 * freetype_set_outline_text_metrics
3657 static BOOL
freetype_set_outline_text_metrics( struct gdi_font
*font
)
3659 FT_Face ft_face
= get_ft_face( font
);
3662 TT_HoriHeader
*pHori
;
3663 TT_Postscript
*pPost
;
3665 INT ascent
, descent
;
3668 TRACE("font=%p\n", font
);
3670 if (!font
->scalable
) return FALSE
;
3671 if (font
->otm
.otmSize
) return TRUE
; /* already set */
3673 /* note: we store actual pointers in the names instead of offsets,
3674 they are fixed up when returned to the app */
3675 if (!(font
->otm
.otmpFullName
= (char *)get_face_name( ft_face
, TT_NAME_ID_UNIQUE_ID
, system_lcid
)))
3677 static const WCHAR fake_nameW
[] = {'f','a','k','e',' ','n','a','m','e', 0};
3678 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w((WCHAR
*)font
->otm
.otmpFamilyName
));
3679 font
->otm
.otmpFullName
= (char *)wcsdup( fake_nameW
);
3681 needed
= sizeof(font
->otm
) + (lstrlenW( (WCHAR
*)font
->otm
.otmpFamilyName
) + 1 +
3682 lstrlenW( (WCHAR
*)font
->otm
.otmpStyleName
) + 1 +
3683 lstrlenW( (WCHAR
*)font
->otm
.otmpFaceName
) + 1 +
3684 lstrlenW( (WCHAR
*)font
->otm
.otmpFullName
) + 1) * sizeof(WCHAR
);
3686 em_scale
= (FT_Fixed
)pFT_MulDiv(font
->ppem
, 1 << 16, ft_face
->units_per_EM
);
3688 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
3690 FIXME("Can't find OS/2 table - not TT font?\n");
3694 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
3696 FIXME("Can't find HHEA table - not TT font?\n");
3700 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
3702 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",
3703 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
3704 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
3705 pOS2
->xAvgCharWidth
,
3706 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
3707 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
3708 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
3710 font
->otm
.otmSize
= needed
;
3712 #define TM font->otm.otmTextMetrics
3714 windescent
= get_fixed_windescent(pOS2
->usWinDescent
);
3715 if(pOS2
->usWinAscent
+ windescent
== 0) {
3716 ascent
= pHori
->Ascender
;
3717 descent
= -pHori
->Descender
;
3719 ascent
= pOS2
->usWinAscent
;
3720 descent
= windescent
;
3723 font
->ntmAvgWidth
= pOS2
->xAvgCharWidth
;
3725 #define SCALE_X(x) (pFT_MulFix(x, em_scale))
3726 #define SCALE_Y(y) (pFT_MulFix(y, em_scale))
3729 TM
.tmAscent
= font
->yMax
;
3730 TM
.tmDescent
= -font
->yMin
;
3731 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
3733 TM
.tmAscent
= SCALE_Y(ascent
);
3734 TM
.tmDescent
= SCALE_Y(descent
);
3735 TM
.tmInternalLeading
= SCALE_Y(ascent
+ descent
- ft_face
->units_per_EM
);
3738 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
3741 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
3743 TM
.tmExternalLeading
= max(0, SCALE_Y(pHori
->Line_Gap
-
3744 ((ascent
+ descent
) -
3745 (pHori
->Ascender
- pHori
->Descender
))));
3747 TM
.tmAveCharWidth
= SCALE_X(pOS2
->xAvgCharWidth
);
3748 if (TM
.tmAveCharWidth
== 0) {
3749 TM
.tmAveCharWidth
= 1;
3751 TM
.tmMaxCharWidth
= SCALE_X(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
);
3752 TM
.tmWeight
= FW_REGULAR
;
3753 if (font
->fake_bold
)
3754 TM
.tmWeight
= FW_BOLD
;
3757 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)
3759 if (pOS2
->usWeightClass
> FW_MEDIUM
)
3760 TM
.tmWeight
= pOS2
->usWeightClass
;
3762 else if (pOS2
->usWeightClass
<= FW_MEDIUM
)
3763 TM
.tmWeight
= pOS2
->usWeightClass
;
3766 TM
.tmDigitizedAspectX
= 96; /* FIXME */
3767 TM
.tmDigitizedAspectY
= 96; /* FIXME */
3768 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
3769 * symbol range to 0 - f0ff
3772 if (face_has_symbol_charmap(ft_face
) || (pOS2
->usFirstCharIndex
>= 0xf000 && pOS2
->usFirstCharIndex
< 0xf100))
3775 switch (PRIMARYLANGID(system_lcid
))
3778 TM
.tmLastChar
= 0xf896;
3782 case LANG_LITHUANIAN
:
3783 TM
.tmLastChar
= 0xf8fd;
3786 TM
.tmLastChar
= 0xf0ff;
3788 TM
.tmBreakChar
= 0x20;
3789 TM
.tmDefaultChar
= 0x1f;
3793 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
; /* Should be the first char in the cmap */
3794 TM
.tmLastChar
= pOS2
->usLastCharIndex
; /* Should be min(cmap_last, os2_last) */
3796 if(pOS2
->usFirstCharIndex
<= 1)
3797 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
+ 2;
3798 else if (pOS2
->usFirstCharIndex
> 0xff)
3799 TM
.tmBreakChar
= 0x20;
3801 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
;
3802 TM
.tmDefaultChar
= TM
.tmBreakChar
- 1;
3804 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
3805 TM
.tmUnderlined
= font
->lf
.lfUnderline
? 255 : 0;
3806 TM
.tmStruckOut
= font
->lf
.lfStrikeOut
? 255 : 0;
3808 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
3809 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
3810 (pOS2
->version
== 0xFFFFU
||
3811 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
3812 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
3814 TM
.tmPitchAndFamily
= 0;
3816 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
])
3818 case PAN_FAMILY_SCRIPT
:
3819 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
3822 case PAN_FAMILY_DECORATIVE
:
3823 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
3828 case PAN_FAMILY_TEXT_DISPLAY
:
3829 case PAN_FAMILY_PICTORIAL
: /* symbol fonts get treated as if they were text */
3830 /* which is clearly not what the panose spec says. */
3832 if(TM
.tmPitchAndFamily
== 0 || /* fixed */
3833 pOS2
->panose
[PAN_PROPORTION_INDEX
] == PAN_PROP_MONOSPACED
)
3834 TM
.tmPitchAndFamily
= FF_MODERN
;
3837 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
])
3842 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
3845 case PAN_SERIF_COVE
:
3846 case PAN_SERIF_OBTUSE_COVE
:
3847 case PAN_SERIF_SQUARE_COVE
:
3848 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
3849 case PAN_SERIF_SQUARE
:
3850 case PAN_SERIF_THIN
:
3851 case PAN_SERIF_BONE
:
3852 case PAN_SERIF_EXAGGERATED
:
3853 case PAN_SERIF_TRIANGLE
:
3854 TM
.tmPitchAndFamily
|= FF_ROMAN
;
3857 case PAN_SERIF_NORMAL_SANS
:
3858 case PAN_SERIF_OBTUSE_SANS
:
3859 case PAN_SERIF_PERP_SANS
:
3860 case PAN_SERIF_FLARED
:
3861 case PAN_SERIF_ROUNDED
:
3862 TM
.tmPitchAndFamily
|= FF_SWISS
;
3869 if(FT_IS_SCALABLE(ft_face
))
3870 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
3872 if(FT_IS_SFNT(ft_face
))
3874 if (font
->ntmFlags
& NTM_PS_OPENTYPE
)
3875 TM
.tmPitchAndFamily
|= TMPF_DEVICE
;
3877 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
3880 TM
.tmCharSet
= font
->charset
;
3882 font
->otm
.otmFiller
= 0;
3883 memcpy(&font
->otm
.otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
3884 font
->otm
.otmfsSelection
= pOS2
->fsSelection
;
3885 if (font
->fake_italic
)
3886 font
->otm
.otmfsSelection
|= 1;
3887 if (font
->fake_bold
)
3888 font
->otm
.otmfsSelection
|= 1 << 5;
3889 /* Only return valid bits that define embedding and subsetting restrictions */
3890 font
->otm
.otmfsType
= pOS2
->fsType
& 0x30e;
3891 font
->otm
.otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
3892 font
->otm
.otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
3893 font
->otm
.otmItalicAngle
= 0; /* POST table */
3894 font
->otm
.otmAscent
= SCALE_Y(pOS2
->sTypoAscender
);
3895 font
->otm
.otmDescent
= SCALE_Y(pOS2
->sTypoDescender
);
3896 font
->otm
.otmLineGap
= SCALE_Y(pOS2
->sTypoLineGap
);
3897 font
->otm
.otmsCapEmHeight
= SCALE_Y(pOS2
->sCapHeight
);
3898 font
->otm
.otmsXHeight
= SCALE_Y(pOS2
->sxHeight
);
3899 font
->otm
.otmrcFontBox
.left
= SCALE_X(ft_face
->bbox
.xMin
);
3900 font
->otm
.otmrcFontBox
.right
= SCALE_X(ft_face
->bbox
.xMax
);
3901 font
->otm
.otmrcFontBox
.top
= SCALE_Y(ft_face
->bbox
.yMax
);
3902 font
->otm
.otmrcFontBox
.bottom
= SCALE_Y(ft_face
->bbox
.yMin
);
3903 font
->otm
.otmMacAscent
= TM
.tmAscent
;
3904 font
->otm
.otmMacDescent
= -TM
.tmDescent
;
3905 font
->otm
.otmMacLineGap
= SCALE_Y(pHori
->Line_Gap
);
3906 font
->otm
.otmusMinimumPPEM
= 0; /* TT Header */
3907 font
->otm
.otmptSubscriptSize
.x
= SCALE_X(pOS2
->ySubscriptXSize
);
3908 font
->otm
.otmptSubscriptSize
.y
= SCALE_Y(pOS2
->ySubscriptYSize
);
3909 font
->otm
.otmptSubscriptOffset
.x
= SCALE_X(pOS2
->ySubscriptXOffset
);
3910 font
->otm
.otmptSubscriptOffset
.y
= SCALE_Y(pOS2
->ySubscriptYOffset
);
3911 font
->otm
.otmptSuperscriptSize
.x
= SCALE_X(pOS2
->ySuperscriptXSize
);
3912 font
->otm
.otmptSuperscriptSize
.y
= SCALE_Y(pOS2
->ySuperscriptYSize
);
3913 font
->otm
.otmptSuperscriptOffset
.x
= SCALE_X(pOS2
->ySuperscriptXOffset
);
3914 font
->otm
.otmptSuperscriptOffset
.y
= SCALE_Y(pOS2
->ySuperscriptYOffset
);
3915 font
->otm
.otmsStrikeoutSize
= SCALE_Y(pOS2
->yStrikeoutSize
);
3916 font
->otm
.otmsStrikeoutPosition
= SCALE_Y(pOS2
->yStrikeoutPosition
);
3918 font
->otm
.otmsUnderscoreSize
= 0;
3919 font
->otm
.otmsUnderscorePosition
= 0;
3921 font
->otm
.otmsUnderscoreSize
= SCALE_Y(pPost
->underlineThickness
);
3922 font
->otm
.otmsUnderscorePosition
= SCALE_Y(pPost
->underlinePosition
);
3930 /*************************************************************
3931 * freetype_get_char_width_info
3933 static BOOL
freetype_get_char_width_info( struct gdi_font
*font
, struct char_width_info
*info
)
3935 FT_Face ft_face
= get_ft_face( font
);
3936 TT_HoriHeader
*pHori
;
3938 TRACE("%p, %p\n", font
, info
);
3940 if ((pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
)))
3942 FT_Fixed em_scale
= pFT_MulDiv(font
->ppem
, 1 << 16, ft_face
->units_per_EM
);
3943 info
->lsb
= (SHORT
)pFT_MulFix(pHori
->min_Left_Side_Bearing
, em_scale
);
3944 info
->rsb
= (SHORT
)pFT_MulFix(pHori
->min_Right_Side_Bearing
, em_scale
);
3951 /*************************************************************
3952 * freetype_get_unicode_ranges
3954 * Retrieve a list of supported Unicode ranges for a given font.
3955 * Can be called with NULL gs to calculate the buffer size. Returns
3956 * the number of ranges found.
3958 static UINT
freetype_get_unicode_ranges( struct gdi_font
*font
, GLYPHSET
*gs
)
3960 FT_Face ft_face
= get_ft_face( font
);
3961 UINT num_ranges
= 0;
3963 if (ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
3966 FT_ULong char_code
, char_code_prev
;
3969 char_code_prev
= char_code
= pFT_Get_First_Char(ft_face
, &glyph_code
);
3971 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
3972 ft_face
->num_glyphs
, glyph_code
, char_code
);
3974 if (!glyph_code
) return 0;
3978 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
3979 gs
->ranges
[0].cGlyphs
= 0;
3980 gs
->cGlyphsSupported
= 0;
3986 if (char_code
< char_code_prev
)
3988 ERR("expected increasing char code from FT_Get_Next_Char\n");
3991 if (char_code
- char_code_prev
> 1)
3996 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
3997 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
3998 gs
->cGlyphsSupported
++;
4003 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
4004 gs
->cGlyphsSupported
++;
4006 char_code_prev
= char_code
;
4007 char_code
= pFT_Get_Next_Char(ft_face
, char_code
, &glyph_code
);
4012 DWORD encoding
= RtlUlongByteSwap(ft_face
->charmap
->encoding
);
4013 FIXME("encoding %s not supported\n", debugstr_an((char *)&encoding
, 4));
4019 /*************************************************************************
4020 * Kerning support for TrueType fonts
4023 struct TT_kern_table
4029 struct TT_kern_subtable
4038 USHORT horizontal
: 1;
4040 USHORT cross_stream
: 1;
4041 USHORT override
: 1;
4042 USHORT reserved1
: 4;
4048 struct TT_format0_kern_subtable
4052 USHORT entrySelector
;
4063 static DWORD
parse_format0_kern_subtable(struct gdi_font
*font
,
4064 const struct TT_format0_kern_subtable
*tt_f0_ks
,
4065 const USHORT
*glyph_to_char
,
4066 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
4068 FT_Face ft_face
= get_ft_face( font
);
4070 const struct TT_kern_pair
*tt_kern_pair
;
4072 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, ft_face
->units_per_EM
);
4074 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
4076 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
4077 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
4078 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
4080 if (!kern_pair
|| !cPairs
)
4083 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
4085 nPairs
= min(nPairs
, cPairs
);
4087 for (i
= 0; i
< nPairs
; i
++)
4089 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
4090 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
4091 /* this algorithm appears to better match what Windows does */
4092 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
4093 if (kern_pair
->iKernAmount
< 0)
4095 kern_pair
->iKernAmount
-= ft_face
->units_per_EM
/ 2;
4096 kern_pair
->iKernAmount
-= font
->ppem
;
4098 else if (kern_pair
->iKernAmount
> 0)
4100 kern_pair
->iKernAmount
+= ft_face
->units_per_EM
/ 2;
4101 kern_pair
->iKernAmount
+= font
->ppem
;
4103 kern_pair
->iKernAmount
/= ft_face
->units_per_EM
;
4105 TRACE("left %u right %u value %d\n",
4106 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
4110 TRACE("copied %u entries\n", nPairs
);
4114 /*************************************************************
4115 * freetype_get_kerning_pairs
4117 static UINT
freetype_get_kerning_pairs( struct gdi_font
*font
, KERNINGPAIR
**pairs
)
4119 FT_Face ft_face
= get_ft_face( font
);
4120 UINT length
, count
= 0;
4122 const struct TT_kern_table
*tt_kern_table
;
4123 const struct TT_kern_subtable
*tt_kern_subtable
;
4125 USHORT
*glyph_to_char
;
4127 length
= freetype_get_font_data(font
, MS_KERN_TAG
, 0, NULL
, 0);
4129 if (length
== GDI_ERROR
)
4131 TRACE("no kerning data in the font\n");
4135 buf
= malloc( length
);
4138 freetype_get_font_data(font
, MS_KERN_TAG
, 0, buf
, length
);
4140 /* build a glyph index to char code map */
4141 glyph_to_char
= calloc( sizeof(USHORT
), 65536 );
4148 if (ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
4154 char_code
= pFT_Get_First_Char(ft_face
, &glyph_code
);
4156 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
4157 ft_face
->num_glyphs
, glyph_code
, char_code
);
4161 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
4163 /* FIXME: This doesn't match what Windows does: it does some fancy
4164 * things with duplicate glyph index to char code mappings, while
4165 * we just avoid overriding existing entries.
4167 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
4168 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
4170 char_code
= pFT_Get_Next_Char(ft_face
, char_code
, &glyph_code
);
4175 DWORD encoding
= RtlUlongByteSwap(ft_face
->charmap
->encoding
);
4178 FIXME("encoding %s not supported\n", debugstr_an((char *)&encoding
, 4));
4179 for (n
= 0; n
<= 65535; n
++)
4180 glyph_to_char
[n
] = (USHORT
)n
;
4183 tt_kern_table
= buf
;
4184 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
4185 TRACE("version %u, nTables %u\n",
4186 GET_BE_WORD(tt_kern_table
->version
), nTables
);
4188 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
4190 for (i
= 0; i
< nTables
; i
++)
4192 struct TT_kern_subtable tt_kern_subtable_copy
;
4194 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
4195 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
4196 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
4198 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
4199 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
4200 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
4202 /* According to the TrueType specification this is the only format
4203 * that will be properly interpreted by Windows and OS/2
4205 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
4207 DWORD new_chunk
, old_total
= count
;
4209 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
4210 glyph_to_char
, NULL
, 0);
4213 *pairs
= realloc( *pairs
, count
* sizeof(**pairs
));
4215 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
4216 glyph_to_char
, *pairs
+ old_total
, new_chunk
);
4219 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
4221 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
4224 free( glyph_to_char
);
4229 static const struct font_backend_funcs font_funcs
=
4231 freetype_load_fonts
,
4232 fontconfig_enum_family_fallbacks
,
4234 freetype_add_mem_font
,
4236 freetype_get_font_data
,
4237 freetype_get_aa_flags
,
4238 freetype_get_glyph_index
,
4239 freetype_get_default_glyph
,
4240 freetype_get_glyph_outline
,
4241 freetype_get_unicode_ranges
,
4242 freetype_get_char_width_info
,
4243 freetype_set_outline_text_metrics
,
4244 freetype_set_bitmap_text_metrics
,
4245 freetype_get_kerning_pairs
,
4246 freetype_destroy_font
4249 const struct font_backend_funcs
*init_freetype_lib(void)
4251 if (!init_freetype()) return NULL
;
4252 #ifdef SONAME_LIBFONTCONFIG
4255 NtQueryDefaultLocale( FALSE
, &system_lcid
);
4259 #else /* HAVE_FREETYPE */
4261 const struct font_backend_funcs
*init_freetype_lib(void)
4266 #endif /* HAVE_FREETYPE */