gdi32: Load font list directly from fontconfig cache.
[wine.git] / dlls / gdi32 / freetype.c
blob7d8bc5f5b05a134cf0a0561b9d9c9a06a045c1c8
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 )
1348 FcPattern *ret, *pattern = pFcPatternCreate();
1349 FcResult result;
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 ret = pFcFontMatch( NULL, pattern, &result );
1357 pFcPatternDestroy( pattern );
1358 if (ret && result == FcResultMatch) return ret;
1359 pFcPatternDestroy( ret );
1360 return NULL;
1363 static void fontconfig_add_font( FcPattern *pattern, DWORD flags )
1365 const char *unix_name, *format;
1366 WCHAR *dos_name;
1367 FcBool scalable;
1368 DWORD aa_flags;
1369 int face_index;
1371 TRACE( "(%p %#x)\n", pattern, flags );
1373 if (pFcPatternGetString( pattern, FC_FILE, 0, (FcChar8 **)&unix_name ) != FcResultMatch)
1374 return;
1376 if (pFcPatternGetBool( pattern, FC_SCALABLE, 0, &scalable ) != FcResultMatch)
1377 scalable = FALSE;
1379 if (pFcPatternGetString( pattern, FC_FONTFORMAT, 0, (FcChar8 **)&format ) != FcResultMatch)
1381 TRACE( "ignoring unknown font format %s\n", debugstr_a(unix_name) );
1382 return;
1385 if (!strcmp( format, "Type 1" ))
1387 TRACE( "ignoring Type 1 font %s\n", debugstr_a(unix_name) );
1388 return;
1391 if (!scalable && !(flags & ADDFONT_ALLOW_BITMAP))
1393 TRACE( "ignoring non-scalable font %s\n", debugstr_a(unix_name) );
1394 return;
1397 if (!(aa_flags = parse_aa_pattern( pattern ))) aa_flags = default_aa_flags;
1398 flags |= ADDFONT_AA_FLAGS(aa_flags);
1400 if (pFcPatternGetInteger( pattern, FC_INDEX, 0, &face_index ) != FcResultMatch)
1401 face_index = 0;
1403 dos_name = get_dos_file_name( unix_name );
1404 add_unix_face( unix_name, dos_name, NULL, 0, face_index, flags, NULL );
1405 RtlFreeHeap( GetProcessHeap(), 0, dos_name );
1408 static void init_fontconfig(void)
1410 void *fc_handle = dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW);
1412 if (!fc_handle)
1414 TRACE("Wine cannot find the fontconfig library (%s).\n", SONAME_LIBFONTCONFIG);
1415 return;
1418 #define LOAD_FUNCPTR(f) if((p##f = dlsym(fc_handle, #f)) == NULL){WARN("Can't find symbol %s\n", #f); return;}
1419 LOAD_FUNCPTR(FcConfigSubstitute);
1420 LOAD_FUNCPTR(FcDefaultSubstitute);
1421 LOAD_FUNCPTR(FcFontList);
1422 LOAD_FUNCPTR(FcFontMatch);
1423 LOAD_FUNCPTR(FcFontSetDestroy);
1424 LOAD_FUNCPTR(FcInit);
1425 LOAD_FUNCPTR(FcPatternAddString);
1426 LOAD_FUNCPTR(FcPatternCreate);
1427 LOAD_FUNCPTR(FcPatternDestroy);
1428 LOAD_FUNCPTR(FcPatternGetBool);
1429 LOAD_FUNCPTR(FcPatternGetInteger);
1430 LOAD_FUNCPTR(FcPatternGetString);
1431 LOAD_FUNCPTR(FcConfigGetFontDirs);
1432 LOAD_FUNCPTR(FcConfigGetCurrent);
1433 LOAD_FUNCPTR(FcCacheCopySet);
1434 LOAD_FUNCPTR(FcCacheNumSubdir);
1435 LOAD_FUNCPTR(FcCacheSubdir);
1436 LOAD_FUNCPTR(FcDirCacheRead);
1437 LOAD_FUNCPTR(FcDirCacheUnload);
1438 LOAD_FUNCPTR(FcStrListCreate);
1439 LOAD_FUNCPTR(FcStrListDone);
1440 LOAD_FUNCPTR(FcStrListNext);
1441 LOAD_FUNCPTR(FcStrSetAdd);
1442 LOAD_FUNCPTR(FcStrSetCreate);
1443 LOAD_FUNCPTR(FcStrSetDestroy);
1444 LOAD_FUNCPTR(FcStrSetMember);
1445 #undef LOAD_FUNCPTR
1447 if (pFcInit())
1449 FcPattern *pattern = pFcPatternCreate();
1450 pFcConfigSubstitute( NULL, pattern, FcMatchFont );
1451 default_aa_flags = parse_aa_pattern( pattern );
1452 pFcPatternDestroy( pattern );
1454 if (!default_aa_flags)
1456 FcPattern *pattern = pFcPatternCreate();
1457 pFcConfigSubstitute( NULL, pattern, FcMatchPattern );
1458 default_aa_flags = parse_aa_pattern( pattern );
1459 pFcPatternDestroy( pattern );
1461 pattern_serif = create_family_pattern( "serif" );
1462 pattern_fixed = create_family_pattern( "monospace" );
1463 pattern_sans = create_family_pattern( "sans" );
1465 TRACE( "enabled, default flags = %x\n", default_aa_flags );
1466 fontconfig_enabled = TRUE;
1470 static void fontconfig_add_fonts_from_dir_list( FcConfig *config, FcStrList *dir_list, FcStrSet *done_set, DWORD flags )
1472 const FcChar8 *dir;
1473 FcFontSet *font_set;
1474 FcStrList *subdir_list = NULL;
1475 FcStrSet *subdir_set = NULL;
1476 FcCache *cache = NULL;
1477 int i;
1479 TRACE( "(%p %p %p %#x)\n", config, dir_list, done_set, flags );
1481 while ((dir = pFcStrListNext( dir_list )))
1483 if (pFcStrSetMember( done_set, dir )) continue;
1485 TRACE( "adding fonts from %s\n", dir );
1486 if (!(cache = pFcDirCacheRead( dir, FcFalse, config ))) continue;
1488 if (!(font_set = pFcCacheCopySet( cache ))) goto done;
1489 for (i = 0; i < font_set->nfont; i++)
1490 fontconfig_add_font( font_set->fonts[i], flags );
1491 pFcFontSetDestroy( font_set );
1492 font_set = NULL;
1494 if (!(subdir_set = pFcStrSetCreate())) goto done;
1495 for (i = 0; i < pFcCacheNumSubdir( cache ); i++)
1496 pFcStrSetAdd( subdir_set, pFcCacheSubdir( cache, i ) );
1497 pFcDirCacheUnload( cache );
1498 cache = NULL;
1500 if (!(subdir_list = pFcStrListCreate( subdir_set ))) goto done;
1501 pFcStrSetDestroy( subdir_set );
1502 subdir_set = NULL;
1504 pFcStrSetAdd( done_set, dir );
1505 fontconfig_add_fonts_from_dir_list( config, subdir_list, done_set, flags );
1506 pFcStrListDone( subdir_list );
1507 subdir_list = NULL;
1510 done:
1511 if (font_set) pFcFontSetDestroy( font_set );
1512 if (subdir_list) pFcStrListDone( subdir_list );
1513 if (subdir_set) pFcStrSetDestroy( subdir_set );
1514 if (cache) pFcDirCacheUnload( cache );
1517 static void load_fontconfig_fonts( void )
1519 FcStrList *dir_list = NULL;
1520 FcStrSet *done_set = NULL;
1521 FcConfig *config;
1523 if (!fontconfig_enabled) return;
1524 if (!(config = pFcConfigGetCurrent())) goto done;
1525 if (!(done_set = pFcStrSetCreate())) goto done;
1526 if (!(dir_list = pFcConfigGetFontDirs( config ))) goto done;
1528 fontconfig_add_fonts_from_dir_list( config, dir_list, done_set, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE );
1530 done:
1531 if (dir_list) pFcStrListDone( dir_list );
1532 if (done_set) pFcStrSetDestroy( done_set );
1535 #elif defined(HAVE_CARBON_CARBON_H)
1537 static void load_mac_font_callback(const void *value, void *context)
1539 CFStringRef pathStr = value;
1540 CFIndex len;
1541 char* path;
1543 len = CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr);
1544 path = RtlAllocateHeap(GetProcessHeap(), 0, len);
1545 if (path && CFStringGetFileSystemRepresentation(pathStr, path, len))
1547 TRACE("font file %s\n", path);
1548 AddFontToList(NULL, path, NULL, 0, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
1550 RtlFreeHeap(GetProcessHeap(), 0, path);
1553 static void load_mac_fonts(void)
1555 CFStringRef removeDupesKey;
1556 CFBooleanRef removeDupesValue;
1557 CFDictionaryRef options;
1558 CTFontCollectionRef col;
1559 CFArrayRef descs;
1560 CFMutableSetRef paths;
1561 CFIndex i;
1563 removeDupesKey = kCTFontCollectionRemoveDuplicatesOption;
1564 removeDupesValue = kCFBooleanTrue;
1565 options = CFDictionaryCreate(NULL, (const void**)&removeDupesKey, (const void**)&removeDupesValue, 1,
1566 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1567 col = CTFontCollectionCreateFromAvailableFonts(options);
1568 if (options) CFRelease(options);
1569 if (!col)
1571 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
1572 return;
1575 descs = CTFontCollectionCreateMatchingFontDescriptors(col);
1576 CFRelease(col);
1577 if (!descs)
1579 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
1580 return;
1583 paths = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
1584 if (!paths)
1586 WARN("CFSetCreateMutable failed\n");
1587 CFRelease(descs);
1588 return;
1591 for (i = 0; i < CFArrayGetCount(descs); i++)
1593 CTFontDescriptorRef desc;
1594 CFURLRef url;
1595 CFStringRef ext;
1596 CFStringRef path;
1598 desc = CFArrayGetValueAtIndex(descs, i);
1600 #if defined(MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
1601 url = CTFontDescriptorCopyAttribute(desc, kCTFontURLAttribute);
1602 #else
1603 /* CTFontDescriptor doesn't support kCTFontURLAttribute prior to 10.6, so
1604 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
1606 CTFontRef font;
1607 ATSFontRef atsFont;
1608 OSStatus status;
1609 FSRef fsref;
1611 font = CTFontCreateWithFontDescriptor(desc, 0, NULL);
1612 if (!font) continue;
1614 atsFont = CTFontGetPlatformFont(font, NULL);
1615 if (!atsFont)
1617 CFRelease(font);
1618 continue;
1621 status = ATSFontGetFileReference(atsFont, &fsref);
1622 CFRelease(font);
1623 if (status != noErr) continue;
1625 url = CFURLCreateFromFSRef(NULL, &fsref);
1627 #endif
1628 if (!url) continue;
1630 ext = CFURLCopyPathExtension(url);
1631 if (ext)
1633 BOOL skip = (CFStringCompare(ext, CFSTR("pfa"), kCFCompareCaseInsensitive) == kCFCompareEqualTo ||
1634 CFStringCompare(ext, CFSTR("pfb"), kCFCompareCaseInsensitive) == kCFCompareEqualTo);
1635 CFRelease(ext);
1636 if (skip)
1638 CFRelease(url);
1639 continue;
1643 path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
1644 CFRelease(url);
1645 if (!path) continue;
1647 CFSetAddValue(paths, path);
1648 CFRelease(path);
1651 CFRelease(descs);
1653 CFSetApplyFunction(paths, load_mac_font_callback, NULL);
1654 CFRelease(paths);
1657 #endif
1660 static BOOL init_freetype(void)
1662 ft_handle = dlopen(SONAME_LIBFREETYPE, RTLD_NOW);
1663 if(!ft_handle) {
1664 WINE_MESSAGE(
1665 "Wine cannot find the FreeType font library. To enable Wine to\n"
1666 "use TrueType fonts please install a version of FreeType greater than\n"
1667 "or equal to 2.0.5.\n"
1668 "http://www.freetype.org\n");
1669 return FALSE;
1672 #define LOAD_FUNCPTR(f) if((p##f = dlsym(ft_handle, #f)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
1674 LOAD_FUNCPTR(FT_Done_Face)
1675 LOAD_FUNCPTR(FT_Get_Char_Index)
1676 LOAD_FUNCPTR(FT_Get_First_Char)
1677 LOAD_FUNCPTR(FT_Get_Next_Char)
1678 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
1679 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
1680 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
1681 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
1682 LOAD_FUNCPTR(FT_Init_FreeType)
1683 LOAD_FUNCPTR(FT_Library_Version)
1684 LOAD_FUNCPTR(FT_Load_Glyph)
1685 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
1686 LOAD_FUNCPTR(FT_Matrix_Multiply)
1687 LOAD_FUNCPTR(FT_MulDiv)
1688 #ifndef FT_MULFIX_INLINED
1689 LOAD_FUNCPTR(FT_MulFix)
1690 #endif
1691 LOAD_FUNCPTR(FT_New_Face)
1692 LOAD_FUNCPTR(FT_New_Memory_Face)
1693 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
1694 LOAD_FUNCPTR(FT_Outline_Get_CBox)
1695 LOAD_FUNCPTR(FT_Outline_Transform)
1696 LOAD_FUNCPTR(FT_Outline_Translate)
1697 LOAD_FUNCPTR(FT_Render_Glyph)
1698 LOAD_FUNCPTR(FT_Set_Charmap)
1699 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
1700 LOAD_FUNCPTR(FT_Vector_Length)
1701 LOAD_FUNCPTR(FT_Vector_Transform)
1702 LOAD_FUNCPTR(FT_Vector_Unit)
1703 #undef LOAD_FUNCPTR
1704 /* Don't warn if these ones are missing */
1705 pFT_Outline_Embolden = dlsym(ft_handle, "FT_Outline_Embolden");
1706 pFT_Get_TrueType_Engine_Type = dlsym(ft_handle, "FT_Get_TrueType_Engine_Type");
1707 #ifdef FT_LCD_FILTER_H
1708 pFT_Library_SetLcdFilter = dlsym(ft_handle, "FT_Library_SetLcdFilter");
1709 #endif
1710 pFT_Property_Set = dlsym(ft_handle, "FT_Property_Set");
1712 if(pFT_Init_FreeType(&library) != 0) {
1713 ERR("Can't init FreeType library\n");
1714 dlclose(ft_handle);
1715 ft_handle = NULL;
1716 return FALSE;
1718 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
1720 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
1721 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
1722 ((FT_Version.minor << 8) & 0x00ff00) |
1723 ((FT_Version.patch ) & 0x0000ff);
1725 /* In FreeType < 2.8.1 v40's FT_LOAD_TARGET_MONO has broken advance widths. */
1726 if (pFT_Property_Set && FT_SimpleVersion < FT_VERSION_VALUE(2, 8, 1))
1728 FT_UInt interpreter_version = 35;
1729 pFT_Property_Set( library, "truetype", "interpreter-version", &interpreter_version );
1732 return TRUE;
1734 sym_not_found:
1735 WINE_MESSAGE(
1736 "Wine cannot find certain functions that it needs inside the FreeType\n"
1737 "font library. To enable Wine to use TrueType fonts please upgrade\n"
1738 "FreeType to at least version 2.1.4.\n"
1739 "http://www.freetype.org\n");
1740 dlclose(ft_handle);
1741 ft_handle = NULL;
1742 return FALSE;
1745 /*************************************************************
1746 * freetype_load_fonts
1748 static void CDECL freetype_load_fonts(void)
1750 #ifdef SONAME_LIBFONTCONFIG
1751 load_fontconfig_fonts();
1752 #elif defined(HAVE_CARBON_CARBON_H)
1753 load_mac_fonts();
1754 #elif defined(__ANDROID__)
1755 ReadFontDir("/system/fonts", TRUE);
1756 #endif
1759 /* Some fonts have large usWinDescent values, as a result of storing signed short
1760 in unsigned field. That's probably caused by sTypoDescent vs usWinDescent confusion in
1761 some font generation tools. */
1762 static inline USHORT get_fixed_windescent(USHORT windescent)
1764 return abs((SHORT)windescent);
1767 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
1769 TT_OS2 *pOS2;
1770 TT_HoriHeader *pHori;
1772 LONG ppem;
1773 const LONG MAX_PPEM = (1 << 16) - 1;
1775 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1776 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1778 if(height == 0) height = 16;
1780 /* Calc. height of EM square:
1782 * For +ve lfHeight we have
1783 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
1784 * Re-arranging gives:
1785 * ppem = units_per_em * lfheight / (winAscent + winDescent)
1787 * For -ve lfHeight we have
1788 * |lfHeight| = ppem
1789 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
1790 * with il = winAscent + winDescent - units_per_em]
1794 if(height > 0) {
1795 USHORT windescent = get_fixed_windescent(pOS2->usWinDescent);
1796 if(pOS2->usWinAscent + windescent == 0)
1797 ppem = pFT_MulDiv(ft_face->units_per_EM, height, pHori->Ascender - pHori->Descender);
1798 else
1799 ppem = pFT_MulDiv(ft_face->units_per_EM, height, pOS2->usWinAscent + windescent);
1800 if(ppem > MAX_PPEM) {
1801 WARN("Ignoring too large height %d, ppem %d\n", height, ppem);
1802 ppem = 1;
1805 else if(height >= -MAX_PPEM)
1806 ppem = -height;
1807 else {
1808 WARN("Ignoring too large height %d\n", height);
1809 ppem = 1;
1812 return ppem;
1815 static struct font_mapping *map_font_file( const char *name )
1817 struct font_mapping *mapping;
1818 struct stat st;
1819 int fd;
1821 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
1822 if (fstat( fd, &st ) == -1) goto error;
1824 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
1826 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
1828 mapping->refcount++;
1829 close( fd );
1830 return mapping;
1833 if (!(mapping = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*mapping) )))
1834 goto error;
1836 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
1837 close( fd );
1839 if (mapping->data == MAP_FAILED)
1841 RtlFreeHeap( GetProcessHeap(), 0, mapping );
1842 return NULL;
1844 mapping->refcount = 1;
1845 mapping->dev = st.st_dev;
1846 mapping->ino = st.st_ino;
1847 mapping->size = st.st_size;
1848 list_add_tail( &mappings_list, &mapping->entry );
1849 return mapping;
1851 error:
1852 close( fd );
1853 return NULL;
1856 static void unmap_font_file( struct font_mapping *mapping )
1858 if (!--mapping->refcount)
1860 list_remove( &mapping->entry );
1861 munmap( mapping->data, mapping->size );
1862 RtlFreeHeap( GetProcessHeap(), 0, mapping );
1866 static LONG load_VDMX(struct gdi_font *font, LONG height);
1868 /*************************************************************
1869 * freetype_destroy_font
1871 static void CDECL freetype_destroy_font( struct gdi_font *font )
1873 struct font_private_data *data = font->private;
1875 if (data->ft_face) pFT_Done_Face( data->ft_face );
1876 if (data->mapping) unmap_font_file( data->mapping );
1877 RtlFreeHeap( GetProcessHeap(), 0, data );
1880 /*************************************************************
1881 * freetype_get_font_data
1883 static DWORD CDECL freetype_get_font_data( struct gdi_font *font, DWORD table, DWORD offset,
1884 void *buf, DWORD cbData)
1886 FT_Face ft_face = get_ft_face( font );
1887 FT_ULong len;
1888 FT_Error err;
1890 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
1892 if(!buf)
1893 len = 0;
1894 else
1895 len = cbData;
1897 /* if font is a member of TTC, 'ttcf' tag allows reading from beginning of TTC file,
1898 0 tag means to read from start of collection member data. */
1899 if (font->ttc_item_offset)
1901 if (table == MS_TTCF_TAG)
1902 table = 0;
1903 else if (table == 0)
1904 offset += font->ttc_item_offset;
1907 /* make sure value of len is the value freetype says it needs */
1908 if (buf && len)
1910 FT_ULong needed = 0;
1911 err = pFT_Load_Sfnt_Table(ft_face, RtlUlongByteSwap(table), offset, NULL, &needed);
1912 if( !err && needed < len) len = needed;
1914 err = pFT_Load_Sfnt_Table(ft_face, RtlUlongByteSwap(table), offset, buf, &len);
1915 if (err)
1917 TRACE("Can't find table %s\n", debugstr_an((char*)&table, 4));
1918 return GDI_ERROR;
1920 return len;
1923 /*************************************************************
1924 * load_VDMX
1926 * load the vdmx entry for the specified height
1931 typedef struct {
1932 WORD version;
1933 WORD numRecs;
1934 WORD numRatios;
1935 } VDMX_Header;
1937 typedef struct {
1938 BYTE bCharSet;
1939 BYTE xRatio;
1940 BYTE yStartRatio;
1941 BYTE yEndRatio;
1942 } Ratios;
1944 typedef struct {
1945 WORD recs;
1946 BYTE startsz;
1947 BYTE endsz;
1948 } VDMX_group;
1950 typedef struct {
1951 WORD yPelHeight;
1952 WORD yMax;
1953 WORD yMin;
1954 } VDMX_vTable;
1956 static LONG load_VDMX(struct gdi_font *font, LONG height)
1958 VDMX_Header hdr;
1959 VDMX_group group;
1960 BYTE devXRatio, devYRatio;
1961 USHORT numRecs, numRatios;
1962 DWORD result, offset = -1;
1963 LONG ppem = 0;
1964 int i;
1966 result = freetype_get_font_data(font, MS_VDMX_TAG, 0, &hdr, sizeof(hdr));
1968 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
1969 return ppem;
1971 /* FIXME: need the real device aspect ratio */
1972 devXRatio = 1;
1973 devYRatio = 1;
1975 numRecs = GET_BE_WORD(hdr.numRecs);
1976 numRatios = GET_BE_WORD(hdr.numRatios);
1978 TRACE("version = %d numRecs = %d numRatios = %d\n", GET_BE_WORD(hdr.version), numRecs, numRatios);
1979 for(i = 0; i < numRatios; i++) {
1980 Ratios ratio;
1982 offset = sizeof(hdr) + (i * sizeof(Ratios));
1983 freetype_get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
1984 offset = -1;
1986 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
1988 if (!ratio.bCharSet) continue;
1990 if((ratio.xRatio == 0 &&
1991 ratio.yStartRatio == 0 &&
1992 ratio.yEndRatio == 0) ||
1993 (devXRatio == ratio.xRatio &&
1994 devYRatio >= ratio.yStartRatio &&
1995 devYRatio <= ratio.yEndRatio))
1997 WORD group_offset;
1999 offset = sizeof(hdr) + numRatios * sizeof(ratio) + i * sizeof(group_offset);
2000 freetype_get_font_data(font, MS_VDMX_TAG, offset, &group_offset, sizeof(group_offset));
2001 offset = GET_BE_WORD(group_offset);
2002 break;
2006 if(offset == -1) return 0;
2008 if(freetype_get_font_data(font, MS_VDMX_TAG, offset, &group, sizeof(group)) != GDI_ERROR) {
2009 USHORT recs;
2010 BYTE startsz, endsz;
2011 WORD *vTable;
2013 recs = GET_BE_WORD(group.recs);
2014 startsz = group.startsz;
2015 endsz = group.endsz;
2017 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
2019 vTable = RtlAllocateHeap(GetProcessHeap(), 0, recs * sizeof(VDMX_vTable));
2020 result = freetype_get_font_data(font, MS_VDMX_TAG, offset + sizeof(group), vTable, recs * sizeof(VDMX_vTable));
2021 if(result == GDI_ERROR) {
2022 FIXME("Failed to retrieve vTable\n");
2023 goto end;
2026 if(height > 0) {
2027 for(i = 0; i < recs; i++) {
2028 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2029 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2030 ppem = GET_BE_WORD(vTable[i * 3]);
2032 if(yMax + -yMin == height) {
2033 font->yMax = yMax;
2034 font->yMin = yMin;
2035 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2036 break;
2038 if(yMax + -yMin > height) {
2039 if(--i < 0) {
2040 ppem = 0;
2041 goto end; /* failed */
2043 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2044 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2045 ppem = GET_BE_WORD(vTable[i * 3]);
2046 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2047 break;
2050 if(!font->yMax) {
2051 ppem = 0;
2052 TRACE("ppem not found for height %d\n", height);
2054 } else {
2055 ppem = -height;
2056 if(ppem < startsz || ppem > endsz)
2058 ppem = 0;
2059 goto end;
2062 for(i = 0; i < recs; i++) {
2063 USHORT yPelHeight;
2064 yPelHeight = GET_BE_WORD(vTable[i * 3]);
2066 if(yPelHeight > ppem)
2068 ppem = 0;
2069 break; /* failed */
2072 if(yPelHeight == ppem) {
2073 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2074 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2075 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
2076 break;
2080 end:
2081 RtlFreeHeap(GetProcessHeap(), 0, vTable);
2084 return ppem;
2087 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
2089 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
2090 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
2091 FT_Int i;
2093 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
2095 for (i = 0; i < ft_face->num_charmaps; i++)
2097 if (ft_face->charmaps[i]->encoding == encoding)
2099 TRACE("found cmap with platform_id %u, encoding_id %u\n",
2100 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
2102 switch (ft_face->charmaps[i]->platform_id)
2104 default:
2105 cmap_def = ft_face->charmaps[i];
2106 break;
2107 case 0: /* Apple Unicode */
2108 cmap0 = ft_face->charmaps[i];
2109 break;
2110 case 1: /* Macintosh */
2111 cmap1 = ft_face->charmaps[i];
2112 break;
2113 case 2: /* ISO */
2114 cmap2 = ft_face->charmaps[i];
2115 break;
2116 case 3: /* Microsoft */
2117 cmap3 = ft_face->charmaps[i];
2118 break;
2122 if (cmap3) /* prefer Microsoft cmap table */
2123 ft_err = pFT_Set_Charmap(ft_face, cmap3);
2124 else if (cmap1)
2125 ft_err = pFT_Set_Charmap(ft_face, cmap1);
2126 else if (cmap2)
2127 ft_err = pFT_Set_Charmap(ft_face, cmap2);
2128 else if (cmap0)
2129 ft_err = pFT_Set_Charmap(ft_face, cmap0);
2130 else if (cmap_def)
2131 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
2134 return ft_err == FT_Err_Ok;
2138 static FT_Encoding pick_charmap( FT_Face face, int charset )
2140 static const FT_Encoding regular_order[] = { FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, FT_ENCODING_MS_SYMBOL, 0 };
2141 static const FT_Encoding symbol_order[] = { FT_ENCODING_MS_SYMBOL, FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, 0 };
2142 const FT_Encoding *encs = regular_order;
2144 if (charset == SYMBOL_CHARSET) encs = symbol_order;
2146 while (*encs != 0)
2148 if (select_charmap( face, *encs )) break;
2149 encs++;
2152 if (!face->charmap && face->num_charmaps)
2154 if (!pFT_Set_Charmap(face, face->charmaps[0]))
2155 return face->charmap->encoding;
2158 return *encs;
2161 static BOOL get_gasp_flags( struct gdi_font *font, WORD *flags )
2163 FT_Face ft_face = get_ft_face( font );
2164 DWORD size;
2165 WORD buf[16]; /* Enough for seven ranges before we need to alloc */
2166 WORD *alloced = NULL, *ptr = buf;
2167 WORD num_recs, version;
2168 BOOL ret = FALSE;
2170 *flags = 0;
2171 size = freetype_get_font_data( font, MS_GASP_TAG, 0, NULL, 0 );
2172 if (size == GDI_ERROR) return FALSE;
2173 if (size < 4 * sizeof(WORD)) return FALSE;
2174 if (size > sizeof(buf))
2176 ptr = alloced = RtlAllocateHeap( GetProcessHeap(), 0, size );
2177 if (!ptr) return FALSE;
2180 freetype_get_font_data( font, MS_GASP_TAG, 0, ptr, size );
2182 version = GET_BE_WORD( *ptr++ );
2183 num_recs = GET_BE_WORD( *ptr++ );
2185 if (version > 1 || size < (num_recs * 2 + 2) * sizeof(WORD))
2187 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version, size, num_recs );
2188 goto done;
2191 while (num_recs--)
2193 *flags = GET_BE_WORD( *(ptr + 1) );
2194 if (ft_face->size->metrics.y_ppem <= GET_BE_WORD( *ptr )) break;
2195 ptr += 2;
2197 TRACE( "got flags %04x for ppem %d\n", *flags, ft_face->size->metrics.y_ppem );
2198 ret = TRUE;
2200 done:
2201 RtlFreeHeap( GetProcessHeap(), 0, alloced );
2202 return ret;
2205 /*************************************************************
2206 * fontconfig_enum_family_fallbacks
2208 static BOOL CDECL fontconfig_enum_family_fallbacks( DWORD pitch_and_family, int index,
2209 WCHAR buffer[LF_FACESIZE] )
2211 #ifdef SONAME_LIBFONTCONFIG
2212 FcPattern *pat;
2213 char *str;
2214 DWORD len;
2216 if ((pitch_and_family & FIXED_PITCH) || (pitch_and_family & 0xf0) == FF_MODERN) pat = pattern_fixed;
2217 else if ((pitch_and_family & 0xf0) == FF_ROMAN) pat = pattern_serif;
2218 else pat = pattern_sans;
2220 if (!pat) return FALSE;
2221 if (pFcPatternGetString( pat, FC_FAMILY, index, (FcChar8 **)&str ) != FcResultMatch) return FALSE;
2222 RtlUTF8ToUnicodeN( buffer, (LF_FACESIZE - 1) * sizeof(WCHAR), &len, str, strlen(str) );
2223 buffer[len / sizeof(WCHAR)] = 0;
2224 return TRUE;
2225 #endif
2226 return FALSE;
2229 static DWORD get_ttc_offset( FT_Face ft_face, UINT face_index )
2231 FT_ULong len;
2232 DWORD header, offset;
2234 /* see if it's a TTC */
2235 len = sizeof(header);
2236 if (pFT_Load_Sfnt_Table( ft_face, 0, 0, (void *)&header, &len )) return 0;
2237 if (header != MS_TTCF_TAG) return 0;
2239 len = sizeof(offset);
2240 if (pFT_Load_Sfnt_Table( ft_face, 0, (3 + face_index) * sizeof(DWORD), (void *)&offset, &len ))
2241 return 0;
2243 return GET_BE_DWORD( offset );
2246 /*************************************************************
2247 * freetype_load_font
2249 static BOOL CDECL freetype_load_font( struct gdi_font *font )
2251 struct font_private_data *data;
2252 INT width = 0, height;
2253 FT_Face ft_face;
2254 void *data_ptr;
2255 SIZE_T data_size;
2257 if (!(data = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data) ))) return FALSE;
2258 font->private = data;
2260 if (font->file[0])
2262 char *filename = get_unix_file_name( font->file );
2263 data->mapping = map_font_file( filename );
2264 RtlFreeHeap( GetProcessHeap(), 0, filename );
2265 if (!data->mapping)
2267 WARN("failed to map %s\n", debugstr_w(font->file));
2268 return FALSE;
2270 data_ptr = data->mapping->data;
2271 data_size = data->mapping->size;
2273 else
2275 data_ptr = font->data_ptr;
2276 data_size = font->data_size;
2279 if (pFT_New_Memory_Face( library, data_ptr, data_size, font->face_index, &ft_face )) return FALSE;
2281 data->ft_face = ft_face;
2282 font->scalable = FT_IS_SCALABLE( ft_face );
2283 if (!font->fs.fsCsb[0]) get_fontsig( ft_face, &font->fs );
2284 if (!font->ntmFlags) font->ntmFlags = get_ntm_flags( ft_face );
2285 if (!font->aa_flags) font->aa_flags = ADDFONT_AA_FLAGS( default_aa_flags );
2286 if (!font->otm.otmpFamilyName)
2288 font->otm.otmpFamilyName = (char *)ft_face_get_family_name( ft_face, system_lcid );
2289 font->otm.otmpStyleName = (char *)ft_face_get_style_name( ft_face, system_lcid );
2290 font->otm.otmpFaceName = (char *)ft_face_get_full_name( ft_face, system_lcid );
2293 if (font->scalable)
2295 /* load the VDMX table if we have one */
2296 font->ppem = load_VDMX( font, font->lf.lfHeight );
2297 if (font->ppem == 0) font->ppem = calc_ppem_for_height( ft_face, font->lf.lfHeight );
2298 TRACE( "height %d => ppem %d\n", font->lf.lfHeight, font->ppem );
2299 height = font->ppem;
2300 font->ttc_item_offset = get_ttc_offset( ft_face, font->face_index );
2302 else
2304 struct bitmap_font_size size;
2306 get_bitmap_size( ft_face, &size );
2307 width = size.x_ppem >> 6;
2308 height = size.y_ppem >> 6;
2309 font->ppem = height;
2312 pFT_Set_Pixel_Sizes( ft_face, width, height );
2313 pick_charmap( ft_face, font->charset );
2314 return TRUE;
2318 /*************************************************************
2319 * freetype_get_aa_flags
2321 static UINT CDECL freetype_get_aa_flags( struct gdi_font *font, UINT aa_flags, BOOL antialias_fakes )
2323 /* fixup the antialiasing flags for that font */
2324 switch (aa_flags)
2326 case WINE_GGO_HRGB_BITMAP:
2327 case WINE_GGO_HBGR_BITMAP:
2328 case WINE_GGO_VRGB_BITMAP:
2329 case WINE_GGO_VBGR_BITMAP:
2330 if (is_subpixel_rendering_enabled()) break;
2331 aa_flags = GGO_GRAY4_BITMAP;
2332 /* fall through */
2333 case GGO_GRAY2_BITMAP:
2334 case GGO_GRAY4_BITMAP:
2335 case GGO_GRAY8_BITMAP:
2336 case WINE_GGO_GRAY16_BITMAP:
2337 if ((!antialias_fakes || (!font->fake_bold && !font->fake_italic)) && is_hinting_enabled())
2339 WORD gasp_flags;
2340 if (get_gasp_flags( font, &gasp_flags ) && !(gasp_flags & GASP_DOGRAY))
2342 TRACE( "font %s %d aa disabled by GASP\n",
2343 debugstr_w(font->lf.lfFaceName), font->lf.lfHeight );
2344 aa_flags = GGO_BITMAP;
2348 return aa_flags;
2351 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
2353 pt->x.value = vec->x >> 6;
2354 pt->x.fract = (vec->x & 0x3f) << 10;
2355 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
2356 pt->y.value = vec->y >> 6;
2357 pt->y.fract = (vec->y & 0x3f) << 10;
2358 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
2361 static FT_UInt get_glyph_index_symbol( struct gdi_font *font, UINT glyph )
2363 FT_Face ft_face = get_ft_face( font );
2364 FT_UInt ret;
2366 if (glyph < 0x100) glyph += 0xf000;
2367 /* there are a number of old pre-Unicode "broken" TTFs, which
2368 do have symbols at U+00XX instead of U+f0XX */
2369 if (!(ret = pFT_Get_Char_Index(ft_face, glyph)))
2370 ret = pFT_Get_Char_Index(ft_face, glyph - 0xf000);
2372 return ret;
2375 /*************************************************************
2376 * freetype_get_glyph_index
2378 static BOOL CDECL freetype_get_glyph_index( struct gdi_font *font, UINT *glyph, BOOL use_encoding )
2380 FT_Face ft_face = get_ft_face( font );
2382 if (!use_encoding ^ (ft_face->charmap->encoding == FT_ENCODING_NONE)) return FALSE;
2384 if (ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
2386 if (!(*glyph = get_glyph_index_symbol( font, *glyph )))
2388 WCHAR wc = *glyph;
2389 DWORD len;
2390 char ch;
2392 RtlUnicodeToMultiByteN( &ch, 1, &len, &wc, sizeof(wc) );
2393 if (len) *glyph = get_glyph_index_symbol( font, (unsigned char)ch );
2395 return TRUE;
2397 *glyph = pFT_Get_Char_Index( ft_face, *glyph );
2398 return TRUE;
2401 /*************************************************************
2402 * freetype_get_default_glyph
2404 static UINT CDECL freetype_get_default_glyph( struct gdi_font *font )
2406 FT_Face ft_face = get_ft_face( font );
2407 FT_WinFNT_HeaderRec winfnt;
2408 TT_OS2 *pOS2;
2410 if ((pOS2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 )))
2412 UINT glyph = pOS2->usDefaultChar;
2413 freetype_get_glyph_index( font, &glyph, TRUE );
2414 return glyph;
2416 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt )) return winfnt.default_char + winfnt.first_char;
2417 return 32;
2421 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
2423 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
2424 return !memcmp(matrix, &identity, sizeof(FMAT2));
2427 static inline FT_Vector normalize_vector(FT_Vector *vec)
2429 FT_Vector out;
2430 FT_Fixed len;
2431 len = pFT_Vector_Length(vec);
2432 if (len) {
2433 out.x = (vec->x << 6) / len;
2434 out.y = (vec->y << 6) / len;
2436 else
2437 out.x = out.y = 0;
2438 return out;
2441 /* get_glyph_outline() glyph transform matrices index */
2442 enum matrices_index
2444 matrix_hori,
2445 matrix_vert,
2446 matrix_unrotated
2449 static BOOL get_transform_matrices( struct gdi_font *font, BOOL vertical, const MAT2 *user_transform,
2450 FT_Matrix matrices[3] )
2452 static const FT_Matrix identity_mat = { (1 << 16), 0, 0, (1 << 16) };
2453 BOOL needs_transform = FALSE;
2454 double width_ratio;
2455 int i;
2457 matrices[matrix_unrotated] = identity_mat;
2459 /* Scaling factor */
2460 if (font->aveWidth)
2462 if (!freetype_set_outline_text_metrics( font )) freetype_set_bitmap_text_metrics( font );
2463 width_ratio = (double)font->aveWidth;
2464 width_ratio /= (double)font->otm.otmTextMetrics.tmAveCharWidth;
2466 else
2467 width_ratio = font->scale_y;
2469 /* Scaling transform */
2470 if (width_ratio != 1.0 || font->scale_y != 1)
2472 FT_Matrix scale_mat;
2473 scale_mat.xx = FT_FixedFromFloat( width_ratio );
2474 scale_mat.xy = 0;
2475 scale_mat.yx = 0;
2476 scale_mat.yy = font->scale_y << 16;
2478 pFT_Matrix_Multiply( &scale_mat, &matrices[matrix_unrotated] );
2479 needs_transform = TRUE;
2482 /* Slant transform */
2483 if (font->fake_italic)
2485 FT_Matrix slant_mat;
2486 slant_mat.xx = (1 << 16);
2487 slant_mat.xy = (1 << 16) >> 2;
2488 slant_mat.yx = 0;
2489 slant_mat.yy = (1 << 16);
2491 pFT_Matrix_Multiply( &slant_mat, &matrices[matrix_unrotated] );
2492 needs_transform = TRUE;
2495 /* Rotation transform */
2496 matrices[matrix_hori] = matrices[matrix_unrotated];
2497 if (font->scalable && font->lf.lfOrientation % 3600)
2499 FT_Matrix rotation_mat;
2500 FT_Vector angle;
2502 pFT_Vector_Unit( &angle, pFT_MulDiv( 1 << 16, font->lf.lfOrientation, 10 ) );
2503 rotation_mat.xx = angle.x;
2504 rotation_mat.xy = -angle.y;
2505 rotation_mat.yx = angle.y;
2506 rotation_mat.yy = angle.x;
2507 pFT_Matrix_Multiply( &rotation_mat, &matrices[matrix_hori] );
2508 needs_transform = TRUE;
2511 /* Vertical transform */
2512 matrices[matrix_vert] = matrices[matrix_hori];
2513 if (vertical)
2515 FT_Matrix vertical_mat = { 0, -(1 << 16), 1 << 16, 0 }; /* 90 degrees rotation */
2517 pFT_Matrix_Multiply( &vertical_mat, &matrices[matrix_vert] );
2518 needs_transform = TRUE;
2521 /* World transform */
2522 if (!is_identity_FMAT2( &font->matrix ))
2524 FT_Matrix world_mat;
2525 world_mat.xx = FT_FixedFromFloat( font->matrix.eM11 );
2526 world_mat.xy = -FT_FixedFromFloat( font->matrix.eM21 );
2527 world_mat.yx = -FT_FixedFromFloat( font->matrix.eM12 );
2528 world_mat.yy = FT_FixedFromFloat( font->matrix.eM22 );
2530 for (i = 0; i < 3; i++)
2531 pFT_Matrix_Multiply( &world_mat, &matrices[i] );
2532 needs_transform = TRUE;
2535 /* Extra transformation specified by caller */
2536 if (user_transform)
2538 FT_Matrix user_mat;
2539 user_mat.xx = FT_FixedFromFIXED( user_transform->eM11 );
2540 user_mat.xy = FT_FixedFromFIXED( user_transform->eM21 );
2541 user_mat.yx = FT_FixedFromFIXED( user_transform->eM12 );
2542 user_mat.yy = FT_FixedFromFIXED( user_transform->eM22 );
2544 for (i = 0; i < 3; i++)
2545 pFT_Matrix_Multiply( &user_mat, &matrices[i] );
2546 needs_transform = TRUE;
2549 return needs_transform;
2552 static BOOL get_bold_glyph_outline(FT_GlyphSlot glyph, LONG ppem, FT_Glyph_Metrics *metrics)
2554 FT_Error err;
2555 FT_Pos strength;
2556 FT_BBox bbox;
2558 if(glyph->format != FT_GLYPH_FORMAT_OUTLINE)
2559 return FALSE;
2560 if(!pFT_Outline_Embolden)
2561 return FALSE;
2563 strength = pFT_MulDiv(ppem, 1 << 6, 24);
2564 err = pFT_Outline_Embolden(&glyph->outline, strength);
2565 if(err) {
2566 TRACE("FT_Ouline_Embolden returns %d\n", err);
2567 return FALSE;
2570 pFT_Outline_Get_CBox(&glyph->outline, &bbox);
2571 metrics->width = bbox.xMax - bbox.xMin;
2572 metrics->height = bbox.yMax - bbox.yMin;
2573 metrics->horiBearingX = bbox.xMin;
2574 metrics->horiBearingY = bbox.yMax;
2575 metrics->vertBearingX = metrics->horiBearingX - metrics->horiAdvance / 2;
2576 metrics->vertBearingY = (metrics->vertAdvance - metrics->height) / 2;
2577 return TRUE;
2580 static inline BYTE get_max_level( UINT format )
2582 switch( format )
2584 case GGO_GRAY2_BITMAP: return 4;
2585 case GGO_GRAY4_BITMAP: return 16;
2586 case GGO_GRAY8_BITMAP: return 64;
2588 return 255;
2591 static FT_Vector get_advance_metric(struct gdi_font *incoming_font, struct gdi_font *font,
2592 const FT_Glyph_Metrics *metrics,
2593 const FT_Matrix *transMat, BOOL vertical_metrics)
2595 FT_Vector adv;
2596 FT_Fixed base_advance, em_scale = 0;
2597 BOOL fixed_pitch_full = FALSE;
2599 if (vertical_metrics)
2600 base_advance = metrics->vertAdvance;
2601 else
2602 base_advance = metrics->horiAdvance;
2604 adv.x = base_advance;
2605 adv.y = 0;
2607 /* In fixed-pitch font, we adjust the fullwidth character advance so that
2608 they have double halfwidth character width. E.g. if the font is 19 ppem,
2609 we return 20 (not 19) for fullwidth characters as we return 10 for
2610 halfwidth characters. */
2611 if (freetype_set_outline_text_metrics(incoming_font) &&
2612 !(incoming_font->otm.otmTextMetrics.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
2613 UINT avg_advance;
2614 em_scale = pFT_MulDiv(incoming_font->ppem, 1 << 16, get_ft_face(incoming_font)->units_per_EM);
2615 avg_advance = pFT_MulFix(incoming_font->ntmAvgWidth, em_scale);
2616 fixed_pitch_full = (avg_advance > 0 &&
2617 (base_advance + 63) >> 6 ==
2618 pFT_MulFix(incoming_font->ntmAvgWidth*2, em_scale));
2619 if (fixed_pitch_full && !transMat)
2620 adv.x = (avg_advance * 2) << 6;
2623 if (transMat) {
2624 pFT_Vector_Transform(&adv, transMat);
2625 if (fixed_pitch_full && adv.y == 0) {
2626 FT_Vector vec;
2627 vec.x = incoming_font->ntmAvgWidth;
2628 vec.y = 0;
2629 pFT_Vector_Transform(&vec, transMat);
2630 adv.x = (pFT_MulFix(vec.x, em_scale) * 2) << 6;
2634 if (font->fake_bold) {
2635 if (!transMat)
2636 adv.x += 1 << 6;
2637 else {
2638 FT_Vector fake_bold_adv, vec = { 1 << 6, 0 };
2639 pFT_Vector_Transform(&vec, transMat);
2640 fake_bold_adv = normalize_vector(&vec);
2641 adv.x += fake_bold_adv.x;
2642 adv.y += fake_bold_adv.y;
2646 adv.x = (adv.x + 63) & -64;
2647 adv.y = -((adv.y + 63) & -64);
2648 return adv;
2651 static FT_BBox get_transformed_bbox( const FT_Glyph_Metrics *metrics,
2652 BOOL needs_transform, const FT_Matrix metrices[3] )
2654 FT_BBox bbox = { 0, 0, 0, 0 };
2656 if (!needs_transform)
2658 bbox.xMin = (metrics->horiBearingX) & -64;
2659 bbox.xMax = (metrics->horiBearingX + metrics->width + 63) & -64;
2660 bbox.yMax = (metrics->horiBearingY + 63) & -64;
2661 bbox.yMin = (metrics->horiBearingY - metrics->height) & -64;
2663 else
2665 FT_Vector vec;
2666 INT xc, yc;
2668 for (xc = 0; xc < 2; xc++)
2670 for (yc = 0; yc < 2; yc++)
2672 vec.x = metrics->horiBearingX + xc * metrics->width;
2673 vec.y = metrics->horiBearingY - yc * metrics->height;
2674 TRACE( "Vec %ld,i %ld\n", vec.x, vec.y );
2675 pFT_Vector_Transform( &vec, &metrices[matrix_vert] );
2676 if (xc == 0 && yc == 0)
2678 bbox.xMin = bbox.xMax = vec.x;
2679 bbox.yMin = bbox.yMax = vec.y;
2681 else
2683 if (vec.x < bbox.xMin) bbox.xMin = vec.x;
2684 else if (vec.x > bbox.xMax) bbox.xMax = vec.x;
2685 if (vec.y < bbox.yMin) bbox.yMin = vec.y;
2686 else if (vec.y > bbox.yMax) bbox.yMax = vec.y;
2690 bbox.xMin = bbox.xMin & -64;
2691 bbox.xMax = (bbox.xMax + 63) & -64;
2692 bbox.yMin = bbox.yMin & -64;
2693 bbox.yMax = (bbox.yMax + 63) & -64;
2694 TRACE( "transformed box: (%ld, %ld - %ld, %ld)\n", bbox.xMin, bbox.yMax, bbox.xMax, bbox.yMin );
2697 return bbox;
2700 static void compute_metrics( struct gdi_font *incoming_font, struct gdi_font *font,
2701 FT_BBox bbox, const FT_Glyph_Metrics *metrics,
2702 BOOL vertical, BOOL vertical_metrics,
2703 BOOL needs_transform, const FT_Matrix matrices[3],
2704 GLYPHMETRICS *gm, ABC *abc )
2706 FT_Vector adv, vec, origin;
2708 if (!needs_transform)
2710 adv = get_advance_metric( incoming_font, font, metrics, NULL, vertical_metrics );
2711 gm->gmCellIncX = adv.x >> 6;
2712 gm->gmCellIncY = 0;
2713 origin.x = bbox.xMin;
2714 origin.y = bbox.yMax;
2715 abc->abcA = origin.x >> 6;
2716 abc->abcB = (metrics->width + 63) >> 6;
2718 else
2720 FT_Pos lsb;
2722 if (vertical && freetype_set_outline_text_metrics( font ))
2724 if (vertical_metrics)
2725 lsb = metrics->horiBearingY + metrics->vertBearingY;
2726 else
2727 lsb = metrics->vertAdvance + (font->otm.otmDescent << 6);
2728 vec.x = lsb;
2729 vec.y = font->otm.otmDescent << 6;
2730 TRACE( "Vec %ld,%ld\n", vec.x>>6, vec.y>>6 );
2731 pFT_Vector_Transform( &vec, &matrices[matrix_hori] );
2732 origin.x = (vec.x + bbox.xMin) & -64;
2733 origin.y = (vec.y + bbox.yMax + 63) & -64;
2734 lsb -= metrics->horiBearingY;
2736 else
2738 origin.x = bbox.xMin;
2739 origin.y = bbox.yMax;
2740 lsb = metrics->horiBearingX;
2743 adv = get_advance_metric( incoming_font, font, metrics, &matrices[matrix_hori],
2744 vertical_metrics );
2745 gm->gmCellIncX = adv.x >> 6;
2746 gm->gmCellIncY = adv.y >> 6;
2748 adv = get_advance_metric( incoming_font, font, metrics, &matrices[matrix_unrotated],
2749 vertical_metrics );
2750 adv.x = pFT_Vector_Length( &adv );
2751 adv.y = 0;
2753 vec.x = lsb;
2754 vec.y = 0;
2755 pFT_Vector_Transform( &vec, &matrices[matrix_unrotated] );
2756 if (lsb > 0) abc->abcA = pFT_Vector_Length( &vec ) >> 6;
2757 else abc->abcA = -((pFT_Vector_Length( &vec ) + 63) >> 6);
2759 /* We use lsb again to avoid rounding errors */
2760 vec.x = lsb + (vertical ? metrics->height : metrics->width);
2761 vec.y = 0;
2762 pFT_Vector_Transform( &vec, &matrices[matrix_unrotated] );
2763 abc->abcB = ((pFT_Vector_Length( &vec ) + 63) >> 6) - abc->abcA;
2765 if (!abc->abcB) abc->abcB = 1;
2766 abc->abcC = (adv.x >> 6) - abc->abcA - abc->abcB;
2768 gm->gmptGlyphOrigin.x = origin.x >> 6;
2769 gm->gmptGlyphOrigin.y = origin.y >> 6;
2770 gm->gmBlackBoxX = (bbox.xMax - bbox.xMin) >> 6;
2771 gm->gmBlackBoxY = (bbox.yMax - bbox.yMin) >> 6;
2772 if (!gm->gmBlackBoxX) gm->gmBlackBoxX = 1;
2773 if (!gm->gmBlackBoxY) gm->gmBlackBoxY = 1;
2775 TRACE( "gm: %u, %u, %s, %d, %d abc %d, %u, %d\n",
2776 gm->gmBlackBoxX, gm->gmBlackBoxY, wine_dbgstr_point(&gm->gmptGlyphOrigin),
2777 gm->gmCellIncX, gm->gmCellIncY, abc->abcA, abc->abcB, abc->abcC );
2781 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
2783 static DWORD get_mono_glyph_bitmap( FT_GlyphSlot glyph, FT_BBox bbox,
2784 BOOL fake_bold, BOOL needs_transform, FT_Matrix matrices[3],
2785 DWORD buflen, BYTE *buf )
2787 DWORD width = (bbox.xMax - bbox.xMin ) >> 6;
2788 DWORD height = (bbox.yMax - bbox.yMin ) >> 6;
2789 DWORD pitch = ((width + 31) >> 5) << 2;
2790 DWORD needed = pitch * height;
2791 FT_Bitmap ft_bitmap;
2792 BYTE *src, *dst;
2793 INT w, h, x;
2795 if (!buf || !buflen) return needed;
2796 if (!needed) return GDI_ERROR; /* empty glyph */
2797 if (needed > buflen) return GDI_ERROR;
2799 switch (glyph->format)
2801 case FT_GLYPH_FORMAT_BITMAP:
2802 src = glyph->bitmap.buffer;
2803 dst = buf;
2804 w = min( pitch, (glyph->bitmap.width + 7) >> 3 );
2805 h = min( height, glyph->bitmap.rows );
2806 while (h--)
2808 if (!fake_bold)
2809 memcpy( dst, src, w );
2810 else
2812 dst[0] = 0;
2813 for (x = 0; x < w; x++)
2815 dst[x] = (dst[x] & 0x80) | (src[x] >> 1) | src[x];
2816 if (x + 1 < pitch)
2817 dst[x + 1] = (src[x] & 0x01) << 7;
2820 src += glyph->bitmap.pitch;
2821 dst += pitch;
2823 break;
2825 case FT_GLYPH_FORMAT_OUTLINE:
2826 ft_bitmap.width = width;
2827 ft_bitmap.rows = height;
2828 ft_bitmap.pitch = pitch;
2829 ft_bitmap.pixel_mode = FT_PIXEL_MODE_MONO;
2830 ft_bitmap.buffer = buf;
2832 if (needs_transform)
2833 pFT_Outline_Transform( &glyph->outline, &matrices[matrix_vert] );
2834 pFT_Outline_Translate( &glyph->outline, -bbox.xMin, -bbox.yMin );
2836 /* Note: FreeType will only set 'black' bits for us. */
2837 memset( buf, 0, buflen );
2838 pFT_Outline_Get_Bitmap( library, &glyph->outline, &ft_bitmap );
2839 break;
2841 default:
2842 FIXME( "loaded glyph format %x\n", glyph->format );
2843 return GDI_ERROR;
2846 return needed;
2849 static DWORD get_antialias_glyph_bitmap( FT_GlyphSlot glyph, FT_BBox bbox, UINT format,
2850 BOOL fake_bold, BOOL needs_transform, FT_Matrix matrices[3],
2851 DWORD buflen, BYTE *buf )
2853 DWORD width = (bbox.xMax - bbox.xMin ) >> 6;
2854 DWORD height = (bbox.yMax - bbox.yMin ) >> 6;
2855 DWORD pitch = (width + 3) / 4 * 4;
2856 DWORD needed = pitch * height;
2857 FT_Bitmap ft_bitmap;
2858 INT w, h, x, max_level;
2859 BYTE *src, *dst;
2861 if (!buf || !buflen) return needed;
2862 if (!needed) return GDI_ERROR; /* empty glyph */
2863 if (needed > buflen) return GDI_ERROR;
2865 max_level = get_max_level( format );
2867 switch (glyph->format)
2869 case FT_GLYPH_FORMAT_BITMAP:
2870 src = glyph->bitmap.buffer;
2871 dst = buf;
2872 memset( buf, 0, buflen );
2874 w = min( pitch, glyph->bitmap.width );
2875 h = min( height, glyph->bitmap.rows );
2876 while (h--)
2878 for (x = 0; x < w; x++)
2880 if (src[x / 8] & masks[x % 8])
2882 dst[x] = max_level;
2883 if (fake_bold && x + 1 < pitch) dst[x + 1] = max_level;
2886 src += glyph->bitmap.pitch;
2887 dst += pitch;
2889 break;
2891 case FT_GLYPH_FORMAT_OUTLINE:
2892 ft_bitmap.width = width;
2893 ft_bitmap.rows = height;
2894 ft_bitmap.pitch = pitch;
2895 ft_bitmap.pixel_mode = FT_PIXEL_MODE_GRAY;
2896 ft_bitmap.buffer = buf;
2898 if (needs_transform)
2899 pFT_Outline_Transform( &glyph->outline, &matrices[matrix_vert] );
2900 pFT_Outline_Translate( &glyph->outline, -bbox.xMin, -bbox.yMin );
2902 memset( buf, 0, buflen );
2903 pFT_Outline_Get_Bitmap( library, &glyph->outline, &ft_bitmap );
2905 if (max_level != 255)
2907 INT row, col;
2908 BYTE *ptr, *start;
2910 for (row = 0, start = buf; row < height; row++)
2912 for (col = 0, ptr = start; col < width; col++, ptr++)
2913 *ptr = (((int)*ptr) * (max_level + 1)) / 256;
2914 start += pitch;
2917 break;
2919 default:
2920 FIXME("loaded glyph format %x\n", glyph->format);
2921 return GDI_ERROR;
2924 return needed;
2927 static DWORD get_subpixel_glyph_bitmap( FT_GlyphSlot glyph, FT_BBox bbox, UINT format,
2928 BOOL fake_bold, BOOL needs_transform, FT_Matrix matrices[3],
2929 GLYPHMETRICS *gm, DWORD buflen, BYTE *buf )
2931 DWORD width = (bbox.xMax - bbox.xMin ) >> 6;
2932 DWORD height = (bbox.yMax - bbox.yMin ) >> 6;
2933 DWORD pitch, needed = 0;
2934 BYTE *src, *dst;
2935 INT w, h, x;
2937 switch (glyph->format)
2939 case FT_GLYPH_FORMAT_BITMAP:
2940 pitch = width * 4;
2941 needed = pitch * height;
2943 if (!buf || !buflen) break;
2944 if (!needed) return GDI_ERROR; /* empty glyph */
2945 if (needed > buflen) return GDI_ERROR;
2947 src = glyph->bitmap.buffer;
2948 dst = buf;
2949 memset( buf, 0, buflen );
2951 w = min( width, glyph->bitmap.width );
2952 h = min( height, glyph->bitmap.rows );
2953 while (h--)
2955 for (x = 0; x < w; x++)
2957 if ( src[x / 8] & masks[x % 8] )
2959 ((unsigned int *)dst)[x] = ~0u;
2960 if (fake_bold && x + 1 < width) ((unsigned int *)dst)[x + 1] = ~0u;
2963 src += glyph->bitmap.pitch;
2964 dst += pitch;
2966 break;
2968 case FT_GLYPH_FORMAT_OUTLINE:
2970 INT src_pitch, src_width, src_height, x_shift, y_shift;
2971 INT sub_stride, hmul, vmul;
2972 const INT *sub_order;
2973 const INT rgb_order[3] = { 0, 1, 2 };
2974 const INT bgr_order[3] = { 2, 1, 0 };
2975 FT_Render_Mode render_mode =
2976 (format == WINE_GGO_HRGB_BITMAP ||
2977 format == WINE_GGO_HBGR_BITMAP) ? FT_RENDER_MODE_LCD : FT_RENDER_MODE_LCD_V;
2979 if (!width || !height) /* empty glyph */
2981 if (!buf || !buflen) break;
2982 return GDI_ERROR;
2985 if ( render_mode == FT_RENDER_MODE_LCD)
2987 gm->gmBlackBoxX += 2;
2988 gm->gmptGlyphOrigin.x -= 1;
2989 bbox.xMin -= (1 << 6);
2991 else
2993 gm->gmBlackBoxY += 2;
2994 gm->gmptGlyphOrigin.y += 1;
2995 bbox.yMax += (1 << 6);
2998 width = gm->gmBlackBoxX;
2999 height = gm->gmBlackBoxY;
3000 pitch = width * 4;
3001 needed = pitch * height;
3003 if (!buf || !buflen) return needed;
3004 if (needed > buflen) return GDI_ERROR;
3006 if (needs_transform)
3007 pFT_Outline_Transform( &glyph->outline, &matrices[matrix_vert] );
3009 #ifdef FT_LCD_FILTER_H
3010 if (pFT_Library_SetLcdFilter)
3011 pFT_Library_SetLcdFilter( library, FT_LCD_FILTER_DEFAULT );
3012 #endif
3013 pFT_Render_Glyph( glyph, render_mode );
3015 src_pitch = glyph->bitmap.pitch;
3016 src_width = glyph->bitmap.width;
3017 src_height = glyph->bitmap.rows;
3018 src = glyph->bitmap.buffer;
3019 dst = buf;
3020 memset( buf, 0, buflen );
3022 sub_order = (format == WINE_GGO_HRGB_BITMAP ||
3023 format == WINE_GGO_VRGB_BITMAP) ? rgb_order : bgr_order;
3024 sub_stride = render_mode == FT_RENDER_MODE_LCD ? 1 : src_pitch;
3025 hmul = render_mode == FT_RENDER_MODE_LCD ? 3 : 1;
3026 vmul = render_mode == FT_RENDER_MODE_LCD ? 1 : 3;
3028 x_shift = glyph->bitmap_left - (bbox.xMin >> 6);
3029 if ( x_shift < 0 )
3031 src += hmul * -x_shift;
3032 src_width -= hmul * -x_shift;
3034 else if ( x_shift > 0 )
3036 dst += x_shift * sizeof(unsigned int);
3037 width -= x_shift;
3040 y_shift = (bbox.yMax >> 6) - glyph->bitmap_top;
3041 if ( y_shift < 0 )
3043 src += src_pitch * vmul * -y_shift;
3044 src_height -= vmul * -y_shift;
3046 else if ( y_shift > 0 )
3048 dst += y_shift * pitch;
3049 height -= y_shift;
3052 w = min( width, src_width / hmul );
3053 h = min( height, src_height / vmul );
3054 while (h--)
3056 for (x = 0; x < w; x++)
3058 ((unsigned int *)dst)[x] =
3059 ((unsigned int)src[hmul * x + sub_stride * sub_order[0]] << 16) |
3060 ((unsigned int)src[hmul * x + sub_stride * sub_order[1]] << 8) |
3061 ((unsigned int)src[hmul * x + sub_stride * sub_order[2]]);
3063 src += src_pitch * vmul;
3064 dst += pitch;
3066 break;
3068 default:
3069 FIXME ( "loaded glyph format %x\n", glyph->format );
3070 return GDI_ERROR;
3073 return needed;
3076 static unsigned int get_native_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
3078 TTPOLYGONHEADER *pph;
3079 TTPOLYCURVE *ppc;
3080 unsigned int needed = 0, point = 0, contour, first_pt;
3081 unsigned int pph_start, cpfx;
3082 DWORD type;
3084 for (contour = 0; contour < outline->n_contours; contour++)
3086 /* Ignore contours containing one point */
3087 if (point == outline->contours[contour])
3089 point++;
3090 continue;
3093 pph_start = needed;
3094 pph = (TTPOLYGONHEADER *)(buf + needed);
3095 first_pt = point;
3096 if (buf)
3098 pph->dwType = TT_POLYGON_TYPE;
3099 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3101 needed += sizeof(*pph);
3102 point++;
3103 while (point <= outline->contours[contour])
3105 ppc = (TTPOLYCURVE *)(buf + needed);
3106 type = outline->tags[point] & FT_Curve_Tag_On ?
3107 TT_PRIM_LINE : TT_PRIM_QSPLINE;
3108 cpfx = 0;
3111 if (buf)
3112 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3113 cpfx++;
3114 point++;
3115 } while (point <= outline->contours[contour] &&
3116 (outline->tags[point] & FT_Curve_Tag_On) ==
3117 (outline->tags[point-1] & FT_Curve_Tag_On));
3118 /* At the end of a contour Windows adds the start point, but
3119 only for Beziers */
3120 if (point > outline->contours[contour] &&
3121 !(outline->tags[point-1] & FT_Curve_Tag_On))
3123 if (buf)
3124 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
3125 cpfx++;
3127 else if (point <= outline->contours[contour] &&
3128 outline->tags[point] & FT_Curve_Tag_On)
3130 /* add closing pt for bezier */
3131 if (buf)
3132 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3133 cpfx++;
3134 point++;
3136 if (buf)
3138 ppc->wType = type;
3139 ppc->cpfx = cpfx;
3141 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3143 if (buf)
3144 pph->cb = needed - pph_start;
3146 return needed;
3149 static unsigned int get_bezier_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
3151 /* Convert the quadratic Beziers to cubic Beziers.
3152 The parametric eqn for a cubic Bezier is, from PLRM:
3153 r(t) = at^3 + bt^2 + ct + r0
3154 with the control points:
3155 r1 = r0 + c/3
3156 r2 = r1 + (c + b)/3
3157 r3 = r0 + c + b + a
3159 A quadratic Bezier has the form:
3160 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3162 So equating powers of t leads to:
3163 r1 = 2/3 p1 + 1/3 p0
3164 r2 = 2/3 p1 + 1/3 p2
3165 and of course r0 = p0, r3 = p2
3167 int contour, point = 0, first_pt;
3168 TTPOLYGONHEADER *pph;
3169 TTPOLYCURVE *ppc;
3170 DWORD pph_start, cpfx, type;
3171 FT_Vector cubic_control[4];
3172 unsigned int needed = 0;
3174 for (contour = 0; contour < outline->n_contours; contour++)
3176 pph_start = needed;
3177 pph = (TTPOLYGONHEADER *)(buf + needed);
3178 first_pt = point;
3179 if (buf)
3181 pph->dwType = TT_POLYGON_TYPE;
3182 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3184 needed += sizeof(*pph);
3185 point++;
3186 while (point <= outline->contours[contour])
3188 ppc = (TTPOLYCURVE *)(buf + needed);
3189 type = outline->tags[point] & FT_Curve_Tag_On ?
3190 TT_PRIM_LINE : TT_PRIM_CSPLINE;
3191 cpfx = 0;
3194 if (type == TT_PRIM_LINE)
3196 if (buf)
3197 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3198 cpfx++;
3199 point++;
3201 else
3203 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
3204 so cpfx = 3n */
3206 /* FIXME: Possible optimization in endpoint calculation
3207 if there are two consecutive curves */
3208 cubic_control[0] = outline->points[point-1];
3209 if (!(outline->tags[point-1] & FT_Curve_Tag_On))
3211 cubic_control[0].x += outline->points[point].x + 1;
3212 cubic_control[0].y += outline->points[point].y + 1;
3213 cubic_control[0].x >>= 1;
3214 cubic_control[0].y >>= 1;
3216 if (point+1 > outline->contours[contour])
3217 cubic_control[3] = outline->points[first_pt];
3218 else
3220 cubic_control[3] = outline->points[point+1];
3221 if (!(outline->tags[point+1] & FT_Curve_Tag_On))
3223 cubic_control[3].x += outline->points[point].x + 1;
3224 cubic_control[3].y += outline->points[point].y + 1;
3225 cubic_control[3].x >>= 1;
3226 cubic_control[3].y >>= 1;
3229 /* r1 = 1/3 p0 + 2/3 p1
3230 r2 = 1/3 p2 + 2/3 p1 */
3231 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
3232 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
3233 cubic_control[2] = cubic_control[1];
3234 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
3235 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
3236 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
3237 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
3238 if (buf)
3240 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
3241 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
3242 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
3244 cpfx += 3;
3245 point++;
3247 } while (point <= outline->contours[contour] &&
3248 (outline->tags[point] & FT_Curve_Tag_On) ==
3249 (outline->tags[point-1] & FT_Curve_Tag_On));
3250 /* At the end of a contour Windows adds the start point,
3251 but only for Beziers and we've already done that.
3253 if (point <= outline->contours[contour] &&
3254 outline->tags[point] & FT_Curve_Tag_On)
3256 /* This is the closing pt of a bezier, but we've already
3257 added it, so just inc point and carry on */
3258 point++;
3260 if (buf)
3262 ppc->wType = type;
3263 ppc->cpfx = cpfx;
3265 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3267 if (buf)
3268 pph->cb = needed - pph_start;
3270 return needed;
3273 static FT_Int get_load_flags( UINT format )
3275 FT_Int load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
3277 if (format & GGO_UNHINTED)
3278 return load_flags | FT_LOAD_NO_HINTING;
3280 switch (format & ~GGO_GLYPH_INDEX)
3282 case GGO_BITMAP:
3283 load_flags |= FT_LOAD_TARGET_MONO;
3284 break;
3285 case GGO_GRAY2_BITMAP:
3286 case GGO_GRAY4_BITMAP:
3287 case GGO_GRAY8_BITMAP:
3288 case WINE_GGO_GRAY16_BITMAP:
3289 load_flags |= FT_LOAD_TARGET_NORMAL;
3290 break;
3291 case WINE_GGO_HRGB_BITMAP:
3292 case WINE_GGO_HBGR_BITMAP:
3293 load_flags |= FT_LOAD_TARGET_LCD;
3294 break;
3295 case WINE_GGO_VRGB_BITMAP:
3296 case WINE_GGO_VBGR_BITMAP:
3297 load_flags |= FT_LOAD_TARGET_LCD_V;
3298 break;
3301 return load_flags;
3304 /*************************************************************
3305 * freetype_get_glyph_outline
3307 static DWORD CDECL freetype_get_glyph_outline( struct gdi_font *font, UINT glyph, UINT format,
3308 GLYPHMETRICS *lpgm, ABC *abc, DWORD buflen, void *buf,
3309 const MAT2 *lpmat, BOOL tategaki )
3311 struct gdi_font *base_font = font->base_font ? font->base_font : font;
3312 FT_Face ft_face = get_ft_face( font );
3313 FT_Glyph_Metrics metrics;
3314 FT_Error err;
3315 FT_BBox bbox;
3316 FT_Int load_flags = get_load_flags(format);
3317 FT_Matrix matrices[3];
3318 BOOL needsTransform = FALSE;
3319 BOOL vertical_metrics;
3321 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm, buflen, buf, lpmat);
3323 TRACE("font transform %f %f %f %f\n",
3324 font->matrix.eM11, font->matrix.eM12,
3325 font->matrix.eM21, font->matrix.eM22);
3327 needsTransform = get_transform_matrices( font, tategaki, lpmat, matrices );
3329 vertical_metrics = (tategaki && FT_HAS_VERTICAL(ft_face));
3330 /* there is a freetype bug where vertical metrics are only
3331 properly scaled and correct in 2.4.0 or greater */
3332 if (vertical_metrics && FT_SimpleVersion < FT_VERSION_VALUE(2, 4, 0))
3333 vertical_metrics = FALSE;
3335 if (needsTransform || format != GGO_BITMAP) load_flags |= FT_LOAD_NO_BITMAP;
3336 if (vertical_metrics) load_flags |= FT_LOAD_VERTICAL_LAYOUT;
3338 err = pFT_Load_Glyph(ft_face, glyph, load_flags);
3339 if (err && !(load_flags & FT_LOAD_NO_HINTING))
3341 WARN("Failed to load glyph %#x, retrying without hinting. Error %#x.\n", glyph, err);
3342 load_flags |= FT_LOAD_NO_HINTING;
3343 err = pFT_Load_Glyph(ft_face, glyph, load_flags);
3346 if(err) {
3347 WARN("Failed to load glyph %#x, error %#x.\n", glyph, err);
3348 return GDI_ERROR;
3351 metrics = ft_face->glyph->metrics;
3352 if(font->fake_bold) {
3353 if (!get_bold_glyph_outline(ft_face->glyph, font->ppem, &metrics) && metrics.width)
3354 metrics.width += 1 << 6;
3357 /* Some poorly-created fonts contain glyphs that exceed the boundaries set
3358 * by the text metrics. The proper behavior is to clip the glyph metrics to
3359 * fit within the maximums specified in the text metrics. */
3360 if (freetype_set_outline_text_metrics(base_font) ||
3361 freetype_set_bitmap_text_metrics(base_font)) {
3362 TEXTMETRICW *ptm = &base_font->otm.otmTextMetrics;
3363 INT top = min( metrics.horiBearingY, ptm->tmAscent << 6 );
3364 INT bottom = max( metrics.horiBearingY - metrics.height, -(ptm->tmDescent << 6) );
3365 metrics.horiBearingY = top;
3366 metrics.height = top - bottom;
3368 /* TODO: Are we supposed to clip the width as well...? */
3369 /* metrics.width = min( metrics.width, ptm->tmMaxCharWidth << 6 ); */
3372 bbox = get_transformed_bbox( &metrics, needsTransform, matrices );
3373 compute_metrics( base_font, font, bbox, &metrics, tategaki,
3374 vertical_metrics, needsTransform, matrices, lpgm, abc );
3376 switch (format)
3378 case GGO_METRICS:
3379 return 1; /* FIXME */
3381 case GGO_BITMAP:
3382 return get_mono_glyph_bitmap( ft_face->glyph, bbox, font->fake_bold,
3383 needsTransform, matrices, buflen, buf );
3385 case GGO_GRAY2_BITMAP:
3386 case GGO_GRAY4_BITMAP:
3387 case GGO_GRAY8_BITMAP:
3388 case WINE_GGO_GRAY16_BITMAP:
3389 return get_antialias_glyph_bitmap( ft_face->glyph, bbox, format, font->fake_bold,
3390 needsTransform, matrices, buflen, buf );
3392 case WINE_GGO_HRGB_BITMAP:
3393 case WINE_GGO_HBGR_BITMAP:
3394 case WINE_GGO_VRGB_BITMAP:
3395 case WINE_GGO_VBGR_BITMAP:
3396 return get_subpixel_glyph_bitmap( ft_face->glyph, bbox, format, font->fake_bold,
3397 needsTransform, matrices, lpgm, buflen, buf );
3399 case GGO_NATIVE:
3400 if (ft_face->glyph->format == ft_glyph_format_outline)
3402 FT_Outline *outline = &ft_face->glyph->outline;
3403 UINT needed;
3405 if (buflen == 0) buf = NULL;
3407 if (needsTransform && buf)
3408 pFT_Outline_Transform( outline, &matrices[matrix_vert] );
3410 needed = get_native_glyph_outline(outline, buflen, NULL);
3412 if (!buf || !buflen) return needed;
3413 if (needed > buflen) return GDI_ERROR;
3414 return get_native_glyph_outline(outline, buflen, buf);
3416 TRACE("loaded a bitmap\n");
3417 return GDI_ERROR;
3419 case GGO_BEZIER:
3420 if (ft_face->glyph->format == ft_glyph_format_outline)
3422 FT_Outline *outline = &ft_face->glyph->outline;
3423 UINT needed;
3425 if (buflen == 0) buf = NULL;
3427 if (needsTransform && buf)
3428 pFT_Outline_Transform( outline, &matrices[matrix_vert] );
3430 needed = get_bezier_glyph_outline(outline, buflen, NULL);
3432 if (!buf || !buflen) return needed;
3433 if (needed > buflen) return GDI_ERROR;
3434 return get_bezier_glyph_outline(outline, buflen, buf);
3436 TRACE("loaded a bitmap\n");
3437 return GDI_ERROR;
3439 default:
3440 FIXME("Unsupported format %d\n", format);
3441 return GDI_ERROR;
3445 /*************************************************************
3446 * freetype_set_bitmap_text_metrics
3448 static BOOL CDECL freetype_set_bitmap_text_metrics( struct gdi_font *font )
3450 FT_Face ft_face = get_ft_face( font );
3451 FT_WinFNT_HeaderRec winfnt_header;
3453 if (font->otm.otmSize) return TRUE; /* already set */
3454 font->otm.otmSize = offsetof( OUTLINETEXTMETRICW, otmFiller );
3456 #define TM font->otm.otmTextMetrics
3457 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
3459 TM.tmHeight = winfnt_header.pixel_height;
3460 TM.tmAscent = winfnt_header.ascent;
3461 TM.tmDescent = TM.tmHeight - TM.tmAscent;
3462 TM.tmInternalLeading = winfnt_header.internal_leading;
3463 TM.tmExternalLeading = winfnt_header.external_leading;
3464 TM.tmAveCharWidth = winfnt_header.avg_width;
3465 TM.tmMaxCharWidth = winfnt_header.max_width;
3466 TM.tmWeight = winfnt_header.weight;
3467 TM.tmOverhang = 0;
3468 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
3469 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
3470 TM.tmFirstChar = winfnt_header.first_char;
3471 TM.tmLastChar = winfnt_header.last_char;
3472 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
3473 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
3474 TM.tmItalic = winfnt_header.italic;
3475 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
3476 TM.tmCharSet = winfnt_header.charset;
3478 else
3480 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
3481 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
3482 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3483 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
3484 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
3485 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
3486 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
3487 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
3488 TM.tmOverhang = 0;
3489 TM.tmDigitizedAspectX = 96; /* FIXME */
3490 TM.tmDigitizedAspectY = 96; /* FIXME */
3491 TM.tmFirstChar = 1;
3492 TM.tmLastChar = 255;
3493 TM.tmDefaultChar = 32;
3494 TM.tmBreakChar = 32;
3495 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
3496 /* NB inverted meaning of TMPF_FIXED_PITCH */
3497 TM.tmPitchAndFamily = FT_IS_FIXED_WIDTH(ft_face) ? 0 : TMPF_FIXED_PITCH;
3498 TM.tmCharSet = font->charset;
3500 TM.tmUnderlined = font->lf.lfUnderline ? 0xff : 0;
3501 TM.tmStruckOut = font->lf.lfStrikeOut ? 0xff : 0;
3503 if(font->fake_bold)
3504 TM.tmWeight = FW_BOLD;
3505 #undef TM
3507 return TRUE;
3511 static BOOL face_has_symbol_charmap(FT_Face ft_face)
3513 int i;
3515 for(i = 0; i < ft_face->num_charmaps; i++)
3517 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
3518 return TRUE;
3520 return FALSE;
3523 /*************************************************************
3524 * freetype_set_outline_text_metrics
3526 static BOOL CDECL freetype_set_outline_text_metrics( struct gdi_font *font )
3528 FT_Face ft_face = get_ft_face( font );
3529 UINT needed;
3530 TT_OS2 *pOS2;
3531 TT_HoriHeader *pHori;
3532 TT_Postscript *pPost;
3533 FT_Fixed em_scale;
3534 INT ascent, descent;
3535 USHORT windescent;
3537 TRACE("font=%p\n", font);
3539 if (!font->scalable) return FALSE;
3540 if (font->otm.otmSize) return TRUE; /* already set */
3542 /* note: we store actual pointers in the names instead of offsets,
3543 they are fixed up when returned to the app */
3544 if (!(font->otm.otmpFullName = (char *)get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, system_lcid )))
3546 static const WCHAR fake_nameW[] = {'f','a','k','e',' ','n','a','m','e', 0};
3547 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w((WCHAR *)font->otm.otmpFamilyName));
3548 font->otm.otmpFullName = (char *)strdupW(fake_nameW);
3550 needed = sizeof(font->otm) + (lstrlenW( (WCHAR *)font->otm.otmpFamilyName ) + 1 +
3551 lstrlenW( (WCHAR *)font->otm.otmpStyleName ) + 1 +
3552 lstrlenW( (WCHAR *)font->otm.otmpFaceName ) + 1 +
3553 lstrlenW( (WCHAR *)font->otm.otmpFullName ) + 1) * sizeof(WCHAR);
3555 em_scale = (FT_Fixed)pFT_MulDiv(font->ppem, 1 << 16, ft_face->units_per_EM);
3557 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3558 if(!pOS2) {
3559 FIXME("Can't find OS/2 table - not TT font?\n");
3560 return FALSE;
3563 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3564 if(!pHori) {
3565 FIXME("Can't find HHEA table - not TT font?\n");
3566 return FALSE;
3569 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
3571 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",
3572 pOS2->usWinAscent, pOS2->usWinDescent,
3573 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
3574 pOS2->xAvgCharWidth,
3575 ft_face->ascender, ft_face->descender, ft_face->height,
3576 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
3577 ft_face->bbox.yMax, ft_face->bbox.yMin);
3579 font->otm.otmSize = needed;
3581 #define TM font->otm.otmTextMetrics
3583 windescent = get_fixed_windescent(pOS2->usWinDescent);
3584 if(pOS2->usWinAscent + windescent == 0) {
3585 ascent = pHori->Ascender;
3586 descent = -pHori->Descender;
3587 } else {
3588 ascent = pOS2->usWinAscent;
3589 descent = windescent;
3592 font->ntmCellHeight = ascent + descent;
3593 font->ntmAvgWidth = pOS2->xAvgCharWidth;
3595 #define SCALE_X(x) (pFT_MulFix(x, em_scale))
3596 #define SCALE_Y(y) (pFT_MulFix(y, em_scale))
3598 if(font->yMax) {
3599 TM.tmAscent = font->yMax;
3600 TM.tmDescent = -font->yMin;
3601 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
3602 } else {
3603 TM.tmAscent = SCALE_Y(ascent);
3604 TM.tmDescent = SCALE_Y(descent);
3605 TM.tmInternalLeading = SCALE_Y(ascent + descent - ft_face->units_per_EM);
3608 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3610 /* MSDN says:
3611 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
3613 TM.tmExternalLeading = max(0, SCALE_Y(pHori->Line_Gap -
3614 ((ascent + descent) -
3615 (pHori->Ascender - pHori->Descender))));
3617 TM.tmAveCharWidth = SCALE_X(pOS2->xAvgCharWidth);
3618 if (TM.tmAveCharWidth == 0) {
3619 TM.tmAveCharWidth = 1;
3621 TM.tmMaxCharWidth = SCALE_X(ft_face->bbox.xMax - ft_face->bbox.xMin);
3622 TM.tmWeight = FW_REGULAR;
3623 if (font->fake_bold)
3624 TM.tmWeight = FW_BOLD;
3625 else
3627 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
3629 if (pOS2->usWeightClass > FW_MEDIUM)
3630 TM.tmWeight = pOS2->usWeightClass;
3632 else if (pOS2->usWeightClass <= FW_MEDIUM)
3633 TM.tmWeight = pOS2->usWeightClass;
3635 TM.tmOverhang = 0;
3636 TM.tmDigitizedAspectX = 96; /* FIXME */
3637 TM.tmDigitizedAspectY = 96; /* FIXME */
3638 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
3639 * symbol range to 0 - f0ff
3642 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
3644 TM.tmFirstChar = 0;
3645 switch (PRIMARYLANGID(system_lcid))
3647 case LANG_HEBREW:
3648 TM.tmLastChar = 0xf896;
3649 break;
3650 case LANG_ESTONIAN:
3651 case LANG_LATVIAN:
3652 case LANG_LITHUANIAN:
3653 TM.tmLastChar = 0xf8fd;
3654 break;
3655 default:
3656 TM.tmLastChar = 0xf0ff;
3658 TM.tmBreakChar = 0x20;
3659 TM.tmDefaultChar = 0x1f;
3661 else
3663 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
3664 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
3666 if(pOS2->usFirstCharIndex <= 1)
3667 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
3668 else if (pOS2->usFirstCharIndex > 0xff)
3669 TM.tmBreakChar = 0x20;
3670 else
3671 TM.tmBreakChar = pOS2->usFirstCharIndex;
3672 TM.tmDefaultChar = TM.tmBreakChar - 1;
3674 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
3675 TM.tmUnderlined = font->lf.lfUnderline ? 255 : 0;
3676 TM.tmStruckOut = font->lf.lfStrikeOut ? 255 : 0;
3678 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
3679 if(!FT_IS_FIXED_WIDTH(ft_face) &&
3680 (pOS2->version == 0xFFFFU ||
3681 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
3682 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
3683 else
3684 TM.tmPitchAndFamily = 0;
3686 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
3688 case PAN_FAMILY_SCRIPT:
3689 TM.tmPitchAndFamily |= FF_SCRIPT;
3690 break;
3692 case PAN_FAMILY_DECORATIVE:
3693 TM.tmPitchAndFamily |= FF_DECORATIVE;
3694 break;
3696 case PAN_ANY:
3697 case PAN_NO_FIT:
3698 case PAN_FAMILY_TEXT_DISPLAY:
3699 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
3700 /* which is clearly not what the panose spec says. */
3701 default:
3702 if(TM.tmPitchAndFamily == 0 || /* fixed */
3703 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
3704 TM.tmPitchAndFamily = FF_MODERN;
3705 else
3707 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
3709 case PAN_ANY:
3710 case PAN_NO_FIT:
3711 default:
3712 TM.tmPitchAndFamily |= FF_DONTCARE;
3713 break;
3715 case PAN_SERIF_COVE:
3716 case PAN_SERIF_OBTUSE_COVE:
3717 case PAN_SERIF_SQUARE_COVE:
3718 case PAN_SERIF_OBTUSE_SQUARE_COVE:
3719 case PAN_SERIF_SQUARE:
3720 case PAN_SERIF_THIN:
3721 case PAN_SERIF_BONE:
3722 case PAN_SERIF_EXAGGERATED:
3723 case PAN_SERIF_TRIANGLE:
3724 TM.tmPitchAndFamily |= FF_ROMAN;
3725 break;
3727 case PAN_SERIF_NORMAL_SANS:
3728 case PAN_SERIF_OBTUSE_SANS:
3729 case PAN_SERIF_PERP_SANS:
3730 case PAN_SERIF_FLARED:
3731 case PAN_SERIF_ROUNDED:
3732 TM.tmPitchAndFamily |= FF_SWISS;
3733 break;
3736 break;
3739 if(FT_IS_SCALABLE(ft_face))
3740 TM.tmPitchAndFamily |= TMPF_VECTOR;
3742 if(FT_IS_SFNT(ft_face))
3744 if (font->ntmFlags & NTM_PS_OPENTYPE)
3745 TM.tmPitchAndFamily |= TMPF_DEVICE;
3746 else
3747 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
3750 TM.tmCharSet = font->charset;
3752 font->otm.otmFiller = 0;
3753 memcpy(&font->otm.otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
3754 font->otm.otmfsSelection = pOS2->fsSelection;
3755 if (font->fake_italic)
3756 font->otm.otmfsSelection |= 1;
3757 if (font->fake_bold)
3758 font->otm.otmfsSelection |= 1 << 5;
3759 /* Only return valid bits that define embedding and subsetting restrictions */
3760 font->otm.otmfsType = pOS2->fsType & 0x30e;
3761 font->otm.otmsCharSlopeRise = pHori->caret_Slope_Rise;
3762 font->otm.otmsCharSlopeRun = pHori->caret_Slope_Run;
3763 font->otm.otmItalicAngle = 0; /* POST table */
3764 font->otm.otmEMSquare = ft_face->units_per_EM;
3765 font->otm.otmAscent = SCALE_Y(pOS2->sTypoAscender);
3766 font->otm.otmDescent = SCALE_Y(pOS2->sTypoDescender);
3767 font->otm.otmLineGap = SCALE_Y(pOS2->sTypoLineGap);
3768 font->otm.otmsCapEmHeight = SCALE_Y(pOS2->sCapHeight);
3769 font->otm.otmsXHeight = SCALE_Y(pOS2->sxHeight);
3770 font->otm.otmrcFontBox.left = SCALE_X(ft_face->bbox.xMin);
3771 font->otm.otmrcFontBox.right = SCALE_X(ft_face->bbox.xMax);
3772 font->otm.otmrcFontBox.top = SCALE_Y(ft_face->bbox.yMax);
3773 font->otm.otmrcFontBox.bottom = SCALE_Y(ft_face->bbox.yMin);
3774 font->otm.otmMacAscent = TM.tmAscent;
3775 font->otm.otmMacDescent = -TM.tmDescent;
3776 font->otm.otmMacLineGap = SCALE_Y(pHori->Line_Gap);
3777 font->otm.otmusMinimumPPEM = 0; /* TT Header */
3778 font->otm.otmptSubscriptSize.x = SCALE_X(pOS2->ySubscriptXSize);
3779 font->otm.otmptSubscriptSize.y = SCALE_Y(pOS2->ySubscriptYSize);
3780 font->otm.otmptSubscriptOffset.x = SCALE_X(pOS2->ySubscriptXOffset);
3781 font->otm.otmptSubscriptOffset.y = SCALE_Y(pOS2->ySubscriptYOffset);
3782 font->otm.otmptSuperscriptSize.x = SCALE_X(pOS2->ySuperscriptXSize);
3783 font->otm.otmptSuperscriptSize.y = SCALE_Y(pOS2->ySuperscriptYSize);
3784 font->otm.otmptSuperscriptOffset.x = SCALE_X(pOS2->ySuperscriptXOffset);
3785 font->otm.otmptSuperscriptOffset.y = SCALE_Y(pOS2->ySuperscriptYOffset);
3786 font->otm.otmsStrikeoutSize = SCALE_Y(pOS2->yStrikeoutSize);
3787 font->otm.otmsStrikeoutPosition = SCALE_Y(pOS2->yStrikeoutPosition);
3788 if(!pPost) {
3789 font->otm.otmsUnderscoreSize = 0;
3790 font->otm.otmsUnderscorePosition = 0;
3791 } else {
3792 font->otm.otmsUnderscoreSize = SCALE_Y(pPost->underlineThickness);
3793 font->otm.otmsUnderscorePosition = SCALE_Y(pPost->underlinePosition);
3795 #undef SCALE_X
3796 #undef SCALE_Y
3797 #undef TM
3798 return TRUE;
3801 /*************************************************************
3802 * freetype_get_char_width_info
3804 static BOOL CDECL freetype_get_char_width_info( struct gdi_font *font, struct char_width_info *info )
3806 FT_Face ft_face = get_ft_face( font );
3807 TT_HoriHeader *pHori;
3809 TRACE("%p, %p\n", font, info);
3811 if ((pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea)))
3813 FT_Fixed em_scale = pFT_MulDiv(font->ppem, 1 << 16, ft_face->units_per_EM);
3814 info->lsb = (SHORT)pFT_MulFix(pHori->min_Left_Side_Bearing, em_scale);
3815 info->rsb = (SHORT)pFT_MulFix(pHori->min_Right_Side_Bearing, em_scale);
3816 return TRUE;
3818 return FALSE;
3822 /*************************************************************
3823 * freetype_get_unicode_ranges
3825 * Retrieve a list of supported Unicode ranges for a given font.
3826 * Can be called with NULL gs to calculate the buffer size. Returns
3827 * the number of ranges found.
3829 static DWORD CDECL freetype_get_unicode_ranges( struct gdi_font *font, GLYPHSET *gs )
3831 FT_Face ft_face = get_ft_face( font );
3832 DWORD num_ranges = 0;
3834 if (ft_face->charmap->encoding == FT_ENCODING_UNICODE)
3836 FT_UInt glyph_code;
3837 FT_ULong char_code, char_code_prev;
3839 glyph_code = 0;
3840 char_code_prev = char_code = pFT_Get_First_Char(ft_face, &glyph_code);
3842 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
3843 ft_face->num_glyphs, glyph_code, char_code);
3845 if (!glyph_code) return 0;
3847 if (gs)
3849 gs->ranges[0].wcLow = (USHORT)char_code;
3850 gs->ranges[0].cGlyphs = 0;
3851 gs->cGlyphsSupported = 0;
3854 num_ranges = 1;
3855 while (glyph_code)
3857 if (char_code < char_code_prev)
3859 ERR("expected increasing char code from FT_Get_Next_Char\n");
3860 return 0;
3862 if (char_code - char_code_prev > 1)
3864 num_ranges++;
3865 if (gs)
3867 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
3868 gs->ranges[num_ranges - 1].cGlyphs = 1;
3869 gs->cGlyphsSupported++;
3872 else if (gs)
3874 gs->ranges[num_ranges - 1].cGlyphs++;
3875 gs->cGlyphsSupported++;
3877 char_code_prev = char_code;
3878 char_code = pFT_Get_Next_Char(ft_face, char_code, &glyph_code);
3881 else
3883 DWORD encoding = RtlUlongByteSwap(ft_face->charmap->encoding);
3884 FIXME("encoding %s not supported\n", debugstr_an((char *)&encoding, 4));
3887 return num_ranges;
3890 /*************************************************************************
3891 * Kerning support for TrueType fonts
3894 struct TT_kern_table
3896 USHORT version;
3897 USHORT nTables;
3900 struct TT_kern_subtable
3902 USHORT version;
3903 USHORT length;
3904 union
3906 USHORT word;
3907 struct
3909 USHORT horizontal : 1;
3910 USHORT minimum : 1;
3911 USHORT cross_stream: 1;
3912 USHORT override : 1;
3913 USHORT reserved1 : 4;
3914 USHORT format : 8;
3915 } bits;
3916 } coverage;
3919 struct TT_format0_kern_subtable
3921 USHORT nPairs;
3922 USHORT searchRange;
3923 USHORT entrySelector;
3924 USHORT rangeShift;
3927 struct TT_kern_pair
3929 USHORT left;
3930 USHORT right;
3931 short value;
3934 static DWORD parse_format0_kern_subtable(struct gdi_font *font,
3935 const struct TT_format0_kern_subtable *tt_f0_ks,
3936 const USHORT *glyph_to_char,
3937 KERNINGPAIR *kern_pair, DWORD cPairs)
3939 FT_Face ft_face = get_ft_face( font );
3940 USHORT i, nPairs;
3941 const struct TT_kern_pair *tt_kern_pair;
3943 TRACE("font height %d, units_per_EM %d\n", font->ppem, ft_face->units_per_EM);
3945 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
3947 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
3948 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
3949 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
3951 if (!kern_pair || !cPairs)
3952 return nPairs;
3954 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
3956 nPairs = min(nPairs, cPairs);
3958 for (i = 0; i < nPairs; i++)
3960 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
3961 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
3962 /* this algorithm appears to better match what Windows does */
3963 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
3964 if (kern_pair->iKernAmount < 0)
3966 kern_pair->iKernAmount -= ft_face->units_per_EM / 2;
3967 kern_pair->iKernAmount -= font->ppem;
3969 else if (kern_pair->iKernAmount > 0)
3971 kern_pair->iKernAmount += ft_face->units_per_EM / 2;
3972 kern_pair->iKernAmount += font->ppem;
3974 kern_pair->iKernAmount /= ft_face->units_per_EM;
3976 TRACE("left %u right %u value %d\n",
3977 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
3979 kern_pair++;
3981 TRACE("copied %u entries\n", nPairs);
3982 return nPairs;
3985 /*************************************************************
3986 * freetype_get_kerning_pairs
3988 static DWORD CDECL freetype_get_kerning_pairs( struct gdi_font *font, KERNINGPAIR **pairs )
3990 FT_Face ft_face = get_ft_face( font );
3991 DWORD length, count = 0;
3992 void *buf;
3993 const struct TT_kern_table *tt_kern_table;
3994 const struct TT_kern_subtable *tt_kern_subtable;
3995 USHORT i, nTables;
3996 USHORT *glyph_to_char;
3998 length = freetype_get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
4000 if (length == GDI_ERROR)
4002 TRACE("no kerning data in the font\n");
4003 return 0;
4006 buf = RtlAllocateHeap(GetProcessHeap(), 0, length);
4007 if (!buf) return 0;
4009 freetype_get_font_data(font, MS_KERN_TAG, 0, buf, length);
4011 /* build a glyph index to char code map */
4012 glyph_to_char = RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
4013 if (!glyph_to_char)
4015 RtlFreeHeap(GetProcessHeap(), 0, buf);
4016 return 0;
4019 if (ft_face->charmap->encoding == FT_ENCODING_UNICODE)
4021 FT_UInt glyph_code;
4022 FT_ULong char_code;
4024 glyph_code = 0;
4025 char_code = pFT_Get_First_Char(ft_face, &glyph_code);
4027 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
4028 ft_face->num_glyphs, glyph_code, char_code);
4030 while (glyph_code)
4032 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
4034 /* FIXME: This doesn't match what Windows does: it does some fancy
4035 * things with duplicate glyph index to char code mappings, while
4036 * we just avoid overriding existing entries.
4038 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
4039 glyph_to_char[glyph_code] = (USHORT)char_code;
4041 char_code = pFT_Get_Next_Char(ft_face, char_code, &glyph_code);
4044 else
4046 DWORD encoding = RtlUlongByteSwap(ft_face->charmap->encoding);
4047 ULONG n;
4049 FIXME("encoding %s not supported\n", debugstr_an((char *)&encoding, 4));
4050 for (n = 0; n <= 65535; n++)
4051 glyph_to_char[n] = (USHORT)n;
4054 tt_kern_table = buf;
4055 nTables = GET_BE_WORD(tt_kern_table->nTables);
4056 TRACE("version %u, nTables %u\n",
4057 GET_BE_WORD(tt_kern_table->version), nTables);
4059 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
4061 for (i = 0; i < nTables; i++)
4063 struct TT_kern_subtable tt_kern_subtable_copy;
4065 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
4066 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
4067 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
4069 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
4070 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
4071 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
4073 /* According to the TrueType specification this is the only format
4074 * that will be properly interpreted by Windows and OS/2
4076 if (tt_kern_subtable_copy.coverage.bits.format == 0)
4078 DWORD new_chunk, old_total = count;
4080 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
4081 glyph_to_char, NULL, 0);
4082 count += new_chunk;
4084 if (!*pairs)
4085 *pairs = RtlAllocateHeap(GetProcessHeap(), 0, count * sizeof(**pairs));
4086 else
4087 *pairs = RtlReAllocateHeap(GetProcessHeap(), 0, *pairs, count * sizeof(**pairs));
4089 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
4090 glyph_to_char, *pairs + old_total, new_chunk);
4092 else
4093 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
4095 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
4098 RtlFreeHeap(GetProcessHeap(), 0, glyph_to_char);
4099 RtlFreeHeap(GetProcessHeap(), 0, buf);
4100 return count;
4103 static const struct font_backend_funcs font_funcs =
4105 freetype_load_fonts,
4106 fontconfig_enum_family_fallbacks,
4107 freetype_add_font,
4108 freetype_add_mem_font,
4109 freetype_load_font,
4110 freetype_get_font_data,
4111 freetype_get_aa_flags,
4112 freetype_get_glyph_index,
4113 freetype_get_default_glyph,
4114 freetype_get_glyph_outline,
4115 freetype_get_unicode_ranges,
4116 freetype_get_char_width_info,
4117 freetype_set_outline_text_metrics,
4118 freetype_set_bitmap_text_metrics,
4119 freetype_get_kerning_pairs,
4120 freetype_destroy_font
4123 static NTSTATUS init_freetype_lib( HMODULE module, DWORD reason, const void *ptr_in, void *ptr_out )
4125 callback_funcs = ptr_in;
4126 if (!init_freetype()) return STATUS_DLL_NOT_FOUND;
4127 #ifdef SONAME_LIBFONTCONFIG
4128 init_fontconfig();
4129 #endif
4130 NtQueryDefaultLocale( FALSE, &system_lcid );
4131 *(const struct font_backend_funcs **)ptr_out = &font_funcs;
4132 return STATUS_SUCCESS;
4135 #else /* HAVE_FREETYPE */
4137 static NTSTATUS init_freetype_lib( HMODULE module, DWORD reason, const void *ptr_in, void *ptr_out )
4139 return STATUS_DLL_NOT_FOUND;
4142 #endif /* HAVE_FREETYPE */
4144 NTSTATUS CDECL __wine_init_unix_lib( HMODULE module, DWORD reason, const void *ptr_in, void *ptr_out )
4146 if (reason != DLL_PROCESS_ATTACH) return STATUS_SUCCESS;
4148 if (ptr_in) return init_freetype_lib( module, reason, ptr_in, ptr_out );
4149 else return init_opengl_lib( module, reason, ptr_in, ptr_out );