gdi32: Fix a GdiFont leak.
[wine/gsoc_dplay.git] / dlls / gdi32 / freetype.c
blob067d41f380184d41966cad46e4b46d265cb7c215
1 /*
2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
5 * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
7 * This file contains the WineEng* functions.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "config.h"
25 #include "wine/port.h"
27 #include <stdarg.h>
28 #include <stdlib.h>
29 #ifdef HAVE_SYS_STAT_H
30 # include <sys/stat.h>
31 #endif
32 #ifdef HAVE_SYS_MMAN_H
33 # include <sys/mman.h>
34 #endif
35 #include <string.h>
36 #include <dirent.h>
37 #include <stdio.h>
38 #include <assert.h>
40 #ifdef HAVE_CARBON_CARBON_H
41 #define LoadResource __carbon_LoadResource
42 #define CompareString __carbon_CompareString
43 #define GetCurrentThread __carbon_GetCurrentThread
44 #define GetCurrentProcess __carbon_GetCurrentProcess
45 #define AnimatePalette __carbon_AnimatePalette
46 #define EqualRgn __carbon_EqualRgn
47 #define FillRgn __carbon_FillRgn
48 #define FrameRgn __carbon_FrameRgn
49 #define GetPixel __carbon_GetPixel
50 #define InvertRgn __carbon_InvertRgn
51 #define LineTo __carbon_LineTo
52 #define OffsetRgn __carbon_OffsetRgn
53 #define PaintRgn __carbon_PaintRgn
54 #define Polygon __carbon_Polygon
55 #define ResizePalette __carbon_ResizePalette
56 #define SetRectRgn __carbon_SetRectRgn
57 #include <Carbon/Carbon.h>
58 #undef LoadResource
59 #undef CompareString
60 #undef GetCurrentThread
61 #undef _CDECL
62 #undef DPRINTF
63 #undef GetCurrentProcess
64 #undef AnimatePalette
65 #undef EqualRgn
66 #undef FillRgn
67 #undef FrameRgn
68 #undef GetPixel
69 #undef InvertRgn
70 #undef LineTo
71 #undef OffsetRgn
72 #undef PaintRgn
73 #undef Polygon
74 #undef ResizePalette
75 #undef SetRectRgn
76 #endif /* HAVE_CARBON_CARBON_H */
78 #include "windef.h"
79 #include "winbase.h"
80 #include "winternl.h"
81 #include "winerror.h"
82 #include "winreg.h"
83 #include "wingdi.h"
84 #include "gdi_private.h"
85 #include "wine/unicode.h"
86 #include "wine/debug.h"
87 #include "wine/list.h"
89 WINE_DEFAULT_DEBUG_CHANNEL(font);
91 #ifdef HAVE_FREETYPE
93 #ifdef HAVE_FT2BUILD_H
94 #include <ft2build.h>
95 #endif
96 #ifdef HAVE_FREETYPE_FREETYPE_H
97 #include <freetype/freetype.h>
98 #endif
99 #ifdef HAVE_FREETYPE_FTGLYPH_H
100 #include <freetype/ftglyph.h>
101 #endif
102 #ifdef HAVE_FREETYPE_TTTABLES_H
103 #include <freetype/tttables.h>
104 #endif
105 #ifdef HAVE_FREETYPE_FTTYPES_H
106 #include <freetype/fttypes.h>
107 #endif
108 #ifdef HAVE_FREETYPE_FTSNAMES_H
109 #include <freetype/ftsnames.h>
110 #else
111 # ifdef HAVE_FREETYPE_FTNAMES_H
112 # include <freetype/ftnames.h>
113 # endif
114 #endif
115 #ifdef HAVE_FREETYPE_TTNAMEID_H
116 #include <freetype/ttnameid.h>
117 #endif
118 #ifdef HAVE_FREETYPE_FTOUTLN_H
119 #include <freetype/ftoutln.h>
120 #endif
121 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
122 #include <freetype/internal/sfnt.h>
123 #endif
124 #ifdef HAVE_FREETYPE_FTTRIGON_H
125 #include <freetype/fttrigon.h>
126 #endif
127 #ifdef HAVE_FREETYPE_FTWINFNT_H
128 #include <freetype/ftwinfnt.h>
129 #endif
130 #ifdef HAVE_FREETYPE_FTMODAPI_H
131 #include <freetype/ftmodapi.h>
132 #endif
134 #ifndef HAVE_FT_TRUETYPEENGINETYPE
135 typedef enum
137 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
138 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
139 FT_TRUETYPE_ENGINE_TYPE_PATENTED
140 } FT_TrueTypeEngineType;
141 #endif
143 static FT_Library library = 0;
144 typedef struct
146 FT_Int major;
147 FT_Int minor;
148 FT_Int patch;
149 } FT_Version_t;
150 static FT_Version_t FT_Version;
151 static DWORD FT_SimpleVersion;
153 static void *ft_handle = NULL;
155 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
156 MAKE_FUNCPTR(FT_Vector_Unit);
157 MAKE_FUNCPTR(FT_Done_Face);
158 MAKE_FUNCPTR(FT_Get_Char_Index);
159 MAKE_FUNCPTR(FT_Get_Module);
160 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
161 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
163 MAKE_FUNCPTR(FT_Init_FreeType);
164 MAKE_FUNCPTR(FT_Load_Glyph);
165 MAKE_FUNCPTR(FT_Matrix_Multiply);
166 MAKE_FUNCPTR(FT_MulFix);
167 MAKE_FUNCPTR(FT_New_Face);
168 MAKE_FUNCPTR(FT_New_Memory_Face);
169 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
170 MAKE_FUNCPTR(FT_Outline_Transform);
171 MAKE_FUNCPTR(FT_Outline_Translate);
172 MAKE_FUNCPTR(FT_Select_Charmap);
173 MAKE_FUNCPTR(FT_Set_Charmap);
174 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
175 MAKE_FUNCPTR(FT_Vector_Transform);
176 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
177 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
178 static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*);
179 static FT_ULong (*pFT_Get_Next_Char)(FT_Face,FT_ULong,FT_UInt*);
180 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
181 #ifdef HAVE_FREETYPE_FTWINFNT_H
182 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
183 #endif
185 #ifdef SONAME_LIBFONTCONFIG
186 #include <fontconfig/fontconfig.h>
187 MAKE_FUNCPTR(FcConfigGetCurrent);
188 MAKE_FUNCPTR(FcFontList);
189 MAKE_FUNCPTR(FcFontSetDestroy);
190 MAKE_FUNCPTR(FcInit);
191 MAKE_FUNCPTR(FcObjectSetAdd);
192 MAKE_FUNCPTR(FcObjectSetCreate);
193 MAKE_FUNCPTR(FcObjectSetDestroy);
194 MAKE_FUNCPTR(FcPatternCreate);
195 MAKE_FUNCPTR(FcPatternDestroy);
196 MAKE_FUNCPTR(FcPatternGetBool);
197 MAKE_FUNCPTR(FcPatternGetString);
198 #endif
200 #undef MAKE_FUNCPTR
202 #ifndef FT_MAKE_TAG
203 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
204 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
205 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
206 #endif
208 #ifndef ft_encoding_none
209 #define FT_ENCODING_NONE ft_encoding_none
210 #endif
211 #ifndef ft_encoding_ms_symbol
212 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
213 #endif
214 #ifndef ft_encoding_unicode
215 #define FT_ENCODING_UNICODE ft_encoding_unicode
216 #endif
217 #ifndef ft_encoding_apple_roman
218 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
219 #endif
221 #ifdef WORDS_BIGENDIAN
222 #define GET_BE_WORD(x) (x)
223 #else
224 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
225 #endif
227 /* This is bascially a copy of FT_Bitmap_Size with an extra element added */
228 typedef struct {
229 FT_Short height;
230 FT_Short width;
231 FT_Pos size;
232 FT_Pos x_ppem;
233 FT_Pos y_ppem;
234 FT_Short internal_leading;
235 } Bitmap_Size;
237 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
238 So to let this compile on older versions of FreeType we'll define the
239 new structure here. */
240 typedef struct {
241 FT_Short height, width;
242 FT_Pos size, x_ppem, y_ppem;
243 } My_FT_Bitmap_Size;
245 typedef struct tagFace {
246 struct list entry;
247 WCHAR *StyleName;
248 char *file;
249 void *font_data_ptr;
250 DWORD font_data_size;
251 FT_Long face_index;
252 BOOL Italic;
253 BOOL Bold;
254 FONTSIGNATURE fs;
255 FONTSIGNATURE fs_links;
256 DWORD ntmFlags; /* Only some bits stored here. Others are computed on the fly */
257 FT_Fixed font_version;
258 BOOL scalable;
259 Bitmap_Size size; /* set if face is a bitmap */
260 BOOL external; /* TRUE if we should manually add this font to the registry */
261 struct tagFamily *family;
262 /* Cached data for Enum */
263 BOOL cache_valid;
264 ENUMLOGFONTEXW elf;
265 NEWTEXTMETRICEXW ntm;
266 DWORD type;
267 } Face;
269 typedef struct tagFamily {
270 struct list entry;
271 const WCHAR *FamilyName;
272 struct list faces;
273 } Family;
275 typedef struct {
276 GLYPHMETRICS gm;
277 INT adv; /* These three hold to widths of the unrotated chars */
278 INT lsb;
279 INT bbx;
280 BOOL init;
281 } GM;
283 typedef struct {
284 FLOAT eM11, eM12;
285 FLOAT eM21, eM22;
286 } FMAT2;
288 typedef struct {
289 DWORD hash;
290 LOGFONTW lf;
291 FMAT2 matrix;
292 BOOL can_use_bitmap;
293 } FONT_DESC;
295 typedef struct tagHFONTLIST {
296 struct list entry;
297 HFONT hfont;
298 } HFONTLIST;
300 typedef struct {
301 struct list entry;
302 Face *face;
303 GdiFont *font;
304 } CHILD_FONT;
306 struct tagGdiFont {
307 struct list entry;
308 FT_Face ft_face;
309 struct font_mapping *mapping;
310 LPWSTR name;
311 int charset;
312 int codepage;
313 BOOL fake_italic;
314 BOOL fake_bold;
315 BYTE underline;
316 BYTE strikeout;
317 INT orientation;
318 GM **gm;
319 DWORD gmsize;
320 struct list hfontlist;
321 FONT_DESC font_desc;
322 LONG aveWidth, ppem;
323 float scale_x, scale_y;
324 SHORT yMax;
325 SHORT yMin;
326 OUTLINETEXTMETRICW *potm;
327 DWORD ntmFlags;
328 DWORD total_kern_pairs;
329 KERNINGPAIR *kern_pairs;
330 FONTSIGNATURE fs;
331 GdiFont *base_font;
332 struct list child_fonts;
335 typedef struct {
336 struct list entry;
337 const WCHAR *font_name;
338 struct list links;
339 } SYSTEM_LINKS;
341 #define GM_BLOCK_SIZE 128
342 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
344 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
345 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
346 #define UNUSED_CACHE_SIZE 10
347 static struct list child_font_list = LIST_INIT(child_font_list);
348 static struct list system_links = LIST_INIT(system_links);
350 static struct list font_subst_list = LIST_INIT(font_subst_list);
352 static struct list font_list = LIST_INIT(font_list);
354 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
355 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
356 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
358 static const WCHAR RegularW[] = {'R','e','g','u','l','a','r','\0'};
360 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
361 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
362 'W','i','n','d','o','w','s','\\',
363 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
364 'F','o','n','t','s','\0'};
366 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
367 'W','i','n','d','o','w','s',' ','N','T','\\',
368 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
369 'F','o','n','t','s','\0'};
371 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
372 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
373 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
374 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
376 static const WCHAR * const SystemFontValues[4] = {
377 System_Value,
378 OEMFont_Value,
379 FixedSys_Value,
380 NULL
383 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
384 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
386 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
387 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
388 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
389 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
390 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
391 'E','u','r','o','p','e','a','n','\0'};
392 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
393 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
394 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
395 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
396 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
397 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
398 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
399 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
400 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
401 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
402 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
403 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
405 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
406 WesternW, /*00*/
407 Central_EuropeanW,
408 CyrillicW,
409 GreekW,
410 TurkishW,
411 HebrewW,
412 ArabicW,
413 BalticW,
414 VietnameseW, /*08*/
415 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
416 ThaiW,
417 JapaneseW,
418 CHINESE_GB2312W,
419 HangulW,
420 CHINESE_BIG5W,
421 Hangul_Johab_W,
422 NULL, NULL, /*23*/
423 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
424 SymbolW /*31*/
427 typedef struct {
428 WCHAR *name;
429 INT charset;
430 } NameCs;
432 typedef struct tagFontSubst {
433 struct list entry;
434 NameCs from;
435 NameCs to;
436 } FontSubst;
438 struct font_mapping
440 struct list entry;
441 int refcount;
442 dev_t dev;
443 ino_t ino;
444 void *data;
445 size_t size;
448 static struct list mappings_list = LIST_INIT( mappings_list );
450 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
452 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
454 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
456 /****************************************
457 * Notes on .fon files
459 * The fonts System, FixedSys and Terminal are special. There are typically multiple
460 * versions installed for different resolutions and codepages. Windows stores which one to use
461 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
462 * Key Meaning
463 * FIXEDFON.FON FixedSys
464 * FONTS.FON System
465 * OEMFONT.FON Terminal
466 * LogPixels Current dpi set by the display control panel applet
467 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
468 * also has a LogPixels value that appears to mirror this)
470 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
471 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
472 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
473 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
474 * so that makes sense.
476 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
477 * to be mapped into the registry on Windows 2000 at least).
478 * I have
479 * woafont=app850.fon
480 * ega80woa.fon=ega80850.fon
481 * ega40woa.fon=ega40850.fon
482 * cga80woa.fon=cga80850.fon
483 * cga40woa.fon=cga40850.fon
486 #ifdef HAVE_CARBON_CARBON_H
487 static char *find_cache_dir(void)
489 FSRef ref;
490 OSErr err;
491 static char cached_path[MAX_PATH];
492 static const char *wine = "/Wine", *fonts = "/Fonts";
494 if(*cached_path) return cached_path;
496 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
497 if(err != noErr)
499 WARN("can't create cached data folder\n");
500 return NULL;
502 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
503 if(err != noErr)
505 WARN("can't create cached data path\n");
506 *cached_path = '\0';
507 return NULL;
509 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
511 ERR("Could not create full path\n");
512 *cached_path = '\0';
513 return NULL;
515 strcat(cached_path, wine);
517 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
519 WARN("Couldn't mkdir %s\n", cached_path);
520 *cached_path = '\0';
521 return NULL;
523 strcat(cached_path, fonts);
524 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
526 WARN("Couldn't mkdir %s\n", cached_path);
527 *cached_path = '\0';
528 return NULL;
530 return cached_path;
533 /******************************************************************
534 * expand_mac_font
536 * Extracts individual TrueType font files from a Mac suitcase font
537 * and saves them into the user's caches directory (see
538 * find_cache_dir()).
539 * Returns a NULL terminated array of filenames.
541 * We do this because they are apps that try to read ttf files
542 * themselves and they don't like Mac suitcase files.
544 static char **expand_mac_font(const char *path)
546 FSRef ref;
547 SInt16 res_ref;
548 OSStatus s;
549 unsigned int idx;
550 const char *out_dir;
551 const char *filename;
552 int output_len;
553 struct {
554 char **array;
555 unsigned int size, max_size;
556 } ret;
558 TRACE("path %s\n", path);
560 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
561 if(s != noErr)
563 WARN("failed to get ref\n");
564 return NULL;
567 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
568 if(s != noErr)
570 TRACE("no data fork, so trying resource fork\n");
571 res_ref = FSOpenResFile(&ref, fsRdPerm);
572 if(res_ref == -1)
574 TRACE("unable to open resource fork\n");
575 return NULL;
579 ret.size = 0;
580 ret.max_size = 10;
581 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
582 if(!ret.array)
584 CloseResFile(res_ref);
585 return NULL;
588 out_dir = find_cache_dir();
590 filename = strrchr(path, '/');
591 if(!filename) filename = path;
592 else filename++;
594 /* output filename has the form out_dir/filename_%04x.ttf */
595 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
597 UseResFile(res_ref);
598 idx = 1;
599 while(1)
601 FamRec *fam_rec;
602 unsigned short *num_faces_ptr, num_faces, face;
603 AsscEntry *assoc;
604 Handle fond;
605 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
607 fond = Get1IndResource(fond_res, idx);
608 if(!fond) break;
609 TRACE("got fond resource %d\n", idx);
610 HLock(fond);
612 fam_rec = *(FamRec**)fond;
613 num_faces_ptr = (unsigned short *)(fam_rec + 1);
614 num_faces = GET_BE_WORD(*num_faces_ptr);
615 num_faces++;
616 assoc = (AsscEntry*)(num_faces_ptr + 1);
617 TRACE("num faces %04x\n", num_faces);
618 for(face = 0; face < num_faces; face++, assoc++)
620 Handle sfnt;
621 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
622 unsigned short size, font_id;
623 char *output;
625 size = GET_BE_WORD(assoc->fontSize);
626 font_id = GET_BE_WORD(assoc->fontID);
627 if(size != 0)
629 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
630 continue;
633 TRACE("trying to load sfnt id %04x\n", font_id);
634 sfnt = GetResource(sfnt_res, font_id);
635 if(!sfnt)
637 TRACE("can't get sfnt resource %04x\n", font_id);
638 continue;
641 output = HeapAlloc(GetProcessHeap(), 0, output_len);
642 if(output)
644 int fd;
646 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
648 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
649 if(fd != -1 || errno == EEXIST)
651 if(fd != -1)
653 unsigned char *sfnt_data;
655 HLock(sfnt);
656 sfnt_data = *(unsigned char**)sfnt;
657 write(fd, sfnt_data, GetHandleSize(sfnt));
658 HUnlock(sfnt);
659 close(fd);
661 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
663 ret.max_size *= 2;
664 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
666 ret.array[ret.size++] = output;
668 else
670 WARN("unable to create %s\n", output);
671 HeapFree(GetProcessHeap(), 0, output);
674 ReleaseResource(sfnt);
676 HUnlock(fond);
677 ReleaseResource(fond);
678 idx++;
680 CloseResFile(res_ref);
682 return ret.array;
685 #endif /* HAVE_CARBON_CARBON_H */
687 static inline BOOL is_win9x(void)
689 return GetVersion() & 0x80000000;
692 This function builds an FT_Fixed from a float. It puts the integer part
693 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
694 It fails if the integer part of the float number is greater than SHORT_MAX.
696 static inline FT_Fixed FT_FixedFromFloat(float f)
698 short value = f;
699 unsigned short fract = (f - value) * 0xFFFF;
700 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
704 This function builds an FT_Fixed from a FIXED. It simply put f.value
705 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
707 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
709 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
713 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
715 Family *family;
716 Face *face;
717 const char *file;
718 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
719 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
721 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
722 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
724 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
726 if(face_name && strcmpiW(face_name, family->FamilyName))
727 continue;
728 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
730 if (!face->file)
731 continue;
732 file = strrchr(face->file, '/');
733 if(!file)
734 file = face->file;
735 else
736 file++;
737 if(!strcasecmp(file, file_nameA))
739 HeapFree(GetProcessHeap(), 0, file_nameA);
740 return face;
744 HeapFree(GetProcessHeap(), 0, file_nameA);
745 return NULL;
748 static Family *find_family_from_name(const WCHAR *name)
750 Family *family;
752 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
754 if(!strcmpiW(family->FamilyName, name))
755 return family;
758 return NULL;
761 static void DumpSubstList(void)
763 FontSubst *psub;
765 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
767 if(psub->from.charset != -1 || psub->to.charset != -1)
768 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
769 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
770 else
771 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
772 debugstr_w(psub->to.name));
774 return;
777 static LPWSTR strdupW(LPCWSTR p)
779 LPWSTR ret;
780 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
781 ret = HeapAlloc(GetProcessHeap(), 0, len);
782 memcpy(ret, p, len);
783 return ret;
786 static LPSTR strdupA(LPCSTR p)
788 LPSTR ret;
789 DWORD len = (strlen(p) + 1);
790 ret = HeapAlloc(GetProcessHeap(), 0, len);
791 memcpy(ret, p, len);
792 return ret;
795 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
796 INT from_charset)
798 FontSubst *element;
800 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
802 if(!strcmpiW(element->from.name, from_name) &&
803 (element->from.charset == from_charset ||
804 element->from.charset == -1))
805 return element;
808 return NULL;
811 #define ADD_FONT_SUBST_FORCE 1
813 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
815 FontSubst *from_exist, *to_exist;
817 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
819 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
821 list_remove(&from_exist->entry);
822 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
823 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
824 HeapFree(GetProcessHeap(), 0, from_exist);
825 from_exist = NULL;
828 if(!from_exist)
830 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
832 if(to_exist)
834 HeapFree(GetProcessHeap(), 0, subst->to.name);
835 subst->to.name = strdupW(to_exist->to.name);
838 list_add_tail(subst_list, &subst->entry);
840 return TRUE;
843 HeapFree(GetProcessHeap(), 0, subst->from.name);
844 HeapFree(GetProcessHeap(), 0, subst->to.name);
845 HeapFree(GetProcessHeap(), 0, subst);
846 return FALSE;
849 static void split_subst_info(NameCs *nc, LPSTR str)
851 CHAR *p = strrchr(str, ',');
852 DWORD len;
854 nc->charset = -1;
855 if(p && *(p+1)) {
856 nc->charset = strtol(p+1, NULL, 10);
857 *p = '\0';
859 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
860 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
861 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
864 static void LoadSubstList(void)
866 FontSubst *psub;
867 HKEY hkey;
868 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
869 LPSTR value;
870 LPVOID data;
872 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
873 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
874 &hkey) == ERROR_SUCCESS) {
876 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
877 &valuelen, &datalen, NULL, NULL);
879 valuelen++; /* returned value doesn't include room for '\0' */
880 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
881 data = HeapAlloc(GetProcessHeap(), 0, datalen);
883 dlen = datalen;
884 vlen = valuelen;
885 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
886 &dlen) == ERROR_SUCCESS) {
887 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
889 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
890 split_subst_info(&psub->from, value);
891 split_subst_info(&psub->to, data);
893 /* Win 2000 doesn't allow mapping between different charsets
894 or mapping of DEFAULT_CHARSET */
895 if((psub->to.charset != psub->from.charset) ||
896 psub->to.charset == DEFAULT_CHARSET) {
897 HeapFree(GetProcessHeap(), 0, psub->to.name);
898 HeapFree(GetProcessHeap(), 0, psub->from.name);
899 HeapFree(GetProcessHeap(), 0, psub);
900 } else {
901 add_font_subst(&font_subst_list, psub, 0);
903 /* reset dlen and vlen */
904 dlen = datalen;
905 vlen = valuelen;
907 HeapFree(GetProcessHeap(), 0, data);
908 HeapFree(GetProcessHeap(), 0, value);
909 RegCloseKey(hkey);
913 static WCHAR *get_familyname(FT_Face ft_face)
915 WCHAR *family = NULL;
916 FT_SfntName name;
917 FT_UInt num_names, name_index, i;
919 if(FT_IS_SFNT(ft_face))
921 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
923 for(name_index = 0; name_index < num_names; name_index++)
925 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
927 if((name.name_id == TT_NAME_ID_FONT_FAMILY) &&
928 (name.language_id == GetUserDefaultLCID()) &&
929 (name.platform_id == TT_PLATFORM_MICROSOFT) &&
930 (name.encoding_id == TT_MS_ID_UNICODE_CS))
932 /* String is not nul terminated and string_len is a byte length. */
933 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
934 for(i = 0; i < name.string_len / 2; i++)
936 WORD *tmp = (WORD *)&name.string[i * 2];
937 family[i] = GET_BE_WORD(*tmp);
939 family[i] = 0;
941 TRACE("Got localised name %s\n", debugstr_w(family));
942 return family;
948 return NULL;
952 /*****************************************************************
953 * load_sfnt_table
955 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
956 * of FreeType that don't export this function.
959 static FT_Error load_sfnt_table(FT_Face ft_face, FT_ULong table, FT_Long offset, FT_Byte *buf, FT_ULong *len)
962 FT_Error err;
964 /* If the FT_Load_Sfnt_Table function is there we'll use it */
965 if(pFT_Load_Sfnt_Table)
967 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, len);
969 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
970 else /* Do it the hard way */
972 TT_Face tt_face = (TT_Face) ft_face;
973 SFNT_Interface *sfnt;
974 if (FT_Version.major==2 && FT_Version.minor==0)
976 /* 2.0.x */
977 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
979 else
981 /* A field was added in the middle of the structure in 2.1.x */
982 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
984 err = sfnt->load_any(tt_face, table, offset, buf, len);
986 #else
987 else
989 static int msg;
990 if(!msg)
992 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
993 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
994 "Please upgrade your freetype library.\n");
995 msg++;
997 err = FT_Err_Unimplemented_Feature;
999 #endif
1000 return err;
1004 #define ADDFONT_EXTERNAL_FONT 0x01
1005 #define ADDFONT_FORCE_BITMAP 0x02
1006 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1008 FT_Face ft_face;
1009 TT_OS2 *pOS2;
1010 TT_Header *pHeader = NULL;
1011 WCHAR *english_family, *localised_family, *StyleW;
1012 DWORD len;
1013 Family *family;
1014 Face *face;
1015 struct list *family_elem_ptr, *face_elem_ptr;
1016 FT_Error err;
1017 FT_Long face_index = 0, num_faces;
1018 #ifdef HAVE_FREETYPE_FTWINFNT_H
1019 FT_WinFNT_HeaderRec winfnt_header;
1020 #endif
1021 int i, bitmap_num, internal_leading;
1022 FONTSIGNATURE fs;
1024 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1025 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1027 #ifdef HAVE_CARBON_CARBON_H
1028 if(file && !fake_family)
1030 char **mac_list = expand_mac_font(file);
1031 if(mac_list)
1033 BOOL had_one = FALSE;
1034 char **cursor;
1035 for(cursor = mac_list; *cursor; cursor++)
1037 had_one = TRUE;
1038 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1039 HeapFree(GetProcessHeap(), 0, *cursor);
1041 HeapFree(GetProcessHeap(), 0, mac_list);
1042 if(had_one)
1043 return 1;
1046 #endif /* HAVE_CARBON_CARBON_H */
1048 do {
1049 char *family_name = fake_family;
1051 if (file)
1053 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1054 err = pFT_New_Face(library, file, face_index, &ft_face);
1055 } else
1057 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1058 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1061 if(err != 0) {
1062 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1063 return 0;
1066 if(!FT_IS_SFNT(ft_face) && (FT_IS_SCALABLE(ft_face) || !(flags & ADDFONT_FORCE_BITMAP))) { /* for now we'll accept TT/OT or bitmap fonts*/
1067 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1068 pFT_Done_Face(ft_face);
1069 return 0;
1072 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1073 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1074 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1075 pFT_Done_Face(ft_face);
1076 return 0;
1079 if(FT_IS_SFNT(ft_face))
1081 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1082 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1083 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1085 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1086 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1087 pFT_Done_Face(ft_face);
1088 return 0;
1091 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1092 we don't want to load these. */
1093 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1095 FT_ULong len = 0;
1097 if(!load_sfnt_table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1099 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1100 pFT_Done_Face(ft_face);
1101 return 0;
1106 if(!ft_face->family_name || !ft_face->style_name) {
1107 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1108 pFT_Done_Face(ft_face);
1109 return 0;
1112 if (target_family)
1114 localised_family = get_familyname(ft_face);
1115 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1117 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1118 HeapFree(GetProcessHeap(), 0, localised_family);
1119 num_faces = ft_face->num_faces;
1120 pFT_Done_Face(ft_face);
1121 continue;
1123 HeapFree(GetProcessHeap(), 0, localised_family);
1126 if(!family_name)
1127 family_name = ft_face->family_name;
1129 bitmap_num = 0;
1130 do {
1131 My_FT_Bitmap_Size *size = NULL;
1132 FT_ULong tmp_size;
1134 if(!FT_IS_SCALABLE(ft_face))
1135 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1137 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1138 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1139 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1141 localised_family = NULL;
1142 if(!fake_family) {
1143 localised_family = get_familyname(ft_face);
1144 if(localised_family && !strcmpW(localised_family, english_family)) {
1145 HeapFree(GetProcessHeap(), 0, localised_family);
1146 localised_family = NULL;
1150 family = NULL;
1151 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1152 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1153 if(!strcmpW(family->FamilyName, localised_family ? localised_family : english_family))
1154 break;
1155 family = NULL;
1157 if(!family) {
1158 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1159 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1160 list_init(&family->faces);
1161 list_add_tail(&font_list, &family->entry);
1163 if(localised_family) {
1164 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1165 subst->from.name = strdupW(english_family);
1166 subst->from.charset = -1;
1167 subst->to.name = strdupW(localised_family);
1168 subst->to.charset = -1;
1169 add_font_subst(&font_subst_list, subst, 0);
1172 HeapFree(GetProcessHeap(), 0, localised_family);
1173 HeapFree(GetProcessHeap(), 0, english_family);
1175 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1176 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1177 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1179 internal_leading = 0;
1180 memset(&fs, 0, sizeof(fs));
1182 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1183 if(pOS2) {
1184 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1185 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1186 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1187 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1188 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1189 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1190 if(pOS2->version == 0) {
1191 FT_UInt dummy;
1193 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1194 fs.fsCsb[0] |= 1;
1195 else
1196 fs.fsCsb[0] |= 1L << 31;
1199 #ifdef HAVE_FREETYPE_FTWINFNT_H
1200 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1201 CHARSETINFO csi;
1202 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1203 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1204 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1205 memcpy(&fs, &csi.fs, sizeof(csi.fs));
1206 internal_leading = winfnt_header.internal_leading;
1208 #endif
1210 face_elem_ptr = list_head(&family->faces);
1211 while(face_elem_ptr) {
1212 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1213 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1214 if(!strcmpW(face->StyleName, StyleW) &&
1215 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1216 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1217 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1218 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1220 if(fake_family) {
1221 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1222 HeapFree(GetProcessHeap(), 0, StyleW);
1223 pFT_Done_Face(ft_face);
1224 return 1;
1226 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1227 TRACE("Original font is newer so skipping this one\n");
1228 HeapFree(GetProcessHeap(), 0, StyleW);
1229 pFT_Done_Face(ft_face);
1230 return 1;
1231 } else {
1232 TRACE("Replacing original with this one\n");
1233 list_remove(&face->entry);
1234 HeapFree(GetProcessHeap(), 0, face->file);
1235 HeapFree(GetProcessHeap(), 0, face->StyleName);
1236 HeapFree(GetProcessHeap(), 0, face);
1237 break;
1241 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1242 face->cache_valid = FALSE;
1243 list_add_tail(&family->faces, &face->entry);
1244 face->StyleName = StyleW;
1245 if (file)
1247 face->file = strdupA(file);
1248 face->font_data_ptr = NULL;
1249 face->font_data_size = 0;
1251 else
1253 face->file = NULL;
1254 face->font_data_ptr = font_data_ptr;
1255 face->font_data_size = font_data_size;
1257 face->face_index = face_index;
1258 face->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
1259 face->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
1260 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1261 face->family = family;
1262 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1263 memcpy(&face->fs, &fs, sizeof(face->fs));
1264 memset(&face->fs_links, 0, sizeof(face->fs_links));
1266 if(FT_IS_SCALABLE(ft_face)) {
1267 memset(&face->size, 0, sizeof(face->size));
1268 face->scalable = TRUE;
1269 } else {
1270 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1271 size->height, size->width, size->size >> 6,
1272 size->x_ppem >> 6, size->y_ppem >> 6);
1273 face->size.height = size->height;
1274 face->size.width = size->width;
1275 face->size.size = size->size;
1276 face->size.x_ppem = size->x_ppem;
1277 face->size.y_ppem = size->y_ppem;
1278 face->size.internal_leading = internal_leading;
1279 face->scalable = FALSE;
1282 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1283 tmp_size = 0;
1284 if (pFT_Load_Sfnt_Table && !pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1286 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1287 face->ntmFlags = NTM_PS_OPENTYPE;
1289 else
1290 face->ntmFlags = 0;
1292 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1293 face->fs.fsCsb[0], face->fs.fsCsb[1],
1294 face->fs.fsUsb[0], face->fs.fsUsb[1],
1295 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1298 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1299 for(i = 0; i < ft_face->num_charmaps; i++) {
1300 switch(ft_face->charmaps[i]->encoding) {
1301 case FT_ENCODING_UNICODE:
1302 case FT_ENCODING_APPLE_ROMAN:
1303 face->fs.fsCsb[0] |= 1;
1304 break;
1305 case FT_ENCODING_MS_SYMBOL:
1306 face->fs.fsCsb[0] |= 1L << 31;
1307 break;
1308 default:
1309 break;
1314 if(face->fs.fsCsb[0] & ~(1L << 31))
1315 have_installed_roman_font = TRUE;
1316 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1318 num_faces = ft_face->num_faces;
1319 pFT_Done_Face(ft_face);
1320 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1321 debugstr_w(StyleW));
1322 } while(num_faces > ++face_index);
1323 return num_faces;
1326 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1328 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1331 static void DumpFontList(void)
1333 Family *family;
1334 Face *face;
1335 struct list *family_elem_ptr, *face_elem_ptr;
1337 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1338 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1339 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1340 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1341 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1342 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1343 if(!face->scalable)
1344 TRACE(" %d", face->size.height);
1345 TRACE("\n");
1348 return;
1351 /***********************************************************
1352 * The replacement list is a way to map an entire font
1353 * family onto another family. For example adding
1355 * [HKCU\Software\Wine\Fonts\Replacements]
1356 * "Wingdings"="Winedings"
1358 * would enumerate the Winedings font both as Winedings and
1359 * Wingdings. However if a real Wingdings font is present the
1360 * replacement does not take place.
1363 static void LoadReplaceList(void)
1365 HKEY hkey;
1366 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1367 LPWSTR value;
1368 LPVOID data;
1369 Family *family;
1370 Face *face;
1371 struct list *family_elem_ptr, *face_elem_ptr;
1372 CHAR familyA[400];
1374 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1375 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1377 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1378 &valuelen, &datalen, NULL, NULL);
1380 valuelen++; /* returned value doesn't include room for '\0' */
1381 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1382 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1384 dlen = datalen;
1385 vlen = valuelen;
1386 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1387 &dlen) == ERROR_SUCCESS) {
1388 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1389 /* "NewName"="Oldname" */
1390 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1392 /* Find the old family and hence all of the font files
1393 in that family */
1394 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1395 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1396 if(!strcmpiW(family->FamilyName, data)) {
1397 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1398 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1399 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1400 debugstr_w(face->StyleName), familyA);
1401 /* Now add a new entry with the new family name */
1402 AddFontToList(face->file, face->font_data_ptr, face->font_data_size, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1404 break;
1407 /* reset dlen and vlen */
1408 dlen = datalen;
1409 vlen = valuelen;
1411 HeapFree(GetProcessHeap(), 0, data);
1412 HeapFree(GetProcessHeap(), 0, value);
1413 RegCloseKey(hkey);
1417 /*************************************************************
1418 * init_system_links
1420 static BOOL init_system_links(void)
1422 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1423 'W','i','n','d','o','w','s',' ','N','T','\\',
1424 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1425 'S','y','s','t','e','m','L','i','n','k',0};
1426 HKEY hkey;
1427 BOOL ret = FALSE;
1428 DWORD type, max_val, max_data, val_len, data_len, index;
1429 WCHAR *value, *data;
1430 WCHAR *entry, *next;
1431 SYSTEM_LINKS *font_link, *system_font_link;
1432 CHILD_FONT *child_font;
1433 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
1434 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1435 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1436 FONTSIGNATURE fs;
1437 Family *family;
1438 Face *face;
1439 FontSubst *psub;
1441 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1443 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1444 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1445 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1446 val_len = max_val + 1;
1447 data_len = max_data;
1448 index = 0;
1449 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1451 TRACE("%s:\n", debugstr_w(value));
1453 memset(&fs, 0, sizeof(fs));
1454 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1455 psub = get_font_subst(&font_subst_list, value, -1);
1456 font_link->font_name = (psub)? strdupW(psub->to.name) : strdupW(value);
1457 list_init(&font_link->links);
1458 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1460 WCHAR *face_name;
1461 CHILD_FONT *child_font;
1463 TRACE("\t%s\n", debugstr_w(entry));
1465 next = entry + strlenW(entry) + 1;
1467 face_name = strchrW(entry, ',');
1468 if(face_name)
1470 *face_name++ = 0;
1471 while(isspaceW(*face_name))
1472 face_name++;
1474 psub = get_font_subst(&font_subst_list, face_name, -1);
1475 if(psub)
1476 face_name = psub->to.name;
1478 face = find_face_from_filename(entry, face_name);
1479 if(!face)
1481 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1482 continue;
1485 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1486 child_font->face = face;
1487 child_font->font = NULL;
1488 fs.fsCsb[0] |= face->fs.fsCsb[0];
1489 fs.fsCsb[1] |= face->fs.fsCsb[1];
1490 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1491 list_add_tail(&font_link->links, &child_font->entry);
1493 family = find_family_from_name(font_link->font_name);
1494 if(family)
1496 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1498 memcpy(&face->fs_links, &fs, sizeof(fs));
1501 list_add_tail(&system_links, &font_link->entry);
1502 val_len = max_val + 1;
1503 data_len = max_data;
1506 HeapFree(GetProcessHeap(), 0, value);
1507 HeapFree(GetProcessHeap(), 0, data);
1508 RegCloseKey(hkey);
1511 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1512 that Tahoma has */
1514 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1515 system_font_link->font_name = strdupW(System);
1516 list_init(&system_font_link->links);
1518 face = find_face_from_filename(tahoma_ttf, Tahoma);
1519 if(face)
1521 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1522 child_font->face = face;
1523 child_font->font = NULL;
1524 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
1525 list_add_tail(&system_font_link->links, &child_font->entry);
1527 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1529 if(!strcmpiW(font_link->font_name, Tahoma))
1531 CHILD_FONT *font_link_entry;
1532 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1534 CHILD_FONT *new_child;
1535 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1536 new_child->face = font_link_entry->face;
1537 new_child->font = NULL;
1538 list_add_tail(&system_font_link->links, &new_child->entry);
1540 break;
1543 list_add_tail(&system_links, &system_font_link->entry);
1544 return ret;
1547 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1549 DIR *dir;
1550 struct dirent *dent;
1551 char path[MAX_PATH];
1553 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1555 dir = opendir(dirname);
1556 if(!dir) {
1557 WARN("Can't open directory %s\n", debugstr_a(dirname));
1558 return FALSE;
1560 while((dent = readdir(dir)) != NULL) {
1561 struct stat statbuf;
1563 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1564 continue;
1566 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1568 sprintf(path, "%s/%s", dirname, dent->d_name);
1570 if(stat(path, &statbuf) == -1)
1572 WARN("Can't stat %s\n", debugstr_a(path));
1573 continue;
1575 if(S_ISDIR(statbuf.st_mode))
1576 ReadFontDir(path, external_fonts);
1577 else
1578 AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1580 closedir(dir);
1581 return TRUE;
1584 static void load_fontconfig_fonts(void)
1586 #ifdef SONAME_LIBFONTCONFIG
1587 void *fc_handle = NULL;
1588 FcConfig *config;
1589 FcPattern *pat;
1590 FcObjectSet *os;
1591 FcFontSet *fontset;
1592 int i, len;
1593 char *file;
1594 const char *ext;
1596 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1597 if(!fc_handle) {
1598 TRACE("Wine cannot find the fontconfig library (%s).\n",
1599 SONAME_LIBFONTCONFIG);
1600 return;
1602 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
1603 LOAD_FUNCPTR(FcConfigGetCurrent);
1604 LOAD_FUNCPTR(FcFontList);
1605 LOAD_FUNCPTR(FcFontSetDestroy);
1606 LOAD_FUNCPTR(FcInit);
1607 LOAD_FUNCPTR(FcObjectSetAdd);
1608 LOAD_FUNCPTR(FcObjectSetCreate);
1609 LOAD_FUNCPTR(FcObjectSetDestroy);
1610 LOAD_FUNCPTR(FcPatternCreate);
1611 LOAD_FUNCPTR(FcPatternDestroy);
1612 LOAD_FUNCPTR(FcPatternGetBool);
1613 LOAD_FUNCPTR(FcPatternGetString);
1614 #undef LOAD_FUNCPTR
1616 if(!pFcInit()) return;
1618 config = pFcConfigGetCurrent();
1619 pat = pFcPatternCreate();
1620 os = pFcObjectSetCreate();
1621 pFcObjectSetAdd(os, FC_FILE);
1622 pFcObjectSetAdd(os, FC_SCALABLE);
1623 fontset = pFcFontList(config, pat, os);
1624 if(!fontset) return;
1625 for(i = 0; i < fontset->nfont; i++) {
1626 FcBool scalable;
1628 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1629 continue;
1630 TRACE("fontconfig: %s\n", file);
1632 /* We're just interested in OT/TT fonts for now, so this hack just
1633 picks up the scalable fonts without extensions .pf[ab] to save time
1634 loading every other font */
1636 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1638 TRACE("not scalable\n");
1639 continue;
1642 len = strlen( file );
1643 if(len < 4) continue;
1644 ext = &file[ len - 3 ];
1645 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1646 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT);
1648 pFcFontSetDestroy(fontset);
1649 pFcObjectSetDestroy(os);
1650 pFcPatternDestroy(pat);
1651 sym_not_found:
1652 #endif
1653 return;
1656 static BOOL load_font_from_data_dir(LPCWSTR file)
1658 BOOL ret = FALSE;
1659 const char *data_dir = wine_get_data_dir();
1661 if (!data_dir) data_dir = wine_get_build_dir();
1663 if (data_dir)
1665 INT len;
1666 char *unix_name;
1668 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1670 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1672 strcpy(unix_name, data_dir);
1673 strcat(unix_name, "/fonts/");
1675 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1677 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1678 HeapFree(GetProcessHeap(), 0, unix_name);
1680 return ret;
1683 static void load_system_fonts(void)
1685 HKEY hkey;
1686 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1687 const WCHAR * const *value;
1688 DWORD dlen, type;
1689 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1690 char *unixname;
1692 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1693 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1694 strcatW(windowsdir, fontsW);
1695 for(value = SystemFontValues; *value; value++) {
1696 dlen = sizeof(data);
1697 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1698 type == REG_SZ) {
1699 BOOL added = FALSE;
1701 sprintfW(pathW, fmtW, windowsdir, data);
1702 if((unixname = wine_get_unix_file_name(pathW))) {
1703 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1704 HeapFree(GetProcessHeap(), 0, unixname);
1706 if (!added)
1707 load_font_from_data_dir(data);
1710 RegCloseKey(hkey);
1714 /*************************************************************
1716 * This adds registry entries for any externally loaded fonts
1717 * (fonts from fontconfig or FontDirs). It also deletes entries
1718 * of no longer existing fonts.
1721 static void update_reg_entries(void)
1723 HKEY winkey = 0, externalkey = 0;
1724 LPWSTR valueW;
1725 LPVOID data;
1726 DWORD dlen, vlen, datalen, valuelen, i, type, len, len_fam;
1727 Family *family;
1728 Face *face;
1729 struct list *family_elem_ptr, *face_elem_ptr;
1730 WCHAR *file;
1731 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1732 static const WCHAR spaceW[] = {' ', '\0'};
1733 char *path;
1735 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1736 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winkey, NULL) != ERROR_SUCCESS) {
1737 ERR("Can't create Windows font reg key\n");
1738 goto end;
1740 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1741 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &externalkey) != ERROR_SUCCESS) {
1742 ERR("Can't create external font reg key\n");
1743 goto end;
1746 /* Delete all external fonts added last time */
1748 RegQueryInfoKeyW(externalkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1749 &valuelen, &datalen, NULL, NULL);
1750 valuelen++; /* returned value doesn't include room for '\0' */
1751 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1752 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1754 dlen = datalen * sizeof(WCHAR);
1755 vlen = valuelen;
1756 i = 0;
1757 while(RegEnumValueW(externalkey, i++, valueW, &vlen, NULL, &type, data,
1758 &dlen) == ERROR_SUCCESS) {
1760 RegDeleteValueW(winkey, valueW);
1761 /* reset dlen and vlen */
1762 dlen = datalen;
1763 vlen = valuelen;
1765 HeapFree(GetProcessHeap(), 0, data);
1766 HeapFree(GetProcessHeap(), 0, valueW);
1768 /* Delete the old external fonts key */
1769 RegCloseKey(externalkey);
1770 externalkey = 0;
1771 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
1773 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1774 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1775 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
1776 ERR("Can't create external font reg key\n");
1777 goto end;
1780 /* enumerate the fonts and add external ones to the two keys */
1782 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1783 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1784 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1785 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1786 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1787 if(!face->external) continue;
1788 len = len_fam;
1789 if(strcmpiW(face->StyleName, RegularW))
1790 len = len_fam + strlenW(face->StyleName) + 1;
1791 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1792 strcpyW(valueW, family->FamilyName);
1793 if(len != len_fam) {
1794 strcatW(valueW, spaceW);
1795 strcatW(valueW, face->StyleName);
1797 strcatW(valueW, TrueType);
1798 if((path = strrchr(face->file, '/')) == NULL)
1799 path = face->file;
1800 else
1801 path++;
1802 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1804 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1805 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1806 RegSetValueExW(winkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1807 RegSetValueExW(externalkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1809 HeapFree(GetProcessHeap(), 0, file);
1810 HeapFree(GetProcessHeap(), 0, valueW);
1813 end:
1814 if(externalkey)
1815 RegCloseKey(externalkey);
1816 if(winkey)
1817 RegCloseKey(winkey);
1818 return;
1822 /*************************************************************
1823 * WineEngAddFontResourceEx
1826 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1828 if (ft_handle) /* do it only if we have freetype up and running */
1830 char *unixname;
1832 if(flags)
1833 FIXME("Ignoring flags %x\n", flags);
1835 if((unixname = wine_get_unix_file_name(file)))
1837 INT ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1838 HeapFree(GetProcessHeap(), 0, unixname);
1839 return ret;
1842 return 0;
1845 /*************************************************************
1846 * WineEngAddFontMemResourceEx
1849 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
1851 if (ft_handle) /* do it only if we have freetype up and running */
1853 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
1855 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
1856 memcpy(pFontCopy, pbFont, cbFont);
1858 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
1860 if (*pcFonts == 0)
1862 TRACE("AddFontToList failed\n");
1863 HeapFree(GetProcessHeap(), 0, pFontCopy);
1864 return NULL;
1866 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
1867 * For now return something unique but quite random
1869 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
1870 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
1873 *pcFonts = 0;
1874 return 0;
1877 /*************************************************************
1878 * WineEngRemoveFontResourceEx
1881 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1883 FIXME(":stub\n");
1884 return TRUE;
1887 static const struct nls_update_font_list
1889 UINT ansi_cp, oem_cp;
1890 const char *oem, *fixed, *system;
1891 const char *courier, *serif, *small, *sserif;
1892 /* these are for font substitute */
1893 const char *shelldlg, *tmsrmn;
1894 } nls_update_font_list[] =
1896 /* Latin 1 (United States) */
1897 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
1898 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1899 "Tahoma","Times New Roman",
1901 /* Latin 1 (Multilingual) */
1902 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
1903 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1904 "Tahoma","Times New Roman", /* FIXME unverified */
1906 /* Eastern Europe */
1907 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
1908 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
1909 "Tahoma","Times New Roman", /* FIXME unverified */
1911 /* Cyrillic */
1912 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
1913 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
1914 "Tahoma","Times New Roman", /* FIXME unverified */
1916 /* Greek */
1917 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
1918 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
1919 "Tahoma","Times New Roman", /* FIXME unverified */
1921 /* Turkish */
1922 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
1923 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
1924 "Tahoma","Times New Roman", /* FIXME unverified */
1926 /* Hebrew */
1927 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
1928 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
1929 "Tahoma","Times New Roman", /* FIXME unverified */
1931 /* Arabic */
1932 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
1933 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
1934 "Tahoma","Times New Roman", /* FIXME unverified */
1936 /* Baltic */
1937 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
1938 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
1939 "Tahoma","Times New Roman", /* FIXME unverified */
1941 /* Vietnamese */
1942 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
1943 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1944 "Tahoma","Times New Roman", /* FIXME unverified */
1946 /* Thai */
1947 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
1948 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
1949 "Tahoma","Times New Roman", /* FIXME unverified */
1951 /* Japanese */
1952 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
1953 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
1954 "MS UI Gothic","MS Serif",
1956 /* Chinese Simplified */
1957 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
1958 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1959 "Tahoma", "Times New Roman", /* FIXME unverified */
1961 /* Korean */
1962 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
1963 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1964 "Gulim", "Batang",
1966 /* Chinese Traditional */
1967 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
1968 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1969 "Tahoma", "Times New Roman", /* FIXME unverified */
1973 static inline HKEY create_fonts_NT_registry_key(void)
1975 HKEY hkey = 0;
1977 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
1978 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1979 return hkey;
1982 static inline HKEY create_fonts_9x_registry_key(void)
1984 HKEY hkey = 0;
1986 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
1987 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1988 return hkey;
1991 static inline HKEY create_config_fonts_registry_key(void)
1993 HKEY hkey = 0;
1995 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
1996 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1997 return hkey;
2000 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
2002 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
2003 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
2004 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
2005 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2008 static void update_font_info(void)
2010 char buf[40], cpbuf[40];
2011 DWORD len, type;
2012 HKEY hkey = 0;
2013 UINT i, ansi_cp = 0, oem_cp = 0;
2015 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2016 return;
2018 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2019 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2020 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2021 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2022 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2024 len = sizeof(buf);
2025 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2027 if (!strcmp( buf, cpbuf )) /* already set correctly */
2029 RegCloseKey(hkey);
2030 return;
2032 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2034 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2036 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2037 RegCloseKey(hkey);
2039 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2041 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2042 nls_update_font_list[i].oem_cp == oem_cp)
2044 HKEY hkey;
2046 hkey = create_config_fonts_registry_key();
2047 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2048 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2049 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2050 RegCloseKey(hkey);
2052 hkey = create_fonts_NT_registry_key();
2053 add_font_list(hkey, &nls_update_font_list[i]);
2054 RegCloseKey(hkey);
2056 hkey = create_fonts_9x_registry_key();
2057 add_font_list(hkey, &nls_update_font_list[i]);
2058 RegCloseKey(hkey);
2060 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2062 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2063 strlen(nls_update_font_list[i].shelldlg)+1);
2064 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2065 strlen(nls_update_font_list[i].tmsrmn)+1);
2066 RegCloseKey(hkey);
2068 return;
2071 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2074 /*************************************************************
2075 * WineEngInit
2077 * Initialize FreeType library and create a list of available faces
2079 BOOL WineEngInit(void)
2081 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2082 static const WCHAR pathW[] = {'P','a','t','h',0};
2083 HKEY hkey;
2084 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2085 LPVOID data;
2086 WCHAR windowsdir[MAX_PATH];
2087 char *unixname;
2088 HANDLE font_mutex;
2089 const char *data_dir;
2091 TRACE("\n");
2093 /* update locale dependent font info in registry */
2094 update_font_info();
2096 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2097 if(!ft_handle) {
2098 WINE_MESSAGE(
2099 "Wine cannot find the FreeType font library. To enable Wine to\n"
2100 "use TrueType fonts please install a version of FreeType greater than\n"
2101 "or equal to 2.0.5.\n"
2102 "http://www.freetype.org\n");
2103 return FALSE;
2106 #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;}
2108 LOAD_FUNCPTR(FT_Vector_Unit)
2109 LOAD_FUNCPTR(FT_Done_Face)
2110 LOAD_FUNCPTR(FT_Get_Char_Index)
2111 LOAD_FUNCPTR(FT_Get_Module)
2112 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2113 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2114 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2115 LOAD_FUNCPTR(FT_Init_FreeType)
2116 LOAD_FUNCPTR(FT_Load_Glyph)
2117 LOAD_FUNCPTR(FT_Matrix_Multiply)
2118 LOAD_FUNCPTR(FT_MulFix)
2119 LOAD_FUNCPTR(FT_New_Face)
2120 LOAD_FUNCPTR(FT_New_Memory_Face)
2121 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2122 LOAD_FUNCPTR(FT_Outline_Transform)
2123 LOAD_FUNCPTR(FT_Outline_Translate)
2124 LOAD_FUNCPTR(FT_Select_Charmap)
2125 LOAD_FUNCPTR(FT_Set_Charmap)
2126 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2127 LOAD_FUNCPTR(FT_Vector_Transform)
2129 #undef LOAD_FUNCPTR
2130 /* Don't warn if this one is missing */
2131 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
2132 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
2133 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
2134 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
2135 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2136 #ifdef HAVE_FREETYPE_FTWINFNT_H
2137 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2138 #endif
2139 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2140 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2141 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2142 <= 2.0.3 has FT_Sqrt64 */
2143 goto sym_not_found;
2146 if(pFT_Init_FreeType(&library) != 0) {
2147 ERR("Can't init FreeType library\n");
2148 wine_dlclose(ft_handle, NULL, 0);
2149 ft_handle = NULL;
2150 return FALSE;
2152 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
2153 if (pFT_Library_Version)
2155 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2157 if (FT_Version.major<=0)
2159 FT_Version.major=2;
2160 FT_Version.minor=0;
2161 FT_Version.patch=5;
2163 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2164 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2165 ((FT_Version.minor << 8) & 0x00ff00) |
2166 ((FT_Version.patch ) & 0x0000ff);
2168 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2169 ERR("Failed to create font mutex\n");
2170 return FALSE;
2172 WaitForSingleObject(font_mutex, INFINITE);
2174 /* load the system bitmap fonts */
2175 load_system_fonts();
2177 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2178 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2179 strcatW(windowsdir, fontsW);
2180 if((unixname = wine_get_unix_file_name(windowsdir)))
2182 ReadFontDir(unixname, FALSE);
2183 HeapFree(GetProcessHeap(), 0, unixname);
2186 /* load the system truetype fonts */
2187 data_dir = wine_get_data_dir();
2188 if (!data_dir) data_dir = wine_get_build_dir();
2189 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2190 strcpy(unixname, data_dir);
2191 strcat(unixname, "/fonts/");
2192 ReadFontDir(unixname, TRUE);
2193 HeapFree(GetProcessHeap(), 0, unixname);
2196 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2197 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2198 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2199 will skip these. */
2200 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2201 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2202 &hkey) == ERROR_SUCCESS) {
2203 LPWSTR valueW;
2204 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2205 &valuelen, &datalen, NULL, NULL);
2207 valuelen++; /* returned value doesn't include room for '\0' */
2208 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2209 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2210 if (valueW && data)
2212 dlen = datalen * sizeof(WCHAR);
2213 vlen = valuelen;
2214 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
2215 &dlen) == ERROR_SUCCESS) {
2216 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
2218 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
2220 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2221 HeapFree(GetProcessHeap(), 0, unixname);
2224 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
2226 WCHAR pathW[MAX_PATH];
2227 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2228 BOOL added = FALSE;
2230 sprintfW(pathW, fmtW, windowsdir, data);
2231 if((unixname = wine_get_unix_file_name(pathW)))
2233 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2234 HeapFree(GetProcessHeap(), 0, unixname);
2236 if (!added)
2237 load_font_from_data_dir(data);
2239 /* reset dlen and vlen */
2240 dlen = datalen;
2241 vlen = valuelen;
2244 HeapFree(GetProcessHeap(), 0, data);
2245 HeapFree(GetProcessHeap(), 0, valueW);
2246 RegCloseKey(hkey);
2249 load_fontconfig_fonts();
2251 /* then look in any directories that we've specified in the config file */
2252 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2253 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2255 DWORD len;
2256 LPWSTR valueW;
2257 LPSTR valueA, ptr;
2259 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2261 len += sizeof(WCHAR);
2262 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2263 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2265 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2266 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2267 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2268 TRACE( "got font path %s\n", debugstr_a(valueA) );
2269 ptr = valueA;
2270 while (ptr)
2272 LPSTR next = strchr( ptr, ':' );
2273 if (next) *next++ = 0;
2274 ReadFontDir( ptr, TRUE );
2275 ptr = next;
2277 HeapFree( GetProcessHeap(), 0, valueA );
2279 HeapFree( GetProcessHeap(), 0, valueW );
2281 RegCloseKey(hkey);
2284 DumpFontList();
2285 LoadSubstList();
2286 DumpSubstList();
2287 LoadReplaceList();
2288 update_reg_entries();
2290 init_system_links();
2292 ReleaseMutex(font_mutex);
2293 return TRUE;
2294 sym_not_found:
2295 WINE_MESSAGE(
2296 "Wine cannot find certain functions that it needs inside the FreeType\n"
2297 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2298 "FreeType to at least version 2.0.5.\n"
2299 "http://www.freetype.org\n");
2300 wine_dlclose(ft_handle, NULL, 0);
2301 ft_handle = NULL;
2302 return FALSE;
2306 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2308 TT_OS2 *pOS2;
2309 TT_HoriHeader *pHori;
2311 LONG ppem;
2313 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2314 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2316 if(height == 0) height = 16;
2318 /* Calc. height of EM square:
2320 * For +ve lfHeight we have
2321 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2322 * Re-arranging gives:
2323 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2325 * For -ve lfHeight we have
2326 * |lfHeight| = ppem
2327 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2328 * with il = winAscent + winDescent - units_per_em]
2332 if(height > 0) {
2333 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2334 ppem = ft_face->units_per_EM * height /
2335 (pHori->Ascender - pHori->Descender);
2336 else
2337 ppem = ft_face->units_per_EM * height /
2338 (pOS2->usWinAscent + pOS2->usWinDescent);
2340 else
2341 ppem = -height;
2343 return ppem;
2346 static struct font_mapping *map_font_file( const char *name )
2348 struct font_mapping *mapping;
2349 struct stat st;
2350 int fd;
2352 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2353 if (fstat( fd, &st ) == -1) goto error;
2355 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2357 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2359 mapping->refcount++;
2360 close( fd );
2361 return mapping;
2364 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2365 goto error;
2367 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2368 close( fd );
2370 if (mapping->data == MAP_FAILED)
2372 HeapFree( GetProcessHeap(), 0, mapping );
2373 return NULL;
2375 mapping->refcount = 1;
2376 mapping->dev = st.st_dev;
2377 mapping->ino = st.st_ino;
2378 mapping->size = st.st_size;
2379 list_add_tail( &mappings_list, &mapping->entry );
2380 return mapping;
2382 error:
2383 close( fd );
2384 return NULL;
2387 static void unmap_font_file( struct font_mapping *mapping )
2389 if (!--mapping->refcount)
2391 list_remove( &mapping->entry );
2392 munmap( mapping->data, mapping->size );
2393 HeapFree( GetProcessHeap(), 0, mapping );
2397 static LONG load_VDMX(GdiFont*, LONG);
2399 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
2401 FT_Error err;
2402 FT_Face ft_face;
2403 void *data_ptr;
2404 DWORD data_size;
2406 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
2408 if (face->file)
2410 if (!(font->mapping = map_font_file( face->file )))
2412 WARN("failed to map %s\n", debugstr_a(face->file));
2413 return 0;
2415 data_ptr = font->mapping->data;
2416 data_size = font->mapping->size;
2418 else
2420 data_ptr = face->font_data_ptr;
2421 data_size = face->font_data_size;
2424 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
2425 if(err) {
2426 ERR("FT_New_Face rets %d\n", err);
2427 return 0;
2430 /* set it here, as load_VDMX needs it */
2431 font->ft_face = ft_face;
2433 if(FT_IS_SCALABLE(ft_face)) {
2434 /* load the VDMX table if we have one */
2435 font->ppem = load_VDMX(font, height);
2436 if(font->ppem == 0)
2437 font->ppem = calc_ppem_for_height(ft_face, height);
2439 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
2440 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
2441 } else {
2442 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
2443 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
2445 return ft_face;
2449 static int get_nearest_charset(Face *face, int *cp)
2451 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2452 a single face with the requested charset. The idea is to check if
2453 the selected font supports the current ANSI codepage, if it does
2454 return the corresponding charset, else return the first charset */
2456 CHARSETINFO csi;
2457 int acp = GetACP(), i;
2458 DWORD fs0;
2460 *cp = acp;
2461 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
2462 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2463 return csi.ciCharset;
2465 for(i = 0; i < 32; i++) {
2466 fs0 = 1L << i;
2467 if(face->fs.fsCsb[0] & fs0) {
2468 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
2469 *cp = csi.ciACP;
2470 return csi.ciCharset;
2472 else
2473 FIXME("TCI failing on %x\n", fs0);
2477 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2478 face->fs.fsCsb[0], face->file);
2479 *cp = acp;
2480 return DEFAULT_CHARSET;
2483 static GdiFont *alloc_font(void)
2485 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
2486 ret->gmsize = 1;
2487 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
2488 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
2489 ret->potm = NULL;
2490 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
2491 ret->total_kern_pairs = (DWORD)-1;
2492 ret->kern_pairs = NULL;
2493 list_init(&ret->hfontlist);
2494 list_init(&ret->child_fonts);
2495 return ret;
2498 static void free_font(GdiFont *font)
2500 struct list *cursor, *cursor2;
2501 int i;
2503 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
2505 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
2506 struct list *first_hfont;
2507 HFONTLIST *hfontlist;
2508 list_remove(cursor);
2509 if(child->font)
2511 first_hfont = list_head(&child->font->hfontlist);
2512 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2513 DeleteObject(hfontlist->hfont);
2514 HeapFree(GetProcessHeap(), 0, hfontlist);
2515 free_font(child->font);
2517 HeapFree(GetProcessHeap(), 0, child);
2520 if (font->ft_face) pFT_Done_Face(font->ft_face);
2521 if (font->mapping) unmap_font_file( font->mapping );
2522 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
2523 HeapFree(GetProcessHeap(), 0, font->potm);
2524 HeapFree(GetProcessHeap(), 0, font->name);
2525 for (i = 0; i < font->gmsize; i++)
2526 HeapFree(GetProcessHeap(),0,font->gm[i]);
2527 HeapFree(GetProcessHeap(), 0, font->gm);
2528 HeapFree(GetProcessHeap(), 0, font);
2532 /*************************************************************
2533 * load_VDMX
2535 * load the vdmx entry for the specified height
2538 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2539 ( ( (FT_ULong)_x4 << 24 ) | \
2540 ( (FT_ULong)_x3 << 16 ) | \
2541 ( (FT_ULong)_x2 << 8 ) | \
2542 (FT_ULong)_x1 )
2544 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2546 typedef struct {
2547 BYTE bCharSet;
2548 BYTE xRatio;
2549 BYTE yStartRatio;
2550 BYTE yEndRatio;
2551 } Ratios;
2553 typedef struct {
2554 WORD recs;
2555 BYTE startsz;
2556 BYTE endsz;
2557 } VDMX_group;
2559 static LONG load_VDMX(GdiFont *font, LONG height)
2561 WORD hdr[3], tmp;
2562 VDMX_group group;
2563 BYTE devXRatio, devYRatio;
2564 USHORT numRecs, numRatios;
2565 DWORD result, offset = -1;
2566 LONG ppem = 0;
2567 int i;
2569 /* For documentation on VDMX records, see
2570 * http://www.microsoft.com/OpenType/OTSpec/vdmx.htm
2573 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
2575 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2576 return ppem;
2578 /* FIXME: need the real device aspect ratio */
2579 devXRatio = 1;
2580 devYRatio = 1;
2582 numRecs = GET_BE_WORD(hdr[1]);
2583 numRatios = GET_BE_WORD(hdr[2]);
2585 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
2586 for(i = 0; i < numRatios; i++) {
2587 Ratios ratio;
2589 offset = (3 * 2) + (i * sizeof(Ratios));
2590 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2591 offset = -1;
2593 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2595 if((ratio.xRatio == 0 &&
2596 ratio.yStartRatio == 0 &&
2597 ratio.yEndRatio == 0) ||
2598 (devXRatio == ratio.xRatio &&
2599 devYRatio >= ratio.yStartRatio &&
2600 devYRatio <= ratio.yEndRatio))
2602 offset = (3 * 2) + (numRatios * 4) + (i * 2);
2603 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
2604 offset = GET_BE_WORD(tmp);
2605 break;
2609 if(offset == -1) {
2610 FIXME("No suitable ratio found\n");
2611 return ppem;
2614 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
2615 USHORT recs;
2616 BYTE startsz, endsz;
2617 WORD *vTable;
2619 recs = GET_BE_WORD(group.recs);
2620 startsz = group.startsz;
2621 endsz = group.endsz;
2623 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
2625 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
2626 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
2627 if(result == GDI_ERROR) {
2628 FIXME("Failed to retrieve vTable\n");
2629 goto end;
2632 if(height > 0) {
2633 for(i = 0; i < recs; i++) {
2634 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2635 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2636 ppem = GET_BE_WORD(vTable[i * 3]);
2638 if(yMax + -yMin == height) {
2639 font->yMax = yMax;
2640 font->yMin = yMin;
2641 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2642 break;
2644 if(yMax + -yMin > height) {
2645 if(--i < 0) {
2646 ppem = 0;
2647 goto end; /* failed */
2649 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2650 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2651 ppem = GET_BE_WORD(vTable[i * 3]);
2652 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2653 break;
2656 if(!font->yMax) {
2657 ppem = 0;
2658 TRACE("ppem not found for height %d\n", height);
2660 } else {
2661 ppem = -height;
2662 if(ppem < startsz || ppem > endsz)
2663 goto end;
2665 for(i = 0; i < recs; i++) {
2666 USHORT yPelHeight;
2667 yPelHeight = GET_BE_WORD(vTable[i * 3]);
2669 if(yPelHeight > ppem)
2670 break; /* failed */
2672 if(yPelHeight == ppem) {
2673 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2674 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2675 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
2676 break;
2680 end:
2681 HeapFree(GetProcessHeap(), 0, vTable);
2684 return ppem;
2687 static BOOL fontcmp(GdiFont *font, FONT_DESC *fd)
2689 if(font->font_desc.hash != fd->hash) return TRUE;
2690 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
2691 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
2692 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
2693 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
2696 static void calc_hash(FONT_DESC *pfd)
2698 DWORD hash = 0, *ptr, two_chars;
2699 WORD *pwc;
2700 unsigned int i;
2702 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
2703 hash ^= *ptr;
2704 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
2705 hash ^= *ptr;
2706 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
2707 two_chars = *ptr;
2708 pwc = (WCHAR *)&two_chars;
2709 if(!*pwc) break;
2710 *pwc = toupperW(*pwc);
2711 pwc++;
2712 *pwc = toupperW(*pwc);
2713 hash ^= two_chars;
2714 if(!*pwc) break;
2716 hash ^= !pfd->can_use_bitmap;
2717 pfd->hash = hash;
2718 return;
2721 static GdiFont *find_in_cache(HFONT hfont, LOGFONTW *plf, XFORM *pxf, BOOL can_use_bitmap)
2723 GdiFont *ret;
2724 FONT_DESC fd;
2725 HFONTLIST *hflist;
2726 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2728 memcpy(&fd.lf, plf, sizeof(LOGFONTW));
2729 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
2730 fd.can_use_bitmap = can_use_bitmap;
2731 calc_hash(&fd);
2733 /* try the in-use list */
2734 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
2735 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2736 if(!fontcmp(ret, &fd)) {
2737 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2738 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
2739 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2740 if(hflist->hfont == hfont)
2741 return ret;
2743 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2744 hflist->hfont = hfont;
2745 list_add_head(&ret->hfontlist, &hflist->entry);
2746 return ret;
2750 /* then the unused list */
2751 font_elem_ptr = list_head(&unused_gdi_font_list);
2752 while(font_elem_ptr) {
2753 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2754 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2755 if(!fontcmp(ret, &fd)) {
2756 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2757 assert(list_empty(&ret->hfontlist));
2758 TRACE("Found %p in unused list\n", ret);
2759 list_remove(&ret->entry);
2760 list_add_head(&gdi_font_list, &ret->entry);
2761 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2762 hflist->hfont = hfont;
2763 list_add_head(&ret->hfontlist, &hflist->entry);
2764 return ret;
2767 return NULL;
2771 /*************************************************************
2772 * create_child_font_list
2774 static BOOL create_child_font_list(GdiFont *font)
2776 BOOL ret = FALSE;
2777 SYSTEM_LINKS *font_link;
2778 CHILD_FONT *font_link_entry, *new_child;
2780 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2782 if(!strcmpW(font_link->font_name, font->name))
2784 TRACE("found entry in system list\n");
2785 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2787 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2788 new_child->face = font_link_entry->face;
2789 new_child->font = NULL;
2790 list_add_tail(&font->child_fonts, &new_child->entry);
2791 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
2793 ret = TRUE;
2794 break;
2798 return ret;
2801 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
2803 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
2805 if (pFT_Set_Charmap)
2807 FT_Int i;
2808 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
2810 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
2812 for (i = 0; i < ft_face->num_charmaps; i++)
2814 if (ft_face->charmaps[i]->encoding == encoding)
2816 TRACE("found cmap with platform_id %u, encoding_id %u\n",
2817 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
2819 switch (ft_face->charmaps[i]->platform_id)
2821 default:
2822 cmap_def = ft_face->charmaps[i];
2823 break;
2824 case 0: /* Apple Unicode */
2825 cmap0 = ft_face->charmaps[i];
2826 break;
2827 case 1: /* Macintosh */
2828 cmap1 = ft_face->charmaps[i];
2829 break;
2830 case 2: /* ISO */
2831 cmap2 = ft_face->charmaps[i];
2832 break;
2833 case 3: /* Microsoft */
2834 cmap3 = ft_face->charmaps[i];
2835 break;
2839 if (cmap3) /* prefer Microsoft cmap table */
2840 ft_err = pFT_Set_Charmap(ft_face, cmap3);
2841 else if (cmap1)
2842 ft_err = pFT_Set_Charmap(ft_face, cmap1);
2843 else if (cmap2)
2844 ft_err = pFT_Set_Charmap(ft_face, cmap2);
2845 else if (cmap0)
2846 ft_err = pFT_Set_Charmap(ft_face, cmap0);
2847 else if (cmap_def)
2848 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
2850 return ft_err == FT_Err_Ok;
2853 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
2856 /*************************************************************
2857 * WineEngCreateFontInstance
2860 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
2862 GdiFont *ret;
2863 Face *face, *best, *best_bitmap;
2864 Family *family, *last_resort_family;
2865 struct list *family_elem_ptr, *face_elem_ptr;
2866 INT height, width = 0;
2867 unsigned int score = 0, new_score;
2868 signed int diff = 0, newdiff;
2869 BOOL bd, it, can_use_bitmap;
2870 LOGFONTW lf;
2871 CHARSETINFO csi;
2872 HFONTLIST *hflist;
2874 LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry)
2876 struct list *first_hfont = list_head(&ret->hfontlist);
2877 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2878 if(hflist->hfont == hfont)
2879 return ret;
2882 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
2883 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
2885 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
2886 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
2887 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
2888 lf.lfEscapement);
2890 /* check the cache first */
2891 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
2892 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
2893 return ret;
2896 TRACE("not in cache\n");
2897 if(list_empty(&font_list)) /* No fonts installed */
2899 TRACE("No fonts installed\n");
2900 return NULL;
2902 if(!have_installed_roman_font)
2904 TRACE("No roman font installed\n");
2905 return NULL;
2908 ret = alloc_font();
2910 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
2911 memcpy(&ret->font_desc.lf, &lf, sizeof(LOGFONTW));
2912 ret->font_desc.can_use_bitmap = can_use_bitmap;
2913 calc_hash(&ret->font_desc);
2914 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2915 hflist->hfont = hfont;
2916 list_add_head(&ret->hfontlist, &hflist->entry);
2919 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
2920 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
2921 original value lfCharSet. Note this is a special case for
2922 Symbol and doesn't happen at least for "Wingdings*" */
2924 if(!strcmpiW(lf.lfFaceName, SymbolW))
2925 lf.lfCharSet = SYMBOL_CHARSET;
2927 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
2928 switch(lf.lfCharSet) {
2929 case DEFAULT_CHARSET:
2930 csi.fs.fsCsb[0] = 0;
2931 break;
2932 default:
2933 FIXME("Untranslated charset %d\n", lf.lfCharSet);
2934 csi.fs.fsCsb[0] = 0;
2935 break;
2939 family = NULL;
2940 if(lf.lfFaceName[0] != '\0') {
2941 FontSubst *psub;
2942 SYSTEM_LINKS *font_link;
2943 CHILD_FONT *font_link_entry;
2945 psub = get_font_subst(&font_subst_list, lf.lfFaceName, lf.lfCharSet);
2947 if(psub) {
2948 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
2949 debugstr_w(psub->to.name));
2950 strcpyW(lf.lfFaceName, psub->to.name);
2953 /* We want a match on name and charset or just name if
2954 charset was DEFAULT_CHARSET. If the latter then
2955 we fixup the returned charset later in get_nearest_charset
2956 where we'll either use the charset of the current ansi codepage
2957 or if that's unavailable the first charset that the font supports.
2959 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2960 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2961 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2962 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2963 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2964 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
2965 if(face->scalable || can_use_bitmap)
2966 goto found;
2972 * Try check the SystemLink list first for a replacement font.
2973 * We may find good replacements there.
2975 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2977 if(!strcmpiW(font_link->font_name, lf.lfFaceName))
2979 TRACE("found entry in system list\n");
2980 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2982 face = font_link_entry->face;
2983 family = face->family;
2984 if(csi.fs.fsCsb[0] &
2985 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
2987 if(face->scalable || can_use_bitmap)
2988 goto found;
2995 /* If requested charset was DEFAULT_CHARSET then try using charset
2996 corresponding to the current ansi codepage */
2997 if(!csi.fs.fsCsb[0]) {
2998 INT acp = GetACP();
2999 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
3000 FIXME("TCI failed on codepage %d\n", acp);
3001 csi.fs.fsCsb[0] = 0;
3002 } else
3003 lf.lfCharSet = csi.ciCharset;
3006 /* Face families are in the top 4 bits of lfPitchAndFamily,
3007 so mask with 0xF0 before testing */
3009 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
3010 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
3011 strcpyW(lf.lfFaceName, defFixed);
3012 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
3013 strcpyW(lf.lfFaceName, defSerif);
3014 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
3015 strcpyW(lf.lfFaceName, defSans);
3016 else
3017 strcpyW(lf.lfFaceName, defSans);
3018 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3019 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3020 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
3021 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3022 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3023 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3024 if(face->scalable || can_use_bitmap)
3025 goto found;
3030 last_resort_family = NULL;
3031 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3032 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3033 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3034 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3035 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
3036 if(face->scalable)
3037 goto found;
3038 if(can_use_bitmap && !last_resort_family)
3039 last_resort_family = family;
3044 if(last_resort_family) {
3045 family = last_resort_family;
3046 csi.fs.fsCsb[0] = 0;
3047 goto found;
3050 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3051 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3052 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3053 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3054 if(face->scalable) {
3055 csi.fs.fsCsb[0] = 0;
3056 WARN("just using first face for now\n");
3057 goto found;
3059 if(can_use_bitmap && !last_resort_family)
3060 last_resort_family = family;
3063 if(!last_resort_family) {
3064 FIXME("can't find a single appropriate font - bailing\n");
3065 free_font(ret);
3066 return NULL;
3069 WARN("could only find a bitmap font - this will probably look awful!\n");
3070 family = last_resort_family;
3071 csi.fs.fsCsb[0] = 0;
3073 found:
3074 it = lf.lfItalic ? 1 : 0;
3075 bd = lf.lfWeight > 550 ? 1 : 0;
3077 height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
3078 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
3080 face = best = best_bitmap = NULL;
3081 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
3083 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3085 new_score = (face->Italic ^ it) + (face->Bold ^ bd);
3086 if(!best || new_score <= score)
3088 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3089 face->Italic, face->Bold, it, bd);
3090 score = new_score;
3091 best = face;
3092 if(best->scalable && score == 0) break;
3093 if(!best->scalable)
3095 if(height > 0)
3096 newdiff = height - (signed int)(best->size.height);
3097 else
3098 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
3099 if(!best_bitmap || new_score < score ||
3100 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
3102 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
3103 diff = newdiff;
3104 best_bitmap = best;
3105 if(score == 0 && diff == 0) break;
3111 if(best)
3112 face = best->scalable ? best : best_bitmap;
3113 ret->fake_italic = (it && !face->Italic);
3114 ret->fake_bold = (bd && !face->Bold);
3116 memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
3118 if(csi.fs.fsCsb[0]) {
3119 ret->charset = lf.lfCharSet;
3120 ret->codepage = csi.ciACP;
3122 else
3123 ret->charset = get_nearest_charset(face, &ret->codepage);
3125 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
3126 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
3128 ret->scale_x = 0.0;
3129 ret->scale_y = 0.0;
3131 ret->aveWidth = abs(lf.lfWidth);
3133 if(!face->scalable) {
3134 ret->ppem = face->size.height;
3135 if (height != 0) ret->ppem += diff;
3137 width = face->size.x_ppem >> 6;
3138 height = face->size.y_ppem >> 6;
3140 ret->ft_face = OpenFontFace(ret, face, width, height);
3142 if (!ret->ft_face)
3144 free_font( ret );
3145 return 0;
3148 ret->ntmFlags = face->ntmFlags;
3150 if (ret->charset == SYMBOL_CHARSET &&
3151 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
3152 /* No ops */
3154 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
3155 /* No ops */
3157 else {
3158 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
3161 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
3162 ret->name = strdupW(family->FamilyName);
3163 ret->underline = lf.lfUnderline ? 0xff : 0;
3164 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
3165 create_child_font_list(ret);
3167 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
3169 list_add_head(&gdi_font_list, &ret->entry);
3170 return ret;
3173 static void dump_gdi_font_list(void)
3175 GdiFont *gdiFont;
3176 struct list *elem_ptr;
3178 TRACE("---------- gdiFont Cache ----------\n");
3179 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
3180 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3181 TRACE("gdiFont=%p %s %d\n",
3182 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3185 TRACE("---------- Unused gdiFont Cache ----------\n");
3186 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
3187 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3188 TRACE("gdiFont=%p %s %d\n",
3189 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3193 /*************************************************************
3194 * WineEngDestroyFontInstance
3196 * free the gdiFont associated with this handle
3199 BOOL WineEngDestroyFontInstance(HFONT handle)
3201 GdiFont *gdiFont;
3202 HFONTLIST *hflist;
3203 BOOL ret = FALSE;
3204 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3205 int i = 0;
3207 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
3209 struct list *first_hfont = list_head(&gdiFont->hfontlist);
3210 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3211 if(hflist->hfont == handle)
3213 TRACE("removing child font %p from child list\n", gdiFont);
3214 list_remove(&gdiFont->entry);
3215 return TRUE;
3219 TRACE("destroying hfont=%p\n", handle);
3220 if(TRACE_ON(font))
3221 dump_gdi_font_list();
3223 font_elem_ptr = list_head(&gdi_font_list);
3224 while(font_elem_ptr) {
3225 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3226 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3228 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3229 while(hfontlist_elem_ptr) {
3230 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3231 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3232 if(hflist->hfont == handle) {
3233 list_remove(&hflist->entry);
3234 HeapFree(GetProcessHeap(), 0, hflist);
3235 ret = TRUE;
3238 if(list_empty(&gdiFont->hfontlist)) {
3239 TRACE("Moving to Unused list\n");
3240 list_remove(&gdiFont->entry);
3241 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3246 font_elem_ptr = list_head(&unused_gdi_font_list);
3247 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3248 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3249 while(font_elem_ptr) {
3250 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3251 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3252 TRACE("freeing %p\n", gdiFont);
3253 list_remove(&gdiFont->entry);
3254 free_font(gdiFont);
3256 return ret;
3259 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
3260 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
3262 OUTLINETEXTMETRICW *potm = NULL;
3263 UINT size;
3264 TEXTMETRICW tm, *ptm;
3265 GdiFont *font;
3266 LONG width, height;
3268 if (face->cache_valid)
3270 TRACE("Cached\n");
3271 memcpy(pelf,&face->elf,sizeof(ENUMLOGFONTEXW));
3272 memcpy(pntm,&face->ntm,sizeof(NEWTEXTMETRICEXW));
3273 *ptype = face->type;
3274 return;
3277 font = alloc_font();
3279 if(face->scalable) {
3280 height = 100;
3281 width = 0;
3282 } else {
3283 height = face->size.y_ppem >> 6;
3284 width = face->size.x_ppem >> 6;
3287 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
3289 free_font(font);
3290 return;
3293 font->name = strdupW(face->family->FamilyName);
3294 font->ntmFlags = face->ntmFlags;
3296 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
3298 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
3299 if(size) {
3300 potm = HeapAlloc(GetProcessHeap(), 0, size);
3301 WineEngGetOutlineTextMetrics(font, size, potm);
3302 ptm = &potm->otmTextMetrics;
3303 } else {
3304 WineEngGetTextMetrics(font, &tm);
3305 ptm = &tm;
3308 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = ptm->tmHeight;
3309 pntm->ntmTm.tmAscent = ptm->tmAscent;
3310 pntm->ntmTm.tmDescent = ptm->tmDescent;
3311 pntm->ntmTm.tmInternalLeading = ptm->tmInternalLeading;
3312 pntm->ntmTm.tmExternalLeading = ptm->tmExternalLeading;
3313 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = ptm->tmAveCharWidth;
3314 pntm->ntmTm.tmMaxCharWidth = ptm->tmMaxCharWidth;
3315 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = ptm->tmWeight;
3316 pntm->ntmTm.tmOverhang = ptm->tmOverhang;
3317 pntm->ntmTm.tmDigitizedAspectX = ptm->tmDigitizedAspectX;
3318 pntm->ntmTm.tmDigitizedAspectY = ptm->tmDigitizedAspectY;
3319 pntm->ntmTm.tmFirstChar = ptm->tmFirstChar;
3320 pntm->ntmTm.tmLastChar = ptm->tmLastChar;
3321 pntm->ntmTm.tmDefaultChar = ptm->tmDefaultChar;
3322 pntm->ntmTm.tmBreakChar = ptm->tmBreakChar;
3323 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = ptm->tmItalic;
3324 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = ptm->tmUnderlined;
3325 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = ptm->tmStruckOut;
3326 pntm->ntmTm.tmPitchAndFamily = ptm->tmPitchAndFamily;
3327 pelf->elfLogFont.lfPitchAndFamily = (ptm->tmPitchAndFamily & 0xf1) + 1;
3328 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = ptm->tmCharSet;
3329 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
3330 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
3331 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
3333 *ptype = 0;
3334 if (ptm->tmPitchAndFamily & TMPF_TRUETYPE)
3335 *ptype |= TRUETYPE_FONTTYPE;
3336 if (ptm->tmPitchAndFamily & TMPF_DEVICE)
3337 *ptype |= DEVICE_FONTTYPE;
3338 if(!(ptm->tmPitchAndFamily & TMPF_VECTOR))
3339 *ptype |= RASTER_FONTTYPE;
3341 pntm->ntmTm.ntmFlags = ptm->tmItalic ? NTM_ITALIC : 0;
3342 if(ptm->tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
3343 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
3344 pntm->ntmTm.ntmFlags |= face->ntmFlags;
3346 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
3347 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
3348 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
3350 if(potm) {
3351 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
3353 lstrcpynW(pelf->elfLogFont.lfFaceName,
3354 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
3355 LF_FACESIZE);
3356 lstrcpynW(pelf->elfFullName,
3357 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
3358 LF_FULLFACESIZE);
3359 lstrcpynW(pelf->elfStyle,
3360 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
3361 LF_FACESIZE);
3363 HeapFree(GetProcessHeap(), 0, potm);
3364 } else {
3365 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
3367 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
3368 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FACESIZE);
3369 pelf->elfStyle[0] = '\0';
3372 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
3374 memcpy(&face->elf,pelf,sizeof(ENUMLOGFONTEXW));
3375 memcpy(&face->ntm,pntm,sizeof(NEWTEXTMETRICEXW));
3376 face->type = *ptype;
3377 face->cache_valid = TRUE;
3379 free_font(font);
3382 /*************************************************************
3383 * WineEngEnumFonts
3386 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3388 Family *family;
3389 Face *face;
3390 struct list *family_elem_ptr, *face_elem_ptr;
3391 ENUMLOGFONTEXW elf;
3392 NEWTEXTMETRICEXW ntm;
3393 DWORD type, ret = 1;
3394 FONTSIGNATURE fs;
3395 CHARSETINFO csi;
3396 LOGFONTW lf;
3397 int i;
3399 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
3401 if(plf->lfFaceName[0]) {
3402 FontSubst *psub;
3403 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
3405 if(psub) {
3406 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
3407 debugstr_w(psub->to.name));
3408 memcpy(&lf, plf, sizeof(lf));
3409 strcpyW(lf.lfFaceName, psub->to.name);
3410 plf = &lf;
3413 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3414 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3415 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
3416 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3417 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3418 GetEnumStructs(face, &elf, &ntm, &type);
3419 for(i = 0; i < 32; i++) {
3420 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3421 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3422 strcpyW(elf.elfScript, OEM_DOSW);
3423 i = 32; /* break out of loop */
3424 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3425 continue;
3426 else {
3427 fs.fsCsb[0] = 1L << i;
3428 fs.fsCsb[1] = 0;
3429 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3430 TCI_SRCFONTSIG))
3431 csi.ciCharset = DEFAULT_CHARSET;
3432 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3433 if(csi.ciCharset != DEFAULT_CHARSET) {
3434 elf.elfLogFont.lfCharSet =
3435 ntm.ntmTm.tmCharSet = csi.ciCharset;
3436 if(ElfScriptsW[i])
3437 strcpyW(elf.elfScript, ElfScriptsW[i]);
3438 else
3439 FIXME("Unknown elfscript for bit %d\n", i);
3442 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3443 debugstr_w(elf.elfLogFont.lfFaceName),
3444 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3445 csi.ciCharset, type, debugstr_w(elf.elfScript),
3446 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3447 ntm.ntmTm.ntmFlags);
3448 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
3449 if(!ret) goto end;
3454 } else {
3455 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3456 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3457 face_elem_ptr = list_head(&family->faces);
3458 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3459 GetEnumStructs(face, &elf, &ntm, &type);
3460 for(i = 0; i < 32; i++) {
3461 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3462 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3463 strcpyW(elf.elfScript, OEM_DOSW);
3464 i = 32; /* break out of loop */
3465 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3466 continue;
3467 else {
3468 fs.fsCsb[0] = 1L << i;
3469 fs.fsCsb[1] = 0;
3470 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3471 TCI_SRCFONTSIG))
3472 csi.ciCharset = DEFAULT_CHARSET;
3473 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3474 if(csi.ciCharset != DEFAULT_CHARSET) {
3475 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
3476 csi.ciCharset;
3477 if(ElfScriptsW[i])
3478 strcpyW(elf.elfScript, ElfScriptsW[i]);
3479 else
3480 FIXME("Unknown elfscript for bit %d\n", i);
3483 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3484 debugstr_w(elf.elfLogFont.lfFaceName),
3485 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3486 csi.ciCharset, type, debugstr_w(elf.elfScript),
3487 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3488 ntm.ntmTm.ntmFlags);
3489 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
3490 if(!ret) goto end;
3494 end:
3495 return ret;
3498 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
3500 pt->x.value = vec->x >> 6;
3501 pt->x.fract = (vec->x & 0x3f) << 10;
3502 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
3503 pt->y.value = vec->y >> 6;
3504 pt->y.fract = (vec->y & 0x3f) << 10;
3505 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
3506 return;
3509 /***************************************************
3510 * According to the MSDN documentation on WideCharToMultiByte,
3511 * certain codepages cannot set the default_used parameter.
3512 * This returns TRUE if the codepage can set that parameter, false else
3513 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
3515 static BOOL codepage_sets_default_used(UINT codepage)
3517 switch (codepage)
3519 case CP_UTF7:
3520 case CP_UTF8:
3521 case CP_SYMBOL:
3522 return FALSE;
3523 default:
3524 return TRUE;
3528 static FT_UInt get_glyph_index(GdiFont *font, UINT glyph)
3530 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
3531 WCHAR wc = (WCHAR)glyph;
3532 BOOL default_used;
3533 BOOL *default_used_pointer;
3534 FT_UInt ret;
3535 char buf;
3536 default_used_pointer = NULL;
3537 default_used = FALSE;
3538 if (codepage_sets_default_used(font->codepage))
3539 default_used_pointer = &default_used;
3540 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
3541 ret = 0;
3542 else
3543 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
3544 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
3545 return ret;
3548 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
3549 glyph = glyph + 0xf000;
3550 return pFT_Get_Char_Index(font->ft_face, glyph);
3553 /*************************************************************
3554 * WineEngGetGlyphIndices
3556 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
3558 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
3559 LPWORD pgi, DWORD flags)
3561 int i;
3562 WCHAR default_char = 0;
3563 TEXTMETRICW textm;
3565 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0x001f; /* Indicate non existence */
3567 for(i = 0; i < count; i++)
3569 pgi[i] = get_glyph_index(font, lpstr[i]);
3570 if (pgi[i] == 0)
3572 if (!default_char)
3574 WineEngGetTextMetrics(font, &textm);
3575 default_char = textm.tmDefaultChar;
3577 pgi[i] = default_char;
3580 return count;
3583 /*************************************************************
3584 * WineEngGetGlyphOutline
3586 * Behaves in exactly the same way as the win32 api GetGlyphOutline
3587 * except that the first parameter is the HWINEENGFONT of the font in
3588 * question rather than an HDC.
3591 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
3592 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
3593 const MAT2* lpmat)
3595 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
3596 FT_Face ft_face = incoming_font->ft_face;
3597 GdiFont *font = incoming_font;
3598 FT_UInt glyph_index;
3599 DWORD width, height, pitch, needed = 0;
3600 FT_Bitmap ft_bitmap;
3601 FT_Error err;
3602 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
3603 FT_Angle angle = 0;
3604 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
3605 float widthRatio = 1.0, heightRatio = 1.0;
3606 FT_Matrix transMat = identityMat;
3607 BOOL needsTransform = FALSE;
3610 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
3611 buflen, buf, lpmat);
3613 if(format & GGO_GLYPH_INDEX) {
3614 glyph_index = glyph;
3615 format &= ~GGO_GLYPH_INDEX;
3616 } else {
3617 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
3618 ft_face = font->ft_face;
3621 if(glyph_index >= font->gmsize * GM_BLOCK_SIZE) {
3622 font->gmsize = (glyph_index / GM_BLOCK_SIZE + 1);
3623 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
3624 font->gmsize * sizeof(GM*));
3625 } else {
3626 if(format == GGO_METRICS && font->gm[glyph_index / GM_BLOCK_SIZE] != NULL && FONT_GM(font,glyph_index)->init ) {
3627 *lpgm = FONT_GM(font,glyph_index)->gm;
3628 return 1; /* FIXME */
3632 if (!font->gm[glyph_index / GM_BLOCK_SIZE])
3633 font->gm[glyph_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3635 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP) || lpmat)
3636 load_flags |= FT_LOAD_NO_BITMAP;
3638 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
3640 if(err) {
3641 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
3642 return GDI_ERROR;
3645 /* Scaling factor */
3646 if (font->scale_x != 0.0)
3648 widthRatio = font->scale_x;
3649 heightRatio = font->scale_y;
3652 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
3653 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
3655 adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
3656 lsb = left >> 6;
3657 bbx = (right - left) >> 6;
3659 /* Scaling transform */
3660 if(font->aveWidth) {
3661 FT_Matrix scaleMat;
3662 scaleMat.xx = FT_FixedFromFloat(widthRatio);
3663 scaleMat.xy = 0;
3664 scaleMat.yx = 0;
3665 scaleMat.yy = FT_FixedFromFloat(heightRatio);
3667 pFT_Matrix_Multiply(&scaleMat, &transMat);
3668 needsTransform = TRUE;
3671 /* Slant transform */
3672 if (font->fake_italic) {
3673 FT_Matrix slantMat;
3675 slantMat.xx = (1 << 16);
3676 slantMat.xy = ((1 << 16) >> 2);
3677 slantMat.yx = 0;
3678 slantMat.yy = (1 << 16);
3679 pFT_Matrix_Multiply(&slantMat, &transMat);
3680 needsTransform = TRUE;
3683 /* Rotation transform */
3684 if(font->orientation) {
3685 FT_Matrix rotationMat;
3686 FT_Vector vecAngle;
3687 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
3688 pFT_Vector_Unit(&vecAngle, angle);
3689 rotationMat.xx = vecAngle.x;
3690 rotationMat.xy = -vecAngle.y;
3691 rotationMat.yx = -rotationMat.xy;
3692 rotationMat.yy = rotationMat.xx;
3694 pFT_Matrix_Multiply(&rotationMat, &transMat);
3695 needsTransform = TRUE;
3698 /* Extra transformation specified by caller */
3699 if (lpmat) {
3700 FT_Matrix extraMat;
3701 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
3702 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
3703 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
3704 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
3705 pFT_Matrix_Multiply(&extraMat, &transMat);
3706 needsTransform = TRUE;
3709 if(!needsTransform) {
3710 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
3711 bottom = (ft_face->glyph->metrics.horiBearingY -
3712 ft_face->glyph->metrics.height) & -64;
3713 lpgm->gmCellIncX = adv;
3714 lpgm->gmCellIncY = 0;
3715 } else {
3716 INT xc, yc;
3717 FT_Vector vec;
3718 for(xc = 0; xc < 2; xc++) {
3719 for(yc = 0; yc < 2; yc++) {
3720 vec.x = (ft_face->glyph->metrics.horiBearingX +
3721 xc * ft_face->glyph->metrics.width);
3722 vec.y = ft_face->glyph->metrics.horiBearingY -
3723 yc * ft_face->glyph->metrics.height;
3724 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
3725 pFT_Vector_Transform(&vec, &transMat);
3726 if(xc == 0 && yc == 0) {
3727 left = right = vec.x;
3728 top = bottom = vec.y;
3729 } else {
3730 if(vec.x < left) left = vec.x;
3731 else if(vec.x > right) right = vec.x;
3732 if(vec.y < bottom) bottom = vec.y;
3733 else if(vec.y > top) top = vec.y;
3737 left = left & -64;
3738 right = (right + 63) & -64;
3739 bottom = bottom & -64;
3740 top = (top + 63) & -64;
3742 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
3743 vec.x = ft_face->glyph->metrics.horiAdvance;
3744 vec.y = 0;
3745 pFT_Vector_Transform(&vec, &transMat);
3746 lpgm->gmCellIncX = (vec.x+63) >> 6;
3747 lpgm->gmCellIncY = -((vec.y+63) >> 6);
3749 lpgm->gmBlackBoxX = (right - left) >> 6;
3750 lpgm->gmBlackBoxY = (top - bottom) >> 6;
3751 lpgm->gmptGlyphOrigin.x = left >> 6;
3752 lpgm->gmptGlyphOrigin.y = top >> 6;
3754 if(format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP)
3756 FONT_GM(font,glyph_index)->gm = *lpgm;
3757 FONT_GM(font,glyph_index)->adv = adv;
3758 FONT_GM(font,glyph_index)->lsb = lsb;
3759 FONT_GM(font,glyph_index)->bbx = bbx;
3760 FONT_GM(font,glyph_index)->init = TRUE;
3763 if(format == GGO_METRICS)
3764 return 1; /* FIXME */
3766 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP) {
3767 TRACE("loaded a bitmap\n");
3768 return GDI_ERROR;
3771 switch(format) {
3772 case GGO_BITMAP:
3773 width = lpgm->gmBlackBoxX;
3774 height = lpgm->gmBlackBoxY;
3775 pitch = ((width + 31) >> 5) << 2;
3776 needed = pitch * height;
3778 if(!buf || !buflen) break;
3780 switch(ft_face->glyph->format) {
3781 case ft_glyph_format_bitmap:
3783 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
3784 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
3785 INT h = ft_face->glyph->bitmap.rows;
3786 while(h--) {
3787 memcpy(dst, src, w);
3788 src += ft_face->glyph->bitmap.pitch;
3789 dst += pitch;
3791 break;
3794 case ft_glyph_format_outline:
3795 ft_bitmap.width = width;
3796 ft_bitmap.rows = height;
3797 ft_bitmap.pitch = pitch;
3798 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
3799 ft_bitmap.buffer = buf;
3801 if(needsTransform) {
3802 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3805 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3807 /* Note: FreeType will only set 'black' bits for us. */
3808 memset(buf, 0, needed);
3809 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3810 break;
3812 default:
3813 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
3814 return GDI_ERROR;
3816 break;
3818 case GGO_GRAY2_BITMAP:
3819 case GGO_GRAY4_BITMAP:
3820 case GGO_GRAY8_BITMAP:
3821 case WINE_GGO_GRAY16_BITMAP:
3823 unsigned int mult, row, col;
3824 BYTE *start, *ptr;
3826 width = lpgm->gmBlackBoxX;
3827 height = lpgm->gmBlackBoxY;
3828 pitch = (width + 3) / 4 * 4;
3829 needed = pitch * height;
3831 if(!buf || !buflen) break;
3833 switch(ft_face->glyph->format) {
3834 case ft_glyph_format_bitmap:
3836 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
3837 INT h = ft_face->glyph->bitmap.rows;
3838 INT x;
3839 while(h--) {
3840 for(x = 0; x < pitch; x++)
3841 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
3842 src += ft_face->glyph->bitmap.pitch;
3843 dst += pitch;
3845 return needed;
3847 case ft_glyph_format_outline:
3849 ft_bitmap.width = width;
3850 ft_bitmap.rows = height;
3851 ft_bitmap.pitch = pitch;
3852 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
3853 ft_bitmap.buffer = buf;
3855 if(needsTransform)
3856 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3858 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3860 memset(ft_bitmap.buffer, 0, buflen);
3862 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3864 if(format == GGO_GRAY2_BITMAP)
3865 mult = 4;
3866 else if(format == GGO_GRAY4_BITMAP)
3867 mult = 16;
3868 else if(format == GGO_GRAY8_BITMAP)
3869 mult = 64;
3870 else /* format == WINE_GGO_GRAY16_BITMAP */
3871 return needed;
3873 break;
3875 default:
3876 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
3877 return GDI_ERROR;
3880 start = buf;
3881 for(row = 0; row < height; row++) {
3882 ptr = start;
3883 for(col = 0; col < width; col++, ptr++) {
3884 *ptr = (((int)*ptr) * mult + 128) / 256;
3886 start += pitch;
3888 break;
3891 case GGO_NATIVE:
3893 int contour, point = 0, first_pt;
3894 FT_Outline *outline = &ft_face->glyph->outline;
3895 TTPOLYGONHEADER *pph;
3896 TTPOLYCURVE *ppc;
3897 DWORD pph_start, cpfx, type;
3899 if(buflen == 0) buf = NULL;
3901 if (needsTransform && buf) {
3902 pFT_Outline_Transform(outline, &transMat);
3905 for(contour = 0; contour < outline->n_contours; contour++) {
3906 pph_start = needed;
3907 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3908 first_pt = point;
3909 if(buf) {
3910 pph->dwType = TT_POLYGON_TYPE;
3911 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3913 needed += sizeof(*pph);
3914 point++;
3915 while(point <= outline->contours[contour]) {
3916 ppc = (TTPOLYCURVE *)((char *)buf + needed);
3917 type = (outline->tags[point] & FT_Curve_Tag_On) ?
3918 TT_PRIM_LINE : TT_PRIM_QSPLINE;
3919 cpfx = 0;
3920 do {
3921 if(buf)
3922 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3923 cpfx++;
3924 point++;
3925 } while(point <= outline->contours[contour] &&
3926 (outline->tags[point] & FT_Curve_Tag_On) ==
3927 (outline->tags[point-1] & FT_Curve_Tag_On));
3928 /* At the end of a contour Windows adds the start point, but
3929 only for Beziers */
3930 if(point > outline->contours[contour] &&
3931 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
3932 if(buf)
3933 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
3934 cpfx++;
3935 } else if(point <= outline->contours[contour] &&
3936 outline->tags[point] & FT_Curve_Tag_On) {
3937 /* add closing pt for bezier */
3938 if(buf)
3939 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3940 cpfx++;
3941 point++;
3943 if(buf) {
3944 ppc->wType = type;
3945 ppc->cpfx = cpfx;
3947 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3949 if(buf)
3950 pph->cb = needed - pph_start;
3952 break;
3954 case GGO_BEZIER:
3956 /* Convert the quadratic Beziers to cubic Beziers.
3957 The parametric eqn for a cubic Bezier is, from PLRM:
3958 r(t) = at^3 + bt^2 + ct + r0
3959 with the control points:
3960 r1 = r0 + c/3
3961 r2 = r1 + (c + b)/3
3962 r3 = r0 + c + b + a
3964 A quadratic Beizer has the form:
3965 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3967 So equating powers of t leads to:
3968 r1 = 2/3 p1 + 1/3 p0
3969 r2 = 2/3 p1 + 1/3 p2
3970 and of course r0 = p0, r3 = p2
3973 int contour, point = 0, first_pt;
3974 FT_Outline *outline = &ft_face->glyph->outline;
3975 TTPOLYGONHEADER *pph;
3976 TTPOLYCURVE *ppc;
3977 DWORD pph_start, cpfx, type;
3978 FT_Vector cubic_control[4];
3979 if(buflen == 0) buf = NULL;
3981 if (needsTransform && buf) {
3982 pFT_Outline_Transform(outline, &transMat);
3985 for(contour = 0; contour < outline->n_contours; contour++) {
3986 pph_start = needed;
3987 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3988 first_pt = point;
3989 if(buf) {
3990 pph->dwType = TT_POLYGON_TYPE;
3991 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3993 needed += sizeof(*pph);
3994 point++;
3995 while(point <= outline->contours[contour]) {
3996 ppc = (TTPOLYCURVE *)((char *)buf + needed);
3997 type = (outline->tags[point] & FT_Curve_Tag_On) ?
3998 TT_PRIM_LINE : TT_PRIM_CSPLINE;
3999 cpfx = 0;
4000 do {
4001 if(type == TT_PRIM_LINE) {
4002 if(buf)
4003 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4004 cpfx++;
4005 point++;
4006 } else {
4007 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
4008 so cpfx = 3n */
4010 /* FIXME: Possible optimization in endpoint calculation
4011 if there are two consecutive curves */
4012 cubic_control[0] = outline->points[point-1];
4013 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
4014 cubic_control[0].x += outline->points[point].x + 1;
4015 cubic_control[0].y += outline->points[point].y + 1;
4016 cubic_control[0].x >>= 1;
4017 cubic_control[0].y >>= 1;
4019 if(point+1 > outline->contours[contour])
4020 cubic_control[3] = outline->points[first_pt];
4021 else {
4022 cubic_control[3] = outline->points[point+1];
4023 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
4024 cubic_control[3].x += outline->points[point].x + 1;
4025 cubic_control[3].y += outline->points[point].y + 1;
4026 cubic_control[3].x >>= 1;
4027 cubic_control[3].y >>= 1;
4030 /* r1 = 1/3 p0 + 2/3 p1
4031 r2 = 1/3 p2 + 2/3 p1 */
4032 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
4033 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
4034 cubic_control[2] = cubic_control[1];
4035 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
4036 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
4037 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
4038 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
4039 if(buf) {
4040 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
4041 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
4042 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
4044 cpfx += 3;
4045 point++;
4047 } while(point <= outline->contours[contour] &&
4048 (outline->tags[point] & FT_Curve_Tag_On) ==
4049 (outline->tags[point-1] & FT_Curve_Tag_On));
4050 /* At the end of a contour Windows adds the start point,
4051 but only for Beziers and we've already done that.
4053 if(point <= outline->contours[contour] &&
4054 outline->tags[point] & FT_Curve_Tag_On) {
4055 /* This is the closing pt of a bezier, but we've already
4056 added it, so just inc point and carry on */
4057 point++;
4059 if(buf) {
4060 ppc->wType = type;
4061 ppc->cpfx = cpfx;
4063 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
4065 if(buf)
4066 pph->cb = needed - pph_start;
4068 break;
4071 default:
4072 FIXME("Unsupported format %d\n", format);
4073 return GDI_ERROR;
4075 return needed;
4078 static BOOL get_bitmap_text_metrics(GdiFont *font)
4080 FT_Face ft_face = font->ft_face;
4081 #ifdef HAVE_FREETYPE_FTWINFNT_H
4082 FT_WinFNT_HeaderRec winfnt_header;
4083 #endif
4084 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
4085 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
4086 font->potm->otmSize = size;
4088 #define TM font->potm->otmTextMetrics
4089 #ifdef HAVE_FREETYPE_FTWINFNT_H
4090 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
4092 TM.tmHeight = winfnt_header.pixel_height;
4093 TM.tmAscent = winfnt_header.ascent;
4094 TM.tmDescent = TM.tmHeight - TM.tmAscent;
4095 TM.tmInternalLeading = winfnt_header.internal_leading;
4096 TM.tmExternalLeading = winfnt_header.external_leading;
4097 TM.tmAveCharWidth = winfnt_header.avg_width;
4098 TM.tmMaxCharWidth = winfnt_header.max_width;
4099 TM.tmWeight = winfnt_header.weight;
4100 TM.tmOverhang = 0;
4101 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
4102 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
4103 TM.tmFirstChar = winfnt_header.first_char;
4104 TM.tmLastChar = winfnt_header.last_char;
4105 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
4106 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
4107 TM.tmItalic = winfnt_header.italic;
4108 TM.tmUnderlined = font->underline;
4109 TM.tmStruckOut = font->strikeout;
4110 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
4111 TM.tmCharSet = winfnt_header.charset;
4113 else
4114 #endif
4116 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
4117 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
4118 TM.tmHeight = TM.tmAscent + TM.tmDescent;
4119 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
4120 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
4121 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
4122 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
4123 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
4124 TM.tmOverhang = 0;
4125 TM.tmDigitizedAspectX = 96; /* FIXME */
4126 TM.tmDigitizedAspectY = 96; /* FIXME */
4127 TM.tmFirstChar = 1;
4128 TM.tmLastChar = 255;
4129 TM.tmDefaultChar = 32;
4130 TM.tmBreakChar = 32;
4131 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
4132 TM.tmUnderlined = font->underline;
4133 TM.tmStruckOut = font->strikeout;
4134 /* NB inverted meaning of TMPF_FIXED_PITCH */
4135 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
4136 TM.tmCharSet = font->charset;
4138 #undef TM
4140 return TRUE;
4144 static void scale_font_metrics(GdiFont *font, LPTEXTMETRICW ptm)
4146 if (font->scale_x == 0.0)
4148 if (FT_IS_SCALABLE(font->ft_face) || !font->ppem)
4149 font->scale_y = 1.0;
4150 else
4152 font->scale_y = (float)font->ppem * font->font_desc.matrix.eM22;
4153 font->scale_y /= (float)font->potm->otmTextMetrics.tmHeight;
4156 if (font->aveWidth)
4158 font->scale_x = (float)font->aveWidth * font->font_desc.matrix.eM11;
4159 font->scale_x /= (float)font->potm->otmTextMetrics.tmAveCharWidth;
4161 else
4162 font->scale_x = font->scale_y;
4164 TRACE("font scale x: %f y: %f\n", font->scale_x, font->scale_y);
4166 ptm->tmHeight = (float)ptm->tmHeight * font->scale_y;
4167 ptm->tmAscent = (float)ptm->tmAscent * font->scale_y;
4168 ptm->tmDescent = (float)ptm->tmDescent * font->scale_y;
4169 ptm->tmInternalLeading = (float)ptm->tmInternalLeading * font->scale_y;
4170 ptm->tmExternalLeading = (float)ptm->tmExternalLeading * font->scale_y;
4172 ptm->tmAveCharWidth = (float)ptm->tmAveCharWidth * font->scale_x;
4173 ptm->tmMaxCharWidth = (float)ptm->tmMaxCharWidth * font->scale_x;
4176 /*************************************************************
4177 * WineEngGetTextMetrics
4180 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
4182 if(!font->potm) {
4183 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
4184 if(!get_bitmap_text_metrics(font))
4185 return FALSE;
4187 if(!font->potm) return FALSE;
4188 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
4189 scale_font_metrics(font, ptm);
4191 return TRUE;
4195 /*************************************************************
4196 * WineEngGetOutlineTextMetrics
4199 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
4200 OUTLINETEXTMETRICW *potm)
4202 FT_Face ft_face = font->ft_face;
4203 UINT needed, lenfam, lensty, ret;
4204 TT_OS2 *pOS2;
4205 TT_HoriHeader *pHori;
4206 TT_Postscript *pPost;
4207 FT_Fixed x_scale, y_scale;
4208 WCHAR *family_nameW, *style_nameW;
4209 static const WCHAR spaceW[] = {' ', '\0'};
4210 char *cp;
4211 INT ascent, descent;
4213 TRACE("font=%p\n", font);
4215 if(!FT_IS_SCALABLE(ft_face))
4216 return 0;
4218 if(font->potm) {
4219 if(cbSize >= font->potm->otmSize)
4221 memcpy(potm, font->potm, font->potm->otmSize);
4222 scale_font_metrics(font, &potm->otmTextMetrics);
4224 return font->potm->otmSize;
4228 needed = sizeof(*potm);
4230 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
4231 family_nameW = strdupW(font->name);
4233 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
4234 * sizeof(WCHAR);
4235 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
4236 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
4237 style_nameW, lensty/sizeof(WCHAR));
4239 /* These names should be read from the TT name table */
4241 /* length of otmpFamilyName */
4242 needed += lenfam;
4244 /* length of otmpFaceName */
4245 if(!strcasecmp(ft_face->style_name, "regular")) {
4246 needed += lenfam; /* just the family name */
4247 } else {
4248 needed += lenfam + lensty; /* family + " " + style */
4251 /* length of otmpStyleName */
4252 needed += lensty;
4254 /* length of otmpFullName */
4255 needed += lenfam + lensty;
4258 x_scale = ft_face->size->metrics.x_scale;
4259 y_scale = ft_face->size->metrics.y_scale;
4261 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
4262 if(!pOS2) {
4263 FIXME("Can't find OS/2 table - not TT font?\n");
4264 ret = 0;
4265 goto end;
4268 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
4269 if(!pHori) {
4270 FIXME("Can't find HHEA table - not TT font?\n");
4271 ret = 0;
4272 goto end;
4275 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
4277 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",
4278 pOS2->usWinAscent, pOS2->usWinDescent,
4279 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
4280 ft_face->ascender, ft_face->descender, ft_face->height,
4281 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
4282 ft_face->bbox.yMax, ft_face->bbox.yMin);
4284 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
4285 font->potm->otmSize = needed;
4287 #define TM font->potm->otmTextMetrics
4289 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
4290 ascent = pHori->Ascender;
4291 descent = -pHori->Descender;
4292 } else {
4293 ascent = pOS2->usWinAscent;
4294 descent = pOS2->usWinDescent;
4297 if(font->yMax) {
4298 TM.tmAscent = font->yMax;
4299 TM.tmDescent = -font->yMin;
4300 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
4301 } else {
4302 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
4303 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
4304 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
4305 - ft_face->units_per_EM, y_scale) + 32) >> 6;
4308 TM.tmHeight = TM.tmAscent + TM.tmDescent;
4310 /* MSDN says:
4311 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
4313 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
4314 ((ascent + descent) -
4315 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
4317 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
4318 if (TM.tmAveCharWidth == 0) {
4319 TM.tmAveCharWidth = 1;
4321 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
4322 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
4323 TM.tmOverhang = 0;
4324 TM.tmDigitizedAspectX = 300;
4325 TM.tmDigitizedAspectY = 300;
4326 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
4327 * symbol range to 0 - f0ff
4329 if (font->charset == SYMBOL_CHARSET)
4330 TM.tmFirstChar = 0;
4331 else
4332 TM.tmFirstChar = pOS2->usFirstCharIndex;
4333 TM.tmLastChar = pOS2->usLastCharIndex;
4334 TM.tmDefaultChar = pOS2->usDefaultChar ? pOS2->usDefaultChar : 0x1f;
4335 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
4336 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
4337 TM.tmUnderlined = font->underline;
4338 TM.tmStruckOut = font->strikeout;
4340 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
4341 if(!FT_IS_FIXED_WIDTH(ft_face) &&
4342 (pOS2->version == 0xFFFFU ||
4343 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
4344 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
4345 else
4346 TM.tmPitchAndFamily = 0;
4348 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
4349 case PAN_FAMILY_SCRIPT:
4350 TM.tmPitchAndFamily |= FF_SCRIPT;
4351 break;
4352 case PAN_FAMILY_DECORATIVE:
4353 case PAN_FAMILY_PICTORIAL:
4354 TM.tmPitchAndFamily |= FF_DECORATIVE;
4355 break;
4356 case PAN_FAMILY_TEXT_DISPLAY:
4357 if(TM.tmPitchAndFamily == 0) /* fixed */
4358 TM.tmPitchAndFamily = FF_MODERN;
4359 else {
4360 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
4361 case PAN_SERIF_NORMAL_SANS:
4362 case PAN_SERIF_OBTUSE_SANS:
4363 case PAN_SERIF_PERP_SANS:
4364 TM.tmPitchAndFamily |= FF_SWISS;
4365 break;
4366 default:
4367 TM.tmPitchAndFamily |= FF_ROMAN;
4370 break;
4371 default:
4372 TM.tmPitchAndFamily |= FF_DONTCARE;
4375 if(FT_IS_SCALABLE(ft_face))
4376 TM.tmPitchAndFamily |= TMPF_VECTOR;
4378 if(FT_IS_SFNT(ft_face))
4380 if (font->ntmFlags & NTM_PS_OPENTYPE)
4381 TM.tmPitchAndFamily |= TMPF_DEVICE;
4382 else
4383 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
4386 TM.tmCharSet = font->charset;
4387 #undef TM
4389 font->potm->otmFiller = 0;
4390 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
4391 font->potm->otmfsSelection = pOS2->fsSelection;
4392 font->potm->otmfsType = pOS2->fsType;
4393 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
4394 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
4395 font->potm->otmItalicAngle = 0; /* POST table */
4396 font->potm->otmEMSquare = ft_face->units_per_EM;
4397 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
4398 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
4399 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
4400 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
4401 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
4402 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
4403 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
4404 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
4405 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
4406 font->potm->otmMacAscent = 0; /* where do these come from ? */
4407 font->potm->otmMacDescent = 0;
4408 font->potm->otmMacLineGap = 0;
4409 font->potm->otmusMinimumPPEM = 0; /* TT Header */
4410 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
4411 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
4412 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
4413 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
4414 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
4415 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
4416 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
4417 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
4418 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
4419 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
4420 if(!pPost) {
4421 font->potm->otmsUnderscoreSize = 0;
4422 font->potm->otmsUnderscorePosition = 0;
4423 } else {
4424 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
4425 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
4428 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
4429 cp = (char*)font->potm + sizeof(*font->potm);
4430 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
4431 strcpyW((WCHAR*)cp, family_nameW);
4432 cp += lenfam;
4433 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
4434 strcpyW((WCHAR*)cp, style_nameW);
4435 cp += lensty;
4436 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
4437 strcpyW((WCHAR*)cp, family_nameW);
4438 if(strcasecmp(ft_face->style_name, "regular")) {
4439 strcatW((WCHAR*)cp, spaceW);
4440 strcatW((WCHAR*)cp, style_nameW);
4441 cp += lenfam + lensty;
4442 } else
4443 cp += lenfam;
4444 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
4445 strcpyW((WCHAR*)cp, family_nameW);
4446 strcatW((WCHAR*)cp, spaceW);
4447 strcatW((WCHAR*)cp, style_nameW);
4448 ret = needed;
4450 if(potm && needed <= cbSize)
4452 memcpy(potm, font->potm, font->potm->otmSize);
4453 scale_font_metrics(font, &potm->otmTextMetrics);
4456 end:
4457 HeapFree(GetProcessHeap(), 0, style_nameW);
4458 HeapFree(GetProcessHeap(), 0, family_nameW);
4460 return ret;
4463 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
4465 HFONTLIST *hfontlist;
4466 child->font = alloc_font();
4467 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
4468 if(!child->font->ft_face)
4470 free_font(child->font);
4471 child->font = NULL;
4472 return FALSE;
4475 child->font->ntmFlags = child->face->ntmFlags;
4476 child->font->orientation = font->orientation;
4477 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
4478 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
4479 list_add_head(&child->font->hfontlist, &hfontlist->entry);
4480 child->font->base_font = font;
4481 list_add_head(&child_font_list, &child->font->entry);
4482 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
4483 return TRUE;
4486 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
4488 FT_UInt g;
4489 CHILD_FONT *child_font;
4491 if(font->base_font)
4492 font = font->base_font;
4494 *linked_font = font;
4496 if((*glyph = get_glyph_index(font, c)))
4497 return TRUE;
4499 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
4501 if(!child_font->font)
4502 if(!load_child_font(font, child_font))
4503 continue;
4505 if(!child_font->font->ft_face)
4506 continue;
4507 g = get_glyph_index(child_font->font, c);
4508 if(g)
4510 *glyph = g;
4511 *linked_font = child_font->font;
4512 return TRUE;
4515 return FALSE;
4518 /*************************************************************
4519 * WineEngGetCharWidth
4522 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
4523 LPINT buffer)
4525 UINT c;
4526 GLYPHMETRICS gm;
4527 FT_UInt glyph_index;
4528 GdiFont *linked_font;
4530 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
4532 for(c = firstChar; c <= lastChar; c++) {
4533 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
4534 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4535 &gm, 0, NULL, NULL);
4536 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
4538 return TRUE;
4541 /*************************************************************
4542 * WineEngGetCharABCWidths
4545 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
4546 LPABC buffer)
4548 UINT c;
4549 GLYPHMETRICS gm;
4550 FT_UInt glyph_index;
4551 GdiFont *linked_font;
4553 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
4555 if(!FT_IS_SCALABLE(font->ft_face))
4556 return FALSE;
4558 for(c = firstChar; c <= lastChar; c++) {
4559 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
4560 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4561 &gm, 0, NULL, NULL);
4562 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
4563 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
4564 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
4565 FONT_GM(linked_font,glyph_index)->bbx;
4567 return TRUE;
4570 /*************************************************************
4571 * WineEngGetCharABCWidthsI
4574 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
4575 LPABC buffer)
4577 UINT c;
4578 GLYPHMETRICS gm;
4579 FT_UInt glyph_index;
4580 GdiFont *linked_font;
4582 if(!FT_HAS_HORIZONTAL(font->ft_face))
4583 return FALSE;
4585 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
4586 if (!pgi)
4587 for(c = firstChar; c < firstChar+count; c++) {
4588 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
4589 &gm, 0, NULL, NULL);
4590 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
4591 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
4592 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
4593 - FONT_GM(linked_font,c)->bbx;
4595 else
4596 for(c = 0; c < count; c++) {
4597 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
4598 &gm, 0, NULL, NULL);
4599 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
4600 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
4601 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
4602 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
4605 return TRUE;
4608 /*************************************************************
4609 * WineEngGetTextExtentExPoint
4612 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
4613 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
4615 INT idx;
4616 INT nfit = 0, ext;
4617 GLYPHMETRICS gm;
4618 TEXTMETRICW tm;
4619 FT_UInt glyph_index;
4620 GdiFont *linked_font;
4622 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
4623 max_ext, size);
4625 size->cx = 0;
4626 WineEngGetTextMetrics(font, &tm);
4627 size->cy = tm.tmHeight;
4629 for(idx = 0; idx < count; idx++) {
4630 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
4631 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4632 &gm, 0, NULL, NULL);
4633 size->cx += FONT_GM(linked_font,glyph_index)->adv;
4634 ext = size->cx;
4635 if (! pnfit || ext <= max_ext) {
4636 ++nfit;
4637 if (dxs)
4638 dxs[idx] = ext;
4642 if (pnfit)
4643 *pnfit = nfit;
4645 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
4646 return TRUE;
4649 /*************************************************************
4650 * WineEngGetTextExtentExPointI
4653 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
4654 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
4656 INT idx;
4657 INT nfit = 0, ext;
4658 GLYPHMETRICS gm;
4659 TEXTMETRICW tm;
4661 TRACE("%p, %p, %d, %d, %p\n", font, indices, count, max_ext, size);
4663 size->cx = 0;
4664 WineEngGetTextMetrics(font, &tm);
4665 size->cy = tm.tmHeight;
4667 for(idx = 0; idx < count; idx++) {
4668 WineEngGetGlyphOutline(font, indices[idx],
4669 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
4670 NULL);
4671 size->cx += FONT_GM(font,indices[idx])->adv;
4672 ext = size->cx;
4673 if (! pnfit || ext <= max_ext) {
4674 ++nfit;
4675 if (dxs)
4676 dxs[idx] = ext;
4680 if (pnfit)
4681 *pnfit = nfit;
4683 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
4684 return TRUE;
4687 /*************************************************************
4688 * WineEngGetFontData
4691 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
4692 DWORD cbData)
4694 FT_Face ft_face = font->ft_face;
4695 FT_ULong len;
4696 FT_Error err;
4698 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
4699 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
4700 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
4702 if(!FT_IS_SFNT(ft_face))
4703 return GDI_ERROR;
4705 if(!buf || !cbData)
4706 len = 0;
4707 else
4708 len = cbData;
4710 if(table) { /* MS tags differ in endidness from FT ones */
4711 table = table >> 24 | table << 24 |
4712 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
4715 /* make sure value of len is the value freetype says it needs */
4716 if(buf && len)
4718 FT_ULong needed = 0;
4719 err = load_sfnt_table(ft_face, table, offset, NULL, &needed);
4720 if( !err && needed < len) len = needed;
4722 err = load_sfnt_table(ft_face, table, offset, buf, &len);
4724 if(err) {
4725 TRACE("Can't find table %c%c%c%c\n",
4726 /* bytes were reversed */
4727 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
4728 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
4729 return GDI_ERROR;
4731 return len;
4734 /*************************************************************
4735 * WineEngGetTextFace
4738 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
4740 if(str) {
4741 lstrcpynW(str, font->name, count);
4742 return strlenW(font->name);
4743 } else
4744 return strlenW(font->name) + 1;
4747 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
4749 if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
4750 return font->charset;
4753 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
4755 GdiFont *font = dc->gdiFont, *linked_font;
4756 struct list *first_hfont;
4757 BOOL ret;
4759 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
4760 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
4761 if(font == linked_font)
4762 *new_hfont = dc->hFont;
4763 else
4765 first_hfont = list_head(&linked_font->hfontlist);
4766 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
4769 return ret;
4772 /* Retrieve a list of supported Unicode ranges for a given font.
4773 * Can be called with NULL gs to calculate the buffer size. Returns
4774 * the number of ranges found.
4776 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
4778 DWORD num_ranges = 0;
4780 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
4782 FT_UInt glyph_code;
4783 FT_ULong char_code, char_code_prev;
4785 glyph_code = 0;
4786 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
4788 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
4789 face->num_glyphs, glyph_code, char_code);
4791 if (!glyph_code) return 0;
4793 if (gs)
4795 gs->ranges[0].wcLow = (USHORT)char_code;
4796 gs->ranges[0].cGlyphs = 0;
4797 gs->cGlyphsSupported = 0;
4800 num_ranges = 1;
4801 while (glyph_code)
4803 if (char_code < char_code_prev)
4805 ERR("expected increasing char code from FT_Get_Next_Char\n");
4806 return 0;
4808 if (char_code - char_code_prev > 1)
4810 num_ranges++;
4811 if (gs)
4813 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
4814 gs->ranges[num_ranges - 1].cGlyphs = 1;
4815 gs->cGlyphsSupported++;
4818 else if (gs)
4820 gs->ranges[num_ranges - 1].cGlyphs++;
4821 gs->cGlyphsSupported++;
4823 char_code_prev = char_code;
4824 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
4827 else
4828 FIXME("encoding %u not supported\n", face->charmap->encoding);
4830 return num_ranges;
4833 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
4835 DWORD size = 0;
4836 DWORD num_ranges = get_font_unicode_ranges(font->ft_face, glyphset);
4838 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
4839 if (glyphset)
4841 glyphset->cbThis = size;
4842 glyphset->cRanges = num_ranges;
4844 return size;
4847 /*************************************************************
4848 * FontIsLinked
4850 BOOL WineEngFontIsLinked(GdiFont *font)
4852 return !list_empty(&font->child_fonts);
4855 static BOOL is_hinting_enabled(void)
4857 /* Use the >= 2.2.0 function if available */
4858 if(pFT_Get_TrueType_Engine_Type)
4860 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
4861 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
4863 #ifdef FT_DRIVER_HAS_HINTER
4864 else
4866 FT_Module mod;
4868 /* otherwise if we've been compiled with < 2.2.0 headers
4869 use the internal macro */
4870 mod = pFT_Get_Module(library, "truetype");
4871 if(mod && FT_DRIVER_HAS_HINTER(mod))
4872 return TRUE;
4874 #endif
4876 return FALSE;
4879 /*************************************************************************
4880 * GetRasterizerCaps (GDI32.@)
4882 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
4884 static int hinting = -1;
4886 if(hinting == -1)
4888 hinting = is_hinting_enabled();
4889 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
4892 lprs->nSize = sizeof(RASTERIZER_STATUS);
4893 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
4894 lprs->nLanguageID = 0;
4895 return TRUE;
4898 /*************************************************************************
4899 * Kerning support for TrueType fonts
4901 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
4903 struct TT_kern_table
4905 USHORT version;
4906 USHORT nTables;
4909 struct TT_kern_subtable
4911 USHORT version;
4912 USHORT length;
4913 union
4915 USHORT word;
4916 struct
4918 USHORT horizontal : 1;
4919 USHORT minimum : 1;
4920 USHORT cross_stream: 1;
4921 USHORT override : 1;
4922 USHORT reserved1 : 4;
4923 USHORT format : 8;
4924 } bits;
4925 } coverage;
4928 struct TT_format0_kern_subtable
4930 USHORT nPairs;
4931 USHORT searchRange;
4932 USHORT entrySelector;
4933 USHORT rangeShift;
4936 struct TT_kern_pair
4938 USHORT left;
4939 USHORT right;
4940 short value;
4943 static DWORD parse_format0_kern_subtable(GdiFont *font,
4944 const struct TT_format0_kern_subtable *tt_f0_ks,
4945 const USHORT *glyph_to_char,
4946 KERNINGPAIR *kern_pair, DWORD cPairs)
4948 USHORT i, nPairs;
4949 const struct TT_kern_pair *tt_kern_pair;
4951 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
4953 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
4955 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
4956 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
4957 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
4959 if (!kern_pair || !cPairs)
4960 return nPairs;
4962 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
4964 nPairs = min(nPairs, cPairs);
4966 for (i = 0; i < nPairs; i++)
4968 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
4969 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
4970 /* this algorithm appears to better match what Windows does */
4971 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
4972 if (kern_pair->iKernAmount < 0)
4974 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
4975 kern_pair->iKernAmount -= font->ppem;
4977 else if (kern_pair->iKernAmount > 0)
4979 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
4980 kern_pair->iKernAmount += font->ppem;
4982 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
4984 TRACE("left %u right %u value %d\n",
4985 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
4987 kern_pair++;
4989 TRACE("copied %u entries\n", nPairs);
4990 return nPairs;
4993 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
4995 DWORD length;
4996 void *buf;
4997 const struct TT_kern_table *tt_kern_table;
4998 const struct TT_kern_subtable *tt_kern_subtable;
4999 USHORT i, nTables;
5000 USHORT *glyph_to_char;
5002 if (font->total_kern_pairs != (DWORD)-1)
5004 if (cPairs && kern_pair)
5006 cPairs = min(cPairs, font->total_kern_pairs);
5007 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
5008 return cPairs;
5010 return font->total_kern_pairs;
5013 font->total_kern_pairs = 0;
5015 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
5017 if (length == GDI_ERROR)
5019 TRACE("no kerning data in the font\n");
5020 return 0;
5023 buf = HeapAlloc(GetProcessHeap(), 0, length);
5024 if (!buf)
5026 WARN("Out of memory\n");
5027 return 0;
5030 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
5032 /* build a glyph index to char code map */
5033 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
5034 if (!glyph_to_char)
5036 WARN("Out of memory allocating a glyph index to char code map\n");
5037 HeapFree(GetProcessHeap(), 0, buf);
5038 return 0;
5041 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
5043 FT_UInt glyph_code;
5044 FT_ULong char_code;
5046 glyph_code = 0;
5047 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
5049 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
5050 font->ft_face->num_glyphs, glyph_code, char_code);
5052 while (glyph_code)
5054 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
5056 /* FIXME: This doesn't match what Windows does: it does some fancy
5057 * things with duplicate glyph index to char code mappings, while
5058 * we just avoid overriding existing entries.
5060 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
5061 glyph_to_char[glyph_code] = (USHORT)char_code;
5063 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
5066 else
5068 ULONG n;
5070 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
5071 for (n = 0; n <= 65535; n++)
5072 glyph_to_char[n] = (USHORT)n;
5075 tt_kern_table = buf;
5076 nTables = GET_BE_WORD(tt_kern_table->nTables);
5077 TRACE("version %u, nTables %u\n",
5078 GET_BE_WORD(tt_kern_table->version), nTables);
5080 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
5082 for (i = 0; i < nTables; i++)
5084 struct TT_kern_subtable tt_kern_subtable_copy;
5086 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
5087 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
5088 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
5090 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
5091 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
5092 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
5094 /* According to the TrueType specification this is the only format
5095 * that will be properly interpreted by Windows and OS/2
5097 if (tt_kern_subtable_copy.coverage.bits.format == 0)
5099 DWORD new_chunk, old_total = font->total_kern_pairs;
5101 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
5102 glyph_to_char, NULL, 0);
5103 font->total_kern_pairs += new_chunk;
5105 if (!font->kern_pairs)
5106 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
5107 font->total_kern_pairs * sizeof(*font->kern_pairs));
5108 else
5109 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
5110 font->total_kern_pairs * sizeof(*font->kern_pairs));
5112 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
5113 glyph_to_char, font->kern_pairs + old_total, new_chunk);
5115 else
5116 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
5118 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
5121 HeapFree(GetProcessHeap(), 0, glyph_to_char);
5122 HeapFree(GetProcessHeap(), 0, buf);
5124 if (cPairs && kern_pair)
5126 cPairs = min(cPairs, font->total_kern_pairs);
5127 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
5128 return cPairs;
5130 return font->total_kern_pairs;
5133 #else /* HAVE_FREETYPE */
5135 /*************************************************************************/
5137 BOOL WineEngInit(void)
5139 return FALSE;
5141 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
5143 return NULL;
5145 BOOL WineEngDestroyFontInstance(HFONT hfont)
5147 return FALSE;
5150 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
5152 return 1;
5155 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
5156 LPWORD pgi, DWORD flags)
5158 return GDI_ERROR;
5161 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
5162 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5163 const MAT2* lpmat)
5165 ERR("called but we don't have FreeType\n");
5166 return GDI_ERROR;
5169 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
5171 ERR("called but we don't have FreeType\n");
5172 return FALSE;
5175 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
5176 OUTLINETEXTMETRICW *potm)
5178 ERR("called but we don't have FreeType\n");
5179 return 0;
5182 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5183 LPINT buffer)
5185 ERR("called but we don't have FreeType\n");
5186 return FALSE;
5189 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5190 LPABC buffer)
5192 ERR("called but we don't have FreeType\n");
5193 return FALSE;
5196 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
5197 LPABC buffer)
5199 ERR("called but we don't have FreeType\n");
5200 return FALSE;
5203 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
5204 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
5206 ERR("called but we don't have FreeType\n");
5207 return FALSE;
5210 BOOL WineEngGetTextExtentExPointI(GdiFont *font, const WORD *indices, INT count,
5211 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
5213 ERR("called but we don't have FreeType\n");
5214 return FALSE;
5217 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
5218 DWORD cbData)
5220 ERR("called but we don't have FreeType\n");
5221 return GDI_ERROR;
5224 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
5226 ERR("called but we don't have FreeType\n");
5227 return 0;
5230 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
5232 FIXME(":stub\n");
5233 return 1;
5236 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
5238 FIXME(":stub\n");
5239 return TRUE;
5242 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
5244 FIXME(":stub\n");
5245 return NULL;
5248 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
5250 FIXME(":stub\n");
5251 return DEFAULT_CHARSET;
5254 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
5256 return FALSE;
5259 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
5261 FIXME("(%p, %p): stub\n", font, glyphset);
5262 return 0;
5265 BOOL WineEngFontIsLinked(GdiFont *font)
5267 return FALSE;
5270 /*************************************************************************
5271 * GetRasterizerCaps (GDI32.@)
5273 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
5275 lprs->nSize = sizeof(RASTERIZER_STATUS);
5276 lprs->wFlags = 0;
5277 lprs->nLanguageID = 0;
5278 return TRUE;
5281 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
5283 ERR("called but we don't have FreeType\n");
5284 return 0;
5287 #endif /* HAVE_FREETYPE */