gdi32: Store ft_face font props on unix_face.
[wine.git] / dlls / gdi32 / freetype.c
blobcb993034d095251f3ce3fc0eccfd3b792ac30949
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"
29 #include "wine/port.h"
31 #include <stdarg.h>
32 #include <stdlib.h>
33 #ifdef HAVE_SYS_STAT_H
34 # include <sys/stat.h>
35 #endif
36 #ifdef HAVE_SYS_MMAN_H
37 # include <sys/mman.h>
38 #endif
39 #include <string.h>
40 #ifdef HAVE_DIRENT_H
41 # include <dirent.h>
42 #endif
43 #include <stdio.h>
44 #include <assert.h>
46 #ifdef HAVE_CARBON_CARBON_H
47 #define LoadResource __carbon_LoadResource
48 #define CompareString __carbon_CompareString
49 #define GetCurrentThread __carbon_GetCurrentThread
50 #define GetCurrentProcess __carbon_GetCurrentProcess
51 #define AnimatePalette __carbon_AnimatePalette
52 #define EqualRgn __carbon_EqualRgn
53 #define FillRgn __carbon_FillRgn
54 #define FrameRgn __carbon_FrameRgn
55 #define GetPixel __carbon_GetPixel
56 #define InvertRgn __carbon_InvertRgn
57 #define LineTo __carbon_LineTo
58 #define OffsetRgn __carbon_OffsetRgn
59 #define PaintRgn __carbon_PaintRgn
60 #define Polygon __carbon_Polygon
61 #define ResizePalette __carbon_ResizePalette
62 #define SetRectRgn __carbon_SetRectRgn
63 #include <Carbon/Carbon.h>
64 #undef LoadResource
65 #undef CompareString
66 #undef GetCurrentThread
67 #undef _CDECL
68 #undef GetCurrentProcess
69 #undef AnimatePalette
70 #undef EqualRgn
71 #undef FillRgn
72 #undef FrameRgn
73 #undef GetPixel
74 #undef InvertRgn
75 #undef LineTo
76 #undef OffsetRgn
77 #undef PaintRgn
78 #undef Polygon
79 #undef ResizePalette
80 #undef SetRectRgn
81 #endif /* HAVE_CARBON_CARBON_H */
83 #ifdef HAVE_FT2BUILD_H
84 #include <ft2build.h>
85 #include FT_FREETYPE_H
86 #include FT_GLYPH_H
87 #include FT_TYPES_H
88 #include FT_TRUETYPE_TABLES_H
89 #include FT_SFNT_NAMES_H
90 #include FT_TRUETYPE_IDS_H
91 #include FT_OUTLINE_H
92 #include FT_TRIGONOMETRY_H
93 #include FT_MODULE_H
94 #include FT_WINFONTS_H
95 #ifdef FT_LCD_FILTER_H
96 #include FT_LCD_FILTER_H
97 #endif
98 #endif /* HAVE_FT2BUILD_H */
100 #include "ntstatus.h"
101 #define WIN32_NO_STATUS
102 #include "windef.h"
103 #include "winbase.h"
104 #include "winternl.h"
105 #include "winerror.h"
106 #include "winreg.h"
107 #include "wingdi.h"
108 #include "gdi_private.h"
109 #include "wine/debug.h"
110 #include "wine/list.h"
112 #include "resource.h"
114 #ifdef HAVE_FREETYPE
116 WINE_DEFAULT_DEBUG_CHANNEL(font);
118 #ifndef HAVE_FT_TRUETYPEENGINETYPE
119 typedef enum
121 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
122 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
123 FT_TRUETYPE_ENGINE_TYPE_PATENTED
124 } FT_TrueTypeEngineType;
125 #endif
127 static FT_Library library = 0;
128 typedef struct
130 FT_Int major;
131 FT_Int minor;
132 FT_Int patch;
133 } FT_Version_t;
134 static FT_Version_t FT_Version;
135 static DWORD FT_SimpleVersion;
136 #define FT_VERSION_VALUE(major, minor, patch) (((major) << 16) | ((minor) << 8) | (patch))
138 static void *ft_handle = NULL;
140 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
141 MAKE_FUNCPTR(FT_Done_Face);
142 MAKE_FUNCPTR(FT_Get_Char_Index);
143 MAKE_FUNCPTR(FT_Get_First_Char);
144 MAKE_FUNCPTR(FT_Get_Next_Char);
145 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
146 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
147 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
148 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
149 MAKE_FUNCPTR(FT_Init_FreeType);
150 MAKE_FUNCPTR(FT_Library_Version);
151 MAKE_FUNCPTR(FT_Load_Glyph);
152 MAKE_FUNCPTR(FT_Load_Sfnt_Table);
153 MAKE_FUNCPTR(FT_Matrix_Multiply);
154 MAKE_FUNCPTR(FT_MulDiv);
155 #ifdef FT_MULFIX_INLINED
156 #define pFT_MulFix FT_MULFIX_INLINED
157 #else
158 MAKE_FUNCPTR(FT_MulFix);
159 #endif
160 MAKE_FUNCPTR(FT_New_Face);
161 MAKE_FUNCPTR(FT_New_Memory_Face);
162 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
163 MAKE_FUNCPTR(FT_Outline_Get_CBox);
164 MAKE_FUNCPTR(FT_Outline_Transform);
165 MAKE_FUNCPTR(FT_Outline_Translate);
166 MAKE_FUNCPTR(FT_Render_Glyph);
167 MAKE_FUNCPTR(FT_Set_Charmap);
168 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
169 MAKE_FUNCPTR(FT_Vector_Length);
170 MAKE_FUNCPTR(FT_Vector_Transform);
171 MAKE_FUNCPTR(FT_Vector_Unit);
172 static FT_Error (*pFT_Outline_Embolden)(FT_Outline *, FT_Pos);
173 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
174 #ifdef FT_LCD_FILTER_H
175 static FT_Error (*pFT_Library_SetLcdFilter)(FT_Library, FT_LcdFilter);
176 #endif
177 static FT_Error (*pFT_Property_Set)(FT_Library, const FT_String *, const FT_String *, const void *);
179 #ifdef SONAME_LIBFONTCONFIG
180 #include <fontconfig/fontconfig.h>
181 MAKE_FUNCPTR(FcConfigSubstitute);
182 MAKE_FUNCPTR(FcDefaultSubstitute);
183 MAKE_FUNCPTR(FcFontList);
184 MAKE_FUNCPTR(FcFontMatch);
185 MAKE_FUNCPTR(FcFontSetDestroy);
186 MAKE_FUNCPTR(FcInit);
187 MAKE_FUNCPTR(FcPatternAddString);
188 MAKE_FUNCPTR(FcPatternCreate);
189 MAKE_FUNCPTR(FcPatternDestroy);
190 MAKE_FUNCPTR(FcPatternGetBool);
191 MAKE_FUNCPTR(FcPatternGetInteger);
192 MAKE_FUNCPTR(FcPatternGetString);
193 MAKE_FUNCPTR(FcConfigGetFontDirs);
194 MAKE_FUNCPTR(FcConfigGetCurrent);
195 MAKE_FUNCPTR(FcCacheCopySet);
196 MAKE_FUNCPTR(FcCacheNumSubdir);
197 MAKE_FUNCPTR(FcCacheSubdir);
198 MAKE_FUNCPTR(FcDirCacheRead);
199 MAKE_FUNCPTR(FcDirCacheUnload);
200 MAKE_FUNCPTR(FcStrListCreate);
201 MAKE_FUNCPTR(FcStrListDone);
202 MAKE_FUNCPTR(FcStrListNext);
203 MAKE_FUNCPTR(FcStrSetAdd);
204 MAKE_FUNCPTR(FcStrSetCreate);
205 MAKE_FUNCPTR(FcStrSetDestroy);
206 MAKE_FUNCPTR(FcStrSetMember);
207 #ifndef FC_NAMELANG
208 #define FC_NAMELANG "namelang"
209 #endif
210 #ifndef FC_PRGNAME
211 #define FC_PRGNAME "prgname"
212 #endif
213 #endif /* SONAME_LIBFONTCONFIG */
215 #undef MAKE_FUNCPTR
217 #ifndef FT_MAKE_TAG
218 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
219 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
220 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
221 #endif
223 #ifndef ft_encoding_none
224 #define FT_ENCODING_NONE ft_encoding_none
225 #endif
226 #ifndef ft_encoding_ms_symbol
227 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
228 #endif
229 #ifndef ft_encoding_unicode
230 #define FT_ENCODING_UNICODE ft_encoding_unicode
231 #endif
232 #ifndef ft_encoding_apple_roman
233 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
234 #endif
236 #ifdef WORDS_BIGENDIAN
237 #define GET_BE_WORD(x) (x)
238 #define GET_BE_DWORD(x) (x)
239 #else
240 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
241 #define GET_BE_DWORD(x) RtlUlongByteSwap(x)
242 #endif
244 /* 'gasp' flags */
245 #define GASP_GRIDFIT 0x01
246 #define GASP_DOGRAY 0x02
248 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
249 So to let this compile on older versions of FreeType we'll define the
250 new structure here. */
251 typedef struct {
252 FT_Short height, width;
253 FT_Pos size, x_ppem, y_ppem;
254 } My_FT_Bitmap_Size;
256 struct font_private_data
258 FT_Face ft_face;
259 struct font_mapping *mapping;
262 static inline FT_Face get_ft_face( struct gdi_font *font )
264 return ((struct font_private_data *)font->private)->ft_face;
267 static const struct font_callback_funcs *callback_funcs;
269 struct font_mapping
271 struct list entry;
272 int refcount;
273 dev_t dev;
274 ino_t ino;
275 void *data;
276 size_t size;
279 static struct list mappings_list = LIST_INIT( mappings_list );
281 static UINT default_aa_flags;
282 static LCID system_lcid;
284 static BOOL CDECL freetype_set_outline_text_metrics( struct gdi_font *font );
285 static BOOL CDECL freetype_set_bitmap_text_metrics( struct gdi_font *font );
287 /****************************************
288 * Notes on .fon files
290 * The fonts System, FixedSys and Terminal are special. There are typically multiple
291 * versions installed for different resolutions and codepages. Windows stores which one to use
292 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
293 * Key Meaning
294 * FIXEDFON.FON FixedSys
295 * FONTS.FON System
296 * OEMFONT.FON Terminal
297 * LogPixels Current dpi set by the display control panel applet
298 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
299 * also has a LogPixels value that appears to mirror this)
301 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
302 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
303 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
304 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
305 * so that makes sense.
307 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
308 * to be mapped into the registry on Windows 2000 at least).
309 * I have
310 * woafont=app850.fon
311 * ega80woa.fon=ega80850.fon
312 * ega40woa.fon=ega40850.fon
313 * cga80woa.fon=cga80850.fon
314 * cga40woa.fon=cga40850.fon
317 #ifdef HAVE_CARBON_CARBON_H
318 static char *find_cache_dir(void)
320 FSRef ref;
321 OSErr err;
322 static char cached_path[MAX_PATH];
323 static const char *wine = "/Wine", *fonts = "/Fonts";
325 if(*cached_path) return cached_path;
327 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
328 if(err != noErr)
330 WARN("can't create cached data folder\n");
331 return NULL;
333 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
334 if(err != noErr)
336 WARN("can't create cached data path\n");
337 *cached_path = '\0';
338 return NULL;
340 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
342 ERR("Could not create full path\n");
343 *cached_path = '\0';
344 return NULL;
346 strcat(cached_path, wine);
348 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
350 WARN("Couldn't mkdir %s\n", cached_path);
351 *cached_path = '\0';
352 return NULL;
354 strcat(cached_path, fonts);
355 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
357 WARN("Couldn't mkdir %s\n", cached_path);
358 *cached_path = '\0';
359 return NULL;
361 return cached_path;
364 /******************************************************************
365 * expand_mac_font
367 * Extracts individual TrueType font files from a Mac suitcase font
368 * and saves them into the user's caches directory (see
369 * find_cache_dir()).
370 * Returns a NULL terminated array of filenames.
372 * We do this because they are apps that try to read ttf files
373 * themselves and they don't like Mac suitcase files.
375 static char **expand_mac_font(const char *path)
377 FSRef ref;
378 ResFileRefNum res_ref;
379 OSStatus s;
380 unsigned int idx;
381 const char *out_dir;
382 const char *filename;
383 int output_len;
384 struct {
385 char **array;
386 unsigned int size, max_size;
387 } ret;
389 TRACE("path %s\n", path);
391 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
392 if(s != noErr)
394 WARN("failed to get ref\n");
395 return NULL;
398 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
399 if(s != noErr)
401 TRACE("no data fork, so trying resource fork\n");
402 res_ref = FSOpenResFile(&ref, fsRdPerm);
403 if(res_ref == -1)
405 TRACE("unable to open resource fork\n");
406 return NULL;
410 ret.size = 0;
411 ret.max_size = 10;
412 ret.array = RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
413 if(!ret.array)
415 CloseResFile(res_ref);
416 return NULL;
419 out_dir = find_cache_dir();
421 filename = strrchr(path, '/');
422 if(!filename) filename = path;
423 else filename++;
425 /* output filename has the form out_dir/filename_%04x.ttf */
426 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
428 UseResFile(res_ref);
429 idx = 1;
430 while(1)
432 FamRec *fam_rec;
433 unsigned short *num_faces_ptr, num_faces, face;
434 AsscEntry *assoc;
435 Handle fond;
436 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
438 fond = Get1IndResource(fond_res, idx);
439 if(!fond) break;
440 TRACE("got fond resource %d\n", idx);
441 HLock(fond);
443 fam_rec = *(FamRec**)fond;
444 num_faces_ptr = (unsigned short *)(fam_rec + 1);
445 num_faces = GET_BE_WORD(*num_faces_ptr);
446 num_faces++;
447 assoc = (AsscEntry*)(num_faces_ptr + 1);
448 TRACE("num faces %04x\n", num_faces);
449 for(face = 0; face < num_faces; face++, assoc++)
451 Handle sfnt;
452 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
453 unsigned short size, font_id;
454 char *output;
456 size = GET_BE_WORD(assoc->fontSize);
457 font_id = GET_BE_WORD(assoc->fontID);
458 if(size != 0)
460 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
461 continue;
464 TRACE("trying to load sfnt id %04x\n", font_id);
465 sfnt = GetResource(sfnt_res, font_id);
466 if(!sfnt)
468 TRACE("can't get sfnt resource %04x\n", font_id);
469 continue;
472 output = RtlAllocateHeap(GetProcessHeap(), 0, output_len);
473 if(output)
475 int fd;
477 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
479 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
480 if(fd != -1 || errno == EEXIST)
482 if(fd != -1)
484 unsigned char *sfnt_data;
486 HLock(sfnt);
487 sfnt_data = *(unsigned char**)sfnt;
488 write(fd, sfnt_data, GetHandleSize(sfnt));
489 HUnlock(sfnt);
490 close(fd);
492 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
494 ret.max_size *= 2;
495 ret.array = RtlReAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
497 ret.array[ret.size++] = output;
499 else
501 WARN("unable to create %s\n", output);
502 RtlFreeHeap(GetProcessHeap(), 0, output);
505 ReleaseResource(sfnt);
507 HUnlock(fond);
508 ReleaseResource(fond);
509 idx++;
511 CloseResFile(res_ref);
513 return ret.array;
516 #endif /* HAVE_CARBON_CARBON_H */
519 This function builds an FT_Fixed from a double. It fails if the absolute
520 value of the float number is greater than 32768.
522 static inline FT_Fixed FT_FixedFromFloat(double f)
524 return f * 0x10000;
528 This function builds an FT_Fixed from a FIXED. It simply put f.value
529 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
531 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
533 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
536 static BOOL is_hinting_enabled(void)
538 static int enabled = -1;
540 if (enabled == -1)
542 /* Use the >= 2.2.0 function if available */
543 if (pFT_Get_TrueType_Engine_Type)
545 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
546 enabled = (type == FT_TRUETYPE_ENGINE_TYPE_PATENTED);
548 else enabled = FALSE;
549 TRACE("hinting is %senabled\n", enabled ? "" : "NOT ");
551 return enabled;
554 static BOOL is_subpixel_rendering_enabled( void )
556 static int enabled = -1;
557 if (enabled == -1)
559 /* FreeType >= 2.8.1 offers LCD-optimezed rendering without lcd filters. */
560 if (FT_SimpleVersion >= FT_VERSION_VALUE(2, 8, 1))
561 enabled = TRUE;
562 #ifdef FT_LCD_FILTER_H
563 else if (pFT_Library_SetLcdFilter &&
564 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature)
565 enabled = TRUE;
566 #endif
567 else enabled = FALSE;
569 TRACE("subpixel rendering is %senabled\n", enabled ? "" : "NOT ");
571 return enabled;
575 static LPWSTR strdupW(LPCWSTR p)
577 LPWSTR ret;
578 DWORD len = (lstrlenW(p) + 1) * sizeof(WCHAR);
579 ret = RtlAllocateHeap(GetProcessHeap(), 0, len);
580 memcpy(ret, p, len);
581 return ret;
584 static WCHAR *towstr(const char *str)
586 DWORD len = strlen(str) + 1;
587 WCHAR *wstr = RtlAllocateHeap( GetProcessHeap(), 0, len * sizeof(WCHAR) );
588 RtlMultiByteToUnicodeN( wstr, len * sizeof(WCHAR), &len, str, len );
589 return wstr;
593 static const LANGID mac_langid_table[] =
595 MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ENGLISH */
596 MAKELANGID(LANG_FRENCH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FRENCH */
597 MAKELANGID(LANG_GERMAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GERMAN */
598 MAKELANGID(LANG_ITALIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ITALIAN */
599 MAKELANGID(LANG_DUTCH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_DUTCH */
600 MAKELANGID(LANG_SWEDISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SWEDISH */
601 MAKELANGID(LANG_SPANISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SPANISH */
602 MAKELANGID(LANG_DANISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_DANISH */
603 MAKELANGID(LANG_PORTUGUESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PORTUGUESE */
604 MAKELANGID(LANG_NORWEGIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_NORWEGIAN */
605 MAKELANGID(LANG_HEBREW,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HEBREW */
606 MAKELANGID(LANG_JAPANESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_JAPANESE */
607 MAKELANGID(LANG_ARABIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ARABIC */
608 MAKELANGID(LANG_FINNISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FINNISH */
609 MAKELANGID(LANG_GREEK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GREEK */
610 MAKELANGID(LANG_ICELANDIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ICELANDIC */
611 MAKELANGID(LANG_MALTESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALTESE */
612 MAKELANGID(LANG_TURKISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TURKISH */
613 MAKELANGID(LANG_CROATIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CROATIAN */
614 MAKELANGID(LANG_CHINESE_TRADITIONAL,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CHINESE_TRADITIONAL */
615 MAKELANGID(LANG_URDU,SUBLANG_DEFAULT), /* TT_MAC_LANGID_URDU */
616 MAKELANGID(LANG_HINDI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HINDI */
617 MAKELANGID(LANG_THAI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_THAI */
618 MAKELANGID(LANG_KOREAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KOREAN */
619 MAKELANGID(LANG_LITHUANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LITHUANIAN */
620 MAKELANGID(LANG_POLISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_POLISH */
621 MAKELANGID(LANG_HUNGARIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HUNGARIAN */
622 MAKELANGID(LANG_ESTONIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ESTONIAN */
623 MAKELANGID(LANG_LATVIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LETTISH */
624 MAKELANGID(LANG_SAMI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SAAMISK */
625 MAKELANGID(LANG_FAEROESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FAEROESE */
626 MAKELANGID(LANG_FARSI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FARSI */
627 MAKELANGID(LANG_RUSSIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_RUSSIAN */
628 MAKELANGID(LANG_CHINESE_SIMPLIFIED,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CHINESE_SIMPLIFIED */
629 MAKELANGID(LANG_DUTCH,SUBLANG_DUTCH_BELGIAN), /* TT_MAC_LANGID_FLEMISH */
630 MAKELANGID(LANG_IRISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_IRISH */
631 MAKELANGID(LANG_ALBANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ALBANIAN */
632 MAKELANGID(LANG_ROMANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ROMANIAN */
633 MAKELANGID(LANG_CZECH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CZECH */
634 MAKELANGID(LANG_SLOVAK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SLOVAK */
635 MAKELANGID(LANG_SLOVENIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SLOVENIAN */
636 0, /* TT_MAC_LANGID_YIDDISH */
637 MAKELANGID(LANG_SERBIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SERBIAN */
638 MAKELANGID(LANG_MACEDONIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MACEDONIAN */
639 MAKELANGID(LANG_BULGARIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BULGARIAN */
640 MAKELANGID(LANG_UKRAINIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UKRAINIAN */
641 MAKELANGID(LANG_BELARUSIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BYELORUSSIAN */
642 MAKELANGID(LANG_UZBEK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UZBEK */
643 MAKELANGID(LANG_KAZAK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KAZAKH */
644 MAKELANGID(LANG_AZERI,SUBLANG_AZERI_CYRILLIC), /* TT_MAC_LANGID_AZERBAIJANI */
645 0, /* TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT */
646 MAKELANGID(LANG_ARMENIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ARMENIAN */
647 MAKELANGID(LANG_GEORGIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GEORGIAN */
648 0, /* TT_MAC_LANGID_MOLDAVIAN */
649 MAKELANGID(LANG_KYRGYZ,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KIRGHIZ */
650 MAKELANGID(LANG_TAJIK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TAJIKI */
651 MAKELANGID(LANG_TURKMEN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TURKMEN */
652 MAKELANGID(LANG_MONGOLIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MONGOLIAN */
653 MAKELANGID(LANG_MONGOLIAN,SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA), /* TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT */
654 MAKELANGID(LANG_PASHTO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PASHTO */
655 0, /* TT_MAC_LANGID_KURDISH */
656 MAKELANGID(LANG_KASHMIRI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KASHMIRI */
657 MAKELANGID(LANG_SINDHI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SINDHI */
658 MAKELANGID(LANG_TIBETAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TIBETAN */
659 MAKELANGID(LANG_NEPALI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_NEPALI */
660 MAKELANGID(LANG_SANSKRIT,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SANSKRIT */
661 MAKELANGID(LANG_MARATHI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MARATHI */
662 MAKELANGID(LANG_BENGALI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BENGALI */
663 MAKELANGID(LANG_ASSAMESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ASSAMESE */
664 MAKELANGID(LANG_GUJARATI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GUJARATI */
665 MAKELANGID(LANG_PUNJABI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PUNJABI */
666 MAKELANGID(LANG_ORIYA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ORIYA */
667 MAKELANGID(LANG_MALAYALAM,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAYALAM */
668 MAKELANGID(LANG_KANNADA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KANNADA */
669 MAKELANGID(LANG_TAMIL,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TAMIL */
670 MAKELANGID(LANG_TELUGU,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TELUGU */
671 MAKELANGID(LANG_SINHALESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SINHALESE */
672 0, /* TT_MAC_LANGID_BURMESE */
673 MAKELANGID(LANG_KHMER,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KHMER */
674 MAKELANGID(LANG_LAO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LAO */
675 MAKELANGID(LANG_VIETNAMESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_VIETNAMESE */
676 MAKELANGID(LANG_INDONESIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_INDONESIAN */
677 0, /* TT_MAC_LANGID_TAGALOG */
678 MAKELANGID(LANG_MALAY,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAY_ROMAN_SCRIPT */
679 0, /* TT_MAC_LANGID_MALAY_ARABIC_SCRIPT */
680 MAKELANGID(LANG_AMHARIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_AMHARIC */
681 MAKELANGID(LANG_TIGRIGNA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TIGRINYA */
682 0, /* TT_MAC_LANGID_GALLA */
683 0, /* TT_MAC_LANGID_SOMALI */
684 MAKELANGID(LANG_SWAHILI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SWAHILI */
685 0, /* TT_MAC_LANGID_RUANDA */
686 0, /* TT_MAC_LANGID_RUNDI */
687 0, /* TT_MAC_LANGID_CHEWA */
688 MAKELANGID(LANG_MALAGASY,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAGASY */
689 MAKELANGID(LANG_ESPERANTO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ESPERANTO */
690 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 95-111 */
691 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 112-127 */
692 MAKELANGID(LANG_WELSH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_WELSH */
693 MAKELANGID(LANG_BASQUE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BASQUE */
694 MAKELANGID(LANG_CATALAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CATALAN */
695 0, /* TT_MAC_LANGID_LATIN */
696 MAKELANGID(LANG_QUECHUA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_QUECHUA */
697 0, /* TT_MAC_LANGID_GUARANI */
698 0, /* TT_MAC_LANGID_AYMARA */
699 MAKELANGID(LANG_TATAR,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TATAR */
700 MAKELANGID(LANG_UIGHUR,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UIGHUR */
701 0, /* TT_MAC_LANGID_DZONGKHA */
702 0, /* TT_MAC_LANGID_JAVANESE */
703 0, /* TT_MAC_LANGID_SUNDANESE */
704 MAKELANGID(LANG_GALICIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GALICIAN */
705 MAKELANGID(LANG_AFRIKAANS,SUBLANG_DEFAULT), /* TT_MAC_LANGID_AFRIKAANS */
706 MAKELANGID(LANG_BRETON,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BRETON */
707 MAKELANGID(LANG_INUKTITUT,SUBLANG_DEFAULT), /* TT_MAC_LANGID_INUKTITUT */
708 MAKELANGID(LANG_SCOTTISH_GAELIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SCOTTISH_GAELIC */
709 MAKELANGID(LANG_MANX_GAELIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MANX_GAELIC */
710 MAKELANGID(LANG_IRISH,SUBLANG_IRISH_IRELAND), /* TT_MAC_LANGID_IRISH_GAELIC */
711 0, /* TT_MAC_LANGID_TONGAN */
712 0, /* TT_MAC_LANGID_GREEK_POLYTONIC */
713 MAKELANGID(LANG_GREENLANDIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GREELANDIC */
714 MAKELANGID(LANG_AZERI,SUBLANG_AZERI_LATIN), /* TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT */
717 static CPTABLEINFO *get_mac_code_page( const FT_SfntName *name )
719 static CPTABLEINFO tables[100];
720 int id = name->encoding_id;
721 USHORT *ptr;
722 SIZE_T size;
724 if (name->encoding_id == TT_MAC_ID_SIMPLIFIED_CHINESE) id = 8; /* special case */
725 if (id >= ARRAY_SIZE(tables)) return NULL;
726 if (!tables[id].CodePage)
728 if (NtGetNlsSectionPtr( 11, 10000 + id, NULL, (void **)&ptr, &size )) return NULL;
729 RtlInitCodePageTable( ptr, &tables[id] );
731 return &tables[id];
734 static int match_name_table_language( const FT_SfntName *name, LANGID lang )
736 LANGID name_lang;
737 int res = 0;
739 switch (name->platform_id)
741 case TT_PLATFORM_MICROSOFT:
742 res += 5; /* prefer the Microsoft name */
743 switch (name->encoding_id)
745 case TT_MS_ID_UNICODE_CS:
746 case TT_MS_ID_SYMBOL_CS:
747 name_lang = name->language_id;
748 break;
749 default:
750 return 0;
752 break;
753 case TT_PLATFORM_MACINTOSH:
754 if (!get_mac_code_page( name )) return 0;
755 if (name->language_id >= ARRAY_SIZE( mac_langid_table )) return 0;
756 name_lang = mac_langid_table[name->language_id];
757 break;
758 case TT_PLATFORM_APPLE_UNICODE:
759 res += 2; /* prefer Unicode encodings */
760 switch (name->encoding_id)
762 case TT_APPLE_ID_DEFAULT:
763 case TT_APPLE_ID_ISO_10646:
764 case TT_APPLE_ID_UNICODE_2_0:
765 if (name->language_id >= ARRAY_SIZE( mac_langid_table )) return 0;
766 name_lang = mac_langid_table[name->language_id];
767 break;
768 default:
769 return 0;
771 break;
772 default:
773 return 0;
775 if (name_lang == lang) res += 30;
776 else if (PRIMARYLANGID( name_lang ) == PRIMARYLANGID( lang )) res += 20;
777 else if (name_lang == MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT )) res += 10;
778 else if (lang == MAKELANGID( LANG_NEUTRAL, SUBLANG_NEUTRAL )) res += 5 * (0x100000 - name_lang);
779 return res;
782 static WCHAR *copy_name_table_string( const FT_SfntName *name )
784 WCHAR *ret;
785 CPTABLEINFO *cp;
786 DWORD i;
788 switch (name->platform_id)
790 case TT_PLATFORM_APPLE_UNICODE:
791 case TT_PLATFORM_MICROSOFT:
792 ret = RtlAllocateHeap( GetProcessHeap(), 0, name->string_len + sizeof(WCHAR) );
793 for (i = 0; i < name->string_len / 2; i++)
794 ret[i] = (name->string[i * 2] << 8) | name->string[i * 2 + 1];
795 ret[i] = 0;
796 return ret;
797 case TT_PLATFORM_MACINTOSH:
798 if (!(cp = get_mac_code_page( name ))) return NULL;
799 ret = RtlAllocateHeap( GetProcessHeap(), 0, (name->string_len + 1) * sizeof(WCHAR) );
800 RtlCustomCPToUnicodeN( cp, ret, name->string_len * sizeof(WCHAR), &i,
801 (char *)name->string, name->string_len );
802 ret[i / sizeof(WCHAR)] = 0;
803 return ret;
805 return NULL;
808 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, LANGID language_id)
810 FT_SfntName name;
811 FT_UInt num_names, name_index;
812 int res, best_lang = 0, best_index = -1;
814 if (!FT_IS_SFNT(ft_face)) return NULL;
816 num_names = pFT_Get_Sfnt_Name_Count( ft_face );
818 for (name_index = 0; name_index < num_names; name_index++)
820 if (pFT_Get_Sfnt_Name( ft_face, name_index, &name )) continue;
821 if (name.name_id != name_id) continue;
822 res = match_name_table_language( &name, language_id );
823 if (res > best_lang)
825 best_lang = res;
826 best_index = name_index;
830 if (best_index != -1 && !pFT_Get_Sfnt_Name( ft_face, best_index, &name ))
832 WCHAR *ret = copy_name_table_string( &name );
833 TRACE( "name %u found platform %u lang %04x %s\n",
834 name_id, name.platform_id, name.language_id, debugstr_w( ret ));
835 return ret;
837 return NULL;
840 static WCHAR *ft_face_get_family_name( FT_Face ft_face, LANGID langid )
842 WCHAR *family_name;
844 if ((family_name = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, langid )))
845 return family_name;
847 return towstr( ft_face->family_name );
850 static WCHAR *ft_face_get_style_name( FT_Face ft_face, LANGID langid )
852 WCHAR *style_name;
854 if ((style_name = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, langid )))
855 return style_name;
857 return towstr( ft_face->style_name );
860 static WCHAR *ft_face_get_full_name( FT_Face ft_face, LANGID langid )
862 static const WCHAR space_w[] = {' ',0};
863 WCHAR *full_name, *style_name;
864 SIZE_T length;
866 if ((full_name = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, langid )))
867 return full_name;
869 full_name = ft_face_get_family_name( ft_face, langid );
870 style_name = ft_face_get_style_name( ft_face, langid );
872 length = lstrlenW( full_name ) + lstrlenW( space_w ) + lstrlenW( style_name ) + 1;
873 full_name = RtlReAllocateHeap( GetProcessHeap(), 0, full_name, length * sizeof(WCHAR) );
875 lstrcatW( full_name, space_w );
876 lstrcatW( full_name, style_name );
877 RtlFreeHeap( GetProcessHeap(), 0, style_name );
879 WARN( "full name not found, using %s instead\n", debugstr_w(full_name) );
880 return full_name;
883 static inline FT_Fixed get_font_version( FT_Face ft_face )
885 FT_Fixed version = 0;
886 TT_Header *header;
888 header = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head );
889 if (header) version = header->Font_Revision;
891 return version;
894 static inline DWORD get_ntm_flags( FT_Face ft_face )
896 DWORD flags = 0;
897 FT_ULong table_size = 0;
898 FT_WinFNT_HeaderRec winfnt_header;
900 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) flags |= NTM_ITALIC;
901 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD) flags |= NTM_BOLD;
903 /* fixup the flag for our fake-bold implementation. */
904 if (!FT_IS_SCALABLE( ft_face ) &&
905 !pFT_Get_WinFNT_Header( ft_face, &winfnt_header ) &&
906 winfnt_header.weight > FW_NORMAL )
907 flags |= NTM_BOLD;
909 if (flags == 0) flags = NTM_REGULAR;
911 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL, &table_size ))
912 flags |= NTM_PS_OPENTYPE;
914 return flags;
917 static inline void get_bitmap_size( FT_Face ft_face, struct bitmap_font_size *face_size )
919 My_FT_Bitmap_Size *size;
920 FT_WinFNT_HeaderRec winfnt_header;
922 size = (My_FT_Bitmap_Size *)ft_face->available_sizes;
923 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
924 size->height, size->width, size->size >> 6,
925 size->x_ppem >> 6, size->y_ppem >> 6);
926 face_size->height = size->height;
927 face_size->width = size->width;
928 face_size->size = size->size;
929 face_size->x_ppem = size->x_ppem;
930 face_size->y_ppem = size->y_ppem;
932 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header )) {
933 face_size->internal_leading = winfnt_header.internal_leading;
934 if (winfnt_header.external_leading > 0 &&
935 (face_size->height ==
936 winfnt_header.pixel_height + winfnt_header.external_leading))
937 face_size->height = winfnt_header.pixel_height;
941 static inline void get_fontsig( FT_Face ft_face, FONTSIGNATURE *fs )
943 TT_OS2 *os2;
944 FT_WinFNT_HeaderRec winfnt_header;
945 int i;
947 memset( fs, 0, sizeof(*fs) );
949 os2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 );
950 if (os2)
952 fs->fsUsb[0] = os2->ulUnicodeRange1;
953 fs->fsUsb[1] = os2->ulUnicodeRange2;
954 fs->fsUsb[2] = os2->ulUnicodeRange3;
955 fs->fsUsb[3] = os2->ulUnicodeRange4;
957 if (os2->version == 0)
959 if (os2->usFirstCharIndex >= 0xf000 && os2->usFirstCharIndex < 0xf100)
960 fs->fsCsb[0] = FS_SYMBOL;
961 else
962 fs->fsCsb[0] = FS_LATIN1;
964 else
966 fs->fsCsb[0] = os2->ulCodePageRange1;
967 fs->fsCsb[1] = os2->ulCodePageRange2;
970 else
972 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
974 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
975 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
976 switch (winfnt_header.charset)
978 case ANSI_CHARSET: fs->fsCsb[0] = FS_LATIN1; break;
979 case EASTEUROPE_CHARSET: fs->fsCsb[0] = FS_LATIN2; break;
980 case RUSSIAN_CHARSET: fs->fsCsb[0] = FS_CYRILLIC; break;
981 case GREEK_CHARSET: fs->fsCsb[0] = FS_GREEK; break;
982 case TURKISH_CHARSET: fs->fsCsb[0] = FS_TURKISH; break;
983 case HEBREW_CHARSET: fs->fsCsb[0] = FS_HEBREW; break;
984 case ARABIC_CHARSET: fs->fsCsb[0] = FS_ARABIC; break;
985 case BALTIC_CHARSET: fs->fsCsb[0] = FS_BALTIC; break;
986 case VIETNAMESE_CHARSET: fs->fsCsb[0] = FS_VIETNAMESE; break;
987 case THAI_CHARSET: fs->fsCsb[0] = FS_THAI; break;
988 case SHIFTJIS_CHARSET: fs->fsCsb[0] = FS_JISJAPAN; break;
989 case GB2312_CHARSET: fs->fsCsb[0] = FS_CHINESESIMP; break;
990 case HANGEUL_CHARSET: fs->fsCsb[0] = FS_WANSUNG; break;
991 case CHINESEBIG5_CHARSET: fs->fsCsb[0] = FS_CHINESETRAD; break;
992 case JOHAB_CHARSET: fs->fsCsb[0] = FS_JOHAB; break;
993 case SYMBOL_CHARSET: fs->fsCsb[0] = FS_SYMBOL; break;
998 if (fs->fsCsb[0] == 0)
1000 /* let's see if we can find any interesting cmaps */
1001 for (i = 0; i < ft_face->num_charmaps; i++)
1003 switch (ft_face->charmaps[i]->encoding)
1005 case FT_ENCODING_UNICODE:
1006 case FT_ENCODING_APPLE_ROMAN:
1007 fs->fsCsb[0] |= FS_LATIN1;
1008 break;
1009 case FT_ENCODING_MS_SYMBOL:
1010 fs->fsCsb[0] |= FS_SYMBOL;
1011 break;
1012 default:
1013 break;
1019 static FT_Face new_ft_face( const char *file, void *font_data_ptr, DWORD font_data_size,
1020 FT_Long face_index, BOOL allow_bitmap )
1022 FT_Error err;
1023 TT_OS2 *pOS2;
1024 FT_Face ft_face;
1026 if (file)
1028 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1029 err = pFT_New_Face(library, file, face_index, &ft_face);
1031 else
1033 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1034 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1037 if (err != 0)
1039 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1040 return NULL;
1043 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1044 if (!FT_IS_SCALABLE( ft_face ) && FT_SimpleVersion < FT_VERSION_VALUE(2, 1, 9))
1046 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1047 goto fail;
1050 if (!FT_IS_SFNT( ft_face ))
1052 if (FT_IS_SCALABLE( ft_face ) || !allow_bitmap )
1054 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1055 goto fail;
1058 else
1060 if (!(pOS2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 )) ||
1061 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_hhea ) ||
1062 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head ))
1064 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1065 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1066 goto fail;
1069 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1070 we don't want to load these. */
1071 if (!memcmp( pOS2->achVendID, "Wine", sizeof(pOS2->achVendID) ))
1073 FT_ULong len = 0;
1075 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len ))
1077 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1078 goto fail;
1083 if (!ft_face->family_name || !ft_face->style_name)
1085 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1086 goto fail;
1089 return ft_face;
1090 fail:
1091 pFT_Done_Face( ft_face );
1092 return NULL;
1095 struct unix_face
1097 FT_Face ft_face;
1098 BOOL scalable;
1099 UINT num_faces;
1100 WCHAR *family_name;
1101 WCHAR *second_name;
1102 WCHAR *style_name;
1103 WCHAR *full_name;
1104 DWORD ntm_flags;
1105 DWORD font_version;
1106 FONTSIGNATURE fs;
1107 struct bitmap_font_size size;
1110 static struct unix_face *unix_face_create( const char *unix_name, void *data_ptr, DWORD data_size,
1111 UINT face_index, DWORD flags )
1113 struct unix_face *This;
1114 struct stat st;
1115 int fd;
1117 TRACE( "unix_name %s, face_index %u, data_ptr %p, data_size %u, flags %#x\n",
1118 unix_name, face_index, data_ptr, data_size, flags );
1120 if (unix_name)
1122 if ((fd = open( unix_name, O_RDONLY )) == -1) return NULL;
1123 if (fstat( fd, &st ) == -1)
1125 close( fd );
1126 return NULL;
1128 data_size = st.st_size;
1129 data_ptr = mmap( NULL, data_size, PROT_READ, MAP_PRIVATE, fd, 0 );
1130 close( fd );
1131 if (data_ptr == MAP_FAILED) return NULL;
1134 if (!(This = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This) ))) goto done;
1136 if (!(This->ft_face = new_ft_face( unix_name, data_ptr, data_size, face_index, flags & ADDFONT_ALLOW_BITMAP )))
1138 RtlFreeHeap( GetProcessHeap(), 0, This );
1139 This = NULL;
1141 else
1143 This->scalable = FT_IS_SCALABLE( This->ft_face );
1144 This->num_faces = This->ft_face->num_faces;
1146 This->family_name = ft_face_get_family_name( This->ft_face, system_lcid );
1147 This->second_name = ft_face_get_family_name( This->ft_face, MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT) );
1149 /* try to find another secondary name, preferring the lowest langids */
1150 if (!RtlCompareUnicodeStrings( This->family_name, lstrlenW( This->family_name ),
1151 This->second_name, lstrlenW( This->second_name ), TRUE ))
1153 RtlFreeHeap( GetProcessHeap(), 0, This->second_name );
1154 This->second_name = ft_face_get_family_name( This->ft_face, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL) );
1155 if (!RtlCompareUnicodeStrings( This->family_name, lstrlenW( This->family_name ),
1156 This->second_name, lstrlenW( This->second_name ), TRUE ))
1158 RtlFreeHeap( GetProcessHeap(), 0, This->second_name );
1159 This->second_name = NULL;
1163 This->style_name = ft_face_get_style_name( This->ft_face, system_lcid );
1164 This->full_name = ft_face_get_full_name( This->ft_face, system_lcid );
1166 This->ntm_flags = get_ntm_flags( This->ft_face );
1167 This->font_version = get_font_version( This->ft_face );
1168 if (!This->scalable) get_bitmap_size( This->ft_face, &This->size );
1169 get_fontsig( This->ft_face, &This->fs );
1172 done:
1173 if (unix_name) munmap( data_ptr, data_size );
1174 return This;
1177 static void unix_face_destroy( struct unix_face *This )
1179 pFT_Done_Face( This->ft_face );
1180 RtlFreeHeap( GetProcessHeap(), 0, This->full_name );
1181 RtlFreeHeap( GetProcessHeap(), 0, This->style_name );
1182 RtlFreeHeap( GetProcessHeap(), 0, This->second_name );
1183 RtlFreeHeap( GetProcessHeap(), 0, This->family_name );
1184 RtlFreeHeap( GetProcessHeap(), 0, This );
1187 static int add_unix_face( const char *unix_name, const WCHAR *file, void *data_ptr, SIZE_T data_size,
1188 DWORD face_index, DWORD flags, DWORD *num_faces )
1190 struct unix_face *unix_face;
1191 int ret;
1193 if (num_faces) *num_faces = 0;
1195 if (!(unix_face = unix_face_create( unix_name, data_ptr, data_size, face_index, flags )))
1196 return 0;
1198 if (unix_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1200 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(unix_name));
1201 unix_face_destroy( unix_face );
1202 return 0;
1205 if (!HIWORD( flags )) flags |= ADDFONT_AA_FLAGS( default_aa_flags );
1207 ret = callback_funcs->add_gdi_face( unix_face->family_name, unix_face->second_name, unix_face->style_name, unix_face->full_name,
1208 file, data_ptr, data_size, face_index, unix_face->fs, unix_face->ntm_flags,
1209 unix_face->font_version, flags, unix_face->scalable ? NULL : &unix_face->size );
1211 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n", unix_face->fs.fsCsb[0], unix_face->fs.fsCsb[1],
1212 unix_face->fs.fsUsb[0], unix_face->fs.fsUsb[1], unix_face->fs.fsUsb[2], unix_face->fs.fsUsb[3]);
1214 if (num_faces) *num_faces = unix_face->num_faces;
1215 unix_face_destroy( unix_face );
1216 return ret;
1219 static WCHAR *get_dos_file_name( LPCSTR str )
1221 WCHAR *buffer;
1222 SIZE_T len = strlen(str) + 1;
1224 len += 8; /* \??\unix prefix */
1225 if (!(buffer = RtlAllocateHeap( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return NULL;
1226 if (wine_unix_to_nt_file_name( str, buffer, &len ))
1228 RtlFreeHeap( GetProcessHeap(), 0, buffer );
1229 return NULL;
1231 if (buffer[5] == ':')
1233 /* get rid of the \??\ prefix */
1234 /* FIXME: should implement RtlNtPathNameToDosPathName and use that instead */
1235 memmove( buffer, buffer + 4, (len - 4) * sizeof(WCHAR) );
1237 else buffer[1] = '\\';
1238 return buffer;
1241 static char *get_unix_file_name( LPCWSTR dosW )
1243 UNICODE_STRING nt_name;
1244 NTSTATUS status;
1245 SIZE_T size = 256;
1246 char *buffer;
1248 if (!RtlDosPathNameToNtPathName_U( dosW, &nt_name, NULL, NULL )) return NULL;
1249 for (;;)
1251 if (!(buffer = RtlAllocateHeap( GetProcessHeap(), 0, size )))
1253 RtlFreeUnicodeString( &nt_name );
1254 return NULL;
1256 status = wine_nt_to_unix_file_name( &nt_name, buffer, &size, FILE_OPEN_IF );
1257 if (status != STATUS_BUFFER_TOO_SMALL) break;
1258 RtlFreeHeap( GetProcessHeap(), 0, buffer );
1260 RtlFreeUnicodeString( &nt_name );
1261 if (status && status != STATUS_NO_SUCH_FILE)
1263 RtlFreeHeap( GetProcessHeap(), 0, buffer );
1264 RtlSetLastWin32ErrorAndNtStatusFromNtStatus( status );
1265 return NULL;
1267 return buffer;
1270 static INT AddFontToList(const WCHAR *dos_name, const char *unix_name, void *font_data_ptr,
1271 DWORD font_data_size, DWORD flags)
1273 DWORD face_index = 0, num_faces;
1274 INT ret = 0;
1275 WCHAR *filename = NULL;
1277 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1278 assert(unix_name || !(flags & ADDFONT_EXTERNAL_FONT));
1280 #ifdef HAVE_CARBON_CARBON_H
1281 if(unix_name)
1283 char **mac_list = expand_mac_font(unix_name);
1284 if(mac_list)
1286 BOOL had_one = FALSE;
1287 char **cursor;
1288 for(cursor = mac_list; *cursor; cursor++)
1290 had_one = TRUE;
1291 AddFontToList(NULL, *cursor, NULL, 0, flags);
1292 RtlFreeHeap(GetProcessHeap(), 0, *cursor);
1294 RtlFreeHeap(GetProcessHeap(), 0, mac_list);
1295 if(had_one)
1296 return 1;
1299 #endif /* HAVE_CARBON_CARBON_H */
1301 if (!dos_name && unix_name) dos_name = filename = get_dos_file_name( unix_name );
1304 ret += add_unix_face( unix_name, dos_name, font_data_ptr, font_data_size, face_index, flags, &num_faces );
1305 while (num_faces > ++face_index);
1307 RtlFreeHeap( GetProcessHeap(), 0, filename );
1308 return ret;
1311 /*************************************************************
1312 * freetype_add_font
1314 static INT CDECL freetype_add_font( const WCHAR *file, DWORD flags )
1316 int ret = 0;
1317 char *unixname = get_unix_file_name( file );
1319 if (unixname)
1321 ret = AddFontToList( file, unixname, NULL, 0, flags );
1322 RtlFreeHeap( GetProcessHeap(), 0, unixname );
1324 return ret;
1327 /*************************************************************
1328 * freetype_add_mem_font
1330 static INT CDECL freetype_add_mem_font( void *ptr, SIZE_T size, DWORD flags )
1332 return AddFontToList( NULL, NULL, ptr, size, flags );
1335 #ifdef __ANDROID__
1336 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1338 DIR *dir;
1339 struct dirent *dent;
1340 char path[MAX_PATH];
1342 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1344 dir = opendir(dirname);
1345 if(!dir) {
1346 WARN("Can't open directory %s\n", debugstr_a(dirname));
1347 return FALSE;
1349 while((dent = readdir(dir)) != NULL) {
1350 struct stat statbuf;
1352 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1353 continue;
1355 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1357 sprintf(path, "%s/%s", dirname, dent->d_name);
1359 if(stat(path, &statbuf) == -1)
1361 WARN("Can't stat %s\n", debugstr_a(path));
1362 continue;
1364 if(S_ISDIR(statbuf.st_mode))
1365 ReadFontDir(path, external_fonts);
1366 else
1368 DWORD addfont_flags = 0;
1369 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
1370 AddFontToList(NULL, path, NULL, 0, addfont_flags);
1373 closedir(dir);
1374 return TRUE;
1376 #endif
1378 #ifdef SONAME_LIBFONTCONFIG
1380 static BOOL fontconfig_enabled;
1381 static FcPattern *pattern_serif;
1382 static FcPattern *pattern_fixed;
1383 static FcPattern *pattern_sans;
1385 static UINT parse_aa_pattern( FcPattern *pattern )
1387 FcBool antialias;
1388 int rgba;
1389 UINT aa_flags = 0;
1391 if (pFcPatternGetBool( pattern, FC_ANTIALIAS, 0, &antialias ) == FcResultMatch)
1392 aa_flags = antialias ? GGO_GRAY4_BITMAP : GGO_BITMAP;
1394 if (pFcPatternGetInteger( pattern, FC_RGBA, 0, &rgba ) == FcResultMatch)
1396 switch (rgba)
1398 case FC_RGBA_RGB: aa_flags = WINE_GGO_HRGB_BITMAP; break;
1399 case FC_RGBA_BGR: aa_flags = WINE_GGO_HBGR_BITMAP; break;
1400 case FC_RGBA_VRGB: aa_flags = WINE_GGO_VRGB_BITMAP; break;
1401 case FC_RGBA_VBGR: aa_flags = WINE_GGO_VBGR_BITMAP; break;
1402 case FC_RGBA_NONE: aa_flags = aa_flags ? aa_flags : GGO_GRAY4_BITMAP; break;
1405 return aa_flags;
1408 static FcPattern *create_family_pattern( const char *name, FcPattern **cached )
1410 FcPattern *ret = NULL, *tmp, *pattern = pFcPatternCreate();
1411 FcResult result;
1412 if (*cached) return *cached;
1413 pFcPatternAddString( pattern, FC_FAMILY, (const FcChar8 *)name );
1414 pFcPatternAddString( pattern, FC_NAMELANG, (const FcChar8 *)"en-us" );
1415 pFcPatternAddString( pattern, FC_PRGNAME, (const FcChar8 *)"wine" );
1416 pFcConfigSubstitute( NULL, pattern, FcMatchPattern );
1417 pFcDefaultSubstitute( pattern );
1418 tmp = pFcFontMatch( NULL, pattern, &result );
1419 pFcPatternDestroy( pattern );
1420 if (result != FcResultMatch) pFcPatternDestroy( tmp );
1421 else if ((ret = InterlockedCompareExchangePointer( (void **)cached, tmp, NULL ))) pFcPatternDestroy( tmp );
1422 else ret = tmp;
1423 return ret;
1426 static void fontconfig_add_font( FcPattern *pattern, DWORD flags )
1428 const char *unix_name, *format;
1429 WCHAR *dos_name;
1430 FcBool scalable;
1431 DWORD aa_flags;
1432 int face_index;
1434 TRACE( "(%p %#x)\n", pattern, flags );
1436 if (pFcPatternGetString( pattern, FC_FILE, 0, (FcChar8 **)&unix_name ) != FcResultMatch)
1437 return;
1439 if (pFcPatternGetBool( pattern, FC_SCALABLE, 0, &scalable ) != FcResultMatch)
1440 scalable = FALSE;
1442 if (pFcPatternGetString( pattern, FC_FONTFORMAT, 0, (FcChar8 **)&format ) != FcResultMatch)
1444 TRACE( "ignoring unknown font format %s\n", debugstr_a(unix_name) );
1445 return;
1448 if (!strcmp( format, "Type 1" ))
1450 TRACE( "ignoring Type 1 font %s\n", debugstr_a(unix_name) );
1451 return;
1454 if (!scalable && !(flags & ADDFONT_ALLOW_BITMAP))
1456 TRACE( "ignoring non-scalable font %s\n", debugstr_a(unix_name) );
1457 return;
1460 if (!(aa_flags = parse_aa_pattern( pattern ))) aa_flags = default_aa_flags;
1461 flags |= ADDFONT_AA_FLAGS(aa_flags);
1463 if (pFcPatternGetInteger( pattern, FC_INDEX, 0, &face_index ) != FcResultMatch)
1464 face_index = 0;
1466 dos_name = get_dos_file_name( unix_name );
1467 add_unix_face( unix_name, dos_name, NULL, 0, face_index, flags, NULL );
1468 RtlFreeHeap( GetProcessHeap(), 0, dos_name );
1471 static void init_fontconfig(void)
1473 void *fc_handle = dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW);
1475 if (!fc_handle)
1477 TRACE("Wine cannot find the fontconfig library (%s).\n", SONAME_LIBFONTCONFIG);
1478 return;
1481 #define LOAD_FUNCPTR(f) if((p##f = dlsym(fc_handle, #f)) == NULL){WARN("Can't find symbol %s\n", #f); return;}
1482 LOAD_FUNCPTR(FcConfigSubstitute);
1483 LOAD_FUNCPTR(FcDefaultSubstitute);
1484 LOAD_FUNCPTR(FcFontList);
1485 LOAD_FUNCPTR(FcFontMatch);
1486 LOAD_FUNCPTR(FcFontSetDestroy);
1487 LOAD_FUNCPTR(FcInit);
1488 LOAD_FUNCPTR(FcPatternAddString);
1489 LOAD_FUNCPTR(FcPatternCreate);
1490 LOAD_FUNCPTR(FcPatternDestroy);
1491 LOAD_FUNCPTR(FcPatternGetBool);
1492 LOAD_FUNCPTR(FcPatternGetInteger);
1493 LOAD_FUNCPTR(FcPatternGetString);
1494 LOAD_FUNCPTR(FcConfigGetFontDirs);
1495 LOAD_FUNCPTR(FcConfigGetCurrent);
1496 LOAD_FUNCPTR(FcCacheCopySet);
1497 LOAD_FUNCPTR(FcCacheNumSubdir);
1498 LOAD_FUNCPTR(FcCacheSubdir);
1499 LOAD_FUNCPTR(FcDirCacheRead);
1500 LOAD_FUNCPTR(FcDirCacheUnload);
1501 LOAD_FUNCPTR(FcStrListCreate);
1502 LOAD_FUNCPTR(FcStrListDone);
1503 LOAD_FUNCPTR(FcStrListNext);
1504 LOAD_FUNCPTR(FcStrSetAdd);
1505 LOAD_FUNCPTR(FcStrSetCreate);
1506 LOAD_FUNCPTR(FcStrSetDestroy);
1507 LOAD_FUNCPTR(FcStrSetMember);
1508 #undef LOAD_FUNCPTR
1510 if (pFcInit())
1512 FcPattern *pattern = pFcPatternCreate();
1513 pFcConfigSubstitute( NULL, pattern, FcMatchFont );
1514 default_aa_flags = parse_aa_pattern( pattern );
1515 pFcPatternDestroy( pattern );
1517 if (!default_aa_flags)
1519 FcPattern *pattern = pFcPatternCreate();
1520 pFcConfigSubstitute( NULL, pattern, FcMatchPattern );
1521 default_aa_flags = parse_aa_pattern( pattern );
1522 pFcPatternDestroy( pattern );
1525 TRACE( "enabled, default flags = %x\n", default_aa_flags );
1526 fontconfig_enabled = TRUE;
1530 static void fontconfig_add_fonts_from_dir_list( FcConfig *config, FcStrList *dir_list, FcStrSet *done_set, DWORD flags )
1532 const FcChar8 *dir;
1533 FcFontSet *font_set = NULL;
1534 FcStrList *subdir_list = NULL;
1535 FcStrSet *subdir_set = NULL;
1536 FcCache *cache = NULL;
1537 int i;
1539 TRACE( "(%p %p %p %#x)\n", config, dir_list, done_set, flags );
1541 while ((dir = pFcStrListNext( dir_list )))
1543 if (pFcStrSetMember( done_set, dir )) continue;
1545 TRACE( "adding fonts from %s\n", dir );
1546 if (!(cache = pFcDirCacheRead( dir, FcFalse, config ))) continue;
1548 if (!(font_set = pFcCacheCopySet( cache ))) goto done;
1549 for (i = 0; i < font_set->nfont; i++)
1550 fontconfig_add_font( font_set->fonts[i], flags );
1551 pFcFontSetDestroy( font_set );
1552 font_set = NULL;
1554 if (!(subdir_set = pFcStrSetCreate())) goto done;
1555 for (i = 0; i < pFcCacheNumSubdir( cache ); i++)
1556 pFcStrSetAdd( subdir_set, pFcCacheSubdir( cache, i ) );
1557 pFcDirCacheUnload( cache );
1558 cache = NULL;
1560 if (!(subdir_list = pFcStrListCreate( subdir_set ))) goto done;
1561 pFcStrSetDestroy( subdir_set );
1562 subdir_set = NULL;
1564 pFcStrSetAdd( done_set, dir );
1565 fontconfig_add_fonts_from_dir_list( config, subdir_list, done_set, flags );
1566 pFcStrListDone( subdir_list );
1567 subdir_list = NULL;
1570 done:
1571 if (font_set) pFcFontSetDestroy( font_set );
1572 if (subdir_list) pFcStrListDone( subdir_list );
1573 if (subdir_set) pFcStrSetDestroy( subdir_set );
1574 if (cache) pFcDirCacheUnload( cache );
1577 static void load_fontconfig_fonts( void )
1579 FcStrList *dir_list = NULL;
1580 FcStrSet *done_set = NULL;
1581 FcConfig *config;
1583 if (!fontconfig_enabled) return;
1584 if (!(config = pFcConfigGetCurrent())) goto done;
1585 if (!(done_set = pFcStrSetCreate())) goto done;
1586 if (!(dir_list = pFcConfigGetFontDirs( config ))) goto done;
1588 fontconfig_add_fonts_from_dir_list( config, dir_list, done_set, ADDFONT_EXTERNAL_FONT );
1590 done:
1591 if (dir_list) pFcStrListDone( dir_list );
1592 if (done_set) pFcStrSetDestroy( done_set );
1595 #elif defined(HAVE_CARBON_CARBON_H)
1597 static void load_mac_font_callback(const void *value, void *context)
1599 CFStringRef pathStr = value;
1600 CFIndex len;
1601 char* path;
1603 len = CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr);
1604 path = RtlAllocateHeap(GetProcessHeap(), 0, len);
1605 if (path && CFStringGetFileSystemRepresentation(pathStr, path, len))
1607 TRACE("font file %s\n", path);
1608 AddFontToList(NULL, path, NULL, 0, ADDFONT_EXTERNAL_FONT);
1610 RtlFreeHeap(GetProcessHeap(), 0, path);
1613 static void load_mac_fonts(void)
1615 CFStringRef removeDupesKey;
1616 CFBooleanRef removeDupesValue;
1617 CFDictionaryRef options;
1618 CTFontCollectionRef col;
1619 CFArrayRef descs;
1620 CFMutableSetRef paths;
1621 CFIndex i;
1623 removeDupesKey = kCTFontCollectionRemoveDuplicatesOption;
1624 removeDupesValue = kCFBooleanTrue;
1625 options = CFDictionaryCreate(NULL, (const void**)&removeDupesKey, (const void**)&removeDupesValue, 1,
1626 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1627 col = CTFontCollectionCreateFromAvailableFonts(options);
1628 if (options) CFRelease(options);
1629 if (!col)
1631 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
1632 return;
1635 descs = CTFontCollectionCreateMatchingFontDescriptors(col);
1636 CFRelease(col);
1637 if (!descs)
1639 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
1640 return;
1643 paths = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
1644 if (!paths)
1646 WARN("CFSetCreateMutable failed\n");
1647 CFRelease(descs);
1648 return;
1651 for (i = 0; i < CFArrayGetCount(descs); i++)
1653 CTFontDescriptorRef desc;
1654 CFURLRef url;
1655 CFStringRef ext;
1656 CFStringRef path;
1658 desc = CFArrayGetValueAtIndex(descs, i);
1660 #if defined(MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
1661 url = CTFontDescriptorCopyAttribute(desc, kCTFontURLAttribute);
1662 #else
1663 /* CTFontDescriptor doesn't support kCTFontURLAttribute prior to 10.6, so
1664 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
1666 CTFontRef font;
1667 ATSFontRef atsFont;
1668 OSStatus status;
1669 FSRef fsref;
1671 font = CTFontCreateWithFontDescriptor(desc, 0, NULL);
1672 if (!font) continue;
1674 atsFont = CTFontGetPlatformFont(font, NULL);
1675 if (!atsFont)
1677 CFRelease(font);
1678 continue;
1681 status = ATSFontGetFileReference(atsFont, &fsref);
1682 CFRelease(font);
1683 if (status != noErr) continue;
1685 url = CFURLCreateFromFSRef(NULL, &fsref);
1687 #endif
1688 if (!url) continue;
1690 ext = CFURLCopyPathExtension(url);
1691 if (ext)
1693 BOOL skip = (CFStringCompare(ext, CFSTR("pfa"), kCFCompareCaseInsensitive) == kCFCompareEqualTo ||
1694 CFStringCompare(ext, CFSTR("pfb"), kCFCompareCaseInsensitive) == kCFCompareEqualTo);
1695 CFRelease(ext);
1696 if (skip)
1698 CFRelease(url);
1699 continue;
1703 path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
1704 CFRelease(url);
1705 if (!path) continue;
1707 CFSetAddValue(paths, path);
1708 CFRelease(path);
1711 CFRelease(descs);
1713 CFSetApplyFunction(paths, load_mac_font_callback, NULL);
1714 CFRelease(paths);
1717 #endif
1720 static BOOL init_freetype(void)
1722 ft_handle = dlopen(SONAME_LIBFREETYPE, RTLD_NOW);
1723 if(!ft_handle) {
1724 WINE_MESSAGE(
1725 "Wine cannot find the FreeType font library. To enable Wine to\n"
1726 "use TrueType fonts please install a version of FreeType greater than\n"
1727 "or equal to 2.0.5.\n"
1728 "http://www.freetype.org\n");
1729 return FALSE;
1732 #define LOAD_FUNCPTR(f) if((p##f = dlsym(ft_handle, #f)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
1734 LOAD_FUNCPTR(FT_Done_Face)
1735 LOAD_FUNCPTR(FT_Get_Char_Index)
1736 LOAD_FUNCPTR(FT_Get_First_Char)
1737 LOAD_FUNCPTR(FT_Get_Next_Char)
1738 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
1739 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
1740 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
1741 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
1742 LOAD_FUNCPTR(FT_Init_FreeType)
1743 LOAD_FUNCPTR(FT_Library_Version)
1744 LOAD_FUNCPTR(FT_Load_Glyph)
1745 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
1746 LOAD_FUNCPTR(FT_Matrix_Multiply)
1747 LOAD_FUNCPTR(FT_MulDiv)
1748 #ifndef FT_MULFIX_INLINED
1749 LOAD_FUNCPTR(FT_MulFix)
1750 #endif
1751 LOAD_FUNCPTR(FT_New_Face)
1752 LOAD_FUNCPTR(FT_New_Memory_Face)
1753 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
1754 LOAD_FUNCPTR(FT_Outline_Get_CBox)
1755 LOAD_FUNCPTR(FT_Outline_Transform)
1756 LOAD_FUNCPTR(FT_Outline_Translate)
1757 LOAD_FUNCPTR(FT_Render_Glyph)
1758 LOAD_FUNCPTR(FT_Set_Charmap)
1759 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
1760 LOAD_FUNCPTR(FT_Vector_Length)
1761 LOAD_FUNCPTR(FT_Vector_Transform)
1762 LOAD_FUNCPTR(FT_Vector_Unit)
1763 #undef LOAD_FUNCPTR
1764 /* Don't warn if these ones are missing */
1765 pFT_Outline_Embolden = dlsym(ft_handle, "FT_Outline_Embolden");
1766 pFT_Get_TrueType_Engine_Type = dlsym(ft_handle, "FT_Get_TrueType_Engine_Type");
1767 #ifdef FT_LCD_FILTER_H
1768 pFT_Library_SetLcdFilter = dlsym(ft_handle, "FT_Library_SetLcdFilter");
1769 #endif
1770 pFT_Property_Set = dlsym(ft_handle, "FT_Property_Set");
1772 if(pFT_Init_FreeType(&library) != 0) {
1773 ERR("Can't init FreeType library\n");
1774 dlclose(ft_handle);
1775 ft_handle = NULL;
1776 return FALSE;
1778 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
1780 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
1781 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
1782 ((FT_Version.minor << 8) & 0x00ff00) |
1783 ((FT_Version.patch ) & 0x0000ff);
1785 /* In FreeType < 2.8.1 v40's FT_LOAD_TARGET_MONO has broken advance widths. */
1786 if (pFT_Property_Set && FT_SimpleVersion < FT_VERSION_VALUE(2, 8, 1))
1788 FT_UInt interpreter_version = 35;
1789 pFT_Property_Set( library, "truetype", "interpreter-version", &interpreter_version );
1792 return TRUE;
1794 sym_not_found:
1795 WINE_MESSAGE(
1796 "Wine cannot find certain functions that it needs inside the FreeType\n"
1797 "font library. To enable Wine to use TrueType fonts please upgrade\n"
1798 "FreeType to at least version 2.1.4.\n"
1799 "http://www.freetype.org\n");
1800 dlclose(ft_handle);
1801 ft_handle = NULL;
1802 return FALSE;
1805 /*************************************************************
1806 * freetype_load_fonts
1808 static void CDECL freetype_load_fonts(void)
1810 #ifdef SONAME_LIBFONTCONFIG
1811 load_fontconfig_fonts();
1812 #elif defined(HAVE_CARBON_CARBON_H)
1813 load_mac_fonts();
1814 #elif defined(__ANDROID__)
1815 ReadFontDir("/system/fonts", TRUE);
1816 #endif
1819 /* Some fonts have large usWinDescent values, as a result of storing signed short
1820 in unsigned field. That's probably caused by sTypoDescent vs usWinDescent confusion in
1821 some font generation tools. */
1822 static inline USHORT get_fixed_windescent(USHORT windescent)
1824 return abs((SHORT)windescent);
1827 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
1829 TT_OS2 *pOS2;
1830 TT_HoriHeader *pHori;
1832 LONG ppem;
1833 const LONG MAX_PPEM = (1 << 16) - 1;
1835 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1836 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1838 if(height == 0) height = 16;
1840 /* Calc. height of EM square:
1842 * For +ve lfHeight we have
1843 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
1844 * Re-arranging gives:
1845 * ppem = units_per_em * lfheight / (winAscent + winDescent)
1847 * For -ve lfHeight we have
1848 * |lfHeight| = ppem
1849 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
1850 * with il = winAscent + winDescent - units_per_em]
1854 if(height > 0) {
1855 USHORT windescent = get_fixed_windescent(pOS2->usWinDescent);
1856 if(pOS2->usWinAscent + windescent == 0)
1857 ppem = pFT_MulDiv(ft_face->units_per_EM, height, pHori->Ascender - pHori->Descender);
1858 else
1859 ppem = pFT_MulDiv(ft_face->units_per_EM, height, pOS2->usWinAscent + windescent);
1860 if(ppem > MAX_PPEM) {
1861 WARN("Ignoring too large height %d, ppem %d\n", height, ppem);
1862 ppem = 1;
1865 else if(height >= -MAX_PPEM)
1866 ppem = -height;
1867 else {
1868 WARN("Ignoring too large height %d\n", height);
1869 ppem = 1;
1872 return ppem;
1875 static struct font_mapping *map_font_file( const char *name )
1877 struct font_mapping *mapping;
1878 struct stat st;
1879 int fd;
1881 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
1882 if (fstat( fd, &st ) == -1) goto error;
1884 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
1886 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
1888 mapping->refcount++;
1889 close( fd );
1890 return mapping;
1893 if (!(mapping = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*mapping) )))
1894 goto error;
1896 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
1897 close( fd );
1899 if (mapping->data == MAP_FAILED)
1901 RtlFreeHeap( GetProcessHeap(), 0, mapping );
1902 return NULL;
1904 mapping->refcount = 1;
1905 mapping->dev = st.st_dev;
1906 mapping->ino = st.st_ino;
1907 mapping->size = st.st_size;
1908 list_add_tail( &mappings_list, &mapping->entry );
1909 return mapping;
1911 error:
1912 close( fd );
1913 return NULL;
1916 static void unmap_font_file( struct font_mapping *mapping )
1918 if (!--mapping->refcount)
1920 list_remove( &mapping->entry );
1921 munmap( mapping->data, mapping->size );
1922 RtlFreeHeap( GetProcessHeap(), 0, mapping );
1926 static LONG load_VDMX(struct gdi_font *font, LONG height);
1928 /*************************************************************
1929 * freetype_destroy_font
1931 static void CDECL freetype_destroy_font( struct gdi_font *font )
1933 struct font_private_data *data = font->private;
1935 if (data->ft_face) pFT_Done_Face( data->ft_face );
1936 if (data->mapping) unmap_font_file( data->mapping );
1937 RtlFreeHeap( GetProcessHeap(), 0, data );
1940 /*************************************************************
1941 * freetype_get_font_data
1943 static DWORD CDECL freetype_get_font_data( struct gdi_font *font, DWORD table, DWORD offset,
1944 void *buf, DWORD cbData)
1946 FT_Face ft_face = get_ft_face( font );
1947 FT_ULong len;
1948 FT_Error err;
1950 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
1952 if(!buf)
1953 len = 0;
1954 else
1955 len = cbData;
1957 /* if font is a member of TTC, 'ttcf' tag allows reading from beginning of TTC file,
1958 0 tag means to read from start of collection member data. */
1959 if (font->ttc_item_offset)
1961 if (table == MS_TTCF_TAG)
1962 table = 0;
1963 else if (table == 0)
1964 offset += font->ttc_item_offset;
1967 /* make sure value of len is the value freetype says it needs */
1968 if (buf && len)
1970 FT_ULong needed = 0;
1971 err = pFT_Load_Sfnt_Table(ft_face, RtlUlongByteSwap(table), offset, NULL, &needed);
1972 if( !err && needed < len) len = needed;
1974 err = pFT_Load_Sfnt_Table(ft_face, RtlUlongByteSwap(table), offset, buf, &len);
1975 if (err)
1977 TRACE("Can't find table %s\n", debugstr_an((char*)&table, 4));
1978 return GDI_ERROR;
1980 return len;
1983 /*************************************************************
1984 * load_VDMX
1986 * load the vdmx entry for the specified height
1991 typedef struct {
1992 WORD version;
1993 WORD numRecs;
1994 WORD numRatios;
1995 } VDMX_Header;
1997 typedef struct {
1998 BYTE bCharSet;
1999 BYTE xRatio;
2000 BYTE yStartRatio;
2001 BYTE yEndRatio;
2002 } Ratios;
2004 typedef struct {
2005 WORD recs;
2006 BYTE startsz;
2007 BYTE endsz;
2008 } VDMX_group;
2010 typedef struct {
2011 WORD yPelHeight;
2012 WORD yMax;
2013 WORD yMin;
2014 } VDMX_vTable;
2016 static LONG load_VDMX(struct gdi_font *font, LONG height)
2018 VDMX_Header hdr;
2019 VDMX_group group;
2020 BYTE devXRatio, devYRatio;
2021 USHORT numRecs, numRatios;
2022 DWORD result, offset = -1;
2023 LONG ppem = 0;
2024 int i;
2026 result = freetype_get_font_data(font, MS_VDMX_TAG, 0, &hdr, sizeof(hdr));
2028 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2029 return ppem;
2031 /* FIXME: need the real device aspect ratio */
2032 devXRatio = 1;
2033 devYRatio = 1;
2035 numRecs = GET_BE_WORD(hdr.numRecs);
2036 numRatios = GET_BE_WORD(hdr.numRatios);
2038 TRACE("version = %d numRecs = %d numRatios = %d\n", GET_BE_WORD(hdr.version), numRecs, numRatios);
2039 for(i = 0; i < numRatios; i++) {
2040 Ratios ratio;
2042 offset = sizeof(hdr) + (i * sizeof(Ratios));
2043 freetype_get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2044 offset = -1;
2046 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2048 if (!ratio.bCharSet) continue;
2050 if((ratio.xRatio == 0 &&
2051 ratio.yStartRatio == 0 &&
2052 ratio.yEndRatio == 0) ||
2053 (devXRatio == ratio.xRatio &&
2054 devYRatio >= ratio.yStartRatio &&
2055 devYRatio <= ratio.yEndRatio))
2057 WORD group_offset;
2059 offset = sizeof(hdr) + numRatios * sizeof(ratio) + i * sizeof(group_offset);
2060 freetype_get_font_data(font, MS_VDMX_TAG, offset, &group_offset, sizeof(group_offset));
2061 offset = GET_BE_WORD(group_offset);
2062 break;
2066 if(offset == -1) return 0;
2068 if(freetype_get_font_data(font, MS_VDMX_TAG, offset, &group, sizeof(group)) != GDI_ERROR) {
2069 USHORT recs;
2070 BYTE startsz, endsz;
2071 WORD *vTable;
2073 recs = GET_BE_WORD(group.recs);
2074 startsz = group.startsz;
2075 endsz = group.endsz;
2077 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
2079 vTable = RtlAllocateHeap(GetProcessHeap(), 0, recs * sizeof(VDMX_vTable));
2080 result = freetype_get_font_data(font, MS_VDMX_TAG, offset + sizeof(group), vTable, recs * sizeof(VDMX_vTable));
2081 if(result == GDI_ERROR) {
2082 FIXME("Failed to retrieve vTable\n");
2083 goto end;
2086 if(height > 0) {
2087 for(i = 0; i < recs; i++) {
2088 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2089 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2090 ppem = GET_BE_WORD(vTable[i * 3]);
2092 if(yMax + -yMin == height) {
2093 font->yMax = yMax;
2094 font->yMin = yMin;
2095 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2096 break;
2098 if(yMax + -yMin > height) {
2099 if(--i < 0) {
2100 ppem = 0;
2101 goto end; /* failed */
2103 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2104 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2105 ppem = GET_BE_WORD(vTable[i * 3]);
2106 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2107 break;
2110 if(!font->yMax) {
2111 ppem = 0;
2112 TRACE("ppem not found for height %d\n", height);
2114 } else {
2115 ppem = -height;
2116 if(ppem < startsz || ppem > endsz)
2118 ppem = 0;
2119 goto end;
2122 for(i = 0; i < recs; i++) {
2123 USHORT yPelHeight;
2124 yPelHeight = GET_BE_WORD(vTable[i * 3]);
2126 if(yPelHeight > ppem)
2128 ppem = 0;
2129 break; /* failed */
2132 if(yPelHeight == ppem) {
2133 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2134 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2135 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
2136 break;
2140 end:
2141 RtlFreeHeap(GetProcessHeap(), 0, vTable);
2144 return ppem;
2147 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
2149 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
2150 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
2151 FT_Int i;
2153 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
2155 for (i = 0; i < ft_face->num_charmaps; i++)
2157 if (ft_face->charmaps[i]->encoding == encoding)
2159 TRACE("found cmap with platform_id %u, encoding_id %u\n",
2160 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
2162 switch (ft_face->charmaps[i]->platform_id)
2164 default:
2165 cmap_def = ft_face->charmaps[i];
2166 break;
2167 case 0: /* Apple Unicode */
2168 cmap0 = ft_face->charmaps[i];
2169 break;
2170 case 1: /* Macintosh */
2171 cmap1 = ft_face->charmaps[i];
2172 break;
2173 case 2: /* ISO */
2174 cmap2 = ft_face->charmaps[i];
2175 break;
2176 case 3: /* Microsoft */
2177 cmap3 = ft_face->charmaps[i];
2178 break;
2182 if (cmap3) /* prefer Microsoft cmap table */
2183 ft_err = pFT_Set_Charmap(ft_face, cmap3);
2184 else if (cmap1)
2185 ft_err = pFT_Set_Charmap(ft_face, cmap1);
2186 else if (cmap2)
2187 ft_err = pFT_Set_Charmap(ft_face, cmap2);
2188 else if (cmap0)
2189 ft_err = pFT_Set_Charmap(ft_face, cmap0);
2190 else if (cmap_def)
2191 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
2194 return ft_err == FT_Err_Ok;
2198 static FT_Encoding pick_charmap( FT_Face face, int charset )
2200 static const FT_Encoding regular_order[] = { FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, FT_ENCODING_MS_SYMBOL, 0 };
2201 static const FT_Encoding symbol_order[] = { FT_ENCODING_MS_SYMBOL, FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, 0 };
2202 const FT_Encoding *encs = regular_order;
2204 if (charset == SYMBOL_CHARSET) encs = symbol_order;
2206 while (*encs != 0)
2208 if (select_charmap( face, *encs )) break;
2209 encs++;
2212 if (!face->charmap && face->num_charmaps)
2214 if (!pFT_Set_Charmap(face, face->charmaps[0]))
2215 return face->charmap->encoding;
2218 return *encs;
2221 static BOOL get_gasp_flags( struct gdi_font *font, WORD *flags )
2223 FT_Face ft_face = get_ft_face( font );
2224 DWORD size;
2225 WORD buf[16]; /* Enough for seven ranges before we need to alloc */
2226 WORD *alloced = NULL, *ptr = buf;
2227 WORD num_recs, version;
2228 BOOL ret = FALSE;
2230 *flags = 0;
2231 size = freetype_get_font_data( font, MS_GASP_TAG, 0, NULL, 0 );
2232 if (size == GDI_ERROR) return FALSE;
2233 if (size < 4 * sizeof(WORD)) return FALSE;
2234 if (size > sizeof(buf))
2236 ptr = alloced = RtlAllocateHeap( GetProcessHeap(), 0, size );
2237 if (!ptr) return FALSE;
2240 freetype_get_font_data( font, MS_GASP_TAG, 0, ptr, size );
2242 version = GET_BE_WORD( *ptr++ );
2243 num_recs = GET_BE_WORD( *ptr++ );
2245 if (version > 1 || size < (num_recs * 2 + 2) * sizeof(WORD))
2247 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version, size, num_recs );
2248 goto done;
2251 while (num_recs--)
2253 *flags = GET_BE_WORD( *(ptr + 1) );
2254 if (ft_face->size->metrics.y_ppem <= GET_BE_WORD( *ptr )) break;
2255 ptr += 2;
2257 TRACE( "got flags %04x for ppem %d\n", *flags, ft_face->size->metrics.y_ppem );
2258 ret = TRUE;
2260 done:
2261 RtlFreeHeap( GetProcessHeap(), 0, alloced );
2262 return ret;
2265 /*************************************************************
2266 * fontconfig_enum_family_fallbacks
2268 static BOOL CDECL fontconfig_enum_family_fallbacks( DWORD pitch_and_family, int index,
2269 WCHAR buffer[LF_FACESIZE] )
2271 #ifdef SONAME_LIBFONTCONFIG
2272 FcPattern *pat;
2273 char *str;
2274 DWORD len;
2276 if ((pitch_and_family & FIXED_PITCH) || (pitch_and_family & 0xf0) == FF_MODERN) pat = create_family_pattern( "monospace", &pattern_fixed );
2277 else if ((pitch_and_family & 0xf0) == FF_ROMAN) pat = create_family_pattern( "serif", &pattern_serif );
2278 else pat = create_family_pattern( "sans", &pattern_sans );
2280 if (!pat) return FALSE;
2281 if (pFcPatternGetString( pat, FC_FAMILY, index, (FcChar8 **)&str ) != FcResultMatch) return FALSE;
2282 RtlUTF8ToUnicodeN( buffer, (LF_FACESIZE - 1) * sizeof(WCHAR), &len, str, strlen(str) );
2283 buffer[len / sizeof(WCHAR)] = 0;
2284 return TRUE;
2285 #endif
2286 return FALSE;
2289 static DWORD get_ttc_offset( FT_Face ft_face, UINT face_index )
2291 FT_ULong len;
2292 DWORD header, offset;
2294 /* see if it's a TTC */
2295 len = sizeof(header);
2296 if (pFT_Load_Sfnt_Table( ft_face, 0, 0, (void *)&header, &len )) return 0;
2297 if (header != MS_TTCF_TAG) return 0;
2299 len = sizeof(offset);
2300 if (pFT_Load_Sfnt_Table( ft_face, 0, (3 + face_index) * sizeof(DWORD), (void *)&offset, &len ))
2301 return 0;
2303 return GET_BE_DWORD( offset );
2306 /*************************************************************
2307 * freetype_load_font
2309 static BOOL CDECL freetype_load_font( struct gdi_font *font )
2311 struct font_private_data *data;
2312 INT width = 0, height;
2313 FT_Face ft_face;
2314 void *data_ptr;
2315 SIZE_T data_size;
2317 if (!(data = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data) ))) return FALSE;
2318 font->private = data;
2320 if (font->file[0])
2322 char *filename = get_unix_file_name( font->file );
2323 data->mapping = map_font_file( filename );
2324 RtlFreeHeap( GetProcessHeap(), 0, filename );
2325 if (!data->mapping)
2327 WARN("failed to map %s\n", debugstr_w(font->file));
2328 return FALSE;
2330 data_ptr = data->mapping->data;
2331 data_size = data->mapping->size;
2333 else
2335 data_ptr = font->data_ptr;
2336 data_size = font->data_size;
2339 if (pFT_New_Memory_Face( library, data_ptr, data_size, font->face_index, &ft_face )) return FALSE;
2341 data->ft_face = ft_face;
2342 font->scalable = FT_IS_SCALABLE( ft_face );
2343 if (!font->fs.fsCsb[0]) get_fontsig( ft_face, &font->fs );
2344 if (!font->ntmFlags) font->ntmFlags = get_ntm_flags( ft_face );
2345 if (!font->aa_flags) font->aa_flags = ADDFONT_AA_FLAGS( default_aa_flags );
2346 if (!font->otm.otmpFamilyName)
2348 font->otm.otmpFamilyName = (char *)ft_face_get_family_name( ft_face, system_lcid );
2349 font->otm.otmpStyleName = (char *)ft_face_get_style_name( ft_face, system_lcid );
2350 font->otm.otmpFaceName = (char *)ft_face_get_full_name( ft_face, system_lcid );
2353 if (font->scalable)
2355 /* load the VDMX table if we have one */
2356 font->ppem = load_VDMX( font, font->lf.lfHeight );
2357 if (font->ppem == 0) font->ppem = calc_ppem_for_height( ft_face, font->lf.lfHeight );
2358 TRACE( "height %d => ppem %d\n", font->lf.lfHeight, font->ppem );
2359 height = font->ppem;
2360 font->ttc_item_offset = get_ttc_offset( ft_face, font->face_index );
2362 else
2364 struct bitmap_font_size size;
2366 get_bitmap_size( ft_face, &size );
2367 width = size.x_ppem >> 6;
2368 height = size.y_ppem >> 6;
2369 font->ppem = height;
2372 pFT_Set_Pixel_Sizes( ft_face, width, height );
2373 pick_charmap( ft_face, font->charset );
2374 return TRUE;
2378 /*************************************************************
2379 * freetype_get_aa_flags
2381 static UINT CDECL freetype_get_aa_flags( struct gdi_font *font, UINT aa_flags, BOOL antialias_fakes )
2383 /* fixup the antialiasing flags for that font */
2384 switch (aa_flags)
2386 case WINE_GGO_HRGB_BITMAP:
2387 case WINE_GGO_HBGR_BITMAP:
2388 case WINE_GGO_VRGB_BITMAP:
2389 case WINE_GGO_VBGR_BITMAP:
2390 if (is_subpixel_rendering_enabled()) break;
2391 aa_flags = GGO_GRAY4_BITMAP;
2392 /* fall through */
2393 case GGO_GRAY2_BITMAP:
2394 case GGO_GRAY4_BITMAP:
2395 case GGO_GRAY8_BITMAP:
2396 case WINE_GGO_GRAY16_BITMAP:
2397 if ((!antialias_fakes || (!font->fake_bold && !font->fake_italic)) && is_hinting_enabled())
2399 WORD gasp_flags;
2400 if (get_gasp_flags( font, &gasp_flags ) && !(gasp_flags & GASP_DOGRAY))
2402 TRACE( "font %s %d aa disabled by GASP\n",
2403 debugstr_w(font->lf.lfFaceName), font->lf.lfHeight );
2404 aa_flags = GGO_BITMAP;
2408 return aa_flags;
2411 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
2413 pt->x.value = vec->x >> 6;
2414 pt->x.fract = (vec->x & 0x3f) << 10;
2415 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
2416 pt->y.value = vec->y >> 6;
2417 pt->y.fract = (vec->y & 0x3f) << 10;
2418 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
2421 static FT_UInt get_glyph_index_symbol( struct gdi_font *font, UINT glyph )
2423 FT_Face ft_face = get_ft_face( font );
2424 FT_UInt ret;
2426 if (glyph < 0x100) glyph += 0xf000;
2427 /* there are a number of old pre-Unicode "broken" TTFs, which
2428 do have symbols at U+00XX instead of U+f0XX */
2429 if (!(ret = pFT_Get_Char_Index(ft_face, glyph)))
2430 ret = pFT_Get_Char_Index(ft_face, glyph - 0xf000);
2432 return ret;
2435 /*************************************************************
2436 * freetype_get_glyph_index
2438 static BOOL CDECL freetype_get_glyph_index( struct gdi_font *font, UINT *glyph, BOOL use_encoding )
2440 FT_Face ft_face = get_ft_face( font );
2442 if (!use_encoding ^ (ft_face->charmap->encoding == FT_ENCODING_NONE)) return FALSE;
2444 if (ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
2446 if (!(*glyph = get_glyph_index_symbol( font, *glyph )))
2448 WCHAR wc = *glyph;
2449 DWORD len;
2450 char ch;
2452 RtlUnicodeToMultiByteN( &ch, 1, &len, &wc, sizeof(wc) );
2453 if (len) *glyph = get_glyph_index_symbol( font, (unsigned char)ch );
2455 return TRUE;
2457 *glyph = pFT_Get_Char_Index( ft_face, *glyph );
2458 return TRUE;
2461 /*************************************************************
2462 * freetype_get_default_glyph
2464 static UINT CDECL freetype_get_default_glyph( struct gdi_font *font )
2466 FT_Face ft_face = get_ft_face( font );
2467 FT_WinFNT_HeaderRec winfnt;
2468 TT_OS2 *pOS2;
2470 if ((pOS2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 )))
2472 UINT glyph = pOS2->usDefaultChar;
2473 freetype_get_glyph_index( font, &glyph, TRUE );
2474 return glyph;
2476 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt )) return winfnt.default_char + winfnt.first_char;
2477 return 32;
2481 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
2483 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
2484 return !memcmp(matrix, &identity, sizeof(FMAT2));
2487 static inline FT_Vector normalize_vector(FT_Vector *vec)
2489 FT_Vector out;
2490 FT_Fixed len;
2491 len = pFT_Vector_Length(vec);
2492 if (len) {
2493 out.x = (vec->x << 6) / len;
2494 out.y = (vec->y << 6) / len;
2496 else
2497 out.x = out.y = 0;
2498 return out;
2501 /* get_glyph_outline() glyph transform matrices index */
2502 enum matrices_index
2504 matrix_hori,
2505 matrix_vert,
2506 matrix_unrotated
2509 static BOOL get_transform_matrices( struct gdi_font *font, BOOL vertical, const MAT2 *user_transform,
2510 FT_Matrix matrices[3] )
2512 static const FT_Matrix identity_mat = { (1 << 16), 0, 0, (1 << 16) };
2513 BOOL needs_transform = FALSE;
2514 double width_ratio;
2515 int i;
2517 matrices[matrix_unrotated] = identity_mat;
2519 /* Scaling factor */
2520 if (font->aveWidth)
2522 if (!freetype_set_outline_text_metrics( font )) freetype_set_bitmap_text_metrics( font );
2523 width_ratio = (double)font->aveWidth;
2524 width_ratio /= (double)font->otm.otmTextMetrics.tmAveCharWidth;
2526 else
2527 width_ratio = font->scale_y;
2529 /* Scaling transform */
2530 if (width_ratio != 1.0 || font->scale_y != 1)
2532 FT_Matrix scale_mat;
2533 scale_mat.xx = FT_FixedFromFloat( width_ratio );
2534 scale_mat.xy = 0;
2535 scale_mat.yx = 0;
2536 scale_mat.yy = font->scale_y << 16;
2538 pFT_Matrix_Multiply( &scale_mat, &matrices[matrix_unrotated] );
2539 needs_transform = TRUE;
2542 /* Slant transform */
2543 if (font->fake_italic)
2545 FT_Matrix slant_mat;
2546 slant_mat.xx = (1 << 16);
2547 slant_mat.xy = (1 << 16) >> 2;
2548 slant_mat.yx = 0;
2549 slant_mat.yy = (1 << 16);
2551 pFT_Matrix_Multiply( &slant_mat, &matrices[matrix_unrotated] );
2552 needs_transform = TRUE;
2555 /* Rotation transform */
2556 matrices[matrix_hori] = matrices[matrix_unrotated];
2557 if (font->scalable && font->lf.lfOrientation % 3600)
2559 FT_Matrix rotation_mat;
2560 FT_Vector angle;
2562 pFT_Vector_Unit( &angle, pFT_MulDiv( 1 << 16, font->lf.lfOrientation, 10 ) );
2563 rotation_mat.xx = angle.x;
2564 rotation_mat.xy = -angle.y;
2565 rotation_mat.yx = angle.y;
2566 rotation_mat.yy = angle.x;
2567 pFT_Matrix_Multiply( &rotation_mat, &matrices[matrix_hori] );
2568 needs_transform = TRUE;
2571 /* Vertical transform */
2572 matrices[matrix_vert] = matrices[matrix_hori];
2573 if (vertical)
2575 FT_Matrix vertical_mat = { 0, -(1 << 16), 1 << 16, 0 }; /* 90 degrees rotation */
2577 pFT_Matrix_Multiply( &vertical_mat, &matrices[matrix_vert] );
2578 needs_transform = TRUE;
2581 /* World transform */
2582 if (!is_identity_FMAT2( &font->matrix ))
2584 FT_Matrix world_mat;
2585 world_mat.xx = FT_FixedFromFloat( font->matrix.eM11 );
2586 world_mat.xy = -FT_FixedFromFloat( font->matrix.eM21 );
2587 world_mat.yx = -FT_FixedFromFloat( font->matrix.eM12 );
2588 world_mat.yy = FT_FixedFromFloat( font->matrix.eM22 );
2590 for (i = 0; i < 3; i++)
2591 pFT_Matrix_Multiply( &world_mat, &matrices[i] );
2592 needs_transform = TRUE;
2595 /* Extra transformation specified by caller */
2596 if (user_transform)
2598 FT_Matrix user_mat;
2599 user_mat.xx = FT_FixedFromFIXED( user_transform->eM11 );
2600 user_mat.xy = FT_FixedFromFIXED( user_transform->eM21 );
2601 user_mat.yx = FT_FixedFromFIXED( user_transform->eM12 );
2602 user_mat.yy = FT_FixedFromFIXED( user_transform->eM22 );
2604 for (i = 0; i < 3; i++)
2605 pFT_Matrix_Multiply( &user_mat, &matrices[i] );
2606 needs_transform = TRUE;
2609 return needs_transform;
2612 static BOOL get_bold_glyph_outline(FT_GlyphSlot glyph, LONG ppem, FT_Glyph_Metrics *metrics)
2614 FT_Error err;
2615 FT_Pos strength;
2616 FT_BBox bbox;
2618 if(glyph->format != FT_GLYPH_FORMAT_OUTLINE)
2619 return FALSE;
2620 if(!pFT_Outline_Embolden)
2621 return FALSE;
2623 strength = pFT_MulDiv(ppem, 1 << 6, 24);
2624 err = pFT_Outline_Embolden(&glyph->outline, strength);
2625 if(err) {
2626 TRACE("FT_Ouline_Embolden returns %d\n", err);
2627 return FALSE;
2630 pFT_Outline_Get_CBox(&glyph->outline, &bbox);
2631 metrics->width = bbox.xMax - bbox.xMin;
2632 metrics->height = bbox.yMax - bbox.yMin;
2633 metrics->horiBearingX = bbox.xMin;
2634 metrics->horiBearingY = bbox.yMax;
2635 metrics->vertBearingX = metrics->horiBearingX - metrics->horiAdvance / 2;
2636 metrics->vertBearingY = (metrics->vertAdvance - metrics->height) / 2;
2637 return TRUE;
2640 static inline BYTE get_max_level( UINT format )
2642 switch( format )
2644 case GGO_GRAY2_BITMAP: return 4;
2645 case GGO_GRAY4_BITMAP: return 16;
2646 case GGO_GRAY8_BITMAP: return 64;
2648 return 255;
2651 static FT_Vector get_advance_metric(struct gdi_font *incoming_font, struct gdi_font *font,
2652 const FT_Glyph_Metrics *metrics,
2653 const FT_Matrix *transMat, BOOL vertical_metrics)
2655 FT_Vector adv;
2656 FT_Fixed base_advance, em_scale = 0;
2657 BOOL fixed_pitch_full = FALSE;
2659 if (vertical_metrics)
2660 base_advance = metrics->vertAdvance;
2661 else
2662 base_advance = metrics->horiAdvance;
2664 adv.x = base_advance;
2665 adv.y = 0;
2667 /* In fixed-pitch font, we adjust the fullwidth character advance so that
2668 they have double halfwidth character width. E.g. if the font is 19 ppem,
2669 we return 20 (not 19) for fullwidth characters as we return 10 for
2670 halfwidth characters. */
2671 if (freetype_set_outline_text_metrics(incoming_font) &&
2672 !(incoming_font->otm.otmTextMetrics.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
2673 UINT avg_advance;
2674 em_scale = pFT_MulDiv(incoming_font->ppem, 1 << 16, get_ft_face(incoming_font)->units_per_EM);
2675 avg_advance = pFT_MulFix(incoming_font->ntmAvgWidth, em_scale);
2676 fixed_pitch_full = (avg_advance > 0 &&
2677 (base_advance + 63) >> 6 ==
2678 pFT_MulFix(incoming_font->ntmAvgWidth*2, em_scale));
2679 if (fixed_pitch_full && !transMat)
2680 adv.x = (avg_advance * 2) << 6;
2683 if (transMat) {
2684 pFT_Vector_Transform(&adv, transMat);
2685 if (fixed_pitch_full && adv.y == 0) {
2686 FT_Vector vec;
2687 vec.x = incoming_font->ntmAvgWidth;
2688 vec.y = 0;
2689 pFT_Vector_Transform(&vec, transMat);
2690 adv.x = (pFT_MulFix(vec.x, em_scale) * 2) << 6;
2694 if (font->fake_bold) {
2695 if (!transMat)
2696 adv.x += 1 << 6;
2697 else {
2698 FT_Vector fake_bold_adv, vec = { 1 << 6, 0 };
2699 pFT_Vector_Transform(&vec, transMat);
2700 fake_bold_adv = normalize_vector(&vec);
2701 adv.x += fake_bold_adv.x;
2702 adv.y += fake_bold_adv.y;
2706 adv.x = (adv.x + 63) & -64;
2707 adv.y = -((adv.y + 63) & -64);
2708 return adv;
2711 static FT_BBox get_transformed_bbox( const FT_Glyph_Metrics *metrics,
2712 BOOL needs_transform, const FT_Matrix metrices[3] )
2714 FT_BBox bbox = { 0, 0, 0, 0 };
2716 if (!needs_transform)
2718 bbox.xMin = (metrics->horiBearingX) & -64;
2719 bbox.xMax = (metrics->horiBearingX + metrics->width + 63) & -64;
2720 bbox.yMax = (metrics->horiBearingY + 63) & -64;
2721 bbox.yMin = (metrics->horiBearingY - metrics->height) & -64;
2723 else
2725 FT_Vector vec;
2726 INT xc, yc;
2728 for (xc = 0; xc < 2; xc++)
2730 for (yc = 0; yc < 2; yc++)
2732 vec.x = metrics->horiBearingX + xc * metrics->width;
2733 vec.y = metrics->horiBearingY - yc * metrics->height;
2734 TRACE( "Vec %ld,i %ld\n", vec.x, vec.y );
2735 pFT_Vector_Transform( &vec, &metrices[matrix_vert] );
2736 if (xc == 0 && yc == 0)
2738 bbox.xMin = bbox.xMax = vec.x;
2739 bbox.yMin = bbox.yMax = vec.y;
2741 else
2743 if (vec.x < bbox.xMin) bbox.xMin = vec.x;
2744 else if (vec.x > bbox.xMax) bbox.xMax = vec.x;
2745 if (vec.y < bbox.yMin) bbox.yMin = vec.y;
2746 else if (vec.y > bbox.yMax) bbox.yMax = vec.y;
2750 bbox.xMin = bbox.xMin & -64;
2751 bbox.xMax = (bbox.xMax + 63) & -64;
2752 bbox.yMin = bbox.yMin & -64;
2753 bbox.yMax = (bbox.yMax + 63) & -64;
2754 TRACE( "transformed box: (%ld, %ld - %ld, %ld)\n", bbox.xMin, bbox.yMax, bbox.xMax, bbox.yMin );
2757 return bbox;
2760 static void compute_metrics( struct gdi_font *incoming_font, struct gdi_font *font,
2761 FT_BBox bbox, const FT_Glyph_Metrics *metrics,
2762 BOOL vertical, BOOL vertical_metrics,
2763 BOOL needs_transform, const FT_Matrix matrices[3],
2764 GLYPHMETRICS *gm, ABC *abc )
2766 FT_Vector adv, vec, origin;
2768 if (!needs_transform)
2770 adv = get_advance_metric( incoming_font, font, metrics, NULL, vertical_metrics );
2771 gm->gmCellIncX = adv.x >> 6;
2772 gm->gmCellIncY = 0;
2773 origin.x = bbox.xMin;
2774 origin.y = bbox.yMax;
2775 abc->abcA = origin.x >> 6;
2776 abc->abcB = (metrics->width + 63) >> 6;
2778 else
2780 FT_Pos lsb;
2782 if (vertical && freetype_set_outline_text_metrics( font ))
2784 if (vertical_metrics)
2785 lsb = metrics->horiBearingY + metrics->vertBearingY;
2786 else
2787 lsb = metrics->vertAdvance + (font->otm.otmDescent << 6);
2788 vec.x = lsb;
2789 vec.y = font->otm.otmDescent << 6;
2790 TRACE( "Vec %ld,%ld\n", vec.x>>6, vec.y>>6 );
2791 pFT_Vector_Transform( &vec, &matrices[matrix_hori] );
2792 origin.x = (vec.x + bbox.xMin) & -64;
2793 origin.y = (vec.y + bbox.yMax + 63) & -64;
2794 lsb -= metrics->horiBearingY;
2796 else
2798 origin.x = bbox.xMin;
2799 origin.y = bbox.yMax;
2800 lsb = metrics->horiBearingX;
2803 adv = get_advance_metric( incoming_font, font, metrics, &matrices[matrix_hori],
2804 vertical_metrics );
2805 gm->gmCellIncX = adv.x >> 6;
2806 gm->gmCellIncY = adv.y >> 6;
2808 adv = get_advance_metric( incoming_font, font, metrics, &matrices[matrix_unrotated],
2809 vertical_metrics );
2810 adv.x = pFT_Vector_Length( &adv );
2811 adv.y = 0;
2813 vec.x = lsb;
2814 vec.y = 0;
2815 pFT_Vector_Transform( &vec, &matrices[matrix_unrotated] );
2816 if (lsb > 0) abc->abcA = pFT_Vector_Length( &vec ) >> 6;
2817 else abc->abcA = -((pFT_Vector_Length( &vec ) + 63) >> 6);
2819 /* We use lsb again to avoid rounding errors */
2820 vec.x = lsb + (vertical ? metrics->height : metrics->width);
2821 vec.y = 0;
2822 pFT_Vector_Transform( &vec, &matrices[matrix_unrotated] );
2823 abc->abcB = ((pFT_Vector_Length( &vec ) + 63) >> 6) - abc->abcA;
2825 if (!abc->abcB) abc->abcB = 1;
2826 abc->abcC = (adv.x >> 6) - abc->abcA - abc->abcB;
2828 gm->gmptGlyphOrigin.x = origin.x >> 6;
2829 gm->gmptGlyphOrigin.y = origin.y >> 6;
2830 gm->gmBlackBoxX = (bbox.xMax - bbox.xMin) >> 6;
2831 gm->gmBlackBoxY = (bbox.yMax - bbox.yMin) >> 6;
2832 if (!gm->gmBlackBoxX) gm->gmBlackBoxX = 1;
2833 if (!gm->gmBlackBoxY) gm->gmBlackBoxY = 1;
2835 TRACE( "gm: %u, %u, %s, %d, %d abc %d, %u, %d\n",
2836 gm->gmBlackBoxX, gm->gmBlackBoxY, wine_dbgstr_point(&gm->gmptGlyphOrigin),
2837 gm->gmCellIncX, gm->gmCellIncY, abc->abcA, abc->abcB, abc->abcC );
2841 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
2843 static DWORD get_mono_glyph_bitmap( FT_GlyphSlot glyph, FT_BBox bbox,
2844 BOOL fake_bold, BOOL needs_transform, FT_Matrix matrices[3],
2845 DWORD buflen, BYTE *buf )
2847 DWORD width = (bbox.xMax - bbox.xMin ) >> 6;
2848 DWORD height = (bbox.yMax - bbox.yMin ) >> 6;
2849 DWORD pitch = ((width + 31) >> 5) << 2;
2850 DWORD needed = pitch * height;
2851 FT_Bitmap ft_bitmap;
2852 BYTE *src, *dst;
2853 INT w, h, x;
2855 if (!buf || !buflen) return needed;
2856 if (!needed) return GDI_ERROR; /* empty glyph */
2857 if (needed > buflen) return GDI_ERROR;
2859 switch (glyph->format)
2861 case FT_GLYPH_FORMAT_BITMAP:
2862 src = glyph->bitmap.buffer;
2863 dst = buf;
2864 w = min( pitch, (glyph->bitmap.width + 7) >> 3 );
2865 h = min( height, glyph->bitmap.rows );
2866 while (h--)
2868 if (!fake_bold)
2869 memcpy( dst, src, w );
2870 else
2872 dst[0] = 0;
2873 for (x = 0; x < w; x++)
2875 dst[x] = (dst[x] & 0x80) | (src[x] >> 1) | src[x];
2876 if (x + 1 < pitch)
2877 dst[x + 1] = (src[x] & 0x01) << 7;
2880 src += glyph->bitmap.pitch;
2881 dst += pitch;
2883 break;
2885 case FT_GLYPH_FORMAT_OUTLINE:
2886 ft_bitmap.width = width;
2887 ft_bitmap.rows = height;
2888 ft_bitmap.pitch = pitch;
2889 ft_bitmap.pixel_mode = FT_PIXEL_MODE_MONO;
2890 ft_bitmap.buffer = buf;
2892 if (needs_transform)
2893 pFT_Outline_Transform( &glyph->outline, &matrices[matrix_vert] );
2894 pFT_Outline_Translate( &glyph->outline, -bbox.xMin, -bbox.yMin );
2896 /* Note: FreeType will only set 'black' bits for us. */
2897 memset( buf, 0, buflen );
2898 pFT_Outline_Get_Bitmap( library, &glyph->outline, &ft_bitmap );
2899 break;
2901 default:
2902 FIXME( "loaded glyph format %x\n", glyph->format );
2903 return GDI_ERROR;
2906 return needed;
2909 static DWORD get_antialias_glyph_bitmap( FT_GlyphSlot glyph, FT_BBox bbox, UINT format,
2910 BOOL fake_bold, BOOL needs_transform, FT_Matrix matrices[3],
2911 DWORD buflen, BYTE *buf )
2913 DWORD width = (bbox.xMax - bbox.xMin ) >> 6;
2914 DWORD height = (bbox.yMax - bbox.yMin ) >> 6;
2915 DWORD pitch = (width + 3) / 4 * 4;
2916 DWORD needed = pitch * height;
2917 FT_Bitmap ft_bitmap;
2918 INT w, h, x, max_level;
2919 BYTE *src, *dst;
2921 if (!buf || !buflen) return needed;
2922 if (!needed) return GDI_ERROR; /* empty glyph */
2923 if (needed > buflen) return GDI_ERROR;
2925 max_level = get_max_level( format );
2927 switch (glyph->format)
2929 case FT_GLYPH_FORMAT_BITMAP:
2930 src = glyph->bitmap.buffer;
2931 dst = buf;
2932 memset( buf, 0, buflen );
2934 w = min( pitch, glyph->bitmap.width );
2935 h = min( height, glyph->bitmap.rows );
2936 while (h--)
2938 for (x = 0; x < w; x++)
2940 if (src[x / 8] & masks[x % 8])
2942 dst[x] = max_level;
2943 if (fake_bold && x + 1 < pitch) dst[x + 1] = max_level;
2946 src += glyph->bitmap.pitch;
2947 dst += pitch;
2949 break;
2951 case FT_GLYPH_FORMAT_OUTLINE:
2952 ft_bitmap.width = width;
2953 ft_bitmap.rows = height;
2954 ft_bitmap.pitch = pitch;
2955 ft_bitmap.pixel_mode = FT_PIXEL_MODE_GRAY;
2956 ft_bitmap.buffer = buf;
2958 if (needs_transform)
2959 pFT_Outline_Transform( &glyph->outline, &matrices[matrix_vert] );
2960 pFT_Outline_Translate( &glyph->outline, -bbox.xMin, -bbox.yMin );
2962 memset( buf, 0, buflen );
2963 pFT_Outline_Get_Bitmap( library, &glyph->outline, &ft_bitmap );
2965 if (max_level != 255)
2967 INT row, col;
2968 BYTE *ptr, *start;
2970 for (row = 0, start = buf; row < height; row++)
2972 for (col = 0, ptr = start; col < width; col++, ptr++)
2973 *ptr = (((int)*ptr) * (max_level + 1)) / 256;
2974 start += pitch;
2977 break;
2979 default:
2980 FIXME("loaded glyph format %x\n", glyph->format);
2981 return GDI_ERROR;
2984 return needed;
2987 static DWORD get_subpixel_glyph_bitmap( FT_GlyphSlot glyph, FT_BBox bbox, UINT format,
2988 BOOL fake_bold, BOOL needs_transform, FT_Matrix matrices[3],
2989 GLYPHMETRICS *gm, DWORD buflen, BYTE *buf )
2991 DWORD width = (bbox.xMax - bbox.xMin ) >> 6;
2992 DWORD height = (bbox.yMax - bbox.yMin ) >> 6;
2993 DWORD pitch, needed = 0;
2994 BYTE *src, *dst;
2995 INT w, h, x;
2997 switch (glyph->format)
2999 case FT_GLYPH_FORMAT_BITMAP:
3000 pitch = width * 4;
3001 needed = pitch * height;
3003 if (!buf || !buflen) break;
3004 if (!needed) return GDI_ERROR; /* empty glyph */
3005 if (needed > buflen) return GDI_ERROR;
3007 src = glyph->bitmap.buffer;
3008 dst = buf;
3009 memset( buf, 0, buflen );
3011 w = min( width, glyph->bitmap.width );
3012 h = min( height, glyph->bitmap.rows );
3013 while (h--)
3015 for (x = 0; x < w; x++)
3017 if ( src[x / 8] & masks[x % 8] )
3019 ((unsigned int *)dst)[x] = ~0u;
3020 if (fake_bold && x + 1 < width) ((unsigned int *)dst)[x + 1] = ~0u;
3023 src += glyph->bitmap.pitch;
3024 dst += pitch;
3026 break;
3028 case FT_GLYPH_FORMAT_OUTLINE:
3030 INT src_pitch, src_width, src_height, x_shift, y_shift;
3031 INT sub_stride, hmul, vmul;
3032 const INT *sub_order;
3033 const INT rgb_order[3] = { 0, 1, 2 };
3034 const INT bgr_order[3] = { 2, 1, 0 };
3035 FT_Render_Mode render_mode =
3036 (format == WINE_GGO_HRGB_BITMAP ||
3037 format == WINE_GGO_HBGR_BITMAP) ? FT_RENDER_MODE_LCD : FT_RENDER_MODE_LCD_V;
3039 if (!width || !height) /* empty glyph */
3041 if (!buf || !buflen) break;
3042 return GDI_ERROR;
3045 if ( render_mode == FT_RENDER_MODE_LCD)
3047 gm->gmBlackBoxX += 2;
3048 gm->gmptGlyphOrigin.x -= 1;
3049 bbox.xMin -= (1 << 6);
3051 else
3053 gm->gmBlackBoxY += 2;
3054 gm->gmptGlyphOrigin.y += 1;
3055 bbox.yMax += (1 << 6);
3058 width = gm->gmBlackBoxX;
3059 height = gm->gmBlackBoxY;
3060 pitch = width * 4;
3061 needed = pitch * height;
3063 if (!buf || !buflen) return needed;
3064 if (needed > buflen) return GDI_ERROR;
3066 if (needs_transform)
3067 pFT_Outline_Transform( &glyph->outline, &matrices[matrix_vert] );
3069 #ifdef FT_LCD_FILTER_H
3070 if (pFT_Library_SetLcdFilter)
3071 pFT_Library_SetLcdFilter( library, FT_LCD_FILTER_DEFAULT );
3072 #endif
3073 pFT_Render_Glyph( glyph, render_mode );
3075 src_pitch = glyph->bitmap.pitch;
3076 src_width = glyph->bitmap.width;
3077 src_height = glyph->bitmap.rows;
3078 src = glyph->bitmap.buffer;
3079 dst = buf;
3080 memset( buf, 0, buflen );
3082 sub_order = (format == WINE_GGO_HRGB_BITMAP ||
3083 format == WINE_GGO_VRGB_BITMAP) ? rgb_order : bgr_order;
3084 sub_stride = render_mode == FT_RENDER_MODE_LCD ? 1 : src_pitch;
3085 hmul = render_mode == FT_RENDER_MODE_LCD ? 3 : 1;
3086 vmul = render_mode == FT_RENDER_MODE_LCD ? 1 : 3;
3088 x_shift = glyph->bitmap_left - (bbox.xMin >> 6);
3089 if ( x_shift < 0 )
3091 src += hmul * -x_shift;
3092 src_width -= hmul * -x_shift;
3094 else if ( x_shift > 0 )
3096 dst += x_shift * sizeof(unsigned int);
3097 width -= x_shift;
3100 y_shift = (bbox.yMax >> 6) - glyph->bitmap_top;
3101 if ( y_shift < 0 )
3103 src += src_pitch * vmul * -y_shift;
3104 src_height -= vmul * -y_shift;
3106 else if ( y_shift > 0 )
3108 dst += y_shift * pitch;
3109 height -= y_shift;
3112 w = min( width, src_width / hmul );
3113 h = min( height, src_height / vmul );
3114 while (h--)
3116 for (x = 0; x < w; x++)
3118 ((unsigned int *)dst)[x] =
3119 ((unsigned int)src[hmul * x + sub_stride * sub_order[0]] << 16) |
3120 ((unsigned int)src[hmul * x + sub_stride * sub_order[1]] << 8) |
3121 ((unsigned int)src[hmul * x + sub_stride * sub_order[2]]);
3123 src += src_pitch * vmul;
3124 dst += pitch;
3126 break;
3128 default:
3129 FIXME ( "loaded glyph format %x\n", glyph->format );
3130 return GDI_ERROR;
3133 return needed;
3136 static unsigned int get_native_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
3138 TTPOLYGONHEADER *pph;
3139 TTPOLYCURVE *ppc;
3140 unsigned int needed = 0, point = 0, contour, first_pt;
3141 unsigned int pph_start, cpfx;
3142 DWORD type;
3144 for (contour = 0; contour < outline->n_contours; contour++)
3146 /* Ignore contours containing one point */
3147 if (point == outline->contours[contour])
3149 point++;
3150 continue;
3153 pph_start = needed;
3154 pph = (TTPOLYGONHEADER *)(buf + needed);
3155 first_pt = point;
3156 if (buf)
3158 pph->dwType = TT_POLYGON_TYPE;
3159 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3161 needed += sizeof(*pph);
3162 point++;
3163 while (point <= outline->contours[contour])
3165 ppc = (TTPOLYCURVE *)(buf + needed);
3166 type = outline->tags[point] & FT_Curve_Tag_On ?
3167 TT_PRIM_LINE : TT_PRIM_QSPLINE;
3168 cpfx = 0;
3171 if (buf)
3172 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3173 cpfx++;
3174 point++;
3175 } while (point <= outline->contours[contour] &&
3176 (outline->tags[point] & FT_Curve_Tag_On) ==
3177 (outline->tags[point-1] & FT_Curve_Tag_On));
3178 /* At the end of a contour Windows adds the start point, but
3179 only for Beziers */
3180 if (point > outline->contours[contour] &&
3181 !(outline->tags[point-1] & FT_Curve_Tag_On))
3183 if (buf)
3184 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
3185 cpfx++;
3187 else if (point <= outline->contours[contour] &&
3188 outline->tags[point] & FT_Curve_Tag_On)
3190 /* add closing pt for bezier */
3191 if (buf)
3192 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3193 cpfx++;
3194 point++;
3196 if (buf)
3198 ppc->wType = type;
3199 ppc->cpfx = cpfx;
3201 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3203 if (buf)
3204 pph->cb = needed - pph_start;
3206 return needed;
3209 static unsigned int get_bezier_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
3211 /* Convert the quadratic Beziers to cubic Beziers.
3212 The parametric eqn for a cubic Bezier is, from PLRM:
3213 r(t) = at^3 + bt^2 + ct + r0
3214 with the control points:
3215 r1 = r0 + c/3
3216 r2 = r1 + (c + b)/3
3217 r3 = r0 + c + b + a
3219 A quadratic Bezier has the form:
3220 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3222 So equating powers of t leads to:
3223 r1 = 2/3 p1 + 1/3 p0
3224 r2 = 2/3 p1 + 1/3 p2
3225 and of course r0 = p0, r3 = p2
3227 int contour, point = 0, first_pt;
3228 TTPOLYGONHEADER *pph;
3229 TTPOLYCURVE *ppc;
3230 DWORD pph_start, cpfx, type;
3231 FT_Vector cubic_control[4];
3232 unsigned int needed = 0;
3234 for (contour = 0; contour < outline->n_contours; contour++)
3236 pph_start = needed;
3237 pph = (TTPOLYGONHEADER *)(buf + needed);
3238 first_pt = point;
3239 if (buf)
3241 pph->dwType = TT_POLYGON_TYPE;
3242 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3244 needed += sizeof(*pph);
3245 point++;
3246 while (point <= outline->contours[contour])
3248 ppc = (TTPOLYCURVE *)(buf + needed);
3249 type = outline->tags[point] & FT_Curve_Tag_On ?
3250 TT_PRIM_LINE : TT_PRIM_CSPLINE;
3251 cpfx = 0;
3254 if (type == TT_PRIM_LINE)
3256 if (buf)
3257 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3258 cpfx++;
3259 point++;
3261 else
3263 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
3264 so cpfx = 3n */
3266 /* FIXME: Possible optimization in endpoint calculation
3267 if there are two consecutive curves */
3268 cubic_control[0] = outline->points[point-1];
3269 if (!(outline->tags[point-1] & FT_Curve_Tag_On))
3271 cubic_control[0].x += outline->points[point].x + 1;
3272 cubic_control[0].y += outline->points[point].y + 1;
3273 cubic_control[0].x >>= 1;
3274 cubic_control[0].y >>= 1;
3276 if (point+1 > outline->contours[contour])
3277 cubic_control[3] = outline->points[first_pt];
3278 else
3280 cubic_control[3] = outline->points[point+1];
3281 if (!(outline->tags[point+1] & FT_Curve_Tag_On))
3283 cubic_control[3].x += outline->points[point].x + 1;
3284 cubic_control[3].y += outline->points[point].y + 1;
3285 cubic_control[3].x >>= 1;
3286 cubic_control[3].y >>= 1;
3289 /* r1 = 1/3 p0 + 2/3 p1
3290 r2 = 1/3 p2 + 2/3 p1 */
3291 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
3292 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
3293 cubic_control[2] = cubic_control[1];
3294 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
3295 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
3296 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
3297 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
3298 if (buf)
3300 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
3301 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
3302 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
3304 cpfx += 3;
3305 point++;
3307 } while (point <= outline->contours[contour] &&
3308 (outline->tags[point] & FT_Curve_Tag_On) ==
3309 (outline->tags[point-1] & FT_Curve_Tag_On));
3310 /* At the end of a contour Windows adds the start point,
3311 but only for Beziers and we've already done that.
3313 if (point <= outline->contours[contour] &&
3314 outline->tags[point] & FT_Curve_Tag_On)
3316 /* This is the closing pt of a bezier, but we've already
3317 added it, so just inc point and carry on */
3318 point++;
3320 if (buf)
3322 ppc->wType = type;
3323 ppc->cpfx = cpfx;
3325 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3327 if (buf)
3328 pph->cb = needed - pph_start;
3330 return needed;
3333 static FT_Int get_load_flags( UINT format )
3335 FT_Int load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
3337 if (format & GGO_UNHINTED)
3338 return load_flags | FT_LOAD_NO_HINTING;
3340 switch (format & ~GGO_GLYPH_INDEX)
3342 case GGO_BITMAP:
3343 load_flags |= FT_LOAD_TARGET_MONO;
3344 break;
3345 case GGO_GRAY2_BITMAP:
3346 case GGO_GRAY4_BITMAP:
3347 case GGO_GRAY8_BITMAP:
3348 case WINE_GGO_GRAY16_BITMAP:
3349 load_flags |= FT_LOAD_TARGET_NORMAL;
3350 break;
3351 case WINE_GGO_HRGB_BITMAP:
3352 case WINE_GGO_HBGR_BITMAP:
3353 load_flags |= FT_LOAD_TARGET_LCD;
3354 break;
3355 case WINE_GGO_VRGB_BITMAP:
3356 case WINE_GGO_VBGR_BITMAP:
3357 load_flags |= FT_LOAD_TARGET_LCD_V;
3358 break;
3361 return load_flags;
3364 /*************************************************************
3365 * freetype_get_glyph_outline
3367 static DWORD CDECL freetype_get_glyph_outline( struct gdi_font *font, UINT glyph, UINT format,
3368 GLYPHMETRICS *lpgm, ABC *abc, DWORD buflen, void *buf,
3369 const MAT2 *lpmat, BOOL tategaki )
3371 struct gdi_font *base_font = font->base_font ? font->base_font : font;
3372 FT_Face ft_face = get_ft_face( font );
3373 FT_Glyph_Metrics metrics;
3374 FT_Error err;
3375 FT_BBox bbox;
3376 FT_Int load_flags = get_load_flags(format);
3377 FT_Matrix matrices[3];
3378 BOOL needsTransform = FALSE;
3379 BOOL vertical_metrics;
3381 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm, buflen, buf, lpmat);
3383 TRACE("font transform %f %f %f %f\n",
3384 font->matrix.eM11, font->matrix.eM12,
3385 font->matrix.eM21, font->matrix.eM22);
3387 needsTransform = get_transform_matrices( font, tategaki, lpmat, matrices );
3389 vertical_metrics = (tategaki && FT_HAS_VERTICAL(ft_face));
3390 /* there is a freetype bug where vertical metrics are only
3391 properly scaled and correct in 2.4.0 or greater */
3392 if (vertical_metrics && FT_SimpleVersion < FT_VERSION_VALUE(2, 4, 0))
3393 vertical_metrics = FALSE;
3395 if (needsTransform || format != GGO_BITMAP) load_flags |= FT_LOAD_NO_BITMAP;
3396 if (vertical_metrics) load_flags |= FT_LOAD_VERTICAL_LAYOUT;
3398 err = pFT_Load_Glyph(ft_face, glyph, load_flags);
3399 if (err && !(load_flags & FT_LOAD_NO_HINTING))
3401 WARN("Failed to load glyph %#x, retrying without hinting. Error %#x.\n", glyph, err);
3402 load_flags |= FT_LOAD_NO_HINTING;
3403 err = pFT_Load_Glyph(ft_face, glyph, load_flags);
3406 if(err) {
3407 WARN("Failed to load glyph %#x, error %#x.\n", glyph, err);
3408 return GDI_ERROR;
3411 metrics = ft_face->glyph->metrics;
3412 if(font->fake_bold) {
3413 if (!get_bold_glyph_outline(ft_face->glyph, font->ppem, &metrics) && metrics.width)
3414 metrics.width += 1 << 6;
3417 /* Some poorly-created fonts contain glyphs that exceed the boundaries set
3418 * by the text metrics. The proper behavior is to clip the glyph metrics to
3419 * fit within the maximums specified in the text metrics. */
3420 if (freetype_set_outline_text_metrics(base_font) ||
3421 freetype_set_bitmap_text_metrics(base_font)) {
3422 TEXTMETRICW *ptm = &base_font->otm.otmTextMetrics;
3423 INT top = min( metrics.horiBearingY, ptm->tmAscent << 6 );
3424 INT bottom = max( metrics.horiBearingY - metrics.height, -(ptm->tmDescent << 6) );
3425 metrics.horiBearingY = top;
3426 metrics.height = top - bottom;
3428 /* TODO: Are we supposed to clip the width as well...? */
3429 /* metrics.width = min( metrics.width, ptm->tmMaxCharWidth << 6 ); */
3432 bbox = get_transformed_bbox( &metrics, needsTransform, matrices );
3433 compute_metrics( base_font, font, bbox, &metrics, tategaki,
3434 vertical_metrics, needsTransform, matrices, lpgm, abc );
3436 switch (format)
3438 case GGO_METRICS:
3439 return 1; /* FIXME */
3441 case GGO_BITMAP:
3442 return get_mono_glyph_bitmap( ft_face->glyph, bbox, font->fake_bold,
3443 needsTransform, matrices, buflen, buf );
3445 case GGO_GRAY2_BITMAP:
3446 case GGO_GRAY4_BITMAP:
3447 case GGO_GRAY8_BITMAP:
3448 case WINE_GGO_GRAY16_BITMAP:
3449 return get_antialias_glyph_bitmap( ft_face->glyph, bbox, format, font->fake_bold,
3450 needsTransform, matrices, buflen, buf );
3452 case WINE_GGO_HRGB_BITMAP:
3453 case WINE_GGO_HBGR_BITMAP:
3454 case WINE_GGO_VRGB_BITMAP:
3455 case WINE_GGO_VBGR_BITMAP:
3456 return get_subpixel_glyph_bitmap( ft_face->glyph, bbox, format, font->fake_bold,
3457 needsTransform, matrices, lpgm, buflen, buf );
3459 case GGO_NATIVE:
3460 if (ft_face->glyph->format == ft_glyph_format_outline)
3462 FT_Outline *outline = &ft_face->glyph->outline;
3463 UINT needed;
3465 if (buflen == 0) buf = NULL;
3467 if (needsTransform && buf)
3468 pFT_Outline_Transform( outline, &matrices[matrix_vert] );
3470 needed = get_native_glyph_outline(outline, buflen, NULL);
3472 if (!buf || !buflen) return needed;
3473 if (needed > buflen) return GDI_ERROR;
3474 return get_native_glyph_outline(outline, buflen, buf);
3476 TRACE("loaded a bitmap\n");
3477 return GDI_ERROR;
3479 case GGO_BEZIER:
3480 if (ft_face->glyph->format == ft_glyph_format_outline)
3482 FT_Outline *outline = &ft_face->glyph->outline;
3483 UINT needed;
3485 if (buflen == 0) buf = NULL;
3487 if (needsTransform && buf)
3488 pFT_Outline_Transform( outline, &matrices[matrix_vert] );
3490 needed = get_bezier_glyph_outline(outline, buflen, NULL);
3492 if (!buf || !buflen) return needed;
3493 if (needed > buflen) return GDI_ERROR;
3494 return get_bezier_glyph_outline(outline, buflen, buf);
3496 TRACE("loaded a bitmap\n");
3497 return GDI_ERROR;
3499 default:
3500 FIXME("Unsupported format %d\n", format);
3501 return GDI_ERROR;
3505 /*************************************************************
3506 * freetype_set_bitmap_text_metrics
3508 static BOOL CDECL freetype_set_bitmap_text_metrics( struct gdi_font *font )
3510 FT_Face ft_face = get_ft_face( font );
3511 FT_WinFNT_HeaderRec winfnt_header;
3513 if (font->otm.otmSize) return TRUE; /* already set */
3514 font->otm.otmSize = offsetof( OUTLINETEXTMETRICW, otmFiller );
3516 #define TM font->otm.otmTextMetrics
3517 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
3519 TM.tmHeight = winfnt_header.pixel_height;
3520 TM.tmAscent = winfnt_header.ascent;
3521 TM.tmDescent = TM.tmHeight - TM.tmAscent;
3522 TM.tmInternalLeading = winfnt_header.internal_leading;
3523 TM.tmExternalLeading = winfnt_header.external_leading;
3524 TM.tmAveCharWidth = winfnt_header.avg_width;
3525 TM.tmMaxCharWidth = winfnt_header.max_width;
3526 TM.tmWeight = winfnt_header.weight;
3527 TM.tmOverhang = 0;
3528 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
3529 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
3530 TM.tmFirstChar = winfnt_header.first_char;
3531 TM.tmLastChar = winfnt_header.last_char;
3532 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
3533 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
3534 TM.tmItalic = winfnt_header.italic;
3535 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
3536 TM.tmCharSet = winfnt_header.charset;
3538 else
3540 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
3541 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
3542 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3543 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
3544 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
3545 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
3546 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
3547 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
3548 TM.tmOverhang = 0;
3549 TM.tmDigitizedAspectX = 96; /* FIXME */
3550 TM.tmDigitizedAspectY = 96; /* FIXME */
3551 TM.tmFirstChar = 1;
3552 TM.tmLastChar = 255;
3553 TM.tmDefaultChar = 32;
3554 TM.tmBreakChar = 32;
3555 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
3556 /* NB inverted meaning of TMPF_FIXED_PITCH */
3557 TM.tmPitchAndFamily = FT_IS_FIXED_WIDTH(ft_face) ? 0 : TMPF_FIXED_PITCH;
3558 TM.tmCharSet = font->charset;
3560 TM.tmUnderlined = font->lf.lfUnderline ? 0xff : 0;
3561 TM.tmStruckOut = font->lf.lfStrikeOut ? 0xff : 0;
3563 if(font->fake_bold)
3564 TM.tmWeight = FW_BOLD;
3565 #undef TM
3567 return TRUE;
3571 static BOOL face_has_symbol_charmap(FT_Face ft_face)
3573 int i;
3575 for(i = 0; i < ft_face->num_charmaps; i++)
3577 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
3578 return TRUE;
3580 return FALSE;
3583 /*************************************************************
3584 * freetype_set_outline_text_metrics
3586 static BOOL CDECL freetype_set_outline_text_metrics( struct gdi_font *font )
3588 FT_Face ft_face = get_ft_face( font );
3589 UINT needed;
3590 TT_OS2 *pOS2;
3591 TT_HoriHeader *pHori;
3592 TT_Postscript *pPost;
3593 FT_Fixed em_scale;
3594 INT ascent, descent;
3595 USHORT windescent;
3597 TRACE("font=%p\n", font);
3599 if (!font->scalable) return FALSE;
3600 if (font->otm.otmSize) return TRUE; /* already set */
3602 /* note: we store actual pointers in the names instead of offsets,
3603 they are fixed up when returned to the app */
3604 if (!(font->otm.otmpFullName = (char *)get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, system_lcid )))
3606 static const WCHAR fake_nameW[] = {'f','a','k','e',' ','n','a','m','e', 0};
3607 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w((WCHAR *)font->otm.otmpFamilyName));
3608 font->otm.otmpFullName = (char *)strdupW(fake_nameW);
3610 needed = sizeof(font->otm) + (lstrlenW( (WCHAR *)font->otm.otmpFamilyName ) + 1 +
3611 lstrlenW( (WCHAR *)font->otm.otmpStyleName ) + 1 +
3612 lstrlenW( (WCHAR *)font->otm.otmpFaceName ) + 1 +
3613 lstrlenW( (WCHAR *)font->otm.otmpFullName ) + 1) * sizeof(WCHAR);
3615 em_scale = (FT_Fixed)pFT_MulDiv(font->ppem, 1 << 16, ft_face->units_per_EM);
3617 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3618 if(!pOS2) {
3619 FIXME("Can't find OS/2 table - not TT font?\n");
3620 return FALSE;
3623 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3624 if(!pHori) {
3625 FIXME("Can't find HHEA table - not TT font?\n");
3626 return FALSE;
3629 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
3631 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",
3632 pOS2->usWinAscent, pOS2->usWinDescent,
3633 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
3634 pOS2->xAvgCharWidth,
3635 ft_face->ascender, ft_face->descender, ft_face->height,
3636 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
3637 ft_face->bbox.yMax, ft_face->bbox.yMin);
3639 font->otm.otmSize = needed;
3641 #define TM font->otm.otmTextMetrics
3643 windescent = get_fixed_windescent(pOS2->usWinDescent);
3644 if(pOS2->usWinAscent + windescent == 0) {
3645 ascent = pHori->Ascender;
3646 descent = -pHori->Descender;
3647 } else {
3648 ascent = pOS2->usWinAscent;
3649 descent = windescent;
3652 font->ntmCellHeight = ascent + descent;
3653 font->ntmAvgWidth = pOS2->xAvgCharWidth;
3655 #define SCALE_X(x) (pFT_MulFix(x, em_scale))
3656 #define SCALE_Y(y) (pFT_MulFix(y, em_scale))
3658 if(font->yMax) {
3659 TM.tmAscent = font->yMax;
3660 TM.tmDescent = -font->yMin;
3661 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
3662 } else {
3663 TM.tmAscent = SCALE_Y(ascent);
3664 TM.tmDescent = SCALE_Y(descent);
3665 TM.tmInternalLeading = SCALE_Y(ascent + descent - ft_face->units_per_EM);
3668 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3670 /* MSDN says:
3671 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
3673 TM.tmExternalLeading = max(0, SCALE_Y(pHori->Line_Gap -
3674 ((ascent + descent) -
3675 (pHori->Ascender - pHori->Descender))));
3677 TM.tmAveCharWidth = SCALE_X(pOS2->xAvgCharWidth);
3678 if (TM.tmAveCharWidth == 0) {
3679 TM.tmAveCharWidth = 1;
3681 TM.tmMaxCharWidth = SCALE_X(ft_face->bbox.xMax - ft_face->bbox.xMin);
3682 TM.tmWeight = FW_REGULAR;
3683 if (font->fake_bold)
3684 TM.tmWeight = FW_BOLD;
3685 else
3687 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
3689 if (pOS2->usWeightClass > FW_MEDIUM)
3690 TM.tmWeight = pOS2->usWeightClass;
3692 else if (pOS2->usWeightClass <= FW_MEDIUM)
3693 TM.tmWeight = pOS2->usWeightClass;
3695 TM.tmOverhang = 0;
3696 TM.tmDigitizedAspectX = 96; /* FIXME */
3697 TM.tmDigitizedAspectY = 96; /* FIXME */
3698 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
3699 * symbol range to 0 - f0ff
3702 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
3704 TM.tmFirstChar = 0;
3705 switch (PRIMARYLANGID(system_lcid))
3707 case LANG_HEBREW:
3708 TM.tmLastChar = 0xf896;
3709 break;
3710 case LANG_ESTONIAN:
3711 case LANG_LATVIAN:
3712 case LANG_LITHUANIAN:
3713 TM.tmLastChar = 0xf8fd;
3714 break;
3715 default:
3716 TM.tmLastChar = 0xf0ff;
3718 TM.tmBreakChar = 0x20;
3719 TM.tmDefaultChar = 0x1f;
3721 else
3723 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
3724 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
3726 if(pOS2->usFirstCharIndex <= 1)
3727 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
3728 else if (pOS2->usFirstCharIndex > 0xff)
3729 TM.tmBreakChar = 0x20;
3730 else
3731 TM.tmBreakChar = pOS2->usFirstCharIndex;
3732 TM.tmDefaultChar = TM.tmBreakChar - 1;
3734 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
3735 TM.tmUnderlined = font->lf.lfUnderline ? 255 : 0;
3736 TM.tmStruckOut = font->lf.lfStrikeOut ? 255 : 0;
3738 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
3739 if(!FT_IS_FIXED_WIDTH(ft_face) &&
3740 (pOS2->version == 0xFFFFU ||
3741 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
3742 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
3743 else
3744 TM.tmPitchAndFamily = 0;
3746 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
3748 case PAN_FAMILY_SCRIPT:
3749 TM.tmPitchAndFamily |= FF_SCRIPT;
3750 break;
3752 case PAN_FAMILY_DECORATIVE:
3753 TM.tmPitchAndFamily |= FF_DECORATIVE;
3754 break;
3756 case PAN_ANY:
3757 case PAN_NO_FIT:
3758 case PAN_FAMILY_TEXT_DISPLAY:
3759 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
3760 /* which is clearly not what the panose spec says. */
3761 default:
3762 if(TM.tmPitchAndFamily == 0 || /* fixed */
3763 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
3764 TM.tmPitchAndFamily = FF_MODERN;
3765 else
3767 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
3769 case PAN_ANY:
3770 case PAN_NO_FIT:
3771 default:
3772 TM.tmPitchAndFamily |= FF_DONTCARE;
3773 break;
3775 case PAN_SERIF_COVE:
3776 case PAN_SERIF_OBTUSE_COVE:
3777 case PAN_SERIF_SQUARE_COVE:
3778 case PAN_SERIF_OBTUSE_SQUARE_COVE:
3779 case PAN_SERIF_SQUARE:
3780 case PAN_SERIF_THIN:
3781 case PAN_SERIF_BONE:
3782 case PAN_SERIF_EXAGGERATED:
3783 case PAN_SERIF_TRIANGLE:
3784 TM.tmPitchAndFamily |= FF_ROMAN;
3785 break;
3787 case PAN_SERIF_NORMAL_SANS:
3788 case PAN_SERIF_OBTUSE_SANS:
3789 case PAN_SERIF_PERP_SANS:
3790 case PAN_SERIF_FLARED:
3791 case PAN_SERIF_ROUNDED:
3792 TM.tmPitchAndFamily |= FF_SWISS;
3793 break;
3796 break;
3799 if(FT_IS_SCALABLE(ft_face))
3800 TM.tmPitchAndFamily |= TMPF_VECTOR;
3802 if(FT_IS_SFNT(ft_face))
3804 if (font->ntmFlags & NTM_PS_OPENTYPE)
3805 TM.tmPitchAndFamily |= TMPF_DEVICE;
3806 else
3807 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
3810 TM.tmCharSet = font->charset;
3812 font->otm.otmFiller = 0;
3813 memcpy(&font->otm.otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
3814 font->otm.otmfsSelection = pOS2->fsSelection;
3815 if (font->fake_italic)
3816 font->otm.otmfsSelection |= 1;
3817 if (font->fake_bold)
3818 font->otm.otmfsSelection |= 1 << 5;
3819 /* Only return valid bits that define embedding and subsetting restrictions */
3820 font->otm.otmfsType = pOS2->fsType & 0x30e;
3821 font->otm.otmsCharSlopeRise = pHori->caret_Slope_Rise;
3822 font->otm.otmsCharSlopeRun = pHori->caret_Slope_Run;
3823 font->otm.otmItalicAngle = 0; /* POST table */
3824 font->otm.otmEMSquare = ft_face->units_per_EM;
3825 font->otm.otmAscent = SCALE_Y(pOS2->sTypoAscender);
3826 font->otm.otmDescent = SCALE_Y(pOS2->sTypoDescender);
3827 font->otm.otmLineGap = SCALE_Y(pOS2->sTypoLineGap);
3828 font->otm.otmsCapEmHeight = SCALE_Y(pOS2->sCapHeight);
3829 font->otm.otmsXHeight = SCALE_Y(pOS2->sxHeight);
3830 font->otm.otmrcFontBox.left = SCALE_X(ft_face->bbox.xMin);
3831 font->otm.otmrcFontBox.right = SCALE_X(ft_face->bbox.xMax);
3832 font->otm.otmrcFontBox.top = SCALE_Y(ft_face->bbox.yMax);
3833 font->otm.otmrcFontBox.bottom = SCALE_Y(ft_face->bbox.yMin);
3834 font->otm.otmMacAscent = TM.tmAscent;
3835 font->otm.otmMacDescent = -TM.tmDescent;
3836 font->otm.otmMacLineGap = SCALE_Y(pHori->Line_Gap);
3837 font->otm.otmusMinimumPPEM = 0; /* TT Header */
3838 font->otm.otmptSubscriptSize.x = SCALE_X(pOS2->ySubscriptXSize);
3839 font->otm.otmptSubscriptSize.y = SCALE_Y(pOS2->ySubscriptYSize);
3840 font->otm.otmptSubscriptOffset.x = SCALE_X(pOS2->ySubscriptXOffset);
3841 font->otm.otmptSubscriptOffset.y = SCALE_Y(pOS2->ySubscriptYOffset);
3842 font->otm.otmptSuperscriptSize.x = SCALE_X(pOS2->ySuperscriptXSize);
3843 font->otm.otmptSuperscriptSize.y = SCALE_Y(pOS2->ySuperscriptYSize);
3844 font->otm.otmptSuperscriptOffset.x = SCALE_X(pOS2->ySuperscriptXOffset);
3845 font->otm.otmptSuperscriptOffset.y = SCALE_Y(pOS2->ySuperscriptYOffset);
3846 font->otm.otmsStrikeoutSize = SCALE_Y(pOS2->yStrikeoutSize);
3847 font->otm.otmsStrikeoutPosition = SCALE_Y(pOS2->yStrikeoutPosition);
3848 if(!pPost) {
3849 font->otm.otmsUnderscoreSize = 0;
3850 font->otm.otmsUnderscorePosition = 0;
3851 } else {
3852 font->otm.otmsUnderscoreSize = SCALE_Y(pPost->underlineThickness);
3853 font->otm.otmsUnderscorePosition = SCALE_Y(pPost->underlinePosition);
3855 #undef SCALE_X
3856 #undef SCALE_Y
3857 #undef TM
3858 return TRUE;
3861 /*************************************************************
3862 * freetype_get_char_width_info
3864 static BOOL CDECL freetype_get_char_width_info( struct gdi_font *font, struct char_width_info *info )
3866 FT_Face ft_face = get_ft_face( font );
3867 TT_HoriHeader *pHori;
3869 TRACE("%p, %p\n", font, info);
3871 if ((pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea)))
3873 FT_Fixed em_scale = pFT_MulDiv(font->ppem, 1 << 16, ft_face->units_per_EM);
3874 info->lsb = (SHORT)pFT_MulFix(pHori->min_Left_Side_Bearing, em_scale);
3875 info->rsb = (SHORT)pFT_MulFix(pHori->min_Right_Side_Bearing, em_scale);
3876 return TRUE;
3878 return FALSE;
3882 /*************************************************************
3883 * freetype_get_unicode_ranges
3885 * Retrieve a list of supported Unicode ranges for a given font.
3886 * Can be called with NULL gs to calculate the buffer size. Returns
3887 * the number of ranges found.
3889 static DWORD CDECL freetype_get_unicode_ranges( struct gdi_font *font, GLYPHSET *gs )
3891 FT_Face ft_face = get_ft_face( font );
3892 DWORD num_ranges = 0;
3894 if (ft_face->charmap->encoding == FT_ENCODING_UNICODE)
3896 FT_UInt glyph_code;
3897 FT_ULong char_code, char_code_prev;
3899 glyph_code = 0;
3900 char_code_prev = char_code = pFT_Get_First_Char(ft_face, &glyph_code);
3902 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
3903 ft_face->num_glyphs, glyph_code, char_code);
3905 if (!glyph_code) return 0;
3907 if (gs)
3909 gs->ranges[0].wcLow = (USHORT)char_code;
3910 gs->ranges[0].cGlyphs = 0;
3911 gs->cGlyphsSupported = 0;
3914 num_ranges = 1;
3915 while (glyph_code)
3917 if (char_code < char_code_prev)
3919 ERR("expected increasing char code from FT_Get_Next_Char\n");
3920 return 0;
3922 if (char_code - char_code_prev > 1)
3924 num_ranges++;
3925 if (gs)
3927 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
3928 gs->ranges[num_ranges - 1].cGlyphs = 1;
3929 gs->cGlyphsSupported++;
3932 else if (gs)
3934 gs->ranges[num_ranges - 1].cGlyphs++;
3935 gs->cGlyphsSupported++;
3937 char_code_prev = char_code;
3938 char_code = pFT_Get_Next_Char(ft_face, char_code, &glyph_code);
3941 else
3943 DWORD encoding = RtlUlongByteSwap(ft_face->charmap->encoding);
3944 FIXME("encoding %s not supported\n", debugstr_an((char *)&encoding, 4));
3947 return num_ranges;
3950 /*************************************************************************
3951 * Kerning support for TrueType fonts
3954 struct TT_kern_table
3956 USHORT version;
3957 USHORT nTables;
3960 struct TT_kern_subtable
3962 USHORT version;
3963 USHORT length;
3964 union
3966 USHORT word;
3967 struct
3969 USHORT horizontal : 1;
3970 USHORT minimum : 1;
3971 USHORT cross_stream: 1;
3972 USHORT override : 1;
3973 USHORT reserved1 : 4;
3974 USHORT format : 8;
3975 } bits;
3976 } coverage;
3979 struct TT_format0_kern_subtable
3981 USHORT nPairs;
3982 USHORT searchRange;
3983 USHORT entrySelector;
3984 USHORT rangeShift;
3987 struct TT_kern_pair
3989 USHORT left;
3990 USHORT right;
3991 short value;
3994 static DWORD parse_format0_kern_subtable(struct gdi_font *font,
3995 const struct TT_format0_kern_subtable *tt_f0_ks,
3996 const USHORT *glyph_to_char,
3997 KERNINGPAIR *kern_pair, DWORD cPairs)
3999 FT_Face ft_face = get_ft_face( font );
4000 USHORT i, nPairs;
4001 const struct TT_kern_pair *tt_kern_pair;
4003 TRACE("font height %d, units_per_EM %d\n", font->ppem, ft_face->units_per_EM);
4005 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
4007 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
4008 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
4009 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
4011 if (!kern_pair || !cPairs)
4012 return nPairs;
4014 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
4016 nPairs = min(nPairs, cPairs);
4018 for (i = 0; i < nPairs; i++)
4020 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
4021 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
4022 /* this algorithm appears to better match what Windows does */
4023 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
4024 if (kern_pair->iKernAmount < 0)
4026 kern_pair->iKernAmount -= ft_face->units_per_EM / 2;
4027 kern_pair->iKernAmount -= font->ppem;
4029 else if (kern_pair->iKernAmount > 0)
4031 kern_pair->iKernAmount += ft_face->units_per_EM / 2;
4032 kern_pair->iKernAmount += font->ppem;
4034 kern_pair->iKernAmount /= ft_face->units_per_EM;
4036 TRACE("left %u right %u value %d\n",
4037 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
4039 kern_pair++;
4041 TRACE("copied %u entries\n", nPairs);
4042 return nPairs;
4045 /*************************************************************
4046 * freetype_get_kerning_pairs
4048 static DWORD CDECL freetype_get_kerning_pairs( struct gdi_font *font, KERNINGPAIR **pairs )
4050 FT_Face ft_face = get_ft_face( font );
4051 DWORD length, count = 0;
4052 void *buf;
4053 const struct TT_kern_table *tt_kern_table;
4054 const struct TT_kern_subtable *tt_kern_subtable;
4055 USHORT i, nTables;
4056 USHORT *glyph_to_char;
4058 length = freetype_get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
4060 if (length == GDI_ERROR)
4062 TRACE("no kerning data in the font\n");
4063 return 0;
4066 buf = RtlAllocateHeap(GetProcessHeap(), 0, length);
4067 if (!buf) return 0;
4069 freetype_get_font_data(font, MS_KERN_TAG, 0, buf, length);
4071 /* build a glyph index to char code map */
4072 glyph_to_char = RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
4073 if (!glyph_to_char)
4075 RtlFreeHeap(GetProcessHeap(), 0, buf);
4076 return 0;
4079 if (ft_face->charmap->encoding == FT_ENCODING_UNICODE)
4081 FT_UInt glyph_code;
4082 FT_ULong char_code;
4084 glyph_code = 0;
4085 char_code = pFT_Get_First_Char(ft_face, &glyph_code);
4087 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
4088 ft_face->num_glyphs, glyph_code, char_code);
4090 while (glyph_code)
4092 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
4094 /* FIXME: This doesn't match what Windows does: it does some fancy
4095 * things with duplicate glyph index to char code mappings, while
4096 * we just avoid overriding existing entries.
4098 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
4099 glyph_to_char[glyph_code] = (USHORT)char_code;
4101 char_code = pFT_Get_Next_Char(ft_face, char_code, &glyph_code);
4104 else
4106 DWORD encoding = RtlUlongByteSwap(ft_face->charmap->encoding);
4107 ULONG n;
4109 FIXME("encoding %s not supported\n", debugstr_an((char *)&encoding, 4));
4110 for (n = 0; n <= 65535; n++)
4111 glyph_to_char[n] = (USHORT)n;
4114 tt_kern_table = buf;
4115 nTables = GET_BE_WORD(tt_kern_table->nTables);
4116 TRACE("version %u, nTables %u\n",
4117 GET_BE_WORD(tt_kern_table->version), nTables);
4119 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
4121 for (i = 0; i < nTables; i++)
4123 struct TT_kern_subtable tt_kern_subtable_copy;
4125 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
4126 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
4127 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
4129 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
4130 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
4131 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
4133 /* According to the TrueType specification this is the only format
4134 * that will be properly interpreted by Windows and OS/2
4136 if (tt_kern_subtable_copy.coverage.bits.format == 0)
4138 DWORD new_chunk, old_total = count;
4140 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
4141 glyph_to_char, NULL, 0);
4142 count += new_chunk;
4144 if (!*pairs)
4145 *pairs = RtlAllocateHeap(GetProcessHeap(), 0, count * sizeof(**pairs));
4146 else
4147 *pairs = RtlReAllocateHeap(GetProcessHeap(), 0, *pairs, count * sizeof(**pairs));
4149 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
4150 glyph_to_char, *pairs + old_total, new_chunk);
4152 else
4153 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
4155 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
4158 RtlFreeHeap(GetProcessHeap(), 0, glyph_to_char);
4159 RtlFreeHeap(GetProcessHeap(), 0, buf);
4160 return count;
4163 static const struct font_backend_funcs font_funcs =
4165 freetype_load_fonts,
4166 fontconfig_enum_family_fallbacks,
4167 freetype_add_font,
4168 freetype_add_mem_font,
4169 freetype_load_font,
4170 freetype_get_font_data,
4171 freetype_get_aa_flags,
4172 freetype_get_glyph_index,
4173 freetype_get_default_glyph,
4174 freetype_get_glyph_outline,
4175 freetype_get_unicode_ranges,
4176 freetype_get_char_width_info,
4177 freetype_set_outline_text_metrics,
4178 freetype_set_bitmap_text_metrics,
4179 freetype_get_kerning_pairs,
4180 freetype_destroy_font
4183 static NTSTATUS init_freetype_lib( HMODULE module, DWORD reason, const void *ptr_in, void *ptr_out )
4185 callback_funcs = ptr_in;
4186 if (!init_freetype()) return STATUS_DLL_NOT_FOUND;
4187 #ifdef SONAME_LIBFONTCONFIG
4188 init_fontconfig();
4189 #endif
4190 NtQueryDefaultLocale( FALSE, &system_lcid );
4191 *(const struct font_backend_funcs **)ptr_out = &font_funcs;
4192 return STATUS_SUCCESS;
4195 #else /* HAVE_FREETYPE */
4197 static NTSTATUS init_freetype_lib( HMODULE module, DWORD reason, const void *ptr_in, void *ptr_out )
4199 return STATUS_DLL_NOT_FOUND;
4202 #endif /* HAVE_FREETYPE */
4204 NTSTATUS CDECL __wine_init_unix_lib( HMODULE module, DWORD reason, const void *ptr_in, void *ptr_out )
4206 if (reason != DLL_PROCESS_ATTACH) return STATUS_SUCCESS;
4208 if (ptr_in) return init_freetype_lib( module, reason, ptr_in, ptr_out );
4209 else return init_opengl_lib( module, reason, ptr_in, ptr_out );