cmd: DIR command outputs free space for the path.
[wine.git] / dlls / win32u / freetype.c
blobfd402758daa85538d92595a46d0997de4e7a005d
1 /*
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
24 #if 0
25 #pragma makedep unix
26 #endif
28 #include "config.h"
30 #include <stdarg.h>
31 #include <stdlib.h>
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <fcntl.h>
35 #include <dlfcn.h>
36 #include <sys/mman.h>
37 #include <string.h>
38 #include <dirent.h>
39 #include <stdio.h>
40 #include <assert.h>
41 #include <unistd.h>
43 #ifdef __APPLE__
44 #define LoadResource __carbon_LoadResource
45 #define CheckMenuItem __carbon_CheckMenuItem
46 #define CompareString __carbon_CompareString
47 #define GetCurrentThread __carbon_GetCurrentThread
48 #define GetCurrentProcess __carbon_GetCurrentProcess
49 #define AnimatePalette __carbon_AnimatePalette
50 #define DeleteMenu __carbon_DeleteMenu
51 #define DrawMenu __carbon_DrawMenu
52 #define DrawMenuBar __carbon_DrawMenuBar
53 #define EnableMenuItem __carbon_EnableMenuItem
54 #define EqualRgn __carbon_EqualRgn
55 #define FillRgn __carbon_FillRgn
56 #define FrameRgn __carbon_FrameRgn
57 #define GetMenu __carbon_GetMenu
58 #define GetPixel __carbon_GetPixel
59 #define InvertRgn __carbon_InvertRgn
60 #define IsWindowVisible __carbon_IsWindowVisible
61 #define LineTo __carbon_LineTo
62 #define MoveWindow __carbon_MoveWindow
63 #define OffsetRgn __carbon_OffsetRgn
64 #define PaintRgn __carbon_PaintRgn
65 #define Polygon __carbon_Polygon
66 #define ResizePalette __carbon_ResizePalette
67 #define SetRectRgn __carbon_SetRectRgn
68 #define ShowWindow __carbon_ShowWindow
69 #include <Carbon/Carbon.h>
70 #undef LoadResource
71 #undef CompareString
72 #undef GetCurrentThread
73 #undef _CDECL
74 #undef GetCurrentProcess
75 #undef AnimatePalette
76 #undef CheckMenuItem
77 #undef DeleteMenu
78 #undef DrawMenu
79 #undef DrawMenuBar
80 #undef EnableMenuItem
81 #undef EqualRgn
82 #undef FillRgn
83 #undef FrameRgn
84 #undef GetMenu
85 #undef GetPixel
86 #undef InvertRgn
87 #undef IsWindowVisible
88 #undef LineTo
89 #undef MoveWindow
90 #undef OffsetRgn
91 #undef PaintRgn
92 #undef Polygon
93 #undef ResizePalette
94 #undef SetRectRgn
95 #undef ShowWindow
96 #endif /* __APPLE__ */
98 #ifdef HAVE_FT2BUILD_H
99 #include <ft2build.h>
100 #include FT_FREETYPE_H
101 #include FT_GLYPH_H
102 #include FT_TYPES_H
103 #include FT_TRUETYPE_TABLES_H
104 #include FT_SFNT_NAMES_H
105 #include FT_TRUETYPE_IDS_H
106 #include FT_OUTLINE_H
107 #include FT_TRIGONOMETRY_H
108 #include FT_MODULE_H
109 #include FT_WINFONTS_H
110 #ifdef FT_LCD_FILTER_H
111 #include FT_LCD_FILTER_H
112 #endif
113 #endif /* HAVE_FT2BUILD_H */
115 #include "ntstatus.h"
116 #define WIN32_NO_STATUS
117 #include "windef.h"
118 #include "winbase.h"
119 #include "winternl.h"
120 #include "winerror.h"
121 #include "winreg.h"
122 #include "wingdi.h"
123 #include "ntgdi_private.h"
124 #include "wine/debug.h"
125 #include "wine/list.h"
127 #ifdef HAVE_FREETYPE
129 WINE_DEFAULT_DEBUG_CHANNEL(font);
131 #ifndef HAVE_FT_TRUETYPEENGINETYPE
132 typedef enum
134 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
135 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
136 FT_TRUETYPE_ENGINE_TYPE_PATENTED
137 } FT_TrueTypeEngineType;
138 #endif
140 static FT_Library library = 0;
141 typedef struct
143 FT_Int major;
144 FT_Int minor;
145 FT_Int patch;
146 } FT_Version_t;
147 static FT_Version_t FT_Version;
148 static DWORD FT_SimpleVersion;
149 #define FT_VERSION_VALUE(major, minor, patch) (((major) << 16) | ((minor) << 8) | (patch))
151 static void *ft_handle = NULL;
153 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
154 MAKE_FUNCPTR(FT_Done_Face);
155 MAKE_FUNCPTR(FT_Get_Char_Index);
156 MAKE_FUNCPTR(FT_Get_First_Char);
157 MAKE_FUNCPTR(FT_Get_Next_Char);
158 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
159 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
160 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
161 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
162 MAKE_FUNCPTR(FT_Init_FreeType);
163 MAKE_FUNCPTR(FT_Library_Version);
164 MAKE_FUNCPTR(FT_Load_Glyph);
165 MAKE_FUNCPTR(FT_Load_Sfnt_Table);
166 MAKE_FUNCPTR(FT_Matrix_Multiply);
167 MAKE_FUNCPTR(FT_MulDiv);
168 #ifdef FT_MULFIX_INLINED
169 #define pFT_MulFix FT_MULFIX_INLINED
170 #else
171 MAKE_FUNCPTR(FT_MulFix);
172 #endif
173 MAKE_FUNCPTR(FT_New_Face);
174 MAKE_FUNCPTR(FT_New_Memory_Face);
175 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
176 MAKE_FUNCPTR(FT_Outline_Get_CBox);
177 MAKE_FUNCPTR(FT_Outline_Transform);
178 MAKE_FUNCPTR(FT_Outline_Translate);
179 MAKE_FUNCPTR(FT_Render_Glyph);
180 MAKE_FUNCPTR(FT_Set_Charmap);
181 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
182 MAKE_FUNCPTR(FT_Vector_Length);
183 MAKE_FUNCPTR(FT_Vector_Transform);
184 MAKE_FUNCPTR(FT_Vector_Unit);
185 static FT_Error (*pFT_Outline_Embolden)(FT_Outline *, FT_Pos);
186 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
187 #ifdef FT_LCD_FILTER_H
188 static FT_Error (*pFT_Library_SetLcdFilter)(FT_Library, FT_LcdFilter);
189 #endif
190 static FT_Error (*pFT_Property_Set)(FT_Library, const FT_String *, const FT_String *, const void *);
192 #ifdef SONAME_LIBFONTCONFIG
193 #include <fontconfig/fontconfig.h>
194 MAKE_FUNCPTR(FcConfigSubstitute);
195 MAKE_FUNCPTR(FcDefaultSubstitute);
196 MAKE_FUNCPTR(FcFontList);
197 MAKE_FUNCPTR(FcFontMatch);
198 MAKE_FUNCPTR(FcFontSetDestroy);
199 MAKE_FUNCPTR(FcInit);
200 MAKE_FUNCPTR(FcPatternAddString);
201 MAKE_FUNCPTR(FcPatternCreate);
202 MAKE_FUNCPTR(FcPatternDestroy);
203 MAKE_FUNCPTR(FcPatternGetBool);
204 MAKE_FUNCPTR(FcPatternGetInteger);
205 MAKE_FUNCPTR(FcPatternGetString);
206 MAKE_FUNCPTR(FcConfigGetFontDirs);
207 MAKE_FUNCPTR(FcConfigGetCurrent);
208 MAKE_FUNCPTR(FcCacheCopySet);
209 MAKE_FUNCPTR(FcCacheNumSubdir);
210 MAKE_FUNCPTR(FcCacheSubdir);
211 MAKE_FUNCPTR(FcDirCacheRead);
212 MAKE_FUNCPTR(FcDirCacheUnload);
213 MAKE_FUNCPTR(FcStrListCreate);
214 MAKE_FUNCPTR(FcStrListDone);
215 MAKE_FUNCPTR(FcStrListNext);
216 MAKE_FUNCPTR(FcStrSetAdd);
217 MAKE_FUNCPTR(FcStrSetCreate);
218 MAKE_FUNCPTR(FcStrSetDestroy);
219 MAKE_FUNCPTR(FcStrSetMember);
220 #ifndef FC_NAMELANG
221 #define FC_NAMELANG "namelang"
222 #endif
223 #ifndef FC_PRGNAME
224 #define FC_PRGNAME "prgname"
225 #endif
226 #endif /* SONAME_LIBFONTCONFIG */
228 #undef MAKE_FUNCPTR
230 #ifndef FT_MAKE_TAG
231 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
232 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
233 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
234 #endif
236 #ifndef ft_encoding_none
237 #define FT_ENCODING_NONE ft_encoding_none
238 #endif
239 #ifndef ft_encoding_ms_symbol
240 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
241 #endif
242 #ifndef ft_encoding_unicode
243 #define FT_ENCODING_UNICODE ft_encoding_unicode
244 #endif
245 #ifndef ft_encoding_apple_roman
246 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
247 #endif
249 #ifdef WORDS_BIGENDIAN
250 #define GET_BE_WORD(x) (x)
251 #define GET_BE_DWORD(x) (x)
252 #else
253 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
254 #define GET_BE_DWORD(x) RtlUlongByteSwap(x)
255 #endif
257 /* 'gasp' flags */
258 #define GASP_GRIDFIT 0x01
259 #define GASP_DOGRAY 0x02
261 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
262 So to let this compile on older versions of FreeType we'll define the
263 new structure here. */
264 typedef struct {
265 FT_Short height, width;
266 FT_Pos size, x_ppem, y_ppem;
267 } My_FT_Bitmap_Size;
269 struct font_private_data
271 FT_Face ft_face;
272 struct font_mapping *mapping;
275 static inline FT_Face get_ft_face( struct gdi_font *font )
277 return ((struct font_private_data *)font->private)->ft_face;
280 struct font_mapping
282 struct list entry;
283 int refcount;
284 dev_t dev;
285 ino_t ino;
286 void *data;
287 size_t size;
290 static struct list mappings_list = LIST_INIT( mappings_list );
292 static UINT default_aa_flags;
293 static LCID system_lcid;
295 static BOOL freetype_set_outline_text_metrics( struct gdi_font *font );
296 static BOOL freetype_set_bitmap_text_metrics( struct gdi_font *font );
298 /****************************************
299 * Notes on .fon files
301 * The fonts System, FixedSys and Terminal are special. There are typically multiple
302 * versions installed for different resolutions and codepages. Windows stores which one to use
303 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
304 * Key Meaning
305 * FIXEDFON.FON FixedSys
306 * FONTS.FON System
307 * OEMFONT.FON Terminal
308 * LogPixels Current dpi set by the display control panel applet
309 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
310 * also has a LogPixels value that appears to mirror this)
312 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
313 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
314 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
315 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
316 * so that makes sense.
318 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
319 * to be mapped into the registry on Windows 2000 at least).
320 * I have
321 * woafont=app850.fon
322 * ega80woa.fon=ega80850.fon
323 * ega40woa.fon=ega40850.fon
324 * cga80woa.fon=cga80850.fon
325 * cga40woa.fon=cga40850.fon
328 #ifdef __APPLE__
329 static char *find_cache_dir(void)
331 FSRef ref;
332 OSErr err;
333 static char cached_path[MAX_PATH];
334 static const char *wine = "/Wine", *fonts = "/Fonts";
336 if(*cached_path) return cached_path;
338 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
339 if(err != noErr)
341 WARN("can't create cached data folder\n");
342 return NULL;
344 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
345 if(err != noErr)
347 WARN("can't create cached data path\n");
348 *cached_path = '\0';
349 return NULL;
351 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
353 ERR("Could not create full path\n");
354 *cached_path = '\0';
355 return NULL;
357 strcat(cached_path, wine);
359 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
361 WARN("Couldn't mkdir %s\n", cached_path);
362 *cached_path = '\0';
363 return NULL;
365 strcat(cached_path, fonts);
366 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
368 WARN("Couldn't mkdir %s\n", cached_path);
369 *cached_path = '\0';
370 return NULL;
372 return cached_path;
375 /******************************************************************
376 * expand_mac_font
378 * Extracts individual TrueType font files from a Mac suitcase font
379 * and saves them into the user's caches directory (see
380 * find_cache_dir()).
381 * Returns a NULL terminated array of filenames.
383 * We do this because they are apps that try to read ttf files
384 * themselves and they don't like Mac suitcase files.
386 static char **expand_mac_font(const char *path)
388 FSRef ref;
389 ResFileRefNum res_ref;
390 OSStatus s;
391 unsigned int idx;
392 const char *out_dir;
393 const char *filename;
394 int output_len;
395 struct {
396 char **array;
397 unsigned int size, max_size;
398 } ret;
400 TRACE("path %s\n", path);
402 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
403 if(s != noErr)
405 WARN("failed to get ref\n");
406 return NULL;
409 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
410 if(s != noErr)
412 TRACE("no data fork, so trying resource fork\n");
413 res_ref = FSOpenResFile(&ref, fsRdPerm);
414 if(res_ref == -1)
416 TRACE("unable to open resource fork\n");
417 return NULL;
421 ret.size = 0;
422 ret.max_size = 10;
423 ret.array = calloc( ret.max_size, sizeof(*ret.array) );
424 if(!ret.array)
426 CloseResFile(res_ref);
427 return NULL;
430 out_dir = find_cache_dir();
432 filename = strrchr(path, '/');
433 if(!filename) filename = path;
434 else filename++;
436 /* output filename has the form out_dir/filename_%04x.ttf */
437 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
439 UseResFile(res_ref);
440 idx = 1;
441 while(1)
443 FamRec *fam_rec;
444 unsigned short *num_faces_ptr, num_faces, face;
445 AsscEntry *assoc;
446 Handle fond;
447 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
449 fond = Get1IndResource(fond_res, idx);
450 if(!fond) break;
451 TRACE("got fond resource %d\n", idx);
452 HLock(fond);
454 fam_rec = *(FamRec**)fond;
455 num_faces_ptr = (unsigned short *)(fam_rec + 1);
456 num_faces = GET_BE_WORD(*num_faces_ptr);
457 num_faces++;
458 assoc = (AsscEntry*)(num_faces_ptr + 1);
459 TRACE("num faces %04x\n", num_faces);
460 for(face = 0; face < num_faces; face++, assoc++)
462 Handle sfnt;
463 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
464 unsigned short size, font_id;
465 char *output;
467 size = GET_BE_WORD(assoc->fontSize);
468 font_id = GET_BE_WORD(assoc->fontID);
469 if(size != 0)
471 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
472 continue;
475 TRACE("trying to load sfnt id %04x\n", font_id);
476 sfnt = GetResource(sfnt_res, font_id);
477 if(!sfnt)
479 TRACE("can't get sfnt resource %04x\n", font_id);
480 continue;
483 output = malloc( output_len);
484 if(output)
486 int fd;
488 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
490 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
491 if(fd != -1 || errno == EEXIST)
493 if(fd != -1)
495 unsigned char *sfnt_data;
497 HLock(sfnt);
498 sfnt_data = *(unsigned char**)sfnt;
499 write(fd, sfnt_data, GetHandleSize(sfnt));
500 HUnlock(sfnt);
501 close(fd);
503 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
505 ret.array = realloc( ret.array, ret.max_size * sizeof(*ret.array) * 2 );
506 memset( ret.array + ret.max_size, 0, ret.max_size * sizeof(*ret.array) );
507 ret.max_size *= 2;
509 ret.array[ret.size++] = output;
511 else
513 WARN("unable to create %s\n", output);
514 free( output );
517 ReleaseResource(sfnt);
519 HUnlock(fond);
520 ReleaseResource(fond);
521 idx++;
523 CloseResFile(res_ref);
525 return ret.array;
528 #endif /* __APPLE__ */
531 This function builds an FT_Fixed from a double. It fails if the absolute
532 value of the float number is greater than 32768.
534 static inline FT_Fixed FT_FixedFromFloat(double f)
536 return f * 0x10000;
540 This function builds an FT_Fixed from a FIXED. It simply put f.value
541 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
543 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
545 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
548 static BOOL is_hinting_enabled(void)
550 static int enabled = -1;
552 if (enabled == -1)
554 /* Use the >= 2.2.0 function if available */
555 if (pFT_Get_TrueType_Engine_Type)
557 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
558 enabled = (type == FT_TRUETYPE_ENGINE_TYPE_PATENTED);
560 else enabled = FALSE;
561 TRACE("hinting is %senabled\n", enabled ? "" : "NOT ");
563 return enabled;
566 static BOOL is_subpixel_rendering_enabled( void )
568 static int enabled = -1;
569 if (enabled == -1)
571 /* FreeType >= 2.8.1 offers LCD-optimezed rendering without lcd filters. */
572 if (FT_SimpleVersion >= FT_VERSION_VALUE(2, 8, 1))
573 enabled = TRUE;
574 #ifdef FT_LCD_FILTER_H
575 else if (pFT_Library_SetLcdFilter &&
576 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature)
577 enabled = TRUE;
578 #endif
579 else enabled = FALSE;
581 TRACE("subpixel rendering is %senabled\n", enabled ? "" : "NOT ");
583 return enabled;
587 static const LANGID mac_langid_table[] =
589 MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ENGLISH */
590 MAKELANGID(LANG_FRENCH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FRENCH */
591 MAKELANGID(LANG_GERMAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GERMAN */
592 MAKELANGID(LANG_ITALIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ITALIAN */
593 MAKELANGID(LANG_DUTCH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_DUTCH */
594 MAKELANGID(LANG_SWEDISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SWEDISH */
595 MAKELANGID(LANG_SPANISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SPANISH */
596 MAKELANGID(LANG_DANISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_DANISH */
597 MAKELANGID(LANG_PORTUGUESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PORTUGUESE */
598 MAKELANGID(LANG_NORWEGIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_NORWEGIAN */
599 MAKELANGID(LANG_HEBREW,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HEBREW */
600 MAKELANGID(LANG_JAPANESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_JAPANESE */
601 MAKELANGID(LANG_ARABIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ARABIC */
602 MAKELANGID(LANG_FINNISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FINNISH */
603 MAKELANGID(LANG_GREEK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GREEK */
604 MAKELANGID(LANG_ICELANDIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ICELANDIC */
605 MAKELANGID(LANG_MALTESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALTESE */
606 MAKELANGID(LANG_TURKISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TURKISH */
607 MAKELANGID(LANG_CROATIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CROATIAN */
608 MAKELANGID(LANG_CHINESE_TRADITIONAL,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CHINESE_TRADITIONAL */
609 MAKELANGID(LANG_URDU,SUBLANG_DEFAULT), /* TT_MAC_LANGID_URDU */
610 MAKELANGID(LANG_HINDI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HINDI */
611 MAKELANGID(LANG_THAI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_THAI */
612 MAKELANGID(LANG_KOREAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KOREAN */
613 MAKELANGID(LANG_LITHUANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LITHUANIAN */
614 MAKELANGID(LANG_POLISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_POLISH */
615 MAKELANGID(LANG_HUNGARIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HUNGARIAN */
616 MAKELANGID(LANG_ESTONIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ESTONIAN */
617 MAKELANGID(LANG_LATVIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LETTISH */
618 MAKELANGID(LANG_SAMI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SAAMISK */
619 MAKELANGID(LANG_FAEROESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FAEROESE */
620 MAKELANGID(LANG_FARSI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FARSI */
621 MAKELANGID(LANG_RUSSIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_RUSSIAN */
622 MAKELANGID(LANG_CHINESE_SIMPLIFIED,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CHINESE_SIMPLIFIED */
623 MAKELANGID(LANG_DUTCH,SUBLANG_DUTCH_BELGIAN), /* TT_MAC_LANGID_FLEMISH */
624 MAKELANGID(LANG_IRISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_IRISH */
625 MAKELANGID(LANG_ALBANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ALBANIAN */
626 MAKELANGID(LANG_ROMANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ROMANIAN */
627 MAKELANGID(LANG_CZECH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CZECH */
628 MAKELANGID(LANG_SLOVAK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SLOVAK */
629 MAKELANGID(LANG_SLOVENIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SLOVENIAN */
630 0, /* TT_MAC_LANGID_YIDDISH */
631 MAKELANGID(LANG_SERBIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SERBIAN */
632 MAKELANGID(LANG_MACEDONIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MACEDONIAN */
633 MAKELANGID(LANG_BULGARIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BULGARIAN */
634 MAKELANGID(LANG_UKRAINIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UKRAINIAN */
635 MAKELANGID(LANG_BELARUSIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BYELORUSSIAN */
636 MAKELANGID(LANG_UZBEK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UZBEK */
637 MAKELANGID(LANG_KAZAK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KAZAKH */
638 MAKELANGID(LANG_AZERI,SUBLANG_AZERI_CYRILLIC), /* TT_MAC_LANGID_AZERBAIJANI */
639 0, /* TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT */
640 MAKELANGID(LANG_ARMENIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ARMENIAN */
641 MAKELANGID(LANG_GEORGIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GEORGIAN */
642 0, /* TT_MAC_LANGID_MOLDAVIAN */
643 MAKELANGID(LANG_KYRGYZ,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KIRGHIZ */
644 MAKELANGID(LANG_TAJIK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TAJIKI */
645 MAKELANGID(LANG_TURKMEN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TURKMEN */
646 MAKELANGID(LANG_MONGOLIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MONGOLIAN */
647 MAKELANGID(LANG_MONGOLIAN,SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA), /* TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT */
648 MAKELANGID(LANG_PASHTO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PASHTO */
649 0, /* TT_MAC_LANGID_KURDISH */
650 MAKELANGID(LANG_KASHMIRI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KASHMIRI */
651 MAKELANGID(LANG_SINDHI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SINDHI */
652 MAKELANGID(LANG_TIBETAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TIBETAN */
653 MAKELANGID(LANG_NEPALI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_NEPALI */
654 MAKELANGID(LANG_SANSKRIT,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SANSKRIT */
655 MAKELANGID(LANG_MARATHI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MARATHI */
656 MAKELANGID(LANG_BENGALI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BENGALI */
657 MAKELANGID(LANG_ASSAMESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ASSAMESE */
658 MAKELANGID(LANG_GUJARATI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GUJARATI */
659 MAKELANGID(LANG_PUNJABI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PUNJABI */
660 MAKELANGID(LANG_ORIYA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ORIYA */
661 MAKELANGID(LANG_MALAYALAM,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAYALAM */
662 MAKELANGID(LANG_KANNADA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KANNADA */
663 MAKELANGID(LANG_TAMIL,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TAMIL */
664 MAKELANGID(LANG_TELUGU,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TELUGU */
665 MAKELANGID(LANG_SINHALESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SINHALESE */
666 0, /* TT_MAC_LANGID_BURMESE */
667 MAKELANGID(LANG_KHMER,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KHMER */
668 MAKELANGID(LANG_LAO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LAO */
669 MAKELANGID(LANG_VIETNAMESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_VIETNAMESE */
670 MAKELANGID(LANG_INDONESIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_INDONESIAN */
671 0, /* TT_MAC_LANGID_TAGALOG */
672 MAKELANGID(LANG_MALAY,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAY_ROMAN_SCRIPT */
673 0, /* TT_MAC_LANGID_MALAY_ARABIC_SCRIPT */
674 MAKELANGID(LANG_AMHARIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_AMHARIC */
675 MAKELANGID(LANG_TIGRIGNA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TIGRINYA */
676 0, /* TT_MAC_LANGID_GALLA */
677 0, /* TT_MAC_LANGID_SOMALI */
678 MAKELANGID(LANG_SWAHILI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SWAHILI */
679 0, /* TT_MAC_LANGID_RUANDA */
680 0, /* TT_MAC_LANGID_RUNDI */
681 0, /* TT_MAC_LANGID_CHEWA */
682 0, /* TT_MAC_LANGID_MALAGASY */
683 0, /* TT_MAC_LANGID_ESPERANTO */
684 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 95-111 */
685 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 112-127 */
686 MAKELANGID(LANG_WELSH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_WELSH */
687 MAKELANGID(LANG_BASQUE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BASQUE */
688 MAKELANGID(LANG_CATALAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CATALAN */
689 0, /* TT_MAC_LANGID_LATIN */
690 MAKELANGID(LANG_QUECHUA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_QUECHUA */
691 0, /* TT_MAC_LANGID_GUARANI */
692 0, /* TT_MAC_LANGID_AYMARA */
693 MAKELANGID(LANG_TATAR,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TATAR */
694 MAKELANGID(LANG_UIGHUR,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UIGHUR */
695 0, /* TT_MAC_LANGID_DZONGKHA */
696 0, /* TT_MAC_LANGID_JAVANESE */
697 0, /* TT_MAC_LANGID_SUNDANESE */
698 MAKELANGID(LANG_GALICIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GALICIAN */
699 MAKELANGID(LANG_AFRIKAANS,SUBLANG_DEFAULT), /* TT_MAC_LANGID_AFRIKAANS */
700 MAKELANGID(LANG_BRETON,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BRETON */
701 MAKELANGID(LANG_INUKTITUT,SUBLANG_DEFAULT), /* TT_MAC_LANGID_INUKTITUT */
702 MAKELANGID(LANG_SCOTTISH_GAELIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SCOTTISH_GAELIC */
703 0, /* TT_MAC_LANGID_MANX_GAELIC */
704 MAKELANGID(LANG_IRISH,SUBLANG_IRISH_IRELAND), /* TT_MAC_LANGID_IRISH_GAELIC */
705 0, /* TT_MAC_LANGID_TONGAN */
706 0, /* TT_MAC_LANGID_GREEK_POLYTONIC */
707 MAKELANGID(LANG_GREENLANDIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GREELANDIC */
708 MAKELANGID(LANG_AZERI,SUBLANG_AZERI_LATIN), /* TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT */
711 static CPTABLEINFO *get_mac_code_page( const FT_SfntName *name )
713 int id = name->encoding_id;
715 if (name->encoding_id == TT_MAC_ID_SIMPLIFIED_CHINESE) id = 8; /* special case */
716 return get_cptable( 10000 + id );
719 static int match_name_table_language( const FT_SfntName *name, LANGID lang )
721 LANGID name_lang;
722 int res = 0;
724 switch (name->platform_id)
726 case TT_PLATFORM_MICROSOFT:
727 res += 5; /* prefer the Microsoft name */
728 switch (name->encoding_id)
730 case TT_MS_ID_UNICODE_CS:
731 case TT_MS_ID_SYMBOL_CS:
732 name_lang = name->language_id;
733 break;
734 default:
735 return 0;
737 break;
738 case TT_PLATFORM_MACINTOSH:
739 if (!get_mac_code_page( name )) return 0;
740 if (name->language_id >= ARRAY_SIZE( mac_langid_table )) return 0;
741 name_lang = mac_langid_table[name->language_id];
742 break;
743 case TT_PLATFORM_APPLE_UNICODE:
744 res += 2; /* prefer Unicode encodings */
745 switch (name->encoding_id)
747 case TT_APPLE_ID_DEFAULT:
748 case TT_APPLE_ID_ISO_10646:
749 case TT_APPLE_ID_UNICODE_2_0:
750 if (name->language_id >= ARRAY_SIZE( mac_langid_table )) return 0;
751 name_lang = mac_langid_table[name->language_id];
752 break;
753 default:
754 return 0;
756 break;
757 default:
758 return 0;
760 if (name_lang == lang) res += 30;
761 else if (PRIMARYLANGID( name_lang ) == PRIMARYLANGID( lang )) res += 20;
762 else if (name_lang == MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT )) res += 10;
763 else if (lang == MAKELANGID( LANG_NEUTRAL, SUBLANG_NEUTRAL )) res += 5 * (0x100000 - name_lang);
764 return res;
767 static WCHAR *copy_name_table_string( const FT_SfntName *name )
769 WCHAR *ret;
770 CPTABLEINFO *cp;
771 DWORD i;
773 switch (name->platform_id)
775 case TT_PLATFORM_APPLE_UNICODE:
776 case TT_PLATFORM_MICROSOFT:
777 ret = malloc( name->string_len + sizeof(WCHAR) );
778 for (i = 0; i < name->string_len / 2; i++)
779 ret[i] = (name->string[i * 2] << 8) | name->string[i * 2 + 1];
780 ret[i] = 0;
781 return ret;
782 case TT_PLATFORM_MACINTOSH:
783 if (!(cp = get_mac_code_page( name ))) return NULL;
784 ret = malloc( (name->string_len + 1) * sizeof(WCHAR) );
785 i = win32u_mbtowc( cp, ret, name->string_len, (char *)name->string, name->string_len );
786 ret[i] = 0;
787 return ret;
789 return NULL;
792 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, LANGID language_id)
794 FT_SfntName name;
795 FT_UInt num_names, name_index;
796 int res, best_lang = 0, best_index = -1;
798 if (!FT_IS_SFNT(ft_face)) return NULL;
800 num_names = pFT_Get_Sfnt_Name_Count( ft_face );
802 for (name_index = 0; name_index < num_names; name_index++)
804 if (pFT_Get_Sfnt_Name( ft_face, name_index, &name )) continue;
805 if (name.name_id != name_id) continue;
806 res = match_name_table_language( &name, language_id );
807 if (res > best_lang)
809 best_lang = res;
810 best_index = name_index;
814 if (best_index != -1 && !pFT_Get_Sfnt_Name( ft_face, best_index, &name ))
816 WCHAR *ret = copy_name_table_string( &name );
817 TRACE( "name %u found platform %u lang %04x %s\n",
818 name_id, name.platform_id, name.language_id, debugstr_w( ret ));
819 return ret;
821 return NULL;
824 static WCHAR *ft_face_get_family_name( FT_Face ft_face, LANGID langid )
826 WCHAR *family_name;
828 if ((family_name = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, langid )))
829 return family_name;
831 return towstr( ft_face->family_name );
834 static WCHAR *ft_face_get_style_name( FT_Face ft_face, LANGID langid )
836 WCHAR *style_name;
838 if ((style_name = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, langid )))
839 return style_name;
841 return towstr( ft_face->style_name );
844 static WCHAR *ft_face_get_full_name( FT_Face ft_face, LANGID langid )
846 static const WCHAR space_w[] = {' ',0};
847 WCHAR *full_name, *style_name;
848 SIZE_T length;
850 if ((full_name = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, langid )))
851 return full_name;
853 full_name = ft_face_get_family_name( ft_face, langid );
854 style_name = ft_face_get_style_name( ft_face, langid );
856 length = lstrlenW( full_name ) + lstrlenW( space_w ) + lstrlenW( style_name ) + 1;
857 full_name = realloc( full_name, length * sizeof(WCHAR) );
859 lstrcatW( full_name, space_w );
860 lstrcatW( full_name, style_name );
861 free( style_name );
863 WARN( "full name not found, using %s instead\n", debugstr_w(full_name) );
864 return full_name;
867 static inline FT_Fixed get_font_version( FT_Face ft_face )
869 FT_Fixed version = 0;
870 TT_Header *header;
872 header = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head );
873 if (header) version = header->Font_Revision;
875 return version;
878 static inline DWORD get_ntm_flags( FT_Face ft_face )
880 DWORD flags = 0;
881 FT_ULong table_size = 0;
882 FT_WinFNT_HeaderRec winfnt_header;
884 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) flags |= NTM_ITALIC;
885 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD) flags |= NTM_BOLD;
887 /* fixup the flag for our fake-bold implementation. */
888 if (!FT_IS_SCALABLE( ft_face ) &&
889 !pFT_Get_WinFNT_Header( ft_face, &winfnt_header ) &&
890 winfnt_header.weight > FW_NORMAL )
891 flags |= NTM_BOLD;
893 if (flags == 0) flags = NTM_REGULAR;
895 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL, &table_size ))
896 flags |= NTM_PS_OPENTYPE;
898 return flags;
901 static inline void get_bitmap_size( FT_Face ft_face, struct bitmap_font_size *face_size )
903 My_FT_Bitmap_Size *size;
904 FT_WinFNT_HeaderRec winfnt_header;
906 size = (My_FT_Bitmap_Size *)ft_face->available_sizes;
907 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
908 size->height, size->width, size->size >> 6,
909 size->x_ppem >> 6, size->y_ppem >> 6);
910 face_size->height = size->height;
911 face_size->width = size->width;
912 face_size->size = size->size;
913 face_size->x_ppem = size->x_ppem;
914 face_size->y_ppem = size->y_ppem;
916 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header )) {
917 face_size->internal_leading = winfnt_header.internal_leading;
918 if (winfnt_header.external_leading > 0 &&
919 (face_size->height ==
920 winfnt_header.pixel_height + winfnt_header.external_leading))
921 face_size->height = winfnt_header.pixel_height;
925 static inline void get_fontsig( FT_Face ft_face, FONTSIGNATURE *fs )
927 TT_OS2 *os2;
928 FT_WinFNT_HeaderRec winfnt_header;
929 int i;
931 memset( fs, 0, sizeof(*fs) );
933 os2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 );
934 if (os2)
936 fs->fsUsb[0] = os2->ulUnicodeRange1;
937 fs->fsUsb[1] = os2->ulUnicodeRange2;
938 fs->fsUsb[2] = os2->ulUnicodeRange3;
939 fs->fsUsb[3] = os2->ulUnicodeRange4;
941 if (os2->version == 0)
943 if (os2->usFirstCharIndex >= 0xf000 && os2->usFirstCharIndex < 0xf100)
944 fs->fsCsb[0] = FS_SYMBOL;
945 else
946 fs->fsCsb[0] = FS_LATIN1;
948 else
950 fs->fsCsb[0] = os2->ulCodePageRange1;
951 fs->fsCsb[1] = os2->ulCodePageRange2;
954 else
956 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
958 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
959 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
960 switch (winfnt_header.charset)
962 case ANSI_CHARSET: fs->fsCsb[0] = FS_LATIN1; break;
963 case EASTEUROPE_CHARSET: fs->fsCsb[0] = FS_LATIN2; break;
964 case RUSSIAN_CHARSET: fs->fsCsb[0] = FS_CYRILLIC; break;
965 case GREEK_CHARSET: fs->fsCsb[0] = FS_GREEK; break;
966 case TURKISH_CHARSET: fs->fsCsb[0] = FS_TURKISH; break;
967 case HEBREW_CHARSET: fs->fsCsb[0] = FS_HEBREW; break;
968 case ARABIC_CHARSET: fs->fsCsb[0] = FS_ARABIC; break;
969 case BALTIC_CHARSET: fs->fsCsb[0] = FS_BALTIC; break;
970 case VIETNAMESE_CHARSET: fs->fsCsb[0] = FS_VIETNAMESE; break;
971 case THAI_CHARSET: fs->fsCsb[0] = FS_THAI; break;
972 case SHIFTJIS_CHARSET: fs->fsCsb[0] = FS_JISJAPAN; break;
973 case GB2312_CHARSET: fs->fsCsb[0] = FS_CHINESESIMP; break;
974 case HANGEUL_CHARSET: fs->fsCsb[0] = FS_WANSUNG; break;
975 case CHINESEBIG5_CHARSET: fs->fsCsb[0] = FS_CHINESETRAD; break;
976 case JOHAB_CHARSET: fs->fsCsb[0] = FS_JOHAB; break;
977 case SYMBOL_CHARSET: fs->fsCsb[0] = FS_SYMBOL; break;
982 if (fs->fsCsb[0] == 0)
984 /* let's see if we can find any interesting cmaps */
985 for (i = 0; i < ft_face->num_charmaps; i++)
987 switch (ft_face->charmaps[i]->encoding)
989 case FT_ENCODING_UNICODE:
990 case FT_ENCODING_APPLE_ROMAN:
991 fs->fsCsb[0] |= FS_LATIN1;
992 break;
993 case FT_ENCODING_MS_SYMBOL:
994 fs->fsCsb[0] |= FS_SYMBOL;
995 break;
996 default:
997 break;
1003 static FT_Face new_ft_face( const char *file, void *font_data_ptr, UINT font_data_size,
1004 FT_Long face_index, BOOL allow_bitmap )
1006 FT_Error err;
1007 TT_OS2 *pOS2;
1008 FT_Face ft_face;
1010 if (file)
1012 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1013 err = pFT_New_Face(library, file, face_index, &ft_face);
1015 else
1017 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1018 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1021 if (err != 0)
1023 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1024 return NULL;
1027 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1028 if (!FT_IS_SCALABLE( ft_face ) && FT_SimpleVersion < FT_VERSION_VALUE(2, 1, 9))
1030 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1031 goto fail;
1034 if (!FT_IS_SFNT( ft_face ))
1036 if (FT_IS_SCALABLE( ft_face ) || !allow_bitmap )
1038 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1039 goto fail;
1042 else
1044 if (!(pOS2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 )) ||
1045 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_hhea ) ||
1046 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head ))
1048 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1049 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1050 goto fail;
1053 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1054 we don't want to load these. */
1055 if (!memcmp( pOS2->achVendID, "Wine", sizeof(pOS2->achVendID) ))
1057 FT_ULong len = 0;
1059 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len ))
1061 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1062 goto fail;
1067 if (!ft_face->family_name || !ft_face->style_name)
1069 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1070 goto fail;
1073 return ft_face;
1074 fail:
1075 pFT_Done_Face( ft_face );
1076 return NULL;
1079 struct family_names_data
1081 LANGID primary_langid;
1082 struct opentype_name family_name;
1083 struct opentype_name second_name;
1084 BOOL primary_seen;
1085 BOOL english_seen;
1088 static BOOL search_family_names_callback( LANGID langid, struct opentype_name *name, void *user )
1090 struct family_names_data *data = user;
1092 if (langid == MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT))
1094 data->english_seen = TRUE;
1095 if (data->primary_langid == langid) data->primary_seen = TRUE;
1097 if (!data->family_name.bytes) data->family_name = *name;
1098 else if (data->primary_langid != langid) data->second_name = *name;
1100 else if (data->primary_langid == langid)
1102 data->primary_seen = TRUE;
1103 if (data->family_name.bytes) data->second_name = data->family_name;
1104 data->family_name = *name;
1106 else if (!data->second_name.bytes) data->second_name = *name;
1108 if (data->family_name.bytes && data->second_name.bytes && data->primary_seen && data->english_seen)
1109 return TRUE;
1110 return FALSE;
1113 struct face_name_data
1115 LANGID primary_langid;
1116 struct opentype_name face_name;
1119 static BOOL search_face_name_callback( LANGID langid, struct opentype_name *name, void *user )
1121 struct face_name_data *data = user;
1123 if (langid == data->primary_langid || (langid == MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT) && !data->face_name.bytes))
1124 data->face_name = *name;
1126 return langid == data->primary_langid;
1129 static WCHAR *decode_opentype_name( struct opentype_name *name )
1131 WCHAR buffer[512];
1132 DWORD len;
1134 if (!name->codepage)
1136 len = min( ARRAY_SIZE(buffer), name->length / sizeof(WCHAR) );
1137 while (len--) buffer[len] = GET_BE_WORD( ((WORD *)name->bytes)[len] );
1138 len = min( ARRAY_SIZE(buffer), name->length / sizeof(WCHAR) );
1140 else
1142 CPTABLEINFO *cptable = get_cptable( name->codepage );
1143 if (!cptable) return NULL;
1144 len = win32u_mbtowc( cptable, buffer, ARRAY_SIZE(buffer), name->bytes, name->length );
1147 buffer[ARRAY_SIZE(buffer) - 1] = 0;
1148 if (len == ARRAY_SIZE(buffer)) WARN("Truncated font name %s -> %s\n", debugstr_an(name->bytes, name->length), debugstr_w(buffer));
1149 else buffer[len] = 0;
1151 return wcsdup( buffer );
1154 struct unix_face
1156 FT_Face ft_face;
1157 BOOL scalable;
1158 UINT num_faces;
1159 WCHAR *family_name;
1160 WCHAR *second_name;
1161 WCHAR *style_name;
1162 WCHAR *full_name;
1163 DWORD ntm_flags;
1164 DWORD font_version;
1165 FONTSIGNATURE fs;
1166 struct bitmap_font_size size;
1169 static struct unix_face *unix_face_create( const char *unix_name, void *data_ptr, UINT data_size,
1170 UINT face_index, UINT flags )
1172 static const WCHAR space_w[] = {' ',0};
1174 const struct ttc_sfnt_v1 *ttc_sfnt_v1;
1175 const struct tt_name_v0 *tt_name_v0;
1176 struct unix_face *This;
1177 struct stat st;
1178 DWORD face_count;
1179 int fd, length;
1181 TRACE( "unix_name %s, face_index %u, data_ptr %p, data_size %u, flags %#x\n",
1182 unix_name, face_index, data_ptr, data_size, flags );
1184 if (unix_name)
1186 if ((fd = open( unix_name, O_RDONLY )) == -1) return NULL;
1187 if (fstat( fd, &st ) == -1)
1189 close( fd );
1190 return NULL;
1192 data_size = st.st_size;
1193 data_ptr = mmap( NULL, data_size, PROT_READ, MAP_PRIVATE, fd, 0 );
1194 close( fd );
1195 if (data_ptr == MAP_FAILED) return NULL;
1198 if (!(This = calloc( 1, sizeof(*This) ))) goto done;
1200 if (opentype_get_ttc_sfnt_v1( data_ptr, data_size, face_index, &face_count, &ttc_sfnt_v1 ) &&
1201 opentype_get_tt_name_v0( data_ptr, data_size, ttc_sfnt_v1, &tt_name_v0 ) &&
1202 opentype_get_properties( data_ptr, data_size, ttc_sfnt_v1, &This->font_version,
1203 &This->fs, &This->ntm_flags ))
1205 struct family_names_data family_names;
1206 struct face_name_data style_name;
1207 struct face_name_data full_name;
1208 LANGID primary_langid = system_lcid;
1210 This->scalable = TRUE;
1211 This->num_faces = face_count;
1213 memset( &family_names, 0, sizeof(family_names) );
1214 family_names.primary_langid = primary_langid;
1215 opentype_enum_family_names( tt_name_v0, search_family_names_callback, &family_names );
1216 This->family_name = decode_opentype_name( &family_names.family_name );
1217 This->second_name = decode_opentype_name( &family_names.second_name );
1219 memset( &style_name, 0, sizeof(style_name) );
1220 style_name.primary_langid = primary_langid;
1221 opentype_enum_style_names( tt_name_v0, search_face_name_callback, &style_name );
1222 This->style_name = decode_opentype_name( &style_name.face_name );
1224 memset( &full_name, 0, sizeof(full_name) );
1225 full_name.primary_langid = primary_langid;
1226 opentype_enum_full_names( tt_name_v0, search_face_name_callback, &full_name );
1227 This->full_name = decode_opentype_name( &full_name.face_name );
1229 TRACE( "parsed font names family_name %s, second_name %s, primary_seen %d, english_seen %d, "
1230 "full_name %s, style_name %s\n",
1231 debugstr_w(This->family_name), debugstr_w(This->second_name),
1232 family_names.primary_seen, family_names.english_seen,
1233 debugstr_w(This->full_name), debugstr_w(This->style_name) );
1235 if (!This->full_name && This->family_name && This->style_name)
1237 length = lstrlenW( This->family_name ) + lstrlenW( space_w ) + lstrlenW( This->style_name ) + 1;
1238 This->full_name = malloc( length * sizeof(WCHAR) );
1239 lstrcpyW( This->full_name, This->family_name );
1240 lstrcatW( This->full_name, space_w );
1241 lstrcatW( This->full_name, This->style_name );
1242 WARN( "full name not found, using %s instead\n", debugstr_w(This->full_name) );
1245 else if ((This->ft_face = new_ft_face( unix_name, data_ptr, data_size, face_index, flags & ADDFONT_ALLOW_BITMAP )))
1247 WARN( "unable to parse font, falling back to FreeType\n" );
1248 This->scalable = FT_IS_SCALABLE( This->ft_face );
1249 This->num_faces = This->ft_face->num_faces;
1251 This->family_name = ft_face_get_family_name( This->ft_face, system_lcid );
1252 This->second_name = ft_face_get_family_name( This->ft_face, MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT) );
1254 /* try to find another secondary name, preferring the lowest langids */
1255 if (!wcsicmp( This->family_name, This->second_name ))
1257 free( This->second_name );
1258 This->second_name = ft_face_get_family_name( This->ft_face, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL) );
1259 if (!wcsicmp( This->family_name, This->second_name ))
1261 free( This->second_name );
1262 This->second_name = NULL;
1266 This->style_name = ft_face_get_style_name( This->ft_face, system_lcid );
1267 This->full_name = ft_face_get_full_name( This->ft_face, system_lcid );
1269 This->ntm_flags = get_ntm_flags( This->ft_face );
1270 This->font_version = get_font_version( This->ft_face );
1271 if (!This->scalable) get_bitmap_size( This->ft_face, &This->size );
1272 get_fontsig( This->ft_face, &This->fs );
1274 else
1276 free( This );
1277 This = NULL;
1280 done:
1281 if (unix_name) munmap( data_ptr, data_size );
1282 return This;
1285 static void unix_face_destroy( struct unix_face *This )
1287 if (This->ft_face) pFT_Done_Face( This->ft_face );
1288 free( This->full_name );
1289 free( This->style_name );
1290 free( This->second_name );
1291 free( This->family_name );
1292 free( This );
1295 static int add_unix_face( const char *unix_name, const WCHAR *file, void *data_ptr, SIZE_T data_size,
1296 DWORD face_index, DWORD flags, DWORD *num_faces )
1298 struct unix_face *unix_face;
1299 int ret;
1301 if (num_faces) *num_faces = 0;
1303 if (!(unix_face = unix_face_create( unix_name, data_ptr, data_size, face_index, flags )))
1304 return 0;
1306 if (unix_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1308 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(unix_name));
1309 unix_face_destroy( unix_face );
1310 return 0;
1313 if (!HIWORD( flags )) flags |= ADDFONT_AA_FLAGS( default_aa_flags );
1315 ret = add_gdi_face( unix_face->family_name, unix_face->second_name, unix_face->style_name, unix_face->full_name,
1316 file, data_ptr, data_size, face_index, unix_face->fs, unix_face->ntm_flags,
1317 unix_face->font_version, flags, unix_face->scalable ? NULL : &unix_face->size );
1319 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1320 (int)unix_face->fs.fsCsb[0], (int)unix_face->fs.fsCsb[1],
1321 (int)unix_face->fs.fsUsb[0], (int)unix_face->fs.fsUsb[1],
1322 (int)unix_face->fs.fsUsb[2], (int)unix_face->fs.fsUsb[3]);
1324 if (num_faces) *num_faces = unix_face->num_faces;
1325 unix_face_destroy( unix_face );
1326 return ret;
1329 static WCHAR *get_dos_file_name( LPCSTR str )
1331 WCHAR *buffer;
1332 ULONG len = strlen(str) + 1;
1334 len += 8; /* \??\unix prefix */
1335 if (!(buffer = malloc( len * sizeof(WCHAR) ))) return NULL;
1336 if (wine_unix_to_nt_file_name( str, buffer, &len ))
1338 free( buffer );
1339 return NULL;
1341 return buffer;
1344 static char *get_unix_file_name( LPCWSTR path )
1346 UNICODE_STRING nt_name;
1347 OBJECT_ATTRIBUTES attr;
1348 NTSTATUS status;
1349 ULONG size = 256;
1350 char *buffer;
1352 nt_name.Buffer = (WCHAR *)path;
1353 nt_name.MaximumLength = nt_name.Length = lstrlenW( path ) * sizeof(WCHAR);
1354 InitializeObjectAttributes( &attr, &nt_name, 0, 0, NULL );
1355 for (;;)
1357 if (!(buffer = malloc( size ))) return NULL;
1358 status = wine_nt_to_unix_file_name( &attr, buffer, &size, FILE_OPEN_IF );
1359 if (status != STATUS_BUFFER_TOO_SMALL) break;
1360 free( buffer );
1362 if (status && status != STATUS_NO_SUCH_FILE)
1364 free( buffer );
1365 return NULL;
1367 return buffer;
1370 static INT AddFontToList(const WCHAR *dos_name, const char *unix_name, void *font_data_ptr,
1371 UINT font_data_size, UINT flags)
1373 DWORD face_index = 0, num_faces;
1374 INT ret = 0;
1375 WCHAR *filename = NULL;
1377 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1378 assert(unix_name || !(flags & ADDFONT_EXTERNAL_FONT));
1380 #ifdef __APPLE__
1381 if(unix_name)
1383 char **mac_list = expand_mac_font(unix_name);
1384 if(mac_list)
1386 BOOL had_one = FALSE;
1387 char **cursor;
1388 for(cursor = mac_list; *cursor; cursor++)
1390 had_one = TRUE;
1391 AddFontToList(NULL, *cursor, NULL, 0, flags);
1392 free( *cursor );
1394 free( mac_list );
1395 if(had_one)
1396 return 1;
1399 #endif /* __APPLE__ */
1401 if (!dos_name && unix_name) dos_name = filename = get_dos_file_name( unix_name );
1404 ret += add_unix_face( unix_name, dos_name, font_data_ptr, font_data_size, face_index, flags, &num_faces );
1405 while (num_faces > ++face_index);
1407 free( filename );
1408 return ret;
1411 /*************************************************************
1412 * freetype_add_font
1414 static INT freetype_add_font( const WCHAR *file, UINT flags )
1416 int ret = 0;
1417 char *unixname = get_unix_file_name( file );
1419 if (unixname)
1421 ret = AddFontToList( file, unixname, NULL, 0, flags );
1422 free( unixname );
1424 return ret;
1427 /*************************************************************
1428 * freetype_add_mem_font
1430 static INT freetype_add_mem_font( void *ptr, SIZE_T size, UINT flags )
1432 return AddFontToList( NULL, NULL, ptr, size, flags );
1435 #ifdef __ANDROID__
1436 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1438 DIR *dir;
1439 struct dirent *dent;
1440 char path[MAX_PATH];
1442 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1444 dir = opendir(dirname);
1445 if(!dir) {
1446 WARN("Can't open directory %s\n", debugstr_a(dirname));
1447 return FALSE;
1449 while((dent = readdir(dir)) != NULL) {
1450 struct stat statbuf;
1452 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1453 continue;
1455 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1457 sprintf(path, "%s/%s", dirname, dent->d_name);
1459 if(stat(path, &statbuf) == -1)
1461 WARN("Can't stat %s\n", debugstr_a(path));
1462 continue;
1464 if(S_ISDIR(statbuf.st_mode))
1465 ReadFontDir(path, external_fonts);
1466 else
1468 DWORD addfont_flags = 0;
1469 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
1470 AddFontToList(NULL, path, NULL, 0, addfont_flags);
1473 closedir(dir);
1474 return TRUE;
1476 #endif
1478 #ifdef SONAME_LIBFONTCONFIG
1480 static BOOL fontconfig_enabled;
1481 static FcPattern *pattern_serif;
1482 static FcPattern *pattern_fixed;
1483 static FcPattern *pattern_sans;
1485 static UINT parse_aa_pattern( FcPattern *pattern )
1487 FcBool antialias;
1488 int rgba;
1489 UINT aa_flags = 0;
1491 if (pFcPatternGetBool( pattern, FC_ANTIALIAS, 0, &antialias ) == FcResultMatch)
1492 aa_flags = antialias ? GGO_GRAY4_BITMAP : GGO_BITMAP;
1494 if (pFcPatternGetInteger( pattern, FC_RGBA, 0, &rgba ) == FcResultMatch)
1496 switch (rgba)
1498 case FC_RGBA_RGB: aa_flags = WINE_GGO_HRGB_BITMAP; break;
1499 case FC_RGBA_BGR: aa_flags = WINE_GGO_HBGR_BITMAP; break;
1500 case FC_RGBA_VRGB: aa_flags = WINE_GGO_VRGB_BITMAP; break;
1501 case FC_RGBA_VBGR: aa_flags = WINE_GGO_VBGR_BITMAP; break;
1502 case FC_RGBA_NONE: aa_flags = aa_flags ? aa_flags : GGO_GRAY4_BITMAP; break;
1505 return aa_flags;
1508 static FcPattern *create_family_pattern( const char *name, FcPattern **cached )
1510 FcPattern *ret = NULL, *tmp, *pattern;
1511 FcResult result;
1512 if (*cached) return *cached;
1513 pattern = pFcPatternCreate();
1514 pFcPatternAddString( pattern, FC_FAMILY, (const FcChar8 *)name );
1515 pFcPatternAddString( pattern, FC_NAMELANG, (const FcChar8 *)"en-us" );
1516 pFcPatternAddString( pattern, FC_PRGNAME, (const FcChar8 *)"wine" );
1517 pFcConfigSubstitute( NULL, pattern, FcMatchPattern );
1518 pFcDefaultSubstitute( pattern );
1519 tmp = pFcFontMatch( NULL, pattern, &result );
1520 pFcPatternDestroy( pattern );
1521 if (result != FcResultMatch) pFcPatternDestroy( tmp );
1522 else if ((ret = InterlockedCompareExchangePointer( (void **)cached, tmp, NULL ))) pFcPatternDestroy( tmp );
1523 else ret = tmp;
1524 return ret;
1527 static void fontconfig_add_font( FcPattern *pattern, UINT flags )
1529 const char *unix_name, *format;
1530 WCHAR *dos_name;
1531 FcBool scalable;
1532 DWORD aa_flags;
1533 int face_index;
1535 TRACE( "(%p %#x)\n", pattern, flags );
1537 if (pFcPatternGetString( pattern, FC_FILE, 0, (FcChar8 **)&unix_name ) != FcResultMatch)
1538 return;
1540 if (pFcPatternGetBool( pattern, FC_SCALABLE, 0, &scalable ) != FcResultMatch)
1541 scalable = FALSE;
1543 if (pFcPatternGetString( pattern, FC_FONTFORMAT, 0, (FcChar8 **)&format ) != FcResultMatch)
1545 TRACE( "ignoring unknown font format %s\n", debugstr_a(unix_name) );
1546 return;
1549 if (!strcmp( format, "Type 1" ))
1551 TRACE( "ignoring Type 1 font %s\n", debugstr_a(unix_name) );
1552 return;
1555 if (!scalable && !(flags & ADDFONT_ALLOW_BITMAP))
1557 TRACE( "ignoring non-scalable font %s\n", debugstr_a(unix_name) );
1558 return;
1561 if (!(aa_flags = parse_aa_pattern( pattern ))) aa_flags = default_aa_flags;
1562 flags |= ADDFONT_AA_FLAGS(aa_flags);
1564 if (pFcPatternGetInteger( pattern, FC_INDEX, 0, &face_index ) != FcResultMatch)
1565 face_index = 0;
1567 dos_name = get_dos_file_name( unix_name );
1568 add_unix_face( unix_name, dos_name, NULL, 0, face_index, flags, NULL );
1569 free( dos_name );
1572 static void init_fontconfig(void)
1574 void *fc_handle = dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW);
1576 if (!fc_handle)
1578 TRACE("Wine cannot find the fontconfig library (%s).\n", SONAME_LIBFONTCONFIG);
1579 return;
1582 #define LOAD_FUNCPTR(f) if((p##f = dlsym(fc_handle, #f)) == NULL){WARN("Can't find symbol %s\n", #f); return;}
1583 LOAD_FUNCPTR(FcConfigSubstitute);
1584 LOAD_FUNCPTR(FcDefaultSubstitute);
1585 LOAD_FUNCPTR(FcFontList);
1586 LOAD_FUNCPTR(FcFontMatch);
1587 LOAD_FUNCPTR(FcFontSetDestroy);
1588 LOAD_FUNCPTR(FcInit);
1589 LOAD_FUNCPTR(FcPatternAddString);
1590 LOAD_FUNCPTR(FcPatternCreate);
1591 LOAD_FUNCPTR(FcPatternDestroy);
1592 LOAD_FUNCPTR(FcPatternGetBool);
1593 LOAD_FUNCPTR(FcPatternGetInteger);
1594 LOAD_FUNCPTR(FcPatternGetString);
1595 LOAD_FUNCPTR(FcConfigGetFontDirs);
1596 LOAD_FUNCPTR(FcConfigGetCurrent);
1597 LOAD_FUNCPTR(FcCacheCopySet);
1598 LOAD_FUNCPTR(FcCacheNumSubdir);
1599 LOAD_FUNCPTR(FcCacheSubdir);
1600 LOAD_FUNCPTR(FcDirCacheRead);
1601 LOAD_FUNCPTR(FcDirCacheUnload);
1602 LOAD_FUNCPTR(FcStrListCreate);
1603 LOAD_FUNCPTR(FcStrListDone);
1604 LOAD_FUNCPTR(FcStrListNext);
1605 LOAD_FUNCPTR(FcStrSetAdd);
1606 LOAD_FUNCPTR(FcStrSetCreate);
1607 LOAD_FUNCPTR(FcStrSetDestroy);
1608 LOAD_FUNCPTR(FcStrSetMember);
1609 #undef LOAD_FUNCPTR
1611 if (pFcInit())
1613 FcPattern *pattern = pFcPatternCreate();
1614 pFcConfigSubstitute( NULL, pattern, FcMatchFont );
1615 default_aa_flags = parse_aa_pattern( pattern );
1616 pFcPatternDestroy( pattern );
1618 if (!default_aa_flags)
1620 FcPattern *pattern = pFcPatternCreate();
1621 pFcConfigSubstitute( NULL, pattern, FcMatchPattern );
1622 default_aa_flags = parse_aa_pattern( pattern );
1623 pFcPatternDestroy( pattern );
1626 TRACE( "enabled, default flags = %x\n", default_aa_flags );
1627 fontconfig_enabled = TRUE;
1631 static void fontconfig_add_fonts_from_dir_list( FcConfig *config, FcStrList *dir_list, FcStrSet *done_set, UINT flags )
1633 const FcChar8 *dir;
1634 FcFontSet *font_set = NULL;
1635 FcStrList *subdir_list = NULL;
1636 FcStrSet *subdir_set = NULL;
1637 FcCache *cache = NULL;
1638 int i;
1640 TRACE( "(%p %p %p %#x)\n", config, dir_list, done_set, flags );
1642 while ((dir = pFcStrListNext( dir_list )))
1644 if (pFcStrSetMember( done_set, dir )) continue;
1646 TRACE( "adding fonts from %s\n", dir );
1647 if (!(cache = pFcDirCacheRead( dir, FcFalse, config ))) continue;
1649 if (!(font_set = pFcCacheCopySet( cache ))) goto done;
1650 for (i = 0; i < font_set->nfont; i++)
1651 fontconfig_add_font( font_set->fonts[i], flags );
1652 pFcFontSetDestroy( font_set );
1653 font_set = NULL;
1655 if (!(subdir_set = pFcStrSetCreate())) goto done;
1656 for (i = 0; i < pFcCacheNumSubdir( cache ); i++)
1657 pFcStrSetAdd( subdir_set, pFcCacheSubdir( cache, i ) );
1658 pFcDirCacheUnload( cache );
1659 cache = NULL;
1661 if (!(subdir_list = pFcStrListCreate( subdir_set ))) goto done;
1662 pFcStrSetDestroy( subdir_set );
1663 subdir_set = NULL;
1665 pFcStrSetAdd( done_set, dir );
1666 fontconfig_add_fonts_from_dir_list( config, subdir_list, done_set, flags );
1667 pFcStrListDone( subdir_list );
1668 subdir_list = NULL;
1671 done:
1672 if (subdir_set) pFcStrSetDestroy( subdir_set );
1673 if (cache) pFcDirCacheUnload( cache );
1676 static void load_fontconfig_fonts( void )
1678 FcStrList *dir_list = NULL;
1679 FcStrSet *done_set = NULL;
1680 FcConfig *config;
1682 if (!fontconfig_enabled) return;
1683 if (!(config = pFcConfigGetCurrent())) goto done;
1684 if (!(done_set = pFcStrSetCreate())) goto done;
1685 if (!(dir_list = pFcConfigGetFontDirs( config ))) goto done;
1687 fontconfig_add_fonts_from_dir_list( config, dir_list, done_set, ADDFONT_EXTERNAL_FONT );
1689 done:
1690 if (dir_list) pFcStrListDone( dir_list );
1691 if (done_set) pFcStrSetDestroy( done_set );
1694 #elif defined(__APPLE__)
1696 static void load_mac_font_callback(const void *value, void *context)
1698 CFStringRef pathStr = value;
1699 CFIndex len;
1700 char* path;
1702 len = CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr);
1703 path = malloc( len );
1704 if (path && CFStringGetFileSystemRepresentation(pathStr, path, len))
1706 TRACE("font file %s\n", path);
1707 AddFontToList(NULL, path, NULL, 0, ADDFONT_EXTERNAL_FONT);
1709 free( path );
1712 static void load_mac_fonts(void)
1714 CFStringRef removeDupesKey;
1715 CFBooleanRef removeDupesValue;
1716 CFDictionaryRef options;
1717 CTFontCollectionRef col;
1718 CFArrayRef descs;
1719 CFMutableSetRef paths;
1720 CFIndex i;
1722 removeDupesKey = kCTFontCollectionRemoveDuplicatesOption;
1723 removeDupesValue = kCFBooleanTrue;
1724 options = CFDictionaryCreate(NULL, (const void**)&removeDupesKey, (const void**)&removeDupesValue, 1,
1725 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1726 col = CTFontCollectionCreateFromAvailableFonts(options);
1727 if (options) CFRelease(options);
1728 if (!col)
1730 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
1731 return;
1734 descs = CTFontCollectionCreateMatchingFontDescriptors(col);
1735 CFRelease(col);
1736 if (!descs)
1738 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
1739 return;
1742 paths = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
1743 if (!paths)
1745 WARN("CFSetCreateMutable failed\n");
1746 CFRelease(descs);
1747 return;
1750 for (i = 0; i < CFArrayGetCount(descs); i++)
1752 CTFontDescriptorRef desc;
1753 CFURLRef url;
1754 CFStringRef ext;
1755 CFStringRef path;
1757 desc = CFArrayGetValueAtIndex(descs, i);
1758 url = CTFontDescriptorCopyAttribute(desc, kCTFontURLAttribute);
1759 if (!url) continue;
1761 ext = CFURLCopyPathExtension(url);
1762 if (ext)
1764 BOOL skip = (CFStringCompare(ext, CFSTR("pfa"), kCFCompareCaseInsensitive) == kCFCompareEqualTo ||
1765 CFStringCompare(ext, CFSTR("pfb"), kCFCompareCaseInsensitive) == kCFCompareEqualTo);
1766 CFRelease(ext);
1767 if (skip)
1769 CFRelease(url);
1770 continue;
1774 path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
1775 CFRelease(url);
1776 if (!path) continue;
1778 CFSetAddValue(paths, path);
1779 CFRelease(path);
1782 CFRelease(descs);
1784 CFSetApplyFunction(paths, load_mac_font_callback, NULL);
1785 CFRelease(paths);
1788 #endif
1791 static BOOL init_freetype(void)
1793 ft_handle = dlopen(SONAME_LIBFREETYPE, RTLD_NOW);
1794 if(!ft_handle) {
1795 WINE_MESSAGE(
1796 "Wine cannot find the FreeType font library. To enable Wine to\n"
1797 "use TrueType fonts please install a version of FreeType greater than\n"
1798 "or equal to 2.0.5.\n"
1799 "http://www.freetype.org\n");
1800 return FALSE;
1803 #define LOAD_FUNCPTR(f) if((p##f = dlsym(ft_handle, #f)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
1805 LOAD_FUNCPTR(FT_Done_Face)
1806 LOAD_FUNCPTR(FT_Get_Char_Index)
1807 LOAD_FUNCPTR(FT_Get_First_Char)
1808 LOAD_FUNCPTR(FT_Get_Next_Char)
1809 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
1810 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
1811 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
1812 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
1813 LOAD_FUNCPTR(FT_Init_FreeType)
1814 LOAD_FUNCPTR(FT_Library_Version)
1815 LOAD_FUNCPTR(FT_Load_Glyph)
1816 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
1817 LOAD_FUNCPTR(FT_Matrix_Multiply)
1818 LOAD_FUNCPTR(FT_MulDiv)
1819 #ifndef FT_MULFIX_INLINED
1820 LOAD_FUNCPTR(FT_MulFix)
1821 #endif
1822 LOAD_FUNCPTR(FT_New_Face)
1823 LOAD_FUNCPTR(FT_New_Memory_Face)
1824 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
1825 LOAD_FUNCPTR(FT_Outline_Get_CBox)
1826 LOAD_FUNCPTR(FT_Outline_Transform)
1827 LOAD_FUNCPTR(FT_Outline_Translate)
1828 LOAD_FUNCPTR(FT_Render_Glyph)
1829 LOAD_FUNCPTR(FT_Set_Charmap)
1830 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
1831 LOAD_FUNCPTR(FT_Vector_Length)
1832 LOAD_FUNCPTR(FT_Vector_Transform)
1833 LOAD_FUNCPTR(FT_Vector_Unit)
1834 #undef LOAD_FUNCPTR
1835 /* Don't warn if these ones are missing */
1836 pFT_Outline_Embolden = dlsym(ft_handle, "FT_Outline_Embolden");
1837 pFT_Get_TrueType_Engine_Type = dlsym(ft_handle, "FT_Get_TrueType_Engine_Type");
1838 #ifdef FT_LCD_FILTER_H
1839 pFT_Library_SetLcdFilter = dlsym(ft_handle, "FT_Library_SetLcdFilter");
1840 #endif
1841 pFT_Property_Set = dlsym(ft_handle, "FT_Property_Set");
1843 if(pFT_Init_FreeType(&library) != 0) {
1844 ERR("Can't init FreeType library\n");
1845 dlclose(ft_handle);
1846 ft_handle = NULL;
1847 return FALSE;
1849 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
1851 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
1852 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
1853 ((FT_Version.minor << 8) & 0x00ff00) |
1854 ((FT_Version.patch ) & 0x0000ff);
1856 /* In FreeType < 2.8.1 v40's FT_LOAD_TARGET_MONO has broken advance widths. */
1857 if (pFT_Property_Set && FT_SimpleVersion < FT_VERSION_VALUE(2, 8, 1))
1859 FT_UInt interpreter_version = 35;
1860 pFT_Property_Set( library, "truetype", "interpreter-version", &interpreter_version );
1863 #ifdef FT_LCD_FILTER_H
1864 if (pFT_Library_SetLcdFilter)
1865 pFT_Library_SetLcdFilter( library, FT_LCD_FILTER_DEFAULT );
1866 #endif
1868 return TRUE;
1870 sym_not_found:
1871 WINE_MESSAGE(
1872 "Wine cannot find certain functions that it needs inside the FreeType\n"
1873 "font library. To enable Wine to use TrueType fonts please upgrade\n"
1874 "FreeType to at least version 2.1.4.\n"
1875 "http://www.freetype.org\n");
1876 dlclose(ft_handle);
1877 ft_handle = NULL;
1878 return FALSE;
1881 /*************************************************************
1882 * freetype_load_fonts
1884 static void freetype_load_fonts(void)
1886 #ifdef SONAME_LIBFONTCONFIG
1887 load_fontconfig_fonts();
1888 #elif defined(__APPLE__)
1889 load_mac_fonts();
1890 #elif defined(__ANDROID__)
1891 ReadFontDir("/system/fonts", TRUE);
1892 #endif
1895 /* Some fonts have large usWinDescent values, as a result of storing signed short
1896 in unsigned field. That's probably caused by sTypoDescent vs usWinDescent confusion in
1897 some font generation tools. */
1898 static inline USHORT get_fixed_windescent(USHORT windescent)
1900 return abs((SHORT)windescent);
1903 static int calc_ppem_for_height(FT_Face ft_face, int height)
1905 TT_OS2 *pOS2;
1906 TT_HoriHeader *pHori;
1908 int ppem;
1909 const int MAX_PPEM = (1 << 16) - 1;
1911 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1912 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1914 if(height == 0) height = 16;
1916 /* Calc. height of EM square:
1918 * For +ve lfHeight we have
1919 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
1920 * Re-arranging gives:
1921 * ppem = units_per_em * lfheight / (winAscent + winDescent)
1923 * For -ve lfHeight we have
1924 * |lfHeight| = ppem
1925 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
1926 * with il = winAscent + winDescent - units_per_em]
1930 if(height > 0) {
1931 USHORT windescent = get_fixed_windescent(pOS2->usWinDescent);
1932 int units;
1934 if(pOS2->usWinAscent + windescent == 0)
1935 units = pHori->Ascender - pHori->Descender;
1936 else
1937 units = pOS2->usWinAscent + windescent;
1938 ppem = pFT_MulDiv(ft_face->units_per_EM, height, units);
1940 /* If rounding ends up getting a font exceeding height, choose a smaller ppem */
1941 if(ppem > 1 && pFT_MulDiv(units, ppem, ft_face->units_per_EM) > height)
1942 --ppem;
1944 if(ppem > MAX_PPEM) {
1945 WARN("Ignoring too large height %d, ppem %d\n", height, ppem);
1946 ppem = 1;
1949 else if(height >= -MAX_PPEM)
1950 ppem = -height;
1951 else {
1952 WARN("Ignoring too large height %d\n", height);
1953 ppem = 1;
1956 return ppem;
1959 static struct font_mapping *map_font_file( const char *name )
1961 struct font_mapping *mapping;
1962 struct stat st;
1963 int fd;
1965 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
1966 if (fstat( fd, &st ) == -1) goto error;
1968 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
1970 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
1972 mapping->refcount++;
1973 close( fd );
1974 return mapping;
1977 if (!(mapping = malloc( sizeof(*mapping) )))
1978 goto error;
1980 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
1981 close( fd );
1983 if (mapping->data == MAP_FAILED)
1985 free( mapping );
1986 return NULL;
1988 mapping->refcount = 1;
1989 mapping->dev = st.st_dev;
1990 mapping->ino = st.st_ino;
1991 mapping->size = st.st_size;
1992 list_add_tail( &mappings_list, &mapping->entry );
1993 return mapping;
1995 error:
1996 close( fd );
1997 return NULL;
2000 static void unmap_font_file( struct font_mapping *mapping )
2002 if (!--mapping->refcount)
2004 list_remove( &mapping->entry );
2005 munmap( mapping->data, mapping->size );
2006 free( mapping );
2010 static int load_VDMX(struct gdi_font *font, int height);
2012 /*************************************************************
2013 * freetype_destroy_font
2015 static void freetype_destroy_font( struct gdi_font *font )
2017 struct font_private_data *data = font->private;
2019 if (data->ft_face) pFT_Done_Face( data->ft_face );
2020 if (data->mapping) unmap_font_file( data->mapping );
2021 free( data );
2024 /*************************************************************
2025 * freetype_get_font_data
2027 static UINT freetype_get_font_data( struct gdi_font *font, UINT table, UINT offset,
2028 void *buf, UINT cbData)
2030 FT_Face ft_face = get_ft_face( font );
2031 FT_ULong len;
2032 FT_Error err;
2034 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
2036 if(!buf)
2037 len = 0;
2038 else
2039 len = cbData;
2041 /* if font is a member of TTC, 'ttcf' tag allows reading from beginning of TTC file,
2042 0 tag means to read from start of collection member data. */
2043 if (font->ttc_item_offset)
2045 if (table == MS_TTCF_TAG)
2046 table = 0;
2047 else if (table == 0)
2048 offset += font->ttc_item_offset;
2051 /* make sure value of len is the value freetype says it needs */
2052 if (buf && len)
2054 FT_ULong needed = 0;
2055 err = pFT_Load_Sfnt_Table(ft_face, RtlUlongByteSwap(table), offset, NULL, &needed);
2056 if( !err && needed < len) len = needed;
2058 err = pFT_Load_Sfnt_Table(ft_face, RtlUlongByteSwap(table), offset, buf, &len);
2059 if (err)
2061 TRACE("Can't find table %s\n", debugstr_an((char*)&table, 4));
2062 return GDI_ERROR;
2064 return len;
2067 /*************************************************************
2068 * load_VDMX
2070 * load the vdmx entry for the specified height
2075 typedef struct {
2076 WORD version;
2077 WORD numRecs;
2078 WORD numRatios;
2079 } VDMX_Header;
2081 typedef struct {
2082 BYTE bCharSet;
2083 BYTE xRatio;
2084 BYTE yStartRatio;
2085 BYTE yEndRatio;
2086 } Ratios;
2088 typedef struct {
2089 WORD recs;
2090 BYTE startsz;
2091 BYTE endsz;
2092 } VDMX_group;
2094 typedef struct {
2095 WORD yPelHeight;
2096 WORD yMax;
2097 WORD yMin;
2098 } VDMX_vTable;
2100 static int load_VDMX(struct gdi_font *font, int height)
2102 VDMX_Header hdr;
2103 VDMX_group group;
2104 BYTE devXRatio, devYRatio;
2105 USHORT numRecs, numRatios;
2106 UINT result, offset = -1;
2107 int i, ppem = 0;
2109 result = freetype_get_font_data(font, MS_VDMX_TAG, 0, &hdr, sizeof(hdr));
2111 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2112 return ppem;
2114 /* FIXME: need the real device aspect ratio */
2115 devXRatio = 1;
2116 devYRatio = 1;
2118 numRecs = GET_BE_WORD(hdr.numRecs);
2119 numRatios = GET_BE_WORD(hdr.numRatios);
2121 TRACE("version = %d numRecs = %d numRatios = %d\n", GET_BE_WORD(hdr.version), numRecs, numRatios);
2122 for(i = 0; i < numRatios; i++) {
2123 Ratios ratio;
2125 offset = sizeof(hdr) + (i * sizeof(Ratios));
2126 freetype_get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2127 offset = -1;
2129 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2131 if (!ratio.bCharSet) continue;
2133 if((ratio.xRatio == 0 &&
2134 ratio.yStartRatio == 0 &&
2135 ratio.yEndRatio == 0) ||
2136 (devXRatio == ratio.xRatio &&
2137 devYRatio >= ratio.yStartRatio &&
2138 devYRatio <= ratio.yEndRatio))
2140 WORD group_offset;
2142 offset = sizeof(hdr) + numRatios * sizeof(ratio) + i * sizeof(group_offset);
2143 freetype_get_font_data(font, MS_VDMX_TAG, offset, &group_offset, sizeof(group_offset));
2144 offset = GET_BE_WORD(group_offset);
2145 break;
2149 if(offset == -1) return 0;
2151 if(freetype_get_font_data(font, MS_VDMX_TAG, offset, &group, sizeof(group)) != GDI_ERROR) {
2152 USHORT recs;
2153 BYTE startsz, endsz;
2154 WORD *vTable;
2156 recs = GET_BE_WORD(group.recs);
2157 startsz = group.startsz;
2158 endsz = group.endsz;
2160 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
2162 vTable = malloc( recs * sizeof(VDMX_vTable) );
2163 result = freetype_get_font_data(font, MS_VDMX_TAG, offset + sizeof(group), vTable, recs * sizeof(VDMX_vTable));
2164 if(result == GDI_ERROR) {
2165 FIXME("Failed to retrieve vTable\n");
2166 goto end;
2169 if(height > 0) {
2170 for(i = 0; i < recs; i++) {
2171 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2172 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2173 ppem = GET_BE_WORD(vTable[i * 3]);
2175 if(yMax + -yMin == height) {
2176 font->yMax = yMax;
2177 font->yMin = yMin;
2178 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2179 break;
2181 if(yMax + -yMin > height) {
2182 if(--i < 0) {
2183 ppem = 0;
2184 goto end; /* failed */
2186 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2187 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2188 ppem = GET_BE_WORD(vTable[i * 3]);
2189 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2190 break;
2193 if(!font->yMax) {
2194 ppem = 0;
2195 TRACE("ppem not found for height %d\n", height);
2197 } else {
2198 ppem = -height;
2199 if(ppem < startsz || ppem > endsz)
2201 ppem = 0;
2202 goto end;
2205 for(i = 0; i < recs; i++) {
2206 USHORT yPelHeight;
2207 yPelHeight = GET_BE_WORD(vTable[i * 3]);
2209 if(yPelHeight > ppem)
2211 ppem = 0;
2212 break; /* failed */
2215 if(yPelHeight == ppem) {
2216 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2217 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2218 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
2219 break;
2223 end:
2224 free( vTable );
2227 return ppem;
2230 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
2232 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
2233 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
2234 FT_Int i;
2236 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
2238 for (i = 0; i < ft_face->num_charmaps; i++)
2240 if (ft_face->charmaps[i]->encoding == encoding)
2242 TRACE("found cmap with platform_id %u, encoding_id %u\n",
2243 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
2245 switch (ft_face->charmaps[i]->platform_id)
2247 default:
2248 cmap_def = ft_face->charmaps[i];
2249 break;
2250 case 0: /* Apple Unicode */
2251 cmap0 = ft_face->charmaps[i];
2252 break;
2253 case 1: /* Macintosh */
2254 cmap1 = ft_face->charmaps[i];
2255 break;
2256 case 2: /* ISO */
2257 cmap2 = ft_face->charmaps[i];
2258 break;
2259 case 3: /* Microsoft */
2260 cmap3 = ft_face->charmaps[i];
2261 break;
2265 if (cmap3) /* prefer Microsoft cmap table */
2266 ft_err = pFT_Set_Charmap(ft_face, cmap3);
2267 else if (cmap1)
2268 ft_err = pFT_Set_Charmap(ft_face, cmap1);
2269 else if (cmap2)
2270 ft_err = pFT_Set_Charmap(ft_face, cmap2);
2271 else if (cmap0)
2272 ft_err = pFT_Set_Charmap(ft_face, cmap0);
2273 else if (cmap_def)
2274 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
2277 return ft_err == FT_Err_Ok;
2281 static FT_Encoding pick_charmap( FT_Face face, int charset )
2283 static const FT_Encoding regular_order[] = { FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, FT_ENCODING_MS_SYMBOL, 0 };
2284 static const FT_Encoding symbol_order[] = { FT_ENCODING_MS_SYMBOL, FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, 0 };
2285 const FT_Encoding *encs = regular_order;
2287 if (charset == SYMBOL_CHARSET) encs = symbol_order;
2289 while (*encs != 0)
2291 if (select_charmap( face, *encs )) break;
2292 encs++;
2295 if (!face->charmap && face->num_charmaps)
2297 if (!pFT_Set_Charmap(face, face->charmaps[0]))
2298 return face->charmap->encoding;
2301 return *encs;
2304 static BOOL get_gasp_flags( struct gdi_font *font, WORD *flags )
2306 FT_Face ft_face = get_ft_face( font );
2307 UINT size;
2308 WORD buf[16]; /* Enough for seven ranges before we need to alloc */
2309 WORD *alloced = NULL, *ptr = buf;
2310 WORD num_recs, version;
2311 BOOL ret = FALSE;
2313 *flags = 0;
2314 size = freetype_get_font_data( font, MS_GASP_TAG, 0, NULL, 0 );
2315 if (size == GDI_ERROR) return FALSE;
2316 if (size < 4 * sizeof(WORD)) return FALSE;
2317 if (size > sizeof(buf))
2319 ptr = alloced = malloc( size );
2320 if (!ptr) return FALSE;
2323 freetype_get_font_data( font, MS_GASP_TAG, 0, ptr, size );
2325 version = GET_BE_WORD( *ptr++ );
2326 num_recs = GET_BE_WORD( *ptr++ );
2328 if (version > 1 || size < (num_recs * 2 + 2) * sizeof(WORD))
2330 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version, size, num_recs );
2331 goto done;
2334 while (num_recs--)
2336 *flags = GET_BE_WORD( *(ptr + 1) );
2337 if (ft_face->size->metrics.y_ppem <= GET_BE_WORD( *ptr )) break;
2338 ptr += 2;
2340 TRACE( "got flags %04x for ppem %d\n", *flags, ft_face->size->metrics.y_ppem );
2341 ret = TRUE;
2343 done:
2344 free( alloced );
2345 return ret;
2348 /*************************************************************
2349 * fontconfig_enum_family_fallbacks
2351 static BOOL fontconfig_enum_family_fallbacks( UINT pitch_and_family, int index,
2352 WCHAR buffer[LF_FACESIZE] )
2354 #ifdef SONAME_LIBFONTCONFIG
2355 FcPattern *pat;
2356 char *str;
2357 DWORD len;
2359 if ((pitch_and_family & FIXED_PITCH) || (pitch_and_family & 0xf0) == FF_MODERN) pat = create_family_pattern( "monospace", &pattern_fixed );
2360 else if ((pitch_and_family & 0xf0) == FF_ROMAN) pat = create_family_pattern( "serif", &pattern_serif );
2361 else pat = create_family_pattern( "sans", &pattern_sans );
2363 if (!pat) return FALSE;
2364 if (pFcPatternGetString( pat, FC_FAMILY, index, (FcChar8 **)&str ) != FcResultMatch) return FALSE;
2365 RtlUTF8ToUnicodeN( buffer, (LF_FACESIZE - 1) * sizeof(WCHAR), &len, str, strlen(str) );
2366 buffer[len / sizeof(WCHAR)] = 0;
2367 return TRUE;
2368 #endif
2369 return FALSE;
2372 static DWORD get_ttc_offset( FT_Face ft_face, UINT face_index )
2374 FT_ULong len;
2375 DWORD header, offset;
2377 /* see if it's a TTC */
2378 len = sizeof(header);
2379 if (pFT_Load_Sfnt_Table( ft_face, 0, 0, (void *)&header, &len )) return 0;
2380 if (header != MS_TTCF_TAG) return 0;
2382 len = sizeof(offset);
2383 if (pFT_Load_Sfnt_Table( ft_face, 0, (3 + face_index) * sizeof(DWORD), (void *)&offset, &len ))
2384 return 0;
2386 return GET_BE_DWORD( offset );
2389 /*************************************************************
2390 * freetype_load_font
2392 static BOOL freetype_load_font( struct gdi_font *font )
2394 struct font_private_data *data;
2395 INT width = 0, height;
2396 FT_Face ft_face;
2397 void *data_ptr;
2398 SIZE_T data_size;
2400 if (!(data = calloc( 1, sizeof(*data) ))) return FALSE;
2401 font->private = data;
2403 if (font->file[0])
2405 char *filename = get_unix_file_name( font->file );
2406 data->mapping = map_font_file( filename );
2407 free( filename );
2408 if (!data->mapping)
2410 WARN("failed to map %s\n", debugstr_w(font->file));
2411 return FALSE;
2413 data_ptr = data->mapping->data;
2414 data_size = data->mapping->size;
2416 else
2418 data_ptr = font->data_ptr;
2419 data_size = font->data_size;
2422 if (pFT_New_Memory_Face( library, data_ptr, data_size, font->face_index, &ft_face )) return FALSE;
2424 data->ft_face = ft_face;
2425 font->scalable = FT_IS_SCALABLE( ft_face );
2426 if (!font->fs.fsCsb[0]) get_fontsig( ft_face, &font->fs );
2427 if (!font->ntmFlags) font->ntmFlags = get_ntm_flags( ft_face );
2428 if (!font->aa_flags) font->aa_flags = ADDFONT_AA_FLAGS( default_aa_flags );
2429 if (!font->otm.otmpFamilyName)
2431 font->otm.otmpFamilyName = (char *)ft_face_get_family_name( ft_face, system_lcid );
2432 font->otm.otmpStyleName = (char *)ft_face_get_style_name( ft_face, system_lcid );
2433 font->otm.otmpFaceName = (char *)ft_face_get_full_name( ft_face, system_lcid );
2436 if (font->scalable)
2438 /* load the VDMX table if we have one */
2439 font->ppem = load_VDMX( font, font->lf.lfHeight );
2440 if (font->ppem == 0) font->ppem = calc_ppem_for_height( ft_face, font->lf.lfHeight );
2441 TRACE( "height %d => ppem %d\n", (int)font->lf.lfHeight, font->ppem );
2442 height = font->ppem;
2443 font->ttc_item_offset = get_ttc_offset( ft_face, font->face_index );
2444 font->otm.otmEMSquare = ft_face->units_per_EM;
2446 else
2448 struct bitmap_font_size size;
2450 get_bitmap_size( ft_face, &size );
2451 width = size.x_ppem >> 6;
2452 height = size.y_ppem >> 6;
2453 font->ppem = height;
2456 pFT_Set_Pixel_Sizes( ft_face, width, height );
2457 pick_charmap( ft_face, font->charset );
2458 return TRUE;
2462 /*************************************************************
2463 * freetype_get_aa_flags
2465 static UINT freetype_get_aa_flags( struct gdi_font *font, UINT aa_flags, BOOL antialias_fakes )
2467 /* fixup the antialiasing flags for that font */
2468 switch (aa_flags)
2470 case WINE_GGO_HRGB_BITMAP:
2471 case WINE_GGO_HBGR_BITMAP:
2472 case WINE_GGO_VRGB_BITMAP:
2473 case WINE_GGO_VBGR_BITMAP:
2474 if (is_subpixel_rendering_enabled()) break;
2475 aa_flags = GGO_GRAY4_BITMAP;
2476 /* fall through */
2477 case GGO_GRAY2_BITMAP:
2478 case GGO_GRAY4_BITMAP:
2479 case GGO_GRAY8_BITMAP:
2480 case WINE_GGO_GRAY16_BITMAP:
2481 if ((!antialias_fakes || (!font->fake_bold && !font->fake_italic)) && is_hinting_enabled())
2483 WORD gasp_flags;
2484 if (get_gasp_flags( font, &gasp_flags ) && !(gasp_flags & GASP_DOGRAY))
2486 TRACE( "font %s %d aa disabled by GASP\n",
2487 debugstr_w(font->lf.lfFaceName), (int)font->lf.lfHeight );
2488 aa_flags = GGO_BITMAP;
2492 return aa_flags;
2495 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
2497 pt->x.value = vec->x >> 6;
2498 pt->x.fract = (vec->x & 0x3f) << 10;
2499 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
2500 pt->y.value = vec->y >> 6;
2501 pt->y.fract = (vec->y & 0x3f) << 10;
2502 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
2505 static FT_UInt get_glyph_index_symbol( struct gdi_font *font, UINT glyph )
2507 FT_Face ft_face = get_ft_face( font );
2508 FT_UInt ret;
2510 if (glyph < 0x100) glyph += 0xf000;
2511 /* there are a number of old pre-Unicode "broken" TTFs, which
2512 do have symbols at U+00XX instead of U+f0XX */
2513 if (!(ret = pFT_Get_Char_Index(ft_face, glyph)))
2514 ret = pFT_Get_Char_Index(ft_face, glyph - 0xf000);
2516 return ret;
2519 /*************************************************************
2520 * freetype_get_glyph_index
2522 static BOOL freetype_get_glyph_index( struct gdi_font *font, UINT *glyph, BOOL use_encoding )
2524 FT_Face ft_face = get_ft_face( font );
2526 if (!use_encoding ^ (ft_face->charmap->encoding == FT_ENCODING_NONE)) return FALSE;
2528 if (ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
2530 if (!(*glyph = get_glyph_index_symbol( font, *glyph )))
2532 WCHAR wc = *glyph;
2533 DWORD len;
2534 char ch;
2536 len = win32u_wctomb( &ansi_cp, &ch, 1, &wc, 1 );
2537 if (len) *glyph = get_glyph_index_symbol( font, (unsigned char)ch );
2539 return TRUE;
2541 *glyph = pFT_Get_Char_Index( ft_face, *glyph );
2542 return TRUE;
2545 /*************************************************************
2546 * freetype_get_default_glyph
2548 static UINT freetype_get_default_glyph( struct gdi_font *font )
2550 FT_Face ft_face = get_ft_face( font );
2551 FT_WinFNT_HeaderRec winfnt;
2552 TT_OS2 *pOS2;
2554 if ((pOS2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 )))
2556 UINT glyph = pOS2->usDefaultChar;
2557 if (glyph) freetype_get_glyph_index( font, &glyph, TRUE );
2558 return glyph;
2560 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt )) return winfnt.default_char + winfnt.first_char;
2561 return 32;
2565 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
2567 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
2568 return !memcmp(matrix, &identity, sizeof(FMAT2));
2571 static inline FT_Vector normalize_vector(FT_Vector *vec)
2573 FT_Vector out;
2574 FT_Fixed len;
2575 len = pFT_Vector_Length(vec);
2576 if (len) {
2577 out.x = (vec->x << 6) / len;
2578 out.y = (vec->y << 6) / len;
2580 else
2581 out.x = out.y = 0;
2582 return out;
2585 /* get_glyph_outline() glyph transform matrices index */
2586 enum matrices_index
2588 matrix_hori,
2589 matrix_vert,
2590 matrix_unrotated
2593 static FT_Matrix *get_transform_matrices( struct gdi_font *font, BOOL vertical, const MAT2 *user_transform,
2594 FT_Matrix matrices[3] )
2596 static const FT_Matrix identity_mat = { (1 << 16), 0, 0, (1 << 16) };
2597 BOOL needs_transform = FALSE;
2598 double width_ratio;
2599 int i;
2601 matrices[matrix_unrotated] = identity_mat;
2603 /* Scaling factor */
2604 if (font->aveWidth)
2606 if (!freetype_set_outline_text_metrics( font )) freetype_set_bitmap_text_metrics( font );
2607 width_ratio = (double)font->aveWidth;
2608 width_ratio /= (double)font->otm.otmTextMetrics.tmAveCharWidth;
2610 else
2611 width_ratio = font->scale_y;
2613 /* Scaling transform */
2614 if (width_ratio != 1.0 || font->scale_y != 1)
2616 FT_Matrix scale_mat;
2617 scale_mat.xx = FT_FixedFromFloat( width_ratio );
2618 scale_mat.xy = 0;
2619 scale_mat.yx = 0;
2620 scale_mat.yy = font->scale_y << 16;
2622 pFT_Matrix_Multiply( &scale_mat, &matrices[matrix_unrotated] );
2623 needs_transform = TRUE;
2626 /* Slant transform */
2627 if (font->fake_italic)
2629 FT_Matrix slant_mat;
2630 slant_mat.xx = (1 << 16);
2631 slant_mat.xy = (1 << 16) >> 2;
2632 slant_mat.yx = 0;
2633 slant_mat.yy = (1 << 16);
2635 pFT_Matrix_Multiply( &slant_mat, &matrices[matrix_unrotated] );
2636 needs_transform = TRUE;
2639 /* Rotation transform */
2640 matrices[matrix_hori] = matrices[matrix_unrotated];
2641 if (font->scalable && font->lf.lfOrientation % 3600)
2643 FT_Matrix rotation_mat;
2644 FT_Vector angle;
2646 pFT_Vector_Unit( &angle, pFT_MulDiv( 1 << 16, font->lf.lfOrientation, 10 ) );
2647 rotation_mat.xx = angle.x;
2648 rotation_mat.xy = -angle.y;
2649 rotation_mat.yx = angle.y;
2650 rotation_mat.yy = angle.x;
2651 pFT_Matrix_Multiply( &rotation_mat, &matrices[matrix_hori] );
2652 needs_transform = TRUE;
2655 /* Vertical transform */
2656 matrices[matrix_vert] = matrices[matrix_hori];
2657 if (vertical)
2659 FT_Matrix vertical_mat = { 0, -(1 << 16), 1 << 16, 0 }; /* 90 degrees rotation */
2661 pFT_Matrix_Multiply( &vertical_mat, &matrices[matrix_vert] );
2662 needs_transform = TRUE;
2665 /* World transform */
2666 if (!is_identity_FMAT2( &font->matrix ))
2668 FT_Matrix world_mat;
2669 world_mat.xx = FT_FixedFromFloat( font->matrix.eM11 );
2670 world_mat.xy = -FT_FixedFromFloat( font->matrix.eM21 );
2671 world_mat.yx = -FT_FixedFromFloat( font->matrix.eM12 );
2672 world_mat.yy = FT_FixedFromFloat( font->matrix.eM22 );
2674 for (i = 0; i < 3; i++)
2675 pFT_Matrix_Multiply( &world_mat, &matrices[i] );
2676 needs_transform = TRUE;
2679 /* Extra transformation specified by caller */
2680 if (user_transform)
2682 FT_Matrix user_mat;
2683 user_mat.xx = FT_FixedFromFIXED( user_transform->eM11 );
2684 user_mat.xy = FT_FixedFromFIXED( user_transform->eM21 );
2685 user_mat.yx = FT_FixedFromFIXED( user_transform->eM12 );
2686 user_mat.yy = FT_FixedFromFIXED( user_transform->eM22 );
2688 for (i = 0; i < 3; i++)
2689 pFT_Matrix_Multiply( &user_mat, &matrices[i] );
2690 needs_transform = TRUE;
2693 return needs_transform ? matrices : NULL;
2696 static BOOL get_bold_glyph_outline(FT_GlyphSlot glyph, LONG ppem, FT_Glyph_Metrics *metrics)
2698 FT_Error err;
2699 FT_Pos strength;
2700 FT_BBox bbox;
2702 if(glyph->format != FT_GLYPH_FORMAT_OUTLINE)
2703 return FALSE;
2704 if(!pFT_Outline_Embolden)
2705 return FALSE;
2707 strength = pFT_MulDiv(ppem, 1 << 6, 24);
2708 err = pFT_Outline_Embolden(&glyph->outline, strength);
2709 if(err) {
2710 TRACE("FT_Ouline_Embolden returns %d\n", err);
2711 return FALSE;
2714 pFT_Outline_Get_CBox(&glyph->outline, &bbox);
2715 metrics->width = bbox.xMax - bbox.xMin;
2716 metrics->height = bbox.yMax - bbox.yMin;
2717 metrics->horiBearingX = bbox.xMin;
2718 metrics->horiBearingY = bbox.yMax;
2719 metrics->vertBearingX = metrics->horiBearingX - metrics->horiAdvance / 2;
2720 metrics->vertBearingY = (metrics->vertAdvance - metrics->height) / 2;
2721 return TRUE;
2724 static inline BYTE get_max_level( UINT format )
2726 switch( format )
2728 case GGO_GRAY2_BITMAP: return 4;
2729 case GGO_GRAY4_BITMAP: return 16;
2730 case GGO_GRAY8_BITMAP: return 64;
2732 return 255;
2735 static FT_Vector get_advance_metric( struct gdi_font *font, FT_Pos base_advance,
2736 const FT_Matrix *transMat )
2738 FT_Vector adv;
2739 FT_Fixed em_scale = 0;
2740 BOOL fixed_pitch_full = FALSE;
2741 struct gdi_font *incoming_font = font->base_font ? font->base_font : font;
2743 adv.x = base_advance;
2744 adv.y = 0;
2746 /* In fixed-pitch font, we adjust the fullwidth character advance so that
2747 they have double halfwidth character width. E.g. if the font is 19 ppem,
2748 we return 20 (not 19) for fullwidth characters as we return 10 for
2749 halfwidth characters. */
2750 if (freetype_set_outline_text_metrics(incoming_font) &&
2751 !(incoming_font->otm.otmTextMetrics.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
2752 UINT avg_advance;
2753 em_scale = pFT_MulDiv(incoming_font->ppem, 1 << 16, get_ft_face(incoming_font)->units_per_EM);
2754 avg_advance = pFT_MulFix(incoming_font->ntmAvgWidth, em_scale);
2755 fixed_pitch_full = (avg_advance > 0 &&
2756 (base_advance + 63) >> 6 ==
2757 pFT_MulFix(incoming_font->ntmAvgWidth*2, em_scale));
2758 if (fixed_pitch_full && !transMat)
2759 adv.x = (avg_advance * 2) << 6;
2762 if (transMat) {
2763 pFT_Vector_Transform(&adv, transMat);
2764 if (fixed_pitch_full && adv.y == 0) {
2765 FT_Vector vec;
2766 vec.x = incoming_font->ntmAvgWidth;
2767 vec.y = 0;
2768 pFT_Vector_Transform(&vec, transMat);
2769 adv.x = (pFT_MulFix(vec.x, em_scale) * 2) << 6;
2773 if (font->fake_bold) {
2774 if (!transMat)
2775 adv.x += 1 << 6;
2776 else {
2777 FT_Vector fake_bold_adv, vec = { 1 << 6, 0 };
2778 pFT_Vector_Transform(&vec, transMat);
2779 fake_bold_adv = normalize_vector(&vec);
2780 adv.x += fake_bold_adv.x;
2781 adv.y += fake_bold_adv.y;
2785 adv.x = (adv.x + 63) & -64;
2786 adv.y = -((adv.y + 63) & -64);
2787 return adv;
2790 static FT_BBox get_transformed_bbox( const FT_Glyph_Metrics *metrics, const FT_Matrix *matrices )
2792 FT_BBox bbox = { 0, 0, 0, 0 };
2794 if (!matrices)
2796 bbox.xMin = (metrics->horiBearingX) & -64;
2797 bbox.xMax = (metrics->horiBearingX + metrics->width + 63) & -64;
2798 bbox.yMax = (metrics->horiBearingY + 63) & -64;
2799 bbox.yMin = (metrics->horiBearingY - metrics->height) & -64;
2801 else
2803 FT_Vector vec;
2804 INT xc, yc;
2806 for (xc = 0; xc < 2; xc++)
2808 for (yc = 0; yc < 2; yc++)
2810 vec.x = metrics->horiBearingX + xc * metrics->width;
2811 vec.y = metrics->horiBearingY - yc * metrics->height;
2812 TRACE( "Vec %ld, %ld\n", vec.x, vec.y );
2813 pFT_Vector_Transform( &vec, &matrices[matrix_vert] );
2814 if (xc == 0 && yc == 0)
2816 bbox.xMin = bbox.xMax = vec.x;
2817 bbox.yMin = bbox.yMax = vec.y;
2819 else
2821 if (vec.x < bbox.xMin) bbox.xMin = vec.x;
2822 else if (vec.x > bbox.xMax) bbox.xMax = vec.x;
2823 if (vec.y < bbox.yMin) bbox.yMin = vec.y;
2824 else if (vec.y > bbox.yMax) bbox.yMax = vec.y;
2828 bbox.xMin = bbox.xMin & -64;
2829 bbox.xMax = (bbox.xMax + 63) & -64;
2830 bbox.yMin = bbox.yMin & -64;
2831 bbox.yMax = (bbox.yMax + 63) & -64;
2832 TRACE( "transformed box: (%ld, %ld - %ld, %ld)\n", bbox.xMin, bbox.yMax, bbox.xMax, bbox.yMin );
2835 return bbox;
2838 static void compute_metrics( struct gdi_font *font, FT_BBox bbox, const FT_Glyph_Metrics *metrics,
2839 BOOL vertical, BOOL vertical_metrics, const FT_Matrix *matrices,
2840 GLYPHMETRICS *gm, ABC *abc )
2842 FT_Vector adv, vec, origin;
2843 FT_Fixed base_advance = vertical_metrics ? metrics->vertAdvance : metrics->horiAdvance;
2845 if (!matrices)
2847 adv = get_advance_metric( font, base_advance, NULL );
2848 gm->gmCellIncX = adv.x >> 6;
2849 gm->gmCellIncY = 0;
2850 origin.x = bbox.xMin;
2851 origin.y = bbox.yMax;
2852 abc->abcA = origin.x >> 6;
2853 abc->abcB = (metrics->width + 63) >> 6;
2855 else
2857 FT_Pos lsb;
2859 if (vertical && freetype_set_outline_text_metrics( font ))
2861 if (vertical_metrics)
2862 lsb = metrics->horiBearingY + metrics->vertBearingY;
2863 else
2864 lsb = metrics->vertAdvance + (font->otm.otmDescent << 6);
2865 vec.x = lsb;
2866 vec.y = font->otm.otmDescent << 6;
2867 TRACE( "Vec %ld,%ld\n", vec.x>>6, vec.y>>6 );
2868 pFT_Vector_Transform( &vec, &matrices[matrix_hori] );
2869 origin.x = (vec.x + bbox.xMin) & -64;
2870 origin.y = (vec.y + bbox.yMax + 63) & -64;
2871 lsb -= metrics->horiBearingY;
2873 else
2875 origin.x = bbox.xMin;
2876 origin.y = bbox.yMax;
2877 lsb = metrics->horiBearingX;
2880 adv = get_advance_metric( font, base_advance, &matrices[matrix_hori] );
2881 gm->gmCellIncX = adv.x >> 6;
2882 gm->gmCellIncY = adv.y >> 6;
2884 adv = get_advance_metric( font, base_advance, &matrices[matrix_unrotated] );
2885 adv.x = pFT_Vector_Length( &adv );
2886 adv.y = 0;
2888 vec.x = lsb;
2889 vec.y = 0;
2890 pFT_Vector_Transform( &vec, &matrices[matrix_unrotated] );
2891 if (lsb > 0) abc->abcA = pFT_Vector_Length( &vec ) >> 6;
2892 else abc->abcA = -((pFT_Vector_Length( &vec ) + 63) >> 6);
2894 /* We use lsb again to avoid rounding errors */
2895 vec.x = lsb + (vertical ? metrics->height : metrics->width);
2896 vec.y = 0;
2897 pFT_Vector_Transform( &vec, &matrices[matrix_unrotated] );
2898 abc->abcB = ((pFT_Vector_Length( &vec ) + 63) >> 6) - abc->abcA;
2900 if (!abc->abcB) abc->abcB = 1;
2901 abc->abcC = (adv.x >> 6) - abc->abcA - abc->abcB;
2903 gm->gmptGlyphOrigin.x = origin.x >> 6;
2904 gm->gmptGlyphOrigin.y = origin.y >> 6;
2905 gm->gmBlackBoxX = (bbox.xMax - bbox.xMin) >> 6;
2906 gm->gmBlackBoxY = (bbox.yMax - bbox.yMin) >> 6;
2907 if (!gm->gmBlackBoxX) gm->gmBlackBoxX = 1;
2908 if (!gm->gmBlackBoxY) gm->gmBlackBoxY = 1;
2910 TRACE( "gm: %u, %u, %s, %d, %d abc %d, %u, %d\n",
2911 gm->gmBlackBoxX, gm->gmBlackBoxY, wine_dbgstr_point(&gm->gmptGlyphOrigin),
2912 gm->gmCellIncX, gm->gmCellIncY, abc->abcA, abc->abcB, abc->abcC );
2916 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
2918 static DWORD get_mono_glyph_bitmap( FT_GlyphSlot glyph, FT_BBox bbox,
2919 BOOL fake_bold, const FT_Matrix *matrices,
2920 DWORD buflen, BYTE *buf )
2922 DWORD width = (bbox.xMax - bbox.xMin ) >> 6;
2923 DWORD height = (bbox.yMax - bbox.yMin ) >> 6;
2924 DWORD pitch = ((width + 31) >> 5) << 2;
2925 DWORD needed = pitch * height;
2926 FT_Bitmap ft_bitmap;
2927 BYTE *src, *dst;
2928 INT w, h, x;
2930 if (!buf || !buflen) return needed;
2931 if (!needed) return GDI_ERROR; /* empty glyph */
2932 if (needed > buflen) return GDI_ERROR;
2934 switch (glyph->format)
2936 case FT_GLYPH_FORMAT_BITMAP:
2937 src = glyph->bitmap.buffer;
2938 dst = buf;
2939 w = min( pitch, (glyph->bitmap.width + 7) >> 3 );
2940 h = min( height, glyph->bitmap.rows );
2941 while (h--)
2943 if (!fake_bold)
2944 memcpy( dst, src, w );
2945 else
2947 dst[0] = 0;
2948 for (x = 0; x < w; x++)
2950 dst[x] = (dst[x] & 0x80) | (src[x] >> 1) | src[x];
2951 if (x + 1 < pitch)
2952 dst[x + 1] = (src[x] & 0x01) << 7;
2955 src += glyph->bitmap.pitch;
2956 dst += pitch;
2958 break;
2960 case FT_GLYPH_FORMAT_OUTLINE:
2961 ft_bitmap.width = width;
2962 ft_bitmap.rows = height;
2963 ft_bitmap.pitch = pitch;
2964 ft_bitmap.pixel_mode = FT_PIXEL_MODE_MONO;
2965 ft_bitmap.buffer = buf;
2967 if (matrices)
2968 pFT_Outline_Transform( &glyph->outline, &matrices[matrix_vert] );
2969 pFT_Outline_Translate( &glyph->outline, -bbox.xMin, -bbox.yMin );
2971 /* Note: FreeType will only set 'black' bits for us. */
2972 memset( buf, 0, buflen );
2973 pFT_Outline_Get_Bitmap( library, &glyph->outline, &ft_bitmap );
2974 break;
2976 default:
2977 FIXME( "loaded glyph format %x\n", glyph->format );
2978 return GDI_ERROR;
2981 return needed;
2984 static DWORD get_antialias_glyph_bitmap( FT_GlyphSlot glyph, FT_BBox bbox, UINT format,
2985 BOOL fake_bold, const FT_Matrix *matrices,
2986 DWORD buflen, BYTE *buf )
2988 DWORD width = (bbox.xMax - bbox.xMin ) >> 6;
2989 DWORD height = (bbox.yMax - bbox.yMin ) >> 6;
2990 DWORD pitch = (width + 3) / 4 * 4;
2991 DWORD needed = pitch * height;
2992 FT_Bitmap ft_bitmap;
2993 INT w, h, x, max_level;
2994 BYTE *src, *dst;
2996 if (!buf || !buflen) return needed;
2997 if (!needed) return GDI_ERROR; /* empty glyph */
2998 if (needed > buflen) return GDI_ERROR;
3000 max_level = get_max_level( format );
3002 switch (glyph->format)
3004 case FT_GLYPH_FORMAT_BITMAP:
3005 src = glyph->bitmap.buffer;
3006 dst = buf;
3007 memset( buf, 0, buflen );
3009 w = min( pitch, glyph->bitmap.width );
3010 h = min( height, glyph->bitmap.rows );
3011 while (h--)
3013 for (x = 0; x < w; x++)
3015 if (src[x / 8] & masks[x % 8])
3017 dst[x] = max_level;
3018 if (fake_bold && x + 1 < pitch) dst[x + 1] = max_level;
3021 src += glyph->bitmap.pitch;
3022 dst += pitch;
3024 break;
3026 case FT_GLYPH_FORMAT_OUTLINE:
3027 ft_bitmap.width = width;
3028 ft_bitmap.rows = height;
3029 ft_bitmap.pitch = pitch;
3030 ft_bitmap.pixel_mode = FT_PIXEL_MODE_GRAY;
3031 ft_bitmap.buffer = buf;
3033 if (matrices)
3034 pFT_Outline_Transform( &glyph->outline, &matrices[matrix_vert] );
3035 pFT_Outline_Translate( &glyph->outline, -bbox.xMin, -bbox.yMin );
3037 memset( buf, 0, buflen );
3038 pFT_Outline_Get_Bitmap( library, &glyph->outline, &ft_bitmap );
3040 if (max_level != 255)
3042 INT row, col;
3043 BYTE *ptr, *start;
3045 for (row = 0, start = buf; row < height; row++)
3047 for (col = 0, ptr = start; col < width; col++, ptr++)
3048 *ptr = (((int)*ptr) * (max_level + 1)) / 256;
3049 start += pitch;
3052 break;
3054 default:
3055 FIXME("loaded glyph format %x\n", glyph->format);
3056 return GDI_ERROR;
3059 return needed;
3062 static DWORD get_subpixel_glyph_bitmap( FT_GlyphSlot glyph, FT_BBox bbox, UINT format,
3063 BOOL fake_bold, const FT_Matrix *matrices,
3064 GLYPHMETRICS *gm, DWORD buflen, BYTE *buf )
3066 DWORD width = (bbox.xMax - bbox.xMin ) >> 6;
3067 DWORD height = (bbox.yMax - bbox.yMin ) >> 6;
3068 DWORD pitch, needed = 0;
3069 BYTE *src, *dst;
3070 INT w, h, x;
3072 switch (glyph->format)
3074 case FT_GLYPH_FORMAT_BITMAP:
3075 pitch = width * 4;
3076 needed = pitch * height;
3078 if (!buf || !buflen) break;
3079 if (!needed) return GDI_ERROR; /* empty glyph */
3080 if (needed > buflen) return GDI_ERROR;
3082 src = glyph->bitmap.buffer;
3083 dst = buf;
3084 memset( buf, 0, buflen );
3086 w = min( width, glyph->bitmap.width );
3087 h = min( height, glyph->bitmap.rows );
3088 while (h--)
3090 for (x = 0; x < w; x++)
3092 if ( src[x / 8] & masks[x % 8] )
3094 ((unsigned int *)dst)[x] = ~0u;
3095 if (fake_bold && x + 1 < width) ((unsigned int *)dst)[x + 1] = ~0u;
3098 src += glyph->bitmap.pitch;
3099 dst += pitch;
3101 break;
3103 case FT_GLYPH_FORMAT_OUTLINE:
3105 INT src_pitch, src_width, src_height, x_shift, y_shift;
3106 INT sub_stride, hmul, vmul;
3107 const INT *sub_order;
3108 const INT rgb_order[3] = { 0, 1, 2 };
3109 const INT bgr_order[3] = { 2, 1, 0 };
3110 FT_Render_Mode render_mode =
3111 (format == WINE_GGO_HRGB_BITMAP ||
3112 format == WINE_GGO_HBGR_BITMAP) ? FT_RENDER_MODE_LCD : FT_RENDER_MODE_LCD_V;
3114 if (!width || !height) /* empty glyph */
3116 if (!buf || !buflen) break;
3117 return GDI_ERROR;
3120 if ( render_mode == FT_RENDER_MODE_LCD)
3122 gm->gmBlackBoxX += 2;
3123 gm->gmptGlyphOrigin.x -= 1;
3124 bbox.xMin -= (1 << 6);
3126 else
3128 gm->gmBlackBoxY += 2;
3129 gm->gmptGlyphOrigin.y += 1;
3130 bbox.yMax += (1 << 6);
3133 width = gm->gmBlackBoxX;
3134 height = gm->gmBlackBoxY;
3135 pitch = width * 4;
3136 needed = pitch * height;
3138 if (!buf || !buflen) return needed;
3139 if (needed > buflen) return GDI_ERROR;
3141 if (matrices)
3142 pFT_Outline_Transform( &glyph->outline, &matrices[matrix_vert] );
3144 pFT_Render_Glyph( glyph, render_mode );
3146 src_pitch = glyph->bitmap.pitch;
3147 src_width = glyph->bitmap.width;
3148 src_height = glyph->bitmap.rows;
3149 src = glyph->bitmap.buffer;
3150 dst = buf;
3151 memset( buf, 0, buflen );
3153 sub_order = (format == WINE_GGO_HRGB_BITMAP ||
3154 format == WINE_GGO_VRGB_BITMAP) ? rgb_order : bgr_order;
3155 sub_stride = render_mode == FT_RENDER_MODE_LCD ? 1 : src_pitch;
3156 hmul = render_mode == FT_RENDER_MODE_LCD ? 3 : 1;
3157 vmul = render_mode == FT_RENDER_MODE_LCD ? 1 : 3;
3159 x_shift = glyph->bitmap_left - (bbox.xMin >> 6);
3160 if ( x_shift < 0 )
3162 src += hmul * -x_shift;
3163 src_width -= hmul * -x_shift;
3165 else if ( x_shift > 0 )
3167 dst += x_shift * sizeof(unsigned int);
3168 width -= x_shift;
3171 y_shift = (bbox.yMax >> 6) - glyph->bitmap_top;
3172 if ( y_shift < 0 )
3174 src += src_pitch * vmul * -y_shift;
3175 src_height -= vmul * -y_shift;
3177 else if ( y_shift > 0 )
3179 dst += y_shift * pitch;
3180 height -= y_shift;
3183 w = min( width, src_width / hmul );
3184 h = min( height, src_height / vmul );
3185 while (h--)
3187 for (x = 0; x < w; x++)
3189 ((unsigned int *)dst)[x] =
3190 ((unsigned int)src[hmul * x + sub_stride * sub_order[0]] << 16) |
3191 ((unsigned int)src[hmul * x + sub_stride * sub_order[1]] << 8) |
3192 ((unsigned int)src[hmul * x + sub_stride * sub_order[2]]);
3194 src += src_pitch * vmul;
3195 dst += pitch;
3197 break;
3199 default:
3200 FIXME ( "loaded glyph format %x\n", glyph->format );
3201 return GDI_ERROR;
3204 return needed;
3207 static unsigned int get_native_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
3209 TTPOLYGONHEADER *pph;
3210 TTPOLYCURVE *ppc;
3211 unsigned int needed = 0, point = 0, contour, first_pt;
3212 unsigned int pph_start, cpfx;
3213 DWORD type;
3215 for (contour = 0; contour < outline->n_contours; contour++)
3217 /* Ignore contours containing one point */
3218 if (point == outline->contours[contour])
3220 point++;
3221 continue;
3224 pph_start = needed;
3225 pph = (TTPOLYGONHEADER *)(buf + needed);
3226 first_pt = point;
3227 if (buf)
3229 pph->dwType = TT_POLYGON_TYPE;
3230 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3232 needed += sizeof(*pph);
3233 point++;
3234 while (point <= outline->contours[contour])
3236 ppc = (TTPOLYCURVE *)(buf + needed);
3237 type = outline->tags[point] & FT_Curve_Tag_On ?
3238 TT_PRIM_LINE : TT_PRIM_QSPLINE;
3239 cpfx = 0;
3242 if (buf)
3243 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3244 cpfx++;
3245 point++;
3246 } while (point <= outline->contours[contour] &&
3247 (outline->tags[point] & FT_Curve_Tag_On) ==
3248 (outline->tags[point-1] & FT_Curve_Tag_On));
3249 /* At the end of a contour Windows adds the start point, but
3250 only for Beziers */
3251 if (point > outline->contours[contour] &&
3252 !(outline->tags[point-1] & FT_Curve_Tag_On))
3254 if (buf)
3255 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
3256 cpfx++;
3258 else if (point <= outline->contours[contour] &&
3259 outline->tags[point] & FT_Curve_Tag_On)
3261 /* add closing pt for bezier */
3262 if (buf)
3263 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3264 cpfx++;
3265 point++;
3267 if (buf)
3269 ppc->wType = type;
3270 ppc->cpfx = cpfx;
3272 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3274 if (buf)
3275 pph->cb = needed - pph_start;
3277 return needed;
3280 static unsigned int get_bezier_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
3282 /* Convert the quadratic Beziers to cubic Beziers.
3283 The parametric eqn for a cubic Bezier is, from PLRM:
3284 r(t) = at^3 + bt^2 + ct + r0
3285 with the control points:
3286 r1 = r0 + c/3
3287 r2 = r1 + (c + b)/3
3288 r3 = r0 + c + b + a
3290 A quadratic Bezier has the form:
3291 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3293 So equating powers of t leads to:
3294 r1 = 2/3 p1 + 1/3 p0
3295 r2 = 2/3 p1 + 1/3 p2
3296 and of course r0 = p0, r3 = p2
3298 int contour, point = 0, first_pt;
3299 TTPOLYGONHEADER *pph;
3300 TTPOLYCURVE *ppc;
3301 DWORD pph_start, cpfx, type;
3302 FT_Vector cubic_control[4];
3303 unsigned int needed = 0;
3305 for (contour = 0; contour < outline->n_contours; contour++)
3307 pph_start = needed;
3308 pph = (TTPOLYGONHEADER *)(buf + needed);
3309 first_pt = point;
3310 if (buf)
3312 pph->dwType = TT_POLYGON_TYPE;
3313 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3315 needed += sizeof(*pph);
3316 point++;
3317 while (point <= outline->contours[contour])
3319 ppc = (TTPOLYCURVE *)(buf + needed);
3320 type = outline->tags[point] & FT_Curve_Tag_On ?
3321 TT_PRIM_LINE : TT_PRIM_CSPLINE;
3322 cpfx = 0;
3325 if (type == TT_PRIM_LINE)
3327 if (buf)
3328 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3329 cpfx++;
3330 point++;
3332 else
3334 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
3335 so cpfx = 3n */
3337 /* FIXME: Possible optimization in endpoint calculation
3338 if there are two consecutive curves */
3339 cubic_control[0] = outline->points[point-1];
3340 if (!(outline->tags[point-1] & FT_Curve_Tag_On))
3342 cubic_control[0].x += outline->points[point].x + 1;
3343 cubic_control[0].y += outline->points[point].y + 1;
3344 cubic_control[0].x >>= 1;
3345 cubic_control[0].y >>= 1;
3347 if (point+1 > outline->contours[contour])
3348 cubic_control[3] = outline->points[first_pt];
3349 else
3351 cubic_control[3] = outline->points[point+1];
3352 if (!(outline->tags[point+1] & FT_Curve_Tag_On))
3354 cubic_control[3].x += outline->points[point].x + 1;
3355 cubic_control[3].y += outline->points[point].y + 1;
3356 cubic_control[3].x >>= 1;
3357 cubic_control[3].y >>= 1;
3360 /* r1 = 1/3 p0 + 2/3 p1
3361 r2 = 1/3 p2 + 2/3 p1 */
3362 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
3363 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
3364 cubic_control[2] = cubic_control[1];
3365 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
3366 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
3367 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
3368 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
3369 if (buf)
3371 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
3372 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
3373 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
3375 cpfx += 3;
3376 point++;
3378 } while (point <= outline->contours[contour] &&
3379 (outline->tags[point] & FT_Curve_Tag_On) ==
3380 (outline->tags[point-1] & FT_Curve_Tag_On));
3381 /* At the end of a contour Windows adds the start point,
3382 but only for Beziers and we've already done that.
3384 if (point <= outline->contours[contour] &&
3385 outline->tags[point] & FT_Curve_Tag_On)
3387 /* This is the closing pt of a bezier, but we've already
3388 added it, so just inc point and carry on */
3389 point++;
3391 if (buf)
3393 ppc->wType = type;
3394 ppc->cpfx = cpfx;
3396 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3398 if (buf)
3399 pph->cb = needed - pph_start;
3401 return needed;
3404 static FT_Int get_load_flags( UINT format )
3406 FT_Int load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
3408 if (format & GGO_UNHINTED)
3409 return load_flags | FT_LOAD_NO_HINTING;
3411 switch (format & ~GGO_GLYPH_INDEX)
3413 case GGO_BITMAP:
3414 load_flags |= FT_LOAD_TARGET_MONO;
3415 break;
3416 case GGO_GRAY2_BITMAP:
3417 case GGO_GRAY4_BITMAP:
3418 case GGO_GRAY8_BITMAP:
3419 case WINE_GGO_GRAY16_BITMAP:
3420 load_flags |= FT_LOAD_TARGET_NORMAL;
3421 break;
3422 case WINE_GGO_HRGB_BITMAP:
3423 case WINE_GGO_HBGR_BITMAP:
3424 load_flags |= FT_LOAD_TARGET_LCD;
3425 break;
3426 case WINE_GGO_VRGB_BITMAP:
3427 case WINE_GGO_VBGR_BITMAP:
3428 load_flags |= FT_LOAD_TARGET_LCD_V;
3429 break;
3432 return load_flags;
3435 /*************************************************************
3436 * freetype_get_glyph_outline
3438 static UINT freetype_get_glyph_outline( struct gdi_font *font, UINT glyph, UINT format,
3439 GLYPHMETRICS *lpgm, ABC *abc, UINT buflen, void *buf,
3440 const MAT2 *lpmat, BOOL tategaki )
3442 struct gdi_font *base_font = font->base_font ? font->base_font : font;
3443 FT_Face ft_face = get_ft_face( font );
3444 FT_Glyph_Metrics metrics;
3445 FT_Error err;
3446 FT_BBox bbox;
3447 FT_Int load_flags = get_load_flags(format);
3448 FT_Matrix transform_matrices[3], *matrices = NULL;
3449 BOOL vertical_metrics;
3451 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm, buflen, buf, lpmat);
3453 TRACE("font transform %f %f %f %f\n",
3454 font->matrix.eM11, font->matrix.eM12,
3455 font->matrix.eM21, font->matrix.eM22);
3457 format &= ~GGO_UNHINTED;
3459 matrices = get_transform_matrices( font, tategaki, lpmat, transform_matrices );
3461 vertical_metrics = (tategaki && FT_HAS_VERTICAL(ft_face));
3462 /* there is a freetype bug where vertical metrics are only
3463 properly scaled and correct in 2.4.0 or greater */
3464 if (vertical_metrics && FT_SimpleVersion < FT_VERSION_VALUE(2, 4, 0))
3465 vertical_metrics = FALSE;
3467 if (matrices || format != GGO_BITMAP) load_flags |= FT_LOAD_NO_BITMAP;
3468 if (vertical_metrics) load_flags |= FT_LOAD_VERTICAL_LAYOUT;
3470 err = pFT_Load_Glyph(ft_face, glyph, load_flags);
3471 if (err && !(load_flags & FT_LOAD_NO_HINTING))
3473 WARN("Failed to load glyph %#x, retrying without hinting. Error %#x.\n", glyph, err);
3474 load_flags |= FT_LOAD_NO_HINTING;
3475 err = pFT_Load_Glyph(ft_face, glyph, load_flags);
3478 if(err) {
3479 WARN("Failed to load glyph %#x, error %#x.\n", glyph, err);
3480 return GDI_ERROR;
3483 metrics = ft_face->glyph->metrics;
3484 if(font->fake_bold) {
3485 if (!get_bold_glyph_outline(ft_face->glyph, font->ppem, &metrics) && metrics.width)
3486 metrics.width += 1 << 6;
3489 /* Some poorly-created fonts contain glyphs that exceed the boundaries set
3490 * by the text metrics. The proper behavior is to clip the glyph metrics to
3491 * fit within the maximums specified in the text metrics. */
3492 if (freetype_set_outline_text_metrics(base_font) ||
3493 freetype_set_bitmap_text_metrics(base_font)) {
3494 TEXTMETRICW *ptm = &base_font->otm.otmTextMetrics;
3495 INT top = min( metrics.horiBearingY, ptm->tmAscent << 6 );
3496 INT bottom = max( metrics.horiBearingY - metrics.height, -(ptm->tmDescent << 6) );
3497 metrics.horiBearingY = top;
3498 metrics.height = top - bottom;
3500 /* TODO: Are we supposed to clip the width as well...? */
3501 /* metrics.width = min( metrics.width, ptm->tmMaxCharWidth << 6 ); */
3504 bbox = get_transformed_bbox( &metrics, matrices );
3505 compute_metrics( font, bbox, &metrics, tategaki, vertical_metrics, matrices, lpgm, abc );
3507 switch (format)
3509 case GGO_METRICS:
3510 return 1; /* FIXME */
3512 case GGO_BITMAP:
3513 return get_mono_glyph_bitmap( ft_face->glyph, bbox, font->fake_bold,
3514 matrices, buflen, buf );
3516 case GGO_GRAY2_BITMAP:
3517 case GGO_GRAY4_BITMAP:
3518 case GGO_GRAY8_BITMAP:
3519 case WINE_GGO_GRAY16_BITMAP:
3520 return get_antialias_glyph_bitmap( ft_face->glyph, bbox, format, font->fake_bold,
3521 matrices, buflen, buf );
3523 case WINE_GGO_HRGB_BITMAP:
3524 case WINE_GGO_HBGR_BITMAP:
3525 case WINE_GGO_VRGB_BITMAP:
3526 case WINE_GGO_VBGR_BITMAP:
3527 return get_subpixel_glyph_bitmap( ft_face->glyph, bbox, format, font->fake_bold,
3528 matrices, lpgm, buflen, buf );
3530 case GGO_NATIVE:
3531 if (ft_face->glyph->format == ft_glyph_format_outline)
3533 FT_Outline *outline = &ft_face->glyph->outline;
3534 UINT needed;
3536 if (buflen == 0) buf = NULL;
3538 if (matrices && buf)
3539 pFT_Outline_Transform( outline, &matrices[matrix_vert] );
3541 needed = get_native_glyph_outline(outline, buflen, NULL);
3543 if (!buf || !buflen) return needed;
3544 if (needed > buflen) return GDI_ERROR;
3545 return get_native_glyph_outline(outline, buflen, buf);
3547 TRACE("loaded a bitmap\n");
3548 return GDI_ERROR;
3550 case GGO_BEZIER:
3551 if (ft_face->glyph->format == ft_glyph_format_outline)
3553 FT_Outline *outline = &ft_face->glyph->outline;
3554 UINT needed;
3556 if (buflen == 0) buf = NULL;
3558 if (matrices && buf)
3559 pFT_Outline_Transform( outline, &matrices[matrix_vert] );
3561 needed = get_bezier_glyph_outline(outline, buflen, NULL);
3563 if (!buf || !buflen) return needed;
3564 if (needed > buflen) return GDI_ERROR;
3565 return get_bezier_glyph_outline(outline, buflen, buf);
3567 TRACE("loaded a bitmap\n");
3568 return GDI_ERROR;
3570 default:
3571 FIXME("Unsupported format %d\n", format);
3572 return GDI_ERROR;
3576 /*************************************************************
3577 * freetype_set_bitmap_text_metrics
3579 static BOOL freetype_set_bitmap_text_metrics( struct gdi_font *font )
3581 FT_Face ft_face = get_ft_face( font );
3582 FT_WinFNT_HeaderRec winfnt_header;
3584 if (font->otm.otmSize) return TRUE; /* already set */
3585 font->otm.otmSize = offsetof( OUTLINETEXTMETRICW, otmFiller );
3587 #define TM font->otm.otmTextMetrics
3588 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
3590 TM.tmHeight = winfnt_header.pixel_height;
3591 TM.tmAscent = winfnt_header.ascent;
3592 TM.tmDescent = TM.tmHeight - TM.tmAscent;
3593 TM.tmInternalLeading = winfnt_header.internal_leading;
3594 TM.tmExternalLeading = winfnt_header.external_leading;
3595 TM.tmAveCharWidth = winfnt_header.avg_width;
3596 TM.tmMaxCharWidth = winfnt_header.max_width;
3597 TM.tmWeight = winfnt_header.weight;
3598 TM.tmOverhang = 0;
3599 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
3600 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
3601 TM.tmFirstChar = winfnt_header.first_char;
3602 TM.tmLastChar = winfnt_header.last_char;
3603 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
3604 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
3605 TM.tmItalic = winfnt_header.italic;
3606 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
3607 TM.tmCharSet = winfnt_header.charset;
3609 else
3611 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
3612 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
3613 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3614 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
3615 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
3616 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
3617 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
3618 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
3619 TM.tmOverhang = 0;
3620 TM.tmDigitizedAspectX = 96; /* FIXME */
3621 TM.tmDigitizedAspectY = 96; /* FIXME */
3622 TM.tmFirstChar = 1;
3623 TM.tmLastChar = 255;
3624 TM.tmDefaultChar = 32;
3625 TM.tmBreakChar = 32;
3626 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
3627 /* NB inverted meaning of TMPF_FIXED_PITCH */
3628 TM.tmPitchAndFamily = FT_IS_FIXED_WIDTH(ft_face) ? 0 : TMPF_FIXED_PITCH;
3629 TM.tmCharSet = font->charset;
3631 TM.tmUnderlined = font->lf.lfUnderline ? 0xff : 0;
3632 TM.tmStruckOut = font->lf.lfStrikeOut ? 0xff : 0;
3634 if(font->fake_bold)
3635 TM.tmWeight = FW_BOLD;
3636 #undef TM
3638 return TRUE;
3642 static BOOL face_has_symbol_charmap(FT_Face ft_face)
3644 int i;
3646 for(i = 0; i < ft_face->num_charmaps; i++)
3648 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
3649 return TRUE;
3651 return FALSE;
3654 /*************************************************************
3655 * freetype_set_outline_text_metrics
3657 static BOOL freetype_set_outline_text_metrics( struct gdi_font *font )
3659 FT_Face ft_face = get_ft_face( font );
3660 UINT needed;
3661 TT_OS2 *pOS2;
3662 TT_HoriHeader *pHori;
3663 TT_Postscript *pPost;
3664 FT_Fixed em_scale;
3665 INT ascent, descent;
3666 USHORT windescent;
3668 TRACE("font=%p\n", font);
3670 if (!font->scalable) return FALSE;
3671 if (font->otm.otmSize) return TRUE; /* already set */
3673 /* note: we store actual pointers in the names instead of offsets,
3674 they are fixed up when returned to the app */
3675 if (!(font->otm.otmpFullName = (char *)get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, system_lcid )))
3677 static const WCHAR fake_nameW[] = {'f','a','k','e',' ','n','a','m','e', 0};
3678 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w((WCHAR *)font->otm.otmpFamilyName));
3679 font->otm.otmpFullName = (char *)wcsdup( fake_nameW );
3681 needed = sizeof(font->otm) + (lstrlenW( (WCHAR *)font->otm.otmpFamilyName ) + 1 +
3682 lstrlenW( (WCHAR *)font->otm.otmpStyleName ) + 1 +
3683 lstrlenW( (WCHAR *)font->otm.otmpFaceName ) + 1 +
3684 lstrlenW( (WCHAR *)font->otm.otmpFullName ) + 1) * sizeof(WCHAR);
3686 em_scale = (FT_Fixed)pFT_MulDiv(font->ppem, 1 << 16, ft_face->units_per_EM);
3688 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3689 if(!pOS2) {
3690 FIXME("Can't find OS/2 table - not TT font?\n");
3691 return FALSE;
3694 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3695 if(!pHori) {
3696 FIXME("Can't find HHEA table - not TT font?\n");
3697 return FALSE;
3700 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
3702 TRACE("OS/2 winA = %u winD = %u typoA = %d typoD = %d typoLG = %d avgW %d FT_Face a = %d, d = %d, h = %d: HORZ a = %d, d = %d lg = %d maxY = %ld minY = %ld\n",
3703 pOS2->usWinAscent, pOS2->usWinDescent,
3704 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
3705 pOS2->xAvgCharWidth,
3706 ft_face->ascender, ft_face->descender, ft_face->height,
3707 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
3708 ft_face->bbox.yMax, ft_face->bbox.yMin);
3710 font->otm.otmSize = needed;
3712 #define TM font->otm.otmTextMetrics
3714 windescent = get_fixed_windescent(pOS2->usWinDescent);
3715 if(pOS2->usWinAscent + windescent == 0) {
3716 ascent = pHori->Ascender;
3717 descent = -pHori->Descender;
3718 } else {
3719 ascent = pOS2->usWinAscent;
3720 descent = windescent;
3723 font->ntmAvgWidth = pOS2->xAvgCharWidth;
3725 #define SCALE_X(x) (pFT_MulFix(x, em_scale))
3726 #define SCALE_Y(y) (pFT_MulFix(y, em_scale))
3728 if(font->yMax) {
3729 TM.tmAscent = font->yMax;
3730 TM.tmDescent = -font->yMin;
3731 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
3732 } else {
3733 TM.tmAscent = SCALE_Y(ascent);
3734 TM.tmDescent = SCALE_Y(descent);
3735 TM.tmInternalLeading = SCALE_Y(ascent + descent - ft_face->units_per_EM);
3738 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3740 /* MSDN says:
3741 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
3743 TM.tmExternalLeading = max(0, SCALE_Y(pHori->Line_Gap -
3744 ((ascent + descent) -
3745 (pHori->Ascender - pHori->Descender))));
3747 TM.tmAveCharWidth = SCALE_X(pOS2->xAvgCharWidth);
3748 if (TM.tmAveCharWidth == 0) {
3749 TM.tmAveCharWidth = 1;
3751 TM.tmMaxCharWidth = SCALE_X(ft_face->bbox.xMax - ft_face->bbox.xMin);
3752 TM.tmWeight = FW_REGULAR;
3753 if (font->fake_bold)
3754 TM.tmWeight = FW_BOLD;
3755 else
3757 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
3759 if (pOS2->usWeightClass > FW_MEDIUM)
3760 TM.tmWeight = pOS2->usWeightClass;
3762 else if (pOS2->usWeightClass <= FW_MEDIUM)
3763 TM.tmWeight = pOS2->usWeightClass;
3765 TM.tmOverhang = 0;
3766 TM.tmDigitizedAspectX = 96; /* FIXME */
3767 TM.tmDigitizedAspectY = 96; /* FIXME */
3768 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
3769 * symbol range to 0 - f0ff
3772 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
3774 TM.tmFirstChar = 0;
3775 switch (PRIMARYLANGID(system_lcid))
3777 case LANG_HEBREW:
3778 TM.tmLastChar = 0xf896;
3779 break;
3780 case LANG_ESTONIAN:
3781 case LANG_LATVIAN:
3782 case LANG_LITHUANIAN:
3783 TM.tmLastChar = 0xf8fd;
3784 break;
3785 default:
3786 TM.tmLastChar = 0xf0ff;
3788 TM.tmBreakChar = 0x20;
3789 TM.tmDefaultChar = 0x1f;
3791 else
3793 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
3794 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
3796 if(pOS2->usFirstCharIndex <= 1)
3797 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
3798 else if (pOS2->usFirstCharIndex > 0xff)
3799 TM.tmBreakChar = 0x20;
3800 else
3801 TM.tmBreakChar = pOS2->usFirstCharIndex;
3802 TM.tmDefaultChar = TM.tmBreakChar - 1;
3804 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
3805 TM.tmUnderlined = font->lf.lfUnderline ? 255 : 0;
3806 TM.tmStruckOut = font->lf.lfStrikeOut ? 255 : 0;
3808 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
3809 if(!FT_IS_FIXED_WIDTH(ft_face) &&
3810 (pOS2->version == 0xFFFFU ||
3811 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
3812 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
3813 else
3814 TM.tmPitchAndFamily = 0;
3816 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
3818 case PAN_FAMILY_SCRIPT:
3819 TM.tmPitchAndFamily |= FF_SCRIPT;
3820 break;
3822 case PAN_FAMILY_DECORATIVE:
3823 TM.tmPitchAndFamily |= FF_DECORATIVE;
3824 break;
3826 case PAN_ANY:
3827 case PAN_NO_FIT:
3828 case PAN_FAMILY_TEXT_DISPLAY:
3829 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
3830 /* which is clearly not what the panose spec says. */
3831 default:
3832 if(TM.tmPitchAndFamily == 0 || /* fixed */
3833 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
3834 TM.tmPitchAndFamily = FF_MODERN;
3835 else
3837 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
3839 case PAN_ANY:
3840 case PAN_NO_FIT:
3841 default:
3842 TM.tmPitchAndFamily |= FF_DONTCARE;
3843 break;
3845 case PAN_SERIF_COVE:
3846 case PAN_SERIF_OBTUSE_COVE:
3847 case PAN_SERIF_SQUARE_COVE:
3848 case PAN_SERIF_OBTUSE_SQUARE_COVE:
3849 case PAN_SERIF_SQUARE:
3850 case PAN_SERIF_THIN:
3851 case PAN_SERIF_BONE:
3852 case PAN_SERIF_EXAGGERATED:
3853 case PAN_SERIF_TRIANGLE:
3854 TM.tmPitchAndFamily |= FF_ROMAN;
3855 break;
3857 case PAN_SERIF_NORMAL_SANS:
3858 case PAN_SERIF_OBTUSE_SANS:
3859 case PAN_SERIF_PERP_SANS:
3860 case PAN_SERIF_FLARED:
3861 case PAN_SERIF_ROUNDED:
3862 TM.tmPitchAndFamily |= FF_SWISS;
3863 break;
3866 break;
3869 if(FT_IS_SCALABLE(ft_face))
3870 TM.tmPitchAndFamily |= TMPF_VECTOR;
3872 if(FT_IS_SFNT(ft_face))
3874 if (font->ntmFlags & NTM_PS_OPENTYPE)
3875 TM.tmPitchAndFamily |= TMPF_DEVICE;
3876 else
3877 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
3880 TM.tmCharSet = font->charset;
3882 font->otm.otmFiller = 0;
3883 memcpy(&font->otm.otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
3884 font->otm.otmfsSelection = pOS2->fsSelection;
3885 if (font->fake_italic)
3886 font->otm.otmfsSelection |= 1;
3887 if (font->fake_bold)
3888 font->otm.otmfsSelection |= 1 << 5;
3889 /* Only return valid bits that define embedding and subsetting restrictions */
3890 font->otm.otmfsType = pOS2->fsType & 0x30e;
3891 font->otm.otmsCharSlopeRise = pHori->caret_Slope_Rise;
3892 font->otm.otmsCharSlopeRun = pHori->caret_Slope_Run;
3893 font->otm.otmItalicAngle = 0; /* POST table */
3894 font->otm.otmAscent = SCALE_Y(pOS2->sTypoAscender);
3895 font->otm.otmDescent = SCALE_Y(pOS2->sTypoDescender);
3896 font->otm.otmLineGap = SCALE_Y(pOS2->sTypoLineGap);
3897 font->otm.otmsCapEmHeight = SCALE_Y(pOS2->sCapHeight);
3898 font->otm.otmsXHeight = SCALE_Y(pOS2->sxHeight);
3899 font->otm.otmrcFontBox.left = SCALE_X(ft_face->bbox.xMin);
3900 font->otm.otmrcFontBox.right = SCALE_X(ft_face->bbox.xMax);
3901 font->otm.otmrcFontBox.top = SCALE_Y(ft_face->bbox.yMax);
3902 font->otm.otmrcFontBox.bottom = SCALE_Y(ft_face->bbox.yMin);
3903 font->otm.otmMacAscent = TM.tmAscent;
3904 font->otm.otmMacDescent = -TM.tmDescent;
3905 font->otm.otmMacLineGap = SCALE_Y(pHori->Line_Gap);
3906 font->otm.otmusMinimumPPEM = 0; /* TT Header */
3907 font->otm.otmptSubscriptSize.x = SCALE_X(pOS2->ySubscriptXSize);
3908 font->otm.otmptSubscriptSize.y = SCALE_Y(pOS2->ySubscriptYSize);
3909 font->otm.otmptSubscriptOffset.x = SCALE_X(pOS2->ySubscriptXOffset);
3910 font->otm.otmptSubscriptOffset.y = SCALE_Y(pOS2->ySubscriptYOffset);
3911 font->otm.otmptSuperscriptSize.x = SCALE_X(pOS2->ySuperscriptXSize);
3912 font->otm.otmptSuperscriptSize.y = SCALE_Y(pOS2->ySuperscriptYSize);
3913 font->otm.otmptSuperscriptOffset.x = SCALE_X(pOS2->ySuperscriptXOffset);
3914 font->otm.otmptSuperscriptOffset.y = SCALE_Y(pOS2->ySuperscriptYOffset);
3915 font->otm.otmsStrikeoutSize = SCALE_Y(pOS2->yStrikeoutSize);
3916 font->otm.otmsStrikeoutPosition = SCALE_Y(pOS2->yStrikeoutPosition);
3917 if(!pPost) {
3918 font->otm.otmsUnderscoreSize = 0;
3919 font->otm.otmsUnderscorePosition = 0;
3920 } else {
3921 font->otm.otmsUnderscoreSize = SCALE_Y(pPost->underlineThickness);
3922 font->otm.otmsUnderscorePosition = SCALE_Y(pPost->underlinePosition);
3924 #undef SCALE_X
3925 #undef SCALE_Y
3926 #undef TM
3927 return TRUE;
3930 /*************************************************************
3931 * freetype_get_char_width_info
3933 static BOOL freetype_get_char_width_info( struct gdi_font *font, struct char_width_info *info )
3935 FT_Face ft_face = get_ft_face( font );
3936 TT_HoriHeader *pHori;
3938 TRACE("%p, %p\n", font, info);
3940 if ((pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea)))
3942 FT_Fixed em_scale = pFT_MulDiv(font->ppem, 1 << 16, ft_face->units_per_EM);
3943 info->lsb = (SHORT)pFT_MulFix(pHori->min_Left_Side_Bearing, em_scale);
3944 info->rsb = (SHORT)pFT_MulFix(pHori->min_Right_Side_Bearing, em_scale);
3945 return TRUE;
3947 return FALSE;
3951 /*************************************************************
3952 * freetype_get_unicode_ranges
3954 * Retrieve a list of supported Unicode ranges for a given font.
3955 * Can be called with NULL gs to calculate the buffer size. Returns
3956 * the number of ranges found.
3958 static UINT freetype_get_unicode_ranges( struct gdi_font *font, GLYPHSET *gs )
3960 FT_Face ft_face = get_ft_face( font );
3961 UINT num_ranges = 0;
3963 if (ft_face->charmap->encoding == FT_ENCODING_UNICODE)
3965 FT_UInt glyph_code;
3966 FT_ULong char_code, char_code_prev;
3968 glyph_code = 0;
3969 char_code_prev = char_code = pFT_Get_First_Char(ft_face, &glyph_code);
3971 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
3972 ft_face->num_glyphs, glyph_code, char_code);
3974 if (!glyph_code) return 0;
3976 if (gs)
3978 gs->ranges[0].wcLow = (USHORT)char_code;
3979 gs->ranges[0].cGlyphs = 0;
3980 gs->cGlyphsSupported = 0;
3983 num_ranges = 1;
3984 while (glyph_code)
3986 if (char_code < char_code_prev)
3988 ERR("expected increasing char code from FT_Get_Next_Char\n");
3989 return 0;
3991 if (char_code - char_code_prev > 1)
3993 num_ranges++;
3994 if (gs)
3996 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
3997 gs->ranges[num_ranges - 1].cGlyphs = 1;
3998 gs->cGlyphsSupported++;
4001 else if (gs)
4003 gs->ranges[num_ranges - 1].cGlyphs++;
4004 gs->cGlyphsSupported++;
4006 char_code_prev = char_code;
4007 char_code = pFT_Get_Next_Char(ft_face, char_code, &glyph_code);
4010 else
4012 DWORD encoding = RtlUlongByteSwap(ft_face->charmap->encoding);
4013 FIXME("encoding %s not supported\n", debugstr_an((char *)&encoding, 4));
4016 return num_ranges;
4019 /*************************************************************************
4020 * Kerning support for TrueType fonts
4023 struct TT_kern_table
4025 USHORT version;
4026 USHORT nTables;
4029 struct TT_kern_subtable
4031 USHORT version;
4032 USHORT length;
4033 union
4035 USHORT word;
4036 struct
4038 USHORT horizontal : 1;
4039 USHORT minimum : 1;
4040 USHORT cross_stream: 1;
4041 USHORT override : 1;
4042 USHORT reserved1 : 4;
4043 USHORT format : 8;
4044 } bits;
4045 } coverage;
4048 struct TT_format0_kern_subtable
4050 USHORT nPairs;
4051 USHORT searchRange;
4052 USHORT entrySelector;
4053 USHORT rangeShift;
4056 struct TT_kern_pair
4058 USHORT left;
4059 USHORT right;
4060 short value;
4063 static DWORD parse_format0_kern_subtable(struct gdi_font *font,
4064 const struct TT_format0_kern_subtable *tt_f0_ks,
4065 const USHORT *glyph_to_char,
4066 KERNINGPAIR *kern_pair, DWORD cPairs)
4068 FT_Face ft_face = get_ft_face( font );
4069 USHORT i, nPairs;
4070 const struct TT_kern_pair *tt_kern_pair;
4072 TRACE("font height %d, units_per_EM %d\n", font->ppem, ft_face->units_per_EM);
4074 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
4076 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
4077 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
4078 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
4080 if (!kern_pair || !cPairs)
4081 return nPairs;
4083 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
4085 nPairs = min(nPairs, cPairs);
4087 for (i = 0; i < nPairs; i++)
4089 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
4090 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
4091 /* this algorithm appears to better match what Windows does */
4092 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
4093 if (kern_pair->iKernAmount < 0)
4095 kern_pair->iKernAmount -= ft_face->units_per_EM / 2;
4096 kern_pair->iKernAmount -= font->ppem;
4098 else if (kern_pair->iKernAmount > 0)
4100 kern_pair->iKernAmount += ft_face->units_per_EM / 2;
4101 kern_pair->iKernAmount += font->ppem;
4103 kern_pair->iKernAmount /= ft_face->units_per_EM;
4105 TRACE("left %u right %u value %d\n",
4106 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
4108 kern_pair++;
4110 TRACE("copied %u entries\n", nPairs);
4111 return nPairs;
4114 /*************************************************************
4115 * freetype_get_kerning_pairs
4117 static UINT freetype_get_kerning_pairs( struct gdi_font *font, KERNINGPAIR **pairs )
4119 FT_Face ft_face = get_ft_face( font );
4120 UINT length, count = 0;
4121 void *buf;
4122 const struct TT_kern_table *tt_kern_table;
4123 const struct TT_kern_subtable *tt_kern_subtable;
4124 USHORT i, nTables;
4125 USHORT *glyph_to_char;
4127 length = freetype_get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
4129 if (length == GDI_ERROR)
4131 TRACE("no kerning data in the font\n");
4132 return 0;
4135 buf = malloc( length );
4136 if (!buf) return 0;
4138 freetype_get_font_data(font, MS_KERN_TAG, 0, buf, length);
4140 /* build a glyph index to char code map */
4141 glyph_to_char = calloc( sizeof(USHORT), 65536 );
4142 if (!glyph_to_char)
4144 free( buf );
4145 return 0;
4148 if (ft_face->charmap->encoding == FT_ENCODING_UNICODE)
4150 FT_UInt glyph_code;
4151 FT_ULong char_code;
4153 glyph_code = 0;
4154 char_code = pFT_Get_First_Char(ft_face, &glyph_code);
4156 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
4157 ft_face->num_glyphs, glyph_code, char_code);
4159 while (glyph_code)
4161 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
4163 /* FIXME: This doesn't match what Windows does: it does some fancy
4164 * things with duplicate glyph index to char code mappings, while
4165 * we just avoid overriding existing entries.
4167 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
4168 glyph_to_char[glyph_code] = (USHORT)char_code;
4170 char_code = pFT_Get_Next_Char(ft_face, char_code, &glyph_code);
4173 else
4175 DWORD encoding = RtlUlongByteSwap(ft_face->charmap->encoding);
4176 ULONG n;
4178 FIXME("encoding %s not supported\n", debugstr_an((char *)&encoding, 4));
4179 for (n = 0; n <= 65535; n++)
4180 glyph_to_char[n] = (USHORT)n;
4183 tt_kern_table = buf;
4184 nTables = GET_BE_WORD(tt_kern_table->nTables);
4185 TRACE("version %u, nTables %u\n",
4186 GET_BE_WORD(tt_kern_table->version), nTables);
4188 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
4190 for (i = 0; i < nTables; i++)
4192 struct TT_kern_subtable tt_kern_subtable_copy;
4194 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
4195 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
4196 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
4198 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
4199 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
4200 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
4202 /* According to the TrueType specification this is the only format
4203 * that will be properly interpreted by Windows and OS/2
4205 if (tt_kern_subtable_copy.coverage.bits.format == 0)
4207 DWORD new_chunk, old_total = count;
4209 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
4210 glyph_to_char, NULL, 0);
4211 count += new_chunk;
4213 *pairs = realloc( *pairs, count * sizeof(**pairs));
4215 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
4216 glyph_to_char, *pairs + old_total, new_chunk);
4218 else
4219 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
4221 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
4224 free( glyph_to_char );
4225 free( buf );
4226 return count;
4229 static const struct font_backend_funcs font_funcs =
4231 freetype_load_fonts,
4232 fontconfig_enum_family_fallbacks,
4233 freetype_add_font,
4234 freetype_add_mem_font,
4235 freetype_load_font,
4236 freetype_get_font_data,
4237 freetype_get_aa_flags,
4238 freetype_get_glyph_index,
4239 freetype_get_default_glyph,
4240 freetype_get_glyph_outline,
4241 freetype_get_unicode_ranges,
4242 freetype_get_char_width_info,
4243 freetype_set_outline_text_metrics,
4244 freetype_set_bitmap_text_metrics,
4245 freetype_get_kerning_pairs,
4246 freetype_destroy_font
4249 const struct font_backend_funcs *init_freetype_lib(void)
4251 if (!init_freetype()) return NULL;
4252 #ifdef SONAME_LIBFONTCONFIG
4253 init_fontconfig();
4254 #endif
4255 NtQueryDefaultLocale( FALSE, &system_lcid );
4256 return &font_funcs;
4259 #else /* HAVE_FREETYPE */
4261 const struct font_backend_funcs *init_freetype_lib(void)
4263 return NULL;
4266 #endif /* HAVE_FREETYPE */