gdi32: Child fonts need to be scaled like their parent. With input from Dmitry Timoshkov.
[wine/multimedia.git] / dlls / gdi32 / freetype.c
blob81dc3005028e60efba8089d253e92a4284acc588
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 struct enum_data
247 ENUMLOGFONTEXW elf;
248 NEWTEXTMETRICEXW ntm;
249 DWORD type;
252 typedef struct tagFace {
253 struct list entry;
254 WCHAR *StyleName;
255 char *file;
256 void *font_data_ptr;
257 DWORD font_data_size;
258 FT_Long face_index;
259 BOOL Italic;
260 BOOL Bold;
261 FONTSIGNATURE fs;
262 FONTSIGNATURE fs_links;
263 DWORD ntmFlags; /* Only some bits stored here. Others are computed on the fly */
264 FT_Fixed font_version;
265 BOOL scalable;
266 Bitmap_Size size; /* set if face is a bitmap */
267 BOOL external; /* TRUE if we should manually add this font to the registry */
268 struct tagFamily *family;
269 /* Cached data for Enum */
270 struct enum_data *cached_enum_data;
271 } Face;
273 typedef struct tagFamily {
274 struct list entry;
275 const WCHAR *FamilyName;
276 struct list faces;
277 } Family;
279 typedef struct {
280 GLYPHMETRICS gm;
281 INT adv; /* These three hold to widths of the unrotated chars */
282 INT lsb;
283 INT bbx;
284 BOOL init;
285 } GM;
287 typedef struct {
288 FLOAT eM11, eM12;
289 FLOAT eM21, eM22;
290 } FMAT2;
292 typedef struct {
293 DWORD hash;
294 LOGFONTW lf;
295 FMAT2 matrix;
296 BOOL can_use_bitmap;
297 } FONT_DESC;
299 typedef struct tagHFONTLIST {
300 struct list entry;
301 HFONT hfont;
302 } HFONTLIST;
304 typedef struct {
305 struct list entry;
306 Face *face;
307 GdiFont *font;
308 } CHILD_FONT;
310 struct tagGdiFont {
311 struct list entry;
312 FT_Face ft_face;
313 struct font_mapping *mapping;
314 LPWSTR name;
315 int charset;
316 int codepage;
317 BOOL fake_italic;
318 BOOL fake_bold;
319 BYTE underline;
320 BYTE strikeout;
321 INT orientation;
322 GM **gm;
323 DWORD gmsize;
324 struct list hfontlist;
325 FONT_DESC font_desc;
326 LONG aveWidth, ppem;
327 float scale_y;
328 SHORT yMax;
329 SHORT yMin;
330 OUTLINETEXTMETRICW *potm;
331 DWORD ntmFlags;
332 DWORD total_kern_pairs;
333 KERNINGPAIR *kern_pairs;
334 FONTSIGNATURE fs;
335 GdiFont *base_font;
336 struct list child_fonts;
339 typedef struct {
340 struct list entry;
341 const WCHAR *font_name;
342 struct list links;
343 } SYSTEM_LINKS;
345 #define GM_BLOCK_SIZE 128
346 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
348 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
349 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
350 #define UNUSED_CACHE_SIZE 10
351 static struct list child_font_list = LIST_INIT(child_font_list);
352 static struct list system_links = LIST_INIT(system_links);
354 static struct list font_subst_list = LIST_INIT(font_subst_list);
356 static struct list font_list = LIST_INIT(font_list);
358 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
359 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
360 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
362 static const WCHAR RegularW[] = {'R','e','g','u','l','a','r','\0'};
364 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
365 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
366 'W','i','n','d','o','w','s','\\',
367 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
368 'F','o','n','t','s','\0'};
370 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
371 'W','i','n','d','o','w','s',' ','N','T','\\',
372 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
373 'F','o','n','t','s','\0'};
375 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
376 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
377 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
378 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
380 static const WCHAR * const SystemFontValues[4] = {
381 System_Value,
382 OEMFont_Value,
383 FixedSys_Value,
384 NULL
387 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
388 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
390 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
391 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
392 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
393 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
394 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
395 'E','u','r','o','p','e','a','n','\0'};
396 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
397 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
398 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
399 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
400 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
401 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
402 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
403 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
404 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
405 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
406 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
407 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
409 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
410 WesternW, /*00*/
411 Central_EuropeanW,
412 CyrillicW,
413 GreekW,
414 TurkishW,
415 HebrewW,
416 ArabicW,
417 BalticW,
418 VietnameseW, /*08*/
419 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
420 ThaiW,
421 JapaneseW,
422 CHINESE_GB2312W,
423 HangulW,
424 CHINESE_BIG5W,
425 Hangul_Johab_W,
426 NULL, NULL, /*23*/
427 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
428 SymbolW /*31*/
431 typedef struct {
432 WCHAR *name;
433 INT charset;
434 } NameCs;
436 typedef struct tagFontSubst {
437 struct list entry;
438 NameCs from;
439 NameCs to;
440 } FontSubst;
442 struct font_mapping
444 struct list entry;
445 int refcount;
446 dev_t dev;
447 ino_t ino;
448 void *data;
449 size_t size;
452 static struct list mappings_list = LIST_INIT( mappings_list );
454 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
456 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
458 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
460 /****************************************
461 * Notes on .fon files
463 * The fonts System, FixedSys and Terminal are special. There are typically multiple
464 * versions installed for different resolutions and codepages. Windows stores which one to use
465 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
466 * Key Meaning
467 * FIXEDFON.FON FixedSys
468 * FONTS.FON System
469 * OEMFONT.FON Terminal
470 * LogPixels Current dpi set by the display control panel applet
471 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
472 * also has a LogPixels value that appears to mirror this)
474 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
475 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
476 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
477 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
478 * so that makes sense.
480 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
481 * to be mapped into the registry on Windows 2000 at least).
482 * I have
483 * woafont=app850.fon
484 * ega80woa.fon=ega80850.fon
485 * ega40woa.fon=ega40850.fon
486 * cga80woa.fon=cga80850.fon
487 * cga40woa.fon=cga40850.fon
490 #ifdef HAVE_CARBON_CARBON_H
491 static char *find_cache_dir(void)
493 FSRef ref;
494 OSErr err;
495 static char cached_path[MAX_PATH];
496 static const char *wine = "/Wine", *fonts = "/Fonts";
498 if(*cached_path) return cached_path;
500 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
501 if(err != noErr)
503 WARN("can't create cached data folder\n");
504 return NULL;
506 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
507 if(err != noErr)
509 WARN("can't create cached data path\n");
510 *cached_path = '\0';
511 return NULL;
513 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
515 ERR("Could not create full path\n");
516 *cached_path = '\0';
517 return NULL;
519 strcat(cached_path, wine);
521 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
523 WARN("Couldn't mkdir %s\n", cached_path);
524 *cached_path = '\0';
525 return NULL;
527 strcat(cached_path, fonts);
528 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
530 WARN("Couldn't mkdir %s\n", cached_path);
531 *cached_path = '\0';
532 return NULL;
534 return cached_path;
537 /******************************************************************
538 * expand_mac_font
540 * Extracts individual TrueType font files from a Mac suitcase font
541 * and saves them into the user's caches directory (see
542 * find_cache_dir()).
543 * Returns a NULL terminated array of filenames.
545 * We do this because they are apps that try to read ttf files
546 * themselves and they don't like Mac suitcase files.
548 static char **expand_mac_font(const char *path)
550 FSRef ref;
551 SInt16 res_ref;
552 OSStatus s;
553 unsigned int idx;
554 const char *out_dir;
555 const char *filename;
556 int output_len;
557 struct {
558 char **array;
559 unsigned int size, max_size;
560 } ret;
562 TRACE("path %s\n", path);
564 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
565 if(s != noErr)
567 WARN("failed to get ref\n");
568 return NULL;
571 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
572 if(s != noErr)
574 TRACE("no data fork, so trying resource fork\n");
575 res_ref = FSOpenResFile(&ref, fsRdPerm);
576 if(res_ref == -1)
578 TRACE("unable to open resource fork\n");
579 return NULL;
583 ret.size = 0;
584 ret.max_size = 10;
585 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
586 if(!ret.array)
588 CloseResFile(res_ref);
589 return NULL;
592 out_dir = find_cache_dir();
594 filename = strrchr(path, '/');
595 if(!filename) filename = path;
596 else filename++;
598 /* output filename has the form out_dir/filename_%04x.ttf */
599 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
601 UseResFile(res_ref);
602 idx = 1;
603 while(1)
605 FamRec *fam_rec;
606 unsigned short *num_faces_ptr, num_faces, face;
607 AsscEntry *assoc;
608 Handle fond;
609 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
611 fond = Get1IndResource(fond_res, idx);
612 if(!fond) break;
613 TRACE("got fond resource %d\n", idx);
614 HLock(fond);
616 fam_rec = *(FamRec**)fond;
617 num_faces_ptr = (unsigned short *)(fam_rec + 1);
618 num_faces = GET_BE_WORD(*num_faces_ptr);
619 num_faces++;
620 assoc = (AsscEntry*)(num_faces_ptr + 1);
621 TRACE("num faces %04x\n", num_faces);
622 for(face = 0; face < num_faces; face++, assoc++)
624 Handle sfnt;
625 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
626 unsigned short size, font_id;
627 char *output;
629 size = GET_BE_WORD(assoc->fontSize);
630 font_id = GET_BE_WORD(assoc->fontID);
631 if(size != 0)
633 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
634 continue;
637 TRACE("trying to load sfnt id %04x\n", font_id);
638 sfnt = GetResource(sfnt_res, font_id);
639 if(!sfnt)
641 TRACE("can't get sfnt resource %04x\n", font_id);
642 continue;
645 output = HeapAlloc(GetProcessHeap(), 0, output_len);
646 if(output)
648 int fd;
650 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
652 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
653 if(fd != -1 || errno == EEXIST)
655 if(fd != -1)
657 unsigned char *sfnt_data;
659 HLock(sfnt);
660 sfnt_data = *(unsigned char**)sfnt;
661 write(fd, sfnt_data, GetHandleSize(sfnt));
662 HUnlock(sfnt);
663 close(fd);
665 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
667 ret.max_size *= 2;
668 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
670 ret.array[ret.size++] = output;
672 else
674 WARN("unable to create %s\n", output);
675 HeapFree(GetProcessHeap(), 0, output);
678 ReleaseResource(sfnt);
680 HUnlock(fond);
681 ReleaseResource(fond);
682 idx++;
684 CloseResFile(res_ref);
686 return ret.array;
689 #endif /* HAVE_CARBON_CARBON_H */
691 static inline BOOL is_win9x(void)
693 return GetVersion() & 0x80000000;
696 This function builds an FT_Fixed from a float. It puts the integer part
697 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
698 It fails if the integer part of the float number is greater than SHORT_MAX.
700 static inline FT_Fixed FT_FixedFromFloat(float f)
702 short value = f;
703 unsigned short fract = (f - value) * 0xFFFF;
704 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
708 This function builds an FT_Fixed from a FIXED. It simply put f.value
709 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
711 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
713 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
717 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
719 Family *family;
720 Face *face;
721 const char *file;
722 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
723 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
725 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
726 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
728 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
730 if(face_name && strcmpiW(face_name, family->FamilyName))
731 continue;
732 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
734 if (!face->file)
735 continue;
736 file = strrchr(face->file, '/');
737 if(!file)
738 file = face->file;
739 else
740 file++;
741 if(!strcasecmp(file, file_nameA))
743 HeapFree(GetProcessHeap(), 0, file_nameA);
744 return face;
748 HeapFree(GetProcessHeap(), 0, file_nameA);
749 return NULL;
752 static Family *find_family_from_name(const WCHAR *name)
754 Family *family;
756 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
758 if(!strcmpiW(family->FamilyName, name))
759 return family;
762 return NULL;
765 static void DumpSubstList(void)
767 FontSubst *psub;
769 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
771 if(psub->from.charset != -1 || psub->to.charset != -1)
772 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
773 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
774 else
775 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
776 debugstr_w(psub->to.name));
778 return;
781 static LPWSTR strdupW(LPCWSTR p)
783 LPWSTR ret;
784 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
785 ret = HeapAlloc(GetProcessHeap(), 0, len);
786 memcpy(ret, p, len);
787 return ret;
790 static LPSTR strdupA(LPCSTR p)
792 LPSTR ret;
793 DWORD len = (strlen(p) + 1);
794 ret = HeapAlloc(GetProcessHeap(), 0, len);
795 memcpy(ret, p, len);
796 return ret;
799 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
800 INT from_charset)
802 FontSubst *element;
804 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
806 if(!strcmpiW(element->from.name, from_name) &&
807 (element->from.charset == from_charset ||
808 element->from.charset == -1))
809 return element;
812 return NULL;
815 #define ADD_FONT_SUBST_FORCE 1
817 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
819 FontSubst *from_exist, *to_exist;
821 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
823 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
825 list_remove(&from_exist->entry);
826 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
827 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
828 HeapFree(GetProcessHeap(), 0, from_exist);
829 from_exist = NULL;
832 if(!from_exist)
834 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
836 if(to_exist)
838 HeapFree(GetProcessHeap(), 0, subst->to.name);
839 subst->to.name = strdupW(to_exist->to.name);
842 list_add_tail(subst_list, &subst->entry);
844 return TRUE;
847 HeapFree(GetProcessHeap(), 0, subst->from.name);
848 HeapFree(GetProcessHeap(), 0, subst->to.name);
849 HeapFree(GetProcessHeap(), 0, subst);
850 return FALSE;
853 static void split_subst_info(NameCs *nc, LPSTR str)
855 CHAR *p = strrchr(str, ',');
856 DWORD len;
858 nc->charset = -1;
859 if(p && *(p+1)) {
860 nc->charset = strtol(p+1, NULL, 10);
861 *p = '\0';
863 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
864 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
865 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
868 static void LoadSubstList(void)
870 FontSubst *psub;
871 HKEY hkey;
872 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
873 LPSTR value;
874 LPVOID data;
876 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
877 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
878 &hkey) == ERROR_SUCCESS) {
880 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
881 &valuelen, &datalen, NULL, NULL);
883 valuelen++; /* returned value doesn't include room for '\0' */
884 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
885 data = HeapAlloc(GetProcessHeap(), 0, datalen);
887 dlen = datalen;
888 vlen = valuelen;
889 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
890 &dlen) == ERROR_SUCCESS) {
891 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
893 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
894 split_subst_info(&psub->from, value);
895 split_subst_info(&psub->to, data);
897 /* Win 2000 doesn't allow mapping between different charsets
898 or mapping of DEFAULT_CHARSET */
899 if((psub->to.charset != psub->from.charset) ||
900 psub->to.charset == DEFAULT_CHARSET) {
901 HeapFree(GetProcessHeap(), 0, psub->to.name);
902 HeapFree(GetProcessHeap(), 0, psub->from.name);
903 HeapFree(GetProcessHeap(), 0, psub);
904 } else {
905 add_font_subst(&font_subst_list, psub, 0);
907 /* reset dlen and vlen */
908 dlen = datalen;
909 vlen = valuelen;
911 HeapFree(GetProcessHeap(), 0, data);
912 HeapFree(GetProcessHeap(), 0, value);
913 RegCloseKey(hkey);
917 static WCHAR *get_familyname(FT_Face ft_face)
919 WCHAR *family = NULL;
920 FT_SfntName name;
921 FT_UInt num_names, name_index, i;
923 if(FT_IS_SFNT(ft_face))
925 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
927 for(name_index = 0; name_index < num_names; name_index++)
929 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
931 if((name.name_id == TT_NAME_ID_FONT_FAMILY) &&
932 (name.language_id == GetUserDefaultLCID()) &&
933 (name.platform_id == TT_PLATFORM_MICROSOFT) &&
934 (name.encoding_id == TT_MS_ID_UNICODE_CS))
936 /* String is not nul terminated and string_len is a byte length. */
937 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
938 for(i = 0; i < name.string_len / 2; i++)
940 WORD *tmp = (WORD *)&name.string[i * 2];
941 family[i] = GET_BE_WORD(*tmp);
943 family[i] = 0;
945 TRACE("Got localised name %s\n", debugstr_w(family));
946 return family;
952 return NULL;
956 /*****************************************************************
957 * load_sfnt_table
959 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
960 * of FreeType that don't export this function.
963 static FT_Error load_sfnt_table(FT_Face ft_face, FT_ULong table, FT_Long offset, FT_Byte *buf, FT_ULong *len)
966 FT_Error err;
968 /* If the FT_Load_Sfnt_Table function is there we'll use it */
969 if(pFT_Load_Sfnt_Table)
971 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, len);
973 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
974 else /* Do it the hard way */
976 TT_Face tt_face = (TT_Face) ft_face;
977 SFNT_Interface *sfnt;
978 if (FT_Version.major==2 && FT_Version.minor==0)
980 /* 2.0.x */
981 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
983 else
985 /* A field was added in the middle of the structure in 2.1.x */
986 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
988 err = sfnt->load_any(tt_face, table, offset, buf, len);
990 #else
991 else
993 static int msg;
994 if(!msg)
996 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
997 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
998 "Please upgrade your freetype library.\n");
999 msg++;
1001 err = FT_Err_Unimplemented_Feature;
1003 #endif
1004 return err;
1008 #define ADDFONT_EXTERNAL_FONT 0x01
1009 #define ADDFONT_FORCE_BITMAP 0x02
1010 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1012 FT_Face ft_face;
1013 TT_OS2 *pOS2;
1014 TT_Header *pHeader = NULL;
1015 WCHAR *english_family, *localised_family, *StyleW;
1016 DWORD len;
1017 Family *family;
1018 Face *face;
1019 struct list *family_elem_ptr, *face_elem_ptr;
1020 FT_Error err;
1021 FT_Long face_index = 0, num_faces;
1022 #ifdef HAVE_FREETYPE_FTWINFNT_H
1023 FT_WinFNT_HeaderRec winfnt_header;
1024 #endif
1025 int i, bitmap_num, internal_leading;
1026 FONTSIGNATURE fs;
1028 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1029 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1031 #ifdef HAVE_CARBON_CARBON_H
1032 if(file && !fake_family)
1034 char **mac_list = expand_mac_font(file);
1035 if(mac_list)
1037 BOOL had_one = FALSE;
1038 char **cursor;
1039 for(cursor = mac_list; *cursor; cursor++)
1041 had_one = TRUE;
1042 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1043 HeapFree(GetProcessHeap(), 0, *cursor);
1045 HeapFree(GetProcessHeap(), 0, mac_list);
1046 if(had_one)
1047 return 1;
1050 #endif /* HAVE_CARBON_CARBON_H */
1052 do {
1053 char *family_name = fake_family;
1055 if (file)
1057 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1058 err = pFT_New_Face(library, file, face_index, &ft_face);
1059 } else
1061 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1062 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1065 if(err != 0) {
1066 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1067 return 0;
1070 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*/
1071 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1072 pFT_Done_Face(ft_face);
1073 return 0;
1076 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1077 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1078 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1079 pFT_Done_Face(ft_face);
1080 return 0;
1083 if(FT_IS_SFNT(ft_face))
1085 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1086 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1087 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1089 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1090 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1091 pFT_Done_Face(ft_face);
1092 return 0;
1095 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1096 we don't want to load these. */
1097 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1099 FT_ULong len = 0;
1101 if(!load_sfnt_table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1103 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1104 pFT_Done_Face(ft_face);
1105 return 0;
1110 if(!ft_face->family_name || !ft_face->style_name) {
1111 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1112 pFT_Done_Face(ft_face);
1113 return 0;
1116 if (target_family)
1118 localised_family = get_familyname(ft_face);
1119 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1121 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1122 HeapFree(GetProcessHeap(), 0, localised_family);
1123 num_faces = ft_face->num_faces;
1124 pFT_Done_Face(ft_face);
1125 continue;
1127 HeapFree(GetProcessHeap(), 0, localised_family);
1130 if(!family_name)
1131 family_name = ft_face->family_name;
1133 bitmap_num = 0;
1134 do {
1135 My_FT_Bitmap_Size *size = NULL;
1136 FT_ULong tmp_size;
1138 if(!FT_IS_SCALABLE(ft_face))
1139 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1141 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1142 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1143 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1145 localised_family = NULL;
1146 if(!fake_family) {
1147 localised_family = get_familyname(ft_face);
1148 if(localised_family && !strcmpW(localised_family, english_family)) {
1149 HeapFree(GetProcessHeap(), 0, localised_family);
1150 localised_family = NULL;
1154 family = NULL;
1155 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1156 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1157 if(!strcmpW(family->FamilyName, localised_family ? localised_family : english_family))
1158 break;
1159 family = NULL;
1161 if(!family) {
1162 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1163 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1164 list_init(&family->faces);
1165 list_add_tail(&font_list, &family->entry);
1167 if(localised_family) {
1168 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1169 subst->from.name = strdupW(english_family);
1170 subst->from.charset = -1;
1171 subst->to.name = strdupW(localised_family);
1172 subst->to.charset = -1;
1173 add_font_subst(&font_subst_list, subst, 0);
1176 HeapFree(GetProcessHeap(), 0, localised_family);
1177 HeapFree(GetProcessHeap(), 0, english_family);
1179 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1180 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1181 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1183 internal_leading = 0;
1184 memset(&fs, 0, sizeof(fs));
1186 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1187 if(pOS2) {
1188 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1189 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1190 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1191 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1192 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1193 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1194 if(pOS2->version == 0) {
1195 FT_UInt dummy;
1197 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1198 fs.fsCsb[0] |= FS_LATIN1;
1199 else
1200 fs.fsCsb[0] |= FS_SYMBOL;
1203 #ifdef HAVE_FREETYPE_FTWINFNT_H
1204 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1205 CHARSETINFO csi;
1206 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1207 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1208 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1209 memcpy(&fs, &csi.fs, sizeof(csi.fs));
1210 internal_leading = winfnt_header.internal_leading;
1212 #endif
1214 face_elem_ptr = list_head(&family->faces);
1215 while(face_elem_ptr) {
1216 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1217 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1218 if(!strcmpW(face->StyleName, StyleW) &&
1219 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1220 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1221 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1222 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1224 if(fake_family) {
1225 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1226 HeapFree(GetProcessHeap(), 0, StyleW);
1227 pFT_Done_Face(ft_face);
1228 return 1;
1230 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1231 TRACE("Original font is newer so skipping this one\n");
1232 HeapFree(GetProcessHeap(), 0, StyleW);
1233 pFT_Done_Face(ft_face);
1234 return 1;
1235 } else {
1236 TRACE("Replacing original with this one\n");
1237 list_remove(&face->entry);
1238 HeapFree(GetProcessHeap(), 0, face->file);
1239 HeapFree(GetProcessHeap(), 0, face->StyleName);
1240 HeapFree(GetProcessHeap(), 0, face);
1241 break;
1245 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1246 face->cached_enum_data = NULL;
1247 list_add_tail(&family->faces, &face->entry);
1248 face->StyleName = StyleW;
1249 if (file)
1251 face->file = strdupA(file);
1252 face->font_data_ptr = NULL;
1253 face->font_data_size = 0;
1255 else
1257 face->file = NULL;
1258 face->font_data_ptr = font_data_ptr;
1259 face->font_data_size = font_data_size;
1261 face->face_index = face_index;
1262 face->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
1263 face->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
1264 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1265 face->family = family;
1266 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1267 memcpy(&face->fs, &fs, sizeof(face->fs));
1268 memset(&face->fs_links, 0, sizeof(face->fs_links));
1270 if(FT_IS_SCALABLE(ft_face)) {
1271 memset(&face->size, 0, sizeof(face->size));
1272 face->scalable = TRUE;
1273 } else {
1274 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1275 size->height, size->width, size->size >> 6,
1276 size->x_ppem >> 6, size->y_ppem >> 6);
1277 face->size.height = size->height;
1278 face->size.width = size->width;
1279 face->size.size = size->size;
1280 face->size.x_ppem = size->x_ppem;
1281 face->size.y_ppem = size->y_ppem;
1282 face->size.internal_leading = internal_leading;
1283 face->scalable = FALSE;
1286 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1287 tmp_size = 0;
1288 if (pFT_Load_Sfnt_Table && !pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1290 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1291 face->ntmFlags = NTM_PS_OPENTYPE;
1293 else
1294 face->ntmFlags = 0;
1296 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1297 face->fs.fsCsb[0], face->fs.fsCsb[1],
1298 face->fs.fsUsb[0], face->fs.fsUsb[1],
1299 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1302 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1303 for(i = 0; i < ft_face->num_charmaps; i++) {
1304 switch(ft_face->charmaps[i]->encoding) {
1305 case FT_ENCODING_UNICODE:
1306 case FT_ENCODING_APPLE_ROMAN:
1307 face->fs.fsCsb[0] |= FS_LATIN1;
1308 break;
1309 case FT_ENCODING_MS_SYMBOL:
1310 face->fs.fsCsb[0] |= FS_SYMBOL;
1311 break;
1312 default:
1313 break;
1318 if (!(face->fs.fsCsb[0] & FS_SYMBOL))
1319 have_installed_roman_font = TRUE;
1320 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1322 num_faces = ft_face->num_faces;
1323 pFT_Done_Face(ft_face);
1324 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1325 debugstr_w(StyleW));
1326 } while(num_faces > ++face_index);
1327 return num_faces;
1330 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1332 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1335 static void DumpFontList(void)
1337 Family *family;
1338 Face *face;
1339 struct list *family_elem_ptr, *face_elem_ptr;
1341 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1342 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1343 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1344 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1345 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1346 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1347 if(!face->scalable)
1348 TRACE(" %d", face->size.height);
1349 TRACE("\n");
1352 return;
1355 /***********************************************************
1356 * The replacement list is a way to map an entire font
1357 * family onto another family. For example adding
1359 * [HKCU\Software\Wine\Fonts\Replacements]
1360 * "Wingdings"="Winedings"
1362 * would enumerate the Winedings font both as Winedings and
1363 * Wingdings. However if a real Wingdings font is present the
1364 * replacement does not take place.
1367 static void LoadReplaceList(void)
1369 HKEY hkey;
1370 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1371 LPWSTR value;
1372 LPVOID data;
1373 Family *family;
1374 Face *face;
1375 struct list *family_elem_ptr, *face_elem_ptr;
1376 CHAR familyA[400];
1378 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1379 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1381 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1382 &valuelen, &datalen, NULL, NULL);
1384 valuelen++; /* returned value doesn't include room for '\0' */
1385 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1386 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1388 dlen = datalen;
1389 vlen = valuelen;
1390 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1391 &dlen) == ERROR_SUCCESS) {
1392 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1393 /* "NewName"="Oldname" */
1394 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1396 /* Find the old family and hence all of the font files
1397 in that family */
1398 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1399 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1400 if(!strcmpiW(family->FamilyName, data)) {
1401 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1402 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1403 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1404 debugstr_w(face->StyleName), familyA);
1405 /* Now add a new entry with the new family name */
1406 AddFontToList(face->file, face->font_data_ptr, face->font_data_size, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1408 break;
1411 /* reset dlen and vlen */
1412 dlen = datalen;
1413 vlen = valuelen;
1415 HeapFree(GetProcessHeap(), 0, data);
1416 HeapFree(GetProcessHeap(), 0, value);
1417 RegCloseKey(hkey);
1421 /*************************************************************
1422 * init_system_links
1424 static BOOL init_system_links(void)
1426 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1427 'W','i','n','d','o','w','s',' ','N','T','\\',
1428 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1429 'S','y','s','t','e','m','L','i','n','k',0};
1430 HKEY hkey;
1431 BOOL ret = FALSE;
1432 DWORD type, max_val, max_data, val_len, data_len, index;
1433 WCHAR *value, *data;
1434 WCHAR *entry, *next;
1435 SYSTEM_LINKS *font_link, *system_font_link;
1436 CHILD_FONT *child_font;
1437 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
1438 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1439 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1440 FONTSIGNATURE fs;
1441 Family *family;
1442 Face *face;
1443 FontSubst *psub;
1445 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1447 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1448 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1449 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1450 val_len = max_val + 1;
1451 data_len = max_data;
1452 index = 0;
1453 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1455 TRACE("%s:\n", debugstr_w(value));
1457 memset(&fs, 0, sizeof(fs));
1458 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1459 psub = get_font_subst(&font_subst_list, value, -1);
1460 font_link->font_name = (psub)? strdupW(psub->to.name) : strdupW(value);
1461 list_init(&font_link->links);
1462 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1464 WCHAR *face_name;
1465 CHILD_FONT *child_font;
1467 TRACE("\t%s\n", debugstr_w(entry));
1469 next = entry + strlenW(entry) + 1;
1471 face_name = strchrW(entry, ',');
1472 if(face_name)
1474 *face_name++ = 0;
1475 while(isspaceW(*face_name))
1476 face_name++;
1478 psub = get_font_subst(&font_subst_list, face_name, -1);
1479 if(psub)
1480 face_name = psub->to.name;
1482 face = find_face_from_filename(entry, face_name);
1483 if(!face)
1485 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1486 continue;
1489 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1490 child_font->face = face;
1491 child_font->font = NULL;
1492 fs.fsCsb[0] |= face->fs.fsCsb[0];
1493 fs.fsCsb[1] |= face->fs.fsCsb[1];
1494 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1495 list_add_tail(&font_link->links, &child_font->entry);
1497 family = find_family_from_name(font_link->font_name);
1498 if(family)
1500 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1502 memcpy(&face->fs_links, &fs, sizeof(fs));
1505 list_add_tail(&system_links, &font_link->entry);
1506 val_len = max_val + 1;
1507 data_len = max_data;
1510 HeapFree(GetProcessHeap(), 0, value);
1511 HeapFree(GetProcessHeap(), 0, data);
1512 RegCloseKey(hkey);
1515 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1516 that Tahoma has */
1518 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1519 system_font_link->font_name = strdupW(System);
1520 list_init(&system_font_link->links);
1522 face = find_face_from_filename(tahoma_ttf, Tahoma);
1523 if(face)
1525 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1526 child_font->face = face;
1527 child_font->font = NULL;
1528 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
1529 list_add_tail(&system_font_link->links, &child_font->entry);
1531 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1533 if(!strcmpiW(font_link->font_name, Tahoma))
1535 CHILD_FONT *font_link_entry;
1536 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1538 CHILD_FONT *new_child;
1539 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1540 new_child->face = font_link_entry->face;
1541 new_child->font = NULL;
1542 list_add_tail(&system_font_link->links, &new_child->entry);
1544 break;
1547 list_add_tail(&system_links, &system_font_link->entry);
1548 return ret;
1551 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1553 DIR *dir;
1554 struct dirent *dent;
1555 char path[MAX_PATH];
1557 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1559 dir = opendir(dirname);
1560 if(!dir) {
1561 WARN("Can't open directory %s\n", debugstr_a(dirname));
1562 return FALSE;
1564 while((dent = readdir(dir)) != NULL) {
1565 struct stat statbuf;
1567 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1568 continue;
1570 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1572 sprintf(path, "%s/%s", dirname, dent->d_name);
1574 if(stat(path, &statbuf) == -1)
1576 WARN("Can't stat %s\n", debugstr_a(path));
1577 continue;
1579 if(S_ISDIR(statbuf.st_mode))
1580 ReadFontDir(path, external_fonts);
1581 else
1582 AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1584 closedir(dir);
1585 return TRUE;
1588 static void load_fontconfig_fonts(void)
1590 #ifdef SONAME_LIBFONTCONFIG
1591 void *fc_handle = NULL;
1592 FcConfig *config;
1593 FcPattern *pat;
1594 FcObjectSet *os;
1595 FcFontSet *fontset;
1596 int i, len;
1597 char *file;
1598 const char *ext;
1600 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1601 if(!fc_handle) {
1602 TRACE("Wine cannot find the fontconfig library (%s).\n",
1603 SONAME_LIBFONTCONFIG);
1604 return;
1606 #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;}
1607 LOAD_FUNCPTR(FcConfigGetCurrent);
1608 LOAD_FUNCPTR(FcFontList);
1609 LOAD_FUNCPTR(FcFontSetDestroy);
1610 LOAD_FUNCPTR(FcInit);
1611 LOAD_FUNCPTR(FcObjectSetAdd);
1612 LOAD_FUNCPTR(FcObjectSetCreate);
1613 LOAD_FUNCPTR(FcObjectSetDestroy);
1614 LOAD_FUNCPTR(FcPatternCreate);
1615 LOAD_FUNCPTR(FcPatternDestroy);
1616 LOAD_FUNCPTR(FcPatternGetBool);
1617 LOAD_FUNCPTR(FcPatternGetString);
1618 #undef LOAD_FUNCPTR
1620 if(!pFcInit()) return;
1622 config = pFcConfigGetCurrent();
1623 pat = pFcPatternCreate();
1624 os = pFcObjectSetCreate();
1625 pFcObjectSetAdd(os, FC_FILE);
1626 pFcObjectSetAdd(os, FC_SCALABLE);
1627 fontset = pFcFontList(config, pat, os);
1628 if(!fontset) return;
1629 for(i = 0; i < fontset->nfont; i++) {
1630 FcBool scalable;
1632 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1633 continue;
1634 TRACE("fontconfig: %s\n", file);
1636 /* We're just interested in OT/TT fonts for now, so this hack just
1637 picks up the scalable fonts without extensions .pf[ab] to save time
1638 loading every other font */
1640 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1642 TRACE("not scalable\n");
1643 continue;
1646 len = strlen( file );
1647 if(len < 4) continue;
1648 ext = &file[ len - 3 ];
1649 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1650 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT);
1652 pFcFontSetDestroy(fontset);
1653 pFcObjectSetDestroy(os);
1654 pFcPatternDestroy(pat);
1655 sym_not_found:
1656 #endif
1657 return;
1660 static BOOL load_font_from_data_dir(LPCWSTR file)
1662 BOOL ret = FALSE;
1663 const char *data_dir = wine_get_data_dir();
1665 if (!data_dir) data_dir = wine_get_build_dir();
1667 if (data_dir)
1669 INT len;
1670 char *unix_name;
1672 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1674 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1676 strcpy(unix_name, data_dir);
1677 strcat(unix_name, "/fonts/");
1679 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1681 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1682 HeapFree(GetProcessHeap(), 0, unix_name);
1684 return ret;
1687 static BOOL load_font_from_winfonts_dir(LPCWSTR file)
1689 static const WCHAR slashW[] = {'\\','\0'};
1690 BOOL ret = FALSE;
1691 WCHAR windowsdir[MAX_PATH];
1692 char *unixname;
1694 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1695 strcatW(windowsdir, fontsW);
1696 strcatW(windowsdir, slashW);
1697 strcatW(windowsdir, file);
1698 if ((unixname = wine_get_unix_file_name(windowsdir))) {
1699 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1700 HeapFree(GetProcessHeap(), 0, unixname);
1702 return ret;
1705 static void load_system_fonts(void)
1707 HKEY hkey;
1708 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1709 const WCHAR * const *value;
1710 DWORD dlen, type;
1711 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1712 char *unixname;
1714 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1715 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1716 strcatW(windowsdir, fontsW);
1717 for(value = SystemFontValues; *value; value++) {
1718 dlen = sizeof(data);
1719 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1720 type == REG_SZ) {
1721 BOOL added = FALSE;
1723 sprintfW(pathW, fmtW, windowsdir, data);
1724 if((unixname = wine_get_unix_file_name(pathW))) {
1725 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1726 HeapFree(GetProcessHeap(), 0, unixname);
1728 if (!added)
1729 load_font_from_data_dir(data);
1732 RegCloseKey(hkey);
1736 /*************************************************************
1738 * This adds registry entries for any externally loaded fonts
1739 * (fonts from fontconfig or FontDirs). It also deletes entries
1740 * of no longer existing fonts.
1743 static void update_reg_entries(void)
1745 HKEY winkey = 0, externalkey = 0;
1746 LPWSTR valueW;
1747 LPVOID data;
1748 DWORD dlen, vlen, datalen, valuelen, i, type, len, len_fam;
1749 Family *family;
1750 Face *face;
1751 struct list *family_elem_ptr, *face_elem_ptr;
1752 WCHAR *file;
1753 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1754 static const WCHAR spaceW[] = {' ', '\0'};
1755 char *path;
1757 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1758 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winkey, NULL) != ERROR_SUCCESS) {
1759 ERR("Can't create Windows font reg key\n");
1760 goto end;
1762 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1763 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &externalkey) != ERROR_SUCCESS) {
1764 ERR("Can't create external font reg key\n");
1765 goto end;
1768 /* Delete all external fonts added last time */
1770 RegQueryInfoKeyW(externalkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1771 &valuelen, &datalen, NULL, NULL);
1772 valuelen++; /* returned value doesn't include room for '\0' */
1773 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1774 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1776 dlen = datalen * sizeof(WCHAR);
1777 vlen = valuelen;
1778 i = 0;
1779 while(RegEnumValueW(externalkey, i++, valueW, &vlen, NULL, &type, data,
1780 &dlen) == ERROR_SUCCESS) {
1782 RegDeleteValueW(winkey, valueW);
1783 /* reset dlen and vlen */
1784 dlen = datalen;
1785 vlen = valuelen;
1787 HeapFree(GetProcessHeap(), 0, data);
1788 HeapFree(GetProcessHeap(), 0, valueW);
1790 /* Delete the old external fonts key */
1791 RegCloseKey(externalkey);
1792 externalkey = 0;
1793 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
1795 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1796 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1797 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
1798 ERR("Can't create external font reg key\n");
1799 goto end;
1802 /* enumerate the fonts and add external ones to the two keys */
1804 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1805 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1806 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1807 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1808 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1809 if(!face->external) continue;
1810 len = len_fam;
1811 if(strcmpiW(face->StyleName, RegularW))
1812 len = len_fam + strlenW(face->StyleName) + 1;
1813 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1814 strcpyW(valueW, family->FamilyName);
1815 if(len != len_fam) {
1816 strcatW(valueW, spaceW);
1817 strcatW(valueW, face->StyleName);
1819 strcatW(valueW, TrueType);
1820 if((path = strrchr(face->file, '/')) == NULL)
1821 path = face->file;
1822 else
1823 path++;
1824 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1826 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1827 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1828 RegSetValueExW(winkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1829 RegSetValueExW(externalkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1831 HeapFree(GetProcessHeap(), 0, file);
1832 HeapFree(GetProcessHeap(), 0, valueW);
1835 end:
1836 if(externalkey)
1837 RegCloseKey(externalkey);
1838 if(winkey)
1839 RegCloseKey(winkey);
1840 return;
1844 /*************************************************************
1845 * WineEngAddFontResourceEx
1848 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1850 INT ret = 0;
1851 if (ft_handle) /* do it only if we have freetype up and running */
1853 char *unixname;
1855 if(flags)
1856 FIXME("Ignoring flags %x\n", flags);
1858 if((unixname = wine_get_unix_file_name(file)))
1860 ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1861 HeapFree(GetProcessHeap(), 0, unixname);
1863 if (!ret && !strchrW(file, '\\')) {
1864 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
1865 ret = load_font_from_winfonts_dir(file);
1866 if (!ret) {
1867 /* Try in datadir/fonts (or builddir/fonts),
1868 * needed for Magic the Gathering Online
1870 ret = load_font_from_data_dir(file);
1874 return ret;
1877 /*************************************************************
1878 * WineEngAddFontMemResourceEx
1881 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
1883 if (ft_handle) /* do it only if we have freetype up and running */
1885 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
1887 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
1888 memcpy(pFontCopy, pbFont, cbFont);
1890 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
1892 if (*pcFonts == 0)
1894 TRACE("AddFontToList failed\n");
1895 HeapFree(GetProcessHeap(), 0, pFontCopy);
1896 return NULL;
1898 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
1899 * For now return something unique but quite random
1901 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
1902 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
1905 *pcFonts = 0;
1906 return 0;
1909 /*************************************************************
1910 * WineEngRemoveFontResourceEx
1913 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1915 FIXME(":stub\n");
1916 return TRUE;
1919 static const struct nls_update_font_list
1921 UINT ansi_cp, oem_cp;
1922 const char *oem, *fixed, *system;
1923 const char *courier, *serif, *small, *sserif;
1924 /* these are for font substitute */
1925 const char *shelldlg, *tmsrmn;
1926 } nls_update_font_list[] =
1928 /* Latin 1 (United States) */
1929 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
1930 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1931 "Tahoma","Times New Roman",
1933 /* Latin 1 (Multilingual) */
1934 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
1935 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1936 "Tahoma","Times New Roman", /* FIXME unverified */
1938 /* Eastern Europe */
1939 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
1940 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
1941 "Tahoma","Times New Roman", /* FIXME unverified */
1943 /* Cyrillic */
1944 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
1945 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
1946 "Tahoma","Times New Roman", /* FIXME unverified */
1948 /* Greek */
1949 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
1950 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
1951 "Tahoma","Times New Roman", /* FIXME unverified */
1953 /* Turkish */
1954 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
1955 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
1956 "Tahoma","Times New Roman", /* FIXME unverified */
1958 /* Hebrew */
1959 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
1960 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
1961 "Tahoma","Times New Roman", /* FIXME unverified */
1963 /* Arabic */
1964 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
1965 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
1966 "Tahoma","Times New Roman", /* FIXME unverified */
1968 /* Baltic */
1969 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
1970 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
1971 "Tahoma","Times New Roman", /* FIXME unverified */
1973 /* Vietnamese */
1974 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
1975 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1976 "Tahoma","Times New Roman", /* FIXME unverified */
1978 /* Thai */
1979 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
1980 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
1981 "Tahoma","Times New Roman", /* FIXME unverified */
1983 /* Japanese */
1984 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
1985 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
1986 "MS UI Gothic","MS Serif",
1988 /* Chinese Simplified */
1989 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
1990 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1991 "Tahoma", "Times New Roman", /* FIXME unverified */
1993 /* Korean */
1994 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
1995 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1996 "Gulim", "Batang",
1998 /* Chinese Traditional */
1999 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
2000 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
2001 "PMingLiU", "MingLiU",
2005 static inline HKEY create_fonts_NT_registry_key(void)
2007 HKEY hkey = 0;
2009 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
2010 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2011 return hkey;
2014 static inline HKEY create_fonts_9x_registry_key(void)
2016 HKEY hkey = 0;
2018 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
2019 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2020 return hkey;
2023 static inline HKEY create_config_fonts_registry_key(void)
2025 HKEY hkey = 0;
2027 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
2028 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
2029 return hkey;
2032 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2034 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2035 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2036 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2037 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2040 static void update_font_info(void)
2042 char buf[40], cpbuf[40];
2043 DWORD len, type;
2044 HKEY hkey = 0;
2045 UINT i, ansi_cp = 0, oem_cp = 0;
2047 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2048 return;
2050 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2051 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2052 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2053 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2054 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2056 len = sizeof(buf);
2057 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2059 if (!strcmp( buf, cpbuf )) /* already set correctly */
2061 RegCloseKey(hkey);
2062 return;
2064 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2066 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2068 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2069 RegCloseKey(hkey);
2071 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2073 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2074 nls_update_font_list[i].oem_cp == oem_cp)
2076 HKEY hkey;
2078 hkey = create_config_fonts_registry_key();
2079 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2080 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2081 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2082 RegCloseKey(hkey);
2084 hkey = create_fonts_NT_registry_key();
2085 add_font_list(hkey, &nls_update_font_list[i]);
2086 RegCloseKey(hkey);
2088 hkey = create_fonts_9x_registry_key();
2089 add_font_list(hkey, &nls_update_font_list[i]);
2090 RegCloseKey(hkey);
2092 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2094 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2095 strlen(nls_update_font_list[i].shelldlg)+1);
2096 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2097 strlen(nls_update_font_list[i].tmsrmn)+1);
2098 RegCloseKey(hkey);
2100 return;
2103 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2106 /*************************************************************
2107 * WineEngInit
2109 * Initialize FreeType library and create a list of available faces
2111 BOOL WineEngInit(void)
2113 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2114 static const WCHAR pathW[] = {'P','a','t','h',0};
2115 HKEY hkey;
2116 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2117 LPVOID data;
2118 WCHAR windowsdir[MAX_PATH];
2119 char *unixname;
2120 HANDLE font_mutex;
2121 const char *data_dir;
2123 TRACE("\n");
2125 /* update locale dependent font info in registry */
2126 update_font_info();
2128 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2129 if(!ft_handle) {
2130 WINE_MESSAGE(
2131 "Wine cannot find the FreeType font library. To enable Wine to\n"
2132 "use TrueType fonts please install a version of FreeType greater than\n"
2133 "or equal to 2.0.5.\n"
2134 "http://www.freetype.org\n");
2135 return FALSE;
2138 #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;}
2140 LOAD_FUNCPTR(FT_Vector_Unit)
2141 LOAD_FUNCPTR(FT_Done_Face)
2142 LOAD_FUNCPTR(FT_Get_Char_Index)
2143 LOAD_FUNCPTR(FT_Get_Module)
2144 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2145 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2146 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2147 LOAD_FUNCPTR(FT_Init_FreeType)
2148 LOAD_FUNCPTR(FT_Load_Glyph)
2149 LOAD_FUNCPTR(FT_Matrix_Multiply)
2150 LOAD_FUNCPTR(FT_MulFix)
2151 LOAD_FUNCPTR(FT_New_Face)
2152 LOAD_FUNCPTR(FT_New_Memory_Face)
2153 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2154 LOAD_FUNCPTR(FT_Outline_Transform)
2155 LOAD_FUNCPTR(FT_Outline_Translate)
2156 LOAD_FUNCPTR(FT_Select_Charmap)
2157 LOAD_FUNCPTR(FT_Set_Charmap)
2158 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2159 LOAD_FUNCPTR(FT_Vector_Transform)
2161 #undef LOAD_FUNCPTR
2162 /* Don't warn if this one is missing */
2163 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
2164 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
2165 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
2166 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
2167 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2168 #ifdef HAVE_FREETYPE_FTWINFNT_H
2169 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2170 #endif
2171 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2172 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2173 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2174 <= 2.0.3 has FT_Sqrt64 */
2175 goto sym_not_found;
2178 if(pFT_Init_FreeType(&library) != 0) {
2179 ERR("Can't init FreeType library\n");
2180 wine_dlclose(ft_handle, NULL, 0);
2181 ft_handle = NULL;
2182 return FALSE;
2184 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
2185 if (pFT_Library_Version)
2187 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2189 if (FT_Version.major<=0)
2191 FT_Version.major=2;
2192 FT_Version.minor=0;
2193 FT_Version.patch=5;
2195 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2196 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2197 ((FT_Version.minor << 8) & 0x00ff00) |
2198 ((FT_Version.patch ) & 0x0000ff);
2200 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2201 ERR("Failed to create font mutex\n");
2202 return FALSE;
2204 WaitForSingleObject(font_mutex, INFINITE);
2206 /* load the system bitmap fonts */
2207 load_system_fonts();
2209 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2210 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2211 strcatW(windowsdir, fontsW);
2212 if((unixname = wine_get_unix_file_name(windowsdir)))
2214 ReadFontDir(unixname, FALSE);
2215 HeapFree(GetProcessHeap(), 0, unixname);
2218 /* load the system truetype fonts */
2219 data_dir = wine_get_data_dir();
2220 if (!data_dir) data_dir = wine_get_build_dir();
2221 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2222 strcpy(unixname, data_dir);
2223 strcat(unixname, "/fonts/");
2224 ReadFontDir(unixname, TRUE);
2225 HeapFree(GetProcessHeap(), 0, unixname);
2228 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2229 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2230 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2231 will skip these. */
2232 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2233 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2234 &hkey) == ERROR_SUCCESS) {
2235 LPWSTR valueW;
2236 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2237 &valuelen, &datalen, NULL, NULL);
2239 valuelen++; /* returned value doesn't include room for '\0' */
2240 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2241 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2242 if (valueW && data)
2244 dlen = datalen * sizeof(WCHAR);
2245 vlen = valuelen;
2246 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
2247 &dlen) == ERROR_SUCCESS) {
2248 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
2250 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
2252 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2253 HeapFree(GetProcessHeap(), 0, unixname);
2256 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
2258 WCHAR pathW[MAX_PATH];
2259 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2260 BOOL added = FALSE;
2262 sprintfW(pathW, fmtW, windowsdir, data);
2263 if((unixname = wine_get_unix_file_name(pathW)))
2265 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2266 HeapFree(GetProcessHeap(), 0, unixname);
2268 if (!added)
2269 load_font_from_data_dir(data);
2271 /* reset dlen and vlen */
2272 dlen = datalen;
2273 vlen = valuelen;
2276 HeapFree(GetProcessHeap(), 0, data);
2277 HeapFree(GetProcessHeap(), 0, valueW);
2278 RegCloseKey(hkey);
2281 load_fontconfig_fonts();
2283 /* then look in any directories that we've specified in the config file */
2284 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2285 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2287 DWORD len;
2288 LPWSTR valueW;
2289 LPSTR valueA, ptr;
2291 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2293 len += sizeof(WCHAR);
2294 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2295 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2297 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2298 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2299 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2300 TRACE( "got font path %s\n", debugstr_a(valueA) );
2301 ptr = valueA;
2302 while (ptr)
2304 LPSTR next = strchr( ptr, ':' );
2305 if (next) *next++ = 0;
2306 ReadFontDir( ptr, TRUE );
2307 ptr = next;
2309 HeapFree( GetProcessHeap(), 0, valueA );
2311 HeapFree( GetProcessHeap(), 0, valueW );
2313 RegCloseKey(hkey);
2316 DumpFontList();
2317 LoadSubstList();
2318 DumpSubstList();
2319 LoadReplaceList();
2320 update_reg_entries();
2322 init_system_links();
2324 ReleaseMutex(font_mutex);
2325 return TRUE;
2326 sym_not_found:
2327 WINE_MESSAGE(
2328 "Wine cannot find certain functions that it needs inside the FreeType\n"
2329 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2330 "FreeType to at least version 2.0.5.\n"
2331 "http://www.freetype.org\n");
2332 wine_dlclose(ft_handle, NULL, 0);
2333 ft_handle = NULL;
2334 return FALSE;
2338 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2340 TT_OS2 *pOS2;
2341 TT_HoriHeader *pHori;
2343 LONG ppem;
2345 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2346 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2348 if(height == 0) height = 16;
2350 /* Calc. height of EM square:
2352 * For +ve lfHeight we have
2353 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2354 * Re-arranging gives:
2355 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2357 * For -ve lfHeight we have
2358 * |lfHeight| = ppem
2359 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2360 * with il = winAscent + winDescent - units_per_em]
2364 if(height > 0) {
2365 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2366 ppem = ft_face->units_per_EM * height /
2367 (pHori->Ascender - pHori->Descender);
2368 else
2369 ppem = ft_face->units_per_EM * height /
2370 (pOS2->usWinAscent + pOS2->usWinDescent);
2372 else
2373 ppem = -height;
2375 return ppem;
2378 static struct font_mapping *map_font_file( const char *name )
2380 struct font_mapping *mapping;
2381 struct stat st;
2382 int fd;
2384 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2385 if (fstat( fd, &st ) == -1) goto error;
2387 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2389 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2391 mapping->refcount++;
2392 close( fd );
2393 return mapping;
2396 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2397 goto error;
2399 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2400 close( fd );
2402 if (mapping->data == MAP_FAILED)
2404 HeapFree( GetProcessHeap(), 0, mapping );
2405 return NULL;
2407 mapping->refcount = 1;
2408 mapping->dev = st.st_dev;
2409 mapping->ino = st.st_ino;
2410 mapping->size = st.st_size;
2411 list_add_tail( &mappings_list, &mapping->entry );
2412 return mapping;
2414 error:
2415 close( fd );
2416 return NULL;
2419 static void unmap_font_file( struct font_mapping *mapping )
2421 if (!--mapping->refcount)
2423 list_remove( &mapping->entry );
2424 munmap( mapping->data, mapping->size );
2425 HeapFree( GetProcessHeap(), 0, mapping );
2429 static LONG load_VDMX(GdiFont*, LONG);
2431 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
2433 FT_Error err;
2434 FT_Face ft_face;
2435 void *data_ptr;
2436 DWORD data_size;
2438 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
2440 if (face->file)
2442 if (!(font->mapping = map_font_file( face->file )))
2444 WARN("failed to map %s\n", debugstr_a(face->file));
2445 return 0;
2447 data_ptr = font->mapping->data;
2448 data_size = font->mapping->size;
2450 else
2452 data_ptr = face->font_data_ptr;
2453 data_size = face->font_data_size;
2456 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
2457 if(err) {
2458 ERR("FT_New_Face rets %d\n", err);
2459 return 0;
2462 /* set it here, as load_VDMX needs it */
2463 font->ft_face = ft_face;
2465 if(FT_IS_SCALABLE(ft_face)) {
2466 /* load the VDMX table if we have one */
2467 font->ppem = load_VDMX(font, height);
2468 if(font->ppem == 0)
2469 font->ppem = calc_ppem_for_height(ft_face, height);
2471 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
2472 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
2473 } else {
2474 font->ppem = height;
2475 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
2476 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
2478 return ft_face;
2482 static int get_nearest_charset(Face *face, int *cp)
2484 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2485 a single face with the requested charset. The idea is to check if
2486 the selected font supports the current ANSI codepage, if it does
2487 return the corresponding charset, else return the first charset */
2489 CHARSETINFO csi;
2490 int acp = GetACP(), i;
2491 DWORD fs0;
2493 *cp = acp;
2494 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
2495 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2496 return csi.ciCharset;
2498 for(i = 0; i < 32; i++) {
2499 fs0 = 1L << i;
2500 if(face->fs.fsCsb[0] & fs0) {
2501 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
2502 *cp = csi.ciACP;
2503 return csi.ciCharset;
2505 else
2506 FIXME("TCI failing on %x\n", fs0);
2510 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2511 face->fs.fsCsb[0], face->file);
2512 *cp = acp;
2513 return DEFAULT_CHARSET;
2516 static GdiFont *alloc_font(void)
2518 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
2519 ret->gmsize = 1;
2520 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
2521 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
2522 ret->potm = NULL;
2523 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
2524 ret->total_kern_pairs = (DWORD)-1;
2525 ret->kern_pairs = NULL;
2526 list_init(&ret->hfontlist);
2527 list_init(&ret->child_fonts);
2528 return ret;
2531 static void free_font(GdiFont *font)
2533 struct list *cursor, *cursor2;
2534 int i;
2536 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
2538 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
2539 struct list *first_hfont;
2540 HFONTLIST *hfontlist;
2541 list_remove(cursor);
2542 if(child->font)
2544 first_hfont = list_head(&child->font->hfontlist);
2545 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2546 DeleteObject(hfontlist->hfont);
2547 HeapFree(GetProcessHeap(), 0, hfontlist);
2548 free_font(child->font);
2550 HeapFree(GetProcessHeap(), 0, child);
2553 if (font->ft_face) pFT_Done_Face(font->ft_face);
2554 if (font->mapping) unmap_font_file( font->mapping );
2555 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
2556 HeapFree(GetProcessHeap(), 0, font->potm);
2557 HeapFree(GetProcessHeap(), 0, font->name);
2558 for (i = 0; i < font->gmsize; i++)
2559 HeapFree(GetProcessHeap(),0,font->gm[i]);
2560 HeapFree(GetProcessHeap(), 0, font->gm);
2561 HeapFree(GetProcessHeap(), 0, font);
2565 /*************************************************************
2566 * load_VDMX
2568 * load the vdmx entry for the specified height
2571 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2572 ( ( (FT_ULong)_x4 << 24 ) | \
2573 ( (FT_ULong)_x3 << 16 ) | \
2574 ( (FT_ULong)_x2 << 8 ) | \
2575 (FT_ULong)_x1 )
2577 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2579 typedef struct {
2580 BYTE bCharSet;
2581 BYTE xRatio;
2582 BYTE yStartRatio;
2583 BYTE yEndRatio;
2584 } Ratios;
2586 typedef struct {
2587 WORD recs;
2588 BYTE startsz;
2589 BYTE endsz;
2590 } VDMX_group;
2592 static LONG load_VDMX(GdiFont *font, LONG height)
2594 WORD hdr[3], tmp;
2595 VDMX_group group;
2596 BYTE devXRatio, devYRatio;
2597 USHORT numRecs, numRatios;
2598 DWORD result, offset = -1;
2599 LONG ppem = 0;
2600 int i;
2602 /* For documentation on VDMX records, see
2603 * http://www.microsoft.com/OpenType/OTSpec/vdmx.htm
2606 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
2608 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2609 return ppem;
2611 /* FIXME: need the real device aspect ratio */
2612 devXRatio = 1;
2613 devYRatio = 1;
2615 numRecs = GET_BE_WORD(hdr[1]);
2616 numRatios = GET_BE_WORD(hdr[2]);
2618 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
2619 for(i = 0; i < numRatios; i++) {
2620 Ratios ratio;
2622 offset = (3 * 2) + (i * sizeof(Ratios));
2623 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2624 offset = -1;
2626 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2628 if((ratio.xRatio == 0 &&
2629 ratio.yStartRatio == 0 &&
2630 ratio.yEndRatio == 0) ||
2631 (devXRatio == ratio.xRatio &&
2632 devYRatio >= ratio.yStartRatio &&
2633 devYRatio <= ratio.yEndRatio))
2635 offset = (3 * 2) + (numRatios * 4) + (i * 2);
2636 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
2637 offset = GET_BE_WORD(tmp);
2638 break;
2642 if(offset == -1) {
2643 FIXME("No suitable ratio found\n");
2644 return ppem;
2647 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
2648 USHORT recs;
2649 BYTE startsz, endsz;
2650 WORD *vTable;
2652 recs = GET_BE_WORD(group.recs);
2653 startsz = group.startsz;
2654 endsz = group.endsz;
2656 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
2658 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
2659 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
2660 if(result == GDI_ERROR) {
2661 FIXME("Failed to retrieve vTable\n");
2662 goto end;
2665 if(height > 0) {
2666 for(i = 0; i < recs; i++) {
2667 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2668 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2669 ppem = GET_BE_WORD(vTable[i * 3]);
2671 if(yMax + -yMin == height) {
2672 font->yMax = yMax;
2673 font->yMin = yMin;
2674 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2675 break;
2677 if(yMax + -yMin > height) {
2678 if(--i < 0) {
2679 ppem = 0;
2680 goto end; /* failed */
2682 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2683 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2684 ppem = GET_BE_WORD(vTable[i * 3]);
2685 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2686 break;
2689 if(!font->yMax) {
2690 ppem = 0;
2691 TRACE("ppem not found for height %d\n", height);
2693 } else {
2694 ppem = -height;
2695 if(ppem < startsz || ppem > endsz)
2696 goto end;
2698 for(i = 0; i < recs; i++) {
2699 USHORT yPelHeight;
2700 yPelHeight = GET_BE_WORD(vTable[i * 3]);
2702 if(yPelHeight > ppem)
2703 break; /* failed */
2705 if(yPelHeight == ppem) {
2706 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2707 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2708 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
2709 break;
2713 end:
2714 HeapFree(GetProcessHeap(), 0, vTable);
2717 return ppem;
2720 static BOOL fontcmp(GdiFont *font, FONT_DESC *fd)
2722 if(font->font_desc.hash != fd->hash) return TRUE;
2723 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
2724 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
2725 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
2726 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
2729 static void calc_hash(FONT_DESC *pfd)
2731 DWORD hash = 0, *ptr, two_chars;
2732 WORD *pwc;
2733 unsigned int i;
2735 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
2736 hash ^= *ptr;
2737 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
2738 hash ^= *ptr;
2739 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
2740 two_chars = *ptr;
2741 pwc = (WCHAR *)&two_chars;
2742 if(!*pwc) break;
2743 *pwc = toupperW(*pwc);
2744 pwc++;
2745 *pwc = toupperW(*pwc);
2746 hash ^= two_chars;
2747 if(!*pwc) break;
2749 hash ^= !pfd->can_use_bitmap;
2750 pfd->hash = hash;
2751 return;
2754 static GdiFont *find_in_cache(HFONT hfont, LOGFONTW *plf, XFORM *pxf, BOOL can_use_bitmap)
2756 GdiFont *ret;
2757 FONT_DESC fd;
2758 HFONTLIST *hflist;
2759 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2761 memcpy(&fd.lf, plf, sizeof(LOGFONTW));
2762 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
2763 fd.can_use_bitmap = can_use_bitmap;
2764 calc_hash(&fd);
2766 /* try the in-use list */
2767 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
2768 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2769 if(!fontcmp(ret, &fd)) {
2770 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2771 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
2772 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2773 if(hflist->hfont == hfont)
2774 return ret;
2776 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2777 hflist->hfont = hfont;
2778 list_add_head(&ret->hfontlist, &hflist->entry);
2779 return ret;
2783 /* then the unused list */
2784 font_elem_ptr = list_head(&unused_gdi_font_list);
2785 while(font_elem_ptr) {
2786 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2787 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2788 if(!fontcmp(ret, &fd)) {
2789 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2790 assert(list_empty(&ret->hfontlist));
2791 TRACE("Found %p in unused list\n", ret);
2792 list_remove(&ret->entry);
2793 list_add_head(&gdi_font_list, &ret->entry);
2794 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2795 hflist->hfont = hfont;
2796 list_add_head(&ret->hfontlist, &hflist->entry);
2797 return ret;
2800 return NULL;
2804 /*************************************************************
2805 * create_child_font_list
2807 static BOOL create_child_font_list(GdiFont *font)
2809 BOOL ret = FALSE;
2810 SYSTEM_LINKS *font_link;
2811 CHILD_FONT *font_link_entry, *new_child;
2813 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2815 if(!strcmpW(font_link->font_name, font->name))
2817 TRACE("found entry in system list\n");
2818 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2820 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2821 new_child->face = font_link_entry->face;
2822 new_child->font = NULL;
2823 list_add_tail(&font->child_fonts, &new_child->entry);
2824 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
2826 ret = TRUE;
2827 break;
2831 return ret;
2834 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
2836 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
2838 if (pFT_Set_Charmap)
2840 FT_Int i;
2841 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
2843 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
2845 for (i = 0; i < ft_face->num_charmaps; i++)
2847 if (ft_face->charmaps[i]->encoding == encoding)
2849 TRACE("found cmap with platform_id %u, encoding_id %u\n",
2850 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
2852 switch (ft_face->charmaps[i]->platform_id)
2854 default:
2855 cmap_def = ft_face->charmaps[i];
2856 break;
2857 case 0: /* Apple Unicode */
2858 cmap0 = ft_face->charmaps[i];
2859 break;
2860 case 1: /* Macintosh */
2861 cmap1 = ft_face->charmaps[i];
2862 break;
2863 case 2: /* ISO */
2864 cmap2 = ft_face->charmaps[i];
2865 break;
2866 case 3: /* Microsoft */
2867 cmap3 = ft_face->charmaps[i];
2868 break;
2872 if (cmap3) /* prefer Microsoft cmap table */
2873 ft_err = pFT_Set_Charmap(ft_face, cmap3);
2874 else if (cmap1)
2875 ft_err = pFT_Set_Charmap(ft_face, cmap1);
2876 else if (cmap2)
2877 ft_err = pFT_Set_Charmap(ft_face, cmap2);
2878 else if (cmap0)
2879 ft_err = pFT_Set_Charmap(ft_face, cmap0);
2880 else if (cmap_def)
2881 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
2883 return ft_err == FT_Err_Ok;
2886 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
2889 /*************************************************************
2890 * WineEngCreateFontInstance
2893 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
2895 GdiFont *ret;
2896 Face *face, *best, *best_bitmap;
2897 Family *family, *last_resort_family;
2898 struct list *family_elem_ptr, *face_elem_ptr;
2899 INT height, width = 0;
2900 unsigned int score = 0, new_score;
2901 signed int diff = 0, newdiff;
2902 BOOL bd, it, can_use_bitmap;
2903 LOGFONTW lf;
2904 CHARSETINFO csi;
2905 HFONTLIST *hflist;
2907 LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry)
2909 struct list *first_hfont = list_head(&ret->hfontlist);
2910 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2911 if(hflist->hfont == hfont)
2912 return ret;
2915 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
2916 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
2918 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
2919 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
2920 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
2921 lf.lfEscapement);
2923 /* check the cache first */
2924 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
2925 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
2926 return ret;
2929 TRACE("not in cache\n");
2930 if(list_empty(&font_list)) /* No fonts installed */
2932 TRACE("No fonts installed\n");
2933 return NULL;
2935 if(!have_installed_roman_font)
2937 TRACE("No roman font installed\n");
2938 return NULL;
2941 ret = alloc_font();
2943 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
2944 memcpy(&ret->font_desc.lf, &lf, sizeof(LOGFONTW));
2945 ret->font_desc.can_use_bitmap = can_use_bitmap;
2946 calc_hash(&ret->font_desc);
2947 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2948 hflist->hfont = hfont;
2949 list_add_head(&ret->hfontlist, &hflist->entry);
2952 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
2953 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
2954 original value lfCharSet. Note this is a special case for
2955 Symbol and doesn't happen at least for "Wingdings*" */
2957 if(!strcmpiW(lf.lfFaceName, SymbolW))
2958 lf.lfCharSet = SYMBOL_CHARSET;
2960 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
2961 switch(lf.lfCharSet) {
2962 case DEFAULT_CHARSET:
2963 csi.fs.fsCsb[0] = 0;
2964 break;
2965 default:
2966 FIXME("Untranslated charset %d\n", lf.lfCharSet);
2967 csi.fs.fsCsb[0] = 0;
2968 break;
2972 family = NULL;
2973 if(lf.lfFaceName[0] != '\0') {
2974 FontSubst *psub;
2975 SYSTEM_LINKS *font_link;
2976 CHILD_FONT *font_link_entry;
2978 psub = get_font_subst(&font_subst_list, lf.lfFaceName, lf.lfCharSet);
2980 if(psub) {
2981 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
2982 debugstr_w(psub->to.name));
2983 strcpyW(lf.lfFaceName, psub->to.name);
2986 /* We want a match on name and charset or just name if
2987 charset was DEFAULT_CHARSET. If the latter then
2988 we fixup the returned charset later in get_nearest_charset
2989 where we'll either use the charset of the current ansi codepage
2990 or if that's unavailable the first charset that the font supports.
2992 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2993 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2994 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2995 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2996 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2997 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
2998 if(face->scalable || can_use_bitmap)
2999 goto found;
3005 * Try check the SystemLink list first for a replacement font.
3006 * We may find good replacements there.
3008 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
3010 if(!strcmpiW(font_link->font_name, lf.lfFaceName))
3012 TRACE("found entry in system list\n");
3013 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
3015 face = font_link_entry->face;
3016 family = face->family;
3017 if(csi.fs.fsCsb[0] &
3018 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
3020 if(face->scalable || can_use_bitmap)
3021 goto found;
3028 /* If requested charset was DEFAULT_CHARSET then try using charset
3029 corresponding to the current ansi codepage */
3030 if(!csi.fs.fsCsb[0]) {
3031 INT acp = GetACP();
3032 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
3033 FIXME("TCI failed on codepage %d\n", acp);
3034 csi.fs.fsCsb[0] = 0;
3035 } else
3036 lf.lfCharSet = csi.ciCharset;
3039 /* Face families are in the top 4 bits of lfPitchAndFamily,
3040 so mask with 0xF0 before testing */
3042 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
3043 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
3044 strcpyW(lf.lfFaceName, defFixed);
3045 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
3046 strcpyW(lf.lfFaceName, defSerif);
3047 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
3048 strcpyW(lf.lfFaceName, defSans);
3049 else
3050 strcpyW(lf.lfFaceName, defSans);
3051 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3052 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3053 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
3054 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3055 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3056 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3057 if(face->scalable || can_use_bitmap)
3058 goto found;
3063 last_resort_family = NULL;
3064 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3065 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3066 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3067 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3068 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
3069 if(face->scalable)
3070 goto found;
3071 if(can_use_bitmap && !last_resort_family)
3072 last_resort_family = family;
3077 if(last_resort_family) {
3078 family = last_resort_family;
3079 csi.fs.fsCsb[0] = 0;
3080 goto found;
3083 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3084 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3085 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3086 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3087 if(face->scalable) {
3088 csi.fs.fsCsb[0] = 0;
3089 WARN("just using first face for now\n");
3090 goto found;
3092 if(can_use_bitmap && !last_resort_family)
3093 last_resort_family = family;
3096 if(!last_resort_family) {
3097 FIXME("can't find a single appropriate font - bailing\n");
3098 free_font(ret);
3099 return NULL;
3102 WARN("could only find a bitmap font - this will probably look awful!\n");
3103 family = last_resort_family;
3104 csi.fs.fsCsb[0] = 0;
3106 found:
3107 it = lf.lfItalic ? 1 : 0;
3108 bd = lf.lfWeight > 550 ? 1 : 0;
3110 height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
3111 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
3113 face = best = best_bitmap = NULL;
3114 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
3116 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3118 new_score = (face->Italic ^ it) + (face->Bold ^ bd);
3119 if(!best || new_score <= score)
3121 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3122 face->Italic, face->Bold, it, bd);
3123 score = new_score;
3124 best = face;
3125 if(best->scalable && score == 0) break;
3126 if(!best->scalable)
3128 if(height > 0)
3129 newdiff = height - (signed int)(best->size.height);
3130 else
3131 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
3132 if(!best_bitmap || new_score < score ||
3133 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
3135 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
3136 diff = newdiff;
3137 best_bitmap = best;
3138 if(score == 0 && diff == 0) break;
3144 if(best)
3145 face = best->scalable ? best : best_bitmap;
3146 ret->fake_italic = (it && !face->Italic);
3147 ret->fake_bold = (bd && !face->Bold);
3149 memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
3151 if(csi.fs.fsCsb[0]) {
3152 ret->charset = lf.lfCharSet;
3153 ret->codepage = csi.ciACP;
3155 else
3156 ret->charset = get_nearest_charset(face, &ret->codepage);
3158 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
3159 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
3161 ret->aveWidth = abs(lf.lfWidth);
3163 if(!face->scalable) {
3164 /* Windows uses integer scaling factors for bitmap fonts */
3165 INT scale, scaled_height;
3167 if (height != 0) height = diff;
3168 else height = 0;
3169 height += face->size.height;
3171 scale = (height + face->size.height - 1) / face->size.height;
3172 scaled_height = scale * face->size.height;
3173 /* XP allows not more than 10% deviation */
3174 if (scale > 1 && scaled_height - height > scaled_height / 10) scale--;
3175 ret->scale_y = scale;
3177 width = face->size.x_ppem >> 6;
3178 height = face->size.y_ppem >> 6;
3180 else
3181 ret->scale_y = 1.0;
3182 TRACE("font scale y: %f\n", ret->scale_y);
3184 ret->ft_face = OpenFontFace(ret, face, width, height);
3186 if (!ret->ft_face)
3188 free_font( ret );
3189 return 0;
3192 ret->ntmFlags = face->ntmFlags;
3194 if (ret->charset == SYMBOL_CHARSET &&
3195 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
3196 /* No ops */
3198 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
3199 /* No ops */
3201 else {
3202 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
3205 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
3206 ret->name = strdupW(family->FamilyName);
3207 ret->underline = lf.lfUnderline ? 0xff : 0;
3208 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
3209 create_child_font_list(ret);
3211 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
3213 list_add_head(&gdi_font_list, &ret->entry);
3214 return ret;
3217 static void dump_gdi_font_list(void)
3219 GdiFont *gdiFont;
3220 struct list *elem_ptr;
3222 TRACE("---------- gdiFont Cache ----------\n");
3223 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
3224 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3225 TRACE("gdiFont=%p %s %d\n",
3226 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3229 TRACE("---------- Unused gdiFont Cache ----------\n");
3230 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
3231 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3232 TRACE("gdiFont=%p %s %d\n",
3233 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3237 /*************************************************************
3238 * WineEngDestroyFontInstance
3240 * free the gdiFont associated with this handle
3243 BOOL WineEngDestroyFontInstance(HFONT handle)
3245 GdiFont *gdiFont;
3246 HFONTLIST *hflist;
3247 BOOL ret = FALSE;
3248 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3249 int i = 0;
3251 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
3253 struct list *first_hfont = list_head(&gdiFont->hfontlist);
3254 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3255 if(hflist->hfont == handle)
3257 TRACE("removing child font %p from child list\n", gdiFont);
3258 list_remove(&gdiFont->entry);
3259 return TRUE;
3263 TRACE("destroying hfont=%p\n", handle);
3264 if(TRACE_ON(font))
3265 dump_gdi_font_list();
3267 font_elem_ptr = list_head(&gdi_font_list);
3268 while(font_elem_ptr) {
3269 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3270 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3272 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3273 while(hfontlist_elem_ptr) {
3274 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3275 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3276 if(hflist->hfont == handle) {
3277 list_remove(&hflist->entry);
3278 HeapFree(GetProcessHeap(), 0, hflist);
3279 ret = TRUE;
3282 if(list_empty(&gdiFont->hfontlist)) {
3283 TRACE("Moving to Unused list\n");
3284 list_remove(&gdiFont->entry);
3285 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3290 font_elem_ptr = list_head(&unused_gdi_font_list);
3291 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3292 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3293 while(font_elem_ptr) {
3294 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3295 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3296 TRACE("freeing %p\n", gdiFont);
3297 list_remove(&gdiFont->entry);
3298 free_font(gdiFont);
3300 return ret;
3303 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
3304 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
3306 GdiFont *font;
3307 LONG width, height;
3309 if (face->cached_enum_data)
3311 TRACE("Cached\n");
3312 memcpy(pelf, &face->cached_enum_data->elf, sizeof(ENUMLOGFONTEXW));
3313 memcpy(pntm, &face->cached_enum_data->ntm, sizeof(NEWTEXTMETRICEXW));
3314 *ptype = face->cached_enum_data->type;
3315 return;
3318 font = alloc_font();
3320 if(face->scalable) {
3321 height = 100;
3322 width = 0;
3323 } else {
3324 height = face->size.y_ppem >> 6;
3325 width = face->size.x_ppem >> 6;
3327 font->scale_y = 1.0;
3329 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
3331 free_font(font);
3332 return;
3335 font->name = strdupW(face->family->FamilyName);
3336 font->ntmFlags = face->ntmFlags;
3338 if (WineEngGetOutlineTextMetrics(font, 0, NULL))
3340 memcpy(&pntm->ntmTm, &font->potm->otmTextMetrics, sizeof(TEXTMETRICW));
3342 pntm->ntmTm.ntmSizeEM = font->potm->otmEMSquare;
3344 lstrcpynW(pelf->elfLogFont.lfFaceName,
3345 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFamilyName),
3346 LF_FACESIZE);
3347 lstrcpynW(pelf->elfFullName,
3348 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpFaceName),
3349 LF_FULLFACESIZE);
3350 lstrcpynW(pelf->elfStyle,
3351 (WCHAR*)((char*)font->potm + (ULONG_PTR)font->potm->otmpStyleName),
3352 LF_FACESIZE);
3354 else
3356 WineEngGetTextMetrics(font, (TEXTMETRICW *)&pntm->ntmTm);
3358 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
3360 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
3361 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FULLFACESIZE);
3362 lstrcpynW(pelf->elfStyle, face->StyleName, LF_FACESIZE);
3365 pntm->ntmTm.ntmFlags = face->ntmFlags;
3366 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
3367 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
3368 memcpy(&pntm->ntmFontSig, &face->fs, sizeof(FONTSIGNATURE));
3370 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
3372 pelf->elfLogFont.lfEscapement = 0;
3373 pelf->elfLogFont.lfOrientation = 0;
3374 pelf->elfLogFont.lfHeight = pntm->ntmTm.tmHeight;
3375 pelf->elfLogFont.lfWidth = pntm->ntmTm.tmAveCharWidth;
3376 pelf->elfLogFont.lfWeight = pntm->ntmTm.tmWeight;
3377 pelf->elfLogFont.lfItalic = pntm->ntmTm.tmItalic;
3378 pelf->elfLogFont.lfUnderline = pntm->ntmTm.tmUnderlined;
3379 pelf->elfLogFont.lfStrikeOut = pntm->ntmTm.tmStruckOut;
3380 pelf->elfLogFont.lfCharSet = pntm->ntmTm.tmCharSet;
3381 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
3382 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
3383 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
3384 pelf->elfLogFont.lfPitchAndFamily = (pntm->ntmTm.tmPitchAndFamily & 0xf1) + 1;
3386 *ptype = 0;
3387 if (pntm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE)
3388 *ptype |= TRUETYPE_FONTTYPE;
3389 if (pntm->ntmTm.tmPitchAndFamily & TMPF_DEVICE)
3390 *ptype |= DEVICE_FONTTYPE;
3391 if(!(pntm->ntmTm.tmPitchAndFamily & TMPF_VECTOR))
3392 *ptype |= RASTER_FONTTYPE;
3394 face->cached_enum_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*face->cached_enum_data));
3395 if (face->cached_enum_data)
3397 memcpy(&face->cached_enum_data->elf, pelf, sizeof(ENUMLOGFONTEXW));
3398 memcpy(&face->cached_enum_data->ntm, pntm, sizeof(NEWTEXTMETRICEXW));
3399 face->cached_enum_data->type = *ptype;
3402 free_font(font);
3405 /*************************************************************
3406 * WineEngEnumFonts
3409 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3411 Family *family;
3412 Face *face;
3413 struct list *family_elem_ptr, *face_elem_ptr;
3414 ENUMLOGFONTEXW elf;
3415 NEWTEXTMETRICEXW ntm;
3416 DWORD type, ret = 1;
3417 FONTSIGNATURE fs;
3418 CHARSETINFO csi;
3419 LOGFONTW lf;
3420 int i;
3422 if (!plf)
3424 lf.lfCharSet = DEFAULT_CHARSET;
3425 lf.lfPitchAndFamily = 0;
3426 lf.lfFaceName[0] = 0;
3427 plf = &lf;
3430 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
3432 if(plf->lfFaceName[0]) {
3433 FontSubst *psub;
3434 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
3436 if(psub) {
3437 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
3438 debugstr_w(psub->to.name));
3439 memcpy(&lf, plf, sizeof(lf));
3440 strcpyW(lf.lfFaceName, psub->to.name);
3441 plf = &lf;
3444 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3445 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3446 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
3447 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3448 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3449 GetEnumStructs(face, &elf, &ntm, &type);
3450 for(i = 0; i < 32; i++) {
3451 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3452 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3453 strcpyW(elf.elfScript, OEM_DOSW);
3454 i = 32; /* break out of loop */
3455 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3456 continue;
3457 else {
3458 fs.fsCsb[0] = 1L << i;
3459 fs.fsCsb[1] = 0;
3460 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3461 TCI_SRCFONTSIG))
3462 csi.ciCharset = DEFAULT_CHARSET;
3463 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3464 if(csi.ciCharset != DEFAULT_CHARSET) {
3465 elf.elfLogFont.lfCharSet =
3466 ntm.ntmTm.tmCharSet = csi.ciCharset;
3467 if(ElfScriptsW[i])
3468 strcpyW(elf.elfScript, ElfScriptsW[i]);
3469 else
3470 FIXME("Unknown elfscript for bit %d\n", i);
3473 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3474 debugstr_w(elf.elfLogFont.lfFaceName),
3475 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3476 csi.ciCharset, type, debugstr_w(elf.elfScript),
3477 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3478 ntm.ntmTm.ntmFlags);
3479 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
3480 if(!ret) goto end;
3485 } else {
3486 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3487 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3488 face_elem_ptr = list_head(&family->faces);
3489 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3490 GetEnumStructs(face, &elf, &ntm, &type);
3491 for(i = 0; i < 32; i++) {
3492 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3493 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3494 strcpyW(elf.elfScript, OEM_DOSW);
3495 i = 32; /* break out of loop */
3496 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3497 continue;
3498 else {
3499 fs.fsCsb[0] = 1L << i;
3500 fs.fsCsb[1] = 0;
3501 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3502 TCI_SRCFONTSIG))
3503 csi.ciCharset = DEFAULT_CHARSET;
3504 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3505 if(csi.ciCharset != DEFAULT_CHARSET) {
3506 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
3507 csi.ciCharset;
3508 if(ElfScriptsW[i])
3509 strcpyW(elf.elfScript, ElfScriptsW[i]);
3510 else
3511 FIXME("Unknown elfscript for bit %d\n", i);
3514 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3515 debugstr_w(elf.elfLogFont.lfFaceName),
3516 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3517 csi.ciCharset, type, debugstr_w(elf.elfScript),
3518 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3519 ntm.ntmTm.ntmFlags);
3520 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
3521 if(!ret) goto end;
3525 end:
3526 return ret;
3529 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
3531 pt->x.value = vec->x >> 6;
3532 pt->x.fract = (vec->x & 0x3f) << 10;
3533 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
3534 pt->y.value = vec->y >> 6;
3535 pt->y.fract = (vec->y & 0x3f) << 10;
3536 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
3537 return;
3540 /***************************************************
3541 * According to the MSDN documentation on WideCharToMultiByte,
3542 * certain codepages cannot set the default_used parameter.
3543 * This returns TRUE if the codepage can set that parameter, false else
3544 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
3546 static BOOL codepage_sets_default_used(UINT codepage)
3548 switch (codepage)
3550 case CP_UTF7:
3551 case CP_UTF8:
3552 case CP_SYMBOL:
3553 return FALSE;
3554 default:
3555 return TRUE;
3559 static FT_UInt get_glyph_index(GdiFont *font, UINT glyph)
3561 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
3562 WCHAR wc = (WCHAR)glyph;
3563 BOOL default_used;
3564 BOOL *default_used_pointer;
3565 FT_UInt ret;
3566 char buf;
3567 default_used_pointer = NULL;
3568 default_used = FALSE;
3569 if (codepage_sets_default_used(font->codepage))
3570 default_used_pointer = &default_used;
3571 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
3572 ret = 0;
3573 else
3574 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
3575 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
3576 return ret;
3579 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
3580 glyph = glyph + 0xf000;
3581 return pFT_Get_Char_Index(font->ft_face, glyph);
3584 /*************************************************************
3585 * WineEngGetGlyphIndices
3587 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
3589 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
3590 LPWORD pgi, DWORD flags)
3592 int i;
3593 WCHAR default_char = 0;
3594 TEXTMETRICW textm;
3596 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0x001f; /* Indicate non existence */
3598 for(i = 0; i < count; i++)
3600 pgi[i] = get_glyph_index(font, lpstr[i]);
3601 if (pgi[i] == 0)
3603 if (!default_char)
3605 WineEngGetTextMetrics(font, &textm);
3606 default_char = textm.tmDefaultChar;
3608 pgi[i] = default_char;
3611 return count;
3614 /*************************************************************
3615 * WineEngGetGlyphOutline
3617 * Behaves in exactly the same way as the win32 api GetGlyphOutline
3618 * except that the first parameter is the HWINEENGFONT of the font in
3619 * question rather than an HDC.
3622 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
3623 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
3624 const MAT2* lpmat)
3626 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
3627 FT_Face ft_face = incoming_font->ft_face;
3628 GdiFont *font = incoming_font;
3629 FT_UInt glyph_index;
3630 DWORD width, height, pitch, needed = 0;
3631 FT_Bitmap ft_bitmap;
3632 FT_Error err;
3633 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
3634 FT_Angle angle = 0;
3635 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
3636 float widthRatio = 1.0;
3637 FT_Matrix transMat = identityMat;
3638 BOOL needsTransform = FALSE;
3641 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
3642 buflen, buf, lpmat);
3644 if(format & GGO_GLYPH_INDEX) {
3645 glyph_index = glyph;
3646 format &= ~GGO_GLYPH_INDEX;
3647 } else {
3648 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
3649 ft_face = font->ft_face;
3652 if(glyph_index >= font->gmsize * GM_BLOCK_SIZE) {
3653 font->gmsize = (glyph_index / GM_BLOCK_SIZE + 1);
3654 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
3655 font->gmsize * sizeof(GM*));
3656 } else {
3657 if(format == GGO_METRICS && font->gm[glyph_index / GM_BLOCK_SIZE] != NULL && FONT_GM(font,glyph_index)->init ) {
3658 *lpgm = FONT_GM(font,glyph_index)->gm;
3659 return 1; /* FIXME */
3663 if (!font->gm[glyph_index / GM_BLOCK_SIZE])
3664 font->gm[glyph_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3666 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP) || lpmat)
3667 load_flags |= FT_LOAD_NO_BITMAP;
3669 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
3671 if(err) {
3672 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
3673 return GDI_ERROR;
3676 /* Scaling factor */
3677 if (font->aveWidth && font->potm)
3679 widthRatio = (float)font->aveWidth * font->font_desc.matrix.eM11;
3680 widthRatio /= (float)font->potm->otmTextMetrics.tmAveCharWidth;
3682 else
3683 widthRatio = font->scale_y;
3685 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
3686 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
3688 adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
3689 lsb = left >> 6;
3690 bbx = (right - left) >> 6;
3692 /* Scaling transform */
3693 if(font->aveWidth) {
3694 FT_Matrix scaleMat;
3695 scaleMat.xx = FT_FixedFromFloat(widthRatio);
3696 scaleMat.xy = 0;
3697 scaleMat.yx = 0;
3698 scaleMat.yy = FT_FixedFromFloat(font->scale_y);
3700 pFT_Matrix_Multiply(&scaleMat, &transMat);
3701 needsTransform = TRUE;
3704 /* Slant transform */
3705 if (font->fake_italic) {
3706 FT_Matrix slantMat;
3708 slantMat.xx = (1 << 16);
3709 slantMat.xy = ((1 << 16) >> 2);
3710 slantMat.yx = 0;
3711 slantMat.yy = (1 << 16);
3712 pFT_Matrix_Multiply(&slantMat, &transMat);
3713 needsTransform = TRUE;
3716 /* Rotation transform */
3717 if(font->orientation) {
3718 FT_Matrix rotationMat;
3719 FT_Vector vecAngle;
3720 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
3721 pFT_Vector_Unit(&vecAngle, angle);
3722 rotationMat.xx = vecAngle.x;
3723 rotationMat.xy = -vecAngle.y;
3724 rotationMat.yx = -rotationMat.xy;
3725 rotationMat.yy = rotationMat.xx;
3727 pFT_Matrix_Multiply(&rotationMat, &transMat);
3728 needsTransform = TRUE;
3731 /* Extra transformation specified by caller */
3732 if (lpmat) {
3733 FT_Matrix extraMat;
3734 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
3735 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
3736 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
3737 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
3738 pFT_Matrix_Multiply(&extraMat, &transMat);
3739 needsTransform = TRUE;
3742 if(!needsTransform) {
3743 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
3744 bottom = (ft_face->glyph->metrics.horiBearingY -
3745 ft_face->glyph->metrics.height) & -64;
3746 lpgm->gmCellIncX = adv;
3747 lpgm->gmCellIncY = 0;
3748 } else {
3749 INT xc, yc;
3750 FT_Vector vec;
3751 for(xc = 0; xc < 2; xc++) {
3752 for(yc = 0; yc < 2; yc++) {
3753 vec.x = (ft_face->glyph->metrics.horiBearingX +
3754 xc * ft_face->glyph->metrics.width);
3755 vec.y = ft_face->glyph->metrics.horiBearingY -
3756 yc * ft_face->glyph->metrics.height;
3757 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
3758 pFT_Vector_Transform(&vec, &transMat);
3759 if(xc == 0 && yc == 0) {
3760 left = right = vec.x;
3761 top = bottom = vec.y;
3762 } else {
3763 if(vec.x < left) left = vec.x;
3764 else if(vec.x > right) right = vec.x;
3765 if(vec.y < bottom) bottom = vec.y;
3766 else if(vec.y > top) top = vec.y;
3770 left = left & -64;
3771 right = (right + 63) & -64;
3772 bottom = bottom & -64;
3773 top = (top + 63) & -64;
3775 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
3776 vec.x = ft_face->glyph->metrics.horiAdvance;
3777 vec.y = 0;
3778 pFT_Vector_Transform(&vec, &transMat);
3779 lpgm->gmCellIncX = (vec.x+63) >> 6;
3780 lpgm->gmCellIncY = -((vec.y+63) >> 6);
3782 lpgm->gmBlackBoxX = (right - left) >> 6;
3783 lpgm->gmBlackBoxY = (top - bottom) >> 6;
3784 lpgm->gmptGlyphOrigin.x = left >> 6;
3785 lpgm->gmptGlyphOrigin.y = top >> 6;
3787 if(format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP)
3789 FONT_GM(font,glyph_index)->gm = *lpgm;
3790 FONT_GM(font,glyph_index)->adv = adv;
3791 FONT_GM(font,glyph_index)->lsb = lsb;
3792 FONT_GM(font,glyph_index)->bbx = bbx;
3793 FONT_GM(font,glyph_index)->init = TRUE;
3796 if(format == GGO_METRICS)
3797 return 1; /* FIXME */
3799 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP) {
3800 TRACE("loaded a bitmap\n");
3801 return GDI_ERROR;
3804 switch(format) {
3805 case GGO_BITMAP:
3806 width = lpgm->gmBlackBoxX;
3807 height = lpgm->gmBlackBoxY;
3808 pitch = ((width + 31) >> 5) << 2;
3809 needed = pitch * height;
3811 if(!buf || !buflen) break;
3813 switch(ft_face->glyph->format) {
3814 case ft_glyph_format_bitmap:
3816 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
3817 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
3818 INT h = ft_face->glyph->bitmap.rows;
3819 while(h--) {
3820 memcpy(dst, src, w);
3821 src += ft_face->glyph->bitmap.pitch;
3822 dst += pitch;
3824 break;
3827 case ft_glyph_format_outline:
3828 ft_bitmap.width = width;
3829 ft_bitmap.rows = height;
3830 ft_bitmap.pitch = pitch;
3831 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
3832 ft_bitmap.buffer = buf;
3834 if(needsTransform) {
3835 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3838 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3840 /* Note: FreeType will only set 'black' bits for us. */
3841 memset(buf, 0, needed);
3842 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3843 break;
3845 default:
3846 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
3847 return GDI_ERROR;
3849 break;
3851 case GGO_GRAY2_BITMAP:
3852 case GGO_GRAY4_BITMAP:
3853 case GGO_GRAY8_BITMAP:
3854 case WINE_GGO_GRAY16_BITMAP:
3856 unsigned int mult, row, col;
3857 BYTE *start, *ptr;
3859 width = lpgm->gmBlackBoxX;
3860 height = lpgm->gmBlackBoxY;
3861 pitch = (width + 3) / 4 * 4;
3862 needed = pitch * height;
3864 if(!buf || !buflen) break;
3866 switch(ft_face->glyph->format) {
3867 case ft_glyph_format_bitmap:
3869 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
3870 INT h = ft_face->glyph->bitmap.rows;
3871 INT x;
3872 while(h--) {
3873 for(x = 0; x < pitch; x++)
3874 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
3875 src += ft_face->glyph->bitmap.pitch;
3876 dst += pitch;
3878 return needed;
3880 case ft_glyph_format_outline:
3882 ft_bitmap.width = width;
3883 ft_bitmap.rows = height;
3884 ft_bitmap.pitch = pitch;
3885 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
3886 ft_bitmap.buffer = buf;
3888 if(needsTransform)
3889 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3891 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3893 memset(ft_bitmap.buffer, 0, buflen);
3895 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3897 if(format == GGO_GRAY2_BITMAP)
3898 mult = 4;
3899 else if(format == GGO_GRAY4_BITMAP)
3900 mult = 16;
3901 else if(format == GGO_GRAY8_BITMAP)
3902 mult = 64;
3903 else /* format == WINE_GGO_GRAY16_BITMAP */
3904 return needed;
3906 break;
3908 default:
3909 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
3910 return GDI_ERROR;
3913 start = buf;
3914 for(row = 0; row < height; row++) {
3915 ptr = start;
3916 for(col = 0; col < width; col++, ptr++) {
3917 *ptr = (((int)*ptr) * mult + 128) / 256;
3919 start += pitch;
3921 break;
3924 case GGO_NATIVE:
3926 int contour, point = 0, first_pt;
3927 FT_Outline *outline = &ft_face->glyph->outline;
3928 TTPOLYGONHEADER *pph;
3929 TTPOLYCURVE *ppc;
3930 DWORD pph_start, cpfx, type;
3932 if(buflen == 0) buf = NULL;
3934 if (needsTransform && buf) {
3935 pFT_Outline_Transform(outline, &transMat);
3938 for(contour = 0; contour < outline->n_contours; contour++) {
3939 pph_start = needed;
3940 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3941 first_pt = point;
3942 if(buf) {
3943 pph->dwType = TT_POLYGON_TYPE;
3944 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3946 needed += sizeof(*pph);
3947 point++;
3948 while(point <= outline->contours[contour]) {
3949 ppc = (TTPOLYCURVE *)((char *)buf + needed);
3950 type = (outline->tags[point] & FT_Curve_Tag_On) ?
3951 TT_PRIM_LINE : TT_PRIM_QSPLINE;
3952 cpfx = 0;
3953 do {
3954 if(buf)
3955 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3956 cpfx++;
3957 point++;
3958 } while(point <= outline->contours[contour] &&
3959 (outline->tags[point] & FT_Curve_Tag_On) ==
3960 (outline->tags[point-1] & FT_Curve_Tag_On));
3961 /* At the end of a contour Windows adds the start point, but
3962 only for Beziers */
3963 if(point > outline->contours[contour] &&
3964 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
3965 if(buf)
3966 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
3967 cpfx++;
3968 } else if(point <= outline->contours[contour] &&
3969 outline->tags[point] & FT_Curve_Tag_On) {
3970 /* add closing pt for bezier */
3971 if(buf)
3972 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3973 cpfx++;
3974 point++;
3976 if(buf) {
3977 ppc->wType = type;
3978 ppc->cpfx = cpfx;
3980 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3982 if(buf)
3983 pph->cb = needed - pph_start;
3985 break;
3987 case GGO_BEZIER:
3989 /* Convert the quadratic Beziers to cubic Beziers.
3990 The parametric eqn for a cubic Bezier is, from PLRM:
3991 r(t) = at^3 + bt^2 + ct + r0
3992 with the control points:
3993 r1 = r0 + c/3
3994 r2 = r1 + (c + b)/3
3995 r3 = r0 + c + b + a
3997 A quadratic Beizer has the form:
3998 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
4000 So equating powers of t leads to:
4001 r1 = 2/3 p1 + 1/3 p0
4002 r2 = 2/3 p1 + 1/3 p2
4003 and of course r0 = p0, r3 = p2
4006 int contour, point = 0, first_pt;
4007 FT_Outline *outline = &ft_face->glyph->outline;
4008 TTPOLYGONHEADER *pph;
4009 TTPOLYCURVE *ppc;
4010 DWORD pph_start, cpfx, type;
4011 FT_Vector cubic_control[4];
4012 if(buflen == 0) buf = NULL;
4014 if (needsTransform && buf) {
4015 pFT_Outline_Transform(outline, &transMat);
4018 for(contour = 0; contour < outline->n_contours; contour++) {
4019 pph_start = needed;
4020 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
4021 first_pt = point;
4022 if(buf) {
4023 pph->dwType = TT_POLYGON_TYPE;
4024 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
4026 needed += sizeof(*pph);
4027 point++;
4028 while(point <= outline->contours[contour]) {
4029 ppc = (TTPOLYCURVE *)((char *)buf + needed);
4030 type = (outline->tags[point] & FT_Curve_Tag_On) ?
4031 TT_PRIM_LINE : TT_PRIM_CSPLINE;
4032 cpfx = 0;
4033 do {
4034 if(type == TT_PRIM_LINE) {
4035 if(buf)
4036 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4037 cpfx++;
4038 point++;
4039 } else {
4040 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
4041 so cpfx = 3n */
4043 /* FIXME: Possible optimization in endpoint calculation
4044 if there are two consecutive curves */
4045 cubic_control[0] = outline->points[point-1];
4046 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
4047 cubic_control[0].x += outline->points[point].x + 1;
4048 cubic_control[0].y += outline->points[point].y + 1;
4049 cubic_control[0].x >>= 1;
4050 cubic_control[0].y >>= 1;
4052 if(point+1 > outline->contours[contour])
4053 cubic_control[3] = outline->points[first_pt];
4054 else {
4055 cubic_control[3] = outline->points[point+1];
4056 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
4057 cubic_control[3].x += outline->points[point].x + 1;
4058 cubic_control[3].y += outline->points[point].y + 1;
4059 cubic_control[3].x >>= 1;
4060 cubic_control[3].y >>= 1;
4063 /* r1 = 1/3 p0 + 2/3 p1
4064 r2 = 1/3 p2 + 2/3 p1 */
4065 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
4066 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
4067 cubic_control[2] = cubic_control[1];
4068 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
4069 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
4070 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
4071 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
4072 if(buf) {
4073 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
4074 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
4075 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
4077 cpfx += 3;
4078 point++;
4080 } while(point <= outline->contours[contour] &&
4081 (outline->tags[point] & FT_Curve_Tag_On) ==
4082 (outline->tags[point-1] & FT_Curve_Tag_On));
4083 /* At the end of a contour Windows adds the start point,
4084 but only for Beziers and we've already done that.
4086 if(point <= outline->contours[contour] &&
4087 outline->tags[point] & FT_Curve_Tag_On) {
4088 /* This is the closing pt of a bezier, but we've already
4089 added it, so just inc point and carry on */
4090 point++;
4092 if(buf) {
4093 ppc->wType = type;
4094 ppc->cpfx = cpfx;
4096 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
4098 if(buf)
4099 pph->cb = needed - pph_start;
4101 break;
4104 default:
4105 FIXME("Unsupported format %d\n", format);
4106 return GDI_ERROR;
4108 return needed;
4111 static BOOL get_bitmap_text_metrics(GdiFont *font)
4113 FT_Face ft_face = font->ft_face;
4114 #ifdef HAVE_FREETYPE_FTWINFNT_H
4115 FT_WinFNT_HeaderRec winfnt_header;
4116 #endif
4117 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
4118 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
4119 font->potm->otmSize = size;
4121 #define TM font->potm->otmTextMetrics
4122 #ifdef HAVE_FREETYPE_FTWINFNT_H
4123 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
4125 TM.tmHeight = winfnt_header.pixel_height;
4126 TM.tmAscent = winfnt_header.ascent;
4127 TM.tmDescent = TM.tmHeight - TM.tmAscent;
4128 TM.tmInternalLeading = winfnt_header.internal_leading;
4129 TM.tmExternalLeading = winfnt_header.external_leading;
4130 TM.tmAveCharWidth = winfnt_header.avg_width;
4131 TM.tmMaxCharWidth = winfnt_header.max_width;
4132 TM.tmWeight = winfnt_header.weight;
4133 TM.tmOverhang = 0;
4134 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
4135 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
4136 TM.tmFirstChar = winfnt_header.first_char;
4137 TM.tmLastChar = winfnt_header.last_char;
4138 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
4139 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
4140 TM.tmItalic = winfnt_header.italic;
4141 TM.tmUnderlined = font->underline;
4142 TM.tmStruckOut = font->strikeout;
4143 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
4144 TM.tmCharSet = winfnt_header.charset;
4146 else
4147 #endif
4149 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
4150 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
4151 TM.tmHeight = TM.tmAscent + TM.tmDescent;
4152 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
4153 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
4154 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
4155 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
4156 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
4157 TM.tmOverhang = 0;
4158 TM.tmDigitizedAspectX = 96; /* FIXME */
4159 TM.tmDigitizedAspectY = 96; /* FIXME */
4160 TM.tmFirstChar = 1;
4161 TM.tmLastChar = 255;
4162 TM.tmDefaultChar = 32;
4163 TM.tmBreakChar = 32;
4164 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
4165 TM.tmUnderlined = font->underline;
4166 TM.tmStruckOut = font->strikeout;
4167 /* NB inverted meaning of TMPF_FIXED_PITCH */
4168 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
4169 TM.tmCharSet = font->charset;
4171 #undef TM
4173 return TRUE;
4177 static void scale_font_metrics(GdiFont *font, LPTEXTMETRICW ptm)
4179 float scale_x;
4181 if (font->aveWidth)
4183 scale_x = (float)font->aveWidth * font->font_desc.matrix.eM11;
4184 scale_x /= (float)font->potm->otmTextMetrics.tmAveCharWidth;
4186 else
4187 scale_x = font->scale_y;
4189 ptm->tmHeight = (float)ptm->tmHeight * font->scale_y;
4190 ptm->tmAscent = (float)ptm->tmAscent * font->scale_y;
4191 ptm->tmDescent = (float)ptm->tmDescent * font->scale_y;
4192 ptm->tmInternalLeading = (float)ptm->tmInternalLeading * font->scale_y;
4193 ptm->tmExternalLeading = (float)ptm->tmExternalLeading * font->scale_y;
4195 ptm->tmAveCharWidth = (float)ptm->tmAveCharWidth * scale_x;
4196 ptm->tmMaxCharWidth = (float)ptm->tmMaxCharWidth * scale_x;
4199 /*************************************************************
4200 * WineEngGetTextMetrics
4203 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
4205 if(!font->potm) {
4206 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
4207 if(!get_bitmap_text_metrics(font))
4208 return FALSE;
4210 if(!font->potm) return FALSE;
4211 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
4212 scale_font_metrics(font, ptm);
4214 return TRUE;
4218 /*************************************************************
4219 * WineEngGetOutlineTextMetrics
4222 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
4223 OUTLINETEXTMETRICW *potm)
4225 FT_Face ft_face = font->ft_face;
4226 UINT needed, lenfam, lensty, ret;
4227 TT_OS2 *pOS2;
4228 TT_HoriHeader *pHori;
4229 TT_Postscript *pPost;
4230 FT_Fixed x_scale, y_scale;
4231 WCHAR *family_nameW, *style_nameW;
4232 static const WCHAR spaceW[] = {' ', '\0'};
4233 char *cp;
4234 INT ascent, descent;
4236 TRACE("font=%p\n", font);
4238 if(!FT_IS_SCALABLE(ft_face))
4239 return 0;
4241 if(font->potm) {
4242 if(cbSize >= font->potm->otmSize)
4244 memcpy(potm, font->potm, font->potm->otmSize);
4245 scale_font_metrics(font, &potm->otmTextMetrics);
4247 return font->potm->otmSize;
4251 needed = sizeof(*potm);
4253 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
4254 family_nameW = strdupW(font->name);
4256 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
4257 * sizeof(WCHAR);
4258 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
4259 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
4260 style_nameW, lensty/sizeof(WCHAR));
4262 /* These names should be read from the TT name table */
4264 /* length of otmpFamilyName */
4265 needed += lenfam;
4267 /* length of otmpFaceName */
4268 if(!strcasecmp(ft_face->style_name, "regular")) {
4269 needed += lenfam; /* just the family name */
4270 } else {
4271 needed += lenfam + lensty; /* family + " " + style */
4274 /* length of otmpStyleName */
4275 needed += lensty;
4277 /* length of otmpFullName */
4278 needed += lenfam + lensty;
4281 x_scale = ft_face->size->metrics.x_scale;
4282 y_scale = ft_face->size->metrics.y_scale;
4284 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
4285 if(!pOS2) {
4286 FIXME("Can't find OS/2 table - not TT font?\n");
4287 ret = 0;
4288 goto end;
4291 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
4292 if(!pHori) {
4293 FIXME("Can't find HHEA table - not TT font?\n");
4294 ret = 0;
4295 goto end;
4298 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
4300 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",
4301 pOS2->usWinAscent, pOS2->usWinDescent,
4302 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
4303 ft_face->ascender, ft_face->descender, ft_face->height,
4304 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
4305 ft_face->bbox.yMax, ft_face->bbox.yMin);
4307 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
4308 font->potm->otmSize = needed;
4310 #define TM font->potm->otmTextMetrics
4312 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
4313 ascent = pHori->Ascender;
4314 descent = -pHori->Descender;
4315 } else {
4316 ascent = pOS2->usWinAscent;
4317 descent = pOS2->usWinDescent;
4320 if(font->yMax) {
4321 TM.tmAscent = font->yMax;
4322 TM.tmDescent = -font->yMin;
4323 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
4324 } else {
4325 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
4326 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
4327 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
4328 - ft_face->units_per_EM, y_scale) + 32) >> 6;
4331 TM.tmHeight = TM.tmAscent + TM.tmDescent;
4333 /* MSDN says:
4334 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
4336 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
4337 ((ascent + descent) -
4338 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
4340 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
4341 if (TM.tmAveCharWidth == 0) {
4342 TM.tmAveCharWidth = 1;
4344 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
4345 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
4346 TM.tmOverhang = 0;
4347 TM.tmDigitizedAspectX = 300;
4348 TM.tmDigitizedAspectY = 300;
4349 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
4350 * symbol range to 0 - f0ff
4352 if (font->charset == SYMBOL_CHARSET)
4353 TM.tmFirstChar = 0;
4354 else
4355 TM.tmFirstChar = pOS2->usFirstCharIndex;
4356 TM.tmLastChar = pOS2->usLastCharIndex;
4357 TM.tmDefaultChar = pOS2->usDefaultChar ? pOS2->usDefaultChar : 0x1f;
4358 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
4359 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
4360 TM.tmUnderlined = font->underline;
4361 TM.tmStruckOut = font->strikeout;
4363 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
4364 if(!FT_IS_FIXED_WIDTH(ft_face) &&
4365 (pOS2->version == 0xFFFFU ||
4366 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
4367 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
4368 else
4369 TM.tmPitchAndFamily = 0;
4371 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
4372 case PAN_FAMILY_SCRIPT:
4373 TM.tmPitchAndFamily |= FF_SCRIPT;
4374 break;
4375 case PAN_FAMILY_DECORATIVE:
4376 case PAN_FAMILY_PICTORIAL:
4377 TM.tmPitchAndFamily |= FF_DECORATIVE;
4378 break;
4379 case PAN_FAMILY_TEXT_DISPLAY:
4380 if(TM.tmPitchAndFamily == 0) /* fixed */
4381 TM.tmPitchAndFamily = FF_MODERN;
4382 else {
4383 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
4384 case PAN_SERIF_NORMAL_SANS:
4385 case PAN_SERIF_OBTUSE_SANS:
4386 case PAN_SERIF_PERP_SANS:
4387 TM.tmPitchAndFamily |= FF_SWISS;
4388 break;
4389 default:
4390 TM.tmPitchAndFamily |= FF_ROMAN;
4393 break;
4394 default:
4395 TM.tmPitchAndFamily |= FF_DONTCARE;
4398 if(FT_IS_SCALABLE(ft_face))
4399 TM.tmPitchAndFamily |= TMPF_VECTOR;
4401 if(FT_IS_SFNT(ft_face))
4403 if (font->ntmFlags & NTM_PS_OPENTYPE)
4404 TM.tmPitchAndFamily |= TMPF_DEVICE;
4405 else
4406 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
4409 TM.tmCharSet = font->charset;
4410 #undef TM
4412 font->potm->otmFiller = 0;
4413 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
4414 font->potm->otmfsSelection = pOS2->fsSelection;
4415 font->potm->otmfsType = pOS2->fsType;
4416 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
4417 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
4418 font->potm->otmItalicAngle = 0; /* POST table */
4419 font->potm->otmEMSquare = ft_face->units_per_EM;
4420 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
4421 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
4422 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
4423 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
4424 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
4425 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
4426 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
4427 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
4428 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
4429 font->potm->otmMacAscent = 0; /* where do these come from ? */
4430 font->potm->otmMacDescent = 0;
4431 font->potm->otmMacLineGap = 0;
4432 font->potm->otmusMinimumPPEM = 0; /* TT Header */
4433 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
4434 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
4435 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
4436 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
4437 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
4438 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
4439 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
4440 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
4441 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
4442 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
4443 if(!pPost) {
4444 font->potm->otmsUnderscoreSize = 0;
4445 font->potm->otmsUnderscorePosition = 0;
4446 } else {
4447 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
4448 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
4451 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
4452 cp = (char*)font->potm + sizeof(*font->potm);
4453 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
4454 strcpyW((WCHAR*)cp, family_nameW);
4455 cp += lenfam;
4456 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
4457 strcpyW((WCHAR*)cp, style_nameW);
4458 cp += lensty;
4459 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
4460 strcpyW((WCHAR*)cp, family_nameW);
4461 if(strcasecmp(ft_face->style_name, "regular")) {
4462 strcatW((WCHAR*)cp, spaceW);
4463 strcatW((WCHAR*)cp, style_nameW);
4464 cp += lenfam + lensty;
4465 } else
4466 cp += lenfam;
4467 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
4468 strcpyW((WCHAR*)cp, family_nameW);
4469 strcatW((WCHAR*)cp, spaceW);
4470 strcatW((WCHAR*)cp, style_nameW);
4471 ret = needed;
4473 if(potm && needed <= cbSize)
4475 memcpy(potm, font->potm, font->potm->otmSize);
4476 scale_font_metrics(font, &potm->otmTextMetrics);
4479 end:
4480 HeapFree(GetProcessHeap(), 0, style_nameW);
4481 HeapFree(GetProcessHeap(), 0, family_nameW);
4483 return ret;
4486 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
4488 HFONTLIST *hfontlist;
4489 child->font = alloc_font();
4490 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
4491 if(!child->font->ft_face)
4493 free_font(child->font);
4494 child->font = NULL;
4495 return FALSE;
4498 child->font->ntmFlags = child->face->ntmFlags;
4499 child->font->orientation = font->orientation;
4500 child->font->scale_y = font->scale_y;
4501 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
4502 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
4503 list_add_head(&child->font->hfontlist, &hfontlist->entry);
4504 child->font->base_font = font;
4505 list_add_head(&child_font_list, &child->font->entry);
4506 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
4507 return TRUE;
4510 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
4512 FT_UInt g;
4513 CHILD_FONT *child_font;
4515 if(font->base_font)
4516 font = font->base_font;
4518 *linked_font = font;
4520 if((*glyph = get_glyph_index(font, c)))
4521 return TRUE;
4523 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
4525 if(!child_font->font)
4526 if(!load_child_font(font, child_font))
4527 continue;
4529 if(!child_font->font->ft_face)
4530 continue;
4531 g = get_glyph_index(child_font->font, c);
4532 if(g)
4534 *glyph = g;
4535 *linked_font = child_font->font;
4536 return TRUE;
4539 return FALSE;
4542 /*************************************************************
4543 * WineEngGetCharWidth
4546 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
4547 LPINT buffer)
4549 UINT c;
4550 GLYPHMETRICS gm;
4551 FT_UInt glyph_index;
4552 GdiFont *linked_font;
4554 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
4556 for(c = firstChar; c <= lastChar; c++) {
4557 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
4558 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4559 &gm, 0, NULL, NULL);
4560 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
4562 return TRUE;
4565 /*************************************************************
4566 * WineEngGetCharABCWidths
4569 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
4570 LPABC buffer)
4572 UINT c;
4573 GLYPHMETRICS gm;
4574 FT_UInt glyph_index;
4575 GdiFont *linked_font;
4577 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
4579 if(!FT_IS_SCALABLE(font->ft_face))
4580 return FALSE;
4582 for(c = firstChar; c <= lastChar; c++) {
4583 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
4584 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4585 &gm, 0, NULL, NULL);
4586 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
4587 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
4588 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
4589 FONT_GM(linked_font,glyph_index)->bbx;
4591 return TRUE;
4594 /*************************************************************
4595 * WineEngGetCharABCWidthsI
4598 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
4599 LPABC buffer)
4601 UINT c;
4602 GLYPHMETRICS gm;
4603 FT_UInt glyph_index;
4604 GdiFont *linked_font;
4606 if(!FT_HAS_HORIZONTAL(font->ft_face))
4607 return FALSE;
4609 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
4610 if (!pgi)
4611 for(c = firstChar; c < firstChar+count; c++) {
4612 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
4613 &gm, 0, NULL, NULL);
4614 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
4615 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
4616 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
4617 - FONT_GM(linked_font,c)->bbx;
4619 else
4620 for(c = 0; c < count; c++) {
4621 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
4622 &gm, 0, NULL, NULL);
4623 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
4624 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
4625 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
4626 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
4629 return TRUE;
4632 /*************************************************************
4633 * WineEngGetTextExtentExPoint
4636 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
4637 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
4639 INT idx;
4640 INT nfit = 0, ext;
4641 GLYPHMETRICS gm;
4642 TEXTMETRICW tm;
4643 FT_UInt glyph_index;
4644 GdiFont *linked_font;
4646 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
4647 max_ext, size);
4649 size->cx = 0;
4650 WineEngGetTextMetrics(font, &tm);
4651 size->cy = tm.tmHeight;
4653 for(idx = 0; idx < count; idx++) {
4654 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
4655 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4656 &gm, 0, NULL, NULL);
4657 size->cx += FONT_GM(linked_font,glyph_index)->adv;
4658 ext = size->cx;
4659 if (! pnfit || ext <= max_ext) {
4660 ++nfit;
4661 if (dxs)
4662 dxs[idx] = ext;
4666 if (pnfit)
4667 *pnfit = nfit;
4669 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
4670 return TRUE;
4673 /*************************************************************
4674 * WineEngGetTextExtentExPointI
4677 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
4678 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
4680 INT idx;
4681 INT nfit = 0, ext;
4682 GLYPHMETRICS gm;
4683 TEXTMETRICW tm;
4685 TRACE("%p, %p, %d, %d, %p\n", font, indices, count, max_ext, size);
4687 size->cx = 0;
4688 WineEngGetTextMetrics(font, &tm);
4689 size->cy = tm.tmHeight;
4691 for(idx = 0; idx < count; idx++) {
4692 WineEngGetGlyphOutline(font, indices[idx],
4693 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
4694 NULL);
4695 size->cx += FONT_GM(font,indices[idx])->adv;
4696 ext = size->cx;
4697 if (! pnfit || ext <= max_ext) {
4698 ++nfit;
4699 if (dxs)
4700 dxs[idx] = ext;
4704 if (pnfit)
4705 *pnfit = nfit;
4707 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
4708 return TRUE;
4711 /*************************************************************
4712 * WineEngGetFontData
4715 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
4716 DWORD cbData)
4718 FT_Face ft_face = font->ft_face;
4719 FT_ULong len;
4720 FT_Error err;
4722 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
4723 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
4724 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
4726 if(!FT_IS_SFNT(ft_face))
4727 return GDI_ERROR;
4729 if(!buf || !cbData)
4730 len = 0;
4731 else
4732 len = cbData;
4734 if(table) { /* MS tags differ in endidness from FT ones */
4735 table = table >> 24 | table << 24 |
4736 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
4739 /* make sure value of len is the value freetype says it needs */
4740 if(buf && len)
4742 FT_ULong needed = 0;
4743 err = load_sfnt_table(ft_face, table, offset, NULL, &needed);
4744 if( !err && needed < len) len = needed;
4746 err = load_sfnt_table(ft_face, table, offset, buf, &len);
4748 if(err) {
4749 TRACE("Can't find table %c%c%c%c\n",
4750 /* bytes were reversed */
4751 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
4752 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
4753 return GDI_ERROR;
4755 return len;
4758 /*************************************************************
4759 * WineEngGetTextFace
4762 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
4764 if(str) {
4765 lstrcpynW(str, font->name, count);
4766 return strlenW(font->name);
4767 } else
4768 return strlenW(font->name) + 1;
4771 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
4773 if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
4774 return font->charset;
4777 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
4779 GdiFont *font = dc->gdiFont, *linked_font;
4780 struct list *first_hfont;
4781 BOOL ret;
4783 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
4784 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
4785 if(font == linked_font)
4786 *new_hfont = dc->hFont;
4787 else
4789 first_hfont = list_head(&linked_font->hfontlist);
4790 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
4793 return ret;
4796 /* Retrieve a list of supported Unicode ranges for a given font.
4797 * Can be called with NULL gs to calculate the buffer size. Returns
4798 * the number of ranges found.
4800 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
4802 DWORD num_ranges = 0;
4804 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
4806 FT_UInt glyph_code;
4807 FT_ULong char_code, char_code_prev;
4809 glyph_code = 0;
4810 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
4812 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
4813 face->num_glyphs, glyph_code, char_code);
4815 if (!glyph_code) return 0;
4817 if (gs)
4819 gs->ranges[0].wcLow = (USHORT)char_code;
4820 gs->ranges[0].cGlyphs = 0;
4821 gs->cGlyphsSupported = 0;
4824 num_ranges = 1;
4825 while (glyph_code)
4827 if (char_code < char_code_prev)
4829 ERR("expected increasing char code from FT_Get_Next_Char\n");
4830 return 0;
4832 if (char_code - char_code_prev > 1)
4834 num_ranges++;
4835 if (gs)
4837 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
4838 gs->ranges[num_ranges - 1].cGlyphs = 1;
4839 gs->cGlyphsSupported++;
4842 else if (gs)
4844 gs->ranges[num_ranges - 1].cGlyphs++;
4845 gs->cGlyphsSupported++;
4847 char_code_prev = char_code;
4848 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
4851 else
4852 FIXME("encoding %u not supported\n", face->charmap->encoding);
4854 return num_ranges;
4857 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
4859 DWORD size = 0;
4860 DWORD num_ranges = get_font_unicode_ranges(font->ft_face, glyphset);
4862 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
4863 if (glyphset)
4865 glyphset->cbThis = size;
4866 glyphset->cRanges = num_ranges;
4868 return size;
4871 /*************************************************************
4872 * FontIsLinked
4874 BOOL WineEngFontIsLinked(GdiFont *font)
4876 return !list_empty(&font->child_fonts);
4879 static BOOL is_hinting_enabled(void)
4881 /* Use the >= 2.2.0 function if available */
4882 if(pFT_Get_TrueType_Engine_Type)
4884 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
4885 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
4887 #ifdef FT_DRIVER_HAS_HINTER
4888 else
4890 FT_Module mod;
4892 /* otherwise if we've been compiled with < 2.2.0 headers
4893 use the internal macro */
4894 mod = pFT_Get_Module(library, "truetype");
4895 if(mod && FT_DRIVER_HAS_HINTER(mod))
4896 return TRUE;
4898 #endif
4900 return FALSE;
4903 /*************************************************************************
4904 * GetRasterizerCaps (GDI32.@)
4906 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
4908 static int hinting = -1;
4910 if(hinting == -1)
4912 hinting = is_hinting_enabled();
4913 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
4916 lprs->nSize = sizeof(RASTERIZER_STATUS);
4917 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
4918 lprs->nLanguageID = 0;
4919 return TRUE;
4922 /*************************************************************************
4923 * Kerning support for TrueType fonts
4925 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
4927 struct TT_kern_table
4929 USHORT version;
4930 USHORT nTables;
4933 struct TT_kern_subtable
4935 USHORT version;
4936 USHORT length;
4937 union
4939 USHORT word;
4940 struct
4942 USHORT horizontal : 1;
4943 USHORT minimum : 1;
4944 USHORT cross_stream: 1;
4945 USHORT override : 1;
4946 USHORT reserved1 : 4;
4947 USHORT format : 8;
4948 } bits;
4949 } coverage;
4952 struct TT_format0_kern_subtable
4954 USHORT nPairs;
4955 USHORT searchRange;
4956 USHORT entrySelector;
4957 USHORT rangeShift;
4960 struct TT_kern_pair
4962 USHORT left;
4963 USHORT right;
4964 short value;
4967 static DWORD parse_format0_kern_subtable(GdiFont *font,
4968 const struct TT_format0_kern_subtable *tt_f0_ks,
4969 const USHORT *glyph_to_char,
4970 KERNINGPAIR *kern_pair, DWORD cPairs)
4972 USHORT i, nPairs;
4973 const struct TT_kern_pair *tt_kern_pair;
4975 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
4977 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
4979 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
4980 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
4981 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
4983 if (!kern_pair || !cPairs)
4984 return nPairs;
4986 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
4988 nPairs = min(nPairs, cPairs);
4990 for (i = 0; i < nPairs; i++)
4992 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
4993 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
4994 /* this algorithm appears to better match what Windows does */
4995 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
4996 if (kern_pair->iKernAmount < 0)
4998 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
4999 kern_pair->iKernAmount -= font->ppem;
5001 else if (kern_pair->iKernAmount > 0)
5003 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
5004 kern_pair->iKernAmount += font->ppem;
5006 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
5008 TRACE("left %u right %u value %d\n",
5009 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
5011 kern_pair++;
5013 TRACE("copied %u entries\n", nPairs);
5014 return nPairs;
5017 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
5019 DWORD length;
5020 void *buf;
5021 const struct TT_kern_table *tt_kern_table;
5022 const struct TT_kern_subtable *tt_kern_subtable;
5023 USHORT i, nTables;
5024 USHORT *glyph_to_char;
5026 if (font->total_kern_pairs != (DWORD)-1)
5028 if (cPairs && kern_pair)
5030 cPairs = min(cPairs, font->total_kern_pairs);
5031 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
5032 return cPairs;
5034 return font->total_kern_pairs;
5037 font->total_kern_pairs = 0;
5039 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
5041 if (length == GDI_ERROR)
5043 TRACE("no kerning data in the font\n");
5044 return 0;
5047 buf = HeapAlloc(GetProcessHeap(), 0, length);
5048 if (!buf)
5050 WARN("Out of memory\n");
5051 return 0;
5054 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
5056 /* build a glyph index to char code map */
5057 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
5058 if (!glyph_to_char)
5060 WARN("Out of memory allocating a glyph index to char code map\n");
5061 HeapFree(GetProcessHeap(), 0, buf);
5062 return 0;
5065 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
5067 FT_UInt glyph_code;
5068 FT_ULong char_code;
5070 glyph_code = 0;
5071 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
5073 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
5074 font->ft_face->num_glyphs, glyph_code, char_code);
5076 while (glyph_code)
5078 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
5080 /* FIXME: This doesn't match what Windows does: it does some fancy
5081 * things with duplicate glyph index to char code mappings, while
5082 * we just avoid overriding existing entries.
5084 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
5085 glyph_to_char[glyph_code] = (USHORT)char_code;
5087 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
5090 else
5092 ULONG n;
5094 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
5095 for (n = 0; n <= 65535; n++)
5096 glyph_to_char[n] = (USHORT)n;
5099 tt_kern_table = buf;
5100 nTables = GET_BE_WORD(tt_kern_table->nTables);
5101 TRACE("version %u, nTables %u\n",
5102 GET_BE_WORD(tt_kern_table->version), nTables);
5104 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
5106 for (i = 0; i < nTables; i++)
5108 struct TT_kern_subtable tt_kern_subtable_copy;
5110 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
5111 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
5112 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
5114 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
5115 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
5116 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
5118 /* According to the TrueType specification this is the only format
5119 * that will be properly interpreted by Windows and OS/2
5121 if (tt_kern_subtable_copy.coverage.bits.format == 0)
5123 DWORD new_chunk, old_total = font->total_kern_pairs;
5125 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
5126 glyph_to_char, NULL, 0);
5127 font->total_kern_pairs += new_chunk;
5129 if (!font->kern_pairs)
5130 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
5131 font->total_kern_pairs * sizeof(*font->kern_pairs));
5132 else
5133 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
5134 font->total_kern_pairs * sizeof(*font->kern_pairs));
5136 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
5137 glyph_to_char, font->kern_pairs + old_total, new_chunk);
5139 else
5140 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
5142 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
5145 HeapFree(GetProcessHeap(), 0, glyph_to_char);
5146 HeapFree(GetProcessHeap(), 0, buf);
5148 if (cPairs && kern_pair)
5150 cPairs = min(cPairs, font->total_kern_pairs);
5151 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
5152 return cPairs;
5154 return font->total_kern_pairs;
5157 #else /* HAVE_FREETYPE */
5159 /*************************************************************************/
5161 BOOL WineEngInit(void)
5163 return FALSE;
5165 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
5167 return NULL;
5169 BOOL WineEngDestroyFontInstance(HFONT hfont)
5171 return FALSE;
5174 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
5176 return 1;
5179 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
5180 LPWORD pgi, DWORD flags)
5182 return GDI_ERROR;
5185 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
5186 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5187 const MAT2* lpmat)
5189 ERR("called but we don't have FreeType\n");
5190 return GDI_ERROR;
5193 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
5195 ERR("called but we don't have FreeType\n");
5196 return FALSE;
5199 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
5200 OUTLINETEXTMETRICW *potm)
5202 ERR("called but we don't have FreeType\n");
5203 return 0;
5206 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5207 LPINT buffer)
5209 ERR("called but we don't have FreeType\n");
5210 return FALSE;
5213 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5214 LPABC buffer)
5216 ERR("called but we don't have FreeType\n");
5217 return FALSE;
5220 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
5221 LPABC buffer)
5223 ERR("called but we don't have FreeType\n");
5224 return FALSE;
5227 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
5228 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
5230 ERR("called but we don't have FreeType\n");
5231 return FALSE;
5234 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
5235 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
5237 ERR("called but we don't have FreeType\n");
5238 return FALSE;
5241 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
5242 DWORD cbData)
5244 ERR("called but we don't have FreeType\n");
5245 return GDI_ERROR;
5248 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
5250 ERR("called but we don't have FreeType\n");
5251 return 0;
5254 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
5256 FIXME(":stub\n");
5257 return 1;
5260 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
5262 FIXME(":stub\n");
5263 return TRUE;
5266 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
5268 FIXME(":stub\n");
5269 return NULL;
5272 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
5274 FIXME(":stub\n");
5275 return DEFAULT_CHARSET;
5278 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
5280 return FALSE;
5283 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
5285 FIXME("(%p, %p): stub\n", font, glyphset);
5286 return 0;
5289 BOOL WineEngFontIsLinked(GdiFont *font)
5291 return FALSE;
5294 /*************************************************************************
5295 * GetRasterizerCaps (GDI32.@)
5297 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
5299 lprs->nSize = sizeof(RASTERIZER_STATUS);
5300 lprs->wFlags = 0;
5301 lprs->nLanguageID = 0;
5302 return TRUE;
5305 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
5307 ERR("called but we don't have FreeType\n");
5308 return 0;
5311 #endif /* HAVE_FREETYPE */