gdi32: Fix AddFontResource behavior with relative paths.
[wine/wine64.git] / dlls / gdi32 / freetype.c
blobb72ee509289d5abf4b84207cca86b9b61e404d05
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 #include "config.h"
25 #include "wine/port.h"
27 #include <stdarg.h>
28 #include <stdlib.h>
29 #ifdef HAVE_SYS_STAT_H
30 # include <sys/stat.h>
31 #endif
32 #ifdef HAVE_SYS_MMAN_H
33 # include <sys/mman.h>
34 #endif
35 #include <string.h>
36 #include <dirent.h>
37 #include <stdio.h>
38 #include <assert.h>
40 #ifdef HAVE_CARBON_CARBON_H
41 #define LoadResource __carbon_LoadResource
42 #define CompareString __carbon_CompareString
43 #define GetCurrentThread __carbon_GetCurrentThread
44 #define GetCurrentProcess __carbon_GetCurrentProcess
45 #define AnimatePalette __carbon_AnimatePalette
46 #define EqualRgn __carbon_EqualRgn
47 #define FillRgn __carbon_FillRgn
48 #define FrameRgn __carbon_FrameRgn
49 #define GetPixel __carbon_GetPixel
50 #define InvertRgn __carbon_InvertRgn
51 #define LineTo __carbon_LineTo
52 #define OffsetRgn __carbon_OffsetRgn
53 #define PaintRgn __carbon_PaintRgn
54 #define Polygon __carbon_Polygon
55 #define ResizePalette __carbon_ResizePalette
56 #define SetRectRgn __carbon_SetRectRgn
57 #include <Carbon/Carbon.h>
58 #undef LoadResource
59 #undef CompareString
60 #undef GetCurrentThread
61 #undef _CDECL
62 #undef DPRINTF
63 #undef GetCurrentProcess
64 #undef AnimatePalette
65 #undef EqualRgn
66 #undef FillRgn
67 #undef FrameRgn
68 #undef GetPixel
69 #undef InvertRgn
70 #undef LineTo
71 #undef OffsetRgn
72 #undef PaintRgn
73 #undef Polygon
74 #undef ResizePalette
75 #undef SetRectRgn
76 #endif /* HAVE_CARBON_CARBON_H */
78 #include "windef.h"
79 #include "winbase.h"
80 #include "winternl.h"
81 #include "winerror.h"
82 #include "winreg.h"
83 #include "wingdi.h"
84 #include "gdi_private.h"
85 #include "wine/unicode.h"
86 #include "wine/debug.h"
87 #include "wine/list.h"
89 WINE_DEFAULT_DEBUG_CHANNEL(font);
91 #ifdef HAVE_FREETYPE
93 #ifdef HAVE_FT2BUILD_H
94 #include <ft2build.h>
95 #endif
96 #ifdef HAVE_FREETYPE_FREETYPE_H
97 #include <freetype/freetype.h>
98 #endif
99 #ifdef HAVE_FREETYPE_FTGLYPH_H
100 #include <freetype/ftglyph.h>
101 #endif
102 #ifdef HAVE_FREETYPE_TTTABLES_H
103 #include <freetype/tttables.h>
104 #endif
105 #ifdef HAVE_FREETYPE_FTTYPES_H
106 #include <freetype/fttypes.h>
107 #endif
108 #ifdef HAVE_FREETYPE_FTSNAMES_H
109 #include <freetype/ftsnames.h>
110 #else
111 # ifdef HAVE_FREETYPE_FTNAMES_H
112 # include <freetype/ftnames.h>
113 # endif
114 #endif
115 #ifdef HAVE_FREETYPE_TTNAMEID_H
116 #include <freetype/ttnameid.h>
117 #endif
118 #ifdef HAVE_FREETYPE_FTOUTLN_H
119 #include <freetype/ftoutln.h>
120 #endif
121 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
122 #include <freetype/internal/sfnt.h>
123 #endif
124 #ifdef HAVE_FREETYPE_FTTRIGON_H
125 #include <freetype/fttrigon.h>
126 #endif
127 #ifdef HAVE_FREETYPE_FTWINFNT_H
128 #include <freetype/ftwinfnt.h>
129 #endif
130 #ifdef HAVE_FREETYPE_FTMODAPI_H
131 #include <freetype/ftmodapi.h>
132 #endif
134 #ifndef HAVE_FT_TRUETYPEENGINETYPE
135 typedef enum
137 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
138 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
139 FT_TRUETYPE_ENGINE_TYPE_PATENTED
140 } FT_TrueTypeEngineType;
141 #endif
143 static FT_Library library = 0;
144 typedef struct
146 FT_Int major;
147 FT_Int minor;
148 FT_Int patch;
149 } FT_Version_t;
150 static FT_Version_t FT_Version;
151 static DWORD FT_SimpleVersion;
153 static void *ft_handle = NULL;
155 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
156 MAKE_FUNCPTR(FT_Vector_Unit);
157 MAKE_FUNCPTR(FT_Done_Face);
158 MAKE_FUNCPTR(FT_Get_Char_Index);
159 MAKE_FUNCPTR(FT_Get_Module);
160 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
161 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
163 MAKE_FUNCPTR(FT_Init_FreeType);
164 MAKE_FUNCPTR(FT_Load_Glyph);
165 MAKE_FUNCPTR(FT_Matrix_Multiply);
166 MAKE_FUNCPTR(FT_MulFix);
167 MAKE_FUNCPTR(FT_New_Face);
168 MAKE_FUNCPTR(FT_New_Memory_Face);
169 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
170 MAKE_FUNCPTR(FT_Outline_Transform);
171 MAKE_FUNCPTR(FT_Outline_Translate);
172 MAKE_FUNCPTR(FT_Select_Charmap);
173 MAKE_FUNCPTR(FT_Set_Charmap);
174 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
175 MAKE_FUNCPTR(FT_Vector_Transform);
176 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
177 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
178 static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*);
179 static FT_ULong (*pFT_Get_Next_Char)(FT_Face,FT_ULong,FT_UInt*);
180 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
181 #ifdef HAVE_FREETYPE_FTWINFNT_H
182 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
183 #endif
185 #ifdef SONAME_LIBFONTCONFIG
186 #include <fontconfig/fontconfig.h>
187 MAKE_FUNCPTR(FcConfigGetCurrent);
188 MAKE_FUNCPTR(FcFontList);
189 MAKE_FUNCPTR(FcFontSetDestroy);
190 MAKE_FUNCPTR(FcInit);
191 MAKE_FUNCPTR(FcObjectSetAdd);
192 MAKE_FUNCPTR(FcObjectSetCreate);
193 MAKE_FUNCPTR(FcObjectSetDestroy);
194 MAKE_FUNCPTR(FcPatternCreate);
195 MAKE_FUNCPTR(FcPatternDestroy);
196 MAKE_FUNCPTR(FcPatternGetBool);
197 MAKE_FUNCPTR(FcPatternGetString);
198 #endif
200 #undef MAKE_FUNCPTR
202 #ifndef FT_MAKE_TAG
203 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
204 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
205 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
206 #endif
208 #ifndef ft_encoding_none
209 #define FT_ENCODING_NONE ft_encoding_none
210 #endif
211 #ifndef ft_encoding_ms_symbol
212 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
213 #endif
214 #ifndef ft_encoding_unicode
215 #define FT_ENCODING_UNICODE ft_encoding_unicode
216 #endif
217 #ifndef ft_encoding_apple_roman
218 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
219 #endif
221 #ifdef WORDS_BIGENDIAN
222 #define GET_BE_WORD(x) (x)
223 #else
224 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
225 #endif
227 /* This is bascially a copy of FT_Bitmap_Size with an extra element added */
228 typedef struct {
229 FT_Short height;
230 FT_Short width;
231 FT_Pos size;
232 FT_Pos x_ppem;
233 FT_Pos y_ppem;
234 FT_Short internal_leading;
235 } Bitmap_Size;
237 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
238 So to let this compile on older versions of FreeType we'll define the
239 new structure here. */
240 typedef struct {
241 FT_Short height, width;
242 FT_Pos size, x_ppem, y_ppem;
243 } My_FT_Bitmap_Size;
245 typedef struct tagFace {
246 struct list entry;
247 WCHAR *StyleName;
248 char *file;
249 void *font_data_ptr;
250 DWORD font_data_size;
251 FT_Long face_index;
252 BOOL Italic;
253 BOOL Bold;
254 FONTSIGNATURE fs;
255 FONTSIGNATURE fs_links;
256 DWORD ntmFlags; /* Only some bits stored here. Others are computed on the fly */
257 FT_Fixed font_version;
258 BOOL scalable;
259 Bitmap_Size size; /* set if face is a bitmap */
260 BOOL external; /* TRUE if we should manually add this font to the registry */
261 struct tagFamily *family;
262 /* Cached data for Enum */
263 BOOL cache_valid;
264 ENUMLOGFONTEXW elf;
265 NEWTEXTMETRICEXW ntm;
266 DWORD type;
267 } Face;
269 typedef struct tagFamily {
270 struct list entry;
271 const WCHAR *FamilyName;
272 struct list faces;
273 } Family;
275 typedef struct {
276 GLYPHMETRICS gm;
277 INT adv; /* These three hold to widths of the unrotated chars */
278 INT lsb;
279 INT bbx;
280 BOOL init;
281 } GM;
283 typedef struct {
284 FLOAT eM11, eM12;
285 FLOAT eM21, eM22;
286 } FMAT2;
288 typedef struct {
289 DWORD hash;
290 LOGFONTW lf;
291 FMAT2 matrix;
292 BOOL can_use_bitmap;
293 } FONT_DESC;
295 typedef struct tagHFONTLIST {
296 struct list entry;
297 HFONT hfont;
298 } HFONTLIST;
300 typedef struct {
301 struct list entry;
302 Face *face;
303 GdiFont *font;
304 } CHILD_FONT;
306 struct tagGdiFont {
307 struct list entry;
308 FT_Face ft_face;
309 struct font_mapping *mapping;
310 LPWSTR name;
311 int charset;
312 int codepage;
313 BOOL fake_italic;
314 BOOL fake_bold;
315 BYTE underline;
316 BYTE strikeout;
317 INT orientation;
318 GM **gm;
319 DWORD gmsize;
320 struct list hfontlist;
321 FONT_DESC font_desc;
322 LONG aveWidth, ppem;
323 float scale_x, scale_y;
324 SHORT yMax;
325 SHORT yMin;
326 OUTLINETEXTMETRICW *potm;
327 DWORD ntmFlags;
328 DWORD total_kern_pairs;
329 KERNINGPAIR *kern_pairs;
330 FONTSIGNATURE fs;
331 GdiFont *base_font;
332 struct list child_fonts;
335 typedef struct {
336 struct list entry;
337 const WCHAR *font_name;
338 struct list links;
339 } SYSTEM_LINKS;
341 #define GM_BLOCK_SIZE 128
342 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
344 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
345 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
346 #define UNUSED_CACHE_SIZE 10
347 static struct list child_font_list = LIST_INIT(child_font_list);
348 static struct list system_links = LIST_INIT(system_links);
350 static struct list font_subst_list = LIST_INIT(font_subst_list);
352 static struct list font_list = LIST_INIT(font_list);
354 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
355 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
356 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
358 static const WCHAR RegularW[] = {'R','e','g','u','l','a','r','\0'};
360 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
361 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
362 'W','i','n','d','o','w','s','\\',
363 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
364 'F','o','n','t','s','\0'};
366 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
367 'W','i','n','d','o','w','s',' ','N','T','\\',
368 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
369 'F','o','n','t','s','\0'};
371 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
372 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
373 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
374 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
376 static const WCHAR * const SystemFontValues[4] = {
377 System_Value,
378 OEMFont_Value,
379 FixedSys_Value,
380 NULL
383 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
384 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
386 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
387 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
388 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
389 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
390 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
391 'E','u','r','o','p','e','a','n','\0'};
392 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
393 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
394 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
395 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
396 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
397 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
398 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
399 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
400 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
401 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
402 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
403 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
405 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
406 WesternW, /*00*/
407 Central_EuropeanW,
408 CyrillicW,
409 GreekW,
410 TurkishW,
411 HebrewW,
412 ArabicW,
413 BalticW,
414 VietnameseW, /*08*/
415 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
416 ThaiW,
417 JapaneseW,
418 CHINESE_GB2312W,
419 HangulW,
420 CHINESE_BIG5W,
421 Hangul_Johab_W,
422 NULL, NULL, /*23*/
423 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
424 SymbolW /*31*/
427 typedef struct {
428 WCHAR *name;
429 INT charset;
430 } NameCs;
432 typedef struct tagFontSubst {
433 struct list entry;
434 NameCs from;
435 NameCs to;
436 } FontSubst;
438 struct font_mapping
440 struct list entry;
441 int refcount;
442 dev_t dev;
443 ino_t ino;
444 void *data;
445 size_t size;
448 static struct list mappings_list = LIST_INIT( mappings_list );
450 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
452 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
454 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
456 /****************************************
457 * Notes on .fon files
459 * The fonts System, FixedSys and Terminal are special. There are typically multiple
460 * versions installed for different resolutions and codepages. Windows stores which one to use
461 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
462 * Key Meaning
463 * FIXEDFON.FON FixedSys
464 * FONTS.FON System
465 * OEMFONT.FON Terminal
466 * LogPixels Current dpi set by the display control panel applet
467 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
468 * also has a LogPixels value that appears to mirror this)
470 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
471 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
472 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
473 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
474 * so that makes sense.
476 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
477 * to be mapped into the registry on Windows 2000 at least).
478 * I have
479 * woafont=app850.fon
480 * ega80woa.fon=ega80850.fon
481 * ega40woa.fon=ega40850.fon
482 * cga80woa.fon=cga80850.fon
483 * cga40woa.fon=cga40850.fon
486 #ifdef HAVE_CARBON_CARBON_H
487 static char *find_cache_dir(void)
489 FSRef ref;
490 OSErr err;
491 static char cached_path[MAX_PATH];
492 static const char *wine = "/Wine", *fonts = "/Fonts";
494 if(*cached_path) return cached_path;
496 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
497 if(err != noErr)
499 WARN("can't create cached data folder\n");
500 return NULL;
502 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
503 if(err != noErr)
505 WARN("can't create cached data path\n");
506 *cached_path = '\0';
507 return NULL;
509 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
511 ERR("Could not create full path\n");
512 *cached_path = '\0';
513 return NULL;
515 strcat(cached_path, wine);
517 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
519 WARN("Couldn't mkdir %s\n", cached_path);
520 *cached_path = '\0';
521 return NULL;
523 strcat(cached_path, fonts);
524 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
526 WARN("Couldn't mkdir %s\n", cached_path);
527 *cached_path = '\0';
528 return NULL;
530 return cached_path;
533 /******************************************************************
534 * expand_mac_font
536 * Extracts individual TrueType font files from a Mac suitcase font
537 * and saves them into the user's caches directory (see
538 * find_cache_dir()).
539 * Returns a NULL terminated array of filenames.
541 * We do this because they are apps that try to read ttf files
542 * themselves and they don't like Mac suitcase files.
544 static char **expand_mac_font(const char *path)
546 FSRef ref;
547 SInt16 res_ref;
548 OSStatus s;
549 unsigned int idx;
550 const char *out_dir;
551 const char *filename;
552 int output_len;
553 struct {
554 char **array;
555 unsigned int size, max_size;
556 } ret;
558 TRACE("path %s\n", path);
560 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
561 if(s != noErr)
563 WARN("failed to get ref\n");
564 return NULL;
567 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
568 if(s != noErr)
570 TRACE("no data fork, so trying resource fork\n");
571 res_ref = FSOpenResFile(&ref, fsRdPerm);
572 if(res_ref == -1)
574 TRACE("unable to open resource fork\n");
575 return NULL;
579 ret.size = 0;
580 ret.max_size = 10;
581 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
582 if(!ret.array)
584 CloseResFile(res_ref);
585 return NULL;
588 out_dir = find_cache_dir();
590 filename = strrchr(path, '/');
591 if(!filename) filename = path;
592 else filename++;
594 /* output filename has the form out_dir/filename_%04x.ttf */
595 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
597 UseResFile(res_ref);
598 idx = 1;
599 while(1)
601 FamRec *fam_rec;
602 unsigned short *num_faces_ptr, num_faces, face;
603 AsscEntry *assoc;
604 Handle fond;
605 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
607 fond = Get1IndResource(fond_res, idx);
608 if(!fond) break;
609 TRACE("got fond resource %d\n", idx);
610 HLock(fond);
612 fam_rec = *(FamRec**)fond;
613 num_faces_ptr = (unsigned short *)(fam_rec + 1);
614 num_faces = GET_BE_WORD(*num_faces_ptr);
615 num_faces++;
616 assoc = (AsscEntry*)(num_faces_ptr + 1);
617 TRACE("num faces %04x\n", num_faces);
618 for(face = 0; face < num_faces; face++, assoc++)
620 Handle sfnt;
621 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
622 unsigned short size, font_id;
623 char *output;
625 size = GET_BE_WORD(assoc->fontSize);
626 font_id = GET_BE_WORD(assoc->fontID);
627 if(size != 0)
629 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
630 continue;
633 TRACE("trying to load sfnt id %04x\n", font_id);
634 sfnt = GetResource(sfnt_res, font_id);
635 if(!sfnt)
637 TRACE("can't get sfnt resource %04x\n", font_id);
638 continue;
641 output = HeapAlloc(GetProcessHeap(), 0, output_len);
642 if(output)
644 int fd;
646 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
648 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
649 if(fd != -1 || errno == EEXIST)
651 if(fd != -1)
653 unsigned char *sfnt_data;
655 HLock(sfnt);
656 sfnt_data = *(unsigned char**)sfnt;
657 write(fd, sfnt_data, GetHandleSize(sfnt));
658 HUnlock(sfnt);
659 close(fd);
661 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
663 ret.max_size *= 2;
664 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
666 ret.array[ret.size++] = output;
668 else
670 WARN("unable to create %s\n", output);
671 HeapFree(GetProcessHeap(), 0, output);
674 ReleaseResource(sfnt);
676 HUnlock(fond);
677 ReleaseResource(fond);
678 idx++;
680 CloseResFile(res_ref);
682 return ret.array;
685 #endif /* HAVE_CARBON_CARBON_H */
687 static inline BOOL is_win9x(void)
689 return GetVersion() & 0x80000000;
692 This function builds an FT_Fixed from a float. It puts the integer part
693 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
694 It fails if the integer part of the float number is greater than SHORT_MAX.
696 static inline FT_Fixed FT_FixedFromFloat(float f)
698 short value = f;
699 unsigned short fract = (f - value) * 0xFFFF;
700 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
704 This function builds an FT_Fixed from a FIXED. It simply put f.value
705 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
707 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
709 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
713 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
715 Family *family;
716 Face *face;
717 const char *file;
718 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
719 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
721 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
722 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
724 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
726 if(face_name && strcmpiW(face_name, family->FamilyName))
727 continue;
728 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
730 if (!face->file)
731 continue;
732 file = strrchr(face->file, '/');
733 if(!file)
734 file = face->file;
735 else
736 file++;
737 if(!strcasecmp(file, file_nameA))
739 HeapFree(GetProcessHeap(), 0, file_nameA);
740 return face;
744 HeapFree(GetProcessHeap(), 0, file_nameA);
745 return NULL;
748 static Family *find_family_from_name(const WCHAR *name)
750 Family *family;
752 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
754 if(!strcmpiW(family->FamilyName, name))
755 return family;
758 return NULL;
761 static void DumpSubstList(void)
763 FontSubst *psub;
765 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
767 if(psub->from.charset != -1 || psub->to.charset != -1)
768 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
769 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
770 else
771 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
772 debugstr_w(psub->to.name));
774 return;
777 static LPWSTR strdupW(LPCWSTR p)
779 LPWSTR ret;
780 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
781 ret = HeapAlloc(GetProcessHeap(), 0, len);
782 memcpy(ret, p, len);
783 return ret;
786 static LPSTR strdupA(LPCSTR p)
788 LPSTR ret;
789 DWORD len = (strlen(p) + 1);
790 ret = HeapAlloc(GetProcessHeap(), 0, len);
791 memcpy(ret, p, len);
792 return ret;
795 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
796 INT from_charset)
798 FontSubst *element;
800 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
802 if(!strcmpiW(element->from.name, from_name) &&
803 (element->from.charset == from_charset ||
804 element->from.charset == -1))
805 return element;
808 return NULL;
811 #define ADD_FONT_SUBST_FORCE 1
813 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
815 FontSubst *from_exist, *to_exist;
817 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
819 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
821 list_remove(&from_exist->entry);
822 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
823 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
824 HeapFree(GetProcessHeap(), 0, from_exist);
825 from_exist = NULL;
828 if(!from_exist)
830 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
832 if(to_exist)
834 HeapFree(GetProcessHeap(), 0, subst->to.name);
835 subst->to.name = strdupW(to_exist->to.name);
838 list_add_tail(subst_list, &subst->entry);
840 return TRUE;
843 HeapFree(GetProcessHeap(), 0, subst->from.name);
844 HeapFree(GetProcessHeap(), 0, subst->to.name);
845 HeapFree(GetProcessHeap(), 0, subst);
846 return FALSE;
849 static void split_subst_info(NameCs *nc, LPSTR str)
851 CHAR *p = strrchr(str, ',');
852 DWORD len;
854 nc->charset = -1;
855 if(p && *(p+1)) {
856 nc->charset = strtol(p+1, NULL, 10);
857 *p = '\0';
859 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
860 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
861 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
864 static void LoadSubstList(void)
866 FontSubst *psub;
867 HKEY hkey;
868 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
869 LPSTR value;
870 LPVOID data;
872 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
873 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
874 &hkey) == ERROR_SUCCESS) {
876 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
877 &valuelen, &datalen, NULL, NULL);
879 valuelen++; /* returned value doesn't include room for '\0' */
880 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
881 data = HeapAlloc(GetProcessHeap(), 0, datalen);
883 dlen = datalen;
884 vlen = valuelen;
885 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
886 &dlen) == ERROR_SUCCESS) {
887 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
889 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
890 split_subst_info(&psub->from, value);
891 split_subst_info(&psub->to, data);
893 /* Win 2000 doesn't allow mapping between different charsets
894 or mapping of DEFAULT_CHARSET */
895 if((psub->to.charset != psub->from.charset) ||
896 psub->to.charset == DEFAULT_CHARSET) {
897 HeapFree(GetProcessHeap(), 0, psub->to.name);
898 HeapFree(GetProcessHeap(), 0, psub->from.name);
899 HeapFree(GetProcessHeap(), 0, psub);
900 } else {
901 add_font_subst(&font_subst_list, psub, 0);
903 /* reset dlen and vlen */
904 dlen = datalen;
905 vlen = valuelen;
907 HeapFree(GetProcessHeap(), 0, data);
908 HeapFree(GetProcessHeap(), 0, value);
909 RegCloseKey(hkey);
913 static WCHAR *get_familyname(FT_Face ft_face)
915 WCHAR *family = NULL;
916 FT_SfntName name;
917 FT_UInt num_names, name_index, i;
919 if(FT_IS_SFNT(ft_face))
921 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
923 for(name_index = 0; name_index < num_names; name_index++)
925 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
927 if((name.name_id == TT_NAME_ID_FONT_FAMILY) &&
928 (name.language_id == GetUserDefaultLCID()) &&
929 (name.platform_id == TT_PLATFORM_MICROSOFT) &&
930 (name.encoding_id == TT_MS_ID_UNICODE_CS))
932 /* String is not nul terminated and string_len is a byte length. */
933 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
934 for(i = 0; i < name.string_len / 2; i++)
936 WORD *tmp = (WORD *)&name.string[i * 2];
937 family[i] = GET_BE_WORD(*tmp);
939 family[i] = 0;
941 TRACE("Got localised name %s\n", debugstr_w(family));
942 return family;
948 return NULL;
952 /*****************************************************************
953 * load_sfnt_table
955 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
956 * of FreeType that don't export this function.
959 static FT_Error load_sfnt_table(FT_Face ft_face, FT_ULong table, FT_Long offset, FT_Byte *buf, FT_ULong *len)
962 FT_Error err;
964 /* If the FT_Load_Sfnt_Table function is there we'll use it */
965 if(pFT_Load_Sfnt_Table)
967 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, len);
969 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
970 else /* Do it the hard way */
972 TT_Face tt_face = (TT_Face) ft_face;
973 SFNT_Interface *sfnt;
974 if (FT_Version.major==2 && FT_Version.minor==0)
976 /* 2.0.x */
977 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
979 else
981 /* A field was added in the middle of the structure in 2.1.x */
982 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
984 err = sfnt->load_any(tt_face, table, offset, buf, len);
986 #else
987 else
989 static int msg;
990 if(!msg)
992 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
993 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
994 "Please upgrade your freetype library.\n");
995 msg++;
997 err = FT_Err_Unimplemented_Feature;
999 #endif
1000 return err;
1004 #define ADDFONT_EXTERNAL_FONT 0x01
1005 #define ADDFONT_FORCE_BITMAP 0x02
1006 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1008 FT_Face ft_face;
1009 TT_OS2 *pOS2;
1010 TT_Header *pHeader = NULL;
1011 WCHAR *english_family, *localised_family, *StyleW;
1012 DWORD len;
1013 Family *family;
1014 Face *face;
1015 struct list *family_elem_ptr, *face_elem_ptr;
1016 FT_Error err;
1017 FT_Long face_index = 0, num_faces;
1018 #ifdef HAVE_FREETYPE_FTWINFNT_H
1019 FT_WinFNT_HeaderRec winfnt_header;
1020 #endif
1021 int i, bitmap_num, internal_leading;
1022 FONTSIGNATURE fs;
1024 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1025 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1027 #ifdef HAVE_CARBON_CARBON_H
1028 if(file && !fake_family)
1030 char **mac_list = expand_mac_font(file);
1031 if(mac_list)
1033 BOOL had_one = FALSE;
1034 char **cursor;
1035 for(cursor = mac_list; *cursor; cursor++)
1037 had_one = TRUE;
1038 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1039 HeapFree(GetProcessHeap(), 0, *cursor);
1041 HeapFree(GetProcessHeap(), 0, mac_list);
1042 if(had_one)
1043 return 1;
1046 #endif /* HAVE_CARBON_CARBON_H */
1048 do {
1049 char *family_name = fake_family;
1051 if (file)
1053 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1054 err = pFT_New_Face(library, file, face_index, &ft_face);
1055 } else
1057 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1058 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1061 if(err != 0) {
1062 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1063 return 0;
1066 if(!FT_IS_SFNT(ft_face) && (FT_IS_SCALABLE(ft_face) || !(flags & ADDFONT_FORCE_BITMAP))) { /* for now we'll accept TT/OT or bitmap fonts*/
1067 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1068 pFT_Done_Face(ft_face);
1069 return 0;
1072 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1073 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1074 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1075 pFT_Done_Face(ft_face);
1076 return 0;
1079 if(FT_IS_SFNT(ft_face))
1081 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1082 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1083 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1085 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1086 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1087 pFT_Done_Face(ft_face);
1088 return 0;
1091 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1092 we don't want to load these. */
1093 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1095 FT_ULong len = 0;
1097 if(!load_sfnt_table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1099 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1100 pFT_Done_Face(ft_face);
1101 return 0;
1106 if(!ft_face->family_name || !ft_face->style_name) {
1107 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1108 pFT_Done_Face(ft_face);
1109 return 0;
1112 if (target_family)
1114 localised_family = get_familyname(ft_face);
1115 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1117 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1118 HeapFree(GetProcessHeap(), 0, localised_family);
1119 num_faces = ft_face->num_faces;
1120 pFT_Done_Face(ft_face);
1121 continue;
1123 HeapFree(GetProcessHeap(), 0, localised_family);
1126 if(!family_name)
1127 family_name = ft_face->family_name;
1129 bitmap_num = 0;
1130 do {
1131 My_FT_Bitmap_Size *size = NULL;
1132 FT_ULong tmp_size;
1134 if(!FT_IS_SCALABLE(ft_face))
1135 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1137 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1138 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1139 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1141 localised_family = NULL;
1142 if(!fake_family) {
1143 localised_family = get_familyname(ft_face);
1144 if(localised_family && !strcmpW(localised_family, english_family)) {
1145 HeapFree(GetProcessHeap(), 0, localised_family);
1146 localised_family = NULL;
1150 family = NULL;
1151 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1152 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1153 if(!strcmpW(family->FamilyName, localised_family ? localised_family : english_family))
1154 break;
1155 family = NULL;
1157 if(!family) {
1158 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1159 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1160 list_init(&family->faces);
1161 list_add_tail(&font_list, &family->entry);
1163 if(localised_family) {
1164 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1165 subst->from.name = strdupW(english_family);
1166 subst->from.charset = -1;
1167 subst->to.name = strdupW(localised_family);
1168 subst->to.charset = -1;
1169 add_font_subst(&font_subst_list, subst, 0);
1172 HeapFree(GetProcessHeap(), 0, localised_family);
1173 HeapFree(GetProcessHeap(), 0, english_family);
1175 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1176 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1177 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1179 internal_leading = 0;
1180 memset(&fs, 0, sizeof(fs));
1182 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1183 if(pOS2) {
1184 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1185 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1186 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1187 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1188 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1189 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1190 if(pOS2->version == 0) {
1191 FT_UInt dummy;
1193 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1194 fs.fsCsb[0] |= FS_LATIN1;
1195 else
1196 fs.fsCsb[0] |= FS_SYMBOL;
1199 #ifdef HAVE_FREETYPE_FTWINFNT_H
1200 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1201 CHARSETINFO csi;
1202 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1203 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1204 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1205 memcpy(&fs, &csi.fs, sizeof(csi.fs));
1206 internal_leading = winfnt_header.internal_leading;
1208 #endif
1210 face_elem_ptr = list_head(&family->faces);
1211 while(face_elem_ptr) {
1212 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1213 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1214 if(!strcmpW(face->StyleName, StyleW) &&
1215 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1216 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1217 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1218 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1220 if(fake_family) {
1221 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1222 HeapFree(GetProcessHeap(), 0, StyleW);
1223 pFT_Done_Face(ft_face);
1224 return 1;
1226 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1227 TRACE("Original font is newer so skipping this one\n");
1228 HeapFree(GetProcessHeap(), 0, StyleW);
1229 pFT_Done_Face(ft_face);
1230 return 1;
1231 } else {
1232 TRACE("Replacing original with this one\n");
1233 list_remove(&face->entry);
1234 HeapFree(GetProcessHeap(), 0, face->file);
1235 HeapFree(GetProcessHeap(), 0, face->StyleName);
1236 HeapFree(GetProcessHeap(), 0, face);
1237 break;
1241 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1242 face->cache_valid = FALSE;
1243 list_add_tail(&family->faces, &face->entry);
1244 face->StyleName = StyleW;
1245 if (file)
1247 face->file = strdupA(file);
1248 face->font_data_ptr = NULL;
1249 face->font_data_size = 0;
1251 else
1253 face->file = NULL;
1254 face->font_data_ptr = font_data_ptr;
1255 face->font_data_size = font_data_size;
1257 face->face_index = face_index;
1258 face->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
1259 face->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
1260 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1261 face->family = family;
1262 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1263 memcpy(&face->fs, &fs, sizeof(face->fs));
1264 memset(&face->fs_links, 0, sizeof(face->fs_links));
1266 if(FT_IS_SCALABLE(ft_face)) {
1267 memset(&face->size, 0, sizeof(face->size));
1268 face->scalable = TRUE;
1269 } else {
1270 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1271 size->height, size->width, size->size >> 6,
1272 size->x_ppem >> 6, size->y_ppem >> 6);
1273 face->size.height = size->height;
1274 face->size.width = size->width;
1275 face->size.size = size->size;
1276 face->size.x_ppem = size->x_ppem;
1277 face->size.y_ppem = size->y_ppem;
1278 face->size.internal_leading = internal_leading;
1279 face->scalable = FALSE;
1282 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1283 tmp_size = 0;
1284 if (pFT_Load_Sfnt_Table && !pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1286 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1287 face->ntmFlags = NTM_PS_OPENTYPE;
1289 else
1290 face->ntmFlags = 0;
1292 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1293 face->fs.fsCsb[0], face->fs.fsCsb[1],
1294 face->fs.fsUsb[0], face->fs.fsUsb[1],
1295 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1298 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1299 for(i = 0; i < ft_face->num_charmaps; i++) {
1300 switch(ft_face->charmaps[i]->encoding) {
1301 case FT_ENCODING_UNICODE:
1302 case FT_ENCODING_APPLE_ROMAN:
1303 face->fs.fsCsb[0] |= FS_LATIN1;
1304 break;
1305 case FT_ENCODING_MS_SYMBOL:
1306 face->fs.fsCsb[0] |= FS_SYMBOL;
1307 break;
1308 default:
1309 break;
1314 if (!(face->fs.fsCsb[0] & FS_SYMBOL))
1315 have_installed_roman_font = TRUE;
1316 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1318 num_faces = ft_face->num_faces;
1319 pFT_Done_Face(ft_face);
1320 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1321 debugstr_w(StyleW));
1322 } while(num_faces > ++face_index);
1323 return num_faces;
1326 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1328 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1331 static void DumpFontList(void)
1333 Family *family;
1334 Face *face;
1335 struct list *family_elem_ptr, *face_elem_ptr;
1337 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1338 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1339 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1340 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1341 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1342 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1343 if(!face->scalable)
1344 TRACE(" %d", face->size.height);
1345 TRACE("\n");
1348 return;
1351 /***********************************************************
1352 * The replacement list is a way to map an entire font
1353 * family onto another family. For example adding
1355 * [HKCU\Software\Wine\Fonts\Replacements]
1356 * "Wingdings"="Winedings"
1358 * would enumerate the Winedings font both as Winedings and
1359 * Wingdings. However if a real Wingdings font is present the
1360 * replacement does not take place.
1363 static void LoadReplaceList(void)
1365 HKEY hkey;
1366 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1367 LPWSTR value;
1368 LPVOID data;
1369 Family *family;
1370 Face *face;
1371 struct list *family_elem_ptr, *face_elem_ptr;
1372 CHAR familyA[400];
1374 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1375 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1377 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1378 &valuelen, &datalen, NULL, NULL);
1380 valuelen++; /* returned value doesn't include room for '\0' */
1381 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1382 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1384 dlen = datalen;
1385 vlen = valuelen;
1386 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1387 &dlen) == ERROR_SUCCESS) {
1388 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1389 /* "NewName"="Oldname" */
1390 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1392 /* Find the old family and hence all of the font files
1393 in that family */
1394 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1395 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1396 if(!strcmpiW(family->FamilyName, data)) {
1397 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1398 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1399 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1400 debugstr_w(face->StyleName), familyA);
1401 /* Now add a new entry with the new family name */
1402 AddFontToList(face->file, face->font_data_ptr, face->font_data_size, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1404 break;
1407 /* reset dlen and vlen */
1408 dlen = datalen;
1409 vlen = valuelen;
1411 HeapFree(GetProcessHeap(), 0, data);
1412 HeapFree(GetProcessHeap(), 0, value);
1413 RegCloseKey(hkey);
1417 /*************************************************************
1418 * init_system_links
1420 static BOOL init_system_links(void)
1422 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1423 'W','i','n','d','o','w','s',' ','N','T','\\',
1424 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1425 'S','y','s','t','e','m','L','i','n','k',0};
1426 HKEY hkey;
1427 BOOL ret = FALSE;
1428 DWORD type, max_val, max_data, val_len, data_len, index;
1429 WCHAR *value, *data;
1430 WCHAR *entry, *next;
1431 SYSTEM_LINKS *font_link, *system_font_link;
1432 CHILD_FONT *child_font;
1433 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
1434 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1435 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1436 FONTSIGNATURE fs;
1437 Family *family;
1438 Face *face;
1439 FontSubst *psub;
1441 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1443 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1444 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1445 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1446 val_len = max_val + 1;
1447 data_len = max_data;
1448 index = 0;
1449 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1451 TRACE("%s:\n", debugstr_w(value));
1453 memset(&fs, 0, sizeof(fs));
1454 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1455 psub = get_font_subst(&font_subst_list, value, -1);
1456 font_link->font_name = (psub)? strdupW(psub->to.name) : strdupW(value);
1457 list_init(&font_link->links);
1458 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1460 WCHAR *face_name;
1461 CHILD_FONT *child_font;
1463 TRACE("\t%s\n", debugstr_w(entry));
1465 next = entry + strlenW(entry) + 1;
1467 face_name = strchrW(entry, ',');
1468 if(face_name)
1470 *face_name++ = 0;
1471 while(isspaceW(*face_name))
1472 face_name++;
1474 psub = get_font_subst(&font_subst_list, face_name, -1);
1475 if(psub)
1476 face_name = psub->to.name;
1478 face = find_face_from_filename(entry, face_name);
1479 if(!face)
1481 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1482 continue;
1485 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1486 child_font->face = face;
1487 child_font->font = NULL;
1488 fs.fsCsb[0] |= face->fs.fsCsb[0];
1489 fs.fsCsb[1] |= face->fs.fsCsb[1];
1490 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1491 list_add_tail(&font_link->links, &child_font->entry);
1493 family = find_family_from_name(font_link->font_name);
1494 if(family)
1496 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1498 memcpy(&face->fs_links, &fs, sizeof(fs));
1501 list_add_tail(&system_links, &font_link->entry);
1502 val_len = max_val + 1;
1503 data_len = max_data;
1506 HeapFree(GetProcessHeap(), 0, value);
1507 HeapFree(GetProcessHeap(), 0, data);
1508 RegCloseKey(hkey);
1511 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1512 that Tahoma has */
1514 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1515 system_font_link->font_name = strdupW(System);
1516 list_init(&system_font_link->links);
1518 face = find_face_from_filename(tahoma_ttf, Tahoma);
1519 if(face)
1521 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1522 child_font->face = face;
1523 child_font->font = NULL;
1524 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
1525 list_add_tail(&system_font_link->links, &child_font->entry);
1527 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1529 if(!strcmpiW(font_link->font_name, Tahoma))
1531 CHILD_FONT *font_link_entry;
1532 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1534 CHILD_FONT *new_child;
1535 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1536 new_child->face = font_link_entry->face;
1537 new_child->font = NULL;
1538 list_add_tail(&system_font_link->links, &new_child->entry);
1540 break;
1543 list_add_tail(&system_links, &system_font_link->entry);
1544 return ret;
1547 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1549 DIR *dir;
1550 struct dirent *dent;
1551 char path[MAX_PATH];
1553 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1555 dir = opendir(dirname);
1556 if(!dir) {
1557 WARN("Can't open directory %s\n", debugstr_a(dirname));
1558 return FALSE;
1560 while((dent = readdir(dir)) != NULL) {
1561 struct stat statbuf;
1563 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1564 continue;
1566 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1568 sprintf(path, "%s/%s", dirname, dent->d_name);
1570 if(stat(path, &statbuf) == -1)
1572 WARN("Can't stat %s\n", debugstr_a(path));
1573 continue;
1575 if(S_ISDIR(statbuf.st_mode))
1576 ReadFontDir(path, external_fonts);
1577 else
1578 AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1580 closedir(dir);
1581 return TRUE;
1584 static void load_fontconfig_fonts(void)
1586 #ifdef SONAME_LIBFONTCONFIG
1587 void *fc_handle = NULL;
1588 FcConfig *config;
1589 FcPattern *pat;
1590 FcObjectSet *os;
1591 FcFontSet *fontset;
1592 int i, len;
1593 char *file;
1594 const char *ext;
1596 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1597 if(!fc_handle) {
1598 TRACE("Wine cannot find the fontconfig library (%s).\n",
1599 SONAME_LIBFONTCONFIG);
1600 return;
1602 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
1603 LOAD_FUNCPTR(FcConfigGetCurrent);
1604 LOAD_FUNCPTR(FcFontList);
1605 LOAD_FUNCPTR(FcFontSetDestroy);
1606 LOAD_FUNCPTR(FcInit);
1607 LOAD_FUNCPTR(FcObjectSetAdd);
1608 LOAD_FUNCPTR(FcObjectSetCreate);
1609 LOAD_FUNCPTR(FcObjectSetDestroy);
1610 LOAD_FUNCPTR(FcPatternCreate);
1611 LOAD_FUNCPTR(FcPatternDestroy);
1612 LOAD_FUNCPTR(FcPatternGetBool);
1613 LOAD_FUNCPTR(FcPatternGetString);
1614 #undef LOAD_FUNCPTR
1616 if(!pFcInit()) return;
1618 config = pFcConfigGetCurrent();
1619 pat = pFcPatternCreate();
1620 os = pFcObjectSetCreate();
1621 pFcObjectSetAdd(os, FC_FILE);
1622 pFcObjectSetAdd(os, FC_SCALABLE);
1623 fontset = pFcFontList(config, pat, os);
1624 if(!fontset) return;
1625 for(i = 0; i < fontset->nfont; i++) {
1626 FcBool scalable;
1628 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1629 continue;
1630 TRACE("fontconfig: %s\n", file);
1632 /* We're just interested in OT/TT fonts for now, so this hack just
1633 picks up the scalable fonts without extensions .pf[ab] to save time
1634 loading every other font */
1636 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1638 TRACE("not scalable\n");
1639 continue;
1642 len = strlen( file );
1643 if(len < 4) continue;
1644 ext = &file[ len - 3 ];
1645 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1646 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT);
1648 pFcFontSetDestroy(fontset);
1649 pFcObjectSetDestroy(os);
1650 pFcPatternDestroy(pat);
1651 sym_not_found:
1652 #endif
1653 return;
1656 static BOOL load_font_from_data_dir(LPCWSTR file)
1658 BOOL ret = FALSE;
1659 const char *data_dir = wine_get_data_dir();
1661 if (!data_dir) data_dir = wine_get_build_dir();
1663 if (data_dir)
1665 INT len;
1666 char *unix_name;
1668 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1670 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1672 strcpy(unix_name, data_dir);
1673 strcat(unix_name, "/fonts/");
1675 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1677 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1678 HeapFree(GetProcessHeap(), 0, unix_name);
1680 return ret;
1683 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
1685 static const WCHAR slashW[] = {'\\','\0'};
1686 BOOL ret = FALSE;
1687 WCHAR windowsdir[MAX_PATH];
1688 char *unixname;
1690 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1691 strcatW(windowsdir, fontsW);
1692 strcatW(windowsdir, slashW);
1693 strcatW(windowsdir, file);
1694 if ((unixname = wine_get_unix_file_name(windowsdir))) {
1695 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1696 HeapFree(GetProcessHeap(), 0, unixname);
1698 return ret;
1701 static void load_system_fonts(void)
1703 HKEY hkey;
1704 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1705 const WCHAR * const *value;
1706 DWORD dlen, type;
1707 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1708 char *unixname;
1710 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1711 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1712 strcatW(windowsdir, fontsW);
1713 for(value = SystemFontValues; *value; value++) {
1714 dlen = sizeof(data);
1715 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1716 type == REG_SZ) {
1717 BOOL added = FALSE;
1719 sprintfW(pathW, fmtW, windowsdir, data);
1720 if((unixname = wine_get_unix_file_name(pathW))) {
1721 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1722 HeapFree(GetProcessHeap(), 0, unixname);
1724 if (!added)
1725 load_font_from_data_dir(data);
1728 RegCloseKey(hkey);
1732 /*************************************************************
1734 * This adds registry entries for any externally loaded fonts
1735 * (fonts from fontconfig or FontDirs). It also deletes entries
1736 * of no longer existing fonts.
1739 static void update_reg_entries(void)
1741 HKEY winkey = 0, externalkey = 0;
1742 LPWSTR valueW;
1743 LPVOID data;
1744 DWORD dlen, vlen, datalen, valuelen, i, type, len, len_fam;
1745 Family *family;
1746 Face *face;
1747 struct list *family_elem_ptr, *face_elem_ptr;
1748 WCHAR *file;
1749 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1750 static const WCHAR spaceW[] = {' ', '\0'};
1751 char *path;
1753 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1754 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winkey, NULL) != ERROR_SUCCESS) {
1755 ERR("Can't create Windows font reg key\n");
1756 goto end;
1758 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1759 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &externalkey) != ERROR_SUCCESS) {
1760 ERR("Can't create external font reg key\n");
1761 goto end;
1764 /* Delete all external fonts added last time */
1766 RegQueryInfoKeyW(externalkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1767 &valuelen, &datalen, NULL, NULL);
1768 valuelen++; /* returned value doesn't include room for '\0' */
1769 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1770 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1772 dlen = datalen * sizeof(WCHAR);
1773 vlen = valuelen;
1774 i = 0;
1775 while(RegEnumValueW(externalkey, i++, valueW, &vlen, NULL, &type, data,
1776 &dlen) == ERROR_SUCCESS) {
1778 RegDeleteValueW(winkey, valueW);
1779 /* reset dlen and vlen */
1780 dlen = datalen;
1781 vlen = valuelen;
1783 HeapFree(GetProcessHeap(), 0, data);
1784 HeapFree(GetProcessHeap(), 0, valueW);
1786 /* Delete the old external fonts key */
1787 RegCloseKey(externalkey);
1788 externalkey = 0;
1789 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
1791 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1792 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1793 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
1794 ERR("Can't create external font reg key\n");
1795 goto end;
1798 /* enumerate the fonts and add external ones to the two keys */
1800 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1801 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1802 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1803 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1804 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1805 if(!face->external) continue;
1806 len = len_fam;
1807 if(strcmpiW(face->StyleName, RegularW))
1808 len = len_fam + strlenW(face->StyleName) + 1;
1809 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1810 strcpyW(valueW, family->FamilyName);
1811 if(len != len_fam) {
1812 strcatW(valueW, spaceW);
1813 strcatW(valueW, face->StyleName);
1815 strcatW(valueW, TrueType);
1816 if((path = strrchr(face->file, '/')) == NULL)
1817 path = face->file;
1818 else
1819 path++;
1820 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1822 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1823 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1824 RegSetValueExW(winkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1825 RegSetValueExW(externalkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1827 HeapFree(GetProcessHeap(), 0, file);
1828 HeapFree(GetProcessHeap(), 0, valueW);
1831 end:
1832 if(externalkey)
1833 RegCloseKey(externalkey);
1834 if(winkey)
1835 RegCloseKey(winkey);
1836 return;
1840 /*************************************************************
1841 * WineEngAddFontResourceEx
1844 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1846 INT ret = 0;
1847 if (ft_handle) /* do it only if we have freetype up and running */
1849 char *unixname;
1851 if(flags)
1852 FIXME("Ignoring flags %x\n", flags);
1854 if((unixname = wine_get_unix_file_name(file)))
1856 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1857 HeapFree(GetProcessHeap(), 0, unixname);
1859 if (!ret && !strchrW(file, '\\')) {
1860 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
1861 ret = load_font_from_winfonts_dir(file);
1862 if (!ret) {
1863 /* Try in datadir/fonts (or builddir/fonts),
1864 * needed for Magic the Gathering Online
1866 ret = load_font_from_data_dir(file);
1870 return ret;
1873 /*************************************************************
1874 * WineEngAddFontMemResourceEx
1877 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
1879 if (ft_handle) /* do it only if we have freetype up and running */
1881 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
1883 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
1884 memcpy(pFontCopy, pbFont, cbFont);
1886 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
1888 if (*pcFonts == 0)
1890 TRACE("AddFontToList failed\n");
1891 HeapFree(GetProcessHeap(), 0, pFontCopy);
1892 return NULL;
1894 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
1895 * For now return something unique but quite random
1897 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
1898 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
1901 *pcFonts = 0;
1902 return 0;
1905 /*************************************************************
1906 * WineEngRemoveFontResourceEx
1909 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1911 FIXME(":stub\n");
1912 return TRUE;
1915 static const struct nls_update_font_list
1917 UINT ansi_cp, oem_cp;
1918 const char *oem, *fixed, *system;
1919 const char *courier, *serif, *small, *sserif;
1920 /* these are for font substitute */
1921 const char *shelldlg, *tmsrmn;
1922 } nls_update_font_list[] =
1924 /* Latin 1 (United States) */
1925 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
1926 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1927 "Tahoma","Times New Roman",
1929 /* Latin 1 (Multilingual) */
1930 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
1931 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1932 "Tahoma","Times New Roman", /* FIXME unverified */
1934 /* Eastern Europe */
1935 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
1936 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
1937 "Tahoma","Times New Roman", /* FIXME unverified */
1939 /* Cyrillic */
1940 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
1941 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
1942 "Tahoma","Times New Roman", /* FIXME unverified */
1944 /* Greek */
1945 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
1946 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
1947 "Tahoma","Times New Roman", /* FIXME unverified */
1949 /* Turkish */
1950 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
1951 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
1952 "Tahoma","Times New Roman", /* FIXME unverified */
1954 /* Hebrew */
1955 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
1956 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
1957 "Tahoma","Times New Roman", /* FIXME unverified */
1959 /* Arabic */
1960 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
1961 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
1962 "Tahoma","Times New Roman", /* FIXME unverified */
1964 /* Baltic */
1965 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
1966 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
1967 "Tahoma","Times New Roman", /* FIXME unverified */
1969 /* Vietnamese */
1970 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
1971 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1972 "Tahoma","Times New Roman", /* FIXME unverified */
1974 /* Thai */
1975 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
1976 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
1977 "Tahoma","Times New Roman", /* FIXME unverified */
1979 /* Japanese */
1980 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
1981 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
1982 "MS UI Gothic","MS Serif",
1984 /* Chinese Simplified */
1985 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
1986 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1987 "Tahoma", "Times New Roman", /* FIXME unverified */
1989 /* Korean */
1990 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
1991 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1992 "Gulim", "Batang",
1994 /* Chinese Traditional */
1995 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
1996 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1997 "Tahoma", "Times New Roman", /* FIXME unverified */
2001 static inline HKEY create_fonts_NT_registry_key(void)
2003 HKEY hkey = 0;
2005 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2006 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2007 return hkey;
2010 static inline HKEY create_fonts_9x_registry_key(void)
2012 HKEY hkey = 0;
2014 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2015 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2016 return hkey;
2019 static inline HKEY create_config_fonts_registry_key(void)
2021 HKEY hkey = 0;
2023 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2024 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2025 return hkey;
2028 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2030 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2031 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2032 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2033 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2036 static void update_font_info(void)
2038 char buf[40], cpbuf[40];
2039 DWORD len, type;
2040 HKEY hkey = 0;
2041 UINT i, ansi_cp = 0, oem_cp = 0;
2043 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2044 return;
2046 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2047 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2048 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2049 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2050 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2052 len = sizeof(buf);
2053 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2055 if (!strcmp( buf, cpbuf )) /* already set correctly */
2057 RegCloseKey(hkey);
2058 return;
2060 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2062 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2064 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2065 RegCloseKey(hkey);
2067 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2069 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2070 nls_update_font_list[i].oem_cp == oem_cp)
2072 HKEY hkey;
2074 hkey = create_config_fonts_registry_key();
2075 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2076 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2077 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2078 RegCloseKey(hkey);
2080 hkey = create_fonts_NT_registry_key();
2081 add_font_list(hkey, &nls_update_font_list[i]);
2082 RegCloseKey(hkey);
2084 hkey = create_fonts_9x_registry_key();
2085 add_font_list(hkey, &nls_update_font_list[i]);
2086 RegCloseKey(hkey);
2088 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2090 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2091 strlen(nls_update_font_list[i].shelldlg)+1);
2092 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2093 strlen(nls_update_font_list[i].tmsrmn)+1);
2094 RegCloseKey(hkey);
2096 return;
2099 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2102 /*************************************************************
2103 * WineEngInit
2105 * Initialize FreeType library and create a list of available faces
2107 BOOL WineEngInit(void)
2109 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2110 static const WCHAR pathW[] = {'P','a','t','h',0};
2111 HKEY hkey;
2112 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2113 LPVOID data;
2114 WCHAR windowsdir[MAX_PATH];
2115 char *unixname;
2116 HANDLE font_mutex;
2117 const char *data_dir;
2119 TRACE("\n");
2121 /* update locale dependent font info in registry */
2122 update_font_info();
2124 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2125 if(!ft_handle) {
2126 WINE_MESSAGE(
2127 "Wine cannot find the FreeType font library. To enable Wine to\n"
2128 "use TrueType fonts please install a version of FreeType greater than\n"
2129 "or equal to 2.0.5.\n"
2130 "http://www.freetype.org\n");
2131 return FALSE;
2134 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(ft_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
2136 LOAD_FUNCPTR(FT_Vector_Unit)
2137 LOAD_FUNCPTR(FT_Done_Face)
2138 LOAD_FUNCPTR(FT_Get_Char_Index)
2139 LOAD_FUNCPTR(FT_Get_Module)
2140 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2141 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2142 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2143 LOAD_FUNCPTR(FT_Init_FreeType)
2144 LOAD_FUNCPTR(FT_Load_Glyph)
2145 LOAD_FUNCPTR(FT_Matrix_Multiply)
2146 LOAD_FUNCPTR(FT_MulFix)
2147 LOAD_FUNCPTR(FT_New_Face)
2148 LOAD_FUNCPTR(FT_New_Memory_Face)
2149 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2150 LOAD_FUNCPTR(FT_Outline_Transform)
2151 LOAD_FUNCPTR(FT_Outline_Translate)
2152 LOAD_FUNCPTR(FT_Select_Charmap)
2153 LOAD_FUNCPTR(FT_Set_Charmap)
2154 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2155 LOAD_FUNCPTR(FT_Vector_Transform)
2157 #undef LOAD_FUNCPTR
2158 /* Don't warn if this one is missing */
2159 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
2160 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
2161 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
2162 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
2163 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2164 #ifdef HAVE_FREETYPE_FTWINFNT_H
2165 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2166 #endif
2167 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2168 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2169 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2170 <= 2.0.3 has FT_Sqrt64 */
2171 goto sym_not_found;
2174 if(pFT_Init_FreeType(&library) != 0) {
2175 ERR("Can't init FreeType library\n");
2176 wine_dlclose(ft_handle, NULL, 0);
2177 ft_handle = NULL;
2178 return FALSE;
2180 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
2181 if (pFT_Library_Version)
2183 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2185 if (FT_Version.major<=0)
2187 FT_Version.major=2;
2188 FT_Version.minor=0;
2189 FT_Version.patch=5;
2191 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2192 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2193 ((FT_Version.minor << 8) & 0x00ff00) |
2194 ((FT_Version.patch ) & 0x0000ff);
2196 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2197 ERR("Failed to create font mutex\n");
2198 return FALSE;
2200 WaitForSingleObject(font_mutex, INFINITE);
2202 /* load the system bitmap fonts */
2203 load_system_fonts();
2205 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2206 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2207 strcatW(windowsdir, fontsW);
2208 if((unixname = wine_get_unix_file_name(windowsdir)))
2210 ReadFontDir(unixname, FALSE);
2211 HeapFree(GetProcessHeap(), 0, unixname);
2214 /* load the system truetype fonts */
2215 data_dir = wine_get_data_dir();
2216 if (!data_dir) data_dir = wine_get_build_dir();
2217 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2218 strcpy(unixname, data_dir);
2219 strcat(unixname, "/fonts/");
2220 ReadFontDir(unixname, TRUE);
2221 HeapFree(GetProcessHeap(), 0, unixname);
2224 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2225 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2226 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2227 will skip these. */
2228 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2229 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2230 &hkey) == ERROR_SUCCESS) {
2231 LPWSTR valueW;
2232 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2233 &valuelen, &datalen, NULL, NULL);
2235 valuelen++; /* returned value doesn't include room for '\0' */
2236 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2237 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2238 if (valueW && data)
2240 dlen = datalen * sizeof(WCHAR);
2241 vlen = valuelen;
2242 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
2243 &dlen) == ERROR_SUCCESS) {
2244 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
2246 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
2248 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2249 HeapFree(GetProcessHeap(), 0, unixname);
2252 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
2254 WCHAR pathW[MAX_PATH];
2255 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2256 BOOL added = FALSE;
2258 sprintfW(pathW, fmtW, windowsdir, data);
2259 if((unixname = wine_get_unix_file_name(pathW)))
2261 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2262 HeapFree(GetProcessHeap(), 0, unixname);
2264 if (!added)
2265 load_font_from_data_dir(data);
2267 /* reset dlen and vlen */
2268 dlen = datalen;
2269 vlen = valuelen;
2272 HeapFree(GetProcessHeap(), 0, data);
2273 HeapFree(GetProcessHeap(), 0, valueW);
2274 RegCloseKey(hkey);
2277 load_fontconfig_fonts();
2279 /* then look in any directories that we've specified in the config file */
2280 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2281 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2283 DWORD len;
2284 LPWSTR valueW;
2285 LPSTR valueA, ptr;
2287 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2289 len += sizeof(WCHAR);
2290 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2291 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2293 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2294 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2295 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2296 TRACE( "got font path %s\n", debugstr_a(valueA) );
2297 ptr = valueA;
2298 while (ptr)
2300 LPSTR next = strchr( ptr, ':' );
2301 if (next) *next++ = 0;
2302 ReadFontDir( ptr, TRUE );
2303 ptr = next;
2305 HeapFree( GetProcessHeap(), 0, valueA );
2307 HeapFree( GetProcessHeap(), 0, valueW );
2309 RegCloseKey(hkey);
2312 DumpFontList();
2313 LoadSubstList();
2314 DumpSubstList();
2315 LoadReplaceList();
2316 update_reg_entries();
2318 init_system_links();
2320 ReleaseMutex(font_mutex);
2321 return TRUE;
2322 sym_not_found:
2323 WINE_MESSAGE(
2324 "Wine cannot find certain functions that it needs inside the FreeType\n"
2325 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2326 "FreeType to at least version 2.0.5.\n"
2327 "http://www.freetype.org\n");
2328 wine_dlclose(ft_handle, NULL, 0);
2329 ft_handle = NULL;
2330 return FALSE;
2334 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2336 TT_OS2 *pOS2;
2337 TT_HoriHeader *pHori;
2339 LONG ppem;
2341 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2342 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2344 if(height == 0) height = 16;
2346 /* Calc. height of EM square:
2348 * For +ve lfHeight we have
2349 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2350 * Re-arranging gives:
2351 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2353 * For -ve lfHeight we have
2354 * |lfHeight| = ppem
2355 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2356 * with il = winAscent + winDescent - units_per_em]
2360 if(height > 0) {
2361 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2362 ppem = ft_face->units_per_EM * height /
2363 (pHori->Ascender - pHori->Descender);
2364 else
2365 ppem = ft_face->units_per_EM * height /
2366 (pOS2->usWinAscent + pOS2->usWinDescent);
2368 else
2369 ppem = -height;
2371 return ppem;
2374 static struct font_mapping *map_font_file( const char *name )
2376 struct font_mapping *mapping;
2377 struct stat st;
2378 int fd;
2380 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2381 if (fstat( fd, &st ) == -1) goto error;
2383 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2385 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2387 mapping->refcount++;
2388 close( fd );
2389 return mapping;
2392 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2393 goto error;
2395 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2396 close( fd );
2398 if (mapping->data == MAP_FAILED)
2400 HeapFree( GetProcessHeap(), 0, mapping );
2401 return NULL;
2403 mapping->refcount = 1;
2404 mapping->dev = st.st_dev;
2405 mapping->ino = st.st_ino;
2406 mapping->size = st.st_size;
2407 list_add_tail( &mappings_list, &mapping->entry );
2408 return mapping;
2410 error:
2411 close( fd );
2412 return NULL;
2415 static void unmap_font_file( struct font_mapping *mapping )
2417 if (!--mapping->refcount)
2419 list_remove( &mapping->entry );
2420 munmap( mapping->data, mapping->size );
2421 HeapFree( GetProcessHeap(), 0, mapping );
2425 static LONG load_VDMX(GdiFont*, LONG);
2427 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
2429 FT_Error err;
2430 FT_Face ft_face;
2431 void *data_ptr;
2432 DWORD data_size;
2434 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
2436 if (face->file)
2438 if (!(font->mapping = map_font_file( face->file )))
2440 WARN("failed to map %s\n", debugstr_a(face->file));
2441 return 0;
2443 data_ptr = font->mapping->data;
2444 data_size = font->mapping->size;
2446 else
2448 data_ptr = face->font_data_ptr;
2449 data_size = face->font_data_size;
2452 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
2453 if(err) {
2454 ERR("FT_New_Face rets %d\n", err);
2455 return 0;
2458 /* set it here, as load_VDMX needs it */
2459 font->ft_face = ft_face;
2461 if(FT_IS_SCALABLE(ft_face)) {
2462 /* load the VDMX table if we have one */
2463 font->ppem = load_VDMX(font, height);
2464 if(font->ppem == 0)
2465 font->ppem = calc_ppem_for_height(ft_face, height);
2467 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
2468 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
2469 } else {
2470 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
2471 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
2473 return ft_face;
2477 static int get_nearest_charset(Face *face, int *cp)
2479 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2480 a single face with the requested charset. The idea is to check if
2481 the selected font supports the current ANSI codepage, if it does
2482 return the corresponding charset, else return the first charset */
2484 CHARSETINFO csi;
2485 int acp = GetACP(), i;
2486 DWORD fs0;
2488 *cp = acp;
2489 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
2490 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2491 return csi.ciCharset;
2493 for(i = 0; i < 32; i++) {
2494 fs0 = 1L << i;
2495 if(face->fs.fsCsb[0] & fs0) {
2496 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
2497 *cp = csi.ciACP;
2498 return csi.ciCharset;
2500 else
2501 FIXME("TCI failing on %x\n", fs0);
2505 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2506 face->fs.fsCsb[0], face->file);
2507 *cp = acp;
2508 return DEFAULT_CHARSET;
2511 static GdiFont *alloc_font(void)
2513 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
2514 ret->gmsize = 1;
2515 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
2516 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
2517 ret->potm = NULL;
2518 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
2519 ret->total_kern_pairs = (DWORD)-1;
2520 ret->kern_pairs = NULL;
2521 list_init(&ret->hfontlist);
2522 list_init(&ret->child_fonts);
2523 return ret;
2526 static void free_font(GdiFont *font)
2528 struct list *cursor, *cursor2;
2529 int i;
2531 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
2533 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
2534 struct list *first_hfont;
2535 HFONTLIST *hfontlist;
2536 list_remove(cursor);
2537 if(child->font)
2539 first_hfont = list_head(&child->font->hfontlist);
2540 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2541 DeleteObject(hfontlist->hfont);
2542 HeapFree(GetProcessHeap(), 0, hfontlist);
2543 free_font(child->font);
2545 HeapFree(GetProcessHeap(), 0, child);
2548 if (font->ft_face) pFT_Done_Face(font->ft_face);
2549 if (font->mapping) unmap_font_file( font->mapping );
2550 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
2551 HeapFree(GetProcessHeap(), 0, font->potm);
2552 HeapFree(GetProcessHeap(), 0, font->name);
2553 for (i = 0; i < font->gmsize; i++)
2554 HeapFree(GetProcessHeap(),0,font->gm[i]);
2555 HeapFree(GetProcessHeap(), 0, font->gm);
2556 HeapFree(GetProcessHeap(), 0, font);
2560 /*************************************************************
2561 * load_VDMX
2563 * load the vdmx entry for the specified height
2566 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2567 ( ( (FT_ULong)_x4 << 24 ) | \
2568 ( (FT_ULong)_x3 << 16 ) | \
2569 ( (FT_ULong)_x2 << 8 ) | \
2570 (FT_ULong)_x1 )
2572 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2574 typedef struct {
2575 BYTE bCharSet;
2576 BYTE xRatio;
2577 BYTE yStartRatio;
2578 BYTE yEndRatio;
2579 } Ratios;
2581 typedef struct {
2582 WORD recs;
2583 BYTE startsz;
2584 BYTE endsz;
2585 } VDMX_group;
2587 static LONG load_VDMX(GdiFont *font, LONG height)
2589 WORD hdr[3], tmp;
2590 VDMX_group group;
2591 BYTE devXRatio, devYRatio;
2592 USHORT numRecs, numRatios;
2593 DWORD result, offset = -1;
2594 LONG ppem = 0;
2595 int i;
2597 /* For documentation on VDMX records, see
2598 * http://www.microsoft.com/OpenType/OTSpec/vdmx.htm
2601 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
2603 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2604 return ppem;
2606 /* FIXME: need the real device aspect ratio */
2607 devXRatio = 1;
2608 devYRatio = 1;
2610 numRecs = GET_BE_WORD(hdr[1]);
2611 numRatios = GET_BE_WORD(hdr[2]);
2613 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
2614 for(i = 0; i < numRatios; i++) {
2615 Ratios ratio;
2617 offset = (3 * 2) + (i * sizeof(Ratios));
2618 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2619 offset = -1;
2621 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2623 if((ratio.xRatio == 0 &&
2624 ratio.yStartRatio == 0 &&
2625 ratio.yEndRatio == 0) ||
2626 (devXRatio == ratio.xRatio &&
2627 devYRatio >= ratio.yStartRatio &&
2628 devYRatio <= ratio.yEndRatio))
2630 offset = (3 * 2) + (numRatios * 4) + (i * 2);
2631 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
2632 offset = GET_BE_WORD(tmp);
2633 break;
2637 if(offset == -1) {
2638 FIXME("No suitable ratio found\n");
2639 return ppem;
2642 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
2643 USHORT recs;
2644 BYTE startsz, endsz;
2645 WORD *vTable;
2647 recs = GET_BE_WORD(group.recs);
2648 startsz = group.startsz;
2649 endsz = group.endsz;
2651 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
2653 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
2654 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
2655 if(result == GDI_ERROR) {
2656 FIXME("Failed to retrieve vTable\n");
2657 goto end;
2660 if(height > 0) {
2661 for(i = 0; i < recs; i++) {
2662 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2663 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2664 ppem = GET_BE_WORD(vTable[i * 3]);
2666 if(yMax + -yMin == height) {
2667 font->yMax = yMax;
2668 font->yMin = yMin;
2669 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2670 break;
2672 if(yMax + -yMin > height) {
2673 if(--i < 0) {
2674 ppem = 0;
2675 goto end; /* failed */
2677 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2678 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2679 ppem = GET_BE_WORD(vTable[i * 3]);
2680 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2681 break;
2684 if(!font->yMax) {
2685 ppem = 0;
2686 TRACE("ppem not found for height %d\n", height);
2688 } else {
2689 ppem = -height;
2690 if(ppem < startsz || ppem > endsz)
2691 goto end;
2693 for(i = 0; i < recs; i++) {
2694 USHORT yPelHeight;
2695 yPelHeight = GET_BE_WORD(vTable[i * 3]);
2697 if(yPelHeight > ppem)
2698 break; /* failed */
2700 if(yPelHeight == ppem) {
2701 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2702 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2703 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
2704 break;
2708 end:
2709 HeapFree(GetProcessHeap(), 0, vTable);
2712 return ppem;
2715 static BOOL fontcmp(GdiFont *font, FONT_DESC *fd)
2717 if(font->font_desc.hash != fd->hash) return TRUE;
2718 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
2719 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
2720 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
2721 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
2724 static void calc_hash(FONT_DESC *pfd)
2726 DWORD hash = 0, *ptr, two_chars;
2727 WORD *pwc;
2728 unsigned int i;
2730 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
2731 hash ^= *ptr;
2732 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
2733 hash ^= *ptr;
2734 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
2735 two_chars = *ptr;
2736 pwc = (WCHAR *)&two_chars;
2737 if(!*pwc) break;
2738 *pwc = toupperW(*pwc);
2739 pwc++;
2740 *pwc = toupperW(*pwc);
2741 hash ^= two_chars;
2742 if(!*pwc) break;
2744 hash ^= !pfd->can_use_bitmap;
2745 pfd->hash = hash;
2746 return;
2749 static GdiFont *find_in_cache(HFONT hfont, LOGFONTW *plf, XFORM *pxf, BOOL can_use_bitmap)
2751 GdiFont *ret;
2752 FONT_DESC fd;
2753 HFONTLIST *hflist;
2754 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2756 memcpy(&fd.lf, plf, sizeof(LOGFONTW));
2757 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
2758 fd.can_use_bitmap = can_use_bitmap;
2759 calc_hash(&fd);
2761 /* try the in-use list */
2762 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
2763 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2764 if(!fontcmp(ret, &fd)) {
2765 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2766 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
2767 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2768 if(hflist->hfont == hfont)
2769 return ret;
2771 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2772 hflist->hfont = hfont;
2773 list_add_head(&ret->hfontlist, &hflist->entry);
2774 return ret;
2778 /* then the unused list */
2779 font_elem_ptr = list_head(&unused_gdi_font_list);
2780 while(font_elem_ptr) {
2781 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2782 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2783 if(!fontcmp(ret, &fd)) {
2784 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2785 assert(list_empty(&ret->hfontlist));
2786 TRACE("Found %p in unused list\n", ret);
2787 list_remove(&ret->entry);
2788 list_add_head(&gdi_font_list, &ret->entry);
2789 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2790 hflist->hfont = hfont;
2791 list_add_head(&ret->hfontlist, &hflist->entry);
2792 return ret;
2795 return NULL;
2799 /*************************************************************
2800 * create_child_font_list
2802 static BOOL create_child_font_list(GdiFont *font)
2804 BOOL ret = FALSE;
2805 SYSTEM_LINKS *font_link;
2806 CHILD_FONT *font_link_entry, *new_child;
2808 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2810 if(!strcmpW(font_link->font_name, font->name))
2812 TRACE("found entry in system list\n");
2813 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2815 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2816 new_child->face = font_link_entry->face;
2817 new_child->font = NULL;
2818 list_add_tail(&font->child_fonts, &new_child->entry);
2819 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
2821 ret = TRUE;
2822 break;
2826 return ret;
2829 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
2831 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
2833 if (pFT_Set_Charmap)
2835 FT_Int i;
2836 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
2838 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
2840 for (i = 0; i < ft_face->num_charmaps; i++)
2842 if (ft_face->charmaps[i]->encoding == encoding)
2844 TRACE("found cmap with platform_id %u, encoding_id %u\n",
2845 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
2847 switch (ft_face->charmaps[i]->platform_id)
2849 default:
2850 cmap_def = ft_face->charmaps[i];
2851 break;
2852 case 0: /* Apple Unicode */
2853 cmap0 = ft_face->charmaps[i];
2854 break;
2855 case 1: /* Macintosh */
2856 cmap1 = ft_face->charmaps[i];
2857 break;
2858 case 2: /* ISO */
2859 cmap2 = ft_face->charmaps[i];
2860 break;
2861 case 3: /* Microsoft */
2862 cmap3 = ft_face->charmaps[i];
2863 break;
2867 if (cmap3) /* prefer Microsoft cmap table */
2868 ft_err = pFT_Set_Charmap(ft_face, cmap3);
2869 else if (cmap1)
2870 ft_err = pFT_Set_Charmap(ft_face, cmap1);
2871 else if (cmap2)
2872 ft_err = pFT_Set_Charmap(ft_face, cmap2);
2873 else if (cmap0)
2874 ft_err = pFT_Set_Charmap(ft_face, cmap0);
2875 else if (cmap_def)
2876 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
2878 return ft_err == FT_Err_Ok;
2881 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
2884 /*************************************************************
2885 * WineEngCreateFontInstance
2888 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
2890 GdiFont *ret;
2891 Face *face, *best, *best_bitmap;
2892 Family *family, *last_resort_family;
2893 struct list *family_elem_ptr, *face_elem_ptr;
2894 INT height, width = 0;
2895 unsigned int score = 0, new_score;
2896 signed int diff = 0, newdiff;
2897 BOOL bd, it, can_use_bitmap;
2898 LOGFONTW lf;
2899 CHARSETINFO csi;
2900 HFONTLIST *hflist;
2902 LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry)
2904 struct list *first_hfont = list_head(&ret->hfontlist);
2905 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2906 if(hflist->hfont == hfont)
2907 return ret;
2910 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
2911 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
2913 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
2914 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
2915 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
2916 lf.lfEscapement);
2918 /* check the cache first */
2919 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
2920 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
2921 return ret;
2924 TRACE("not in cache\n");
2925 if(list_empty(&font_list)) /* No fonts installed */
2927 TRACE("No fonts installed\n");
2928 return NULL;
2930 if(!have_installed_roman_font)
2932 TRACE("No roman font installed\n");
2933 return NULL;
2936 ret = alloc_font();
2938 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
2939 memcpy(&ret->font_desc.lf, &lf, sizeof(LOGFONTW));
2940 ret->font_desc.can_use_bitmap = can_use_bitmap;
2941 calc_hash(&ret->font_desc);
2942 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2943 hflist->hfont = hfont;
2944 list_add_head(&ret->hfontlist, &hflist->entry);
2947 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
2948 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
2949 original value lfCharSet. Note this is a special case for
2950 Symbol and doesn't happen at least for "Wingdings*" */
2952 if(!strcmpiW(lf.lfFaceName, SymbolW))
2953 lf.lfCharSet = SYMBOL_CHARSET;
2955 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
2956 switch(lf.lfCharSet) {
2957 case DEFAULT_CHARSET:
2958 csi.fs.fsCsb[0] = 0;
2959 break;
2960 default:
2961 FIXME("Untranslated charset %d\n", lf.lfCharSet);
2962 csi.fs.fsCsb[0] = 0;
2963 break;
2967 family = NULL;
2968 if(lf.lfFaceName[0] != '\0') {
2969 FontSubst *psub;
2970 SYSTEM_LINKS *font_link;
2971 CHILD_FONT *font_link_entry;
2973 psub = get_font_subst(&font_subst_list, lf.lfFaceName, lf.lfCharSet);
2975 if(psub) {
2976 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
2977 debugstr_w(psub->to.name));
2978 strcpyW(lf.lfFaceName, psub->to.name);
2981 /* We want a match on name and charset or just name if
2982 charset was DEFAULT_CHARSET. If the latter then
2983 we fixup the returned charset later in get_nearest_charset
2984 where we'll either use the charset of the current ansi codepage
2985 or if that's unavailable the first charset that the font supports.
2987 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2988 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2989 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2990 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2991 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2992 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
2993 if(face->scalable || can_use_bitmap)
2994 goto found;
3000 * Try check the SystemLink list first for a replacement font.
3001 * We may find good replacements there.
3003 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3005 if(!strcmpiW(font_link->font_name, lf.lfFaceName))
3007 TRACE("found entry in system list\n");
3008 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3010 face = font_link_entry->face;
3011 family = face->family;
3012 if(csi.fs.fsCsb[0] &
3013 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
3015 if(face->scalable || can_use_bitmap)
3016 goto found;
3023 /* If requested charset was DEFAULT_CHARSET then try using charset
3024 corresponding to the current ansi codepage */
3025 if(!csi.fs.fsCsb[0]) {
3026 INT acp = GetACP();
3027 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
3028 FIXME("TCI failed on codepage %d\n", acp);
3029 csi.fs.fsCsb[0] = 0;
3030 } else
3031 lf.lfCharSet = csi.ciCharset;
3034 /* Face families are in the top 4 bits of lfPitchAndFamily,
3035 so mask with 0xF0 before testing */
3037 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
3038 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
3039 strcpyW(lf.lfFaceName, defFixed);
3040 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
3041 strcpyW(lf.lfFaceName, defSerif);
3042 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
3043 strcpyW(lf.lfFaceName, defSans);
3044 else
3045 strcpyW(lf.lfFaceName, defSans);
3046 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3047 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3048 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
3049 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3050 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3051 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3052 if(face->scalable || can_use_bitmap)
3053 goto found;
3058 last_resort_family = NULL;
3059 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3060 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3061 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3062 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3063 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
3064 if(face->scalable)
3065 goto found;
3066 if(can_use_bitmap && !last_resort_family)
3067 last_resort_family = family;
3072 if(last_resort_family) {
3073 family = last_resort_family;
3074 csi.fs.fsCsb[0] = 0;
3075 goto found;
3078 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3079 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3080 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3081 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3082 if(face->scalable) {
3083 csi.fs.fsCsb[0] = 0;
3084 WARN("just using first face for now\n");
3085 goto found;
3087 if(can_use_bitmap && !last_resort_family)
3088 last_resort_family = family;
3091 if(!last_resort_family) {
3092 FIXME("can't find a single appropriate font - bailing\n");
3093 free_font(ret);
3094 return NULL;
3097 WARN("could only find a bitmap font - this will probably look awful!\n");
3098 family = last_resort_family;
3099 csi.fs.fsCsb[0] = 0;
3101 found:
3102 it = lf.lfItalic ? 1 : 0;
3103 bd = lf.lfWeight > 550 ? 1 : 0;
3105 height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
3106 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
3108 face = best = best_bitmap = NULL;
3109 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
3111 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3113 new_score = (face->Italic ^ it) + (face->Bold ^ bd);
3114 if(!best || new_score <= score)
3116 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3117 face->Italic, face->Bold, it, bd);
3118 score = new_score;
3119 best = face;
3120 if(best->scalable && score == 0) break;
3121 if(!best->scalable)
3123 if(height > 0)
3124 newdiff = height - (signed int)(best->size.height);
3125 else
3126 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
3127 if(!best_bitmap || new_score < score ||
3128 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
3130 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
3131 diff = newdiff;
3132 best_bitmap = best;
3133 if(score == 0 && diff == 0) break;
3139 if(best)
3140 face = best->scalable ? best : best_bitmap;
3141 ret->fake_italic = (it && !face->Italic);
3142 ret->fake_bold = (bd && !face->Bold);
3144 memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
3146 if(csi.fs.fsCsb[0]) {
3147 ret->charset = lf.lfCharSet;
3148 ret->codepage = csi.ciACP;
3150 else
3151 ret->charset = get_nearest_charset(face, &ret->codepage);
3153 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
3154 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
3156 ret->scale_x = 0.0;
3157 ret->scale_y = 0.0;
3159 ret->aveWidth = abs(lf.lfWidth);
3161 if(!face->scalable) {
3162 ret->ppem = face->size.height;
3163 if (height != 0) ret->ppem += diff;
3165 width = face->size.x_ppem >> 6;
3166 height = face->size.y_ppem >> 6;
3168 ret->ft_face = OpenFontFace(ret, face, width, height);
3170 if (!ret->ft_face)
3172 free_font( ret );
3173 return 0;
3176 ret->ntmFlags = face->ntmFlags;
3178 if (ret->charset == SYMBOL_CHARSET &&
3179 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
3180 /* No ops */
3182 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
3183 /* No ops */
3185 else {
3186 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
3189 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
3190 ret->name = strdupW(family->FamilyName);
3191 ret->underline = lf.lfUnderline ? 0xff : 0;
3192 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
3193 create_child_font_list(ret);
3195 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
3197 list_add_head(&gdi_font_list, &ret->entry);
3198 return ret;
3201 static void dump_gdi_font_list(void)
3203 GdiFont *gdiFont;
3204 struct list *elem_ptr;
3206 TRACE("---------- gdiFont Cache ----------\n");
3207 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
3208 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3209 TRACE("gdiFont=%p %s %d\n",
3210 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3213 TRACE("---------- Unused gdiFont Cache ----------\n");
3214 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
3215 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3216 TRACE("gdiFont=%p %s %d\n",
3217 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3221 /*************************************************************
3222 * WineEngDestroyFontInstance
3224 * free the gdiFont associated with this handle
3227 BOOL WineEngDestroyFontInstance(HFONT handle)
3229 GdiFont *gdiFont;
3230 HFONTLIST *hflist;
3231 BOOL ret = FALSE;
3232 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3233 int i = 0;
3235 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
3237 struct list *first_hfont = list_head(&gdiFont->hfontlist);
3238 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3239 if(hflist->hfont == handle)
3241 TRACE("removing child font %p from child list\n", gdiFont);
3242 list_remove(&gdiFont->entry);
3243 return TRUE;
3247 TRACE("destroying hfont=%p\n", handle);
3248 if(TRACE_ON(font))
3249 dump_gdi_font_list();
3251 font_elem_ptr = list_head(&gdi_font_list);
3252 while(font_elem_ptr) {
3253 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3254 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3256 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3257 while(hfontlist_elem_ptr) {
3258 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3259 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3260 if(hflist->hfont == handle) {
3261 list_remove(&hflist->entry);
3262 HeapFree(GetProcessHeap(), 0, hflist);
3263 ret = TRUE;
3266 if(list_empty(&gdiFont->hfontlist)) {
3267 TRACE("Moving to Unused list\n");
3268 list_remove(&gdiFont->entry);
3269 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3274 font_elem_ptr = list_head(&unused_gdi_font_list);
3275 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3276 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3277 while(font_elem_ptr) {
3278 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3279 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3280 TRACE("freeing %p\n", gdiFont);
3281 list_remove(&gdiFont->entry);
3282 free_font(gdiFont);
3284 return ret;
3287 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
3288 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
3290 GdiFont *font;
3291 LONG width, height;
3293 if (face->cache_valid)
3295 TRACE("Cached\n");
3296 memcpy(pelf,&face->elf,sizeof(ENUMLOGFONTEXW));
3297 memcpy(pntm,&face->ntm,sizeof(NEWTEXTMETRICEXW));
3298 *ptype = face->type;
3299 return;
3302 font = alloc_font();
3304 if(face->scalable) {
3305 height = 100;
3306 width = 0;
3307 } else {
3308 height = face->size.y_ppem >> 6;
3309 width = face->size.x_ppem >> 6;
3312 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
3314 free_font(font);
3315 return;
3318 font->name = strdupW(face->family->FamilyName);
3319 font->ntmFlags = face->ntmFlags;
3321 if (WineEngGetOutlineTextMetrics(font, 0, NULL))
3323 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
3325 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
3327 lstrcpynW(pelf->elfLogFont.lfFaceName,
3328 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
3329 LF_FACESIZE);
3330 lstrcpynW(pelf->elfFullName,
3331 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
3332 LF_FULLFACESIZE);
3333 lstrcpynW(pelf->elfStyle,
3334 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
3335 LF_FACESIZE);
3337 else
3339 WineEngGetTextMetrics(font, (TEXTMETRICW *)&pntm->ntmTm);
3341 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
3343 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
3344 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
3345 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
3348 pntm->ntmTm.ntmFlags = face->ntmFlags;
3349 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
3350 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
3351 memcpy(&pntm->ntmFontSig, &face->fs, sizeof(FONTSIGNATURE));
3353 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
3355 pelf->elfLogFont.lfEscapement = 0;
3356 pelf->elfLogFont.lfOrientation = 0;
3357 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
3358 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
3359 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
3360 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
3361 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
3362 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
3363 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
3364 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
3365 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
3366 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
3367 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
3369 *ptype = 0;
3370 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
3371 *ptype |= TRUETYPE_FONTTYPE;
3372 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
3373 *ptype |= DEVICE_FONTTYPE;
3374 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
3375 *ptype |= RASTER_FONTTYPE;
3377 memcpy(&face->elf,pelf,sizeof(ENUMLOGFONTEXW));
3378 memcpy(&face->ntm,pntm,sizeof(NEWTEXTMETRICEXW));
3379 face->type = *ptype;
3380 face->cache_valid = TRUE;
3382 free_font(font);
3385 /*************************************************************
3386 * WineEngEnumFonts
3389 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3391 Family *family;
3392 Face *face;
3393 struct list *family_elem_ptr, *face_elem_ptr;
3394 ENUMLOGFONTEXW elf;
3395 NEWTEXTMETRICEXW ntm;
3396 DWORD type, ret = 1;
3397 FONTSIGNATURE fs;
3398 CHARSETINFO csi;
3399 LOGFONTW lf;
3400 int i;
3402 if (!plf)
3404 lf.lfCharSet = DEFAULT_CHARSET;
3405 lf.lfPitchAndFamily = 0;
3406 lf.lfFaceName[0] = 0;
3407 plf = &lf;
3410 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
3412 if(plf->lfFaceName[0]) {
3413 FontSubst *psub;
3414 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
3416 if(psub) {
3417 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
3418 debugstr_w(psub->to.name));
3419 memcpy(&lf, plf, sizeof(lf));
3420 strcpyW(lf.lfFaceName, psub->to.name);
3421 plf = &lf;
3424 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3425 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3426 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
3427 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3428 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3429 GetEnumStructs(face, &elf, &ntm, &type);
3430 for(i = 0; i < 32; i++) {
3431 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3432 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3433 strcpyW(elf.elfScript, OEM_DOSW);
3434 i = 32; /* break out of loop */
3435 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3436 continue;
3437 else {
3438 fs.fsCsb[0] = 1L << i;
3439 fs.fsCsb[1] = 0;
3440 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3441 TCI_SRCFONTSIG))
3442 csi.ciCharset = DEFAULT_CHARSET;
3443 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3444 if(csi.ciCharset != DEFAULT_CHARSET) {
3445 elf.elfLogFont.lfCharSet =
3446 ntm.ntmTm.tmCharSet = csi.ciCharset;
3447 if(ElfScriptsW[i])
3448 strcpyW(elf.elfScript, ElfScriptsW[i]);
3449 else
3450 FIXME("Unknown elfscript for bit %d\n", i);
3453 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3454 debugstr_w(elf.elfLogFont.lfFaceName),
3455 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3456 csi.ciCharset, type, debugstr_w(elf.elfScript),
3457 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3458 ntm.ntmTm.ntmFlags);
3459 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
3460 if(!ret) goto end;
3465 } else {
3466 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3467 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3468 face_elem_ptr = list_head(&family->faces);
3469 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3470 GetEnumStructs(face, &elf, &ntm, &type);
3471 for(i = 0; i < 32; i++) {
3472 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3473 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3474 strcpyW(elf.elfScript, OEM_DOSW);
3475 i = 32; /* break out of loop */
3476 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3477 continue;
3478 else {
3479 fs.fsCsb[0] = 1L << i;
3480 fs.fsCsb[1] = 0;
3481 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3482 TCI_SRCFONTSIG))
3483 csi.ciCharset = DEFAULT_CHARSET;
3484 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3485 if(csi.ciCharset != DEFAULT_CHARSET) {
3486 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
3487 csi.ciCharset;
3488 if(ElfScriptsW[i])
3489 strcpyW(elf.elfScript, ElfScriptsW[i]);
3490 else
3491 FIXME("Unknown elfscript for bit %d\n", i);
3494 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3495 debugstr_w(elf.elfLogFont.lfFaceName),
3496 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3497 csi.ciCharset, type, debugstr_w(elf.elfScript),
3498 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3499 ntm.ntmTm.ntmFlags);
3500 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
3501 if(!ret) goto end;
3505 end:
3506 return ret;
3509 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
3511 pt->x.value = vec->x >> 6;
3512 pt->x.fract = (vec->x & 0x3f) << 10;
3513 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
3514 pt->y.value = vec->y >> 6;
3515 pt->y.fract = (vec->y & 0x3f) << 10;
3516 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
3517 return;
3520 /***************************************************
3521 * According to the MSDN documentation on WideCharToMultiByte,
3522 * certain codepages cannot set the default_used parameter.
3523 * This returns TRUE if the codepage can set that parameter, false else
3524 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
3526 static BOOL codepage_sets_default_used(UINT codepage)
3528 switch (codepage)
3530 case CP_UTF7:
3531 case CP_UTF8:
3532 case CP_SYMBOL:
3533 return FALSE;
3534 default:
3535 return TRUE;
3539 static FT_UInt get_glyph_index(GdiFont *font, UINT glyph)
3541 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
3542 WCHAR wc = (WCHAR)glyph;
3543 BOOL default_used;
3544 BOOL *default_used_pointer;
3545 FT_UInt ret;
3546 char buf;
3547 default_used_pointer = NULL;
3548 default_used = FALSE;
3549 if (codepage_sets_default_used(font->codepage))
3550 default_used_pointer = &default_used;
3551 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
3552 ret = 0;
3553 else
3554 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
3555 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
3556 return ret;
3559 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
3560 glyph = glyph + 0xf000;
3561 return pFT_Get_Char_Index(font->ft_face, glyph);
3564 /*************************************************************
3565 * WineEngGetGlyphIndices
3567 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
3569 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
3570 LPWORD pgi, DWORD flags)
3572 int i;
3573 WCHAR default_char = 0;
3574 TEXTMETRICW textm;
3576 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0x001f; /* Indicate non existence */
3578 for(i = 0; i < count; i++)
3580 pgi[i] = get_glyph_index(font, lpstr[i]);
3581 if (pgi[i] == 0)
3583 if (!default_char)
3585 WineEngGetTextMetrics(font, &textm);
3586 default_char = textm.tmDefaultChar;
3588 pgi[i] = default_char;
3591 return count;
3594 /*************************************************************
3595 * WineEngGetGlyphOutline
3597 * Behaves in exactly the same way as the win32 api GetGlyphOutline
3598 * except that the first parameter is the HWINEENGFONT of the font in
3599 * question rather than an HDC.
3602 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
3603 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
3604 const MAT2* lpmat)
3606 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
3607 FT_Face ft_face = incoming_font->ft_face;
3608 GdiFont *font = incoming_font;
3609 FT_UInt glyph_index;
3610 DWORD width, height, pitch, needed = 0;
3611 FT_Bitmap ft_bitmap;
3612 FT_Error err;
3613 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
3614 FT_Angle angle = 0;
3615 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
3616 float widthRatio = 1.0, heightRatio = 1.0;
3617 FT_Matrix transMat = identityMat;
3618 BOOL needsTransform = FALSE;
3621 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
3622 buflen, buf, lpmat);
3624 if(format & GGO_GLYPH_INDEX) {
3625 glyph_index = glyph;
3626 format &= ~GGO_GLYPH_INDEX;
3627 } else {
3628 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
3629 ft_face = font->ft_face;
3632 if(glyph_index >= font->gmsize * GM_BLOCK_SIZE) {
3633 font->gmsize = (glyph_index / GM_BLOCK_SIZE + 1);
3634 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
3635 font->gmsize * sizeof(GM*));
3636 } else {
3637 if(format == GGO_METRICS && font->gm[glyph_index / GM_BLOCK_SIZE] != NULL && FONT_GM(font,glyph_index)->init ) {
3638 *lpgm = FONT_GM(font,glyph_index)->gm;
3639 return 1; /* FIXME */
3643 if (!font->gm[glyph_index / GM_BLOCK_SIZE])
3644 font->gm[glyph_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3646 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP) || lpmat)
3647 load_flags |= FT_LOAD_NO_BITMAP;
3649 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
3651 if(err) {
3652 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
3653 return GDI_ERROR;
3656 /* Scaling factor */
3657 if (font->scale_x != 0.0)
3659 widthRatio = font->scale_x;
3660 heightRatio = font->scale_y;
3663 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
3664 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
3666 adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
3667 lsb = left >> 6;
3668 bbx = (right - left) >> 6;
3670 /* Scaling transform */
3671 if(font->aveWidth) {
3672 FT_Matrix scaleMat;
3673 scaleMat.xx = FT_FixedFromFloat(widthRatio);
3674 scaleMat.xy = 0;
3675 scaleMat.yx = 0;
3676 scaleMat.yy = FT_FixedFromFloat(heightRatio);
3678 pFT_Matrix_Multiply(&scaleMat, &transMat);
3679 needsTransform = TRUE;
3682 /* Slant transform */
3683 if (font->fake_italic) {
3684 FT_Matrix slantMat;
3686 slantMat.xx = (1 << 16);
3687 slantMat.xy = ((1 << 16) >> 2);
3688 slantMat.yx = 0;
3689 slantMat.yy = (1 << 16);
3690 pFT_Matrix_Multiply(&slantMat, &transMat);
3691 needsTransform = TRUE;
3694 /* Rotation transform */
3695 if(font->orientation) {
3696 FT_Matrix rotationMat;
3697 FT_Vector vecAngle;
3698 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
3699 pFT_Vector_Unit(&vecAngle, angle);
3700 rotationMat.xx = vecAngle.x;
3701 rotationMat.xy = -vecAngle.y;
3702 rotationMat.yx = -rotationMat.xy;
3703 rotationMat.yy = rotationMat.xx;
3705 pFT_Matrix_Multiply(&rotationMat, &transMat);
3706 needsTransform = TRUE;
3709 /* Extra transformation specified by caller */
3710 if (lpmat) {
3711 FT_Matrix extraMat;
3712 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
3713 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
3714 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
3715 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
3716 pFT_Matrix_Multiply(&extraMat, &transMat);
3717 needsTransform = TRUE;
3720 if(!needsTransform) {
3721 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
3722 bottom = (ft_face->glyph->metrics.horiBearingY -
3723 ft_face->glyph->metrics.height) & -64;
3724 lpgm->gmCellIncX = adv;
3725 lpgm->gmCellIncY = 0;
3726 } else {
3727 INT xc, yc;
3728 FT_Vector vec;
3729 for(xc = 0; xc < 2; xc++) {
3730 for(yc = 0; yc < 2; yc++) {
3731 vec.x = (ft_face->glyph->metrics.horiBearingX +
3732 xc * ft_face->glyph->metrics.width);
3733 vec.y = ft_face->glyph->metrics.horiBearingY -
3734 yc * ft_face->glyph->metrics.height;
3735 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
3736 pFT_Vector_Transform(&vec, &transMat);
3737 if(xc == 0 && yc == 0) {
3738 left = right = vec.x;
3739 top = bottom = vec.y;
3740 } else {
3741 if(vec.x < left) left = vec.x;
3742 else if(vec.x > right) right = vec.x;
3743 if(vec.y < bottom) bottom = vec.y;
3744 else if(vec.y > top) top = vec.y;
3748 left = left & -64;
3749 right = (right + 63) & -64;
3750 bottom = bottom & -64;
3751 top = (top + 63) & -64;
3753 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
3754 vec.x = ft_face->glyph->metrics.horiAdvance;
3755 vec.y = 0;
3756 pFT_Vector_Transform(&vec, &transMat);
3757 lpgm->gmCellIncX = (vec.x+63) >> 6;
3758 lpgm->gmCellIncY = -((vec.y+63) >> 6);
3760 lpgm->gmBlackBoxX = (right - left) >> 6;
3761 lpgm->gmBlackBoxY = (top - bottom) >> 6;
3762 lpgm->gmptGlyphOrigin.x = left >> 6;
3763 lpgm->gmptGlyphOrigin.y = top >> 6;
3765 if(format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP)
3767 FONT_GM(font,glyph_index)->gm = *lpgm;
3768 FONT_GM(font,glyph_index)->adv = adv;
3769 FONT_GM(font,glyph_index)->lsb = lsb;
3770 FONT_GM(font,glyph_index)->bbx = bbx;
3771 FONT_GM(font,glyph_index)->init = TRUE;
3774 if(format == GGO_METRICS)
3775 return 1; /* FIXME */
3777 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP) {
3778 TRACE("loaded a bitmap\n");
3779 return GDI_ERROR;
3782 switch(format) {
3783 case GGO_BITMAP:
3784 width = lpgm->gmBlackBoxX;
3785 height = lpgm->gmBlackBoxY;
3786 pitch = ((width + 31) >> 5) << 2;
3787 needed = pitch * height;
3789 if(!buf || !buflen) break;
3791 switch(ft_face->glyph->format) {
3792 case ft_glyph_format_bitmap:
3794 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
3795 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
3796 INT h = ft_face->glyph->bitmap.rows;
3797 while(h--) {
3798 memcpy(dst, src, w);
3799 src += ft_face->glyph->bitmap.pitch;
3800 dst += pitch;
3802 break;
3805 case ft_glyph_format_outline:
3806 ft_bitmap.width = width;
3807 ft_bitmap.rows = height;
3808 ft_bitmap.pitch = pitch;
3809 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
3810 ft_bitmap.buffer = buf;
3812 if(needsTransform) {
3813 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3816 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3818 /* Note: FreeType will only set 'black' bits for us. */
3819 memset(buf, 0, needed);
3820 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3821 break;
3823 default:
3824 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
3825 return GDI_ERROR;
3827 break;
3829 case GGO_GRAY2_BITMAP:
3830 case GGO_GRAY4_BITMAP:
3831 case GGO_GRAY8_BITMAP:
3832 case WINE_GGO_GRAY16_BITMAP:
3834 unsigned int mult, row, col;
3835 BYTE *start, *ptr;
3837 width = lpgm->gmBlackBoxX;
3838 height = lpgm->gmBlackBoxY;
3839 pitch = (width + 3) / 4 * 4;
3840 needed = pitch * height;
3842 if(!buf || !buflen) break;
3844 switch(ft_face->glyph->format) {
3845 case ft_glyph_format_bitmap:
3847 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
3848 INT h = ft_face->glyph->bitmap.rows;
3849 INT x;
3850 while(h--) {
3851 for(x = 0; x < pitch; x++)
3852 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
3853 src += ft_face->glyph->bitmap.pitch;
3854 dst += pitch;
3856 return needed;
3858 case ft_glyph_format_outline:
3860 ft_bitmap.width = width;
3861 ft_bitmap.rows = height;
3862 ft_bitmap.pitch = pitch;
3863 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
3864 ft_bitmap.buffer = buf;
3866 if(needsTransform)
3867 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3869 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3871 memset(ft_bitmap.buffer, 0, buflen);
3873 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3875 if(format == GGO_GRAY2_BITMAP)
3876 mult = 4;
3877 else if(format == GGO_GRAY4_BITMAP)
3878 mult = 16;
3879 else if(format == GGO_GRAY8_BITMAP)
3880 mult = 64;
3881 else /* format == WINE_GGO_GRAY16_BITMAP */
3882 return needed;
3884 break;
3886 default:
3887 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
3888 return GDI_ERROR;
3891 start = buf;
3892 for(row = 0; row < height; row++) {
3893 ptr = start;
3894 for(col = 0; col < width; col++, ptr++) {
3895 *ptr = (((int)*ptr) * mult + 128) / 256;
3897 start += pitch;
3899 break;
3902 case GGO_NATIVE:
3904 int contour, point = 0, first_pt;
3905 FT_Outline *outline = &ft_face->glyph->outline;
3906 TTPOLYGONHEADER *pph;
3907 TTPOLYCURVE *ppc;
3908 DWORD pph_start, cpfx, type;
3910 if(buflen == 0) buf = NULL;
3912 if (needsTransform && buf) {
3913 pFT_Outline_Transform(outline, &transMat);
3916 for(contour = 0; contour < outline->n_contours; contour++) {
3917 pph_start = needed;
3918 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3919 first_pt = point;
3920 if(buf) {
3921 pph->dwType = TT_POLYGON_TYPE;
3922 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3924 needed += sizeof(*pph);
3925 point++;
3926 while(point <= outline->contours[contour]) {
3927 ppc = (TTPOLYCURVE *)((char *)buf + needed);
3928 type = (outline->tags[point] & FT_Curve_Tag_On) ?
3929 TT_PRIM_LINE : TT_PRIM_QSPLINE;
3930 cpfx = 0;
3931 do {
3932 if(buf)
3933 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3934 cpfx++;
3935 point++;
3936 } while(point <= outline->contours[contour] &&
3937 (outline->tags[point] & FT_Curve_Tag_On) ==
3938 (outline->tags[point-1] & FT_Curve_Tag_On));
3939 /* At the end of a contour Windows adds the start point, but
3940 only for Beziers */
3941 if(point > outline->contours[contour] &&
3942 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
3943 if(buf)
3944 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
3945 cpfx++;
3946 } else if(point <= outline->contours[contour] &&
3947 outline->tags[point] & FT_Curve_Tag_On) {
3948 /* add closing pt for bezier */
3949 if(buf)
3950 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3951 cpfx++;
3952 point++;
3954 if(buf) {
3955 ppc->wType = type;
3956 ppc->cpfx = cpfx;
3958 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3960 if(buf)
3961 pph->cb = needed - pph_start;
3963 break;
3965 case GGO_BEZIER:
3967 /* Convert the quadratic Beziers to cubic Beziers.
3968 The parametric eqn for a cubic Bezier is, from PLRM:
3969 r(t) = at^3 + bt^2 + ct + r0
3970 with the control points:
3971 r1 = r0 + c/3
3972 r2 = r1 + (c + b)/3
3973 r3 = r0 + c + b + a
3975 A quadratic Beizer has the form:
3976 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3978 So equating powers of t leads to:
3979 r1 = 2/3 p1 + 1/3 p0
3980 r2 = 2/3 p1 + 1/3 p2
3981 and of course r0 = p0, r3 = p2
3984 int contour, point = 0, first_pt;
3985 FT_Outline *outline = &ft_face->glyph->outline;
3986 TTPOLYGONHEADER *pph;
3987 TTPOLYCURVE *ppc;
3988 DWORD pph_start, cpfx, type;
3989 FT_Vector cubic_control[4];
3990 if(buflen == 0) buf = NULL;
3992 if (needsTransform && buf) {
3993 pFT_Outline_Transform(outline, &transMat);
3996 for(contour = 0; contour < outline->n_contours; contour++) {
3997 pph_start = needed;
3998 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3999 first_pt = point;
4000 if(buf) {
4001 pph->dwType = TT_POLYGON_TYPE;
4002 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
4004 needed += sizeof(*pph);
4005 point++;
4006 while(point <= outline->contours[contour]) {
4007 ppc = (TTPOLYCURVE *)((char *)buf + needed);
4008 type = (outline->tags[point] & FT_Curve_Tag_On) ?
4009 TT_PRIM_LINE : TT_PRIM_CSPLINE;
4010 cpfx = 0;
4011 do {
4012 if(type == TT_PRIM_LINE) {
4013 if(buf)
4014 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4015 cpfx++;
4016 point++;
4017 } else {
4018 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
4019 so cpfx = 3n */
4021 /* FIXME: Possible optimization in endpoint calculation
4022 if there are two consecutive curves */
4023 cubic_control[0] = outline->points[point-1];
4024 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
4025 cubic_control[0].x += outline->points[point].x + 1;
4026 cubic_control[0].y += outline->points[point].y + 1;
4027 cubic_control[0].x >>= 1;
4028 cubic_control[0].y >>= 1;
4030 if(point+1 > outline->contours[contour])
4031 cubic_control[3] = outline->points[first_pt];
4032 else {
4033 cubic_control[3] = outline->points[point+1];
4034 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
4035 cubic_control[3].x += outline->points[point].x + 1;
4036 cubic_control[3].y += outline->points[point].y + 1;
4037 cubic_control[3].x >>= 1;
4038 cubic_control[3].y >>= 1;
4041 /* r1 = 1/3 p0 + 2/3 p1
4042 r2 = 1/3 p2 + 2/3 p1 */
4043 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
4044 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
4045 cubic_control[2] = cubic_control[1];
4046 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
4047 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
4048 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
4049 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
4050 if(buf) {
4051 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
4052 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
4053 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
4055 cpfx += 3;
4056 point++;
4058 } while(point <= outline->contours[contour] &&
4059 (outline->tags[point] & FT_Curve_Tag_On) ==
4060 (outline->tags[point-1] & FT_Curve_Tag_On));
4061 /* At the end of a contour Windows adds the start point,
4062 but only for Beziers and we've already done that.
4064 if(point <= outline->contours[contour] &&
4065 outline->tags[point] & FT_Curve_Tag_On) {
4066 /* This is the closing pt of a bezier, but we've already
4067 added it, so just inc point and carry on */
4068 point++;
4070 if(buf) {
4071 ppc->wType = type;
4072 ppc->cpfx = cpfx;
4074 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
4076 if(buf)
4077 pph->cb = needed - pph_start;
4079 break;
4082 default:
4083 FIXME("Unsupported format %d\n", format);
4084 return GDI_ERROR;
4086 return needed;
4089 static BOOL get_bitmap_text_metrics(GdiFont *font)
4091 FT_Face ft_face = font->ft_face;
4092 #ifdef HAVE_FREETYPE_FTWINFNT_H
4093 FT_WinFNT_HeaderRec winfnt_header;
4094 #endif
4095 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
4096 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
4097 font->potm->otmSize = size;
4099 #define TM font->potm->otmTextMetrics
4100 #ifdef HAVE_FREETYPE_FTWINFNT_H
4101 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
4103 TM.tmHeight = winfnt_header.pixel_height;
4104 TM.tmAscent = winfnt_header.ascent;
4105 TM.tmDescent = TM.tmHeight - TM.tmAscent;
4106 TM.tmInternalLeading = winfnt_header.internal_leading;
4107 TM.tmExternalLeading = winfnt_header.external_leading;
4108 TM.tmAveCharWidth = winfnt_header.avg_width;
4109 TM.tmMaxCharWidth = winfnt_header.max_width;
4110 TM.tmWeight = winfnt_header.weight;
4111 TM.tmOverhang = 0;
4112 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
4113 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
4114 TM.tmFirstChar = winfnt_header.first_char;
4115 TM.tmLastChar = winfnt_header.last_char;
4116 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
4117 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
4118 TM.tmItalic = winfnt_header.italic;
4119 TM.tmUnderlined = font->underline;
4120 TM.tmStruckOut = font->strikeout;
4121 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
4122 TM.tmCharSet = winfnt_header.charset;
4124 else
4125 #endif
4127 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
4128 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
4129 TM.tmHeight = TM.tmAscent + TM.tmDescent;
4130 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
4131 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
4132 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
4133 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
4134 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
4135 TM.tmOverhang = 0;
4136 TM.tmDigitizedAspectX = 96; /* FIXME */
4137 TM.tmDigitizedAspectY = 96; /* FIXME */
4138 TM.tmFirstChar = 1;
4139 TM.tmLastChar = 255;
4140 TM.tmDefaultChar = 32;
4141 TM.tmBreakChar = 32;
4142 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
4143 TM.tmUnderlined = font->underline;
4144 TM.tmStruckOut = font->strikeout;
4145 /* NB inverted meaning of TMPF_FIXED_PITCH */
4146 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
4147 TM.tmCharSet = font->charset;
4149 #undef TM
4151 return TRUE;
4155 static void scale_font_metrics(GdiFont *font, LPTEXTMETRICW ptm)
4157 if (font->scale_x == 0.0)
4159 if (FT_IS_SCALABLE(font->ft_face) || !font->ppem)
4160 font->scale_y = 1.0;
4161 else
4163 font->scale_y = (float)font->ppem * font->font_desc.matrix.eM22;
4164 font->scale_y /= (float)font->potm->otmTextMetrics.tmHeight;
4167 if (font->aveWidth)
4169 font->scale_x = (float)font->aveWidth * font->font_desc.matrix.eM11;
4170 font->scale_x /= (float)font->potm->otmTextMetrics.tmAveCharWidth;
4172 else
4173 font->scale_x = font->scale_y;
4175 TRACE("font scale x: %f y: %f\n", font->scale_x, font->scale_y);
4177 ptm->tmHeight = (float)ptm->tmHeight * font->scale_y;
4178 ptm->tmAscent = (float)ptm->tmAscent * font->scale_y;
4179 ptm->tmDescent = (float)ptm->tmDescent * font->scale_y;
4180 ptm->tmInternalLeading = (float)ptm->tmInternalLeading * font->scale_y;
4181 ptm->tmExternalLeading = (float)ptm->tmExternalLeading * font->scale_y;
4183 ptm->tmAveCharWidth = (float)ptm->tmAveCharWidth * font->scale_x;
4184 ptm->tmMaxCharWidth = (float)ptm->tmMaxCharWidth * font->scale_x;
4187 /*************************************************************
4188 * WineEngGetTextMetrics
4191 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
4193 if(!font->potm) {
4194 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
4195 if(!get_bitmap_text_metrics(font))
4196 return FALSE;
4198 if(!font->potm) return FALSE;
4199 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
4200 scale_font_metrics(font, ptm);
4202 return TRUE;
4206 /*************************************************************
4207 * WineEngGetOutlineTextMetrics
4210 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
4211 OUTLINETEXTMETRICW *potm)
4213 FT_Face ft_face = font->ft_face;
4214 UINT needed, lenfam, lensty, ret;
4215 TT_OS2 *pOS2;
4216 TT_HoriHeader *pHori;
4217 TT_Postscript *pPost;
4218 FT_Fixed x_scale, y_scale;
4219 WCHAR *family_nameW, *style_nameW;
4220 static const WCHAR spaceW[] = {' ', '\0'};
4221 char *cp;
4222 INT ascent, descent;
4224 TRACE("font=%p\n", font);
4226 if(!FT_IS_SCALABLE(ft_face))
4227 return 0;
4229 if(font->potm) {
4230 if(cbSize >= font->potm->otmSize)
4232 memcpy(potm, font->potm, font->potm->otmSize);
4233 scale_font_metrics(font, &potm->otmTextMetrics);
4235 return font->potm->otmSize;
4239 needed = sizeof(*potm);
4241 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
4242 family_nameW = strdupW(font->name);
4244 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
4245 * sizeof(WCHAR);
4246 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
4247 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
4248 style_nameW, lensty/sizeof(WCHAR));
4250 /* These names should be read from the TT name table */
4252 /* length of otmpFamilyName */
4253 needed += lenfam;
4255 /* length of otmpFaceName */
4256 if(!strcasecmp(ft_face->style_name, "regular")) {
4257 needed += lenfam; /* just the family name */
4258 } else {
4259 needed += lenfam + lensty; /* family + " " + style */
4262 /* length of otmpStyleName */
4263 needed += lensty;
4265 /* length of otmpFullName */
4266 needed += lenfam + lensty;
4269 x_scale = ft_face->size->metrics.x_scale;
4270 y_scale = ft_face->size->metrics.y_scale;
4272 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
4273 if(!pOS2) {
4274 FIXME("Can't find OS/2 table - not TT font?\n");
4275 ret = 0;
4276 goto end;
4279 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
4280 if(!pHori) {
4281 FIXME("Can't find HHEA table - not TT font?\n");
4282 ret = 0;
4283 goto end;
4286 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
4288 TRACE("OS/2 winA = %d winD = %d typoA = %d typoD = %d typoLG = %d FT_Face a = %d, d = %d, h = %d: HORZ a = %d, d = %d lg = %d maxY = %ld minY = %ld\n",
4289 pOS2->usWinAscent, pOS2->usWinDescent,
4290 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
4291 ft_face->ascender, ft_face->descender, ft_face->height,
4292 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
4293 ft_face->bbox.yMax, ft_face->bbox.yMin);
4295 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
4296 font->potm->otmSize = needed;
4298 #define TM font->potm->otmTextMetrics
4300 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
4301 ascent = pHori->Ascender;
4302 descent = -pHori->Descender;
4303 } else {
4304 ascent = pOS2->usWinAscent;
4305 descent = pOS2->usWinDescent;
4308 if(font->yMax) {
4309 TM.tmAscent = font->yMax;
4310 TM.tmDescent = -font->yMin;
4311 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
4312 } else {
4313 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
4314 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
4315 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
4316 - ft_face->units_per_EM, y_scale) + 32) >> 6;
4319 TM.tmHeight = TM.tmAscent + TM.tmDescent;
4321 /* MSDN says:
4322 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
4324 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
4325 ((ascent + descent) -
4326 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
4328 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
4329 if (TM.tmAveCharWidth == 0) {
4330 TM.tmAveCharWidth = 1;
4332 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
4333 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
4334 TM.tmOverhang = 0;
4335 TM.tmDigitizedAspectX = 300;
4336 TM.tmDigitizedAspectY = 300;
4337 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
4338 * symbol range to 0 - f0ff
4340 if (font->charset == SYMBOL_CHARSET)
4341 TM.tmFirstChar = 0;
4342 else
4343 TM.tmFirstChar = pOS2->usFirstCharIndex;
4344 TM.tmLastChar = pOS2->usLastCharIndex;
4345 TM.tmDefaultChar = pOS2->usDefaultChar ? pOS2->usDefaultChar : 0x1f;
4346 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
4347 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
4348 TM.tmUnderlined = font->underline;
4349 TM.tmStruckOut = font->strikeout;
4351 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
4352 if(!FT_IS_FIXED_WIDTH(ft_face) &&
4353 (pOS2->version == 0xFFFFU ||
4354 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
4355 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
4356 else
4357 TM.tmPitchAndFamily = 0;
4359 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
4360 case PAN_FAMILY_SCRIPT:
4361 TM.tmPitchAndFamily |= FF_SCRIPT;
4362 break;
4363 case PAN_FAMILY_DECORATIVE:
4364 case PAN_FAMILY_PICTORIAL:
4365 TM.tmPitchAndFamily |= FF_DECORATIVE;
4366 break;
4367 case PAN_FAMILY_TEXT_DISPLAY:
4368 if(TM.tmPitchAndFamily == 0) /* fixed */
4369 TM.tmPitchAndFamily = FF_MODERN;
4370 else {
4371 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
4372 case PAN_SERIF_NORMAL_SANS:
4373 case PAN_SERIF_OBTUSE_SANS:
4374 case PAN_SERIF_PERP_SANS:
4375 TM.tmPitchAndFamily |= FF_SWISS;
4376 break;
4377 default:
4378 TM.tmPitchAndFamily |= FF_ROMAN;
4381 break;
4382 default:
4383 TM.tmPitchAndFamily |= FF_DONTCARE;
4386 if(FT_IS_SCALABLE(ft_face))
4387 TM.tmPitchAndFamily |= TMPF_VECTOR;
4389 if(FT_IS_SFNT(ft_face))
4391 if (font->ntmFlags & NTM_PS_OPENTYPE)
4392 TM.tmPitchAndFamily |= TMPF_DEVICE;
4393 else
4394 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
4397 TM.tmCharSet = font->charset;
4398 #undef TM
4400 font->potm->otmFiller = 0;
4401 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
4402 font->potm->otmfsSelection = pOS2->fsSelection;
4403 font->potm->otmfsType = pOS2->fsType;
4404 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
4405 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
4406 font->potm->otmItalicAngle = 0; /* POST table */
4407 font->potm->otmEMSquare = ft_face->units_per_EM;
4408 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
4409 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
4410 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
4411 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
4412 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
4413 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
4414 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
4415 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
4416 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
4417 font->potm->otmMacAscent = 0; /* where do these come from ? */
4418 font->potm->otmMacDescent = 0;
4419 font->potm->otmMacLineGap = 0;
4420 font->potm->otmusMinimumPPEM = 0; /* TT Header */
4421 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
4422 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
4423 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
4424 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
4425 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
4426 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
4427 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
4428 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
4429 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
4430 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
4431 if(!pPost) {
4432 font->potm->otmsUnderscoreSize = 0;
4433 font->potm->otmsUnderscorePosition = 0;
4434 } else {
4435 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
4436 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
4439 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
4440 cp = (char*)font->potm + sizeof(*font->potm);
4441 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
4442 strcpyW((WCHAR*)cp, family_nameW);
4443 cp += lenfam;
4444 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
4445 strcpyW((WCHAR*)cp, style_nameW);
4446 cp += lensty;
4447 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
4448 strcpyW((WCHAR*)cp, family_nameW);
4449 if(strcasecmp(ft_face->style_name, "regular")) {
4450 strcatW((WCHAR*)cp, spaceW);
4451 strcatW((WCHAR*)cp, style_nameW);
4452 cp += lenfam + lensty;
4453 } else
4454 cp += lenfam;
4455 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
4456 strcpyW((WCHAR*)cp, family_nameW);
4457 strcatW((WCHAR*)cp, spaceW);
4458 strcatW((WCHAR*)cp, style_nameW);
4459 ret = needed;
4461 if(potm && needed <= cbSize)
4463 memcpy(potm, font->potm, font->potm->otmSize);
4464 scale_font_metrics(font, &potm->otmTextMetrics);
4467 end:
4468 HeapFree(GetProcessHeap(), 0, style_nameW);
4469 HeapFree(GetProcessHeap(), 0, family_nameW);
4471 return ret;
4474 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
4476 HFONTLIST *hfontlist;
4477 child->font = alloc_font();
4478 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
4479 if(!child->font->ft_face)
4481 free_font(child->font);
4482 child->font = NULL;
4483 return FALSE;
4486 child->font->ntmFlags = child->face->ntmFlags;
4487 child->font->orientation = font->orientation;
4488 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
4489 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
4490 list_add_head(&child->font->hfontlist, &hfontlist->entry);
4491 child->font->base_font = font;
4492 list_add_head(&child_font_list, &child->font->entry);
4493 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
4494 return TRUE;
4497 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
4499 FT_UInt g;
4500 CHILD_FONT *child_font;
4502 if(font->base_font)
4503 font = font->base_font;
4505 *linked_font = font;
4507 if((*glyph = get_glyph_index(font, c)))
4508 return TRUE;
4510 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
4512 if(!child_font->font)
4513 if(!load_child_font(font, child_font))
4514 continue;
4516 if(!child_font->font->ft_face)
4517 continue;
4518 g = get_glyph_index(child_font->font, c);
4519 if(g)
4521 *glyph = g;
4522 *linked_font = child_font->font;
4523 return TRUE;
4526 return FALSE;
4529 /*************************************************************
4530 * WineEngGetCharWidth
4533 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
4534 LPINT buffer)
4536 UINT c;
4537 GLYPHMETRICS gm;
4538 FT_UInt glyph_index;
4539 GdiFont *linked_font;
4541 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
4543 for(c = firstChar; c <= lastChar; c++) {
4544 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
4545 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4546 &gm, 0, NULL, NULL);
4547 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
4549 return TRUE;
4552 /*************************************************************
4553 * WineEngGetCharABCWidths
4556 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
4557 LPABC buffer)
4559 UINT c;
4560 GLYPHMETRICS gm;
4561 FT_UInt glyph_index;
4562 GdiFont *linked_font;
4564 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
4566 if(!FT_IS_SCALABLE(font->ft_face))
4567 return FALSE;
4569 for(c = firstChar; c <= lastChar; c++) {
4570 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
4571 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4572 &gm, 0, NULL, NULL);
4573 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
4574 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
4575 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
4576 FONT_GM(linked_font,glyph_index)->bbx;
4578 return TRUE;
4581 /*************************************************************
4582 * WineEngGetCharABCWidthsI
4585 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
4586 LPABC buffer)
4588 UINT c;
4589 GLYPHMETRICS gm;
4590 FT_UInt glyph_index;
4591 GdiFont *linked_font;
4593 if(!FT_HAS_HORIZONTAL(font->ft_face))
4594 return FALSE;
4596 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
4597 if (!pgi)
4598 for(c = firstChar; c < firstChar+count; c++) {
4599 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
4600 &gm, 0, NULL, NULL);
4601 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
4602 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
4603 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
4604 - FONT_GM(linked_font,c)->bbx;
4606 else
4607 for(c = 0; c < count; c++) {
4608 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
4609 &gm, 0, NULL, NULL);
4610 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
4611 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
4612 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
4613 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
4616 return TRUE;
4619 /*************************************************************
4620 * WineEngGetTextExtentExPoint
4623 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
4624 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
4626 INT idx;
4627 INT nfit = 0, ext;
4628 GLYPHMETRICS gm;
4629 TEXTMETRICW tm;
4630 FT_UInt glyph_index;
4631 GdiFont *linked_font;
4633 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
4634 max_ext, size);
4636 size->cx = 0;
4637 WineEngGetTextMetrics(font, &tm);
4638 size->cy = tm.tmHeight;
4640 for(idx = 0; idx < count; idx++) {
4641 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
4642 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4643 &gm, 0, NULL, NULL);
4644 size->cx += FONT_GM(linked_font,glyph_index)->adv;
4645 ext = size->cx;
4646 if (! pnfit || ext <= max_ext) {
4647 ++nfit;
4648 if (dxs)
4649 dxs[idx] = ext;
4653 if (pnfit)
4654 *pnfit = nfit;
4656 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
4657 return TRUE;
4660 /*************************************************************
4661 * WineEngGetTextExtentExPointI
4664 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
4665 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
4667 INT idx;
4668 INT nfit = 0, ext;
4669 GLYPHMETRICS gm;
4670 TEXTMETRICW tm;
4672 TRACE("%p, %p, %d, %d, %p\n", font, indices, count, max_ext, size);
4674 size->cx = 0;
4675 WineEngGetTextMetrics(font, &tm);
4676 size->cy = tm.tmHeight;
4678 for(idx = 0; idx < count; idx++) {
4679 WineEngGetGlyphOutline(font, indices[idx],
4680 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
4681 NULL);
4682 size->cx += FONT_GM(font,indices[idx])->adv;
4683 ext = size->cx;
4684 if (! pnfit || ext <= max_ext) {
4685 ++nfit;
4686 if (dxs)
4687 dxs[idx] = ext;
4691 if (pnfit)
4692 *pnfit = nfit;
4694 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
4695 return TRUE;
4698 /*************************************************************
4699 * WineEngGetFontData
4702 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
4703 DWORD cbData)
4705 FT_Face ft_face = font->ft_face;
4706 FT_ULong len;
4707 FT_Error err;
4709 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
4710 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
4711 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
4713 if(!FT_IS_SFNT(ft_face))
4714 return GDI_ERROR;
4716 if(!buf || !cbData)
4717 len = 0;
4718 else
4719 len = cbData;
4721 if(table) { /* MS tags differ in endidness from FT ones */
4722 table = table >> 24 | table << 24 |
4723 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
4726 /* make sure value of len is the value freetype says it needs */
4727 if(buf && len)
4729 FT_ULong needed = 0;
4730 err = load_sfnt_table(ft_face, table, offset, NULL, &needed);
4731 if( !err && needed < len) len = needed;
4733 err = load_sfnt_table(ft_face, table, offset, buf, &len);
4735 if(err) {
4736 TRACE("Can't find table %c%c%c%c\n",
4737 /* bytes were reversed */
4738 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
4739 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
4740 return GDI_ERROR;
4742 return len;
4745 /*************************************************************
4746 * WineEngGetTextFace
4749 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
4751 if(str) {
4752 lstrcpynW(str, font->name, count);
4753 return strlenW(font->name);
4754 } else
4755 return strlenW(font->name) + 1;
4758 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
4760 if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
4761 return font->charset;
4764 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
4766 GdiFont *font = dc->gdiFont, *linked_font;
4767 struct list *first_hfont;
4768 BOOL ret;
4770 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
4771 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
4772 if(font == linked_font)
4773 *new_hfont = dc->hFont;
4774 else
4776 first_hfont = list_head(&linked_font->hfontlist);
4777 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
4780 return ret;
4783 /* Retrieve a list of supported Unicode ranges for a given font.
4784 * Can be called with NULL gs to calculate the buffer size. Returns
4785 * the number of ranges found.
4787 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
4789 DWORD num_ranges = 0;
4791 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
4793 FT_UInt glyph_code;
4794 FT_ULong char_code, char_code_prev;
4796 glyph_code = 0;
4797 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
4799 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
4800 face->num_glyphs, glyph_code, char_code);
4802 if (!glyph_code) return 0;
4804 if (gs)
4806 gs->ranges[0].wcLow = (USHORT)char_code;
4807 gs->ranges[0].cGlyphs = 0;
4808 gs->cGlyphsSupported = 0;
4811 num_ranges = 1;
4812 while (glyph_code)
4814 if (char_code < char_code_prev)
4816 ERR("expected increasing char code from FT_Get_Next_Char\n");
4817 return 0;
4819 if (char_code - char_code_prev > 1)
4821 num_ranges++;
4822 if (gs)
4824 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
4825 gs->ranges[num_ranges - 1].cGlyphs = 1;
4826 gs->cGlyphsSupported++;
4829 else if (gs)
4831 gs->ranges[num_ranges - 1].cGlyphs++;
4832 gs->cGlyphsSupported++;
4834 char_code_prev = char_code;
4835 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
4838 else
4839 FIXME("encoding %u not supported\n", face->charmap->encoding);
4841 return num_ranges;
4844 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
4846 DWORD size = 0;
4847 DWORD num_ranges = get_font_unicode_ranges(font->ft_face, glyphset);
4849 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
4850 if (glyphset)
4852 glyphset->cbThis = size;
4853 glyphset->cRanges = num_ranges;
4855 return size;
4858 /*************************************************************
4859 * FontIsLinked
4861 BOOL WineEngFontIsLinked(GdiFont *font)
4863 return !list_empty(&font->child_fonts);
4866 static BOOL is_hinting_enabled(void)
4868 /* Use the >= 2.2.0 function if available */
4869 if(pFT_Get_TrueType_Engine_Type)
4871 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
4872 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
4874 #ifdef FT_DRIVER_HAS_HINTER
4875 else
4877 FT_Module mod;
4879 /* otherwise if we've been compiled with < 2.2.0 headers
4880 use the internal macro */
4881 mod = pFT_Get_Module(library, "truetype");
4882 if(mod && FT_DRIVER_HAS_HINTER(mod))
4883 return TRUE;
4885 #endif
4887 return FALSE;
4890 /*************************************************************************
4891 * GetRasterizerCaps (GDI32.@)
4893 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
4895 static int hinting = -1;
4897 if(hinting == -1)
4899 hinting = is_hinting_enabled();
4900 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
4903 lprs->nSize = sizeof(RASTERIZER_STATUS);
4904 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
4905 lprs->nLanguageID = 0;
4906 return TRUE;
4909 /*************************************************************************
4910 * Kerning support for TrueType fonts
4912 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
4914 struct TT_kern_table
4916 USHORT version;
4917 USHORT nTables;
4920 struct TT_kern_subtable
4922 USHORT version;
4923 USHORT length;
4924 union
4926 USHORT word;
4927 struct
4929 USHORT horizontal : 1;
4930 USHORT minimum : 1;
4931 USHORT cross_stream: 1;
4932 USHORT override : 1;
4933 USHORT reserved1 : 4;
4934 USHORT format : 8;
4935 } bits;
4936 } coverage;
4939 struct TT_format0_kern_subtable
4941 USHORT nPairs;
4942 USHORT searchRange;
4943 USHORT entrySelector;
4944 USHORT rangeShift;
4947 struct TT_kern_pair
4949 USHORT left;
4950 USHORT right;
4951 short value;
4954 static DWORD parse_format0_kern_subtable(GdiFont *font,
4955 const struct TT_format0_kern_subtable *tt_f0_ks,
4956 const USHORT *glyph_to_char,
4957 KERNINGPAIR *kern_pair, DWORD cPairs)
4959 USHORT i, nPairs;
4960 const struct TT_kern_pair *tt_kern_pair;
4962 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
4964 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
4966 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
4967 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
4968 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
4970 if (!kern_pair || !cPairs)
4971 return nPairs;
4973 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
4975 nPairs = min(nPairs, cPairs);
4977 for (i = 0; i < nPairs; i++)
4979 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
4980 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
4981 /* this algorithm appears to better match what Windows does */
4982 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
4983 if (kern_pair->iKernAmount < 0)
4985 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
4986 kern_pair->iKernAmount -= font->ppem;
4988 else if (kern_pair->iKernAmount > 0)
4990 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
4991 kern_pair->iKernAmount += font->ppem;
4993 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
4995 TRACE("left %u right %u value %d\n",
4996 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
4998 kern_pair++;
5000 TRACE("copied %u entries\n", nPairs);
5001 return nPairs;
5004 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
5006 DWORD length;
5007 void *buf;
5008 const struct TT_kern_table *tt_kern_table;
5009 const struct TT_kern_subtable *tt_kern_subtable;
5010 USHORT i, nTables;
5011 USHORT *glyph_to_char;
5013 if (font->total_kern_pairs != (DWORD)-1)
5015 if (cPairs && kern_pair)
5017 cPairs = min(cPairs, font->total_kern_pairs);
5018 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
5019 return cPairs;
5021 return font->total_kern_pairs;
5024 font->total_kern_pairs = 0;
5026 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
5028 if (length == GDI_ERROR)
5030 TRACE("no kerning data in the font\n");
5031 return 0;
5034 buf = HeapAlloc(GetProcessHeap(), 0, length);
5035 if (!buf)
5037 WARN("Out of memory\n");
5038 return 0;
5041 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
5043 /* build a glyph index to char code map */
5044 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
5045 if (!glyph_to_char)
5047 WARN("Out of memory allocating a glyph index to char code map\n");
5048 HeapFree(GetProcessHeap(), 0, buf);
5049 return 0;
5052 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
5054 FT_UInt glyph_code;
5055 FT_ULong char_code;
5057 glyph_code = 0;
5058 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
5060 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
5061 font->ft_face->num_glyphs, glyph_code, char_code);
5063 while (glyph_code)
5065 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
5067 /* FIXME: This doesn't match what Windows does: it does some fancy
5068 * things with duplicate glyph index to char code mappings, while
5069 * we just avoid overriding existing entries.
5071 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
5072 glyph_to_char[glyph_code] = (USHORT)char_code;
5074 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
5077 else
5079 ULONG n;
5081 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
5082 for (n = 0; n <= 65535; n++)
5083 glyph_to_char[n] = (USHORT)n;
5086 tt_kern_table = buf;
5087 nTables = GET_BE_WORD(tt_kern_table->nTables);
5088 TRACE("version %u, nTables %u\n",
5089 GET_BE_WORD(tt_kern_table->version), nTables);
5091 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
5093 for (i = 0; i < nTables; i++)
5095 struct TT_kern_subtable tt_kern_subtable_copy;
5097 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
5098 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
5099 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
5101 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
5102 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
5103 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
5105 /* According to the TrueType specification this is the only format
5106 * that will be properly interpreted by Windows and OS/2
5108 if (tt_kern_subtable_copy.coverage.bits.format == 0)
5110 DWORD new_chunk, old_total = font->total_kern_pairs;
5112 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
5113 glyph_to_char, NULL, 0);
5114 font->total_kern_pairs += new_chunk;
5116 if (!font->kern_pairs)
5117 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
5118 font->total_kern_pairs * sizeof(*font->kern_pairs));
5119 else
5120 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
5121 font->total_kern_pairs * sizeof(*font->kern_pairs));
5123 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
5124 glyph_to_char, font->kern_pairs + old_total, new_chunk);
5126 else
5127 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
5129 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
5132 HeapFree(GetProcessHeap(), 0, glyph_to_char);
5133 HeapFree(GetProcessHeap(), 0, buf);
5135 if (cPairs && kern_pair)
5137 cPairs = min(cPairs, font->total_kern_pairs);
5138 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
5139 return cPairs;
5141 return font->total_kern_pairs;
5144 #else /* HAVE_FREETYPE */
5146 /*************************************************************************/
5148 BOOL WineEngInit(void)
5150 return FALSE;
5152 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
5154 return NULL;
5156 BOOL WineEngDestroyFontInstance(HFONT hfont)
5158 return FALSE;
5161 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
5163 return 1;
5166 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
5167 LPWORD pgi, DWORD flags)
5169 return GDI_ERROR;
5172 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
5173 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5174 const MAT2* lpmat)
5176 ERR("called but we don't have FreeType\n");
5177 return GDI_ERROR;
5180 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
5182 ERR("called but we don't have FreeType\n");
5183 return FALSE;
5186 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
5187 OUTLINETEXTMETRICW *potm)
5189 ERR("called but we don't have FreeType\n");
5190 return 0;
5193 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5194 LPINT buffer)
5196 ERR("called but we don't have FreeType\n");
5197 return FALSE;
5200 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5201 LPABC buffer)
5203 ERR("called but we don't have FreeType\n");
5204 return FALSE;
5207 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
5208 LPABC buffer)
5210 ERR("called but we don't have FreeType\n");
5211 return FALSE;
5214 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
5215 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
5217 ERR("called but we don't have FreeType\n");
5218 return FALSE;
5221 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
5222 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
5224 ERR("called but we don't have FreeType\n");
5225 return FALSE;
5228 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
5229 DWORD cbData)
5231 ERR("called but we don't have FreeType\n");
5232 return GDI_ERROR;
5235 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
5237 ERR("called but we don't have FreeType\n");
5238 return 0;
5241 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
5243 FIXME(":stub\n");
5244 return 1;
5247 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
5249 FIXME(":stub\n");
5250 return TRUE;
5253 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
5255 FIXME(":stub\n");
5256 return NULL;
5259 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
5261 FIXME(":stub\n");
5262 return DEFAULT_CHARSET;
5265 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
5267 return FALSE;
5270 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
5272 FIXME("(%p, %p): stub\n", font, glyphset);
5273 return 0;
5276 BOOL WineEngFontIsLinked(GdiFont *font)
5278 return FALSE;
5281 /*************************************************************************
5282 * GetRasterizerCaps (GDI32.@)
5284 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
5286 lprs->nSize = sizeof(RASTERIZER_STATUS);
5287 lprs->wFlags = 0;
5288 lprs->nLanguageID = 0;
5289 return TRUE;
5292 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
5294 ERR("called but we don't have FreeType\n");
5295 return 0;
5298 #endif /* HAVE_FREETYPE */