mf/session: Forward more events to the application.
[wine/zf.git] / dlls / gdi32 / freetype.c
blobb29d9fcc88ee40e15d558193c23399280c036e7a
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_cptable( WORD cp )
719 static CPTABLEINFO tables[100];
720 unsigned int i;
721 USHORT *ptr;
722 SIZE_T size;
724 for (i = 0; i < ARRAY_SIZE(tables) && tables[i].CodePage; i++)
725 if (tables[i].CodePage == cp) return &tables[i];
726 if (NtGetNlsSectionPtr( 11, cp, NULL, (void **)&ptr, &size )) return NULL;
727 if (i == ARRAY_SIZE(tables)) ERR( "too many code pages\n" );
728 RtlInitCodePageTable( ptr, &tables[i] );
729 return &tables[i];
732 static CPTABLEINFO *get_mac_code_page( const FT_SfntName *name )
734 int id = name->encoding_id;
736 if (name->encoding_id == TT_MAC_ID_SIMPLIFIED_CHINESE) id = 8; /* special case */
737 return get_cptable( 10000 + id );
740 static int match_name_table_language( const FT_SfntName *name, LANGID lang )
742 LANGID name_lang;
743 int res = 0;
745 switch (name->platform_id)
747 case TT_PLATFORM_MICROSOFT:
748 res += 5; /* prefer the Microsoft name */
749 switch (name->encoding_id)
751 case TT_MS_ID_UNICODE_CS:
752 case TT_MS_ID_SYMBOL_CS:
753 name_lang = name->language_id;
754 break;
755 default:
756 return 0;
758 break;
759 case TT_PLATFORM_MACINTOSH:
760 if (!get_mac_code_page( name )) return 0;
761 if (name->language_id >= ARRAY_SIZE( mac_langid_table )) return 0;
762 name_lang = mac_langid_table[name->language_id];
763 break;
764 case TT_PLATFORM_APPLE_UNICODE:
765 res += 2; /* prefer Unicode encodings */
766 switch (name->encoding_id)
768 case TT_APPLE_ID_DEFAULT:
769 case TT_APPLE_ID_ISO_10646:
770 case TT_APPLE_ID_UNICODE_2_0:
771 if (name->language_id >= ARRAY_SIZE( mac_langid_table )) return 0;
772 name_lang = mac_langid_table[name->language_id];
773 break;
774 default:
775 return 0;
777 break;
778 default:
779 return 0;
781 if (name_lang == lang) res += 30;
782 else if (PRIMARYLANGID( name_lang ) == PRIMARYLANGID( lang )) res += 20;
783 else if (name_lang == MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT )) res += 10;
784 else if (lang == MAKELANGID( LANG_NEUTRAL, SUBLANG_NEUTRAL )) res += 5 * (0x100000 - name_lang);
785 return res;
788 static WCHAR *copy_name_table_string( const FT_SfntName *name )
790 WCHAR *ret;
791 CPTABLEINFO *cp;
792 DWORD i;
794 switch (name->platform_id)
796 case TT_PLATFORM_APPLE_UNICODE:
797 case TT_PLATFORM_MICROSOFT:
798 ret = RtlAllocateHeap( GetProcessHeap(), 0, name->string_len + sizeof(WCHAR) );
799 for (i = 0; i < name->string_len / 2; i++)
800 ret[i] = (name->string[i * 2] << 8) | name->string[i * 2 + 1];
801 ret[i] = 0;
802 return ret;
803 case TT_PLATFORM_MACINTOSH:
804 if (!(cp = get_mac_code_page( name ))) return NULL;
805 ret = RtlAllocateHeap( GetProcessHeap(), 0, (name->string_len + 1) * sizeof(WCHAR) );
806 RtlCustomCPToUnicodeN( cp, ret, name->string_len * sizeof(WCHAR), &i,
807 (char *)name->string, name->string_len );
808 ret[i / sizeof(WCHAR)] = 0;
809 return ret;
811 return NULL;
814 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, LANGID language_id)
816 FT_SfntName name;
817 FT_UInt num_names, name_index;
818 int res, best_lang = 0, best_index = -1;
820 if (!FT_IS_SFNT(ft_face)) return NULL;
822 num_names = pFT_Get_Sfnt_Name_Count( ft_face );
824 for (name_index = 0; name_index < num_names; name_index++)
826 if (pFT_Get_Sfnt_Name( ft_face, name_index, &name )) continue;
827 if (name.name_id != name_id) continue;
828 res = match_name_table_language( &name, language_id );
829 if (res > best_lang)
831 best_lang = res;
832 best_index = name_index;
836 if (best_index != -1 && !pFT_Get_Sfnt_Name( ft_face, best_index, &name ))
838 WCHAR *ret = copy_name_table_string( &name );
839 TRACE( "name %u found platform %u lang %04x %s\n",
840 name_id, name.platform_id, name.language_id, debugstr_w( ret ));
841 return ret;
843 return NULL;
846 static WCHAR *ft_face_get_family_name( FT_Face ft_face, LANGID langid )
848 WCHAR *family_name;
850 if ((family_name = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, langid )))
851 return family_name;
853 return towstr( ft_face->family_name );
856 static WCHAR *ft_face_get_style_name( FT_Face ft_face, LANGID langid )
858 WCHAR *style_name;
860 if ((style_name = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, langid )))
861 return style_name;
863 return towstr( ft_face->style_name );
866 static WCHAR *ft_face_get_full_name( FT_Face ft_face, LANGID langid )
868 static const WCHAR space_w[] = {' ',0};
869 WCHAR *full_name, *style_name;
870 SIZE_T length;
872 if ((full_name = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, langid )))
873 return full_name;
875 full_name = ft_face_get_family_name( ft_face, langid );
876 style_name = ft_face_get_style_name( ft_face, langid );
878 length = lstrlenW( full_name ) + lstrlenW( space_w ) + lstrlenW( style_name ) + 1;
879 full_name = RtlReAllocateHeap( GetProcessHeap(), 0, full_name, length * sizeof(WCHAR) );
881 lstrcatW( full_name, space_w );
882 lstrcatW( full_name, style_name );
883 RtlFreeHeap( GetProcessHeap(), 0, style_name );
885 WARN( "full name not found, using %s instead\n", debugstr_w(full_name) );
886 return full_name;
889 static inline FT_Fixed get_font_version( FT_Face ft_face )
891 FT_Fixed version = 0;
892 TT_Header *header;
894 header = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head );
895 if (header) version = header->Font_Revision;
897 return version;
900 static inline DWORD get_ntm_flags( FT_Face ft_face )
902 DWORD flags = 0;
903 FT_ULong table_size = 0;
904 FT_WinFNT_HeaderRec winfnt_header;
906 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) flags |= NTM_ITALIC;
907 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD) flags |= NTM_BOLD;
909 /* fixup the flag for our fake-bold implementation. */
910 if (!FT_IS_SCALABLE( ft_face ) &&
911 !pFT_Get_WinFNT_Header( ft_face, &winfnt_header ) &&
912 winfnt_header.weight > FW_NORMAL )
913 flags |= NTM_BOLD;
915 if (flags == 0) flags = NTM_REGULAR;
917 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL, &table_size ))
918 flags |= NTM_PS_OPENTYPE;
920 return flags;
923 static inline void get_bitmap_size( FT_Face ft_face, struct bitmap_font_size *face_size )
925 My_FT_Bitmap_Size *size;
926 FT_WinFNT_HeaderRec winfnt_header;
928 size = (My_FT_Bitmap_Size *)ft_face->available_sizes;
929 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
930 size->height, size->width, size->size >> 6,
931 size->x_ppem >> 6, size->y_ppem >> 6);
932 face_size->height = size->height;
933 face_size->width = size->width;
934 face_size->size = size->size;
935 face_size->x_ppem = size->x_ppem;
936 face_size->y_ppem = size->y_ppem;
938 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header )) {
939 face_size->internal_leading = winfnt_header.internal_leading;
940 if (winfnt_header.external_leading > 0 &&
941 (face_size->height ==
942 winfnt_header.pixel_height + winfnt_header.external_leading))
943 face_size->height = winfnt_header.pixel_height;
947 static inline void get_fontsig( FT_Face ft_face, FONTSIGNATURE *fs )
949 TT_OS2 *os2;
950 FT_WinFNT_HeaderRec winfnt_header;
951 int i;
953 memset( fs, 0, sizeof(*fs) );
955 os2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 );
956 if (os2)
958 fs->fsUsb[0] = os2->ulUnicodeRange1;
959 fs->fsUsb[1] = os2->ulUnicodeRange2;
960 fs->fsUsb[2] = os2->ulUnicodeRange3;
961 fs->fsUsb[3] = os2->ulUnicodeRange4;
963 if (os2->version == 0)
965 if (os2->usFirstCharIndex >= 0xf000 && os2->usFirstCharIndex < 0xf100)
966 fs->fsCsb[0] = FS_SYMBOL;
967 else
968 fs->fsCsb[0] = FS_LATIN1;
970 else
972 fs->fsCsb[0] = os2->ulCodePageRange1;
973 fs->fsCsb[1] = os2->ulCodePageRange2;
976 else
978 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
980 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
981 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
982 switch (winfnt_header.charset)
984 case ANSI_CHARSET: fs->fsCsb[0] = FS_LATIN1; break;
985 case EASTEUROPE_CHARSET: fs->fsCsb[0] = FS_LATIN2; break;
986 case RUSSIAN_CHARSET: fs->fsCsb[0] = FS_CYRILLIC; break;
987 case GREEK_CHARSET: fs->fsCsb[0] = FS_GREEK; break;
988 case TURKISH_CHARSET: fs->fsCsb[0] = FS_TURKISH; break;
989 case HEBREW_CHARSET: fs->fsCsb[0] = FS_HEBREW; break;
990 case ARABIC_CHARSET: fs->fsCsb[0] = FS_ARABIC; break;
991 case BALTIC_CHARSET: fs->fsCsb[0] = FS_BALTIC; break;
992 case VIETNAMESE_CHARSET: fs->fsCsb[0] = FS_VIETNAMESE; break;
993 case THAI_CHARSET: fs->fsCsb[0] = FS_THAI; break;
994 case SHIFTJIS_CHARSET: fs->fsCsb[0] = FS_JISJAPAN; break;
995 case GB2312_CHARSET: fs->fsCsb[0] = FS_CHINESESIMP; break;
996 case HANGEUL_CHARSET: fs->fsCsb[0] = FS_WANSUNG; break;
997 case CHINESEBIG5_CHARSET: fs->fsCsb[0] = FS_CHINESETRAD; break;
998 case JOHAB_CHARSET: fs->fsCsb[0] = FS_JOHAB; break;
999 case SYMBOL_CHARSET: fs->fsCsb[0] = FS_SYMBOL; break;
1004 if (fs->fsCsb[0] == 0)
1006 /* let's see if we can find any interesting cmaps */
1007 for (i = 0; i < ft_face->num_charmaps; i++)
1009 switch (ft_face->charmaps[i]->encoding)
1011 case FT_ENCODING_UNICODE:
1012 case FT_ENCODING_APPLE_ROMAN:
1013 fs->fsCsb[0] |= FS_LATIN1;
1014 break;
1015 case FT_ENCODING_MS_SYMBOL:
1016 fs->fsCsb[0] |= FS_SYMBOL;
1017 break;
1018 default:
1019 break;
1025 static FT_Face new_ft_face( const char *file, void *font_data_ptr, DWORD font_data_size,
1026 FT_Long face_index, BOOL allow_bitmap )
1028 FT_Error err;
1029 TT_OS2 *pOS2;
1030 FT_Face ft_face;
1032 if (file)
1034 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1035 err = pFT_New_Face(library, file, face_index, &ft_face);
1037 else
1039 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1040 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1043 if (err != 0)
1045 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1046 return NULL;
1049 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1050 if (!FT_IS_SCALABLE( ft_face ) && FT_SimpleVersion < FT_VERSION_VALUE(2, 1, 9))
1052 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1053 goto fail;
1056 if (!FT_IS_SFNT( ft_face ))
1058 if (FT_IS_SCALABLE( ft_face ) || !allow_bitmap )
1060 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1061 goto fail;
1064 else
1066 if (!(pOS2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 )) ||
1067 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_hhea ) ||
1068 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head ))
1070 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1071 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1072 goto fail;
1075 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1076 we don't want to load these. */
1077 if (!memcmp( pOS2->achVendID, "Wine", sizeof(pOS2->achVendID) ))
1079 FT_ULong len = 0;
1081 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len ))
1083 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1084 goto fail;
1089 if (!ft_face->family_name || !ft_face->style_name)
1091 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1092 goto fail;
1095 return ft_face;
1096 fail:
1097 pFT_Done_Face( ft_face );
1098 return NULL;
1101 struct family_names_data
1103 LANGID primary_langid;
1104 struct opentype_name family_name;
1105 struct opentype_name second_name;
1106 BOOL primary_seen;
1107 BOOL english_seen;
1110 static BOOL search_family_names_callback( LANGID langid, struct opentype_name *name, void *user )
1112 struct family_names_data *data = user;
1114 if (langid == MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT))
1116 data->english_seen = TRUE;
1117 if (data->primary_langid == langid) data->primary_seen = TRUE;
1119 if (!data->family_name.bytes) data->family_name = *name;
1120 else if (data->primary_langid != langid) data->second_name = *name;
1122 else if (data->primary_langid == langid)
1124 data->primary_seen = TRUE;
1125 if (!data->second_name.bytes) data->second_name = data->family_name;
1126 data->family_name = *name;
1128 else if (!data->second_name.bytes) data->second_name = *name;
1130 if (data->family_name.bytes && data->second_name.bytes && data->primary_seen && data->english_seen)
1131 return TRUE;
1132 return FALSE;
1135 struct face_name_data
1137 LANGID primary_langid;
1138 struct opentype_name face_name;
1141 static BOOL search_face_name_callback( LANGID langid, struct opentype_name *name, void *user )
1143 struct face_name_data *data = user;
1145 if (langid == data->primary_langid || (langid == MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT) && !data->face_name.bytes))
1146 data->face_name = *name;
1148 return langid == data->primary_langid;
1151 static WCHAR *decode_opentype_name( struct opentype_name *name )
1153 WCHAR buffer[512];
1154 DWORD len;
1156 if (!name->codepage)
1158 len = min( ARRAY_SIZE(buffer), name->length / sizeof(WCHAR) );
1159 while (len--) buffer[len] = GET_BE_WORD( ((WORD *)name->bytes)[len] );
1160 len = min( ARRAY_SIZE(buffer), name->length / sizeof(WCHAR) );
1162 else
1164 CPTABLEINFO *cptable = get_cptable( name->codepage );
1165 if (!cptable) return NULL;
1166 RtlCustomCPToUnicodeN( cptable, buffer, sizeof(buffer), &len, name->bytes, name->length );
1167 len /= sizeof(WCHAR);
1170 buffer[ARRAY_SIZE(buffer) - 1] = 0;
1171 if (len == ARRAY_SIZE(buffer)) WARN("Truncated font name %s -> %s\n", debugstr_an(name->bytes, name->length), debugstr_w(buffer));
1172 else buffer[len] = 0;
1174 return strdupW( buffer );
1177 struct unix_face
1179 FT_Face ft_face;
1180 BOOL scalable;
1181 UINT num_faces;
1182 WCHAR *family_name;
1183 WCHAR *second_name;
1184 WCHAR *style_name;
1185 WCHAR *full_name;
1186 DWORD ntm_flags;
1187 DWORD font_version;
1188 FONTSIGNATURE fs;
1189 struct bitmap_font_size size;
1192 static struct unix_face *unix_face_create( const char *unix_name, void *data_ptr, DWORD data_size,
1193 UINT face_index, DWORD flags )
1195 static const WCHAR space_w[] = {' ',0};
1197 const struct ttc_sfnt_v1 *ttc_sfnt_v1;
1198 const struct tt_name_v0 *tt_name_v0;
1199 struct unix_face *This;
1200 struct stat st;
1201 DWORD face_count;
1202 int fd, length;
1204 TRACE( "unix_name %s, face_index %u, data_ptr %p, data_size %u, flags %#x\n",
1205 unix_name, face_index, data_ptr, data_size, flags );
1207 if (unix_name)
1209 if ((fd = open( unix_name, O_RDONLY )) == -1) return NULL;
1210 if (fstat( fd, &st ) == -1)
1212 close( fd );
1213 return NULL;
1215 data_size = st.st_size;
1216 data_ptr = mmap( NULL, data_size, PROT_READ, MAP_PRIVATE, fd, 0 );
1217 close( fd );
1218 if (data_ptr == MAP_FAILED) return NULL;
1221 if (!(This = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This) ))) goto done;
1223 if (opentype_get_ttc_sfnt_v1( data_ptr, data_size, face_index, &face_count, &ttc_sfnt_v1 ) &&
1224 opentype_get_tt_name_v0( data_ptr, data_size, ttc_sfnt_v1, &tt_name_v0 ) &&
1225 opentype_get_properties( data_ptr, data_size, ttc_sfnt_v1, &This->font_version,
1226 &This->fs, &This->ntm_flags ))
1228 struct family_names_data family_names;
1229 struct face_name_data style_name;
1230 struct face_name_data full_name;
1231 LANGID primary_langid = system_lcid;
1233 This->scalable = TRUE;
1234 This->num_faces = face_count;
1236 memset( &family_names, 0, sizeof(family_names) );
1237 family_names.primary_langid = primary_langid;
1238 opentype_enum_family_names( tt_name_v0, search_family_names_callback, &family_names );
1239 This->family_name = decode_opentype_name( &family_names.family_name );
1240 This->second_name = decode_opentype_name( &family_names.second_name );
1242 memset( &style_name, 0, sizeof(style_name) );
1243 style_name.primary_langid = primary_langid;
1244 opentype_enum_style_names( tt_name_v0, search_face_name_callback, &style_name );
1245 This->style_name = decode_opentype_name( &style_name.face_name );
1247 memset( &full_name, 0, sizeof(full_name) );
1248 style_name.primary_langid = primary_langid;
1249 opentype_enum_full_names( tt_name_v0, search_face_name_callback, &full_name );
1250 This->full_name = decode_opentype_name( &full_name.face_name );
1252 TRACE( "parsed font names family_name %s, second_name %s, primary_seen %d, english_seen %d, "
1253 "full_name %s, style_name %s\n",
1254 debugstr_w(This->family_name), debugstr_w(This->second_name),
1255 family_names.primary_seen, family_names.english_seen,
1256 debugstr_w(This->full_name), debugstr_w(This->style_name) );
1258 if (!This->full_name && This->family_name && This->style_name)
1260 length = lstrlenW( This->family_name ) + lstrlenW( space_w ) + lstrlenW( This->style_name ) + 1;
1261 This->full_name = RtlAllocateHeap( GetProcessHeap(), 0, length * sizeof(WCHAR) );
1262 lstrcpyW( This->full_name, This->family_name );
1263 lstrcatW( This->full_name, space_w );
1264 lstrcatW( This->full_name, This->style_name );
1265 WARN( "full name not found, using %s instead\n", debugstr_w(This->full_name) );
1268 else if ((This->ft_face = new_ft_face( unix_name, data_ptr, data_size, face_index, flags & ADDFONT_ALLOW_BITMAP )))
1270 WARN( "unable to parse font, falling back to FreeType\n" );
1271 This->scalable = FT_IS_SCALABLE( This->ft_face );
1272 This->num_faces = This->ft_face->num_faces;
1274 This->family_name = ft_face_get_family_name( This->ft_face, system_lcid );
1275 This->second_name = ft_face_get_family_name( This->ft_face, MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT) );
1277 /* try to find another secondary name, preferring the lowest langids */
1278 if (!RtlCompareUnicodeStrings( This->family_name, lstrlenW( This->family_name ),
1279 This->second_name, lstrlenW( This->second_name ), TRUE ))
1281 RtlFreeHeap( GetProcessHeap(), 0, This->second_name );
1282 This->second_name = ft_face_get_family_name( This->ft_face, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL) );
1283 if (!RtlCompareUnicodeStrings( This->family_name, lstrlenW( This->family_name ),
1284 This->second_name, lstrlenW( This->second_name ), TRUE ))
1286 RtlFreeHeap( GetProcessHeap(), 0, This->second_name );
1287 This->second_name = NULL;
1291 This->style_name = ft_face_get_style_name( This->ft_face, system_lcid );
1292 This->full_name = ft_face_get_full_name( This->ft_face, system_lcid );
1294 This->ntm_flags = get_ntm_flags( This->ft_face );
1295 This->font_version = get_font_version( This->ft_face );
1296 if (!This->scalable) get_bitmap_size( This->ft_face, &This->size );
1297 get_fontsig( This->ft_face, &This->fs );
1299 else
1301 RtlFreeHeap( GetProcessHeap(), 0, This );
1302 This = NULL;
1305 done:
1306 if (unix_name) munmap( data_ptr, data_size );
1307 return This;
1310 static void unix_face_destroy( struct unix_face *This )
1312 if (This->ft_face) pFT_Done_Face( This->ft_face );
1313 RtlFreeHeap( GetProcessHeap(), 0, This->full_name );
1314 RtlFreeHeap( GetProcessHeap(), 0, This->style_name );
1315 RtlFreeHeap( GetProcessHeap(), 0, This->second_name );
1316 RtlFreeHeap( GetProcessHeap(), 0, This->family_name );
1317 RtlFreeHeap( GetProcessHeap(), 0, This );
1320 static int add_unix_face( const char *unix_name, const WCHAR *file, void *data_ptr, SIZE_T data_size,
1321 DWORD face_index, DWORD flags, DWORD *num_faces )
1323 struct unix_face *unix_face;
1324 int ret;
1326 if (num_faces) *num_faces = 0;
1328 if (!(unix_face = unix_face_create( unix_name, data_ptr, data_size, face_index, flags )))
1329 return 0;
1331 if (unix_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1333 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(unix_name));
1334 unix_face_destroy( unix_face );
1335 return 0;
1338 if (!HIWORD( flags )) flags |= ADDFONT_AA_FLAGS( default_aa_flags );
1340 ret = callback_funcs->add_gdi_face( unix_face->family_name, unix_face->second_name, unix_face->style_name, unix_face->full_name,
1341 file, data_ptr, data_size, face_index, unix_face->fs, unix_face->ntm_flags,
1342 unix_face->font_version, flags, unix_face->scalable ? NULL : &unix_face->size );
1344 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n", unix_face->fs.fsCsb[0], unix_face->fs.fsCsb[1],
1345 unix_face->fs.fsUsb[0], unix_face->fs.fsUsb[1], unix_face->fs.fsUsb[2], unix_face->fs.fsUsb[3]);
1347 if (num_faces) *num_faces = unix_face->num_faces;
1348 unix_face_destroy( unix_face );
1349 return ret;
1352 static WCHAR *get_dos_file_name( LPCSTR str )
1354 WCHAR *buffer;
1355 SIZE_T len = strlen(str) + 1;
1357 len += 8; /* \??\unix prefix */
1358 if (!(buffer = RtlAllocateHeap( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return NULL;
1359 if (wine_unix_to_nt_file_name( str, buffer, &len ))
1361 RtlFreeHeap( GetProcessHeap(), 0, buffer );
1362 return NULL;
1364 if (buffer[5] == ':')
1366 /* get rid of the \??\ prefix */
1367 /* FIXME: should implement RtlNtPathNameToDosPathName and use that instead */
1368 memmove( buffer, buffer + 4, (len - 4) * sizeof(WCHAR) );
1370 else buffer[1] = '\\';
1371 return buffer;
1374 static char *get_unix_file_name( LPCWSTR dosW )
1376 UNICODE_STRING nt_name;
1377 NTSTATUS status;
1378 SIZE_T size = 256;
1379 char *buffer;
1381 if (!RtlDosPathNameToNtPathName_U( dosW, &nt_name, NULL, NULL )) return NULL;
1382 for (;;)
1384 if (!(buffer = RtlAllocateHeap( GetProcessHeap(), 0, size )))
1386 RtlFreeUnicodeString( &nt_name );
1387 return NULL;
1389 status = wine_nt_to_unix_file_name( &nt_name, buffer, &size, FILE_OPEN_IF );
1390 if (status != STATUS_BUFFER_TOO_SMALL) break;
1391 RtlFreeHeap( GetProcessHeap(), 0, buffer );
1393 RtlFreeUnicodeString( &nt_name );
1394 if (status && status != STATUS_NO_SUCH_FILE)
1396 RtlFreeHeap( GetProcessHeap(), 0, buffer );
1397 RtlSetLastWin32ErrorAndNtStatusFromNtStatus( status );
1398 return NULL;
1400 return buffer;
1403 static INT AddFontToList(const WCHAR *dos_name, const char *unix_name, void *font_data_ptr,
1404 DWORD font_data_size, DWORD flags)
1406 DWORD face_index = 0, num_faces;
1407 INT ret = 0;
1408 WCHAR *filename = NULL;
1410 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1411 assert(unix_name || !(flags & ADDFONT_EXTERNAL_FONT));
1413 #ifdef HAVE_CARBON_CARBON_H
1414 if(unix_name)
1416 char **mac_list = expand_mac_font(unix_name);
1417 if(mac_list)
1419 BOOL had_one = FALSE;
1420 char **cursor;
1421 for(cursor = mac_list; *cursor; cursor++)
1423 had_one = TRUE;
1424 AddFontToList(NULL, *cursor, NULL, 0, flags);
1425 RtlFreeHeap(GetProcessHeap(), 0, *cursor);
1427 RtlFreeHeap(GetProcessHeap(), 0, mac_list);
1428 if(had_one)
1429 return 1;
1432 #endif /* HAVE_CARBON_CARBON_H */
1434 if (!dos_name && unix_name) dos_name = filename = get_dos_file_name( unix_name );
1437 ret += add_unix_face( unix_name, dos_name, font_data_ptr, font_data_size, face_index, flags, &num_faces );
1438 while (num_faces > ++face_index);
1440 RtlFreeHeap( GetProcessHeap(), 0, filename );
1441 return ret;
1444 /*************************************************************
1445 * freetype_add_font
1447 static INT CDECL freetype_add_font( const WCHAR *file, DWORD flags )
1449 int ret = 0;
1450 char *unixname = get_unix_file_name( file );
1452 if (unixname)
1454 ret = AddFontToList( file, unixname, NULL, 0, flags );
1455 RtlFreeHeap( GetProcessHeap(), 0, unixname );
1457 return ret;
1460 /*************************************************************
1461 * freetype_add_mem_font
1463 static INT CDECL freetype_add_mem_font( void *ptr, SIZE_T size, DWORD flags )
1465 return AddFontToList( NULL, NULL, ptr, size, flags );
1468 #ifdef __ANDROID__
1469 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1471 DIR *dir;
1472 struct dirent *dent;
1473 char path[MAX_PATH];
1475 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1477 dir = opendir(dirname);
1478 if(!dir) {
1479 WARN("Can't open directory %s\n", debugstr_a(dirname));
1480 return FALSE;
1482 while((dent = readdir(dir)) != NULL) {
1483 struct stat statbuf;
1485 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1486 continue;
1488 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1490 sprintf(path, "%s/%s", dirname, dent->d_name);
1492 if(stat(path, &statbuf) == -1)
1494 WARN("Can't stat %s\n", debugstr_a(path));
1495 continue;
1497 if(S_ISDIR(statbuf.st_mode))
1498 ReadFontDir(path, external_fonts);
1499 else
1501 DWORD addfont_flags = 0;
1502 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
1503 AddFontToList(NULL, path, NULL, 0, addfont_flags);
1506 closedir(dir);
1507 return TRUE;
1509 #endif
1511 #ifdef SONAME_LIBFONTCONFIG
1513 static BOOL fontconfig_enabled;
1514 static FcPattern *pattern_serif;
1515 static FcPattern *pattern_fixed;
1516 static FcPattern *pattern_sans;
1518 static UINT parse_aa_pattern( FcPattern *pattern )
1520 FcBool antialias;
1521 int rgba;
1522 UINT aa_flags = 0;
1524 if (pFcPatternGetBool( pattern, FC_ANTIALIAS, 0, &antialias ) == FcResultMatch)
1525 aa_flags = antialias ? GGO_GRAY4_BITMAP : GGO_BITMAP;
1527 if (pFcPatternGetInteger( pattern, FC_RGBA, 0, &rgba ) == FcResultMatch)
1529 switch (rgba)
1531 case FC_RGBA_RGB: aa_flags = WINE_GGO_HRGB_BITMAP; break;
1532 case FC_RGBA_BGR: aa_flags = WINE_GGO_HBGR_BITMAP; break;
1533 case FC_RGBA_VRGB: aa_flags = WINE_GGO_VRGB_BITMAP; break;
1534 case FC_RGBA_VBGR: aa_flags = WINE_GGO_VBGR_BITMAP; break;
1535 case FC_RGBA_NONE: aa_flags = aa_flags ? aa_flags : GGO_GRAY4_BITMAP; break;
1538 return aa_flags;
1541 static FcPattern *create_family_pattern( const char *name, FcPattern **cached )
1543 FcPattern *ret = NULL, *tmp, *pattern = pFcPatternCreate();
1544 FcResult result;
1545 if (*cached) return *cached;
1546 pFcPatternAddString( pattern, FC_FAMILY, (const FcChar8 *)name );
1547 pFcPatternAddString( pattern, FC_NAMELANG, (const FcChar8 *)"en-us" );
1548 pFcPatternAddString( pattern, FC_PRGNAME, (const FcChar8 *)"wine" );
1549 pFcConfigSubstitute( NULL, pattern, FcMatchPattern );
1550 pFcDefaultSubstitute( pattern );
1551 tmp = pFcFontMatch( NULL, pattern, &result );
1552 pFcPatternDestroy( pattern );
1553 if (result != FcResultMatch) pFcPatternDestroy( tmp );
1554 else if ((ret = InterlockedCompareExchangePointer( (void **)cached, tmp, NULL ))) pFcPatternDestroy( tmp );
1555 else ret = tmp;
1556 return ret;
1559 static void fontconfig_add_font( FcPattern *pattern, DWORD flags )
1561 const char *unix_name, *format;
1562 WCHAR *dos_name;
1563 FcBool scalable;
1564 DWORD aa_flags;
1565 int face_index;
1567 TRACE( "(%p %#x)\n", pattern, flags );
1569 if (pFcPatternGetString( pattern, FC_FILE, 0, (FcChar8 **)&unix_name ) != FcResultMatch)
1570 return;
1572 if (pFcPatternGetBool( pattern, FC_SCALABLE, 0, &scalable ) != FcResultMatch)
1573 scalable = FALSE;
1575 if (pFcPatternGetString( pattern, FC_FONTFORMAT, 0, (FcChar8 **)&format ) != FcResultMatch)
1577 TRACE( "ignoring unknown font format %s\n", debugstr_a(unix_name) );
1578 return;
1581 if (!strcmp( format, "Type 1" ))
1583 TRACE( "ignoring Type 1 font %s\n", debugstr_a(unix_name) );
1584 return;
1587 if (!scalable && !(flags & ADDFONT_ALLOW_BITMAP))
1589 TRACE( "ignoring non-scalable font %s\n", debugstr_a(unix_name) );
1590 return;
1593 if (!(aa_flags = parse_aa_pattern( pattern ))) aa_flags = default_aa_flags;
1594 flags |= ADDFONT_AA_FLAGS(aa_flags);
1596 if (pFcPatternGetInteger( pattern, FC_INDEX, 0, &face_index ) != FcResultMatch)
1597 face_index = 0;
1599 dos_name = get_dos_file_name( unix_name );
1600 add_unix_face( unix_name, dos_name, NULL, 0, face_index, flags, NULL );
1601 RtlFreeHeap( GetProcessHeap(), 0, dos_name );
1604 static void init_fontconfig(void)
1606 void *fc_handle = dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW);
1608 if (!fc_handle)
1610 TRACE("Wine cannot find the fontconfig library (%s).\n", SONAME_LIBFONTCONFIG);
1611 return;
1614 #define LOAD_FUNCPTR(f) if((p##f = dlsym(fc_handle, #f)) == NULL){WARN("Can't find symbol %s\n", #f); return;}
1615 LOAD_FUNCPTR(FcConfigSubstitute);
1616 LOAD_FUNCPTR(FcDefaultSubstitute);
1617 LOAD_FUNCPTR(FcFontList);
1618 LOAD_FUNCPTR(FcFontMatch);
1619 LOAD_FUNCPTR(FcFontSetDestroy);
1620 LOAD_FUNCPTR(FcInit);
1621 LOAD_FUNCPTR(FcPatternAddString);
1622 LOAD_FUNCPTR(FcPatternCreate);
1623 LOAD_FUNCPTR(FcPatternDestroy);
1624 LOAD_FUNCPTR(FcPatternGetBool);
1625 LOAD_FUNCPTR(FcPatternGetInteger);
1626 LOAD_FUNCPTR(FcPatternGetString);
1627 LOAD_FUNCPTR(FcConfigGetFontDirs);
1628 LOAD_FUNCPTR(FcConfigGetCurrent);
1629 LOAD_FUNCPTR(FcCacheCopySet);
1630 LOAD_FUNCPTR(FcCacheNumSubdir);
1631 LOAD_FUNCPTR(FcCacheSubdir);
1632 LOAD_FUNCPTR(FcDirCacheRead);
1633 LOAD_FUNCPTR(FcDirCacheUnload);
1634 LOAD_FUNCPTR(FcStrListCreate);
1635 LOAD_FUNCPTR(FcStrListDone);
1636 LOAD_FUNCPTR(FcStrListNext);
1637 LOAD_FUNCPTR(FcStrSetAdd);
1638 LOAD_FUNCPTR(FcStrSetCreate);
1639 LOAD_FUNCPTR(FcStrSetDestroy);
1640 LOAD_FUNCPTR(FcStrSetMember);
1641 #undef LOAD_FUNCPTR
1643 if (pFcInit())
1645 FcPattern *pattern = pFcPatternCreate();
1646 pFcConfigSubstitute( NULL, pattern, FcMatchFont );
1647 default_aa_flags = parse_aa_pattern( pattern );
1648 pFcPatternDestroy( pattern );
1650 if (!default_aa_flags)
1652 FcPattern *pattern = pFcPatternCreate();
1653 pFcConfigSubstitute( NULL, pattern, FcMatchPattern );
1654 default_aa_flags = parse_aa_pattern( pattern );
1655 pFcPatternDestroy( pattern );
1658 TRACE( "enabled, default flags = %x\n", default_aa_flags );
1659 fontconfig_enabled = TRUE;
1663 static void fontconfig_add_fonts_from_dir_list( FcConfig *config, FcStrList *dir_list, FcStrSet *done_set, DWORD flags )
1665 const FcChar8 *dir;
1666 FcFontSet *font_set = NULL;
1667 FcStrList *subdir_list = NULL;
1668 FcStrSet *subdir_set = NULL;
1669 FcCache *cache = NULL;
1670 int i;
1672 TRACE( "(%p %p %p %#x)\n", config, dir_list, done_set, flags );
1674 while ((dir = pFcStrListNext( dir_list )))
1676 if (pFcStrSetMember( done_set, dir )) continue;
1678 TRACE( "adding fonts from %s\n", dir );
1679 if (!(cache = pFcDirCacheRead( dir, FcFalse, config ))) continue;
1681 if (!(font_set = pFcCacheCopySet( cache ))) goto done;
1682 for (i = 0; i < font_set->nfont; i++)
1683 fontconfig_add_font( font_set->fonts[i], flags );
1684 pFcFontSetDestroy( font_set );
1685 font_set = NULL;
1687 if (!(subdir_set = pFcStrSetCreate())) goto done;
1688 for (i = 0; i < pFcCacheNumSubdir( cache ); i++)
1689 pFcStrSetAdd( subdir_set, pFcCacheSubdir( cache, i ) );
1690 pFcDirCacheUnload( cache );
1691 cache = NULL;
1693 if (!(subdir_list = pFcStrListCreate( subdir_set ))) goto done;
1694 pFcStrSetDestroy( subdir_set );
1695 subdir_set = NULL;
1697 pFcStrSetAdd( done_set, dir );
1698 fontconfig_add_fonts_from_dir_list( config, subdir_list, done_set, flags );
1699 pFcStrListDone( subdir_list );
1700 subdir_list = NULL;
1703 done:
1704 if (font_set) pFcFontSetDestroy( font_set );
1705 if (subdir_list) pFcStrListDone( subdir_list );
1706 if (subdir_set) pFcStrSetDestroy( subdir_set );
1707 if (cache) pFcDirCacheUnload( cache );
1710 static void load_fontconfig_fonts( void )
1712 FcStrList *dir_list = NULL;
1713 FcStrSet *done_set = NULL;
1714 FcConfig *config;
1716 if (!fontconfig_enabled) return;
1717 if (!(config = pFcConfigGetCurrent())) goto done;
1718 if (!(done_set = pFcStrSetCreate())) goto done;
1719 if (!(dir_list = pFcConfigGetFontDirs( config ))) goto done;
1721 fontconfig_add_fonts_from_dir_list( config, dir_list, done_set, ADDFONT_EXTERNAL_FONT );
1723 done:
1724 if (dir_list) pFcStrListDone( dir_list );
1725 if (done_set) pFcStrSetDestroy( done_set );
1728 #elif defined(HAVE_CARBON_CARBON_H)
1730 static void load_mac_font_callback(const void *value, void *context)
1732 CFStringRef pathStr = value;
1733 CFIndex len;
1734 char* path;
1736 len = CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr);
1737 path = RtlAllocateHeap(GetProcessHeap(), 0, len);
1738 if (path && CFStringGetFileSystemRepresentation(pathStr, path, len))
1740 TRACE("font file %s\n", path);
1741 AddFontToList(NULL, path, NULL, 0, ADDFONT_EXTERNAL_FONT);
1743 RtlFreeHeap(GetProcessHeap(), 0, path);
1746 static void load_mac_fonts(void)
1748 CFStringRef removeDupesKey;
1749 CFBooleanRef removeDupesValue;
1750 CFDictionaryRef options;
1751 CTFontCollectionRef col;
1752 CFArrayRef descs;
1753 CFMutableSetRef paths;
1754 CFIndex i;
1756 removeDupesKey = kCTFontCollectionRemoveDuplicatesOption;
1757 removeDupesValue = kCFBooleanTrue;
1758 options = CFDictionaryCreate(NULL, (const void**)&removeDupesKey, (const void**)&removeDupesValue, 1,
1759 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1760 col = CTFontCollectionCreateFromAvailableFonts(options);
1761 if (options) CFRelease(options);
1762 if (!col)
1764 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
1765 return;
1768 descs = CTFontCollectionCreateMatchingFontDescriptors(col);
1769 CFRelease(col);
1770 if (!descs)
1772 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
1773 return;
1776 paths = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
1777 if (!paths)
1779 WARN("CFSetCreateMutable failed\n");
1780 CFRelease(descs);
1781 return;
1784 for (i = 0; i < CFArrayGetCount(descs); i++)
1786 CTFontDescriptorRef desc;
1787 CFURLRef url;
1788 CFStringRef ext;
1789 CFStringRef path;
1791 desc = CFArrayGetValueAtIndex(descs, i);
1793 #if defined(MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
1794 url = CTFontDescriptorCopyAttribute(desc, kCTFontURLAttribute);
1795 #else
1796 /* CTFontDescriptor doesn't support kCTFontURLAttribute prior to 10.6, so
1797 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
1799 CTFontRef font;
1800 ATSFontRef atsFont;
1801 OSStatus status;
1802 FSRef fsref;
1804 font = CTFontCreateWithFontDescriptor(desc, 0, NULL);
1805 if (!font) continue;
1807 atsFont = CTFontGetPlatformFont(font, NULL);
1808 if (!atsFont)
1810 CFRelease(font);
1811 continue;
1814 status = ATSFontGetFileReference(atsFont, &fsref);
1815 CFRelease(font);
1816 if (status != noErr) continue;
1818 url = CFURLCreateFromFSRef(NULL, &fsref);
1820 #endif
1821 if (!url) continue;
1823 ext = CFURLCopyPathExtension(url);
1824 if (ext)
1826 BOOL skip = (CFStringCompare(ext, CFSTR("pfa"), kCFCompareCaseInsensitive) == kCFCompareEqualTo ||
1827 CFStringCompare(ext, CFSTR("pfb"), kCFCompareCaseInsensitive) == kCFCompareEqualTo);
1828 CFRelease(ext);
1829 if (skip)
1831 CFRelease(url);
1832 continue;
1836 path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
1837 CFRelease(url);
1838 if (!path) continue;
1840 CFSetAddValue(paths, path);
1841 CFRelease(path);
1844 CFRelease(descs);
1846 CFSetApplyFunction(paths, load_mac_font_callback, NULL);
1847 CFRelease(paths);
1850 #endif
1853 static BOOL init_freetype(void)
1855 ft_handle = dlopen(SONAME_LIBFREETYPE, RTLD_NOW);
1856 if(!ft_handle) {
1857 WINE_MESSAGE(
1858 "Wine cannot find the FreeType font library. To enable Wine to\n"
1859 "use TrueType fonts please install a version of FreeType greater than\n"
1860 "or equal to 2.0.5.\n"
1861 "http://www.freetype.org\n");
1862 return FALSE;
1865 #define LOAD_FUNCPTR(f) if((p##f = dlsym(ft_handle, #f)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
1867 LOAD_FUNCPTR(FT_Done_Face)
1868 LOAD_FUNCPTR(FT_Get_Char_Index)
1869 LOAD_FUNCPTR(FT_Get_First_Char)
1870 LOAD_FUNCPTR(FT_Get_Next_Char)
1871 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
1872 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
1873 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
1874 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
1875 LOAD_FUNCPTR(FT_Init_FreeType)
1876 LOAD_FUNCPTR(FT_Library_Version)
1877 LOAD_FUNCPTR(FT_Load_Glyph)
1878 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
1879 LOAD_FUNCPTR(FT_Matrix_Multiply)
1880 LOAD_FUNCPTR(FT_MulDiv)
1881 #ifndef FT_MULFIX_INLINED
1882 LOAD_FUNCPTR(FT_MulFix)
1883 #endif
1884 LOAD_FUNCPTR(FT_New_Face)
1885 LOAD_FUNCPTR(FT_New_Memory_Face)
1886 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
1887 LOAD_FUNCPTR(FT_Outline_Get_CBox)
1888 LOAD_FUNCPTR(FT_Outline_Transform)
1889 LOAD_FUNCPTR(FT_Outline_Translate)
1890 LOAD_FUNCPTR(FT_Render_Glyph)
1891 LOAD_FUNCPTR(FT_Set_Charmap)
1892 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
1893 LOAD_FUNCPTR(FT_Vector_Length)
1894 LOAD_FUNCPTR(FT_Vector_Transform)
1895 LOAD_FUNCPTR(FT_Vector_Unit)
1896 #undef LOAD_FUNCPTR
1897 /* Don't warn if these ones are missing */
1898 pFT_Outline_Embolden = dlsym(ft_handle, "FT_Outline_Embolden");
1899 pFT_Get_TrueType_Engine_Type = dlsym(ft_handle, "FT_Get_TrueType_Engine_Type");
1900 #ifdef FT_LCD_FILTER_H
1901 pFT_Library_SetLcdFilter = dlsym(ft_handle, "FT_Library_SetLcdFilter");
1902 #endif
1903 pFT_Property_Set = dlsym(ft_handle, "FT_Property_Set");
1905 if(pFT_Init_FreeType(&library) != 0) {
1906 ERR("Can't init FreeType library\n");
1907 dlclose(ft_handle);
1908 ft_handle = NULL;
1909 return FALSE;
1911 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
1913 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
1914 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
1915 ((FT_Version.minor << 8) & 0x00ff00) |
1916 ((FT_Version.patch ) & 0x0000ff);
1918 /* In FreeType < 2.8.1 v40's FT_LOAD_TARGET_MONO has broken advance widths. */
1919 if (pFT_Property_Set && FT_SimpleVersion < FT_VERSION_VALUE(2, 8, 1))
1921 FT_UInt interpreter_version = 35;
1922 pFT_Property_Set( library, "truetype", "interpreter-version", &interpreter_version );
1925 #ifdef FT_LCD_FILTER_H
1926 if (pFT_Library_SetLcdFilter)
1927 pFT_Library_SetLcdFilter( library, FT_LCD_FILTER_DEFAULT );
1928 #endif
1930 return TRUE;
1932 sym_not_found:
1933 WINE_MESSAGE(
1934 "Wine cannot find certain functions that it needs inside the FreeType\n"
1935 "font library. To enable Wine to use TrueType fonts please upgrade\n"
1936 "FreeType to at least version 2.1.4.\n"
1937 "http://www.freetype.org\n");
1938 dlclose(ft_handle);
1939 ft_handle = NULL;
1940 return FALSE;
1943 /*************************************************************
1944 * freetype_load_fonts
1946 static void CDECL freetype_load_fonts(void)
1948 #ifdef SONAME_LIBFONTCONFIG
1949 load_fontconfig_fonts();
1950 #elif defined(HAVE_CARBON_CARBON_H)
1951 load_mac_fonts();
1952 #elif defined(__ANDROID__)
1953 ReadFontDir("/system/fonts", TRUE);
1954 #endif
1957 /* Some fonts have large usWinDescent values, as a result of storing signed short
1958 in unsigned field. That's probably caused by sTypoDescent vs usWinDescent confusion in
1959 some font generation tools. */
1960 static inline USHORT get_fixed_windescent(USHORT windescent)
1962 return abs((SHORT)windescent);
1965 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
1967 TT_OS2 *pOS2;
1968 TT_HoriHeader *pHori;
1970 LONG ppem;
1971 const LONG MAX_PPEM = (1 << 16) - 1;
1973 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1974 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1976 if(height == 0) height = 16;
1978 /* Calc. height of EM square:
1980 * For +ve lfHeight we have
1981 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
1982 * Re-arranging gives:
1983 * ppem = units_per_em * lfheight / (winAscent + winDescent)
1985 * For -ve lfHeight we have
1986 * |lfHeight| = ppem
1987 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
1988 * with il = winAscent + winDescent - units_per_em]
1992 if(height > 0) {
1993 USHORT windescent = get_fixed_windescent(pOS2->usWinDescent);
1994 if(pOS2->usWinAscent + windescent == 0)
1995 ppem = pFT_MulDiv(ft_face->units_per_EM, height, pHori->Ascender - pHori->Descender);
1996 else
1997 ppem = pFT_MulDiv(ft_face->units_per_EM, height, pOS2->usWinAscent + windescent);
1998 if(ppem > MAX_PPEM) {
1999 WARN("Ignoring too large height %d, ppem %d\n", height, ppem);
2000 ppem = 1;
2003 else if(height >= -MAX_PPEM)
2004 ppem = -height;
2005 else {
2006 WARN("Ignoring too large height %d\n", height);
2007 ppem = 1;
2010 return ppem;
2013 static struct font_mapping *map_font_file( const char *name )
2015 struct font_mapping *mapping;
2016 struct stat st;
2017 int fd;
2019 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2020 if (fstat( fd, &st ) == -1) goto error;
2022 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2024 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2026 mapping->refcount++;
2027 close( fd );
2028 return mapping;
2031 if (!(mapping = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*mapping) )))
2032 goto error;
2034 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2035 close( fd );
2037 if (mapping->data == MAP_FAILED)
2039 RtlFreeHeap( GetProcessHeap(), 0, mapping );
2040 return NULL;
2042 mapping->refcount = 1;
2043 mapping->dev = st.st_dev;
2044 mapping->ino = st.st_ino;
2045 mapping->size = st.st_size;
2046 list_add_tail( &mappings_list, &mapping->entry );
2047 return mapping;
2049 error:
2050 close( fd );
2051 return NULL;
2054 static void unmap_font_file( struct font_mapping *mapping )
2056 if (!--mapping->refcount)
2058 list_remove( &mapping->entry );
2059 munmap( mapping->data, mapping->size );
2060 RtlFreeHeap( GetProcessHeap(), 0, mapping );
2064 static LONG load_VDMX(struct gdi_font *font, LONG height);
2066 /*************************************************************
2067 * freetype_destroy_font
2069 static void CDECL freetype_destroy_font( struct gdi_font *font )
2071 struct font_private_data *data = font->private;
2073 if (data->ft_face) pFT_Done_Face( data->ft_face );
2074 if (data->mapping) unmap_font_file( data->mapping );
2075 RtlFreeHeap( GetProcessHeap(), 0, data );
2078 /*************************************************************
2079 * freetype_get_font_data
2081 static DWORD CDECL freetype_get_font_data( struct gdi_font *font, DWORD table, DWORD offset,
2082 void *buf, DWORD cbData)
2084 FT_Face ft_face = get_ft_face( font );
2085 FT_ULong len;
2086 FT_Error err;
2088 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
2090 if(!buf)
2091 len = 0;
2092 else
2093 len = cbData;
2095 /* if font is a member of TTC, 'ttcf' tag allows reading from beginning of TTC file,
2096 0 tag means to read from start of collection member data. */
2097 if (font->ttc_item_offset)
2099 if (table == MS_TTCF_TAG)
2100 table = 0;
2101 else if (table == 0)
2102 offset += font->ttc_item_offset;
2105 /* make sure value of len is the value freetype says it needs */
2106 if (buf && len)
2108 FT_ULong needed = 0;
2109 err = pFT_Load_Sfnt_Table(ft_face, RtlUlongByteSwap(table), offset, NULL, &needed);
2110 if( !err && needed < len) len = needed;
2112 err = pFT_Load_Sfnt_Table(ft_face, RtlUlongByteSwap(table), offset, buf, &len);
2113 if (err)
2115 TRACE("Can't find table %s\n", debugstr_an((char*)&table, 4));
2116 return GDI_ERROR;
2118 return len;
2121 /*************************************************************
2122 * load_VDMX
2124 * load the vdmx entry for the specified height
2129 typedef struct {
2130 WORD version;
2131 WORD numRecs;
2132 WORD numRatios;
2133 } VDMX_Header;
2135 typedef struct {
2136 BYTE bCharSet;
2137 BYTE xRatio;
2138 BYTE yStartRatio;
2139 BYTE yEndRatio;
2140 } Ratios;
2142 typedef struct {
2143 WORD recs;
2144 BYTE startsz;
2145 BYTE endsz;
2146 } VDMX_group;
2148 typedef struct {
2149 WORD yPelHeight;
2150 WORD yMax;
2151 WORD yMin;
2152 } VDMX_vTable;
2154 static LONG load_VDMX(struct gdi_font *font, LONG height)
2156 VDMX_Header hdr;
2157 VDMX_group group;
2158 BYTE devXRatio, devYRatio;
2159 USHORT numRecs, numRatios;
2160 DWORD result, offset = -1;
2161 LONG ppem = 0;
2162 int i;
2164 result = freetype_get_font_data(font, MS_VDMX_TAG, 0, &hdr, sizeof(hdr));
2166 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2167 return ppem;
2169 /* FIXME: need the real device aspect ratio */
2170 devXRatio = 1;
2171 devYRatio = 1;
2173 numRecs = GET_BE_WORD(hdr.numRecs);
2174 numRatios = GET_BE_WORD(hdr.numRatios);
2176 TRACE("version = %d numRecs = %d numRatios = %d\n", GET_BE_WORD(hdr.version), numRecs, numRatios);
2177 for(i = 0; i < numRatios; i++) {
2178 Ratios ratio;
2180 offset = sizeof(hdr) + (i * sizeof(Ratios));
2181 freetype_get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2182 offset = -1;
2184 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2186 if (!ratio.bCharSet) continue;
2188 if((ratio.xRatio == 0 &&
2189 ratio.yStartRatio == 0 &&
2190 ratio.yEndRatio == 0) ||
2191 (devXRatio == ratio.xRatio &&
2192 devYRatio >= ratio.yStartRatio &&
2193 devYRatio <= ratio.yEndRatio))
2195 WORD group_offset;
2197 offset = sizeof(hdr) + numRatios * sizeof(ratio) + i * sizeof(group_offset);
2198 freetype_get_font_data(font, MS_VDMX_TAG, offset, &group_offset, sizeof(group_offset));
2199 offset = GET_BE_WORD(group_offset);
2200 break;
2204 if(offset == -1) return 0;
2206 if(freetype_get_font_data(font, MS_VDMX_TAG, offset, &group, sizeof(group)) != GDI_ERROR) {
2207 USHORT recs;
2208 BYTE startsz, endsz;
2209 WORD *vTable;
2211 recs = GET_BE_WORD(group.recs);
2212 startsz = group.startsz;
2213 endsz = group.endsz;
2215 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
2217 vTable = RtlAllocateHeap(GetProcessHeap(), 0, recs * sizeof(VDMX_vTable));
2218 result = freetype_get_font_data(font, MS_VDMX_TAG, offset + sizeof(group), vTable, recs * sizeof(VDMX_vTable));
2219 if(result == GDI_ERROR) {
2220 FIXME("Failed to retrieve vTable\n");
2221 goto end;
2224 if(height > 0) {
2225 for(i = 0; i < recs; i++) {
2226 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2227 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2228 ppem = GET_BE_WORD(vTable[i * 3]);
2230 if(yMax + -yMin == height) {
2231 font->yMax = yMax;
2232 font->yMin = yMin;
2233 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2234 break;
2236 if(yMax + -yMin > height) {
2237 if(--i < 0) {
2238 ppem = 0;
2239 goto end; /* failed */
2241 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2242 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2243 ppem = GET_BE_WORD(vTable[i * 3]);
2244 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2245 break;
2248 if(!font->yMax) {
2249 ppem = 0;
2250 TRACE("ppem not found for height %d\n", height);
2252 } else {
2253 ppem = -height;
2254 if(ppem < startsz || ppem > endsz)
2256 ppem = 0;
2257 goto end;
2260 for(i = 0; i < recs; i++) {
2261 USHORT yPelHeight;
2262 yPelHeight = GET_BE_WORD(vTable[i * 3]);
2264 if(yPelHeight > ppem)
2266 ppem = 0;
2267 break; /* failed */
2270 if(yPelHeight == ppem) {
2271 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2272 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2273 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
2274 break;
2278 end:
2279 RtlFreeHeap(GetProcessHeap(), 0, vTable);
2282 return ppem;
2285 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
2287 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
2288 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
2289 FT_Int i;
2291 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
2293 for (i = 0; i < ft_face->num_charmaps; i++)
2295 if (ft_face->charmaps[i]->encoding == encoding)
2297 TRACE("found cmap with platform_id %u, encoding_id %u\n",
2298 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
2300 switch (ft_face->charmaps[i]->platform_id)
2302 default:
2303 cmap_def = ft_face->charmaps[i];
2304 break;
2305 case 0: /* Apple Unicode */
2306 cmap0 = ft_face->charmaps[i];
2307 break;
2308 case 1: /* Macintosh */
2309 cmap1 = ft_face->charmaps[i];
2310 break;
2311 case 2: /* ISO */
2312 cmap2 = ft_face->charmaps[i];
2313 break;
2314 case 3: /* Microsoft */
2315 cmap3 = ft_face->charmaps[i];
2316 break;
2320 if (cmap3) /* prefer Microsoft cmap table */
2321 ft_err = pFT_Set_Charmap(ft_face, cmap3);
2322 else if (cmap1)
2323 ft_err = pFT_Set_Charmap(ft_face, cmap1);
2324 else if (cmap2)
2325 ft_err = pFT_Set_Charmap(ft_face, cmap2);
2326 else if (cmap0)
2327 ft_err = pFT_Set_Charmap(ft_face, cmap0);
2328 else if (cmap_def)
2329 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
2332 return ft_err == FT_Err_Ok;
2336 static FT_Encoding pick_charmap( FT_Face face, int charset )
2338 static const FT_Encoding regular_order[] = { FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, FT_ENCODING_MS_SYMBOL, 0 };
2339 static const FT_Encoding symbol_order[] = { FT_ENCODING_MS_SYMBOL, FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, 0 };
2340 const FT_Encoding *encs = regular_order;
2342 if (charset == SYMBOL_CHARSET) encs = symbol_order;
2344 while (*encs != 0)
2346 if (select_charmap( face, *encs )) break;
2347 encs++;
2350 if (!face->charmap && face->num_charmaps)
2352 if (!pFT_Set_Charmap(face, face->charmaps[0]))
2353 return face->charmap->encoding;
2356 return *encs;
2359 static BOOL get_gasp_flags( struct gdi_font *font, WORD *flags )
2361 FT_Face ft_face = get_ft_face( font );
2362 DWORD size;
2363 WORD buf[16]; /* Enough for seven ranges before we need to alloc */
2364 WORD *alloced = NULL, *ptr = buf;
2365 WORD num_recs, version;
2366 BOOL ret = FALSE;
2368 *flags = 0;
2369 size = freetype_get_font_data( font, MS_GASP_TAG, 0, NULL, 0 );
2370 if (size == GDI_ERROR) return FALSE;
2371 if (size < 4 * sizeof(WORD)) return FALSE;
2372 if (size > sizeof(buf))
2374 ptr = alloced = RtlAllocateHeap( GetProcessHeap(), 0, size );
2375 if (!ptr) return FALSE;
2378 freetype_get_font_data( font, MS_GASP_TAG, 0, ptr, size );
2380 version = GET_BE_WORD( *ptr++ );
2381 num_recs = GET_BE_WORD( *ptr++ );
2383 if (version > 1 || size < (num_recs * 2 + 2) * sizeof(WORD))
2385 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version, size, num_recs );
2386 goto done;
2389 while (num_recs--)
2391 *flags = GET_BE_WORD( *(ptr + 1) );
2392 if (ft_face->size->metrics.y_ppem <= GET_BE_WORD( *ptr )) break;
2393 ptr += 2;
2395 TRACE( "got flags %04x for ppem %d\n", *flags, ft_face->size->metrics.y_ppem );
2396 ret = TRUE;
2398 done:
2399 RtlFreeHeap( GetProcessHeap(), 0, alloced );
2400 return ret;
2403 /*************************************************************
2404 * fontconfig_enum_family_fallbacks
2406 static BOOL CDECL fontconfig_enum_family_fallbacks( DWORD pitch_and_family, int index,
2407 WCHAR buffer[LF_FACESIZE] )
2409 #ifdef SONAME_LIBFONTCONFIG
2410 FcPattern *pat;
2411 char *str;
2412 DWORD len;
2414 if ((pitch_and_family & FIXED_PITCH) || (pitch_and_family & 0xf0) == FF_MODERN) pat = create_family_pattern( "monospace", &pattern_fixed );
2415 else if ((pitch_and_family & 0xf0) == FF_ROMAN) pat = create_family_pattern( "serif", &pattern_serif );
2416 else pat = create_family_pattern( "sans", &pattern_sans );
2418 if (!pat) return FALSE;
2419 if (pFcPatternGetString( pat, FC_FAMILY, index, (FcChar8 **)&str ) != FcResultMatch) return FALSE;
2420 RtlUTF8ToUnicodeN( buffer, (LF_FACESIZE - 1) * sizeof(WCHAR), &len, str, strlen(str) );
2421 buffer[len / sizeof(WCHAR)] = 0;
2422 return TRUE;
2423 #endif
2424 return FALSE;
2427 static DWORD get_ttc_offset( FT_Face ft_face, UINT face_index )
2429 FT_ULong len;
2430 DWORD header, offset;
2432 /* see if it's a TTC */
2433 len = sizeof(header);
2434 if (pFT_Load_Sfnt_Table( ft_face, 0, 0, (void *)&header, &len )) return 0;
2435 if (header != MS_TTCF_TAG) return 0;
2437 len = sizeof(offset);
2438 if (pFT_Load_Sfnt_Table( ft_face, 0, (3 + face_index) * sizeof(DWORD), (void *)&offset, &len ))
2439 return 0;
2441 return GET_BE_DWORD( offset );
2444 /*************************************************************
2445 * freetype_load_font
2447 static BOOL CDECL freetype_load_font( struct gdi_font *font )
2449 struct font_private_data *data;
2450 INT width = 0, height;
2451 FT_Face ft_face;
2452 void *data_ptr;
2453 SIZE_T data_size;
2455 if (!(data = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data) ))) return FALSE;
2456 font->private = data;
2458 if (font->file[0])
2460 char *filename = get_unix_file_name( font->file );
2461 data->mapping = map_font_file( filename );
2462 RtlFreeHeap( GetProcessHeap(), 0, filename );
2463 if (!data->mapping)
2465 WARN("failed to map %s\n", debugstr_w(font->file));
2466 return FALSE;
2468 data_ptr = data->mapping->data;
2469 data_size = data->mapping->size;
2471 else
2473 data_ptr = font->data_ptr;
2474 data_size = font->data_size;
2477 if (pFT_New_Memory_Face( library, data_ptr, data_size, font->face_index, &ft_face )) return FALSE;
2479 data->ft_face = ft_face;
2480 font->scalable = FT_IS_SCALABLE( ft_face );
2481 if (!font->fs.fsCsb[0]) get_fontsig( ft_face, &font->fs );
2482 if (!font->ntmFlags) font->ntmFlags = get_ntm_flags( ft_face );
2483 if (!font->aa_flags) font->aa_flags = ADDFONT_AA_FLAGS( default_aa_flags );
2484 if (!font->otm.otmpFamilyName)
2486 font->otm.otmpFamilyName = (char *)ft_face_get_family_name( ft_face, system_lcid );
2487 font->otm.otmpStyleName = (char *)ft_face_get_style_name( ft_face, system_lcid );
2488 font->otm.otmpFaceName = (char *)ft_face_get_full_name( ft_face, system_lcid );
2491 if (font->scalable)
2493 /* load the VDMX table if we have one */
2494 font->ppem = load_VDMX( font, font->lf.lfHeight );
2495 if (font->ppem == 0) font->ppem = calc_ppem_for_height( ft_face, font->lf.lfHeight );
2496 TRACE( "height %d => ppem %d\n", font->lf.lfHeight, font->ppem );
2497 height = font->ppem;
2498 font->ttc_item_offset = get_ttc_offset( ft_face, font->face_index );
2499 font->otm.otmEMSquare = ft_face->units_per_EM;
2501 else
2503 struct bitmap_font_size size;
2505 get_bitmap_size( ft_face, &size );
2506 width = size.x_ppem >> 6;
2507 height = size.y_ppem >> 6;
2508 font->ppem = height;
2511 pFT_Set_Pixel_Sizes( ft_face, width, height );
2512 pick_charmap( ft_face, font->charset );
2513 return TRUE;
2517 /*************************************************************
2518 * freetype_get_aa_flags
2520 static UINT CDECL freetype_get_aa_flags( struct gdi_font *font, UINT aa_flags, BOOL antialias_fakes )
2522 /* fixup the antialiasing flags for that font */
2523 switch (aa_flags)
2525 case WINE_GGO_HRGB_BITMAP:
2526 case WINE_GGO_HBGR_BITMAP:
2527 case WINE_GGO_VRGB_BITMAP:
2528 case WINE_GGO_VBGR_BITMAP:
2529 if (is_subpixel_rendering_enabled()) break;
2530 aa_flags = GGO_GRAY4_BITMAP;
2531 /* fall through */
2532 case GGO_GRAY2_BITMAP:
2533 case GGO_GRAY4_BITMAP:
2534 case GGO_GRAY8_BITMAP:
2535 case WINE_GGO_GRAY16_BITMAP:
2536 if ((!antialias_fakes || (!font->fake_bold && !font->fake_italic)) && is_hinting_enabled())
2538 WORD gasp_flags;
2539 if (get_gasp_flags( font, &gasp_flags ) && !(gasp_flags & GASP_DOGRAY))
2541 TRACE( "font %s %d aa disabled by GASP\n",
2542 debugstr_w(font->lf.lfFaceName), font->lf.lfHeight );
2543 aa_flags = GGO_BITMAP;
2547 return aa_flags;
2550 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
2552 pt->x.value = vec->x >> 6;
2553 pt->x.fract = (vec->x & 0x3f) << 10;
2554 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
2555 pt->y.value = vec->y >> 6;
2556 pt->y.fract = (vec->y & 0x3f) << 10;
2557 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
2560 static FT_UInt get_glyph_index_symbol( struct gdi_font *font, UINT glyph )
2562 FT_Face ft_face = get_ft_face( font );
2563 FT_UInt ret;
2565 if (glyph < 0x100) glyph += 0xf000;
2566 /* there are a number of old pre-Unicode "broken" TTFs, which
2567 do have symbols at U+00XX instead of U+f0XX */
2568 if (!(ret = pFT_Get_Char_Index(ft_face, glyph)))
2569 ret = pFT_Get_Char_Index(ft_face, glyph - 0xf000);
2571 return ret;
2574 /*************************************************************
2575 * freetype_get_glyph_index
2577 static BOOL CDECL freetype_get_glyph_index( struct gdi_font *font, UINT *glyph, BOOL use_encoding )
2579 FT_Face ft_face = get_ft_face( font );
2581 if (!use_encoding ^ (ft_face->charmap->encoding == FT_ENCODING_NONE)) return FALSE;
2583 if (ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
2585 if (!(*glyph = get_glyph_index_symbol( font, *glyph )))
2587 WCHAR wc = *glyph;
2588 DWORD len;
2589 char ch;
2591 RtlUnicodeToMultiByteN( &ch, 1, &len, &wc, sizeof(wc) );
2592 if (len) *glyph = get_glyph_index_symbol( font, (unsigned char)ch );
2594 return TRUE;
2596 *glyph = pFT_Get_Char_Index( ft_face, *glyph );
2597 return TRUE;
2600 /*************************************************************
2601 * freetype_get_default_glyph
2603 static UINT CDECL freetype_get_default_glyph( struct gdi_font *font )
2605 FT_Face ft_face = get_ft_face( font );
2606 FT_WinFNT_HeaderRec winfnt;
2607 TT_OS2 *pOS2;
2609 if ((pOS2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 )))
2611 UINT glyph = pOS2->usDefaultChar;
2612 if (glyph) freetype_get_glyph_index( font, &glyph, TRUE );
2613 return glyph;
2615 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt )) return winfnt.default_char + winfnt.first_char;
2616 return 32;
2620 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
2622 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
2623 return !memcmp(matrix, &identity, sizeof(FMAT2));
2626 static inline FT_Vector normalize_vector(FT_Vector *vec)
2628 FT_Vector out;
2629 FT_Fixed len;
2630 len = pFT_Vector_Length(vec);
2631 if (len) {
2632 out.x = (vec->x << 6) / len;
2633 out.y = (vec->y << 6) / len;
2635 else
2636 out.x = out.y = 0;
2637 return out;
2640 /* get_glyph_outline() glyph transform matrices index */
2641 enum matrices_index
2643 matrix_hori,
2644 matrix_vert,
2645 matrix_unrotated
2648 static FT_Matrix *get_transform_matrices( struct gdi_font *font, BOOL vertical, const MAT2 *user_transform,
2649 FT_Matrix matrices[3] )
2651 static const FT_Matrix identity_mat = { (1 << 16), 0, 0, (1 << 16) };
2652 BOOL needs_transform = FALSE;
2653 double width_ratio;
2654 int i;
2656 matrices[matrix_unrotated] = identity_mat;
2658 /* Scaling factor */
2659 if (font->aveWidth)
2661 if (!freetype_set_outline_text_metrics( font )) freetype_set_bitmap_text_metrics( font );
2662 width_ratio = (double)font->aveWidth;
2663 width_ratio /= (double)font->otm.otmTextMetrics.tmAveCharWidth;
2665 else
2666 width_ratio = font->scale_y;
2668 /* Scaling transform */
2669 if (width_ratio != 1.0 || font->scale_y != 1)
2671 FT_Matrix scale_mat;
2672 scale_mat.xx = FT_FixedFromFloat( width_ratio );
2673 scale_mat.xy = 0;
2674 scale_mat.yx = 0;
2675 scale_mat.yy = font->scale_y << 16;
2677 pFT_Matrix_Multiply( &scale_mat, &matrices[matrix_unrotated] );
2678 needs_transform = TRUE;
2681 /* Slant transform */
2682 if (font->fake_italic)
2684 FT_Matrix slant_mat;
2685 slant_mat.xx = (1 << 16);
2686 slant_mat.xy = (1 << 16) >> 2;
2687 slant_mat.yx = 0;
2688 slant_mat.yy = (1 << 16);
2690 pFT_Matrix_Multiply( &slant_mat, &matrices[matrix_unrotated] );
2691 needs_transform = TRUE;
2694 /* Rotation transform */
2695 matrices[matrix_hori] = matrices[matrix_unrotated];
2696 if (font->scalable && font->lf.lfOrientation % 3600)
2698 FT_Matrix rotation_mat;
2699 FT_Vector angle;
2701 pFT_Vector_Unit( &angle, pFT_MulDiv( 1 << 16, font->lf.lfOrientation, 10 ) );
2702 rotation_mat.xx = angle.x;
2703 rotation_mat.xy = -angle.y;
2704 rotation_mat.yx = angle.y;
2705 rotation_mat.yy = angle.x;
2706 pFT_Matrix_Multiply( &rotation_mat, &matrices[matrix_hori] );
2707 needs_transform = TRUE;
2710 /* Vertical transform */
2711 matrices[matrix_vert] = matrices[matrix_hori];
2712 if (vertical)
2714 FT_Matrix vertical_mat = { 0, -(1 << 16), 1 << 16, 0 }; /* 90 degrees rotation */
2716 pFT_Matrix_Multiply( &vertical_mat, &matrices[matrix_vert] );
2717 needs_transform = TRUE;
2720 /* World transform */
2721 if (!is_identity_FMAT2( &font->matrix ))
2723 FT_Matrix world_mat;
2724 world_mat.xx = FT_FixedFromFloat( font->matrix.eM11 );
2725 world_mat.xy = -FT_FixedFromFloat( font->matrix.eM21 );
2726 world_mat.yx = -FT_FixedFromFloat( font->matrix.eM12 );
2727 world_mat.yy = FT_FixedFromFloat( font->matrix.eM22 );
2729 for (i = 0; i < 3; i++)
2730 pFT_Matrix_Multiply( &world_mat, &matrices[i] );
2731 needs_transform = TRUE;
2734 /* Extra transformation specified by caller */
2735 if (user_transform)
2737 FT_Matrix user_mat;
2738 user_mat.xx = FT_FixedFromFIXED( user_transform->eM11 );
2739 user_mat.xy = FT_FixedFromFIXED( user_transform->eM21 );
2740 user_mat.yx = FT_FixedFromFIXED( user_transform->eM12 );
2741 user_mat.yy = FT_FixedFromFIXED( user_transform->eM22 );
2743 for (i = 0; i < 3; i++)
2744 pFT_Matrix_Multiply( &user_mat, &matrices[i] );
2745 needs_transform = TRUE;
2748 return needs_transform ? matrices : NULL;
2751 static BOOL get_bold_glyph_outline(FT_GlyphSlot glyph, LONG ppem, FT_Glyph_Metrics *metrics)
2753 FT_Error err;
2754 FT_Pos strength;
2755 FT_BBox bbox;
2757 if(glyph->format != FT_GLYPH_FORMAT_OUTLINE)
2758 return FALSE;
2759 if(!pFT_Outline_Embolden)
2760 return FALSE;
2762 strength = pFT_MulDiv(ppem, 1 << 6, 24);
2763 err = pFT_Outline_Embolden(&glyph->outline, strength);
2764 if(err) {
2765 TRACE("FT_Ouline_Embolden returns %d\n", err);
2766 return FALSE;
2769 pFT_Outline_Get_CBox(&glyph->outline, &bbox);
2770 metrics->width = bbox.xMax - bbox.xMin;
2771 metrics->height = bbox.yMax - bbox.yMin;
2772 metrics->horiBearingX = bbox.xMin;
2773 metrics->horiBearingY = bbox.yMax;
2774 metrics->vertBearingX = metrics->horiBearingX - metrics->horiAdvance / 2;
2775 metrics->vertBearingY = (metrics->vertAdvance - metrics->height) / 2;
2776 return TRUE;
2779 static inline BYTE get_max_level( UINT format )
2781 switch( format )
2783 case GGO_GRAY2_BITMAP: return 4;
2784 case GGO_GRAY4_BITMAP: return 16;
2785 case GGO_GRAY8_BITMAP: return 64;
2787 return 255;
2790 static FT_Vector get_advance_metric( struct gdi_font *font, FT_Pos base_advance,
2791 const FT_Matrix *transMat )
2793 FT_Vector adv;
2794 FT_Fixed em_scale = 0;
2795 BOOL fixed_pitch_full = FALSE;
2796 struct gdi_font *incoming_font = font->base_font ? font->base_font : font;
2798 adv.x = base_advance;
2799 adv.y = 0;
2801 /* In fixed-pitch font, we adjust the fullwidth character advance so that
2802 they have double halfwidth character width. E.g. if the font is 19 ppem,
2803 we return 20 (not 19) for fullwidth characters as we return 10 for
2804 halfwidth characters. */
2805 if (freetype_set_outline_text_metrics(incoming_font) &&
2806 !(incoming_font->otm.otmTextMetrics.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
2807 UINT avg_advance;
2808 em_scale = pFT_MulDiv(incoming_font->ppem, 1 << 16, get_ft_face(incoming_font)->units_per_EM);
2809 avg_advance = pFT_MulFix(incoming_font->ntmAvgWidth, em_scale);
2810 fixed_pitch_full = (avg_advance > 0 &&
2811 (base_advance + 63) >> 6 ==
2812 pFT_MulFix(incoming_font->ntmAvgWidth*2, em_scale));
2813 if (fixed_pitch_full && !transMat)
2814 adv.x = (avg_advance * 2) << 6;
2817 if (transMat) {
2818 pFT_Vector_Transform(&adv, transMat);
2819 if (fixed_pitch_full && adv.y == 0) {
2820 FT_Vector vec;
2821 vec.x = incoming_font->ntmAvgWidth;
2822 vec.y = 0;
2823 pFT_Vector_Transform(&vec, transMat);
2824 adv.x = (pFT_MulFix(vec.x, em_scale) * 2) << 6;
2828 if (font->fake_bold) {
2829 if (!transMat)
2830 adv.x += 1 << 6;
2831 else {
2832 FT_Vector fake_bold_adv, vec = { 1 << 6, 0 };
2833 pFT_Vector_Transform(&vec, transMat);
2834 fake_bold_adv = normalize_vector(&vec);
2835 adv.x += fake_bold_adv.x;
2836 adv.y += fake_bold_adv.y;
2840 adv.x = (adv.x + 63) & -64;
2841 adv.y = -((adv.y + 63) & -64);
2842 return adv;
2845 static FT_BBox get_transformed_bbox( const FT_Glyph_Metrics *metrics, const FT_Matrix *matrices )
2847 FT_BBox bbox = { 0, 0, 0, 0 };
2849 if (!matrices)
2851 bbox.xMin = (metrics->horiBearingX) & -64;
2852 bbox.xMax = (metrics->horiBearingX + metrics->width + 63) & -64;
2853 bbox.yMax = (metrics->horiBearingY + 63) & -64;
2854 bbox.yMin = (metrics->horiBearingY - metrics->height) & -64;
2856 else
2858 FT_Vector vec;
2859 INT xc, yc;
2861 for (xc = 0; xc < 2; xc++)
2863 for (yc = 0; yc < 2; yc++)
2865 vec.x = metrics->horiBearingX + xc * metrics->width;
2866 vec.y = metrics->horiBearingY - yc * metrics->height;
2867 TRACE( "Vec %ld, %ld\n", vec.x, vec.y );
2868 pFT_Vector_Transform( &vec, &matrices[matrix_vert] );
2869 if (xc == 0 && yc == 0)
2871 bbox.xMin = bbox.xMax = vec.x;
2872 bbox.yMin = bbox.yMax = vec.y;
2874 else
2876 if (vec.x < bbox.xMin) bbox.xMin = vec.x;
2877 else if (vec.x > bbox.xMax) bbox.xMax = vec.x;
2878 if (vec.y < bbox.yMin) bbox.yMin = vec.y;
2879 else if (vec.y > bbox.yMax) bbox.yMax = vec.y;
2883 bbox.xMin = bbox.xMin & -64;
2884 bbox.xMax = (bbox.xMax + 63) & -64;
2885 bbox.yMin = bbox.yMin & -64;
2886 bbox.yMax = (bbox.yMax + 63) & -64;
2887 TRACE( "transformed box: (%ld, %ld - %ld, %ld)\n", bbox.xMin, bbox.yMax, bbox.xMax, bbox.yMin );
2890 return bbox;
2893 static void compute_metrics( struct gdi_font *font, FT_BBox bbox, const FT_Glyph_Metrics *metrics,
2894 BOOL vertical, BOOL vertical_metrics, const FT_Matrix *matrices,
2895 GLYPHMETRICS *gm, ABC *abc )
2897 FT_Vector adv, vec, origin;
2898 FT_Fixed base_advance = vertical_metrics ? metrics->vertAdvance : metrics->horiAdvance;
2900 if (!matrices)
2902 adv = get_advance_metric( font, base_advance, NULL );
2903 gm->gmCellIncX = adv.x >> 6;
2904 gm->gmCellIncY = 0;
2905 origin.x = bbox.xMin;
2906 origin.y = bbox.yMax;
2907 abc->abcA = origin.x >> 6;
2908 abc->abcB = (metrics->width + 63) >> 6;
2910 else
2912 FT_Pos lsb;
2914 if (vertical && freetype_set_outline_text_metrics( font ))
2916 if (vertical_metrics)
2917 lsb = metrics->horiBearingY + metrics->vertBearingY;
2918 else
2919 lsb = metrics->vertAdvance + (font->otm.otmDescent << 6);
2920 vec.x = lsb;
2921 vec.y = font->otm.otmDescent << 6;
2922 TRACE( "Vec %ld,%ld\n", vec.x>>6, vec.y>>6 );
2923 pFT_Vector_Transform( &vec, &matrices[matrix_hori] );
2924 origin.x = (vec.x + bbox.xMin) & -64;
2925 origin.y = (vec.y + bbox.yMax + 63) & -64;
2926 lsb -= metrics->horiBearingY;
2928 else
2930 origin.x = bbox.xMin;
2931 origin.y = bbox.yMax;
2932 lsb = metrics->horiBearingX;
2935 adv = get_advance_metric( font, base_advance, &matrices[matrix_hori] );
2936 gm->gmCellIncX = adv.x >> 6;
2937 gm->gmCellIncY = adv.y >> 6;
2939 adv = get_advance_metric( font, base_advance, &matrices[matrix_unrotated] );
2940 adv.x = pFT_Vector_Length( &adv );
2941 adv.y = 0;
2943 vec.x = lsb;
2944 vec.y = 0;
2945 pFT_Vector_Transform( &vec, &matrices[matrix_unrotated] );
2946 if (lsb > 0) abc->abcA = pFT_Vector_Length( &vec ) >> 6;
2947 else abc->abcA = -((pFT_Vector_Length( &vec ) + 63) >> 6);
2949 /* We use lsb again to avoid rounding errors */
2950 vec.x = lsb + (vertical ? metrics->height : metrics->width);
2951 vec.y = 0;
2952 pFT_Vector_Transform( &vec, &matrices[matrix_unrotated] );
2953 abc->abcB = ((pFT_Vector_Length( &vec ) + 63) >> 6) - abc->abcA;
2955 if (!abc->abcB) abc->abcB = 1;
2956 abc->abcC = (adv.x >> 6) - abc->abcA - abc->abcB;
2958 gm->gmptGlyphOrigin.x = origin.x >> 6;
2959 gm->gmptGlyphOrigin.y = origin.y >> 6;
2960 gm->gmBlackBoxX = (bbox.xMax - bbox.xMin) >> 6;
2961 gm->gmBlackBoxY = (bbox.yMax - bbox.yMin) >> 6;
2962 if (!gm->gmBlackBoxX) gm->gmBlackBoxX = 1;
2963 if (!gm->gmBlackBoxY) gm->gmBlackBoxY = 1;
2965 TRACE( "gm: %u, %u, %s, %d, %d abc %d, %u, %d\n",
2966 gm->gmBlackBoxX, gm->gmBlackBoxY, wine_dbgstr_point(&gm->gmptGlyphOrigin),
2967 gm->gmCellIncX, gm->gmCellIncY, abc->abcA, abc->abcB, abc->abcC );
2971 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
2973 static DWORD get_mono_glyph_bitmap( FT_GlyphSlot glyph, FT_BBox bbox,
2974 BOOL fake_bold, const FT_Matrix *matrices,
2975 DWORD buflen, BYTE *buf )
2977 DWORD width = (bbox.xMax - bbox.xMin ) >> 6;
2978 DWORD height = (bbox.yMax - bbox.yMin ) >> 6;
2979 DWORD pitch = ((width + 31) >> 5) << 2;
2980 DWORD needed = pitch * height;
2981 FT_Bitmap ft_bitmap;
2982 BYTE *src, *dst;
2983 INT w, h, x;
2985 if (!buf || !buflen) return needed;
2986 if (!needed) return GDI_ERROR; /* empty glyph */
2987 if (needed > buflen) return GDI_ERROR;
2989 switch (glyph->format)
2991 case FT_GLYPH_FORMAT_BITMAP:
2992 src = glyph->bitmap.buffer;
2993 dst = buf;
2994 w = min( pitch, (glyph->bitmap.width + 7) >> 3 );
2995 h = min( height, glyph->bitmap.rows );
2996 while (h--)
2998 if (!fake_bold)
2999 memcpy( dst, src, w );
3000 else
3002 dst[0] = 0;
3003 for (x = 0; x < w; x++)
3005 dst[x] = (dst[x] & 0x80) | (src[x] >> 1) | src[x];
3006 if (x + 1 < pitch)
3007 dst[x + 1] = (src[x] & 0x01) << 7;
3010 src += glyph->bitmap.pitch;
3011 dst += pitch;
3013 break;
3015 case FT_GLYPH_FORMAT_OUTLINE:
3016 ft_bitmap.width = width;
3017 ft_bitmap.rows = height;
3018 ft_bitmap.pitch = pitch;
3019 ft_bitmap.pixel_mode = FT_PIXEL_MODE_MONO;
3020 ft_bitmap.buffer = buf;
3022 if (matrices)
3023 pFT_Outline_Transform( &glyph->outline, &matrices[matrix_vert] );
3024 pFT_Outline_Translate( &glyph->outline, -bbox.xMin, -bbox.yMin );
3026 /* Note: FreeType will only set 'black' bits for us. */
3027 memset( buf, 0, buflen );
3028 pFT_Outline_Get_Bitmap( library, &glyph->outline, &ft_bitmap );
3029 break;
3031 default:
3032 FIXME( "loaded glyph format %x\n", glyph->format );
3033 return GDI_ERROR;
3036 return needed;
3039 static DWORD get_antialias_glyph_bitmap( FT_GlyphSlot glyph, FT_BBox bbox, UINT format,
3040 BOOL fake_bold, const FT_Matrix *matrices,
3041 DWORD buflen, BYTE *buf )
3043 DWORD width = (bbox.xMax - bbox.xMin ) >> 6;
3044 DWORD height = (bbox.yMax - bbox.yMin ) >> 6;
3045 DWORD pitch = (width + 3) / 4 * 4;
3046 DWORD needed = pitch * height;
3047 FT_Bitmap ft_bitmap;
3048 INT w, h, x, max_level;
3049 BYTE *src, *dst;
3051 if (!buf || !buflen) return needed;
3052 if (!needed) return GDI_ERROR; /* empty glyph */
3053 if (needed > buflen) return GDI_ERROR;
3055 max_level = get_max_level( format );
3057 switch (glyph->format)
3059 case FT_GLYPH_FORMAT_BITMAP:
3060 src = glyph->bitmap.buffer;
3061 dst = buf;
3062 memset( buf, 0, buflen );
3064 w = min( pitch, glyph->bitmap.width );
3065 h = min( height, glyph->bitmap.rows );
3066 while (h--)
3068 for (x = 0; x < w; x++)
3070 if (src[x / 8] & masks[x % 8])
3072 dst[x] = max_level;
3073 if (fake_bold && x + 1 < pitch) dst[x + 1] = max_level;
3076 src += glyph->bitmap.pitch;
3077 dst += pitch;
3079 break;
3081 case FT_GLYPH_FORMAT_OUTLINE:
3082 ft_bitmap.width = width;
3083 ft_bitmap.rows = height;
3084 ft_bitmap.pitch = pitch;
3085 ft_bitmap.pixel_mode = FT_PIXEL_MODE_GRAY;
3086 ft_bitmap.buffer = buf;
3088 if (matrices)
3089 pFT_Outline_Transform( &glyph->outline, &matrices[matrix_vert] );
3090 pFT_Outline_Translate( &glyph->outline, -bbox.xMin, -bbox.yMin );
3092 memset( buf, 0, buflen );
3093 pFT_Outline_Get_Bitmap( library, &glyph->outline, &ft_bitmap );
3095 if (max_level != 255)
3097 INT row, col;
3098 BYTE *ptr, *start;
3100 for (row = 0, start = buf; row < height; row++)
3102 for (col = 0, ptr = start; col < width; col++, ptr++)
3103 *ptr = (((int)*ptr) * (max_level + 1)) / 256;
3104 start += pitch;
3107 break;
3109 default:
3110 FIXME("loaded glyph format %x\n", glyph->format);
3111 return GDI_ERROR;
3114 return needed;
3117 static DWORD get_subpixel_glyph_bitmap( FT_GlyphSlot glyph, FT_BBox bbox, UINT format,
3118 BOOL fake_bold, const FT_Matrix *matrices,
3119 GLYPHMETRICS *gm, DWORD buflen, BYTE *buf )
3121 DWORD width = (bbox.xMax - bbox.xMin ) >> 6;
3122 DWORD height = (bbox.yMax - bbox.yMin ) >> 6;
3123 DWORD pitch, needed = 0;
3124 BYTE *src, *dst;
3125 INT w, h, x;
3127 switch (glyph->format)
3129 case FT_GLYPH_FORMAT_BITMAP:
3130 pitch = width * 4;
3131 needed = pitch * height;
3133 if (!buf || !buflen) break;
3134 if (!needed) return GDI_ERROR; /* empty glyph */
3135 if (needed > buflen) return GDI_ERROR;
3137 src = glyph->bitmap.buffer;
3138 dst = buf;
3139 memset( buf, 0, buflen );
3141 w = min( width, glyph->bitmap.width );
3142 h = min( height, glyph->bitmap.rows );
3143 while (h--)
3145 for (x = 0; x < w; x++)
3147 if ( src[x / 8] & masks[x % 8] )
3149 ((unsigned int *)dst)[x] = ~0u;
3150 if (fake_bold && x + 1 < width) ((unsigned int *)dst)[x + 1] = ~0u;
3153 src += glyph->bitmap.pitch;
3154 dst += pitch;
3156 break;
3158 case FT_GLYPH_FORMAT_OUTLINE:
3160 INT src_pitch, src_width, src_height, x_shift, y_shift;
3161 INT sub_stride, hmul, vmul;
3162 const INT *sub_order;
3163 const INT rgb_order[3] = { 0, 1, 2 };
3164 const INT bgr_order[3] = { 2, 1, 0 };
3165 FT_Render_Mode render_mode =
3166 (format == WINE_GGO_HRGB_BITMAP ||
3167 format == WINE_GGO_HBGR_BITMAP) ? FT_RENDER_MODE_LCD : FT_RENDER_MODE_LCD_V;
3169 if (!width || !height) /* empty glyph */
3171 if (!buf || !buflen) break;
3172 return GDI_ERROR;
3175 if ( render_mode == FT_RENDER_MODE_LCD)
3177 gm->gmBlackBoxX += 2;
3178 gm->gmptGlyphOrigin.x -= 1;
3179 bbox.xMin -= (1 << 6);
3181 else
3183 gm->gmBlackBoxY += 2;
3184 gm->gmptGlyphOrigin.y += 1;
3185 bbox.yMax += (1 << 6);
3188 width = gm->gmBlackBoxX;
3189 height = gm->gmBlackBoxY;
3190 pitch = width * 4;
3191 needed = pitch * height;
3193 if (!buf || !buflen) return needed;
3194 if (needed > buflen) return GDI_ERROR;
3196 if (matrices)
3197 pFT_Outline_Transform( &glyph->outline, &matrices[matrix_vert] );
3199 pFT_Render_Glyph( glyph, render_mode );
3201 src_pitch = glyph->bitmap.pitch;
3202 src_width = glyph->bitmap.width;
3203 src_height = glyph->bitmap.rows;
3204 src = glyph->bitmap.buffer;
3205 dst = buf;
3206 memset( buf, 0, buflen );
3208 sub_order = (format == WINE_GGO_HRGB_BITMAP ||
3209 format == WINE_GGO_VRGB_BITMAP) ? rgb_order : bgr_order;
3210 sub_stride = render_mode == FT_RENDER_MODE_LCD ? 1 : src_pitch;
3211 hmul = render_mode == FT_RENDER_MODE_LCD ? 3 : 1;
3212 vmul = render_mode == FT_RENDER_MODE_LCD ? 1 : 3;
3214 x_shift = glyph->bitmap_left - (bbox.xMin >> 6);
3215 if ( x_shift < 0 )
3217 src += hmul * -x_shift;
3218 src_width -= hmul * -x_shift;
3220 else if ( x_shift > 0 )
3222 dst += x_shift * sizeof(unsigned int);
3223 width -= x_shift;
3226 y_shift = (bbox.yMax >> 6) - glyph->bitmap_top;
3227 if ( y_shift < 0 )
3229 src += src_pitch * vmul * -y_shift;
3230 src_height -= vmul * -y_shift;
3232 else if ( y_shift > 0 )
3234 dst += y_shift * pitch;
3235 height -= y_shift;
3238 w = min( width, src_width / hmul );
3239 h = min( height, src_height / vmul );
3240 while (h--)
3242 for (x = 0; x < w; x++)
3244 ((unsigned int *)dst)[x] =
3245 ((unsigned int)src[hmul * x + sub_stride * sub_order[0]] << 16) |
3246 ((unsigned int)src[hmul * x + sub_stride * sub_order[1]] << 8) |
3247 ((unsigned int)src[hmul * x + sub_stride * sub_order[2]]);
3249 src += src_pitch * vmul;
3250 dst += pitch;
3252 break;
3254 default:
3255 FIXME ( "loaded glyph format %x\n", glyph->format );
3256 return GDI_ERROR;
3259 return needed;
3262 static unsigned int get_native_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
3264 TTPOLYGONHEADER *pph;
3265 TTPOLYCURVE *ppc;
3266 unsigned int needed = 0, point = 0, contour, first_pt;
3267 unsigned int pph_start, cpfx;
3268 DWORD type;
3270 for (contour = 0; contour < outline->n_contours; contour++)
3272 /* Ignore contours containing one point */
3273 if (point == outline->contours[contour])
3275 point++;
3276 continue;
3279 pph_start = needed;
3280 pph = (TTPOLYGONHEADER *)(buf + needed);
3281 first_pt = point;
3282 if (buf)
3284 pph->dwType = TT_POLYGON_TYPE;
3285 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3287 needed += sizeof(*pph);
3288 point++;
3289 while (point <= outline->contours[contour])
3291 ppc = (TTPOLYCURVE *)(buf + needed);
3292 type = outline->tags[point] & FT_Curve_Tag_On ?
3293 TT_PRIM_LINE : TT_PRIM_QSPLINE;
3294 cpfx = 0;
3297 if (buf)
3298 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3299 cpfx++;
3300 point++;
3301 } while (point <= outline->contours[contour] &&
3302 (outline->tags[point] & FT_Curve_Tag_On) ==
3303 (outline->tags[point-1] & FT_Curve_Tag_On));
3304 /* At the end of a contour Windows adds the start point, but
3305 only for Beziers */
3306 if (point > outline->contours[contour] &&
3307 !(outline->tags[point-1] & FT_Curve_Tag_On))
3309 if (buf)
3310 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
3311 cpfx++;
3313 else if (point <= outline->contours[contour] &&
3314 outline->tags[point] & FT_Curve_Tag_On)
3316 /* add closing pt for bezier */
3317 if (buf)
3318 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3319 cpfx++;
3320 point++;
3322 if (buf)
3324 ppc->wType = type;
3325 ppc->cpfx = cpfx;
3327 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3329 if (buf)
3330 pph->cb = needed - pph_start;
3332 return needed;
3335 static unsigned int get_bezier_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
3337 /* Convert the quadratic Beziers to cubic Beziers.
3338 The parametric eqn for a cubic Bezier is, from PLRM:
3339 r(t) = at^3 + bt^2 + ct + r0
3340 with the control points:
3341 r1 = r0 + c/3
3342 r2 = r1 + (c + b)/3
3343 r3 = r0 + c + b + a
3345 A quadratic Bezier has the form:
3346 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3348 So equating powers of t leads to:
3349 r1 = 2/3 p1 + 1/3 p0
3350 r2 = 2/3 p1 + 1/3 p2
3351 and of course r0 = p0, r3 = p2
3353 int contour, point = 0, first_pt;
3354 TTPOLYGONHEADER *pph;
3355 TTPOLYCURVE *ppc;
3356 DWORD pph_start, cpfx, type;
3357 FT_Vector cubic_control[4];
3358 unsigned int needed = 0;
3360 for (contour = 0; contour < outline->n_contours; contour++)
3362 pph_start = needed;
3363 pph = (TTPOLYGONHEADER *)(buf + needed);
3364 first_pt = point;
3365 if (buf)
3367 pph->dwType = TT_POLYGON_TYPE;
3368 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3370 needed += sizeof(*pph);
3371 point++;
3372 while (point <= outline->contours[contour])
3374 ppc = (TTPOLYCURVE *)(buf + needed);
3375 type = outline->tags[point] & FT_Curve_Tag_On ?
3376 TT_PRIM_LINE : TT_PRIM_CSPLINE;
3377 cpfx = 0;
3380 if (type == TT_PRIM_LINE)
3382 if (buf)
3383 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3384 cpfx++;
3385 point++;
3387 else
3389 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
3390 so cpfx = 3n */
3392 /* FIXME: Possible optimization in endpoint calculation
3393 if there are two consecutive curves */
3394 cubic_control[0] = outline->points[point-1];
3395 if (!(outline->tags[point-1] & FT_Curve_Tag_On))
3397 cubic_control[0].x += outline->points[point].x + 1;
3398 cubic_control[0].y += outline->points[point].y + 1;
3399 cubic_control[0].x >>= 1;
3400 cubic_control[0].y >>= 1;
3402 if (point+1 > outline->contours[contour])
3403 cubic_control[3] = outline->points[first_pt];
3404 else
3406 cubic_control[3] = outline->points[point+1];
3407 if (!(outline->tags[point+1] & FT_Curve_Tag_On))
3409 cubic_control[3].x += outline->points[point].x + 1;
3410 cubic_control[3].y += outline->points[point].y + 1;
3411 cubic_control[3].x >>= 1;
3412 cubic_control[3].y >>= 1;
3415 /* r1 = 1/3 p0 + 2/3 p1
3416 r2 = 1/3 p2 + 2/3 p1 */
3417 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
3418 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
3419 cubic_control[2] = cubic_control[1];
3420 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
3421 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
3422 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
3423 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
3424 if (buf)
3426 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
3427 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
3428 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
3430 cpfx += 3;
3431 point++;
3433 } while (point <= outline->contours[contour] &&
3434 (outline->tags[point] & FT_Curve_Tag_On) ==
3435 (outline->tags[point-1] & FT_Curve_Tag_On));
3436 /* At the end of a contour Windows adds the start point,
3437 but only for Beziers and we've already done that.
3439 if (point <= outline->contours[contour] &&
3440 outline->tags[point] & FT_Curve_Tag_On)
3442 /* This is the closing pt of a bezier, but we've already
3443 added it, so just inc point and carry on */
3444 point++;
3446 if (buf)
3448 ppc->wType = type;
3449 ppc->cpfx = cpfx;
3451 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3453 if (buf)
3454 pph->cb = needed - pph_start;
3456 return needed;
3459 static FT_Int get_load_flags( UINT format )
3461 FT_Int load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
3463 if (format & GGO_UNHINTED)
3464 return load_flags | FT_LOAD_NO_HINTING;
3466 switch (format & ~GGO_GLYPH_INDEX)
3468 case GGO_BITMAP:
3469 load_flags |= FT_LOAD_TARGET_MONO;
3470 break;
3471 case GGO_GRAY2_BITMAP:
3472 case GGO_GRAY4_BITMAP:
3473 case GGO_GRAY8_BITMAP:
3474 case WINE_GGO_GRAY16_BITMAP:
3475 load_flags |= FT_LOAD_TARGET_NORMAL;
3476 break;
3477 case WINE_GGO_HRGB_BITMAP:
3478 case WINE_GGO_HBGR_BITMAP:
3479 load_flags |= FT_LOAD_TARGET_LCD;
3480 break;
3481 case WINE_GGO_VRGB_BITMAP:
3482 case WINE_GGO_VBGR_BITMAP:
3483 load_flags |= FT_LOAD_TARGET_LCD_V;
3484 break;
3487 return load_flags;
3490 /*************************************************************
3491 * freetype_get_glyph_outline
3493 static DWORD CDECL freetype_get_glyph_outline( struct gdi_font *font, UINT glyph, UINT format,
3494 GLYPHMETRICS *lpgm, ABC *abc, DWORD buflen, void *buf,
3495 const MAT2 *lpmat, BOOL tategaki )
3497 struct gdi_font *base_font = font->base_font ? font->base_font : font;
3498 FT_Face ft_face = get_ft_face( font );
3499 FT_Glyph_Metrics metrics;
3500 FT_Error err;
3501 FT_BBox bbox;
3502 FT_Int load_flags = get_load_flags(format);
3503 FT_Matrix transform_matrices[3], *matrices = NULL;
3504 BOOL vertical_metrics;
3506 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm, buflen, buf, lpmat);
3508 TRACE("font transform %f %f %f %f\n",
3509 font->matrix.eM11, font->matrix.eM12,
3510 font->matrix.eM21, font->matrix.eM22);
3512 format &= ~GGO_UNHINTED;
3514 matrices = get_transform_matrices( font, tategaki, lpmat, transform_matrices );
3516 vertical_metrics = (tategaki && FT_HAS_VERTICAL(ft_face));
3517 /* there is a freetype bug where vertical metrics are only
3518 properly scaled and correct in 2.4.0 or greater */
3519 if (vertical_metrics && FT_SimpleVersion < FT_VERSION_VALUE(2, 4, 0))
3520 vertical_metrics = FALSE;
3522 if (matrices || format != GGO_BITMAP) load_flags |= FT_LOAD_NO_BITMAP;
3523 if (vertical_metrics) load_flags |= FT_LOAD_VERTICAL_LAYOUT;
3525 err = pFT_Load_Glyph(ft_face, glyph, load_flags);
3526 if (err && !(load_flags & FT_LOAD_NO_HINTING))
3528 WARN("Failed to load glyph %#x, retrying without hinting. Error %#x.\n", glyph, err);
3529 load_flags |= FT_LOAD_NO_HINTING;
3530 err = pFT_Load_Glyph(ft_face, glyph, load_flags);
3533 if(err) {
3534 WARN("Failed to load glyph %#x, error %#x.\n", glyph, err);
3535 return GDI_ERROR;
3538 metrics = ft_face->glyph->metrics;
3539 if(font->fake_bold) {
3540 if (!get_bold_glyph_outline(ft_face->glyph, font->ppem, &metrics) && metrics.width)
3541 metrics.width += 1 << 6;
3544 /* Some poorly-created fonts contain glyphs that exceed the boundaries set
3545 * by the text metrics. The proper behavior is to clip the glyph metrics to
3546 * fit within the maximums specified in the text metrics. */
3547 if (freetype_set_outline_text_metrics(base_font) ||
3548 freetype_set_bitmap_text_metrics(base_font)) {
3549 TEXTMETRICW *ptm = &base_font->otm.otmTextMetrics;
3550 INT top = min( metrics.horiBearingY, ptm->tmAscent << 6 );
3551 INT bottom = max( metrics.horiBearingY - metrics.height, -(ptm->tmDescent << 6) );
3552 metrics.horiBearingY = top;
3553 metrics.height = top - bottom;
3555 /* TODO: Are we supposed to clip the width as well...? */
3556 /* metrics.width = min( metrics.width, ptm->tmMaxCharWidth << 6 ); */
3559 bbox = get_transformed_bbox( &metrics, matrices );
3560 compute_metrics( font, bbox, &metrics, tategaki, vertical_metrics, matrices, lpgm, abc );
3562 switch (format)
3564 case GGO_METRICS:
3565 return 1; /* FIXME */
3567 case GGO_BITMAP:
3568 return get_mono_glyph_bitmap( ft_face->glyph, bbox, font->fake_bold,
3569 matrices, buflen, buf );
3571 case GGO_GRAY2_BITMAP:
3572 case GGO_GRAY4_BITMAP:
3573 case GGO_GRAY8_BITMAP:
3574 case WINE_GGO_GRAY16_BITMAP:
3575 return get_antialias_glyph_bitmap( ft_face->glyph, bbox, format, font->fake_bold,
3576 matrices, buflen, buf );
3578 case WINE_GGO_HRGB_BITMAP:
3579 case WINE_GGO_HBGR_BITMAP:
3580 case WINE_GGO_VRGB_BITMAP:
3581 case WINE_GGO_VBGR_BITMAP:
3582 return get_subpixel_glyph_bitmap( ft_face->glyph, bbox, format, font->fake_bold,
3583 matrices, lpgm, buflen, buf );
3585 case GGO_NATIVE:
3586 if (ft_face->glyph->format == ft_glyph_format_outline)
3588 FT_Outline *outline = &ft_face->glyph->outline;
3589 UINT needed;
3591 if (buflen == 0) buf = NULL;
3593 if (matrices && buf)
3594 pFT_Outline_Transform( outline, &matrices[matrix_vert] );
3596 needed = get_native_glyph_outline(outline, buflen, NULL);
3598 if (!buf || !buflen) return needed;
3599 if (needed > buflen) return GDI_ERROR;
3600 return get_native_glyph_outline(outline, buflen, buf);
3602 TRACE("loaded a bitmap\n");
3603 return GDI_ERROR;
3605 case GGO_BEZIER:
3606 if (ft_face->glyph->format == ft_glyph_format_outline)
3608 FT_Outline *outline = &ft_face->glyph->outline;
3609 UINT needed;
3611 if (buflen == 0) buf = NULL;
3613 if (matrices && buf)
3614 pFT_Outline_Transform( outline, &matrices[matrix_vert] );
3616 needed = get_bezier_glyph_outline(outline, buflen, NULL);
3618 if (!buf || !buflen) return needed;
3619 if (needed > buflen) return GDI_ERROR;
3620 return get_bezier_glyph_outline(outline, buflen, buf);
3622 TRACE("loaded a bitmap\n");
3623 return GDI_ERROR;
3625 default:
3626 FIXME("Unsupported format %d\n", format);
3627 return GDI_ERROR;
3631 /*************************************************************
3632 * freetype_set_bitmap_text_metrics
3634 static BOOL CDECL freetype_set_bitmap_text_metrics( struct gdi_font *font )
3636 FT_Face ft_face = get_ft_face( font );
3637 FT_WinFNT_HeaderRec winfnt_header;
3639 if (font->otm.otmSize) return TRUE; /* already set */
3640 font->otm.otmSize = offsetof( OUTLINETEXTMETRICW, otmFiller );
3642 #define TM font->otm.otmTextMetrics
3643 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
3645 TM.tmHeight = winfnt_header.pixel_height;
3646 TM.tmAscent = winfnt_header.ascent;
3647 TM.tmDescent = TM.tmHeight - TM.tmAscent;
3648 TM.tmInternalLeading = winfnt_header.internal_leading;
3649 TM.tmExternalLeading = winfnt_header.external_leading;
3650 TM.tmAveCharWidth = winfnt_header.avg_width;
3651 TM.tmMaxCharWidth = winfnt_header.max_width;
3652 TM.tmWeight = winfnt_header.weight;
3653 TM.tmOverhang = 0;
3654 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
3655 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
3656 TM.tmFirstChar = winfnt_header.first_char;
3657 TM.tmLastChar = winfnt_header.last_char;
3658 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
3659 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
3660 TM.tmItalic = winfnt_header.italic;
3661 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
3662 TM.tmCharSet = winfnt_header.charset;
3664 else
3666 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
3667 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
3668 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3669 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
3670 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
3671 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
3672 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
3673 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
3674 TM.tmOverhang = 0;
3675 TM.tmDigitizedAspectX = 96; /* FIXME */
3676 TM.tmDigitizedAspectY = 96; /* FIXME */
3677 TM.tmFirstChar = 1;
3678 TM.tmLastChar = 255;
3679 TM.tmDefaultChar = 32;
3680 TM.tmBreakChar = 32;
3681 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
3682 /* NB inverted meaning of TMPF_FIXED_PITCH */
3683 TM.tmPitchAndFamily = FT_IS_FIXED_WIDTH(ft_face) ? 0 : TMPF_FIXED_PITCH;
3684 TM.tmCharSet = font->charset;
3686 TM.tmUnderlined = font->lf.lfUnderline ? 0xff : 0;
3687 TM.tmStruckOut = font->lf.lfStrikeOut ? 0xff : 0;
3689 if(font->fake_bold)
3690 TM.tmWeight = FW_BOLD;
3691 #undef TM
3693 return TRUE;
3697 static BOOL face_has_symbol_charmap(FT_Face ft_face)
3699 int i;
3701 for(i = 0; i < ft_face->num_charmaps; i++)
3703 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
3704 return TRUE;
3706 return FALSE;
3709 /*************************************************************
3710 * freetype_set_outline_text_metrics
3712 static BOOL CDECL freetype_set_outline_text_metrics( struct gdi_font *font )
3714 FT_Face ft_face = get_ft_face( font );
3715 UINT needed;
3716 TT_OS2 *pOS2;
3717 TT_HoriHeader *pHori;
3718 TT_Postscript *pPost;
3719 FT_Fixed em_scale;
3720 INT ascent, descent;
3721 USHORT windescent;
3723 TRACE("font=%p\n", font);
3725 if (!font->scalable) return FALSE;
3726 if (font->otm.otmSize) return TRUE; /* already set */
3728 /* note: we store actual pointers in the names instead of offsets,
3729 they are fixed up when returned to the app */
3730 if (!(font->otm.otmpFullName = (char *)get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, system_lcid )))
3732 static const WCHAR fake_nameW[] = {'f','a','k','e',' ','n','a','m','e', 0};
3733 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w((WCHAR *)font->otm.otmpFamilyName));
3734 font->otm.otmpFullName = (char *)strdupW(fake_nameW);
3736 needed = sizeof(font->otm) + (lstrlenW( (WCHAR *)font->otm.otmpFamilyName ) + 1 +
3737 lstrlenW( (WCHAR *)font->otm.otmpStyleName ) + 1 +
3738 lstrlenW( (WCHAR *)font->otm.otmpFaceName ) + 1 +
3739 lstrlenW( (WCHAR *)font->otm.otmpFullName ) + 1) * sizeof(WCHAR);
3741 em_scale = (FT_Fixed)pFT_MulDiv(font->ppem, 1 << 16, ft_face->units_per_EM);
3743 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3744 if(!pOS2) {
3745 FIXME("Can't find OS/2 table - not TT font?\n");
3746 return FALSE;
3749 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3750 if(!pHori) {
3751 FIXME("Can't find HHEA table - not TT font?\n");
3752 return FALSE;
3755 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
3757 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",
3758 pOS2->usWinAscent, pOS2->usWinDescent,
3759 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
3760 pOS2->xAvgCharWidth,
3761 ft_face->ascender, ft_face->descender, ft_face->height,
3762 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
3763 ft_face->bbox.yMax, ft_face->bbox.yMin);
3765 font->otm.otmSize = needed;
3767 #define TM font->otm.otmTextMetrics
3769 windescent = get_fixed_windescent(pOS2->usWinDescent);
3770 if(pOS2->usWinAscent + windescent == 0) {
3771 ascent = pHori->Ascender;
3772 descent = -pHori->Descender;
3773 } else {
3774 ascent = pOS2->usWinAscent;
3775 descent = windescent;
3778 font->ntmAvgWidth = pOS2->xAvgCharWidth;
3780 #define SCALE_X(x) (pFT_MulFix(x, em_scale))
3781 #define SCALE_Y(y) (pFT_MulFix(y, em_scale))
3783 if(font->yMax) {
3784 TM.tmAscent = font->yMax;
3785 TM.tmDescent = -font->yMin;
3786 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
3787 } else {
3788 TM.tmAscent = SCALE_Y(ascent);
3789 TM.tmDescent = SCALE_Y(descent);
3790 TM.tmInternalLeading = SCALE_Y(ascent + descent - ft_face->units_per_EM);
3793 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3795 /* MSDN says:
3796 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
3798 TM.tmExternalLeading = max(0, SCALE_Y(pHori->Line_Gap -
3799 ((ascent + descent) -
3800 (pHori->Ascender - pHori->Descender))));
3802 TM.tmAveCharWidth = SCALE_X(pOS2->xAvgCharWidth);
3803 if (TM.tmAveCharWidth == 0) {
3804 TM.tmAveCharWidth = 1;
3806 TM.tmMaxCharWidth = SCALE_X(ft_face->bbox.xMax - ft_face->bbox.xMin);
3807 TM.tmWeight = FW_REGULAR;
3808 if (font->fake_bold)
3809 TM.tmWeight = FW_BOLD;
3810 else
3812 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
3814 if (pOS2->usWeightClass > FW_MEDIUM)
3815 TM.tmWeight = pOS2->usWeightClass;
3817 else if (pOS2->usWeightClass <= FW_MEDIUM)
3818 TM.tmWeight = pOS2->usWeightClass;
3820 TM.tmOverhang = 0;
3821 TM.tmDigitizedAspectX = 96; /* FIXME */
3822 TM.tmDigitizedAspectY = 96; /* FIXME */
3823 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
3824 * symbol range to 0 - f0ff
3827 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
3829 TM.tmFirstChar = 0;
3830 switch (PRIMARYLANGID(system_lcid))
3832 case LANG_HEBREW:
3833 TM.tmLastChar = 0xf896;
3834 break;
3835 case LANG_ESTONIAN:
3836 case LANG_LATVIAN:
3837 case LANG_LITHUANIAN:
3838 TM.tmLastChar = 0xf8fd;
3839 break;
3840 default:
3841 TM.tmLastChar = 0xf0ff;
3843 TM.tmBreakChar = 0x20;
3844 TM.tmDefaultChar = 0x1f;
3846 else
3848 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
3849 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
3851 if(pOS2->usFirstCharIndex <= 1)
3852 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
3853 else if (pOS2->usFirstCharIndex > 0xff)
3854 TM.tmBreakChar = 0x20;
3855 else
3856 TM.tmBreakChar = pOS2->usFirstCharIndex;
3857 TM.tmDefaultChar = TM.tmBreakChar - 1;
3859 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
3860 TM.tmUnderlined = font->lf.lfUnderline ? 255 : 0;
3861 TM.tmStruckOut = font->lf.lfStrikeOut ? 255 : 0;
3863 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
3864 if(!FT_IS_FIXED_WIDTH(ft_face) &&
3865 (pOS2->version == 0xFFFFU ||
3866 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
3867 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
3868 else
3869 TM.tmPitchAndFamily = 0;
3871 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
3873 case PAN_FAMILY_SCRIPT:
3874 TM.tmPitchAndFamily |= FF_SCRIPT;
3875 break;
3877 case PAN_FAMILY_DECORATIVE:
3878 TM.tmPitchAndFamily |= FF_DECORATIVE;
3879 break;
3881 case PAN_ANY:
3882 case PAN_NO_FIT:
3883 case PAN_FAMILY_TEXT_DISPLAY:
3884 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
3885 /* which is clearly not what the panose spec says. */
3886 default:
3887 if(TM.tmPitchAndFamily == 0 || /* fixed */
3888 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
3889 TM.tmPitchAndFamily = FF_MODERN;
3890 else
3892 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
3894 case PAN_ANY:
3895 case PAN_NO_FIT:
3896 default:
3897 TM.tmPitchAndFamily |= FF_DONTCARE;
3898 break;
3900 case PAN_SERIF_COVE:
3901 case PAN_SERIF_OBTUSE_COVE:
3902 case PAN_SERIF_SQUARE_COVE:
3903 case PAN_SERIF_OBTUSE_SQUARE_COVE:
3904 case PAN_SERIF_SQUARE:
3905 case PAN_SERIF_THIN:
3906 case PAN_SERIF_BONE:
3907 case PAN_SERIF_EXAGGERATED:
3908 case PAN_SERIF_TRIANGLE:
3909 TM.tmPitchAndFamily |= FF_ROMAN;
3910 break;
3912 case PAN_SERIF_NORMAL_SANS:
3913 case PAN_SERIF_OBTUSE_SANS:
3914 case PAN_SERIF_PERP_SANS:
3915 case PAN_SERIF_FLARED:
3916 case PAN_SERIF_ROUNDED:
3917 TM.tmPitchAndFamily |= FF_SWISS;
3918 break;
3921 break;
3924 if(FT_IS_SCALABLE(ft_face))
3925 TM.tmPitchAndFamily |= TMPF_VECTOR;
3927 if(FT_IS_SFNT(ft_face))
3929 if (font->ntmFlags & NTM_PS_OPENTYPE)
3930 TM.tmPitchAndFamily |= TMPF_DEVICE;
3931 else
3932 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
3935 TM.tmCharSet = font->charset;
3937 font->otm.otmFiller = 0;
3938 memcpy(&font->otm.otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
3939 font->otm.otmfsSelection = pOS2->fsSelection;
3940 if (font->fake_italic)
3941 font->otm.otmfsSelection |= 1;
3942 if (font->fake_bold)
3943 font->otm.otmfsSelection |= 1 << 5;
3944 /* Only return valid bits that define embedding and subsetting restrictions */
3945 font->otm.otmfsType = pOS2->fsType & 0x30e;
3946 font->otm.otmsCharSlopeRise = pHori->caret_Slope_Rise;
3947 font->otm.otmsCharSlopeRun = pHori->caret_Slope_Run;
3948 font->otm.otmItalicAngle = 0; /* POST table */
3949 font->otm.otmAscent = SCALE_Y(pOS2->sTypoAscender);
3950 font->otm.otmDescent = SCALE_Y(pOS2->sTypoDescender);
3951 font->otm.otmLineGap = SCALE_Y(pOS2->sTypoLineGap);
3952 font->otm.otmsCapEmHeight = SCALE_Y(pOS2->sCapHeight);
3953 font->otm.otmsXHeight = SCALE_Y(pOS2->sxHeight);
3954 font->otm.otmrcFontBox.left = SCALE_X(ft_face->bbox.xMin);
3955 font->otm.otmrcFontBox.right = SCALE_X(ft_face->bbox.xMax);
3956 font->otm.otmrcFontBox.top = SCALE_Y(ft_face->bbox.yMax);
3957 font->otm.otmrcFontBox.bottom = SCALE_Y(ft_face->bbox.yMin);
3958 font->otm.otmMacAscent = TM.tmAscent;
3959 font->otm.otmMacDescent = -TM.tmDescent;
3960 font->otm.otmMacLineGap = SCALE_Y(pHori->Line_Gap);
3961 font->otm.otmusMinimumPPEM = 0; /* TT Header */
3962 font->otm.otmptSubscriptSize.x = SCALE_X(pOS2->ySubscriptXSize);
3963 font->otm.otmptSubscriptSize.y = SCALE_Y(pOS2->ySubscriptYSize);
3964 font->otm.otmptSubscriptOffset.x = SCALE_X(pOS2->ySubscriptXOffset);
3965 font->otm.otmptSubscriptOffset.y = SCALE_Y(pOS2->ySubscriptYOffset);
3966 font->otm.otmptSuperscriptSize.x = SCALE_X(pOS2->ySuperscriptXSize);
3967 font->otm.otmptSuperscriptSize.y = SCALE_Y(pOS2->ySuperscriptYSize);
3968 font->otm.otmptSuperscriptOffset.x = SCALE_X(pOS2->ySuperscriptXOffset);
3969 font->otm.otmptSuperscriptOffset.y = SCALE_Y(pOS2->ySuperscriptYOffset);
3970 font->otm.otmsStrikeoutSize = SCALE_Y(pOS2->yStrikeoutSize);
3971 font->otm.otmsStrikeoutPosition = SCALE_Y(pOS2->yStrikeoutPosition);
3972 if(!pPost) {
3973 font->otm.otmsUnderscoreSize = 0;
3974 font->otm.otmsUnderscorePosition = 0;
3975 } else {
3976 font->otm.otmsUnderscoreSize = SCALE_Y(pPost->underlineThickness);
3977 font->otm.otmsUnderscorePosition = SCALE_Y(pPost->underlinePosition);
3979 #undef SCALE_X
3980 #undef SCALE_Y
3981 #undef TM
3982 return TRUE;
3985 /*************************************************************
3986 * freetype_get_char_width_info
3988 static BOOL CDECL freetype_get_char_width_info( struct gdi_font *font, struct char_width_info *info )
3990 FT_Face ft_face = get_ft_face( font );
3991 TT_HoriHeader *pHori;
3993 TRACE("%p, %p\n", font, info);
3995 if ((pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea)))
3997 FT_Fixed em_scale = pFT_MulDiv(font->ppem, 1 << 16, ft_face->units_per_EM);
3998 info->lsb = (SHORT)pFT_MulFix(pHori->min_Left_Side_Bearing, em_scale);
3999 info->rsb = (SHORT)pFT_MulFix(pHori->min_Right_Side_Bearing, em_scale);
4000 return TRUE;
4002 return FALSE;
4006 /*************************************************************
4007 * freetype_get_unicode_ranges
4009 * Retrieve a list of supported Unicode ranges for a given font.
4010 * Can be called with NULL gs to calculate the buffer size. Returns
4011 * the number of ranges found.
4013 static DWORD CDECL freetype_get_unicode_ranges( struct gdi_font *font, GLYPHSET *gs )
4015 FT_Face ft_face = get_ft_face( font );
4016 DWORD num_ranges = 0;
4018 if (ft_face->charmap->encoding == FT_ENCODING_UNICODE)
4020 FT_UInt glyph_code;
4021 FT_ULong char_code, char_code_prev;
4023 glyph_code = 0;
4024 char_code_prev = char_code = pFT_Get_First_Char(ft_face, &glyph_code);
4026 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
4027 ft_face->num_glyphs, glyph_code, char_code);
4029 if (!glyph_code) return 0;
4031 if (gs)
4033 gs->ranges[0].wcLow = (USHORT)char_code;
4034 gs->ranges[0].cGlyphs = 0;
4035 gs->cGlyphsSupported = 0;
4038 num_ranges = 1;
4039 while (glyph_code)
4041 if (char_code < char_code_prev)
4043 ERR("expected increasing char code from FT_Get_Next_Char\n");
4044 return 0;
4046 if (char_code - char_code_prev > 1)
4048 num_ranges++;
4049 if (gs)
4051 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
4052 gs->ranges[num_ranges - 1].cGlyphs = 1;
4053 gs->cGlyphsSupported++;
4056 else if (gs)
4058 gs->ranges[num_ranges - 1].cGlyphs++;
4059 gs->cGlyphsSupported++;
4061 char_code_prev = char_code;
4062 char_code = pFT_Get_Next_Char(ft_face, char_code, &glyph_code);
4065 else
4067 DWORD encoding = RtlUlongByteSwap(ft_face->charmap->encoding);
4068 FIXME("encoding %s not supported\n", debugstr_an((char *)&encoding, 4));
4071 return num_ranges;
4074 /*************************************************************************
4075 * Kerning support for TrueType fonts
4078 struct TT_kern_table
4080 USHORT version;
4081 USHORT nTables;
4084 struct TT_kern_subtable
4086 USHORT version;
4087 USHORT length;
4088 union
4090 USHORT word;
4091 struct
4093 USHORT horizontal : 1;
4094 USHORT minimum : 1;
4095 USHORT cross_stream: 1;
4096 USHORT override : 1;
4097 USHORT reserved1 : 4;
4098 USHORT format : 8;
4099 } bits;
4100 } coverage;
4103 struct TT_format0_kern_subtable
4105 USHORT nPairs;
4106 USHORT searchRange;
4107 USHORT entrySelector;
4108 USHORT rangeShift;
4111 struct TT_kern_pair
4113 USHORT left;
4114 USHORT right;
4115 short value;
4118 static DWORD parse_format0_kern_subtable(struct gdi_font *font,
4119 const struct TT_format0_kern_subtable *tt_f0_ks,
4120 const USHORT *glyph_to_char,
4121 KERNINGPAIR *kern_pair, DWORD cPairs)
4123 FT_Face ft_face = get_ft_face( font );
4124 USHORT i, nPairs;
4125 const struct TT_kern_pair *tt_kern_pair;
4127 TRACE("font height %d, units_per_EM %d\n", font->ppem, ft_face->units_per_EM);
4129 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
4131 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
4132 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
4133 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
4135 if (!kern_pair || !cPairs)
4136 return nPairs;
4138 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
4140 nPairs = min(nPairs, cPairs);
4142 for (i = 0; i < nPairs; i++)
4144 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
4145 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
4146 /* this algorithm appears to better match what Windows does */
4147 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
4148 if (kern_pair->iKernAmount < 0)
4150 kern_pair->iKernAmount -= ft_face->units_per_EM / 2;
4151 kern_pair->iKernAmount -= font->ppem;
4153 else if (kern_pair->iKernAmount > 0)
4155 kern_pair->iKernAmount += ft_face->units_per_EM / 2;
4156 kern_pair->iKernAmount += font->ppem;
4158 kern_pair->iKernAmount /= ft_face->units_per_EM;
4160 TRACE("left %u right %u value %d\n",
4161 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
4163 kern_pair++;
4165 TRACE("copied %u entries\n", nPairs);
4166 return nPairs;
4169 /*************************************************************
4170 * freetype_get_kerning_pairs
4172 static DWORD CDECL freetype_get_kerning_pairs( struct gdi_font *font, KERNINGPAIR **pairs )
4174 FT_Face ft_face = get_ft_face( font );
4175 DWORD length, count = 0;
4176 void *buf;
4177 const struct TT_kern_table *tt_kern_table;
4178 const struct TT_kern_subtable *tt_kern_subtable;
4179 USHORT i, nTables;
4180 USHORT *glyph_to_char;
4182 length = freetype_get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
4184 if (length == GDI_ERROR)
4186 TRACE("no kerning data in the font\n");
4187 return 0;
4190 buf = RtlAllocateHeap(GetProcessHeap(), 0, length);
4191 if (!buf) return 0;
4193 freetype_get_font_data(font, MS_KERN_TAG, 0, buf, length);
4195 /* build a glyph index to char code map */
4196 glyph_to_char = RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
4197 if (!glyph_to_char)
4199 RtlFreeHeap(GetProcessHeap(), 0, buf);
4200 return 0;
4203 if (ft_face->charmap->encoding == FT_ENCODING_UNICODE)
4205 FT_UInt glyph_code;
4206 FT_ULong char_code;
4208 glyph_code = 0;
4209 char_code = pFT_Get_First_Char(ft_face, &glyph_code);
4211 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
4212 ft_face->num_glyphs, glyph_code, char_code);
4214 while (glyph_code)
4216 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
4218 /* FIXME: This doesn't match what Windows does: it does some fancy
4219 * things with duplicate glyph index to char code mappings, while
4220 * we just avoid overriding existing entries.
4222 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
4223 glyph_to_char[glyph_code] = (USHORT)char_code;
4225 char_code = pFT_Get_Next_Char(ft_face, char_code, &glyph_code);
4228 else
4230 DWORD encoding = RtlUlongByteSwap(ft_face->charmap->encoding);
4231 ULONG n;
4233 FIXME("encoding %s not supported\n", debugstr_an((char *)&encoding, 4));
4234 for (n = 0; n <= 65535; n++)
4235 glyph_to_char[n] = (USHORT)n;
4238 tt_kern_table = buf;
4239 nTables = GET_BE_WORD(tt_kern_table->nTables);
4240 TRACE("version %u, nTables %u\n",
4241 GET_BE_WORD(tt_kern_table->version), nTables);
4243 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
4245 for (i = 0; i < nTables; i++)
4247 struct TT_kern_subtable tt_kern_subtable_copy;
4249 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
4250 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
4251 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
4253 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
4254 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
4255 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
4257 /* According to the TrueType specification this is the only format
4258 * that will be properly interpreted by Windows and OS/2
4260 if (tt_kern_subtable_copy.coverage.bits.format == 0)
4262 DWORD new_chunk, old_total = count;
4264 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
4265 glyph_to_char, NULL, 0);
4266 count += new_chunk;
4268 if (!*pairs)
4269 *pairs = RtlAllocateHeap(GetProcessHeap(), 0, count * sizeof(**pairs));
4270 else
4271 *pairs = RtlReAllocateHeap(GetProcessHeap(), 0, *pairs, count * sizeof(**pairs));
4273 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
4274 glyph_to_char, *pairs + old_total, new_chunk);
4276 else
4277 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
4279 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
4282 RtlFreeHeap(GetProcessHeap(), 0, glyph_to_char);
4283 RtlFreeHeap(GetProcessHeap(), 0, buf);
4284 return count;
4287 static const struct font_backend_funcs font_funcs =
4289 freetype_load_fonts,
4290 fontconfig_enum_family_fallbacks,
4291 freetype_add_font,
4292 freetype_add_mem_font,
4293 freetype_load_font,
4294 freetype_get_font_data,
4295 freetype_get_aa_flags,
4296 freetype_get_glyph_index,
4297 freetype_get_default_glyph,
4298 freetype_get_glyph_outline,
4299 freetype_get_unicode_ranges,
4300 freetype_get_char_width_info,
4301 freetype_set_outline_text_metrics,
4302 freetype_set_bitmap_text_metrics,
4303 freetype_get_kerning_pairs,
4304 freetype_destroy_font
4307 static NTSTATUS init_freetype_lib( HMODULE module, DWORD reason, const void *ptr_in, void *ptr_out )
4309 callback_funcs = ptr_in;
4310 if (!init_freetype()) return STATUS_DLL_NOT_FOUND;
4311 #ifdef SONAME_LIBFONTCONFIG
4312 init_fontconfig();
4313 #endif
4314 NtQueryDefaultLocale( FALSE, &system_lcid );
4315 *(const struct font_backend_funcs **)ptr_out = &font_funcs;
4316 return STATUS_SUCCESS;
4319 #else /* HAVE_FREETYPE */
4321 static NTSTATUS init_freetype_lib( HMODULE module, DWORD reason, const void *ptr_in, void *ptr_out )
4323 return STATUS_DLL_NOT_FOUND;
4326 #endif /* HAVE_FREETYPE */
4328 NTSTATUS CDECL __wine_init_unix_lib( HMODULE module, DWORD reason, const void *ptr_in, void *ptr_out )
4330 if (reason != DLL_PROCESS_ATTACH) return STATUS_SUCCESS;
4332 if (ptr_in) return init_freetype_lib( module, reason, ptr_in, ptr_out );
4333 else return init_opengl_lib( module, reason, ptr_in, ptr_out );