gdi32: Handle EMFs recording directly in LineTo implementation.
[wine.git] / dlls / gdi32 / freetype.c
blobee14bd25119e55ebb3d80ba0bead751d14f63f56
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 "ntgdi_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 full_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;
1544 FcResult result;
1545 if (*cached) return *cached;
1546 pattern = pFcPatternCreate();
1547 pFcPatternAddString( pattern, FC_FAMILY, (const FcChar8 *)name );
1548 pFcPatternAddString( pattern, FC_NAMELANG, (const FcChar8 *)"en-us" );
1549 pFcPatternAddString( pattern, FC_PRGNAME, (const FcChar8 *)"wine" );
1550 pFcConfigSubstitute( NULL, pattern, FcMatchPattern );
1551 pFcDefaultSubstitute( pattern );
1552 tmp = pFcFontMatch( NULL, pattern, &result );
1553 pFcPatternDestroy( pattern );
1554 if (result != FcResultMatch) pFcPatternDestroy( tmp );
1555 else if ((ret = InterlockedCompareExchangePointer( (void **)cached, tmp, NULL ))) pFcPatternDestroy( tmp );
1556 else ret = tmp;
1557 return ret;
1560 static void fontconfig_add_font( FcPattern *pattern, DWORD flags )
1562 const char *unix_name, *format;
1563 WCHAR *dos_name;
1564 FcBool scalable;
1565 DWORD aa_flags;
1566 int face_index;
1568 TRACE( "(%p %#x)\n", pattern, flags );
1570 if (pFcPatternGetString( pattern, FC_FILE, 0, (FcChar8 **)&unix_name ) != FcResultMatch)
1571 return;
1573 if (pFcPatternGetBool( pattern, FC_SCALABLE, 0, &scalable ) != FcResultMatch)
1574 scalable = FALSE;
1576 if (pFcPatternGetString( pattern, FC_FONTFORMAT, 0, (FcChar8 **)&format ) != FcResultMatch)
1578 TRACE( "ignoring unknown font format %s\n", debugstr_a(unix_name) );
1579 return;
1582 if (!strcmp( format, "Type 1" ))
1584 TRACE( "ignoring Type 1 font %s\n", debugstr_a(unix_name) );
1585 return;
1588 if (!scalable && !(flags & ADDFONT_ALLOW_BITMAP))
1590 TRACE( "ignoring non-scalable font %s\n", debugstr_a(unix_name) );
1591 return;
1594 if (!(aa_flags = parse_aa_pattern( pattern ))) aa_flags = default_aa_flags;
1595 flags |= ADDFONT_AA_FLAGS(aa_flags);
1597 if (pFcPatternGetInteger( pattern, FC_INDEX, 0, &face_index ) != FcResultMatch)
1598 face_index = 0;
1600 dos_name = get_dos_file_name( unix_name );
1601 add_unix_face( unix_name, dos_name, NULL, 0, face_index, flags, NULL );
1602 RtlFreeHeap( GetProcessHeap(), 0, dos_name );
1605 static void init_fontconfig(void)
1607 void *fc_handle = dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW);
1609 if (!fc_handle)
1611 TRACE("Wine cannot find the fontconfig library (%s).\n", SONAME_LIBFONTCONFIG);
1612 return;
1615 #define LOAD_FUNCPTR(f) if((p##f = dlsym(fc_handle, #f)) == NULL){WARN("Can't find symbol %s\n", #f); return;}
1616 LOAD_FUNCPTR(FcConfigSubstitute);
1617 LOAD_FUNCPTR(FcDefaultSubstitute);
1618 LOAD_FUNCPTR(FcFontList);
1619 LOAD_FUNCPTR(FcFontMatch);
1620 LOAD_FUNCPTR(FcFontSetDestroy);
1621 LOAD_FUNCPTR(FcInit);
1622 LOAD_FUNCPTR(FcPatternAddString);
1623 LOAD_FUNCPTR(FcPatternCreate);
1624 LOAD_FUNCPTR(FcPatternDestroy);
1625 LOAD_FUNCPTR(FcPatternGetBool);
1626 LOAD_FUNCPTR(FcPatternGetInteger);
1627 LOAD_FUNCPTR(FcPatternGetString);
1628 LOAD_FUNCPTR(FcConfigGetFontDirs);
1629 LOAD_FUNCPTR(FcConfigGetCurrent);
1630 LOAD_FUNCPTR(FcCacheCopySet);
1631 LOAD_FUNCPTR(FcCacheNumSubdir);
1632 LOAD_FUNCPTR(FcCacheSubdir);
1633 LOAD_FUNCPTR(FcDirCacheRead);
1634 LOAD_FUNCPTR(FcDirCacheUnload);
1635 LOAD_FUNCPTR(FcStrListCreate);
1636 LOAD_FUNCPTR(FcStrListDone);
1637 LOAD_FUNCPTR(FcStrListNext);
1638 LOAD_FUNCPTR(FcStrSetAdd);
1639 LOAD_FUNCPTR(FcStrSetCreate);
1640 LOAD_FUNCPTR(FcStrSetDestroy);
1641 LOAD_FUNCPTR(FcStrSetMember);
1642 #undef LOAD_FUNCPTR
1644 if (pFcInit())
1646 FcPattern *pattern = pFcPatternCreate();
1647 pFcConfigSubstitute( NULL, pattern, FcMatchFont );
1648 default_aa_flags = parse_aa_pattern( pattern );
1649 pFcPatternDestroy( pattern );
1651 if (!default_aa_flags)
1653 FcPattern *pattern = pFcPatternCreate();
1654 pFcConfigSubstitute( NULL, pattern, FcMatchPattern );
1655 default_aa_flags = parse_aa_pattern( pattern );
1656 pFcPatternDestroy( pattern );
1659 TRACE( "enabled, default flags = %x\n", default_aa_flags );
1660 fontconfig_enabled = TRUE;
1664 static void fontconfig_add_fonts_from_dir_list( FcConfig *config, FcStrList *dir_list, FcStrSet *done_set, DWORD flags )
1666 const FcChar8 *dir;
1667 FcFontSet *font_set = NULL;
1668 FcStrList *subdir_list = NULL;
1669 FcStrSet *subdir_set = NULL;
1670 FcCache *cache = NULL;
1671 int i;
1673 TRACE( "(%p %p %p %#x)\n", config, dir_list, done_set, flags );
1675 while ((dir = pFcStrListNext( dir_list )))
1677 if (pFcStrSetMember( done_set, dir )) continue;
1679 TRACE( "adding fonts from %s\n", dir );
1680 if (!(cache = pFcDirCacheRead( dir, FcFalse, config ))) continue;
1682 if (!(font_set = pFcCacheCopySet( cache ))) goto done;
1683 for (i = 0; i < font_set->nfont; i++)
1684 fontconfig_add_font( font_set->fonts[i], flags );
1685 pFcFontSetDestroy( font_set );
1686 font_set = NULL;
1688 if (!(subdir_set = pFcStrSetCreate())) goto done;
1689 for (i = 0; i < pFcCacheNumSubdir( cache ); i++)
1690 pFcStrSetAdd( subdir_set, pFcCacheSubdir( cache, i ) );
1691 pFcDirCacheUnload( cache );
1692 cache = NULL;
1694 if (!(subdir_list = pFcStrListCreate( subdir_set ))) goto done;
1695 pFcStrSetDestroy( subdir_set );
1696 subdir_set = NULL;
1698 pFcStrSetAdd( done_set, dir );
1699 fontconfig_add_fonts_from_dir_list( config, subdir_list, done_set, flags );
1700 pFcStrListDone( subdir_list );
1701 subdir_list = NULL;
1704 done:
1705 if (subdir_set) pFcStrSetDestroy( subdir_set );
1706 if (cache) pFcDirCacheUnload( cache );
1709 static void load_fontconfig_fonts( void )
1711 FcStrList *dir_list = NULL;
1712 FcStrSet *done_set = NULL;
1713 FcConfig *config;
1715 if (!fontconfig_enabled) return;
1716 if (!(config = pFcConfigGetCurrent())) goto done;
1717 if (!(done_set = pFcStrSetCreate())) goto done;
1718 if (!(dir_list = pFcConfigGetFontDirs( config ))) goto done;
1720 fontconfig_add_fonts_from_dir_list( config, dir_list, done_set, ADDFONT_EXTERNAL_FONT );
1722 done:
1723 if (dir_list) pFcStrListDone( dir_list );
1724 if (done_set) pFcStrSetDestroy( done_set );
1727 #elif defined(HAVE_CARBON_CARBON_H)
1729 static void load_mac_font_callback(const void *value, void *context)
1731 CFStringRef pathStr = value;
1732 CFIndex len;
1733 char* path;
1735 len = CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr);
1736 path = RtlAllocateHeap(GetProcessHeap(), 0, len);
1737 if (path && CFStringGetFileSystemRepresentation(pathStr, path, len))
1739 TRACE("font file %s\n", path);
1740 AddFontToList(NULL, path, NULL, 0, ADDFONT_EXTERNAL_FONT);
1742 RtlFreeHeap(GetProcessHeap(), 0, path);
1745 static void load_mac_fonts(void)
1747 CFStringRef removeDupesKey;
1748 CFBooleanRef removeDupesValue;
1749 CFDictionaryRef options;
1750 CTFontCollectionRef col;
1751 CFArrayRef descs;
1752 CFMutableSetRef paths;
1753 CFIndex i;
1755 removeDupesKey = kCTFontCollectionRemoveDuplicatesOption;
1756 removeDupesValue = kCFBooleanTrue;
1757 options = CFDictionaryCreate(NULL, (const void**)&removeDupesKey, (const void**)&removeDupesValue, 1,
1758 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1759 col = CTFontCollectionCreateFromAvailableFonts(options);
1760 if (options) CFRelease(options);
1761 if (!col)
1763 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
1764 return;
1767 descs = CTFontCollectionCreateMatchingFontDescriptors(col);
1768 CFRelease(col);
1769 if (!descs)
1771 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
1772 return;
1775 paths = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
1776 if (!paths)
1778 WARN("CFSetCreateMutable failed\n");
1779 CFRelease(descs);
1780 return;
1783 for (i = 0; i < CFArrayGetCount(descs); i++)
1785 CTFontDescriptorRef desc;
1786 CFURLRef url;
1787 CFStringRef ext;
1788 CFStringRef path;
1790 desc = CFArrayGetValueAtIndex(descs, i);
1792 #if defined(MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
1793 url = CTFontDescriptorCopyAttribute(desc, kCTFontURLAttribute);
1794 #else
1795 /* CTFontDescriptor doesn't support kCTFontURLAttribute prior to 10.6, so
1796 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
1798 CTFontRef font;
1799 ATSFontRef atsFont;
1800 OSStatus status;
1801 FSRef fsref;
1803 font = CTFontCreateWithFontDescriptor(desc, 0, NULL);
1804 if (!font) continue;
1806 atsFont = CTFontGetPlatformFont(font, NULL);
1807 if (!atsFont)
1809 CFRelease(font);
1810 continue;
1813 status = ATSFontGetFileReference(atsFont, &fsref);
1814 CFRelease(font);
1815 if (status != noErr) continue;
1817 url = CFURLCreateFromFSRef(NULL, &fsref);
1819 #endif
1820 if (!url) continue;
1822 ext = CFURLCopyPathExtension(url);
1823 if (ext)
1825 BOOL skip = (CFStringCompare(ext, CFSTR("pfa"), kCFCompareCaseInsensitive) == kCFCompareEqualTo ||
1826 CFStringCompare(ext, CFSTR("pfb"), kCFCompareCaseInsensitive) == kCFCompareEqualTo);
1827 CFRelease(ext);
1828 if (skip)
1830 CFRelease(url);
1831 continue;
1835 path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
1836 CFRelease(url);
1837 if (!path) continue;
1839 CFSetAddValue(paths, path);
1840 CFRelease(path);
1843 CFRelease(descs);
1845 CFSetApplyFunction(paths, load_mac_font_callback, NULL);
1846 CFRelease(paths);
1849 #endif
1852 static BOOL init_freetype(void)
1854 ft_handle = dlopen(SONAME_LIBFREETYPE, RTLD_NOW);
1855 if(!ft_handle) {
1856 WINE_MESSAGE(
1857 "Wine cannot find the FreeType font library. To enable Wine to\n"
1858 "use TrueType fonts please install a version of FreeType greater than\n"
1859 "or equal to 2.0.5.\n"
1860 "http://www.freetype.org\n");
1861 return FALSE;
1864 #define LOAD_FUNCPTR(f) if((p##f = dlsym(ft_handle, #f)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
1866 LOAD_FUNCPTR(FT_Done_Face)
1867 LOAD_FUNCPTR(FT_Get_Char_Index)
1868 LOAD_FUNCPTR(FT_Get_First_Char)
1869 LOAD_FUNCPTR(FT_Get_Next_Char)
1870 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
1871 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
1872 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
1873 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
1874 LOAD_FUNCPTR(FT_Init_FreeType)
1875 LOAD_FUNCPTR(FT_Library_Version)
1876 LOAD_FUNCPTR(FT_Load_Glyph)
1877 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
1878 LOAD_FUNCPTR(FT_Matrix_Multiply)
1879 LOAD_FUNCPTR(FT_MulDiv)
1880 #ifndef FT_MULFIX_INLINED
1881 LOAD_FUNCPTR(FT_MulFix)
1882 #endif
1883 LOAD_FUNCPTR(FT_New_Face)
1884 LOAD_FUNCPTR(FT_New_Memory_Face)
1885 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
1886 LOAD_FUNCPTR(FT_Outline_Get_CBox)
1887 LOAD_FUNCPTR(FT_Outline_Transform)
1888 LOAD_FUNCPTR(FT_Outline_Translate)
1889 LOAD_FUNCPTR(FT_Render_Glyph)
1890 LOAD_FUNCPTR(FT_Set_Charmap)
1891 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
1892 LOAD_FUNCPTR(FT_Vector_Length)
1893 LOAD_FUNCPTR(FT_Vector_Transform)
1894 LOAD_FUNCPTR(FT_Vector_Unit)
1895 #undef LOAD_FUNCPTR
1896 /* Don't warn if these ones are missing */
1897 pFT_Outline_Embolden = dlsym(ft_handle, "FT_Outline_Embolden");
1898 pFT_Get_TrueType_Engine_Type = dlsym(ft_handle, "FT_Get_TrueType_Engine_Type");
1899 #ifdef FT_LCD_FILTER_H
1900 pFT_Library_SetLcdFilter = dlsym(ft_handle, "FT_Library_SetLcdFilter");
1901 #endif
1902 pFT_Property_Set = dlsym(ft_handle, "FT_Property_Set");
1904 if(pFT_Init_FreeType(&library) != 0) {
1905 ERR("Can't init FreeType library\n");
1906 dlclose(ft_handle);
1907 ft_handle = NULL;
1908 return FALSE;
1910 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
1912 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
1913 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
1914 ((FT_Version.minor << 8) & 0x00ff00) |
1915 ((FT_Version.patch ) & 0x0000ff);
1917 /* In FreeType < 2.8.1 v40's FT_LOAD_TARGET_MONO has broken advance widths. */
1918 if (pFT_Property_Set && FT_SimpleVersion < FT_VERSION_VALUE(2, 8, 1))
1920 FT_UInt interpreter_version = 35;
1921 pFT_Property_Set( library, "truetype", "interpreter-version", &interpreter_version );
1924 #ifdef FT_LCD_FILTER_H
1925 if (pFT_Library_SetLcdFilter)
1926 pFT_Library_SetLcdFilter( library, FT_LCD_FILTER_DEFAULT );
1927 #endif
1929 return TRUE;
1931 sym_not_found:
1932 WINE_MESSAGE(
1933 "Wine cannot find certain functions that it needs inside the FreeType\n"
1934 "font library. To enable Wine to use TrueType fonts please upgrade\n"
1935 "FreeType to at least version 2.1.4.\n"
1936 "http://www.freetype.org\n");
1937 dlclose(ft_handle);
1938 ft_handle = NULL;
1939 return FALSE;
1942 /*************************************************************
1943 * freetype_load_fonts
1945 static void CDECL freetype_load_fonts(void)
1947 #ifdef SONAME_LIBFONTCONFIG
1948 load_fontconfig_fonts();
1949 #elif defined(HAVE_CARBON_CARBON_H)
1950 load_mac_fonts();
1951 #elif defined(__ANDROID__)
1952 ReadFontDir("/system/fonts", TRUE);
1953 #endif
1956 /* Some fonts have large usWinDescent values, as a result of storing signed short
1957 in unsigned field. That's probably caused by sTypoDescent vs usWinDescent confusion in
1958 some font generation tools. */
1959 static inline USHORT get_fixed_windescent(USHORT windescent)
1961 return abs((SHORT)windescent);
1964 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
1966 TT_OS2 *pOS2;
1967 TT_HoriHeader *pHori;
1969 LONG ppem;
1970 const LONG MAX_PPEM = (1 << 16) - 1;
1972 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1973 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1975 if(height == 0) height = 16;
1977 /* Calc. height of EM square:
1979 * For +ve lfHeight we have
1980 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
1981 * Re-arranging gives:
1982 * ppem = units_per_em * lfheight / (winAscent + winDescent)
1984 * For -ve lfHeight we have
1985 * |lfHeight| = ppem
1986 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
1987 * with il = winAscent + winDescent - units_per_em]
1991 if(height > 0) {
1992 USHORT windescent = get_fixed_windescent(pOS2->usWinDescent);
1993 if(pOS2->usWinAscent + windescent == 0)
1994 ppem = pFT_MulDiv(ft_face->units_per_EM, height, pHori->Ascender - pHori->Descender);
1995 else
1996 ppem = pFT_MulDiv(ft_face->units_per_EM, height, pOS2->usWinAscent + windescent);
1997 if(ppem > MAX_PPEM) {
1998 WARN("Ignoring too large height %d, ppem %d\n", height, ppem);
1999 ppem = 1;
2002 else if(height >= -MAX_PPEM)
2003 ppem = -height;
2004 else {
2005 WARN("Ignoring too large height %d\n", height);
2006 ppem = 1;
2009 return ppem;
2012 static struct font_mapping *map_font_file( const char *name )
2014 struct font_mapping *mapping;
2015 struct stat st;
2016 int fd;
2018 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2019 if (fstat( fd, &st ) == -1) goto error;
2021 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2023 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2025 mapping->refcount++;
2026 close( fd );
2027 return mapping;
2030 if (!(mapping = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*mapping) )))
2031 goto error;
2033 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2034 close( fd );
2036 if (mapping->data == MAP_FAILED)
2038 RtlFreeHeap( GetProcessHeap(), 0, mapping );
2039 return NULL;
2041 mapping->refcount = 1;
2042 mapping->dev = st.st_dev;
2043 mapping->ino = st.st_ino;
2044 mapping->size = st.st_size;
2045 list_add_tail( &mappings_list, &mapping->entry );
2046 return mapping;
2048 error:
2049 close( fd );
2050 return NULL;
2053 static void unmap_font_file( struct font_mapping *mapping )
2055 if (!--mapping->refcount)
2057 list_remove( &mapping->entry );
2058 munmap( mapping->data, mapping->size );
2059 RtlFreeHeap( GetProcessHeap(), 0, mapping );
2063 static LONG load_VDMX(struct gdi_font *font, LONG height);
2065 /*************************************************************
2066 * freetype_destroy_font
2068 static void CDECL freetype_destroy_font( struct gdi_font *font )
2070 struct font_private_data *data = font->private;
2072 if (data->ft_face) pFT_Done_Face( data->ft_face );
2073 if (data->mapping) unmap_font_file( data->mapping );
2074 RtlFreeHeap( GetProcessHeap(), 0, data );
2077 /*************************************************************
2078 * freetype_get_font_data
2080 static DWORD CDECL freetype_get_font_data( struct gdi_font *font, DWORD table, DWORD offset,
2081 void *buf, DWORD cbData)
2083 FT_Face ft_face = get_ft_face( font );
2084 FT_ULong len;
2085 FT_Error err;
2087 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
2089 if(!buf)
2090 len = 0;
2091 else
2092 len = cbData;
2094 /* if font is a member of TTC, 'ttcf' tag allows reading from beginning of TTC file,
2095 0 tag means to read from start of collection member data. */
2096 if (font->ttc_item_offset)
2098 if (table == MS_TTCF_TAG)
2099 table = 0;
2100 else if (table == 0)
2101 offset += font->ttc_item_offset;
2104 /* make sure value of len is the value freetype says it needs */
2105 if (buf && len)
2107 FT_ULong needed = 0;
2108 err = pFT_Load_Sfnt_Table(ft_face, RtlUlongByteSwap(table), offset, NULL, &needed);
2109 if( !err && needed < len) len = needed;
2111 err = pFT_Load_Sfnt_Table(ft_face, RtlUlongByteSwap(table), offset, buf, &len);
2112 if (err)
2114 TRACE("Can't find table %s\n", debugstr_an((char*)&table, 4));
2115 return GDI_ERROR;
2117 return len;
2120 /*************************************************************
2121 * load_VDMX
2123 * load the vdmx entry for the specified height
2128 typedef struct {
2129 WORD version;
2130 WORD numRecs;
2131 WORD numRatios;
2132 } VDMX_Header;
2134 typedef struct {
2135 BYTE bCharSet;
2136 BYTE xRatio;
2137 BYTE yStartRatio;
2138 BYTE yEndRatio;
2139 } Ratios;
2141 typedef struct {
2142 WORD recs;
2143 BYTE startsz;
2144 BYTE endsz;
2145 } VDMX_group;
2147 typedef struct {
2148 WORD yPelHeight;
2149 WORD yMax;
2150 WORD yMin;
2151 } VDMX_vTable;
2153 static LONG load_VDMX(struct gdi_font *font, LONG height)
2155 VDMX_Header hdr;
2156 VDMX_group group;
2157 BYTE devXRatio, devYRatio;
2158 USHORT numRecs, numRatios;
2159 DWORD result, offset = -1;
2160 LONG ppem = 0;
2161 int i;
2163 result = freetype_get_font_data(font, MS_VDMX_TAG, 0, &hdr, sizeof(hdr));
2165 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2166 return ppem;
2168 /* FIXME: need the real device aspect ratio */
2169 devXRatio = 1;
2170 devYRatio = 1;
2172 numRecs = GET_BE_WORD(hdr.numRecs);
2173 numRatios = GET_BE_WORD(hdr.numRatios);
2175 TRACE("version = %d numRecs = %d numRatios = %d\n", GET_BE_WORD(hdr.version), numRecs, numRatios);
2176 for(i = 0; i < numRatios; i++) {
2177 Ratios ratio;
2179 offset = sizeof(hdr) + (i * sizeof(Ratios));
2180 freetype_get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2181 offset = -1;
2183 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2185 if (!ratio.bCharSet) continue;
2187 if((ratio.xRatio == 0 &&
2188 ratio.yStartRatio == 0 &&
2189 ratio.yEndRatio == 0) ||
2190 (devXRatio == ratio.xRatio &&
2191 devYRatio >= ratio.yStartRatio &&
2192 devYRatio <= ratio.yEndRatio))
2194 WORD group_offset;
2196 offset = sizeof(hdr) + numRatios * sizeof(ratio) + i * sizeof(group_offset);
2197 freetype_get_font_data(font, MS_VDMX_TAG, offset, &group_offset, sizeof(group_offset));
2198 offset = GET_BE_WORD(group_offset);
2199 break;
2203 if(offset == -1) return 0;
2205 if(freetype_get_font_data(font, MS_VDMX_TAG, offset, &group, sizeof(group)) != GDI_ERROR) {
2206 USHORT recs;
2207 BYTE startsz, endsz;
2208 WORD *vTable;
2210 recs = GET_BE_WORD(group.recs);
2211 startsz = group.startsz;
2212 endsz = group.endsz;
2214 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
2216 vTable = RtlAllocateHeap(GetProcessHeap(), 0, recs * sizeof(VDMX_vTable));
2217 result = freetype_get_font_data(font, MS_VDMX_TAG, offset + sizeof(group), vTable, recs * sizeof(VDMX_vTable));
2218 if(result == GDI_ERROR) {
2219 FIXME("Failed to retrieve vTable\n");
2220 goto end;
2223 if(height > 0) {
2224 for(i = 0; i < recs; i++) {
2225 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2226 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2227 ppem = GET_BE_WORD(vTable[i * 3]);
2229 if(yMax + -yMin == height) {
2230 font->yMax = yMax;
2231 font->yMin = yMin;
2232 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2233 break;
2235 if(yMax + -yMin > height) {
2236 if(--i < 0) {
2237 ppem = 0;
2238 goto end; /* failed */
2240 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2241 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2242 ppem = GET_BE_WORD(vTable[i * 3]);
2243 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2244 break;
2247 if(!font->yMax) {
2248 ppem = 0;
2249 TRACE("ppem not found for height %d\n", height);
2251 } else {
2252 ppem = -height;
2253 if(ppem < startsz || ppem > endsz)
2255 ppem = 0;
2256 goto end;
2259 for(i = 0; i < recs; i++) {
2260 USHORT yPelHeight;
2261 yPelHeight = GET_BE_WORD(vTable[i * 3]);
2263 if(yPelHeight > ppem)
2265 ppem = 0;
2266 break; /* failed */
2269 if(yPelHeight == ppem) {
2270 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2271 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2272 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
2273 break;
2277 end:
2278 RtlFreeHeap(GetProcessHeap(), 0, vTable);
2281 return ppem;
2284 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
2286 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
2287 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
2288 FT_Int i;
2290 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
2292 for (i = 0; i < ft_face->num_charmaps; i++)
2294 if (ft_face->charmaps[i]->encoding == encoding)
2296 TRACE("found cmap with platform_id %u, encoding_id %u\n",
2297 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
2299 switch (ft_face->charmaps[i]->platform_id)
2301 default:
2302 cmap_def = ft_face->charmaps[i];
2303 break;
2304 case 0: /* Apple Unicode */
2305 cmap0 = ft_face->charmaps[i];
2306 break;
2307 case 1: /* Macintosh */
2308 cmap1 = ft_face->charmaps[i];
2309 break;
2310 case 2: /* ISO */
2311 cmap2 = ft_face->charmaps[i];
2312 break;
2313 case 3: /* Microsoft */
2314 cmap3 = ft_face->charmaps[i];
2315 break;
2319 if (cmap3) /* prefer Microsoft cmap table */
2320 ft_err = pFT_Set_Charmap(ft_face, cmap3);
2321 else if (cmap1)
2322 ft_err = pFT_Set_Charmap(ft_face, cmap1);
2323 else if (cmap2)
2324 ft_err = pFT_Set_Charmap(ft_face, cmap2);
2325 else if (cmap0)
2326 ft_err = pFT_Set_Charmap(ft_face, cmap0);
2327 else if (cmap_def)
2328 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
2331 return ft_err == FT_Err_Ok;
2335 static FT_Encoding pick_charmap( FT_Face face, int charset )
2337 static const FT_Encoding regular_order[] = { FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, FT_ENCODING_MS_SYMBOL, 0 };
2338 static const FT_Encoding symbol_order[] = { FT_ENCODING_MS_SYMBOL, FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, 0 };
2339 const FT_Encoding *encs = regular_order;
2341 if (charset == SYMBOL_CHARSET) encs = symbol_order;
2343 while (*encs != 0)
2345 if (select_charmap( face, *encs )) break;
2346 encs++;
2349 if (!face->charmap && face->num_charmaps)
2351 if (!pFT_Set_Charmap(face, face->charmaps[0]))
2352 return face->charmap->encoding;
2355 return *encs;
2358 static BOOL get_gasp_flags( struct gdi_font *font, WORD *flags )
2360 FT_Face ft_face = get_ft_face( font );
2361 DWORD size;
2362 WORD buf[16]; /* Enough for seven ranges before we need to alloc */
2363 WORD *alloced = NULL, *ptr = buf;
2364 WORD num_recs, version;
2365 BOOL ret = FALSE;
2367 *flags = 0;
2368 size = freetype_get_font_data( font, MS_GASP_TAG, 0, NULL, 0 );
2369 if (size == GDI_ERROR) return FALSE;
2370 if (size < 4 * sizeof(WORD)) return FALSE;
2371 if (size > sizeof(buf))
2373 ptr = alloced = RtlAllocateHeap( GetProcessHeap(), 0, size );
2374 if (!ptr) return FALSE;
2377 freetype_get_font_data( font, MS_GASP_TAG, 0, ptr, size );
2379 version = GET_BE_WORD( *ptr++ );
2380 num_recs = GET_BE_WORD( *ptr++ );
2382 if (version > 1 || size < (num_recs * 2 + 2) * sizeof(WORD))
2384 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version, size, num_recs );
2385 goto done;
2388 while (num_recs--)
2390 *flags = GET_BE_WORD( *(ptr + 1) );
2391 if (ft_face->size->metrics.y_ppem <= GET_BE_WORD( *ptr )) break;
2392 ptr += 2;
2394 TRACE( "got flags %04x for ppem %d\n", *flags, ft_face->size->metrics.y_ppem );
2395 ret = TRUE;
2397 done:
2398 RtlFreeHeap( GetProcessHeap(), 0, alloced );
2399 return ret;
2402 /*************************************************************
2403 * fontconfig_enum_family_fallbacks
2405 static BOOL CDECL fontconfig_enum_family_fallbacks( DWORD pitch_and_family, int index,
2406 WCHAR buffer[LF_FACESIZE] )
2408 #ifdef SONAME_LIBFONTCONFIG
2409 FcPattern *pat;
2410 char *str;
2411 DWORD len;
2413 if ((pitch_and_family & FIXED_PITCH) || (pitch_and_family & 0xf0) == FF_MODERN) pat = create_family_pattern( "monospace", &pattern_fixed );
2414 else if ((pitch_and_family & 0xf0) == FF_ROMAN) pat = create_family_pattern( "serif", &pattern_serif );
2415 else pat = create_family_pattern( "sans", &pattern_sans );
2417 if (!pat) return FALSE;
2418 if (pFcPatternGetString( pat, FC_FAMILY, index, (FcChar8 **)&str ) != FcResultMatch) return FALSE;
2419 RtlUTF8ToUnicodeN( buffer, (LF_FACESIZE - 1) * sizeof(WCHAR), &len, str, strlen(str) );
2420 buffer[len / sizeof(WCHAR)] = 0;
2421 return TRUE;
2422 #endif
2423 return FALSE;
2426 static DWORD get_ttc_offset( FT_Face ft_face, UINT face_index )
2428 FT_ULong len;
2429 DWORD header, offset;
2431 /* see if it's a TTC */
2432 len = sizeof(header);
2433 if (pFT_Load_Sfnt_Table( ft_face, 0, 0, (void *)&header, &len )) return 0;
2434 if (header != MS_TTCF_TAG) return 0;
2436 len = sizeof(offset);
2437 if (pFT_Load_Sfnt_Table( ft_face, 0, (3 + face_index) * sizeof(DWORD), (void *)&offset, &len ))
2438 return 0;
2440 return GET_BE_DWORD( offset );
2443 /*************************************************************
2444 * freetype_load_font
2446 static BOOL CDECL freetype_load_font( struct gdi_font *font )
2448 struct font_private_data *data;
2449 INT width = 0, height;
2450 FT_Face ft_face;
2451 void *data_ptr;
2452 SIZE_T data_size;
2454 if (!(data = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data) ))) return FALSE;
2455 font->private = data;
2457 if (font->file[0])
2459 char *filename = get_unix_file_name( font->file );
2460 data->mapping = map_font_file( filename );
2461 RtlFreeHeap( GetProcessHeap(), 0, filename );
2462 if (!data->mapping)
2464 WARN("failed to map %s\n", debugstr_w(font->file));
2465 return FALSE;
2467 data_ptr = data->mapping->data;
2468 data_size = data->mapping->size;
2470 else
2472 data_ptr = font->data_ptr;
2473 data_size = font->data_size;
2476 if (pFT_New_Memory_Face( library, data_ptr, data_size, font->face_index, &ft_face )) return FALSE;
2478 data->ft_face = ft_face;
2479 font->scalable = FT_IS_SCALABLE( ft_face );
2480 if (!font->fs.fsCsb[0]) get_fontsig( ft_face, &font->fs );
2481 if (!font->ntmFlags) font->ntmFlags = get_ntm_flags( ft_face );
2482 if (!font->aa_flags) font->aa_flags = ADDFONT_AA_FLAGS( default_aa_flags );
2483 if (!font->otm.otmpFamilyName)
2485 font->otm.otmpFamilyName = (char *)ft_face_get_family_name( ft_face, system_lcid );
2486 font->otm.otmpStyleName = (char *)ft_face_get_style_name( ft_face, system_lcid );
2487 font->otm.otmpFaceName = (char *)ft_face_get_full_name( ft_face, system_lcid );
2490 if (font->scalable)
2492 /* load the VDMX table if we have one */
2493 font->ppem = load_VDMX( font, font->lf.lfHeight );
2494 if (font->ppem == 0) font->ppem = calc_ppem_for_height( ft_face, font->lf.lfHeight );
2495 TRACE( "height %d => ppem %d\n", font->lf.lfHeight, font->ppem );
2496 height = font->ppem;
2497 font->ttc_item_offset = get_ttc_offset( ft_face, font->face_index );
2498 font->otm.otmEMSquare = ft_face->units_per_EM;
2500 else
2502 struct bitmap_font_size size;
2504 get_bitmap_size( ft_face, &size );
2505 width = size.x_ppem >> 6;
2506 height = size.y_ppem >> 6;
2507 font->ppem = height;
2510 pFT_Set_Pixel_Sizes( ft_face, width, height );
2511 pick_charmap( ft_face, font->charset );
2512 return TRUE;
2516 /*************************************************************
2517 * freetype_get_aa_flags
2519 static UINT CDECL freetype_get_aa_flags( struct gdi_font *font, UINT aa_flags, BOOL antialias_fakes )
2521 /* fixup the antialiasing flags for that font */
2522 switch (aa_flags)
2524 case WINE_GGO_HRGB_BITMAP:
2525 case WINE_GGO_HBGR_BITMAP:
2526 case WINE_GGO_VRGB_BITMAP:
2527 case WINE_GGO_VBGR_BITMAP:
2528 if (is_subpixel_rendering_enabled()) break;
2529 aa_flags = GGO_GRAY4_BITMAP;
2530 /* fall through */
2531 case GGO_GRAY2_BITMAP:
2532 case GGO_GRAY4_BITMAP:
2533 case GGO_GRAY8_BITMAP:
2534 case WINE_GGO_GRAY16_BITMAP:
2535 if ((!antialias_fakes || (!font->fake_bold && !font->fake_italic)) && is_hinting_enabled())
2537 WORD gasp_flags;
2538 if (get_gasp_flags( font, &gasp_flags ) && !(gasp_flags & GASP_DOGRAY))
2540 TRACE( "font %s %d aa disabled by GASP\n",
2541 debugstr_w(font->lf.lfFaceName), font->lf.lfHeight );
2542 aa_flags = GGO_BITMAP;
2546 return aa_flags;
2549 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
2551 pt->x.value = vec->x >> 6;
2552 pt->x.fract = (vec->x & 0x3f) << 10;
2553 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
2554 pt->y.value = vec->y >> 6;
2555 pt->y.fract = (vec->y & 0x3f) << 10;
2556 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
2559 static FT_UInt get_glyph_index_symbol( struct gdi_font *font, UINT glyph )
2561 FT_Face ft_face = get_ft_face( font );
2562 FT_UInt ret;
2564 if (glyph < 0x100) glyph += 0xf000;
2565 /* there are a number of old pre-Unicode "broken" TTFs, which
2566 do have symbols at U+00XX instead of U+f0XX */
2567 if (!(ret = pFT_Get_Char_Index(ft_face, glyph)))
2568 ret = pFT_Get_Char_Index(ft_face, glyph - 0xf000);
2570 return ret;
2573 /*************************************************************
2574 * freetype_get_glyph_index
2576 static BOOL CDECL freetype_get_glyph_index( struct gdi_font *font, UINT *glyph, BOOL use_encoding )
2578 FT_Face ft_face = get_ft_face( font );
2580 if (!use_encoding ^ (ft_face->charmap->encoding == FT_ENCODING_NONE)) return FALSE;
2582 if (ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
2584 if (!(*glyph = get_glyph_index_symbol( font, *glyph )))
2586 WCHAR wc = *glyph;
2587 DWORD len;
2588 char ch;
2590 RtlUnicodeToMultiByteN( &ch, 1, &len, &wc, sizeof(wc) );
2591 if (len) *glyph = get_glyph_index_symbol( font, (unsigned char)ch );
2593 return TRUE;
2595 *glyph = pFT_Get_Char_Index( ft_face, *glyph );
2596 return TRUE;
2599 /*************************************************************
2600 * freetype_get_default_glyph
2602 static UINT CDECL freetype_get_default_glyph( struct gdi_font *font )
2604 FT_Face ft_face = get_ft_face( font );
2605 FT_WinFNT_HeaderRec winfnt;
2606 TT_OS2 *pOS2;
2608 if ((pOS2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 )))
2610 UINT glyph = pOS2->usDefaultChar;
2611 if (glyph) freetype_get_glyph_index( font, &glyph, TRUE );
2612 return glyph;
2614 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt )) return winfnt.default_char + winfnt.first_char;
2615 return 32;
2619 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
2621 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
2622 return !memcmp(matrix, &identity, sizeof(FMAT2));
2625 static inline FT_Vector normalize_vector(FT_Vector *vec)
2627 FT_Vector out;
2628 FT_Fixed len;
2629 len = pFT_Vector_Length(vec);
2630 if (len) {
2631 out.x = (vec->x << 6) / len;
2632 out.y = (vec->y << 6) / len;
2634 else
2635 out.x = out.y = 0;
2636 return out;
2639 /* get_glyph_outline() glyph transform matrices index */
2640 enum matrices_index
2642 matrix_hori,
2643 matrix_vert,
2644 matrix_unrotated
2647 static FT_Matrix *get_transform_matrices( struct gdi_font *font, BOOL vertical, const MAT2 *user_transform,
2648 FT_Matrix matrices[3] )
2650 static const FT_Matrix identity_mat = { (1 << 16), 0, 0, (1 << 16) };
2651 BOOL needs_transform = FALSE;
2652 double width_ratio;
2653 int i;
2655 matrices[matrix_unrotated] = identity_mat;
2657 /* Scaling factor */
2658 if (font->aveWidth)
2660 if (!freetype_set_outline_text_metrics( font )) freetype_set_bitmap_text_metrics( font );
2661 width_ratio = (double)font->aveWidth;
2662 width_ratio /= (double)font->otm.otmTextMetrics.tmAveCharWidth;
2664 else
2665 width_ratio = font->scale_y;
2667 /* Scaling transform */
2668 if (width_ratio != 1.0 || font->scale_y != 1)
2670 FT_Matrix scale_mat;
2671 scale_mat.xx = FT_FixedFromFloat( width_ratio );
2672 scale_mat.xy = 0;
2673 scale_mat.yx = 0;
2674 scale_mat.yy = font->scale_y << 16;
2676 pFT_Matrix_Multiply( &scale_mat, &matrices[matrix_unrotated] );
2677 needs_transform = TRUE;
2680 /* Slant transform */
2681 if (font->fake_italic)
2683 FT_Matrix slant_mat;
2684 slant_mat.xx = (1 << 16);
2685 slant_mat.xy = (1 << 16) >> 2;
2686 slant_mat.yx = 0;
2687 slant_mat.yy = (1 << 16);
2689 pFT_Matrix_Multiply( &slant_mat, &matrices[matrix_unrotated] );
2690 needs_transform = TRUE;
2693 /* Rotation transform */
2694 matrices[matrix_hori] = matrices[matrix_unrotated];
2695 if (font->scalable && font->lf.lfOrientation % 3600)
2697 FT_Matrix rotation_mat;
2698 FT_Vector angle;
2700 pFT_Vector_Unit( &angle, pFT_MulDiv( 1 << 16, font->lf.lfOrientation, 10 ) );
2701 rotation_mat.xx = angle.x;
2702 rotation_mat.xy = -angle.y;
2703 rotation_mat.yx = angle.y;
2704 rotation_mat.yy = angle.x;
2705 pFT_Matrix_Multiply( &rotation_mat, &matrices[matrix_hori] );
2706 needs_transform = TRUE;
2709 /* Vertical transform */
2710 matrices[matrix_vert] = matrices[matrix_hori];
2711 if (vertical)
2713 FT_Matrix vertical_mat = { 0, -(1 << 16), 1 << 16, 0 }; /* 90 degrees rotation */
2715 pFT_Matrix_Multiply( &vertical_mat, &matrices[matrix_vert] );
2716 needs_transform = TRUE;
2719 /* World transform */
2720 if (!is_identity_FMAT2( &font->matrix ))
2722 FT_Matrix world_mat;
2723 world_mat.xx = FT_FixedFromFloat( font->matrix.eM11 );
2724 world_mat.xy = -FT_FixedFromFloat( font->matrix.eM21 );
2725 world_mat.yx = -FT_FixedFromFloat( font->matrix.eM12 );
2726 world_mat.yy = FT_FixedFromFloat( font->matrix.eM22 );
2728 for (i = 0; i < 3; i++)
2729 pFT_Matrix_Multiply( &world_mat, &matrices[i] );
2730 needs_transform = TRUE;
2733 /* Extra transformation specified by caller */
2734 if (user_transform)
2736 FT_Matrix user_mat;
2737 user_mat.xx = FT_FixedFromFIXED( user_transform->eM11 );
2738 user_mat.xy = FT_FixedFromFIXED( user_transform->eM21 );
2739 user_mat.yx = FT_FixedFromFIXED( user_transform->eM12 );
2740 user_mat.yy = FT_FixedFromFIXED( user_transform->eM22 );
2742 for (i = 0; i < 3; i++)
2743 pFT_Matrix_Multiply( &user_mat, &matrices[i] );
2744 needs_transform = TRUE;
2747 return needs_transform ? matrices : NULL;
2750 static BOOL get_bold_glyph_outline(FT_GlyphSlot glyph, LONG ppem, FT_Glyph_Metrics *metrics)
2752 FT_Error err;
2753 FT_Pos strength;
2754 FT_BBox bbox;
2756 if(glyph->format != FT_GLYPH_FORMAT_OUTLINE)
2757 return FALSE;
2758 if(!pFT_Outline_Embolden)
2759 return FALSE;
2761 strength = pFT_MulDiv(ppem, 1 << 6, 24);
2762 err = pFT_Outline_Embolden(&glyph->outline, strength);
2763 if(err) {
2764 TRACE("FT_Ouline_Embolden returns %d\n", err);
2765 return FALSE;
2768 pFT_Outline_Get_CBox(&glyph->outline, &bbox);
2769 metrics->width = bbox.xMax - bbox.xMin;
2770 metrics->height = bbox.yMax - bbox.yMin;
2771 metrics->horiBearingX = bbox.xMin;
2772 metrics->horiBearingY = bbox.yMax;
2773 metrics->vertBearingX = metrics->horiBearingX - metrics->horiAdvance / 2;
2774 metrics->vertBearingY = (metrics->vertAdvance - metrics->height) / 2;
2775 return TRUE;
2778 static inline BYTE get_max_level( UINT format )
2780 switch( format )
2782 case GGO_GRAY2_BITMAP: return 4;
2783 case GGO_GRAY4_BITMAP: return 16;
2784 case GGO_GRAY8_BITMAP: return 64;
2786 return 255;
2789 static FT_Vector get_advance_metric( struct gdi_font *font, FT_Pos base_advance,
2790 const FT_Matrix *transMat )
2792 FT_Vector adv;
2793 FT_Fixed em_scale = 0;
2794 BOOL fixed_pitch_full = FALSE;
2795 struct gdi_font *incoming_font = font->base_font ? font->base_font : font;
2797 adv.x = base_advance;
2798 adv.y = 0;
2800 /* In fixed-pitch font, we adjust the fullwidth character advance so that
2801 they have double halfwidth character width. E.g. if the font is 19 ppem,
2802 we return 20 (not 19) for fullwidth characters as we return 10 for
2803 halfwidth characters. */
2804 if (freetype_set_outline_text_metrics(incoming_font) &&
2805 !(incoming_font->otm.otmTextMetrics.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
2806 UINT avg_advance;
2807 em_scale = pFT_MulDiv(incoming_font->ppem, 1 << 16, get_ft_face(incoming_font)->units_per_EM);
2808 avg_advance = pFT_MulFix(incoming_font->ntmAvgWidth, em_scale);
2809 fixed_pitch_full = (avg_advance > 0 &&
2810 (base_advance + 63) >> 6 ==
2811 pFT_MulFix(incoming_font->ntmAvgWidth*2, em_scale));
2812 if (fixed_pitch_full && !transMat)
2813 adv.x = (avg_advance * 2) << 6;
2816 if (transMat) {
2817 pFT_Vector_Transform(&adv, transMat);
2818 if (fixed_pitch_full && adv.y == 0) {
2819 FT_Vector vec;
2820 vec.x = incoming_font->ntmAvgWidth;
2821 vec.y = 0;
2822 pFT_Vector_Transform(&vec, transMat);
2823 adv.x = (pFT_MulFix(vec.x, em_scale) * 2) << 6;
2827 if (font->fake_bold) {
2828 if (!transMat)
2829 adv.x += 1 << 6;
2830 else {
2831 FT_Vector fake_bold_adv, vec = { 1 << 6, 0 };
2832 pFT_Vector_Transform(&vec, transMat);
2833 fake_bold_adv = normalize_vector(&vec);
2834 adv.x += fake_bold_adv.x;
2835 adv.y += fake_bold_adv.y;
2839 adv.x = (adv.x + 63) & -64;
2840 adv.y = -((adv.y + 63) & -64);
2841 return adv;
2844 static FT_BBox get_transformed_bbox( const FT_Glyph_Metrics *metrics, const FT_Matrix *matrices )
2846 FT_BBox bbox = { 0, 0, 0, 0 };
2848 if (!matrices)
2850 bbox.xMin = (metrics->horiBearingX) & -64;
2851 bbox.xMax = (metrics->horiBearingX + metrics->width + 63) & -64;
2852 bbox.yMax = (metrics->horiBearingY + 63) & -64;
2853 bbox.yMin = (metrics->horiBearingY - metrics->height) & -64;
2855 else
2857 FT_Vector vec;
2858 INT xc, yc;
2860 for (xc = 0; xc < 2; xc++)
2862 for (yc = 0; yc < 2; yc++)
2864 vec.x = metrics->horiBearingX + xc * metrics->width;
2865 vec.y = metrics->horiBearingY - yc * metrics->height;
2866 TRACE( "Vec %ld, %ld\n", vec.x, vec.y );
2867 pFT_Vector_Transform( &vec, &matrices[matrix_vert] );
2868 if (xc == 0 && yc == 0)
2870 bbox.xMin = bbox.xMax = vec.x;
2871 bbox.yMin = bbox.yMax = vec.y;
2873 else
2875 if (vec.x < bbox.xMin) bbox.xMin = vec.x;
2876 else if (vec.x > bbox.xMax) bbox.xMax = vec.x;
2877 if (vec.y < bbox.yMin) bbox.yMin = vec.y;
2878 else if (vec.y > bbox.yMax) bbox.yMax = vec.y;
2882 bbox.xMin = bbox.xMin & -64;
2883 bbox.xMax = (bbox.xMax + 63) & -64;
2884 bbox.yMin = bbox.yMin & -64;
2885 bbox.yMax = (bbox.yMax + 63) & -64;
2886 TRACE( "transformed box: (%ld, %ld - %ld, %ld)\n", bbox.xMin, bbox.yMax, bbox.xMax, bbox.yMin );
2889 return bbox;
2892 static void compute_metrics( struct gdi_font *font, FT_BBox bbox, const FT_Glyph_Metrics *metrics,
2893 BOOL vertical, BOOL vertical_metrics, const FT_Matrix *matrices,
2894 GLYPHMETRICS *gm, ABC *abc )
2896 FT_Vector adv, vec, origin;
2897 FT_Fixed base_advance = vertical_metrics ? metrics->vertAdvance : metrics->horiAdvance;
2899 if (!matrices)
2901 adv = get_advance_metric( font, base_advance, NULL );
2902 gm->gmCellIncX = adv.x >> 6;
2903 gm->gmCellIncY = 0;
2904 origin.x = bbox.xMin;
2905 origin.y = bbox.yMax;
2906 abc->abcA = origin.x >> 6;
2907 abc->abcB = (metrics->width + 63) >> 6;
2909 else
2911 FT_Pos lsb;
2913 if (vertical && freetype_set_outline_text_metrics( font ))
2915 if (vertical_metrics)
2916 lsb = metrics->horiBearingY + metrics->vertBearingY;
2917 else
2918 lsb = metrics->vertAdvance + (font->otm.otmDescent << 6);
2919 vec.x = lsb;
2920 vec.y = font->otm.otmDescent << 6;
2921 TRACE( "Vec %ld,%ld\n", vec.x>>6, vec.y>>6 );
2922 pFT_Vector_Transform( &vec, &matrices[matrix_hori] );
2923 origin.x = (vec.x + bbox.xMin) & -64;
2924 origin.y = (vec.y + bbox.yMax + 63) & -64;
2925 lsb -= metrics->horiBearingY;
2927 else
2929 origin.x = bbox.xMin;
2930 origin.y = bbox.yMax;
2931 lsb = metrics->horiBearingX;
2934 adv = get_advance_metric( font, base_advance, &matrices[matrix_hori] );
2935 gm->gmCellIncX = adv.x >> 6;
2936 gm->gmCellIncY = adv.y >> 6;
2938 adv = get_advance_metric( font, base_advance, &matrices[matrix_unrotated] );
2939 adv.x = pFT_Vector_Length( &adv );
2940 adv.y = 0;
2942 vec.x = lsb;
2943 vec.y = 0;
2944 pFT_Vector_Transform( &vec, &matrices[matrix_unrotated] );
2945 if (lsb > 0) abc->abcA = pFT_Vector_Length( &vec ) >> 6;
2946 else abc->abcA = -((pFT_Vector_Length( &vec ) + 63) >> 6);
2948 /* We use lsb again to avoid rounding errors */
2949 vec.x = lsb + (vertical ? metrics->height : metrics->width);
2950 vec.y = 0;
2951 pFT_Vector_Transform( &vec, &matrices[matrix_unrotated] );
2952 abc->abcB = ((pFT_Vector_Length( &vec ) + 63) >> 6) - abc->abcA;
2954 if (!abc->abcB) abc->abcB = 1;
2955 abc->abcC = (adv.x >> 6) - abc->abcA - abc->abcB;
2957 gm->gmptGlyphOrigin.x = origin.x >> 6;
2958 gm->gmptGlyphOrigin.y = origin.y >> 6;
2959 gm->gmBlackBoxX = (bbox.xMax - bbox.xMin) >> 6;
2960 gm->gmBlackBoxY = (bbox.yMax - bbox.yMin) >> 6;
2961 if (!gm->gmBlackBoxX) gm->gmBlackBoxX = 1;
2962 if (!gm->gmBlackBoxY) gm->gmBlackBoxY = 1;
2964 TRACE( "gm: %u, %u, %s, %d, %d abc %d, %u, %d\n",
2965 gm->gmBlackBoxX, gm->gmBlackBoxY, wine_dbgstr_point(&gm->gmptGlyphOrigin),
2966 gm->gmCellIncX, gm->gmCellIncY, abc->abcA, abc->abcB, abc->abcC );
2970 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
2972 static DWORD get_mono_glyph_bitmap( FT_GlyphSlot glyph, FT_BBox bbox,
2973 BOOL fake_bold, const FT_Matrix *matrices,
2974 DWORD buflen, BYTE *buf )
2976 DWORD width = (bbox.xMax - bbox.xMin ) >> 6;
2977 DWORD height = (bbox.yMax - bbox.yMin ) >> 6;
2978 DWORD pitch = ((width + 31) >> 5) << 2;
2979 DWORD needed = pitch * height;
2980 FT_Bitmap ft_bitmap;
2981 BYTE *src, *dst;
2982 INT w, h, x;
2984 if (!buf || !buflen) return needed;
2985 if (!needed) return GDI_ERROR; /* empty glyph */
2986 if (needed > buflen) return GDI_ERROR;
2988 switch (glyph->format)
2990 case FT_GLYPH_FORMAT_BITMAP:
2991 src = glyph->bitmap.buffer;
2992 dst = buf;
2993 w = min( pitch, (glyph->bitmap.width + 7) >> 3 );
2994 h = min( height, glyph->bitmap.rows );
2995 while (h--)
2997 if (!fake_bold)
2998 memcpy( dst, src, w );
2999 else
3001 dst[0] = 0;
3002 for (x = 0; x < w; x++)
3004 dst[x] = (dst[x] & 0x80) | (src[x] >> 1) | src[x];
3005 if (x + 1 < pitch)
3006 dst[x + 1] = (src[x] & 0x01) << 7;
3009 src += glyph->bitmap.pitch;
3010 dst += pitch;
3012 break;
3014 case FT_GLYPH_FORMAT_OUTLINE:
3015 ft_bitmap.width = width;
3016 ft_bitmap.rows = height;
3017 ft_bitmap.pitch = pitch;
3018 ft_bitmap.pixel_mode = FT_PIXEL_MODE_MONO;
3019 ft_bitmap.buffer = buf;
3021 if (matrices)
3022 pFT_Outline_Transform( &glyph->outline, &matrices[matrix_vert] );
3023 pFT_Outline_Translate( &glyph->outline, -bbox.xMin, -bbox.yMin );
3025 /* Note: FreeType will only set 'black' bits for us. */
3026 memset( buf, 0, buflen );
3027 pFT_Outline_Get_Bitmap( library, &glyph->outline, &ft_bitmap );
3028 break;
3030 default:
3031 FIXME( "loaded glyph format %x\n", glyph->format );
3032 return GDI_ERROR;
3035 return needed;
3038 static DWORD get_antialias_glyph_bitmap( FT_GlyphSlot glyph, FT_BBox bbox, UINT format,
3039 BOOL fake_bold, const FT_Matrix *matrices,
3040 DWORD buflen, BYTE *buf )
3042 DWORD width = (bbox.xMax - bbox.xMin ) >> 6;
3043 DWORD height = (bbox.yMax - bbox.yMin ) >> 6;
3044 DWORD pitch = (width + 3) / 4 * 4;
3045 DWORD needed = pitch * height;
3046 FT_Bitmap ft_bitmap;
3047 INT w, h, x, max_level;
3048 BYTE *src, *dst;
3050 if (!buf || !buflen) return needed;
3051 if (!needed) return GDI_ERROR; /* empty glyph */
3052 if (needed > buflen) return GDI_ERROR;
3054 max_level = get_max_level( format );
3056 switch (glyph->format)
3058 case FT_GLYPH_FORMAT_BITMAP:
3059 src = glyph->bitmap.buffer;
3060 dst = buf;
3061 memset( buf, 0, buflen );
3063 w = min( pitch, glyph->bitmap.width );
3064 h = min( height, glyph->bitmap.rows );
3065 while (h--)
3067 for (x = 0; x < w; x++)
3069 if (src[x / 8] & masks[x % 8])
3071 dst[x] = max_level;
3072 if (fake_bold && x + 1 < pitch) dst[x + 1] = max_level;
3075 src += glyph->bitmap.pitch;
3076 dst += pitch;
3078 break;
3080 case FT_GLYPH_FORMAT_OUTLINE:
3081 ft_bitmap.width = width;
3082 ft_bitmap.rows = height;
3083 ft_bitmap.pitch = pitch;
3084 ft_bitmap.pixel_mode = FT_PIXEL_MODE_GRAY;
3085 ft_bitmap.buffer = buf;
3087 if (matrices)
3088 pFT_Outline_Transform( &glyph->outline, &matrices[matrix_vert] );
3089 pFT_Outline_Translate( &glyph->outline, -bbox.xMin, -bbox.yMin );
3091 memset( buf, 0, buflen );
3092 pFT_Outline_Get_Bitmap( library, &glyph->outline, &ft_bitmap );
3094 if (max_level != 255)
3096 INT row, col;
3097 BYTE *ptr, *start;
3099 for (row = 0, start = buf; row < height; row++)
3101 for (col = 0, ptr = start; col < width; col++, ptr++)
3102 *ptr = (((int)*ptr) * (max_level + 1)) / 256;
3103 start += pitch;
3106 break;
3108 default:
3109 FIXME("loaded glyph format %x\n", glyph->format);
3110 return GDI_ERROR;
3113 return needed;
3116 static DWORD get_subpixel_glyph_bitmap( FT_GlyphSlot glyph, FT_BBox bbox, UINT format,
3117 BOOL fake_bold, const FT_Matrix *matrices,
3118 GLYPHMETRICS *gm, DWORD buflen, BYTE *buf )
3120 DWORD width = (bbox.xMax - bbox.xMin ) >> 6;
3121 DWORD height = (bbox.yMax - bbox.yMin ) >> 6;
3122 DWORD pitch, needed = 0;
3123 BYTE *src, *dst;
3124 INT w, h, x;
3126 switch (glyph->format)
3128 case FT_GLYPH_FORMAT_BITMAP:
3129 pitch = width * 4;
3130 needed = pitch * height;
3132 if (!buf || !buflen) break;
3133 if (!needed) return GDI_ERROR; /* empty glyph */
3134 if (needed > buflen) return GDI_ERROR;
3136 src = glyph->bitmap.buffer;
3137 dst = buf;
3138 memset( buf, 0, buflen );
3140 w = min( width, glyph->bitmap.width );
3141 h = min( height, glyph->bitmap.rows );
3142 while (h--)
3144 for (x = 0; x < w; x++)
3146 if ( src[x / 8] & masks[x % 8] )
3148 ((unsigned int *)dst)[x] = ~0u;
3149 if (fake_bold && x + 1 < width) ((unsigned int *)dst)[x + 1] = ~0u;
3152 src += glyph->bitmap.pitch;
3153 dst += pitch;
3155 break;
3157 case FT_GLYPH_FORMAT_OUTLINE:
3159 INT src_pitch, src_width, src_height, x_shift, y_shift;
3160 INT sub_stride, hmul, vmul;
3161 const INT *sub_order;
3162 const INT rgb_order[3] = { 0, 1, 2 };
3163 const INT bgr_order[3] = { 2, 1, 0 };
3164 FT_Render_Mode render_mode =
3165 (format == WINE_GGO_HRGB_BITMAP ||
3166 format == WINE_GGO_HBGR_BITMAP) ? FT_RENDER_MODE_LCD : FT_RENDER_MODE_LCD_V;
3168 if (!width || !height) /* empty glyph */
3170 if (!buf || !buflen) break;
3171 return GDI_ERROR;
3174 if ( render_mode == FT_RENDER_MODE_LCD)
3176 gm->gmBlackBoxX += 2;
3177 gm->gmptGlyphOrigin.x -= 1;
3178 bbox.xMin -= (1 << 6);
3180 else
3182 gm->gmBlackBoxY += 2;
3183 gm->gmptGlyphOrigin.y += 1;
3184 bbox.yMax += (1 << 6);
3187 width = gm->gmBlackBoxX;
3188 height = gm->gmBlackBoxY;
3189 pitch = width * 4;
3190 needed = pitch * height;
3192 if (!buf || !buflen) return needed;
3193 if (needed > buflen) return GDI_ERROR;
3195 if (matrices)
3196 pFT_Outline_Transform( &glyph->outline, &matrices[matrix_vert] );
3198 pFT_Render_Glyph( glyph, render_mode );
3200 src_pitch = glyph->bitmap.pitch;
3201 src_width = glyph->bitmap.width;
3202 src_height = glyph->bitmap.rows;
3203 src = glyph->bitmap.buffer;
3204 dst = buf;
3205 memset( buf, 0, buflen );
3207 sub_order = (format == WINE_GGO_HRGB_BITMAP ||
3208 format == WINE_GGO_VRGB_BITMAP) ? rgb_order : bgr_order;
3209 sub_stride = render_mode == FT_RENDER_MODE_LCD ? 1 : src_pitch;
3210 hmul = render_mode == FT_RENDER_MODE_LCD ? 3 : 1;
3211 vmul = render_mode == FT_RENDER_MODE_LCD ? 1 : 3;
3213 x_shift = glyph->bitmap_left - (bbox.xMin >> 6);
3214 if ( x_shift < 0 )
3216 src += hmul * -x_shift;
3217 src_width -= hmul * -x_shift;
3219 else if ( x_shift > 0 )
3221 dst += x_shift * sizeof(unsigned int);
3222 width -= x_shift;
3225 y_shift = (bbox.yMax >> 6) - glyph->bitmap_top;
3226 if ( y_shift < 0 )
3228 src += src_pitch * vmul * -y_shift;
3229 src_height -= vmul * -y_shift;
3231 else if ( y_shift > 0 )
3233 dst += y_shift * pitch;
3234 height -= y_shift;
3237 w = min( width, src_width / hmul );
3238 h = min( height, src_height / vmul );
3239 while (h--)
3241 for (x = 0; x < w; x++)
3243 ((unsigned int *)dst)[x] =
3244 ((unsigned int)src[hmul * x + sub_stride * sub_order[0]] << 16) |
3245 ((unsigned int)src[hmul * x + sub_stride * sub_order[1]] << 8) |
3246 ((unsigned int)src[hmul * x + sub_stride * sub_order[2]]);
3248 src += src_pitch * vmul;
3249 dst += pitch;
3251 break;
3253 default:
3254 FIXME ( "loaded glyph format %x\n", glyph->format );
3255 return GDI_ERROR;
3258 return needed;
3261 static unsigned int get_native_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
3263 TTPOLYGONHEADER *pph;
3264 TTPOLYCURVE *ppc;
3265 unsigned int needed = 0, point = 0, contour, first_pt;
3266 unsigned int pph_start, cpfx;
3267 DWORD type;
3269 for (contour = 0; contour < outline->n_contours; contour++)
3271 /* Ignore contours containing one point */
3272 if (point == outline->contours[contour])
3274 point++;
3275 continue;
3278 pph_start = needed;
3279 pph = (TTPOLYGONHEADER *)(buf + needed);
3280 first_pt = point;
3281 if (buf)
3283 pph->dwType = TT_POLYGON_TYPE;
3284 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3286 needed += sizeof(*pph);
3287 point++;
3288 while (point <= outline->contours[contour])
3290 ppc = (TTPOLYCURVE *)(buf + needed);
3291 type = outline->tags[point] & FT_Curve_Tag_On ?
3292 TT_PRIM_LINE : TT_PRIM_QSPLINE;
3293 cpfx = 0;
3296 if (buf)
3297 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3298 cpfx++;
3299 point++;
3300 } while (point <= outline->contours[contour] &&
3301 (outline->tags[point] & FT_Curve_Tag_On) ==
3302 (outline->tags[point-1] & FT_Curve_Tag_On));
3303 /* At the end of a contour Windows adds the start point, but
3304 only for Beziers */
3305 if (point > outline->contours[contour] &&
3306 !(outline->tags[point-1] & FT_Curve_Tag_On))
3308 if (buf)
3309 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
3310 cpfx++;
3312 else if (point <= outline->contours[contour] &&
3313 outline->tags[point] & FT_Curve_Tag_On)
3315 /* add closing pt for bezier */
3316 if (buf)
3317 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3318 cpfx++;
3319 point++;
3321 if (buf)
3323 ppc->wType = type;
3324 ppc->cpfx = cpfx;
3326 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3328 if (buf)
3329 pph->cb = needed - pph_start;
3331 return needed;
3334 static unsigned int get_bezier_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
3336 /* Convert the quadratic Beziers to cubic Beziers.
3337 The parametric eqn for a cubic Bezier is, from PLRM:
3338 r(t) = at^3 + bt^2 + ct + r0
3339 with the control points:
3340 r1 = r0 + c/3
3341 r2 = r1 + (c + b)/3
3342 r3 = r0 + c + b + a
3344 A quadratic Bezier has the form:
3345 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3347 So equating powers of t leads to:
3348 r1 = 2/3 p1 + 1/3 p0
3349 r2 = 2/3 p1 + 1/3 p2
3350 and of course r0 = p0, r3 = p2
3352 int contour, point = 0, first_pt;
3353 TTPOLYGONHEADER *pph;
3354 TTPOLYCURVE *ppc;
3355 DWORD pph_start, cpfx, type;
3356 FT_Vector cubic_control[4];
3357 unsigned int needed = 0;
3359 for (contour = 0; contour < outline->n_contours; contour++)
3361 pph_start = needed;
3362 pph = (TTPOLYGONHEADER *)(buf + needed);
3363 first_pt = point;
3364 if (buf)
3366 pph->dwType = TT_POLYGON_TYPE;
3367 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3369 needed += sizeof(*pph);
3370 point++;
3371 while (point <= outline->contours[contour])
3373 ppc = (TTPOLYCURVE *)(buf + needed);
3374 type = outline->tags[point] & FT_Curve_Tag_On ?
3375 TT_PRIM_LINE : TT_PRIM_CSPLINE;
3376 cpfx = 0;
3379 if (type == TT_PRIM_LINE)
3381 if (buf)
3382 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3383 cpfx++;
3384 point++;
3386 else
3388 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
3389 so cpfx = 3n */
3391 /* FIXME: Possible optimization in endpoint calculation
3392 if there are two consecutive curves */
3393 cubic_control[0] = outline->points[point-1];
3394 if (!(outline->tags[point-1] & FT_Curve_Tag_On))
3396 cubic_control[0].x += outline->points[point].x + 1;
3397 cubic_control[0].y += outline->points[point].y + 1;
3398 cubic_control[0].x >>= 1;
3399 cubic_control[0].y >>= 1;
3401 if (point+1 > outline->contours[contour])
3402 cubic_control[3] = outline->points[first_pt];
3403 else
3405 cubic_control[3] = outline->points[point+1];
3406 if (!(outline->tags[point+1] & FT_Curve_Tag_On))
3408 cubic_control[3].x += outline->points[point].x + 1;
3409 cubic_control[3].y += outline->points[point].y + 1;
3410 cubic_control[3].x >>= 1;
3411 cubic_control[3].y >>= 1;
3414 /* r1 = 1/3 p0 + 2/3 p1
3415 r2 = 1/3 p2 + 2/3 p1 */
3416 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
3417 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
3418 cubic_control[2] = cubic_control[1];
3419 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
3420 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
3421 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
3422 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
3423 if (buf)
3425 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
3426 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
3427 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
3429 cpfx += 3;
3430 point++;
3432 } while (point <= outline->contours[contour] &&
3433 (outline->tags[point] & FT_Curve_Tag_On) ==
3434 (outline->tags[point-1] & FT_Curve_Tag_On));
3435 /* At the end of a contour Windows adds the start point,
3436 but only for Beziers and we've already done that.
3438 if (point <= outline->contours[contour] &&
3439 outline->tags[point] & FT_Curve_Tag_On)
3441 /* This is the closing pt of a bezier, but we've already
3442 added it, so just inc point and carry on */
3443 point++;
3445 if (buf)
3447 ppc->wType = type;
3448 ppc->cpfx = cpfx;
3450 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3452 if (buf)
3453 pph->cb = needed - pph_start;
3455 return needed;
3458 static FT_Int get_load_flags( UINT format )
3460 FT_Int load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
3462 if (format & GGO_UNHINTED)
3463 return load_flags | FT_LOAD_NO_HINTING;
3465 switch (format & ~GGO_GLYPH_INDEX)
3467 case GGO_BITMAP:
3468 load_flags |= FT_LOAD_TARGET_MONO;
3469 break;
3470 case GGO_GRAY2_BITMAP:
3471 case GGO_GRAY4_BITMAP:
3472 case GGO_GRAY8_BITMAP:
3473 case WINE_GGO_GRAY16_BITMAP:
3474 load_flags |= FT_LOAD_TARGET_NORMAL;
3475 break;
3476 case WINE_GGO_HRGB_BITMAP:
3477 case WINE_GGO_HBGR_BITMAP:
3478 load_flags |= FT_LOAD_TARGET_LCD;
3479 break;
3480 case WINE_GGO_VRGB_BITMAP:
3481 case WINE_GGO_VBGR_BITMAP:
3482 load_flags |= FT_LOAD_TARGET_LCD_V;
3483 break;
3486 return load_flags;
3489 /*************************************************************
3490 * freetype_get_glyph_outline
3492 static DWORD CDECL freetype_get_glyph_outline( struct gdi_font *font, UINT glyph, UINT format,
3493 GLYPHMETRICS *lpgm, ABC *abc, DWORD buflen, void *buf,
3494 const MAT2 *lpmat, BOOL tategaki )
3496 struct gdi_font *base_font = font->base_font ? font->base_font : font;
3497 FT_Face ft_face = get_ft_face( font );
3498 FT_Glyph_Metrics metrics;
3499 FT_Error err;
3500 FT_BBox bbox;
3501 FT_Int load_flags = get_load_flags(format);
3502 FT_Matrix transform_matrices[3], *matrices = NULL;
3503 BOOL vertical_metrics;
3505 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm, buflen, buf, lpmat);
3507 TRACE("font transform %f %f %f %f\n",
3508 font->matrix.eM11, font->matrix.eM12,
3509 font->matrix.eM21, font->matrix.eM22);
3511 format &= ~GGO_UNHINTED;
3513 matrices = get_transform_matrices( font, tategaki, lpmat, transform_matrices );
3515 vertical_metrics = (tategaki && FT_HAS_VERTICAL(ft_face));
3516 /* there is a freetype bug where vertical metrics are only
3517 properly scaled and correct in 2.4.0 or greater */
3518 if (vertical_metrics && FT_SimpleVersion < FT_VERSION_VALUE(2, 4, 0))
3519 vertical_metrics = FALSE;
3521 if (matrices || format != GGO_BITMAP) load_flags |= FT_LOAD_NO_BITMAP;
3522 if (vertical_metrics) load_flags |= FT_LOAD_VERTICAL_LAYOUT;
3524 err = pFT_Load_Glyph(ft_face, glyph, load_flags);
3525 if (err && !(load_flags & FT_LOAD_NO_HINTING))
3527 WARN("Failed to load glyph %#x, retrying without hinting. Error %#x.\n", glyph, err);
3528 load_flags |= FT_LOAD_NO_HINTING;
3529 err = pFT_Load_Glyph(ft_face, glyph, load_flags);
3532 if(err) {
3533 WARN("Failed to load glyph %#x, error %#x.\n", glyph, err);
3534 return GDI_ERROR;
3537 metrics = ft_face->glyph->metrics;
3538 if(font->fake_bold) {
3539 if (!get_bold_glyph_outline(ft_face->glyph, font->ppem, &metrics) && metrics.width)
3540 metrics.width += 1 << 6;
3543 /* Some poorly-created fonts contain glyphs that exceed the boundaries set
3544 * by the text metrics. The proper behavior is to clip the glyph metrics to
3545 * fit within the maximums specified in the text metrics. */
3546 if (freetype_set_outline_text_metrics(base_font) ||
3547 freetype_set_bitmap_text_metrics(base_font)) {
3548 TEXTMETRICW *ptm = &base_font->otm.otmTextMetrics;
3549 INT top = min( metrics.horiBearingY, ptm->tmAscent << 6 );
3550 INT bottom = max( metrics.horiBearingY - metrics.height, -(ptm->tmDescent << 6) );
3551 metrics.horiBearingY = top;
3552 metrics.height = top - bottom;
3554 /* TODO: Are we supposed to clip the width as well...? */
3555 /* metrics.width = min( metrics.width, ptm->tmMaxCharWidth << 6 ); */
3558 bbox = get_transformed_bbox( &metrics, matrices );
3559 compute_metrics( font, bbox, &metrics, tategaki, vertical_metrics, matrices, lpgm, abc );
3561 switch (format)
3563 case GGO_METRICS:
3564 return 1; /* FIXME */
3566 case GGO_BITMAP:
3567 return get_mono_glyph_bitmap( ft_face->glyph, bbox, font->fake_bold,
3568 matrices, buflen, buf );
3570 case GGO_GRAY2_BITMAP:
3571 case GGO_GRAY4_BITMAP:
3572 case GGO_GRAY8_BITMAP:
3573 case WINE_GGO_GRAY16_BITMAP:
3574 return get_antialias_glyph_bitmap( ft_face->glyph, bbox, format, font->fake_bold,
3575 matrices, buflen, buf );
3577 case WINE_GGO_HRGB_BITMAP:
3578 case WINE_GGO_HBGR_BITMAP:
3579 case WINE_GGO_VRGB_BITMAP:
3580 case WINE_GGO_VBGR_BITMAP:
3581 return get_subpixel_glyph_bitmap( ft_face->glyph, bbox, format, font->fake_bold,
3582 matrices, lpgm, buflen, buf );
3584 case GGO_NATIVE:
3585 if (ft_face->glyph->format == ft_glyph_format_outline)
3587 FT_Outline *outline = &ft_face->glyph->outline;
3588 UINT needed;
3590 if (buflen == 0) buf = NULL;
3592 if (matrices && buf)
3593 pFT_Outline_Transform( outline, &matrices[matrix_vert] );
3595 needed = get_native_glyph_outline(outline, buflen, NULL);
3597 if (!buf || !buflen) return needed;
3598 if (needed > buflen) return GDI_ERROR;
3599 return get_native_glyph_outline(outline, buflen, buf);
3601 TRACE("loaded a bitmap\n");
3602 return GDI_ERROR;
3604 case GGO_BEZIER:
3605 if (ft_face->glyph->format == ft_glyph_format_outline)
3607 FT_Outline *outline = &ft_face->glyph->outline;
3608 UINT needed;
3610 if (buflen == 0) buf = NULL;
3612 if (matrices && buf)
3613 pFT_Outline_Transform( outline, &matrices[matrix_vert] );
3615 needed = get_bezier_glyph_outline(outline, buflen, NULL);
3617 if (!buf || !buflen) return needed;
3618 if (needed > buflen) return GDI_ERROR;
3619 return get_bezier_glyph_outline(outline, buflen, buf);
3621 TRACE("loaded a bitmap\n");
3622 return GDI_ERROR;
3624 default:
3625 FIXME("Unsupported format %d\n", format);
3626 return GDI_ERROR;
3630 /*************************************************************
3631 * freetype_set_bitmap_text_metrics
3633 static BOOL CDECL freetype_set_bitmap_text_metrics( struct gdi_font *font )
3635 FT_Face ft_face = get_ft_face( font );
3636 FT_WinFNT_HeaderRec winfnt_header;
3638 if (font->otm.otmSize) return TRUE; /* already set */
3639 font->otm.otmSize = offsetof( OUTLINETEXTMETRICW, otmFiller );
3641 #define TM font->otm.otmTextMetrics
3642 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
3644 TM.tmHeight = winfnt_header.pixel_height;
3645 TM.tmAscent = winfnt_header.ascent;
3646 TM.tmDescent = TM.tmHeight - TM.tmAscent;
3647 TM.tmInternalLeading = winfnt_header.internal_leading;
3648 TM.tmExternalLeading = winfnt_header.external_leading;
3649 TM.tmAveCharWidth = winfnt_header.avg_width;
3650 TM.tmMaxCharWidth = winfnt_header.max_width;
3651 TM.tmWeight = winfnt_header.weight;
3652 TM.tmOverhang = 0;
3653 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
3654 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
3655 TM.tmFirstChar = winfnt_header.first_char;
3656 TM.tmLastChar = winfnt_header.last_char;
3657 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
3658 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
3659 TM.tmItalic = winfnt_header.italic;
3660 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
3661 TM.tmCharSet = winfnt_header.charset;
3663 else
3665 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
3666 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
3667 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3668 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
3669 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
3670 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
3671 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
3672 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
3673 TM.tmOverhang = 0;
3674 TM.tmDigitizedAspectX = 96; /* FIXME */
3675 TM.tmDigitizedAspectY = 96; /* FIXME */
3676 TM.tmFirstChar = 1;
3677 TM.tmLastChar = 255;
3678 TM.tmDefaultChar = 32;
3679 TM.tmBreakChar = 32;
3680 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
3681 /* NB inverted meaning of TMPF_FIXED_PITCH */
3682 TM.tmPitchAndFamily = FT_IS_FIXED_WIDTH(ft_face) ? 0 : TMPF_FIXED_PITCH;
3683 TM.tmCharSet = font->charset;
3685 TM.tmUnderlined = font->lf.lfUnderline ? 0xff : 0;
3686 TM.tmStruckOut = font->lf.lfStrikeOut ? 0xff : 0;
3688 if(font->fake_bold)
3689 TM.tmWeight = FW_BOLD;
3690 #undef TM
3692 return TRUE;
3696 static BOOL face_has_symbol_charmap(FT_Face ft_face)
3698 int i;
3700 for(i = 0; i < ft_face->num_charmaps; i++)
3702 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
3703 return TRUE;
3705 return FALSE;
3708 /*************************************************************
3709 * freetype_set_outline_text_metrics
3711 static BOOL CDECL freetype_set_outline_text_metrics( struct gdi_font *font )
3713 FT_Face ft_face = get_ft_face( font );
3714 UINT needed;
3715 TT_OS2 *pOS2;
3716 TT_HoriHeader *pHori;
3717 TT_Postscript *pPost;
3718 FT_Fixed em_scale;
3719 INT ascent, descent;
3720 USHORT windescent;
3722 TRACE("font=%p\n", font);
3724 if (!font->scalable) return FALSE;
3725 if (font->otm.otmSize) return TRUE; /* already set */
3727 /* note: we store actual pointers in the names instead of offsets,
3728 they are fixed up when returned to the app */
3729 if (!(font->otm.otmpFullName = (char *)get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, system_lcid )))
3731 static const WCHAR fake_nameW[] = {'f','a','k','e',' ','n','a','m','e', 0};
3732 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w((WCHAR *)font->otm.otmpFamilyName));
3733 font->otm.otmpFullName = (char *)strdupW(fake_nameW);
3735 needed = sizeof(font->otm) + (lstrlenW( (WCHAR *)font->otm.otmpFamilyName ) + 1 +
3736 lstrlenW( (WCHAR *)font->otm.otmpStyleName ) + 1 +
3737 lstrlenW( (WCHAR *)font->otm.otmpFaceName ) + 1 +
3738 lstrlenW( (WCHAR *)font->otm.otmpFullName ) + 1) * sizeof(WCHAR);
3740 em_scale = (FT_Fixed)pFT_MulDiv(font->ppem, 1 << 16, ft_face->units_per_EM);
3742 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3743 if(!pOS2) {
3744 FIXME("Can't find OS/2 table - not TT font?\n");
3745 return FALSE;
3748 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3749 if(!pHori) {
3750 FIXME("Can't find HHEA table - not TT font?\n");
3751 return FALSE;
3754 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
3756 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",
3757 pOS2->usWinAscent, pOS2->usWinDescent,
3758 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
3759 pOS2->xAvgCharWidth,
3760 ft_face->ascender, ft_face->descender, ft_face->height,
3761 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
3762 ft_face->bbox.yMax, ft_face->bbox.yMin);
3764 font->otm.otmSize = needed;
3766 #define TM font->otm.otmTextMetrics
3768 windescent = get_fixed_windescent(pOS2->usWinDescent);
3769 if(pOS2->usWinAscent + windescent == 0) {
3770 ascent = pHori->Ascender;
3771 descent = -pHori->Descender;
3772 } else {
3773 ascent = pOS2->usWinAscent;
3774 descent = windescent;
3777 font->ntmAvgWidth = pOS2->xAvgCharWidth;
3779 #define SCALE_X(x) (pFT_MulFix(x, em_scale))
3780 #define SCALE_Y(y) (pFT_MulFix(y, em_scale))
3782 if(font->yMax) {
3783 TM.tmAscent = font->yMax;
3784 TM.tmDescent = -font->yMin;
3785 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
3786 } else {
3787 TM.tmAscent = SCALE_Y(ascent);
3788 TM.tmDescent = SCALE_Y(descent);
3789 TM.tmInternalLeading = SCALE_Y(ascent + descent - ft_face->units_per_EM);
3792 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3794 /* MSDN says:
3795 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
3797 TM.tmExternalLeading = max(0, SCALE_Y(pHori->Line_Gap -
3798 ((ascent + descent) -
3799 (pHori->Ascender - pHori->Descender))));
3801 TM.tmAveCharWidth = SCALE_X(pOS2->xAvgCharWidth);
3802 if (TM.tmAveCharWidth == 0) {
3803 TM.tmAveCharWidth = 1;
3805 TM.tmMaxCharWidth = SCALE_X(ft_face->bbox.xMax - ft_face->bbox.xMin);
3806 TM.tmWeight = FW_REGULAR;
3807 if (font->fake_bold)
3808 TM.tmWeight = FW_BOLD;
3809 else
3811 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
3813 if (pOS2->usWeightClass > FW_MEDIUM)
3814 TM.tmWeight = pOS2->usWeightClass;
3816 else if (pOS2->usWeightClass <= FW_MEDIUM)
3817 TM.tmWeight = pOS2->usWeightClass;
3819 TM.tmOverhang = 0;
3820 TM.tmDigitizedAspectX = 96; /* FIXME */
3821 TM.tmDigitizedAspectY = 96; /* FIXME */
3822 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
3823 * symbol range to 0 - f0ff
3826 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
3828 TM.tmFirstChar = 0;
3829 switch (PRIMARYLANGID(system_lcid))
3831 case LANG_HEBREW:
3832 TM.tmLastChar = 0xf896;
3833 break;
3834 case LANG_ESTONIAN:
3835 case LANG_LATVIAN:
3836 case LANG_LITHUANIAN:
3837 TM.tmLastChar = 0xf8fd;
3838 break;
3839 default:
3840 TM.tmLastChar = 0xf0ff;
3842 TM.tmBreakChar = 0x20;
3843 TM.tmDefaultChar = 0x1f;
3845 else
3847 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
3848 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
3850 if(pOS2->usFirstCharIndex <= 1)
3851 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
3852 else if (pOS2->usFirstCharIndex > 0xff)
3853 TM.tmBreakChar = 0x20;
3854 else
3855 TM.tmBreakChar = pOS2->usFirstCharIndex;
3856 TM.tmDefaultChar = TM.tmBreakChar - 1;
3858 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
3859 TM.tmUnderlined = font->lf.lfUnderline ? 255 : 0;
3860 TM.tmStruckOut = font->lf.lfStrikeOut ? 255 : 0;
3862 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
3863 if(!FT_IS_FIXED_WIDTH(ft_face) &&
3864 (pOS2->version == 0xFFFFU ||
3865 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
3866 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
3867 else
3868 TM.tmPitchAndFamily = 0;
3870 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
3872 case PAN_FAMILY_SCRIPT:
3873 TM.tmPitchAndFamily |= FF_SCRIPT;
3874 break;
3876 case PAN_FAMILY_DECORATIVE:
3877 TM.tmPitchAndFamily |= FF_DECORATIVE;
3878 break;
3880 case PAN_ANY:
3881 case PAN_NO_FIT:
3882 case PAN_FAMILY_TEXT_DISPLAY:
3883 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
3884 /* which is clearly not what the panose spec says. */
3885 default:
3886 if(TM.tmPitchAndFamily == 0 || /* fixed */
3887 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
3888 TM.tmPitchAndFamily = FF_MODERN;
3889 else
3891 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
3893 case PAN_ANY:
3894 case PAN_NO_FIT:
3895 default:
3896 TM.tmPitchAndFamily |= FF_DONTCARE;
3897 break;
3899 case PAN_SERIF_COVE:
3900 case PAN_SERIF_OBTUSE_COVE:
3901 case PAN_SERIF_SQUARE_COVE:
3902 case PAN_SERIF_OBTUSE_SQUARE_COVE:
3903 case PAN_SERIF_SQUARE:
3904 case PAN_SERIF_THIN:
3905 case PAN_SERIF_BONE:
3906 case PAN_SERIF_EXAGGERATED:
3907 case PAN_SERIF_TRIANGLE:
3908 TM.tmPitchAndFamily |= FF_ROMAN;
3909 break;
3911 case PAN_SERIF_NORMAL_SANS:
3912 case PAN_SERIF_OBTUSE_SANS:
3913 case PAN_SERIF_PERP_SANS:
3914 case PAN_SERIF_FLARED:
3915 case PAN_SERIF_ROUNDED:
3916 TM.tmPitchAndFamily |= FF_SWISS;
3917 break;
3920 break;
3923 if(FT_IS_SCALABLE(ft_face))
3924 TM.tmPitchAndFamily |= TMPF_VECTOR;
3926 if(FT_IS_SFNT(ft_face))
3928 if (font->ntmFlags & NTM_PS_OPENTYPE)
3929 TM.tmPitchAndFamily |= TMPF_DEVICE;
3930 else
3931 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
3934 TM.tmCharSet = font->charset;
3936 font->otm.otmFiller = 0;
3937 memcpy(&font->otm.otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
3938 font->otm.otmfsSelection = pOS2->fsSelection;
3939 if (font->fake_italic)
3940 font->otm.otmfsSelection |= 1;
3941 if (font->fake_bold)
3942 font->otm.otmfsSelection |= 1 << 5;
3943 /* Only return valid bits that define embedding and subsetting restrictions */
3944 font->otm.otmfsType = pOS2->fsType & 0x30e;
3945 font->otm.otmsCharSlopeRise = pHori->caret_Slope_Rise;
3946 font->otm.otmsCharSlopeRun = pHori->caret_Slope_Run;
3947 font->otm.otmItalicAngle = 0; /* POST table */
3948 font->otm.otmAscent = SCALE_Y(pOS2->sTypoAscender);
3949 font->otm.otmDescent = SCALE_Y(pOS2->sTypoDescender);
3950 font->otm.otmLineGap = SCALE_Y(pOS2->sTypoLineGap);
3951 font->otm.otmsCapEmHeight = SCALE_Y(pOS2->sCapHeight);
3952 font->otm.otmsXHeight = SCALE_Y(pOS2->sxHeight);
3953 font->otm.otmrcFontBox.left = SCALE_X(ft_face->bbox.xMin);
3954 font->otm.otmrcFontBox.right = SCALE_X(ft_face->bbox.xMax);
3955 font->otm.otmrcFontBox.top = SCALE_Y(ft_face->bbox.yMax);
3956 font->otm.otmrcFontBox.bottom = SCALE_Y(ft_face->bbox.yMin);
3957 font->otm.otmMacAscent = TM.tmAscent;
3958 font->otm.otmMacDescent = -TM.tmDescent;
3959 font->otm.otmMacLineGap = SCALE_Y(pHori->Line_Gap);
3960 font->otm.otmusMinimumPPEM = 0; /* TT Header */
3961 font->otm.otmptSubscriptSize.x = SCALE_X(pOS2->ySubscriptXSize);
3962 font->otm.otmptSubscriptSize.y = SCALE_Y(pOS2->ySubscriptYSize);
3963 font->otm.otmptSubscriptOffset.x = SCALE_X(pOS2->ySubscriptXOffset);
3964 font->otm.otmptSubscriptOffset.y = SCALE_Y(pOS2->ySubscriptYOffset);
3965 font->otm.otmptSuperscriptSize.x = SCALE_X(pOS2->ySuperscriptXSize);
3966 font->otm.otmptSuperscriptSize.y = SCALE_Y(pOS2->ySuperscriptYSize);
3967 font->otm.otmptSuperscriptOffset.x = SCALE_X(pOS2->ySuperscriptXOffset);
3968 font->otm.otmptSuperscriptOffset.y = SCALE_Y(pOS2->ySuperscriptYOffset);
3969 font->otm.otmsStrikeoutSize = SCALE_Y(pOS2->yStrikeoutSize);
3970 font->otm.otmsStrikeoutPosition = SCALE_Y(pOS2->yStrikeoutPosition);
3971 if(!pPost) {
3972 font->otm.otmsUnderscoreSize = 0;
3973 font->otm.otmsUnderscorePosition = 0;
3974 } else {
3975 font->otm.otmsUnderscoreSize = SCALE_Y(pPost->underlineThickness);
3976 font->otm.otmsUnderscorePosition = SCALE_Y(pPost->underlinePosition);
3978 #undef SCALE_X
3979 #undef SCALE_Y
3980 #undef TM
3981 return TRUE;
3984 /*************************************************************
3985 * freetype_get_char_width_info
3987 static BOOL CDECL freetype_get_char_width_info( struct gdi_font *font, struct char_width_info *info )
3989 FT_Face ft_face = get_ft_face( font );
3990 TT_HoriHeader *pHori;
3992 TRACE("%p, %p\n", font, info);
3994 if ((pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea)))
3996 FT_Fixed em_scale = pFT_MulDiv(font->ppem, 1 << 16, ft_face->units_per_EM);
3997 info->lsb = (SHORT)pFT_MulFix(pHori->min_Left_Side_Bearing, em_scale);
3998 info->rsb = (SHORT)pFT_MulFix(pHori->min_Right_Side_Bearing, em_scale);
3999 return TRUE;
4001 return FALSE;
4005 /*************************************************************
4006 * freetype_get_unicode_ranges
4008 * Retrieve a list of supported Unicode ranges for a given font.
4009 * Can be called with NULL gs to calculate the buffer size. Returns
4010 * the number of ranges found.
4012 static DWORD CDECL freetype_get_unicode_ranges( struct gdi_font *font, GLYPHSET *gs )
4014 FT_Face ft_face = get_ft_face( font );
4015 DWORD num_ranges = 0;
4017 if (ft_face->charmap->encoding == FT_ENCODING_UNICODE)
4019 FT_UInt glyph_code;
4020 FT_ULong char_code, char_code_prev;
4022 glyph_code = 0;
4023 char_code_prev = char_code = pFT_Get_First_Char(ft_face, &glyph_code);
4025 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
4026 ft_face->num_glyphs, glyph_code, char_code);
4028 if (!glyph_code) return 0;
4030 if (gs)
4032 gs->ranges[0].wcLow = (USHORT)char_code;
4033 gs->ranges[0].cGlyphs = 0;
4034 gs->cGlyphsSupported = 0;
4037 num_ranges = 1;
4038 while (glyph_code)
4040 if (char_code < char_code_prev)
4042 ERR("expected increasing char code from FT_Get_Next_Char\n");
4043 return 0;
4045 if (char_code - char_code_prev > 1)
4047 num_ranges++;
4048 if (gs)
4050 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
4051 gs->ranges[num_ranges - 1].cGlyphs = 1;
4052 gs->cGlyphsSupported++;
4055 else if (gs)
4057 gs->ranges[num_ranges - 1].cGlyphs++;
4058 gs->cGlyphsSupported++;
4060 char_code_prev = char_code;
4061 char_code = pFT_Get_Next_Char(ft_face, char_code, &glyph_code);
4064 else
4066 DWORD encoding = RtlUlongByteSwap(ft_face->charmap->encoding);
4067 FIXME("encoding %s not supported\n", debugstr_an((char *)&encoding, 4));
4070 return num_ranges;
4073 /*************************************************************************
4074 * Kerning support for TrueType fonts
4077 struct TT_kern_table
4079 USHORT version;
4080 USHORT nTables;
4083 struct TT_kern_subtable
4085 USHORT version;
4086 USHORT length;
4087 union
4089 USHORT word;
4090 struct
4092 USHORT horizontal : 1;
4093 USHORT minimum : 1;
4094 USHORT cross_stream: 1;
4095 USHORT override : 1;
4096 USHORT reserved1 : 4;
4097 USHORT format : 8;
4098 } bits;
4099 } coverage;
4102 struct TT_format0_kern_subtable
4104 USHORT nPairs;
4105 USHORT searchRange;
4106 USHORT entrySelector;
4107 USHORT rangeShift;
4110 struct TT_kern_pair
4112 USHORT left;
4113 USHORT right;
4114 short value;
4117 static DWORD parse_format0_kern_subtable(struct gdi_font *font,
4118 const struct TT_format0_kern_subtable *tt_f0_ks,
4119 const USHORT *glyph_to_char,
4120 KERNINGPAIR *kern_pair, DWORD cPairs)
4122 FT_Face ft_face = get_ft_face( font );
4123 USHORT i, nPairs;
4124 const struct TT_kern_pair *tt_kern_pair;
4126 TRACE("font height %d, units_per_EM %d\n", font->ppem, ft_face->units_per_EM);
4128 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
4130 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
4131 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
4132 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
4134 if (!kern_pair || !cPairs)
4135 return nPairs;
4137 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
4139 nPairs = min(nPairs, cPairs);
4141 for (i = 0; i < nPairs; i++)
4143 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
4144 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
4145 /* this algorithm appears to better match what Windows does */
4146 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
4147 if (kern_pair->iKernAmount < 0)
4149 kern_pair->iKernAmount -= ft_face->units_per_EM / 2;
4150 kern_pair->iKernAmount -= font->ppem;
4152 else if (kern_pair->iKernAmount > 0)
4154 kern_pair->iKernAmount += ft_face->units_per_EM / 2;
4155 kern_pair->iKernAmount += font->ppem;
4157 kern_pair->iKernAmount /= ft_face->units_per_EM;
4159 TRACE("left %u right %u value %d\n",
4160 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
4162 kern_pair++;
4164 TRACE("copied %u entries\n", nPairs);
4165 return nPairs;
4168 /*************************************************************
4169 * freetype_get_kerning_pairs
4171 static DWORD CDECL freetype_get_kerning_pairs( struct gdi_font *font, KERNINGPAIR **pairs )
4173 FT_Face ft_face = get_ft_face( font );
4174 DWORD length, count = 0;
4175 void *buf;
4176 const struct TT_kern_table *tt_kern_table;
4177 const struct TT_kern_subtable *tt_kern_subtable;
4178 USHORT i, nTables;
4179 USHORT *glyph_to_char;
4181 length = freetype_get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
4183 if (length == GDI_ERROR)
4185 TRACE("no kerning data in the font\n");
4186 return 0;
4189 buf = RtlAllocateHeap(GetProcessHeap(), 0, length);
4190 if (!buf) return 0;
4192 freetype_get_font_data(font, MS_KERN_TAG, 0, buf, length);
4194 /* build a glyph index to char code map */
4195 glyph_to_char = RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
4196 if (!glyph_to_char)
4198 RtlFreeHeap(GetProcessHeap(), 0, buf);
4199 return 0;
4202 if (ft_face->charmap->encoding == FT_ENCODING_UNICODE)
4204 FT_UInt glyph_code;
4205 FT_ULong char_code;
4207 glyph_code = 0;
4208 char_code = pFT_Get_First_Char(ft_face, &glyph_code);
4210 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
4211 ft_face->num_glyphs, glyph_code, char_code);
4213 while (glyph_code)
4215 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
4217 /* FIXME: This doesn't match what Windows does: it does some fancy
4218 * things with duplicate glyph index to char code mappings, while
4219 * we just avoid overriding existing entries.
4221 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
4222 glyph_to_char[glyph_code] = (USHORT)char_code;
4224 char_code = pFT_Get_Next_Char(ft_face, char_code, &glyph_code);
4227 else
4229 DWORD encoding = RtlUlongByteSwap(ft_face->charmap->encoding);
4230 ULONG n;
4232 FIXME("encoding %s not supported\n", debugstr_an((char *)&encoding, 4));
4233 for (n = 0; n <= 65535; n++)
4234 glyph_to_char[n] = (USHORT)n;
4237 tt_kern_table = buf;
4238 nTables = GET_BE_WORD(tt_kern_table->nTables);
4239 TRACE("version %u, nTables %u\n",
4240 GET_BE_WORD(tt_kern_table->version), nTables);
4242 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
4244 for (i = 0; i < nTables; i++)
4246 struct TT_kern_subtable tt_kern_subtable_copy;
4248 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
4249 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
4250 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
4252 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
4253 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
4254 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
4256 /* According to the TrueType specification this is the only format
4257 * that will be properly interpreted by Windows and OS/2
4259 if (tt_kern_subtable_copy.coverage.bits.format == 0)
4261 DWORD new_chunk, old_total = count;
4263 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
4264 glyph_to_char, NULL, 0);
4265 count += new_chunk;
4267 if (!*pairs)
4268 *pairs = RtlAllocateHeap(GetProcessHeap(), 0, count * sizeof(**pairs));
4269 else
4270 *pairs = RtlReAllocateHeap(GetProcessHeap(), 0, *pairs, count * sizeof(**pairs));
4272 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
4273 glyph_to_char, *pairs + old_total, new_chunk);
4275 else
4276 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
4278 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
4281 RtlFreeHeap(GetProcessHeap(), 0, glyph_to_char);
4282 RtlFreeHeap(GetProcessHeap(), 0, buf);
4283 return count;
4286 static const struct font_backend_funcs font_funcs =
4288 freetype_load_fonts,
4289 fontconfig_enum_family_fallbacks,
4290 freetype_add_font,
4291 freetype_add_mem_font,
4292 freetype_load_font,
4293 freetype_get_font_data,
4294 freetype_get_aa_flags,
4295 freetype_get_glyph_index,
4296 freetype_get_default_glyph,
4297 freetype_get_glyph_outline,
4298 freetype_get_unicode_ranges,
4299 freetype_get_char_width_info,
4300 freetype_set_outline_text_metrics,
4301 freetype_set_bitmap_text_metrics,
4302 freetype_get_kerning_pairs,
4303 freetype_destroy_font
4306 static NTSTATUS init_freetype_lib( HMODULE module, DWORD reason, const void *ptr_in, void *ptr_out )
4308 callback_funcs = ptr_in;
4309 if (!init_freetype()) return STATUS_DLL_NOT_FOUND;
4310 #ifdef SONAME_LIBFONTCONFIG
4311 init_fontconfig();
4312 #endif
4313 NtQueryDefaultLocale( FALSE, &system_lcid );
4314 *(const struct font_backend_funcs **)ptr_out = &font_funcs;
4315 return STATUS_SUCCESS;
4318 #else /* HAVE_FREETYPE */
4320 static NTSTATUS init_freetype_lib( HMODULE module, DWORD reason, const void *ptr_in, void *ptr_out )
4322 return STATUS_DLL_NOT_FOUND;
4325 #endif /* HAVE_FREETYPE */
4327 NTSTATUS CDECL __wine_init_unix_lib( HMODULE module, DWORD reason, const void *ptr_in, void *ptr_out )
4329 if (reason != DLL_PROCESS_ATTACH) return STATUS_SUCCESS;
4331 if (ptr_in) return init_freetype_lib( module, reason, ptr_in, ptr_out );
4332 else return init_opengl_lib( module, reason, ptr_in, ptr_out );