2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
5 * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
7 * This file contains the WineEng* functions.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
29 #include "wine/port.h"
33 #ifdef HAVE_SYS_STAT_H
34 # include <sys/stat.h>
36 #ifdef HAVE_SYS_MMAN_H
37 # include <sys/mman.h>
46 #ifdef HAVE_CARBON_CARBON_H
47 #define LoadResource __carbon_LoadResource
48 #define CompareString __carbon_CompareString
49 #define GetCurrentThread __carbon_GetCurrentThread
50 #define GetCurrentProcess __carbon_GetCurrentProcess
51 #define AnimatePalette __carbon_AnimatePalette
52 #define EqualRgn __carbon_EqualRgn
53 #define FillRgn __carbon_FillRgn
54 #define FrameRgn __carbon_FrameRgn
55 #define GetPixel __carbon_GetPixel
56 #define InvertRgn __carbon_InvertRgn
57 #define LineTo __carbon_LineTo
58 #define OffsetRgn __carbon_OffsetRgn
59 #define PaintRgn __carbon_PaintRgn
60 #define Polygon __carbon_Polygon
61 #define ResizePalette __carbon_ResizePalette
62 #define SetRectRgn __carbon_SetRectRgn
63 #include <Carbon/Carbon.h>
66 #undef GetCurrentThread
68 #undef GetCurrentProcess
81 #endif /* HAVE_CARBON_CARBON_H */
83 #ifdef HAVE_FT2BUILD_H
85 #include FT_FREETYPE_H
88 #include FT_TRUETYPE_TABLES_H
89 #include FT_SFNT_NAMES_H
90 #include FT_TRUETYPE_IDS_H
92 #include FT_TRIGONOMETRY_H
94 #include FT_WINFONTS_H
95 #ifdef FT_LCD_FILTER_H
96 #include FT_LCD_FILTER_H
98 #endif /* HAVE_FT2BUILD_H */
100 #include "ntstatus.h"
101 #define WIN32_NO_STATUS
104 #include "winternl.h"
105 #include "winerror.h"
108 #include "gdi_private.h"
109 #include "wine/debug.h"
110 #include "wine/list.h"
112 #include "resource.h"
116 WINE_DEFAULT_DEBUG_CHANNEL(font
);
118 #ifndef HAVE_FT_TRUETYPEENGINETYPE
121 FT_TRUETYPE_ENGINE_TYPE_NONE
= 0,
122 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED
,
123 FT_TRUETYPE_ENGINE_TYPE_PATENTED
124 } FT_TrueTypeEngineType
;
127 static FT_Library library
= 0;
134 static FT_Version_t FT_Version
;
135 static DWORD FT_SimpleVersion
;
136 #define FT_VERSION_VALUE(major, minor, patch) (((major) << 16) | ((minor) << 8) | (patch))
138 static void *ft_handle
= NULL
;
140 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
141 MAKE_FUNCPTR(FT_Done_Face
);
142 MAKE_FUNCPTR(FT_Get_Char_Index
);
143 MAKE_FUNCPTR(FT_Get_First_Char
);
144 MAKE_FUNCPTR(FT_Get_Next_Char
);
145 MAKE_FUNCPTR(FT_Get_Sfnt_Name
);
146 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count
);
147 MAKE_FUNCPTR(FT_Get_Sfnt_Table
);
148 MAKE_FUNCPTR(FT_Get_WinFNT_Header
);
149 MAKE_FUNCPTR(FT_Init_FreeType
);
150 MAKE_FUNCPTR(FT_Library_Version
);
151 MAKE_FUNCPTR(FT_Load_Glyph
);
152 MAKE_FUNCPTR(FT_Load_Sfnt_Table
);
153 MAKE_FUNCPTR(FT_Matrix_Multiply
);
154 MAKE_FUNCPTR(FT_MulDiv
);
155 #ifdef FT_MULFIX_INLINED
156 #define pFT_MulFix FT_MULFIX_INLINED
158 MAKE_FUNCPTR(FT_MulFix
);
160 MAKE_FUNCPTR(FT_New_Face
);
161 MAKE_FUNCPTR(FT_New_Memory_Face
);
162 MAKE_FUNCPTR(FT_Outline_Get_Bitmap
);
163 MAKE_FUNCPTR(FT_Outline_Get_CBox
);
164 MAKE_FUNCPTR(FT_Outline_Transform
);
165 MAKE_FUNCPTR(FT_Outline_Translate
);
166 MAKE_FUNCPTR(FT_Render_Glyph
);
167 MAKE_FUNCPTR(FT_Set_Charmap
);
168 MAKE_FUNCPTR(FT_Set_Pixel_Sizes
);
169 MAKE_FUNCPTR(FT_Vector_Length
);
170 MAKE_FUNCPTR(FT_Vector_Transform
);
171 MAKE_FUNCPTR(FT_Vector_Unit
);
172 static FT_Error (*pFT_Outline_Embolden
)(FT_Outline
*, FT_Pos
);
173 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type
)(FT_Library
);
174 #ifdef FT_LCD_FILTER_H
175 static FT_Error (*pFT_Library_SetLcdFilter
)(FT_Library
, FT_LcdFilter
);
177 static FT_Error (*pFT_Property_Set
)(FT_Library
, const FT_String
*, const FT_String
*, const void *);
179 #ifdef SONAME_LIBFONTCONFIG
180 #include <fontconfig/fontconfig.h>
181 MAKE_FUNCPTR(FcConfigSubstitute
);
182 MAKE_FUNCPTR(FcDefaultSubstitute
);
183 MAKE_FUNCPTR(FcFontList
);
184 MAKE_FUNCPTR(FcFontMatch
);
185 MAKE_FUNCPTR(FcFontSetDestroy
);
186 MAKE_FUNCPTR(FcInit
);
187 MAKE_FUNCPTR(FcPatternAddString
);
188 MAKE_FUNCPTR(FcPatternCreate
);
189 MAKE_FUNCPTR(FcPatternDestroy
);
190 MAKE_FUNCPTR(FcPatternGetBool
);
191 MAKE_FUNCPTR(FcPatternGetInteger
);
192 MAKE_FUNCPTR(FcPatternGetString
);
193 MAKE_FUNCPTR(FcConfigGetFontDirs
);
194 MAKE_FUNCPTR(FcConfigGetCurrent
);
195 MAKE_FUNCPTR(FcCacheCopySet
);
196 MAKE_FUNCPTR(FcCacheNumSubdir
);
197 MAKE_FUNCPTR(FcCacheSubdir
);
198 MAKE_FUNCPTR(FcDirCacheRead
);
199 MAKE_FUNCPTR(FcDirCacheUnload
);
200 MAKE_FUNCPTR(FcStrListCreate
);
201 MAKE_FUNCPTR(FcStrListDone
);
202 MAKE_FUNCPTR(FcStrListNext
);
203 MAKE_FUNCPTR(FcStrSetAdd
);
204 MAKE_FUNCPTR(FcStrSetCreate
);
205 MAKE_FUNCPTR(FcStrSetDestroy
);
206 MAKE_FUNCPTR(FcStrSetMember
);
208 #define FC_NAMELANG "namelang"
211 #define FC_PRGNAME "prgname"
213 #endif /* SONAME_LIBFONTCONFIG */
218 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
219 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
220 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
223 #ifndef ft_encoding_none
224 #define FT_ENCODING_NONE ft_encoding_none
226 #ifndef ft_encoding_ms_symbol
227 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
229 #ifndef ft_encoding_unicode
230 #define FT_ENCODING_UNICODE ft_encoding_unicode
232 #ifndef ft_encoding_apple_roman
233 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
236 #ifdef WORDS_BIGENDIAN
237 #define GET_BE_WORD(x) (x)
238 #define GET_BE_DWORD(x) (x)
240 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
241 #define GET_BE_DWORD(x) RtlUlongByteSwap(x)
245 #define GASP_GRIDFIT 0x01
246 #define GASP_DOGRAY 0x02
248 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
249 So to let this compile on older versions of FreeType we'll define the
250 new structure here. */
252 FT_Short height
, width
;
253 FT_Pos size
, x_ppem
, y_ppem
;
256 struct font_private_data
259 struct font_mapping
*mapping
;
262 static inline FT_Face
get_ft_face( struct gdi_font
*font
)
264 return ((struct font_private_data
*)font
->private)->ft_face
;
267 static const struct font_callback_funcs
*callback_funcs
;
279 static struct list mappings_list
= LIST_INIT( mappings_list
);
281 static UINT default_aa_flags
;
282 static LCID system_lcid
;
284 static BOOL CDECL
freetype_set_outline_text_metrics( struct gdi_font
*font
);
285 static BOOL CDECL
freetype_set_bitmap_text_metrics( struct gdi_font
*font
);
287 /****************************************
288 * Notes on .fon files
290 * The fonts System, FixedSys and Terminal are special. There are typically multiple
291 * versions installed for different resolutions and codepages. Windows stores which one to use
292 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
294 * FIXEDFON.FON FixedSys
296 * OEMFONT.FON Terminal
297 * LogPixels Current dpi set by the display control panel applet
298 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
299 * also has a LogPixels value that appears to mirror this)
301 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
302 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
303 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
304 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
305 * so that makes sense.
307 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
308 * to be mapped into the registry on Windows 2000 at least).
311 * ega80woa.fon=ega80850.fon
312 * ega40woa.fon=ega40850.fon
313 * cga80woa.fon=cga80850.fon
314 * cga40woa.fon=cga40850.fon
317 #ifdef HAVE_CARBON_CARBON_H
318 static char *find_cache_dir(void)
322 static char cached_path
[MAX_PATH
];
323 static const char *wine
= "/Wine", *fonts
= "/Fonts";
325 if(*cached_path
) return cached_path
;
327 err
= FSFindFolder(kUserDomain
, kCachedDataFolderType
, kCreateFolder
, &ref
);
330 WARN("can't create cached data folder\n");
333 err
= FSRefMakePath(&ref
, (unsigned char*)cached_path
, sizeof(cached_path
));
336 WARN("can't create cached data path\n");
340 if(strlen(cached_path
) + strlen(wine
) + strlen(fonts
) + 1 > sizeof(cached_path
))
342 ERR("Could not create full path\n");
346 strcat(cached_path
, wine
);
348 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
350 WARN("Couldn't mkdir %s\n", cached_path
);
354 strcat(cached_path
, fonts
);
355 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
357 WARN("Couldn't mkdir %s\n", cached_path
);
364 /******************************************************************
367 * Extracts individual TrueType font files from a Mac suitcase font
368 * and saves them into the user's caches directory (see
370 * Returns a NULL terminated array of filenames.
372 * We do this because they are apps that try to read ttf files
373 * themselves and they don't like Mac suitcase files.
375 static char **expand_mac_font(const char *path
)
378 ResFileRefNum res_ref
;
382 const char *filename
;
386 unsigned int size
, max_size
;
389 TRACE("path %s\n", path
);
391 s
= FSPathMakeRef((unsigned char*)path
, &ref
, FALSE
);
394 WARN("failed to get ref\n");
398 s
= FSOpenResourceFile(&ref
, 0, NULL
, fsRdPerm
, &res_ref
);
401 TRACE("no data fork, so trying resource fork\n");
402 res_ref
= FSOpenResFile(&ref
, fsRdPerm
);
405 TRACE("unable to open resource fork\n");
412 ret
.array
= RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.max_size
* sizeof(*ret
.array
));
415 CloseResFile(res_ref
);
419 out_dir
= find_cache_dir();
421 filename
= strrchr(path
, '/');
422 if(!filename
) filename
= path
;
425 /* output filename has the form out_dir/filename_%04x.ttf */
426 output_len
= strlen(out_dir
) + 1 + strlen(filename
) + 5 + 5;
433 unsigned short *num_faces_ptr
, num_faces
, face
;
436 ResType fond_res
= FT_MAKE_TAG('F','O','N','D');
438 fond
= Get1IndResource(fond_res
, idx
);
440 TRACE("got fond resource %d\n", idx
);
443 fam_rec
= *(FamRec
**)fond
;
444 num_faces_ptr
= (unsigned short *)(fam_rec
+ 1);
445 num_faces
= GET_BE_WORD(*num_faces_ptr
);
447 assoc
= (AsscEntry
*)(num_faces_ptr
+ 1);
448 TRACE("num faces %04x\n", num_faces
);
449 for(face
= 0; face
< num_faces
; face
++, assoc
++)
452 ResType sfnt_res
= FT_MAKE_TAG('s','f','n','t');
453 unsigned short size
, font_id
;
456 size
= GET_BE_WORD(assoc
->fontSize
);
457 font_id
= GET_BE_WORD(assoc
->fontID
);
460 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id
, size
);
464 TRACE("trying to load sfnt id %04x\n", font_id
);
465 sfnt
= GetResource(sfnt_res
, font_id
);
468 TRACE("can't get sfnt resource %04x\n", font_id
);
472 output
= RtlAllocateHeap(GetProcessHeap(), 0, output_len
);
477 sprintf(output
, "%s/%s_%04x.ttf", out_dir
, filename
, font_id
);
479 fd
= open(output
, O_CREAT
| O_EXCL
| O_WRONLY
, 0600);
480 if(fd
!= -1 || errno
== EEXIST
)
484 unsigned char *sfnt_data
;
487 sfnt_data
= *(unsigned char**)sfnt
;
488 write(fd
, sfnt_data
, GetHandleSize(sfnt
));
492 if(ret
.size
>= ret
.max_size
- 1) /* Always want the last element to be NULL */
495 ret
.array
= RtlReAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.array
, ret
.max_size
* sizeof(*ret
.array
));
497 ret
.array
[ret
.size
++] = output
;
501 WARN("unable to create %s\n", output
);
502 RtlFreeHeap(GetProcessHeap(), 0, output
);
505 ReleaseResource(sfnt
);
508 ReleaseResource(fond
);
511 CloseResFile(res_ref
);
516 #endif /* HAVE_CARBON_CARBON_H */
519 This function builds an FT_Fixed from a double. It fails if the absolute
520 value of the float number is greater than 32768.
522 static inline FT_Fixed
FT_FixedFromFloat(double f
)
528 This function builds an FT_Fixed from a FIXED. It simply put f.value
529 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
531 static inline FT_Fixed
FT_FixedFromFIXED(FIXED f
)
533 return (FT_Fixed
)((int)f
.value
<< 16 | (unsigned int)f
.fract
);
536 static BOOL
is_hinting_enabled(void)
538 static int enabled
= -1;
542 /* Use the >= 2.2.0 function if available */
543 if (pFT_Get_TrueType_Engine_Type
)
545 FT_TrueTypeEngineType type
= pFT_Get_TrueType_Engine_Type(library
);
546 enabled
= (type
== FT_TRUETYPE_ENGINE_TYPE_PATENTED
);
548 else enabled
= FALSE
;
549 TRACE("hinting is %senabled\n", enabled
? "" : "NOT ");
554 static BOOL
is_subpixel_rendering_enabled( void )
556 static int enabled
= -1;
559 /* FreeType >= 2.8.1 offers LCD-optimezed rendering without lcd filters. */
560 if (FT_SimpleVersion
>= FT_VERSION_VALUE(2, 8, 1))
562 #ifdef FT_LCD_FILTER_H
563 else if (pFT_Library_SetLcdFilter
&&
564 pFT_Library_SetLcdFilter( NULL
, 0 ) != FT_Err_Unimplemented_Feature
)
567 else enabled
= FALSE
;
569 TRACE("subpixel rendering is %senabled\n", enabled
? "" : "NOT ");
575 static LPWSTR
strdupW(LPCWSTR p
)
578 DWORD len
= (lstrlenW(p
) + 1) * sizeof(WCHAR
);
579 ret
= RtlAllocateHeap(GetProcessHeap(), 0, len
);
584 static WCHAR
*towstr(const char *str
)
586 DWORD len
= strlen(str
) + 1;
587 WCHAR
*wstr
= RtlAllocateHeap( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
588 RtlMultiByteToUnicodeN( wstr
, len
* sizeof(WCHAR
), &len
, str
, len
);
593 static const LANGID mac_langid_table
[] =
595 MAKELANGID(LANG_ENGLISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ENGLISH */
596 MAKELANGID(LANG_FRENCH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FRENCH */
597 MAKELANGID(LANG_GERMAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GERMAN */
598 MAKELANGID(LANG_ITALIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ITALIAN */
599 MAKELANGID(LANG_DUTCH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_DUTCH */
600 MAKELANGID(LANG_SWEDISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SWEDISH */
601 MAKELANGID(LANG_SPANISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SPANISH */
602 MAKELANGID(LANG_DANISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_DANISH */
603 MAKELANGID(LANG_PORTUGUESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PORTUGUESE */
604 MAKELANGID(LANG_NORWEGIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_NORWEGIAN */
605 MAKELANGID(LANG_HEBREW
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HEBREW */
606 MAKELANGID(LANG_JAPANESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_JAPANESE */
607 MAKELANGID(LANG_ARABIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ARABIC */
608 MAKELANGID(LANG_FINNISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FINNISH */
609 MAKELANGID(LANG_GREEK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GREEK */
610 MAKELANGID(LANG_ICELANDIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ICELANDIC */
611 MAKELANGID(LANG_MALTESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALTESE */
612 MAKELANGID(LANG_TURKISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TURKISH */
613 MAKELANGID(LANG_CROATIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CROATIAN */
614 MAKELANGID(LANG_CHINESE_TRADITIONAL
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CHINESE_TRADITIONAL */
615 MAKELANGID(LANG_URDU
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_URDU */
616 MAKELANGID(LANG_HINDI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HINDI */
617 MAKELANGID(LANG_THAI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_THAI */
618 MAKELANGID(LANG_KOREAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KOREAN */
619 MAKELANGID(LANG_LITHUANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LITHUANIAN */
620 MAKELANGID(LANG_POLISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_POLISH */
621 MAKELANGID(LANG_HUNGARIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HUNGARIAN */
622 MAKELANGID(LANG_ESTONIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ESTONIAN */
623 MAKELANGID(LANG_LATVIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LETTISH */
624 MAKELANGID(LANG_SAMI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SAAMISK */
625 MAKELANGID(LANG_FAEROESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FAEROESE */
626 MAKELANGID(LANG_FARSI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FARSI */
627 MAKELANGID(LANG_RUSSIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_RUSSIAN */
628 MAKELANGID(LANG_CHINESE_SIMPLIFIED
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CHINESE_SIMPLIFIED */
629 MAKELANGID(LANG_DUTCH
,SUBLANG_DUTCH_BELGIAN
), /* TT_MAC_LANGID_FLEMISH */
630 MAKELANGID(LANG_IRISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_IRISH */
631 MAKELANGID(LANG_ALBANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ALBANIAN */
632 MAKELANGID(LANG_ROMANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ROMANIAN */
633 MAKELANGID(LANG_CZECH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CZECH */
634 MAKELANGID(LANG_SLOVAK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SLOVAK */
635 MAKELANGID(LANG_SLOVENIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SLOVENIAN */
636 0, /* TT_MAC_LANGID_YIDDISH */
637 MAKELANGID(LANG_SERBIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SERBIAN */
638 MAKELANGID(LANG_MACEDONIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MACEDONIAN */
639 MAKELANGID(LANG_BULGARIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BULGARIAN */
640 MAKELANGID(LANG_UKRAINIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UKRAINIAN */
641 MAKELANGID(LANG_BELARUSIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BYELORUSSIAN */
642 MAKELANGID(LANG_UZBEK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UZBEK */
643 MAKELANGID(LANG_KAZAK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KAZAKH */
644 MAKELANGID(LANG_AZERI
,SUBLANG_AZERI_CYRILLIC
), /* TT_MAC_LANGID_AZERBAIJANI */
645 0, /* TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT */
646 MAKELANGID(LANG_ARMENIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ARMENIAN */
647 MAKELANGID(LANG_GEORGIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GEORGIAN */
648 0, /* TT_MAC_LANGID_MOLDAVIAN */
649 MAKELANGID(LANG_KYRGYZ
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KIRGHIZ */
650 MAKELANGID(LANG_TAJIK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TAJIKI */
651 MAKELANGID(LANG_TURKMEN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TURKMEN */
652 MAKELANGID(LANG_MONGOLIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MONGOLIAN */
653 MAKELANGID(LANG_MONGOLIAN
,SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA
), /* TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT */
654 MAKELANGID(LANG_PASHTO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PASHTO */
655 0, /* TT_MAC_LANGID_KURDISH */
656 MAKELANGID(LANG_KASHMIRI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KASHMIRI */
657 MAKELANGID(LANG_SINDHI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SINDHI */
658 MAKELANGID(LANG_TIBETAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TIBETAN */
659 MAKELANGID(LANG_NEPALI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_NEPALI */
660 MAKELANGID(LANG_SANSKRIT
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SANSKRIT */
661 MAKELANGID(LANG_MARATHI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MARATHI */
662 MAKELANGID(LANG_BENGALI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BENGALI */
663 MAKELANGID(LANG_ASSAMESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ASSAMESE */
664 MAKELANGID(LANG_GUJARATI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GUJARATI */
665 MAKELANGID(LANG_PUNJABI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PUNJABI */
666 MAKELANGID(LANG_ORIYA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ORIYA */
667 MAKELANGID(LANG_MALAYALAM
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAYALAM */
668 MAKELANGID(LANG_KANNADA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KANNADA */
669 MAKELANGID(LANG_TAMIL
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TAMIL */
670 MAKELANGID(LANG_TELUGU
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TELUGU */
671 MAKELANGID(LANG_SINHALESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SINHALESE */
672 0, /* TT_MAC_LANGID_BURMESE */
673 MAKELANGID(LANG_KHMER
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KHMER */
674 MAKELANGID(LANG_LAO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LAO */
675 MAKELANGID(LANG_VIETNAMESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_VIETNAMESE */
676 MAKELANGID(LANG_INDONESIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_INDONESIAN */
677 0, /* TT_MAC_LANGID_TAGALOG */
678 MAKELANGID(LANG_MALAY
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAY_ROMAN_SCRIPT */
679 0, /* TT_MAC_LANGID_MALAY_ARABIC_SCRIPT */
680 MAKELANGID(LANG_AMHARIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_AMHARIC */
681 MAKELANGID(LANG_TIGRIGNA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TIGRINYA */
682 0, /* TT_MAC_LANGID_GALLA */
683 0, /* TT_MAC_LANGID_SOMALI */
684 MAKELANGID(LANG_SWAHILI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SWAHILI */
685 0, /* TT_MAC_LANGID_RUANDA */
686 0, /* TT_MAC_LANGID_RUNDI */
687 0, /* TT_MAC_LANGID_CHEWA */
688 MAKELANGID(LANG_MALAGASY
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAGASY */
689 MAKELANGID(LANG_ESPERANTO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ESPERANTO */
690 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 95-111 */
691 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 112-127 */
692 MAKELANGID(LANG_WELSH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_WELSH */
693 MAKELANGID(LANG_BASQUE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BASQUE */
694 MAKELANGID(LANG_CATALAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CATALAN */
695 0, /* TT_MAC_LANGID_LATIN */
696 MAKELANGID(LANG_QUECHUA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_QUECHUA */
697 0, /* TT_MAC_LANGID_GUARANI */
698 0, /* TT_MAC_LANGID_AYMARA */
699 MAKELANGID(LANG_TATAR
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TATAR */
700 MAKELANGID(LANG_UIGHUR
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UIGHUR */
701 0, /* TT_MAC_LANGID_DZONGKHA */
702 0, /* TT_MAC_LANGID_JAVANESE */
703 0, /* TT_MAC_LANGID_SUNDANESE */
704 MAKELANGID(LANG_GALICIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GALICIAN */
705 MAKELANGID(LANG_AFRIKAANS
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_AFRIKAANS */
706 MAKELANGID(LANG_BRETON
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BRETON */
707 MAKELANGID(LANG_INUKTITUT
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_INUKTITUT */
708 MAKELANGID(LANG_SCOTTISH_GAELIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SCOTTISH_GAELIC */
709 MAKELANGID(LANG_MANX_GAELIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MANX_GAELIC */
710 MAKELANGID(LANG_IRISH
,SUBLANG_IRISH_IRELAND
), /* TT_MAC_LANGID_IRISH_GAELIC */
711 0, /* TT_MAC_LANGID_TONGAN */
712 0, /* TT_MAC_LANGID_GREEK_POLYTONIC */
713 MAKELANGID(LANG_GREENLANDIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GREELANDIC */
714 MAKELANGID(LANG_AZERI
,SUBLANG_AZERI_LATIN
), /* TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT */
717 static CPTABLEINFO
*get_mac_code_page( const FT_SfntName
*name
)
719 static CPTABLEINFO tables
[100];
720 int id
= name
->encoding_id
;
724 if (name
->encoding_id
== TT_MAC_ID_SIMPLIFIED_CHINESE
) id
= 8; /* special case */
725 if (id
>= ARRAY_SIZE(tables
)) return NULL
;
726 if (!tables
[id
].CodePage
)
728 if (NtGetNlsSectionPtr( 11, 10000 + id
, NULL
, (void **)&ptr
, &size
)) return NULL
;
729 RtlInitCodePageTable( ptr
, &tables
[id
] );
734 static int match_name_table_language( const FT_SfntName
*name
, LANGID lang
)
739 switch (name
->platform_id
)
741 case TT_PLATFORM_MICROSOFT
:
742 res
+= 5; /* prefer the Microsoft name */
743 switch (name
->encoding_id
)
745 case TT_MS_ID_UNICODE_CS
:
746 case TT_MS_ID_SYMBOL_CS
:
747 name_lang
= name
->language_id
;
753 case TT_PLATFORM_MACINTOSH
:
754 if (!get_mac_code_page( name
)) return 0;
755 if (name
->language_id
>= ARRAY_SIZE( mac_langid_table
)) return 0;
756 name_lang
= mac_langid_table
[name
->language_id
];
758 case TT_PLATFORM_APPLE_UNICODE
:
759 res
+= 2; /* prefer Unicode encodings */
760 switch (name
->encoding_id
)
762 case TT_APPLE_ID_DEFAULT
:
763 case TT_APPLE_ID_ISO_10646
:
764 case TT_APPLE_ID_UNICODE_2_0
:
765 if (name
->language_id
>= ARRAY_SIZE( mac_langid_table
)) return 0;
766 name_lang
= mac_langid_table
[name
->language_id
];
775 if (name_lang
== lang
) res
+= 30;
776 else if (PRIMARYLANGID( name_lang
) == PRIMARYLANGID( lang
)) res
+= 20;
777 else if (name_lang
== MAKELANGID( LANG_ENGLISH
, SUBLANG_DEFAULT
)) res
+= 10;
778 else if (lang
== MAKELANGID( LANG_NEUTRAL
, SUBLANG_NEUTRAL
)) res
+= 5 * (0x100000 - name_lang
);
782 static WCHAR
*copy_name_table_string( const FT_SfntName
*name
)
788 switch (name
->platform_id
)
790 case TT_PLATFORM_APPLE_UNICODE
:
791 case TT_PLATFORM_MICROSOFT
:
792 ret
= RtlAllocateHeap( GetProcessHeap(), 0, name
->string_len
+ sizeof(WCHAR
) );
793 for (i
= 0; i
< name
->string_len
/ 2; i
++)
794 ret
[i
] = (name
->string
[i
* 2] << 8) | name
->string
[i
* 2 + 1];
797 case TT_PLATFORM_MACINTOSH
:
798 if (!(cp
= get_mac_code_page( name
))) return NULL
;
799 ret
= RtlAllocateHeap( GetProcessHeap(), 0, (name
->string_len
+ 1) * sizeof(WCHAR
) );
800 RtlCustomCPToUnicodeN( cp
, ret
, name
->string_len
* sizeof(WCHAR
), &i
,
801 (char *)name
->string
, name
->string_len
);
802 ret
[i
/ sizeof(WCHAR
)] = 0;
808 static WCHAR
*get_face_name(FT_Face ft_face
, FT_UShort name_id
, LANGID language_id
)
811 FT_UInt num_names
, name_index
;
812 int res
, best_lang
= 0, best_index
= -1;
814 if (!FT_IS_SFNT(ft_face
)) return NULL
;
816 num_names
= pFT_Get_Sfnt_Name_Count( ft_face
);
818 for (name_index
= 0; name_index
< num_names
; name_index
++)
820 if (pFT_Get_Sfnt_Name( ft_face
, name_index
, &name
)) continue;
821 if (name
.name_id
!= name_id
) continue;
822 res
= match_name_table_language( &name
, language_id
);
826 best_index
= name_index
;
830 if (best_index
!= -1 && !pFT_Get_Sfnt_Name( ft_face
, best_index
, &name
))
832 WCHAR
*ret
= copy_name_table_string( &name
);
833 TRACE( "name %u found platform %u lang %04x %s\n",
834 name_id
, name
.platform_id
, name
.language_id
, debugstr_w( ret
));
840 static WCHAR
*ft_face_get_family_name( FT_Face ft_face
, LANGID langid
)
844 if ((family_name
= get_face_name( ft_face
, TT_NAME_ID_FONT_FAMILY
, langid
)))
847 return towstr( ft_face
->family_name
);
850 static WCHAR
*ft_face_get_style_name( FT_Face ft_face
, LANGID langid
)
854 if ((style_name
= get_face_name( ft_face
, TT_NAME_ID_FONT_SUBFAMILY
, langid
)))
857 return towstr( ft_face
->style_name
);
860 static WCHAR
*ft_face_get_full_name( FT_Face ft_face
, LANGID langid
)
862 static const WCHAR space_w
[] = {' ',0};
863 WCHAR
*full_name
, *style_name
;
866 if ((full_name
= get_face_name( ft_face
, TT_NAME_ID_FULL_NAME
, langid
)))
869 full_name
= ft_face_get_family_name( ft_face
, langid
);
870 style_name
= ft_face_get_style_name( ft_face
, langid
);
872 length
= lstrlenW( full_name
) + lstrlenW( space_w
) + lstrlenW( style_name
) + 1;
873 full_name
= RtlReAllocateHeap( GetProcessHeap(), 0, full_name
, length
* sizeof(WCHAR
) );
875 lstrcatW( full_name
, space_w
);
876 lstrcatW( full_name
, style_name
);
877 RtlFreeHeap( GetProcessHeap(), 0, style_name
);
879 WARN( "full name not found, using %s instead\n", debugstr_w(full_name
) );
883 static inline FT_Fixed
get_font_version( FT_Face ft_face
)
885 FT_Fixed version
= 0;
888 header
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_head
);
889 if (header
) version
= header
->Font_Revision
;
894 static inline DWORD
get_ntm_flags( FT_Face ft_face
)
897 FT_ULong table_size
= 0;
898 FT_WinFNT_HeaderRec winfnt_header
;
900 if (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) flags
|= NTM_ITALIC
;
901 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
) flags
|= NTM_BOLD
;
903 /* fixup the flag for our fake-bold implementation. */
904 if (!FT_IS_SCALABLE( ft_face
) &&
905 !pFT_Get_WinFNT_Header( ft_face
, &winfnt_header
) &&
906 winfnt_header
.weight
> FW_NORMAL
)
909 if (flags
== 0) flags
= NTM_REGULAR
;
911 if (!pFT_Load_Sfnt_Table( ft_face
, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL
, &table_size
))
912 flags
|= NTM_PS_OPENTYPE
;
917 static inline void get_bitmap_size( FT_Face ft_face
, struct bitmap_font_size
*face_size
)
919 My_FT_Bitmap_Size
*size
;
920 FT_WinFNT_HeaderRec winfnt_header
;
922 size
= (My_FT_Bitmap_Size
*)ft_face
->available_sizes
;
923 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
924 size
->height
, size
->width
, size
->size
>> 6,
925 size
->x_ppem
>> 6, size
->y_ppem
>> 6);
926 face_size
->height
= size
->height
;
927 face_size
->width
= size
->width
;
928 face_size
->size
= size
->size
;
929 face_size
->x_ppem
= size
->x_ppem
;
930 face_size
->y_ppem
= size
->y_ppem
;
932 if (!pFT_Get_WinFNT_Header( ft_face
, &winfnt_header
)) {
933 face_size
->internal_leading
= winfnt_header
.internal_leading
;
934 if (winfnt_header
.external_leading
> 0 &&
935 (face_size
->height
==
936 winfnt_header
.pixel_height
+ winfnt_header
.external_leading
))
937 face_size
->height
= winfnt_header
.pixel_height
;
941 static inline void get_fontsig( FT_Face ft_face
, FONTSIGNATURE
*fs
)
944 FT_WinFNT_HeaderRec winfnt_header
;
947 memset( fs
, 0, sizeof(*fs
) );
949 os2
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_os2
);
952 fs
->fsUsb
[0] = os2
->ulUnicodeRange1
;
953 fs
->fsUsb
[1] = os2
->ulUnicodeRange2
;
954 fs
->fsUsb
[2] = os2
->ulUnicodeRange3
;
955 fs
->fsUsb
[3] = os2
->ulUnicodeRange4
;
957 if (os2
->version
== 0)
959 if (os2
->usFirstCharIndex
>= 0xf000 && os2
->usFirstCharIndex
< 0xf100)
960 fs
->fsCsb
[0] = FS_SYMBOL
;
962 fs
->fsCsb
[0] = FS_LATIN1
;
966 fs
->fsCsb
[0] = os2
->ulCodePageRange1
;
967 fs
->fsCsb
[1] = os2
->ulCodePageRange2
;
972 if (!pFT_Get_WinFNT_Header( ft_face
, &winfnt_header
))
974 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header
.pixel_height
, winfnt_header
.charset
,
975 winfnt_header
.vertical_resolution
,winfnt_header
.horizontal_resolution
, winfnt_header
.nominal_point_size
);
976 switch (winfnt_header
.charset
)
978 case ANSI_CHARSET
: fs
->fsCsb
[0] = FS_LATIN1
; break;
979 case EASTEUROPE_CHARSET
: fs
->fsCsb
[0] = FS_LATIN2
; break;
980 case RUSSIAN_CHARSET
: fs
->fsCsb
[0] = FS_CYRILLIC
; break;
981 case GREEK_CHARSET
: fs
->fsCsb
[0] = FS_GREEK
; break;
982 case TURKISH_CHARSET
: fs
->fsCsb
[0] = FS_TURKISH
; break;
983 case HEBREW_CHARSET
: fs
->fsCsb
[0] = FS_HEBREW
; break;
984 case ARABIC_CHARSET
: fs
->fsCsb
[0] = FS_ARABIC
; break;
985 case BALTIC_CHARSET
: fs
->fsCsb
[0] = FS_BALTIC
; break;
986 case VIETNAMESE_CHARSET
: fs
->fsCsb
[0] = FS_VIETNAMESE
; break;
987 case THAI_CHARSET
: fs
->fsCsb
[0] = FS_THAI
; break;
988 case SHIFTJIS_CHARSET
: fs
->fsCsb
[0] = FS_JISJAPAN
; break;
989 case GB2312_CHARSET
: fs
->fsCsb
[0] = FS_CHINESESIMP
; break;
990 case HANGEUL_CHARSET
: fs
->fsCsb
[0] = FS_WANSUNG
; break;
991 case CHINESEBIG5_CHARSET
: fs
->fsCsb
[0] = FS_CHINESETRAD
; break;
992 case JOHAB_CHARSET
: fs
->fsCsb
[0] = FS_JOHAB
; break;
993 case SYMBOL_CHARSET
: fs
->fsCsb
[0] = FS_SYMBOL
; break;
998 if (fs
->fsCsb
[0] == 0)
1000 /* let's see if we can find any interesting cmaps */
1001 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
1003 switch (ft_face
->charmaps
[i
]->encoding
)
1005 case FT_ENCODING_UNICODE
:
1006 case FT_ENCODING_APPLE_ROMAN
:
1007 fs
->fsCsb
[0] |= FS_LATIN1
;
1009 case FT_ENCODING_MS_SYMBOL
:
1010 fs
->fsCsb
[0] |= FS_SYMBOL
;
1019 static FT_Face
new_ft_face( const char *file
, void *font_data_ptr
, DWORD font_data_size
,
1020 FT_Long face_index
, BOOL allow_bitmap
)
1028 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
1029 err
= pFT_New_Face(library
, file
, face_index
, &ft_face
);
1033 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr
, font_data_size
, face_index
);
1034 err
= pFT_New_Memory_Face(library
, font_data_ptr
, font_data_size
, face_index
, &ft_face
);
1039 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file
), font_data_ptr
, err
);
1043 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1044 if (!FT_IS_SCALABLE( ft_face
) && FT_SimpleVersion
< FT_VERSION_VALUE(2, 1, 9))
1046 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1050 if (!FT_IS_SFNT( ft_face
))
1052 if (FT_IS_SCALABLE( ft_face
) || !allow_bitmap
)
1054 WARN("Ignoring font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1060 if (!(pOS2
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_os2
)) ||
1061 !pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_hhea
) ||
1062 !pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_head
))
1064 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1065 "Skipping this font.\n", debugstr_a(file
), font_data_ptr
);
1069 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1070 we don't want to load these. */
1071 if (!memcmp( pOS2
->achVendID
, "Wine", sizeof(pOS2
->achVendID
) ))
1075 if (!pFT_Load_Sfnt_Table( ft_face
, FT_MAKE_TAG('E','B','S','C'), 0, NULL
, &len
))
1077 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file
));
1083 if (!ft_face
->family_name
|| !ft_face
->style_name
)
1085 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file
), font_data_ptr
);
1091 pFT_Done_Face( ft_face
);
1095 static int add_unix_face( const char *unix_name
, const WCHAR
*file
, void *data_ptr
, SIZE_T data_size
,
1096 DWORD face_index
, DWORD flags
, DWORD
*num_faces
)
1098 struct bitmap_font_size size
;
1101 WCHAR
*family_name
, *second_name
, *style_name
, *full_name
;
1104 if (num_faces
) *num_faces
= 0;
1106 if (!(ft_face
= new_ft_face( unix_name
, data_ptr
, data_size
, face_index
, flags
& ADDFONT_ALLOW_BITMAP
)))
1109 if (ft_face
->family_name
[0] == '.') /* Ignore fonts with names beginning with a dot */
1111 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(unix_name
));
1112 pFT_Done_Face( ft_face
);
1116 family_name
= ft_face_get_family_name( ft_face
, system_lcid
);
1117 second_name
= ft_face_get_family_name( ft_face
, MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
) );
1118 style_name
= ft_face_get_style_name( ft_face
, system_lcid
);
1119 full_name
= ft_face_get_full_name( ft_face
, system_lcid
);
1121 /* try to find another secondary name, preferring the lowest langids */
1122 if (!RtlCompareUnicodeStrings( family_name
, lstrlenW(family_name
),
1123 second_name
, lstrlenW(second_name
), TRUE
))
1125 RtlFreeHeap( GetProcessHeap(), 0, second_name
);
1126 second_name
= ft_face_get_family_name( ft_face
, MAKELANGID(LANG_NEUTRAL
, SUBLANG_NEUTRAL
) );
1127 if (!RtlCompareUnicodeStrings( family_name
, lstrlenW(family_name
),
1128 second_name
, lstrlenW(second_name
), TRUE
))
1130 RtlFreeHeap( GetProcessHeap(), 0, second_name
);
1135 get_fontsig( ft_face
, &fs
);
1136 if (!FT_IS_SCALABLE( ft_face
)) get_bitmap_size( ft_face
, &size
);
1137 if (!HIWORD( flags
)) flags
|= ADDFONT_AA_FLAGS( default_aa_flags
);
1139 ret
= callback_funcs
->add_gdi_face( family_name
, second_name
, style_name
, full_name
, file
,
1140 data_ptr
, data_size
, face_index
, fs
, get_ntm_flags( ft_face
),
1141 get_font_version( ft_face
), flags
,
1142 FT_IS_SCALABLE(ft_face
) ? NULL
: &size
);
1144 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1145 fs
.fsCsb
[0], fs
.fsCsb
[1], fs
.fsUsb
[0], fs
.fsUsb
[1], fs
.fsUsb
[2], fs
.fsUsb
[3]);
1147 RtlFreeHeap( GetProcessHeap(), 0, family_name
);
1148 RtlFreeHeap( GetProcessHeap(), 0, second_name
);
1149 RtlFreeHeap( GetProcessHeap(), 0, style_name
);
1150 RtlFreeHeap( GetProcessHeap(), 0, full_name
);
1152 if (num_faces
) *num_faces
= ft_face
->num_faces
;
1153 pFT_Done_Face( ft_face
);
1157 static WCHAR
*get_dos_file_name( LPCSTR str
)
1160 SIZE_T len
= strlen(str
) + 1;
1162 len
+= 8; /* \??\unix prefix */
1163 if (!(buffer
= RtlAllocateHeap( GetProcessHeap(), 0, len
* sizeof(WCHAR
) ))) return NULL
;
1164 if (wine_unix_to_nt_file_name( str
, buffer
, &len
))
1166 RtlFreeHeap( GetProcessHeap(), 0, buffer
);
1169 if (buffer
[5] == ':')
1171 /* get rid of the \??\ prefix */
1172 /* FIXME: should implement RtlNtPathNameToDosPathName and use that instead */
1173 memmove( buffer
, buffer
+ 4, (len
- 4) * sizeof(WCHAR
) );
1175 else buffer
[1] = '\\';
1179 static char *get_unix_file_name( LPCWSTR dosW
)
1181 UNICODE_STRING nt_name
;
1186 if (!RtlDosPathNameToNtPathName_U( dosW
, &nt_name
, NULL
, NULL
)) return NULL
;
1189 if (!(buffer
= RtlAllocateHeap( GetProcessHeap(), 0, size
)))
1191 RtlFreeUnicodeString( &nt_name
);
1194 status
= wine_nt_to_unix_file_name( &nt_name
, buffer
, &size
, FILE_OPEN_IF
);
1195 if (status
!= STATUS_BUFFER_TOO_SMALL
) break;
1196 RtlFreeHeap( GetProcessHeap(), 0, buffer
);
1198 RtlFreeUnicodeString( &nt_name
);
1199 if (status
&& status
!= STATUS_NO_SUCH_FILE
)
1201 RtlFreeHeap( GetProcessHeap(), 0, buffer
);
1202 RtlSetLastWin32ErrorAndNtStatusFromNtStatus( status
);
1208 static INT
AddFontToList(const WCHAR
*dos_name
, const char *unix_name
, void *font_data_ptr
,
1209 DWORD font_data_size
, DWORD flags
)
1211 DWORD face_index
= 0, num_faces
;
1213 WCHAR
*filename
= NULL
;
1215 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1216 assert(unix_name
|| !(flags
& ADDFONT_EXTERNAL_FONT
));
1218 #ifdef HAVE_CARBON_CARBON_H
1221 char **mac_list
= expand_mac_font(unix_name
);
1224 BOOL had_one
= FALSE
;
1226 for(cursor
= mac_list
; *cursor
; cursor
++)
1229 AddFontToList(NULL
, *cursor
, NULL
, 0, flags
);
1230 RtlFreeHeap(GetProcessHeap(), 0, *cursor
);
1232 RtlFreeHeap(GetProcessHeap(), 0, mac_list
);
1237 #endif /* HAVE_CARBON_CARBON_H */
1239 if (!dos_name
&& unix_name
) dos_name
= filename
= get_dos_file_name( unix_name
);
1242 ret
+= add_unix_face( unix_name
, dos_name
, font_data_ptr
, font_data_size
, face_index
, flags
, &num_faces
);
1243 while (num_faces
> ++face_index
);
1245 RtlFreeHeap( GetProcessHeap(), 0, filename
);
1249 /*************************************************************
1252 static INT CDECL
freetype_add_font( const WCHAR
*file
, DWORD flags
)
1255 char *unixname
= get_unix_file_name( file
);
1259 ret
= AddFontToList( file
, unixname
, NULL
, 0, flags
);
1260 RtlFreeHeap( GetProcessHeap(), 0, unixname
);
1265 /*************************************************************
1266 * freetype_add_mem_font
1268 static INT CDECL
freetype_add_mem_font( void *ptr
, SIZE_T size
, DWORD flags
)
1270 return AddFontToList( NULL
, NULL
, ptr
, size
, flags
);
1274 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
1277 struct dirent
*dent
;
1278 char path
[MAX_PATH
];
1280 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
1282 dir
= opendir(dirname
);
1284 WARN("Can't open directory %s\n", debugstr_a(dirname
));
1287 while((dent
= readdir(dir
)) != NULL
) {
1288 struct stat statbuf
;
1290 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
1293 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
1295 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
1297 if(stat(path
, &statbuf
) == -1)
1299 WARN("Can't stat %s\n", debugstr_a(path
));
1302 if(S_ISDIR(statbuf
.st_mode
))
1303 ReadFontDir(path
, external_fonts
);
1306 DWORD addfont_flags
= ADDFONT_ADD_TO_CACHE
;
1307 if(external_fonts
) addfont_flags
|= ADDFONT_EXTERNAL_FONT
;
1308 AddFontToList(NULL
, path
, NULL
, 0, addfont_flags
);
1316 #ifdef SONAME_LIBFONTCONFIG
1318 static BOOL fontconfig_enabled
;
1319 static FcPattern
*pattern_serif
;
1320 static FcPattern
*pattern_fixed
;
1321 static FcPattern
*pattern_sans
;
1323 static UINT
parse_aa_pattern( FcPattern
*pattern
)
1329 if (pFcPatternGetBool( pattern
, FC_ANTIALIAS
, 0, &antialias
) == FcResultMatch
)
1330 aa_flags
= antialias
? GGO_GRAY4_BITMAP
: GGO_BITMAP
;
1332 if (pFcPatternGetInteger( pattern
, FC_RGBA
, 0, &rgba
) == FcResultMatch
)
1336 case FC_RGBA_RGB
: aa_flags
= WINE_GGO_HRGB_BITMAP
; break;
1337 case FC_RGBA_BGR
: aa_flags
= WINE_GGO_HBGR_BITMAP
; break;
1338 case FC_RGBA_VRGB
: aa_flags
= WINE_GGO_VRGB_BITMAP
; break;
1339 case FC_RGBA_VBGR
: aa_flags
= WINE_GGO_VBGR_BITMAP
; break;
1340 case FC_RGBA_NONE
: aa_flags
= aa_flags
? aa_flags
: GGO_GRAY4_BITMAP
; break;
1346 static FcPattern
*create_family_pattern( const char *name
, FcPattern
**cached
)
1348 FcPattern
*ret
= NULL
, *tmp
, *pattern
= pFcPatternCreate();
1350 if (*cached
) return *cached
;
1351 pFcPatternAddString( pattern
, FC_FAMILY
, (const FcChar8
*)name
);
1352 pFcPatternAddString( pattern
, FC_NAMELANG
, (const FcChar8
*)"en-us" );
1353 pFcPatternAddString( pattern
, FC_PRGNAME
, (const FcChar8
*)"wine" );
1354 pFcConfigSubstitute( NULL
, pattern
, FcMatchPattern
);
1355 pFcDefaultSubstitute( pattern
);
1356 tmp
= pFcFontMatch( NULL
, pattern
, &result
);
1357 pFcPatternDestroy( pattern
);
1358 if (result
!= FcResultMatch
) pFcPatternDestroy( tmp
);
1359 else if ((ret
= InterlockedCompareExchangePointer( (void **)cached
, tmp
, NULL
))) pFcPatternDestroy( tmp
);
1364 static void fontconfig_add_font( FcPattern
*pattern
, DWORD flags
)
1366 const char *unix_name
, *format
;
1372 TRACE( "(%p %#x)\n", pattern
, flags
);
1374 if (pFcPatternGetString( pattern
, FC_FILE
, 0, (FcChar8
**)&unix_name
) != FcResultMatch
)
1377 if (pFcPatternGetBool( pattern
, FC_SCALABLE
, 0, &scalable
) != FcResultMatch
)
1380 if (pFcPatternGetString( pattern
, FC_FONTFORMAT
, 0, (FcChar8
**)&format
) != FcResultMatch
)
1382 TRACE( "ignoring unknown font format %s\n", debugstr_a(unix_name
) );
1386 if (!strcmp( format
, "Type 1" ))
1388 TRACE( "ignoring Type 1 font %s\n", debugstr_a(unix_name
) );
1392 if (!scalable
&& !(flags
& ADDFONT_ALLOW_BITMAP
))
1394 TRACE( "ignoring non-scalable font %s\n", debugstr_a(unix_name
) );
1398 if (!(aa_flags
= parse_aa_pattern( pattern
))) aa_flags
= default_aa_flags
;
1399 flags
|= ADDFONT_AA_FLAGS(aa_flags
);
1401 if (pFcPatternGetInteger( pattern
, FC_INDEX
, 0, &face_index
) != FcResultMatch
)
1404 dos_name
= get_dos_file_name( unix_name
);
1405 add_unix_face( unix_name
, dos_name
, NULL
, 0, face_index
, flags
, NULL
);
1406 RtlFreeHeap( GetProcessHeap(), 0, dos_name
);
1409 static void init_fontconfig(void)
1411 void *fc_handle
= dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
);
1415 TRACE("Wine cannot find the fontconfig library (%s).\n", SONAME_LIBFONTCONFIG
);
1419 #define LOAD_FUNCPTR(f) if((p##f = dlsym(fc_handle, #f)) == NULL){WARN("Can't find symbol %s\n", #f); return;}
1420 LOAD_FUNCPTR(FcConfigSubstitute
);
1421 LOAD_FUNCPTR(FcDefaultSubstitute
);
1422 LOAD_FUNCPTR(FcFontList
);
1423 LOAD_FUNCPTR(FcFontMatch
);
1424 LOAD_FUNCPTR(FcFontSetDestroy
);
1425 LOAD_FUNCPTR(FcInit
);
1426 LOAD_FUNCPTR(FcPatternAddString
);
1427 LOAD_FUNCPTR(FcPatternCreate
);
1428 LOAD_FUNCPTR(FcPatternDestroy
);
1429 LOAD_FUNCPTR(FcPatternGetBool
);
1430 LOAD_FUNCPTR(FcPatternGetInteger
);
1431 LOAD_FUNCPTR(FcPatternGetString
);
1432 LOAD_FUNCPTR(FcConfigGetFontDirs
);
1433 LOAD_FUNCPTR(FcConfigGetCurrent
);
1434 LOAD_FUNCPTR(FcCacheCopySet
);
1435 LOAD_FUNCPTR(FcCacheNumSubdir
);
1436 LOAD_FUNCPTR(FcCacheSubdir
);
1437 LOAD_FUNCPTR(FcDirCacheRead
);
1438 LOAD_FUNCPTR(FcDirCacheUnload
);
1439 LOAD_FUNCPTR(FcStrListCreate
);
1440 LOAD_FUNCPTR(FcStrListDone
);
1441 LOAD_FUNCPTR(FcStrListNext
);
1442 LOAD_FUNCPTR(FcStrSetAdd
);
1443 LOAD_FUNCPTR(FcStrSetCreate
);
1444 LOAD_FUNCPTR(FcStrSetDestroy
);
1445 LOAD_FUNCPTR(FcStrSetMember
);
1450 FcPattern
*pattern
= pFcPatternCreate();
1451 pFcConfigSubstitute( NULL
, pattern
, FcMatchFont
);
1452 default_aa_flags
= parse_aa_pattern( pattern
);
1453 pFcPatternDestroy( pattern
);
1455 if (!default_aa_flags
)
1457 FcPattern
*pattern
= pFcPatternCreate();
1458 pFcConfigSubstitute( NULL
, pattern
, FcMatchPattern
);
1459 default_aa_flags
= parse_aa_pattern( pattern
);
1460 pFcPatternDestroy( pattern
);
1463 TRACE( "enabled, default flags = %x\n", default_aa_flags
);
1464 fontconfig_enabled
= TRUE
;
1468 static void fontconfig_add_fonts_from_dir_list( FcConfig
*config
, FcStrList
*dir_list
, FcStrSet
*done_set
, DWORD flags
)
1471 FcFontSet
*font_set
;
1472 FcStrList
*subdir_list
= NULL
;
1473 FcStrSet
*subdir_set
= NULL
;
1474 FcCache
*cache
= NULL
;
1477 TRACE( "(%p %p %p %#x)\n", config
, dir_list
, done_set
, flags
);
1479 while ((dir
= pFcStrListNext( dir_list
)))
1481 if (pFcStrSetMember( done_set
, dir
)) continue;
1483 TRACE( "adding fonts from %s\n", dir
);
1484 if (!(cache
= pFcDirCacheRead( dir
, FcFalse
, config
))) continue;
1486 if (!(font_set
= pFcCacheCopySet( cache
))) goto done
;
1487 for (i
= 0; i
< font_set
->nfont
; i
++)
1488 fontconfig_add_font( font_set
->fonts
[i
], flags
);
1489 pFcFontSetDestroy( font_set
);
1492 if (!(subdir_set
= pFcStrSetCreate())) goto done
;
1493 for (i
= 0; i
< pFcCacheNumSubdir( cache
); i
++)
1494 pFcStrSetAdd( subdir_set
, pFcCacheSubdir( cache
, i
) );
1495 pFcDirCacheUnload( cache
);
1498 if (!(subdir_list
= pFcStrListCreate( subdir_set
))) goto done
;
1499 pFcStrSetDestroy( subdir_set
);
1502 pFcStrSetAdd( done_set
, dir
);
1503 fontconfig_add_fonts_from_dir_list( config
, subdir_list
, done_set
, flags
);
1504 pFcStrListDone( subdir_list
);
1509 if (font_set
) pFcFontSetDestroy( font_set
);
1510 if (subdir_list
) pFcStrListDone( subdir_list
);
1511 if (subdir_set
) pFcStrSetDestroy( subdir_set
);
1512 if (cache
) pFcDirCacheUnload( cache
);
1515 static void load_fontconfig_fonts( void )
1517 FcStrList
*dir_list
= NULL
;
1518 FcStrSet
*done_set
= NULL
;
1521 if (!fontconfig_enabled
) return;
1522 if (!(config
= pFcConfigGetCurrent())) goto done
;
1523 if (!(done_set
= pFcStrSetCreate())) goto done
;
1524 if (!(dir_list
= pFcConfigGetFontDirs( config
))) goto done
;
1526 fontconfig_add_fonts_from_dir_list( config
, dir_list
, done_set
, ADDFONT_EXTERNAL_FONT
| ADDFONT_ADD_TO_CACHE
);
1529 if (dir_list
) pFcStrListDone( dir_list
);
1530 if (done_set
) pFcStrSetDestroy( done_set
);
1533 #elif defined(HAVE_CARBON_CARBON_H)
1535 static void load_mac_font_callback(const void *value
, void *context
)
1537 CFStringRef pathStr
= value
;
1541 len
= CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr
);
1542 path
= RtlAllocateHeap(GetProcessHeap(), 0, len
);
1543 if (path
&& CFStringGetFileSystemRepresentation(pathStr
, path
, len
))
1545 TRACE("font file %s\n", path
);
1546 AddFontToList(NULL
, path
, NULL
, 0, ADDFONT_EXTERNAL_FONT
| ADDFONT_ADD_TO_CACHE
);
1548 RtlFreeHeap(GetProcessHeap(), 0, path
);
1551 static void load_mac_fonts(void)
1553 CFStringRef removeDupesKey
;
1554 CFBooleanRef removeDupesValue
;
1555 CFDictionaryRef options
;
1556 CTFontCollectionRef col
;
1558 CFMutableSetRef paths
;
1561 removeDupesKey
= kCTFontCollectionRemoveDuplicatesOption
;
1562 removeDupesValue
= kCFBooleanTrue
;
1563 options
= CFDictionaryCreate(NULL
, (const void**)&removeDupesKey
, (const void**)&removeDupesValue
, 1,
1564 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1565 col
= CTFontCollectionCreateFromAvailableFonts(options
);
1566 if (options
) CFRelease(options
);
1569 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
1573 descs
= CTFontCollectionCreateMatchingFontDescriptors(col
);
1577 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
1581 paths
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
1584 WARN("CFSetCreateMutable failed\n");
1589 for (i
= 0; i
< CFArrayGetCount(descs
); i
++)
1591 CTFontDescriptorRef desc
;
1596 desc
= CFArrayGetValueAtIndex(descs
, i
);
1598 #if defined(MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
1599 url
= CTFontDescriptorCopyAttribute(desc
, kCTFontURLAttribute
);
1601 /* CTFontDescriptor doesn't support kCTFontURLAttribute prior to 10.6, so
1602 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
1609 font
= CTFontCreateWithFontDescriptor(desc
, 0, NULL
);
1610 if (!font
) continue;
1612 atsFont
= CTFontGetPlatformFont(font
, NULL
);
1619 status
= ATSFontGetFileReference(atsFont
, &fsref
);
1621 if (status
!= noErr
) continue;
1623 url
= CFURLCreateFromFSRef(NULL
, &fsref
);
1628 ext
= CFURLCopyPathExtension(url
);
1631 BOOL skip
= (CFStringCompare(ext
, CFSTR("pfa"), kCFCompareCaseInsensitive
) == kCFCompareEqualTo
||
1632 CFStringCompare(ext
, CFSTR("pfb"), kCFCompareCaseInsensitive
) == kCFCompareEqualTo
);
1641 path
= CFURLCopyFileSystemPath(url
, kCFURLPOSIXPathStyle
);
1643 if (!path
) continue;
1645 CFSetAddValue(paths
, path
);
1651 CFSetApplyFunction(paths
, load_mac_font_callback
, NULL
);
1658 static BOOL
init_freetype(void)
1660 ft_handle
= dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
);
1663 "Wine cannot find the FreeType font library. To enable Wine to\n"
1664 "use TrueType fonts please install a version of FreeType greater than\n"
1665 "or equal to 2.0.5.\n"
1666 "http://www.freetype.org\n");
1670 #define LOAD_FUNCPTR(f) if((p##f = dlsym(ft_handle, #f)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
1672 LOAD_FUNCPTR(FT_Done_Face
)
1673 LOAD_FUNCPTR(FT_Get_Char_Index
)
1674 LOAD_FUNCPTR(FT_Get_First_Char
)
1675 LOAD_FUNCPTR(FT_Get_Next_Char
)
1676 LOAD_FUNCPTR(FT_Get_Sfnt_Name
)
1677 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count
)
1678 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
1679 LOAD_FUNCPTR(FT_Get_WinFNT_Header
)
1680 LOAD_FUNCPTR(FT_Init_FreeType
)
1681 LOAD_FUNCPTR(FT_Library_Version
)
1682 LOAD_FUNCPTR(FT_Load_Glyph
)
1683 LOAD_FUNCPTR(FT_Load_Sfnt_Table
)
1684 LOAD_FUNCPTR(FT_Matrix_Multiply
)
1685 LOAD_FUNCPTR(FT_MulDiv
)
1686 #ifndef FT_MULFIX_INLINED
1687 LOAD_FUNCPTR(FT_MulFix
)
1689 LOAD_FUNCPTR(FT_New_Face
)
1690 LOAD_FUNCPTR(FT_New_Memory_Face
)
1691 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
1692 LOAD_FUNCPTR(FT_Outline_Get_CBox
)
1693 LOAD_FUNCPTR(FT_Outline_Transform
)
1694 LOAD_FUNCPTR(FT_Outline_Translate
)
1695 LOAD_FUNCPTR(FT_Render_Glyph
)
1696 LOAD_FUNCPTR(FT_Set_Charmap
)
1697 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
1698 LOAD_FUNCPTR(FT_Vector_Length
)
1699 LOAD_FUNCPTR(FT_Vector_Transform
)
1700 LOAD_FUNCPTR(FT_Vector_Unit
)
1702 /* Don't warn if these ones are missing */
1703 pFT_Outline_Embolden
= dlsym(ft_handle
, "FT_Outline_Embolden");
1704 pFT_Get_TrueType_Engine_Type
= dlsym(ft_handle
, "FT_Get_TrueType_Engine_Type");
1705 #ifdef FT_LCD_FILTER_H
1706 pFT_Library_SetLcdFilter
= dlsym(ft_handle
, "FT_Library_SetLcdFilter");
1708 pFT_Property_Set
= dlsym(ft_handle
, "FT_Property_Set");
1710 if(pFT_Init_FreeType(&library
) != 0) {
1711 ERR("Can't init FreeType library\n");
1716 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
1718 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
1719 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
1720 ((FT_Version
.minor
<< 8) & 0x00ff00) |
1721 ((FT_Version
.patch
) & 0x0000ff);
1723 /* In FreeType < 2.8.1 v40's FT_LOAD_TARGET_MONO has broken advance widths. */
1724 if (pFT_Property_Set
&& FT_SimpleVersion
< FT_VERSION_VALUE(2, 8, 1))
1726 FT_UInt interpreter_version
= 35;
1727 pFT_Property_Set( library
, "truetype", "interpreter-version", &interpreter_version
);
1734 "Wine cannot find certain functions that it needs inside the FreeType\n"
1735 "font library. To enable Wine to use TrueType fonts please upgrade\n"
1736 "FreeType to at least version 2.1.4.\n"
1737 "http://www.freetype.org\n");
1743 /*************************************************************
1744 * freetype_load_fonts
1746 static void CDECL
freetype_load_fonts(void)
1748 #ifdef SONAME_LIBFONTCONFIG
1749 load_fontconfig_fonts();
1750 #elif defined(HAVE_CARBON_CARBON_H)
1752 #elif defined(__ANDROID__)
1753 ReadFontDir("/system/fonts", TRUE
);
1757 /* Some fonts have large usWinDescent values, as a result of storing signed short
1758 in unsigned field. That's probably caused by sTypoDescent vs usWinDescent confusion in
1759 some font generation tools. */
1760 static inline USHORT
get_fixed_windescent(USHORT windescent
)
1762 return abs((SHORT
)windescent
);
1765 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
1768 TT_HoriHeader
*pHori
;
1771 const LONG MAX_PPEM
= (1 << 16) - 1;
1773 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
1774 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
1776 if(height
== 0) height
= 16;
1778 /* Calc. height of EM square:
1780 * For +ve lfHeight we have
1781 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
1782 * Re-arranging gives:
1783 * ppem = units_per_em * lfheight / (winAscent + winDescent)
1785 * For -ve lfHeight we have
1787 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
1788 * with il = winAscent + winDescent - units_per_em]
1793 USHORT windescent
= get_fixed_windescent(pOS2
->usWinDescent
);
1794 if(pOS2
->usWinAscent
+ windescent
== 0)
1795 ppem
= pFT_MulDiv(ft_face
->units_per_EM
, height
, pHori
->Ascender
- pHori
->Descender
);
1797 ppem
= pFT_MulDiv(ft_face
->units_per_EM
, height
, pOS2
->usWinAscent
+ windescent
);
1798 if(ppem
> MAX_PPEM
) {
1799 WARN("Ignoring too large height %d, ppem %d\n", height
, ppem
);
1803 else if(height
>= -MAX_PPEM
)
1806 WARN("Ignoring too large height %d\n", height
);
1813 static struct font_mapping
*map_font_file( const char *name
)
1815 struct font_mapping
*mapping
;
1819 if ((fd
= open( name
, O_RDONLY
)) == -1) return NULL
;
1820 if (fstat( fd
, &st
) == -1) goto error
;
1822 LIST_FOR_EACH_ENTRY( mapping
, &mappings_list
, struct font_mapping
, entry
)
1824 if (mapping
->dev
== st
.st_dev
&& mapping
->ino
== st
.st_ino
)
1826 mapping
->refcount
++;
1831 if (!(mapping
= RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*mapping
) )))
1834 mapping
->data
= mmap( NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0 );
1837 if (mapping
->data
== MAP_FAILED
)
1839 RtlFreeHeap( GetProcessHeap(), 0, mapping
);
1842 mapping
->refcount
= 1;
1843 mapping
->dev
= st
.st_dev
;
1844 mapping
->ino
= st
.st_ino
;
1845 mapping
->size
= st
.st_size
;
1846 list_add_tail( &mappings_list
, &mapping
->entry
);
1854 static void unmap_font_file( struct font_mapping
*mapping
)
1856 if (!--mapping
->refcount
)
1858 list_remove( &mapping
->entry
);
1859 munmap( mapping
->data
, mapping
->size
);
1860 RtlFreeHeap( GetProcessHeap(), 0, mapping
);
1864 static LONG
load_VDMX(struct gdi_font
*font
, LONG height
);
1866 /*************************************************************
1867 * freetype_destroy_font
1869 static void CDECL
freetype_destroy_font( struct gdi_font
*font
)
1871 struct font_private_data
*data
= font
->private;
1873 if (data
->ft_face
) pFT_Done_Face( data
->ft_face
);
1874 if (data
->mapping
) unmap_font_file( data
->mapping
);
1875 RtlFreeHeap( GetProcessHeap(), 0, data
);
1878 /*************************************************************
1879 * freetype_get_font_data
1881 static DWORD CDECL
freetype_get_font_data( struct gdi_font
*font
, DWORD table
, DWORD offset
,
1882 void *buf
, DWORD cbData
)
1884 FT_Face ft_face
= get_ft_face( font
);
1888 if (!FT_IS_SFNT(ft_face
)) return GDI_ERROR
;
1895 /* if font is a member of TTC, 'ttcf' tag allows reading from beginning of TTC file,
1896 0 tag means to read from start of collection member data. */
1897 if (font
->ttc_item_offset
)
1899 if (table
== MS_TTCF_TAG
)
1901 else if (table
== 0)
1902 offset
+= font
->ttc_item_offset
;
1905 /* make sure value of len is the value freetype says it needs */
1908 FT_ULong needed
= 0;
1909 err
= pFT_Load_Sfnt_Table(ft_face
, RtlUlongByteSwap(table
), offset
, NULL
, &needed
);
1910 if( !err
&& needed
< len
) len
= needed
;
1912 err
= pFT_Load_Sfnt_Table(ft_face
, RtlUlongByteSwap(table
), offset
, buf
, &len
);
1915 TRACE("Can't find table %s\n", debugstr_an((char*)&table
, 4));
1921 /*************************************************************
1924 * load the vdmx entry for the specified height
1954 static LONG
load_VDMX(struct gdi_font
*font
, LONG height
)
1958 BYTE devXRatio
, devYRatio
;
1959 USHORT numRecs
, numRatios
;
1960 DWORD result
, offset
= -1;
1964 result
= freetype_get_font_data(font
, MS_VDMX_TAG
, 0, &hdr
, sizeof(hdr
));
1966 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
1969 /* FIXME: need the real device aspect ratio */
1973 numRecs
= GET_BE_WORD(hdr
.numRecs
);
1974 numRatios
= GET_BE_WORD(hdr
.numRatios
);
1976 TRACE("version = %d numRecs = %d numRatios = %d\n", GET_BE_WORD(hdr
.version
), numRecs
, numRatios
);
1977 for(i
= 0; i
< numRatios
; i
++) {
1980 offset
= sizeof(hdr
) + (i
* sizeof(Ratios
));
1981 freetype_get_font_data(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
1984 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
1986 if (!ratio
.bCharSet
) continue;
1988 if((ratio
.xRatio
== 0 &&
1989 ratio
.yStartRatio
== 0 &&
1990 ratio
.yEndRatio
== 0) ||
1991 (devXRatio
== ratio
.xRatio
&&
1992 devYRatio
>= ratio
.yStartRatio
&&
1993 devYRatio
<= ratio
.yEndRatio
))
1997 offset
= sizeof(hdr
) + numRatios
* sizeof(ratio
) + i
* sizeof(group_offset
);
1998 freetype_get_font_data(font
, MS_VDMX_TAG
, offset
, &group_offset
, sizeof(group_offset
));
1999 offset
= GET_BE_WORD(group_offset
);
2004 if(offset
== -1) return 0;
2006 if(freetype_get_font_data(font
, MS_VDMX_TAG
, offset
, &group
, sizeof(group
)) != GDI_ERROR
) {
2008 BYTE startsz
, endsz
;
2011 recs
= GET_BE_WORD(group
.recs
);
2012 startsz
= group
.startsz
;
2013 endsz
= group
.endsz
;
2015 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
2017 vTable
= RtlAllocateHeap(GetProcessHeap(), 0, recs
* sizeof(VDMX_vTable
));
2018 result
= freetype_get_font_data(font
, MS_VDMX_TAG
, offset
+ sizeof(group
), vTable
, recs
* sizeof(VDMX_vTable
));
2019 if(result
== GDI_ERROR
) {
2020 FIXME("Failed to retrieve vTable\n");
2025 for(i
= 0; i
< recs
; i
++) {
2026 SHORT yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
2027 SHORT yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
2028 ppem
= GET_BE_WORD(vTable
[i
* 3]);
2030 if(yMax
+ -yMin
== height
) {
2033 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
2036 if(yMax
+ -yMin
> height
) {
2039 goto end
; /* failed */
2041 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
2042 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
2043 ppem
= GET_BE_WORD(vTable
[i
* 3]);
2044 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
2050 TRACE("ppem not found for height %d\n", height
);
2054 if(ppem
< startsz
|| ppem
> endsz
)
2060 for(i
= 0; i
< recs
; i
++) {
2062 yPelHeight
= GET_BE_WORD(vTable
[i
* 3]);
2064 if(yPelHeight
> ppem
)
2070 if(yPelHeight
== ppem
) {
2071 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
2072 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
2073 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem
, font
->yMax
, font
->yMin
);
2079 RtlFreeHeap(GetProcessHeap(), 0, vTable
);
2085 static BOOL
select_charmap(FT_Face ft_face
, FT_Encoding encoding
)
2087 FT_Error ft_err
= FT_Err_Invalid_CharMap_Handle
;
2088 FT_CharMap cmap0
, cmap1
, cmap2
, cmap3
, cmap_def
;
2091 cmap0
= cmap1
= cmap2
= cmap3
= cmap_def
= NULL
;
2093 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
2095 if (ft_face
->charmaps
[i
]->encoding
== encoding
)
2097 TRACE("found cmap with platform_id %u, encoding_id %u\n",
2098 ft_face
->charmaps
[i
]->platform_id
, ft_face
->charmaps
[i
]->encoding_id
);
2100 switch (ft_face
->charmaps
[i
]->platform_id
)
2103 cmap_def
= ft_face
->charmaps
[i
];
2105 case 0: /* Apple Unicode */
2106 cmap0
= ft_face
->charmaps
[i
];
2108 case 1: /* Macintosh */
2109 cmap1
= ft_face
->charmaps
[i
];
2112 cmap2
= ft_face
->charmaps
[i
];
2114 case 3: /* Microsoft */
2115 cmap3
= ft_face
->charmaps
[i
];
2120 if (cmap3
) /* prefer Microsoft cmap table */
2121 ft_err
= pFT_Set_Charmap(ft_face
, cmap3
);
2123 ft_err
= pFT_Set_Charmap(ft_face
, cmap1
);
2125 ft_err
= pFT_Set_Charmap(ft_face
, cmap2
);
2127 ft_err
= pFT_Set_Charmap(ft_face
, cmap0
);
2129 ft_err
= pFT_Set_Charmap(ft_face
, cmap_def
);
2132 return ft_err
== FT_Err_Ok
;
2136 static FT_Encoding
pick_charmap( FT_Face face
, int charset
)
2138 static const FT_Encoding regular_order
[] = { FT_ENCODING_UNICODE
, FT_ENCODING_APPLE_ROMAN
, FT_ENCODING_MS_SYMBOL
, 0 };
2139 static const FT_Encoding symbol_order
[] = { FT_ENCODING_MS_SYMBOL
, FT_ENCODING_UNICODE
, FT_ENCODING_APPLE_ROMAN
, 0 };
2140 const FT_Encoding
*encs
= regular_order
;
2142 if (charset
== SYMBOL_CHARSET
) encs
= symbol_order
;
2146 if (select_charmap( face
, *encs
)) break;
2150 if (!face
->charmap
&& face
->num_charmaps
)
2152 if (!pFT_Set_Charmap(face
, face
->charmaps
[0]))
2153 return face
->charmap
->encoding
;
2159 static BOOL
get_gasp_flags( struct gdi_font
*font
, WORD
*flags
)
2161 FT_Face ft_face
= get_ft_face( font
);
2163 WORD buf
[16]; /* Enough for seven ranges before we need to alloc */
2164 WORD
*alloced
= NULL
, *ptr
= buf
;
2165 WORD num_recs
, version
;
2169 size
= freetype_get_font_data( font
, MS_GASP_TAG
, 0, NULL
, 0 );
2170 if (size
== GDI_ERROR
) return FALSE
;
2171 if (size
< 4 * sizeof(WORD
)) return FALSE
;
2172 if (size
> sizeof(buf
))
2174 ptr
= alloced
= RtlAllocateHeap( GetProcessHeap(), 0, size
);
2175 if (!ptr
) return FALSE
;
2178 freetype_get_font_data( font
, MS_GASP_TAG
, 0, ptr
, size
);
2180 version
= GET_BE_WORD( *ptr
++ );
2181 num_recs
= GET_BE_WORD( *ptr
++ );
2183 if (version
> 1 || size
< (num_recs
* 2 + 2) * sizeof(WORD
))
2185 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version
, size
, num_recs
);
2191 *flags
= GET_BE_WORD( *(ptr
+ 1) );
2192 if (ft_face
->size
->metrics
.y_ppem
<= GET_BE_WORD( *ptr
)) break;
2195 TRACE( "got flags %04x for ppem %d\n", *flags
, ft_face
->size
->metrics
.y_ppem
);
2199 RtlFreeHeap( GetProcessHeap(), 0, alloced
);
2203 /*************************************************************
2204 * fontconfig_enum_family_fallbacks
2206 static BOOL CDECL
fontconfig_enum_family_fallbacks( DWORD pitch_and_family
, int index
,
2207 WCHAR buffer
[LF_FACESIZE
] )
2209 #ifdef SONAME_LIBFONTCONFIG
2214 if ((pitch_and_family
& FIXED_PITCH
) || (pitch_and_family
& 0xf0) == FF_MODERN
) pat
= create_family_pattern( "monospace", &pattern_fixed
);
2215 else if ((pitch_and_family
& 0xf0) == FF_ROMAN
) pat
= create_family_pattern( "serif", &pattern_serif
);
2216 else pat
= create_family_pattern( "sans", &pattern_sans
);
2218 if (!pat
) return FALSE
;
2219 if (pFcPatternGetString( pat
, FC_FAMILY
, index
, (FcChar8
**)&str
) != FcResultMatch
) return FALSE
;
2220 RtlUTF8ToUnicodeN( buffer
, (LF_FACESIZE
- 1) * sizeof(WCHAR
), &len
, str
, strlen(str
) );
2221 buffer
[len
/ sizeof(WCHAR
)] = 0;
2227 static DWORD
get_ttc_offset( FT_Face ft_face
, UINT face_index
)
2230 DWORD header
, offset
;
2232 /* see if it's a TTC */
2233 len
= sizeof(header
);
2234 if (pFT_Load_Sfnt_Table( ft_face
, 0, 0, (void *)&header
, &len
)) return 0;
2235 if (header
!= MS_TTCF_TAG
) return 0;
2237 len
= sizeof(offset
);
2238 if (pFT_Load_Sfnt_Table( ft_face
, 0, (3 + face_index
) * sizeof(DWORD
), (void *)&offset
, &len
))
2241 return GET_BE_DWORD( offset
);
2244 /*************************************************************
2245 * freetype_load_font
2247 static BOOL CDECL
freetype_load_font( struct gdi_font
*font
)
2249 struct font_private_data
*data
;
2250 INT width
= 0, height
;
2255 if (!(data
= RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*data
) ))) return FALSE
;
2256 font
->private = data
;
2260 char *filename
= get_unix_file_name( font
->file
);
2261 data
->mapping
= map_font_file( filename
);
2262 RtlFreeHeap( GetProcessHeap(), 0, filename
);
2265 WARN("failed to map %s\n", debugstr_w(font
->file
));
2268 data_ptr
= data
->mapping
->data
;
2269 data_size
= data
->mapping
->size
;
2273 data_ptr
= font
->data_ptr
;
2274 data_size
= font
->data_size
;
2277 if (pFT_New_Memory_Face( library
, data_ptr
, data_size
, font
->face_index
, &ft_face
)) return FALSE
;
2279 data
->ft_face
= ft_face
;
2280 font
->scalable
= FT_IS_SCALABLE( ft_face
);
2281 if (!font
->fs
.fsCsb
[0]) get_fontsig( ft_face
, &font
->fs
);
2282 if (!font
->ntmFlags
) font
->ntmFlags
= get_ntm_flags( ft_face
);
2283 if (!font
->aa_flags
) font
->aa_flags
= ADDFONT_AA_FLAGS( default_aa_flags
);
2284 if (!font
->otm
.otmpFamilyName
)
2286 font
->otm
.otmpFamilyName
= (char *)ft_face_get_family_name( ft_face
, system_lcid
);
2287 font
->otm
.otmpStyleName
= (char *)ft_face_get_style_name( ft_face
, system_lcid
);
2288 font
->otm
.otmpFaceName
= (char *)ft_face_get_full_name( ft_face
, system_lcid
);
2293 /* load the VDMX table if we have one */
2294 font
->ppem
= load_VDMX( font
, font
->lf
.lfHeight
);
2295 if (font
->ppem
== 0) font
->ppem
= calc_ppem_for_height( ft_face
, font
->lf
.lfHeight
);
2296 TRACE( "height %d => ppem %d\n", font
->lf
.lfHeight
, font
->ppem
);
2297 height
= font
->ppem
;
2298 font
->ttc_item_offset
= get_ttc_offset( ft_face
, font
->face_index
);
2302 struct bitmap_font_size size
;
2304 get_bitmap_size( ft_face
, &size
);
2305 width
= size
.x_ppem
>> 6;
2306 height
= size
.y_ppem
>> 6;
2307 font
->ppem
= height
;
2310 pFT_Set_Pixel_Sizes( ft_face
, width
, height
);
2311 pick_charmap( ft_face
, font
->charset
);
2316 /*************************************************************
2317 * freetype_get_aa_flags
2319 static UINT CDECL
freetype_get_aa_flags( struct gdi_font
*font
, UINT aa_flags
, BOOL antialias_fakes
)
2321 /* fixup the antialiasing flags for that font */
2324 case WINE_GGO_HRGB_BITMAP
:
2325 case WINE_GGO_HBGR_BITMAP
:
2326 case WINE_GGO_VRGB_BITMAP
:
2327 case WINE_GGO_VBGR_BITMAP
:
2328 if (is_subpixel_rendering_enabled()) break;
2329 aa_flags
= GGO_GRAY4_BITMAP
;
2331 case GGO_GRAY2_BITMAP
:
2332 case GGO_GRAY4_BITMAP
:
2333 case GGO_GRAY8_BITMAP
:
2334 case WINE_GGO_GRAY16_BITMAP
:
2335 if ((!antialias_fakes
|| (!font
->fake_bold
&& !font
->fake_italic
)) && is_hinting_enabled())
2338 if (get_gasp_flags( font
, &gasp_flags
) && !(gasp_flags
& GASP_DOGRAY
))
2340 TRACE( "font %s %d aa disabled by GASP\n",
2341 debugstr_w(font
->lf
.lfFaceName
), font
->lf
.lfHeight
);
2342 aa_flags
= GGO_BITMAP
;
2349 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
2351 pt
->x
.value
= vec
->x
>> 6;
2352 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
2353 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
2354 pt
->y
.value
= vec
->y
>> 6;
2355 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
2356 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
2359 static FT_UInt
get_glyph_index_symbol( struct gdi_font
*font
, UINT glyph
)
2361 FT_Face ft_face
= get_ft_face( font
);
2364 if (glyph
< 0x100) glyph
+= 0xf000;
2365 /* there are a number of old pre-Unicode "broken" TTFs, which
2366 do have symbols at U+00XX instead of U+f0XX */
2367 if (!(ret
= pFT_Get_Char_Index(ft_face
, glyph
)))
2368 ret
= pFT_Get_Char_Index(ft_face
, glyph
- 0xf000);
2373 /*************************************************************
2374 * freetype_get_glyph_index
2376 static BOOL CDECL
freetype_get_glyph_index( struct gdi_font
*font
, UINT
*glyph
, BOOL use_encoding
)
2378 FT_Face ft_face
= get_ft_face( font
);
2380 if (!use_encoding
^ (ft_face
->charmap
->encoding
== FT_ENCODING_NONE
)) return FALSE
;
2382 if (ft_face
->charmap
->encoding
== FT_ENCODING_MS_SYMBOL
)
2384 if (!(*glyph
= get_glyph_index_symbol( font
, *glyph
)))
2390 RtlUnicodeToMultiByteN( &ch
, 1, &len
, &wc
, sizeof(wc
) );
2391 if (len
) *glyph
= get_glyph_index_symbol( font
, (unsigned char)ch
);
2395 *glyph
= pFT_Get_Char_Index( ft_face
, *glyph
);
2399 /*************************************************************
2400 * freetype_get_default_glyph
2402 static UINT CDECL
freetype_get_default_glyph( struct gdi_font
*font
)
2404 FT_Face ft_face
= get_ft_face( font
);
2405 FT_WinFNT_HeaderRec winfnt
;
2408 if ((pOS2
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_os2
)))
2410 UINT glyph
= pOS2
->usDefaultChar
;
2411 freetype_get_glyph_index( font
, &glyph
, TRUE
);
2414 if (!pFT_Get_WinFNT_Header( ft_face
, &winfnt
)) return winfnt
.default_char
+ winfnt
.first_char
;
2419 static inline BOOL
is_identity_FMAT2(const FMAT2
*matrix
)
2421 static const FMAT2 identity
= { 1.0, 0.0, 0.0, 1.0 };
2422 return !memcmp(matrix
, &identity
, sizeof(FMAT2
));
2425 static inline FT_Vector
normalize_vector(FT_Vector
*vec
)
2429 len
= pFT_Vector_Length(vec
);
2431 out
.x
= (vec
->x
<< 6) / len
;
2432 out
.y
= (vec
->y
<< 6) / len
;
2439 /* get_glyph_outline() glyph transform matrices index */
2447 static BOOL
get_transform_matrices( struct gdi_font
*font
, BOOL vertical
, const MAT2
*user_transform
,
2448 FT_Matrix matrices
[3] )
2450 static const FT_Matrix identity_mat
= { (1 << 16), 0, 0, (1 << 16) };
2451 BOOL needs_transform
= FALSE
;
2455 matrices
[matrix_unrotated
] = identity_mat
;
2457 /* Scaling factor */
2460 if (!freetype_set_outline_text_metrics( font
)) freetype_set_bitmap_text_metrics( font
);
2461 width_ratio
= (double)font
->aveWidth
;
2462 width_ratio
/= (double)font
->otm
.otmTextMetrics
.tmAveCharWidth
;
2465 width_ratio
= font
->scale_y
;
2467 /* Scaling transform */
2468 if (width_ratio
!= 1.0 || font
->scale_y
!= 1)
2470 FT_Matrix scale_mat
;
2471 scale_mat
.xx
= FT_FixedFromFloat( width_ratio
);
2474 scale_mat
.yy
= font
->scale_y
<< 16;
2476 pFT_Matrix_Multiply( &scale_mat
, &matrices
[matrix_unrotated
] );
2477 needs_transform
= TRUE
;
2480 /* Slant transform */
2481 if (font
->fake_italic
)
2483 FT_Matrix slant_mat
;
2484 slant_mat
.xx
= (1 << 16);
2485 slant_mat
.xy
= (1 << 16) >> 2;
2487 slant_mat
.yy
= (1 << 16);
2489 pFT_Matrix_Multiply( &slant_mat
, &matrices
[matrix_unrotated
] );
2490 needs_transform
= TRUE
;
2493 /* Rotation transform */
2494 matrices
[matrix_hori
] = matrices
[matrix_unrotated
];
2495 if (font
->scalable
&& font
->lf
.lfOrientation
% 3600)
2497 FT_Matrix rotation_mat
;
2500 pFT_Vector_Unit( &angle
, pFT_MulDiv( 1 << 16, font
->lf
.lfOrientation
, 10 ) );
2501 rotation_mat
.xx
= angle
.x
;
2502 rotation_mat
.xy
= -angle
.y
;
2503 rotation_mat
.yx
= angle
.y
;
2504 rotation_mat
.yy
= angle
.x
;
2505 pFT_Matrix_Multiply( &rotation_mat
, &matrices
[matrix_hori
] );
2506 needs_transform
= TRUE
;
2509 /* Vertical transform */
2510 matrices
[matrix_vert
] = matrices
[matrix_hori
];
2513 FT_Matrix vertical_mat
= { 0, -(1 << 16), 1 << 16, 0 }; /* 90 degrees rotation */
2515 pFT_Matrix_Multiply( &vertical_mat
, &matrices
[matrix_vert
] );
2516 needs_transform
= TRUE
;
2519 /* World transform */
2520 if (!is_identity_FMAT2( &font
->matrix
))
2522 FT_Matrix world_mat
;
2523 world_mat
.xx
= FT_FixedFromFloat( font
->matrix
.eM11
);
2524 world_mat
.xy
= -FT_FixedFromFloat( font
->matrix
.eM21
);
2525 world_mat
.yx
= -FT_FixedFromFloat( font
->matrix
.eM12
);
2526 world_mat
.yy
= FT_FixedFromFloat( font
->matrix
.eM22
);
2528 for (i
= 0; i
< 3; i
++)
2529 pFT_Matrix_Multiply( &world_mat
, &matrices
[i
] );
2530 needs_transform
= TRUE
;
2533 /* Extra transformation specified by caller */
2537 user_mat
.xx
= FT_FixedFromFIXED( user_transform
->eM11
);
2538 user_mat
.xy
= FT_FixedFromFIXED( user_transform
->eM21
);
2539 user_mat
.yx
= FT_FixedFromFIXED( user_transform
->eM12
);
2540 user_mat
.yy
= FT_FixedFromFIXED( user_transform
->eM22
);
2542 for (i
= 0; i
< 3; i
++)
2543 pFT_Matrix_Multiply( &user_mat
, &matrices
[i
] );
2544 needs_transform
= TRUE
;
2547 return needs_transform
;
2550 static BOOL
get_bold_glyph_outline(FT_GlyphSlot glyph
, LONG ppem
, FT_Glyph_Metrics
*metrics
)
2556 if(glyph
->format
!= FT_GLYPH_FORMAT_OUTLINE
)
2558 if(!pFT_Outline_Embolden
)
2561 strength
= pFT_MulDiv(ppem
, 1 << 6, 24);
2562 err
= pFT_Outline_Embolden(&glyph
->outline
, strength
);
2564 TRACE("FT_Ouline_Embolden returns %d\n", err
);
2568 pFT_Outline_Get_CBox(&glyph
->outline
, &bbox
);
2569 metrics
->width
= bbox
.xMax
- bbox
.xMin
;
2570 metrics
->height
= bbox
.yMax
- bbox
.yMin
;
2571 metrics
->horiBearingX
= bbox
.xMin
;
2572 metrics
->horiBearingY
= bbox
.yMax
;
2573 metrics
->vertBearingX
= metrics
->horiBearingX
- metrics
->horiAdvance
/ 2;
2574 metrics
->vertBearingY
= (metrics
->vertAdvance
- metrics
->height
) / 2;
2578 static inline BYTE
get_max_level( UINT format
)
2582 case GGO_GRAY2_BITMAP
: return 4;
2583 case GGO_GRAY4_BITMAP
: return 16;
2584 case GGO_GRAY8_BITMAP
: return 64;
2589 static FT_Vector
get_advance_metric(struct gdi_font
*incoming_font
, struct gdi_font
*font
,
2590 const FT_Glyph_Metrics
*metrics
,
2591 const FT_Matrix
*transMat
, BOOL vertical_metrics
)
2594 FT_Fixed base_advance
, em_scale
= 0;
2595 BOOL fixed_pitch_full
= FALSE
;
2597 if (vertical_metrics
)
2598 base_advance
= metrics
->vertAdvance
;
2600 base_advance
= metrics
->horiAdvance
;
2602 adv
.x
= base_advance
;
2605 /* In fixed-pitch font, we adjust the fullwidth character advance so that
2606 they have double halfwidth character width. E.g. if the font is 19 ppem,
2607 we return 20 (not 19) for fullwidth characters as we return 10 for
2608 halfwidth characters. */
2609 if (freetype_set_outline_text_metrics(incoming_font
) &&
2610 !(incoming_font
->otm
.otmTextMetrics
.tmPitchAndFamily
& TMPF_FIXED_PITCH
)) {
2612 em_scale
= pFT_MulDiv(incoming_font
->ppem
, 1 << 16, get_ft_face(incoming_font
)->units_per_EM
);
2613 avg_advance
= pFT_MulFix(incoming_font
->ntmAvgWidth
, em_scale
);
2614 fixed_pitch_full
= (avg_advance
> 0 &&
2615 (base_advance
+ 63) >> 6 ==
2616 pFT_MulFix(incoming_font
->ntmAvgWidth
*2, em_scale
));
2617 if (fixed_pitch_full
&& !transMat
)
2618 adv
.x
= (avg_advance
* 2) << 6;
2622 pFT_Vector_Transform(&adv
, transMat
);
2623 if (fixed_pitch_full
&& adv
.y
== 0) {
2625 vec
.x
= incoming_font
->ntmAvgWidth
;
2627 pFT_Vector_Transform(&vec
, transMat
);
2628 adv
.x
= (pFT_MulFix(vec
.x
, em_scale
) * 2) << 6;
2632 if (font
->fake_bold
) {
2636 FT_Vector fake_bold_adv
, vec
= { 1 << 6, 0 };
2637 pFT_Vector_Transform(&vec
, transMat
);
2638 fake_bold_adv
= normalize_vector(&vec
);
2639 adv
.x
+= fake_bold_adv
.x
;
2640 adv
.y
+= fake_bold_adv
.y
;
2644 adv
.x
= (adv
.x
+ 63) & -64;
2645 adv
.y
= -((adv
.y
+ 63) & -64);
2649 static FT_BBox
get_transformed_bbox( const FT_Glyph_Metrics
*metrics
,
2650 BOOL needs_transform
, const FT_Matrix metrices
[3] )
2652 FT_BBox bbox
= { 0, 0, 0, 0 };
2654 if (!needs_transform
)
2656 bbox
.xMin
= (metrics
->horiBearingX
) & -64;
2657 bbox
.xMax
= (metrics
->horiBearingX
+ metrics
->width
+ 63) & -64;
2658 bbox
.yMax
= (metrics
->horiBearingY
+ 63) & -64;
2659 bbox
.yMin
= (metrics
->horiBearingY
- metrics
->height
) & -64;
2666 for (xc
= 0; xc
< 2; xc
++)
2668 for (yc
= 0; yc
< 2; yc
++)
2670 vec
.x
= metrics
->horiBearingX
+ xc
* metrics
->width
;
2671 vec
.y
= metrics
->horiBearingY
- yc
* metrics
->height
;
2672 TRACE( "Vec %ld,i %ld\n", vec
.x
, vec
.y
);
2673 pFT_Vector_Transform( &vec
, &metrices
[matrix_vert
] );
2674 if (xc
== 0 && yc
== 0)
2676 bbox
.xMin
= bbox
.xMax
= vec
.x
;
2677 bbox
.yMin
= bbox
.yMax
= vec
.y
;
2681 if (vec
.x
< bbox
.xMin
) bbox
.xMin
= vec
.x
;
2682 else if (vec
.x
> bbox
.xMax
) bbox
.xMax
= vec
.x
;
2683 if (vec
.y
< bbox
.yMin
) bbox
.yMin
= vec
.y
;
2684 else if (vec
.y
> bbox
.yMax
) bbox
.yMax
= vec
.y
;
2688 bbox
.xMin
= bbox
.xMin
& -64;
2689 bbox
.xMax
= (bbox
.xMax
+ 63) & -64;
2690 bbox
.yMin
= bbox
.yMin
& -64;
2691 bbox
.yMax
= (bbox
.yMax
+ 63) & -64;
2692 TRACE( "transformed box: (%ld, %ld - %ld, %ld)\n", bbox
.xMin
, bbox
.yMax
, bbox
.xMax
, bbox
.yMin
);
2698 static void compute_metrics( struct gdi_font
*incoming_font
, struct gdi_font
*font
,
2699 FT_BBox bbox
, const FT_Glyph_Metrics
*metrics
,
2700 BOOL vertical
, BOOL vertical_metrics
,
2701 BOOL needs_transform
, const FT_Matrix matrices
[3],
2702 GLYPHMETRICS
*gm
, ABC
*abc
)
2704 FT_Vector adv
, vec
, origin
;
2706 if (!needs_transform
)
2708 adv
= get_advance_metric( incoming_font
, font
, metrics
, NULL
, vertical_metrics
);
2709 gm
->gmCellIncX
= adv
.x
>> 6;
2711 origin
.x
= bbox
.xMin
;
2712 origin
.y
= bbox
.yMax
;
2713 abc
->abcA
= origin
.x
>> 6;
2714 abc
->abcB
= (metrics
->width
+ 63) >> 6;
2720 if (vertical
&& freetype_set_outline_text_metrics( font
))
2722 if (vertical_metrics
)
2723 lsb
= metrics
->horiBearingY
+ metrics
->vertBearingY
;
2725 lsb
= metrics
->vertAdvance
+ (font
->otm
.otmDescent
<< 6);
2727 vec
.y
= font
->otm
.otmDescent
<< 6;
2728 TRACE( "Vec %ld,%ld\n", vec
.x
>>6, vec
.y
>>6 );
2729 pFT_Vector_Transform( &vec
, &matrices
[matrix_hori
] );
2730 origin
.x
= (vec
.x
+ bbox
.xMin
) & -64;
2731 origin
.y
= (vec
.y
+ bbox
.yMax
+ 63) & -64;
2732 lsb
-= metrics
->horiBearingY
;
2736 origin
.x
= bbox
.xMin
;
2737 origin
.y
= bbox
.yMax
;
2738 lsb
= metrics
->horiBearingX
;
2741 adv
= get_advance_metric( incoming_font
, font
, metrics
, &matrices
[matrix_hori
],
2743 gm
->gmCellIncX
= adv
.x
>> 6;
2744 gm
->gmCellIncY
= adv
.y
>> 6;
2746 adv
= get_advance_metric( incoming_font
, font
, metrics
, &matrices
[matrix_unrotated
],
2748 adv
.x
= pFT_Vector_Length( &adv
);
2753 pFT_Vector_Transform( &vec
, &matrices
[matrix_unrotated
] );
2754 if (lsb
> 0) abc
->abcA
= pFT_Vector_Length( &vec
) >> 6;
2755 else abc
->abcA
= -((pFT_Vector_Length( &vec
) + 63) >> 6);
2757 /* We use lsb again to avoid rounding errors */
2758 vec
.x
= lsb
+ (vertical
? metrics
->height
: metrics
->width
);
2760 pFT_Vector_Transform( &vec
, &matrices
[matrix_unrotated
] );
2761 abc
->abcB
= ((pFT_Vector_Length( &vec
) + 63) >> 6) - abc
->abcA
;
2763 if (!abc
->abcB
) abc
->abcB
= 1;
2764 abc
->abcC
= (adv
.x
>> 6) - abc
->abcA
- abc
->abcB
;
2766 gm
->gmptGlyphOrigin
.x
= origin
.x
>> 6;
2767 gm
->gmptGlyphOrigin
.y
= origin
.y
>> 6;
2768 gm
->gmBlackBoxX
= (bbox
.xMax
- bbox
.xMin
) >> 6;
2769 gm
->gmBlackBoxY
= (bbox
.yMax
- bbox
.yMin
) >> 6;
2770 if (!gm
->gmBlackBoxX
) gm
->gmBlackBoxX
= 1;
2771 if (!gm
->gmBlackBoxY
) gm
->gmBlackBoxY
= 1;
2773 TRACE( "gm: %u, %u, %s, %d, %d abc %d, %u, %d\n",
2774 gm
->gmBlackBoxX
, gm
->gmBlackBoxY
, wine_dbgstr_point(&gm
->gmptGlyphOrigin
),
2775 gm
->gmCellIncX
, gm
->gmCellIncY
, abc
->abcA
, abc
->abcB
, abc
->abcC
);
2779 static const BYTE masks
[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
2781 static DWORD
get_mono_glyph_bitmap( FT_GlyphSlot glyph
, FT_BBox bbox
,
2782 BOOL fake_bold
, BOOL needs_transform
, FT_Matrix matrices
[3],
2783 DWORD buflen
, BYTE
*buf
)
2785 DWORD width
= (bbox
.xMax
- bbox
.xMin
) >> 6;
2786 DWORD height
= (bbox
.yMax
- bbox
.yMin
) >> 6;
2787 DWORD pitch
= ((width
+ 31) >> 5) << 2;
2788 DWORD needed
= pitch
* height
;
2789 FT_Bitmap ft_bitmap
;
2793 if (!buf
|| !buflen
) return needed
;
2794 if (!needed
) return GDI_ERROR
; /* empty glyph */
2795 if (needed
> buflen
) return GDI_ERROR
;
2797 switch (glyph
->format
)
2799 case FT_GLYPH_FORMAT_BITMAP
:
2800 src
= glyph
->bitmap
.buffer
;
2802 w
= min( pitch
, (glyph
->bitmap
.width
+ 7) >> 3 );
2803 h
= min( height
, glyph
->bitmap
.rows
);
2807 memcpy( dst
, src
, w
);
2811 for (x
= 0; x
< w
; x
++)
2813 dst
[x
] = (dst
[x
] & 0x80) | (src
[x
] >> 1) | src
[x
];
2815 dst
[x
+ 1] = (src
[x
] & 0x01) << 7;
2818 src
+= glyph
->bitmap
.pitch
;
2823 case FT_GLYPH_FORMAT_OUTLINE
:
2824 ft_bitmap
.width
= width
;
2825 ft_bitmap
.rows
= height
;
2826 ft_bitmap
.pitch
= pitch
;
2827 ft_bitmap
.pixel_mode
= FT_PIXEL_MODE_MONO
;
2828 ft_bitmap
.buffer
= buf
;
2830 if (needs_transform
)
2831 pFT_Outline_Transform( &glyph
->outline
, &matrices
[matrix_vert
] );
2832 pFT_Outline_Translate( &glyph
->outline
, -bbox
.xMin
, -bbox
.yMin
);
2834 /* Note: FreeType will only set 'black' bits for us. */
2835 memset( buf
, 0, buflen
);
2836 pFT_Outline_Get_Bitmap( library
, &glyph
->outline
, &ft_bitmap
);
2840 FIXME( "loaded glyph format %x\n", glyph
->format
);
2847 static DWORD
get_antialias_glyph_bitmap( FT_GlyphSlot glyph
, FT_BBox bbox
, UINT format
,
2848 BOOL fake_bold
, BOOL needs_transform
, FT_Matrix matrices
[3],
2849 DWORD buflen
, BYTE
*buf
)
2851 DWORD width
= (bbox
.xMax
- bbox
.xMin
) >> 6;
2852 DWORD height
= (bbox
.yMax
- bbox
.yMin
) >> 6;
2853 DWORD pitch
= (width
+ 3) / 4 * 4;
2854 DWORD needed
= pitch
* height
;
2855 FT_Bitmap ft_bitmap
;
2856 INT w
, h
, x
, max_level
;
2859 if (!buf
|| !buflen
) return needed
;
2860 if (!needed
) return GDI_ERROR
; /* empty glyph */
2861 if (needed
> buflen
) return GDI_ERROR
;
2863 max_level
= get_max_level( format
);
2865 switch (glyph
->format
)
2867 case FT_GLYPH_FORMAT_BITMAP
:
2868 src
= glyph
->bitmap
.buffer
;
2870 memset( buf
, 0, buflen
);
2872 w
= min( pitch
, glyph
->bitmap
.width
);
2873 h
= min( height
, glyph
->bitmap
.rows
);
2876 for (x
= 0; x
< w
; x
++)
2878 if (src
[x
/ 8] & masks
[x
% 8])
2881 if (fake_bold
&& x
+ 1 < pitch
) dst
[x
+ 1] = max_level
;
2884 src
+= glyph
->bitmap
.pitch
;
2889 case FT_GLYPH_FORMAT_OUTLINE
:
2890 ft_bitmap
.width
= width
;
2891 ft_bitmap
.rows
= height
;
2892 ft_bitmap
.pitch
= pitch
;
2893 ft_bitmap
.pixel_mode
= FT_PIXEL_MODE_GRAY
;
2894 ft_bitmap
.buffer
= buf
;
2896 if (needs_transform
)
2897 pFT_Outline_Transform( &glyph
->outline
, &matrices
[matrix_vert
] );
2898 pFT_Outline_Translate( &glyph
->outline
, -bbox
.xMin
, -bbox
.yMin
);
2900 memset( buf
, 0, buflen
);
2901 pFT_Outline_Get_Bitmap( library
, &glyph
->outline
, &ft_bitmap
);
2903 if (max_level
!= 255)
2908 for (row
= 0, start
= buf
; row
< height
; row
++)
2910 for (col
= 0, ptr
= start
; col
< width
; col
++, ptr
++)
2911 *ptr
= (((int)*ptr
) * (max_level
+ 1)) / 256;
2918 FIXME("loaded glyph format %x\n", glyph
->format
);
2925 static DWORD
get_subpixel_glyph_bitmap( FT_GlyphSlot glyph
, FT_BBox bbox
, UINT format
,
2926 BOOL fake_bold
, BOOL needs_transform
, FT_Matrix matrices
[3],
2927 GLYPHMETRICS
*gm
, DWORD buflen
, BYTE
*buf
)
2929 DWORD width
= (bbox
.xMax
- bbox
.xMin
) >> 6;
2930 DWORD height
= (bbox
.yMax
- bbox
.yMin
) >> 6;
2931 DWORD pitch
, needed
= 0;
2935 switch (glyph
->format
)
2937 case FT_GLYPH_FORMAT_BITMAP
:
2939 needed
= pitch
* height
;
2941 if (!buf
|| !buflen
) break;
2942 if (!needed
) return GDI_ERROR
; /* empty glyph */
2943 if (needed
> buflen
) return GDI_ERROR
;
2945 src
= glyph
->bitmap
.buffer
;
2947 memset( buf
, 0, buflen
);
2949 w
= min( width
, glyph
->bitmap
.width
);
2950 h
= min( height
, glyph
->bitmap
.rows
);
2953 for (x
= 0; x
< w
; x
++)
2955 if ( src
[x
/ 8] & masks
[x
% 8] )
2957 ((unsigned int *)dst
)[x
] = ~0u;
2958 if (fake_bold
&& x
+ 1 < width
) ((unsigned int *)dst
)[x
+ 1] = ~0u;
2961 src
+= glyph
->bitmap
.pitch
;
2966 case FT_GLYPH_FORMAT_OUTLINE
:
2968 INT src_pitch
, src_width
, src_height
, x_shift
, y_shift
;
2969 INT sub_stride
, hmul
, vmul
;
2970 const INT
*sub_order
;
2971 const INT rgb_order
[3] = { 0, 1, 2 };
2972 const INT bgr_order
[3] = { 2, 1, 0 };
2973 FT_Render_Mode render_mode
=
2974 (format
== WINE_GGO_HRGB_BITMAP
||
2975 format
== WINE_GGO_HBGR_BITMAP
) ? FT_RENDER_MODE_LCD
: FT_RENDER_MODE_LCD_V
;
2977 if (!width
|| !height
) /* empty glyph */
2979 if (!buf
|| !buflen
) break;
2983 if ( render_mode
== FT_RENDER_MODE_LCD
)
2985 gm
->gmBlackBoxX
+= 2;
2986 gm
->gmptGlyphOrigin
.x
-= 1;
2987 bbox
.xMin
-= (1 << 6);
2991 gm
->gmBlackBoxY
+= 2;
2992 gm
->gmptGlyphOrigin
.y
+= 1;
2993 bbox
.yMax
+= (1 << 6);
2996 width
= gm
->gmBlackBoxX
;
2997 height
= gm
->gmBlackBoxY
;
2999 needed
= pitch
* height
;
3001 if (!buf
|| !buflen
) return needed
;
3002 if (needed
> buflen
) return GDI_ERROR
;
3004 if (needs_transform
)
3005 pFT_Outline_Transform( &glyph
->outline
, &matrices
[matrix_vert
] );
3007 #ifdef FT_LCD_FILTER_H
3008 if (pFT_Library_SetLcdFilter
)
3009 pFT_Library_SetLcdFilter( library
, FT_LCD_FILTER_DEFAULT
);
3011 pFT_Render_Glyph( glyph
, render_mode
);
3013 src_pitch
= glyph
->bitmap
.pitch
;
3014 src_width
= glyph
->bitmap
.width
;
3015 src_height
= glyph
->bitmap
.rows
;
3016 src
= glyph
->bitmap
.buffer
;
3018 memset( buf
, 0, buflen
);
3020 sub_order
= (format
== WINE_GGO_HRGB_BITMAP
||
3021 format
== WINE_GGO_VRGB_BITMAP
) ? rgb_order
: bgr_order
;
3022 sub_stride
= render_mode
== FT_RENDER_MODE_LCD
? 1 : src_pitch
;
3023 hmul
= render_mode
== FT_RENDER_MODE_LCD
? 3 : 1;
3024 vmul
= render_mode
== FT_RENDER_MODE_LCD
? 1 : 3;
3026 x_shift
= glyph
->bitmap_left
- (bbox
.xMin
>> 6);
3029 src
+= hmul
* -x_shift
;
3030 src_width
-= hmul
* -x_shift
;
3032 else if ( x_shift
> 0 )
3034 dst
+= x_shift
* sizeof(unsigned int);
3038 y_shift
= (bbox
.yMax
>> 6) - glyph
->bitmap_top
;
3041 src
+= src_pitch
* vmul
* -y_shift
;
3042 src_height
-= vmul
* -y_shift
;
3044 else if ( y_shift
> 0 )
3046 dst
+= y_shift
* pitch
;
3050 w
= min( width
, src_width
/ hmul
);
3051 h
= min( height
, src_height
/ vmul
);
3054 for (x
= 0; x
< w
; x
++)
3056 ((unsigned int *)dst
)[x
] =
3057 ((unsigned int)src
[hmul
* x
+ sub_stride
* sub_order
[0]] << 16) |
3058 ((unsigned int)src
[hmul
* x
+ sub_stride
* sub_order
[1]] << 8) |
3059 ((unsigned int)src
[hmul
* x
+ sub_stride
* sub_order
[2]]);
3061 src
+= src_pitch
* vmul
;
3067 FIXME ( "loaded glyph format %x\n", glyph
->format
);
3074 static unsigned int get_native_glyph_outline(FT_Outline
*outline
, unsigned int buflen
, char *buf
)
3076 TTPOLYGONHEADER
*pph
;
3078 unsigned int needed
= 0, point
= 0, contour
, first_pt
;
3079 unsigned int pph_start
, cpfx
;
3082 for (contour
= 0; contour
< outline
->n_contours
; contour
++)
3084 /* Ignore contours containing one point */
3085 if (point
== outline
->contours
[contour
])
3092 pph
= (TTPOLYGONHEADER
*)(buf
+ needed
);
3096 pph
->dwType
= TT_POLYGON_TYPE
;
3097 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
3099 needed
+= sizeof(*pph
);
3101 while (point
<= outline
->contours
[contour
])
3103 ppc
= (TTPOLYCURVE
*)(buf
+ needed
);
3104 type
= outline
->tags
[point
] & FT_Curve_Tag_On
?
3105 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
3110 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
3113 } while (point
<= outline
->contours
[contour
] &&
3114 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
3115 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
3116 /* At the end of a contour Windows adds the start point, but
3118 if (point
> outline
->contours
[contour
] &&
3119 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
))
3122 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
3125 else if (point
<= outline
->contours
[contour
] &&
3126 outline
->tags
[point
] & FT_Curve_Tag_On
)
3128 /* add closing pt for bezier */
3130 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
3139 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
3142 pph
->cb
= needed
- pph_start
;
3147 static unsigned int get_bezier_glyph_outline(FT_Outline
*outline
, unsigned int buflen
, char *buf
)
3149 /* Convert the quadratic Beziers to cubic Beziers.
3150 The parametric eqn for a cubic Bezier is, from PLRM:
3151 r(t) = at^3 + bt^2 + ct + r0
3152 with the control points:
3157 A quadratic Bezier has the form:
3158 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3160 So equating powers of t leads to:
3161 r1 = 2/3 p1 + 1/3 p0
3162 r2 = 2/3 p1 + 1/3 p2
3163 and of course r0 = p0, r3 = p2
3165 int contour
, point
= 0, first_pt
;
3166 TTPOLYGONHEADER
*pph
;
3168 DWORD pph_start
, cpfx
, type
;
3169 FT_Vector cubic_control
[4];
3170 unsigned int needed
= 0;
3172 for (contour
= 0; contour
< outline
->n_contours
; contour
++)
3175 pph
= (TTPOLYGONHEADER
*)(buf
+ needed
);
3179 pph
->dwType
= TT_POLYGON_TYPE
;
3180 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
3182 needed
+= sizeof(*pph
);
3184 while (point
<= outline
->contours
[contour
])
3186 ppc
= (TTPOLYCURVE
*)(buf
+ needed
);
3187 type
= outline
->tags
[point
] & FT_Curve_Tag_On
?
3188 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
3192 if (type
== TT_PRIM_LINE
)
3195 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
3201 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
3204 /* FIXME: Possible optimization in endpoint calculation
3205 if there are two consecutive curves */
3206 cubic_control
[0] = outline
->points
[point
-1];
3207 if (!(outline
->tags
[point
-1] & FT_Curve_Tag_On
))
3209 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
3210 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
3211 cubic_control
[0].x
>>= 1;
3212 cubic_control
[0].y
>>= 1;
3214 if (point
+1 > outline
->contours
[contour
])
3215 cubic_control
[3] = outline
->points
[first_pt
];
3218 cubic_control
[3] = outline
->points
[point
+1];
3219 if (!(outline
->tags
[point
+1] & FT_Curve_Tag_On
))
3221 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
3222 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
3223 cubic_control
[3].x
>>= 1;
3224 cubic_control
[3].y
>>= 1;
3227 /* r1 = 1/3 p0 + 2/3 p1
3228 r2 = 1/3 p2 + 2/3 p1 */
3229 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
3230 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
3231 cubic_control
[2] = cubic_control
[1];
3232 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
3233 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
3234 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
3235 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
3238 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
3239 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
3240 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
3245 } while (point
<= outline
->contours
[contour
] &&
3246 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
3247 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
3248 /* At the end of a contour Windows adds the start point,
3249 but only for Beziers and we've already done that.
3251 if (point
<= outline
->contours
[contour
] &&
3252 outline
->tags
[point
] & FT_Curve_Tag_On
)
3254 /* This is the closing pt of a bezier, but we've already
3255 added it, so just inc point and carry on */
3263 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
3266 pph
->cb
= needed
- pph_start
;
3271 static FT_Int
get_load_flags( UINT format
)
3273 FT_Int load_flags
= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
3275 if (format
& GGO_UNHINTED
)
3276 return load_flags
| FT_LOAD_NO_HINTING
;
3278 switch (format
& ~GGO_GLYPH_INDEX
)
3281 load_flags
|= FT_LOAD_TARGET_MONO
;
3283 case GGO_GRAY2_BITMAP
:
3284 case GGO_GRAY4_BITMAP
:
3285 case GGO_GRAY8_BITMAP
:
3286 case WINE_GGO_GRAY16_BITMAP
:
3287 load_flags
|= FT_LOAD_TARGET_NORMAL
;
3289 case WINE_GGO_HRGB_BITMAP
:
3290 case WINE_GGO_HBGR_BITMAP
:
3291 load_flags
|= FT_LOAD_TARGET_LCD
;
3293 case WINE_GGO_VRGB_BITMAP
:
3294 case WINE_GGO_VBGR_BITMAP
:
3295 load_flags
|= FT_LOAD_TARGET_LCD_V
;
3302 /*************************************************************
3303 * freetype_get_glyph_outline
3305 static DWORD CDECL
freetype_get_glyph_outline( struct gdi_font
*font
, UINT glyph
, UINT format
,
3306 GLYPHMETRICS
*lpgm
, ABC
*abc
, DWORD buflen
, void *buf
,
3307 const MAT2
*lpmat
, BOOL tategaki
)
3309 struct gdi_font
*base_font
= font
->base_font
? font
->base_font
: font
;
3310 FT_Face ft_face
= get_ft_face( font
);
3311 FT_Glyph_Metrics metrics
;
3314 FT_Int load_flags
= get_load_flags(format
);
3315 FT_Matrix matrices
[3];
3316 BOOL needsTransform
= FALSE
;
3317 BOOL vertical_metrics
;
3319 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
, buflen
, buf
, lpmat
);
3321 TRACE("font transform %f %f %f %f\n",
3322 font
->matrix
.eM11
, font
->matrix
.eM12
,
3323 font
->matrix
.eM21
, font
->matrix
.eM22
);
3325 needsTransform
= get_transform_matrices( font
, tategaki
, lpmat
, matrices
);
3327 vertical_metrics
= (tategaki
&& FT_HAS_VERTICAL(ft_face
));
3328 /* there is a freetype bug where vertical metrics are only
3329 properly scaled and correct in 2.4.0 or greater */
3330 if (vertical_metrics
&& FT_SimpleVersion
< FT_VERSION_VALUE(2, 4, 0))
3331 vertical_metrics
= FALSE
;
3333 if (needsTransform
|| format
!= GGO_BITMAP
) load_flags
|= FT_LOAD_NO_BITMAP
;
3334 if (vertical_metrics
) load_flags
|= FT_LOAD_VERTICAL_LAYOUT
;
3336 err
= pFT_Load_Glyph(ft_face
, glyph
, load_flags
);
3337 if (err
&& !(load_flags
& FT_LOAD_NO_HINTING
))
3339 WARN("Failed to load glyph %#x, retrying without hinting. Error %#x.\n", glyph
, err
);
3340 load_flags
|= FT_LOAD_NO_HINTING
;
3341 err
= pFT_Load_Glyph(ft_face
, glyph
, load_flags
);
3345 WARN("Failed to load glyph %#x, error %#x.\n", glyph
, err
);
3349 metrics
= ft_face
->glyph
->metrics
;
3350 if(font
->fake_bold
) {
3351 if (!get_bold_glyph_outline(ft_face
->glyph
, font
->ppem
, &metrics
) && metrics
.width
)
3352 metrics
.width
+= 1 << 6;
3355 /* Some poorly-created fonts contain glyphs that exceed the boundaries set
3356 * by the text metrics. The proper behavior is to clip the glyph metrics to
3357 * fit within the maximums specified in the text metrics. */
3358 if (freetype_set_outline_text_metrics(base_font
) ||
3359 freetype_set_bitmap_text_metrics(base_font
)) {
3360 TEXTMETRICW
*ptm
= &base_font
->otm
.otmTextMetrics
;
3361 INT top
= min( metrics
.horiBearingY
, ptm
->tmAscent
<< 6 );
3362 INT bottom
= max( metrics
.horiBearingY
- metrics
.height
, -(ptm
->tmDescent
<< 6) );
3363 metrics
.horiBearingY
= top
;
3364 metrics
.height
= top
- bottom
;
3366 /* TODO: Are we supposed to clip the width as well...? */
3367 /* metrics.width = min( metrics.width, ptm->tmMaxCharWidth << 6 ); */
3370 bbox
= get_transformed_bbox( &metrics
, needsTransform
, matrices
);
3371 compute_metrics( base_font
, font
, bbox
, &metrics
, tategaki
,
3372 vertical_metrics
, needsTransform
, matrices
, lpgm
, abc
);
3377 return 1; /* FIXME */
3380 return get_mono_glyph_bitmap( ft_face
->glyph
, bbox
, font
->fake_bold
,
3381 needsTransform
, matrices
, buflen
, buf
);
3383 case GGO_GRAY2_BITMAP
:
3384 case GGO_GRAY4_BITMAP
:
3385 case GGO_GRAY8_BITMAP
:
3386 case WINE_GGO_GRAY16_BITMAP
:
3387 return get_antialias_glyph_bitmap( ft_face
->glyph
, bbox
, format
, font
->fake_bold
,
3388 needsTransform
, matrices
, buflen
, buf
);
3390 case WINE_GGO_HRGB_BITMAP
:
3391 case WINE_GGO_HBGR_BITMAP
:
3392 case WINE_GGO_VRGB_BITMAP
:
3393 case WINE_GGO_VBGR_BITMAP
:
3394 return get_subpixel_glyph_bitmap( ft_face
->glyph
, bbox
, format
, font
->fake_bold
,
3395 needsTransform
, matrices
, lpgm
, buflen
, buf
);
3398 if (ft_face
->glyph
->format
== ft_glyph_format_outline
)
3400 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
3403 if (buflen
== 0) buf
= NULL
;
3405 if (needsTransform
&& buf
)
3406 pFT_Outline_Transform( outline
, &matrices
[matrix_vert
] );
3408 needed
= get_native_glyph_outline(outline
, buflen
, NULL
);
3410 if (!buf
|| !buflen
) return needed
;
3411 if (needed
> buflen
) return GDI_ERROR
;
3412 return get_native_glyph_outline(outline
, buflen
, buf
);
3414 TRACE("loaded a bitmap\n");
3418 if (ft_face
->glyph
->format
== ft_glyph_format_outline
)
3420 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
3423 if (buflen
== 0) buf
= NULL
;
3425 if (needsTransform
&& buf
)
3426 pFT_Outline_Transform( outline
, &matrices
[matrix_vert
] );
3428 needed
= get_bezier_glyph_outline(outline
, buflen
, NULL
);
3430 if (!buf
|| !buflen
) return needed
;
3431 if (needed
> buflen
) return GDI_ERROR
;
3432 return get_bezier_glyph_outline(outline
, buflen
, buf
);
3434 TRACE("loaded a bitmap\n");
3438 FIXME("Unsupported format %d\n", format
);
3443 /*************************************************************
3444 * freetype_set_bitmap_text_metrics
3446 static BOOL CDECL
freetype_set_bitmap_text_metrics( struct gdi_font
*font
)
3448 FT_Face ft_face
= get_ft_face( font
);
3449 FT_WinFNT_HeaderRec winfnt_header
;
3451 if (font
->otm
.otmSize
) return TRUE
; /* already set */
3452 font
->otm
.otmSize
= offsetof( OUTLINETEXTMETRICW
, otmFiller
);
3454 #define TM font->otm.otmTextMetrics
3455 if(!pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
3457 TM
.tmHeight
= winfnt_header
.pixel_height
;
3458 TM
.tmAscent
= winfnt_header
.ascent
;
3459 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
3460 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
3461 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
3462 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
3463 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
3464 TM
.tmWeight
= winfnt_header
.weight
;
3466 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
3467 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
3468 TM
.tmFirstChar
= winfnt_header
.first_char
;
3469 TM
.tmLastChar
= winfnt_header
.last_char
;
3470 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
3471 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
3472 TM
.tmItalic
= winfnt_header
.italic
;
3473 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
3474 TM
.tmCharSet
= winfnt_header
.charset
;
3478 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
3479 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
3480 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
3481 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
3482 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
3483 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
3484 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
3485 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
3487 TM
.tmDigitizedAspectX
= 96; /* FIXME */
3488 TM
.tmDigitizedAspectY
= 96; /* FIXME */
3490 TM
.tmLastChar
= 255;
3491 TM
.tmDefaultChar
= 32;
3492 TM
.tmBreakChar
= 32;
3493 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
3494 /* NB inverted meaning of TMPF_FIXED_PITCH */
3495 TM
.tmPitchAndFamily
= FT_IS_FIXED_WIDTH(ft_face
) ? 0 : TMPF_FIXED_PITCH
;
3496 TM
.tmCharSet
= font
->charset
;
3498 TM
.tmUnderlined
= font
->lf
.lfUnderline
? 0xff : 0;
3499 TM
.tmStruckOut
= font
->lf
.lfStrikeOut
? 0xff : 0;
3502 TM
.tmWeight
= FW_BOLD
;
3509 static BOOL
face_has_symbol_charmap(FT_Face ft_face
)
3513 for(i
= 0; i
< ft_face
->num_charmaps
; i
++)
3515 if(ft_face
->charmaps
[i
]->encoding
== FT_ENCODING_MS_SYMBOL
)
3521 /*************************************************************
3522 * freetype_set_outline_text_metrics
3524 static BOOL CDECL
freetype_set_outline_text_metrics( struct gdi_font
*font
)
3526 FT_Face ft_face
= get_ft_face( font
);
3529 TT_HoriHeader
*pHori
;
3530 TT_Postscript
*pPost
;
3532 INT ascent
, descent
;
3535 TRACE("font=%p\n", font
);
3537 if (!font
->scalable
) return FALSE
;
3538 if (font
->otm
.otmSize
) return TRUE
; /* already set */
3540 /* note: we store actual pointers in the names instead of offsets,
3541 they are fixed up when returned to the app */
3542 if (!(font
->otm
.otmpFullName
= (char *)get_face_name( ft_face
, TT_NAME_ID_UNIQUE_ID
, system_lcid
)))
3544 static const WCHAR fake_nameW
[] = {'f','a','k','e',' ','n','a','m','e', 0};
3545 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w((WCHAR
*)font
->otm
.otmpFamilyName
));
3546 font
->otm
.otmpFullName
= (char *)strdupW(fake_nameW
);
3548 needed
= sizeof(font
->otm
) + (lstrlenW( (WCHAR
*)font
->otm
.otmpFamilyName
) + 1 +
3549 lstrlenW( (WCHAR
*)font
->otm
.otmpStyleName
) + 1 +
3550 lstrlenW( (WCHAR
*)font
->otm
.otmpFaceName
) + 1 +
3551 lstrlenW( (WCHAR
*)font
->otm
.otmpFullName
) + 1) * sizeof(WCHAR
);
3553 em_scale
= (FT_Fixed
)pFT_MulDiv(font
->ppem
, 1 << 16, ft_face
->units_per_EM
);
3555 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
3557 FIXME("Can't find OS/2 table - not TT font?\n");
3561 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
3563 FIXME("Can't find HHEA table - not TT font?\n");
3567 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
3569 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",
3570 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
3571 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
3572 pOS2
->xAvgCharWidth
,
3573 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
3574 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
3575 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
3577 font
->otm
.otmSize
= needed
;
3579 #define TM font->otm.otmTextMetrics
3581 windescent
= get_fixed_windescent(pOS2
->usWinDescent
);
3582 if(pOS2
->usWinAscent
+ windescent
== 0) {
3583 ascent
= pHori
->Ascender
;
3584 descent
= -pHori
->Descender
;
3586 ascent
= pOS2
->usWinAscent
;
3587 descent
= windescent
;
3590 font
->ntmCellHeight
= ascent
+ descent
;
3591 font
->ntmAvgWidth
= pOS2
->xAvgCharWidth
;
3593 #define SCALE_X(x) (pFT_MulFix(x, em_scale))
3594 #define SCALE_Y(y) (pFT_MulFix(y, em_scale))
3597 TM
.tmAscent
= font
->yMax
;
3598 TM
.tmDescent
= -font
->yMin
;
3599 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
3601 TM
.tmAscent
= SCALE_Y(ascent
);
3602 TM
.tmDescent
= SCALE_Y(descent
);
3603 TM
.tmInternalLeading
= SCALE_Y(ascent
+ descent
- ft_face
->units_per_EM
);
3606 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
3609 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
3611 TM
.tmExternalLeading
= max(0, SCALE_Y(pHori
->Line_Gap
-
3612 ((ascent
+ descent
) -
3613 (pHori
->Ascender
- pHori
->Descender
))));
3615 TM
.tmAveCharWidth
= SCALE_X(pOS2
->xAvgCharWidth
);
3616 if (TM
.tmAveCharWidth
== 0) {
3617 TM
.tmAveCharWidth
= 1;
3619 TM
.tmMaxCharWidth
= SCALE_X(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
);
3620 TM
.tmWeight
= FW_REGULAR
;
3621 if (font
->fake_bold
)
3622 TM
.tmWeight
= FW_BOLD
;
3625 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)
3627 if (pOS2
->usWeightClass
> FW_MEDIUM
)
3628 TM
.tmWeight
= pOS2
->usWeightClass
;
3630 else if (pOS2
->usWeightClass
<= FW_MEDIUM
)
3631 TM
.tmWeight
= pOS2
->usWeightClass
;
3634 TM
.tmDigitizedAspectX
= 96; /* FIXME */
3635 TM
.tmDigitizedAspectY
= 96; /* FIXME */
3636 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
3637 * symbol range to 0 - f0ff
3640 if (face_has_symbol_charmap(ft_face
) || (pOS2
->usFirstCharIndex
>= 0xf000 && pOS2
->usFirstCharIndex
< 0xf100))
3643 switch (PRIMARYLANGID(system_lcid
))
3646 TM
.tmLastChar
= 0xf896;
3650 case LANG_LITHUANIAN
:
3651 TM
.tmLastChar
= 0xf8fd;
3654 TM
.tmLastChar
= 0xf0ff;
3656 TM
.tmBreakChar
= 0x20;
3657 TM
.tmDefaultChar
= 0x1f;
3661 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
; /* Should be the first char in the cmap */
3662 TM
.tmLastChar
= pOS2
->usLastCharIndex
; /* Should be min(cmap_last, os2_last) */
3664 if(pOS2
->usFirstCharIndex
<= 1)
3665 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
+ 2;
3666 else if (pOS2
->usFirstCharIndex
> 0xff)
3667 TM
.tmBreakChar
= 0x20;
3669 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
;
3670 TM
.tmDefaultChar
= TM
.tmBreakChar
- 1;
3672 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
3673 TM
.tmUnderlined
= font
->lf
.lfUnderline
? 255 : 0;
3674 TM
.tmStruckOut
= font
->lf
.lfStrikeOut
? 255 : 0;
3676 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
3677 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
3678 (pOS2
->version
== 0xFFFFU
||
3679 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
3680 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
3682 TM
.tmPitchAndFamily
= 0;
3684 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
])
3686 case PAN_FAMILY_SCRIPT
:
3687 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
3690 case PAN_FAMILY_DECORATIVE
:
3691 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
3696 case PAN_FAMILY_TEXT_DISPLAY
:
3697 case PAN_FAMILY_PICTORIAL
: /* symbol fonts get treated as if they were text */
3698 /* which is clearly not what the panose spec says. */
3700 if(TM
.tmPitchAndFamily
== 0 || /* fixed */
3701 pOS2
->panose
[PAN_PROPORTION_INDEX
] == PAN_PROP_MONOSPACED
)
3702 TM
.tmPitchAndFamily
= FF_MODERN
;
3705 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
])
3710 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
3713 case PAN_SERIF_COVE
:
3714 case PAN_SERIF_OBTUSE_COVE
:
3715 case PAN_SERIF_SQUARE_COVE
:
3716 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
3717 case PAN_SERIF_SQUARE
:
3718 case PAN_SERIF_THIN
:
3719 case PAN_SERIF_BONE
:
3720 case PAN_SERIF_EXAGGERATED
:
3721 case PAN_SERIF_TRIANGLE
:
3722 TM
.tmPitchAndFamily
|= FF_ROMAN
;
3725 case PAN_SERIF_NORMAL_SANS
:
3726 case PAN_SERIF_OBTUSE_SANS
:
3727 case PAN_SERIF_PERP_SANS
:
3728 case PAN_SERIF_FLARED
:
3729 case PAN_SERIF_ROUNDED
:
3730 TM
.tmPitchAndFamily
|= FF_SWISS
;
3737 if(FT_IS_SCALABLE(ft_face
))
3738 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
3740 if(FT_IS_SFNT(ft_face
))
3742 if (font
->ntmFlags
& NTM_PS_OPENTYPE
)
3743 TM
.tmPitchAndFamily
|= TMPF_DEVICE
;
3745 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
3748 TM
.tmCharSet
= font
->charset
;
3750 font
->otm
.otmFiller
= 0;
3751 memcpy(&font
->otm
.otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
3752 font
->otm
.otmfsSelection
= pOS2
->fsSelection
;
3753 if (font
->fake_italic
)
3754 font
->otm
.otmfsSelection
|= 1;
3755 if (font
->fake_bold
)
3756 font
->otm
.otmfsSelection
|= 1 << 5;
3757 /* Only return valid bits that define embedding and subsetting restrictions */
3758 font
->otm
.otmfsType
= pOS2
->fsType
& 0x30e;
3759 font
->otm
.otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
3760 font
->otm
.otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
3761 font
->otm
.otmItalicAngle
= 0; /* POST table */
3762 font
->otm
.otmEMSquare
= ft_face
->units_per_EM
;
3763 font
->otm
.otmAscent
= SCALE_Y(pOS2
->sTypoAscender
);
3764 font
->otm
.otmDescent
= SCALE_Y(pOS2
->sTypoDescender
);
3765 font
->otm
.otmLineGap
= SCALE_Y(pOS2
->sTypoLineGap
);
3766 font
->otm
.otmsCapEmHeight
= SCALE_Y(pOS2
->sCapHeight
);
3767 font
->otm
.otmsXHeight
= SCALE_Y(pOS2
->sxHeight
);
3768 font
->otm
.otmrcFontBox
.left
= SCALE_X(ft_face
->bbox
.xMin
);
3769 font
->otm
.otmrcFontBox
.right
= SCALE_X(ft_face
->bbox
.xMax
);
3770 font
->otm
.otmrcFontBox
.top
= SCALE_Y(ft_face
->bbox
.yMax
);
3771 font
->otm
.otmrcFontBox
.bottom
= SCALE_Y(ft_face
->bbox
.yMin
);
3772 font
->otm
.otmMacAscent
= TM
.tmAscent
;
3773 font
->otm
.otmMacDescent
= -TM
.tmDescent
;
3774 font
->otm
.otmMacLineGap
= SCALE_Y(pHori
->Line_Gap
);
3775 font
->otm
.otmusMinimumPPEM
= 0; /* TT Header */
3776 font
->otm
.otmptSubscriptSize
.x
= SCALE_X(pOS2
->ySubscriptXSize
);
3777 font
->otm
.otmptSubscriptSize
.y
= SCALE_Y(pOS2
->ySubscriptYSize
);
3778 font
->otm
.otmptSubscriptOffset
.x
= SCALE_X(pOS2
->ySubscriptXOffset
);
3779 font
->otm
.otmptSubscriptOffset
.y
= SCALE_Y(pOS2
->ySubscriptYOffset
);
3780 font
->otm
.otmptSuperscriptSize
.x
= SCALE_X(pOS2
->ySuperscriptXSize
);
3781 font
->otm
.otmptSuperscriptSize
.y
= SCALE_Y(pOS2
->ySuperscriptYSize
);
3782 font
->otm
.otmptSuperscriptOffset
.x
= SCALE_X(pOS2
->ySuperscriptXOffset
);
3783 font
->otm
.otmptSuperscriptOffset
.y
= SCALE_Y(pOS2
->ySuperscriptYOffset
);
3784 font
->otm
.otmsStrikeoutSize
= SCALE_Y(pOS2
->yStrikeoutSize
);
3785 font
->otm
.otmsStrikeoutPosition
= SCALE_Y(pOS2
->yStrikeoutPosition
);
3787 font
->otm
.otmsUnderscoreSize
= 0;
3788 font
->otm
.otmsUnderscorePosition
= 0;
3790 font
->otm
.otmsUnderscoreSize
= SCALE_Y(pPost
->underlineThickness
);
3791 font
->otm
.otmsUnderscorePosition
= SCALE_Y(pPost
->underlinePosition
);
3799 /*************************************************************
3800 * freetype_get_char_width_info
3802 static BOOL CDECL
freetype_get_char_width_info( struct gdi_font
*font
, struct char_width_info
*info
)
3804 FT_Face ft_face
= get_ft_face( font
);
3805 TT_HoriHeader
*pHori
;
3807 TRACE("%p, %p\n", font
, info
);
3809 if ((pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
)))
3811 FT_Fixed em_scale
= pFT_MulDiv(font
->ppem
, 1 << 16, ft_face
->units_per_EM
);
3812 info
->lsb
= (SHORT
)pFT_MulFix(pHori
->min_Left_Side_Bearing
, em_scale
);
3813 info
->rsb
= (SHORT
)pFT_MulFix(pHori
->min_Right_Side_Bearing
, em_scale
);
3820 /*************************************************************
3821 * freetype_get_unicode_ranges
3823 * Retrieve a list of supported Unicode ranges for a given font.
3824 * Can be called with NULL gs to calculate the buffer size. Returns
3825 * the number of ranges found.
3827 static DWORD CDECL
freetype_get_unicode_ranges( struct gdi_font
*font
, GLYPHSET
*gs
)
3829 FT_Face ft_face
= get_ft_face( font
);
3830 DWORD num_ranges
= 0;
3832 if (ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
3835 FT_ULong char_code
, char_code_prev
;
3838 char_code_prev
= char_code
= pFT_Get_First_Char(ft_face
, &glyph_code
);
3840 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
3841 ft_face
->num_glyphs
, glyph_code
, char_code
);
3843 if (!glyph_code
) return 0;
3847 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
3848 gs
->ranges
[0].cGlyphs
= 0;
3849 gs
->cGlyphsSupported
= 0;
3855 if (char_code
< char_code_prev
)
3857 ERR("expected increasing char code from FT_Get_Next_Char\n");
3860 if (char_code
- char_code_prev
> 1)
3865 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
3866 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
3867 gs
->cGlyphsSupported
++;
3872 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
3873 gs
->cGlyphsSupported
++;
3875 char_code_prev
= char_code
;
3876 char_code
= pFT_Get_Next_Char(ft_face
, char_code
, &glyph_code
);
3881 DWORD encoding
= RtlUlongByteSwap(ft_face
->charmap
->encoding
);
3882 FIXME("encoding %s not supported\n", debugstr_an((char *)&encoding
, 4));
3888 /*************************************************************************
3889 * Kerning support for TrueType fonts
3892 struct TT_kern_table
3898 struct TT_kern_subtable
3907 USHORT horizontal
: 1;
3909 USHORT cross_stream
: 1;
3910 USHORT override
: 1;
3911 USHORT reserved1
: 4;
3917 struct TT_format0_kern_subtable
3921 USHORT entrySelector
;
3932 static DWORD
parse_format0_kern_subtable(struct gdi_font
*font
,
3933 const struct TT_format0_kern_subtable
*tt_f0_ks
,
3934 const USHORT
*glyph_to_char
,
3935 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
3937 FT_Face ft_face
= get_ft_face( font
);
3939 const struct TT_kern_pair
*tt_kern_pair
;
3941 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, ft_face
->units_per_EM
);
3943 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
3945 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
3946 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
3947 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
3949 if (!kern_pair
|| !cPairs
)
3952 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
3954 nPairs
= min(nPairs
, cPairs
);
3956 for (i
= 0; i
< nPairs
; i
++)
3958 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
3959 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
3960 /* this algorithm appears to better match what Windows does */
3961 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
3962 if (kern_pair
->iKernAmount
< 0)
3964 kern_pair
->iKernAmount
-= ft_face
->units_per_EM
/ 2;
3965 kern_pair
->iKernAmount
-= font
->ppem
;
3967 else if (kern_pair
->iKernAmount
> 0)
3969 kern_pair
->iKernAmount
+= ft_face
->units_per_EM
/ 2;
3970 kern_pair
->iKernAmount
+= font
->ppem
;
3972 kern_pair
->iKernAmount
/= ft_face
->units_per_EM
;
3974 TRACE("left %u right %u value %d\n",
3975 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
3979 TRACE("copied %u entries\n", nPairs
);
3983 /*************************************************************
3984 * freetype_get_kerning_pairs
3986 static DWORD CDECL
freetype_get_kerning_pairs( struct gdi_font
*font
, KERNINGPAIR
**pairs
)
3988 FT_Face ft_face
= get_ft_face( font
);
3989 DWORD length
, count
= 0;
3991 const struct TT_kern_table
*tt_kern_table
;
3992 const struct TT_kern_subtable
*tt_kern_subtable
;
3994 USHORT
*glyph_to_char
;
3996 length
= freetype_get_font_data(font
, MS_KERN_TAG
, 0, NULL
, 0);
3998 if (length
== GDI_ERROR
)
4000 TRACE("no kerning data in the font\n");
4004 buf
= RtlAllocateHeap(GetProcessHeap(), 0, length
);
4007 freetype_get_font_data(font
, MS_KERN_TAG
, 0, buf
, length
);
4009 /* build a glyph index to char code map */
4010 glyph_to_char
= RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(USHORT
) * 65536);
4013 RtlFreeHeap(GetProcessHeap(), 0, buf
);
4017 if (ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
4023 char_code
= pFT_Get_First_Char(ft_face
, &glyph_code
);
4025 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
4026 ft_face
->num_glyphs
, glyph_code
, char_code
);
4030 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
4032 /* FIXME: This doesn't match what Windows does: it does some fancy
4033 * things with duplicate glyph index to char code mappings, while
4034 * we just avoid overriding existing entries.
4036 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
4037 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
4039 char_code
= pFT_Get_Next_Char(ft_face
, char_code
, &glyph_code
);
4044 DWORD encoding
= RtlUlongByteSwap(ft_face
->charmap
->encoding
);
4047 FIXME("encoding %s not supported\n", debugstr_an((char *)&encoding
, 4));
4048 for (n
= 0; n
<= 65535; n
++)
4049 glyph_to_char
[n
] = (USHORT
)n
;
4052 tt_kern_table
= buf
;
4053 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
4054 TRACE("version %u, nTables %u\n",
4055 GET_BE_WORD(tt_kern_table
->version
), nTables
);
4057 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
4059 for (i
= 0; i
< nTables
; i
++)
4061 struct TT_kern_subtable tt_kern_subtable_copy
;
4063 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
4064 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
4065 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
4067 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
4068 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
4069 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
4071 /* According to the TrueType specification this is the only format
4072 * that will be properly interpreted by Windows and OS/2
4074 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
4076 DWORD new_chunk
, old_total
= count
;
4078 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
4079 glyph_to_char
, NULL
, 0);
4083 *pairs
= RtlAllocateHeap(GetProcessHeap(), 0, count
* sizeof(**pairs
));
4085 *pairs
= RtlReAllocateHeap(GetProcessHeap(), 0, *pairs
, count
* sizeof(**pairs
));
4087 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
4088 glyph_to_char
, *pairs
+ old_total
, new_chunk
);
4091 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
4093 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
4096 RtlFreeHeap(GetProcessHeap(), 0, glyph_to_char
);
4097 RtlFreeHeap(GetProcessHeap(), 0, buf
);
4101 static const struct font_backend_funcs font_funcs
=
4103 freetype_load_fonts
,
4104 fontconfig_enum_family_fallbacks
,
4106 freetype_add_mem_font
,
4108 freetype_get_font_data
,
4109 freetype_get_aa_flags
,
4110 freetype_get_glyph_index
,
4111 freetype_get_default_glyph
,
4112 freetype_get_glyph_outline
,
4113 freetype_get_unicode_ranges
,
4114 freetype_get_char_width_info
,
4115 freetype_set_outline_text_metrics
,
4116 freetype_set_bitmap_text_metrics
,
4117 freetype_get_kerning_pairs
,
4118 freetype_destroy_font
4121 static NTSTATUS
init_freetype_lib( HMODULE module
, DWORD reason
, const void *ptr_in
, void *ptr_out
)
4123 callback_funcs
= ptr_in
;
4124 if (!init_freetype()) return STATUS_DLL_NOT_FOUND
;
4125 #ifdef SONAME_LIBFONTCONFIG
4128 NtQueryDefaultLocale( FALSE
, &system_lcid
);
4129 *(const struct font_backend_funcs
**)ptr_out
= &font_funcs
;
4130 return STATUS_SUCCESS
;
4133 #else /* HAVE_FREETYPE */
4135 static NTSTATUS
init_freetype_lib( HMODULE module
, DWORD reason
, const void *ptr_in
, void *ptr_out
)
4137 return STATUS_DLL_NOT_FOUND
;
4140 #endif /* HAVE_FREETYPE */
4142 NTSTATUS CDECL
__wine_init_unix_lib( HMODULE module
, DWORD reason
, const void *ptr_in
, void *ptr_out
)
4144 if (reason
!= DLL_PROCESS_ATTACH
) return STATUS_SUCCESS
;
4146 if (ptr_in
) return init_freetype_lib( module
, reason
, ptr_in
, ptr_out
);
4147 else return init_opengl_lib( module
, reason
, ptr_in
, ptr_out
);