windows.media.speech: Add IIterable<IInspectable*> stubs.
[wine.git] / dlls / win32u / freetype.c
blobb6063a14570c235fc1b7a9663d792fc38ae46c57
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 HAVE_CARBON_CARBON_H
44 #define LoadResource __carbon_LoadResource
45 #define CheckMenuItem __carbon_CheckMenuItem
46 #define CompareString __carbon_CompareString
47 #define GetCurrentThread __carbon_GetCurrentThread
48 #define GetCurrentProcess __carbon_GetCurrentProcess
49 #define AnimatePalette __carbon_AnimatePalette
50 #define DeleteMenu __carbon_DeleteMenu
51 #define DrawMenu __carbon_DrawMenu
52 #define DrawMenuBar __carbon_DrawMenuBar
53 #define EnableMenuItem __carbon_EnableMenuItem
54 #define EqualRgn __carbon_EqualRgn
55 #define FillRgn __carbon_FillRgn
56 #define FrameRgn __carbon_FrameRgn
57 #define GetMenu __carbon_GetMenu
58 #define GetPixel __carbon_GetPixel
59 #define InvertRgn __carbon_InvertRgn
60 #define IsWindowVisible __carbon_IsWindowVisible
61 #define LineTo __carbon_LineTo
62 #define MoveWindow __carbon_MoveWindow
63 #define OffsetRgn __carbon_OffsetRgn
64 #define PaintRgn __carbon_PaintRgn
65 #define Polygon __carbon_Polygon
66 #define ResizePalette __carbon_ResizePalette
67 #define SetRectRgn __carbon_SetRectRgn
68 #define ShowWindow __carbon_ShowWindow
69 #include <Carbon/Carbon.h>
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 /* HAVE_CARBON_CARBON_H */
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 HAVE_CARBON_CARBON_H
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 /* HAVE_CARBON_CARBON_H */
531 This function builds an FT_Fixed from a double. It fails if the absolute
532 value of the float number is greater than 32768.
534 static inline FT_Fixed FT_FixedFromFloat(double f)
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 LPWSTR strdupW(LPCWSTR p)
589 LPWSTR ret;
590 DWORD len = (lstrlenW(p) + 1) * sizeof(WCHAR);
591 ret = malloc( len );
592 memcpy(ret, p, len);
593 return ret;
596 static WCHAR *towstr(const char *str)
598 DWORD len = strlen(str) + 1;
599 WCHAR *wstr = malloc( len * sizeof(WCHAR) );
600 win32u_mbtowc( NULL, wstr, len * sizeof(WCHAR), str, len );
601 return wstr;
605 static const LANGID mac_langid_table[] =
607 MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ENGLISH */
608 MAKELANGID(LANG_FRENCH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FRENCH */
609 MAKELANGID(LANG_GERMAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GERMAN */
610 MAKELANGID(LANG_ITALIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ITALIAN */
611 MAKELANGID(LANG_DUTCH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_DUTCH */
612 MAKELANGID(LANG_SWEDISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SWEDISH */
613 MAKELANGID(LANG_SPANISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SPANISH */
614 MAKELANGID(LANG_DANISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_DANISH */
615 MAKELANGID(LANG_PORTUGUESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PORTUGUESE */
616 MAKELANGID(LANG_NORWEGIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_NORWEGIAN */
617 MAKELANGID(LANG_HEBREW,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HEBREW */
618 MAKELANGID(LANG_JAPANESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_JAPANESE */
619 MAKELANGID(LANG_ARABIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ARABIC */
620 MAKELANGID(LANG_FINNISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FINNISH */
621 MAKELANGID(LANG_GREEK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GREEK */
622 MAKELANGID(LANG_ICELANDIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ICELANDIC */
623 MAKELANGID(LANG_MALTESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALTESE */
624 MAKELANGID(LANG_TURKISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TURKISH */
625 MAKELANGID(LANG_CROATIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CROATIAN */
626 MAKELANGID(LANG_CHINESE_TRADITIONAL,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CHINESE_TRADITIONAL */
627 MAKELANGID(LANG_URDU,SUBLANG_DEFAULT), /* TT_MAC_LANGID_URDU */
628 MAKELANGID(LANG_HINDI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HINDI */
629 MAKELANGID(LANG_THAI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_THAI */
630 MAKELANGID(LANG_KOREAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KOREAN */
631 MAKELANGID(LANG_LITHUANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LITHUANIAN */
632 MAKELANGID(LANG_POLISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_POLISH */
633 MAKELANGID(LANG_HUNGARIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HUNGARIAN */
634 MAKELANGID(LANG_ESTONIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ESTONIAN */
635 MAKELANGID(LANG_LATVIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LETTISH */
636 MAKELANGID(LANG_SAMI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SAAMISK */
637 MAKELANGID(LANG_FAEROESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FAEROESE */
638 MAKELANGID(LANG_FARSI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FARSI */
639 MAKELANGID(LANG_RUSSIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_RUSSIAN */
640 MAKELANGID(LANG_CHINESE_SIMPLIFIED,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CHINESE_SIMPLIFIED */
641 MAKELANGID(LANG_DUTCH,SUBLANG_DUTCH_BELGIAN), /* TT_MAC_LANGID_FLEMISH */
642 MAKELANGID(LANG_IRISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_IRISH */
643 MAKELANGID(LANG_ALBANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ALBANIAN */
644 MAKELANGID(LANG_ROMANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ROMANIAN */
645 MAKELANGID(LANG_CZECH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CZECH */
646 MAKELANGID(LANG_SLOVAK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SLOVAK */
647 MAKELANGID(LANG_SLOVENIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SLOVENIAN */
648 0, /* TT_MAC_LANGID_YIDDISH */
649 MAKELANGID(LANG_SERBIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SERBIAN */
650 MAKELANGID(LANG_MACEDONIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MACEDONIAN */
651 MAKELANGID(LANG_BULGARIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BULGARIAN */
652 MAKELANGID(LANG_UKRAINIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UKRAINIAN */
653 MAKELANGID(LANG_BELARUSIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BYELORUSSIAN */
654 MAKELANGID(LANG_UZBEK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UZBEK */
655 MAKELANGID(LANG_KAZAK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KAZAKH */
656 MAKELANGID(LANG_AZERI,SUBLANG_AZERI_CYRILLIC), /* TT_MAC_LANGID_AZERBAIJANI */
657 0, /* TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT */
658 MAKELANGID(LANG_ARMENIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ARMENIAN */
659 MAKELANGID(LANG_GEORGIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GEORGIAN */
660 0, /* TT_MAC_LANGID_MOLDAVIAN */
661 MAKELANGID(LANG_KYRGYZ,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KIRGHIZ */
662 MAKELANGID(LANG_TAJIK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TAJIKI */
663 MAKELANGID(LANG_TURKMEN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TURKMEN */
664 MAKELANGID(LANG_MONGOLIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MONGOLIAN */
665 MAKELANGID(LANG_MONGOLIAN,SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA), /* TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT */
666 MAKELANGID(LANG_PASHTO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PASHTO */
667 0, /* TT_MAC_LANGID_KURDISH */
668 MAKELANGID(LANG_KASHMIRI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KASHMIRI */
669 MAKELANGID(LANG_SINDHI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SINDHI */
670 MAKELANGID(LANG_TIBETAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TIBETAN */
671 MAKELANGID(LANG_NEPALI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_NEPALI */
672 MAKELANGID(LANG_SANSKRIT,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SANSKRIT */
673 MAKELANGID(LANG_MARATHI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MARATHI */
674 MAKELANGID(LANG_BENGALI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BENGALI */
675 MAKELANGID(LANG_ASSAMESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ASSAMESE */
676 MAKELANGID(LANG_GUJARATI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GUJARATI */
677 MAKELANGID(LANG_PUNJABI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PUNJABI */
678 MAKELANGID(LANG_ORIYA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ORIYA */
679 MAKELANGID(LANG_MALAYALAM,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAYALAM */
680 MAKELANGID(LANG_KANNADA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KANNADA */
681 MAKELANGID(LANG_TAMIL,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TAMIL */
682 MAKELANGID(LANG_TELUGU,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TELUGU */
683 MAKELANGID(LANG_SINHALESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SINHALESE */
684 0, /* TT_MAC_LANGID_BURMESE */
685 MAKELANGID(LANG_KHMER,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KHMER */
686 MAKELANGID(LANG_LAO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LAO */
687 MAKELANGID(LANG_VIETNAMESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_VIETNAMESE */
688 MAKELANGID(LANG_INDONESIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_INDONESIAN */
689 0, /* TT_MAC_LANGID_TAGALOG */
690 MAKELANGID(LANG_MALAY,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAY_ROMAN_SCRIPT */
691 0, /* TT_MAC_LANGID_MALAY_ARABIC_SCRIPT */
692 MAKELANGID(LANG_AMHARIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_AMHARIC */
693 MAKELANGID(LANG_TIGRIGNA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TIGRINYA */
694 0, /* TT_MAC_LANGID_GALLA */
695 0, /* TT_MAC_LANGID_SOMALI */
696 MAKELANGID(LANG_SWAHILI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SWAHILI */
697 0, /* TT_MAC_LANGID_RUANDA */
698 0, /* TT_MAC_LANGID_RUNDI */
699 0, /* TT_MAC_LANGID_CHEWA */
700 MAKELANGID(LANG_MALAGASY,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAGASY */
701 MAKELANGID(LANG_ESPERANTO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ESPERANTO */
702 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 95-111 */
703 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 112-127 */
704 MAKELANGID(LANG_WELSH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_WELSH */
705 MAKELANGID(LANG_BASQUE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BASQUE */
706 MAKELANGID(LANG_CATALAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CATALAN */
707 0, /* TT_MAC_LANGID_LATIN */
708 MAKELANGID(LANG_QUECHUA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_QUECHUA */
709 0, /* TT_MAC_LANGID_GUARANI */
710 0, /* TT_MAC_LANGID_AYMARA */
711 MAKELANGID(LANG_TATAR,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TATAR */
712 MAKELANGID(LANG_UIGHUR,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UIGHUR */
713 0, /* TT_MAC_LANGID_DZONGKHA */
714 0, /* TT_MAC_LANGID_JAVANESE */
715 0, /* TT_MAC_LANGID_SUNDANESE */
716 MAKELANGID(LANG_GALICIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GALICIAN */
717 MAKELANGID(LANG_AFRIKAANS,SUBLANG_DEFAULT), /* TT_MAC_LANGID_AFRIKAANS */
718 MAKELANGID(LANG_BRETON,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BRETON */
719 MAKELANGID(LANG_INUKTITUT,SUBLANG_DEFAULT), /* TT_MAC_LANGID_INUKTITUT */
720 MAKELANGID(LANG_SCOTTISH_GAELIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SCOTTISH_GAELIC */
721 MAKELANGID(LANG_MANX_GAELIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MANX_GAELIC */
722 MAKELANGID(LANG_IRISH,SUBLANG_IRISH_IRELAND), /* TT_MAC_LANGID_IRISH_GAELIC */
723 0, /* TT_MAC_LANGID_TONGAN */
724 0, /* TT_MAC_LANGID_GREEK_POLYTONIC */
725 MAKELANGID(LANG_GREENLANDIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GREELANDIC */
726 MAKELANGID(LANG_AZERI,SUBLANG_AZERI_LATIN), /* TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT */
729 static CPTABLEINFO *get_mac_code_page( const FT_SfntName *name )
731 int id = name->encoding_id;
733 if (name->encoding_id == TT_MAC_ID_SIMPLIFIED_CHINESE) id = 8; /* special case */
734 return get_cptable( 10000 + id );
737 static int match_name_table_language( const FT_SfntName *name, LANGID lang )
739 LANGID name_lang;
740 int res = 0;
742 switch (name->platform_id)
744 case TT_PLATFORM_MICROSOFT:
745 res += 5; /* prefer the Microsoft name */
746 switch (name->encoding_id)
748 case TT_MS_ID_UNICODE_CS:
749 case TT_MS_ID_SYMBOL_CS:
750 name_lang = name->language_id;
751 break;
752 default:
753 return 0;
755 break;
756 case TT_PLATFORM_MACINTOSH:
757 if (!get_mac_code_page( name )) return 0;
758 if (name->language_id >= ARRAY_SIZE( mac_langid_table )) return 0;
759 name_lang = mac_langid_table[name->language_id];
760 break;
761 case TT_PLATFORM_APPLE_UNICODE:
762 res += 2; /* prefer Unicode encodings */
763 switch (name->encoding_id)
765 case TT_APPLE_ID_DEFAULT:
766 case TT_APPLE_ID_ISO_10646:
767 case TT_APPLE_ID_UNICODE_2_0:
768 if (name->language_id >= ARRAY_SIZE( mac_langid_table )) return 0;
769 name_lang = mac_langid_table[name->language_id];
770 break;
771 default:
772 return 0;
774 break;
775 default:
776 return 0;
778 if (name_lang == lang) res += 30;
779 else if (PRIMARYLANGID( name_lang ) == PRIMARYLANGID( lang )) res += 20;
780 else if (name_lang == MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT )) res += 10;
781 else if (lang == MAKELANGID( LANG_NEUTRAL, SUBLANG_NEUTRAL )) res += 5 * (0x100000 - name_lang);
782 return res;
785 static WCHAR *copy_name_table_string( const FT_SfntName *name )
787 WCHAR *ret;
788 CPTABLEINFO *cp;
789 DWORD i;
791 switch (name->platform_id)
793 case TT_PLATFORM_APPLE_UNICODE:
794 case TT_PLATFORM_MICROSOFT:
795 ret = malloc( name->string_len + sizeof(WCHAR) );
796 for (i = 0; i < name->string_len / 2; i++)
797 ret[i] = (name->string[i * 2] << 8) | name->string[i * 2 + 1];
798 ret[i] = 0;
799 return ret;
800 case TT_PLATFORM_MACINTOSH:
801 if (!(cp = get_mac_code_page( name ))) return NULL;
802 ret = malloc( (name->string_len + 1) * sizeof(WCHAR) );
803 i = win32u_mbtowc( cp, ret, name->string_len * sizeof(WCHAR),
804 (char *)name->string, name->string_len );
805 ret[i / sizeof(WCHAR)] = 0;
806 return ret;
808 return NULL;
811 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, LANGID language_id)
813 FT_SfntName name;
814 FT_UInt num_names, name_index;
815 int res, best_lang = 0, best_index = -1;
817 if (!FT_IS_SFNT(ft_face)) return NULL;
819 num_names = pFT_Get_Sfnt_Name_Count( ft_face );
821 for (name_index = 0; name_index < num_names; name_index++)
823 if (pFT_Get_Sfnt_Name( ft_face, name_index, &name )) continue;
824 if (name.name_id != name_id) continue;
825 res = match_name_table_language( &name, language_id );
826 if (res > best_lang)
828 best_lang = res;
829 best_index = name_index;
833 if (best_index != -1 && !pFT_Get_Sfnt_Name( ft_face, best_index, &name ))
835 WCHAR *ret = copy_name_table_string( &name );
836 TRACE( "name %u found platform %u lang %04x %s\n",
837 name_id, name.platform_id, name.language_id, debugstr_w( ret ));
838 return ret;
840 return NULL;
843 static WCHAR *ft_face_get_family_name( FT_Face ft_face, LANGID langid )
845 WCHAR *family_name;
847 if ((family_name = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, langid )))
848 return family_name;
850 return towstr( ft_face->family_name );
853 static WCHAR *ft_face_get_style_name( FT_Face ft_face, LANGID langid )
855 WCHAR *style_name;
857 if ((style_name = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, langid )))
858 return style_name;
860 return towstr( ft_face->style_name );
863 static WCHAR *ft_face_get_full_name( FT_Face ft_face, LANGID langid )
865 static const WCHAR space_w[] = {' ',0};
866 WCHAR *full_name, *style_name;
867 SIZE_T length;
869 if ((full_name = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, langid )))
870 return full_name;
872 full_name = ft_face_get_family_name( ft_face, langid );
873 style_name = ft_face_get_style_name( ft_face, langid );
875 length = lstrlenW( full_name ) + lstrlenW( space_w ) + lstrlenW( style_name ) + 1;
876 full_name = realloc( full_name, length * sizeof(WCHAR) );
878 lstrcatW( full_name, space_w );
879 lstrcatW( full_name, style_name );
880 free( style_name );
882 WARN( "full name not found, using %s instead\n", debugstr_w(full_name) );
883 return full_name;
886 static inline FT_Fixed get_font_version( FT_Face ft_face )
888 FT_Fixed version = 0;
889 TT_Header *header;
891 header = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head );
892 if (header) version = header->Font_Revision;
894 return version;
897 static inline DWORD get_ntm_flags( FT_Face ft_face )
899 DWORD flags = 0;
900 FT_ULong table_size = 0;
901 FT_WinFNT_HeaderRec winfnt_header;
903 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) flags |= NTM_ITALIC;
904 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD) flags |= NTM_BOLD;
906 /* fixup the flag for our fake-bold implementation. */
907 if (!FT_IS_SCALABLE( ft_face ) &&
908 !pFT_Get_WinFNT_Header( ft_face, &winfnt_header ) &&
909 winfnt_header.weight > FW_NORMAL )
910 flags |= NTM_BOLD;
912 if (flags == 0) flags = NTM_REGULAR;
914 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL, &table_size ))
915 flags |= NTM_PS_OPENTYPE;
917 return flags;
920 static inline void get_bitmap_size( FT_Face ft_face, struct bitmap_font_size *face_size )
922 My_FT_Bitmap_Size *size;
923 FT_WinFNT_HeaderRec winfnt_header;
925 size = (My_FT_Bitmap_Size *)ft_face->available_sizes;
926 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
927 size->height, size->width, size->size >> 6,
928 size->x_ppem >> 6, size->y_ppem >> 6);
929 face_size->height = size->height;
930 face_size->width = size->width;
931 face_size->size = size->size;
932 face_size->x_ppem = size->x_ppem;
933 face_size->y_ppem = size->y_ppem;
935 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header )) {
936 face_size->internal_leading = winfnt_header.internal_leading;
937 if (winfnt_header.external_leading > 0 &&
938 (face_size->height ==
939 winfnt_header.pixel_height + winfnt_header.external_leading))
940 face_size->height = winfnt_header.pixel_height;
944 static inline void get_fontsig( FT_Face ft_face, FONTSIGNATURE *fs )
946 TT_OS2 *os2;
947 FT_WinFNT_HeaderRec winfnt_header;
948 int i;
950 memset( fs, 0, sizeof(*fs) );
952 os2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 );
953 if (os2)
955 fs->fsUsb[0] = os2->ulUnicodeRange1;
956 fs->fsUsb[1] = os2->ulUnicodeRange2;
957 fs->fsUsb[2] = os2->ulUnicodeRange3;
958 fs->fsUsb[3] = os2->ulUnicodeRange4;
960 if (os2->version == 0)
962 if (os2->usFirstCharIndex >= 0xf000 && os2->usFirstCharIndex < 0xf100)
963 fs->fsCsb[0] = FS_SYMBOL;
964 else
965 fs->fsCsb[0] = FS_LATIN1;
967 else
969 fs->fsCsb[0] = os2->ulCodePageRange1;
970 fs->fsCsb[1] = os2->ulCodePageRange2;
973 else
975 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
977 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
978 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
979 switch (winfnt_header.charset)
981 case ANSI_CHARSET: fs->fsCsb[0] = FS_LATIN1; break;
982 case EASTEUROPE_CHARSET: fs->fsCsb[0] = FS_LATIN2; break;
983 case RUSSIAN_CHARSET: fs->fsCsb[0] = FS_CYRILLIC; break;
984 case GREEK_CHARSET: fs->fsCsb[0] = FS_GREEK; break;
985 case TURKISH_CHARSET: fs->fsCsb[0] = FS_TURKISH; break;
986 case HEBREW_CHARSET: fs->fsCsb[0] = FS_HEBREW; break;
987 case ARABIC_CHARSET: fs->fsCsb[0] = FS_ARABIC; break;
988 case BALTIC_CHARSET: fs->fsCsb[0] = FS_BALTIC; break;
989 case VIETNAMESE_CHARSET: fs->fsCsb[0] = FS_VIETNAMESE; break;
990 case THAI_CHARSET: fs->fsCsb[0] = FS_THAI; break;
991 case SHIFTJIS_CHARSET: fs->fsCsb[0] = FS_JISJAPAN; break;
992 case GB2312_CHARSET: fs->fsCsb[0] = FS_CHINESESIMP; break;
993 case HANGEUL_CHARSET: fs->fsCsb[0] = FS_WANSUNG; break;
994 case CHINESEBIG5_CHARSET: fs->fsCsb[0] = FS_CHINESETRAD; break;
995 case JOHAB_CHARSET: fs->fsCsb[0] = FS_JOHAB; break;
996 case SYMBOL_CHARSET: fs->fsCsb[0] = FS_SYMBOL; break;
1001 if (fs->fsCsb[0] == 0)
1003 /* let's see if we can find any interesting cmaps */
1004 for (i = 0; i < ft_face->num_charmaps; i++)
1006 switch (ft_face->charmaps[i]->encoding)
1008 case FT_ENCODING_UNICODE:
1009 case FT_ENCODING_APPLE_ROMAN:
1010 fs->fsCsb[0] |= FS_LATIN1;
1011 break;
1012 case FT_ENCODING_MS_SYMBOL:
1013 fs->fsCsb[0] |= FS_SYMBOL;
1014 break;
1015 default:
1016 break;
1022 static FT_Face new_ft_face( const char *file, void *font_data_ptr, DWORD font_data_size,
1023 FT_Long face_index, BOOL allow_bitmap )
1025 FT_Error err;
1026 TT_OS2 *pOS2;
1027 FT_Face ft_face;
1029 if (file)
1031 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1032 err = pFT_New_Face(library, file, face_index, &ft_face);
1034 else
1036 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1037 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1040 if (err != 0)
1042 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1043 return NULL;
1046 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1047 if (!FT_IS_SCALABLE( ft_face ) && FT_SimpleVersion < FT_VERSION_VALUE(2, 1, 9))
1049 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1050 goto fail;
1053 if (!FT_IS_SFNT( ft_face ))
1055 if (FT_IS_SCALABLE( ft_face ) || !allow_bitmap )
1057 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1058 goto fail;
1061 else
1063 if (!(pOS2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 )) ||
1064 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_hhea ) ||
1065 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head ))
1067 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1068 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1069 goto fail;
1072 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1073 we don't want to load these. */
1074 if (!memcmp( pOS2->achVendID, "Wine", sizeof(pOS2->achVendID) ))
1076 FT_ULong len = 0;
1078 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len ))
1080 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1081 goto fail;
1086 if (!ft_face->family_name || !ft_face->style_name)
1088 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1089 goto fail;
1092 return ft_face;
1093 fail:
1094 pFT_Done_Face( ft_face );
1095 return NULL;
1098 struct family_names_data
1100 LANGID primary_langid;
1101 struct opentype_name family_name;
1102 struct opentype_name second_name;
1103 BOOL primary_seen;
1104 BOOL english_seen;
1107 static BOOL search_family_names_callback( LANGID langid, struct opentype_name *name, void *user )
1109 struct family_names_data *data = user;
1111 if (langid == MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT))
1113 data->english_seen = TRUE;
1114 if (data->primary_langid == langid) data->primary_seen = TRUE;
1116 if (!data->family_name.bytes) data->family_name = *name;
1117 else if (data->primary_langid != langid) data->second_name = *name;
1119 else if (data->primary_langid == langid)
1121 data->primary_seen = TRUE;
1122 if (!data->second_name.bytes) data->second_name = data->family_name;
1123 data->family_name = *name;
1125 else if (!data->second_name.bytes) data->second_name = *name;
1127 if (data->family_name.bytes && data->second_name.bytes && data->primary_seen && data->english_seen)
1128 return TRUE;
1129 return FALSE;
1132 struct face_name_data
1134 LANGID primary_langid;
1135 struct opentype_name face_name;
1138 static BOOL search_face_name_callback( LANGID langid, struct opentype_name *name, void *user )
1140 struct face_name_data *data = user;
1142 if (langid == data->primary_langid || (langid == MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT) && !data->face_name.bytes))
1143 data->face_name = *name;
1145 return langid == data->primary_langid;
1148 static WCHAR *decode_opentype_name( struct opentype_name *name )
1150 WCHAR buffer[512];
1151 DWORD len;
1153 if (!name->codepage)
1155 len = min( ARRAY_SIZE(buffer), name->length / sizeof(WCHAR) );
1156 while (len--) buffer[len] = GET_BE_WORD( ((WORD *)name->bytes)[len] );
1157 len = min( ARRAY_SIZE(buffer), name->length / sizeof(WCHAR) );
1159 else
1161 CPTABLEINFO *cptable = get_cptable( name->codepage );
1162 if (!cptable) return NULL;
1163 len = win32u_mbtowc( cptable, buffer, sizeof(buffer), name->bytes, name->length );
1164 len /= sizeof(WCHAR);
1167 buffer[ARRAY_SIZE(buffer) - 1] = 0;
1168 if (len == ARRAY_SIZE(buffer)) WARN("Truncated font name %s -> %s\n", debugstr_an(name->bytes, name->length), debugstr_w(buffer));
1169 else buffer[len] = 0;
1171 return strdupW( buffer );
1174 struct unix_face
1176 FT_Face ft_face;
1177 BOOL scalable;
1178 UINT num_faces;
1179 WCHAR *family_name;
1180 WCHAR *second_name;
1181 WCHAR *style_name;
1182 WCHAR *full_name;
1183 DWORD ntm_flags;
1184 DWORD font_version;
1185 FONTSIGNATURE fs;
1186 struct bitmap_font_size size;
1189 static struct unix_face *unix_face_create( const char *unix_name, void *data_ptr, DWORD data_size,
1190 UINT face_index, DWORD flags )
1192 static const WCHAR space_w[] = {' ',0};
1194 const struct ttc_sfnt_v1 *ttc_sfnt_v1;
1195 const struct tt_name_v0 *tt_name_v0;
1196 struct unix_face *This;
1197 struct stat st;
1198 DWORD face_count;
1199 int fd, length;
1201 TRACE( "unix_name %s, face_index %u, data_ptr %p, data_size %u, flags %#x\n",
1202 unix_name, face_index, data_ptr, data_size, flags );
1204 if (unix_name)
1206 if ((fd = open( unix_name, O_RDONLY )) == -1) return NULL;
1207 if (fstat( fd, &st ) == -1)
1209 close( fd );
1210 return NULL;
1212 data_size = st.st_size;
1213 data_ptr = mmap( NULL, data_size, PROT_READ, MAP_PRIVATE, fd, 0 );
1214 close( fd );
1215 if (data_ptr == MAP_FAILED) return NULL;
1218 if (!(This = calloc( 1, sizeof(*This) ))) goto done;
1220 if (opentype_get_ttc_sfnt_v1( data_ptr, data_size, face_index, &face_count, &ttc_sfnt_v1 ) &&
1221 opentype_get_tt_name_v0( data_ptr, data_size, ttc_sfnt_v1, &tt_name_v0 ) &&
1222 opentype_get_properties( data_ptr, data_size, ttc_sfnt_v1, &This->font_version,
1223 &This->fs, &This->ntm_flags ))
1225 struct family_names_data family_names;
1226 struct face_name_data style_name;
1227 struct face_name_data full_name;
1228 LANGID primary_langid = system_lcid;
1230 This->scalable = TRUE;
1231 This->num_faces = face_count;
1233 memset( &family_names, 0, sizeof(family_names) );
1234 family_names.primary_langid = primary_langid;
1235 opentype_enum_family_names( tt_name_v0, search_family_names_callback, &family_names );
1236 This->family_name = decode_opentype_name( &family_names.family_name );
1237 This->second_name = decode_opentype_name( &family_names.second_name );
1239 memset( &style_name, 0, sizeof(style_name) );
1240 style_name.primary_langid = primary_langid;
1241 opentype_enum_style_names( tt_name_v0, search_face_name_callback, &style_name );
1242 This->style_name = decode_opentype_name( &style_name.face_name );
1244 memset( &full_name, 0, sizeof(full_name) );
1245 full_name.primary_langid = primary_langid;
1246 opentype_enum_full_names( tt_name_v0, search_face_name_callback, &full_name );
1247 This->full_name = decode_opentype_name( &full_name.face_name );
1249 TRACE( "parsed font names family_name %s, second_name %s, primary_seen %d, english_seen %d, "
1250 "full_name %s, style_name %s\n",
1251 debugstr_w(This->family_name), debugstr_w(This->second_name),
1252 family_names.primary_seen, family_names.english_seen,
1253 debugstr_w(This->full_name), debugstr_w(This->style_name) );
1255 if (!This->full_name && This->family_name && This->style_name)
1257 length = lstrlenW( This->family_name ) + lstrlenW( space_w ) + lstrlenW( This->style_name ) + 1;
1258 This->full_name = malloc( length * sizeof(WCHAR) );
1259 lstrcpyW( This->full_name, This->family_name );
1260 lstrcatW( This->full_name, space_w );
1261 lstrcatW( This->full_name, This->style_name );
1262 WARN( "full name not found, using %s instead\n", debugstr_w(This->full_name) );
1265 else if ((This->ft_face = new_ft_face( unix_name, data_ptr, data_size, face_index, flags & ADDFONT_ALLOW_BITMAP )))
1267 WARN( "unable to parse font, falling back to FreeType\n" );
1268 This->scalable = FT_IS_SCALABLE( This->ft_face );
1269 This->num_faces = This->ft_face->num_faces;
1271 This->family_name = ft_face_get_family_name( This->ft_face, system_lcid );
1272 This->second_name = ft_face_get_family_name( This->ft_face, MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT) );
1274 /* try to find another secondary name, preferring the lowest langids */
1275 if (!wcsicmp( This->family_name, This->second_name ))
1277 free( This->second_name );
1278 This->second_name = ft_face_get_family_name( This->ft_face, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL) );
1279 if (!wcsicmp( This->family_name, This->second_name ))
1281 free( This->second_name );
1282 This->second_name = NULL;
1286 This->style_name = ft_face_get_style_name( This->ft_face, system_lcid );
1287 This->full_name = ft_face_get_full_name( This->ft_face, system_lcid );
1289 This->ntm_flags = get_ntm_flags( This->ft_face );
1290 This->font_version = get_font_version( This->ft_face );
1291 if (!This->scalable) get_bitmap_size( This->ft_face, &This->size );
1292 get_fontsig( This->ft_face, &This->fs );
1294 else
1296 free( This );
1297 This = NULL;
1300 done:
1301 if (unix_name) munmap( data_ptr, data_size );
1302 return This;
1305 static void unix_face_destroy( struct unix_face *This )
1307 if (This->ft_face) pFT_Done_Face( This->ft_face );
1308 free( This->full_name );
1309 free( This->style_name );
1310 free( This->second_name );
1311 free( This->family_name );
1312 free( This );
1315 static int add_unix_face( const char *unix_name, const WCHAR *file, void *data_ptr, SIZE_T data_size,
1316 DWORD face_index, DWORD flags, DWORD *num_faces )
1318 struct unix_face *unix_face;
1319 int ret;
1321 if (num_faces) *num_faces = 0;
1323 if (!(unix_face = unix_face_create( unix_name, data_ptr, data_size, face_index, flags )))
1324 return 0;
1326 if (unix_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1328 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(unix_name));
1329 unix_face_destroy( unix_face );
1330 return 0;
1333 if (!HIWORD( flags )) flags |= ADDFONT_AA_FLAGS( default_aa_flags );
1335 ret = add_gdi_face( unix_face->family_name, unix_face->second_name, unix_face->style_name, unix_face->full_name,
1336 file, data_ptr, data_size, face_index, unix_face->fs, unix_face->ntm_flags,
1337 unix_face->font_version, flags, unix_face->scalable ? NULL : &unix_face->size );
1339 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n", unix_face->fs.fsCsb[0], unix_face->fs.fsCsb[1],
1340 unix_face->fs.fsUsb[0], unix_face->fs.fsUsb[1], unix_face->fs.fsUsb[2], unix_face->fs.fsUsb[3]);
1342 if (num_faces) *num_faces = unix_face->num_faces;
1343 unix_face_destroy( unix_face );
1344 return ret;
1347 static WCHAR *get_dos_file_name( LPCSTR str )
1349 WCHAR *buffer;
1350 ULONG len = strlen(str) + 1;
1352 len += 8; /* \??\unix prefix */
1353 if (!(buffer = malloc( len * sizeof(WCHAR) ))) return NULL;
1354 if (wine_unix_to_nt_file_name( str, buffer, &len ))
1356 free( buffer );
1357 return NULL;
1359 return buffer;
1362 static char *get_unix_file_name( LPCWSTR path )
1364 UNICODE_STRING nt_name;
1365 OBJECT_ATTRIBUTES attr;
1366 NTSTATUS status;
1367 ULONG size = 256;
1368 char *buffer;
1370 nt_name.Buffer = (WCHAR *)path;
1371 nt_name.MaximumLength = nt_name.Length = lstrlenW( path ) * sizeof(WCHAR);
1372 InitializeObjectAttributes( &attr, &nt_name, 0, 0, NULL );
1373 for (;;)
1375 if (!(buffer = malloc( size ))) return NULL;
1376 status = wine_nt_to_unix_file_name( &attr, buffer, &size, FILE_OPEN_IF );
1377 if (status != STATUS_BUFFER_TOO_SMALL) break;
1378 free( buffer );
1380 if (status && status != STATUS_NO_SUCH_FILE)
1382 free( buffer );
1383 return NULL;
1385 return buffer;
1388 static INT AddFontToList(const WCHAR *dos_name, const char *unix_name, void *font_data_ptr,
1389 DWORD font_data_size, DWORD flags)
1391 DWORD face_index = 0, num_faces;
1392 INT ret = 0;
1393 WCHAR *filename = NULL;
1395 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1396 assert(unix_name || !(flags & ADDFONT_EXTERNAL_FONT));
1398 #ifdef HAVE_CARBON_CARBON_H
1399 if(unix_name)
1401 char **mac_list = expand_mac_font(unix_name);
1402 if(mac_list)
1404 BOOL had_one = FALSE;
1405 char **cursor;
1406 for(cursor = mac_list; *cursor; cursor++)
1408 had_one = TRUE;
1409 AddFontToList(NULL, *cursor, NULL, 0, flags);
1410 free( *cursor );
1412 free( mac_list );
1413 if(had_one)
1414 return 1;
1417 #endif /* HAVE_CARBON_CARBON_H */
1419 if (!dos_name && unix_name) dos_name = filename = get_dos_file_name( unix_name );
1422 ret += add_unix_face( unix_name, dos_name, font_data_ptr, font_data_size, face_index, flags, &num_faces );
1423 while (num_faces > ++face_index);
1425 free( filename );
1426 return ret;
1429 /*************************************************************
1430 * freetype_add_font
1432 static INT freetype_add_font( const WCHAR *file, DWORD flags )
1434 int ret = 0;
1435 char *unixname = get_unix_file_name( file );
1437 if (unixname)
1439 ret = AddFontToList( file, unixname, NULL, 0, flags );
1440 free( unixname );
1442 return ret;
1445 /*************************************************************
1446 * freetype_add_mem_font
1448 static INT freetype_add_mem_font( void *ptr, SIZE_T size, DWORD flags )
1450 return AddFontToList( NULL, NULL, ptr, size, flags );
1453 #ifdef __ANDROID__
1454 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1456 DIR *dir;
1457 struct dirent *dent;
1458 char path[MAX_PATH];
1460 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1462 dir = opendir(dirname);
1463 if(!dir) {
1464 WARN("Can't open directory %s\n", debugstr_a(dirname));
1465 return FALSE;
1467 while((dent = readdir(dir)) != NULL) {
1468 struct stat statbuf;
1470 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1471 continue;
1473 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1475 sprintf(path, "%s/%s", dirname, dent->d_name);
1477 if(stat(path, &statbuf) == -1)
1479 WARN("Can't stat %s\n", debugstr_a(path));
1480 continue;
1482 if(S_ISDIR(statbuf.st_mode))
1483 ReadFontDir(path, external_fonts);
1484 else
1486 DWORD addfont_flags = 0;
1487 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
1488 AddFontToList(NULL, path, NULL, 0, addfont_flags);
1491 closedir(dir);
1492 return TRUE;
1494 #endif
1496 #ifdef SONAME_LIBFONTCONFIG
1498 static BOOL fontconfig_enabled;
1499 static FcPattern *pattern_serif;
1500 static FcPattern *pattern_fixed;
1501 static FcPattern *pattern_sans;
1503 static UINT parse_aa_pattern( FcPattern *pattern )
1505 FcBool antialias;
1506 int rgba;
1507 UINT aa_flags = 0;
1509 if (pFcPatternGetBool( pattern, FC_ANTIALIAS, 0, &antialias ) == FcResultMatch)
1510 aa_flags = antialias ? GGO_GRAY4_BITMAP : GGO_BITMAP;
1512 if (pFcPatternGetInteger( pattern, FC_RGBA, 0, &rgba ) == FcResultMatch)
1514 switch (rgba)
1516 case FC_RGBA_RGB: aa_flags = WINE_GGO_HRGB_BITMAP; break;
1517 case FC_RGBA_BGR: aa_flags = WINE_GGO_HBGR_BITMAP; break;
1518 case FC_RGBA_VRGB: aa_flags = WINE_GGO_VRGB_BITMAP; break;
1519 case FC_RGBA_VBGR: aa_flags = WINE_GGO_VBGR_BITMAP; break;
1520 case FC_RGBA_NONE: aa_flags = aa_flags ? aa_flags : GGO_GRAY4_BITMAP; break;
1523 return aa_flags;
1526 static FcPattern *create_family_pattern( const char *name, FcPattern **cached )
1528 FcPattern *ret = NULL, *tmp, *pattern;
1529 FcResult result;
1530 if (*cached) return *cached;
1531 pattern = pFcPatternCreate();
1532 pFcPatternAddString( pattern, FC_FAMILY, (const FcChar8 *)name );
1533 pFcPatternAddString( pattern, FC_NAMELANG, (const FcChar8 *)"en-us" );
1534 pFcPatternAddString( pattern, FC_PRGNAME, (const FcChar8 *)"wine" );
1535 pFcConfigSubstitute( NULL, pattern, FcMatchPattern );
1536 pFcDefaultSubstitute( pattern );
1537 tmp = pFcFontMatch( NULL, pattern, &result );
1538 pFcPatternDestroy( pattern );
1539 if (result != FcResultMatch) pFcPatternDestroy( tmp );
1540 else if ((ret = InterlockedCompareExchangePointer( (void **)cached, tmp, NULL ))) pFcPatternDestroy( tmp );
1541 else ret = tmp;
1542 return ret;
1545 static void fontconfig_add_font( FcPattern *pattern, DWORD flags )
1547 const char *unix_name, *format;
1548 WCHAR *dos_name;
1549 FcBool scalable;
1550 DWORD aa_flags;
1551 int face_index;
1553 TRACE( "(%p %#x)\n", pattern, flags );
1555 if (pFcPatternGetString( pattern, FC_FILE, 0, (FcChar8 **)&unix_name ) != FcResultMatch)
1556 return;
1558 if (pFcPatternGetBool( pattern, FC_SCALABLE, 0, &scalable ) != FcResultMatch)
1559 scalable = FALSE;
1561 if (pFcPatternGetString( pattern, FC_FONTFORMAT, 0, (FcChar8 **)&format ) != FcResultMatch)
1563 TRACE( "ignoring unknown font format %s\n", debugstr_a(unix_name) );
1564 return;
1567 if (!strcmp( format, "Type 1" ))
1569 TRACE( "ignoring Type 1 font %s\n", debugstr_a(unix_name) );
1570 return;
1573 if (!scalable && !(flags & ADDFONT_ALLOW_BITMAP))
1575 TRACE( "ignoring non-scalable font %s\n", debugstr_a(unix_name) );
1576 return;
1579 if (!(aa_flags = parse_aa_pattern( pattern ))) aa_flags = default_aa_flags;
1580 flags |= ADDFONT_AA_FLAGS(aa_flags);
1582 if (pFcPatternGetInteger( pattern, FC_INDEX, 0, &face_index ) != FcResultMatch)
1583 face_index = 0;
1585 dos_name = get_dos_file_name( unix_name );
1586 add_unix_face( unix_name, dos_name, NULL, 0, face_index, flags, NULL );
1587 free( dos_name );
1590 static void init_fontconfig(void)
1592 void *fc_handle = dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW);
1594 if (!fc_handle)
1596 TRACE("Wine cannot find the fontconfig library (%s).\n", SONAME_LIBFONTCONFIG);
1597 return;
1600 #define LOAD_FUNCPTR(f) if((p##f = dlsym(fc_handle, #f)) == NULL){WARN("Can't find symbol %s\n", #f); return;}
1601 LOAD_FUNCPTR(FcConfigSubstitute);
1602 LOAD_FUNCPTR(FcDefaultSubstitute);
1603 LOAD_FUNCPTR(FcFontList);
1604 LOAD_FUNCPTR(FcFontMatch);
1605 LOAD_FUNCPTR(FcFontSetDestroy);
1606 LOAD_FUNCPTR(FcInit);
1607 LOAD_FUNCPTR(FcPatternAddString);
1608 LOAD_FUNCPTR(FcPatternCreate);
1609 LOAD_FUNCPTR(FcPatternDestroy);
1610 LOAD_FUNCPTR(FcPatternGetBool);
1611 LOAD_FUNCPTR(FcPatternGetInteger);
1612 LOAD_FUNCPTR(FcPatternGetString);
1613 LOAD_FUNCPTR(FcConfigGetFontDirs);
1614 LOAD_FUNCPTR(FcConfigGetCurrent);
1615 LOAD_FUNCPTR(FcCacheCopySet);
1616 LOAD_FUNCPTR(FcCacheNumSubdir);
1617 LOAD_FUNCPTR(FcCacheSubdir);
1618 LOAD_FUNCPTR(FcDirCacheRead);
1619 LOAD_FUNCPTR(FcDirCacheUnload);
1620 LOAD_FUNCPTR(FcStrListCreate);
1621 LOAD_FUNCPTR(FcStrListDone);
1622 LOAD_FUNCPTR(FcStrListNext);
1623 LOAD_FUNCPTR(FcStrSetAdd);
1624 LOAD_FUNCPTR(FcStrSetCreate);
1625 LOAD_FUNCPTR(FcStrSetDestroy);
1626 LOAD_FUNCPTR(FcStrSetMember);
1627 #undef LOAD_FUNCPTR
1629 if (pFcInit())
1631 FcPattern *pattern = pFcPatternCreate();
1632 pFcConfigSubstitute( NULL, pattern, FcMatchFont );
1633 default_aa_flags = parse_aa_pattern( pattern );
1634 pFcPatternDestroy( pattern );
1636 if (!default_aa_flags)
1638 FcPattern *pattern = pFcPatternCreate();
1639 pFcConfigSubstitute( NULL, pattern, FcMatchPattern );
1640 default_aa_flags = parse_aa_pattern( pattern );
1641 pFcPatternDestroy( pattern );
1644 TRACE( "enabled, default flags = %x\n", default_aa_flags );
1645 fontconfig_enabled = TRUE;
1649 static void fontconfig_add_fonts_from_dir_list( FcConfig *config, FcStrList *dir_list, FcStrSet *done_set, DWORD flags )
1651 const FcChar8 *dir;
1652 FcFontSet *font_set = NULL;
1653 FcStrList *subdir_list = NULL;
1654 FcStrSet *subdir_set = NULL;
1655 FcCache *cache = NULL;
1656 int i;
1658 TRACE( "(%p %p %p %#x)\n", config, dir_list, done_set, flags );
1660 while ((dir = pFcStrListNext( dir_list )))
1662 if (pFcStrSetMember( done_set, dir )) continue;
1664 TRACE( "adding fonts from %s\n", dir );
1665 if (!(cache = pFcDirCacheRead( dir, FcFalse, config ))) continue;
1667 if (!(font_set = pFcCacheCopySet( cache ))) goto done;
1668 for (i = 0; i < font_set->nfont; i++)
1669 fontconfig_add_font( font_set->fonts[i], flags );
1670 pFcFontSetDestroy( font_set );
1671 font_set = NULL;
1673 if (!(subdir_set = pFcStrSetCreate())) goto done;
1674 for (i = 0; i < pFcCacheNumSubdir( cache ); i++)
1675 pFcStrSetAdd( subdir_set, pFcCacheSubdir( cache, i ) );
1676 pFcDirCacheUnload( cache );
1677 cache = NULL;
1679 if (!(subdir_list = pFcStrListCreate( subdir_set ))) goto done;
1680 pFcStrSetDestroy( subdir_set );
1681 subdir_set = NULL;
1683 pFcStrSetAdd( done_set, dir );
1684 fontconfig_add_fonts_from_dir_list( config, subdir_list, done_set, flags );
1685 pFcStrListDone( subdir_list );
1686 subdir_list = NULL;
1689 done:
1690 if (subdir_set) pFcStrSetDestroy( subdir_set );
1691 if (cache) pFcDirCacheUnload( cache );
1694 static void load_fontconfig_fonts( void )
1696 FcStrList *dir_list = NULL;
1697 FcStrSet *done_set = NULL;
1698 FcConfig *config;
1700 if (!fontconfig_enabled) return;
1701 if (!(config = pFcConfigGetCurrent())) goto done;
1702 if (!(done_set = pFcStrSetCreate())) goto done;
1703 if (!(dir_list = pFcConfigGetFontDirs( config ))) goto done;
1705 fontconfig_add_fonts_from_dir_list( config, dir_list, done_set, ADDFONT_EXTERNAL_FONT );
1707 done:
1708 if (dir_list) pFcStrListDone( dir_list );
1709 if (done_set) pFcStrSetDestroy( done_set );
1712 #elif defined(HAVE_CARBON_CARBON_H)
1714 static void load_mac_font_callback(const void *value, void *context)
1716 CFStringRef pathStr = value;
1717 CFIndex len;
1718 char* path;
1720 len = CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr);
1721 path = malloc( len );
1722 if (path && CFStringGetFileSystemRepresentation(pathStr, path, len))
1724 TRACE("font file %s\n", path);
1725 AddFontToList(NULL, path, NULL, 0, ADDFONT_EXTERNAL_FONT);
1727 free( path );
1730 static void load_mac_fonts(void)
1732 CFStringRef removeDupesKey;
1733 CFBooleanRef removeDupesValue;
1734 CFDictionaryRef options;
1735 CTFontCollectionRef col;
1736 CFArrayRef descs;
1737 CFMutableSetRef paths;
1738 CFIndex i;
1740 removeDupesKey = kCTFontCollectionRemoveDuplicatesOption;
1741 removeDupesValue = kCFBooleanTrue;
1742 options = CFDictionaryCreate(NULL, (const void**)&removeDupesKey, (const void**)&removeDupesValue, 1,
1743 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1744 col = CTFontCollectionCreateFromAvailableFonts(options);
1745 if (options) CFRelease(options);
1746 if (!col)
1748 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
1749 return;
1752 descs = CTFontCollectionCreateMatchingFontDescriptors(col);
1753 CFRelease(col);
1754 if (!descs)
1756 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
1757 return;
1760 paths = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
1761 if (!paths)
1763 WARN("CFSetCreateMutable failed\n");
1764 CFRelease(descs);
1765 return;
1768 for (i = 0; i < CFArrayGetCount(descs); i++)
1770 CTFontDescriptorRef desc;
1771 CFURLRef url;
1772 CFStringRef ext;
1773 CFStringRef path;
1775 desc = CFArrayGetValueAtIndex(descs, i);
1776 url = CTFontDescriptorCopyAttribute(desc, kCTFontURLAttribute);
1777 if (!url) continue;
1779 ext = CFURLCopyPathExtension(url);
1780 if (ext)
1782 BOOL skip = (CFStringCompare(ext, CFSTR("pfa"), kCFCompareCaseInsensitive) == kCFCompareEqualTo ||
1783 CFStringCompare(ext, CFSTR("pfb"), kCFCompareCaseInsensitive) == kCFCompareEqualTo);
1784 CFRelease(ext);
1785 if (skip)
1787 CFRelease(url);
1788 continue;
1792 path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
1793 CFRelease(url);
1794 if (!path) continue;
1796 CFSetAddValue(paths, path);
1797 CFRelease(path);
1800 CFRelease(descs);
1802 CFSetApplyFunction(paths, load_mac_font_callback, NULL);
1803 CFRelease(paths);
1806 #endif
1809 static BOOL init_freetype(void)
1811 ft_handle = dlopen(SONAME_LIBFREETYPE, RTLD_NOW);
1812 if(!ft_handle) {
1813 WINE_MESSAGE(
1814 "Wine cannot find the FreeType font library. To enable Wine to\n"
1815 "use TrueType fonts please install a version of FreeType greater than\n"
1816 "or equal to 2.0.5.\n"
1817 "http://www.freetype.org\n");
1818 return FALSE;
1821 #define LOAD_FUNCPTR(f) if((p##f = dlsym(ft_handle, #f)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
1823 LOAD_FUNCPTR(FT_Done_Face)
1824 LOAD_FUNCPTR(FT_Get_Char_Index)
1825 LOAD_FUNCPTR(FT_Get_First_Char)
1826 LOAD_FUNCPTR(FT_Get_Next_Char)
1827 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
1828 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
1829 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
1830 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
1831 LOAD_FUNCPTR(FT_Init_FreeType)
1832 LOAD_FUNCPTR(FT_Library_Version)
1833 LOAD_FUNCPTR(FT_Load_Glyph)
1834 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
1835 LOAD_FUNCPTR(FT_Matrix_Multiply)
1836 LOAD_FUNCPTR(FT_MulDiv)
1837 #ifndef FT_MULFIX_INLINED
1838 LOAD_FUNCPTR(FT_MulFix)
1839 #endif
1840 LOAD_FUNCPTR(FT_New_Face)
1841 LOAD_FUNCPTR(FT_New_Memory_Face)
1842 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
1843 LOAD_FUNCPTR(FT_Outline_Get_CBox)
1844 LOAD_FUNCPTR(FT_Outline_Transform)
1845 LOAD_FUNCPTR(FT_Outline_Translate)
1846 LOAD_FUNCPTR(FT_Render_Glyph)
1847 LOAD_FUNCPTR(FT_Set_Charmap)
1848 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
1849 LOAD_FUNCPTR(FT_Vector_Length)
1850 LOAD_FUNCPTR(FT_Vector_Transform)
1851 LOAD_FUNCPTR(FT_Vector_Unit)
1852 #undef LOAD_FUNCPTR
1853 /* Don't warn if these ones are missing */
1854 pFT_Outline_Embolden = dlsym(ft_handle, "FT_Outline_Embolden");
1855 pFT_Get_TrueType_Engine_Type = dlsym(ft_handle, "FT_Get_TrueType_Engine_Type");
1856 #ifdef FT_LCD_FILTER_H
1857 pFT_Library_SetLcdFilter = dlsym(ft_handle, "FT_Library_SetLcdFilter");
1858 #endif
1859 pFT_Property_Set = dlsym(ft_handle, "FT_Property_Set");
1861 if(pFT_Init_FreeType(&library) != 0) {
1862 ERR("Can't init FreeType library\n");
1863 dlclose(ft_handle);
1864 ft_handle = NULL;
1865 return FALSE;
1867 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
1869 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
1870 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
1871 ((FT_Version.minor << 8) & 0x00ff00) |
1872 ((FT_Version.patch ) & 0x0000ff);
1874 /* In FreeType < 2.8.1 v40's FT_LOAD_TARGET_MONO has broken advance widths. */
1875 if (pFT_Property_Set && FT_SimpleVersion < FT_VERSION_VALUE(2, 8, 1))
1877 FT_UInt interpreter_version = 35;
1878 pFT_Property_Set( library, "truetype", "interpreter-version", &interpreter_version );
1881 #ifdef FT_LCD_FILTER_H
1882 if (pFT_Library_SetLcdFilter)
1883 pFT_Library_SetLcdFilter( library, FT_LCD_FILTER_DEFAULT );
1884 #endif
1886 return TRUE;
1888 sym_not_found:
1889 WINE_MESSAGE(
1890 "Wine cannot find certain functions that it needs inside the FreeType\n"
1891 "font library. To enable Wine to use TrueType fonts please upgrade\n"
1892 "FreeType to at least version 2.1.4.\n"
1893 "http://www.freetype.org\n");
1894 dlclose(ft_handle);
1895 ft_handle = NULL;
1896 return FALSE;
1899 /*************************************************************
1900 * freetype_load_fonts
1902 static void freetype_load_fonts(void)
1904 #ifdef SONAME_LIBFONTCONFIG
1905 load_fontconfig_fonts();
1906 #elif defined(HAVE_CARBON_CARBON_H)
1907 load_mac_fonts();
1908 #elif defined(__ANDROID__)
1909 ReadFontDir("/system/fonts", TRUE);
1910 #endif
1913 /* Some fonts have large usWinDescent values, as a result of storing signed short
1914 in unsigned field. That's probably caused by sTypoDescent vs usWinDescent confusion in
1915 some font generation tools. */
1916 static inline USHORT get_fixed_windescent(USHORT windescent)
1918 return abs((SHORT)windescent);
1921 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
1923 TT_OS2 *pOS2;
1924 TT_HoriHeader *pHori;
1926 LONG ppem;
1927 const LONG MAX_PPEM = (1 << 16) - 1;
1929 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1930 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1932 if(height == 0) height = 16;
1934 /* Calc. height of EM square:
1936 * For +ve lfHeight we have
1937 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
1938 * Re-arranging gives:
1939 * ppem = units_per_em * lfheight / (winAscent + winDescent)
1941 * For -ve lfHeight we have
1942 * |lfHeight| = ppem
1943 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
1944 * with il = winAscent + winDescent - units_per_em]
1948 if(height > 0) {
1949 USHORT windescent = get_fixed_windescent(pOS2->usWinDescent);
1950 if(pOS2->usWinAscent + windescent == 0)
1951 ppem = pFT_MulDiv(ft_face->units_per_EM, height, pHori->Ascender - pHori->Descender);
1952 else
1953 ppem = pFT_MulDiv(ft_face->units_per_EM, height, pOS2->usWinAscent + windescent);
1954 if(ppem > MAX_PPEM) {
1955 WARN("Ignoring too large height %d, ppem %d\n", height, ppem);
1956 ppem = 1;
1959 else if(height >= -MAX_PPEM)
1960 ppem = -height;
1961 else {
1962 WARN("Ignoring too large height %d\n", height);
1963 ppem = 1;
1966 return ppem;
1969 static struct font_mapping *map_font_file( const char *name )
1971 struct font_mapping *mapping;
1972 struct stat st;
1973 int fd;
1975 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
1976 if (fstat( fd, &st ) == -1) goto error;
1978 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
1980 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
1982 mapping->refcount++;
1983 close( fd );
1984 return mapping;
1987 if (!(mapping = malloc( sizeof(*mapping) )))
1988 goto error;
1990 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
1991 close( fd );
1993 if (mapping->data == MAP_FAILED)
1995 free( mapping );
1996 return NULL;
1998 mapping->refcount = 1;
1999 mapping->dev = st.st_dev;
2000 mapping->ino = st.st_ino;
2001 mapping->size = st.st_size;
2002 list_add_tail( &mappings_list, &mapping->entry );
2003 return mapping;
2005 error:
2006 close( fd );
2007 return NULL;
2010 static void unmap_font_file( struct font_mapping *mapping )
2012 if (!--mapping->refcount)
2014 list_remove( &mapping->entry );
2015 munmap( mapping->data, mapping->size );
2016 free( mapping );
2020 static LONG load_VDMX(struct gdi_font *font, LONG height);
2022 /*************************************************************
2023 * freetype_destroy_font
2025 static void freetype_destroy_font( struct gdi_font *font )
2027 struct font_private_data *data = font->private;
2029 if (data->ft_face) pFT_Done_Face( data->ft_face );
2030 if (data->mapping) unmap_font_file( data->mapping );
2031 free( data );
2034 /*************************************************************
2035 * freetype_get_font_data
2037 static DWORD freetype_get_font_data( struct gdi_font *font, DWORD table, DWORD offset,
2038 void *buf, DWORD cbData)
2040 FT_Face ft_face = get_ft_face( font );
2041 FT_ULong len;
2042 FT_Error err;
2044 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
2046 if(!buf)
2047 len = 0;
2048 else
2049 len = cbData;
2051 /* if font is a member of TTC, 'ttcf' tag allows reading from beginning of TTC file,
2052 0 tag means to read from start of collection member data. */
2053 if (font->ttc_item_offset)
2055 if (table == MS_TTCF_TAG)
2056 table = 0;
2057 else if (table == 0)
2058 offset += font->ttc_item_offset;
2061 /* make sure value of len is the value freetype says it needs */
2062 if (buf && len)
2064 FT_ULong needed = 0;
2065 err = pFT_Load_Sfnt_Table(ft_face, RtlUlongByteSwap(table), offset, NULL, &needed);
2066 if( !err && needed < len) len = needed;
2068 err = pFT_Load_Sfnt_Table(ft_face, RtlUlongByteSwap(table), offset, buf, &len);
2069 if (err)
2071 TRACE("Can't find table %s\n", debugstr_an((char*)&table, 4));
2072 return GDI_ERROR;
2074 return len;
2077 /*************************************************************
2078 * load_VDMX
2080 * load the vdmx entry for the specified height
2085 typedef struct {
2086 WORD version;
2087 WORD numRecs;
2088 WORD numRatios;
2089 } VDMX_Header;
2091 typedef struct {
2092 BYTE bCharSet;
2093 BYTE xRatio;
2094 BYTE yStartRatio;
2095 BYTE yEndRatio;
2096 } Ratios;
2098 typedef struct {
2099 WORD recs;
2100 BYTE startsz;
2101 BYTE endsz;
2102 } VDMX_group;
2104 typedef struct {
2105 WORD yPelHeight;
2106 WORD yMax;
2107 WORD yMin;
2108 } VDMX_vTable;
2110 static LONG load_VDMX(struct gdi_font *font, LONG height)
2112 VDMX_Header hdr;
2113 VDMX_group group;
2114 BYTE devXRatio, devYRatio;
2115 USHORT numRecs, numRatios;
2116 DWORD result, offset = -1;
2117 LONG ppem = 0;
2118 int i;
2120 result = freetype_get_font_data(font, MS_VDMX_TAG, 0, &hdr, sizeof(hdr));
2122 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2123 return ppem;
2125 /* FIXME: need the real device aspect ratio */
2126 devXRatio = 1;
2127 devYRatio = 1;
2129 numRecs = GET_BE_WORD(hdr.numRecs);
2130 numRatios = GET_BE_WORD(hdr.numRatios);
2132 TRACE("version = %d numRecs = %d numRatios = %d\n", GET_BE_WORD(hdr.version), numRecs, numRatios);
2133 for(i = 0; i < numRatios; i++) {
2134 Ratios ratio;
2136 offset = sizeof(hdr) + (i * sizeof(Ratios));
2137 freetype_get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2138 offset = -1;
2140 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2142 if (!ratio.bCharSet) continue;
2144 if((ratio.xRatio == 0 &&
2145 ratio.yStartRatio == 0 &&
2146 ratio.yEndRatio == 0) ||
2147 (devXRatio == ratio.xRatio &&
2148 devYRatio >= ratio.yStartRatio &&
2149 devYRatio <= ratio.yEndRatio))
2151 WORD group_offset;
2153 offset = sizeof(hdr) + numRatios * sizeof(ratio) + i * sizeof(group_offset);
2154 freetype_get_font_data(font, MS_VDMX_TAG, offset, &group_offset, sizeof(group_offset));
2155 offset = GET_BE_WORD(group_offset);
2156 break;
2160 if(offset == -1) return 0;
2162 if(freetype_get_font_data(font, MS_VDMX_TAG, offset, &group, sizeof(group)) != GDI_ERROR) {
2163 USHORT recs;
2164 BYTE startsz, endsz;
2165 WORD *vTable;
2167 recs = GET_BE_WORD(group.recs);
2168 startsz = group.startsz;
2169 endsz = group.endsz;
2171 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
2173 vTable = malloc( recs * sizeof(VDMX_vTable) );
2174 result = freetype_get_font_data(font, MS_VDMX_TAG, offset + sizeof(group), vTable, recs * sizeof(VDMX_vTable));
2175 if(result == GDI_ERROR) {
2176 FIXME("Failed to retrieve vTable\n");
2177 goto end;
2180 if(height > 0) {
2181 for(i = 0; i < recs; i++) {
2182 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2183 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2184 ppem = GET_BE_WORD(vTable[i * 3]);
2186 if(yMax + -yMin == height) {
2187 font->yMax = yMax;
2188 font->yMin = yMin;
2189 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2190 break;
2192 if(yMax + -yMin > height) {
2193 if(--i < 0) {
2194 ppem = 0;
2195 goto end; /* failed */
2197 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2198 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2199 ppem = GET_BE_WORD(vTable[i * 3]);
2200 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2201 break;
2204 if(!font->yMax) {
2205 ppem = 0;
2206 TRACE("ppem not found for height %d\n", height);
2208 } else {
2209 ppem = -height;
2210 if(ppem < startsz || ppem > endsz)
2212 ppem = 0;
2213 goto end;
2216 for(i = 0; i < recs; i++) {
2217 USHORT yPelHeight;
2218 yPelHeight = GET_BE_WORD(vTable[i * 3]);
2220 if(yPelHeight > ppem)
2222 ppem = 0;
2223 break; /* failed */
2226 if(yPelHeight == ppem) {
2227 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2228 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2229 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
2230 break;
2234 end:
2235 free( vTable );
2238 return ppem;
2241 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
2243 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
2244 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
2245 FT_Int i;
2247 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
2249 for (i = 0; i < ft_face->num_charmaps; i++)
2251 if (ft_face->charmaps[i]->encoding == encoding)
2253 TRACE("found cmap with platform_id %u, encoding_id %u\n",
2254 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
2256 switch (ft_face->charmaps[i]->platform_id)
2258 default:
2259 cmap_def = ft_face->charmaps[i];
2260 break;
2261 case 0: /* Apple Unicode */
2262 cmap0 = ft_face->charmaps[i];
2263 break;
2264 case 1: /* Macintosh */
2265 cmap1 = ft_face->charmaps[i];
2266 break;
2267 case 2: /* ISO */
2268 cmap2 = ft_face->charmaps[i];
2269 break;
2270 case 3: /* Microsoft */
2271 cmap3 = ft_face->charmaps[i];
2272 break;
2276 if (cmap3) /* prefer Microsoft cmap table */
2277 ft_err = pFT_Set_Charmap(ft_face, cmap3);
2278 else if (cmap1)
2279 ft_err = pFT_Set_Charmap(ft_face, cmap1);
2280 else if (cmap2)
2281 ft_err = pFT_Set_Charmap(ft_face, cmap2);
2282 else if (cmap0)
2283 ft_err = pFT_Set_Charmap(ft_face, cmap0);
2284 else if (cmap_def)
2285 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
2288 return ft_err == FT_Err_Ok;
2292 static FT_Encoding pick_charmap( FT_Face face, int charset )
2294 static const FT_Encoding regular_order[] = { FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, FT_ENCODING_MS_SYMBOL, 0 };
2295 static const FT_Encoding symbol_order[] = { FT_ENCODING_MS_SYMBOL, FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, 0 };
2296 const FT_Encoding *encs = regular_order;
2298 if (charset == SYMBOL_CHARSET) encs = symbol_order;
2300 while (*encs != 0)
2302 if (select_charmap( face, *encs )) break;
2303 encs++;
2306 if (!face->charmap && face->num_charmaps)
2308 if (!pFT_Set_Charmap(face, face->charmaps[0]))
2309 return face->charmap->encoding;
2312 return *encs;
2315 static BOOL get_gasp_flags( struct gdi_font *font, WORD *flags )
2317 FT_Face ft_face = get_ft_face( font );
2318 DWORD size;
2319 WORD buf[16]; /* Enough for seven ranges before we need to alloc */
2320 WORD *alloced = NULL, *ptr = buf;
2321 WORD num_recs, version;
2322 BOOL ret = FALSE;
2324 *flags = 0;
2325 size = freetype_get_font_data( font, MS_GASP_TAG, 0, NULL, 0 );
2326 if (size == GDI_ERROR) return FALSE;
2327 if (size < 4 * sizeof(WORD)) return FALSE;
2328 if (size > sizeof(buf))
2330 ptr = alloced = malloc( size );
2331 if (!ptr) return FALSE;
2334 freetype_get_font_data( font, MS_GASP_TAG, 0, ptr, size );
2336 version = GET_BE_WORD( *ptr++ );
2337 num_recs = GET_BE_WORD( *ptr++ );
2339 if (version > 1 || size < (num_recs * 2 + 2) * sizeof(WORD))
2341 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version, size, num_recs );
2342 goto done;
2345 while (num_recs--)
2347 *flags = GET_BE_WORD( *(ptr + 1) );
2348 if (ft_face->size->metrics.y_ppem <= GET_BE_WORD( *ptr )) break;
2349 ptr += 2;
2351 TRACE( "got flags %04x for ppem %d\n", *flags, ft_face->size->metrics.y_ppem );
2352 ret = TRUE;
2354 done:
2355 free( alloced );
2356 return ret;
2359 /*************************************************************
2360 * fontconfig_enum_family_fallbacks
2362 static BOOL fontconfig_enum_family_fallbacks( DWORD pitch_and_family, int index,
2363 WCHAR buffer[LF_FACESIZE] )
2365 #ifdef SONAME_LIBFONTCONFIG
2366 FcPattern *pat;
2367 char *str;
2368 DWORD len;
2370 if ((pitch_and_family & FIXED_PITCH) || (pitch_and_family & 0xf0) == FF_MODERN) pat = create_family_pattern( "monospace", &pattern_fixed );
2371 else if ((pitch_and_family & 0xf0) == FF_ROMAN) pat = create_family_pattern( "serif", &pattern_serif );
2372 else pat = create_family_pattern( "sans", &pattern_sans );
2374 if (!pat) return FALSE;
2375 if (pFcPatternGetString( pat, FC_FAMILY, index, (FcChar8 **)&str ) != FcResultMatch) return FALSE;
2376 RtlUTF8ToUnicodeN( buffer, (LF_FACESIZE - 1) * sizeof(WCHAR), &len, str, strlen(str) );
2377 buffer[len / sizeof(WCHAR)] = 0;
2378 return TRUE;
2379 #endif
2380 return FALSE;
2383 static DWORD get_ttc_offset( FT_Face ft_face, UINT face_index )
2385 FT_ULong len;
2386 DWORD header, offset;
2388 /* see if it's a TTC */
2389 len = sizeof(header);
2390 if (pFT_Load_Sfnt_Table( ft_face, 0, 0, (void *)&header, &len )) return 0;
2391 if (header != MS_TTCF_TAG) return 0;
2393 len = sizeof(offset);
2394 if (pFT_Load_Sfnt_Table( ft_face, 0, (3 + face_index) * sizeof(DWORD), (void *)&offset, &len ))
2395 return 0;
2397 return GET_BE_DWORD( offset );
2400 /*************************************************************
2401 * freetype_load_font
2403 static BOOL freetype_load_font( struct gdi_font *font )
2405 struct font_private_data *data;
2406 INT width = 0, height;
2407 FT_Face ft_face;
2408 void *data_ptr;
2409 SIZE_T data_size;
2411 if (!(data = calloc( 1, sizeof(*data) ))) return FALSE;
2412 font->private = data;
2414 if (font->file[0])
2416 char *filename = get_unix_file_name( font->file );
2417 data->mapping = map_font_file( filename );
2418 free( filename );
2419 if (!data->mapping)
2421 WARN("failed to map %s\n", debugstr_w(font->file));
2422 return FALSE;
2424 data_ptr = data->mapping->data;
2425 data_size = data->mapping->size;
2427 else
2429 data_ptr = font->data_ptr;
2430 data_size = font->data_size;
2433 if (pFT_New_Memory_Face( library, data_ptr, data_size, font->face_index, &ft_face )) return FALSE;
2435 data->ft_face = ft_face;
2436 font->scalable = FT_IS_SCALABLE( ft_face );
2437 if (!font->fs.fsCsb[0]) get_fontsig( ft_face, &font->fs );
2438 if (!font->ntmFlags) font->ntmFlags = get_ntm_flags( ft_face );
2439 if (!font->aa_flags) font->aa_flags = ADDFONT_AA_FLAGS( default_aa_flags );
2440 if (!font->otm.otmpFamilyName)
2442 font->otm.otmpFamilyName = (char *)ft_face_get_family_name( ft_face, system_lcid );
2443 font->otm.otmpStyleName = (char *)ft_face_get_style_name( ft_face, system_lcid );
2444 font->otm.otmpFaceName = (char *)ft_face_get_full_name( ft_face, system_lcid );
2447 if (font->scalable)
2449 /* load the VDMX table if we have one */
2450 font->ppem = load_VDMX( font, font->lf.lfHeight );
2451 if (font->ppem == 0) font->ppem = calc_ppem_for_height( ft_face, font->lf.lfHeight );
2452 TRACE( "height %d => ppem %d\n", font->lf.lfHeight, font->ppem );
2453 height = font->ppem;
2454 font->ttc_item_offset = get_ttc_offset( ft_face, font->face_index );
2455 font->otm.otmEMSquare = ft_face->units_per_EM;
2457 else
2459 struct bitmap_font_size size;
2461 get_bitmap_size( ft_face, &size );
2462 width = size.x_ppem >> 6;
2463 height = size.y_ppem >> 6;
2464 font->ppem = height;
2467 pFT_Set_Pixel_Sizes( ft_face, width, height );
2468 pick_charmap( ft_face, font->charset );
2469 return TRUE;
2473 /*************************************************************
2474 * freetype_get_aa_flags
2476 static UINT freetype_get_aa_flags( struct gdi_font *font, UINT aa_flags, BOOL antialias_fakes )
2478 /* fixup the antialiasing flags for that font */
2479 switch (aa_flags)
2481 case WINE_GGO_HRGB_BITMAP:
2482 case WINE_GGO_HBGR_BITMAP:
2483 case WINE_GGO_VRGB_BITMAP:
2484 case WINE_GGO_VBGR_BITMAP:
2485 if (is_subpixel_rendering_enabled()) break;
2486 aa_flags = GGO_GRAY4_BITMAP;
2487 /* fall through */
2488 case GGO_GRAY2_BITMAP:
2489 case GGO_GRAY4_BITMAP:
2490 case GGO_GRAY8_BITMAP:
2491 case WINE_GGO_GRAY16_BITMAP:
2492 if ((!antialias_fakes || (!font->fake_bold && !font->fake_italic)) && is_hinting_enabled())
2494 WORD gasp_flags;
2495 if (get_gasp_flags( font, &gasp_flags ) && !(gasp_flags & GASP_DOGRAY))
2497 TRACE( "font %s %d aa disabled by GASP\n",
2498 debugstr_w(font->lf.lfFaceName), font->lf.lfHeight );
2499 aa_flags = GGO_BITMAP;
2503 return aa_flags;
2506 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
2508 pt->x.value = vec->x >> 6;
2509 pt->x.fract = (vec->x & 0x3f) << 10;
2510 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
2511 pt->y.value = vec->y >> 6;
2512 pt->y.fract = (vec->y & 0x3f) << 10;
2513 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
2516 static FT_UInt get_glyph_index_symbol( struct gdi_font *font, UINT glyph )
2518 FT_Face ft_face = get_ft_face( font );
2519 FT_UInt ret;
2521 if (glyph < 0x100) glyph += 0xf000;
2522 /* there are a number of old pre-Unicode "broken" TTFs, which
2523 do have symbols at U+00XX instead of U+f0XX */
2524 if (!(ret = pFT_Get_Char_Index(ft_face, glyph)))
2525 ret = pFT_Get_Char_Index(ft_face, glyph - 0xf000);
2527 return ret;
2530 /*************************************************************
2531 * freetype_get_glyph_index
2533 static BOOL freetype_get_glyph_index( struct gdi_font *font, UINT *glyph, BOOL use_encoding )
2535 FT_Face ft_face = get_ft_face( font );
2537 if (!use_encoding ^ (ft_face->charmap->encoding == FT_ENCODING_NONE)) return FALSE;
2539 if (ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
2541 if (!(*glyph = get_glyph_index_symbol( font, *glyph )))
2543 WCHAR wc = *glyph;
2544 DWORD len;
2545 char ch;
2547 len = win32u_wctomb( NULL, &ch, 1, &wc, sizeof(wc) );
2548 if (len) *glyph = get_glyph_index_symbol( font, (unsigned char)ch );
2550 return TRUE;
2552 *glyph = pFT_Get_Char_Index( ft_face, *glyph );
2553 return TRUE;
2556 /*************************************************************
2557 * freetype_get_default_glyph
2559 static UINT freetype_get_default_glyph( struct gdi_font *font )
2561 FT_Face ft_face = get_ft_face( font );
2562 FT_WinFNT_HeaderRec winfnt;
2563 TT_OS2 *pOS2;
2565 if ((pOS2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 )))
2567 UINT glyph = pOS2->usDefaultChar;
2568 if (glyph) freetype_get_glyph_index( font, &glyph, TRUE );
2569 return glyph;
2571 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt )) return winfnt.default_char + winfnt.first_char;
2572 return 32;
2576 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
2578 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
2579 return !memcmp(matrix, &identity, sizeof(FMAT2));
2582 static inline FT_Vector normalize_vector(FT_Vector *vec)
2584 FT_Vector out;
2585 FT_Fixed len;
2586 len = pFT_Vector_Length(vec);
2587 if (len) {
2588 out.x = (vec->x << 6) / len;
2589 out.y = (vec->y << 6) / len;
2591 else
2592 out.x = out.y = 0;
2593 return out;
2596 /* get_glyph_outline() glyph transform matrices index */
2597 enum matrices_index
2599 matrix_hori,
2600 matrix_vert,
2601 matrix_unrotated
2604 static FT_Matrix *get_transform_matrices( struct gdi_font *font, BOOL vertical, const MAT2 *user_transform,
2605 FT_Matrix matrices[3] )
2607 static const FT_Matrix identity_mat = { (1 << 16), 0, 0, (1 << 16) };
2608 BOOL needs_transform = FALSE;
2609 double width_ratio;
2610 int i;
2612 matrices[matrix_unrotated] = identity_mat;
2614 /* Scaling factor */
2615 if (font->aveWidth)
2617 if (!freetype_set_outline_text_metrics( font )) freetype_set_bitmap_text_metrics( font );
2618 width_ratio = (double)font->aveWidth;
2619 width_ratio /= (double)font->otm.otmTextMetrics.tmAveCharWidth;
2621 else
2622 width_ratio = font->scale_y;
2624 /* Scaling transform */
2625 if (width_ratio != 1.0 || font->scale_y != 1)
2627 FT_Matrix scale_mat;
2628 scale_mat.xx = FT_FixedFromFloat( width_ratio );
2629 scale_mat.xy = 0;
2630 scale_mat.yx = 0;
2631 scale_mat.yy = font->scale_y << 16;
2633 pFT_Matrix_Multiply( &scale_mat, &matrices[matrix_unrotated] );
2634 needs_transform = TRUE;
2637 /* Slant transform */
2638 if (font->fake_italic)
2640 FT_Matrix slant_mat;
2641 slant_mat.xx = (1 << 16);
2642 slant_mat.xy = (1 << 16) >> 2;
2643 slant_mat.yx = 0;
2644 slant_mat.yy = (1 << 16);
2646 pFT_Matrix_Multiply( &slant_mat, &matrices[matrix_unrotated] );
2647 needs_transform = TRUE;
2650 /* Rotation transform */
2651 matrices[matrix_hori] = matrices[matrix_unrotated];
2652 if (font->scalable && font->lf.lfOrientation % 3600)
2654 FT_Matrix rotation_mat;
2655 FT_Vector angle;
2657 pFT_Vector_Unit( &angle, pFT_MulDiv( 1 << 16, font->lf.lfOrientation, 10 ) );
2658 rotation_mat.xx = angle.x;
2659 rotation_mat.xy = -angle.y;
2660 rotation_mat.yx = angle.y;
2661 rotation_mat.yy = angle.x;
2662 pFT_Matrix_Multiply( &rotation_mat, &matrices[matrix_hori] );
2663 needs_transform = TRUE;
2666 /* Vertical transform */
2667 matrices[matrix_vert] = matrices[matrix_hori];
2668 if (vertical)
2670 FT_Matrix vertical_mat = { 0, -(1 << 16), 1 << 16, 0 }; /* 90 degrees rotation */
2672 pFT_Matrix_Multiply( &vertical_mat, &matrices[matrix_vert] );
2673 needs_transform = TRUE;
2676 /* World transform */
2677 if (!is_identity_FMAT2( &font->matrix ))
2679 FT_Matrix world_mat;
2680 world_mat.xx = FT_FixedFromFloat( font->matrix.eM11 );
2681 world_mat.xy = -FT_FixedFromFloat( font->matrix.eM21 );
2682 world_mat.yx = -FT_FixedFromFloat( font->matrix.eM12 );
2683 world_mat.yy = FT_FixedFromFloat( font->matrix.eM22 );
2685 for (i = 0; i < 3; i++)
2686 pFT_Matrix_Multiply( &world_mat, &matrices[i] );
2687 needs_transform = TRUE;
2690 /* Extra transformation specified by caller */
2691 if (user_transform)
2693 FT_Matrix user_mat;
2694 user_mat.xx = FT_FixedFromFIXED( user_transform->eM11 );
2695 user_mat.xy = FT_FixedFromFIXED( user_transform->eM21 );
2696 user_mat.yx = FT_FixedFromFIXED( user_transform->eM12 );
2697 user_mat.yy = FT_FixedFromFIXED( user_transform->eM22 );
2699 for (i = 0; i < 3; i++)
2700 pFT_Matrix_Multiply( &user_mat, &matrices[i] );
2701 needs_transform = TRUE;
2704 return needs_transform ? matrices : NULL;
2707 static BOOL get_bold_glyph_outline(FT_GlyphSlot glyph, LONG ppem, FT_Glyph_Metrics *metrics)
2709 FT_Error err;
2710 FT_Pos strength;
2711 FT_BBox bbox;
2713 if(glyph->format != FT_GLYPH_FORMAT_OUTLINE)
2714 return FALSE;
2715 if(!pFT_Outline_Embolden)
2716 return FALSE;
2718 strength = pFT_MulDiv(ppem, 1 << 6, 24);
2719 err = pFT_Outline_Embolden(&glyph->outline, strength);
2720 if(err) {
2721 TRACE("FT_Ouline_Embolden returns %d\n", err);
2722 return FALSE;
2725 pFT_Outline_Get_CBox(&glyph->outline, &bbox);
2726 metrics->width = bbox.xMax - bbox.xMin;
2727 metrics->height = bbox.yMax - bbox.yMin;
2728 metrics->horiBearingX = bbox.xMin;
2729 metrics->horiBearingY = bbox.yMax;
2730 metrics->vertBearingX = metrics->horiBearingX - metrics->horiAdvance / 2;
2731 metrics->vertBearingY = (metrics->vertAdvance - metrics->height) / 2;
2732 return TRUE;
2735 static inline BYTE get_max_level( UINT format )
2737 switch( format )
2739 case GGO_GRAY2_BITMAP: return 4;
2740 case GGO_GRAY4_BITMAP: return 16;
2741 case GGO_GRAY8_BITMAP: return 64;
2743 return 255;
2746 static FT_Vector get_advance_metric( struct gdi_font *font, FT_Pos base_advance,
2747 const FT_Matrix *transMat )
2749 FT_Vector adv;
2750 FT_Fixed em_scale = 0;
2751 BOOL fixed_pitch_full = FALSE;
2752 struct gdi_font *incoming_font = font->base_font ? font->base_font : font;
2754 adv.x = base_advance;
2755 adv.y = 0;
2757 /* In fixed-pitch font, we adjust the fullwidth character advance so that
2758 they have double halfwidth character width. E.g. if the font is 19 ppem,
2759 we return 20 (not 19) for fullwidth characters as we return 10 for
2760 halfwidth characters. */
2761 if (freetype_set_outline_text_metrics(incoming_font) &&
2762 !(incoming_font->otm.otmTextMetrics.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
2763 UINT avg_advance;
2764 em_scale = pFT_MulDiv(incoming_font->ppem, 1 << 16, get_ft_face(incoming_font)->units_per_EM);
2765 avg_advance = pFT_MulFix(incoming_font->ntmAvgWidth, em_scale);
2766 fixed_pitch_full = (avg_advance > 0 &&
2767 (base_advance + 63) >> 6 ==
2768 pFT_MulFix(incoming_font->ntmAvgWidth*2, em_scale));
2769 if (fixed_pitch_full && !transMat)
2770 adv.x = (avg_advance * 2) << 6;
2773 if (transMat) {
2774 pFT_Vector_Transform(&adv, transMat);
2775 if (fixed_pitch_full && adv.y == 0) {
2776 FT_Vector vec;
2777 vec.x = incoming_font->ntmAvgWidth;
2778 vec.y = 0;
2779 pFT_Vector_Transform(&vec, transMat);
2780 adv.x = (pFT_MulFix(vec.x, em_scale) * 2) << 6;
2784 if (font->fake_bold) {
2785 if (!transMat)
2786 adv.x += 1 << 6;
2787 else {
2788 FT_Vector fake_bold_adv, vec = { 1 << 6, 0 };
2789 pFT_Vector_Transform(&vec, transMat);
2790 fake_bold_adv = normalize_vector(&vec);
2791 adv.x += fake_bold_adv.x;
2792 adv.y += fake_bold_adv.y;
2796 adv.x = (adv.x + 63) & -64;
2797 adv.y = -((adv.y + 63) & -64);
2798 return adv;
2801 static FT_BBox get_transformed_bbox( const FT_Glyph_Metrics *metrics, const FT_Matrix *matrices )
2803 FT_BBox bbox = { 0, 0, 0, 0 };
2805 if (!matrices)
2807 bbox.xMin = (metrics->horiBearingX) & -64;
2808 bbox.xMax = (metrics->horiBearingX + metrics->width + 63) & -64;
2809 bbox.yMax = (metrics->horiBearingY + 63) & -64;
2810 bbox.yMin = (metrics->horiBearingY - metrics->height) & -64;
2812 else
2814 FT_Vector vec;
2815 INT xc, yc;
2817 for (xc = 0; xc < 2; xc++)
2819 for (yc = 0; yc < 2; yc++)
2821 vec.x = metrics->horiBearingX + xc * metrics->width;
2822 vec.y = metrics->horiBearingY - yc * metrics->height;
2823 TRACE( "Vec %ld, %ld\n", vec.x, vec.y );
2824 pFT_Vector_Transform( &vec, &matrices[matrix_vert] );
2825 if (xc == 0 && yc == 0)
2827 bbox.xMin = bbox.xMax = vec.x;
2828 bbox.yMin = bbox.yMax = vec.y;
2830 else
2832 if (vec.x < bbox.xMin) bbox.xMin = vec.x;
2833 else if (vec.x > bbox.xMax) bbox.xMax = vec.x;
2834 if (vec.y < bbox.yMin) bbox.yMin = vec.y;
2835 else if (vec.y > bbox.yMax) bbox.yMax = vec.y;
2839 bbox.xMin = bbox.xMin & -64;
2840 bbox.xMax = (bbox.xMax + 63) & -64;
2841 bbox.yMin = bbox.yMin & -64;
2842 bbox.yMax = (bbox.yMax + 63) & -64;
2843 TRACE( "transformed box: (%ld, %ld - %ld, %ld)\n", bbox.xMin, bbox.yMax, bbox.xMax, bbox.yMin );
2846 return bbox;
2849 static void compute_metrics( struct gdi_font *font, FT_BBox bbox, const FT_Glyph_Metrics *metrics,
2850 BOOL vertical, BOOL vertical_metrics, const FT_Matrix *matrices,
2851 GLYPHMETRICS *gm, ABC *abc )
2853 FT_Vector adv, vec, origin;
2854 FT_Fixed base_advance = vertical_metrics ? metrics->vertAdvance : metrics->horiAdvance;
2856 if (!matrices)
2858 adv = get_advance_metric( font, base_advance, NULL );
2859 gm->gmCellIncX = adv.x >> 6;
2860 gm->gmCellIncY = 0;
2861 origin.x = bbox.xMin;
2862 origin.y = bbox.yMax;
2863 abc->abcA = origin.x >> 6;
2864 abc->abcB = (metrics->width + 63) >> 6;
2866 else
2868 FT_Pos lsb;
2870 if (vertical && freetype_set_outline_text_metrics( font ))
2872 if (vertical_metrics)
2873 lsb = metrics->horiBearingY + metrics->vertBearingY;
2874 else
2875 lsb = metrics->vertAdvance + (font->otm.otmDescent << 6);
2876 vec.x = lsb;
2877 vec.y = font->otm.otmDescent << 6;
2878 TRACE( "Vec %ld,%ld\n", vec.x>>6, vec.y>>6 );
2879 pFT_Vector_Transform( &vec, &matrices[matrix_hori] );
2880 origin.x = (vec.x + bbox.xMin) & -64;
2881 origin.y = (vec.y + bbox.yMax + 63) & -64;
2882 lsb -= metrics->horiBearingY;
2884 else
2886 origin.x = bbox.xMin;
2887 origin.y = bbox.yMax;
2888 lsb = metrics->horiBearingX;
2891 adv = get_advance_metric( font, base_advance, &matrices[matrix_hori] );
2892 gm->gmCellIncX = adv.x >> 6;
2893 gm->gmCellIncY = adv.y >> 6;
2895 adv = get_advance_metric( font, base_advance, &matrices[matrix_unrotated] );
2896 adv.x = pFT_Vector_Length( &adv );
2897 adv.y = 0;
2899 vec.x = lsb;
2900 vec.y = 0;
2901 pFT_Vector_Transform( &vec, &matrices[matrix_unrotated] );
2902 if (lsb > 0) abc->abcA = pFT_Vector_Length( &vec ) >> 6;
2903 else abc->abcA = -((pFT_Vector_Length( &vec ) + 63) >> 6);
2905 /* We use lsb again to avoid rounding errors */
2906 vec.x = lsb + (vertical ? metrics->height : metrics->width);
2907 vec.y = 0;
2908 pFT_Vector_Transform( &vec, &matrices[matrix_unrotated] );
2909 abc->abcB = ((pFT_Vector_Length( &vec ) + 63) >> 6) - abc->abcA;
2911 if (!abc->abcB) abc->abcB = 1;
2912 abc->abcC = (adv.x >> 6) - abc->abcA - abc->abcB;
2914 gm->gmptGlyphOrigin.x = origin.x >> 6;
2915 gm->gmptGlyphOrigin.y = origin.y >> 6;
2916 gm->gmBlackBoxX = (bbox.xMax - bbox.xMin) >> 6;
2917 gm->gmBlackBoxY = (bbox.yMax - bbox.yMin) >> 6;
2918 if (!gm->gmBlackBoxX) gm->gmBlackBoxX = 1;
2919 if (!gm->gmBlackBoxY) gm->gmBlackBoxY = 1;
2921 TRACE( "gm: %u, %u, %s, %d, %d abc %d, %u, %d\n",
2922 gm->gmBlackBoxX, gm->gmBlackBoxY, wine_dbgstr_point(&gm->gmptGlyphOrigin),
2923 gm->gmCellIncX, gm->gmCellIncY, abc->abcA, abc->abcB, abc->abcC );
2927 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
2929 static DWORD get_mono_glyph_bitmap( FT_GlyphSlot glyph, FT_BBox bbox,
2930 BOOL fake_bold, const FT_Matrix *matrices,
2931 DWORD buflen, BYTE *buf )
2933 DWORD width = (bbox.xMax - bbox.xMin ) >> 6;
2934 DWORD height = (bbox.yMax - bbox.yMin ) >> 6;
2935 DWORD pitch = ((width + 31) >> 5) << 2;
2936 DWORD needed = pitch * height;
2937 FT_Bitmap ft_bitmap;
2938 BYTE *src, *dst;
2939 INT w, h, x;
2941 if (!buf || !buflen) return needed;
2942 if (!needed) return GDI_ERROR; /* empty glyph */
2943 if (needed > buflen) return GDI_ERROR;
2945 switch (glyph->format)
2947 case FT_GLYPH_FORMAT_BITMAP:
2948 src = glyph->bitmap.buffer;
2949 dst = buf;
2950 w = min( pitch, (glyph->bitmap.width + 7) >> 3 );
2951 h = min( height, glyph->bitmap.rows );
2952 while (h--)
2954 if (!fake_bold)
2955 memcpy( dst, src, w );
2956 else
2958 dst[0] = 0;
2959 for (x = 0; x < w; x++)
2961 dst[x] = (dst[x] & 0x80) | (src[x] >> 1) | src[x];
2962 if (x + 1 < pitch)
2963 dst[x + 1] = (src[x] & 0x01) << 7;
2966 src += glyph->bitmap.pitch;
2967 dst += pitch;
2969 break;
2971 case FT_GLYPH_FORMAT_OUTLINE:
2972 ft_bitmap.width = width;
2973 ft_bitmap.rows = height;
2974 ft_bitmap.pitch = pitch;
2975 ft_bitmap.pixel_mode = FT_PIXEL_MODE_MONO;
2976 ft_bitmap.buffer = buf;
2978 if (matrices)
2979 pFT_Outline_Transform( &glyph->outline, &matrices[matrix_vert] );
2980 pFT_Outline_Translate( &glyph->outline, -bbox.xMin, -bbox.yMin );
2982 /* Note: FreeType will only set 'black' bits for us. */
2983 memset( buf, 0, buflen );
2984 pFT_Outline_Get_Bitmap( library, &glyph->outline, &ft_bitmap );
2985 break;
2987 default:
2988 FIXME( "loaded glyph format %x\n", glyph->format );
2989 return GDI_ERROR;
2992 return needed;
2995 static DWORD get_antialias_glyph_bitmap( FT_GlyphSlot glyph, FT_BBox bbox, UINT format,
2996 BOOL fake_bold, const FT_Matrix *matrices,
2997 DWORD buflen, BYTE *buf )
2999 DWORD width = (bbox.xMax - bbox.xMin ) >> 6;
3000 DWORD height = (bbox.yMax - bbox.yMin ) >> 6;
3001 DWORD pitch = (width + 3) / 4 * 4;
3002 DWORD needed = pitch * height;
3003 FT_Bitmap ft_bitmap;
3004 INT w, h, x, max_level;
3005 BYTE *src, *dst;
3007 if (!buf || !buflen) return needed;
3008 if (!needed) return GDI_ERROR; /* empty glyph */
3009 if (needed > buflen) return GDI_ERROR;
3011 max_level = get_max_level( format );
3013 switch (glyph->format)
3015 case FT_GLYPH_FORMAT_BITMAP:
3016 src = glyph->bitmap.buffer;
3017 dst = buf;
3018 memset( buf, 0, buflen );
3020 w = min( pitch, glyph->bitmap.width );
3021 h = min( height, glyph->bitmap.rows );
3022 while (h--)
3024 for (x = 0; x < w; x++)
3026 if (src[x / 8] & masks[x % 8])
3028 dst[x] = max_level;
3029 if (fake_bold && x + 1 < pitch) dst[x + 1] = max_level;
3032 src += glyph->bitmap.pitch;
3033 dst += pitch;
3035 break;
3037 case FT_GLYPH_FORMAT_OUTLINE:
3038 ft_bitmap.width = width;
3039 ft_bitmap.rows = height;
3040 ft_bitmap.pitch = pitch;
3041 ft_bitmap.pixel_mode = FT_PIXEL_MODE_GRAY;
3042 ft_bitmap.buffer = buf;
3044 if (matrices)
3045 pFT_Outline_Transform( &glyph->outline, &matrices[matrix_vert] );
3046 pFT_Outline_Translate( &glyph->outline, -bbox.xMin, -bbox.yMin );
3048 memset( buf, 0, buflen );
3049 pFT_Outline_Get_Bitmap( library, &glyph->outline, &ft_bitmap );
3051 if (max_level != 255)
3053 INT row, col;
3054 BYTE *ptr, *start;
3056 for (row = 0, start = buf; row < height; row++)
3058 for (col = 0, ptr = start; col < width; col++, ptr++)
3059 *ptr = (((int)*ptr) * (max_level + 1)) / 256;
3060 start += pitch;
3063 break;
3065 default:
3066 FIXME("loaded glyph format %x\n", glyph->format);
3067 return GDI_ERROR;
3070 return needed;
3073 static DWORD get_subpixel_glyph_bitmap( FT_GlyphSlot glyph, FT_BBox bbox, UINT format,
3074 BOOL fake_bold, const FT_Matrix *matrices,
3075 GLYPHMETRICS *gm, DWORD buflen, BYTE *buf )
3077 DWORD width = (bbox.xMax - bbox.xMin ) >> 6;
3078 DWORD height = (bbox.yMax - bbox.yMin ) >> 6;
3079 DWORD pitch, needed = 0;
3080 BYTE *src, *dst;
3081 INT w, h, x;
3083 switch (glyph->format)
3085 case FT_GLYPH_FORMAT_BITMAP:
3086 pitch = width * 4;
3087 needed = pitch * height;
3089 if (!buf || !buflen) break;
3090 if (!needed) return GDI_ERROR; /* empty glyph */
3091 if (needed > buflen) return GDI_ERROR;
3093 src = glyph->bitmap.buffer;
3094 dst = buf;
3095 memset( buf, 0, buflen );
3097 w = min( width, glyph->bitmap.width );
3098 h = min( height, glyph->bitmap.rows );
3099 while (h--)
3101 for (x = 0; x < w; x++)
3103 if ( src[x / 8] & masks[x % 8] )
3105 ((unsigned int *)dst)[x] = ~0u;
3106 if (fake_bold && x + 1 < width) ((unsigned int *)dst)[x + 1] = ~0u;
3109 src += glyph->bitmap.pitch;
3110 dst += pitch;
3112 break;
3114 case FT_GLYPH_FORMAT_OUTLINE:
3116 INT src_pitch, src_width, src_height, x_shift, y_shift;
3117 INT sub_stride, hmul, vmul;
3118 const INT *sub_order;
3119 const INT rgb_order[3] = { 0, 1, 2 };
3120 const INT bgr_order[3] = { 2, 1, 0 };
3121 FT_Render_Mode render_mode =
3122 (format == WINE_GGO_HRGB_BITMAP ||
3123 format == WINE_GGO_HBGR_BITMAP) ? FT_RENDER_MODE_LCD : FT_RENDER_MODE_LCD_V;
3125 if (!width || !height) /* empty glyph */
3127 if (!buf || !buflen) break;
3128 return GDI_ERROR;
3131 if ( render_mode == FT_RENDER_MODE_LCD)
3133 gm->gmBlackBoxX += 2;
3134 gm->gmptGlyphOrigin.x -= 1;
3135 bbox.xMin -= (1 << 6);
3137 else
3139 gm->gmBlackBoxY += 2;
3140 gm->gmptGlyphOrigin.y += 1;
3141 bbox.yMax += (1 << 6);
3144 width = gm->gmBlackBoxX;
3145 height = gm->gmBlackBoxY;
3146 pitch = width * 4;
3147 needed = pitch * height;
3149 if (!buf || !buflen) return needed;
3150 if (needed > buflen) return GDI_ERROR;
3152 if (matrices)
3153 pFT_Outline_Transform( &glyph->outline, &matrices[matrix_vert] );
3155 pFT_Render_Glyph( glyph, render_mode );
3157 src_pitch = glyph->bitmap.pitch;
3158 src_width = glyph->bitmap.width;
3159 src_height = glyph->bitmap.rows;
3160 src = glyph->bitmap.buffer;
3161 dst = buf;
3162 memset( buf, 0, buflen );
3164 sub_order = (format == WINE_GGO_HRGB_BITMAP ||
3165 format == WINE_GGO_VRGB_BITMAP) ? rgb_order : bgr_order;
3166 sub_stride = render_mode == FT_RENDER_MODE_LCD ? 1 : src_pitch;
3167 hmul = render_mode == FT_RENDER_MODE_LCD ? 3 : 1;
3168 vmul = render_mode == FT_RENDER_MODE_LCD ? 1 : 3;
3170 x_shift = glyph->bitmap_left - (bbox.xMin >> 6);
3171 if ( x_shift < 0 )
3173 src += hmul * -x_shift;
3174 src_width -= hmul * -x_shift;
3176 else if ( x_shift > 0 )
3178 dst += x_shift * sizeof(unsigned int);
3179 width -= x_shift;
3182 y_shift = (bbox.yMax >> 6) - glyph->bitmap_top;
3183 if ( y_shift < 0 )
3185 src += src_pitch * vmul * -y_shift;
3186 src_height -= vmul * -y_shift;
3188 else if ( y_shift > 0 )
3190 dst += y_shift * pitch;
3191 height -= y_shift;
3194 w = min( width, src_width / hmul );
3195 h = min( height, src_height / vmul );
3196 while (h--)
3198 for (x = 0; x < w; x++)
3200 ((unsigned int *)dst)[x] =
3201 ((unsigned int)src[hmul * x + sub_stride * sub_order[0]] << 16) |
3202 ((unsigned int)src[hmul * x + sub_stride * sub_order[1]] << 8) |
3203 ((unsigned int)src[hmul * x + sub_stride * sub_order[2]]);
3205 src += src_pitch * vmul;
3206 dst += pitch;
3208 break;
3210 default:
3211 FIXME ( "loaded glyph format %x\n", glyph->format );
3212 return GDI_ERROR;
3215 return needed;
3218 static unsigned int get_native_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
3220 TTPOLYGONHEADER *pph;
3221 TTPOLYCURVE *ppc;
3222 unsigned int needed = 0, point = 0, contour, first_pt;
3223 unsigned int pph_start, cpfx;
3224 DWORD type;
3226 for (contour = 0; contour < outline->n_contours; contour++)
3228 /* Ignore contours containing one point */
3229 if (point == outline->contours[contour])
3231 point++;
3232 continue;
3235 pph_start = needed;
3236 pph = (TTPOLYGONHEADER *)(buf + needed);
3237 first_pt = point;
3238 if (buf)
3240 pph->dwType = TT_POLYGON_TYPE;
3241 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3243 needed += sizeof(*pph);
3244 point++;
3245 while (point <= outline->contours[contour])
3247 ppc = (TTPOLYCURVE *)(buf + needed);
3248 type = outline->tags[point] & FT_Curve_Tag_On ?
3249 TT_PRIM_LINE : TT_PRIM_QSPLINE;
3250 cpfx = 0;
3253 if (buf)
3254 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3255 cpfx++;
3256 point++;
3257 } while (point <= outline->contours[contour] &&
3258 (outline->tags[point] & FT_Curve_Tag_On) ==
3259 (outline->tags[point-1] & FT_Curve_Tag_On));
3260 /* At the end of a contour Windows adds the start point, but
3261 only for Beziers */
3262 if (point > outline->contours[contour] &&
3263 !(outline->tags[point-1] & FT_Curve_Tag_On))
3265 if (buf)
3266 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
3267 cpfx++;
3269 else if (point <= outline->contours[contour] &&
3270 outline->tags[point] & FT_Curve_Tag_On)
3272 /* add closing pt for bezier */
3273 if (buf)
3274 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3275 cpfx++;
3276 point++;
3278 if (buf)
3280 ppc->wType = type;
3281 ppc->cpfx = cpfx;
3283 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3285 if (buf)
3286 pph->cb = needed - pph_start;
3288 return needed;
3291 static unsigned int get_bezier_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
3293 /* Convert the quadratic Beziers to cubic Beziers.
3294 The parametric eqn for a cubic Bezier is, from PLRM:
3295 r(t) = at^3 + bt^2 + ct + r0
3296 with the control points:
3297 r1 = r0 + c/3
3298 r2 = r1 + (c + b)/3
3299 r3 = r0 + c + b + a
3301 A quadratic Bezier has the form:
3302 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3304 So equating powers of t leads to:
3305 r1 = 2/3 p1 + 1/3 p0
3306 r2 = 2/3 p1 + 1/3 p2
3307 and of course r0 = p0, r3 = p2
3309 int contour, point = 0, first_pt;
3310 TTPOLYGONHEADER *pph;
3311 TTPOLYCURVE *ppc;
3312 DWORD pph_start, cpfx, type;
3313 FT_Vector cubic_control[4];
3314 unsigned int needed = 0;
3316 for (contour = 0; contour < outline->n_contours; contour++)
3318 pph_start = needed;
3319 pph = (TTPOLYGONHEADER *)(buf + needed);
3320 first_pt = point;
3321 if (buf)
3323 pph->dwType = TT_POLYGON_TYPE;
3324 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3326 needed += sizeof(*pph);
3327 point++;
3328 while (point <= outline->contours[contour])
3330 ppc = (TTPOLYCURVE *)(buf + needed);
3331 type = outline->tags[point] & FT_Curve_Tag_On ?
3332 TT_PRIM_LINE : TT_PRIM_CSPLINE;
3333 cpfx = 0;
3336 if (type == TT_PRIM_LINE)
3338 if (buf)
3339 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3340 cpfx++;
3341 point++;
3343 else
3345 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
3346 so cpfx = 3n */
3348 /* FIXME: Possible optimization in endpoint calculation
3349 if there are two consecutive curves */
3350 cubic_control[0] = outline->points[point-1];
3351 if (!(outline->tags[point-1] & FT_Curve_Tag_On))
3353 cubic_control[0].x += outline->points[point].x + 1;
3354 cubic_control[0].y += outline->points[point].y + 1;
3355 cubic_control[0].x >>= 1;
3356 cubic_control[0].y >>= 1;
3358 if (point+1 > outline->contours[contour])
3359 cubic_control[3] = outline->points[first_pt];
3360 else
3362 cubic_control[3] = outline->points[point+1];
3363 if (!(outline->tags[point+1] & FT_Curve_Tag_On))
3365 cubic_control[3].x += outline->points[point].x + 1;
3366 cubic_control[3].y += outline->points[point].y + 1;
3367 cubic_control[3].x >>= 1;
3368 cubic_control[3].y >>= 1;
3371 /* r1 = 1/3 p0 + 2/3 p1
3372 r2 = 1/3 p2 + 2/3 p1 */
3373 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
3374 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
3375 cubic_control[2] = cubic_control[1];
3376 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
3377 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
3378 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
3379 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
3380 if (buf)
3382 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
3383 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
3384 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
3386 cpfx += 3;
3387 point++;
3389 } while (point <= outline->contours[contour] &&
3390 (outline->tags[point] & FT_Curve_Tag_On) ==
3391 (outline->tags[point-1] & FT_Curve_Tag_On));
3392 /* At the end of a contour Windows adds the start point,
3393 but only for Beziers and we've already done that.
3395 if (point <= outline->contours[contour] &&
3396 outline->tags[point] & FT_Curve_Tag_On)
3398 /* This is the closing pt of a bezier, but we've already
3399 added it, so just inc point and carry on */
3400 point++;
3402 if (buf)
3404 ppc->wType = type;
3405 ppc->cpfx = cpfx;
3407 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3409 if (buf)
3410 pph->cb = needed - pph_start;
3412 return needed;
3415 static FT_Int get_load_flags( UINT format )
3417 FT_Int load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
3419 if (format & GGO_UNHINTED)
3420 return load_flags | FT_LOAD_NO_HINTING;
3422 switch (format & ~GGO_GLYPH_INDEX)
3424 case GGO_BITMAP:
3425 load_flags |= FT_LOAD_TARGET_MONO;
3426 break;
3427 case GGO_GRAY2_BITMAP:
3428 case GGO_GRAY4_BITMAP:
3429 case GGO_GRAY8_BITMAP:
3430 case WINE_GGO_GRAY16_BITMAP:
3431 load_flags |= FT_LOAD_TARGET_NORMAL;
3432 break;
3433 case WINE_GGO_HRGB_BITMAP:
3434 case WINE_GGO_HBGR_BITMAP:
3435 load_flags |= FT_LOAD_TARGET_LCD;
3436 break;
3437 case WINE_GGO_VRGB_BITMAP:
3438 case WINE_GGO_VBGR_BITMAP:
3439 load_flags |= FT_LOAD_TARGET_LCD_V;
3440 break;
3443 return load_flags;
3446 /*************************************************************
3447 * freetype_get_glyph_outline
3449 static DWORD freetype_get_glyph_outline( struct gdi_font *font, UINT glyph, UINT format,
3450 GLYPHMETRICS *lpgm, ABC *abc, DWORD buflen, void *buf,
3451 const MAT2 *lpmat, BOOL tategaki )
3453 struct gdi_font *base_font = font->base_font ? font->base_font : font;
3454 FT_Face ft_face = get_ft_face( font );
3455 FT_Glyph_Metrics metrics;
3456 FT_Error err;
3457 FT_BBox bbox;
3458 FT_Int load_flags = get_load_flags(format);
3459 FT_Matrix transform_matrices[3], *matrices = NULL;
3460 BOOL vertical_metrics;
3462 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm, buflen, buf, lpmat);
3464 TRACE("font transform %f %f %f %f\n",
3465 font->matrix.eM11, font->matrix.eM12,
3466 font->matrix.eM21, font->matrix.eM22);
3468 format &= ~GGO_UNHINTED;
3470 matrices = get_transform_matrices( font, tategaki, lpmat, transform_matrices );
3472 vertical_metrics = (tategaki && FT_HAS_VERTICAL(ft_face));
3473 /* there is a freetype bug where vertical metrics are only
3474 properly scaled and correct in 2.4.0 or greater */
3475 if (vertical_metrics && FT_SimpleVersion < FT_VERSION_VALUE(2, 4, 0))
3476 vertical_metrics = FALSE;
3478 if (matrices || format != GGO_BITMAP) load_flags |= FT_LOAD_NO_BITMAP;
3479 if (vertical_metrics) load_flags |= FT_LOAD_VERTICAL_LAYOUT;
3481 err = pFT_Load_Glyph(ft_face, glyph, load_flags);
3482 if (err && !(load_flags & FT_LOAD_NO_HINTING))
3484 WARN("Failed to load glyph %#x, retrying without hinting. Error %#x.\n", glyph, err);
3485 load_flags |= FT_LOAD_NO_HINTING;
3486 err = pFT_Load_Glyph(ft_face, glyph, load_flags);
3489 if(err) {
3490 WARN("Failed to load glyph %#x, error %#x.\n", glyph, err);
3491 return GDI_ERROR;
3494 metrics = ft_face->glyph->metrics;
3495 if(font->fake_bold) {
3496 if (!get_bold_glyph_outline(ft_face->glyph, font->ppem, &metrics) && metrics.width)
3497 metrics.width += 1 << 6;
3500 /* Some poorly-created fonts contain glyphs that exceed the boundaries set
3501 * by the text metrics. The proper behavior is to clip the glyph metrics to
3502 * fit within the maximums specified in the text metrics. */
3503 if (freetype_set_outline_text_metrics(base_font) ||
3504 freetype_set_bitmap_text_metrics(base_font)) {
3505 TEXTMETRICW *ptm = &base_font->otm.otmTextMetrics;
3506 INT top = min( metrics.horiBearingY, ptm->tmAscent << 6 );
3507 INT bottom = max( metrics.horiBearingY - metrics.height, -(ptm->tmDescent << 6) );
3508 metrics.horiBearingY = top;
3509 metrics.height = top - bottom;
3511 /* TODO: Are we supposed to clip the width as well...? */
3512 /* metrics.width = min( metrics.width, ptm->tmMaxCharWidth << 6 ); */
3515 bbox = get_transformed_bbox( &metrics, matrices );
3516 compute_metrics( font, bbox, &metrics, tategaki, vertical_metrics, matrices, lpgm, abc );
3518 switch (format)
3520 case GGO_METRICS:
3521 return 1; /* FIXME */
3523 case GGO_BITMAP:
3524 return get_mono_glyph_bitmap( ft_face->glyph, bbox, font->fake_bold,
3525 matrices, buflen, buf );
3527 case GGO_GRAY2_BITMAP:
3528 case GGO_GRAY4_BITMAP:
3529 case GGO_GRAY8_BITMAP:
3530 case WINE_GGO_GRAY16_BITMAP:
3531 return get_antialias_glyph_bitmap( ft_face->glyph, bbox, format, font->fake_bold,
3532 matrices, buflen, buf );
3534 case WINE_GGO_HRGB_BITMAP:
3535 case WINE_GGO_HBGR_BITMAP:
3536 case WINE_GGO_VRGB_BITMAP:
3537 case WINE_GGO_VBGR_BITMAP:
3538 return get_subpixel_glyph_bitmap( ft_face->glyph, bbox, format, font->fake_bold,
3539 matrices, lpgm, buflen, buf );
3541 case GGO_NATIVE:
3542 if (ft_face->glyph->format == ft_glyph_format_outline)
3544 FT_Outline *outline = &ft_face->glyph->outline;
3545 UINT needed;
3547 if (buflen == 0) buf = NULL;
3549 if (matrices && buf)
3550 pFT_Outline_Transform( outline, &matrices[matrix_vert] );
3552 needed = get_native_glyph_outline(outline, buflen, NULL);
3554 if (!buf || !buflen) return needed;
3555 if (needed > buflen) return GDI_ERROR;
3556 return get_native_glyph_outline(outline, buflen, buf);
3558 TRACE("loaded a bitmap\n");
3559 return GDI_ERROR;
3561 case GGO_BEZIER:
3562 if (ft_face->glyph->format == ft_glyph_format_outline)
3564 FT_Outline *outline = &ft_face->glyph->outline;
3565 UINT needed;
3567 if (buflen == 0) buf = NULL;
3569 if (matrices && buf)
3570 pFT_Outline_Transform( outline, &matrices[matrix_vert] );
3572 needed = get_bezier_glyph_outline(outline, buflen, NULL);
3574 if (!buf || !buflen) return needed;
3575 if (needed > buflen) return GDI_ERROR;
3576 return get_bezier_glyph_outline(outline, buflen, buf);
3578 TRACE("loaded a bitmap\n");
3579 return GDI_ERROR;
3581 default:
3582 FIXME("Unsupported format %d\n", format);
3583 return GDI_ERROR;
3587 /*************************************************************
3588 * freetype_set_bitmap_text_metrics
3590 static BOOL freetype_set_bitmap_text_metrics( struct gdi_font *font )
3592 FT_Face ft_face = get_ft_face( font );
3593 FT_WinFNT_HeaderRec winfnt_header;
3595 if (font->otm.otmSize) return TRUE; /* already set */
3596 font->otm.otmSize = offsetof( OUTLINETEXTMETRICW, otmFiller );
3598 #define TM font->otm.otmTextMetrics
3599 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
3601 TM.tmHeight = winfnt_header.pixel_height;
3602 TM.tmAscent = winfnt_header.ascent;
3603 TM.tmDescent = TM.tmHeight - TM.tmAscent;
3604 TM.tmInternalLeading = winfnt_header.internal_leading;
3605 TM.tmExternalLeading = winfnt_header.external_leading;
3606 TM.tmAveCharWidth = winfnt_header.avg_width;
3607 TM.tmMaxCharWidth = winfnt_header.max_width;
3608 TM.tmWeight = winfnt_header.weight;
3609 TM.tmOverhang = 0;
3610 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
3611 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
3612 TM.tmFirstChar = winfnt_header.first_char;
3613 TM.tmLastChar = winfnt_header.last_char;
3614 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
3615 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
3616 TM.tmItalic = winfnt_header.italic;
3617 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
3618 TM.tmCharSet = winfnt_header.charset;
3620 else
3622 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
3623 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
3624 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3625 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
3626 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
3627 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
3628 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
3629 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
3630 TM.tmOverhang = 0;
3631 TM.tmDigitizedAspectX = 96; /* FIXME */
3632 TM.tmDigitizedAspectY = 96; /* FIXME */
3633 TM.tmFirstChar = 1;
3634 TM.tmLastChar = 255;
3635 TM.tmDefaultChar = 32;
3636 TM.tmBreakChar = 32;
3637 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
3638 /* NB inverted meaning of TMPF_FIXED_PITCH */
3639 TM.tmPitchAndFamily = FT_IS_FIXED_WIDTH(ft_face) ? 0 : TMPF_FIXED_PITCH;
3640 TM.tmCharSet = font->charset;
3642 TM.tmUnderlined = font->lf.lfUnderline ? 0xff : 0;
3643 TM.tmStruckOut = font->lf.lfStrikeOut ? 0xff : 0;
3645 if(font->fake_bold)
3646 TM.tmWeight = FW_BOLD;
3647 #undef TM
3649 return TRUE;
3653 static BOOL face_has_symbol_charmap(FT_Face ft_face)
3655 int i;
3657 for(i = 0; i < ft_face->num_charmaps; i++)
3659 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
3660 return TRUE;
3662 return FALSE;
3665 /*************************************************************
3666 * freetype_set_outline_text_metrics
3668 static BOOL freetype_set_outline_text_metrics( struct gdi_font *font )
3670 FT_Face ft_face = get_ft_face( font );
3671 UINT needed;
3672 TT_OS2 *pOS2;
3673 TT_HoriHeader *pHori;
3674 TT_Postscript *pPost;
3675 FT_Fixed em_scale;
3676 INT ascent, descent;
3677 USHORT windescent;
3679 TRACE("font=%p\n", font);
3681 if (!font->scalable) return FALSE;
3682 if (font->otm.otmSize) return TRUE; /* already set */
3684 /* note: we store actual pointers in the names instead of offsets,
3685 they are fixed up when returned to the app */
3686 if (!(font->otm.otmpFullName = (char *)get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, system_lcid )))
3688 static const WCHAR fake_nameW[] = {'f','a','k','e',' ','n','a','m','e', 0};
3689 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w((WCHAR *)font->otm.otmpFamilyName));
3690 font->otm.otmpFullName = (char *)strdupW(fake_nameW);
3692 needed = sizeof(font->otm) + (lstrlenW( (WCHAR *)font->otm.otmpFamilyName ) + 1 +
3693 lstrlenW( (WCHAR *)font->otm.otmpStyleName ) + 1 +
3694 lstrlenW( (WCHAR *)font->otm.otmpFaceName ) + 1 +
3695 lstrlenW( (WCHAR *)font->otm.otmpFullName ) + 1) * sizeof(WCHAR);
3697 em_scale = (FT_Fixed)pFT_MulDiv(font->ppem, 1 << 16, ft_face->units_per_EM);
3699 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3700 if(!pOS2) {
3701 FIXME("Can't find OS/2 table - not TT font?\n");
3702 return FALSE;
3705 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3706 if(!pHori) {
3707 FIXME("Can't find HHEA table - not TT font?\n");
3708 return FALSE;
3711 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
3713 TRACE("OS/2 winA = %u winD = %u typoA = %d typoD = %d typoLG = %d avgW %d FT_Face a = %d, d = %d, h = %d: HORZ a = %d, d = %d lg = %d maxY = %ld minY = %ld\n",
3714 pOS2->usWinAscent, pOS2->usWinDescent,
3715 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
3716 pOS2->xAvgCharWidth,
3717 ft_face->ascender, ft_face->descender, ft_face->height,
3718 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
3719 ft_face->bbox.yMax, ft_face->bbox.yMin);
3721 font->otm.otmSize = needed;
3723 #define TM font->otm.otmTextMetrics
3725 windescent = get_fixed_windescent(pOS2->usWinDescent);
3726 if(pOS2->usWinAscent + windescent == 0) {
3727 ascent = pHori->Ascender;
3728 descent = -pHori->Descender;
3729 } else {
3730 ascent = pOS2->usWinAscent;
3731 descent = windescent;
3734 font->ntmAvgWidth = pOS2->xAvgCharWidth;
3736 #define SCALE_X(x) (pFT_MulFix(x, em_scale))
3737 #define SCALE_Y(y) (pFT_MulFix(y, em_scale))
3739 if(font->yMax) {
3740 TM.tmAscent = font->yMax;
3741 TM.tmDescent = -font->yMin;
3742 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
3743 } else {
3744 TM.tmAscent = SCALE_Y(ascent);
3745 TM.tmDescent = SCALE_Y(descent);
3746 TM.tmInternalLeading = SCALE_Y(ascent + descent - ft_face->units_per_EM);
3749 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3751 /* MSDN says:
3752 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
3754 TM.tmExternalLeading = max(0, SCALE_Y(pHori->Line_Gap -
3755 ((ascent + descent) -
3756 (pHori->Ascender - pHori->Descender))));
3758 TM.tmAveCharWidth = SCALE_X(pOS2->xAvgCharWidth);
3759 if (TM.tmAveCharWidth == 0) {
3760 TM.tmAveCharWidth = 1;
3762 TM.tmMaxCharWidth = SCALE_X(ft_face->bbox.xMax - ft_face->bbox.xMin);
3763 TM.tmWeight = FW_REGULAR;
3764 if (font->fake_bold)
3765 TM.tmWeight = FW_BOLD;
3766 else
3768 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
3770 if (pOS2->usWeightClass > FW_MEDIUM)
3771 TM.tmWeight = pOS2->usWeightClass;
3773 else if (pOS2->usWeightClass <= FW_MEDIUM)
3774 TM.tmWeight = pOS2->usWeightClass;
3776 TM.tmOverhang = 0;
3777 TM.tmDigitizedAspectX = 96; /* FIXME */
3778 TM.tmDigitizedAspectY = 96; /* FIXME */
3779 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
3780 * symbol range to 0 - f0ff
3783 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
3785 TM.tmFirstChar = 0;
3786 switch (PRIMARYLANGID(system_lcid))
3788 case LANG_HEBREW:
3789 TM.tmLastChar = 0xf896;
3790 break;
3791 case LANG_ESTONIAN:
3792 case LANG_LATVIAN:
3793 case LANG_LITHUANIAN:
3794 TM.tmLastChar = 0xf8fd;
3795 break;
3796 default:
3797 TM.tmLastChar = 0xf0ff;
3799 TM.tmBreakChar = 0x20;
3800 TM.tmDefaultChar = 0x1f;
3802 else
3804 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
3805 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
3807 if(pOS2->usFirstCharIndex <= 1)
3808 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
3809 else if (pOS2->usFirstCharIndex > 0xff)
3810 TM.tmBreakChar = 0x20;
3811 else
3812 TM.tmBreakChar = pOS2->usFirstCharIndex;
3813 TM.tmDefaultChar = TM.tmBreakChar - 1;
3815 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
3816 TM.tmUnderlined = font->lf.lfUnderline ? 255 : 0;
3817 TM.tmStruckOut = font->lf.lfStrikeOut ? 255 : 0;
3819 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
3820 if(!FT_IS_FIXED_WIDTH(ft_face) &&
3821 (pOS2->version == 0xFFFFU ||
3822 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
3823 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
3824 else
3825 TM.tmPitchAndFamily = 0;
3827 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
3829 case PAN_FAMILY_SCRIPT:
3830 TM.tmPitchAndFamily |= FF_SCRIPT;
3831 break;
3833 case PAN_FAMILY_DECORATIVE:
3834 TM.tmPitchAndFamily |= FF_DECORATIVE;
3835 break;
3837 case PAN_ANY:
3838 case PAN_NO_FIT:
3839 case PAN_FAMILY_TEXT_DISPLAY:
3840 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
3841 /* which is clearly not what the panose spec says. */
3842 default:
3843 if(TM.tmPitchAndFamily == 0 || /* fixed */
3844 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
3845 TM.tmPitchAndFamily = FF_MODERN;
3846 else
3848 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
3850 case PAN_ANY:
3851 case PAN_NO_FIT:
3852 default:
3853 TM.tmPitchAndFamily |= FF_DONTCARE;
3854 break;
3856 case PAN_SERIF_COVE:
3857 case PAN_SERIF_OBTUSE_COVE:
3858 case PAN_SERIF_SQUARE_COVE:
3859 case PAN_SERIF_OBTUSE_SQUARE_COVE:
3860 case PAN_SERIF_SQUARE:
3861 case PAN_SERIF_THIN:
3862 case PAN_SERIF_BONE:
3863 case PAN_SERIF_EXAGGERATED:
3864 case PAN_SERIF_TRIANGLE:
3865 TM.tmPitchAndFamily |= FF_ROMAN;
3866 break;
3868 case PAN_SERIF_NORMAL_SANS:
3869 case PAN_SERIF_OBTUSE_SANS:
3870 case PAN_SERIF_PERP_SANS:
3871 case PAN_SERIF_FLARED:
3872 case PAN_SERIF_ROUNDED:
3873 TM.tmPitchAndFamily |= FF_SWISS;
3874 break;
3877 break;
3880 if(FT_IS_SCALABLE(ft_face))
3881 TM.tmPitchAndFamily |= TMPF_VECTOR;
3883 if(FT_IS_SFNT(ft_face))
3885 if (font->ntmFlags & NTM_PS_OPENTYPE)
3886 TM.tmPitchAndFamily |= TMPF_DEVICE;
3887 else
3888 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
3891 TM.tmCharSet = font->charset;
3893 font->otm.otmFiller = 0;
3894 memcpy(&font->otm.otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
3895 font->otm.otmfsSelection = pOS2->fsSelection;
3896 if (font->fake_italic)
3897 font->otm.otmfsSelection |= 1;
3898 if (font->fake_bold)
3899 font->otm.otmfsSelection |= 1 << 5;
3900 /* Only return valid bits that define embedding and subsetting restrictions */
3901 font->otm.otmfsType = pOS2->fsType & 0x30e;
3902 font->otm.otmsCharSlopeRise = pHori->caret_Slope_Rise;
3903 font->otm.otmsCharSlopeRun = pHori->caret_Slope_Run;
3904 font->otm.otmItalicAngle = 0; /* POST table */
3905 font->otm.otmAscent = SCALE_Y(pOS2->sTypoAscender);
3906 font->otm.otmDescent = SCALE_Y(pOS2->sTypoDescender);
3907 font->otm.otmLineGap = SCALE_Y(pOS2->sTypoLineGap);
3908 font->otm.otmsCapEmHeight = SCALE_Y(pOS2->sCapHeight);
3909 font->otm.otmsXHeight = SCALE_Y(pOS2->sxHeight);
3910 font->otm.otmrcFontBox.left = SCALE_X(ft_face->bbox.xMin);
3911 font->otm.otmrcFontBox.right = SCALE_X(ft_face->bbox.xMax);
3912 font->otm.otmrcFontBox.top = SCALE_Y(ft_face->bbox.yMax);
3913 font->otm.otmrcFontBox.bottom = SCALE_Y(ft_face->bbox.yMin);
3914 font->otm.otmMacAscent = TM.tmAscent;
3915 font->otm.otmMacDescent = -TM.tmDescent;
3916 font->otm.otmMacLineGap = SCALE_Y(pHori->Line_Gap);
3917 font->otm.otmusMinimumPPEM = 0; /* TT Header */
3918 font->otm.otmptSubscriptSize.x = SCALE_X(pOS2->ySubscriptXSize);
3919 font->otm.otmptSubscriptSize.y = SCALE_Y(pOS2->ySubscriptYSize);
3920 font->otm.otmptSubscriptOffset.x = SCALE_X(pOS2->ySubscriptXOffset);
3921 font->otm.otmptSubscriptOffset.y = SCALE_Y(pOS2->ySubscriptYOffset);
3922 font->otm.otmptSuperscriptSize.x = SCALE_X(pOS2->ySuperscriptXSize);
3923 font->otm.otmptSuperscriptSize.y = SCALE_Y(pOS2->ySuperscriptYSize);
3924 font->otm.otmptSuperscriptOffset.x = SCALE_X(pOS2->ySuperscriptXOffset);
3925 font->otm.otmptSuperscriptOffset.y = SCALE_Y(pOS2->ySuperscriptYOffset);
3926 font->otm.otmsStrikeoutSize = SCALE_Y(pOS2->yStrikeoutSize);
3927 font->otm.otmsStrikeoutPosition = SCALE_Y(pOS2->yStrikeoutPosition);
3928 if(!pPost) {
3929 font->otm.otmsUnderscoreSize = 0;
3930 font->otm.otmsUnderscorePosition = 0;
3931 } else {
3932 font->otm.otmsUnderscoreSize = SCALE_Y(pPost->underlineThickness);
3933 font->otm.otmsUnderscorePosition = SCALE_Y(pPost->underlinePosition);
3935 #undef SCALE_X
3936 #undef SCALE_Y
3937 #undef TM
3938 return TRUE;
3941 /*************************************************************
3942 * freetype_get_char_width_info
3944 static BOOL freetype_get_char_width_info( struct gdi_font *font, struct char_width_info *info )
3946 FT_Face ft_face = get_ft_face( font );
3947 TT_HoriHeader *pHori;
3949 TRACE("%p, %p\n", font, info);
3951 if ((pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea)))
3953 FT_Fixed em_scale = pFT_MulDiv(font->ppem, 1 << 16, ft_face->units_per_EM);
3954 info->lsb = (SHORT)pFT_MulFix(pHori->min_Left_Side_Bearing, em_scale);
3955 info->rsb = (SHORT)pFT_MulFix(pHori->min_Right_Side_Bearing, em_scale);
3956 return TRUE;
3958 return FALSE;
3962 /*************************************************************
3963 * freetype_get_unicode_ranges
3965 * Retrieve a list of supported Unicode ranges for a given font.
3966 * Can be called with NULL gs to calculate the buffer size. Returns
3967 * the number of ranges found.
3969 static DWORD freetype_get_unicode_ranges( struct gdi_font *font, GLYPHSET *gs )
3971 FT_Face ft_face = get_ft_face( font );
3972 DWORD num_ranges = 0;
3974 if (ft_face->charmap->encoding == FT_ENCODING_UNICODE)
3976 FT_UInt glyph_code;
3977 FT_ULong char_code, char_code_prev;
3979 glyph_code = 0;
3980 char_code_prev = char_code = pFT_Get_First_Char(ft_face, &glyph_code);
3982 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
3983 ft_face->num_glyphs, glyph_code, char_code);
3985 if (!glyph_code) return 0;
3987 if (gs)
3989 gs->ranges[0].wcLow = (USHORT)char_code;
3990 gs->ranges[0].cGlyphs = 0;
3991 gs->cGlyphsSupported = 0;
3994 num_ranges = 1;
3995 while (glyph_code)
3997 if (char_code < char_code_prev)
3999 ERR("expected increasing char code from FT_Get_Next_Char\n");
4000 return 0;
4002 if (char_code - char_code_prev > 1)
4004 num_ranges++;
4005 if (gs)
4007 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
4008 gs->ranges[num_ranges - 1].cGlyphs = 1;
4009 gs->cGlyphsSupported++;
4012 else if (gs)
4014 gs->ranges[num_ranges - 1].cGlyphs++;
4015 gs->cGlyphsSupported++;
4017 char_code_prev = char_code;
4018 char_code = pFT_Get_Next_Char(ft_face, char_code, &glyph_code);
4021 else
4023 DWORD encoding = RtlUlongByteSwap(ft_face->charmap->encoding);
4024 FIXME("encoding %s not supported\n", debugstr_an((char *)&encoding, 4));
4027 return num_ranges;
4030 /*************************************************************************
4031 * Kerning support for TrueType fonts
4034 struct TT_kern_table
4036 USHORT version;
4037 USHORT nTables;
4040 struct TT_kern_subtable
4042 USHORT version;
4043 USHORT length;
4044 union
4046 USHORT word;
4047 struct
4049 USHORT horizontal : 1;
4050 USHORT minimum : 1;
4051 USHORT cross_stream: 1;
4052 USHORT override : 1;
4053 USHORT reserved1 : 4;
4054 USHORT format : 8;
4055 } bits;
4056 } coverage;
4059 struct TT_format0_kern_subtable
4061 USHORT nPairs;
4062 USHORT searchRange;
4063 USHORT entrySelector;
4064 USHORT rangeShift;
4067 struct TT_kern_pair
4069 USHORT left;
4070 USHORT right;
4071 short value;
4074 static DWORD parse_format0_kern_subtable(struct gdi_font *font,
4075 const struct TT_format0_kern_subtable *tt_f0_ks,
4076 const USHORT *glyph_to_char,
4077 KERNINGPAIR *kern_pair, DWORD cPairs)
4079 FT_Face ft_face = get_ft_face( font );
4080 USHORT i, nPairs;
4081 const struct TT_kern_pair *tt_kern_pair;
4083 TRACE("font height %d, units_per_EM %d\n", font->ppem, ft_face->units_per_EM);
4085 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
4087 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
4088 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
4089 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
4091 if (!kern_pair || !cPairs)
4092 return nPairs;
4094 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
4096 nPairs = min(nPairs, cPairs);
4098 for (i = 0; i < nPairs; i++)
4100 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
4101 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
4102 /* this algorithm appears to better match what Windows does */
4103 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
4104 if (kern_pair->iKernAmount < 0)
4106 kern_pair->iKernAmount -= ft_face->units_per_EM / 2;
4107 kern_pair->iKernAmount -= font->ppem;
4109 else if (kern_pair->iKernAmount > 0)
4111 kern_pair->iKernAmount += ft_face->units_per_EM / 2;
4112 kern_pair->iKernAmount += font->ppem;
4114 kern_pair->iKernAmount /= ft_face->units_per_EM;
4116 TRACE("left %u right %u value %d\n",
4117 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
4119 kern_pair++;
4121 TRACE("copied %u entries\n", nPairs);
4122 return nPairs;
4125 /*************************************************************
4126 * freetype_get_kerning_pairs
4128 static DWORD freetype_get_kerning_pairs( struct gdi_font *font, KERNINGPAIR **pairs )
4130 FT_Face ft_face = get_ft_face( font );
4131 DWORD length, count = 0;
4132 void *buf;
4133 const struct TT_kern_table *tt_kern_table;
4134 const struct TT_kern_subtable *tt_kern_subtable;
4135 USHORT i, nTables;
4136 USHORT *glyph_to_char;
4138 length = freetype_get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
4140 if (length == GDI_ERROR)
4142 TRACE("no kerning data in the font\n");
4143 return 0;
4146 buf = malloc( length );
4147 if (!buf) return 0;
4149 freetype_get_font_data(font, MS_KERN_TAG, 0, buf, length);
4151 /* build a glyph index to char code map */
4152 glyph_to_char = calloc( sizeof(USHORT), 65536 );
4153 if (!glyph_to_char)
4155 free( buf );
4156 return 0;
4159 if (ft_face->charmap->encoding == FT_ENCODING_UNICODE)
4161 FT_UInt glyph_code;
4162 FT_ULong char_code;
4164 glyph_code = 0;
4165 char_code = pFT_Get_First_Char(ft_face, &glyph_code);
4167 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
4168 ft_face->num_glyphs, glyph_code, char_code);
4170 while (glyph_code)
4172 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
4174 /* FIXME: This doesn't match what Windows does: it does some fancy
4175 * things with duplicate glyph index to char code mappings, while
4176 * we just avoid overriding existing entries.
4178 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
4179 glyph_to_char[glyph_code] = (USHORT)char_code;
4181 char_code = pFT_Get_Next_Char(ft_face, char_code, &glyph_code);
4184 else
4186 DWORD encoding = RtlUlongByteSwap(ft_face->charmap->encoding);
4187 ULONG n;
4189 FIXME("encoding %s not supported\n", debugstr_an((char *)&encoding, 4));
4190 for (n = 0; n <= 65535; n++)
4191 glyph_to_char[n] = (USHORT)n;
4194 tt_kern_table = buf;
4195 nTables = GET_BE_WORD(tt_kern_table->nTables);
4196 TRACE("version %u, nTables %u\n",
4197 GET_BE_WORD(tt_kern_table->version), nTables);
4199 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
4201 for (i = 0; i < nTables; i++)
4203 struct TT_kern_subtable tt_kern_subtable_copy;
4205 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
4206 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
4207 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
4209 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
4210 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
4211 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
4213 /* According to the TrueType specification this is the only format
4214 * that will be properly interpreted by Windows and OS/2
4216 if (tt_kern_subtable_copy.coverage.bits.format == 0)
4218 DWORD new_chunk, old_total = count;
4220 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
4221 glyph_to_char, NULL, 0);
4222 count += new_chunk;
4224 *pairs = realloc( *pairs, count * sizeof(**pairs));
4226 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
4227 glyph_to_char, *pairs + old_total, new_chunk);
4229 else
4230 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
4232 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
4235 free( glyph_to_char );
4236 free( buf );
4237 return count;
4240 static const struct font_backend_funcs font_funcs =
4242 freetype_load_fonts,
4243 fontconfig_enum_family_fallbacks,
4244 freetype_add_font,
4245 freetype_add_mem_font,
4246 freetype_load_font,
4247 freetype_get_font_data,
4248 freetype_get_aa_flags,
4249 freetype_get_glyph_index,
4250 freetype_get_default_glyph,
4251 freetype_get_glyph_outline,
4252 freetype_get_unicode_ranges,
4253 freetype_get_char_width_info,
4254 freetype_set_outline_text_metrics,
4255 freetype_set_bitmap_text_metrics,
4256 freetype_get_kerning_pairs,
4257 freetype_destroy_font
4260 const struct font_backend_funcs *init_freetype_lib(void)
4262 if (!init_freetype()) return NULL;
4263 #ifdef SONAME_LIBFONTCONFIG
4264 init_fontconfig();
4265 #endif
4266 NtQueryDefaultLocale( FALSE, &system_lcid );
4267 return &font_funcs;
4270 #else /* HAVE_FREETYPE */
4272 const struct font_backend_funcs *init_freetype_lib(void)
4274 return NULL;
4277 #endif /* HAVE_FREETYPE */