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
);
194 #define FC_NAMELANG "namelang"
197 #define FC_PRGNAME "prgname"
199 #endif /* SONAME_LIBFONTCONFIG */
204 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
205 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
206 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
209 #ifndef ft_encoding_none
210 #define FT_ENCODING_NONE ft_encoding_none
212 #ifndef ft_encoding_ms_symbol
213 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
215 #ifndef ft_encoding_unicode
216 #define FT_ENCODING_UNICODE ft_encoding_unicode
218 #ifndef ft_encoding_apple_roman
219 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
222 #ifdef WORDS_BIGENDIAN
223 #define GET_BE_WORD(x) (x)
224 #define GET_BE_DWORD(x) (x)
226 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
227 #define GET_BE_DWORD(x) RtlUlongByteSwap(x)
231 #define GASP_GRIDFIT 0x01
232 #define GASP_DOGRAY 0x02
234 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
235 So to let this compile on older versions of FreeType we'll define the
236 new structure here. */
238 FT_Short height
, width
;
239 FT_Pos size
, x_ppem
, y_ppem
;
242 struct font_private_data
245 struct font_mapping
*mapping
;
248 static inline FT_Face
get_ft_face( struct gdi_font
*font
)
250 return ((struct font_private_data
*)font
->private)->ft_face
;
253 static const struct font_callback_funcs
*callback_funcs
;
265 static struct list mappings_list
= LIST_INIT( mappings_list
);
267 static UINT default_aa_flags
;
268 static LCID system_lcid
;
270 static BOOL CDECL
freetype_set_outline_text_metrics( struct gdi_font
*font
);
271 static BOOL CDECL
freetype_set_bitmap_text_metrics( struct gdi_font
*font
);
273 /****************************************
274 * Notes on .fon files
276 * The fonts System, FixedSys and Terminal are special. There are typically multiple
277 * versions installed for different resolutions and codepages. Windows stores which one to use
278 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
280 * FIXEDFON.FON FixedSys
282 * OEMFONT.FON Terminal
283 * LogPixels Current dpi set by the display control panel applet
284 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
285 * also has a LogPixels value that appears to mirror this)
287 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
288 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
289 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
290 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
291 * so that makes sense.
293 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
294 * to be mapped into the registry on Windows 2000 at least).
297 * ega80woa.fon=ega80850.fon
298 * ega40woa.fon=ega40850.fon
299 * cga80woa.fon=cga80850.fon
300 * cga40woa.fon=cga40850.fon
303 #ifdef HAVE_CARBON_CARBON_H
304 static char *find_cache_dir(void)
308 static char cached_path
[MAX_PATH
];
309 static const char *wine
= "/Wine", *fonts
= "/Fonts";
311 if(*cached_path
) return cached_path
;
313 err
= FSFindFolder(kUserDomain
, kCachedDataFolderType
, kCreateFolder
, &ref
);
316 WARN("can't create cached data folder\n");
319 err
= FSRefMakePath(&ref
, (unsigned char*)cached_path
, sizeof(cached_path
));
322 WARN("can't create cached data path\n");
326 if(strlen(cached_path
) + strlen(wine
) + strlen(fonts
) + 1 > sizeof(cached_path
))
328 ERR("Could not create full path\n");
332 strcat(cached_path
, wine
);
334 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
336 WARN("Couldn't mkdir %s\n", cached_path
);
340 strcat(cached_path
, fonts
);
341 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
343 WARN("Couldn't mkdir %s\n", cached_path
);
350 /******************************************************************
353 * Extracts individual TrueType font files from a Mac suitcase font
354 * and saves them into the user's caches directory (see
356 * Returns a NULL terminated array of filenames.
358 * We do this because they are apps that try to read ttf files
359 * themselves and they don't like Mac suitcase files.
361 static char **expand_mac_font(const char *path
)
364 ResFileRefNum res_ref
;
368 const char *filename
;
372 unsigned int size
, max_size
;
375 TRACE("path %s\n", path
);
377 s
= FSPathMakeRef((unsigned char*)path
, &ref
, FALSE
);
380 WARN("failed to get ref\n");
384 s
= FSOpenResourceFile(&ref
, 0, NULL
, fsRdPerm
, &res_ref
);
387 TRACE("no data fork, so trying resource fork\n");
388 res_ref
= FSOpenResFile(&ref
, fsRdPerm
);
391 TRACE("unable to open resource fork\n");
398 ret
.array
= RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.max_size
* sizeof(*ret
.array
));
401 CloseResFile(res_ref
);
405 out_dir
= find_cache_dir();
407 filename
= strrchr(path
, '/');
408 if(!filename
) filename
= path
;
411 /* output filename has the form out_dir/filename_%04x.ttf */
412 output_len
= strlen(out_dir
) + 1 + strlen(filename
) + 5 + 5;
419 unsigned short *num_faces_ptr
, num_faces
, face
;
422 ResType fond_res
= FT_MAKE_TAG('F','O','N','D');
424 fond
= Get1IndResource(fond_res
, idx
);
426 TRACE("got fond resource %d\n", idx
);
429 fam_rec
= *(FamRec
**)fond
;
430 num_faces_ptr
= (unsigned short *)(fam_rec
+ 1);
431 num_faces
= GET_BE_WORD(*num_faces_ptr
);
433 assoc
= (AsscEntry
*)(num_faces_ptr
+ 1);
434 TRACE("num faces %04x\n", num_faces
);
435 for(face
= 0; face
< num_faces
; face
++, assoc
++)
438 ResType sfnt_res
= FT_MAKE_TAG('s','f','n','t');
439 unsigned short size
, font_id
;
442 size
= GET_BE_WORD(assoc
->fontSize
);
443 font_id
= GET_BE_WORD(assoc
->fontID
);
446 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id
, size
);
450 TRACE("trying to load sfnt id %04x\n", font_id
);
451 sfnt
= GetResource(sfnt_res
, font_id
);
454 TRACE("can't get sfnt resource %04x\n", font_id
);
458 output
= RtlAllocateHeap(GetProcessHeap(), 0, output_len
);
463 sprintf(output
, "%s/%s_%04x.ttf", out_dir
, filename
, font_id
);
465 fd
= open(output
, O_CREAT
| O_EXCL
| O_WRONLY
, 0600);
466 if(fd
!= -1 || errno
== EEXIST
)
470 unsigned char *sfnt_data
;
473 sfnt_data
= *(unsigned char**)sfnt
;
474 write(fd
, sfnt_data
, GetHandleSize(sfnt
));
478 if(ret
.size
>= ret
.max_size
- 1) /* Always want the last element to be NULL */
481 ret
.array
= RtlReAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.array
, ret
.max_size
* sizeof(*ret
.array
));
483 ret
.array
[ret
.size
++] = output
;
487 WARN("unable to create %s\n", output
);
488 RtlFreeHeap(GetProcessHeap(), 0, output
);
491 ReleaseResource(sfnt
);
494 ReleaseResource(fond
);
497 CloseResFile(res_ref
);
502 #endif /* HAVE_CARBON_CARBON_H */
505 This function builds an FT_Fixed from a double. It fails if the absolute
506 value of the float number is greater than 32768.
508 static inline FT_Fixed
FT_FixedFromFloat(double f
)
514 This function builds an FT_Fixed from a FIXED. It simply put f.value
515 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
517 static inline FT_Fixed
FT_FixedFromFIXED(FIXED f
)
519 return (FT_Fixed
)((int)f
.value
<< 16 | (unsigned int)f
.fract
);
522 static BOOL
is_hinting_enabled(void)
524 static int enabled
= -1;
528 /* Use the >= 2.2.0 function if available */
529 if (pFT_Get_TrueType_Engine_Type
)
531 FT_TrueTypeEngineType type
= pFT_Get_TrueType_Engine_Type(library
);
532 enabled
= (type
== FT_TRUETYPE_ENGINE_TYPE_PATENTED
);
534 else enabled
= FALSE
;
535 TRACE("hinting is %senabled\n", enabled
? "" : "NOT ");
540 static BOOL
is_subpixel_rendering_enabled( void )
542 static int enabled
= -1;
545 /* FreeType >= 2.8.1 offers LCD-optimezed rendering without lcd filters. */
546 if (FT_SimpleVersion
>= FT_VERSION_VALUE(2, 8, 1))
548 #ifdef FT_LCD_FILTER_H
549 else if (pFT_Library_SetLcdFilter
&&
550 pFT_Library_SetLcdFilter( NULL
, 0 ) != FT_Err_Unimplemented_Feature
)
553 else enabled
= FALSE
;
555 TRACE("subpixel rendering is %senabled\n", enabled
? "" : "NOT ");
561 static LPWSTR
strdupW(LPCWSTR p
)
564 DWORD len
= (lstrlenW(p
) + 1) * sizeof(WCHAR
);
565 ret
= RtlAllocateHeap(GetProcessHeap(), 0, len
);
570 static WCHAR
*towstr(const char *str
)
572 DWORD len
= strlen(str
) + 1;
573 WCHAR
*wstr
= RtlAllocateHeap( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
574 RtlMultiByteToUnicodeN( wstr
, len
* sizeof(WCHAR
), &len
, str
, len
);
579 static const LANGID mac_langid_table
[] =
581 MAKELANGID(LANG_ENGLISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ENGLISH */
582 MAKELANGID(LANG_FRENCH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FRENCH */
583 MAKELANGID(LANG_GERMAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GERMAN */
584 MAKELANGID(LANG_ITALIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ITALIAN */
585 MAKELANGID(LANG_DUTCH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_DUTCH */
586 MAKELANGID(LANG_SWEDISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SWEDISH */
587 MAKELANGID(LANG_SPANISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SPANISH */
588 MAKELANGID(LANG_DANISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_DANISH */
589 MAKELANGID(LANG_PORTUGUESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PORTUGUESE */
590 MAKELANGID(LANG_NORWEGIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_NORWEGIAN */
591 MAKELANGID(LANG_HEBREW
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HEBREW */
592 MAKELANGID(LANG_JAPANESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_JAPANESE */
593 MAKELANGID(LANG_ARABIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ARABIC */
594 MAKELANGID(LANG_FINNISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FINNISH */
595 MAKELANGID(LANG_GREEK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GREEK */
596 MAKELANGID(LANG_ICELANDIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ICELANDIC */
597 MAKELANGID(LANG_MALTESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALTESE */
598 MAKELANGID(LANG_TURKISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TURKISH */
599 MAKELANGID(LANG_CROATIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CROATIAN */
600 MAKELANGID(LANG_CHINESE_TRADITIONAL
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CHINESE_TRADITIONAL */
601 MAKELANGID(LANG_URDU
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_URDU */
602 MAKELANGID(LANG_HINDI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HINDI */
603 MAKELANGID(LANG_THAI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_THAI */
604 MAKELANGID(LANG_KOREAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KOREAN */
605 MAKELANGID(LANG_LITHUANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LITHUANIAN */
606 MAKELANGID(LANG_POLISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_POLISH */
607 MAKELANGID(LANG_HUNGARIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HUNGARIAN */
608 MAKELANGID(LANG_ESTONIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ESTONIAN */
609 MAKELANGID(LANG_LATVIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LETTISH */
610 MAKELANGID(LANG_SAMI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SAAMISK */
611 MAKELANGID(LANG_FAEROESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FAEROESE */
612 MAKELANGID(LANG_FARSI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FARSI */
613 MAKELANGID(LANG_RUSSIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_RUSSIAN */
614 MAKELANGID(LANG_CHINESE_SIMPLIFIED
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CHINESE_SIMPLIFIED */
615 MAKELANGID(LANG_DUTCH
,SUBLANG_DUTCH_BELGIAN
), /* TT_MAC_LANGID_FLEMISH */
616 MAKELANGID(LANG_IRISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_IRISH */
617 MAKELANGID(LANG_ALBANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ALBANIAN */
618 MAKELANGID(LANG_ROMANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ROMANIAN */
619 MAKELANGID(LANG_CZECH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CZECH */
620 MAKELANGID(LANG_SLOVAK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SLOVAK */
621 MAKELANGID(LANG_SLOVENIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SLOVENIAN */
622 0, /* TT_MAC_LANGID_YIDDISH */
623 MAKELANGID(LANG_SERBIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SERBIAN */
624 MAKELANGID(LANG_MACEDONIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MACEDONIAN */
625 MAKELANGID(LANG_BULGARIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BULGARIAN */
626 MAKELANGID(LANG_UKRAINIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UKRAINIAN */
627 MAKELANGID(LANG_BELARUSIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BYELORUSSIAN */
628 MAKELANGID(LANG_UZBEK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UZBEK */
629 MAKELANGID(LANG_KAZAK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KAZAKH */
630 MAKELANGID(LANG_AZERI
,SUBLANG_AZERI_CYRILLIC
), /* TT_MAC_LANGID_AZERBAIJANI */
631 0, /* TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT */
632 MAKELANGID(LANG_ARMENIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ARMENIAN */
633 MAKELANGID(LANG_GEORGIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GEORGIAN */
634 0, /* TT_MAC_LANGID_MOLDAVIAN */
635 MAKELANGID(LANG_KYRGYZ
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KIRGHIZ */
636 MAKELANGID(LANG_TAJIK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TAJIKI */
637 MAKELANGID(LANG_TURKMEN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TURKMEN */
638 MAKELANGID(LANG_MONGOLIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MONGOLIAN */
639 MAKELANGID(LANG_MONGOLIAN
,SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA
), /* TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT */
640 MAKELANGID(LANG_PASHTO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PASHTO */
641 0, /* TT_MAC_LANGID_KURDISH */
642 MAKELANGID(LANG_KASHMIRI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KASHMIRI */
643 MAKELANGID(LANG_SINDHI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SINDHI */
644 MAKELANGID(LANG_TIBETAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TIBETAN */
645 MAKELANGID(LANG_NEPALI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_NEPALI */
646 MAKELANGID(LANG_SANSKRIT
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SANSKRIT */
647 MAKELANGID(LANG_MARATHI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MARATHI */
648 MAKELANGID(LANG_BENGALI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BENGALI */
649 MAKELANGID(LANG_ASSAMESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ASSAMESE */
650 MAKELANGID(LANG_GUJARATI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GUJARATI */
651 MAKELANGID(LANG_PUNJABI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PUNJABI */
652 MAKELANGID(LANG_ORIYA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ORIYA */
653 MAKELANGID(LANG_MALAYALAM
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAYALAM */
654 MAKELANGID(LANG_KANNADA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KANNADA */
655 MAKELANGID(LANG_TAMIL
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TAMIL */
656 MAKELANGID(LANG_TELUGU
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TELUGU */
657 MAKELANGID(LANG_SINHALESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SINHALESE */
658 0, /* TT_MAC_LANGID_BURMESE */
659 MAKELANGID(LANG_KHMER
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KHMER */
660 MAKELANGID(LANG_LAO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LAO */
661 MAKELANGID(LANG_VIETNAMESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_VIETNAMESE */
662 MAKELANGID(LANG_INDONESIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_INDONESIAN */
663 0, /* TT_MAC_LANGID_TAGALOG */
664 MAKELANGID(LANG_MALAY
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAY_ROMAN_SCRIPT */
665 0, /* TT_MAC_LANGID_MALAY_ARABIC_SCRIPT */
666 MAKELANGID(LANG_AMHARIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_AMHARIC */
667 MAKELANGID(LANG_TIGRIGNA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TIGRINYA */
668 0, /* TT_MAC_LANGID_GALLA */
669 0, /* TT_MAC_LANGID_SOMALI */
670 MAKELANGID(LANG_SWAHILI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SWAHILI */
671 0, /* TT_MAC_LANGID_RUANDA */
672 0, /* TT_MAC_LANGID_RUNDI */
673 0, /* TT_MAC_LANGID_CHEWA */
674 MAKELANGID(LANG_MALAGASY
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAGASY */
675 MAKELANGID(LANG_ESPERANTO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ESPERANTO */
676 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 95-111 */
677 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 112-127 */
678 MAKELANGID(LANG_WELSH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_WELSH */
679 MAKELANGID(LANG_BASQUE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BASQUE */
680 MAKELANGID(LANG_CATALAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CATALAN */
681 0, /* TT_MAC_LANGID_LATIN */
682 MAKELANGID(LANG_QUECHUA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_QUECHUA */
683 0, /* TT_MAC_LANGID_GUARANI */
684 0, /* TT_MAC_LANGID_AYMARA */
685 MAKELANGID(LANG_TATAR
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TATAR */
686 MAKELANGID(LANG_UIGHUR
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UIGHUR */
687 0, /* TT_MAC_LANGID_DZONGKHA */
688 0, /* TT_MAC_LANGID_JAVANESE */
689 0, /* TT_MAC_LANGID_SUNDANESE */
690 MAKELANGID(LANG_GALICIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GALICIAN */
691 MAKELANGID(LANG_AFRIKAANS
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_AFRIKAANS */
692 MAKELANGID(LANG_BRETON
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BRETON */
693 MAKELANGID(LANG_INUKTITUT
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_INUKTITUT */
694 MAKELANGID(LANG_SCOTTISH_GAELIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SCOTTISH_GAELIC */
695 MAKELANGID(LANG_MANX_GAELIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MANX_GAELIC */
696 MAKELANGID(LANG_IRISH
,SUBLANG_IRISH_IRELAND
), /* TT_MAC_LANGID_IRISH_GAELIC */
697 0, /* TT_MAC_LANGID_TONGAN */
698 0, /* TT_MAC_LANGID_GREEK_POLYTONIC */
699 MAKELANGID(LANG_GREENLANDIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GREELANDIC */
700 MAKELANGID(LANG_AZERI
,SUBLANG_AZERI_LATIN
), /* TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT */
703 static CPTABLEINFO
*get_mac_code_page( const FT_SfntName
*name
)
705 static CPTABLEINFO tables
[100];
706 int id
= name
->encoding_id
;
710 if (name
->encoding_id
== TT_MAC_ID_SIMPLIFIED_CHINESE
) id
= 8; /* special case */
711 if (id
>= ARRAY_SIZE(tables
)) return NULL
;
712 if (!tables
[id
].CodePage
)
714 if (NtGetNlsSectionPtr( 11, 10000 + id
, NULL
, (void **)&ptr
, &size
)) return NULL
;
715 RtlInitCodePageTable( ptr
, &tables
[id
] );
720 static int match_name_table_language( const FT_SfntName
*name
, LANGID lang
)
725 switch (name
->platform_id
)
727 case TT_PLATFORM_MICROSOFT
:
728 res
+= 5; /* prefer the Microsoft name */
729 switch (name
->encoding_id
)
731 case TT_MS_ID_UNICODE_CS
:
732 case TT_MS_ID_SYMBOL_CS
:
733 name_lang
= name
->language_id
;
739 case TT_PLATFORM_MACINTOSH
:
740 if (!get_mac_code_page( name
)) return 0;
741 if (name
->language_id
>= ARRAY_SIZE( mac_langid_table
)) return 0;
742 name_lang
= mac_langid_table
[name
->language_id
];
744 case TT_PLATFORM_APPLE_UNICODE
:
745 res
+= 2; /* prefer Unicode encodings */
746 switch (name
->encoding_id
)
748 case TT_APPLE_ID_DEFAULT
:
749 case TT_APPLE_ID_ISO_10646
:
750 case TT_APPLE_ID_UNICODE_2_0
:
751 if (name
->language_id
>= ARRAY_SIZE( mac_langid_table
)) return 0;
752 name_lang
= mac_langid_table
[name
->language_id
];
761 if (name_lang
== lang
) res
+= 30;
762 else if (PRIMARYLANGID( name_lang
) == PRIMARYLANGID( lang
)) res
+= 20;
763 else if (name_lang
== MAKELANGID( LANG_ENGLISH
, SUBLANG_DEFAULT
)) res
+= 10;
764 else if (lang
== MAKELANGID( LANG_NEUTRAL
, SUBLANG_NEUTRAL
)) res
+= 5 * (0x100000 - name_lang
);
768 static WCHAR
*copy_name_table_string( const FT_SfntName
*name
)
774 switch (name
->platform_id
)
776 case TT_PLATFORM_APPLE_UNICODE
:
777 case TT_PLATFORM_MICROSOFT
:
778 ret
= RtlAllocateHeap( GetProcessHeap(), 0, name
->string_len
+ sizeof(WCHAR
) );
779 for (i
= 0; i
< name
->string_len
/ 2; i
++)
780 ret
[i
] = (name
->string
[i
* 2] << 8) | name
->string
[i
* 2 + 1];
783 case TT_PLATFORM_MACINTOSH
:
784 if (!(cp
= get_mac_code_page( name
))) return NULL
;
785 ret
= RtlAllocateHeap( GetProcessHeap(), 0, (name
->string_len
+ 1) * sizeof(WCHAR
) );
786 RtlCustomCPToUnicodeN( cp
, ret
, name
->string_len
* sizeof(WCHAR
), &i
,
787 (char *)name
->string
, name
->string_len
);
788 ret
[i
/ sizeof(WCHAR
)] = 0;
794 static WCHAR
*get_face_name(FT_Face ft_face
, FT_UShort name_id
, LANGID language_id
)
797 FT_UInt num_names
, name_index
;
798 int res
, best_lang
= 0, best_index
= -1;
800 if (!FT_IS_SFNT(ft_face
)) return NULL
;
802 num_names
= pFT_Get_Sfnt_Name_Count( ft_face
);
804 for (name_index
= 0; name_index
< num_names
; name_index
++)
806 if (pFT_Get_Sfnt_Name( ft_face
, name_index
, &name
)) continue;
807 if (name
.name_id
!= name_id
) continue;
808 res
= match_name_table_language( &name
, language_id
);
812 best_index
= name_index
;
816 if (best_index
!= -1 && !pFT_Get_Sfnt_Name( ft_face
, best_index
, &name
))
818 WCHAR
*ret
= copy_name_table_string( &name
);
819 TRACE( "name %u found platform %u lang %04x %s\n",
820 name_id
, name
.platform_id
, name
.language_id
, debugstr_w( ret
));
826 static WCHAR
*ft_face_get_family_name( FT_Face ft_face
, LANGID langid
)
830 if ((family_name
= get_face_name( ft_face
, TT_NAME_ID_FONT_FAMILY
, langid
)))
833 return towstr( ft_face
->family_name
);
836 static WCHAR
*ft_face_get_style_name( FT_Face ft_face
, LANGID langid
)
840 if ((style_name
= get_face_name( ft_face
, TT_NAME_ID_FONT_SUBFAMILY
, langid
)))
843 return towstr( ft_face
->style_name
);
846 static WCHAR
*ft_face_get_full_name( FT_Face ft_face
, LANGID langid
)
848 static const WCHAR space_w
[] = {' ',0};
849 WCHAR
*full_name
, *style_name
;
852 if ((full_name
= get_face_name( ft_face
, TT_NAME_ID_FULL_NAME
, langid
)))
855 full_name
= ft_face_get_family_name( ft_face
, langid
);
856 style_name
= ft_face_get_style_name( ft_face
, langid
);
858 length
= lstrlenW( full_name
) + lstrlenW( space_w
) + lstrlenW( style_name
) + 1;
859 full_name
= RtlReAllocateHeap( GetProcessHeap(), 0, full_name
, length
* sizeof(WCHAR
) );
861 lstrcatW( full_name
, space_w
);
862 lstrcatW( full_name
, style_name
);
863 RtlFreeHeap( GetProcessHeap(), 0, style_name
);
865 WARN( "full name not found, using %s instead\n", debugstr_w(full_name
) );
869 static inline FT_Fixed
get_font_version( FT_Face ft_face
)
871 FT_Fixed version
= 0;
874 header
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_head
);
875 if (header
) version
= header
->Font_Revision
;
880 static inline DWORD
get_ntm_flags( FT_Face ft_face
)
883 FT_ULong table_size
= 0;
884 FT_WinFNT_HeaderRec winfnt_header
;
886 if (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) flags
|= NTM_ITALIC
;
887 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
) flags
|= NTM_BOLD
;
889 /* fixup the flag for our fake-bold implementation. */
890 if (!FT_IS_SCALABLE( ft_face
) &&
891 !pFT_Get_WinFNT_Header( ft_face
, &winfnt_header
) &&
892 winfnt_header
.weight
> FW_NORMAL
)
895 if (flags
== 0) flags
= NTM_REGULAR
;
897 if (!pFT_Load_Sfnt_Table( ft_face
, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL
, &table_size
))
898 flags
|= NTM_PS_OPENTYPE
;
903 static inline void get_bitmap_size( FT_Face ft_face
, struct bitmap_font_size
*face_size
)
905 My_FT_Bitmap_Size
*size
;
906 FT_WinFNT_HeaderRec winfnt_header
;
908 size
= (My_FT_Bitmap_Size
*)ft_face
->available_sizes
;
909 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
910 size
->height
, size
->width
, size
->size
>> 6,
911 size
->x_ppem
>> 6, size
->y_ppem
>> 6);
912 face_size
->height
= size
->height
;
913 face_size
->width
= size
->width
;
914 face_size
->size
= size
->size
;
915 face_size
->x_ppem
= size
->x_ppem
;
916 face_size
->y_ppem
= size
->y_ppem
;
918 if (!pFT_Get_WinFNT_Header( ft_face
, &winfnt_header
)) {
919 face_size
->internal_leading
= winfnt_header
.internal_leading
;
920 if (winfnt_header
.external_leading
> 0 &&
921 (face_size
->height
==
922 winfnt_header
.pixel_height
+ winfnt_header
.external_leading
))
923 face_size
->height
= winfnt_header
.pixel_height
;
927 static inline void get_fontsig( FT_Face ft_face
, FONTSIGNATURE
*fs
)
930 FT_WinFNT_HeaderRec winfnt_header
;
933 memset( fs
, 0, sizeof(*fs
) );
935 os2
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_os2
);
938 fs
->fsUsb
[0] = os2
->ulUnicodeRange1
;
939 fs
->fsUsb
[1] = os2
->ulUnicodeRange2
;
940 fs
->fsUsb
[2] = os2
->ulUnicodeRange3
;
941 fs
->fsUsb
[3] = os2
->ulUnicodeRange4
;
943 if (os2
->version
== 0)
945 if (os2
->usFirstCharIndex
>= 0xf000 && os2
->usFirstCharIndex
< 0xf100)
946 fs
->fsCsb
[0] = FS_SYMBOL
;
948 fs
->fsCsb
[0] = FS_LATIN1
;
952 fs
->fsCsb
[0] = os2
->ulCodePageRange1
;
953 fs
->fsCsb
[1] = os2
->ulCodePageRange2
;
958 if (!pFT_Get_WinFNT_Header( ft_face
, &winfnt_header
))
960 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header
.pixel_height
, winfnt_header
.charset
,
961 winfnt_header
.vertical_resolution
,winfnt_header
.horizontal_resolution
, winfnt_header
.nominal_point_size
);
962 switch (winfnt_header
.charset
)
964 case ANSI_CHARSET
: fs
->fsCsb
[0] = FS_LATIN1
; break;
965 case EASTEUROPE_CHARSET
: fs
->fsCsb
[0] = FS_LATIN2
; break;
966 case RUSSIAN_CHARSET
: fs
->fsCsb
[0] = FS_CYRILLIC
; break;
967 case GREEK_CHARSET
: fs
->fsCsb
[0] = FS_GREEK
; break;
968 case TURKISH_CHARSET
: fs
->fsCsb
[0] = FS_TURKISH
; break;
969 case HEBREW_CHARSET
: fs
->fsCsb
[0] = FS_HEBREW
; break;
970 case ARABIC_CHARSET
: fs
->fsCsb
[0] = FS_ARABIC
; break;
971 case BALTIC_CHARSET
: fs
->fsCsb
[0] = FS_BALTIC
; break;
972 case VIETNAMESE_CHARSET
: fs
->fsCsb
[0] = FS_VIETNAMESE
; break;
973 case THAI_CHARSET
: fs
->fsCsb
[0] = FS_THAI
; break;
974 case SHIFTJIS_CHARSET
: fs
->fsCsb
[0] = FS_JISJAPAN
; break;
975 case GB2312_CHARSET
: fs
->fsCsb
[0] = FS_CHINESESIMP
; break;
976 case HANGEUL_CHARSET
: fs
->fsCsb
[0] = FS_WANSUNG
; break;
977 case CHINESEBIG5_CHARSET
: fs
->fsCsb
[0] = FS_CHINESETRAD
; break;
978 case JOHAB_CHARSET
: fs
->fsCsb
[0] = FS_JOHAB
; break;
979 case SYMBOL_CHARSET
: fs
->fsCsb
[0] = FS_SYMBOL
; break;
984 if (fs
->fsCsb
[0] == 0)
986 /* let's see if we can find any interesting cmaps */
987 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
989 switch (ft_face
->charmaps
[i
]->encoding
)
991 case FT_ENCODING_UNICODE
:
992 case FT_ENCODING_APPLE_ROMAN
:
993 fs
->fsCsb
[0] |= FS_LATIN1
;
995 case FT_ENCODING_MS_SYMBOL
:
996 fs
->fsCsb
[0] |= FS_SYMBOL
;
1005 static int AddFaceToList(FT_Face ft_face
, const WCHAR
*file
, void *data_ptr
, SIZE_T data_size
,
1006 FT_Long face_index
, DWORD flags
)
1008 struct bitmap_font_size size
;
1011 WCHAR
*family_name
= ft_face_get_family_name( ft_face
, system_lcid
);
1012 WCHAR
*second_name
= ft_face_get_family_name( ft_face
, MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
) );
1013 WCHAR
*style_name
= ft_face_get_style_name( ft_face
, system_lcid
);
1014 WCHAR
*full_name
= ft_face_get_full_name( ft_face
, system_lcid
);
1016 /* try to find another secondary name, preferring the lowest langids */
1017 if (!RtlCompareUnicodeStrings( family_name
, lstrlenW(family_name
),
1018 second_name
, lstrlenW(second_name
), TRUE
))
1020 RtlFreeHeap( GetProcessHeap(), 0, second_name
);
1021 second_name
= ft_face_get_family_name( ft_face
, MAKELANGID(LANG_NEUTRAL
, SUBLANG_NEUTRAL
) );
1022 if (!RtlCompareUnicodeStrings( family_name
, lstrlenW(family_name
),
1023 second_name
, lstrlenW(second_name
), TRUE
))
1025 RtlFreeHeap( GetProcessHeap(), 0, second_name
);
1030 get_fontsig( ft_face
, &fs
);
1031 if (!FT_IS_SCALABLE( ft_face
)) get_bitmap_size( ft_face
, &size
);
1032 if (!HIWORD( flags
)) flags
|= ADDFONT_AA_FLAGS( default_aa_flags
);
1034 ret
= callback_funcs
->add_gdi_face( family_name
, second_name
, style_name
, full_name
, file
,
1035 data_ptr
, data_size
, face_index
, fs
, get_ntm_flags( ft_face
),
1036 get_font_version( ft_face
), flags
,
1037 FT_IS_SCALABLE(ft_face
) ? NULL
: &size
);
1039 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1040 fs
.fsCsb
[0], fs
.fsCsb
[1], fs
.fsUsb
[0], fs
.fsUsb
[1], fs
.fsUsb
[2], fs
.fsUsb
[3]);
1042 RtlFreeHeap( GetProcessHeap(), 0, family_name
);
1043 RtlFreeHeap( GetProcessHeap(), 0, second_name
);
1044 RtlFreeHeap( GetProcessHeap(), 0, style_name
);
1045 RtlFreeHeap( GetProcessHeap(), 0, full_name
);
1049 static FT_Face
new_ft_face( const char *file
, void *font_data_ptr
, DWORD font_data_size
,
1050 FT_Long face_index
, BOOL allow_bitmap
)
1058 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
1059 err
= pFT_New_Face(library
, file
, face_index
, &ft_face
);
1063 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr
, font_data_size
, face_index
);
1064 err
= pFT_New_Memory_Face(library
, font_data_ptr
, font_data_size
, face_index
, &ft_face
);
1069 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file
), font_data_ptr
, err
);
1073 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1074 if (!FT_IS_SCALABLE( ft_face
) && FT_SimpleVersion
< FT_VERSION_VALUE(2, 1, 9))
1076 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1080 if (!FT_IS_SFNT( ft_face
))
1082 if (FT_IS_SCALABLE( ft_face
) || !allow_bitmap
)
1084 WARN("Ignoring font %s/%p\n", debugstr_a(file
), font_data_ptr
);
1090 if (!(pOS2
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_os2
)) ||
1091 !pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_hhea
) ||
1092 !pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_head
))
1094 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1095 "Skipping this font.\n", debugstr_a(file
), font_data_ptr
);
1099 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1100 we don't want to load these. */
1101 if (!memcmp( pOS2
->achVendID
, "Wine", sizeof(pOS2
->achVendID
) ))
1105 if (!pFT_Load_Sfnt_Table( ft_face
, FT_MAKE_TAG('E','B','S','C'), 0, NULL
, &len
))
1107 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file
));
1113 if (!ft_face
->family_name
|| !ft_face
->style_name
)
1115 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file
), font_data_ptr
);
1121 pFT_Done_Face( ft_face
);
1125 static WCHAR
*get_dos_file_name( LPCSTR str
)
1128 SIZE_T len
= strlen(str
) + 1;
1130 len
+= 8; /* \??\unix prefix */
1131 if (!(buffer
= RtlAllocateHeap( GetProcessHeap(), 0, len
* sizeof(WCHAR
) ))) return NULL
;
1132 if (wine_unix_to_nt_file_name( str
, buffer
, &len
))
1134 RtlFreeHeap( GetProcessHeap(), 0, buffer
);
1137 if (buffer
[5] == ':')
1139 /* get rid of the \??\ prefix */
1140 /* FIXME: should implement RtlNtPathNameToDosPathName and use that instead */
1141 memmove( buffer
, buffer
+ 4, (len
- 4) * sizeof(WCHAR
) );
1143 else buffer
[1] = '\\';
1147 static char *get_unix_file_name( LPCWSTR dosW
)
1149 UNICODE_STRING nt_name
;
1154 if (!RtlDosPathNameToNtPathName_U( dosW
, &nt_name
, NULL
, NULL
)) return NULL
;
1157 if (!(buffer
= RtlAllocateHeap( GetProcessHeap(), 0, size
)))
1159 RtlFreeUnicodeString( &nt_name
);
1162 status
= wine_nt_to_unix_file_name( &nt_name
, buffer
, &size
, FILE_OPEN_IF
);
1163 if (status
!= STATUS_BUFFER_TOO_SMALL
) break;
1164 RtlFreeHeap( GetProcessHeap(), 0, buffer
);
1166 RtlFreeUnicodeString( &nt_name
);
1167 if (status
&& status
!= STATUS_NO_SUCH_FILE
)
1169 RtlFreeHeap( GetProcessHeap(), 0, buffer
);
1170 RtlSetLastWin32ErrorAndNtStatusFromNtStatus( status
);
1176 static INT
AddFontToList(const WCHAR
*dos_name
, const char *unix_name
, void *font_data_ptr
,
1177 DWORD font_data_size
, DWORD flags
)
1180 FT_Long face_index
= 0, num_faces
;
1182 WCHAR
*filename
= NULL
;
1184 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1185 assert(unix_name
|| !(flags
& ADDFONT_EXTERNAL_FONT
));
1187 #ifdef HAVE_CARBON_CARBON_H
1190 char **mac_list
= expand_mac_font(unix_name
);
1193 BOOL had_one
= FALSE
;
1195 for(cursor
= mac_list
; *cursor
; cursor
++)
1198 AddFontToList(NULL
, *cursor
, NULL
, 0, flags
);
1199 RtlFreeHeap(GetProcessHeap(), 0, *cursor
);
1201 RtlFreeHeap(GetProcessHeap(), 0, mac_list
);
1206 #endif /* HAVE_CARBON_CARBON_H */
1208 if (!dos_name
&& unix_name
) dos_name
= filename
= get_dos_file_name( unix_name
);
1211 ft_face
= new_ft_face( unix_name
, font_data_ptr
, font_data_size
, face_index
, flags
& ADDFONT_ALLOW_BITMAP
);
1212 if (!ft_face
) break;
1214 if(ft_face
->family_name
[0] == '.') /* Ignore fonts with names beginning with a dot */
1216 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(unix_name
));
1217 pFT_Done_Face(ft_face
);
1221 ret
+= AddFaceToList(ft_face
, dos_name
, font_data_ptr
, font_data_size
, face_index
, flags
);
1223 num_faces
= ft_face
->num_faces
;
1224 pFT_Done_Face(ft_face
);
1225 } while(num_faces
> ++face_index
);
1226 RtlFreeHeap( GetProcessHeap(), 0, filename
);
1230 /*************************************************************
1233 static INT CDECL
freetype_add_font( const WCHAR
*file
, DWORD flags
)
1236 char *unixname
= get_unix_file_name( file
);
1240 ret
= AddFontToList( file
, unixname
, NULL
, 0, flags
);
1241 RtlFreeHeap( GetProcessHeap(), 0, unixname
);
1246 /*************************************************************
1247 * freetype_add_mem_font
1249 static INT CDECL
freetype_add_mem_font( void *ptr
, SIZE_T size
, DWORD flags
)
1251 return AddFontToList( NULL
, NULL
, ptr
, size
, flags
);
1255 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
1258 struct dirent
*dent
;
1259 char path
[MAX_PATH
];
1261 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
1263 dir
= opendir(dirname
);
1265 WARN("Can't open directory %s\n", debugstr_a(dirname
));
1268 while((dent
= readdir(dir
)) != NULL
) {
1269 struct stat statbuf
;
1271 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
1274 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
1276 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
1278 if(stat(path
, &statbuf
) == -1)
1280 WARN("Can't stat %s\n", debugstr_a(path
));
1283 if(S_ISDIR(statbuf
.st_mode
))
1284 ReadFontDir(path
, external_fonts
);
1287 DWORD addfont_flags
= ADDFONT_ADD_TO_CACHE
;
1288 if(external_fonts
) addfont_flags
|= ADDFONT_EXTERNAL_FONT
;
1289 AddFontToList(NULL
, path
, NULL
, 0, addfont_flags
);
1297 #ifdef SONAME_LIBFONTCONFIG
1299 static BOOL fontconfig_enabled
;
1300 static FcPattern
*pattern_serif
;
1301 static FcPattern
*pattern_fixed
;
1302 static FcPattern
*pattern_sans
;
1304 static UINT
parse_aa_pattern( FcPattern
*pattern
)
1310 if (pFcPatternGetBool( pattern
, FC_ANTIALIAS
, 0, &antialias
) == FcResultMatch
)
1311 aa_flags
= antialias
? GGO_GRAY4_BITMAP
: GGO_BITMAP
;
1313 if (pFcPatternGetInteger( pattern
, FC_RGBA
, 0, &rgba
) == FcResultMatch
)
1317 case FC_RGBA_RGB
: aa_flags
= WINE_GGO_HRGB_BITMAP
; break;
1318 case FC_RGBA_BGR
: aa_flags
= WINE_GGO_HBGR_BITMAP
; break;
1319 case FC_RGBA_VRGB
: aa_flags
= WINE_GGO_VRGB_BITMAP
; break;
1320 case FC_RGBA_VBGR
: aa_flags
= WINE_GGO_VBGR_BITMAP
; break;
1321 case FC_RGBA_NONE
: aa_flags
= aa_flags
? aa_flags
: GGO_GRAY4_BITMAP
; break;
1327 static FcPattern
*create_family_pattern( const char *name
)
1329 FcPattern
*ret
, *pattern
= pFcPatternCreate();
1332 pFcPatternAddString( pattern
, FC_FAMILY
, (const FcChar8
*)name
);
1333 pFcPatternAddString( pattern
, FC_NAMELANG
, (const FcChar8
*)"en-us" );
1334 pFcPatternAddString( pattern
, FC_PRGNAME
, (const FcChar8
*)"wine" );
1335 pFcConfigSubstitute( NULL
, pattern
, FcMatchPattern
);
1336 pFcDefaultSubstitute( pattern
);
1337 ret
= pFcFontMatch( NULL
, pattern
, &result
);
1338 pFcPatternDestroy( pattern
);
1339 if (ret
&& result
== FcResultMatch
) return ret
;
1340 pFcPatternDestroy( ret
);
1344 static void init_fontconfig(void)
1346 void *fc_handle
= dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
);
1350 TRACE("Wine cannot find the fontconfig library (%s).\n", SONAME_LIBFONTCONFIG
);
1354 #define LOAD_FUNCPTR(f) if((p##f = dlsym(fc_handle, #f)) == NULL){WARN("Can't find symbol %s\n", #f); return;}
1355 LOAD_FUNCPTR(FcConfigSubstitute
);
1356 LOAD_FUNCPTR(FcDefaultSubstitute
);
1357 LOAD_FUNCPTR(FcFontList
);
1358 LOAD_FUNCPTR(FcFontMatch
);
1359 LOAD_FUNCPTR(FcFontSetDestroy
);
1360 LOAD_FUNCPTR(FcInit
);
1361 LOAD_FUNCPTR(FcPatternAddString
);
1362 LOAD_FUNCPTR(FcPatternCreate
);
1363 LOAD_FUNCPTR(FcPatternDestroy
);
1364 LOAD_FUNCPTR(FcPatternGetBool
);
1365 LOAD_FUNCPTR(FcPatternGetInteger
);
1366 LOAD_FUNCPTR(FcPatternGetString
);
1371 FcPattern
*pattern
= pFcPatternCreate();
1372 pFcConfigSubstitute( NULL
, pattern
, FcMatchFont
);
1373 default_aa_flags
= parse_aa_pattern( pattern
);
1374 pFcPatternDestroy( pattern
);
1376 if (!default_aa_flags
)
1378 FcPattern
*pattern
= pFcPatternCreate();
1379 pFcConfigSubstitute( NULL
, pattern
, FcMatchPattern
);
1380 default_aa_flags
= parse_aa_pattern( pattern
);
1381 pFcPatternDestroy( pattern
);
1383 pattern_serif
= create_family_pattern( "serif" );
1384 pattern_fixed
= create_family_pattern( "monospace" );
1385 pattern_sans
= create_family_pattern( "sans" );
1387 TRACE( "enabled, default flags = %x\n", default_aa_flags
);
1388 fontconfig_enabled
= TRUE
;
1392 static void load_fontconfig_fonts(void)
1400 if (!fontconfig_enabled
) return;
1402 pat
= pFcPatternCreate();
1405 fontset
= pFcFontList(NULL
, pat
, NULL
);
1408 pFcPatternDestroy(pat
);
1412 for(i
= 0; i
< fontset
->nfont
; i
++) {
1416 if(pFcPatternGetString(fontset
->fonts
[i
], FC_FILE
, 0, (FcChar8
**)&file
) != FcResultMatch
)
1419 pFcConfigSubstitute( NULL
, fontset
->fonts
[i
], FcMatchFont
);
1421 if(pFcPatternGetBool(fontset
->fonts
[i
], FC_SCALABLE
, 0, &scalable
) == FcResultMatch
&& !scalable
)
1423 TRACE("not scalable\n");
1427 if (pFcPatternGetString( fontset
->fonts
[i
], FC_FONTFORMAT
, 0, (FcChar8
**)&format
) != FcResultMatch
)
1429 TRACE( "ignoring unknown font format %s\n", debugstr_a(file
) );
1433 if (!strcmp( format
, "Type 1" ))
1435 TRACE( "ignoring Type 1 font %s\n", debugstr_a(file
) );
1439 aa_flags
= parse_aa_pattern( fontset
->fonts
[i
] );
1440 TRACE("fontconfig: %s aa %x\n", file
, aa_flags
);
1442 AddFontToList( NULL
, file
, NULL
, 0,
1443 ADDFONT_EXTERNAL_FONT
| ADDFONT_ADD_TO_CACHE
| ADDFONT_AA_FLAGS(aa_flags
) );
1445 pFcFontSetDestroy(fontset
);
1446 pFcPatternDestroy(pat
);
1449 #elif defined(HAVE_CARBON_CARBON_H)
1451 static void load_mac_font_callback(const void *value
, void *context
)
1453 CFStringRef pathStr
= value
;
1457 len
= CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr
);
1458 path
= RtlAllocateHeap(GetProcessHeap(), 0, len
);
1459 if (path
&& CFStringGetFileSystemRepresentation(pathStr
, path
, len
))
1461 TRACE("font file %s\n", path
);
1462 AddFontToList(NULL
, path
, NULL
, 0, ADDFONT_EXTERNAL_FONT
| ADDFONT_ADD_TO_CACHE
);
1464 RtlFreeHeap(GetProcessHeap(), 0, path
);
1467 static void load_mac_fonts(void)
1469 CFStringRef removeDupesKey
;
1470 CFBooleanRef removeDupesValue
;
1471 CFDictionaryRef options
;
1472 CTFontCollectionRef col
;
1474 CFMutableSetRef paths
;
1477 removeDupesKey
= kCTFontCollectionRemoveDuplicatesOption
;
1478 removeDupesValue
= kCFBooleanTrue
;
1479 options
= CFDictionaryCreate(NULL
, (const void**)&removeDupesKey
, (const void**)&removeDupesValue
, 1,
1480 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1481 col
= CTFontCollectionCreateFromAvailableFonts(options
);
1482 if (options
) CFRelease(options
);
1485 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
1489 descs
= CTFontCollectionCreateMatchingFontDescriptors(col
);
1493 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
1497 paths
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
1500 WARN("CFSetCreateMutable failed\n");
1505 for (i
= 0; i
< CFArrayGetCount(descs
); i
++)
1507 CTFontDescriptorRef desc
;
1512 desc
= CFArrayGetValueAtIndex(descs
, i
);
1514 #if defined(MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
1515 url
= CTFontDescriptorCopyAttribute(desc
, kCTFontURLAttribute
);
1517 /* CTFontDescriptor doesn't support kCTFontURLAttribute prior to 10.6, so
1518 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
1525 font
= CTFontCreateWithFontDescriptor(desc
, 0, NULL
);
1526 if (!font
) continue;
1528 atsFont
= CTFontGetPlatformFont(font
, NULL
);
1535 status
= ATSFontGetFileReference(atsFont
, &fsref
);
1537 if (status
!= noErr
) continue;
1539 url
= CFURLCreateFromFSRef(NULL
, &fsref
);
1544 ext
= CFURLCopyPathExtension(url
);
1547 BOOL skip
= (CFStringCompare(ext
, CFSTR("pfa"), kCFCompareCaseInsensitive
) == kCFCompareEqualTo
||
1548 CFStringCompare(ext
, CFSTR("pfb"), kCFCompareCaseInsensitive
) == kCFCompareEqualTo
);
1557 path
= CFURLCopyFileSystemPath(url
, kCFURLPOSIXPathStyle
);
1559 if (!path
) continue;
1561 CFSetAddValue(paths
, path
);
1567 CFSetApplyFunction(paths
, load_mac_font_callback
, NULL
);
1574 static BOOL
init_freetype(void)
1576 ft_handle
= dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
);
1579 "Wine cannot find the FreeType font library. To enable Wine to\n"
1580 "use TrueType fonts please install a version of FreeType greater than\n"
1581 "or equal to 2.0.5.\n"
1582 "http://www.freetype.org\n");
1586 #define LOAD_FUNCPTR(f) if((p##f = dlsym(ft_handle, #f)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
1588 LOAD_FUNCPTR(FT_Done_Face
)
1589 LOAD_FUNCPTR(FT_Get_Char_Index
)
1590 LOAD_FUNCPTR(FT_Get_First_Char
)
1591 LOAD_FUNCPTR(FT_Get_Next_Char
)
1592 LOAD_FUNCPTR(FT_Get_Sfnt_Name
)
1593 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count
)
1594 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
1595 LOAD_FUNCPTR(FT_Get_WinFNT_Header
)
1596 LOAD_FUNCPTR(FT_Init_FreeType
)
1597 LOAD_FUNCPTR(FT_Library_Version
)
1598 LOAD_FUNCPTR(FT_Load_Glyph
)
1599 LOAD_FUNCPTR(FT_Load_Sfnt_Table
)
1600 LOAD_FUNCPTR(FT_Matrix_Multiply
)
1601 LOAD_FUNCPTR(FT_MulDiv
)
1602 #ifndef FT_MULFIX_INLINED
1603 LOAD_FUNCPTR(FT_MulFix
)
1605 LOAD_FUNCPTR(FT_New_Face
)
1606 LOAD_FUNCPTR(FT_New_Memory_Face
)
1607 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
1608 LOAD_FUNCPTR(FT_Outline_Get_CBox
)
1609 LOAD_FUNCPTR(FT_Outline_Transform
)
1610 LOAD_FUNCPTR(FT_Outline_Translate
)
1611 LOAD_FUNCPTR(FT_Render_Glyph
)
1612 LOAD_FUNCPTR(FT_Set_Charmap
)
1613 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
1614 LOAD_FUNCPTR(FT_Vector_Length
)
1615 LOAD_FUNCPTR(FT_Vector_Transform
)
1616 LOAD_FUNCPTR(FT_Vector_Unit
)
1618 /* Don't warn if these ones are missing */
1619 pFT_Outline_Embolden
= dlsym(ft_handle
, "FT_Outline_Embolden");
1620 pFT_Get_TrueType_Engine_Type
= dlsym(ft_handle
, "FT_Get_TrueType_Engine_Type");
1621 #ifdef FT_LCD_FILTER_H
1622 pFT_Library_SetLcdFilter
= dlsym(ft_handle
, "FT_Library_SetLcdFilter");
1624 pFT_Property_Set
= dlsym(ft_handle
, "FT_Property_Set");
1626 if(pFT_Init_FreeType(&library
) != 0) {
1627 ERR("Can't init FreeType library\n");
1632 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
1634 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
1635 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
1636 ((FT_Version
.minor
<< 8) & 0x00ff00) |
1637 ((FT_Version
.patch
) & 0x0000ff);
1639 /* In FreeType < 2.8.1 v40's FT_LOAD_TARGET_MONO has broken advance widths. */
1640 if (pFT_Property_Set
&& FT_SimpleVersion
< FT_VERSION_VALUE(2, 8, 1))
1642 FT_UInt interpreter_version
= 35;
1643 pFT_Property_Set( library
, "truetype", "interpreter-version", &interpreter_version
);
1650 "Wine cannot find certain functions that it needs inside the FreeType\n"
1651 "font library. To enable Wine to use TrueType fonts please upgrade\n"
1652 "FreeType to at least version 2.1.4.\n"
1653 "http://www.freetype.org\n");
1659 /*************************************************************
1660 * freetype_load_fonts
1662 static void CDECL
freetype_load_fonts(void)
1664 #ifdef SONAME_LIBFONTCONFIG
1665 load_fontconfig_fonts();
1666 #elif defined(HAVE_CARBON_CARBON_H)
1668 #elif defined(__ANDROID__)
1669 ReadFontDir("/system/fonts", TRUE
);
1673 /* Some fonts have large usWinDescent values, as a result of storing signed short
1674 in unsigned field. That's probably caused by sTypoDescent vs usWinDescent confusion in
1675 some font generation tools. */
1676 static inline USHORT
get_fixed_windescent(USHORT windescent
)
1678 return abs((SHORT
)windescent
);
1681 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
1684 TT_HoriHeader
*pHori
;
1687 const LONG MAX_PPEM
= (1 << 16) - 1;
1689 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
1690 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
1692 if(height
== 0) height
= 16;
1694 /* Calc. height of EM square:
1696 * For +ve lfHeight we have
1697 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
1698 * Re-arranging gives:
1699 * ppem = units_per_em * lfheight / (winAscent + winDescent)
1701 * For -ve lfHeight we have
1703 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
1704 * with il = winAscent + winDescent - units_per_em]
1709 USHORT windescent
= get_fixed_windescent(pOS2
->usWinDescent
);
1710 if(pOS2
->usWinAscent
+ windescent
== 0)
1711 ppem
= pFT_MulDiv(ft_face
->units_per_EM
, height
, pHori
->Ascender
- pHori
->Descender
);
1713 ppem
= pFT_MulDiv(ft_face
->units_per_EM
, height
, pOS2
->usWinAscent
+ windescent
);
1714 if(ppem
> MAX_PPEM
) {
1715 WARN("Ignoring too large height %d, ppem %d\n", height
, ppem
);
1719 else if(height
>= -MAX_PPEM
)
1722 WARN("Ignoring too large height %d\n", height
);
1729 static struct font_mapping
*map_font_file( const char *name
)
1731 struct font_mapping
*mapping
;
1735 if ((fd
= open( name
, O_RDONLY
)) == -1) return NULL
;
1736 if (fstat( fd
, &st
) == -1) goto error
;
1738 LIST_FOR_EACH_ENTRY( mapping
, &mappings_list
, struct font_mapping
, entry
)
1740 if (mapping
->dev
== st
.st_dev
&& mapping
->ino
== st
.st_ino
)
1742 mapping
->refcount
++;
1747 if (!(mapping
= RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*mapping
) )))
1750 mapping
->data
= mmap( NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0 );
1753 if (mapping
->data
== MAP_FAILED
)
1755 RtlFreeHeap( GetProcessHeap(), 0, mapping
);
1758 mapping
->refcount
= 1;
1759 mapping
->dev
= st
.st_dev
;
1760 mapping
->ino
= st
.st_ino
;
1761 mapping
->size
= st
.st_size
;
1762 list_add_tail( &mappings_list
, &mapping
->entry
);
1770 static void unmap_font_file( struct font_mapping
*mapping
)
1772 if (!--mapping
->refcount
)
1774 list_remove( &mapping
->entry
);
1775 munmap( mapping
->data
, mapping
->size
);
1776 RtlFreeHeap( GetProcessHeap(), 0, mapping
);
1780 static LONG
load_VDMX(struct gdi_font
*font
, LONG height
);
1782 /*************************************************************
1783 * freetype_destroy_font
1785 static void CDECL
freetype_destroy_font( struct gdi_font
*font
)
1787 struct font_private_data
*data
= font
->private;
1789 if (data
->ft_face
) pFT_Done_Face( data
->ft_face
);
1790 if (data
->mapping
) unmap_font_file( data
->mapping
);
1791 RtlFreeHeap( GetProcessHeap(), 0, data
);
1794 /*************************************************************
1795 * freetype_get_font_data
1797 static DWORD CDECL
freetype_get_font_data( struct gdi_font
*font
, DWORD table
, DWORD offset
,
1798 void *buf
, DWORD cbData
)
1800 FT_Face ft_face
= get_ft_face( font
);
1804 if (!FT_IS_SFNT(ft_face
)) return GDI_ERROR
;
1811 /* if font is a member of TTC, 'ttcf' tag allows reading from beginning of TTC file,
1812 0 tag means to read from start of collection member data. */
1813 if (font
->ttc_item_offset
)
1815 if (table
== MS_TTCF_TAG
)
1817 else if (table
== 0)
1818 offset
+= font
->ttc_item_offset
;
1821 /* make sure value of len is the value freetype says it needs */
1824 FT_ULong needed
= 0;
1825 err
= pFT_Load_Sfnt_Table(ft_face
, RtlUlongByteSwap(table
), offset
, NULL
, &needed
);
1826 if( !err
&& needed
< len
) len
= needed
;
1828 err
= pFT_Load_Sfnt_Table(ft_face
, RtlUlongByteSwap(table
), offset
, buf
, &len
);
1831 TRACE("Can't find table %s\n", debugstr_an((char*)&table
, 4));
1837 /*************************************************************
1840 * load the vdmx entry for the specified height
1870 static LONG
load_VDMX(struct gdi_font
*font
, LONG height
)
1874 BYTE devXRatio
, devYRatio
;
1875 USHORT numRecs
, numRatios
;
1876 DWORD result
, offset
= -1;
1880 result
= freetype_get_font_data(font
, MS_VDMX_TAG
, 0, &hdr
, sizeof(hdr
));
1882 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
1885 /* FIXME: need the real device aspect ratio */
1889 numRecs
= GET_BE_WORD(hdr
.numRecs
);
1890 numRatios
= GET_BE_WORD(hdr
.numRatios
);
1892 TRACE("version = %d numRecs = %d numRatios = %d\n", GET_BE_WORD(hdr
.version
), numRecs
, numRatios
);
1893 for(i
= 0; i
< numRatios
; i
++) {
1896 offset
= sizeof(hdr
) + (i
* sizeof(Ratios
));
1897 freetype_get_font_data(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
1900 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
1902 if (!ratio
.bCharSet
) continue;
1904 if((ratio
.xRatio
== 0 &&
1905 ratio
.yStartRatio
== 0 &&
1906 ratio
.yEndRatio
== 0) ||
1907 (devXRatio
== ratio
.xRatio
&&
1908 devYRatio
>= ratio
.yStartRatio
&&
1909 devYRatio
<= ratio
.yEndRatio
))
1913 offset
= sizeof(hdr
) + numRatios
* sizeof(ratio
) + i
* sizeof(group_offset
);
1914 freetype_get_font_data(font
, MS_VDMX_TAG
, offset
, &group_offset
, sizeof(group_offset
));
1915 offset
= GET_BE_WORD(group_offset
);
1920 if(offset
== -1) return 0;
1922 if(freetype_get_font_data(font
, MS_VDMX_TAG
, offset
, &group
, sizeof(group
)) != GDI_ERROR
) {
1924 BYTE startsz
, endsz
;
1927 recs
= GET_BE_WORD(group
.recs
);
1928 startsz
= group
.startsz
;
1929 endsz
= group
.endsz
;
1931 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
1933 vTable
= RtlAllocateHeap(GetProcessHeap(), 0, recs
* sizeof(VDMX_vTable
));
1934 result
= freetype_get_font_data(font
, MS_VDMX_TAG
, offset
+ sizeof(group
), vTable
, recs
* sizeof(VDMX_vTable
));
1935 if(result
== GDI_ERROR
) {
1936 FIXME("Failed to retrieve vTable\n");
1941 for(i
= 0; i
< recs
; i
++) {
1942 SHORT yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
1943 SHORT yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
1944 ppem
= GET_BE_WORD(vTable
[i
* 3]);
1946 if(yMax
+ -yMin
== height
) {
1949 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
1952 if(yMax
+ -yMin
> height
) {
1955 goto end
; /* failed */
1957 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
1958 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
1959 ppem
= GET_BE_WORD(vTable
[i
* 3]);
1960 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
1966 TRACE("ppem not found for height %d\n", height
);
1970 if(ppem
< startsz
|| ppem
> endsz
)
1976 for(i
= 0; i
< recs
; i
++) {
1978 yPelHeight
= GET_BE_WORD(vTable
[i
* 3]);
1980 if(yPelHeight
> ppem
)
1986 if(yPelHeight
== ppem
) {
1987 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
1988 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
1989 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem
, font
->yMax
, font
->yMin
);
1995 RtlFreeHeap(GetProcessHeap(), 0, vTable
);
2001 static BOOL
select_charmap(FT_Face ft_face
, FT_Encoding encoding
)
2003 FT_Error ft_err
= FT_Err_Invalid_CharMap_Handle
;
2004 FT_CharMap cmap0
, cmap1
, cmap2
, cmap3
, cmap_def
;
2007 cmap0
= cmap1
= cmap2
= cmap3
= cmap_def
= NULL
;
2009 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
2011 if (ft_face
->charmaps
[i
]->encoding
== encoding
)
2013 TRACE("found cmap with platform_id %u, encoding_id %u\n",
2014 ft_face
->charmaps
[i
]->platform_id
, ft_face
->charmaps
[i
]->encoding_id
);
2016 switch (ft_face
->charmaps
[i
]->platform_id
)
2019 cmap_def
= ft_face
->charmaps
[i
];
2021 case 0: /* Apple Unicode */
2022 cmap0
= ft_face
->charmaps
[i
];
2024 case 1: /* Macintosh */
2025 cmap1
= ft_face
->charmaps
[i
];
2028 cmap2
= ft_face
->charmaps
[i
];
2030 case 3: /* Microsoft */
2031 cmap3
= ft_face
->charmaps
[i
];
2036 if (cmap3
) /* prefer Microsoft cmap table */
2037 ft_err
= pFT_Set_Charmap(ft_face
, cmap3
);
2039 ft_err
= pFT_Set_Charmap(ft_face
, cmap1
);
2041 ft_err
= pFT_Set_Charmap(ft_face
, cmap2
);
2043 ft_err
= pFT_Set_Charmap(ft_face
, cmap0
);
2045 ft_err
= pFT_Set_Charmap(ft_face
, cmap_def
);
2048 return ft_err
== FT_Err_Ok
;
2052 static FT_Encoding
pick_charmap( FT_Face face
, int charset
)
2054 static const FT_Encoding regular_order
[] = { FT_ENCODING_UNICODE
, FT_ENCODING_APPLE_ROMAN
, FT_ENCODING_MS_SYMBOL
, 0 };
2055 static const FT_Encoding symbol_order
[] = { FT_ENCODING_MS_SYMBOL
, FT_ENCODING_UNICODE
, FT_ENCODING_APPLE_ROMAN
, 0 };
2056 const FT_Encoding
*encs
= regular_order
;
2058 if (charset
== SYMBOL_CHARSET
) encs
= symbol_order
;
2062 if (select_charmap( face
, *encs
)) break;
2066 if (!face
->charmap
&& face
->num_charmaps
)
2068 if (!pFT_Set_Charmap(face
, face
->charmaps
[0]))
2069 return face
->charmap
->encoding
;
2075 static BOOL
get_gasp_flags( struct gdi_font
*font
, WORD
*flags
)
2077 FT_Face ft_face
= get_ft_face( font
);
2079 WORD buf
[16]; /* Enough for seven ranges before we need to alloc */
2080 WORD
*alloced
= NULL
, *ptr
= buf
;
2081 WORD num_recs
, version
;
2085 size
= freetype_get_font_data( font
, MS_GASP_TAG
, 0, NULL
, 0 );
2086 if (size
== GDI_ERROR
) return FALSE
;
2087 if (size
< 4 * sizeof(WORD
)) return FALSE
;
2088 if (size
> sizeof(buf
))
2090 ptr
= alloced
= RtlAllocateHeap( GetProcessHeap(), 0, size
);
2091 if (!ptr
) return FALSE
;
2094 freetype_get_font_data( font
, MS_GASP_TAG
, 0, ptr
, size
);
2096 version
= GET_BE_WORD( *ptr
++ );
2097 num_recs
= GET_BE_WORD( *ptr
++ );
2099 if (version
> 1 || size
< (num_recs
* 2 + 2) * sizeof(WORD
))
2101 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version
, size
, num_recs
);
2107 *flags
= GET_BE_WORD( *(ptr
+ 1) );
2108 if (ft_face
->size
->metrics
.y_ppem
<= GET_BE_WORD( *ptr
)) break;
2111 TRACE( "got flags %04x for ppem %d\n", *flags
, ft_face
->size
->metrics
.y_ppem
);
2115 RtlFreeHeap( GetProcessHeap(), 0, alloced
);
2119 /*************************************************************
2120 * fontconfig_enum_family_fallbacks
2122 static BOOL CDECL
fontconfig_enum_family_fallbacks( DWORD pitch_and_family
, int index
,
2123 WCHAR buffer
[LF_FACESIZE
] )
2125 #ifdef SONAME_LIBFONTCONFIG
2130 if ((pitch_and_family
& FIXED_PITCH
) || (pitch_and_family
& 0xf0) == FF_MODERN
) pat
= pattern_fixed
;
2131 else if ((pitch_and_family
& 0xf0) == FF_ROMAN
) pat
= pattern_serif
;
2132 else pat
= pattern_sans
;
2134 if (!pat
) return FALSE
;
2135 if (pFcPatternGetString( pat
, FC_FAMILY
, index
, (FcChar8
**)&str
) != FcResultMatch
) return FALSE
;
2136 RtlUTF8ToUnicodeN( buffer
, (LF_FACESIZE
- 1) * sizeof(WCHAR
), &len
, str
, strlen(str
) );
2137 buffer
[len
/ sizeof(WCHAR
)] = 0;
2143 static DWORD
get_ttc_offset( FT_Face ft_face
, UINT face_index
)
2146 DWORD header
, offset
;
2148 /* see if it's a TTC */
2149 len
= sizeof(header
);
2150 if (pFT_Load_Sfnt_Table( ft_face
, 0, 0, (void *)&header
, &len
)) return 0;
2151 if (header
!= MS_TTCF_TAG
) return 0;
2153 len
= sizeof(offset
);
2154 if (pFT_Load_Sfnt_Table( ft_face
, 0, (3 + face_index
) * sizeof(DWORD
), (void *)&offset
, &len
))
2157 return GET_BE_DWORD( offset
);
2160 /*************************************************************
2161 * freetype_load_font
2163 static BOOL CDECL
freetype_load_font( struct gdi_font
*font
)
2165 struct font_private_data
*data
;
2166 INT width
= 0, height
;
2171 if (!(data
= RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*data
) ))) return FALSE
;
2172 font
->private = data
;
2176 char *filename
= get_unix_file_name( font
->file
);
2177 data
->mapping
= map_font_file( filename
);
2178 RtlFreeHeap( GetProcessHeap(), 0, filename
);
2181 WARN("failed to map %s\n", debugstr_w(font
->file
));
2184 data_ptr
= data
->mapping
->data
;
2185 data_size
= data
->mapping
->size
;
2189 data_ptr
= font
->data_ptr
;
2190 data_size
= font
->data_size
;
2193 if (pFT_New_Memory_Face( library
, data_ptr
, data_size
, font
->face_index
, &ft_face
)) return FALSE
;
2195 data
->ft_face
= ft_face
;
2196 font
->scalable
= FT_IS_SCALABLE( ft_face
);
2197 if (!font
->fs
.fsCsb
[0]) get_fontsig( ft_face
, &font
->fs
);
2198 if (!font
->ntmFlags
) font
->ntmFlags
= get_ntm_flags( ft_face
);
2199 if (!font
->aa_flags
) font
->aa_flags
= ADDFONT_AA_FLAGS( default_aa_flags
);
2200 if (!font
->otm
.otmpFamilyName
)
2202 font
->otm
.otmpFamilyName
= (char *)ft_face_get_family_name( ft_face
, system_lcid
);
2203 font
->otm
.otmpStyleName
= (char *)ft_face_get_style_name( ft_face
, system_lcid
);
2204 font
->otm
.otmpFaceName
= (char *)ft_face_get_full_name( ft_face
, system_lcid
);
2209 /* load the VDMX table if we have one */
2210 font
->ppem
= load_VDMX( font
, font
->lf
.lfHeight
);
2211 if (font
->ppem
== 0) font
->ppem
= calc_ppem_for_height( ft_face
, font
->lf
.lfHeight
);
2212 TRACE( "height %d => ppem %d\n", font
->lf
.lfHeight
, font
->ppem
);
2213 height
= font
->ppem
;
2214 font
->ttc_item_offset
= get_ttc_offset( ft_face
, font
->face_index
);
2218 struct bitmap_font_size size
;
2220 get_bitmap_size( ft_face
, &size
);
2221 width
= size
.x_ppem
>> 6;
2222 height
= size
.y_ppem
>> 6;
2223 font
->ppem
= height
;
2226 pFT_Set_Pixel_Sizes( ft_face
, width
, height
);
2227 pick_charmap( ft_face
, font
->charset
);
2232 /*************************************************************
2233 * freetype_get_aa_flags
2235 static UINT CDECL
freetype_get_aa_flags( struct gdi_font
*font
, UINT aa_flags
, BOOL antialias_fakes
)
2237 /* fixup the antialiasing flags for that font */
2240 case WINE_GGO_HRGB_BITMAP
:
2241 case WINE_GGO_HBGR_BITMAP
:
2242 case WINE_GGO_VRGB_BITMAP
:
2243 case WINE_GGO_VBGR_BITMAP
:
2244 if (is_subpixel_rendering_enabled()) break;
2245 aa_flags
= GGO_GRAY4_BITMAP
;
2247 case GGO_GRAY2_BITMAP
:
2248 case GGO_GRAY4_BITMAP
:
2249 case GGO_GRAY8_BITMAP
:
2250 case WINE_GGO_GRAY16_BITMAP
:
2251 if ((!antialias_fakes
|| (!font
->fake_bold
&& !font
->fake_italic
)) && is_hinting_enabled())
2254 if (get_gasp_flags( font
, &gasp_flags
) && !(gasp_flags
& GASP_DOGRAY
))
2256 TRACE( "font %s %d aa disabled by GASP\n",
2257 debugstr_w(font
->lf
.lfFaceName
), font
->lf
.lfHeight
);
2258 aa_flags
= GGO_BITMAP
;
2265 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
2267 pt
->x
.value
= vec
->x
>> 6;
2268 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
2269 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
2270 pt
->y
.value
= vec
->y
>> 6;
2271 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
2272 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
2275 static FT_UInt
get_glyph_index_symbol( struct gdi_font
*font
, UINT glyph
)
2277 FT_Face ft_face
= get_ft_face( font
);
2280 if (glyph
< 0x100) glyph
+= 0xf000;
2281 /* there are a number of old pre-Unicode "broken" TTFs, which
2282 do have symbols at U+00XX instead of U+f0XX */
2283 if (!(ret
= pFT_Get_Char_Index(ft_face
, glyph
)))
2284 ret
= pFT_Get_Char_Index(ft_face
, glyph
- 0xf000);
2289 /*************************************************************
2290 * freetype_get_glyph_index
2292 static BOOL CDECL
freetype_get_glyph_index( struct gdi_font
*font
, UINT
*glyph
, BOOL use_encoding
)
2294 FT_Face ft_face
= get_ft_face( font
);
2296 if (!use_encoding
^ (ft_face
->charmap
->encoding
== FT_ENCODING_NONE
)) return FALSE
;
2298 if (ft_face
->charmap
->encoding
== FT_ENCODING_MS_SYMBOL
)
2300 if (!(*glyph
= get_glyph_index_symbol( font
, *glyph
)))
2306 RtlUnicodeToMultiByteN( &ch
, 1, &len
, &wc
, sizeof(wc
) );
2307 if (len
) *glyph
= get_glyph_index_symbol( font
, (unsigned char)ch
);
2311 *glyph
= pFT_Get_Char_Index( ft_face
, *glyph
);
2315 /*************************************************************
2316 * freetype_get_default_glyph
2318 static UINT CDECL
freetype_get_default_glyph( struct gdi_font
*font
)
2320 FT_Face ft_face
= get_ft_face( font
);
2321 FT_WinFNT_HeaderRec winfnt
;
2324 if ((pOS2
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_os2
)))
2326 UINT glyph
= pOS2
->usDefaultChar
;
2327 freetype_get_glyph_index( font
, &glyph
, TRUE
);
2330 if (!pFT_Get_WinFNT_Header( ft_face
, &winfnt
)) return winfnt
.default_char
+ winfnt
.first_char
;
2335 static inline BOOL
is_identity_FMAT2(const FMAT2
*matrix
)
2337 static const FMAT2 identity
= { 1.0, 0.0, 0.0, 1.0 };
2338 return !memcmp(matrix
, &identity
, sizeof(FMAT2
));
2341 static inline FT_Vector
normalize_vector(FT_Vector
*vec
)
2345 len
= pFT_Vector_Length(vec
);
2347 out
.x
= (vec
->x
<< 6) / len
;
2348 out
.y
= (vec
->y
<< 6) / len
;
2355 /* get_glyph_outline() glyph transform matrices index */
2363 static BOOL
get_transform_matrices( struct gdi_font
*font
, BOOL vertical
, const MAT2
*user_transform
,
2364 FT_Matrix matrices
[3] )
2366 static const FT_Matrix identity_mat
= { (1 << 16), 0, 0, (1 << 16) };
2367 BOOL needs_transform
= FALSE
;
2371 matrices
[matrix_unrotated
] = identity_mat
;
2373 /* Scaling factor */
2376 if (!freetype_set_outline_text_metrics( font
)) freetype_set_bitmap_text_metrics( font
);
2377 width_ratio
= (double)font
->aveWidth
;
2378 width_ratio
/= (double)font
->otm
.otmTextMetrics
.tmAveCharWidth
;
2381 width_ratio
= font
->scale_y
;
2383 /* Scaling transform */
2384 if (width_ratio
!= 1.0 || font
->scale_y
!= 1)
2386 FT_Matrix scale_mat
;
2387 scale_mat
.xx
= FT_FixedFromFloat( width_ratio
);
2390 scale_mat
.yy
= font
->scale_y
<< 16;
2392 pFT_Matrix_Multiply( &scale_mat
, &matrices
[matrix_unrotated
] );
2393 needs_transform
= TRUE
;
2396 /* Slant transform */
2397 if (font
->fake_italic
)
2399 FT_Matrix slant_mat
;
2400 slant_mat
.xx
= (1 << 16);
2401 slant_mat
.xy
= (1 << 16) >> 2;
2403 slant_mat
.yy
= (1 << 16);
2405 pFT_Matrix_Multiply( &slant_mat
, &matrices
[matrix_unrotated
] );
2406 needs_transform
= TRUE
;
2409 /* Rotation transform */
2410 matrices
[matrix_hori
] = matrices
[matrix_unrotated
];
2411 if (font
->scalable
&& font
->lf
.lfOrientation
% 3600)
2413 FT_Matrix rotation_mat
;
2416 pFT_Vector_Unit( &angle
, pFT_MulDiv( 1 << 16, font
->lf
.lfOrientation
, 10 ) );
2417 rotation_mat
.xx
= angle
.x
;
2418 rotation_mat
.xy
= -angle
.y
;
2419 rotation_mat
.yx
= angle
.y
;
2420 rotation_mat
.yy
= angle
.x
;
2421 pFT_Matrix_Multiply( &rotation_mat
, &matrices
[matrix_hori
] );
2422 needs_transform
= TRUE
;
2425 /* Vertical transform */
2426 matrices
[matrix_vert
] = matrices
[matrix_hori
];
2429 FT_Matrix vertical_mat
= { 0, -(1 << 16), 1 << 16, 0 }; /* 90 degrees rotation */
2431 pFT_Matrix_Multiply( &vertical_mat
, &matrices
[matrix_vert
] );
2432 needs_transform
= TRUE
;
2435 /* World transform */
2436 if (!is_identity_FMAT2( &font
->matrix
))
2438 FT_Matrix world_mat
;
2439 world_mat
.xx
= FT_FixedFromFloat( font
->matrix
.eM11
);
2440 world_mat
.xy
= -FT_FixedFromFloat( font
->matrix
.eM21
);
2441 world_mat
.yx
= -FT_FixedFromFloat( font
->matrix
.eM12
);
2442 world_mat
.yy
= FT_FixedFromFloat( font
->matrix
.eM22
);
2444 for (i
= 0; i
< 3; i
++)
2445 pFT_Matrix_Multiply( &world_mat
, &matrices
[i
] );
2446 needs_transform
= TRUE
;
2449 /* Extra transformation specified by caller */
2453 user_mat
.xx
= FT_FixedFromFIXED( user_transform
->eM11
);
2454 user_mat
.xy
= FT_FixedFromFIXED( user_transform
->eM21
);
2455 user_mat
.yx
= FT_FixedFromFIXED( user_transform
->eM12
);
2456 user_mat
.yy
= FT_FixedFromFIXED( user_transform
->eM22
);
2458 for (i
= 0; i
< 3; i
++)
2459 pFT_Matrix_Multiply( &user_mat
, &matrices
[i
] );
2460 needs_transform
= TRUE
;
2463 return needs_transform
;
2466 static BOOL
get_bold_glyph_outline(FT_GlyphSlot glyph
, LONG ppem
, FT_Glyph_Metrics
*metrics
)
2472 if(glyph
->format
!= FT_GLYPH_FORMAT_OUTLINE
)
2474 if(!pFT_Outline_Embolden
)
2477 strength
= pFT_MulDiv(ppem
, 1 << 6, 24);
2478 err
= pFT_Outline_Embolden(&glyph
->outline
, strength
);
2480 TRACE("FT_Ouline_Embolden returns %d\n", err
);
2484 pFT_Outline_Get_CBox(&glyph
->outline
, &bbox
);
2485 metrics
->width
= bbox
.xMax
- bbox
.xMin
;
2486 metrics
->height
= bbox
.yMax
- bbox
.yMin
;
2487 metrics
->horiBearingX
= bbox
.xMin
;
2488 metrics
->horiBearingY
= bbox
.yMax
;
2489 metrics
->vertBearingX
= metrics
->horiBearingX
- metrics
->horiAdvance
/ 2;
2490 metrics
->vertBearingY
= (metrics
->vertAdvance
- metrics
->height
) / 2;
2494 static inline BYTE
get_max_level( UINT format
)
2498 case GGO_GRAY2_BITMAP
: return 4;
2499 case GGO_GRAY4_BITMAP
: return 16;
2500 case GGO_GRAY8_BITMAP
: return 64;
2505 static FT_Vector
get_advance_metric(struct gdi_font
*incoming_font
, struct gdi_font
*font
,
2506 const FT_Glyph_Metrics
*metrics
,
2507 const FT_Matrix
*transMat
, BOOL vertical_metrics
)
2510 FT_Fixed base_advance
, em_scale
= 0;
2511 BOOL fixed_pitch_full
= FALSE
;
2513 if (vertical_metrics
)
2514 base_advance
= metrics
->vertAdvance
;
2516 base_advance
= metrics
->horiAdvance
;
2518 adv
.x
= base_advance
;
2521 /* In fixed-pitch font, we adjust the fullwidth character advance so that
2522 they have double halfwidth character width. E.g. if the font is 19 ppem,
2523 we return 20 (not 19) for fullwidth characters as we return 10 for
2524 halfwidth characters. */
2525 if (freetype_set_outline_text_metrics(incoming_font
) &&
2526 !(incoming_font
->otm
.otmTextMetrics
.tmPitchAndFamily
& TMPF_FIXED_PITCH
)) {
2528 em_scale
= pFT_MulDiv(incoming_font
->ppem
, 1 << 16, get_ft_face(incoming_font
)->units_per_EM
);
2529 avg_advance
= pFT_MulFix(incoming_font
->ntmAvgWidth
, em_scale
);
2530 fixed_pitch_full
= (avg_advance
> 0 &&
2531 (base_advance
+ 63) >> 6 ==
2532 pFT_MulFix(incoming_font
->ntmAvgWidth
*2, em_scale
));
2533 if (fixed_pitch_full
&& !transMat
)
2534 adv
.x
= (avg_advance
* 2) << 6;
2538 pFT_Vector_Transform(&adv
, transMat
);
2539 if (fixed_pitch_full
&& adv
.y
== 0) {
2541 vec
.x
= incoming_font
->ntmAvgWidth
;
2543 pFT_Vector_Transform(&vec
, transMat
);
2544 adv
.x
= (pFT_MulFix(vec
.x
, em_scale
) * 2) << 6;
2548 if (font
->fake_bold
) {
2552 FT_Vector fake_bold_adv
, vec
= { 1 << 6, 0 };
2553 pFT_Vector_Transform(&vec
, transMat
);
2554 fake_bold_adv
= normalize_vector(&vec
);
2555 adv
.x
+= fake_bold_adv
.x
;
2556 adv
.y
+= fake_bold_adv
.y
;
2560 adv
.x
= (adv
.x
+ 63) & -64;
2561 adv
.y
= -((adv
.y
+ 63) & -64);
2565 static FT_BBox
get_transformed_bbox( const FT_Glyph_Metrics
*metrics
,
2566 BOOL needs_transform
, const FT_Matrix metrices
[3] )
2568 FT_BBox bbox
= { 0, 0, 0, 0 };
2570 if (!needs_transform
)
2572 bbox
.xMin
= (metrics
->horiBearingX
) & -64;
2573 bbox
.xMax
= (metrics
->horiBearingX
+ metrics
->width
+ 63) & -64;
2574 bbox
.yMax
= (metrics
->horiBearingY
+ 63) & -64;
2575 bbox
.yMin
= (metrics
->horiBearingY
- metrics
->height
) & -64;
2582 for (xc
= 0; xc
< 2; xc
++)
2584 for (yc
= 0; yc
< 2; yc
++)
2586 vec
.x
= metrics
->horiBearingX
+ xc
* metrics
->width
;
2587 vec
.y
= metrics
->horiBearingY
- yc
* metrics
->height
;
2588 TRACE( "Vec %ld,i %ld\n", vec
.x
, vec
.y
);
2589 pFT_Vector_Transform( &vec
, &metrices
[matrix_vert
] );
2590 if (xc
== 0 && yc
== 0)
2592 bbox
.xMin
= bbox
.xMax
= vec
.x
;
2593 bbox
.yMin
= bbox
.yMax
= vec
.y
;
2597 if (vec
.x
< bbox
.xMin
) bbox
.xMin
= vec
.x
;
2598 else if (vec
.x
> bbox
.xMax
) bbox
.xMax
= vec
.x
;
2599 if (vec
.y
< bbox
.yMin
) bbox
.yMin
= vec
.y
;
2600 else if (vec
.y
> bbox
.yMax
) bbox
.yMax
= vec
.y
;
2604 bbox
.xMin
= bbox
.xMin
& -64;
2605 bbox
.xMax
= (bbox
.xMax
+ 63) & -64;
2606 bbox
.yMin
= bbox
.yMin
& -64;
2607 bbox
.yMax
= (bbox
.yMax
+ 63) & -64;
2608 TRACE( "transformed box: (%ld, %ld - %ld, %ld)\n", bbox
.xMin
, bbox
.yMax
, bbox
.xMax
, bbox
.yMin
);
2614 static void compute_metrics( struct gdi_font
*incoming_font
, struct gdi_font
*font
,
2615 FT_BBox bbox
, const FT_Glyph_Metrics
*metrics
,
2616 BOOL vertical
, BOOL vertical_metrics
,
2617 BOOL needs_transform
, const FT_Matrix matrices
[3],
2618 GLYPHMETRICS
*gm
, ABC
*abc
)
2620 FT_Vector adv
, vec
, origin
;
2622 if (!needs_transform
)
2624 adv
= get_advance_metric( incoming_font
, font
, metrics
, NULL
, vertical_metrics
);
2625 gm
->gmCellIncX
= adv
.x
>> 6;
2627 origin
.x
= bbox
.xMin
;
2628 origin
.y
= bbox
.yMax
;
2629 abc
->abcA
= origin
.x
>> 6;
2630 abc
->abcB
= (metrics
->width
+ 63) >> 6;
2636 if (vertical
&& freetype_set_outline_text_metrics( font
))
2638 if (vertical_metrics
)
2639 lsb
= metrics
->horiBearingY
+ metrics
->vertBearingY
;
2641 lsb
= metrics
->vertAdvance
+ (font
->otm
.otmDescent
<< 6);
2643 vec
.y
= font
->otm
.otmDescent
<< 6;
2644 TRACE( "Vec %ld,%ld\n", vec
.x
>>6, vec
.y
>>6 );
2645 pFT_Vector_Transform( &vec
, &matrices
[matrix_hori
] );
2646 origin
.x
= (vec
.x
+ bbox
.xMin
) & -64;
2647 origin
.y
= (vec
.y
+ bbox
.yMax
+ 63) & -64;
2648 lsb
-= metrics
->horiBearingY
;
2652 origin
.x
= bbox
.xMin
;
2653 origin
.y
= bbox
.yMax
;
2654 lsb
= metrics
->horiBearingX
;
2657 adv
= get_advance_metric( incoming_font
, font
, metrics
, &matrices
[matrix_hori
],
2659 gm
->gmCellIncX
= adv
.x
>> 6;
2660 gm
->gmCellIncY
= adv
.y
>> 6;
2662 adv
= get_advance_metric( incoming_font
, font
, metrics
, &matrices
[matrix_unrotated
],
2664 adv
.x
= pFT_Vector_Length( &adv
);
2669 pFT_Vector_Transform( &vec
, &matrices
[matrix_unrotated
] );
2670 if (lsb
> 0) abc
->abcA
= pFT_Vector_Length( &vec
) >> 6;
2671 else abc
->abcA
= -((pFT_Vector_Length( &vec
) + 63) >> 6);
2673 /* We use lsb again to avoid rounding errors */
2674 vec
.x
= lsb
+ (vertical
? metrics
->height
: metrics
->width
);
2676 pFT_Vector_Transform( &vec
, &matrices
[matrix_unrotated
] );
2677 abc
->abcB
= ((pFT_Vector_Length( &vec
) + 63) >> 6) - abc
->abcA
;
2679 if (!abc
->abcB
) abc
->abcB
= 1;
2680 abc
->abcC
= (adv
.x
>> 6) - abc
->abcA
- abc
->abcB
;
2682 gm
->gmptGlyphOrigin
.x
= origin
.x
>> 6;
2683 gm
->gmptGlyphOrigin
.y
= origin
.y
>> 6;
2684 gm
->gmBlackBoxX
= (bbox
.xMax
- bbox
.xMin
) >> 6;
2685 gm
->gmBlackBoxY
= (bbox
.yMax
- bbox
.yMin
) >> 6;
2686 if (!gm
->gmBlackBoxX
) gm
->gmBlackBoxX
= 1;
2687 if (!gm
->gmBlackBoxY
) gm
->gmBlackBoxY
= 1;
2689 TRACE( "gm: %u, %u, %s, %d, %d abc %d, %u, %d\n",
2690 gm
->gmBlackBoxX
, gm
->gmBlackBoxY
, wine_dbgstr_point(&gm
->gmptGlyphOrigin
),
2691 gm
->gmCellIncX
, gm
->gmCellIncY
, abc
->abcA
, abc
->abcB
, abc
->abcC
);
2695 static const BYTE masks
[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
2697 static DWORD
get_mono_glyph_bitmap( FT_GlyphSlot glyph
, FT_BBox bbox
,
2698 BOOL fake_bold
, BOOL needs_transform
, FT_Matrix matrices
[3],
2699 DWORD buflen
, BYTE
*buf
)
2701 DWORD width
= (bbox
.xMax
- bbox
.xMin
) >> 6;
2702 DWORD height
= (bbox
.yMax
- bbox
.yMin
) >> 6;
2703 DWORD pitch
= ((width
+ 31) >> 5) << 2;
2704 DWORD needed
= pitch
* height
;
2705 FT_Bitmap ft_bitmap
;
2709 if (!buf
|| !buflen
) return needed
;
2710 if (!needed
) return GDI_ERROR
; /* empty glyph */
2711 if (needed
> buflen
) return GDI_ERROR
;
2713 switch (glyph
->format
)
2715 case FT_GLYPH_FORMAT_BITMAP
:
2716 src
= glyph
->bitmap
.buffer
;
2718 w
= min( pitch
, (glyph
->bitmap
.width
+ 7) >> 3 );
2719 h
= min( height
, glyph
->bitmap
.rows
);
2723 memcpy( dst
, src
, w
);
2727 for (x
= 0; x
< w
; x
++)
2729 dst
[x
] = (dst
[x
] & 0x80) | (src
[x
] >> 1) | src
[x
];
2731 dst
[x
+ 1] = (src
[x
] & 0x01) << 7;
2734 src
+= glyph
->bitmap
.pitch
;
2739 case FT_GLYPH_FORMAT_OUTLINE
:
2740 ft_bitmap
.width
= width
;
2741 ft_bitmap
.rows
= height
;
2742 ft_bitmap
.pitch
= pitch
;
2743 ft_bitmap
.pixel_mode
= FT_PIXEL_MODE_MONO
;
2744 ft_bitmap
.buffer
= buf
;
2746 if (needs_transform
)
2747 pFT_Outline_Transform( &glyph
->outline
, &matrices
[matrix_vert
] );
2748 pFT_Outline_Translate( &glyph
->outline
, -bbox
.xMin
, -bbox
.yMin
);
2750 /* Note: FreeType will only set 'black' bits for us. */
2751 memset( buf
, 0, buflen
);
2752 pFT_Outline_Get_Bitmap( library
, &glyph
->outline
, &ft_bitmap
);
2756 FIXME( "loaded glyph format %x\n", glyph
->format
);
2763 static DWORD
get_antialias_glyph_bitmap( FT_GlyphSlot glyph
, FT_BBox bbox
, UINT format
,
2764 BOOL fake_bold
, BOOL needs_transform
, FT_Matrix matrices
[3],
2765 DWORD buflen
, BYTE
*buf
)
2767 DWORD width
= (bbox
.xMax
- bbox
.xMin
) >> 6;
2768 DWORD height
= (bbox
.yMax
- bbox
.yMin
) >> 6;
2769 DWORD pitch
= (width
+ 3) / 4 * 4;
2770 DWORD needed
= pitch
* height
;
2771 FT_Bitmap ft_bitmap
;
2772 INT w
, h
, x
, max_level
;
2775 if (!buf
|| !buflen
) return needed
;
2776 if (!needed
) return GDI_ERROR
; /* empty glyph */
2777 if (needed
> buflen
) return GDI_ERROR
;
2779 max_level
= get_max_level( format
);
2781 switch (glyph
->format
)
2783 case FT_GLYPH_FORMAT_BITMAP
:
2784 src
= glyph
->bitmap
.buffer
;
2786 memset( buf
, 0, buflen
);
2788 w
= min( pitch
, glyph
->bitmap
.width
);
2789 h
= min( height
, glyph
->bitmap
.rows
);
2792 for (x
= 0; x
< w
; x
++)
2794 if (src
[x
/ 8] & masks
[x
% 8])
2797 if (fake_bold
&& x
+ 1 < pitch
) dst
[x
+ 1] = max_level
;
2800 src
+= glyph
->bitmap
.pitch
;
2805 case FT_GLYPH_FORMAT_OUTLINE
:
2806 ft_bitmap
.width
= width
;
2807 ft_bitmap
.rows
= height
;
2808 ft_bitmap
.pitch
= pitch
;
2809 ft_bitmap
.pixel_mode
= FT_PIXEL_MODE_GRAY
;
2810 ft_bitmap
.buffer
= buf
;
2812 if (needs_transform
)
2813 pFT_Outline_Transform( &glyph
->outline
, &matrices
[matrix_vert
] );
2814 pFT_Outline_Translate( &glyph
->outline
, -bbox
.xMin
, -bbox
.yMin
);
2816 memset( buf
, 0, buflen
);
2817 pFT_Outline_Get_Bitmap( library
, &glyph
->outline
, &ft_bitmap
);
2819 if (max_level
!= 255)
2824 for (row
= 0, start
= buf
; row
< height
; row
++)
2826 for (col
= 0, ptr
= start
; col
< width
; col
++, ptr
++)
2827 *ptr
= (((int)*ptr
) * (max_level
+ 1)) / 256;
2834 FIXME("loaded glyph format %x\n", glyph
->format
);
2841 static DWORD
get_subpixel_glyph_bitmap( FT_GlyphSlot glyph
, FT_BBox bbox
, UINT format
,
2842 BOOL fake_bold
, BOOL needs_transform
, FT_Matrix matrices
[3],
2843 GLYPHMETRICS
*gm
, DWORD buflen
, BYTE
*buf
)
2845 DWORD width
= (bbox
.xMax
- bbox
.xMin
) >> 6;
2846 DWORD height
= (bbox
.yMax
- bbox
.yMin
) >> 6;
2847 DWORD pitch
, needed
= 0;
2851 switch (glyph
->format
)
2853 case FT_GLYPH_FORMAT_BITMAP
:
2855 needed
= pitch
* height
;
2857 if (!buf
|| !buflen
) break;
2858 if (!needed
) return GDI_ERROR
; /* empty glyph */
2859 if (needed
> buflen
) return GDI_ERROR
;
2861 src
= glyph
->bitmap
.buffer
;
2863 memset( buf
, 0, buflen
);
2865 w
= min( width
, glyph
->bitmap
.width
);
2866 h
= min( height
, glyph
->bitmap
.rows
);
2869 for (x
= 0; x
< w
; x
++)
2871 if ( src
[x
/ 8] & masks
[x
% 8] )
2873 ((unsigned int *)dst
)[x
] = ~0u;
2874 if (fake_bold
&& x
+ 1 < width
) ((unsigned int *)dst
)[x
+ 1] = ~0u;
2877 src
+= glyph
->bitmap
.pitch
;
2882 case FT_GLYPH_FORMAT_OUTLINE
:
2884 INT src_pitch
, src_width
, src_height
, x_shift
, y_shift
;
2885 INT sub_stride
, hmul
, vmul
;
2886 const INT
*sub_order
;
2887 const INT rgb_order
[3] = { 0, 1, 2 };
2888 const INT bgr_order
[3] = { 2, 1, 0 };
2889 FT_Render_Mode render_mode
=
2890 (format
== WINE_GGO_HRGB_BITMAP
||
2891 format
== WINE_GGO_HBGR_BITMAP
) ? FT_RENDER_MODE_LCD
: FT_RENDER_MODE_LCD_V
;
2893 if (!width
|| !height
) /* empty glyph */
2895 if (!buf
|| !buflen
) break;
2899 if ( render_mode
== FT_RENDER_MODE_LCD
)
2901 gm
->gmBlackBoxX
+= 2;
2902 gm
->gmptGlyphOrigin
.x
-= 1;
2903 bbox
.xMin
-= (1 << 6);
2907 gm
->gmBlackBoxY
+= 2;
2908 gm
->gmptGlyphOrigin
.y
+= 1;
2909 bbox
.yMax
+= (1 << 6);
2912 width
= gm
->gmBlackBoxX
;
2913 height
= gm
->gmBlackBoxY
;
2915 needed
= pitch
* height
;
2917 if (!buf
|| !buflen
) return needed
;
2918 if (needed
> buflen
) return GDI_ERROR
;
2920 if (needs_transform
)
2921 pFT_Outline_Transform( &glyph
->outline
, &matrices
[matrix_vert
] );
2923 #ifdef FT_LCD_FILTER_H
2924 if (pFT_Library_SetLcdFilter
)
2925 pFT_Library_SetLcdFilter( library
, FT_LCD_FILTER_DEFAULT
);
2927 pFT_Render_Glyph( glyph
, render_mode
);
2929 src_pitch
= glyph
->bitmap
.pitch
;
2930 src_width
= glyph
->bitmap
.width
;
2931 src_height
= glyph
->bitmap
.rows
;
2932 src
= glyph
->bitmap
.buffer
;
2934 memset( buf
, 0, buflen
);
2936 sub_order
= (format
== WINE_GGO_HRGB_BITMAP
||
2937 format
== WINE_GGO_VRGB_BITMAP
) ? rgb_order
: bgr_order
;
2938 sub_stride
= render_mode
== FT_RENDER_MODE_LCD
? 1 : src_pitch
;
2939 hmul
= render_mode
== FT_RENDER_MODE_LCD
? 3 : 1;
2940 vmul
= render_mode
== FT_RENDER_MODE_LCD
? 1 : 3;
2942 x_shift
= glyph
->bitmap_left
- (bbox
.xMin
>> 6);
2945 src
+= hmul
* -x_shift
;
2946 src_width
-= hmul
* -x_shift
;
2948 else if ( x_shift
> 0 )
2950 dst
+= x_shift
* sizeof(unsigned int);
2954 y_shift
= (bbox
.yMax
>> 6) - glyph
->bitmap_top
;
2957 src
+= src_pitch
* vmul
* -y_shift
;
2958 src_height
-= vmul
* -y_shift
;
2960 else if ( y_shift
> 0 )
2962 dst
+= y_shift
* pitch
;
2966 w
= min( width
, src_width
/ hmul
);
2967 h
= min( height
, src_height
/ vmul
);
2970 for (x
= 0; x
< w
; x
++)
2972 ((unsigned int *)dst
)[x
] =
2973 ((unsigned int)src
[hmul
* x
+ sub_stride
* sub_order
[0]] << 16) |
2974 ((unsigned int)src
[hmul
* x
+ sub_stride
* sub_order
[1]] << 8) |
2975 ((unsigned int)src
[hmul
* x
+ sub_stride
* sub_order
[2]]);
2977 src
+= src_pitch
* vmul
;
2983 FIXME ( "loaded glyph format %x\n", glyph
->format
);
2990 static unsigned int get_native_glyph_outline(FT_Outline
*outline
, unsigned int buflen
, char *buf
)
2992 TTPOLYGONHEADER
*pph
;
2994 unsigned int needed
= 0, point
= 0, contour
, first_pt
;
2995 unsigned int pph_start
, cpfx
;
2998 for (contour
= 0; contour
< outline
->n_contours
; contour
++)
3000 /* Ignore contours containing one point */
3001 if (point
== outline
->contours
[contour
])
3008 pph
= (TTPOLYGONHEADER
*)(buf
+ needed
);
3012 pph
->dwType
= TT_POLYGON_TYPE
;
3013 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
3015 needed
+= sizeof(*pph
);
3017 while (point
<= outline
->contours
[contour
])
3019 ppc
= (TTPOLYCURVE
*)(buf
+ needed
);
3020 type
= outline
->tags
[point
] & FT_Curve_Tag_On
?
3021 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
3026 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
3029 } while (point
<= outline
->contours
[contour
] &&
3030 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
3031 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
3032 /* At the end of a contour Windows adds the start point, but
3034 if (point
> outline
->contours
[contour
] &&
3035 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
))
3038 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
3041 else if (point
<= outline
->contours
[contour
] &&
3042 outline
->tags
[point
] & FT_Curve_Tag_On
)
3044 /* add closing pt for bezier */
3046 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
3055 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
3058 pph
->cb
= needed
- pph_start
;
3063 static unsigned int get_bezier_glyph_outline(FT_Outline
*outline
, unsigned int buflen
, char *buf
)
3065 /* Convert the quadratic Beziers to cubic Beziers.
3066 The parametric eqn for a cubic Bezier is, from PLRM:
3067 r(t) = at^3 + bt^2 + ct + r0
3068 with the control points:
3073 A quadratic Bezier has the form:
3074 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3076 So equating powers of t leads to:
3077 r1 = 2/3 p1 + 1/3 p0
3078 r2 = 2/3 p1 + 1/3 p2
3079 and of course r0 = p0, r3 = p2
3081 int contour
, point
= 0, first_pt
;
3082 TTPOLYGONHEADER
*pph
;
3084 DWORD pph_start
, cpfx
, type
;
3085 FT_Vector cubic_control
[4];
3086 unsigned int needed
= 0;
3088 for (contour
= 0; contour
< outline
->n_contours
; contour
++)
3091 pph
= (TTPOLYGONHEADER
*)(buf
+ needed
);
3095 pph
->dwType
= TT_POLYGON_TYPE
;
3096 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
3098 needed
+= sizeof(*pph
);
3100 while (point
<= outline
->contours
[contour
])
3102 ppc
= (TTPOLYCURVE
*)(buf
+ needed
);
3103 type
= outline
->tags
[point
] & FT_Curve_Tag_On
?
3104 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
3108 if (type
== TT_PRIM_LINE
)
3111 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
3117 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
3120 /* FIXME: Possible optimization in endpoint calculation
3121 if there are two consecutive curves */
3122 cubic_control
[0] = outline
->points
[point
-1];
3123 if (!(outline
->tags
[point
-1] & FT_Curve_Tag_On
))
3125 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
3126 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
3127 cubic_control
[0].x
>>= 1;
3128 cubic_control
[0].y
>>= 1;
3130 if (point
+1 > outline
->contours
[contour
])
3131 cubic_control
[3] = outline
->points
[first_pt
];
3134 cubic_control
[3] = outline
->points
[point
+1];
3135 if (!(outline
->tags
[point
+1] & FT_Curve_Tag_On
))
3137 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
3138 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
3139 cubic_control
[3].x
>>= 1;
3140 cubic_control
[3].y
>>= 1;
3143 /* r1 = 1/3 p0 + 2/3 p1
3144 r2 = 1/3 p2 + 2/3 p1 */
3145 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
3146 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
3147 cubic_control
[2] = cubic_control
[1];
3148 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
3149 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
3150 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
3151 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
3154 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
3155 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
3156 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
3161 } while (point
<= outline
->contours
[contour
] &&
3162 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
3163 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
3164 /* At the end of a contour Windows adds the start point,
3165 but only for Beziers and we've already done that.
3167 if (point
<= outline
->contours
[contour
] &&
3168 outline
->tags
[point
] & FT_Curve_Tag_On
)
3170 /* This is the closing pt of a bezier, but we've already
3171 added it, so just inc point and carry on */
3179 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
3182 pph
->cb
= needed
- pph_start
;
3187 static FT_Int
get_load_flags( UINT format
)
3189 FT_Int load_flags
= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
3191 if (format
& GGO_UNHINTED
)
3192 return load_flags
| FT_LOAD_NO_HINTING
;
3194 switch (format
& ~GGO_GLYPH_INDEX
)
3197 load_flags
|= FT_LOAD_TARGET_MONO
;
3199 case GGO_GRAY2_BITMAP
:
3200 case GGO_GRAY4_BITMAP
:
3201 case GGO_GRAY8_BITMAP
:
3202 case WINE_GGO_GRAY16_BITMAP
:
3203 load_flags
|= FT_LOAD_TARGET_NORMAL
;
3205 case WINE_GGO_HRGB_BITMAP
:
3206 case WINE_GGO_HBGR_BITMAP
:
3207 load_flags
|= FT_LOAD_TARGET_LCD
;
3209 case WINE_GGO_VRGB_BITMAP
:
3210 case WINE_GGO_VBGR_BITMAP
:
3211 load_flags
|= FT_LOAD_TARGET_LCD_V
;
3218 /*************************************************************
3219 * freetype_get_glyph_outline
3221 static DWORD CDECL
freetype_get_glyph_outline( struct gdi_font
*font
, UINT glyph
, UINT format
,
3222 GLYPHMETRICS
*lpgm
, ABC
*abc
, DWORD buflen
, void *buf
,
3223 const MAT2
*lpmat
, BOOL tategaki
)
3225 struct gdi_font
*base_font
= font
->base_font
? font
->base_font
: font
;
3226 FT_Face ft_face
= get_ft_face( font
);
3227 FT_Glyph_Metrics metrics
;
3230 FT_Int load_flags
= get_load_flags(format
);
3231 FT_Matrix matrices
[3];
3232 BOOL needsTransform
= FALSE
;
3233 BOOL vertical_metrics
;
3235 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
, buflen
, buf
, lpmat
);
3237 TRACE("font transform %f %f %f %f\n",
3238 font
->matrix
.eM11
, font
->matrix
.eM12
,
3239 font
->matrix
.eM21
, font
->matrix
.eM22
);
3241 needsTransform
= get_transform_matrices( font
, tategaki
, lpmat
, matrices
);
3243 vertical_metrics
= (tategaki
&& FT_HAS_VERTICAL(ft_face
));
3244 /* there is a freetype bug where vertical metrics are only
3245 properly scaled and correct in 2.4.0 or greater */
3246 if (vertical_metrics
&& FT_SimpleVersion
< FT_VERSION_VALUE(2, 4, 0))
3247 vertical_metrics
= FALSE
;
3249 if (needsTransform
|| format
!= GGO_BITMAP
) load_flags
|= FT_LOAD_NO_BITMAP
;
3250 if (vertical_metrics
) load_flags
|= FT_LOAD_VERTICAL_LAYOUT
;
3252 err
= pFT_Load_Glyph(ft_face
, glyph
, load_flags
);
3253 if (err
&& !(load_flags
& FT_LOAD_NO_HINTING
))
3255 WARN("Failed to load glyph %#x, retrying without hinting. Error %#x.\n", glyph
, err
);
3256 load_flags
|= FT_LOAD_NO_HINTING
;
3257 err
= pFT_Load_Glyph(ft_face
, glyph
, load_flags
);
3261 WARN("Failed to load glyph %#x, error %#x.\n", glyph
, err
);
3265 metrics
= ft_face
->glyph
->metrics
;
3266 if(font
->fake_bold
) {
3267 if (!get_bold_glyph_outline(ft_face
->glyph
, font
->ppem
, &metrics
) && metrics
.width
)
3268 metrics
.width
+= 1 << 6;
3271 /* Some poorly-created fonts contain glyphs that exceed the boundaries set
3272 * by the text metrics. The proper behavior is to clip the glyph metrics to
3273 * fit within the maximums specified in the text metrics. */
3274 if (freetype_set_outline_text_metrics(base_font
) ||
3275 freetype_set_bitmap_text_metrics(base_font
)) {
3276 TEXTMETRICW
*ptm
= &base_font
->otm
.otmTextMetrics
;
3277 INT top
= min( metrics
.horiBearingY
, ptm
->tmAscent
<< 6 );
3278 INT bottom
= max( metrics
.horiBearingY
- metrics
.height
, -(ptm
->tmDescent
<< 6) );
3279 metrics
.horiBearingY
= top
;
3280 metrics
.height
= top
- bottom
;
3282 /* TODO: Are we supposed to clip the width as well...? */
3283 /* metrics.width = min( metrics.width, ptm->tmMaxCharWidth << 6 ); */
3286 bbox
= get_transformed_bbox( &metrics
, needsTransform
, matrices
);
3287 compute_metrics( base_font
, font
, bbox
, &metrics
, tategaki
,
3288 vertical_metrics
, needsTransform
, matrices
, lpgm
, abc
);
3293 return 1; /* FIXME */
3296 return get_mono_glyph_bitmap( ft_face
->glyph
, bbox
, font
->fake_bold
,
3297 needsTransform
, matrices
, buflen
, buf
);
3299 case GGO_GRAY2_BITMAP
:
3300 case GGO_GRAY4_BITMAP
:
3301 case GGO_GRAY8_BITMAP
:
3302 case WINE_GGO_GRAY16_BITMAP
:
3303 return get_antialias_glyph_bitmap( ft_face
->glyph
, bbox
, format
, font
->fake_bold
,
3304 needsTransform
, matrices
, buflen
, buf
);
3306 case WINE_GGO_HRGB_BITMAP
:
3307 case WINE_GGO_HBGR_BITMAP
:
3308 case WINE_GGO_VRGB_BITMAP
:
3309 case WINE_GGO_VBGR_BITMAP
:
3310 return get_subpixel_glyph_bitmap( ft_face
->glyph
, bbox
, format
, font
->fake_bold
,
3311 needsTransform
, matrices
, lpgm
, buflen
, buf
);
3314 if (ft_face
->glyph
->format
== ft_glyph_format_outline
)
3316 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
3319 if (buflen
== 0) buf
= NULL
;
3321 if (needsTransform
&& buf
)
3322 pFT_Outline_Transform( outline
, &matrices
[matrix_vert
] );
3324 needed
= get_native_glyph_outline(outline
, buflen
, NULL
);
3326 if (!buf
|| !buflen
) return needed
;
3327 if (needed
> buflen
) return GDI_ERROR
;
3328 return get_native_glyph_outline(outline
, buflen
, buf
);
3330 TRACE("loaded a bitmap\n");
3334 if (ft_face
->glyph
->format
== ft_glyph_format_outline
)
3336 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
3339 if (buflen
== 0) buf
= NULL
;
3341 if (needsTransform
&& buf
)
3342 pFT_Outline_Transform( outline
, &matrices
[matrix_vert
] );
3344 needed
= get_bezier_glyph_outline(outline
, buflen
, NULL
);
3346 if (!buf
|| !buflen
) return needed
;
3347 if (needed
> buflen
) return GDI_ERROR
;
3348 return get_bezier_glyph_outline(outline
, buflen
, buf
);
3350 TRACE("loaded a bitmap\n");
3354 FIXME("Unsupported format %d\n", format
);
3359 /*************************************************************
3360 * freetype_set_bitmap_text_metrics
3362 static BOOL CDECL
freetype_set_bitmap_text_metrics( struct gdi_font
*font
)
3364 FT_Face ft_face
= get_ft_face( font
);
3365 FT_WinFNT_HeaderRec winfnt_header
;
3367 if (font
->otm
.otmSize
) return TRUE
; /* already set */
3368 font
->otm
.otmSize
= offsetof( OUTLINETEXTMETRICW
, otmFiller
);
3370 #define TM font->otm.otmTextMetrics
3371 if(!pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
3373 TM
.tmHeight
= winfnt_header
.pixel_height
;
3374 TM
.tmAscent
= winfnt_header
.ascent
;
3375 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
3376 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
3377 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
3378 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
3379 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
3380 TM
.tmWeight
= winfnt_header
.weight
;
3382 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
3383 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
3384 TM
.tmFirstChar
= winfnt_header
.first_char
;
3385 TM
.tmLastChar
= winfnt_header
.last_char
;
3386 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
3387 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
3388 TM
.tmItalic
= winfnt_header
.italic
;
3389 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
3390 TM
.tmCharSet
= winfnt_header
.charset
;
3394 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
3395 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
3396 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
3397 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
3398 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
3399 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
3400 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
3401 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
3403 TM
.tmDigitizedAspectX
= 96; /* FIXME */
3404 TM
.tmDigitizedAspectY
= 96; /* FIXME */
3406 TM
.tmLastChar
= 255;
3407 TM
.tmDefaultChar
= 32;
3408 TM
.tmBreakChar
= 32;
3409 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
3410 /* NB inverted meaning of TMPF_FIXED_PITCH */
3411 TM
.tmPitchAndFamily
= FT_IS_FIXED_WIDTH(ft_face
) ? 0 : TMPF_FIXED_PITCH
;
3412 TM
.tmCharSet
= font
->charset
;
3414 TM
.tmUnderlined
= font
->lf
.lfUnderline
? 0xff : 0;
3415 TM
.tmStruckOut
= font
->lf
.lfStrikeOut
? 0xff : 0;
3418 TM
.tmWeight
= FW_BOLD
;
3425 static BOOL
face_has_symbol_charmap(FT_Face ft_face
)
3429 for(i
= 0; i
< ft_face
->num_charmaps
; i
++)
3431 if(ft_face
->charmaps
[i
]->encoding
== FT_ENCODING_MS_SYMBOL
)
3437 /*************************************************************
3438 * freetype_set_outline_text_metrics
3440 static BOOL CDECL
freetype_set_outline_text_metrics( struct gdi_font
*font
)
3442 FT_Face ft_face
= get_ft_face( font
);
3445 TT_HoriHeader
*pHori
;
3446 TT_Postscript
*pPost
;
3448 INT ascent
, descent
;
3451 TRACE("font=%p\n", font
);
3453 if (!font
->scalable
) return FALSE
;
3454 if (font
->otm
.otmSize
) return TRUE
; /* already set */
3456 /* note: we store actual pointers in the names instead of offsets,
3457 they are fixed up when returned to the app */
3458 if (!(font
->otm
.otmpFullName
= (char *)get_face_name( ft_face
, TT_NAME_ID_UNIQUE_ID
, system_lcid
)))
3460 static const WCHAR fake_nameW
[] = {'f','a','k','e',' ','n','a','m','e', 0};
3461 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w((WCHAR
*)font
->otm
.otmpFamilyName
));
3462 font
->otm
.otmpFullName
= (char *)strdupW(fake_nameW
);
3464 needed
= sizeof(font
->otm
) + (lstrlenW( (WCHAR
*)font
->otm
.otmpFamilyName
) + 1 +
3465 lstrlenW( (WCHAR
*)font
->otm
.otmpStyleName
) + 1 +
3466 lstrlenW( (WCHAR
*)font
->otm
.otmpFaceName
) + 1 +
3467 lstrlenW( (WCHAR
*)font
->otm
.otmpFullName
) + 1) * sizeof(WCHAR
);
3469 em_scale
= (FT_Fixed
)pFT_MulDiv(font
->ppem
, 1 << 16, ft_face
->units_per_EM
);
3471 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
3473 FIXME("Can't find OS/2 table - not TT font?\n");
3477 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
3479 FIXME("Can't find HHEA table - not TT font?\n");
3483 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
3485 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",
3486 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
3487 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
3488 pOS2
->xAvgCharWidth
,
3489 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
3490 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
3491 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
3493 font
->otm
.otmSize
= needed
;
3495 #define TM font->otm.otmTextMetrics
3497 windescent
= get_fixed_windescent(pOS2
->usWinDescent
);
3498 if(pOS2
->usWinAscent
+ windescent
== 0) {
3499 ascent
= pHori
->Ascender
;
3500 descent
= -pHori
->Descender
;
3502 ascent
= pOS2
->usWinAscent
;
3503 descent
= windescent
;
3506 font
->ntmCellHeight
= ascent
+ descent
;
3507 font
->ntmAvgWidth
= pOS2
->xAvgCharWidth
;
3509 #define SCALE_X(x) (pFT_MulFix(x, em_scale))
3510 #define SCALE_Y(y) (pFT_MulFix(y, em_scale))
3513 TM
.tmAscent
= font
->yMax
;
3514 TM
.tmDescent
= -font
->yMin
;
3515 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
3517 TM
.tmAscent
= SCALE_Y(ascent
);
3518 TM
.tmDescent
= SCALE_Y(descent
);
3519 TM
.tmInternalLeading
= SCALE_Y(ascent
+ descent
- ft_face
->units_per_EM
);
3522 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
3525 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
3527 TM
.tmExternalLeading
= max(0, SCALE_Y(pHori
->Line_Gap
-
3528 ((ascent
+ descent
) -
3529 (pHori
->Ascender
- pHori
->Descender
))));
3531 TM
.tmAveCharWidth
= SCALE_X(pOS2
->xAvgCharWidth
);
3532 if (TM
.tmAveCharWidth
== 0) {
3533 TM
.tmAveCharWidth
= 1;
3535 TM
.tmMaxCharWidth
= SCALE_X(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
);
3536 TM
.tmWeight
= FW_REGULAR
;
3537 if (font
->fake_bold
)
3538 TM
.tmWeight
= FW_BOLD
;
3541 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)
3543 if (pOS2
->usWeightClass
> FW_MEDIUM
)
3544 TM
.tmWeight
= pOS2
->usWeightClass
;
3546 else if (pOS2
->usWeightClass
<= FW_MEDIUM
)
3547 TM
.tmWeight
= pOS2
->usWeightClass
;
3550 TM
.tmDigitizedAspectX
= 96; /* FIXME */
3551 TM
.tmDigitizedAspectY
= 96; /* FIXME */
3552 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
3553 * symbol range to 0 - f0ff
3556 if (face_has_symbol_charmap(ft_face
) || (pOS2
->usFirstCharIndex
>= 0xf000 && pOS2
->usFirstCharIndex
< 0xf100))
3559 switch (PRIMARYLANGID(system_lcid
))
3562 TM
.tmLastChar
= 0xf896;
3566 case LANG_LITHUANIAN
:
3567 TM
.tmLastChar
= 0xf8fd;
3570 TM
.tmLastChar
= 0xf0ff;
3572 TM
.tmBreakChar
= 0x20;
3573 TM
.tmDefaultChar
= 0x1f;
3577 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
; /* Should be the first char in the cmap */
3578 TM
.tmLastChar
= pOS2
->usLastCharIndex
; /* Should be min(cmap_last, os2_last) */
3580 if(pOS2
->usFirstCharIndex
<= 1)
3581 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
+ 2;
3582 else if (pOS2
->usFirstCharIndex
> 0xff)
3583 TM
.tmBreakChar
= 0x20;
3585 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
;
3586 TM
.tmDefaultChar
= TM
.tmBreakChar
- 1;
3588 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
3589 TM
.tmUnderlined
= font
->lf
.lfUnderline
? 255 : 0;
3590 TM
.tmStruckOut
= font
->lf
.lfStrikeOut
? 255 : 0;
3592 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
3593 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
3594 (pOS2
->version
== 0xFFFFU
||
3595 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
3596 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
3598 TM
.tmPitchAndFamily
= 0;
3600 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
])
3602 case PAN_FAMILY_SCRIPT
:
3603 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
3606 case PAN_FAMILY_DECORATIVE
:
3607 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
3612 case PAN_FAMILY_TEXT_DISPLAY
:
3613 case PAN_FAMILY_PICTORIAL
: /* symbol fonts get treated as if they were text */
3614 /* which is clearly not what the panose spec says. */
3616 if(TM
.tmPitchAndFamily
== 0 || /* fixed */
3617 pOS2
->panose
[PAN_PROPORTION_INDEX
] == PAN_PROP_MONOSPACED
)
3618 TM
.tmPitchAndFamily
= FF_MODERN
;
3621 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
])
3626 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
3629 case PAN_SERIF_COVE
:
3630 case PAN_SERIF_OBTUSE_COVE
:
3631 case PAN_SERIF_SQUARE_COVE
:
3632 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
3633 case PAN_SERIF_SQUARE
:
3634 case PAN_SERIF_THIN
:
3635 case PAN_SERIF_BONE
:
3636 case PAN_SERIF_EXAGGERATED
:
3637 case PAN_SERIF_TRIANGLE
:
3638 TM
.tmPitchAndFamily
|= FF_ROMAN
;
3641 case PAN_SERIF_NORMAL_SANS
:
3642 case PAN_SERIF_OBTUSE_SANS
:
3643 case PAN_SERIF_PERP_SANS
:
3644 case PAN_SERIF_FLARED
:
3645 case PAN_SERIF_ROUNDED
:
3646 TM
.tmPitchAndFamily
|= FF_SWISS
;
3653 if(FT_IS_SCALABLE(ft_face
))
3654 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
3656 if(FT_IS_SFNT(ft_face
))
3658 if (font
->ntmFlags
& NTM_PS_OPENTYPE
)
3659 TM
.tmPitchAndFamily
|= TMPF_DEVICE
;
3661 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
3664 TM
.tmCharSet
= font
->charset
;
3666 font
->otm
.otmFiller
= 0;
3667 memcpy(&font
->otm
.otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
3668 font
->otm
.otmfsSelection
= pOS2
->fsSelection
;
3669 if (font
->fake_italic
)
3670 font
->otm
.otmfsSelection
|= 1;
3671 if (font
->fake_bold
)
3672 font
->otm
.otmfsSelection
|= 1 << 5;
3673 /* Only return valid bits that define embedding and subsetting restrictions */
3674 font
->otm
.otmfsType
= pOS2
->fsType
& 0x30e;
3675 font
->otm
.otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
3676 font
->otm
.otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
3677 font
->otm
.otmItalicAngle
= 0; /* POST table */
3678 font
->otm
.otmEMSquare
= ft_face
->units_per_EM
;
3679 font
->otm
.otmAscent
= SCALE_Y(pOS2
->sTypoAscender
);
3680 font
->otm
.otmDescent
= SCALE_Y(pOS2
->sTypoDescender
);
3681 font
->otm
.otmLineGap
= SCALE_Y(pOS2
->sTypoLineGap
);
3682 font
->otm
.otmsCapEmHeight
= SCALE_Y(pOS2
->sCapHeight
);
3683 font
->otm
.otmsXHeight
= SCALE_Y(pOS2
->sxHeight
);
3684 font
->otm
.otmrcFontBox
.left
= SCALE_X(ft_face
->bbox
.xMin
);
3685 font
->otm
.otmrcFontBox
.right
= SCALE_X(ft_face
->bbox
.xMax
);
3686 font
->otm
.otmrcFontBox
.top
= SCALE_Y(ft_face
->bbox
.yMax
);
3687 font
->otm
.otmrcFontBox
.bottom
= SCALE_Y(ft_face
->bbox
.yMin
);
3688 font
->otm
.otmMacAscent
= TM
.tmAscent
;
3689 font
->otm
.otmMacDescent
= -TM
.tmDescent
;
3690 font
->otm
.otmMacLineGap
= SCALE_Y(pHori
->Line_Gap
);
3691 font
->otm
.otmusMinimumPPEM
= 0; /* TT Header */
3692 font
->otm
.otmptSubscriptSize
.x
= SCALE_X(pOS2
->ySubscriptXSize
);
3693 font
->otm
.otmptSubscriptSize
.y
= SCALE_Y(pOS2
->ySubscriptYSize
);
3694 font
->otm
.otmptSubscriptOffset
.x
= SCALE_X(pOS2
->ySubscriptXOffset
);
3695 font
->otm
.otmptSubscriptOffset
.y
= SCALE_Y(pOS2
->ySubscriptYOffset
);
3696 font
->otm
.otmptSuperscriptSize
.x
= SCALE_X(pOS2
->ySuperscriptXSize
);
3697 font
->otm
.otmptSuperscriptSize
.y
= SCALE_Y(pOS2
->ySuperscriptYSize
);
3698 font
->otm
.otmptSuperscriptOffset
.x
= SCALE_X(pOS2
->ySuperscriptXOffset
);
3699 font
->otm
.otmptSuperscriptOffset
.y
= SCALE_Y(pOS2
->ySuperscriptYOffset
);
3700 font
->otm
.otmsStrikeoutSize
= SCALE_Y(pOS2
->yStrikeoutSize
);
3701 font
->otm
.otmsStrikeoutPosition
= SCALE_Y(pOS2
->yStrikeoutPosition
);
3703 font
->otm
.otmsUnderscoreSize
= 0;
3704 font
->otm
.otmsUnderscorePosition
= 0;
3706 font
->otm
.otmsUnderscoreSize
= SCALE_Y(pPost
->underlineThickness
);
3707 font
->otm
.otmsUnderscorePosition
= SCALE_Y(pPost
->underlinePosition
);
3715 /*************************************************************
3716 * freetype_get_char_width_info
3718 static BOOL CDECL
freetype_get_char_width_info( struct gdi_font
*font
, struct char_width_info
*info
)
3720 FT_Face ft_face
= get_ft_face( font
);
3721 TT_HoriHeader
*pHori
;
3723 TRACE("%p, %p\n", font
, info
);
3725 if ((pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
)))
3727 FT_Fixed em_scale
= pFT_MulDiv(font
->ppem
, 1 << 16, ft_face
->units_per_EM
);
3728 info
->lsb
= (SHORT
)pFT_MulFix(pHori
->min_Left_Side_Bearing
, em_scale
);
3729 info
->rsb
= (SHORT
)pFT_MulFix(pHori
->min_Right_Side_Bearing
, em_scale
);
3736 /*************************************************************
3737 * freetype_get_unicode_ranges
3739 * Retrieve a list of supported Unicode ranges for a given font.
3740 * Can be called with NULL gs to calculate the buffer size. Returns
3741 * the number of ranges found.
3743 static DWORD CDECL
freetype_get_unicode_ranges( struct gdi_font
*font
, GLYPHSET
*gs
)
3745 FT_Face ft_face
= get_ft_face( font
);
3746 DWORD num_ranges
= 0;
3748 if (ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
3751 FT_ULong char_code
, char_code_prev
;
3754 char_code_prev
= char_code
= pFT_Get_First_Char(ft_face
, &glyph_code
);
3756 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
3757 ft_face
->num_glyphs
, glyph_code
, char_code
);
3759 if (!glyph_code
) return 0;
3763 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
3764 gs
->ranges
[0].cGlyphs
= 0;
3765 gs
->cGlyphsSupported
= 0;
3771 if (char_code
< char_code_prev
)
3773 ERR("expected increasing char code from FT_Get_Next_Char\n");
3776 if (char_code
- char_code_prev
> 1)
3781 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
3782 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
3783 gs
->cGlyphsSupported
++;
3788 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
3789 gs
->cGlyphsSupported
++;
3791 char_code_prev
= char_code
;
3792 char_code
= pFT_Get_Next_Char(ft_face
, char_code
, &glyph_code
);
3797 DWORD encoding
= RtlUlongByteSwap(ft_face
->charmap
->encoding
);
3798 FIXME("encoding %s not supported\n", debugstr_an((char *)&encoding
, 4));
3804 /*************************************************************************
3805 * Kerning support for TrueType fonts
3808 struct TT_kern_table
3814 struct TT_kern_subtable
3823 USHORT horizontal
: 1;
3825 USHORT cross_stream
: 1;
3826 USHORT override
: 1;
3827 USHORT reserved1
: 4;
3833 struct TT_format0_kern_subtable
3837 USHORT entrySelector
;
3848 static DWORD
parse_format0_kern_subtable(struct gdi_font
*font
,
3849 const struct TT_format0_kern_subtable
*tt_f0_ks
,
3850 const USHORT
*glyph_to_char
,
3851 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
3853 FT_Face ft_face
= get_ft_face( font
);
3855 const struct TT_kern_pair
*tt_kern_pair
;
3857 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, ft_face
->units_per_EM
);
3859 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
3861 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
3862 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
3863 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
3865 if (!kern_pair
|| !cPairs
)
3868 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
3870 nPairs
= min(nPairs
, cPairs
);
3872 for (i
= 0; i
< nPairs
; i
++)
3874 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
3875 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
3876 /* this algorithm appears to better match what Windows does */
3877 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
3878 if (kern_pair
->iKernAmount
< 0)
3880 kern_pair
->iKernAmount
-= ft_face
->units_per_EM
/ 2;
3881 kern_pair
->iKernAmount
-= font
->ppem
;
3883 else if (kern_pair
->iKernAmount
> 0)
3885 kern_pair
->iKernAmount
+= ft_face
->units_per_EM
/ 2;
3886 kern_pair
->iKernAmount
+= font
->ppem
;
3888 kern_pair
->iKernAmount
/= ft_face
->units_per_EM
;
3890 TRACE("left %u right %u value %d\n",
3891 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
3895 TRACE("copied %u entries\n", nPairs
);
3899 /*************************************************************
3900 * freetype_get_kerning_pairs
3902 static DWORD CDECL
freetype_get_kerning_pairs( struct gdi_font
*font
, KERNINGPAIR
**pairs
)
3904 FT_Face ft_face
= get_ft_face( font
);
3905 DWORD length
, count
= 0;
3907 const struct TT_kern_table
*tt_kern_table
;
3908 const struct TT_kern_subtable
*tt_kern_subtable
;
3910 USHORT
*glyph_to_char
;
3912 length
= freetype_get_font_data(font
, MS_KERN_TAG
, 0, NULL
, 0);
3914 if (length
== GDI_ERROR
)
3916 TRACE("no kerning data in the font\n");
3920 buf
= RtlAllocateHeap(GetProcessHeap(), 0, length
);
3923 freetype_get_font_data(font
, MS_KERN_TAG
, 0, buf
, length
);
3925 /* build a glyph index to char code map */
3926 glyph_to_char
= RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(USHORT
) * 65536);
3929 RtlFreeHeap(GetProcessHeap(), 0, buf
);
3933 if (ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
3939 char_code
= pFT_Get_First_Char(ft_face
, &glyph_code
);
3941 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
3942 ft_face
->num_glyphs
, glyph_code
, char_code
);
3946 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
3948 /* FIXME: This doesn't match what Windows does: it does some fancy
3949 * things with duplicate glyph index to char code mappings, while
3950 * we just avoid overriding existing entries.
3952 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
3953 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
3955 char_code
= pFT_Get_Next_Char(ft_face
, char_code
, &glyph_code
);
3960 DWORD encoding
= RtlUlongByteSwap(ft_face
->charmap
->encoding
);
3963 FIXME("encoding %s not supported\n", debugstr_an((char *)&encoding
, 4));
3964 for (n
= 0; n
<= 65535; n
++)
3965 glyph_to_char
[n
] = (USHORT
)n
;
3968 tt_kern_table
= buf
;
3969 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
3970 TRACE("version %u, nTables %u\n",
3971 GET_BE_WORD(tt_kern_table
->version
), nTables
);
3973 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
3975 for (i
= 0; i
< nTables
; i
++)
3977 struct TT_kern_subtable tt_kern_subtable_copy
;
3979 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
3980 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
3981 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
3983 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
3984 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
3985 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
3987 /* According to the TrueType specification this is the only format
3988 * that will be properly interpreted by Windows and OS/2
3990 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
3992 DWORD new_chunk
, old_total
= count
;
3994 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
3995 glyph_to_char
, NULL
, 0);
3999 *pairs
= RtlAllocateHeap(GetProcessHeap(), 0, count
* sizeof(**pairs
));
4001 *pairs
= RtlReAllocateHeap(GetProcessHeap(), 0, *pairs
, count
* sizeof(**pairs
));
4003 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
4004 glyph_to_char
, *pairs
+ old_total
, new_chunk
);
4007 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
4009 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
4012 RtlFreeHeap(GetProcessHeap(), 0, glyph_to_char
);
4013 RtlFreeHeap(GetProcessHeap(), 0, buf
);
4017 static const struct font_backend_funcs font_funcs
=
4019 freetype_load_fonts
,
4020 fontconfig_enum_family_fallbacks
,
4022 freetype_add_mem_font
,
4024 freetype_get_font_data
,
4025 freetype_get_aa_flags
,
4026 freetype_get_glyph_index
,
4027 freetype_get_default_glyph
,
4028 freetype_get_glyph_outline
,
4029 freetype_get_unicode_ranges
,
4030 freetype_get_char_width_info
,
4031 freetype_set_outline_text_metrics
,
4032 freetype_set_bitmap_text_metrics
,
4033 freetype_get_kerning_pairs
,
4034 freetype_destroy_font
4037 static NTSTATUS
init_freetype_lib( HMODULE module
, DWORD reason
, const void *ptr_in
, void *ptr_out
)
4039 callback_funcs
= ptr_in
;
4040 if (!init_freetype()) return STATUS_DLL_NOT_FOUND
;
4041 #ifdef SONAME_LIBFONTCONFIG
4044 NtQueryDefaultLocale( FALSE
, &system_lcid
);
4045 *(const struct font_backend_funcs
**)ptr_out
= &font_funcs
;
4046 return STATUS_SUCCESS
;
4049 #else /* HAVE_FREETYPE */
4051 static NTSTATUS
init_freetype_lib( HMODULE module
, DWORD reason
, const void *ptr_in
, void *ptr_out
)
4053 return STATUS_DLL_NOT_FOUND
;
4056 #endif /* HAVE_FREETYPE */
4058 NTSTATUS CDECL
__wine_init_unix_lib( HMODULE module
, DWORD reason
, const void *ptr_in
, void *ptr_out
)
4060 if (reason
!= DLL_PROCESS_ATTACH
) return STATUS_SUCCESS
;
4062 if (ptr_in
) return init_freetype_lib( module
, reason
, ptr_in
, ptr_out
);
4063 else return init_opengl_lib( module
, reason
, ptr_in
, ptr_out
);