gdi32: Lazily create and cache fontconfig patterns.
[wine.git] / dlls / gdi32 / freetype.c
blob993110e6fe0b1e010dcd9328603c0bd0c8f1275e
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 static int add_unix_face( const char *unix_name, const WCHAR *file, void *data_ptr, SIZE_T data_size,
1096 DWORD face_index, DWORD flags, DWORD *num_faces )
1098 struct bitmap_font_size size;
1099 FONTSIGNATURE fs;
1100 FT_Face ft_face;
1101 WCHAR *family_name, *second_name, *style_name, *full_name;
1102 int ret;
1104 if (num_faces) *num_faces = 0;
1106 if (!(ft_face = new_ft_face( unix_name, data_ptr, data_size, face_index, flags & ADDFONT_ALLOW_BITMAP )))
1107 return 0;
1109 if (ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1111 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(unix_name));
1112 pFT_Done_Face( ft_face );
1113 return 0;
1116 family_name = ft_face_get_family_name( ft_face, system_lcid );
1117 second_name = ft_face_get_family_name( ft_face, MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT) );
1118 style_name = ft_face_get_style_name( ft_face, system_lcid );
1119 full_name = ft_face_get_full_name( ft_face, system_lcid );
1121 /* try to find another secondary name, preferring the lowest langids */
1122 if (!RtlCompareUnicodeStrings( family_name, lstrlenW(family_name),
1123 second_name, lstrlenW(second_name), TRUE ))
1125 RtlFreeHeap( GetProcessHeap(), 0, second_name );
1126 second_name = ft_face_get_family_name( ft_face, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL) );
1127 if (!RtlCompareUnicodeStrings( family_name, lstrlenW(family_name),
1128 second_name, lstrlenW(second_name), TRUE ))
1130 RtlFreeHeap( GetProcessHeap(), 0, second_name );
1131 second_name = NULL;
1135 get_fontsig( ft_face, &fs );
1136 if (!FT_IS_SCALABLE( ft_face )) get_bitmap_size( ft_face, &size );
1137 if (!HIWORD( flags )) flags |= ADDFONT_AA_FLAGS( default_aa_flags );
1139 ret = callback_funcs->add_gdi_face( family_name, second_name, style_name, full_name, file,
1140 data_ptr, data_size, face_index, fs, get_ntm_flags( ft_face ),
1141 get_font_version( ft_face ), flags,
1142 FT_IS_SCALABLE(ft_face) ? NULL : &size );
1144 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1145 fs.fsCsb[0], fs.fsCsb[1], fs.fsUsb[0], fs.fsUsb[1], fs.fsUsb[2], fs.fsUsb[3]);
1147 RtlFreeHeap( GetProcessHeap(), 0, family_name );
1148 RtlFreeHeap( GetProcessHeap(), 0, second_name );
1149 RtlFreeHeap( GetProcessHeap(), 0, style_name );
1150 RtlFreeHeap( GetProcessHeap(), 0, full_name );
1152 if (num_faces) *num_faces = ft_face->num_faces;
1153 pFT_Done_Face( ft_face );
1154 return ret;
1157 static WCHAR *get_dos_file_name( LPCSTR str )
1159 WCHAR *buffer;
1160 SIZE_T len = strlen(str) + 1;
1162 len += 8; /* \??\unix prefix */
1163 if (!(buffer = RtlAllocateHeap( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return NULL;
1164 if (wine_unix_to_nt_file_name( str, buffer, &len ))
1166 RtlFreeHeap( GetProcessHeap(), 0, buffer );
1167 return NULL;
1169 if (buffer[5] == ':')
1171 /* get rid of the \??\ prefix */
1172 /* FIXME: should implement RtlNtPathNameToDosPathName and use that instead */
1173 memmove( buffer, buffer + 4, (len - 4) * sizeof(WCHAR) );
1175 else buffer[1] = '\\';
1176 return buffer;
1179 static char *get_unix_file_name( LPCWSTR dosW )
1181 UNICODE_STRING nt_name;
1182 NTSTATUS status;
1183 SIZE_T size = 256;
1184 char *buffer;
1186 if (!RtlDosPathNameToNtPathName_U( dosW, &nt_name, NULL, NULL )) return NULL;
1187 for (;;)
1189 if (!(buffer = RtlAllocateHeap( GetProcessHeap(), 0, size )))
1191 RtlFreeUnicodeString( &nt_name );
1192 return NULL;
1194 status = wine_nt_to_unix_file_name( &nt_name, buffer, &size, FILE_OPEN_IF );
1195 if (status != STATUS_BUFFER_TOO_SMALL) break;
1196 RtlFreeHeap( GetProcessHeap(), 0, buffer );
1198 RtlFreeUnicodeString( &nt_name );
1199 if (status && status != STATUS_NO_SUCH_FILE)
1201 RtlFreeHeap( GetProcessHeap(), 0, buffer );
1202 RtlSetLastWin32ErrorAndNtStatusFromNtStatus( status );
1203 return NULL;
1205 return buffer;
1208 static INT AddFontToList(const WCHAR *dos_name, const char *unix_name, void *font_data_ptr,
1209 DWORD font_data_size, DWORD flags)
1211 DWORD face_index = 0, num_faces;
1212 INT ret = 0;
1213 WCHAR *filename = NULL;
1215 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1216 assert(unix_name || !(flags & ADDFONT_EXTERNAL_FONT));
1218 #ifdef HAVE_CARBON_CARBON_H
1219 if(unix_name)
1221 char **mac_list = expand_mac_font(unix_name);
1222 if(mac_list)
1224 BOOL had_one = FALSE;
1225 char **cursor;
1226 for(cursor = mac_list; *cursor; cursor++)
1228 had_one = TRUE;
1229 AddFontToList(NULL, *cursor, NULL, 0, flags);
1230 RtlFreeHeap(GetProcessHeap(), 0, *cursor);
1232 RtlFreeHeap(GetProcessHeap(), 0, mac_list);
1233 if(had_one)
1234 return 1;
1237 #endif /* HAVE_CARBON_CARBON_H */
1239 if (!dos_name && unix_name) dos_name = filename = get_dos_file_name( unix_name );
1242 ret += add_unix_face( unix_name, dos_name, font_data_ptr, font_data_size, face_index, flags, &num_faces );
1243 while (num_faces > ++face_index);
1245 RtlFreeHeap( GetProcessHeap(), 0, filename );
1246 return ret;
1249 /*************************************************************
1250 * freetype_add_font
1252 static INT CDECL freetype_add_font( const WCHAR *file, DWORD flags )
1254 int ret = 0;
1255 char *unixname = get_unix_file_name( file );
1257 if (unixname)
1259 ret = AddFontToList( file, unixname, NULL, 0, flags );
1260 RtlFreeHeap( GetProcessHeap(), 0, unixname );
1262 return ret;
1265 /*************************************************************
1266 * freetype_add_mem_font
1268 static INT CDECL freetype_add_mem_font( void *ptr, SIZE_T size, DWORD flags )
1270 return AddFontToList( NULL, NULL, ptr, size, flags );
1273 #ifdef __ANDROID__
1274 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1276 DIR *dir;
1277 struct dirent *dent;
1278 char path[MAX_PATH];
1280 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1282 dir = opendir(dirname);
1283 if(!dir) {
1284 WARN("Can't open directory %s\n", debugstr_a(dirname));
1285 return FALSE;
1287 while((dent = readdir(dir)) != NULL) {
1288 struct stat statbuf;
1290 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1291 continue;
1293 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1295 sprintf(path, "%s/%s", dirname, dent->d_name);
1297 if(stat(path, &statbuf) == -1)
1299 WARN("Can't stat %s\n", debugstr_a(path));
1300 continue;
1302 if(S_ISDIR(statbuf.st_mode))
1303 ReadFontDir(path, external_fonts);
1304 else
1306 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
1307 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
1308 AddFontToList(NULL, path, NULL, 0, addfont_flags);
1311 closedir(dir);
1312 return TRUE;
1314 #endif
1316 #ifdef SONAME_LIBFONTCONFIG
1318 static BOOL fontconfig_enabled;
1319 static FcPattern *pattern_serif;
1320 static FcPattern *pattern_fixed;
1321 static FcPattern *pattern_sans;
1323 static UINT parse_aa_pattern( FcPattern *pattern )
1325 FcBool antialias;
1326 int rgba;
1327 UINT aa_flags = 0;
1329 if (pFcPatternGetBool( pattern, FC_ANTIALIAS, 0, &antialias ) == FcResultMatch)
1330 aa_flags = antialias ? GGO_GRAY4_BITMAP : GGO_BITMAP;
1332 if (pFcPatternGetInteger( pattern, FC_RGBA, 0, &rgba ) == FcResultMatch)
1334 switch (rgba)
1336 case FC_RGBA_RGB: aa_flags = WINE_GGO_HRGB_BITMAP; break;
1337 case FC_RGBA_BGR: aa_flags = WINE_GGO_HBGR_BITMAP; break;
1338 case FC_RGBA_VRGB: aa_flags = WINE_GGO_VRGB_BITMAP; break;
1339 case FC_RGBA_VBGR: aa_flags = WINE_GGO_VBGR_BITMAP; break;
1340 case FC_RGBA_NONE: aa_flags = aa_flags ? aa_flags : GGO_GRAY4_BITMAP; break;
1343 return aa_flags;
1346 static FcPattern *create_family_pattern( const char *name, FcPattern **cached )
1348 FcPattern *ret = NULL, *tmp, *pattern = pFcPatternCreate();
1349 FcResult result;
1350 if (*cached) return *cached;
1351 pFcPatternAddString( pattern, FC_FAMILY, (const FcChar8 *)name );
1352 pFcPatternAddString( pattern, FC_NAMELANG, (const FcChar8 *)"en-us" );
1353 pFcPatternAddString( pattern, FC_PRGNAME, (const FcChar8 *)"wine" );
1354 pFcConfigSubstitute( NULL, pattern, FcMatchPattern );
1355 pFcDefaultSubstitute( pattern );
1356 tmp = pFcFontMatch( NULL, pattern, &result );
1357 pFcPatternDestroy( pattern );
1358 if (result != FcResultMatch) pFcPatternDestroy( tmp );
1359 else if ((ret = InterlockedCompareExchangePointer( (void **)cached, tmp, NULL ))) pFcPatternDestroy( tmp );
1360 else ret = tmp;
1361 return ret;
1364 static void fontconfig_add_font( FcPattern *pattern, DWORD flags )
1366 const char *unix_name, *format;
1367 WCHAR *dos_name;
1368 FcBool scalable;
1369 DWORD aa_flags;
1370 int face_index;
1372 TRACE( "(%p %#x)\n", pattern, flags );
1374 if (pFcPatternGetString( pattern, FC_FILE, 0, (FcChar8 **)&unix_name ) != FcResultMatch)
1375 return;
1377 if (pFcPatternGetBool( pattern, FC_SCALABLE, 0, &scalable ) != FcResultMatch)
1378 scalable = FALSE;
1380 if (pFcPatternGetString( pattern, FC_FONTFORMAT, 0, (FcChar8 **)&format ) != FcResultMatch)
1382 TRACE( "ignoring unknown font format %s\n", debugstr_a(unix_name) );
1383 return;
1386 if (!strcmp( format, "Type 1" ))
1388 TRACE( "ignoring Type 1 font %s\n", debugstr_a(unix_name) );
1389 return;
1392 if (!scalable && !(flags & ADDFONT_ALLOW_BITMAP))
1394 TRACE( "ignoring non-scalable font %s\n", debugstr_a(unix_name) );
1395 return;
1398 if (!(aa_flags = parse_aa_pattern( pattern ))) aa_flags = default_aa_flags;
1399 flags |= ADDFONT_AA_FLAGS(aa_flags);
1401 if (pFcPatternGetInteger( pattern, FC_INDEX, 0, &face_index ) != FcResultMatch)
1402 face_index = 0;
1404 dos_name = get_dos_file_name( unix_name );
1405 add_unix_face( unix_name, dos_name, NULL, 0, face_index, flags, NULL );
1406 RtlFreeHeap( GetProcessHeap(), 0, dos_name );
1409 static void init_fontconfig(void)
1411 void *fc_handle = dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW);
1413 if (!fc_handle)
1415 TRACE("Wine cannot find the fontconfig library (%s).\n", SONAME_LIBFONTCONFIG);
1416 return;
1419 #define LOAD_FUNCPTR(f) if((p##f = dlsym(fc_handle, #f)) == NULL){WARN("Can't find symbol %s\n", #f); return;}
1420 LOAD_FUNCPTR(FcConfigSubstitute);
1421 LOAD_FUNCPTR(FcDefaultSubstitute);
1422 LOAD_FUNCPTR(FcFontList);
1423 LOAD_FUNCPTR(FcFontMatch);
1424 LOAD_FUNCPTR(FcFontSetDestroy);
1425 LOAD_FUNCPTR(FcInit);
1426 LOAD_FUNCPTR(FcPatternAddString);
1427 LOAD_FUNCPTR(FcPatternCreate);
1428 LOAD_FUNCPTR(FcPatternDestroy);
1429 LOAD_FUNCPTR(FcPatternGetBool);
1430 LOAD_FUNCPTR(FcPatternGetInteger);
1431 LOAD_FUNCPTR(FcPatternGetString);
1432 LOAD_FUNCPTR(FcConfigGetFontDirs);
1433 LOAD_FUNCPTR(FcConfigGetCurrent);
1434 LOAD_FUNCPTR(FcCacheCopySet);
1435 LOAD_FUNCPTR(FcCacheNumSubdir);
1436 LOAD_FUNCPTR(FcCacheSubdir);
1437 LOAD_FUNCPTR(FcDirCacheRead);
1438 LOAD_FUNCPTR(FcDirCacheUnload);
1439 LOAD_FUNCPTR(FcStrListCreate);
1440 LOAD_FUNCPTR(FcStrListDone);
1441 LOAD_FUNCPTR(FcStrListNext);
1442 LOAD_FUNCPTR(FcStrSetAdd);
1443 LOAD_FUNCPTR(FcStrSetCreate);
1444 LOAD_FUNCPTR(FcStrSetDestroy);
1445 LOAD_FUNCPTR(FcStrSetMember);
1446 #undef LOAD_FUNCPTR
1448 if (pFcInit())
1450 FcPattern *pattern = pFcPatternCreate();
1451 pFcConfigSubstitute( NULL, pattern, FcMatchFont );
1452 default_aa_flags = parse_aa_pattern( pattern );
1453 pFcPatternDestroy( pattern );
1455 if (!default_aa_flags)
1457 FcPattern *pattern = pFcPatternCreate();
1458 pFcConfigSubstitute( NULL, pattern, FcMatchPattern );
1459 default_aa_flags = parse_aa_pattern( pattern );
1460 pFcPatternDestroy( pattern );
1463 TRACE( "enabled, default flags = %x\n", default_aa_flags );
1464 fontconfig_enabled = TRUE;
1468 static void fontconfig_add_fonts_from_dir_list( FcConfig *config, FcStrList *dir_list, FcStrSet *done_set, DWORD flags )
1470 const FcChar8 *dir;
1471 FcFontSet *font_set;
1472 FcStrList *subdir_list = NULL;
1473 FcStrSet *subdir_set = NULL;
1474 FcCache *cache = NULL;
1475 int i;
1477 TRACE( "(%p %p %p %#x)\n", config, dir_list, done_set, flags );
1479 while ((dir = pFcStrListNext( dir_list )))
1481 if (pFcStrSetMember( done_set, dir )) continue;
1483 TRACE( "adding fonts from %s\n", dir );
1484 if (!(cache = pFcDirCacheRead( dir, FcFalse, config ))) continue;
1486 if (!(font_set = pFcCacheCopySet( cache ))) goto done;
1487 for (i = 0; i < font_set->nfont; i++)
1488 fontconfig_add_font( font_set->fonts[i], flags );
1489 pFcFontSetDestroy( font_set );
1490 font_set = NULL;
1492 if (!(subdir_set = pFcStrSetCreate())) goto done;
1493 for (i = 0; i < pFcCacheNumSubdir( cache ); i++)
1494 pFcStrSetAdd( subdir_set, pFcCacheSubdir( cache, i ) );
1495 pFcDirCacheUnload( cache );
1496 cache = NULL;
1498 if (!(subdir_list = pFcStrListCreate( subdir_set ))) goto done;
1499 pFcStrSetDestroy( subdir_set );
1500 subdir_set = NULL;
1502 pFcStrSetAdd( done_set, dir );
1503 fontconfig_add_fonts_from_dir_list( config, subdir_list, done_set, flags );
1504 pFcStrListDone( subdir_list );
1505 subdir_list = NULL;
1508 done:
1509 if (font_set) pFcFontSetDestroy( font_set );
1510 if (subdir_list) pFcStrListDone( subdir_list );
1511 if (subdir_set) pFcStrSetDestroy( subdir_set );
1512 if (cache) pFcDirCacheUnload( cache );
1515 static void load_fontconfig_fonts( void )
1517 FcStrList *dir_list = NULL;
1518 FcStrSet *done_set = NULL;
1519 FcConfig *config;
1521 if (!fontconfig_enabled) return;
1522 if (!(config = pFcConfigGetCurrent())) goto done;
1523 if (!(done_set = pFcStrSetCreate())) goto done;
1524 if (!(dir_list = pFcConfigGetFontDirs( config ))) goto done;
1526 fontconfig_add_fonts_from_dir_list( config, dir_list, done_set, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE );
1528 done:
1529 if (dir_list) pFcStrListDone( dir_list );
1530 if (done_set) pFcStrSetDestroy( done_set );
1533 #elif defined(HAVE_CARBON_CARBON_H)
1535 static void load_mac_font_callback(const void *value, void *context)
1537 CFStringRef pathStr = value;
1538 CFIndex len;
1539 char* path;
1541 len = CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr);
1542 path = RtlAllocateHeap(GetProcessHeap(), 0, len);
1543 if (path && CFStringGetFileSystemRepresentation(pathStr, path, len))
1545 TRACE("font file %s\n", path);
1546 AddFontToList(NULL, path, NULL, 0, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
1548 RtlFreeHeap(GetProcessHeap(), 0, path);
1551 static void load_mac_fonts(void)
1553 CFStringRef removeDupesKey;
1554 CFBooleanRef removeDupesValue;
1555 CFDictionaryRef options;
1556 CTFontCollectionRef col;
1557 CFArrayRef descs;
1558 CFMutableSetRef paths;
1559 CFIndex i;
1561 removeDupesKey = kCTFontCollectionRemoveDuplicatesOption;
1562 removeDupesValue = kCFBooleanTrue;
1563 options = CFDictionaryCreate(NULL, (const void**)&removeDupesKey, (const void**)&removeDupesValue, 1,
1564 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1565 col = CTFontCollectionCreateFromAvailableFonts(options);
1566 if (options) CFRelease(options);
1567 if (!col)
1569 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
1570 return;
1573 descs = CTFontCollectionCreateMatchingFontDescriptors(col);
1574 CFRelease(col);
1575 if (!descs)
1577 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
1578 return;
1581 paths = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
1582 if (!paths)
1584 WARN("CFSetCreateMutable failed\n");
1585 CFRelease(descs);
1586 return;
1589 for (i = 0; i < CFArrayGetCount(descs); i++)
1591 CTFontDescriptorRef desc;
1592 CFURLRef url;
1593 CFStringRef ext;
1594 CFStringRef path;
1596 desc = CFArrayGetValueAtIndex(descs, i);
1598 #if defined(MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
1599 url = CTFontDescriptorCopyAttribute(desc, kCTFontURLAttribute);
1600 #else
1601 /* CTFontDescriptor doesn't support kCTFontURLAttribute prior to 10.6, so
1602 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
1604 CTFontRef font;
1605 ATSFontRef atsFont;
1606 OSStatus status;
1607 FSRef fsref;
1609 font = CTFontCreateWithFontDescriptor(desc, 0, NULL);
1610 if (!font) continue;
1612 atsFont = CTFontGetPlatformFont(font, NULL);
1613 if (!atsFont)
1615 CFRelease(font);
1616 continue;
1619 status = ATSFontGetFileReference(atsFont, &fsref);
1620 CFRelease(font);
1621 if (status != noErr) continue;
1623 url = CFURLCreateFromFSRef(NULL, &fsref);
1625 #endif
1626 if (!url) continue;
1628 ext = CFURLCopyPathExtension(url);
1629 if (ext)
1631 BOOL skip = (CFStringCompare(ext, CFSTR("pfa"), kCFCompareCaseInsensitive) == kCFCompareEqualTo ||
1632 CFStringCompare(ext, CFSTR("pfb"), kCFCompareCaseInsensitive) == kCFCompareEqualTo);
1633 CFRelease(ext);
1634 if (skip)
1636 CFRelease(url);
1637 continue;
1641 path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
1642 CFRelease(url);
1643 if (!path) continue;
1645 CFSetAddValue(paths, path);
1646 CFRelease(path);
1649 CFRelease(descs);
1651 CFSetApplyFunction(paths, load_mac_font_callback, NULL);
1652 CFRelease(paths);
1655 #endif
1658 static BOOL init_freetype(void)
1660 ft_handle = dlopen(SONAME_LIBFREETYPE, RTLD_NOW);
1661 if(!ft_handle) {
1662 WINE_MESSAGE(
1663 "Wine cannot find the FreeType font library. To enable Wine to\n"
1664 "use TrueType fonts please install a version of FreeType greater than\n"
1665 "or equal to 2.0.5.\n"
1666 "http://www.freetype.org\n");
1667 return FALSE;
1670 #define LOAD_FUNCPTR(f) if((p##f = dlsym(ft_handle, #f)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
1672 LOAD_FUNCPTR(FT_Done_Face)
1673 LOAD_FUNCPTR(FT_Get_Char_Index)
1674 LOAD_FUNCPTR(FT_Get_First_Char)
1675 LOAD_FUNCPTR(FT_Get_Next_Char)
1676 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
1677 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
1678 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
1679 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
1680 LOAD_FUNCPTR(FT_Init_FreeType)
1681 LOAD_FUNCPTR(FT_Library_Version)
1682 LOAD_FUNCPTR(FT_Load_Glyph)
1683 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
1684 LOAD_FUNCPTR(FT_Matrix_Multiply)
1685 LOAD_FUNCPTR(FT_MulDiv)
1686 #ifndef FT_MULFIX_INLINED
1687 LOAD_FUNCPTR(FT_MulFix)
1688 #endif
1689 LOAD_FUNCPTR(FT_New_Face)
1690 LOAD_FUNCPTR(FT_New_Memory_Face)
1691 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
1692 LOAD_FUNCPTR(FT_Outline_Get_CBox)
1693 LOAD_FUNCPTR(FT_Outline_Transform)
1694 LOAD_FUNCPTR(FT_Outline_Translate)
1695 LOAD_FUNCPTR(FT_Render_Glyph)
1696 LOAD_FUNCPTR(FT_Set_Charmap)
1697 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
1698 LOAD_FUNCPTR(FT_Vector_Length)
1699 LOAD_FUNCPTR(FT_Vector_Transform)
1700 LOAD_FUNCPTR(FT_Vector_Unit)
1701 #undef LOAD_FUNCPTR
1702 /* Don't warn if these ones are missing */
1703 pFT_Outline_Embolden = dlsym(ft_handle, "FT_Outline_Embolden");
1704 pFT_Get_TrueType_Engine_Type = dlsym(ft_handle, "FT_Get_TrueType_Engine_Type");
1705 #ifdef FT_LCD_FILTER_H
1706 pFT_Library_SetLcdFilter = dlsym(ft_handle, "FT_Library_SetLcdFilter");
1707 #endif
1708 pFT_Property_Set = dlsym(ft_handle, "FT_Property_Set");
1710 if(pFT_Init_FreeType(&library) != 0) {
1711 ERR("Can't init FreeType library\n");
1712 dlclose(ft_handle);
1713 ft_handle = NULL;
1714 return FALSE;
1716 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
1718 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
1719 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
1720 ((FT_Version.minor << 8) & 0x00ff00) |
1721 ((FT_Version.patch ) & 0x0000ff);
1723 /* In FreeType < 2.8.1 v40's FT_LOAD_TARGET_MONO has broken advance widths. */
1724 if (pFT_Property_Set && FT_SimpleVersion < FT_VERSION_VALUE(2, 8, 1))
1726 FT_UInt interpreter_version = 35;
1727 pFT_Property_Set( library, "truetype", "interpreter-version", &interpreter_version );
1730 return TRUE;
1732 sym_not_found:
1733 WINE_MESSAGE(
1734 "Wine cannot find certain functions that it needs inside the FreeType\n"
1735 "font library. To enable Wine to use TrueType fonts please upgrade\n"
1736 "FreeType to at least version 2.1.4.\n"
1737 "http://www.freetype.org\n");
1738 dlclose(ft_handle);
1739 ft_handle = NULL;
1740 return FALSE;
1743 /*************************************************************
1744 * freetype_load_fonts
1746 static void CDECL freetype_load_fonts(void)
1748 #ifdef SONAME_LIBFONTCONFIG
1749 load_fontconfig_fonts();
1750 #elif defined(HAVE_CARBON_CARBON_H)
1751 load_mac_fonts();
1752 #elif defined(__ANDROID__)
1753 ReadFontDir("/system/fonts", TRUE);
1754 #endif
1757 /* Some fonts have large usWinDescent values, as a result of storing signed short
1758 in unsigned field. That's probably caused by sTypoDescent vs usWinDescent confusion in
1759 some font generation tools. */
1760 static inline USHORT get_fixed_windescent(USHORT windescent)
1762 return abs((SHORT)windescent);
1765 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
1767 TT_OS2 *pOS2;
1768 TT_HoriHeader *pHori;
1770 LONG ppem;
1771 const LONG MAX_PPEM = (1 << 16) - 1;
1773 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1774 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1776 if(height == 0) height = 16;
1778 /* Calc. height of EM square:
1780 * For +ve lfHeight we have
1781 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
1782 * Re-arranging gives:
1783 * ppem = units_per_em * lfheight / (winAscent + winDescent)
1785 * For -ve lfHeight we have
1786 * |lfHeight| = ppem
1787 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
1788 * with il = winAscent + winDescent - units_per_em]
1792 if(height > 0) {
1793 USHORT windescent = get_fixed_windescent(pOS2->usWinDescent);
1794 if(pOS2->usWinAscent + windescent == 0)
1795 ppem = pFT_MulDiv(ft_face->units_per_EM, height, pHori->Ascender - pHori->Descender);
1796 else
1797 ppem = pFT_MulDiv(ft_face->units_per_EM, height, pOS2->usWinAscent + windescent);
1798 if(ppem > MAX_PPEM) {
1799 WARN("Ignoring too large height %d, ppem %d\n", height, ppem);
1800 ppem = 1;
1803 else if(height >= -MAX_PPEM)
1804 ppem = -height;
1805 else {
1806 WARN("Ignoring too large height %d\n", height);
1807 ppem = 1;
1810 return ppem;
1813 static struct font_mapping *map_font_file( const char *name )
1815 struct font_mapping *mapping;
1816 struct stat st;
1817 int fd;
1819 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
1820 if (fstat( fd, &st ) == -1) goto error;
1822 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
1824 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
1826 mapping->refcount++;
1827 close( fd );
1828 return mapping;
1831 if (!(mapping = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*mapping) )))
1832 goto error;
1834 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
1835 close( fd );
1837 if (mapping->data == MAP_FAILED)
1839 RtlFreeHeap( GetProcessHeap(), 0, mapping );
1840 return NULL;
1842 mapping->refcount = 1;
1843 mapping->dev = st.st_dev;
1844 mapping->ino = st.st_ino;
1845 mapping->size = st.st_size;
1846 list_add_tail( &mappings_list, &mapping->entry );
1847 return mapping;
1849 error:
1850 close( fd );
1851 return NULL;
1854 static void unmap_font_file( struct font_mapping *mapping )
1856 if (!--mapping->refcount)
1858 list_remove( &mapping->entry );
1859 munmap( mapping->data, mapping->size );
1860 RtlFreeHeap( GetProcessHeap(), 0, mapping );
1864 static LONG load_VDMX(struct gdi_font *font, LONG height);
1866 /*************************************************************
1867 * freetype_destroy_font
1869 static void CDECL freetype_destroy_font( struct gdi_font *font )
1871 struct font_private_data *data = font->private;
1873 if (data->ft_face) pFT_Done_Face( data->ft_face );
1874 if (data->mapping) unmap_font_file( data->mapping );
1875 RtlFreeHeap( GetProcessHeap(), 0, data );
1878 /*************************************************************
1879 * freetype_get_font_data
1881 static DWORD CDECL freetype_get_font_data( struct gdi_font *font, DWORD table, DWORD offset,
1882 void *buf, DWORD cbData)
1884 FT_Face ft_face = get_ft_face( font );
1885 FT_ULong len;
1886 FT_Error err;
1888 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
1890 if(!buf)
1891 len = 0;
1892 else
1893 len = cbData;
1895 /* if font is a member of TTC, 'ttcf' tag allows reading from beginning of TTC file,
1896 0 tag means to read from start of collection member data. */
1897 if (font->ttc_item_offset)
1899 if (table == MS_TTCF_TAG)
1900 table = 0;
1901 else if (table == 0)
1902 offset += font->ttc_item_offset;
1905 /* make sure value of len is the value freetype says it needs */
1906 if (buf && len)
1908 FT_ULong needed = 0;
1909 err = pFT_Load_Sfnt_Table(ft_face, RtlUlongByteSwap(table), offset, NULL, &needed);
1910 if( !err && needed < len) len = needed;
1912 err = pFT_Load_Sfnt_Table(ft_face, RtlUlongByteSwap(table), offset, buf, &len);
1913 if (err)
1915 TRACE("Can't find table %s\n", debugstr_an((char*)&table, 4));
1916 return GDI_ERROR;
1918 return len;
1921 /*************************************************************
1922 * load_VDMX
1924 * load the vdmx entry for the specified height
1929 typedef struct {
1930 WORD version;
1931 WORD numRecs;
1932 WORD numRatios;
1933 } VDMX_Header;
1935 typedef struct {
1936 BYTE bCharSet;
1937 BYTE xRatio;
1938 BYTE yStartRatio;
1939 BYTE yEndRatio;
1940 } Ratios;
1942 typedef struct {
1943 WORD recs;
1944 BYTE startsz;
1945 BYTE endsz;
1946 } VDMX_group;
1948 typedef struct {
1949 WORD yPelHeight;
1950 WORD yMax;
1951 WORD yMin;
1952 } VDMX_vTable;
1954 static LONG load_VDMX(struct gdi_font *font, LONG height)
1956 VDMX_Header hdr;
1957 VDMX_group group;
1958 BYTE devXRatio, devYRatio;
1959 USHORT numRecs, numRatios;
1960 DWORD result, offset = -1;
1961 LONG ppem = 0;
1962 int i;
1964 result = freetype_get_font_data(font, MS_VDMX_TAG, 0, &hdr, sizeof(hdr));
1966 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
1967 return ppem;
1969 /* FIXME: need the real device aspect ratio */
1970 devXRatio = 1;
1971 devYRatio = 1;
1973 numRecs = GET_BE_WORD(hdr.numRecs);
1974 numRatios = GET_BE_WORD(hdr.numRatios);
1976 TRACE("version = %d numRecs = %d numRatios = %d\n", GET_BE_WORD(hdr.version), numRecs, numRatios);
1977 for(i = 0; i < numRatios; i++) {
1978 Ratios ratio;
1980 offset = sizeof(hdr) + (i * sizeof(Ratios));
1981 freetype_get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
1982 offset = -1;
1984 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
1986 if (!ratio.bCharSet) continue;
1988 if((ratio.xRatio == 0 &&
1989 ratio.yStartRatio == 0 &&
1990 ratio.yEndRatio == 0) ||
1991 (devXRatio == ratio.xRatio &&
1992 devYRatio >= ratio.yStartRatio &&
1993 devYRatio <= ratio.yEndRatio))
1995 WORD group_offset;
1997 offset = sizeof(hdr) + numRatios * sizeof(ratio) + i * sizeof(group_offset);
1998 freetype_get_font_data(font, MS_VDMX_TAG, offset, &group_offset, sizeof(group_offset));
1999 offset = GET_BE_WORD(group_offset);
2000 break;
2004 if(offset == -1) return 0;
2006 if(freetype_get_font_data(font, MS_VDMX_TAG, offset, &group, sizeof(group)) != GDI_ERROR) {
2007 USHORT recs;
2008 BYTE startsz, endsz;
2009 WORD *vTable;
2011 recs = GET_BE_WORD(group.recs);
2012 startsz = group.startsz;
2013 endsz = group.endsz;
2015 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
2017 vTable = RtlAllocateHeap(GetProcessHeap(), 0, recs * sizeof(VDMX_vTable));
2018 result = freetype_get_font_data(font, MS_VDMX_TAG, offset + sizeof(group), vTable, recs * sizeof(VDMX_vTable));
2019 if(result == GDI_ERROR) {
2020 FIXME("Failed to retrieve vTable\n");
2021 goto end;
2024 if(height > 0) {
2025 for(i = 0; i < recs; i++) {
2026 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2027 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2028 ppem = GET_BE_WORD(vTable[i * 3]);
2030 if(yMax + -yMin == height) {
2031 font->yMax = yMax;
2032 font->yMin = yMin;
2033 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2034 break;
2036 if(yMax + -yMin > height) {
2037 if(--i < 0) {
2038 ppem = 0;
2039 goto end; /* failed */
2041 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2042 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2043 ppem = GET_BE_WORD(vTable[i * 3]);
2044 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2045 break;
2048 if(!font->yMax) {
2049 ppem = 0;
2050 TRACE("ppem not found for height %d\n", height);
2052 } else {
2053 ppem = -height;
2054 if(ppem < startsz || ppem > endsz)
2056 ppem = 0;
2057 goto end;
2060 for(i = 0; i < recs; i++) {
2061 USHORT yPelHeight;
2062 yPelHeight = GET_BE_WORD(vTable[i * 3]);
2064 if(yPelHeight > ppem)
2066 ppem = 0;
2067 break; /* failed */
2070 if(yPelHeight == ppem) {
2071 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2072 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2073 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
2074 break;
2078 end:
2079 RtlFreeHeap(GetProcessHeap(), 0, vTable);
2082 return ppem;
2085 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
2087 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
2088 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
2089 FT_Int i;
2091 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
2093 for (i = 0; i < ft_face->num_charmaps; i++)
2095 if (ft_face->charmaps[i]->encoding == encoding)
2097 TRACE("found cmap with platform_id %u, encoding_id %u\n",
2098 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
2100 switch (ft_face->charmaps[i]->platform_id)
2102 default:
2103 cmap_def = ft_face->charmaps[i];
2104 break;
2105 case 0: /* Apple Unicode */
2106 cmap0 = ft_face->charmaps[i];
2107 break;
2108 case 1: /* Macintosh */
2109 cmap1 = ft_face->charmaps[i];
2110 break;
2111 case 2: /* ISO */
2112 cmap2 = ft_face->charmaps[i];
2113 break;
2114 case 3: /* Microsoft */
2115 cmap3 = ft_face->charmaps[i];
2116 break;
2120 if (cmap3) /* prefer Microsoft cmap table */
2121 ft_err = pFT_Set_Charmap(ft_face, cmap3);
2122 else if (cmap1)
2123 ft_err = pFT_Set_Charmap(ft_face, cmap1);
2124 else if (cmap2)
2125 ft_err = pFT_Set_Charmap(ft_face, cmap2);
2126 else if (cmap0)
2127 ft_err = pFT_Set_Charmap(ft_face, cmap0);
2128 else if (cmap_def)
2129 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
2132 return ft_err == FT_Err_Ok;
2136 static FT_Encoding pick_charmap( FT_Face face, int charset )
2138 static const FT_Encoding regular_order[] = { FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, FT_ENCODING_MS_SYMBOL, 0 };
2139 static const FT_Encoding symbol_order[] = { FT_ENCODING_MS_SYMBOL, FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, 0 };
2140 const FT_Encoding *encs = regular_order;
2142 if (charset == SYMBOL_CHARSET) encs = symbol_order;
2144 while (*encs != 0)
2146 if (select_charmap( face, *encs )) break;
2147 encs++;
2150 if (!face->charmap && face->num_charmaps)
2152 if (!pFT_Set_Charmap(face, face->charmaps[0]))
2153 return face->charmap->encoding;
2156 return *encs;
2159 static BOOL get_gasp_flags( struct gdi_font *font, WORD *flags )
2161 FT_Face ft_face = get_ft_face( font );
2162 DWORD size;
2163 WORD buf[16]; /* Enough for seven ranges before we need to alloc */
2164 WORD *alloced = NULL, *ptr = buf;
2165 WORD num_recs, version;
2166 BOOL ret = FALSE;
2168 *flags = 0;
2169 size = freetype_get_font_data( font, MS_GASP_TAG, 0, NULL, 0 );
2170 if (size == GDI_ERROR) return FALSE;
2171 if (size < 4 * sizeof(WORD)) return FALSE;
2172 if (size > sizeof(buf))
2174 ptr = alloced = RtlAllocateHeap( GetProcessHeap(), 0, size );
2175 if (!ptr) return FALSE;
2178 freetype_get_font_data( font, MS_GASP_TAG, 0, ptr, size );
2180 version = GET_BE_WORD( *ptr++ );
2181 num_recs = GET_BE_WORD( *ptr++ );
2183 if (version > 1 || size < (num_recs * 2 + 2) * sizeof(WORD))
2185 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version, size, num_recs );
2186 goto done;
2189 while (num_recs--)
2191 *flags = GET_BE_WORD( *(ptr + 1) );
2192 if (ft_face->size->metrics.y_ppem <= GET_BE_WORD( *ptr )) break;
2193 ptr += 2;
2195 TRACE( "got flags %04x for ppem %d\n", *flags, ft_face->size->metrics.y_ppem );
2196 ret = TRUE;
2198 done:
2199 RtlFreeHeap( GetProcessHeap(), 0, alloced );
2200 return ret;
2203 /*************************************************************
2204 * fontconfig_enum_family_fallbacks
2206 static BOOL CDECL fontconfig_enum_family_fallbacks( DWORD pitch_and_family, int index,
2207 WCHAR buffer[LF_FACESIZE] )
2209 #ifdef SONAME_LIBFONTCONFIG
2210 FcPattern *pat;
2211 char *str;
2212 DWORD len;
2214 if ((pitch_and_family & FIXED_PITCH) || (pitch_and_family & 0xf0) == FF_MODERN) pat = create_family_pattern( "monospace", &pattern_fixed );
2215 else if ((pitch_and_family & 0xf0) == FF_ROMAN) pat = create_family_pattern( "serif", &pattern_serif );
2216 else pat = create_family_pattern( "sans", &pattern_sans );
2218 if (!pat) return FALSE;
2219 if (pFcPatternGetString( pat, FC_FAMILY, index, (FcChar8 **)&str ) != FcResultMatch) return FALSE;
2220 RtlUTF8ToUnicodeN( buffer, (LF_FACESIZE - 1) * sizeof(WCHAR), &len, str, strlen(str) );
2221 buffer[len / sizeof(WCHAR)] = 0;
2222 return TRUE;
2223 #endif
2224 return FALSE;
2227 static DWORD get_ttc_offset( FT_Face ft_face, UINT face_index )
2229 FT_ULong len;
2230 DWORD header, offset;
2232 /* see if it's a TTC */
2233 len = sizeof(header);
2234 if (pFT_Load_Sfnt_Table( ft_face, 0, 0, (void *)&header, &len )) return 0;
2235 if (header != MS_TTCF_TAG) return 0;
2237 len = sizeof(offset);
2238 if (pFT_Load_Sfnt_Table( ft_face, 0, (3 + face_index) * sizeof(DWORD), (void *)&offset, &len ))
2239 return 0;
2241 return GET_BE_DWORD( offset );
2244 /*************************************************************
2245 * freetype_load_font
2247 static BOOL CDECL freetype_load_font( struct gdi_font *font )
2249 struct font_private_data *data;
2250 INT width = 0, height;
2251 FT_Face ft_face;
2252 void *data_ptr;
2253 SIZE_T data_size;
2255 if (!(data = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data) ))) return FALSE;
2256 font->private = data;
2258 if (font->file[0])
2260 char *filename = get_unix_file_name( font->file );
2261 data->mapping = map_font_file( filename );
2262 RtlFreeHeap( GetProcessHeap(), 0, filename );
2263 if (!data->mapping)
2265 WARN("failed to map %s\n", debugstr_w(font->file));
2266 return FALSE;
2268 data_ptr = data->mapping->data;
2269 data_size = data->mapping->size;
2271 else
2273 data_ptr = font->data_ptr;
2274 data_size = font->data_size;
2277 if (pFT_New_Memory_Face( library, data_ptr, data_size, font->face_index, &ft_face )) return FALSE;
2279 data->ft_face = ft_face;
2280 font->scalable = FT_IS_SCALABLE( ft_face );
2281 if (!font->fs.fsCsb[0]) get_fontsig( ft_face, &font->fs );
2282 if (!font->ntmFlags) font->ntmFlags = get_ntm_flags( ft_face );
2283 if (!font->aa_flags) font->aa_flags = ADDFONT_AA_FLAGS( default_aa_flags );
2284 if (!font->otm.otmpFamilyName)
2286 font->otm.otmpFamilyName = (char *)ft_face_get_family_name( ft_face, system_lcid );
2287 font->otm.otmpStyleName = (char *)ft_face_get_style_name( ft_face, system_lcid );
2288 font->otm.otmpFaceName = (char *)ft_face_get_full_name( ft_face, system_lcid );
2291 if (font->scalable)
2293 /* load the VDMX table if we have one */
2294 font->ppem = load_VDMX( font, font->lf.lfHeight );
2295 if (font->ppem == 0) font->ppem = calc_ppem_for_height( ft_face, font->lf.lfHeight );
2296 TRACE( "height %d => ppem %d\n", font->lf.lfHeight, font->ppem );
2297 height = font->ppem;
2298 font->ttc_item_offset = get_ttc_offset( ft_face, font->face_index );
2300 else
2302 struct bitmap_font_size size;
2304 get_bitmap_size( ft_face, &size );
2305 width = size.x_ppem >> 6;
2306 height = size.y_ppem >> 6;
2307 font->ppem = height;
2310 pFT_Set_Pixel_Sizes( ft_face, width, height );
2311 pick_charmap( ft_face, font->charset );
2312 return TRUE;
2316 /*************************************************************
2317 * freetype_get_aa_flags
2319 static UINT CDECL freetype_get_aa_flags( struct gdi_font *font, UINT aa_flags, BOOL antialias_fakes )
2321 /* fixup the antialiasing flags for that font */
2322 switch (aa_flags)
2324 case WINE_GGO_HRGB_BITMAP:
2325 case WINE_GGO_HBGR_BITMAP:
2326 case WINE_GGO_VRGB_BITMAP:
2327 case WINE_GGO_VBGR_BITMAP:
2328 if (is_subpixel_rendering_enabled()) break;
2329 aa_flags = GGO_GRAY4_BITMAP;
2330 /* fall through */
2331 case GGO_GRAY2_BITMAP:
2332 case GGO_GRAY4_BITMAP:
2333 case GGO_GRAY8_BITMAP:
2334 case WINE_GGO_GRAY16_BITMAP:
2335 if ((!antialias_fakes || (!font->fake_bold && !font->fake_italic)) && is_hinting_enabled())
2337 WORD gasp_flags;
2338 if (get_gasp_flags( font, &gasp_flags ) && !(gasp_flags & GASP_DOGRAY))
2340 TRACE( "font %s %d aa disabled by GASP\n",
2341 debugstr_w(font->lf.lfFaceName), font->lf.lfHeight );
2342 aa_flags = GGO_BITMAP;
2346 return aa_flags;
2349 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
2351 pt->x.value = vec->x >> 6;
2352 pt->x.fract = (vec->x & 0x3f) << 10;
2353 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
2354 pt->y.value = vec->y >> 6;
2355 pt->y.fract = (vec->y & 0x3f) << 10;
2356 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
2359 static FT_UInt get_glyph_index_symbol( struct gdi_font *font, UINT glyph )
2361 FT_Face ft_face = get_ft_face( font );
2362 FT_UInt ret;
2364 if (glyph < 0x100) glyph += 0xf000;
2365 /* there are a number of old pre-Unicode "broken" TTFs, which
2366 do have symbols at U+00XX instead of U+f0XX */
2367 if (!(ret = pFT_Get_Char_Index(ft_face, glyph)))
2368 ret = pFT_Get_Char_Index(ft_face, glyph - 0xf000);
2370 return ret;
2373 /*************************************************************
2374 * freetype_get_glyph_index
2376 static BOOL CDECL freetype_get_glyph_index( struct gdi_font *font, UINT *glyph, BOOL use_encoding )
2378 FT_Face ft_face = get_ft_face( font );
2380 if (!use_encoding ^ (ft_face->charmap->encoding == FT_ENCODING_NONE)) return FALSE;
2382 if (ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
2384 if (!(*glyph = get_glyph_index_symbol( font, *glyph )))
2386 WCHAR wc = *glyph;
2387 DWORD len;
2388 char ch;
2390 RtlUnicodeToMultiByteN( &ch, 1, &len, &wc, sizeof(wc) );
2391 if (len) *glyph = get_glyph_index_symbol( font, (unsigned char)ch );
2393 return TRUE;
2395 *glyph = pFT_Get_Char_Index( ft_face, *glyph );
2396 return TRUE;
2399 /*************************************************************
2400 * freetype_get_default_glyph
2402 static UINT CDECL freetype_get_default_glyph( struct gdi_font *font )
2404 FT_Face ft_face = get_ft_face( font );
2405 FT_WinFNT_HeaderRec winfnt;
2406 TT_OS2 *pOS2;
2408 if ((pOS2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 )))
2410 UINT glyph = pOS2->usDefaultChar;
2411 freetype_get_glyph_index( font, &glyph, TRUE );
2412 return glyph;
2414 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt )) return winfnt.default_char + winfnt.first_char;
2415 return 32;
2419 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
2421 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
2422 return !memcmp(matrix, &identity, sizeof(FMAT2));
2425 static inline FT_Vector normalize_vector(FT_Vector *vec)
2427 FT_Vector out;
2428 FT_Fixed len;
2429 len = pFT_Vector_Length(vec);
2430 if (len) {
2431 out.x = (vec->x << 6) / len;
2432 out.y = (vec->y << 6) / len;
2434 else
2435 out.x = out.y = 0;
2436 return out;
2439 /* get_glyph_outline() glyph transform matrices index */
2440 enum matrices_index
2442 matrix_hori,
2443 matrix_vert,
2444 matrix_unrotated
2447 static BOOL get_transform_matrices( struct gdi_font *font, BOOL vertical, const MAT2 *user_transform,
2448 FT_Matrix matrices[3] )
2450 static const FT_Matrix identity_mat = { (1 << 16), 0, 0, (1 << 16) };
2451 BOOL needs_transform = FALSE;
2452 double width_ratio;
2453 int i;
2455 matrices[matrix_unrotated] = identity_mat;
2457 /* Scaling factor */
2458 if (font->aveWidth)
2460 if (!freetype_set_outline_text_metrics( font )) freetype_set_bitmap_text_metrics( font );
2461 width_ratio = (double)font->aveWidth;
2462 width_ratio /= (double)font->otm.otmTextMetrics.tmAveCharWidth;
2464 else
2465 width_ratio = font->scale_y;
2467 /* Scaling transform */
2468 if (width_ratio != 1.0 || font->scale_y != 1)
2470 FT_Matrix scale_mat;
2471 scale_mat.xx = FT_FixedFromFloat( width_ratio );
2472 scale_mat.xy = 0;
2473 scale_mat.yx = 0;
2474 scale_mat.yy = font->scale_y << 16;
2476 pFT_Matrix_Multiply( &scale_mat, &matrices[matrix_unrotated] );
2477 needs_transform = TRUE;
2480 /* Slant transform */
2481 if (font->fake_italic)
2483 FT_Matrix slant_mat;
2484 slant_mat.xx = (1 << 16);
2485 slant_mat.xy = (1 << 16) >> 2;
2486 slant_mat.yx = 0;
2487 slant_mat.yy = (1 << 16);
2489 pFT_Matrix_Multiply( &slant_mat, &matrices[matrix_unrotated] );
2490 needs_transform = TRUE;
2493 /* Rotation transform */
2494 matrices[matrix_hori] = matrices[matrix_unrotated];
2495 if (font->scalable && font->lf.lfOrientation % 3600)
2497 FT_Matrix rotation_mat;
2498 FT_Vector angle;
2500 pFT_Vector_Unit( &angle, pFT_MulDiv( 1 << 16, font->lf.lfOrientation, 10 ) );
2501 rotation_mat.xx = angle.x;
2502 rotation_mat.xy = -angle.y;
2503 rotation_mat.yx = angle.y;
2504 rotation_mat.yy = angle.x;
2505 pFT_Matrix_Multiply( &rotation_mat, &matrices[matrix_hori] );
2506 needs_transform = TRUE;
2509 /* Vertical transform */
2510 matrices[matrix_vert] = matrices[matrix_hori];
2511 if (vertical)
2513 FT_Matrix vertical_mat = { 0, -(1 << 16), 1 << 16, 0 }; /* 90 degrees rotation */
2515 pFT_Matrix_Multiply( &vertical_mat, &matrices[matrix_vert] );
2516 needs_transform = TRUE;
2519 /* World transform */
2520 if (!is_identity_FMAT2( &font->matrix ))
2522 FT_Matrix world_mat;
2523 world_mat.xx = FT_FixedFromFloat( font->matrix.eM11 );
2524 world_mat.xy = -FT_FixedFromFloat( font->matrix.eM21 );
2525 world_mat.yx = -FT_FixedFromFloat( font->matrix.eM12 );
2526 world_mat.yy = FT_FixedFromFloat( font->matrix.eM22 );
2528 for (i = 0; i < 3; i++)
2529 pFT_Matrix_Multiply( &world_mat, &matrices[i] );
2530 needs_transform = TRUE;
2533 /* Extra transformation specified by caller */
2534 if (user_transform)
2536 FT_Matrix user_mat;
2537 user_mat.xx = FT_FixedFromFIXED( user_transform->eM11 );
2538 user_mat.xy = FT_FixedFromFIXED( user_transform->eM21 );
2539 user_mat.yx = FT_FixedFromFIXED( user_transform->eM12 );
2540 user_mat.yy = FT_FixedFromFIXED( user_transform->eM22 );
2542 for (i = 0; i < 3; i++)
2543 pFT_Matrix_Multiply( &user_mat, &matrices[i] );
2544 needs_transform = TRUE;
2547 return needs_transform;
2550 static BOOL get_bold_glyph_outline(FT_GlyphSlot glyph, LONG ppem, FT_Glyph_Metrics *metrics)
2552 FT_Error err;
2553 FT_Pos strength;
2554 FT_BBox bbox;
2556 if(glyph->format != FT_GLYPH_FORMAT_OUTLINE)
2557 return FALSE;
2558 if(!pFT_Outline_Embolden)
2559 return FALSE;
2561 strength = pFT_MulDiv(ppem, 1 << 6, 24);
2562 err = pFT_Outline_Embolden(&glyph->outline, strength);
2563 if(err) {
2564 TRACE("FT_Ouline_Embolden returns %d\n", err);
2565 return FALSE;
2568 pFT_Outline_Get_CBox(&glyph->outline, &bbox);
2569 metrics->width = bbox.xMax - bbox.xMin;
2570 metrics->height = bbox.yMax - bbox.yMin;
2571 metrics->horiBearingX = bbox.xMin;
2572 metrics->horiBearingY = bbox.yMax;
2573 metrics->vertBearingX = metrics->horiBearingX - metrics->horiAdvance / 2;
2574 metrics->vertBearingY = (metrics->vertAdvance - metrics->height) / 2;
2575 return TRUE;
2578 static inline BYTE get_max_level( UINT format )
2580 switch( format )
2582 case GGO_GRAY2_BITMAP: return 4;
2583 case GGO_GRAY4_BITMAP: return 16;
2584 case GGO_GRAY8_BITMAP: return 64;
2586 return 255;
2589 static FT_Vector get_advance_metric(struct gdi_font *incoming_font, struct gdi_font *font,
2590 const FT_Glyph_Metrics *metrics,
2591 const FT_Matrix *transMat, BOOL vertical_metrics)
2593 FT_Vector adv;
2594 FT_Fixed base_advance, em_scale = 0;
2595 BOOL fixed_pitch_full = FALSE;
2597 if (vertical_metrics)
2598 base_advance = metrics->vertAdvance;
2599 else
2600 base_advance = metrics->horiAdvance;
2602 adv.x = base_advance;
2603 adv.y = 0;
2605 /* In fixed-pitch font, we adjust the fullwidth character advance so that
2606 they have double halfwidth character width. E.g. if the font is 19 ppem,
2607 we return 20 (not 19) for fullwidth characters as we return 10 for
2608 halfwidth characters. */
2609 if (freetype_set_outline_text_metrics(incoming_font) &&
2610 !(incoming_font->otm.otmTextMetrics.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
2611 UINT avg_advance;
2612 em_scale = pFT_MulDiv(incoming_font->ppem, 1 << 16, get_ft_face(incoming_font)->units_per_EM);
2613 avg_advance = pFT_MulFix(incoming_font->ntmAvgWidth, em_scale);
2614 fixed_pitch_full = (avg_advance > 0 &&
2615 (base_advance + 63) >> 6 ==
2616 pFT_MulFix(incoming_font->ntmAvgWidth*2, em_scale));
2617 if (fixed_pitch_full && !transMat)
2618 adv.x = (avg_advance * 2) << 6;
2621 if (transMat) {
2622 pFT_Vector_Transform(&adv, transMat);
2623 if (fixed_pitch_full && adv.y == 0) {
2624 FT_Vector vec;
2625 vec.x = incoming_font->ntmAvgWidth;
2626 vec.y = 0;
2627 pFT_Vector_Transform(&vec, transMat);
2628 adv.x = (pFT_MulFix(vec.x, em_scale) * 2) << 6;
2632 if (font->fake_bold) {
2633 if (!transMat)
2634 adv.x += 1 << 6;
2635 else {
2636 FT_Vector fake_bold_adv, vec = { 1 << 6, 0 };
2637 pFT_Vector_Transform(&vec, transMat);
2638 fake_bold_adv = normalize_vector(&vec);
2639 adv.x += fake_bold_adv.x;
2640 adv.y += fake_bold_adv.y;
2644 adv.x = (adv.x + 63) & -64;
2645 adv.y = -((adv.y + 63) & -64);
2646 return adv;
2649 static FT_BBox get_transformed_bbox( const FT_Glyph_Metrics *metrics,
2650 BOOL needs_transform, const FT_Matrix metrices[3] )
2652 FT_BBox bbox = { 0, 0, 0, 0 };
2654 if (!needs_transform)
2656 bbox.xMin = (metrics->horiBearingX) & -64;
2657 bbox.xMax = (metrics->horiBearingX + metrics->width + 63) & -64;
2658 bbox.yMax = (metrics->horiBearingY + 63) & -64;
2659 bbox.yMin = (metrics->horiBearingY - metrics->height) & -64;
2661 else
2663 FT_Vector vec;
2664 INT xc, yc;
2666 for (xc = 0; xc < 2; xc++)
2668 for (yc = 0; yc < 2; yc++)
2670 vec.x = metrics->horiBearingX + xc * metrics->width;
2671 vec.y = metrics->horiBearingY - yc * metrics->height;
2672 TRACE( "Vec %ld,i %ld\n", vec.x, vec.y );
2673 pFT_Vector_Transform( &vec, &metrices[matrix_vert] );
2674 if (xc == 0 && yc == 0)
2676 bbox.xMin = bbox.xMax = vec.x;
2677 bbox.yMin = bbox.yMax = vec.y;
2679 else
2681 if (vec.x < bbox.xMin) bbox.xMin = vec.x;
2682 else if (vec.x > bbox.xMax) bbox.xMax = vec.x;
2683 if (vec.y < bbox.yMin) bbox.yMin = vec.y;
2684 else if (vec.y > bbox.yMax) bbox.yMax = vec.y;
2688 bbox.xMin = bbox.xMin & -64;
2689 bbox.xMax = (bbox.xMax + 63) & -64;
2690 bbox.yMin = bbox.yMin & -64;
2691 bbox.yMax = (bbox.yMax + 63) & -64;
2692 TRACE( "transformed box: (%ld, %ld - %ld, %ld)\n", bbox.xMin, bbox.yMax, bbox.xMax, bbox.yMin );
2695 return bbox;
2698 static void compute_metrics( struct gdi_font *incoming_font, struct gdi_font *font,
2699 FT_BBox bbox, const FT_Glyph_Metrics *metrics,
2700 BOOL vertical, BOOL vertical_metrics,
2701 BOOL needs_transform, const FT_Matrix matrices[3],
2702 GLYPHMETRICS *gm, ABC *abc )
2704 FT_Vector adv, vec, origin;
2706 if (!needs_transform)
2708 adv = get_advance_metric( incoming_font, font, metrics, NULL, vertical_metrics );
2709 gm->gmCellIncX = adv.x >> 6;
2710 gm->gmCellIncY = 0;
2711 origin.x = bbox.xMin;
2712 origin.y = bbox.yMax;
2713 abc->abcA = origin.x >> 6;
2714 abc->abcB = (metrics->width + 63) >> 6;
2716 else
2718 FT_Pos lsb;
2720 if (vertical && freetype_set_outline_text_metrics( font ))
2722 if (vertical_metrics)
2723 lsb = metrics->horiBearingY + metrics->vertBearingY;
2724 else
2725 lsb = metrics->vertAdvance + (font->otm.otmDescent << 6);
2726 vec.x = lsb;
2727 vec.y = font->otm.otmDescent << 6;
2728 TRACE( "Vec %ld,%ld\n", vec.x>>6, vec.y>>6 );
2729 pFT_Vector_Transform( &vec, &matrices[matrix_hori] );
2730 origin.x = (vec.x + bbox.xMin) & -64;
2731 origin.y = (vec.y + bbox.yMax + 63) & -64;
2732 lsb -= metrics->horiBearingY;
2734 else
2736 origin.x = bbox.xMin;
2737 origin.y = bbox.yMax;
2738 lsb = metrics->horiBearingX;
2741 adv = get_advance_metric( incoming_font, font, metrics, &matrices[matrix_hori],
2742 vertical_metrics );
2743 gm->gmCellIncX = adv.x >> 6;
2744 gm->gmCellIncY = adv.y >> 6;
2746 adv = get_advance_metric( incoming_font, font, metrics, &matrices[matrix_unrotated],
2747 vertical_metrics );
2748 adv.x = pFT_Vector_Length( &adv );
2749 adv.y = 0;
2751 vec.x = lsb;
2752 vec.y = 0;
2753 pFT_Vector_Transform( &vec, &matrices[matrix_unrotated] );
2754 if (lsb > 0) abc->abcA = pFT_Vector_Length( &vec ) >> 6;
2755 else abc->abcA = -((pFT_Vector_Length( &vec ) + 63) >> 6);
2757 /* We use lsb again to avoid rounding errors */
2758 vec.x = lsb + (vertical ? metrics->height : metrics->width);
2759 vec.y = 0;
2760 pFT_Vector_Transform( &vec, &matrices[matrix_unrotated] );
2761 abc->abcB = ((pFT_Vector_Length( &vec ) + 63) >> 6) - abc->abcA;
2763 if (!abc->abcB) abc->abcB = 1;
2764 abc->abcC = (adv.x >> 6) - abc->abcA - abc->abcB;
2766 gm->gmptGlyphOrigin.x = origin.x >> 6;
2767 gm->gmptGlyphOrigin.y = origin.y >> 6;
2768 gm->gmBlackBoxX = (bbox.xMax - bbox.xMin) >> 6;
2769 gm->gmBlackBoxY = (bbox.yMax - bbox.yMin) >> 6;
2770 if (!gm->gmBlackBoxX) gm->gmBlackBoxX = 1;
2771 if (!gm->gmBlackBoxY) gm->gmBlackBoxY = 1;
2773 TRACE( "gm: %u, %u, %s, %d, %d abc %d, %u, %d\n",
2774 gm->gmBlackBoxX, gm->gmBlackBoxY, wine_dbgstr_point(&gm->gmptGlyphOrigin),
2775 gm->gmCellIncX, gm->gmCellIncY, abc->abcA, abc->abcB, abc->abcC );
2779 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
2781 static DWORD get_mono_glyph_bitmap( FT_GlyphSlot glyph, FT_BBox bbox,
2782 BOOL fake_bold, BOOL needs_transform, FT_Matrix matrices[3],
2783 DWORD buflen, BYTE *buf )
2785 DWORD width = (bbox.xMax - bbox.xMin ) >> 6;
2786 DWORD height = (bbox.yMax - bbox.yMin ) >> 6;
2787 DWORD pitch = ((width + 31) >> 5) << 2;
2788 DWORD needed = pitch * height;
2789 FT_Bitmap ft_bitmap;
2790 BYTE *src, *dst;
2791 INT w, h, x;
2793 if (!buf || !buflen) return needed;
2794 if (!needed) return GDI_ERROR; /* empty glyph */
2795 if (needed > buflen) return GDI_ERROR;
2797 switch (glyph->format)
2799 case FT_GLYPH_FORMAT_BITMAP:
2800 src = glyph->bitmap.buffer;
2801 dst = buf;
2802 w = min( pitch, (glyph->bitmap.width + 7) >> 3 );
2803 h = min( height, glyph->bitmap.rows );
2804 while (h--)
2806 if (!fake_bold)
2807 memcpy( dst, src, w );
2808 else
2810 dst[0] = 0;
2811 for (x = 0; x < w; x++)
2813 dst[x] = (dst[x] & 0x80) | (src[x] >> 1) | src[x];
2814 if (x + 1 < pitch)
2815 dst[x + 1] = (src[x] & 0x01) << 7;
2818 src += glyph->bitmap.pitch;
2819 dst += pitch;
2821 break;
2823 case FT_GLYPH_FORMAT_OUTLINE:
2824 ft_bitmap.width = width;
2825 ft_bitmap.rows = height;
2826 ft_bitmap.pitch = pitch;
2827 ft_bitmap.pixel_mode = FT_PIXEL_MODE_MONO;
2828 ft_bitmap.buffer = buf;
2830 if (needs_transform)
2831 pFT_Outline_Transform( &glyph->outline, &matrices[matrix_vert] );
2832 pFT_Outline_Translate( &glyph->outline, -bbox.xMin, -bbox.yMin );
2834 /* Note: FreeType will only set 'black' bits for us. */
2835 memset( buf, 0, buflen );
2836 pFT_Outline_Get_Bitmap( library, &glyph->outline, &ft_bitmap );
2837 break;
2839 default:
2840 FIXME( "loaded glyph format %x\n", glyph->format );
2841 return GDI_ERROR;
2844 return needed;
2847 static DWORD get_antialias_glyph_bitmap( FT_GlyphSlot glyph, FT_BBox bbox, UINT format,
2848 BOOL fake_bold, BOOL needs_transform, FT_Matrix matrices[3],
2849 DWORD buflen, BYTE *buf )
2851 DWORD width = (bbox.xMax - bbox.xMin ) >> 6;
2852 DWORD height = (bbox.yMax - bbox.yMin ) >> 6;
2853 DWORD pitch = (width + 3) / 4 * 4;
2854 DWORD needed = pitch * height;
2855 FT_Bitmap ft_bitmap;
2856 INT w, h, x, max_level;
2857 BYTE *src, *dst;
2859 if (!buf || !buflen) return needed;
2860 if (!needed) return GDI_ERROR; /* empty glyph */
2861 if (needed > buflen) return GDI_ERROR;
2863 max_level = get_max_level( format );
2865 switch (glyph->format)
2867 case FT_GLYPH_FORMAT_BITMAP:
2868 src = glyph->bitmap.buffer;
2869 dst = buf;
2870 memset( buf, 0, buflen );
2872 w = min( pitch, glyph->bitmap.width );
2873 h = min( height, glyph->bitmap.rows );
2874 while (h--)
2876 for (x = 0; x < w; x++)
2878 if (src[x / 8] & masks[x % 8])
2880 dst[x] = max_level;
2881 if (fake_bold && x + 1 < pitch) dst[x + 1] = max_level;
2884 src += glyph->bitmap.pitch;
2885 dst += pitch;
2887 break;
2889 case FT_GLYPH_FORMAT_OUTLINE:
2890 ft_bitmap.width = width;
2891 ft_bitmap.rows = height;
2892 ft_bitmap.pitch = pitch;
2893 ft_bitmap.pixel_mode = FT_PIXEL_MODE_GRAY;
2894 ft_bitmap.buffer = buf;
2896 if (needs_transform)
2897 pFT_Outline_Transform( &glyph->outline, &matrices[matrix_vert] );
2898 pFT_Outline_Translate( &glyph->outline, -bbox.xMin, -bbox.yMin );
2900 memset( buf, 0, buflen );
2901 pFT_Outline_Get_Bitmap( library, &glyph->outline, &ft_bitmap );
2903 if (max_level != 255)
2905 INT row, col;
2906 BYTE *ptr, *start;
2908 for (row = 0, start = buf; row < height; row++)
2910 for (col = 0, ptr = start; col < width; col++, ptr++)
2911 *ptr = (((int)*ptr) * (max_level + 1)) / 256;
2912 start += pitch;
2915 break;
2917 default:
2918 FIXME("loaded glyph format %x\n", glyph->format);
2919 return GDI_ERROR;
2922 return needed;
2925 static DWORD get_subpixel_glyph_bitmap( FT_GlyphSlot glyph, FT_BBox bbox, UINT format,
2926 BOOL fake_bold, BOOL needs_transform, FT_Matrix matrices[3],
2927 GLYPHMETRICS *gm, DWORD buflen, BYTE *buf )
2929 DWORD width = (bbox.xMax - bbox.xMin ) >> 6;
2930 DWORD height = (bbox.yMax - bbox.yMin ) >> 6;
2931 DWORD pitch, needed = 0;
2932 BYTE *src, *dst;
2933 INT w, h, x;
2935 switch (glyph->format)
2937 case FT_GLYPH_FORMAT_BITMAP:
2938 pitch = width * 4;
2939 needed = pitch * height;
2941 if (!buf || !buflen) break;
2942 if (!needed) return GDI_ERROR; /* empty glyph */
2943 if (needed > buflen) return GDI_ERROR;
2945 src = glyph->bitmap.buffer;
2946 dst = buf;
2947 memset( buf, 0, buflen );
2949 w = min( width, glyph->bitmap.width );
2950 h = min( height, glyph->bitmap.rows );
2951 while (h--)
2953 for (x = 0; x < w; x++)
2955 if ( src[x / 8] & masks[x % 8] )
2957 ((unsigned int *)dst)[x] = ~0u;
2958 if (fake_bold && x + 1 < width) ((unsigned int *)dst)[x + 1] = ~0u;
2961 src += glyph->bitmap.pitch;
2962 dst += pitch;
2964 break;
2966 case FT_GLYPH_FORMAT_OUTLINE:
2968 INT src_pitch, src_width, src_height, x_shift, y_shift;
2969 INT sub_stride, hmul, vmul;
2970 const INT *sub_order;
2971 const INT rgb_order[3] = { 0, 1, 2 };
2972 const INT bgr_order[3] = { 2, 1, 0 };
2973 FT_Render_Mode render_mode =
2974 (format == WINE_GGO_HRGB_BITMAP ||
2975 format == WINE_GGO_HBGR_BITMAP) ? FT_RENDER_MODE_LCD : FT_RENDER_MODE_LCD_V;
2977 if (!width || !height) /* empty glyph */
2979 if (!buf || !buflen) break;
2980 return GDI_ERROR;
2983 if ( render_mode == FT_RENDER_MODE_LCD)
2985 gm->gmBlackBoxX += 2;
2986 gm->gmptGlyphOrigin.x -= 1;
2987 bbox.xMin -= (1 << 6);
2989 else
2991 gm->gmBlackBoxY += 2;
2992 gm->gmptGlyphOrigin.y += 1;
2993 bbox.yMax += (1 << 6);
2996 width = gm->gmBlackBoxX;
2997 height = gm->gmBlackBoxY;
2998 pitch = width * 4;
2999 needed = pitch * height;
3001 if (!buf || !buflen) return needed;
3002 if (needed > buflen) return GDI_ERROR;
3004 if (needs_transform)
3005 pFT_Outline_Transform( &glyph->outline, &matrices[matrix_vert] );
3007 #ifdef FT_LCD_FILTER_H
3008 if (pFT_Library_SetLcdFilter)
3009 pFT_Library_SetLcdFilter( library, FT_LCD_FILTER_DEFAULT );
3010 #endif
3011 pFT_Render_Glyph( glyph, render_mode );
3013 src_pitch = glyph->bitmap.pitch;
3014 src_width = glyph->bitmap.width;
3015 src_height = glyph->bitmap.rows;
3016 src = glyph->bitmap.buffer;
3017 dst = buf;
3018 memset( buf, 0, buflen );
3020 sub_order = (format == WINE_GGO_HRGB_BITMAP ||
3021 format == WINE_GGO_VRGB_BITMAP) ? rgb_order : bgr_order;
3022 sub_stride = render_mode == FT_RENDER_MODE_LCD ? 1 : src_pitch;
3023 hmul = render_mode == FT_RENDER_MODE_LCD ? 3 : 1;
3024 vmul = render_mode == FT_RENDER_MODE_LCD ? 1 : 3;
3026 x_shift = glyph->bitmap_left - (bbox.xMin >> 6);
3027 if ( x_shift < 0 )
3029 src += hmul * -x_shift;
3030 src_width -= hmul * -x_shift;
3032 else if ( x_shift > 0 )
3034 dst += x_shift * sizeof(unsigned int);
3035 width -= x_shift;
3038 y_shift = (bbox.yMax >> 6) - glyph->bitmap_top;
3039 if ( y_shift < 0 )
3041 src += src_pitch * vmul * -y_shift;
3042 src_height -= vmul * -y_shift;
3044 else if ( y_shift > 0 )
3046 dst += y_shift * pitch;
3047 height -= y_shift;
3050 w = min( width, src_width / hmul );
3051 h = min( height, src_height / vmul );
3052 while (h--)
3054 for (x = 0; x < w; x++)
3056 ((unsigned int *)dst)[x] =
3057 ((unsigned int)src[hmul * x + sub_stride * sub_order[0]] << 16) |
3058 ((unsigned int)src[hmul * x + sub_stride * sub_order[1]] << 8) |
3059 ((unsigned int)src[hmul * x + sub_stride * sub_order[2]]);
3061 src += src_pitch * vmul;
3062 dst += pitch;
3064 break;
3066 default:
3067 FIXME ( "loaded glyph format %x\n", glyph->format );
3068 return GDI_ERROR;
3071 return needed;
3074 static unsigned int get_native_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
3076 TTPOLYGONHEADER *pph;
3077 TTPOLYCURVE *ppc;
3078 unsigned int needed = 0, point = 0, contour, first_pt;
3079 unsigned int pph_start, cpfx;
3080 DWORD type;
3082 for (contour = 0; contour < outline->n_contours; contour++)
3084 /* Ignore contours containing one point */
3085 if (point == outline->contours[contour])
3087 point++;
3088 continue;
3091 pph_start = needed;
3092 pph = (TTPOLYGONHEADER *)(buf + needed);
3093 first_pt = point;
3094 if (buf)
3096 pph->dwType = TT_POLYGON_TYPE;
3097 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3099 needed += sizeof(*pph);
3100 point++;
3101 while (point <= outline->contours[contour])
3103 ppc = (TTPOLYCURVE *)(buf + needed);
3104 type = outline->tags[point] & FT_Curve_Tag_On ?
3105 TT_PRIM_LINE : TT_PRIM_QSPLINE;
3106 cpfx = 0;
3109 if (buf)
3110 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3111 cpfx++;
3112 point++;
3113 } while (point <= outline->contours[contour] &&
3114 (outline->tags[point] & FT_Curve_Tag_On) ==
3115 (outline->tags[point-1] & FT_Curve_Tag_On));
3116 /* At the end of a contour Windows adds the start point, but
3117 only for Beziers */
3118 if (point > outline->contours[contour] &&
3119 !(outline->tags[point-1] & FT_Curve_Tag_On))
3121 if (buf)
3122 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
3123 cpfx++;
3125 else if (point <= outline->contours[contour] &&
3126 outline->tags[point] & FT_Curve_Tag_On)
3128 /* add closing pt for bezier */
3129 if (buf)
3130 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3131 cpfx++;
3132 point++;
3134 if (buf)
3136 ppc->wType = type;
3137 ppc->cpfx = cpfx;
3139 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3141 if (buf)
3142 pph->cb = needed - pph_start;
3144 return needed;
3147 static unsigned int get_bezier_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
3149 /* Convert the quadratic Beziers to cubic Beziers.
3150 The parametric eqn for a cubic Bezier is, from PLRM:
3151 r(t) = at^3 + bt^2 + ct + r0
3152 with the control points:
3153 r1 = r0 + c/3
3154 r2 = r1 + (c + b)/3
3155 r3 = r0 + c + b + a
3157 A quadratic Bezier has the form:
3158 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3160 So equating powers of t leads to:
3161 r1 = 2/3 p1 + 1/3 p0
3162 r2 = 2/3 p1 + 1/3 p2
3163 and of course r0 = p0, r3 = p2
3165 int contour, point = 0, first_pt;
3166 TTPOLYGONHEADER *pph;
3167 TTPOLYCURVE *ppc;
3168 DWORD pph_start, cpfx, type;
3169 FT_Vector cubic_control[4];
3170 unsigned int needed = 0;
3172 for (contour = 0; contour < outline->n_contours; contour++)
3174 pph_start = needed;
3175 pph = (TTPOLYGONHEADER *)(buf + needed);
3176 first_pt = point;
3177 if (buf)
3179 pph->dwType = TT_POLYGON_TYPE;
3180 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3182 needed += sizeof(*pph);
3183 point++;
3184 while (point <= outline->contours[contour])
3186 ppc = (TTPOLYCURVE *)(buf + needed);
3187 type = outline->tags[point] & FT_Curve_Tag_On ?
3188 TT_PRIM_LINE : TT_PRIM_CSPLINE;
3189 cpfx = 0;
3192 if (type == TT_PRIM_LINE)
3194 if (buf)
3195 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3196 cpfx++;
3197 point++;
3199 else
3201 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
3202 so cpfx = 3n */
3204 /* FIXME: Possible optimization in endpoint calculation
3205 if there are two consecutive curves */
3206 cubic_control[0] = outline->points[point-1];
3207 if (!(outline->tags[point-1] & FT_Curve_Tag_On))
3209 cubic_control[0].x += outline->points[point].x + 1;
3210 cubic_control[0].y += outline->points[point].y + 1;
3211 cubic_control[0].x >>= 1;
3212 cubic_control[0].y >>= 1;
3214 if (point+1 > outline->contours[contour])
3215 cubic_control[3] = outline->points[first_pt];
3216 else
3218 cubic_control[3] = outline->points[point+1];
3219 if (!(outline->tags[point+1] & FT_Curve_Tag_On))
3221 cubic_control[3].x += outline->points[point].x + 1;
3222 cubic_control[3].y += outline->points[point].y + 1;
3223 cubic_control[3].x >>= 1;
3224 cubic_control[3].y >>= 1;
3227 /* r1 = 1/3 p0 + 2/3 p1
3228 r2 = 1/3 p2 + 2/3 p1 */
3229 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
3230 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
3231 cubic_control[2] = cubic_control[1];
3232 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
3233 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
3234 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
3235 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
3236 if (buf)
3238 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
3239 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
3240 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
3242 cpfx += 3;
3243 point++;
3245 } while (point <= outline->contours[contour] &&
3246 (outline->tags[point] & FT_Curve_Tag_On) ==
3247 (outline->tags[point-1] & FT_Curve_Tag_On));
3248 /* At the end of a contour Windows adds the start point,
3249 but only for Beziers and we've already done that.
3251 if (point <= outline->contours[contour] &&
3252 outline->tags[point] & FT_Curve_Tag_On)
3254 /* This is the closing pt of a bezier, but we've already
3255 added it, so just inc point and carry on */
3256 point++;
3258 if (buf)
3260 ppc->wType = type;
3261 ppc->cpfx = cpfx;
3263 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3265 if (buf)
3266 pph->cb = needed - pph_start;
3268 return needed;
3271 static FT_Int get_load_flags( UINT format )
3273 FT_Int load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
3275 if (format & GGO_UNHINTED)
3276 return load_flags | FT_LOAD_NO_HINTING;
3278 switch (format & ~GGO_GLYPH_INDEX)
3280 case GGO_BITMAP:
3281 load_flags |= FT_LOAD_TARGET_MONO;
3282 break;
3283 case GGO_GRAY2_BITMAP:
3284 case GGO_GRAY4_BITMAP:
3285 case GGO_GRAY8_BITMAP:
3286 case WINE_GGO_GRAY16_BITMAP:
3287 load_flags |= FT_LOAD_TARGET_NORMAL;
3288 break;
3289 case WINE_GGO_HRGB_BITMAP:
3290 case WINE_GGO_HBGR_BITMAP:
3291 load_flags |= FT_LOAD_TARGET_LCD;
3292 break;
3293 case WINE_GGO_VRGB_BITMAP:
3294 case WINE_GGO_VBGR_BITMAP:
3295 load_flags |= FT_LOAD_TARGET_LCD_V;
3296 break;
3299 return load_flags;
3302 /*************************************************************
3303 * freetype_get_glyph_outline
3305 static DWORD CDECL freetype_get_glyph_outline( struct gdi_font *font, UINT glyph, UINT format,
3306 GLYPHMETRICS *lpgm, ABC *abc, DWORD buflen, void *buf,
3307 const MAT2 *lpmat, BOOL tategaki )
3309 struct gdi_font *base_font = font->base_font ? font->base_font : font;
3310 FT_Face ft_face = get_ft_face( font );
3311 FT_Glyph_Metrics metrics;
3312 FT_Error err;
3313 FT_BBox bbox;
3314 FT_Int load_flags = get_load_flags(format);
3315 FT_Matrix matrices[3];
3316 BOOL needsTransform = FALSE;
3317 BOOL vertical_metrics;
3319 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm, buflen, buf, lpmat);
3321 TRACE("font transform %f %f %f %f\n",
3322 font->matrix.eM11, font->matrix.eM12,
3323 font->matrix.eM21, font->matrix.eM22);
3325 needsTransform = get_transform_matrices( font, tategaki, lpmat, matrices );
3327 vertical_metrics = (tategaki && FT_HAS_VERTICAL(ft_face));
3328 /* there is a freetype bug where vertical metrics are only
3329 properly scaled and correct in 2.4.0 or greater */
3330 if (vertical_metrics && FT_SimpleVersion < FT_VERSION_VALUE(2, 4, 0))
3331 vertical_metrics = FALSE;
3333 if (needsTransform || format != GGO_BITMAP) load_flags |= FT_LOAD_NO_BITMAP;
3334 if (vertical_metrics) load_flags |= FT_LOAD_VERTICAL_LAYOUT;
3336 err = pFT_Load_Glyph(ft_face, glyph, load_flags);
3337 if (err && !(load_flags & FT_LOAD_NO_HINTING))
3339 WARN("Failed to load glyph %#x, retrying without hinting. Error %#x.\n", glyph, err);
3340 load_flags |= FT_LOAD_NO_HINTING;
3341 err = pFT_Load_Glyph(ft_face, glyph, load_flags);
3344 if(err) {
3345 WARN("Failed to load glyph %#x, error %#x.\n", glyph, err);
3346 return GDI_ERROR;
3349 metrics = ft_face->glyph->metrics;
3350 if(font->fake_bold) {
3351 if (!get_bold_glyph_outline(ft_face->glyph, font->ppem, &metrics) && metrics.width)
3352 metrics.width += 1 << 6;
3355 /* Some poorly-created fonts contain glyphs that exceed the boundaries set
3356 * by the text metrics. The proper behavior is to clip the glyph metrics to
3357 * fit within the maximums specified in the text metrics. */
3358 if (freetype_set_outline_text_metrics(base_font) ||
3359 freetype_set_bitmap_text_metrics(base_font)) {
3360 TEXTMETRICW *ptm = &base_font->otm.otmTextMetrics;
3361 INT top = min( metrics.horiBearingY, ptm->tmAscent << 6 );
3362 INT bottom = max( metrics.horiBearingY - metrics.height, -(ptm->tmDescent << 6) );
3363 metrics.horiBearingY = top;
3364 metrics.height = top - bottom;
3366 /* TODO: Are we supposed to clip the width as well...? */
3367 /* metrics.width = min( metrics.width, ptm->tmMaxCharWidth << 6 ); */
3370 bbox = get_transformed_bbox( &metrics, needsTransform, matrices );
3371 compute_metrics( base_font, font, bbox, &metrics, tategaki,
3372 vertical_metrics, needsTransform, matrices, lpgm, abc );
3374 switch (format)
3376 case GGO_METRICS:
3377 return 1; /* FIXME */
3379 case GGO_BITMAP:
3380 return get_mono_glyph_bitmap( ft_face->glyph, bbox, font->fake_bold,
3381 needsTransform, matrices, buflen, buf );
3383 case GGO_GRAY2_BITMAP:
3384 case GGO_GRAY4_BITMAP:
3385 case GGO_GRAY8_BITMAP:
3386 case WINE_GGO_GRAY16_BITMAP:
3387 return get_antialias_glyph_bitmap( ft_face->glyph, bbox, format, font->fake_bold,
3388 needsTransform, matrices, buflen, buf );
3390 case WINE_GGO_HRGB_BITMAP:
3391 case WINE_GGO_HBGR_BITMAP:
3392 case WINE_GGO_VRGB_BITMAP:
3393 case WINE_GGO_VBGR_BITMAP:
3394 return get_subpixel_glyph_bitmap( ft_face->glyph, bbox, format, font->fake_bold,
3395 needsTransform, matrices, lpgm, buflen, buf );
3397 case GGO_NATIVE:
3398 if (ft_face->glyph->format == ft_glyph_format_outline)
3400 FT_Outline *outline = &ft_face->glyph->outline;
3401 UINT needed;
3403 if (buflen == 0) buf = NULL;
3405 if (needsTransform && buf)
3406 pFT_Outline_Transform( outline, &matrices[matrix_vert] );
3408 needed = get_native_glyph_outline(outline, buflen, NULL);
3410 if (!buf || !buflen) return needed;
3411 if (needed > buflen) return GDI_ERROR;
3412 return get_native_glyph_outline(outline, buflen, buf);
3414 TRACE("loaded a bitmap\n");
3415 return GDI_ERROR;
3417 case GGO_BEZIER:
3418 if (ft_face->glyph->format == ft_glyph_format_outline)
3420 FT_Outline *outline = &ft_face->glyph->outline;
3421 UINT needed;
3423 if (buflen == 0) buf = NULL;
3425 if (needsTransform && buf)
3426 pFT_Outline_Transform( outline, &matrices[matrix_vert] );
3428 needed = get_bezier_glyph_outline(outline, buflen, NULL);
3430 if (!buf || !buflen) return needed;
3431 if (needed > buflen) return GDI_ERROR;
3432 return get_bezier_glyph_outline(outline, buflen, buf);
3434 TRACE("loaded a bitmap\n");
3435 return GDI_ERROR;
3437 default:
3438 FIXME("Unsupported format %d\n", format);
3439 return GDI_ERROR;
3443 /*************************************************************
3444 * freetype_set_bitmap_text_metrics
3446 static BOOL CDECL freetype_set_bitmap_text_metrics( struct gdi_font *font )
3448 FT_Face ft_face = get_ft_face( font );
3449 FT_WinFNT_HeaderRec winfnt_header;
3451 if (font->otm.otmSize) return TRUE; /* already set */
3452 font->otm.otmSize = offsetof( OUTLINETEXTMETRICW, otmFiller );
3454 #define TM font->otm.otmTextMetrics
3455 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
3457 TM.tmHeight = winfnt_header.pixel_height;
3458 TM.tmAscent = winfnt_header.ascent;
3459 TM.tmDescent = TM.tmHeight - TM.tmAscent;
3460 TM.tmInternalLeading = winfnt_header.internal_leading;
3461 TM.tmExternalLeading = winfnt_header.external_leading;
3462 TM.tmAveCharWidth = winfnt_header.avg_width;
3463 TM.tmMaxCharWidth = winfnt_header.max_width;
3464 TM.tmWeight = winfnt_header.weight;
3465 TM.tmOverhang = 0;
3466 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
3467 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
3468 TM.tmFirstChar = winfnt_header.first_char;
3469 TM.tmLastChar = winfnt_header.last_char;
3470 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
3471 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
3472 TM.tmItalic = winfnt_header.italic;
3473 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
3474 TM.tmCharSet = winfnt_header.charset;
3476 else
3478 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
3479 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
3480 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3481 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
3482 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
3483 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
3484 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
3485 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
3486 TM.tmOverhang = 0;
3487 TM.tmDigitizedAspectX = 96; /* FIXME */
3488 TM.tmDigitizedAspectY = 96; /* FIXME */
3489 TM.tmFirstChar = 1;
3490 TM.tmLastChar = 255;
3491 TM.tmDefaultChar = 32;
3492 TM.tmBreakChar = 32;
3493 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
3494 /* NB inverted meaning of TMPF_FIXED_PITCH */
3495 TM.tmPitchAndFamily = FT_IS_FIXED_WIDTH(ft_face) ? 0 : TMPF_FIXED_PITCH;
3496 TM.tmCharSet = font->charset;
3498 TM.tmUnderlined = font->lf.lfUnderline ? 0xff : 0;
3499 TM.tmStruckOut = font->lf.lfStrikeOut ? 0xff : 0;
3501 if(font->fake_bold)
3502 TM.tmWeight = FW_BOLD;
3503 #undef TM
3505 return TRUE;
3509 static BOOL face_has_symbol_charmap(FT_Face ft_face)
3511 int i;
3513 for(i = 0; i < ft_face->num_charmaps; i++)
3515 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
3516 return TRUE;
3518 return FALSE;
3521 /*************************************************************
3522 * freetype_set_outline_text_metrics
3524 static BOOL CDECL freetype_set_outline_text_metrics( struct gdi_font *font )
3526 FT_Face ft_face = get_ft_face( font );
3527 UINT needed;
3528 TT_OS2 *pOS2;
3529 TT_HoriHeader *pHori;
3530 TT_Postscript *pPost;
3531 FT_Fixed em_scale;
3532 INT ascent, descent;
3533 USHORT windescent;
3535 TRACE("font=%p\n", font);
3537 if (!font->scalable) return FALSE;
3538 if (font->otm.otmSize) return TRUE; /* already set */
3540 /* note: we store actual pointers in the names instead of offsets,
3541 they are fixed up when returned to the app */
3542 if (!(font->otm.otmpFullName = (char *)get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, system_lcid )))
3544 static const WCHAR fake_nameW[] = {'f','a','k','e',' ','n','a','m','e', 0};
3545 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w((WCHAR *)font->otm.otmpFamilyName));
3546 font->otm.otmpFullName = (char *)strdupW(fake_nameW);
3548 needed = sizeof(font->otm) + (lstrlenW( (WCHAR *)font->otm.otmpFamilyName ) + 1 +
3549 lstrlenW( (WCHAR *)font->otm.otmpStyleName ) + 1 +
3550 lstrlenW( (WCHAR *)font->otm.otmpFaceName ) + 1 +
3551 lstrlenW( (WCHAR *)font->otm.otmpFullName ) + 1) * sizeof(WCHAR);
3553 em_scale = (FT_Fixed)pFT_MulDiv(font->ppem, 1 << 16, ft_face->units_per_EM);
3555 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3556 if(!pOS2) {
3557 FIXME("Can't find OS/2 table - not TT font?\n");
3558 return FALSE;
3561 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3562 if(!pHori) {
3563 FIXME("Can't find HHEA table - not TT font?\n");
3564 return FALSE;
3567 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
3569 TRACE("OS/2 winA = %u winD = %u typoA = %d typoD = %d typoLG = %d avgW %d FT_Face a = %d, d = %d, h = %d: HORZ a = %d, d = %d lg = %d maxY = %ld minY = %ld\n",
3570 pOS2->usWinAscent, pOS2->usWinDescent,
3571 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
3572 pOS2->xAvgCharWidth,
3573 ft_face->ascender, ft_face->descender, ft_face->height,
3574 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
3575 ft_face->bbox.yMax, ft_face->bbox.yMin);
3577 font->otm.otmSize = needed;
3579 #define TM font->otm.otmTextMetrics
3581 windescent = get_fixed_windescent(pOS2->usWinDescent);
3582 if(pOS2->usWinAscent + windescent == 0) {
3583 ascent = pHori->Ascender;
3584 descent = -pHori->Descender;
3585 } else {
3586 ascent = pOS2->usWinAscent;
3587 descent = windescent;
3590 font->ntmCellHeight = ascent + descent;
3591 font->ntmAvgWidth = pOS2->xAvgCharWidth;
3593 #define SCALE_X(x) (pFT_MulFix(x, em_scale))
3594 #define SCALE_Y(y) (pFT_MulFix(y, em_scale))
3596 if(font->yMax) {
3597 TM.tmAscent = font->yMax;
3598 TM.tmDescent = -font->yMin;
3599 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
3600 } else {
3601 TM.tmAscent = SCALE_Y(ascent);
3602 TM.tmDescent = SCALE_Y(descent);
3603 TM.tmInternalLeading = SCALE_Y(ascent + descent - ft_face->units_per_EM);
3606 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3608 /* MSDN says:
3609 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
3611 TM.tmExternalLeading = max(0, SCALE_Y(pHori->Line_Gap -
3612 ((ascent + descent) -
3613 (pHori->Ascender - pHori->Descender))));
3615 TM.tmAveCharWidth = SCALE_X(pOS2->xAvgCharWidth);
3616 if (TM.tmAveCharWidth == 0) {
3617 TM.tmAveCharWidth = 1;
3619 TM.tmMaxCharWidth = SCALE_X(ft_face->bbox.xMax - ft_face->bbox.xMin);
3620 TM.tmWeight = FW_REGULAR;
3621 if (font->fake_bold)
3622 TM.tmWeight = FW_BOLD;
3623 else
3625 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
3627 if (pOS2->usWeightClass > FW_MEDIUM)
3628 TM.tmWeight = pOS2->usWeightClass;
3630 else if (pOS2->usWeightClass <= FW_MEDIUM)
3631 TM.tmWeight = pOS2->usWeightClass;
3633 TM.tmOverhang = 0;
3634 TM.tmDigitizedAspectX = 96; /* FIXME */
3635 TM.tmDigitizedAspectY = 96; /* FIXME */
3636 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
3637 * symbol range to 0 - f0ff
3640 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
3642 TM.tmFirstChar = 0;
3643 switch (PRIMARYLANGID(system_lcid))
3645 case LANG_HEBREW:
3646 TM.tmLastChar = 0xf896;
3647 break;
3648 case LANG_ESTONIAN:
3649 case LANG_LATVIAN:
3650 case LANG_LITHUANIAN:
3651 TM.tmLastChar = 0xf8fd;
3652 break;
3653 default:
3654 TM.tmLastChar = 0xf0ff;
3656 TM.tmBreakChar = 0x20;
3657 TM.tmDefaultChar = 0x1f;
3659 else
3661 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
3662 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
3664 if(pOS2->usFirstCharIndex <= 1)
3665 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
3666 else if (pOS2->usFirstCharIndex > 0xff)
3667 TM.tmBreakChar = 0x20;
3668 else
3669 TM.tmBreakChar = pOS2->usFirstCharIndex;
3670 TM.tmDefaultChar = TM.tmBreakChar - 1;
3672 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
3673 TM.tmUnderlined = font->lf.lfUnderline ? 255 : 0;
3674 TM.tmStruckOut = font->lf.lfStrikeOut ? 255 : 0;
3676 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
3677 if(!FT_IS_FIXED_WIDTH(ft_face) &&
3678 (pOS2->version == 0xFFFFU ||
3679 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
3680 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
3681 else
3682 TM.tmPitchAndFamily = 0;
3684 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
3686 case PAN_FAMILY_SCRIPT:
3687 TM.tmPitchAndFamily |= FF_SCRIPT;
3688 break;
3690 case PAN_FAMILY_DECORATIVE:
3691 TM.tmPitchAndFamily |= FF_DECORATIVE;
3692 break;
3694 case PAN_ANY:
3695 case PAN_NO_FIT:
3696 case PAN_FAMILY_TEXT_DISPLAY:
3697 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
3698 /* which is clearly not what the panose spec says. */
3699 default:
3700 if(TM.tmPitchAndFamily == 0 || /* fixed */
3701 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
3702 TM.tmPitchAndFamily = FF_MODERN;
3703 else
3705 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
3707 case PAN_ANY:
3708 case PAN_NO_FIT:
3709 default:
3710 TM.tmPitchAndFamily |= FF_DONTCARE;
3711 break;
3713 case PAN_SERIF_COVE:
3714 case PAN_SERIF_OBTUSE_COVE:
3715 case PAN_SERIF_SQUARE_COVE:
3716 case PAN_SERIF_OBTUSE_SQUARE_COVE:
3717 case PAN_SERIF_SQUARE:
3718 case PAN_SERIF_THIN:
3719 case PAN_SERIF_BONE:
3720 case PAN_SERIF_EXAGGERATED:
3721 case PAN_SERIF_TRIANGLE:
3722 TM.tmPitchAndFamily |= FF_ROMAN;
3723 break;
3725 case PAN_SERIF_NORMAL_SANS:
3726 case PAN_SERIF_OBTUSE_SANS:
3727 case PAN_SERIF_PERP_SANS:
3728 case PAN_SERIF_FLARED:
3729 case PAN_SERIF_ROUNDED:
3730 TM.tmPitchAndFamily |= FF_SWISS;
3731 break;
3734 break;
3737 if(FT_IS_SCALABLE(ft_face))
3738 TM.tmPitchAndFamily |= TMPF_VECTOR;
3740 if(FT_IS_SFNT(ft_face))
3742 if (font->ntmFlags & NTM_PS_OPENTYPE)
3743 TM.tmPitchAndFamily |= TMPF_DEVICE;
3744 else
3745 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
3748 TM.tmCharSet = font->charset;
3750 font->otm.otmFiller = 0;
3751 memcpy(&font->otm.otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
3752 font->otm.otmfsSelection = pOS2->fsSelection;
3753 if (font->fake_italic)
3754 font->otm.otmfsSelection |= 1;
3755 if (font->fake_bold)
3756 font->otm.otmfsSelection |= 1 << 5;
3757 /* Only return valid bits that define embedding and subsetting restrictions */
3758 font->otm.otmfsType = pOS2->fsType & 0x30e;
3759 font->otm.otmsCharSlopeRise = pHori->caret_Slope_Rise;
3760 font->otm.otmsCharSlopeRun = pHori->caret_Slope_Run;
3761 font->otm.otmItalicAngle = 0; /* POST table */
3762 font->otm.otmEMSquare = ft_face->units_per_EM;
3763 font->otm.otmAscent = SCALE_Y(pOS2->sTypoAscender);
3764 font->otm.otmDescent = SCALE_Y(pOS2->sTypoDescender);
3765 font->otm.otmLineGap = SCALE_Y(pOS2->sTypoLineGap);
3766 font->otm.otmsCapEmHeight = SCALE_Y(pOS2->sCapHeight);
3767 font->otm.otmsXHeight = SCALE_Y(pOS2->sxHeight);
3768 font->otm.otmrcFontBox.left = SCALE_X(ft_face->bbox.xMin);
3769 font->otm.otmrcFontBox.right = SCALE_X(ft_face->bbox.xMax);
3770 font->otm.otmrcFontBox.top = SCALE_Y(ft_face->bbox.yMax);
3771 font->otm.otmrcFontBox.bottom = SCALE_Y(ft_face->bbox.yMin);
3772 font->otm.otmMacAscent = TM.tmAscent;
3773 font->otm.otmMacDescent = -TM.tmDescent;
3774 font->otm.otmMacLineGap = SCALE_Y(pHori->Line_Gap);
3775 font->otm.otmusMinimumPPEM = 0; /* TT Header */
3776 font->otm.otmptSubscriptSize.x = SCALE_X(pOS2->ySubscriptXSize);
3777 font->otm.otmptSubscriptSize.y = SCALE_Y(pOS2->ySubscriptYSize);
3778 font->otm.otmptSubscriptOffset.x = SCALE_X(pOS2->ySubscriptXOffset);
3779 font->otm.otmptSubscriptOffset.y = SCALE_Y(pOS2->ySubscriptYOffset);
3780 font->otm.otmptSuperscriptSize.x = SCALE_X(pOS2->ySuperscriptXSize);
3781 font->otm.otmptSuperscriptSize.y = SCALE_Y(pOS2->ySuperscriptYSize);
3782 font->otm.otmptSuperscriptOffset.x = SCALE_X(pOS2->ySuperscriptXOffset);
3783 font->otm.otmptSuperscriptOffset.y = SCALE_Y(pOS2->ySuperscriptYOffset);
3784 font->otm.otmsStrikeoutSize = SCALE_Y(pOS2->yStrikeoutSize);
3785 font->otm.otmsStrikeoutPosition = SCALE_Y(pOS2->yStrikeoutPosition);
3786 if(!pPost) {
3787 font->otm.otmsUnderscoreSize = 0;
3788 font->otm.otmsUnderscorePosition = 0;
3789 } else {
3790 font->otm.otmsUnderscoreSize = SCALE_Y(pPost->underlineThickness);
3791 font->otm.otmsUnderscorePosition = SCALE_Y(pPost->underlinePosition);
3793 #undef SCALE_X
3794 #undef SCALE_Y
3795 #undef TM
3796 return TRUE;
3799 /*************************************************************
3800 * freetype_get_char_width_info
3802 static BOOL CDECL freetype_get_char_width_info( struct gdi_font *font, struct char_width_info *info )
3804 FT_Face ft_face = get_ft_face( font );
3805 TT_HoriHeader *pHori;
3807 TRACE("%p, %p\n", font, info);
3809 if ((pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea)))
3811 FT_Fixed em_scale = pFT_MulDiv(font->ppem, 1 << 16, ft_face->units_per_EM);
3812 info->lsb = (SHORT)pFT_MulFix(pHori->min_Left_Side_Bearing, em_scale);
3813 info->rsb = (SHORT)pFT_MulFix(pHori->min_Right_Side_Bearing, em_scale);
3814 return TRUE;
3816 return FALSE;
3820 /*************************************************************
3821 * freetype_get_unicode_ranges
3823 * Retrieve a list of supported Unicode ranges for a given font.
3824 * Can be called with NULL gs to calculate the buffer size. Returns
3825 * the number of ranges found.
3827 static DWORD CDECL freetype_get_unicode_ranges( struct gdi_font *font, GLYPHSET *gs )
3829 FT_Face ft_face = get_ft_face( font );
3830 DWORD num_ranges = 0;
3832 if (ft_face->charmap->encoding == FT_ENCODING_UNICODE)
3834 FT_UInt glyph_code;
3835 FT_ULong char_code, char_code_prev;
3837 glyph_code = 0;
3838 char_code_prev = char_code = pFT_Get_First_Char(ft_face, &glyph_code);
3840 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
3841 ft_face->num_glyphs, glyph_code, char_code);
3843 if (!glyph_code) return 0;
3845 if (gs)
3847 gs->ranges[0].wcLow = (USHORT)char_code;
3848 gs->ranges[0].cGlyphs = 0;
3849 gs->cGlyphsSupported = 0;
3852 num_ranges = 1;
3853 while (glyph_code)
3855 if (char_code < char_code_prev)
3857 ERR("expected increasing char code from FT_Get_Next_Char\n");
3858 return 0;
3860 if (char_code - char_code_prev > 1)
3862 num_ranges++;
3863 if (gs)
3865 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
3866 gs->ranges[num_ranges - 1].cGlyphs = 1;
3867 gs->cGlyphsSupported++;
3870 else if (gs)
3872 gs->ranges[num_ranges - 1].cGlyphs++;
3873 gs->cGlyphsSupported++;
3875 char_code_prev = char_code;
3876 char_code = pFT_Get_Next_Char(ft_face, char_code, &glyph_code);
3879 else
3881 DWORD encoding = RtlUlongByteSwap(ft_face->charmap->encoding);
3882 FIXME("encoding %s not supported\n", debugstr_an((char *)&encoding, 4));
3885 return num_ranges;
3888 /*************************************************************************
3889 * Kerning support for TrueType fonts
3892 struct TT_kern_table
3894 USHORT version;
3895 USHORT nTables;
3898 struct TT_kern_subtable
3900 USHORT version;
3901 USHORT length;
3902 union
3904 USHORT word;
3905 struct
3907 USHORT horizontal : 1;
3908 USHORT minimum : 1;
3909 USHORT cross_stream: 1;
3910 USHORT override : 1;
3911 USHORT reserved1 : 4;
3912 USHORT format : 8;
3913 } bits;
3914 } coverage;
3917 struct TT_format0_kern_subtable
3919 USHORT nPairs;
3920 USHORT searchRange;
3921 USHORT entrySelector;
3922 USHORT rangeShift;
3925 struct TT_kern_pair
3927 USHORT left;
3928 USHORT right;
3929 short value;
3932 static DWORD parse_format0_kern_subtable(struct gdi_font *font,
3933 const struct TT_format0_kern_subtable *tt_f0_ks,
3934 const USHORT *glyph_to_char,
3935 KERNINGPAIR *kern_pair, DWORD cPairs)
3937 FT_Face ft_face = get_ft_face( font );
3938 USHORT i, nPairs;
3939 const struct TT_kern_pair *tt_kern_pair;
3941 TRACE("font height %d, units_per_EM %d\n", font->ppem, ft_face->units_per_EM);
3943 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
3945 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
3946 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
3947 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
3949 if (!kern_pair || !cPairs)
3950 return nPairs;
3952 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
3954 nPairs = min(nPairs, cPairs);
3956 for (i = 0; i < nPairs; i++)
3958 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
3959 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
3960 /* this algorithm appears to better match what Windows does */
3961 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
3962 if (kern_pair->iKernAmount < 0)
3964 kern_pair->iKernAmount -= ft_face->units_per_EM / 2;
3965 kern_pair->iKernAmount -= font->ppem;
3967 else if (kern_pair->iKernAmount > 0)
3969 kern_pair->iKernAmount += ft_face->units_per_EM / 2;
3970 kern_pair->iKernAmount += font->ppem;
3972 kern_pair->iKernAmount /= ft_face->units_per_EM;
3974 TRACE("left %u right %u value %d\n",
3975 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
3977 kern_pair++;
3979 TRACE("copied %u entries\n", nPairs);
3980 return nPairs;
3983 /*************************************************************
3984 * freetype_get_kerning_pairs
3986 static DWORD CDECL freetype_get_kerning_pairs( struct gdi_font *font, KERNINGPAIR **pairs )
3988 FT_Face ft_face = get_ft_face( font );
3989 DWORD length, count = 0;
3990 void *buf;
3991 const struct TT_kern_table *tt_kern_table;
3992 const struct TT_kern_subtable *tt_kern_subtable;
3993 USHORT i, nTables;
3994 USHORT *glyph_to_char;
3996 length = freetype_get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
3998 if (length == GDI_ERROR)
4000 TRACE("no kerning data in the font\n");
4001 return 0;
4004 buf = RtlAllocateHeap(GetProcessHeap(), 0, length);
4005 if (!buf) return 0;
4007 freetype_get_font_data(font, MS_KERN_TAG, 0, buf, length);
4009 /* build a glyph index to char code map */
4010 glyph_to_char = RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
4011 if (!glyph_to_char)
4013 RtlFreeHeap(GetProcessHeap(), 0, buf);
4014 return 0;
4017 if (ft_face->charmap->encoding == FT_ENCODING_UNICODE)
4019 FT_UInt glyph_code;
4020 FT_ULong char_code;
4022 glyph_code = 0;
4023 char_code = pFT_Get_First_Char(ft_face, &glyph_code);
4025 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
4026 ft_face->num_glyphs, glyph_code, char_code);
4028 while (glyph_code)
4030 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
4032 /* FIXME: This doesn't match what Windows does: it does some fancy
4033 * things with duplicate glyph index to char code mappings, while
4034 * we just avoid overriding existing entries.
4036 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
4037 glyph_to_char[glyph_code] = (USHORT)char_code;
4039 char_code = pFT_Get_Next_Char(ft_face, char_code, &glyph_code);
4042 else
4044 DWORD encoding = RtlUlongByteSwap(ft_face->charmap->encoding);
4045 ULONG n;
4047 FIXME("encoding %s not supported\n", debugstr_an((char *)&encoding, 4));
4048 for (n = 0; n <= 65535; n++)
4049 glyph_to_char[n] = (USHORT)n;
4052 tt_kern_table = buf;
4053 nTables = GET_BE_WORD(tt_kern_table->nTables);
4054 TRACE("version %u, nTables %u\n",
4055 GET_BE_WORD(tt_kern_table->version), nTables);
4057 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
4059 for (i = 0; i < nTables; i++)
4061 struct TT_kern_subtable tt_kern_subtable_copy;
4063 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
4064 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
4065 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
4067 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
4068 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
4069 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
4071 /* According to the TrueType specification this is the only format
4072 * that will be properly interpreted by Windows and OS/2
4074 if (tt_kern_subtable_copy.coverage.bits.format == 0)
4076 DWORD new_chunk, old_total = count;
4078 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
4079 glyph_to_char, NULL, 0);
4080 count += new_chunk;
4082 if (!*pairs)
4083 *pairs = RtlAllocateHeap(GetProcessHeap(), 0, count * sizeof(**pairs));
4084 else
4085 *pairs = RtlReAllocateHeap(GetProcessHeap(), 0, *pairs, count * sizeof(**pairs));
4087 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
4088 glyph_to_char, *pairs + old_total, new_chunk);
4090 else
4091 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
4093 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
4096 RtlFreeHeap(GetProcessHeap(), 0, glyph_to_char);
4097 RtlFreeHeap(GetProcessHeap(), 0, buf);
4098 return count;
4101 static const struct font_backend_funcs font_funcs =
4103 freetype_load_fonts,
4104 fontconfig_enum_family_fallbacks,
4105 freetype_add_font,
4106 freetype_add_mem_font,
4107 freetype_load_font,
4108 freetype_get_font_data,
4109 freetype_get_aa_flags,
4110 freetype_get_glyph_index,
4111 freetype_get_default_glyph,
4112 freetype_get_glyph_outline,
4113 freetype_get_unicode_ranges,
4114 freetype_get_char_width_info,
4115 freetype_set_outline_text_metrics,
4116 freetype_set_bitmap_text_metrics,
4117 freetype_get_kerning_pairs,
4118 freetype_destroy_font
4121 static NTSTATUS init_freetype_lib( HMODULE module, DWORD reason, const void *ptr_in, void *ptr_out )
4123 callback_funcs = ptr_in;
4124 if (!init_freetype()) return STATUS_DLL_NOT_FOUND;
4125 #ifdef SONAME_LIBFONTCONFIG
4126 init_fontconfig();
4127 #endif
4128 NtQueryDefaultLocale( FALSE, &system_lcid );
4129 *(const struct font_backend_funcs **)ptr_out = &font_funcs;
4130 return STATUS_SUCCESS;
4133 #else /* HAVE_FREETYPE */
4135 static NTSTATUS init_freetype_lib( HMODULE module, DWORD reason, const void *ptr_in, void *ptr_out )
4137 return STATUS_DLL_NOT_FOUND;
4140 #endif /* HAVE_FREETYPE */
4142 NTSTATUS CDECL __wine_init_unix_lib( HMODULE module, DWORD reason, const void *ptr_in, void *ptr_out )
4144 if (reason != DLL_PROCESS_ATTACH) return STATUS_SUCCESS;
4146 if (ptr_in) return init_freetype_lib( module, reason, ptr_in, ptr_out );
4147 else return init_opengl_lib( module, reason, ptr_in, ptr_out );