gdi32: Ignore Type 1 fonts in fontconfig enumeration.
[wine.git] / dlls / gdi32 / freetype.c
blob1722f0c746c70c40198fb6962237e40e48070701
1 /*
2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
5 * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
7 * This file contains the WineEng* functions.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #if 0
25 #pragma makedep unix
26 #endif
28 #include "config.h"
29 #include "wine/port.h"
31 #include <stdarg.h>
32 #include <stdlib.h>
33 #ifdef HAVE_SYS_STAT_H
34 # include <sys/stat.h>
35 #endif
36 #ifdef HAVE_SYS_MMAN_H
37 # include <sys/mman.h>
38 #endif
39 #include <string.h>
40 #ifdef HAVE_DIRENT_H
41 # include <dirent.h>
42 #endif
43 #include <stdio.h>
44 #include <assert.h>
46 #ifdef HAVE_CARBON_CARBON_H
47 #define LoadResource __carbon_LoadResource
48 #define CompareString __carbon_CompareString
49 #define GetCurrentThread __carbon_GetCurrentThread
50 #define GetCurrentProcess __carbon_GetCurrentProcess
51 #define AnimatePalette __carbon_AnimatePalette
52 #define EqualRgn __carbon_EqualRgn
53 #define FillRgn __carbon_FillRgn
54 #define FrameRgn __carbon_FrameRgn
55 #define GetPixel __carbon_GetPixel
56 #define InvertRgn __carbon_InvertRgn
57 #define LineTo __carbon_LineTo
58 #define OffsetRgn __carbon_OffsetRgn
59 #define PaintRgn __carbon_PaintRgn
60 #define Polygon __carbon_Polygon
61 #define ResizePalette __carbon_ResizePalette
62 #define SetRectRgn __carbon_SetRectRgn
63 #include <Carbon/Carbon.h>
64 #undef LoadResource
65 #undef CompareString
66 #undef GetCurrentThread
67 #undef _CDECL
68 #undef GetCurrentProcess
69 #undef AnimatePalette
70 #undef EqualRgn
71 #undef FillRgn
72 #undef FrameRgn
73 #undef GetPixel
74 #undef InvertRgn
75 #undef LineTo
76 #undef OffsetRgn
77 #undef PaintRgn
78 #undef Polygon
79 #undef ResizePalette
80 #undef SetRectRgn
81 #endif /* HAVE_CARBON_CARBON_H */
83 #ifdef HAVE_FT2BUILD_H
84 #include <ft2build.h>
85 #include FT_FREETYPE_H
86 #include FT_GLYPH_H
87 #include FT_TYPES_H
88 #include FT_TRUETYPE_TABLES_H
89 #include FT_SFNT_NAMES_H
90 #include FT_TRUETYPE_IDS_H
91 #include FT_OUTLINE_H
92 #include FT_TRIGONOMETRY_H
93 #include FT_MODULE_H
94 #include FT_WINFONTS_H
95 #ifdef FT_LCD_FILTER_H
96 #include FT_LCD_FILTER_H
97 #endif
98 #endif /* HAVE_FT2BUILD_H */
100 #include "ntstatus.h"
101 #define WIN32_NO_STATUS
102 #include "windef.h"
103 #include "winbase.h"
104 #include "winternl.h"
105 #include "winerror.h"
106 #include "winreg.h"
107 #include "wingdi.h"
108 #include "gdi_private.h"
109 #include "wine/debug.h"
110 #include "wine/list.h"
112 #include "resource.h"
114 #ifdef HAVE_FREETYPE
116 WINE_DEFAULT_DEBUG_CHANNEL(font);
118 #ifndef HAVE_FT_TRUETYPEENGINETYPE
119 typedef enum
121 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
122 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
123 FT_TRUETYPE_ENGINE_TYPE_PATENTED
124 } FT_TrueTypeEngineType;
125 #endif
127 static FT_Library library = 0;
128 typedef struct
130 FT_Int major;
131 FT_Int minor;
132 FT_Int patch;
133 } FT_Version_t;
134 static FT_Version_t FT_Version;
135 static DWORD FT_SimpleVersion;
136 #define FT_VERSION_VALUE(major, minor, patch) (((major) << 16) | ((minor) << 8) | (patch))
138 static void *ft_handle = NULL;
140 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
141 MAKE_FUNCPTR(FT_Done_Face);
142 MAKE_FUNCPTR(FT_Get_Char_Index);
143 MAKE_FUNCPTR(FT_Get_First_Char);
144 MAKE_FUNCPTR(FT_Get_Next_Char);
145 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
146 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
147 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
148 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
149 MAKE_FUNCPTR(FT_Init_FreeType);
150 MAKE_FUNCPTR(FT_Library_Version);
151 MAKE_FUNCPTR(FT_Load_Glyph);
152 MAKE_FUNCPTR(FT_Load_Sfnt_Table);
153 MAKE_FUNCPTR(FT_Matrix_Multiply);
154 MAKE_FUNCPTR(FT_MulDiv);
155 #ifdef FT_MULFIX_INLINED
156 #define pFT_MulFix FT_MULFIX_INLINED
157 #else
158 MAKE_FUNCPTR(FT_MulFix);
159 #endif
160 MAKE_FUNCPTR(FT_New_Face);
161 MAKE_FUNCPTR(FT_New_Memory_Face);
162 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
163 MAKE_FUNCPTR(FT_Outline_Get_CBox);
164 MAKE_FUNCPTR(FT_Outline_Transform);
165 MAKE_FUNCPTR(FT_Outline_Translate);
166 MAKE_FUNCPTR(FT_Render_Glyph);
167 MAKE_FUNCPTR(FT_Set_Charmap);
168 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
169 MAKE_FUNCPTR(FT_Vector_Length);
170 MAKE_FUNCPTR(FT_Vector_Transform);
171 MAKE_FUNCPTR(FT_Vector_Unit);
172 static FT_Error (*pFT_Outline_Embolden)(FT_Outline *, FT_Pos);
173 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
174 #ifdef FT_LCD_FILTER_H
175 static FT_Error (*pFT_Library_SetLcdFilter)(FT_Library, FT_LcdFilter);
176 #endif
177 static FT_Error (*pFT_Property_Set)(FT_Library, const FT_String *, const FT_String *, const void *);
179 #ifdef SONAME_LIBFONTCONFIG
180 #include <fontconfig/fontconfig.h>
181 MAKE_FUNCPTR(FcConfigSubstitute);
182 MAKE_FUNCPTR(FcDefaultSubstitute);
183 MAKE_FUNCPTR(FcFontList);
184 MAKE_FUNCPTR(FcFontMatch);
185 MAKE_FUNCPTR(FcFontSetDestroy);
186 MAKE_FUNCPTR(FcInit);
187 MAKE_FUNCPTR(FcPatternAddString);
188 MAKE_FUNCPTR(FcPatternCreate);
189 MAKE_FUNCPTR(FcPatternDestroy);
190 MAKE_FUNCPTR(FcPatternGetBool);
191 MAKE_FUNCPTR(FcPatternGetInteger);
192 MAKE_FUNCPTR(FcPatternGetString);
193 #ifndef FC_NAMELANG
194 #define FC_NAMELANG "namelang"
195 #endif
196 #ifndef FC_PRGNAME
197 #define FC_PRGNAME "prgname"
198 #endif
199 #endif /* SONAME_LIBFONTCONFIG */
201 #undef MAKE_FUNCPTR
203 #ifndef FT_MAKE_TAG
204 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
205 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
206 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
207 #endif
209 #ifndef ft_encoding_none
210 #define FT_ENCODING_NONE ft_encoding_none
211 #endif
212 #ifndef ft_encoding_ms_symbol
213 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
214 #endif
215 #ifndef ft_encoding_unicode
216 #define FT_ENCODING_UNICODE ft_encoding_unicode
217 #endif
218 #ifndef ft_encoding_apple_roman
219 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
220 #endif
222 #ifdef WORDS_BIGENDIAN
223 #define GET_BE_WORD(x) (x)
224 #define GET_BE_DWORD(x) (x)
225 #else
226 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
227 #define GET_BE_DWORD(x) RtlUlongByteSwap(x)
228 #endif
230 /* 'gasp' flags */
231 #define GASP_GRIDFIT 0x01
232 #define GASP_DOGRAY 0x02
234 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
235 So to let this compile on older versions of FreeType we'll define the
236 new structure here. */
237 typedef struct {
238 FT_Short height, width;
239 FT_Pos size, x_ppem, y_ppem;
240 } My_FT_Bitmap_Size;
242 struct font_private_data
244 FT_Face ft_face;
245 struct font_mapping *mapping;
248 static inline FT_Face get_ft_face( struct gdi_font *font )
250 return ((struct font_private_data *)font->private)->ft_face;
253 static const struct font_callback_funcs *callback_funcs;
255 struct font_mapping
257 struct list entry;
258 int refcount;
259 dev_t dev;
260 ino_t ino;
261 void *data;
262 size_t size;
265 static struct list mappings_list = LIST_INIT( mappings_list );
267 static UINT default_aa_flags;
268 static LCID system_lcid;
270 static BOOL CDECL freetype_set_outline_text_metrics( struct gdi_font *font );
271 static BOOL CDECL freetype_set_bitmap_text_metrics( struct gdi_font *font );
273 /****************************************
274 * Notes on .fon files
276 * The fonts System, FixedSys and Terminal are special. There are typically multiple
277 * versions installed for different resolutions and codepages. Windows stores which one to use
278 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
279 * Key Meaning
280 * FIXEDFON.FON FixedSys
281 * FONTS.FON System
282 * OEMFONT.FON Terminal
283 * LogPixels Current dpi set by the display control panel applet
284 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
285 * also has a LogPixels value that appears to mirror this)
287 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
288 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
289 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
290 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
291 * so that makes sense.
293 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
294 * to be mapped into the registry on Windows 2000 at least).
295 * I have
296 * woafont=app850.fon
297 * ega80woa.fon=ega80850.fon
298 * ega40woa.fon=ega40850.fon
299 * cga80woa.fon=cga80850.fon
300 * cga40woa.fon=cga40850.fon
303 #ifdef HAVE_CARBON_CARBON_H
304 static char *find_cache_dir(void)
306 FSRef ref;
307 OSErr err;
308 static char cached_path[MAX_PATH];
309 static const char *wine = "/Wine", *fonts = "/Fonts";
311 if(*cached_path) return cached_path;
313 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
314 if(err != noErr)
316 WARN("can't create cached data folder\n");
317 return NULL;
319 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
320 if(err != noErr)
322 WARN("can't create cached data path\n");
323 *cached_path = '\0';
324 return NULL;
326 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
328 ERR("Could not create full path\n");
329 *cached_path = '\0';
330 return NULL;
332 strcat(cached_path, wine);
334 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
336 WARN("Couldn't mkdir %s\n", cached_path);
337 *cached_path = '\0';
338 return NULL;
340 strcat(cached_path, fonts);
341 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
343 WARN("Couldn't mkdir %s\n", cached_path);
344 *cached_path = '\0';
345 return NULL;
347 return cached_path;
350 /******************************************************************
351 * expand_mac_font
353 * Extracts individual TrueType font files from a Mac suitcase font
354 * and saves them into the user's caches directory (see
355 * find_cache_dir()).
356 * Returns a NULL terminated array of filenames.
358 * We do this because they are apps that try to read ttf files
359 * themselves and they don't like Mac suitcase files.
361 static char **expand_mac_font(const char *path)
363 FSRef ref;
364 ResFileRefNum res_ref;
365 OSStatus s;
366 unsigned int idx;
367 const char *out_dir;
368 const char *filename;
369 int output_len;
370 struct {
371 char **array;
372 unsigned int size, max_size;
373 } ret;
375 TRACE("path %s\n", path);
377 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
378 if(s != noErr)
380 WARN("failed to get ref\n");
381 return NULL;
384 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
385 if(s != noErr)
387 TRACE("no data fork, so trying resource fork\n");
388 res_ref = FSOpenResFile(&ref, fsRdPerm);
389 if(res_ref == -1)
391 TRACE("unable to open resource fork\n");
392 return NULL;
396 ret.size = 0;
397 ret.max_size = 10;
398 ret.array = RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
399 if(!ret.array)
401 CloseResFile(res_ref);
402 return NULL;
405 out_dir = find_cache_dir();
407 filename = strrchr(path, '/');
408 if(!filename) filename = path;
409 else filename++;
411 /* output filename has the form out_dir/filename_%04x.ttf */
412 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
414 UseResFile(res_ref);
415 idx = 1;
416 while(1)
418 FamRec *fam_rec;
419 unsigned short *num_faces_ptr, num_faces, face;
420 AsscEntry *assoc;
421 Handle fond;
422 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
424 fond = Get1IndResource(fond_res, idx);
425 if(!fond) break;
426 TRACE("got fond resource %d\n", idx);
427 HLock(fond);
429 fam_rec = *(FamRec**)fond;
430 num_faces_ptr = (unsigned short *)(fam_rec + 1);
431 num_faces = GET_BE_WORD(*num_faces_ptr);
432 num_faces++;
433 assoc = (AsscEntry*)(num_faces_ptr + 1);
434 TRACE("num faces %04x\n", num_faces);
435 for(face = 0; face < num_faces; face++, assoc++)
437 Handle sfnt;
438 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
439 unsigned short size, font_id;
440 char *output;
442 size = GET_BE_WORD(assoc->fontSize);
443 font_id = GET_BE_WORD(assoc->fontID);
444 if(size != 0)
446 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
447 continue;
450 TRACE("trying to load sfnt id %04x\n", font_id);
451 sfnt = GetResource(sfnt_res, font_id);
452 if(!sfnt)
454 TRACE("can't get sfnt resource %04x\n", font_id);
455 continue;
458 output = RtlAllocateHeap(GetProcessHeap(), 0, output_len);
459 if(output)
461 int fd;
463 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
465 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
466 if(fd != -1 || errno == EEXIST)
468 if(fd != -1)
470 unsigned char *sfnt_data;
472 HLock(sfnt);
473 sfnt_data = *(unsigned char**)sfnt;
474 write(fd, sfnt_data, GetHandleSize(sfnt));
475 HUnlock(sfnt);
476 close(fd);
478 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
480 ret.max_size *= 2;
481 ret.array = RtlReAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
483 ret.array[ret.size++] = output;
485 else
487 WARN("unable to create %s\n", output);
488 RtlFreeHeap(GetProcessHeap(), 0, output);
491 ReleaseResource(sfnt);
493 HUnlock(fond);
494 ReleaseResource(fond);
495 idx++;
497 CloseResFile(res_ref);
499 return ret.array;
502 #endif /* HAVE_CARBON_CARBON_H */
505 This function builds an FT_Fixed from a double. It fails if the absolute
506 value of the float number is greater than 32768.
508 static inline FT_Fixed FT_FixedFromFloat(double f)
510 return f * 0x10000;
514 This function builds an FT_Fixed from a FIXED. It simply put f.value
515 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
517 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
519 return (FT_Fixed)((int)f.value << 16 | (unsigned int)f.fract);
522 static BOOL is_hinting_enabled(void)
524 static int enabled = -1;
526 if (enabled == -1)
528 /* Use the >= 2.2.0 function if available */
529 if (pFT_Get_TrueType_Engine_Type)
531 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
532 enabled = (type == FT_TRUETYPE_ENGINE_TYPE_PATENTED);
534 else enabled = FALSE;
535 TRACE("hinting is %senabled\n", enabled ? "" : "NOT ");
537 return enabled;
540 static BOOL is_subpixel_rendering_enabled( void )
542 static int enabled = -1;
543 if (enabled == -1)
545 /* FreeType >= 2.8.1 offers LCD-optimezed rendering without lcd filters. */
546 if (FT_SimpleVersion >= FT_VERSION_VALUE(2, 8, 1))
547 enabled = TRUE;
548 #ifdef FT_LCD_FILTER_H
549 else if (pFT_Library_SetLcdFilter &&
550 pFT_Library_SetLcdFilter( NULL, 0 ) != FT_Err_Unimplemented_Feature)
551 enabled = TRUE;
552 #endif
553 else enabled = FALSE;
555 TRACE("subpixel rendering is %senabled\n", enabled ? "" : "NOT ");
557 return enabled;
561 static LPWSTR strdupW(LPCWSTR p)
563 LPWSTR ret;
564 DWORD len = (lstrlenW(p) + 1) * sizeof(WCHAR);
565 ret = RtlAllocateHeap(GetProcessHeap(), 0, len);
566 memcpy(ret, p, len);
567 return ret;
570 static WCHAR *towstr(const char *str)
572 DWORD len = strlen(str) + 1;
573 WCHAR *wstr = RtlAllocateHeap( GetProcessHeap(), 0, len * sizeof(WCHAR) );
574 RtlMultiByteToUnicodeN( wstr, len * sizeof(WCHAR), &len, str, len );
575 return wstr;
579 static const LANGID mac_langid_table[] =
581 MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ENGLISH */
582 MAKELANGID(LANG_FRENCH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FRENCH */
583 MAKELANGID(LANG_GERMAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GERMAN */
584 MAKELANGID(LANG_ITALIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ITALIAN */
585 MAKELANGID(LANG_DUTCH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_DUTCH */
586 MAKELANGID(LANG_SWEDISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SWEDISH */
587 MAKELANGID(LANG_SPANISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SPANISH */
588 MAKELANGID(LANG_DANISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_DANISH */
589 MAKELANGID(LANG_PORTUGUESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PORTUGUESE */
590 MAKELANGID(LANG_NORWEGIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_NORWEGIAN */
591 MAKELANGID(LANG_HEBREW,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HEBREW */
592 MAKELANGID(LANG_JAPANESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_JAPANESE */
593 MAKELANGID(LANG_ARABIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ARABIC */
594 MAKELANGID(LANG_FINNISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FINNISH */
595 MAKELANGID(LANG_GREEK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GREEK */
596 MAKELANGID(LANG_ICELANDIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ICELANDIC */
597 MAKELANGID(LANG_MALTESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALTESE */
598 MAKELANGID(LANG_TURKISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TURKISH */
599 MAKELANGID(LANG_CROATIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CROATIAN */
600 MAKELANGID(LANG_CHINESE_TRADITIONAL,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CHINESE_TRADITIONAL */
601 MAKELANGID(LANG_URDU,SUBLANG_DEFAULT), /* TT_MAC_LANGID_URDU */
602 MAKELANGID(LANG_HINDI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HINDI */
603 MAKELANGID(LANG_THAI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_THAI */
604 MAKELANGID(LANG_KOREAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KOREAN */
605 MAKELANGID(LANG_LITHUANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LITHUANIAN */
606 MAKELANGID(LANG_POLISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_POLISH */
607 MAKELANGID(LANG_HUNGARIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_HUNGARIAN */
608 MAKELANGID(LANG_ESTONIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ESTONIAN */
609 MAKELANGID(LANG_LATVIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LETTISH */
610 MAKELANGID(LANG_SAMI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SAAMISK */
611 MAKELANGID(LANG_FAEROESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FAEROESE */
612 MAKELANGID(LANG_FARSI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_FARSI */
613 MAKELANGID(LANG_RUSSIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_RUSSIAN */
614 MAKELANGID(LANG_CHINESE_SIMPLIFIED,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CHINESE_SIMPLIFIED */
615 MAKELANGID(LANG_DUTCH,SUBLANG_DUTCH_BELGIAN), /* TT_MAC_LANGID_FLEMISH */
616 MAKELANGID(LANG_IRISH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_IRISH */
617 MAKELANGID(LANG_ALBANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ALBANIAN */
618 MAKELANGID(LANG_ROMANIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ROMANIAN */
619 MAKELANGID(LANG_CZECH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CZECH */
620 MAKELANGID(LANG_SLOVAK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SLOVAK */
621 MAKELANGID(LANG_SLOVENIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SLOVENIAN */
622 0, /* TT_MAC_LANGID_YIDDISH */
623 MAKELANGID(LANG_SERBIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SERBIAN */
624 MAKELANGID(LANG_MACEDONIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MACEDONIAN */
625 MAKELANGID(LANG_BULGARIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BULGARIAN */
626 MAKELANGID(LANG_UKRAINIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UKRAINIAN */
627 MAKELANGID(LANG_BELARUSIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BYELORUSSIAN */
628 MAKELANGID(LANG_UZBEK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UZBEK */
629 MAKELANGID(LANG_KAZAK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KAZAKH */
630 MAKELANGID(LANG_AZERI,SUBLANG_AZERI_CYRILLIC), /* TT_MAC_LANGID_AZERBAIJANI */
631 0, /* TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT */
632 MAKELANGID(LANG_ARMENIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ARMENIAN */
633 MAKELANGID(LANG_GEORGIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GEORGIAN */
634 0, /* TT_MAC_LANGID_MOLDAVIAN */
635 MAKELANGID(LANG_KYRGYZ,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KIRGHIZ */
636 MAKELANGID(LANG_TAJIK,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TAJIKI */
637 MAKELANGID(LANG_TURKMEN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TURKMEN */
638 MAKELANGID(LANG_MONGOLIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MONGOLIAN */
639 MAKELANGID(LANG_MONGOLIAN,SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA), /* TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT */
640 MAKELANGID(LANG_PASHTO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PASHTO */
641 0, /* TT_MAC_LANGID_KURDISH */
642 MAKELANGID(LANG_KASHMIRI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KASHMIRI */
643 MAKELANGID(LANG_SINDHI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SINDHI */
644 MAKELANGID(LANG_TIBETAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TIBETAN */
645 MAKELANGID(LANG_NEPALI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_NEPALI */
646 MAKELANGID(LANG_SANSKRIT,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SANSKRIT */
647 MAKELANGID(LANG_MARATHI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MARATHI */
648 MAKELANGID(LANG_BENGALI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BENGALI */
649 MAKELANGID(LANG_ASSAMESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ASSAMESE */
650 MAKELANGID(LANG_GUJARATI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GUJARATI */
651 MAKELANGID(LANG_PUNJABI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_PUNJABI */
652 MAKELANGID(LANG_ORIYA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ORIYA */
653 MAKELANGID(LANG_MALAYALAM,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAYALAM */
654 MAKELANGID(LANG_KANNADA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KANNADA */
655 MAKELANGID(LANG_TAMIL,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TAMIL */
656 MAKELANGID(LANG_TELUGU,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TELUGU */
657 MAKELANGID(LANG_SINHALESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SINHALESE */
658 0, /* TT_MAC_LANGID_BURMESE */
659 MAKELANGID(LANG_KHMER,SUBLANG_DEFAULT), /* TT_MAC_LANGID_KHMER */
660 MAKELANGID(LANG_LAO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_LAO */
661 MAKELANGID(LANG_VIETNAMESE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_VIETNAMESE */
662 MAKELANGID(LANG_INDONESIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_INDONESIAN */
663 0, /* TT_MAC_LANGID_TAGALOG */
664 MAKELANGID(LANG_MALAY,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAY_ROMAN_SCRIPT */
665 0, /* TT_MAC_LANGID_MALAY_ARABIC_SCRIPT */
666 MAKELANGID(LANG_AMHARIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_AMHARIC */
667 MAKELANGID(LANG_TIGRIGNA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TIGRINYA */
668 0, /* TT_MAC_LANGID_GALLA */
669 0, /* TT_MAC_LANGID_SOMALI */
670 MAKELANGID(LANG_SWAHILI,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SWAHILI */
671 0, /* TT_MAC_LANGID_RUANDA */
672 0, /* TT_MAC_LANGID_RUNDI */
673 0, /* TT_MAC_LANGID_CHEWA */
674 MAKELANGID(LANG_MALAGASY,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MALAGASY */
675 MAKELANGID(LANG_ESPERANTO,SUBLANG_DEFAULT), /* TT_MAC_LANGID_ESPERANTO */
676 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 95-111 */
677 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 112-127 */
678 MAKELANGID(LANG_WELSH,SUBLANG_DEFAULT), /* TT_MAC_LANGID_WELSH */
679 MAKELANGID(LANG_BASQUE,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BASQUE */
680 MAKELANGID(LANG_CATALAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_CATALAN */
681 0, /* TT_MAC_LANGID_LATIN */
682 MAKELANGID(LANG_QUECHUA,SUBLANG_DEFAULT), /* TT_MAC_LANGID_QUECHUA */
683 0, /* TT_MAC_LANGID_GUARANI */
684 0, /* TT_MAC_LANGID_AYMARA */
685 MAKELANGID(LANG_TATAR,SUBLANG_DEFAULT), /* TT_MAC_LANGID_TATAR */
686 MAKELANGID(LANG_UIGHUR,SUBLANG_DEFAULT), /* TT_MAC_LANGID_UIGHUR */
687 0, /* TT_MAC_LANGID_DZONGKHA */
688 0, /* TT_MAC_LANGID_JAVANESE */
689 0, /* TT_MAC_LANGID_SUNDANESE */
690 MAKELANGID(LANG_GALICIAN,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GALICIAN */
691 MAKELANGID(LANG_AFRIKAANS,SUBLANG_DEFAULT), /* TT_MAC_LANGID_AFRIKAANS */
692 MAKELANGID(LANG_BRETON,SUBLANG_DEFAULT), /* TT_MAC_LANGID_BRETON */
693 MAKELANGID(LANG_INUKTITUT,SUBLANG_DEFAULT), /* TT_MAC_LANGID_INUKTITUT */
694 MAKELANGID(LANG_SCOTTISH_GAELIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_SCOTTISH_GAELIC */
695 MAKELANGID(LANG_MANX_GAELIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_MANX_GAELIC */
696 MAKELANGID(LANG_IRISH,SUBLANG_IRISH_IRELAND), /* TT_MAC_LANGID_IRISH_GAELIC */
697 0, /* TT_MAC_LANGID_TONGAN */
698 0, /* TT_MAC_LANGID_GREEK_POLYTONIC */
699 MAKELANGID(LANG_GREENLANDIC,SUBLANG_DEFAULT), /* TT_MAC_LANGID_GREELANDIC */
700 MAKELANGID(LANG_AZERI,SUBLANG_AZERI_LATIN), /* TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT */
703 static CPTABLEINFO *get_mac_code_page( const FT_SfntName *name )
705 static CPTABLEINFO tables[100];
706 int id = name->encoding_id;
707 USHORT *ptr;
708 SIZE_T size;
710 if (name->encoding_id == TT_MAC_ID_SIMPLIFIED_CHINESE) id = 8; /* special case */
711 if (id >= ARRAY_SIZE(tables)) return NULL;
712 if (!tables[id].CodePage)
714 if (NtGetNlsSectionPtr( 11, 10000 + id, NULL, (void **)&ptr, &size )) return NULL;
715 RtlInitCodePageTable( ptr, &tables[id] );
717 return &tables[id];
720 static int match_name_table_language( const FT_SfntName *name, LANGID lang )
722 LANGID name_lang;
723 int res = 0;
725 switch (name->platform_id)
727 case TT_PLATFORM_MICROSOFT:
728 res += 5; /* prefer the Microsoft name */
729 switch (name->encoding_id)
731 case TT_MS_ID_UNICODE_CS:
732 case TT_MS_ID_SYMBOL_CS:
733 name_lang = name->language_id;
734 break;
735 default:
736 return 0;
738 break;
739 case TT_PLATFORM_MACINTOSH:
740 if (!get_mac_code_page( name )) return 0;
741 if (name->language_id >= ARRAY_SIZE( mac_langid_table )) return 0;
742 name_lang = mac_langid_table[name->language_id];
743 break;
744 case TT_PLATFORM_APPLE_UNICODE:
745 res += 2; /* prefer Unicode encodings */
746 switch (name->encoding_id)
748 case TT_APPLE_ID_DEFAULT:
749 case TT_APPLE_ID_ISO_10646:
750 case TT_APPLE_ID_UNICODE_2_0:
751 if (name->language_id >= ARRAY_SIZE( mac_langid_table )) return 0;
752 name_lang = mac_langid_table[name->language_id];
753 break;
754 default:
755 return 0;
757 break;
758 default:
759 return 0;
761 if (name_lang == lang) res += 30;
762 else if (PRIMARYLANGID( name_lang ) == PRIMARYLANGID( lang )) res += 20;
763 else if (name_lang == MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT )) res += 10;
764 else if (lang == MAKELANGID( LANG_NEUTRAL, SUBLANG_NEUTRAL )) res += 5 * (0x100000 - name_lang);
765 return res;
768 static WCHAR *copy_name_table_string( const FT_SfntName *name )
770 WCHAR *ret;
771 CPTABLEINFO *cp;
772 DWORD i;
774 switch (name->platform_id)
776 case TT_PLATFORM_APPLE_UNICODE:
777 case TT_PLATFORM_MICROSOFT:
778 ret = RtlAllocateHeap( GetProcessHeap(), 0, name->string_len + sizeof(WCHAR) );
779 for (i = 0; i < name->string_len / 2; i++)
780 ret[i] = (name->string[i * 2] << 8) | name->string[i * 2 + 1];
781 ret[i] = 0;
782 return ret;
783 case TT_PLATFORM_MACINTOSH:
784 if (!(cp = get_mac_code_page( name ))) return NULL;
785 ret = RtlAllocateHeap( GetProcessHeap(), 0, (name->string_len + 1) * sizeof(WCHAR) );
786 RtlCustomCPToUnicodeN( cp, ret, name->string_len * sizeof(WCHAR), &i,
787 (char *)name->string, name->string_len );
788 ret[i / sizeof(WCHAR)] = 0;
789 return ret;
791 return NULL;
794 static WCHAR *get_face_name(FT_Face ft_face, FT_UShort name_id, LANGID language_id)
796 FT_SfntName name;
797 FT_UInt num_names, name_index;
798 int res, best_lang = 0, best_index = -1;
800 if (!FT_IS_SFNT(ft_face)) return NULL;
802 num_names = pFT_Get_Sfnt_Name_Count( ft_face );
804 for (name_index = 0; name_index < num_names; name_index++)
806 if (pFT_Get_Sfnt_Name( ft_face, name_index, &name )) continue;
807 if (name.name_id != name_id) continue;
808 res = match_name_table_language( &name, language_id );
809 if (res > best_lang)
811 best_lang = res;
812 best_index = name_index;
816 if (best_index != -1 && !pFT_Get_Sfnt_Name( ft_face, best_index, &name ))
818 WCHAR *ret = copy_name_table_string( &name );
819 TRACE( "name %u found platform %u lang %04x %s\n",
820 name_id, name.platform_id, name.language_id, debugstr_w( ret ));
821 return ret;
823 return NULL;
826 static WCHAR *ft_face_get_family_name( FT_Face ft_face, LANGID langid )
828 WCHAR *family_name;
830 if ((family_name = get_face_name( ft_face, TT_NAME_ID_FONT_FAMILY, langid )))
831 return family_name;
833 return towstr( ft_face->family_name );
836 static WCHAR *ft_face_get_style_name( FT_Face ft_face, LANGID langid )
838 WCHAR *style_name;
840 if ((style_name = get_face_name( ft_face, TT_NAME_ID_FONT_SUBFAMILY, langid )))
841 return style_name;
843 return towstr( ft_face->style_name );
846 static WCHAR *ft_face_get_full_name( FT_Face ft_face, LANGID langid )
848 static const WCHAR space_w[] = {' ',0};
849 WCHAR *full_name, *style_name;
850 SIZE_T length;
852 if ((full_name = get_face_name( ft_face, TT_NAME_ID_FULL_NAME, langid )))
853 return full_name;
855 full_name = ft_face_get_family_name( ft_face, langid );
856 style_name = ft_face_get_style_name( ft_face, langid );
858 length = lstrlenW( full_name ) + lstrlenW( space_w ) + lstrlenW( style_name ) + 1;
859 full_name = RtlReAllocateHeap( GetProcessHeap(), 0, full_name, length * sizeof(WCHAR) );
861 lstrcatW( full_name, space_w );
862 lstrcatW( full_name, style_name );
863 RtlFreeHeap( GetProcessHeap(), 0, style_name );
865 WARN( "full name not found, using %s instead\n", debugstr_w(full_name) );
866 return full_name;
869 static inline FT_Fixed get_font_version( FT_Face ft_face )
871 FT_Fixed version = 0;
872 TT_Header *header;
874 header = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head );
875 if (header) version = header->Font_Revision;
877 return version;
880 static inline DWORD get_ntm_flags( FT_Face ft_face )
882 DWORD flags = 0;
883 FT_ULong table_size = 0;
884 FT_WinFNT_HeaderRec winfnt_header;
886 if (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) flags |= NTM_ITALIC;
887 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD) flags |= NTM_BOLD;
889 /* fixup the flag for our fake-bold implementation. */
890 if (!FT_IS_SCALABLE( ft_face ) &&
891 !pFT_Get_WinFNT_Header( ft_face, &winfnt_header ) &&
892 winfnt_header.weight > FW_NORMAL )
893 flags |= NTM_BOLD;
895 if (flags == 0) flags = NTM_REGULAR;
897 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL, &table_size ))
898 flags |= NTM_PS_OPENTYPE;
900 return flags;
903 static inline void get_bitmap_size( FT_Face ft_face, struct bitmap_font_size *face_size )
905 My_FT_Bitmap_Size *size;
906 FT_WinFNT_HeaderRec winfnt_header;
908 size = (My_FT_Bitmap_Size *)ft_face->available_sizes;
909 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
910 size->height, size->width, size->size >> 6,
911 size->x_ppem >> 6, size->y_ppem >> 6);
912 face_size->height = size->height;
913 face_size->width = size->width;
914 face_size->size = size->size;
915 face_size->x_ppem = size->x_ppem;
916 face_size->y_ppem = size->y_ppem;
918 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header )) {
919 face_size->internal_leading = winfnt_header.internal_leading;
920 if (winfnt_header.external_leading > 0 &&
921 (face_size->height ==
922 winfnt_header.pixel_height + winfnt_header.external_leading))
923 face_size->height = winfnt_header.pixel_height;
927 static inline void get_fontsig( FT_Face ft_face, FONTSIGNATURE *fs )
929 TT_OS2 *os2;
930 FT_WinFNT_HeaderRec winfnt_header;
931 int i;
933 memset( fs, 0, sizeof(*fs) );
935 os2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 );
936 if (os2)
938 fs->fsUsb[0] = os2->ulUnicodeRange1;
939 fs->fsUsb[1] = os2->ulUnicodeRange2;
940 fs->fsUsb[2] = os2->ulUnicodeRange3;
941 fs->fsUsb[3] = os2->ulUnicodeRange4;
943 if (os2->version == 0)
945 if (os2->usFirstCharIndex >= 0xf000 && os2->usFirstCharIndex < 0xf100)
946 fs->fsCsb[0] = FS_SYMBOL;
947 else
948 fs->fsCsb[0] = FS_LATIN1;
950 else
952 fs->fsCsb[0] = os2->ulCodePageRange1;
953 fs->fsCsb[1] = os2->ulCodePageRange2;
956 else
958 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt_header ))
960 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
961 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
962 switch (winfnt_header.charset)
964 case ANSI_CHARSET: fs->fsCsb[0] = FS_LATIN1; break;
965 case EASTEUROPE_CHARSET: fs->fsCsb[0] = FS_LATIN2; break;
966 case RUSSIAN_CHARSET: fs->fsCsb[0] = FS_CYRILLIC; break;
967 case GREEK_CHARSET: fs->fsCsb[0] = FS_GREEK; break;
968 case TURKISH_CHARSET: fs->fsCsb[0] = FS_TURKISH; break;
969 case HEBREW_CHARSET: fs->fsCsb[0] = FS_HEBREW; break;
970 case ARABIC_CHARSET: fs->fsCsb[0] = FS_ARABIC; break;
971 case BALTIC_CHARSET: fs->fsCsb[0] = FS_BALTIC; break;
972 case VIETNAMESE_CHARSET: fs->fsCsb[0] = FS_VIETNAMESE; break;
973 case THAI_CHARSET: fs->fsCsb[0] = FS_THAI; break;
974 case SHIFTJIS_CHARSET: fs->fsCsb[0] = FS_JISJAPAN; break;
975 case GB2312_CHARSET: fs->fsCsb[0] = FS_CHINESESIMP; break;
976 case HANGEUL_CHARSET: fs->fsCsb[0] = FS_WANSUNG; break;
977 case CHINESEBIG5_CHARSET: fs->fsCsb[0] = FS_CHINESETRAD; break;
978 case JOHAB_CHARSET: fs->fsCsb[0] = FS_JOHAB; break;
979 case SYMBOL_CHARSET: fs->fsCsb[0] = FS_SYMBOL; break;
984 if (fs->fsCsb[0] == 0)
986 /* let's see if we can find any interesting cmaps */
987 for (i = 0; i < ft_face->num_charmaps; i++)
989 switch (ft_face->charmaps[i]->encoding)
991 case FT_ENCODING_UNICODE:
992 case FT_ENCODING_APPLE_ROMAN:
993 fs->fsCsb[0] |= FS_LATIN1;
994 break;
995 case FT_ENCODING_MS_SYMBOL:
996 fs->fsCsb[0] |= FS_SYMBOL;
997 break;
998 default:
999 break;
1005 static int AddFaceToList(FT_Face ft_face, const WCHAR *file, void *data_ptr, SIZE_T data_size,
1006 FT_Long face_index, DWORD flags )
1008 struct bitmap_font_size size;
1009 FONTSIGNATURE fs;
1010 int ret;
1011 WCHAR *family_name = ft_face_get_family_name( ft_face, system_lcid );
1012 WCHAR *second_name = ft_face_get_family_name( ft_face, MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT) );
1013 WCHAR *style_name = ft_face_get_style_name( ft_face, system_lcid );
1014 WCHAR *full_name = ft_face_get_full_name( ft_face, system_lcid );
1016 /* try to find another secondary name, preferring the lowest langids */
1017 if (!RtlCompareUnicodeStrings( family_name, lstrlenW(family_name),
1018 second_name, lstrlenW(second_name), TRUE ))
1020 RtlFreeHeap( GetProcessHeap(), 0, second_name );
1021 second_name = ft_face_get_family_name( ft_face, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL) );
1022 if (!RtlCompareUnicodeStrings( family_name, lstrlenW(family_name),
1023 second_name, lstrlenW(second_name), TRUE ))
1025 RtlFreeHeap( GetProcessHeap(), 0, second_name );
1026 second_name = NULL;
1030 get_fontsig( ft_face, &fs );
1031 if (!FT_IS_SCALABLE( ft_face )) get_bitmap_size( ft_face, &size );
1032 if (!HIWORD( flags )) flags |= ADDFONT_AA_FLAGS( default_aa_flags );
1034 ret = callback_funcs->add_gdi_face( family_name, second_name, style_name, full_name, file,
1035 data_ptr, data_size, face_index, fs, get_ntm_flags( ft_face ),
1036 get_font_version( ft_face ), flags,
1037 FT_IS_SCALABLE(ft_face) ? NULL : &size );
1039 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1040 fs.fsCsb[0], fs.fsCsb[1], fs.fsUsb[0], fs.fsUsb[1], fs.fsUsb[2], fs.fsUsb[3]);
1042 RtlFreeHeap( GetProcessHeap(), 0, family_name );
1043 RtlFreeHeap( GetProcessHeap(), 0, second_name );
1044 RtlFreeHeap( GetProcessHeap(), 0, style_name );
1045 RtlFreeHeap( GetProcessHeap(), 0, full_name );
1046 return ret;
1049 static FT_Face new_ft_face( const char *file, void *font_data_ptr, DWORD font_data_size,
1050 FT_Long face_index, BOOL allow_bitmap )
1052 FT_Error err;
1053 TT_OS2 *pOS2;
1054 FT_Face ft_face;
1056 if (file)
1058 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1059 err = pFT_New_Face(library, file, face_index, &ft_face);
1061 else
1063 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1064 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1067 if (err != 0)
1069 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1070 return NULL;
1073 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1074 if (!FT_IS_SCALABLE( ft_face ) && FT_SimpleVersion < FT_VERSION_VALUE(2, 1, 9))
1076 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1077 goto fail;
1080 if (!FT_IS_SFNT( ft_face ))
1082 if (FT_IS_SCALABLE( ft_face ) || !allow_bitmap )
1084 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1085 goto fail;
1088 else
1090 if (!(pOS2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 )) ||
1091 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_hhea ) ||
1092 !pFT_Get_Sfnt_Table( ft_face, ft_sfnt_head ))
1094 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1095 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1096 goto fail;
1099 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1100 we don't want to load these. */
1101 if (!memcmp( pOS2->achVendID, "Wine", sizeof(pOS2->achVendID) ))
1103 FT_ULong len = 0;
1105 if (!pFT_Load_Sfnt_Table( ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len ))
1107 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1108 goto fail;
1113 if (!ft_face->family_name || !ft_face->style_name)
1115 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1116 goto fail;
1119 return ft_face;
1120 fail:
1121 pFT_Done_Face( ft_face );
1122 return NULL;
1125 static WCHAR *get_dos_file_name( LPCSTR str )
1127 WCHAR *buffer;
1128 SIZE_T len = strlen(str) + 1;
1130 len += 8; /* \??\unix prefix */
1131 if (!(buffer = RtlAllocateHeap( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return NULL;
1132 if (wine_unix_to_nt_file_name( str, buffer, &len ))
1134 RtlFreeHeap( GetProcessHeap(), 0, buffer );
1135 return NULL;
1137 if (buffer[5] == ':')
1139 /* get rid of the \??\ prefix */
1140 /* FIXME: should implement RtlNtPathNameToDosPathName and use that instead */
1141 memmove( buffer, buffer + 4, (len - 4) * sizeof(WCHAR) );
1143 else buffer[1] = '\\';
1144 return buffer;
1147 static char *get_unix_file_name( LPCWSTR dosW )
1149 UNICODE_STRING nt_name;
1150 NTSTATUS status;
1151 SIZE_T size = 256;
1152 char *buffer;
1154 if (!RtlDosPathNameToNtPathName_U( dosW, &nt_name, NULL, NULL )) return NULL;
1155 for (;;)
1157 if (!(buffer = RtlAllocateHeap( GetProcessHeap(), 0, size )))
1159 RtlFreeUnicodeString( &nt_name );
1160 return NULL;
1162 status = wine_nt_to_unix_file_name( &nt_name, buffer, &size, FILE_OPEN_IF );
1163 if (status != STATUS_BUFFER_TOO_SMALL) break;
1164 RtlFreeHeap( GetProcessHeap(), 0, buffer );
1166 RtlFreeUnicodeString( &nt_name );
1167 if (status && status != STATUS_NO_SUCH_FILE)
1169 RtlFreeHeap( GetProcessHeap(), 0, buffer );
1170 RtlSetLastWin32ErrorAndNtStatusFromNtStatus( status );
1171 return NULL;
1173 return buffer;
1176 static INT AddFontToList(const WCHAR *dos_name, const char *unix_name, void *font_data_ptr,
1177 DWORD font_data_size, DWORD flags)
1179 FT_Face ft_face;
1180 FT_Long face_index = 0, num_faces;
1181 INT ret = 0;
1182 WCHAR *filename = NULL;
1184 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1185 assert(unix_name || !(flags & ADDFONT_EXTERNAL_FONT));
1187 #ifdef HAVE_CARBON_CARBON_H
1188 if(unix_name)
1190 char **mac_list = expand_mac_font(unix_name);
1191 if(mac_list)
1193 BOOL had_one = FALSE;
1194 char **cursor;
1195 for(cursor = mac_list; *cursor; cursor++)
1197 had_one = TRUE;
1198 AddFontToList(NULL, *cursor, NULL, 0, flags);
1199 RtlFreeHeap(GetProcessHeap(), 0, *cursor);
1201 RtlFreeHeap(GetProcessHeap(), 0, mac_list);
1202 if(had_one)
1203 return 1;
1206 #endif /* HAVE_CARBON_CARBON_H */
1208 if (!dos_name && unix_name) dos_name = filename = get_dos_file_name( unix_name );
1210 do {
1211 ft_face = new_ft_face( unix_name, font_data_ptr, font_data_size, face_index, flags & ADDFONT_ALLOW_BITMAP );
1212 if (!ft_face) break;
1214 if(ft_face->family_name[0] == '.') /* Ignore fonts with names beginning with a dot */
1216 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(unix_name));
1217 pFT_Done_Face(ft_face);
1218 break;
1221 ret += AddFaceToList(ft_face, dos_name, font_data_ptr, font_data_size, face_index, flags);
1223 num_faces = ft_face->num_faces;
1224 pFT_Done_Face(ft_face);
1225 } while(num_faces > ++face_index);
1226 RtlFreeHeap( GetProcessHeap(), 0, filename );
1227 return ret;
1230 /*************************************************************
1231 * freetype_add_font
1233 static INT CDECL freetype_add_font( const WCHAR *file, DWORD flags )
1235 int ret = 0;
1236 char *unixname = get_unix_file_name( file );
1238 if (unixname)
1240 ret = AddFontToList( file, unixname, NULL, 0, flags );
1241 RtlFreeHeap( GetProcessHeap(), 0, unixname );
1243 return ret;
1246 /*************************************************************
1247 * freetype_add_mem_font
1249 static INT CDECL freetype_add_mem_font( void *ptr, SIZE_T size, DWORD flags )
1251 return AddFontToList( NULL, NULL, ptr, size, flags );
1254 #ifdef __ANDROID__
1255 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1257 DIR *dir;
1258 struct dirent *dent;
1259 char path[MAX_PATH];
1261 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1263 dir = opendir(dirname);
1264 if(!dir) {
1265 WARN("Can't open directory %s\n", debugstr_a(dirname));
1266 return FALSE;
1268 while((dent = readdir(dir)) != NULL) {
1269 struct stat statbuf;
1271 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1272 continue;
1274 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1276 sprintf(path, "%s/%s", dirname, dent->d_name);
1278 if(stat(path, &statbuf) == -1)
1280 WARN("Can't stat %s\n", debugstr_a(path));
1281 continue;
1283 if(S_ISDIR(statbuf.st_mode))
1284 ReadFontDir(path, external_fonts);
1285 else
1287 DWORD addfont_flags = ADDFONT_ADD_TO_CACHE;
1288 if(external_fonts) addfont_flags |= ADDFONT_EXTERNAL_FONT;
1289 AddFontToList(NULL, path, NULL, 0, addfont_flags);
1292 closedir(dir);
1293 return TRUE;
1295 #endif
1297 #ifdef SONAME_LIBFONTCONFIG
1299 static BOOL fontconfig_enabled;
1300 static FcPattern *pattern_serif;
1301 static FcPattern *pattern_fixed;
1302 static FcPattern *pattern_sans;
1304 static UINT parse_aa_pattern( FcPattern *pattern )
1306 FcBool antialias;
1307 int rgba;
1308 UINT aa_flags = 0;
1310 if (pFcPatternGetBool( pattern, FC_ANTIALIAS, 0, &antialias ) == FcResultMatch)
1311 aa_flags = antialias ? GGO_GRAY4_BITMAP : GGO_BITMAP;
1313 if (pFcPatternGetInteger( pattern, FC_RGBA, 0, &rgba ) == FcResultMatch)
1315 switch (rgba)
1317 case FC_RGBA_RGB: aa_flags = WINE_GGO_HRGB_BITMAP; break;
1318 case FC_RGBA_BGR: aa_flags = WINE_GGO_HBGR_BITMAP; break;
1319 case FC_RGBA_VRGB: aa_flags = WINE_GGO_VRGB_BITMAP; break;
1320 case FC_RGBA_VBGR: aa_flags = WINE_GGO_VBGR_BITMAP; break;
1321 case FC_RGBA_NONE: aa_flags = aa_flags ? aa_flags : GGO_GRAY4_BITMAP; break;
1324 return aa_flags;
1327 static FcPattern *create_family_pattern( const char *name )
1329 FcPattern *ret, *pattern = pFcPatternCreate();
1330 FcResult result;
1332 pFcPatternAddString( pattern, FC_FAMILY, (const FcChar8 *)name );
1333 pFcPatternAddString( pattern, FC_NAMELANG, (const FcChar8 *)"en-us" );
1334 pFcPatternAddString( pattern, FC_PRGNAME, (const FcChar8 *)"wine" );
1335 pFcConfigSubstitute( NULL, pattern, FcMatchPattern );
1336 pFcDefaultSubstitute( pattern );
1337 ret = pFcFontMatch( NULL, pattern, &result );
1338 pFcPatternDestroy( pattern );
1339 if (ret && result == FcResultMatch) return ret;
1340 pFcPatternDestroy( ret );
1341 return NULL;
1344 static void init_fontconfig(void)
1346 void *fc_handle = dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW);
1348 if (!fc_handle)
1350 TRACE("Wine cannot find the fontconfig library (%s).\n", SONAME_LIBFONTCONFIG);
1351 return;
1354 #define LOAD_FUNCPTR(f) if((p##f = dlsym(fc_handle, #f)) == NULL){WARN("Can't find symbol %s\n", #f); return;}
1355 LOAD_FUNCPTR(FcConfigSubstitute);
1356 LOAD_FUNCPTR(FcDefaultSubstitute);
1357 LOAD_FUNCPTR(FcFontList);
1358 LOAD_FUNCPTR(FcFontMatch);
1359 LOAD_FUNCPTR(FcFontSetDestroy);
1360 LOAD_FUNCPTR(FcInit);
1361 LOAD_FUNCPTR(FcPatternAddString);
1362 LOAD_FUNCPTR(FcPatternCreate);
1363 LOAD_FUNCPTR(FcPatternDestroy);
1364 LOAD_FUNCPTR(FcPatternGetBool);
1365 LOAD_FUNCPTR(FcPatternGetInteger);
1366 LOAD_FUNCPTR(FcPatternGetString);
1367 #undef LOAD_FUNCPTR
1369 if (pFcInit())
1371 FcPattern *pattern = pFcPatternCreate();
1372 pFcConfigSubstitute( NULL, pattern, FcMatchFont );
1373 default_aa_flags = parse_aa_pattern( pattern );
1374 pFcPatternDestroy( pattern );
1376 if (!default_aa_flags)
1378 FcPattern *pattern = pFcPatternCreate();
1379 pFcConfigSubstitute( NULL, pattern, FcMatchPattern );
1380 default_aa_flags = parse_aa_pattern( pattern );
1381 pFcPatternDestroy( pattern );
1383 pattern_serif = create_family_pattern( "serif" );
1384 pattern_fixed = create_family_pattern( "monospace" );
1385 pattern_sans = create_family_pattern( "sans" );
1387 TRACE( "enabled, default flags = %x\n", default_aa_flags );
1388 fontconfig_enabled = TRUE;
1392 static void load_fontconfig_fonts(void)
1394 FcPattern *pat;
1395 FcFontSet *fontset;
1396 const char *format;
1397 int i;
1398 char *file;
1400 if (!fontconfig_enabled) return;
1402 pat = pFcPatternCreate();
1403 if (!pat) return;
1405 fontset = pFcFontList(NULL, pat, NULL);
1406 if (!fontset)
1408 pFcPatternDestroy(pat);
1409 return;
1412 for(i = 0; i < fontset->nfont; i++) {
1413 FcBool scalable;
1414 DWORD aa_flags;
1416 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1417 continue;
1419 pFcConfigSubstitute( NULL, fontset->fonts[i], FcMatchFont );
1421 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1423 TRACE("not scalable\n");
1424 continue;
1427 if (pFcPatternGetString( fontset->fonts[i], FC_FONTFORMAT, 0, (FcChar8 **)&format ) != FcResultMatch)
1429 TRACE( "ignoring unknown font format %s\n", debugstr_a(file) );
1430 continue;
1433 if (!strcmp( format, "Type 1" ))
1435 TRACE( "ignoring Type 1 font %s\n", debugstr_a(file) );
1436 continue;
1439 aa_flags = parse_aa_pattern( fontset->fonts[i] );
1440 TRACE("fontconfig: %s aa %x\n", file, aa_flags);
1442 AddFontToList( NULL, file, NULL, 0,
1443 ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE | ADDFONT_AA_FLAGS(aa_flags) );
1445 pFcFontSetDestroy(fontset);
1446 pFcPatternDestroy(pat);
1449 #elif defined(HAVE_CARBON_CARBON_H)
1451 static void load_mac_font_callback(const void *value, void *context)
1453 CFStringRef pathStr = value;
1454 CFIndex len;
1455 char* path;
1457 len = CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr);
1458 path = RtlAllocateHeap(GetProcessHeap(), 0, len);
1459 if (path && CFStringGetFileSystemRepresentation(pathStr, path, len))
1461 TRACE("font file %s\n", path);
1462 AddFontToList(NULL, path, NULL, 0, ADDFONT_EXTERNAL_FONT | ADDFONT_ADD_TO_CACHE);
1464 RtlFreeHeap(GetProcessHeap(), 0, path);
1467 static void load_mac_fonts(void)
1469 CFStringRef removeDupesKey;
1470 CFBooleanRef removeDupesValue;
1471 CFDictionaryRef options;
1472 CTFontCollectionRef col;
1473 CFArrayRef descs;
1474 CFMutableSetRef paths;
1475 CFIndex i;
1477 removeDupesKey = kCTFontCollectionRemoveDuplicatesOption;
1478 removeDupesValue = kCFBooleanTrue;
1479 options = CFDictionaryCreate(NULL, (const void**)&removeDupesKey, (const void**)&removeDupesValue, 1,
1480 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1481 col = CTFontCollectionCreateFromAvailableFonts(options);
1482 if (options) CFRelease(options);
1483 if (!col)
1485 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
1486 return;
1489 descs = CTFontCollectionCreateMatchingFontDescriptors(col);
1490 CFRelease(col);
1491 if (!descs)
1493 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
1494 return;
1497 paths = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
1498 if (!paths)
1500 WARN("CFSetCreateMutable failed\n");
1501 CFRelease(descs);
1502 return;
1505 for (i = 0; i < CFArrayGetCount(descs); i++)
1507 CTFontDescriptorRef desc;
1508 CFURLRef url;
1509 CFStringRef ext;
1510 CFStringRef path;
1512 desc = CFArrayGetValueAtIndex(descs, i);
1514 #if defined(MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
1515 url = CTFontDescriptorCopyAttribute(desc, kCTFontURLAttribute);
1516 #else
1517 /* CTFontDescriptor doesn't support kCTFontURLAttribute prior to 10.6, so
1518 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
1520 CTFontRef font;
1521 ATSFontRef atsFont;
1522 OSStatus status;
1523 FSRef fsref;
1525 font = CTFontCreateWithFontDescriptor(desc, 0, NULL);
1526 if (!font) continue;
1528 atsFont = CTFontGetPlatformFont(font, NULL);
1529 if (!atsFont)
1531 CFRelease(font);
1532 continue;
1535 status = ATSFontGetFileReference(atsFont, &fsref);
1536 CFRelease(font);
1537 if (status != noErr) continue;
1539 url = CFURLCreateFromFSRef(NULL, &fsref);
1541 #endif
1542 if (!url) continue;
1544 ext = CFURLCopyPathExtension(url);
1545 if (ext)
1547 BOOL skip = (CFStringCompare(ext, CFSTR("pfa"), kCFCompareCaseInsensitive) == kCFCompareEqualTo ||
1548 CFStringCompare(ext, CFSTR("pfb"), kCFCompareCaseInsensitive) == kCFCompareEqualTo);
1549 CFRelease(ext);
1550 if (skip)
1552 CFRelease(url);
1553 continue;
1557 path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
1558 CFRelease(url);
1559 if (!path) continue;
1561 CFSetAddValue(paths, path);
1562 CFRelease(path);
1565 CFRelease(descs);
1567 CFSetApplyFunction(paths, load_mac_font_callback, NULL);
1568 CFRelease(paths);
1571 #endif
1574 static BOOL init_freetype(void)
1576 ft_handle = dlopen(SONAME_LIBFREETYPE, RTLD_NOW);
1577 if(!ft_handle) {
1578 WINE_MESSAGE(
1579 "Wine cannot find the FreeType font library. To enable Wine to\n"
1580 "use TrueType fonts please install a version of FreeType greater than\n"
1581 "or equal to 2.0.5.\n"
1582 "http://www.freetype.org\n");
1583 return FALSE;
1586 #define LOAD_FUNCPTR(f) if((p##f = dlsym(ft_handle, #f)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
1588 LOAD_FUNCPTR(FT_Done_Face)
1589 LOAD_FUNCPTR(FT_Get_Char_Index)
1590 LOAD_FUNCPTR(FT_Get_First_Char)
1591 LOAD_FUNCPTR(FT_Get_Next_Char)
1592 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
1593 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
1594 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
1595 LOAD_FUNCPTR(FT_Get_WinFNT_Header)
1596 LOAD_FUNCPTR(FT_Init_FreeType)
1597 LOAD_FUNCPTR(FT_Library_Version)
1598 LOAD_FUNCPTR(FT_Load_Glyph)
1599 LOAD_FUNCPTR(FT_Load_Sfnt_Table)
1600 LOAD_FUNCPTR(FT_Matrix_Multiply)
1601 LOAD_FUNCPTR(FT_MulDiv)
1602 #ifndef FT_MULFIX_INLINED
1603 LOAD_FUNCPTR(FT_MulFix)
1604 #endif
1605 LOAD_FUNCPTR(FT_New_Face)
1606 LOAD_FUNCPTR(FT_New_Memory_Face)
1607 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
1608 LOAD_FUNCPTR(FT_Outline_Get_CBox)
1609 LOAD_FUNCPTR(FT_Outline_Transform)
1610 LOAD_FUNCPTR(FT_Outline_Translate)
1611 LOAD_FUNCPTR(FT_Render_Glyph)
1612 LOAD_FUNCPTR(FT_Set_Charmap)
1613 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
1614 LOAD_FUNCPTR(FT_Vector_Length)
1615 LOAD_FUNCPTR(FT_Vector_Transform)
1616 LOAD_FUNCPTR(FT_Vector_Unit)
1617 #undef LOAD_FUNCPTR
1618 /* Don't warn if these ones are missing */
1619 pFT_Outline_Embolden = dlsym(ft_handle, "FT_Outline_Embolden");
1620 pFT_Get_TrueType_Engine_Type = dlsym(ft_handle, "FT_Get_TrueType_Engine_Type");
1621 #ifdef FT_LCD_FILTER_H
1622 pFT_Library_SetLcdFilter = dlsym(ft_handle, "FT_Library_SetLcdFilter");
1623 #endif
1624 pFT_Property_Set = dlsym(ft_handle, "FT_Property_Set");
1626 if(pFT_Init_FreeType(&library) != 0) {
1627 ERR("Can't init FreeType library\n");
1628 dlclose(ft_handle);
1629 ft_handle = NULL;
1630 return FALSE;
1632 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
1634 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
1635 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
1636 ((FT_Version.minor << 8) & 0x00ff00) |
1637 ((FT_Version.patch ) & 0x0000ff);
1639 /* In FreeType < 2.8.1 v40's FT_LOAD_TARGET_MONO has broken advance widths. */
1640 if (pFT_Property_Set && FT_SimpleVersion < FT_VERSION_VALUE(2, 8, 1))
1642 FT_UInt interpreter_version = 35;
1643 pFT_Property_Set( library, "truetype", "interpreter-version", &interpreter_version );
1646 return TRUE;
1648 sym_not_found:
1649 WINE_MESSAGE(
1650 "Wine cannot find certain functions that it needs inside the FreeType\n"
1651 "font library. To enable Wine to use TrueType fonts please upgrade\n"
1652 "FreeType to at least version 2.1.4.\n"
1653 "http://www.freetype.org\n");
1654 dlclose(ft_handle);
1655 ft_handle = NULL;
1656 return FALSE;
1659 /*************************************************************
1660 * freetype_load_fonts
1662 static void CDECL freetype_load_fonts(void)
1664 #ifdef SONAME_LIBFONTCONFIG
1665 load_fontconfig_fonts();
1666 #elif defined(HAVE_CARBON_CARBON_H)
1667 load_mac_fonts();
1668 #elif defined(__ANDROID__)
1669 ReadFontDir("/system/fonts", TRUE);
1670 #endif
1673 /* Some fonts have large usWinDescent values, as a result of storing signed short
1674 in unsigned field. That's probably caused by sTypoDescent vs usWinDescent confusion in
1675 some font generation tools. */
1676 static inline USHORT get_fixed_windescent(USHORT windescent)
1678 return abs((SHORT)windescent);
1681 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
1683 TT_OS2 *pOS2;
1684 TT_HoriHeader *pHori;
1686 LONG ppem;
1687 const LONG MAX_PPEM = (1 << 16) - 1;
1689 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1690 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1692 if(height == 0) height = 16;
1694 /* Calc. height of EM square:
1696 * For +ve lfHeight we have
1697 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
1698 * Re-arranging gives:
1699 * ppem = units_per_em * lfheight / (winAscent + winDescent)
1701 * For -ve lfHeight we have
1702 * |lfHeight| = ppem
1703 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
1704 * with il = winAscent + winDescent - units_per_em]
1708 if(height > 0) {
1709 USHORT windescent = get_fixed_windescent(pOS2->usWinDescent);
1710 if(pOS2->usWinAscent + windescent == 0)
1711 ppem = pFT_MulDiv(ft_face->units_per_EM, height, pHori->Ascender - pHori->Descender);
1712 else
1713 ppem = pFT_MulDiv(ft_face->units_per_EM, height, pOS2->usWinAscent + windescent);
1714 if(ppem > MAX_PPEM) {
1715 WARN("Ignoring too large height %d, ppem %d\n", height, ppem);
1716 ppem = 1;
1719 else if(height >= -MAX_PPEM)
1720 ppem = -height;
1721 else {
1722 WARN("Ignoring too large height %d\n", height);
1723 ppem = 1;
1726 return ppem;
1729 static struct font_mapping *map_font_file( const char *name )
1731 struct font_mapping *mapping;
1732 struct stat st;
1733 int fd;
1735 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
1736 if (fstat( fd, &st ) == -1) goto error;
1738 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
1740 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
1742 mapping->refcount++;
1743 close( fd );
1744 return mapping;
1747 if (!(mapping = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*mapping) )))
1748 goto error;
1750 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
1751 close( fd );
1753 if (mapping->data == MAP_FAILED)
1755 RtlFreeHeap( GetProcessHeap(), 0, mapping );
1756 return NULL;
1758 mapping->refcount = 1;
1759 mapping->dev = st.st_dev;
1760 mapping->ino = st.st_ino;
1761 mapping->size = st.st_size;
1762 list_add_tail( &mappings_list, &mapping->entry );
1763 return mapping;
1765 error:
1766 close( fd );
1767 return NULL;
1770 static void unmap_font_file( struct font_mapping *mapping )
1772 if (!--mapping->refcount)
1774 list_remove( &mapping->entry );
1775 munmap( mapping->data, mapping->size );
1776 RtlFreeHeap( GetProcessHeap(), 0, mapping );
1780 static LONG load_VDMX(struct gdi_font *font, LONG height);
1782 /*************************************************************
1783 * freetype_destroy_font
1785 static void CDECL freetype_destroy_font( struct gdi_font *font )
1787 struct font_private_data *data = font->private;
1789 if (data->ft_face) pFT_Done_Face( data->ft_face );
1790 if (data->mapping) unmap_font_file( data->mapping );
1791 RtlFreeHeap( GetProcessHeap(), 0, data );
1794 /*************************************************************
1795 * freetype_get_font_data
1797 static DWORD CDECL freetype_get_font_data( struct gdi_font *font, DWORD table, DWORD offset,
1798 void *buf, DWORD cbData)
1800 FT_Face ft_face = get_ft_face( font );
1801 FT_ULong len;
1802 FT_Error err;
1804 if (!FT_IS_SFNT(ft_face)) return GDI_ERROR;
1806 if(!buf)
1807 len = 0;
1808 else
1809 len = cbData;
1811 /* if font is a member of TTC, 'ttcf' tag allows reading from beginning of TTC file,
1812 0 tag means to read from start of collection member data. */
1813 if (font->ttc_item_offset)
1815 if (table == MS_TTCF_TAG)
1816 table = 0;
1817 else if (table == 0)
1818 offset += font->ttc_item_offset;
1821 /* make sure value of len is the value freetype says it needs */
1822 if (buf && len)
1824 FT_ULong needed = 0;
1825 err = pFT_Load_Sfnt_Table(ft_face, RtlUlongByteSwap(table), offset, NULL, &needed);
1826 if( !err && needed < len) len = needed;
1828 err = pFT_Load_Sfnt_Table(ft_face, RtlUlongByteSwap(table), offset, buf, &len);
1829 if (err)
1831 TRACE("Can't find table %s\n", debugstr_an((char*)&table, 4));
1832 return GDI_ERROR;
1834 return len;
1837 /*************************************************************
1838 * load_VDMX
1840 * load the vdmx entry for the specified height
1845 typedef struct {
1846 WORD version;
1847 WORD numRecs;
1848 WORD numRatios;
1849 } VDMX_Header;
1851 typedef struct {
1852 BYTE bCharSet;
1853 BYTE xRatio;
1854 BYTE yStartRatio;
1855 BYTE yEndRatio;
1856 } Ratios;
1858 typedef struct {
1859 WORD recs;
1860 BYTE startsz;
1861 BYTE endsz;
1862 } VDMX_group;
1864 typedef struct {
1865 WORD yPelHeight;
1866 WORD yMax;
1867 WORD yMin;
1868 } VDMX_vTable;
1870 static LONG load_VDMX(struct gdi_font *font, LONG height)
1872 VDMX_Header hdr;
1873 VDMX_group group;
1874 BYTE devXRatio, devYRatio;
1875 USHORT numRecs, numRatios;
1876 DWORD result, offset = -1;
1877 LONG ppem = 0;
1878 int i;
1880 result = freetype_get_font_data(font, MS_VDMX_TAG, 0, &hdr, sizeof(hdr));
1882 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
1883 return ppem;
1885 /* FIXME: need the real device aspect ratio */
1886 devXRatio = 1;
1887 devYRatio = 1;
1889 numRecs = GET_BE_WORD(hdr.numRecs);
1890 numRatios = GET_BE_WORD(hdr.numRatios);
1892 TRACE("version = %d numRecs = %d numRatios = %d\n", GET_BE_WORD(hdr.version), numRecs, numRatios);
1893 for(i = 0; i < numRatios; i++) {
1894 Ratios ratio;
1896 offset = sizeof(hdr) + (i * sizeof(Ratios));
1897 freetype_get_font_data(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
1898 offset = -1;
1900 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
1902 if (!ratio.bCharSet) continue;
1904 if((ratio.xRatio == 0 &&
1905 ratio.yStartRatio == 0 &&
1906 ratio.yEndRatio == 0) ||
1907 (devXRatio == ratio.xRatio &&
1908 devYRatio >= ratio.yStartRatio &&
1909 devYRatio <= ratio.yEndRatio))
1911 WORD group_offset;
1913 offset = sizeof(hdr) + numRatios * sizeof(ratio) + i * sizeof(group_offset);
1914 freetype_get_font_data(font, MS_VDMX_TAG, offset, &group_offset, sizeof(group_offset));
1915 offset = GET_BE_WORD(group_offset);
1916 break;
1920 if(offset == -1) return 0;
1922 if(freetype_get_font_data(font, MS_VDMX_TAG, offset, &group, sizeof(group)) != GDI_ERROR) {
1923 USHORT recs;
1924 BYTE startsz, endsz;
1925 WORD *vTable;
1927 recs = GET_BE_WORD(group.recs);
1928 startsz = group.startsz;
1929 endsz = group.endsz;
1931 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
1933 vTable = RtlAllocateHeap(GetProcessHeap(), 0, recs * sizeof(VDMX_vTable));
1934 result = freetype_get_font_data(font, MS_VDMX_TAG, offset + sizeof(group), vTable, recs * sizeof(VDMX_vTable));
1935 if(result == GDI_ERROR) {
1936 FIXME("Failed to retrieve vTable\n");
1937 goto end;
1940 if(height > 0) {
1941 for(i = 0; i < recs; i++) {
1942 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
1943 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
1944 ppem = GET_BE_WORD(vTable[i * 3]);
1946 if(yMax + -yMin == height) {
1947 font->yMax = yMax;
1948 font->yMin = yMin;
1949 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1950 break;
1952 if(yMax + -yMin > height) {
1953 if(--i < 0) {
1954 ppem = 0;
1955 goto end; /* failed */
1957 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
1958 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
1959 ppem = GET_BE_WORD(vTable[i * 3]);
1960 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1961 break;
1964 if(!font->yMax) {
1965 ppem = 0;
1966 TRACE("ppem not found for height %d\n", height);
1968 } else {
1969 ppem = -height;
1970 if(ppem < startsz || ppem > endsz)
1972 ppem = 0;
1973 goto end;
1976 for(i = 0; i < recs; i++) {
1977 USHORT yPelHeight;
1978 yPelHeight = GET_BE_WORD(vTable[i * 3]);
1980 if(yPelHeight > ppem)
1982 ppem = 0;
1983 break; /* failed */
1986 if(yPelHeight == ppem) {
1987 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
1988 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
1989 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
1990 break;
1994 end:
1995 RtlFreeHeap(GetProcessHeap(), 0, vTable);
1998 return ppem;
2001 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
2003 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
2004 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
2005 FT_Int i;
2007 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
2009 for (i = 0; i < ft_face->num_charmaps; i++)
2011 if (ft_face->charmaps[i]->encoding == encoding)
2013 TRACE("found cmap with platform_id %u, encoding_id %u\n",
2014 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
2016 switch (ft_face->charmaps[i]->platform_id)
2018 default:
2019 cmap_def = ft_face->charmaps[i];
2020 break;
2021 case 0: /* Apple Unicode */
2022 cmap0 = ft_face->charmaps[i];
2023 break;
2024 case 1: /* Macintosh */
2025 cmap1 = ft_face->charmaps[i];
2026 break;
2027 case 2: /* ISO */
2028 cmap2 = ft_face->charmaps[i];
2029 break;
2030 case 3: /* Microsoft */
2031 cmap3 = ft_face->charmaps[i];
2032 break;
2036 if (cmap3) /* prefer Microsoft cmap table */
2037 ft_err = pFT_Set_Charmap(ft_face, cmap3);
2038 else if (cmap1)
2039 ft_err = pFT_Set_Charmap(ft_face, cmap1);
2040 else if (cmap2)
2041 ft_err = pFT_Set_Charmap(ft_face, cmap2);
2042 else if (cmap0)
2043 ft_err = pFT_Set_Charmap(ft_face, cmap0);
2044 else if (cmap_def)
2045 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
2048 return ft_err == FT_Err_Ok;
2052 static FT_Encoding pick_charmap( FT_Face face, int charset )
2054 static const FT_Encoding regular_order[] = { FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, FT_ENCODING_MS_SYMBOL, 0 };
2055 static const FT_Encoding symbol_order[] = { FT_ENCODING_MS_SYMBOL, FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, 0 };
2056 const FT_Encoding *encs = regular_order;
2058 if (charset == SYMBOL_CHARSET) encs = symbol_order;
2060 while (*encs != 0)
2062 if (select_charmap( face, *encs )) break;
2063 encs++;
2066 if (!face->charmap && face->num_charmaps)
2068 if (!pFT_Set_Charmap(face, face->charmaps[0]))
2069 return face->charmap->encoding;
2072 return *encs;
2075 static BOOL get_gasp_flags( struct gdi_font *font, WORD *flags )
2077 FT_Face ft_face = get_ft_face( font );
2078 DWORD size;
2079 WORD buf[16]; /* Enough for seven ranges before we need to alloc */
2080 WORD *alloced = NULL, *ptr = buf;
2081 WORD num_recs, version;
2082 BOOL ret = FALSE;
2084 *flags = 0;
2085 size = freetype_get_font_data( font, MS_GASP_TAG, 0, NULL, 0 );
2086 if (size == GDI_ERROR) return FALSE;
2087 if (size < 4 * sizeof(WORD)) return FALSE;
2088 if (size > sizeof(buf))
2090 ptr = alloced = RtlAllocateHeap( GetProcessHeap(), 0, size );
2091 if (!ptr) return FALSE;
2094 freetype_get_font_data( font, MS_GASP_TAG, 0, ptr, size );
2096 version = GET_BE_WORD( *ptr++ );
2097 num_recs = GET_BE_WORD( *ptr++ );
2099 if (version > 1 || size < (num_recs * 2 + 2) * sizeof(WORD))
2101 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version, size, num_recs );
2102 goto done;
2105 while (num_recs--)
2107 *flags = GET_BE_WORD( *(ptr + 1) );
2108 if (ft_face->size->metrics.y_ppem <= GET_BE_WORD( *ptr )) break;
2109 ptr += 2;
2111 TRACE( "got flags %04x for ppem %d\n", *flags, ft_face->size->metrics.y_ppem );
2112 ret = TRUE;
2114 done:
2115 RtlFreeHeap( GetProcessHeap(), 0, alloced );
2116 return ret;
2119 /*************************************************************
2120 * fontconfig_enum_family_fallbacks
2122 static BOOL CDECL fontconfig_enum_family_fallbacks( DWORD pitch_and_family, int index,
2123 WCHAR buffer[LF_FACESIZE] )
2125 #ifdef SONAME_LIBFONTCONFIG
2126 FcPattern *pat;
2127 char *str;
2128 DWORD len;
2130 if ((pitch_and_family & FIXED_PITCH) || (pitch_and_family & 0xf0) == FF_MODERN) pat = pattern_fixed;
2131 else if ((pitch_and_family & 0xf0) == FF_ROMAN) pat = pattern_serif;
2132 else pat = pattern_sans;
2134 if (!pat) return FALSE;
2135 if (pFcPatternGetString( pat, FC_FAMILY, index, (FcChar8 **)&str ) != FcResultMatch) return FALSE;
2136 RtlUTF8ToUnicodeN( buffer, (LF_FACESIZE - 1) * sizeof(WCHAR), &len, str, strlen(str) );
2137 buffer[len / sizeof(WCHAR)] = 0;
2138 return TRUE;
2139 #endif
2140 return FALSE;
2143 static DWORD get_ttc_offset( FT_Face ft_face, UINT face_index )
2145 FT_ULong len;
2146 DWORD header, offset;
2148 /* see if it's a TTC */
2149 len = sizeof(header);
2150 if (pFT_Load_Sfnt_Table( ft_face, 0, 0, (void *)&header, &len )) return 0;
2151 if (header != MS_TTCF_TAG) return 0;
2153 len = sizeof(offset);
2154 if (pFT_Load_Sfnt_Table( ft_face, 0, (3 + face_index) * sizeof(DWORD), (void *)&offset, &len ))
2155 return 0;
2157 return GET_BE_DWORD( offset );
2160 /*************************************************************
2161 * freetype_load_font
2163 static BOOL CDECL freetype_load_font( struct gdi_font *font )
2165 struct font_private_data *data;
2166 INT width = 0, height;
2167 FT_Face ft_face;
2168 void *data_ptr;
2169 SIZE_T data_size;
2171 if (!(data = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data) ))) return FALSE;
2172 font->private = data;
2174 if (font->file[0])
2176 char *filename = get_unix_file_name( font->file );
2177 data->mapping = map_font_file( filename );
2178 RtlFreeHeap( GetProcessHeap(), 0, filename );
2179 if (!data->mapping)
2181 WARN("failed to map %s\n", debugstr_w(font->file));
2182 return FALSE;
2184 data_ptr = data->mapping->data;
2185 data_size = data->mapping->size;
2187 else
2189 data_ptr = font->data_ptr;
2190 data_size = font->data_size;
2193 if (pFT_New_Memory_Face( library, data_ptr, data_size, font->face_index, &ft_face )) return FALSE;
2195 data->ft_face = ft_face;
2196 font->scalable = FT_IS_SCALABLE( ft_face );
2197 if (!font->fs.fsCsb[0]) get_fontsig( ft_face, &font->fs );
2198 if (!font->ntmFlags) font->ntmFlags = get_ntm_flags( ft_face );
2199 if (!font->aa_flags) font->aa_flags = ADDFONT_AA_FLAGS( default_aa_flags );
2200 if (!font->otm.otmpFamilyName)
2202 font->otm.otmpFamilyName = (char *)ft_face_get_family_name( ft_face, system_lcid );
2203 font->otm.otmpStyleName = (char *)ft_face_get_style_name( ft_face, system_lcid );
2204 font->otm.otmpFaceName = (char *)ft_face_get_full_name( ft_face, system_lcid );
2207 if (font->scalable)
2209 /* load the VDMX table if we have one */
2210 font->ppem = load_VDMX( font, font->lf.lfHeight );
2211 if (font->ppem == 0) font->ppem = calc_ppem_for_height( ft_face, font->lf.lfHeight );
2212 TRACE( "height %d => ppem %d\n", font->lf.lfHeight, font->ppem );
2213 height = font->ppem;
2214 font->ttc_item_offset = get_ttc_offset( ft_face, font->face_index );
2216 else
2218 struct bitmap_font_size size;
2220 get_bitmap_size( ft_face, &size );
2221 width = size.x_ppem >> 6;
2222 height = size.y_ppem >> 6;
2223 font->ppem = height;
2226 pFT_Set_Pixel_Sizes( ft_face, width, height );
2227 pick_charmap( ft_face, font->charset );
2228 return TRUE;
2232 /*************************************************************
2233 * freetype_get_aa_flags
2235 static UINT CDECL freetype_get_aa_flags( struct gdi_font *font, UINT aa_flags, BOOL antialias_fakes )
2237 /* fixup the antialiasing flags for that font */
2238 switch (aa_flags)
2240 case WINE_GGO_HRGB_BITMAP:
2241 case WINE_GGO_HBGR_BITMAP:
2242 case WINE_GGO_VRGB_BITMAP:
2243 case WINE_GGO_VBGR_BITMAP:
2244 if (is_subpixel_rendering_enabled()) break;
2245 aa_flags = GGO_GRAY4_BITMAP;
2246 /* fall through */
2247 case GGO_GRAY2_BITMAP:
2248 case GGO_GRAY4_BITMAP:
2249 case GGO_GRAY8_BITMAP:
2250 case WINE_GGO_GRAY16_BITMAP:
2251 if ((!antialias_fakes || (!font->fake_bold && !font->fake_italic)) && is_hinting_enabled())
2253 WORD gasp_flags;
2254 if (get_gasp_flags( font, &gasp_flags ) && !(gasp_flags & GASP_DOGRAY))
2256 TRACE( "font %s %d aa disabled by GASP\n",
2257 debugstr_w(font->lf.lfFaceName), font->lf.lfHeight );
2258 aa_flags = GGO_BITMAP;
2262 return aa_flags;
2265 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
2267 pt->x.value = vec->x >> 6;
2268 pt->x.fract = (vec->x & 0x3f) << 10;
2269 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
2270 pt->y.value = vec->y >> 6;
2271 pt->y.fract = (vec->y & 0x3f) << 10;
2272 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
2275 static FT_UInt get_glyph_index_symbol( struct gdi_font *font, UINT glyph )
2277 FT_Face ft_face = get_ft_face( font );
2278 FT_UInt ret;
2280 if (glyph < 0x100) glyph += 0xf000;
2281 /* there are a number of old pre-Unicode "broken" TTFs, which
2282 do have symbols at U+00XX instead of U+f0XX */
2283 if (!(ret = pFT_Get_Char_Index(ft_face, glyph)))
2284 ret = pFT_Get_Char_Index(ft_face, glyph - 0xf000);
2286 return ret;
2289 /*************************************************************
2290 * freetype_get_glyph_index
2292 static BOOL CDECL freetype_get_glyph_index( struct gdi_font *font, UINT *glyph, BOOL use_encoding )
2294 FT_Face ft_face = get_ft_face( font );
2296 if (!use_encoding ^ (ft_face->charmap->encoding == FT_ENCODING_NONE)) return FALSE;
2298 if (ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
2300 if (!(*glyph = get_glyph_index_symbol( font, *glyph )))
2302 WCHAR wc = *glyph;
2303 DWORD len;
2304 char ch;
2306 RtlUnicodeToMultiByteN( &ch, 1, &len, &wc, sizeof(wc) );
2307 if (len) *glyph = get_glyph_index_symbol( font, (unsigned char)ch );
2309 return TRUE;
2311 *glyph = pFT_Get_Char_Index( ft_face, *glyph );
2312 return TRUE;
2315 /*************************************************************
2316 * freetype_get_default_glyph
2318 static UINT CDECL freetype_get_default_glyph( struct gdi_font *font )
2320 FT_Face ft_face = get_ft_face( font );
2321 FT_WinFNT_HeaderRec winfnt;
2322 TT_OS2 *pOS2;
2324 if ((pOS2 = pFT_Get_Sfnt_Table( ft_face, ft_sfnt_os2 )))
2326 UINT glyph = pOS2->usDefaultChar;
2327 freetype_get_glyph_index( font, &glyph, TRUE );
2328 return glyph;
2330 if (!pFT_Get_WinFNT_Header( ft_face, &winfnt )) return winfnt.default_char + winfnt.first_char;
2331 return 32;
2335 static inline BOOL is_identity_FMAT2(const FMAT2 *matrix)
2337 static const FMAT2 identity = { 1.0, 0.0, 0.0, 1.0 };
2338 return !memcmp(matrix, &identity, sizeof(FMAT2));
2341 static inline FT_Vector normalize_vector(FT_Vector *vec)
2343 FT_Vector out;
2344 FT_Fixed len;
2345 len = pFT_Vector_Length(vec);
2346 if (len) {
2347 out.x = (vec->x << 6) / len;
2348 out.y = (vec->y << 6) / len;
2350 else
2351 out.x = out.y = 0;
2352 return out;
2355 /* get_glyph_outline() glyph transform matrices index */
2356 enum matrices_index
2358 matrix_hori,
2359 matrix_vert,
2360 matrix_unrotated
2363 static BOOL get_transform_matrices( struct gdi_font *font, BOOL vertical, const MAT2 *user_transform,
2364 FT_Matrix matrices[3] )
2366 static const FT_Matrix identity_mat = { (1 << 16), 0, 0, (1 << 16) };
2367 BOOL needs_transform = FALSE;
2368 double width_ratio;
2369 int i;
2371 matrices[matrix_unrotated] = identity_mat;
2373 /* Scaling factor */
2374 if (font->aveWidth)
2376 if (!freetype_set_outline_text_metrics( font )) freetype_set_bitmap_text_metrics( font );
2377 width_ratio = (double)font->aveWidth;
2378 width_ratio /= (double)font->otm.otmTextMetrics.tmAveCharWidth;
2380 else
2381 width_ratio = font->scale_y;
2383 /* Scaling transform */
2384 if (width_ratio != 1.0 || font->scale_y != 1)
2386 FT_Matrix scale_mat;
2387 scale_mat.xx = FT_FixedFromFloat( width_ratio );
2388 scale_mat.xy = 0;
2389 scale_mat.yx = 0;
2390 scale_mat.yy = font->scale_y << 16;
2392 pFT_Matrix_Multiply( &scale_mat, &matrices[matrix_unrotated] );
2393 needs_transform = TRUE;
2396 /* Slant transform */
2397 if (font->fake_italic)
2399 FT_Matrix slant_mat;
2400 slant_mat.xx = (1 << 16);
2401 slant_mat.xy = (1 << 16) >> 2;
2402 slant_mat.yx = 0;
2403 slant_mat.yy = (1 << 16);
2405 pFT_Matrix_Multiply( &slant_mat, &matrices[matrix_unrotated] );
2406 needs_transform = TRUE;
2409 /* Rotation transform */
2410 matrices[matrix_hori] = matrices[matrix_unrotated];
2411 if (font->scalable && font->lf.lfOrientation % 3600)
2413 FT_Matrix rotation_mat;
2414 FT_Vector angle;
2416 pFT_Vector_Unit( &angle, pFT_MulDiv( 1 << 16, font->lf.lfOrientation, 10 ) );
2417 rotation_mat.xx = angle.x;
2418 rotation_mat.xy = -angle.y;
2419 rotation_mat.yx = angle.y;
2420 rotation_mat.yy = angle.x;
2421 pFT_Matrix_Multiply( &rotation_mat, &matrices[matrix_hori] );
2422 needs_transform = TRUE;
2425 /* Vertical transform */
2426 matrices[matrix_vert] = matrices[matrix_hori];
2427 if (vertical)
2429 FT_Matrix vertical_mat = { 0, -(1 << 16), 1 << 16, 0 }; /* 90 degrees rotation */
2431 pFT_Matrix_Multiply( &vertical_mat, &matrices[matrix_vert] );
2432 needs_transform = TRUE;
2435 /* World transform */
2436 if (!is_identity_FMAT2( &font->matrix ))
2438 FT_Matrix world_mat;
2439 world_mat.xx = FT_FixedFromFloat( font->matrix.eM11 );
2440 world_mat.xy = -FT_FixedFromFloat( font->matrix.eM21 );
2441 world_mat.yx = -FT_FixedFromFloat( font->matrix.eM12 );
2442 world_mat.yy = FT_FixedFromFloat( font->matrix.eM22 );
2444 for (i = 0; i < 3; i++)
2445 pFT_Matrix_Multiply( &world_mat, &matrices[i] );
2446 needs_transform = TRUE;
2449 /* Extra transformation specified by caller */
2450 if (user_transform)
2452 FT_Matrix user_mat;
2453 user_mat.xx = FT_FixedFromFIXED( user_transform->eM11 );
2454 user_mat.xy = FT_FixedFromFIXED( user_transform->eM21 );
2455 user_mat.yx = FT_FixedFromFIXED( user_transform->eM12 );
2456 user_mat.yy = FT_FixedFromFIXED( user_transform->eM22 );
2458 for (i = 0; i < 3; i++)
2459 pFT_Matrix_Multiply( &user_mat, &matrices[i] );
2460 needs_transform = TRUE;
2463 return needs_transform;
2466 static BOOL get_bold_glyph_outline(FT_GlyphSlot glyph, LONG ppem, FT_Glyph_Metrics *metrics)
2468 FT_Error err;
2469 FT_Pos strength;
2470 FT_BBox bbox;
2472 if(glyph->format != FT_GLYPH_FORMAT_OUTLINE)
2473 return FALSE;
2474 if(!pFT_Outline_Embolden)
2475 return FALSE;
2477 strength = pFT_MulDiv(ppem, 1 << 6, 24);
2478 err = pFT_Outline_Embolden(&glyph->outline, strength);
2479 if(err) {
2480 TRACE("FT_Ouline_Embolden returns %d\n", err);
2481 return FALSE;
2484 pFT_Outline_Get_CBox(&glyph->outline, &bbox);
2485 metrics->width = bbox.xMax - bbox.xMin;
2486 metrics->height = bbox.yMax - bbox.yMin;
2487 metrics->horiBearingX = bbox.xMin;
2488 metrics->horiBearingY = bbox.yMax;
2489 metrics->vertBearingX = metrics->horiBearingX - metrics->horiAdvance / 2;
2490 metrics->vertBearingY = (metrics->vertAdvance - metrics->height) / 2;
2491 return TRUE;
2494 static inline BYTE get_max_level( UINT format )
2496 switch( format )
2498 case GGO_GRAY2_BITMAP: return 4;
2499 case GGO_GRAY4_BITMAP: return 16;
2500 case GGO_GRAY8_BITMAP: return 64;
2502 return 255;
2505 static FT_Vector get_advance_metric(struct gdi_font *incoming_font, struct gdi_font *font,
2506 const FT_Glyph_Metrics *metrics,
2507 const FT_Matrix *transMat, BOOL vertical_metrics)
2509 FT_Vector adv;
2510 FT_Fixed base_advance, em_scale = 0;
2511 BOOL fixed_pitch_full = FALSE;
2513 if (vertical_metrics)
2514 base_advance = metrics->vertAdvance;
2515 else
2516 base_advance = metrics->horiAdvance;
2518 adv.x = base_advance;
2519 adv.y = 0;
2521 /* In fixed-pitch font, we adjust the fullwidth character advance so that
2522 they have double halfwidth character width. E.g. if the font is 19 ppem,
2523 we return 20 (not 19) for fullwidth characters as we return 10 for
2524 halfwidth characters. */
2525 if (freetype_set_outline_text_metrics(incoming_font) &&
2526 !(incoming_font->otm.otmTextMetrics.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
2527 UINT avg_advance;
2528 em_scale = pFT_MulDiv(incoming_font->ppem, 1 << 16, get_ft_face(incoming_font)->units_per_EM);
2529 avg_advance = pFT_MulFix(incoming_font->ntmAvgWidth, em_scale);
2530 fixed_pitch_full = (avg_advance > 0 &&
2531 (base_advance + 63) >> 6 ==
2532 pFT_MulFix(incoming_font->ntmAvgWidth*2, em_scale));
2533 if (fixed_pitch_full && !transMat)
2534 adv.x = (avg_advance * 2) << 6;
2537 if (transMat) {
2538 pFT_Vector_Transform(&adv, transMat);
2539 if (fixed_pitch_full && adv.y == 0) {
2540 FT_Vector vec;
2541 vec.x = incoming_font->ntmAvgWidth;
2542 vec.y = 0;
2543 pFT_Vector_Transform(&vec, transMat);
2544 adv.x = (pFT_MulFix(vec.x, em_scale) * 2) << 6;
2548 if (font->fake_bold) {
2549 if (!transMat)
2550 adv.x += 1 << 6;
2551 else {
2552 FT_Vector fake_bold_adv, vec = { 1 << 6, 0 };
2553 pFT_Vector_Transform(&vec, transMat);
2554 fake_bold_adv = normalize_vector(&vec);
2555 adv.x += fake_bold_adv.x;
2556 adv.y += fake_bold_adv.y;
2560 adv.x = (adv.x + 63) & -64;
2561 adv.y = -((adv.y + 63) & -64);
2562 return adv;
2565 static FT_BBox get_transformed_bbox( const FT_Glyph_Metrics *metrics,
2566 BOOL needs_transform, const FT_Matrix metrices[3] )
2568 FT_BBox bbox = { 0, 0, 0, 0 };
2570 if (!needs_transform)
2572 bbox.xMin = (metrics->horiBearingX) & -64;
2573 bbox.xMax = (metrics->horiBearingX + metrics->width + 63) & -64;
2574 bbox.yMax = (metrics->horiBearingY + 63) & -64;
2575 bbox.yMin = (metrics->horiBearingY - metrics->height) & -64;
2577 else
2579 FT_Vector vec;
2580 INT xc, yc;
2582 for (xc = 0; xc < 2; xc++)
2584 for (yc = 0; yc < 2; yc++)
2586 vec.x = metrics->horiBearingX + xc * metrics->width;
2587 vec.y = metrics->horiBearingY - yc * metrics->height;
2588 TRACE( "Vec %ld,i %ld\n", vec.x, vec.y );
2589 pFT_Vector_Transform( &vec, &metrices[matrix_vert] );
2590 if (xc == 0 && yc == 0)
2592 bbox.xMin = bbox.xMax = vec.x;
2593 bbox.yMin = bbox.yMax = vec.y;
2595 else
2597 if (vec.x < bbox.xMin) bbox.xMin = vec.x;
2598 else if (vec.x > bbox.xMax) bbox.xMax = vec.x;
2599 if (vec.y < bbox.yMin) bbox.yMin = vec.y;
2600 else if (vec.y > bbox.yMax) bbox.yMax = vec.y;
2604 bbox.xMin = bbox.xMin & -64;
2605 bbox.xMax = (bbox.xMax + 63) & -64;
2606 bbox.yMin = bbox.yMin & -64;
2607 bbox.yMax = (bbox.yMax + 63) & -64;
2608 TRACE( "transformed box: (%ld, %ld - %ld, %ld)\n", bbox.xMin, bbox.yMax, bbox.xMax, bbox.yMin );
2611 return bbox;
2614 static void compute_metrics( struct gdi_font *incoming_font, struct gdi_font *font,
2615 FT_BBox bbox, const FT_Glyph_Metrics *metrics,
2616 BOOL vertical, BOOL vertical_metrics,
2617 BOOL needs_transform, const FT_Matrix matrices[3],
2618 GLYPHMETRICS *gm, ABC *abc )
2620 FT_Vector adv, vec, origin;
2622 if (!needs_transform)
2624 adv = get_advance_metric( incoming_font, font, metrics, NULL, vertical_metrics );
2625 gm->gmCellIncX = adv.x >> 6;
2626 gm->gmCellIncY = 0;
2627 origin.x = bbox.xMin;
2628 origin.y = bbox.yMax;
2629 abc->abcA = origin.x >> 6;
2630 abc->abcB = (metrics->width + 63) >> 6;
2632 else
2634 FT_Pos lsb;
2636 if (vertical && freetype_set_outline_text_metrics( font ))
2638 if (vertical_metrics)
2639 lsb = metrics->horiBearingY + metrics->vertBearingY;
2640 else
2641 lsb = metrics->vertAdvance + (font->otm.otmDescent << 6);
2642 vec.x = lsb;
2643 vec.y = font->otm.otmDescent << 6;
2644 TRACE( "Vec %ld,%ld\n", vec.x>>6, vec.y>>6 );
2645 pFT_Vector_Transform( &vec, &matrices[matrix_hori] );
2646 origin.x = (vec.x + bbox.xMin) & -64;
2647 origin.y = (vec.y + bbox.yMax + 63) & -64;
2648 lsb -= metrics->horiBearingY;
2650 else
2652 origin.x = bbox.xMin;
2653 origin.y = bbox.yMax;
2654 lsb = metrics->horiBearingX;
2657 adv = get_advance_metric( incoming_font, font, metrics, &matrices[matrix_hori],
2658 vertical_metrics );
2659 gm->gmCellIncX = adv.x >> 6;
2660 gm->gmCellIncY = adv.y >> 6;
2662 adv = get_advance_metric( incoming_font, font, metrics, &matrices[matrix_unrotated],
2663 vertical_metrics );
2664 adv.x = pFT_Vector_Length( &adv );
2665 adv.y = 0;
2667 vec.x = lsb;
2668 vec.y = 0;
2669 pFT_Vector_Transform( &vec, &matrices[matrix_unrotated] );
2670 if (lsb > 0) abc->abcA = pFT_Vector_Length( &vec ) >> 6;
2671 else abc->abcA = -((pFT_Vector_Length( &vec ) + 63) >> 6);
2673 /* We use lsb again to avoid rounding errors */
2674 vec.x = lsb + (vertical ? metrics->height : metrics->width);
2675 vec.y = 0;
2676 pFT_Vector_Transform( &vec, &matrices[matrix_unrotated] );
2677 abc->abcB = ((pFT_Vector_Length( &vec ) + 63) >> 6) - abc->abcA;
2679 if (!abc->abcB) abc->abcB = 1;
2680 abc->abcC = (adv.x >> 6) - abc->abcA - abc->abcB;
2682 gm->gmptGlyphOrigin.x = origin.x >> 6;
2683 gm->gmptGlyphOrigin.y = origin.y >> 6;
2684 gm->gmBlackBoxX = (bbox.xMax - bbox.xMin) >> 6;
2685 gm->gmBlackBoxY = (bbox.yMax - bbox.yMin) >> 6;
2686 if (!gm->gmBlackBoxX) gm->gmBlackBoxX = 1;
2687 if (!gm->gmBlackBoxY) gm->gmBlackBoxY = 1;
2689 TRACE( "gm: %u, %u, %s, %d, %d abc %d, %u, %d\n",
2690 gm->gmBlackBoxX, gm->gmBlackBoxY, wine_dbgstr_point(&gm->gmptGlyphOrigin),
2691 gm->gmCellIncX, gm->gmCellIncY, abc->abcA, abc->abcB, abc->abcC );
2695 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
2697 static DWORD get_mono_glyph_bitmap( FT_GlyphSlot glyph, FT_BBox bbox,
2698 BOOL fake_bold, BOOL needs_transform, FT_Matrix matrices[3],
2699 DWORD buflen, BYTE *buf )
2701 DWORD width = (bbox.xMax - bbox.xMin ) >> 6;
2702 DWORD height = (bbox.yMax - bbox.yMin ) >> 6;
2703 DWORD pitch = ((width + 31) >> 5) << 2;
2704 DWORD needed = pitch * height;
2705 FT_Bitmap ft_bitmap;
2706 BYTE *src, *dst;
2707 INT w, h, x;
2709 if (!buf || !buflen) return needed;
2710 if (!needed) return GDI_ERROR; /* empty glyph */
2711 if (needed > buflen) return GDI_ERROR;
2713 switch (glyph->format)
2715 case FT_GLYPH_FORMAT_BITMAP:
2716 src = glyph->bitmap.buffer;
2717 dst = buf;
2718 w = min( pitch, (glyph->bitmap.width + 7) >> 3 );
2719 h = min( height, glyph->bitmap.rows );
2720 while (h--)
2722 if (!fake_bold)
2723 memcpy( dst, src, w );
2724 else
2726 dst[0] = 0;
2727 for (x = 0; x < w; x++)
2729 dst[x] = (dst[x] & 0x80) | (src[x] >> 1) | src[x];
2730 if (x + 1 < pitch)
2731 dst[x + 1] = (src[x] & 0x01) << 7;
2734 src += glyph->bitmap.pitch;
2735 dst += pitch;
2737 break;
2739 case FT_GLYPH_FORMAT_OUTLINE:
2740 ft_bitmap.width = width;
2741 ft_bitmap.rows = height;
2742 ft_bitmap.pitch = pitch;
2743 ft_bitmap.pixel_mode = FT_PIXEL_MODE_MONO;
2744 ft_bitmap.buffer = buf;
2746 if (needs_transform)
2747 pFT_Outline_Transform( &glyph->outline, &matrices[matrix_vert] );
2748 pFT_Outline_Translate( &glyph->outline, -bbox.xMin, -bbox.yMin );
2750 /* Note: FreeType will only set 'black' bits for us. */
2751 memset( buf, 0, buflen );
2752 pFT_Outline_Get_Bitmap( library, &glyph->outline, &ft_bitmap );
2753 break;
2755 default:
2756 FIXME( "loaded glyph format %x\n", glyph->format );
2757 return GDI_ERROR;
2760 return needed;
2763 static DWORD get_antialias_glyph_bitmap( FT_GlyphSlot glyph, FT_BBox bbox, UINT format,
2764 BOOL fake_bold, BOOL needs_transform, FT_Matrix matrices[3],
2765 DWORD buflen, BYTE *buf )
2767 DWORD width = (bbox.xMax - bbox.xMin ) >> 6;
2768 DWORD height = (bbox.yMax - bbox.yMin ) >> 6;
2769 DWORD pitch = (width + 3) / 4 * 4;
2770 DWORD needed = pitch * height;
2771 FT_Bitmap ft_bitmap;
2772 INT w, h, x, max_level;
2773 BYTE *src, *dst;
2775 if (!buf || !buflen) return needed;
2776 if (!needed) return GDI_ERROR; /* empty glyph */
2777 if (needed > buflen) return GDI_ERROR;
2779 max_level = get_max_level( format );
2781 switch (glyph->format)
2783 case FT_GLYPH_FORMAT_BITMAP:
2784 src = glyph->bitmap.buffer;
2785 dst = buf;
2786 memset( buf, 0, buflen );
2788 w = min( pitch, glyph->bitmap.width );
2789 h = min( height, glyph->bitmap.rows );
2790 while (h--)
2792 for (x = 0; x < w; x++)
2794 if (src[x / 8] & masks[x % 8])
2796 dst[x] = max_level;
2797 if (fake_bold && x + 1 < pitch) dst[x + 1] = max_level;
2800 src += glyph->bitmap.pitch;
2801 dst += pitch;
2803 break;
2805 case FT_GLYPH_FORMAT_OUTLINE:
2806 ft_bitmap.width = width;
2807 ft_bitmap.rows = height;
2808 ft_bitmap.pitch = pitch;
2809 ft_bitmap.pixel_mode = FT_PIXEL_MODE_GRAY;
2810 ft_bitmap.buffer = buf;
2812 if (needs_transform)
2813 pFT_Outline_Transform( &glyph->outline, &matrices[matrix_vert] );
2814 pFT_Outline_Translate( &glyph->outline, -bbox.xMin, -bbox.yMin );
2816 memset( buf, 0, buflen );
2817 pFT_Outline_Get_Bitmap( library, &glyph->outline, &ft_bitmap );
2819 if (max_level != 255)
2821 INT row, col;
2822 BYTE *ptr, *start;
2824 for (row = 0, start = buf; row < height; row++)
2826 for (col = 0, ptr = start; col < width; col++, ptr++)
2827 *ptr = (((int)*ptr) * (max_level + 1)) / 256;
2828 start += pitch;
2831 break;
2833 default:
2834 FIXME("loaded glyph format %x\n", glyph->format);
2835 return GDI_ERROR;
2838 return needed;
2841 static DWORD get_subpixel_glyph_bitmap( FT_GlyphSlot glyph, FT_BBox bbox, UINT format,
2842 BOOL fake_bold, BOOL needs_transform, FT_Matrix matrices[3],
2843 GLYPHMETRICS *gm, DWORD buflen, BYTE *buf )
2845 DWORD width = (bbox.xMax - bbox.xMin ) >> 6;
2846 DWORD height = (bbox.yMax - bbox.yMin ) >> 6;
2847 DWORD pitch, needed = 0;
2848 BYTE *src, *dst;
2849 INT w, h, x;
2851 switch (glyph->format)
2853 case FT_GLYPH_FORMAT_BITMAP:
2854 pitch = width * 4;
2855 needed = pitch * height;
2857 if (!buf || !buflen) break;
2858 if (!needed) return GDI_ERROR; /* empty glyph */
2859 if (needed > buflen) return GDI_ERROR;
2861 src = glyph->bitmap.buffer;
2862 dst = buf;
2863 memset( buf, 0, buflen );
2865 w = min( width, glyph->bitmap.width );
2866 h = min( height, glyph->bitmap.rows );
2867 while (h--)
2869 for (x = 0; x < w; x++)
2871 if ( src[x / 8] & masks[x % 8] )
2873 ((unsigned int *)dst)[x] = ~0u;
2874 if (fake_bold && x + 1 < width) ((unsigned int *)dst)[x + 1] = ~0u;
2877 src += glyph->bitmap.pitch;
2878 dst += pitch;
2880 break;
2882 case FT_GLYPH_FORMAT_OUTLINE:
2884 INT src_pitch, src_width, src_height, x_shift, y_shift;
2885 INT sub_stride, hmul, vmul;
2886 const INT *sub_order;
2887 const INT rgb_order[3] = { 0, 1, 2 };
2888 const INT bgr_order[3] = { 2, 1, 0 };
2889 FT_Render_Mode render_mode =
2890 (format == WINE_GGO_HRGB_BITMAP ||
2891 format == WINE_GGO_HBGR_BITMAP) ? FT_RENDER_MODE_LCD : FT_RENDER_MODE_LCD_V;
2893 if (!width || !height) /* empty glyph */
2895 if (!buf || !buflen) break;
2896 return GDI_ERROR;
2899 if ( render_mode == FT_RENDER_MODE_LCD)
2901 gm->gmBlackBoxX += 2;
2902 gm->gmptGlyphOrigin.x -= 1;
2903 bbox.xMin -= (1 << 6);
2905 else
2907 gm->gmBlackBoxY += 2;
2908 gm->gmptGlyphOrigin.y += 1;
2909 bbox.yMax += (1 << 6);
2912 width = gm->gmBlackBoxX;
2913 height = gm->gmBlackBoxY;
2914 pitch = width * 4;
2915 needed = pitch * height;
2917 if (!buf || !buflen) return needed;
2918 if (needed > buflen) return GDI_ERROR;
2920 if (needs_transform)
2921 pFT_Outline_Transform( &glyph->outline, &matrices[matrix_vert] );
2923 #ifdef FT_LCD_FILTER_H
2924 if (pFT_Library_SetLcdFilter)
2925 pFT_Library_SetLcdFilter( library, FT_LCD_FILTER_DEFAULT );
2926 #endif
2927 pFT_Render_Glyph( glyph, render_mode );
2929 src_pitch = glyph->bitmap.pitch;
2930 src_width = glyph->bitmap.width;
2931 src_height = glyph->bitmap.rows;
2932 src = glyph->bitmap.buffer;
2933 dst = buf;
2934 memset( buf, 0, buflen );
2936 sub_order = (format == WINE_GGO_HRGB_BITMAP ||
2937 format == WINE_GGO_VRGB_BITMAP) ? rgb_order : bgr_order;
2938 sub_stride = render_mode == FT_RENDER_MODE_LCD ? 1 : src_pitch;
2939 hmul = render_mode == FT_RENDER_MODE_LCD ? 3 : 1;
2940 vmul = render_mode == FT_RENDER_MODE_LCD ? 1 : 3;
2942 x_shift = glyph->bitmap_left - (bbox.xMin >> 6);
2943 if ( x_shift < 0 )
2945 src += hmul * -x_shift;
2946 src_width -= hmul * -x_shift;
2948 else if ( x_shift > 0 )
2950 dst += x_shift * sizeof(unsigned int);
2951 width -= x_shift;
2954 y_shift = (bbox.yMax >> 6) - glyph->bitmap_top;
2955 if ( y_shift < 0 )
2957 src += src_pitch * vmul * -y_shift;
2958 src_height -= vmul * -y_shift;
2960 else if ( y_shift > 0 )
2962 dst += y_shift * pitch;
2963 height -= y_shift;
2966 w = min( width, src_width / hmul );
2967 h = min( height, src_height / vmul );
2968 while (h--)
2970 for (x = 0; x < w; x++)
2972 ((unsigned int *)dst)[x] =
2973 ((unsigned int)src[hmul * x + sub_stride * sub_order[0]] << 16) |
2974 ((unsigned int)src[hmul * x + sub_stride * sub_order[1]] << 8) |
2975 ((unsigned int)src[hmul * x + sub_stride * sub_order[2]]);
2977 src += src_pitch * vmul;
2978 dst += pitch;
2980 break;
2982 default:
2983 FIXME ( "loaded glyph format %x\n", glyph->format );
2984 return GDI_ERROR;
2987 return needed;
2990 static unsigned int get_native_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
2992 TTPOLYGONHEADER *pph;
2993 TTPOLYCURVE *ppc;
2994 unsigned int needed = 0, point = 0, contour, first_pt;
2995 unsigned int pph_start, cpfx;
2996 DWORD type;
2998 for (contour = 0; contour < outline->n_contours; contour++)
3000 /* Ignore contours containing one point */
3001 if (point == outline->contours[contour])
3003 point++;
3004 continue;
3007 pph_start = needed;
3008 pph = (TTPOLYGONHEADER *)(buf + needed);
3009 first_pt = point;
3010 if (buf)
3012 pph->dwType = TT_POLYGON_TYPE;
3013 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3015 needed += sizeof(*pph);
3016 point++;
3017 while (point <= outline->contours[contour])
3019 ppc = (TTPOLYCURVE *)(buf + needed);
3020 type = outline->tags[point] & FT_Curve_Tag_On ?
3021 TT_PRIM_LINE : TT_PRIM_QSPLINE;
3022 cpfx = 0;
3025 if (buf)
3026 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3027 cpfx++;
3028 point++;
3029 } while (point <= outline->contours[contour] &&
3030 (outline->tags[point] & FT_Curve_Tag_On) ==
3031 (outline->tags[point-1] & FT_Curve_Tag_On));
3032 /* At the end of a contour Windows adds the start point, but
3033 only for Beziers */
3034 if (point > outline->contours[contour] &&
3035 !(outline->tags[point-1] & FT_Curve_Tag_On))
3037 if (buf)
3038 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
3039 cpfx++;
3041 else if (point <= outline->contours[contour] &&
3042 outline->tags[point] & FT_Curve_Tag_On)
3044 /* add closing pt for bezier */
3045 if (buf)
3046 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3047 cpfx++;
3048 point++;
3050 if (buf)
3052 ppc->wType = type;
3053 ppc->cpfx = cpfx;
3055 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3057 if (buf)
3058 pph->cb = needed - pph_start;
3060 return needed;
3063 static unsigned int get_bezier_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
3065 /* Convert the quadratic Beziers to cubic Beziers.
3066 The parametric eqn for a cubic Bezier is, from PLRM:
3067 r(t) = at^3 + bt^2 + ct + r0
3068 with the control points:
3069 r1 = r0 + c/3
3070 r2 = r1 + (c + b)/3
3071 r3 = r0 + c + b + a
3073 A quadratic Bezier has the form:
3074 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3076 So equating powers of t leads to:
3077 r1 = 2/3 p1 + 1/3 p0
3078 r2 = 2/3 p1 + 1/3 p2
3079 and of course r0 = p0, r3 = p2
3081 int contour, point = 0, first_pt;
3082 TTPOLYGONHEADER *pph;
3083 TTPOLYCURVE *ppc;
3084 DWORD pph_start, cpfx, type;
3085 FT_Vector cubic_control[4];
3086 unsigned int needed = 0;
3088 for (contour = 0; contour < outline->n_contours; contour++)
3090 pph_start = needed;
3091 pph = (TTPOLYGONHEADER *)(buf + needed);
3092 first_pt = point;
3093 if (buf)
3095 pph->dwType = TT_POLYGON_TYPE;
3096 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3098 needed += sizeof(*pph);
3099 point++;
3100 while (point <= outline->contours[contour])
3102 ppc = (TTPOLYCURVE *)(buf + needed);
3103 type = outline->tags[point] & FT_Curve_Tag_On ?
3104 TT_PRIM_LINE : TT_PRIM_CSPLINE;
3105 cpfx = 0;
3108 if (type == TT_PRIM_LINE)
3110 if (buf)
3111 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3112 cpfx++;
3113 point++;
3115 else
3117 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
3118 so cpfx = 3n */
3120 /* FIXME: Possible optimization in endpoint calculation
3121 if there are two consecutive curves */
3122 cubic_control[0] = outline->points[point-1];
3123 if (!(outline->tags[point-1] & FT_Curve_Tag_On))
3125 cubic_control[0].x += outline->points[point].x + 1;
3126 cubic_control[0].y += outline->points[point].y + 1;
3127 cubic_control[0].x >>= 1;
3128 cubic_control[0].y >>= 1;
3130 if (point+1 > outline->contours[contour])
3131 cubic_control[3] = outline->points[first_pt];
3132 else
3134 cubic_control[3] = outline->points[point+1];
3135 if (!(outline->tags[point+1] & FT_Curve_Tag_On))
3137 cubic_control[3].x += outline->points[point].x + 1;
3138 cubic_control[3].y += outline->points[point].y + 1;
3139 cubic_control[3].x >>= 1;
3140 cubic_control[3].y >>= 1;
3143 /* r1 = 1/3 p0 + 2/3 p1
3144 r2 = 1/3 p2 + 2/3 p1 */
3145 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
3146 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
3147 cubic_control[2] = cubic_control[1];
3148 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
3149 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
3150 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
3151 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
3152 if (buf)
3154 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
3155 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
3156 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
3158 cpfx += 3;
3159 point++;
3161 } while (point <= outline->contours[contour] &&
3162 (outline->tags[point] & FT_Curve_Tag_On) ==
3163 (outline->tags[point-1] & FT_Curve_Tag_On));
3164 /* At the end of a contour Windows adds the start point,
3165 but only for Beziers and we've already done that.
3167 if (point <= outline->contours[contour] &&
3168 outline->tags[point] & FT_Curve_Tag_On)
3170 /* This is the closing pt of a bezier, but we've already
3171 added it, so just inc point and carry on */
3172 point++;
3174 if (buf)
3176 ppc->wType = type;
3177 ppc->cpfx = cpfx;
3179 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3181 if (buf)
3182 pph->cb = needed - pph_start;
3184 return needed;
3187 static FT_Int get_load_flags( UINT format )
3189 FT_Int load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
3191 if (format & GGO_UNHINTED)
3192 return load_flags | FT_LOAD_NO_HINTING;
3194 switch (format & ~GGO_GLYPH_INDEX)
3196 case GGO_BITMAP:
3197 load_flags |= FT_LOAD_TARGET_MONO;
3198 break;
3199 case GGO_GRAY2_BITMAP:
3200 case GGO_GRAY4_BITMAP:
3201 case GGO_GRAY8_BITMAP:
3202 case WINE_GGO_GRAY16_BITMAP:
3203 load_flags |= FT_LOAD_TARGET_NORMAL;
3204 break;
3205 case WINE_GGO_HRGB_BITMAP:
3206 case WINE_GGO_HBGR_BITMAP:
3207 load_flags |= FT_LOAD_TARGET_LCD;
3208 break;
3209 case WINE_GGO_VRGB_BITMAP:
3210 case WINE_GGO_VBGR_BITMAP:
3211 load_flags |= FT_LOAD_TARGET_LCD_V;
3212 break;
3215 return load_flags;
3218 /*************************************************************
3219 * freetype_get_glyph_outline
3221 static DWORD CDECL freetype_get_glyph_outline( struct gdi_font *font, UINT glyph, UINT format,
3222 GLYPHMETRICS *lpgm, ABC *abc, DWORD buflen, void *buf,
3223 const MAT2 *lpmat, BOOL tategaki )
3225 struct gdi_font *base_font = font->base_font ? font->base_font : font;
3226 FT_Face ft_face = get_ft_face( font );
3227 FT_Glyph_Metrics metrics;
3228 FT_Error err;
3229 FT_BBox bbox;
3230 FT_Int load_flags = get_load_flags(format);
3231 FT_Matrix matrices[3];
3232 BOOL needsTransform = FALSE;
3233 BOOL vertical_metrics;
3235 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm, buflen, buf, lpmat);
3237 TRACE("font transform %f %f %f %f\n",
3238 font->matrix.eM11, font->matrix.eM12,
3239 font->matrix.eM21, font->matrix.eM22);
3241 needsTransform = get_transform_matrices( font, tategaki, lpmat, matrices );
3243 vertical_metrics = (tategaki && FT_HAS_VERTICAL(ft_face));
3244 /* there is a freetype bug where vertical metrics are only
3245 properly scaled and correct in 2.4.0 or greater */
3246 if (vertical_metrics && FT_SimpleVersion < FT_VERSION_VALUE(2, 4, 0))
3247 vertical_metrics = FALSE;
3249 if (needsTransform || format != GGO_BITMAP) load_flags |= FT_LOAD_NO_BITMAP;
3250 if (vertical_metrics) load_flags |= FT_LOAD_VERTICAL_LAYOUT;
3252 err = pFT_Load_Glyph(ft_face, glyph, load_flags);
3253 if (err && !(load_flags & FT_LOAD_NO_HINTING))
3255 WARN("Failed to load glyph %#x, retrying without hinting. Error %#x.\n", glyph, err);
3256 load_flags |= FT_LOAD_NO_HINTING;
3257 err = pFT_Load_Glyph(ft_face, glyph, load_flags);
3260 if(err) {
3261 WARN("Failed to load glyph %#x, error %#x.\n", glyph, err);
3262 return GDI_ERROR;
3265 metrics = ft_face->glyph->metrics;
3266 if(font->fake_bold) {
3267 if (!get_bold_glyph_outline(ft_face->glyph, font->ppem, &metrics) && metrics.width)
3268 metrics.width += 1 << 6;
3271 /* Some poorly-created fonts contain glyphs that exceed the boundaries set
3272 * by the text metrics. The proper behavior is to clip the glyph metrics to
3273 * fit within the maximums specified in the text metrics. */
3274 if (freetype_set_outline_text_metrics(base_font) ||
3275 freetype_set_bitmap_text_metrics(base_font)) {
3276 TEXTMETRICW *ptm = &base_font->otm.otmTextMetrics;
3277 INT top = min( metrics.horiBearingY, ptm->tmAscent << 6 );
3278 INT bottom = max( metrics.horiBearingY - metrics.height, -(ptm->tmDescent << 6) );
3279 metrics.horiBearingY = top;
3280 metrics.height = top - bottom;
3282 /* TODO: Are we supposed to clip the width as well...? */
3283 /* metrics.width = min( metrics.width, ptm->tmMaxCharWidth << 6 ); */
3286 bbox = get_transformed_bbox( &metrics, needsTransform, matrices );
3287 compute_metrics( base_font, font, bbox, &metrics, tategaki,
3288 vertical_metrics, needsTransform, matrices, lpgm, abc );
3290 switch (format)
3292 case GGO_METRICS:
3293 return 1; /* FIXME */
3295 case GGO_BITMAP:
3296 return get_mono_glyph_bitmap( ft_face->glyph, bbox, font->fake_bold,
3297 needsTransform, matrices, buflen, buf );
3299 case GGO_GRAY2_BITMAP:
3300 case GGO_GRAY4_BITMAP:
3301 case GGO_GRAY8_BITMAP:
3302 case WINE_GGO_GRAY16_BITMAP:
3303 return get_antialias_glyph_bitmap( ft_face->glyph, bbox, format, font->fake_bold,
3304 needsTransform, matrices, buflen, buf );
3306 case WINE_GGO_HRGB_BITMAP:
3307 case WINE_GGO_HBGR_BITMAP:
3308 case WINE_GGO_VRGB_BITMAP:
3309 case WINE_GGO_VBGR_BITMAP:
3310 return get_subpixel_glyph_bitmap( ft_face->glyph, bbox, format, font->fake_bold,
3311 needsTransform, matrices, lpgm, buflen, buf );
3313 case GGO_NATIVE:
3314 if (ft_face->glyph->format == ft_glyph_format_outline)
3316 FT_Outline *outline = &ft_face->glyph->outline;
3317 UINT needed;
3319 if (buflen == 0) buf = NULL;
3321 if (needsTransform && buf)
3322 pFT_Outline_Transform( outline, &matrices[matrix_vert] );
3324 needed = get_native_glyph_outline(outline, buflen, NULL);
3326 if (!buf || !buflen) return needed;
3327 if (needed > buflen) return GDI_ERROR;
3328 return get_native_glyph_outline(outline, buflen, buf);
3330 TRACE("loaded a bitmap\n");
3331 return GDI_ERROR;
3333 case GGO_BEZIER:
3334 if (ft_face->glyph->format == ft_glyph_format_outline)
3336 FT_Outline *outline = &ft_face->glyph->outline;
3337 UINT needed;
3339 if (buflen == 0) buf = NULL;
3341 if (needsTransform && buf)
3342 pFT_Outline_Transform( outline, &matrices[matrix_vert] );
3344 needed = get_bezier_glyph_outline(outline, buflen, NULL);
3346 if (!buf || !buflen) return needed;
3347 if (needed > buflen) return GDI_ERROR;
3348 return get_bezier_glyph_outline(outline, buflen, buf);
3350 TRACE("loaded a bitmap\n");
3351 return GDI_ERROR;
3353 default:
3354 FIXME("Unsupported format %d\n", format);
3355 return GDI_ERROR;
3359 /*************************************************************
3360 * freetype_set_bitmap_text_metrics
3362 static BOOL CDECL freetype_set_bitmap_text_metrics( struct gdi_font *font )
3364 FT_Face ft_face = get_ft_face( font );
3365 FT_WinFNT_HeaderRec winfnt_header;
3367 if (font->otm.otmSize) return TRUE; /* already set */
3368 font->otm.otmSize = offsetof( OUTLINETEXTMETRICW, otmFiller );
3370 #define TM font->otm.otmTextMetrics
3371 if(!pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
3373 TM.tmHeight = winfnt_header.pixel_height;
3374 TM.tmAscent = winfnt_header.ascent;
3375 TM.tmDescent = TM.tmHeight - TM.tmAscent;
3376 TM.tmInternalLeading = winfnt_header.internal_leading;
3377 TM.tmExternalLeading = winfnt_header.external_leading;
3378 TM.tmAveCharWidth = winfnt_header.avg_width;
3379 TM.tmMaxCharWidth = winfnt_header.max_width;
3380 TM.tmWeight = winfnt_header.weight;
3381 TM.tmOverhang = 0;
3382 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
3383 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
3384 TM.tmFirstChar = winfnt_header.first_char;
3385 TM.tmLastChar = winfnt_header.last_char;
3386 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
3387 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
3388 TM.tmItalic = winfnt_header.italic;
3389 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
3390 TM.tmCharSet = winfnt_header.charset;
3392 else
3394 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
3395 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
3396 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3397 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
3398 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
3399 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
3400 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
3401 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
3402 TM.tmOverhang = 0;
3403 TM.tmDigitizedAspectX = 96; /* FIXME */
3404 TM.tmDigitizedAspectY = 96; /* FIXME */
3405 TM.tmFirstChar = 1;
3406 TM.tmLastChar = 255;
3407 TM.tmDefaultChar = 32;
3408 TM.tmBreakChar = 32;
3409 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
3410 /* NB inverted meaning of TMPF_FIXED_PITCH */
3411 TM.tmPitchAndFamily = FT_IS_FIXED_WIDTH(ft_face) ? 0 : TMPF_FIXED_PITCH;
3412 TM.tmCharSet = font->charset;
3414 TM.tmUnderlined = font->lf.lfUnderline ? 0xff : 0;
3415 TM.tmStruckOut = font->lf.lfStrikeOut ? 0xff : 0;
3417 if(font->fake_bold)
3418 TM.tmWeight = FW_BOLD;
3419 #undef TM
3421 return TRUE;
3425 static BOOL face_has_symbol_charmap(FT_Face ft_face)
3427 int i;
3429 for(i = 0; i < ft_face->num_charmaps; i++)
3431 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
3432 return TRUE;
3434 return FALSE;
3437 /*************************************************************
3438 * freetype_set_outline_text_metrics
3440 static BOOL CDECL freetype_set_outline_text_metrics( struct gdi_font *font )
3442 FT_Face ft_face = get_ft_face( font );
3443 UINT needed;
3444 TT_OS2 *pOS2;
3445 TT_HoriHeader *pHori;
3446 TT_Postscript *pPost;
3447 FT_Fixed em_scale;
3448 INT ascent, descent;
3449 USHORT windescent;
3451 TRACE("font=%p\n", font);
3453 if (!font->scalable) return FALSE;
3454 if (font->otm.otmSize) return TRUE; /* already set */
3456 /* note: we store actual pointers in the names instead of offsets,
3457 they are fixed up when returned to the app */
3458 if (!(font->otm.otmpFullName = (char *)get_face_name( ft_face, TT_NAME_ID_UNIQUE_ID, system_lcid )))
3460 static const WCHAR fake_nameW[] = {'f','a','k','e',' ','n','a','m','e', 0};
3461 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w((WCHAR *)font->otm.otmpFamilyName));
3462 font->otm.otmpFullName = (char *)strdupW(fake_nameW);
3464 needed = sizeof(font->otm) + (lstrlenW( (WCHAR *)font->otm.otmpFamilyName ) + 1 +
3465 lstrlenW( (WCHAR *)font->otm.otmpStyleName ) + 1 +
3466 lstrlenW( (WCHAR *)font->otm.otmpFaceName ) + 1 +
3467 lstrlenW( (WCHAR *)font->otm.otmpFullName ) + 1) * sizeof(WCHAR);
3469 em_scale = (FT_Fixed)pFT_MulDiv(font->ppem, 1 << 16, ft_face->units_per_EM);
3471 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3472 if(!pOS2) {
3473 FIXME("Can't find OS/2 table - not TT font?\n");
3474 return FALSE;
3477 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3478 if(!pHori) {
3479 FIXME("Can't find HHEA table - not TT font?\n");
3480 return FALSE;
3483 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
3485 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",
3486 pOS2->usWinAscent, pOS2->usWinDescent,
3487 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
3488 pOS2->xAvgCharWidth,
3489 ft_face->ascender, ft_face->descender, ft_face->height,
3490 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
3491 ft_face->bbox.yMax, ft_face->bbox.yMin);
3493 font->otm.otmSize = needed;
3495 #define TM font->otm.otmTextMetrics
3497 windescent = get_fixed_windescent(pOS2->usWinDescent);
3498 if(pOS2->usWinAscent + windescent == 0) {
3499 ascent = pHori->Ascender;
3500 descent = -pHori->Descender;
3501 } else {
3502 ascent = pOS2->usWinAscent;
3503 descent = windescent;
3506 font->ntmCellHeight = ascent + descent;
3507 font->ntmAvgWidth = pOS2->xAvgCharWidth;
3509 #define SCALE_X(x) (pFT_MulFix(x, em_scale))
3510 #define SCALE_Y(y) (pFT_MulFix(y, em_scale))
3512 if(font->yMax) {
3513 TM.tmAscent = font->yMax;
3514 TM.tmDescent = -font->yMin;
3515 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
3516 } else {
3517 TM.tmAscent = SCALE_Y(ascent);
3518 TM.tmDescent = SCALE_Y(descent);
3519 TM.tmInternalLeading = SCALE_Y(ascent + descent - ft_face->units_per_EM);
3522 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3524 /* MSDN says:
3525 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
3527 TM.tmExternalLeading = max(0, SCALE_Y(pHori->Line_Gap -
3528 ((ascent + descent) -
3529 (pHori->Ascender - pHori->Descender))));
3531 TM.tmAveCharWidth = SCALE_X(pOS2->xAvgCharWidth);
3532 if (TM.tmAveCharWidth == 0) {
3533 TM.tmAveCharWidth = 1;
3535 TM.tmMaxCharWidth = SCALE_X(ft_face->bbox.xMax - ft_face->bbox.xMin);
3536 TM.tmWeight = FW_REGULAR;
3537 if (font->fake_bold)
3538 TM.tmWeight = FW_BOLD;
3539 else
3541 if (ft_face->style_flags & FT_STYLE_FLAG_BOLD)
3543 if (pOS2->usWeightClass > FW_MEDIUM)
3544 TM.tmWeight = pOS2->usWeightClass;
3546 else if (pOS2->usWeightClass <= FW_MEDIUM)
3547 TM.tmWeight = pOS2->usWeightClass;
3549 TM.tmOverhang = 0;
3550 TM.tmDigitizedAspectX = 96; /* FIXME */
3551 TM.tmDigitizedAspectY = 96; /* FIXME */
3552 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
3553 * symbol range to 0 - f0ff
3556 if (face_has_symbol_charmap(ft_face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
3558 TM.tmFirstChar = 0;
3559 switch (PRIMARYLANGID(system_lcid))
3561 case LANG_HEBREW:
3562 TM.tmLastChar = 0xf896;
3563 break;
3564 case LANG_ESTONIAN:
3565 case LANG_LATVIAN:
3566 case LANG_LITHUANIAN:
3567 TM.tmLastChar = 0xf8fd;
3568 break;
3569 default:
3570 TM.tmLastChar = 0xf0ff;
3572 TM.tmBreakChar = 0x20;
3573 TM.tmDefaultChar = 0x1f;
3575 else
3577 TM.tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
3578 TM.tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
3580 if(pOS2->usFirstCharIndex <= 1)
3581 TM.tmBreakChar = pOS2->usFirstCharIndex + 2;
3582 else if (pOS2->usFirstCharIndex > 0xff)
3583 TM.tmBreakChar = 0x20;
3584 else
3585 TM.tmBreakChar = pOS2->usFirstCharIndex;
3586 TM.tmDefaultChar = TM.tmBreakChar - 1;
3588 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
3589 TM.tmUnderlined = font->lf.lfUnderline ? 255 : 0;
3590 TM.tmStruckOut = font->lf.lfStrikeOut ? 255 : 0;
3592 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
3593 if(!FT_IS_FIXED_WIDTH(ft_face) &&
3594 (pOS2->version == 0xFFFFU ||
3595 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
3596 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
3597 else
3598 TM.tmPitchAndFamily = 0;
3600 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX])
3602 case PAN_FAMILY_SCRIPT:
3603 TM.tmPitchAndFamily |= FF_SCRIPT;
3604 break;
3606 case PAN_FAMILY_DECORATIVE:
3607 TM.tmPitchAndFamily |= FF_DECORATIVE;
3608 break;
3610 case PAN_ANY:
3611 case PAN_NO_FIT:
3612 case PAN_FAMILY_TEXT_DISPLAY:
3613 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
3614 /* which is clearly not what the panose spec says. */
3615 default:
3616 if(TM.tmPitchAndFamily == 0 || /* fixed */
3617 pOS2->panose[PAN_PROPORTION_INDEX] == PAN_PROP_MONOSPACED)
3618 TM.tmPitchAndFamily = FF_MODERN;
3619 else
3621 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX])
3623 case PAN_ANY:
3624 case PAN_NO_FIT:
3625 default:
3626 TM.tmPitchAndFamily |= FF_DONTCARE;
3627 break;
3629 case PAN_SERIF_COVE:
3630 case PAN_SERIF_OBTUSE_COVE:
3631 case PAN_SERIF_SQUARE_COVE:
3632 case PAN_SERIF_OBTUSE_SQUARE_COVE:
3633 case PAN_SERIF_SQUARE:
3634 case PAN_SERIF_THIN:
3635 case PAN_SERIF_BONE:
3636 case PAN_SERIF_EXAGGERATED:
3637 case PAN_SERIF_TRIANGLE:
3638 TM.tmPitchAndFamily |= FF_ROMAN;
3639 break;
3641 case PAN_SERIF_NORMAL_SANS:
3642 case PAN_SERIF_OBTUSE_SANS:
3643 case PAN_SERIF_PERP_SANS:
3644 case PAN_SERIF_FLARED:
3645 case PAN_SERIF_ROUNDED:
3646 TM.tmPitchAndFamily |= FF_SWISS;
3647 break;
3650 break;
3653 if(FT_IS_SCALABLE(ft_face))
3654 TM.tmPitchAndFamily |= TMPF_VECTOR;
3656 if(FT_IS_SFNT(ft_face))
3658 if (font->ntmFlags & NTM_PS_OPENTYPE)
3659 TM.tmPitchAndFamily |= TMPF_DEVICE;
3660 else
3661 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
3664 TM.tmCharSet = font->charset;
3666 font->otm.otmFiller = 0;
3667 memcpy(&font->otm.otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
3668 font->otm.otmfsSelection = pOS2->fsSelection;
3669 if (font->fake_italic)
3670 font->otm.otmfsSelection |= 1;
3671 if (font->fake_bold)
3672 font->otm.otmfsSelection |= 1 << 5;
3673 /* Only return valid bits that define embedding and subsetting restrictions */
3674 font->otm.otmfsType = pOS2->fsType & 0x30e;
3675 font->otm.otmsCharSlopeRise = pHori->caret_Slope_Rise;
3676 font->otm.otmsCharSlopeRun = pHori->caret_Slope_Run;
3677 font->otm.otmItalicAngle = 0; /* POST table */
3678 font->otm.otmEMSquare = ft_face->units_per_EM;
3679 font->otm.otmAscent = SCALE_Y(pOS2->sTypoAscender);
3680 font->otm.otmDescent = SCALE_Y(pOS2->sTypoDescender);
3681 font->otm.otmLineGap = SCALE_Y(pOS2->sTypoLineGap);
3682 font->otm.otmsCapEmHeight = SCALE_Y(pOS2->sCapHeight);
3683 font->otm.otmsXHeight = SCALE_Y(pOS2->sxHeight);
3684 font->otm.otmrcFontBox.left = SCALE_X(ft_face->bbox.xMin);
3685 font->otm.otmrcFontBox.right = SCALE_X(ft_face->bbox.xMax);
3686 font->otm.otmrcFontBox.top = SCALE_Y(ft_face->bbox.yMax);
3687 font->otm.otmrcFontBox.bottom = SCALE_Y(ft_face->bbox.yMin);
3688 font->otm.otmMacAscent = TM.tmAscent;
3689 font->otm.otmMacDescent = -TM.tmDescent;
3690 font->otm.otmMacLineGap = SCALE_Y(pHori->Line_Gap);
3691 font->otm.otmusMinimumPPEM = 0; /* TT Header */
3692 font->otm.otmptSubscriptSize.x = SCALE_X(pOS2->ySubscriptXSize);
3693 font->otm.otmptSubscriptSize.y = SCALE_Y(pOS2->ySubscriptYSize);
3694 font->otm.otmptSubscriptOffset.x = SCALE_X(pOS2->ySubscriptXOffset);
3695 font->otm.otmptSubscriptOffset.y = SCALE_Y(pOS2->ySubscriptYOffset);
3696 font->otm.otmptSuperscriptSize.x = SCALE_X(pOS2->ySuperscriptXSize);
3697 font->otm.otmptSuperscriptSize.y = SCALE_Y(pOS2->ySuperscriptYSize);
3698 font->otm.otmptSuperscriptOffset.x = SCALE_X(pOS2->ySuperscriptXOffset);
3699 font->otm.otmptSuperscriptOffset.y = SCALE_Y(pOS2->ySuperscriptYOffset);
3700 font->otm.otmsStrikeoutSize = SCALE_Y(pOS2->yStrikeoutSize);
3701 font->otm.otmsStrikeoutPosition = SCALE_Y(pOS2->yStrikeoutPosition);
3702 if(!pPost) {
3703 font->otm.otmsUnderscoreSize = 0;
3704 font->otm.otmsUnderscorePosition = 0;
3705 } else {
3706 font->otm.otmsUnderscoreSize = SCALE_Y(pPost->underlineThickness);
3707 font->otm.otmsUnderscorePosition = SCALE_Y(pPost->underlinePosition);
3709 #undef SCALE_X
3710 #undef SCALE_Y
3711 #undef TM
3712 return TRUE;
3715 /*************************************************************
3716 * freetype_get_char_width_info
3718 static BOOL CDECL freetype_get_char_width_info( struct gdi_font *font, struct char_width_info *info )
3720 FT_Face ft_face = get_ft_face( font );
3721 TT_HoriHeader *pHori;
3723 TRACE("%p, %p\n", font, info);
3725 if ((pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea)))
3727 FT_Fixed em_scale = pFT_MulDiv(font->ppem, 1 << 16, ft_face->units_per_EM);
3728 info->lsb = (SHORT)pFT_MulFix(pHori->min_Left_Side_Bearing, em_scale);
3729 info->rsb = (SHORT)pFT_MulFix(pHori->min_Right_Side_Bearing, em_scale);
3730 return TRUE;
3732 return FALSE;
3736 /*************************************************************
3737 * freetype_get_unicode_ranges
3739 * Retrieve a list of supported Unicode ranges for a given font.
3740 * Can be called with NULL gs to calculate the buffer size. Returns
3741 * the number of ranges found.
3743 static DWORD CDECL freetype_get_unicode_ranges( struct gdi_font *font, GLYPHSET *gs )
3745 FT_Face ft_face = get_ft_face( font );
3746 DWORD num_ranges = 0;
3748 if (ft_face->charmap->encoding == FT_ENCODING_UNICODE)
3750 FT_UInt glyph_code;
3751 FT_ULong char_code, char_code_prev;
3753 glyph_code = 0;
3754 char_code_prev = char_code = pFT_Get_First_Char(ft_face, &glyph_code);
3756 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
3757 ft_face->num_glyphs, glyph_code, char_code);
3759 if (!glyph_code) return 0;
3761 if (gs)
3763 gs->ranges[0].wcLow = (USHORT)char_code;
3764 gs->ranges[0].cGlyphs = 0;
3765 gs->cGlyphsSupported = 0;
3768 num_ranges = 1;
3769 while (glyph_code)
3771 if (char_code < char_code_prev)
3773 ERR("expected increasing char code from FT_Get_Next_Char\n");
3774 return 0;
3776 if (char_code - char_code_prev > 1)
3778 num_ranges++;
3779 if (gs)
3781 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
3782 gs->ranges[num_ranges - 1].cGlyphs = 1;
3783 gs->cGlyphsSupported++;
3786 else if (gs)
3788 gs->ranges[num_ranges - 1].cGlyphs++;
3789 gs->cGlyphsSupported++;
3791 char_code_prev = char_code;
3792 char_code = pFT_Get_Next_Char(ft_face, char_code, &glyph_code);
3795 else
3797 DWORD encoding = RtlUlongByteSwap(ft_face->charmap->encoding);
3798 FIXME("encoding %s not supported\n", debugstr_an((char *)&encoding, 4));
3801 return num_ranges;
3804 /*************************************************************************
3805 * Kerning support for TrueType fonts
3808 struct TT_kern_table
3810 USHORT version;
3811 USHORT nTables;
3814 struct TT_kern_subtable
3816 USHORT version;
3817 USHORT length;
3818 union
3820 USHORT word;
3821 struct
3823 USHORT horizontal : 1;
3824 USHORT minimum : 1;
3825 USHORT cross_stream: 1;
3826 USHORT override : 1;
3827 USHORT reserved1 : 4;
3828 USHORT format : 8;
3829 } bits;
3830 } coverage;
3833 struct TT_format0_kern_subtable
3835 USHORT nPairs;
3836 USHORT searchRange;
3837 USHORT entrySelector;
3838 USHORT rangeShift;
3841 struct TT_kern_pair
3843 USHORT left;
3844 USHORT right;
3845 short value;
3848 static DWORD parse_format0_kern_subtable(struct gdi_font *font,
3849 const struct TT_format0_kern_subtable *tt_f0_ks,
3850 const USHORT *glyph_to_char,
3851 KERNINGPAIR *kern_pair, DWORD cPairs)
3853 FT_Face ft_face = get_ft_face( font );
3854 USHORT i, nPairs;
3855 const struct TT_kern_pair *tt_kern_pair;
3857 TRACE("font height %d, units_per_EM %d\n", font->ppem, ft_face->units_per_EM);
3859 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
3861 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
3862 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
3863 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
3865 if (!kern_pair || !cPairs)
3866 return nPairs;
3868 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
3870 nPairs = min(nPairs, cPairs);
3872 for (i = 0; i < nPairs; i++)
3874 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
3875 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
3876 /* this algorithm appears to better match what Windows does */
3877 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
3878 if (kern_pair->iKernAmount < 0)
3880 kern_pair->iKernAmount -= ft_face->units_per_EM / 2;
3881 kern_pair->iKernAmount -= font->ppem;
3883 else if (kern_pair->iKernAmount > 0)
3885 kern_pair->iKernAmount += ft_face->units_per_EM / 2;
3886 kern_pair->iKernAmount += font->ppem;
3888 kern_pair->iKernAmount /= ft_face->units_per_EM;
3890 TRACE("left %u right %u value %d\n",
3891 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
3893 kern_pair++;
3895 TRACE("copied %u entries\n", nPairs);
3896 return nPairs;
3899 /*************************************************************
3900 * freetype_get_kerning_pairs
3902 static DWORD CDECL freetype_get_kerning_pairs( struct gdi_font *font, KERNINGPAIR **pairs )
3904 FT_Face ft_face = get_ft_face( font );
3905 DWORD length, count = 0;
3906 void *buf;
3907 const struct TT_kern_table *tt_kern_table;
3908 const struct TT_kern_subtable *tt_kern_subtable;
3909 USHORT i, nTables;
3910 USHORT *glyph_to_char;
3912 length = freetype_get_font_data(font, MS_KERN_TAG, 0, NULL, 0);
3914 if (length == GDI_ERROR)
3916 TRACE("no kerning data in the font\n");
3917 return 0;
3920 buf = RtlAllocateHeap(GetProcessHeap(), 0, length);
3921 if (!buf) return 0;
3923 freetype_get_font_data(font, MS_KERN_TAG, 0, buf, length);
3925 /* build a glyph index to char code map */
3926 glyph_to_char = RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
3927 if (!glyph_to_char)
3929 RtlFreeHeap(GetProcessHeap(), 0, buf);
3930 return 0;
3933 if (ft_face->charmap->encoding == FT_ENCODING_UNICODE)
3935 FT_UInt glyph_code;
3936 FT_ULong char_code;
3938 glyph_code = 0;
3939 char_code = pFT_Get_First_Char(ft_face, &glyph_code);
3941 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
3942 ft_face->num_glyphs, glyph_code, char_code);
3944 while (glyph_code)
3946 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
3948 /* FIXME: This doesn't match what Windows does: it does some fancy
3949 * things with duplicate glyph index to char code mappings, while
3950 * we just avoid overriding existing entries.
3952 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
3953 glyph_to_char[glyph_code] = (USHORT)char_code;
3955 char_code = pFT_Get_Next_Char(ft_face, char_code, &glyph_code);
3958 else
3960 DWORD encoding = RtlUlongByteSwap(ft_face->charmap->encoding);
3961 ULONG n;
3963 FIXME("encoding %s not supported\n", debugstr_an((char *)&encoding, 4));
3964 for (n = 0; n <= 65535; n++)
3965 glyph_to_char[n] = (USHORT)n;
3968 tt_kern_table = buf;
3969 nTables = GET_BE_WORD(tt_kern_table->nTables);
3970 TRACE("version %u, nTables %u\n",
3971 GET_BE_WORD(tt_kern_table->version), nTables);
3973 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
3975 for (i = 0; i < nTables; i++)
3977 struct TT_kern_subtable tt_kern_subtable_copy;
3979 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
3980 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
3981 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
3983 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
3984 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
3985 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
3987 /* According to the TrueType specification this is the only format
3988 * that will be properly interpreted by Windows and OS/2
3990 if (tt_kern_subtable_copy.coverage.bits.format == 0)
3992 DWORD new_chunk, old_total = count;
3994 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
3995 glyph_to_char, NULL, 0);
3996 count += new_chunk;
3998 if (!*pairs)
3999 *pairs = RtlAllocateHeap(GetProcessHeap(), 0, count * sizeof(**pairs));
4000 else
4001 *pairs = RtlReAllocateHeap(GetProcessHeap(), 0, *pairs, count * sizeof(**pairs));
4003 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
4004 glyph_to_char, *pairs + old_total, new_chunk);
4006 else
4007 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
4009 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
4012 RtlFreeHeap(GetProcessHeap(), 0, glyph_to_char);
4013 RtlFreeHeap(GetProcessHeap(), 0, buf);
4014 return count;
4017 static const struct font_backend_funcs font_funcs =
4019 freetype_load_fonts,
4020 fontconfig_enum_family_fallbacks,
4021 freetype_add_font,
4022 freetype_add_mem_font,
4023 freetype_load_font,
4024 freetype_get_font_data,
4025 freetype_get_aa_flags,
4026 freetype_get_glyph_index,
4027 freetype_get_default_glyph,
4028 freetype_get_glyph_outline,
4029 freetype_get_unicode_ranges,
4030 freetype_get_char_width_info,
4031 freetype_set_outline_text_metrics,
4032 freetype_set_bitmap_text_metrics,
4033 freetype_get_kerning_pairs,
4034 freetype_destroy_font
4037 static NTSTATUS init_freetype_lib( HMODULE module, DWORD reason, const void *ptr_in, void *ptr_out )
4039 callback_funcs = ptr_in;
4040 if (!init_freetype()) return STATUS_DLL_NOT_FOUND;
4041 #ifdef SONAME_LIBFONTCONFIG
4042 init_fontconfig();
4043 #endif
4044 NtQueryDefaultLocale( FALSE, &system_lcid );
4045 *(const struct font_backend_funcs **)ptr_out = &font_funcs;
4046 return STATUS_SUCCESS;
4049 #else /* HAVE_FREETYPE */
4051 static NTSTATUS init_freetype_lib( HMODULE module, DWORD reason, const void *ptr_in, void *ptr_out )
4053 return STATUS_DLL_NOT_FOUND;
4056 #endif /* HAVE_FREETYPE */
4058 NTSTATUS CDECL __wine_init_unix_lib( HMODULE module, DWORD reason, const void *ptr_in, void *ptr_out )
4060 if (reason != DLL_PROCESS_ATTACH) return STATUS_SUCCESS;
4062 if (ptr_in) return init_freetype_lib( module, reason, ptr_in, ptr_out );
4063 else return init_opengl_lib( module, reason, ptr_in, ptr_out );