push(c) 7dcddf6204ed5518706a76fe66fd836d81e70dd4
[wine/hacks.git] / dlls / gdi32 / freetype.c
blob62563e8cf0239012eceeb64baf9cd5f6f6ae69d4
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 } Face;
264 typedef struct tagFamily {
265 struct list entry;
266 const WCHAR *FamilyName;
267 struct list faces;
268 } Family;
270 typedef struct {
271 GLYPHMETRICS gm;
272 INT adv; /* These three hold to widths of the unrotated chars */
273 INT lsb;
274 INT bbx;
275 BOOL init;
276 } GM;
278 typedef struct {
279 FLOAT eM11, eM12;
280 FLOAT eM21, eM22;
281 } FMAT2;
283 typedef struct {
284 DWORD hash;
285 LOGFONTW lf;
286 FMAT2 matrix;
287 BOOL can_use_bitmap;
288 } FONT_DESC;
290 typedef struct tagHFONTLIST {
291 struct list entry;
292 HFONT hfont;
293 } HFONTLIST;
295 typedef struct {
296 struct list entry;
297 Face *face;
298 GdiFont *font;
299 } CHILD_FONT;
301 struct tagGdiFont {
302 struct list entry;
303 FT_Face ft_face;
304 struct font_mapping *mapping;
305 LPWSTR name;
306 int charset;
307 int codepage;
308 BOOL fake_italic;
309 BOOL fake_bold;
310 BYTE underline;
311 BYTE strikeout;
312 INT orientation;
313 GM **gm;
314 DWORD gmsize;
315 struct list hfontlist;
316 FONT_DESC font_desc;
317 LONG aveWidth;
318 SHORT yMax;
319 SHORT yMin;
320 OUTLINETEXTMETRICW *potm;
321 DWORD ntmFlags;
322 DWORD total_kern_pairs;
323 KERNINGPAIR *kern_pairs;
324 FONTSIGNATURE fs;
325 GdiFont *base_font;
326 struct list child_fonts;
327 LONG ppem;
330 typedef struct {
331 struct list entry;
332 const WCHAR *font_name;
333 struct list links;
334 } SYSTEM_LINKS;
336 #define GM_BLOCK_SIZE 128
337 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
339 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
340 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
341 #define UNUSED_CACHE_SIZE 10
342 static struct list child_font_list = LIST_INIT(child_font_list);
343 static struct list system_links = LIST_INIT(system_links);
345 static struct list font_subst_list = LIST_INIT(font_subst_list);
347 static struct list font_list = LIST_INIT(font_list);
349 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
350 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
351 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
353 static const WCHAR RegularW[] = {'R','e','g','u','l','a','r','\0'};
355 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
356 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
357 'W','i','n','d','o','w','s','\\',
358 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
359 'F','o','n','t','s','\0'};
361 static const WCHAR winnt_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',' ','N','T','\\',
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 system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
367 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
368 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
369 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
371 static const WCHAR * const SystemFontValues[4] = {
372 System_Value,
373 OEMFont_Value,
374 FixedSys_Value,
375 NULL
378 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
379 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
381 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
382 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
383 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
384 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
385 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
386 'E','u','r','o','p','e','a','n','\0'};
387 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
388 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
389 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
390 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
391 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
392 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
393 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
394 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
395 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
396 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
397 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
398 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
400 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
401 WesternW, /*00*/
402 Central_EuropeanW,
403 CyrillicW,
404 GreekW,
405 TurkishW,
406 HebrewW,
407 ArabicW,
408 BalticW,
409 VietnameseW, /*08*/
410 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
411 ThaiW,
412 JapaneseW,
413 CHINESE_GB2312W,
414 HangulW,
415 CHINESE_BIG5W,
416 Hangul_Johab_W,
417 NULL, NULL, /*23*/
418 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
419 SymbolW /*31*/
422 typedef struct {
423 WCHAR *name;
424 INT charset;
425 } NameCs;
427 typedef struct tagFontSubst {
428 struct list entry;
429 NameCs from;
430 NameCs to;
431 } FontSubst;
433 struct font_mapping
435 struct list entry;
436 int refcount;
437 dev_t dev;
438 ino_t ino;
439 void *data;
440 size_t size;
443 static struct list mappings_list = LIST_INIT( mappings_list );
445 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
447 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
449 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
451 /****************************************
452 * Notes on .fon files
454 * The fonts System, FixedSys and Terminal are special. There are typically multiple
455 * versions installed for different resolutions and codepages. Windows stores which one to use
456 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
457 * Key Meaning
458 * FIXEDFON.FON FixedSys
459 * FONTS.FON System
460 * OEMFONT.FON Terminal
461 * LogPixels Current dpi set by the display control panel applet
462 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
463 * also has a LogPixels value that appears to mirror this)
465 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
466 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
467 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
468 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
469 * so that makes sense.
471 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
472 * to be mapped into the registry on Windows 2000 at least).
473 * I have
474 * woafont=app850.fon
475 * ega80woa.fon=ega80850.fon
476 * ega40woa.fon=ega40850.fon
477 * cga80woa.fon=cga80850.fon
478 * cga40woa.fon=cga40850.fon
481 #ifdef HAVE_CARBON_CARBON_H
482 static char *find_cache_dir(void)
484 FSRef ref;
485 OSErr err;
486 static char cached_path[MAX_PATH];
487 static const char *wine = "/Wine", *fonts = "/Fonts";
489 if(*cached_path) return cached_path;
491 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
492 if(err != noErr)
494 WARN("can't create cached data folder\n");
495 return NULL;
497 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
498 if(err != noErr)
500 WARN("can't create cached data path\n");
501 *cached_path = '\0';
502 return NULL;
504 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
506 ERR("Could not create full path\n");
507 *cached_path = '\0';
508 return NULL;
510 strcat(cached_path, wine);
512 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
514 WARN("Couldn't mkdir %s\n", cached_path);
515 *cached_path = '\0';
516 return NULL;
518 strcat(cached_path, fonts);
519 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
521 WARN("Couldn't mkdir %s\n", cached_path);
522 *cached_path = '\0';
523 return NULL;
525 return cached_path;
528 /******************************************************************
529 * expand_mac_font
531 * Extracts individual TrueType font files from a Mac suitcase font
532 * and saves them into the user's caches directory (see
533 * find_cache_dir()).
534 * Returns a NULL terminated array of filenames.
536 * We do this because they are apps that try to read ttf files
537 * themselves and they don't like Mac suitcase files.
539 static char **expand_mac_font(const char *path)
541 FSRef ref;
542 SInt16 res_ref;
543 OSStatus s;
544 unsigned int idx;
545 const char *out_dir;
546 const char *filename;
547 int output_len;
548 struct {
549 char **array;
550 unsigned int size, max_size;
551 } ret;
553 TRACE("path %s\n", path);
555 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
556 if(s != noErr)
558 WARN("failed to get ref\n");
559 return NULL;
562 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
563 if(s != noErr)
565 TRACE("no data fork, so trying resource fork\n");
566 res_ref = FSOpenResFile(&ref, fsRdPerm);
567 if(res_ref == -1)
569 TRACE("unable to open resource fork\n");
570 return NULL;
574 ret.size = 0;
575 ret.max_size = 10;
576 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
577 if(!ret.array)
579 CloseResFile(res_ref);
580 return NULL;
583 out_dir = find_cache_dir();
585 filename = strrchr(path, '/');
586 if(!filename) filename = path;
587 else filename++;
589 /* output filename has the form out_dir/filename_%04x.ttf */
590 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
592 UseResFile(res_ref);
593 idx = 1;
594 while(1)
596 FamRec *fam_rec;
597 unsigned short *num_faces_ptr, num_faces, face;
598 AsscEntry *assoc;
599 Handle fond;
600 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
602 fond = Get1IndResource(fond_res, idx);
603 if(!fond) break;
604 TRACE("got fond resource %d\n", idx);
605 HLock(fond);
607 fam_rec = *(FamRec**)fond;
608 num_faces_ptr = (unsigned short *)(fam_rec + 1);
609 num_faces = GET_BE_WORD(*num_faces_ptr);
610 num_faces++;
611 assoc = (AsscEntry*)(num_faces_ptr + 1);
612 TRACE("num faces %04x\n", num_faces);
613 for(face = 0; face < num_faces; face++, assoc++)
615 Handle sfnt;
616 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
617 unsigned short size, font_id;
618 char *output;
620 size = GET_BE_WORD(assoc->fontSize);
621 font_id = GET_BE_WORD(assoc->fontID);
622 if(size != 0)
624 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
625 continue;
628 TRACE("trying to load sfnt id %04x\n", font_id);
629 sfnt = GetResource(sfnt_res, font_id);
630 if(!sfnt)
632 TRACE("can't get sfnt resource %04x\n", font_id);
633 continue;
636 output = HeapAlloc(GetProcessHeap(), 0, output_len);
637 if(output)
639 int fd;
641 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
643 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
644 if(fd != -1 || errno == EEXIST)
646 if(fd != -1)
648 unsigned char *sfnt_data;
650 HLock(sfnt);
651 sfnt_data = *(unsigned char**)sfnt;
652 write(fd, sfnt_data, GetHandleSize(sfnt));
653 HUnlock(sfnt);
654 close(fd);
656 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
658 ret.max_size *= 2;
659 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
661 ret.array[ret.size++] = output;
663 else
665 WARN("unable to create %s\n", output);
666 HeapFree(GetProcessHeap(), 0, output);
669 ReleaseResource(sfnt);
671 HUnlock(fond);
672 ReleaseResource(fond);
673 idx++;
675 CloseResFile(res_ref);
677 return ret.array;
680 #endif /* HAVE_CARBON_CARBON_H */
682 static inline BOOL is_win9x(void)
684 return GetVersion() & 0x80000000;
687 This function builds an FT_Fixed from a float. It puts the integer part
688 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
689 It fails if the integer part of the float number is greater than SHORT_MAX.
691 static inline FT_Fixed FT_FixedFromFloat(float f)
693 short value = f;
694 unsigned short fract = (f - value) * 0xFFFF;
695 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
699 This function builds an FT_Fixed from a FIXED. It simply put f.value
700 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
702 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
704 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
708 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
710 Family *family;
711 Face *face;
712 const char *file;
713 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
714 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
716 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
717 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
719 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
721 if(face_name && strcmpiW(face_name, family->FamilyName))
722 continue;
723 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
725 if (!face->file)
726 continue;
727 file = strrchr(face->file, '/');
728 if(!file)
729 file = face->file;
730 else
731 file++;
732 if(!strcasecmp(file, file_nameA))
734 HeapFree(GetProcessHeap(), 0, file_nameA);
735 return face;
739 HeapFree(GetProcessHeap(), 0, file_nameA);
740 return NULL;
743 static Family *find_family_from_name(const WCHAR *name)
745 Family *family;
747 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
749 if(!strcmpiW(family->FamilyName, name))
750 return family;
753 return NULL;
756 static void DumpSubstList(void)
758 FontSubst *psub;
760 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
762 if(psub->from.charset != -1 || psub->to.charset != -1)
763 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
764 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
765 else
766 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
767 debugstr_w(psub->to.name));
769 return;
772 static LPWSTR strdupW(LPCWSTR p)
774 LPWSTR ret;
775 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
776 ret = HeapAlloc(GetProcessHeap(), 0, len);
777 memcpy(ret, p, len);
778 return ret;
781 static LPSTR strdupA(LPCSTR p)
783 LPSTR ret;
784 DWORD len = (strlen(p) + 1);
785 ret = HeapAlloc(GetProcessHeap(), 0, len);
786 memcpy(ret, p, len);
787 return ret;
790 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
791 INT from_charset)
793 FontSubst *element;
795 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
797 if(!strcmpiW(element->from.name, from_name) &&
798 (element->from.charset == from_charset ||
799 element->from.charset == -1))
800 return element;
803 return NULL;
806 #define ADD_FONT_SUBST_FORCE 1
808 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
810 FontSubst *from_exist, *to_exist;
812 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
814 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
816 list_remove(&from_exist->entry);
817 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
818 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
819 HeapFree(GetProcessHeap(), 0, from_exist);
820 from_exist = NULL;
823 if(!from_exist)
825 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
827 if(to_exist)
829 HeapFree(GetProcessHeap(), 0, subst->to.name);
830 subst->to.name = strdupW(to_exist->to.name);
833 list_add_tail(subst_list, &subst->entry);
835 return TRUE;
838 HeapFree(GetProcessHeap(), 0, subst->from.name);
839 HeapFree(GetProcessHeap(), 0, subst->to.name);
840 HeapFree(GetProcessHeap(), 0, subst);
841 return FALSE;
844 static void split_subst_info(NameCs *nc, LPSTR str)
846 CHAR *p = strrchr(str, ',');
847 DWORD len;
849 nc->charset = -1;
850 if(p && *(p+1)) {
851 nc->charset = strtol(p+1, NULL, 10);
852 *p = '\0';
854 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
855 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
856 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
859 static void LoadSubstList(void)
861 FontSubst *psub;
862 HKEY hkey;
863 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
864 LPSTR value;
865 LPVOID data;
867 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
868 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
869 &hkey) == ERROR_SUCCESS) {
871 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
872 &valuelen, &datalen, NULL, NULL);
874 valuelen++; /* returned value doesn't include room for '\0' */
875 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
876 data = HeapAlloc(GetProcessHeap(), 0, datalen);
878 dlen = datalen;
879 vlen = valuelen;
880 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
881 &dlen) == ERROR_SUCCESS) {
882 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
884 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
885 split_subst_info(&psub->from, value);
886 split_subst_info(&psub->to, data);
888 /* Win 2000 doesn't allow mapping between different charsets
889 or mapping of DEFAULT_CHARSET */
890 if((psub->to.charset != psub->from.charset) ||
891 psub->to.charset == DEFAULT_CHARSET) {
892 HeapFree(GetProcessHeap(), 0, psub->to.name);
893 HeapFree(GetProcessHeap(), 0, psub->from.name);
894 HeapFree(GetProcessHeap(), 0, psub);
895 } else {
896 add_font_subst(&font_subst_list, psub, 0);
898 /* reset dlen and vlen */
899 dlen = datalen;
900 vlen = valuelen;
902 HeapFree(GetProcessHeap(), 0, data);
903 HeapFree(GetProcessHeap(), 0, value);
904 RegCloseKey(hkey);
908 static WCHAR *get_familyname(FT_Face ft_face)
910 WCHAR *family = NULL;
911 FT_SfntName name;
912 FT_UInt num_names, name_index, i;
914 if(FT_IS_SFNT(ft_face))
916 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
918 for(name_index = 0; name_index < num_names; name_index++)
920 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
922 if((name.name_id == TT_NAME_ID_FONT_FAMILY) &&
923 (name.language_id == GetUserDefaultLCID()) &&
924 (name.platform_id == TT_PLATFORM_MICROSOFT) &&
925 (name.encoding_id == TT_MS_ID_UNICODE_CS))
927 /* String is not nul terminated and string_len is a byte length. */
928 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
929 for(i = 0; i < name.string_len / 2; i++)
931 WORD *tmp = (WORD *)&name.string[i * 2];
932 family[i] = GET_BE_WORD(*tmp);
934 family[i] = 0;
936 TRACE("Got localised name %s\n", debugstr_w(family));
937 return family;
943 return NULL;
947 #define ADDFONT_EXTERNAL_FONT 0x01
948 #define ADDFONT_FORCE_BITMAP 0x02
949 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
951 FT_Face ft_face;
952 TT_OS2 *pOS2;
953 TT_Header *pHeader = NULL;
954 WCHAR *english_family, *localised_family, *StyleW;
955 DWORD len;
956 Family *family;
957 Face *face;
958 struct list *family_elem_ptr, *face_elem_ptr;
959 FT_Error err;
960 FT_Long face_index = 0, num_faces;
961 #ifdef HAVE_FREETYPE_FTWINFNT_H
962 FT_WinFNT_HeaderRec winfnt_header;
963 #endif
964 int i, bitmap_num, internal_leading;
965 FONTSIGNATURE fs;
967 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
968 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
970 #ifdef HAVE_CARBON_CARBON_H
971 if(file && !fake_family)
973 char **mac_list = expand_mac_font(file);
974 if(mac_list)
976 BOOL had_one = FALSE;
977 char **cursor;
978 for(cursor = mac_list; *cursor; cursor++)
980 had_one = TRUE;
981 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
982 HeapFree(GetProcessHeap(), 0, *cursor);
984 HeapFree(GetProcessHeap(), 0, mac_list);
985 if(had_one)
986 return 1;
989 #endif /* HAVE_CARBON_CARBON_H */
991 do {
992 char *family_name = fake_family;
994 if (file)
996 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
997 err = pFT_New_Face(library, file, face_index, &ft_face);
998 } else
1000 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1001 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1004 if(err != 0) {
1005 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1006 return 0;
1009 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*/
1010 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1011 pFT_Done_Face(ft_face);
1012 return 0;
1015 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1016 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1017 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1018 pFT_Done_Face(ft_face);
1019 return 0;
1022 if(FT_IS_SFNT(ft_face) && (!pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2) ||
1023 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1024 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))) {
1025 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1026 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1027 pFT_Done_Face(ft_face);
1028 return 0;
1031 if(!ft_face->family_name || !ft_face->style_name) {
1032 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1033 pFT_Done_Face(ft_face);
1034 return 0;
1037 if (target_family)
1039 localised_family = get_familyname(ft_face);
1040 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1042 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1043 HeapFree(GetProcessHeap(), 0, localised_family);
1044 num_faces = ft_face->num_faces;
1045 pFT_Done_Face(ft_face);
1046 continue;
1048 HeapFree(GetProcessHeap(), 0, localised_family);
1051 if(!family_name)
1052 family_name = ft_face->family_name;
1054 bitmap_num = 0;
1055 do {
1056 My_FT_Bitmap_Size *size = NULL;
1057 FT_ULong tmp_size;
1059 if(!FT_IS_SCALABLE(ft_face))
1060 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1062 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1063 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1064 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1066 localised_family = NULL;
1067 if(!fake_family) {
1068 localised_family = get_familyname(ft_face);
1069 if(localised_family && !strcmpW(localised_family, english_family)) {
1070 HeapFree(GetProcessHeap(), 0, localised_family);
1071 localised_family = NULL;
1075 family = NULL;
1076 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1077 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1078 if(!strcmpW(family->FamilyName, localised_family ? localised_family : english_family))
1079 break;
1080 family = NULL;
1082 if(!family) {
1083 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1084 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1085 list_init(&family->faces);
1086 list_add_tail(&font_list, &family->entry);
1088 if(localised_family) {
1089 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1090 subst->from.name = strdupW(english_family);
1091 subst->from.charset = -1;
1092 subst->to.name = strdupW(localised_family);
1093 subst->to.charset = -1;
1094 add_font_subst(&font_subst_list, subst, 0);
1097 HeapFree(GetProcessHeap(), 0, localised_family);
1098 HeapFree(GetProcessHeap(), 0, english_family);
1100 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1101 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1102 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1104 internal_leading = 0;
1105 memset(&fs, 0, sizeof(fs));
1107 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1108 if(pOS2) {
1109 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1110 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1111 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1112 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1113 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1114 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1115 if(pOS2->version == 0) {
1116 FT_UInt dummy;
1118 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1119 fs.fsCsb[0] |= 1;
1120 else
1121 fs.fsCsb[0] |= 1L << 31;
1124 #ifdef HAVE_FREETYPE_FTWINFNT_H
1125 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1126 CHARSETINFO csi;
1127 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1128 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1129 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1130 memcpy(&fs, &csi.fs, sizeof(csi.fs));
1131 internal_leading = winfnt_header.internal_leading;
1133 #endif
1135 face_elem_ptr = list_head(&family->faces);
1136 while(face_elem_ptr) {
1137 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1138 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1139 if(!strcmpW(face->StyleName, StyleW) &&
1140 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1141 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1142 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1143 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1145 if(fake_family) {
1146 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1147 HeapFree(GetProcessHeap(), 0, StyleW);
1148 pFT_Done_Face(ft_face);
1149 return 1;
1151 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1152 TRACE("Original font is newer so skipping this one\n");
1153 HeapFree(GetProcessHeap(), 0, StyleW);
1154 pFT_Done_Face(ft_face);
1155 return 1;
1156 } else {
1157 TRACE("Replacing original with this one\n");
1158 list_remove(&face->entry);
1159 HeapFree(GetProcessHeap(), 0, face->file);
1160 HeapFree(GetProcessHeap(), 0, face->StyleName);
1161 HeapFree(GetProcessHeap(), 0, face);
1162 break;
1166 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1167 list_add_tail(&family->faces, &face->entry);
1168 face->StyleName = StyleW;
1169 if (file)
1171 face->file = strdupA(file);
1172 face->font_data_ptr = NULL;
1173 face->font_data_size = 0;
1175 else
1177 face->file = NULL;
1178 face->font_data_ptr = font_data_ptr;
1179 face->font_data_size = font_data_size;
1181 face->face_index = face_index;
1182 face->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
1183 face->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
1184 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1185 face->family = family;
1186 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1187 memcpy(&face->fs, &fs, sizeof(face->fs));
1188 memset(&face->fs_links, 0, sizeof(face->fs_links));
1190 if(FT_IS_SCALABLE(ft_face)) {
1191 memset(&face->size, 0, sizeof(face->size));
1192 face->scalable = TRUE;
1193 } else {
1194 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1195 size->height, size->width, size->size >> 6,
1196 size->x_ppem >> 6, size->y_ppem >> 6);
1197 face->size.height = size->height;
1198 face->size.width = size->width;
1199 face->size.size = size->size;
1200 face->size.x_ppem = size->x_ppem;
1201 face->size.y_ppem = size->y_ppem;
1202 face->size.internal_leading = internal_leading;
1203 face->scalable = FALSE;
1206 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1207 tmp_size = 0;
1208 if (pFT_Load_Sfnt_Table && !pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1210 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1211 face->ntmFlags = NTM_PS_OPENTYPE;
1213 else
1214 face->ntmFlags = 0;
1216 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1217 face->fs.fsCsb[0], face->fs.fsCsb[1],
1218 face->fs.fsUsb[0], face->fs.fsUsb[1],
1219 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1222 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1223 for(i = 0; i < ft_face->num_charmaps; i++) {
1224 switch(ft_face->charmaps[i]->encoding) {
1225 case FT_ENCODING_UNICODE:
1226 case FT_ENCODING_APPLE_ROMAN:
1227 face->fs.fsCsb[0] |= 1;
1228 break;
1229 case FT_ENCODING_MS_SYMBOL:
1230 face->fs.fsCsb[0] |= 1L << 31;
1231 break;
1232 default:
1233 break;
1238 if(face->fs.fsCsb[0] & ~(1L << 31))
1239 have_installed_roman_font = TRUE;
1240 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1242 num_faces = ft_face->num_faces;
1243 pFT_Done_Face(ft_face);
1244 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1245 debugstr_w(StyleW));
1246 } while(num_faces > ++face_index);
1247 return num_faces;
1250 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1252 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1255 static void DumpFontList(void)
1257 Family *family;
1258 Face *face;
1259 struct list *family_elem_ptr, *face_elem_ptr;
1261 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1262 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1263 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1264 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1265 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1266 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1267 if(!face->scalable)
1268 TRACE(" %d", face->size.height);
1269 TRACE("\n");
1272 return;
1275 /***********************************************************
1276 * The replacement list is a way to map an entire font
1277 * family onto another family. For example adding
1279 * [HKCU\Software\Wine\Fonts\Replacements]
1280 * "Wingdings"="Winedings"
1282 * would enumerate the Winedings font both as Winedings and
1283 * Wingdings. However if a real Wingdings font is present the
1284 * replacement does not take place.
1287 static void LoadReplaceList(void)
1289 HKEY hkey;
1290 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1291 LPWSTR value;
1292 LPVOID data;
1293 Family *family;
1294 Face *face;
1295 struct list *family_elem_ptr, *face_elem_ptr;
1296 CHAR familyA[400];
1298 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1299 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1301 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1302 &valuelen, &datalen, NULL, NULL);
1304 valuelen++; /* returned value doesn't include room for '\0' */
1305 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1306 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1308 dlen = datalen;
1309 vlen = valuelen;
1310 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1311 &dlen) == ERROR_SUCCESS) {
1312 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1313 /* "NewName"="Oldname" */
1314 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1316 /* Find the old family and hence all of the font files
1317 in that family */
1318 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1319 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1320 if(!strcmpiW(family->FamilyName, data)) {
1321 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1322 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1323 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1324 debugstr_w(face->StyleName), familyA);
1325 /* Now add a new entry with the new family name */
1326 AddFontToList(face->file, face->font_data_ptr, face->font_data_size, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1328 break;
1331 /* reset dlen and vlen */
1332 dlen = datalen;
1333 vlen = valuelen;
1335 HeapFree(GetProcessHeap(), 0, data);
1336 HeapFree(GetProcessHeap(), 0, value);
1337 RegCloseKey(hkey);
1341 /*************************************************************
1342 * init_system_links
1344 static BOOL init_system_links(void)
1346 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1347 'W','i','n','d','o','w','s',' ','N','T','\\',
1348 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1349 'S','y','s','t','e','m','L','i','n','k',0};
1350 HKEY hkey;
1351 BOOL ret = FALSE;
1352 DWORD type, max_val, max_data, val_len, data_len, index;
1353 WCHAR *value, *data;
1354 WCHAR *entry, *next;
1355 SYSTEM_LINKS *font_link, *system_font_link;
1356 CHILD_FONT *child_font;
1357 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
1358 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1359 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1360 FONTSIGNATURE fs;
1361 Family *family;
1362 Face *face;
1363 FontSubst *psub;
1365 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1367 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1368 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1369 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1370 val_len = max_val + 1;
1371 data_len = max_data;
1372 index = 0;
1373 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1375 TRACE("%s:\n", debugstr_w(value));
1377 memset(&fs, 0, sizeof(fs));
1378 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1379 psub = get_font_subst(&font_subst_list, value, -1);
1380 font_link->font_name = (psub)? strdupW(psub->to.name) : strdupW(value);
1381 list_init(&font_link->links);
1382 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1384 WCHAR *face_name;
1385 CHILD_FONT *child_font;
1387 TRACE("\t%s\n", debugstr_w(entry));
1389 next = entry + strlenW(entry) + 1;
1391 face_name = strchrW(entry, ',');
1392 if(face_name)
1394 *face_name++ = 0;
1395 while(isspaceW(*face_name))
1396 face_name++;
1398 psub = get_font_subst(&font_subst_list, face_name, -1);
1399 if(psub)
1400 face_name = psub->to.name;
1402 face = find_face_from_filename(entry, face_name);
1403 if(!face)
1405 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1406 continue;
1409 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1410 child_font->face = face;
1411 child_font->font = NULL;
1412 fs.fsCsb[0] |= face->fs.fsCsb[0];
1413 fs.fsCsb[1] |= face->fs.fsCsb[1];
1414 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1415 list_add_tail(&font_link->links, &child_font->entry);
1417 family = find_family_from_name(font_link->font_name);
1418 if(family)
1420 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1422 memcpy(&face->fs_links, &fs, sizeof(fs));
1425 list_add_tail(&system_links, &font_link->entry);
1426 val_len = max_val + 1;
1427 data_len = max_data;
1430 HeapFree(GetProcessHeap(), 0, value);
1431 HeapFree(GetProcessHeap(), 0, data);
1432 RegCloseKey(hkey);
1435 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1436 that Tahoma has */
1438 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1439 system_font_link->font_name = strdupW(System);
1440 list_init(&system_font_link->links);
1442 face = find_face_from_filename(tahoma_ttf, Tahoma);
1443 if(face)
1445 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1446 child_font->face = face;
1447 child_font->font = NULL;
1448 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
1449 list_add_tail(&system_font_link->links, &child_font->entry);
1451 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1453 if(!strcmpiW(font_link->font_name, Tahoma))
1455 CHILD_FONT *font_link_entry;
1456 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1458 CHILD_FONT *new_child;
1459 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1460 new_child->face = font_link_entry->face;
1461 new_child->font = NULL;
1462 list_add_tail(&system_font_link->links, &new_child->entry);
1464 break;
1467 list_add_tail(&system_links, &system_font_link->entry);
1468 return ret;
1471 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1473 DIR *dir;
1474 struct dirent *dent;
1475 char path[MAX_PATH];
1477 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1479 dir = opendir(dirname);
1480 if(!dir) {
1481 WARN("Can't open directory %s\n", debugstr_a(dirname));
1482 return FALSE;
1484 while((dent = readdir(dir)) != NULL) {
1485 struct stat statbuf;
1487 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1488 continue;
1490 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1492 sprintf(path, "%s/%s", dirname, dent->d_name);
1494 if(stat(path, &statbuf) == -1)
1496 WARN("Can't stat %s\n", debugstr_a(path));
1497 continue;
1499 if(S_ISDIR(statbuf.st_mode))
1500 ReadFontDir(path, external_fonts);
1501 else
1502 AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1504 closedir(dir);
1505 return TRUE;
1508 static void load_fontconfig_fonts(void)
1510 #ifdef SONAME_LIBFONTCONFIG
1511 void *fc_handle = NULL;
1512 FcConfig *config;
1513 FcPattern *pat;
1514 FcObjectSet *os;
1515 FcFontSet *fontset;
1516 int i, len;
1517 char *file;
1518 const char *ext;
1520 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1521 if(!fc_handle) {
1522 TRACE("Wine cannot find the fontconfig library (%s).\n",
1523 SONAME_LIBFONTCONFIG);
1524 return;
1526 #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;}
1527 LOAD_FUNCPTR(FcConfigGetCurrent);
1528 LOAD_FUNCPTR(FcFontList);
1529 LOAD_FUNCPTR(FcFontSetDestroy);
1530 LOAD_FUNCPTR(FcInit);
1531 LOAD_FUNCPTR(FcObjectSetAdd);
1532 LOAD_FUNCPTR(FcObjectSetCreate);
1533 LOAD_FUNCPTR(FcObjectSetDestroy);
1534 LOAD_FUNCPTR(FcPatternCreate);
1535 LOAD_FUNCPTR(FcPatternDestroy);
1536 LOAD_FUNCPTR(FcPatternGetBool);
1537 LOAD_FUNCPTR(FcPatternGetString);
1538 #undef LOAD_FUNCPTR
1540 if(!pFcInit()) return;
1542 config = pFcConfigGetCurrent();
1543 pat = pFcPatternCreate();
1544 os = pFcObjectSetCreate();
1545 pFcObjectSetAdd(os, FC_FILE);
1546 pFcObjectSetAdd(os, FC_SCALABLE);
1547 fontset = pFcFontList(config, pat, os);
1548 if(!fontset) return;
1549 for(i = 0; i < fontset->nfont; i++) {
1550 FcBool scalable;
1552 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1553 continue;
1554 TRACE("fontconfig: %s\n", file);
1556 /* We're just interested in OT/TT fonts for now, so this hack just
1557 picks up the scalable fonts without extensions .pf[ab] to save time
1558 loading every other font */
1560 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1562 TRACE("not scalable\n");
1563 continue;
1566 len = strlen( file );
1567 if(len < 4) continue;
1568 ext = &file[ len - 3 ];
1569 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1570 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT);
1572 pFcFontSetDestroy(fontset);
1573 pFcObjectSetDestroy(os);
1574 pFcPatternDestroy(pat);
1575 sym_not_found:
1576 #endif
1577 return;
1580 static BOOL load_font_from_data_dir(LPCWSTR file)
1582 BOOL ret = FALSE;
1583 const char *data_dir = wine_get_data_dir();
1585 if (!data_dir) data_dir = wine_get_build_dir();
1587 if (data_dir)
1589 INT len;
1590 char *unix_name;
1592 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1594 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1596 strcpy(unix_name, data_dir);
1597 strcat(unix_name, "/fonts/");
1599 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1601 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1602 HeapFree(GetProcessHeap(), 0, unix_name);
1604 return ret;
1607 static void load_system_fonts(void)
1609 HKEY hkey;
1610 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1611 const WCHAR * const *value;
1612 DWORD dlen, type;
1613 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1614 char *unixname;
1616 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1617 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1618 strcatW(windowsdir, fontsW);
1619 for(value = SystemFontValues; *value; value++) {
1620 dlen = sizeof(data);
1621 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1622 type == REG_SZ) {
1623 BOOL added = FALSE;
1625 sprintfW(pathW, fmtW, windowsdir, data);
1626 if((unixname = wine_get_unix_file_name(pathW))) {
1627 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1628 HeapFree(GetProcessHeap(), 0, unixname);
1630 if (!added)
1631 load_font_from_data_dir(data);
1634 RegCloseKey(hkey);
1638 /*************************************************************
1640 * This adds registry entries for any externally loaded fonts
1641 * (fonts from fontconfig or FontDirs). It also deletes entries
1642 * of no longer existing fonts.
1645 static void update_reg_entries(void)
1647 HKEY winkey = 0, externalkey = 0;
1648 LPWSTR valueW;
1649 LPVOID data;
1650 DWORD dlen, vlen, datalen, valuelen, i, type, len, len_fam;
1651 Family *family;
1652 Face *face;
1653 struct list *family_elem_ptr, *face_elem_ptr;
1654 WCHAR *file;
1655 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1656 static const WCHAR spaceW[] = {' ', '\0'};
1657 char *path;
1659 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1660 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winkey, NULL) != ERROR_SUCCESS) {
1661 ERR("Can't create Windows font reg key\n");
1662 goto end;
1664 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1665 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &externalkey) != ERROR_SUCCESS) {
1666 ERR("Can't create external font reg key\n");
1667 goto end;
1670 /* Delete all external fonts added last time */
1672 RegQueryInfoKeyW(externalkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1673 &valuelen, &datalen, NULL, NULL);
1674 valuelen++; /* returned value doesn't include room for '\0' */
1675 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1676 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1678 dlen = datalen * sizeof(WCHAR);
1679 vlen = valuelen;
1680 i = 0;
1681 while(RegEnumValueW(externalkey, i++, valueW, &vlen, NULL, &type, data,
1682 &dlen) == ERROR_SUCCESS) {
1684 RegDeleteValueW(winkey, valueW);
1685 /* reset dlen and vlen */
1686 dlen = datalen;
1687 vlen = valuelen;
1689 HeapFree(GetProcessHeap(), 0, data);
1690 HeapFree(GetProcessHeap(), 0, valueW);
1692 /* Delete the old external fonts key */
1693 RegCloseKey(externalkey);
1694 externalkey = 0;
1695 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
1697 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1698 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1699 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
1700 ERR("Can't create external font reg key\n");
1701 goto end;
1704 /* enumerate the fonts and add external ones to the two keys */
1706 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1707 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1708 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1709 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1710 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1711 if(!face->external) continue;
1712 len = len_fam;
1713 if(strcmpiW(face->StyleName, RegularW))
1714 len = len_fam + strlenW(face->StyleName) + 1;
1715 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1716 strcpyW(valueW, family->FamilyName);
1717 if(len != len_fam) {
1718 strcatW(valueW, spaceW);
1719 strcatW(valueW, face->StyleName);
1721 strcatW(valueW, TrueType);
1722 if((path = strrchr(face->file, '/')) == NULL)
1723 path = face->file;
1724 else
1725 path++;
1726 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1728 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1729 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1730 RegSetValueExW(winkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1731 RegSetValueExW(externalkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1733 HeapFree(GetProcessHeap(), 0, file);
1734 HeapFree(GetProcessHeap(), 0, valueW);
1737 end:
1738 if(externalkey)
1739 RegCloseKey(externalkey);
1740 if(winkey)
1741 RegCloseKey(winkey);
1742 return;
1746 /*************************************************************
1747 * WineEngAddFontResourceEx
1750 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1752 if (ft_handle) /* do it only if we have freetype up and running */
1754 char *unixname;
1756 if(flags)
1757 FIXME("Ignoring flags %x\n", flags);
1759 if((unixname = wine_get_unix_file_name(file)))
1761 INT ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1762 HeapFree(GetProcessHeap(), 0, unixname);
1763 return ret;
1766 return 0;
1769 /*************************************************************
1770 * WineEngAddFontMemResourceEx
1773 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
1775 if (ft_handle) /* do it only if we have freetype up and running */
1777 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
1779 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
1780 memcpy(pFontCopy, pbFont, cbFont);
1782 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
1784 if (*pcFonts == 0)
1786 TRACE("AddFontToList failed\n");
1787 HeapFree(GetProcessHeap(), 0, pFontCopy);
1788 return NULL;
1790 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
1791 * For now return something unique but quite random
1793 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
1794 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
1797 *pcFonts = 0;
1798 return 0;
1801 /*************************************************************
1802 * WineEngRemoveFontResourceEx
1805 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1807 FIXME(":stub\n");
1808 return TRUE;
1811 static const struct nls_update_font_list
1813 UINT ansi_cp, oem_cp;
1814 const char *oem, *fixed, *system;
1815 const char *courier, *serif, *small, *sserif;
1816 /* these are for font substitute */
1817 const char *shelldlg, *tmsrmn;
1818 } nls_update_font_list[] =
1820 /* Latin 1 (United States) */
1821 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
1822 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1823 "Tahoma","Times New Roman",
1825 /* Latin 1 (Multilingual) */
1826 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
1827 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1828 "Tahoma","Times New Roman", /* FIXME unverified */
1830 /* Eastern Europe */
1831 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
1832 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
1833 "Tahoma","Times New Roman", /* FIXME unverified */
1835 /* Cyrillic */
1836 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
1837 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
1838 "Tahoma","Times New Roman", /* FIXME unverified */
1840 /* Greek */
1841 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
1842 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
1843 "Tahoma","Times New Roman", /* FIXME unverified */
1845 /* Turkish */
1846 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
1847 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
1848 "Tahoma","Times New Roman", /* FIXME unverified */
1850 /* Hebrew */
1851 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
1852 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
1853 "Tahoma","Times New Roman", /* FIXME unverified */
1855 /* Arabic */
1856 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
1857 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
1858 "Tahoma","Times New Roman", /* FIXME unverified */
1860 /* Baltic */
1861 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
1862 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
1863 "Tahoma","Times New Roman", /* FIXME unverified */
1865 /* Vietnamese */
1866 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
1867 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1868 "Tahoma","Times New Roman", /* FIXME unverified */
1870 /* Thai */
1871 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
1872 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
1873 "Tahoma","Times New Roman", /* FIXME unverified */
1875 /* Japanese */
1876 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
1877 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
1878 "MS UI Gothic","MS Serif",
1880 /* Chinese Simplified */
1881 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
1882 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1883 "Tahoma", "Times New Roman", /* FIXME unverified */
1885 /* Korean */
1886 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
1887 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1888 "Gulim", "Batang",
1890 /* Chinese Traditional */
1891 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
1892 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1893 "Tahoma", "Times New Roman", /* FIXME unverified */
1897 static inline HKEY create_fonts_NT_registry_key(void)
1899 HKEY hkey = 0;
1901 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
1902 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1903 return hkey;
1906 static inline HKEY create_fonts_9x_registry_key(void)
1908 HKEY hkey = 0;
1910 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
1911 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1912 return hkey;
1915 static inline HKEY create_config_fonts_registry_key(void)
1917 HKEY hkey = 0;
1919 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
1920 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1921 return hkey;
1924 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
1926 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
1927 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
1928 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
1929 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
1932 static void update_font_info(void)
1934 char buf[40], cpbuf[40];
1935 DWORD len, type;
1936 HKEY hkey = 0;
1937 UINT i, ansi_cp = 0, oem_cp = 0;
1939 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
1940 return;
1942 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
1943 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
1944 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
1945 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
1946 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
1948 len = sizeof(buf);
1949 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
1951 if (!strcmp( buf, cpbuf )) /* already set correctly */
1953 RegCloseKey(hkey);
1954 return;
1956 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
1958 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
1960 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
1961 RegCloseKey(hkey);
1963 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
1965 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
1966 nls_update_font_list[i].oem_cp == oem_cp)
1968 HKEY hkey;
1970 hkey = create_config_fonts_registry_key();
1971 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
1972 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
1973 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
1974 RegCloseKey(hkey);
1976 hkey = create_fonts_NT_registry_key();
1977 add_font_list(hkey, &nls_update_font_list[i]);
1978 RegCloseKey(hkey);
1980 hkey = create_fonts_9x_registry_key();
1981 add_font_list(hkey, &nls_update_font_list[i]);
1982 RegCloseKey(hkey);
1984 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
1986 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
1987 strlen(nls_update_font_list[i].shelldlg)+1);
1988 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
1989 strlen(nls_update_font_list[i].tmsrmn)+1);
1990 RegCloseKey(hkey);
1992 return;
1995 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
1998 /*************************************************************
1999 * WineEngInit
2001 * Initialize FreeType library and create a list of available faces
2003 BOOL WineEngInit(void)
2005 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2006 static const WCHAR pathW[] = {'P','a','t','h',0};
2007 HKEY hkey;
2008 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2009 LPVOID data;
2010 WCHAR windowsdir[MAX_PATH];
2011 char *unixname;
2012 HANDLE font_mutex;
2013 const char *data_dir;
2015 TRACE("\n");
2017 /* update locale dependent font info in registry */
2018 update_font_info();
2020 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2021 if(!ft_handle) {
2022 WINE_MESSAGE(
2023 "Wine cannot find the FreeType font library. To enable Wine to\n"
2024 "use TrueType fonts please install a version of FreeType greater than\n"
2025 "or equal to 2.0.5.\n"
2026 "http://www.freetype.org\n");
2027 return FALSE;
2030 #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;}
2032 LOAD_FUNCPTR(FT_Vector_Unit)
2033 LOAD_FUNCPTR(FT_Done_Face)
2034 LOAD_FUNCPTR(FT_Get_Char_Index)
2035 LOAD_FUNCPTR(FT_Get_Module)
2036 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2037 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2038 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2039 LOAD_FUNCPTR(FT_Init_FreeType)
2040 LOAD_FUNCPTR(FT_Load_Glyph)
2041 LOAD_FUNCPTR(FT_Matrix_Multiply)
2042 LOAD_FUNCPTR(FT_MulFix)
2043 LOAD_FUNCPTR(FT_New_Face)
2044 LOAD_FUNCPTR(FT_New_Memory_Face)
2045 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2046 LOAD_FUNCPTR(FT_Outline_Transform)
2047 LOAD_FUNCPTR(FT_Outline_Translate)
2048 LOAD_FUNCPTR(FT_Select_Charmap)
2049 LOAD_FUNCPTR(FT_Set_Charmap)
2050 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2051 LOAD_FUNCPTR(FT_Vector_Transform)
2053 #undef LOAD_FUNCPTR
2054 /* Don't warn if this one is missing */
2055 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
2056 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
2057 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
2058 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
2059 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2060 #ifdef HAVE_FREETYPE_FTWINFNT_H
2061 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2062 #endif
2063 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2064 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2065 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2066 <= 2.0.3 has FT_Sqrt64 */
2067 goto sym_not_found;
2070 if(pFT_Init_FreeType(&library) != 0) {
2071 ERR("Can't init FreeType library\n");
2072 wine_dlclose(ft_handle, NULL, 0);
2073 ft_handle = NULL;
2074 return FALSE;
2076 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
2077 if (pFT_Library_Version)
2079 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2081 if (FT_Version.major<=0)
2083 FT_Version.major=2;
2084 FT_Version.minor=0;
2085 FT_Version.patch=5;
2087 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2088 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2089 ((FT_Version.minor << 8) & 0x00ff00) |
2090 ((FT_Version.patch ) & 0x0000ff);
2092 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2093 ERR("Failed to create font mutex\n");
2094 return FALSE;
2096 WaitForSingleObject(font_mutex, INFINITE);
2098 /* load the system bitmap fonts */
2099 load_system_fonts();
2101 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2102 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2103 strcatW(windowsdir, fontsW);
2104 if((unixname = wine_get_unix_file_name(windowsdir)))
2106 ReadFontDir(unixname, FALSE);
2107 HeapFree(GetProcessHeap(), 0, unixname);
2110 /* load the system truetype fonts */
2111 data_dir = wine_get_data_dir();
2112 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2113 strcpy(unixname, data_dir);
2114 strcat(unixname, "/fonts/");
2115 ReadFontDir(unixname, TRUE);
2116 HeapFree(GetProcessHeap(), 0, unixname);
2119 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2120 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2121 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2122 will skip these. */
2123 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2124 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2125 &hkey) == ERROR_SUCCESS) {
2126 LPWSTR valueW;
2127 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2128 &valuelen, &datalen, NULL, NULL);
2130 valuelen++; /* returned value doesn't include room for '\0' */
2131 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2132 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2133 if (valueW && data)
2135 dlen = datalen * sizeof(WCHAR);
2136 vlen = valuelen;
2137 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
2138 &dlen) == ERROR_SUCCESS) {
2139 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
2141 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
2143 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2144 HeapFree(GetProcessHeap(), 0, unixname);
2147 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
2149 WCHAR pathW[MAX_PATH];
2150 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2151 BOOL added = FALSE;
2153 sprintfW(pathW, fmtW, windowsdir, data);
2154 if((unixname = wine_get_unix_file_name(pathW)))
2156 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2157 HeapFree(GetProcessHeap(), 0, unixname);
2159 if (!added)
2160 load_font_from_data_dir(data);
2162 /* reset dlen and vlen */
2163 dlen = datalen;
2164 vlen = valuelen;
2167 HeapFree(GetProcessHeap(), 0, data);
2168 HeapFree(GetProcessHeap(), 0, valueW);
2169 RegCloseKey(hkey);
2172 load_fontconfig_fonts();
2174 /* then look in any directories that we've specified in the config file */
2175 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2176 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2178 DWORD len;
2179 LPWSTR valueW;
2180 LPSTR valueA, ptr;
2182 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2184 len += sizeof(WCHAR);
2185 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2186 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2188 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2189 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2190 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2191 TRACE( "got font path %s\n", debugstr_a(valueA) );
2192 ptr = valueA;
2193 while (ptr)
2195 LPSTR next = strchr( ptr, ':' );
2196 if (next) *next++ = 0;
2197 ReadFontDir( ptr, TRUE );
2198 ptr = next;
2200 HeapFree( GetProcessHeap(), 0, valueA );
2202 HeapFree( GetProcessHeap(), 0, valueW );
2204 RegCloseKey(hkey);
2207 DumpFontList();
2208 LoadSubstList();
2209 DumpSubstList();
2210 LoadReplaceList();
2211 update_reg_entries();
2213 init_system_links();
2215 ReleaseMutex(font_mutex);
2216 return TRUE;
2217 sym_not_found:
2218 WINE_MESSAGE(
2219 "Wine cannot find certain functions that it needs inside the FreeType\n"
2220 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2221 "FreeType to at least version 2.0.5.\n"
2222 "http://www.freetype.org\n");
2223 wine_dlclose(ft_handle, NULL, 0);
2224 ft_handle = NULL;
2225 return FALSE;
2229 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2231 TT_OS2 *pOS2;
2232 TT_HoriHeader *pHori;
2234 LONG ppem;
2236 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2237 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2239 if(height == 0) height = 16;
2241 /* Calc. height of EM square:
2243 * For +ve lfHeight we have
2244 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2245 * Re-arranging gives:
2246 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2248 * For -ve lfHeight we have
2249 * |lfHeight| = ppem
2250 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2251 * with il = winAscent + winDescent - units_per_em]
2255 if(height > 0) {
2256 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2257 ppem = ft_face->units_per_EM * height /
2258 (pHori->Ascender - pHori->Descender);
2259 else
2260 ppem = ft_face->units_per_EM * height /
2261 (pOS2->usWinAscent + pOS2->usWinDescent);
2263 else
2264 ppem = -height;
2266 return ppem;
2269 static struct font_mapping *map_font_file( const char *name )
2271 struct font_mapping *mapping;
2272 struct stat st;
2273 int fd;
2275 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2276 if (fstat( fd, &st ) == -1) goto error;
2278 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2280 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2282 mapping->refcount++;
2283 close( fd );
2284 return mapping;
2287 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2288 goto error;
2290 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2291 close( fd );
2293 if (mapping->data == MAP_FAILED)
2295 HeapFree( GetProcessHeap(), 0, mapping );
2296 return NULL;
2298 mapping->refcount = 1;
2299 mapping->dev = st.st_dev;
2300 mapping->ino = st.st_ino;
2301 mapping->size = st.st_size;
2302 list_add_tail( &mappings_list, &mapping->entry );
2303 return mapping;
2305 error:
2306 close( fd );
2307 return NULL;
2310 static void unmap_font_file( struct font_mapping *mapping )
2312 if (!--mapping->refcount)
2314 list_remove( &mapping->entry );
2315 munmap( mapping->data, mapping->size );
2316 HeapFree( GetProcessHeap(), 0, mapping );
2320 static LONG load_VDMX(GdiFont*, LONG);
2322 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
2324 FT_Error err;
2325 FT_Face ft_face;
2326 void *data_ptr;
2327 DWORD data_size;
2329 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
2331 if (face->file)
2333 if (!(font->mapping = map_font_file( face->file )))
2335 WARN("failed to map %s\n", debugstr_a(face->file));
2336 return 0;
2338 data_ptr = font->mapping->data;
2339 data_size = font->mapping->size;
2341 else
2343 data_ptr = face->font_data_ptr;
2344 data_size = face->font_data_size;
2347 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
2348 if(err) {
2349 ERR("FT_New_Face rets %d\n", err);
2350 return 0;
2353 /* set it here, as load_VDMX needs it */
2354 font->ft_face = ft_face;
2356 if(FT_IS_SCALABLE(ft_face)) {
2357 /* load the VDMX table if we have one */
2358 font->ppem = load_VDMX(font, height);
2359 if(font->ppem == 0)
2360 font->ppem = calc_ppem_for_height(ft_face, height);
2362 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
2363 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
2364 } else {
2365 font->ppem = height;
2366 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
2367 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
2369 return ft_face;
2373 static int get_nearest_charset(Face *face, int *cp)
2375 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2376 a single face with the requested charset. The idea is to check if
2377 the selected font supports the current ANSI codepage, if it does
2378 return the corresponding charset, else return the first charset */
2380 CHARSETINFO csi;
2381 int acp = GetACP(), i;
2382 DWORD fs0;
2384 *cp = acp;
2385 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
2386 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2387 return csi.ciCharset;
2389 for(i = 0; i < 32; i++) {
2390 fs0 = 1L << i;
2391 if(face->fs.fsCsb[0] & fs0) {
2392 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
2393 *cp = csi.ciACP;
2394 return csi.ciCharset;
2396 else
2397 FIXME("TCI failing on %x\n", fs0);
2401 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2402 face->fs.fsCsb[0], face->file);
2403 *cp = acp;
2404 return DEFAULT_CHARSET;
2407 static GdiFont *alloc_font(void)
2409 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
2410 ret->gmsize = 1;
2411 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
2412 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
2413 ret->potm = NULL;
2414 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
2415 ret->total_kern_pairs = (DWORD)-1;
2416 ret->kern_pairs = NULL;
2417 list_init(&ret->hfontlist);
2418 list_init(&ret->child_fonts);
2419 return ret;
2422 static void free_font(GdiFont *font)
2424 struct list *cursor, *cursor2;
2425 int i;
2427 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
2429 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
2430 struct list *first_hfont;
2431 HFONTLIST *hfontlist;
2432 list_remove(cursor);
2433 if(child->font)
2435 first_hfont = list_head(&child->font->hfontlist);
2436 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2437 DeleteObject(hfontlist->hfont);
2438 HeapFree(GetProcessHeap(), 0, hfontlist);
2439 free_font(child->font);
2441 HeapFree(GetProcessHeap(), 0, child);
2444 if (font->ft_face) pFT_Done_Face(font->ft_face);
2445 if (font->mapping) unmap_font_file( font->mapping );
2446 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
2447 HeapFree(GetProcessHeap(), 0, font->potm);
2448 HeapFree(GetProcessHeap(), 0, font->name);
2449 for (i = 0; i < font->gmsize; i++)
2450 HeapFree(GetProcessHeap(),0,font->gm[i]);
2451 HeapFree(GetProcessHeap(), 0, font->gm);
2452 HeapFree(GetProcessHeap(), 0, font);
2456 /*************************************************************
2457 * load_VDMX
2459 * load the vdmx entry for the specified height
2462 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2463 ( ( (FT_ULong)_x4 << 24 ) | \
2464 ( (FT_ULong)_x3 << 16 ) | \
2465 ( (FT_ULong)_x2 << 8 ) | \
2466 (FT_ULong)_x1 )
2468 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2470 typedef struct {
2471 BYTE bCharSet;
2472 BYTE xRatio;
2473 BYTE yStartRatio;
2474 BYTE yEndRatio;
2475 } Ratios;
2477 typedef struct {
2478 WORD recs;
2479 BYTE startsz;
2480 BYTE endsz;
2481 } VDMX_group;
2483 static LONG load_VDMX(GdiFont *font, LONG height)
2485 WORD hdr[3], tmp;
2486 VDMX_group group;
2487 BYTE devXRatio, devYRatio;
2488 USHORT numRecs, numRatios;
2489 DWORD result, offset = -1;
2490 LONG ppem = 0;
2491 int i;
2493 /* For documentation on VDMX records, see
2494 * http://www.microsoft.com/OpenType/OTSpec/vdmx.htm
2497 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
2499 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2500 return ppem;
2502 /* FIXME: need the real device aspect ratio */
2503 devXRatio = 1;
2504 devYRatio = 1;
2506 numRecs = GET_BE_WORD(hdr[1]);
2507 numRatios = GET_BE_WORD(hdr[2]);
2509 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
2510 for(i = 0; i < numRatios; i++) {
2511 Ratios ratio;
2513 offset = (3 * 2) + (i * sizeof(Ratios));
2514 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2515 offset = -1;
2517 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2519 if((ratio.xRatio == 0 &&
2520 ratio.yStartRatio == 0 &&
2521 ratio.yEndRatio == 0) ||
2522 (devXRatio == ratio.xRatio &&
2523 devYRatio >= ratio.yStartRatio &&
2524 devYRatio <= ratio.yEndRatio))
2526 offset = (3 * 2) + (numRatios * 4) + (i * 2);
2527 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
2528 offset = GET_BE_WORD(tmp);
2529 break;
2533 if(offset == -1) {
2534 FIXME("No suitable ratio found\n");
2535 return ppem;
2538 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
2539 USHORT recs;
2540 BYTE startsz, endsz;
2541 WORD *vTable;
2543 recs = GET_BE_WORD(group.recs);
2544 startsz = group.startsz;
2545 endsz = group.endsz;
2547 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
2549 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
2550 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
2551 if(result == GDI_ERROR) {
2552 FIXME("Failed to retrieve vTable\n");
2553 goto end;
2556 if(height > 0) {
2557 for(i = 0; i < recs; i++) {
2558 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2559 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2560 ppem = GET_BE_WORD(vTable[i * 3]);
2562 if(yMax + -yMin == height) {
2563 font->yMax = yMax;
2564 font->yMin = yMin;
2565 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2566 break;
2568 if(yMax + -yMin > height) {
2569 if(--i < 0) {
2570 ppem = 0;
2571 goto end; /* failed */
2573 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2574 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2575 ppem = GET_BE_WORD(vTable[i * 3]);
2576 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2577 break;
2580 if(!font->yMax) {
2581 ppem = 0;
2582 TRACE("ppem not found for height %d\n", height);
2584 } else {
2585 ppem = -height;
2586 if(ppem < startsz || ppem > endsz)
2587 goto end;
2589 for(i = 0; i < recs; i++) {
2590 USHORT yPelHeight;
2591 yPelHeight = GET_BE_WORD(vTable[i * 3]);
2593 if(yPelHeight > ppem)
2594 break; /* failed */
2596 if(yPelHeight == ppem) {
2597 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2598 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2599 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
2600 break;
2604 end:
2605 HeapFree(GetProcessHeap(), 0, vTable);
2608 return ppem;
2611 static BOOL fontcmp(GdiFont *font, FONT_DESC *fd)
2613 if(font->font_desc.hash != fd->hash) return TRUE;
2614 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
2615 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
2616 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
2617 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
2620 static void calc_hash(FONT_DESC *pfd)
2622 DWORD hash = 0, *ptr, two_chars;
2623 WORD *pwc;
2624 unsigned int i;
2626 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
2627 hash ^= *ptr;
2628 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
2629 hash ^= *ptr;
2630 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
2631 two_chars = *ptr;
2632 pwc = (WCHAR *)&two_chars;
2633 if(!*pwc) break;
2634 *pwc = toupperW(*pwc);
2635 pwc++;
2636 *pwc = toupperW(*pwc);
2637 hash ^= two_chars;
2638 if(!*pwc) break;
2640 hash ^= !pfd->can_use_bitmap;
2641 pfd->hash = hash;
2642 return;
2645 static GdiFont *find_in_cache(HFONT hfont, LOGFONTW *plf, XFORM *pxf, BOOL can_use_bitmap)
2647 GdiFont *ret;
2648 FONT_DESC fd;
2649 HFONTLIST *hflist;
2650 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2652 memcpy(&fd.lf, plf, sizeof(LOGFONTW));
2653 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
2654 fd.can_use_bitmap = can_use_bitmap;
2655 calc_hash(&fd);
2657 /* try the in-use list */
2658 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
2659 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2660 if(!fontcmp(ret, &fd)) {
2661 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2662 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
2663 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2664 if(hflist->hfont == hfont)
2665 return ret;
2667 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2668 hflist->hfont = hfont;
2669 list_add_head(&ret->hfontlist, &hflist->entry);
2670 return ret;
2674 /* then the unused list */
2675 font_elem_ptr = list_head(&unused_gdi_font_list);
2676 while(font_elem_ptr) {
2677 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2678 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2679 if(!fontcmp(ret, &fd)) {
2680 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2681 assert(list_empty(&ret->hfontlist));
2682 TRACE("Found %p in unused list\n", ret);
2683 list_remove(&ret->entry);
2684 list_add_head(&gdi_font_list, &ret->entry);
2685 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2686 hflist->hfont = hfont;
2687 list_add_head(&ret->hfontlist, &hflist->entry);
2688 return ret;
2691 return NULL;
2695 /*************************************************************
2696 * create_child_font_list
2698 static BOOL create_child_font_list(GdiFont *font)
2700 BOOL ret = FALSE;
2701 SYSTEM_LINKS *font_link;
2702 CHILD_FONT *font_link_entry, *new_child;
2704 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2706 if(!strcmpW(font_link->font_name, font->name))
2708 TRACE("found entry in system list\n");
2709 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2711 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2712 new_child->face = font_link_entry->face;
2713 new_child->font = NULL;
2714 list_add_tail(&font->child_fonts, &new_child->entry);
2715 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
2717 ret = TRUE;
2718 break;
2722 return ret;
2725 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
2727 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
2729 if (pFT_Set_Charmap)
2731 FT_Int i;
2732 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
2734 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
2736 for (i = 0; i < ft_face->num_charmaps; i++)
2738 if (ft_face->charmaps[i]->encoding == encoding)
2740 TRACE("found cmap with platform_id %u, encoding_id %u\n",
2741 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
2743 switch (ft_face->charmaps[i]->platform_id)
2745 default:
2746 cmap_def = ft_face->charmaps[i];
2747 break;
2748 case 0: /* Apple Unicode */
2749 cmap0 = ft_face->charmaps[i];
2750 break;
2751 case 1: /* Macintosh */
2752 cmap1 = ft_face->charmaps[i];
2753 break;
2754 case 2: /* ISO */
2755 cmap2 = ft_face->charmaps[i];
2756 break;
2757 case 3: /* Microsoft */
2758 cmap3 = ft_face->charmaps[i];
2759 break;
2763 if (cmap3) /* prefer Microsoft cmap table */
2764 ft_err = pFT_Set_Charmap(ft_face, cmap3);
2765 else if (cmap1)
2766 ft_err = pFT_Set_Charmap(ft_face, cmap1);
2767 else if (cmap2)
2768 ft_err = pFT_Set_Charmap(ft_face, cmap2);
2769 else if (cmap0)
2770 ft_err = pFT_Set_Charmap(ft_face, cmap0);
2771 else if (cmap_def)
2772 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
2774 return ft_err == FT_Err_Ok;
2777 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
2780 /*************************************************************
2781 * WineEngCreateFontInstance
2784 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
2786 GdiFont *ret;
2787 Face *face, *best, *best_bitmap;
2788 Family *family, *last_resort_family;
2789 struct list *family_elem_ptr, *face_elem_ptr;
2790 INT height, width = 0;
2791 unsigned int score = 0, new_score;
2792 signed int diff = 0, newdiff;
2793 BOOL bd, it, can_use_bitmap;
2794 LOGFONTW lf;
2795 CHARSETINFO csi;
2796 HFONTLIST *hflist;
2798 LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry)
2800 struct list *first_hfont = list_head(&ret->hfontlist);
2801 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2802 if(hflist->hfont == hfont)
2803 return ret;
2806 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
2807 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
2809 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
2810 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
2811 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
2812 lf.lfEscapement);
2814 /* check the cache first */
2815 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
2816 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
2817 return ret;
2820 TRACE("not in cache\n");
2821 if(list_empty(&font_list)) /* No fonts installed */
2823 TRACE("No fonts installed\n");
2824 return NULL;
2826 if(!have_installed_roman_font)
2828 TRACE("No roman font installed\n");
2829 return NULL;
2832 ret = alloc_font();
2834 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
2835 memcpy(&ret->font_desc.lf, &lf, sizeof(LOGFONTW));
2836 ret->font_desc.can_use_bitmap = can_use_bitmap;
2837 calc_hash(&ret->font_desc);
2838 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2839 hflist->hfont = hfont;
2840 list_add_head(&ret->hfontlist, &hflist->entry);
2843 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
2844 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
2845 original value lfCharSet. Note this is a special case for
2846 Symbol and doesn't happen at least for "Wingdings*" */
2848 if(!strcmpiW(lf.lfFaceName, SymbolW))
2849 lf.lfCharSet = SYMBOL_CHARSET;
2851 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
2852 switch(lf.lfCharSet) {
2853 case DEFAULT_CHARSET:
2854 csi.fs.fsCsb[0] = 0;
2855 break;
2856 default:
2857 FIXME("Untranslated charset %d\n", lf.lfCharSet);
2858 csi.fs.fsCsb[0] = 0;
2859 break;
2863 family = NULL;
2864 if(lf.lfFaceName[0] != '\0') {
2865 FontSubst *psub;
2866 SYSTEM_LINKS *font_link;
2867 CHILD_FONT *font_link_entry;
2869 psub = get_font_subst(&font_subst_list, lf.lfFaceName, lf.lfCharSet);
2871 if(psub) {
2872 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
2873 debugstr_w(psub->to.name));
2874 strcpyW(lf.lfFaceName, psub->to.name);
2877 /* We want a match on name and charset or just name if
2878 charset was DEFAULT_CHARSET. If the latter then
2879 we fixup the returned charset later in get_nearest_charset
2880 where we'll either use the charset of the current ansi codepage
2881 or if that's unavailable the first charset that the font supports.
2883 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2884 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2885 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2886 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2887 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2888 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
2889 if(face->scalable || can_use_bitmap)
2890 goto found;
2896 * Try check the SystemLink list first for a replacement font.
2897 * We may find good replacements there.
2899 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2901 if(!strcmpiW(font_link->font_name, lf.lfFaceName))
2903 TRACE("found entry in system list\n");
2904 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2906 face = font_link_entry->face;
2907 family = face->family;
2908 if(csi.fs.fsCsb[0] &
2909 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
2911 if(face->scalable || can_use_bitmap)
2912 goto found;
2919 /* If requested charset was DEFAULT_CHARSET then try using charset
2920 corresponding to the current ansi codepage */
2921 if(!csi.fs.fsCsb[0]) {
2922 INT acp = GetACP();
2923 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
2924 FIXME("TCI failed on codepage %d\n", acp);
2925 csi.fs.fsCsb[0] = 0;
2926 } else
2927 lf.lfCharSet = csi.ciCharset;
2930 /* Face families are in the top 4 bits of lfPitchAndFamily,
2931 so mask with 0xF0 before testing */
2933 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
2934 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
2935 strcpyW(lf.lfFaceName, defFixed);
2936 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
2937 strcpyW(lf.lfFaceName, defSerif);
2938 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
2939 strcpyW(lf.lfFaceName, defSans);
2940 else
2941 strcpyW(lf.lfFaceName, defSans);
2942 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2943 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2944 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2945 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2946 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2947 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2948 if(face->scalable || can_use_bitmap)
2949 goto found;
2954 last_resort_family = NULL;
2955 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2956 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2957 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2958 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2959 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
2960 if(face->scalable)
2961 goto found;
2962 if(can_use_bitmap && !last_resort_family)
2963 last_resort_family = family;
2968 if(last_resort_family) {
2969 family = last_resort_family;
2970 csi.fs.fsCsb[0] = 0;
2971 goto found;
2974 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2975 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2976 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2977 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2978 if(face->scalable) {
2979 csi.fs.fsCsb[0] = 0;
2980 WARN("just using first face for now\n");
2981 goto found;
2983 if(can_use_bitmap && !last_resort_family)
2984 last_resort_family = family;
2987 if(!last_resort_family) {
2988 FIXME("can't find a single appropriate font - bailing\n");
2989 free_font(ret);
2990 return NULL;
2993 WARN("could only find a bitmap font - this will probably look awful!\n");
2994 family = last_resort_family;
2995 csi.fs.fsCsb[0] = 0;
2997 found:
2998 it = lf.lfItalic ? 1 : 0;
2999 bd = lf.lfWeight > 550 ? 1 : 0;
3001 height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
3002 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
3004 face = best = best_bitmap = NULL;
3005 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
3007 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3009 new_score = (face->Italic ^ it) + (face->Bold ^ bd);
3010 if(!best || new_score <= score)
3012 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3013 face->Italic, face->Bold, it, bd);
3014 score = new_score;
3015 best = face;
3016 if(best->scalable && score == 0) break;
3017 if(!best->scalable)
3019 if(height > 0)
3020 newdiff = height - (signed int)(best->size.height);
3021 else
3022 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
3023 if(!best_bitmap || new_score < score ||
3024 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
3026 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
3027 diff = newdiff;
3028 best_bitmap = best;
3029 if(score == 0 && diff == 0) break;
3035 if(best)
3036 face = best->scalable ? best : best_bitmap;
3037 ret->fake_italic = (it && !face->Italic);
3038 ret->fake_bold = (bd && !face->Bold);
3040 memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
3042 if(csi.fs.fsCsb[0]) {
3043 ret->charset = lf.lfCharSet;
3044 ret->codepage = csi.ciACP;
3046 else
3047 ret->charset = get_nearest_charset(face, &ret->codepage);
3049 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
3050 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
3052 if(!face->scalable) {
3053 width = face->size.x_ppem >> 6;
3054 height = face->size.y_ppem >> 6;
3056 ret->ft_face = OpenFontFace(ret, face, width, height);
3058 if (!ret->ft_face)
3060 free_font( ret );
3061 return 0;
3064 ret->ntmFlags = face->ntmFlags;
3066 if (ret->charset == SYMBOL_CHARSET &&
3067 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
3068 /* No ops */
3070 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
3071 /* No ops */
3073 else {
3074 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
3077 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
3078 ret->name = strdupW(family->FamilyName);
3079 ret->underline = lf.lfUnderline ? 0xff : 0;
3080 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
3081 create_child_font_list(ret);
3083 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
3085 ret->aveWidth = FT_IS_SCALABLE(ret->ft_face) ? abs(lf.lfWidth) : 0;
3086 list_add_head(&gdi_font_list, &ret->entry);
3087 return ret;
3090 static void dump_gdi_font_list(void)
3092 GdiFont *gdiFont;
3093 struct list *elem_ptr;
3095 TRACE("---------- gdiFont Cache ----------\n");
3096 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
3097 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3098 TRACE("gdiFont=%p %s %d\n",
3099 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3102 TRACE("---------- Unused gdiFont Cache ----------\n");
3103 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
3104 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3105 TRACE("gdiFont=%p %s %d\n",
3106 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3110 /*************************************************************
3111 * WineEngDestroyFontInstance
3113 * free the gdiFont associated with this handle
3116 BOOL WineEngDestroyFontInstance(HFONT handle)
3118 GdiFont *gdiFont;
3119 HFONTLIST *hflist;
3120 BOOL ret = FALSE;
3121 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3122 int i = 0;
3124 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
3126 struct list *first_hfont = list_head(&gdiFont->hfontlist);
3127 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3128 if(hflist->hfont == handle)
3130 TRACE("removing child font %p from child list\n", gdiFont);
3131 list_remove(&gdiFont->entry);
3132 return TRUE;
3136 TRACE("destroying hfont=%p\n", handle);
3137 if(TRACE_ON(font))
3138 dump_gdi_font_list();
3140 font_elem_ptr = list_head(&gdi_font_list);
3141 while(font_elem_ptr) {
3142 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3143 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3145 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3146 while(hfontlist_elem_ptr) {
3147 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3148 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3149 if(hflist->hfont == handle) {
3150 list_remove(&hflist->entry);
3151 HeapFree(GetProcessHeap(), 0, hflist);
3152 ret = TRUE;
3155 if(list_empty(&gdiFont->hfontlist)) {
3156 TRACE("Moving to Unused list\n");
3157 list_remove(&gdiFont->entry);
3158 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3163 font_elem_ptr = list_head(&unused_gdi_font_list);
3164 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3165 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3166 while(font_elem_ptr) {
3167 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3168 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3169 TRACE("freeing %p\n", gdiFont);
3170 list_remove(&gdiFont->entry);
3171 free_font(gdiFont);
3173 return ret;
3176 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
3177 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
3179 OUTLINETEXTMETRICW *potm = NULL;
3180 UINT size;
3181 TEXTMETRICW tm, *ptm;
3182 GdiFont *font = alloc_font();
3183 LONG width, height;
3185 if(face->scalable) {
3186 height = 100;
3187 width = 0;
3188 } else {
3189 height = face->size.y_ppem >> 6;
3190 width = face->size.x_ppem >> 6;
3193 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
3195 free_font(font);
3196 return;
3199 font->name = strdupW(face->family->FamilyName);
3200 font->ntmFlags = face->ntmFlags;
3202 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
3204 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
3205 if(size) {
3206 potm = HeapAlloc(GetProcessHeap(), 0, size);
3207 WineEngGetOutlineTextMetrics(font, size, potm);
3208 ptm = (TEXTMETRICW*)&potm->otmTextMetrics;
3209 } else {
3210 WineEngGetTextMetrics(font, &tm);
3211 ptm = &tm;
3214 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = ptm->tmHeight;
3215 pntm->ntmTm.tmAscent = ptm->tmAscent;
3216 pntm->ntmTm.tmDescent = ptm->tmDescent;
3217 pntm->ntmTm.tmInternalLeading = ptm->tmInternalLeading;
3218 pntm->ntmTm.tmExternalLeading = ptm->tmExternalLeading;
3219 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = ptm->tmAveCharWidth;
3220 pntm->ntmTm.tmMaxCharWidth = ptm->tmMaxCharWidth;
3221 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = ptm->tmWeight;
3222 pntm->ntmTm.tmOverhang = ptm->tmOverhang;
3223 pntm->ntmTm.tmDigitizedAspectX = ptm->tmDigitizedAspectX;
3224 pntm->ntmTm.tmDigitizedAspectY = ptm->tmDigitizedAspectY;
3225 pntm->ntmTm.tmFirstChar = ptm->tmFirstChar;
3226 pntm->ntmTm.tmLastChar = ptm->tmLastChar;
3227 pntm->ntmTm.tmDefaultChar = ptm->tmDefaultChar;
3228 pntm->ntmTm.tmBreakChar = ptm->tmBreakChar;
3229 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = ptm->tmItalic;
3230 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = ptm->tmUnderlined;
3231 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = ptm->tmStruckOut;
3232 pntm->ntmTm.tmPitchAndFamily = ptm->tmPitchAndFamily;
3233 pelf->elfLogFont.lfPitchAndFamily = (ptm->tmPitchAndFamily & 0xf1) + 1;
3234 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = ptm->tmCharSet;
3235 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
3236 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
3237 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
3239 *ptype = 0;
3240 if (ptm->tmPitchAndFamily & TMPF_TRUETYPE)
3241 *ptype |= TRUETYPE_FONTTYPE;
3242 if (ptm->tmPitchAndFamily & TMPF_DEVICE)
3243 *ptype |= DEVICE_FONTTYPE;
3244 if(!(ptm->tmPitchAndFamily & TMPF_VECTOR))
3245 *ptype |= RASTER_FONTTYPE;
3247 pntm->ntmTm.ntmFlags = ptm->tmItalic ? NTM_ITALIC : 0;
3248 if(ptm->tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
3249 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
3250 pntm->ntmTm.ntmFlags |= face->ntmFlags;
3252 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
3253 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
3254 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
3256 if(potm) {
3257 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
3259 lstrcpynW(pelf->elfLogFont.lfFaceName,
3260 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
3261 LF_FACESIZE);
3262 lstrcpynW(pelf->elfFullName,
3263 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
3264 LF_FULLFACESIZE);
3265 lstrcpynW(pelf->elfStyle,
3266 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
3267 LF_FACESIZE);
3269 HeapFree(GetProcessHeap(), 0, potm);
3270 } else {
3271 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
3273 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
3274 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FACESIZE);
3275 pelf->elfStyle[0] = '\0';
3278 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
3280 free_font(font);
3283 /*************************************************************
3284 * WineEngEnumFonts
3287 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3289 Family *family;
3290 Face *face;
3291 struct list *family_elem_ptr, *face_elem_ptr;
3292 ENUMLOGFONTEXW elf;
3293 NEWTEXTMETRICEXW ntm;
3294 DWORD type, ret = 1;
3295 FONTSIGNATURE fs;
3296 CHARSETINFO csi;
3297 LOGFONTW lf;
3298 int i;
3300 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
3302 if(plf->lfFaceName[0]) {
3303 FontSubst *psub;
3304 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
3306 if(psub) {
3307 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
3308 debugstr_w(psub->to.name));
3309 memcpy(&lf, plf, sizeof(lf));
3310 strcpyW(lf.lfFaceName, psub->to.name);
3311 plf = &lf;
3314 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3315 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3316 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
3317 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3318 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3319 GetEnumStructs(face, &elf, &ntm, &type);
3320 for(i = 0; i < 32; i++) {
3321 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3322 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3323 strcpyW(elf.elfScript, OEM_DOSW);
3324 i = 32; /* break out of loop */
3325 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3326 continue;
3327 else {
3328 fs.fsCsb[0] = 1L << i;
3329 fs.fsCsb[1] = 0;
3330 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3331 TCI_SRCFONTSIG))
3332 csi.ciCharset = DEFAULT_CHARSET;
3333 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3334 if(csi.ciCharset != DEFAULT_CHARSET) {
3335 elf.elfLogFont.lfCharSet =
3336 ntm.ntmTm.tmCharSet = csi.ciCharset;
3337 if(ElfScriptsW[i])
3338 strcpyW(elf.elfScript, ElfScriptsW[i]);
3339 else
3340 FIXME("Unknown elfscript for bit %d\n", i);
3343 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3344 debugstr_w(elf.elfLogFont.lfFaceName),
3345 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3346 csi.ciCharset, type, debugstr_w(elf.elfScript),
3347 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3348 ntm.ntmTm.ntmFlags);
3349 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
3350 if(!ret) goto end;
3355 } else {
3356 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3357 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3358 face_elem_ptr = list_head(&family->faces);
3359 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3360 GetEnumStructs(face, &elf, &ntm, &type);
3361 for(i = 0; i < 32; i++) {
3362 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3363 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3364 strcpyW(elf.elfScript, OEM_DOSW);
3365 i = 32; /* break out of loop */
3366 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3367 continue;
3368 else {
3369 fs.fsCsb[0] = 1L << i;
3370 fs.fsCsb[1] = 0;
3371 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3372 TCI_SRCFONTSIG))
3373 csi.ciCharset = DEFAULT_CHARSET;
3374 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3375 if(csi.ciCharset != DEFAULT_CHARSET) {
3376 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
3377 csi.ciCharset;
3378 if(ElfScriptsW[i])
3379 strcpyW(elf.elfScript, ElfScriptsW[i]);
3380 else
3381 FIXME("Unknown elfscript for bit %d\n", i);
3384 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3385 debugstr_w(elf.elfLogFont.lfFaceName),
3386 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3387 csi.ciCharset, type, debugstr_w(elf.elfScript),
3388 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3389 ntm.ntmTm.ntmFlags);
3390 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
3391 if(!ret) goto end;
3395 end:
3396 return ret;
3399 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
3401 pt->x.value = vec->x >> 6;
3402 pt->x.fract = (vec->x & 0x3f) << 10;
3403 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
3404 pt->y.value = vec->y >> 6;
3405 pt->y.fract = (vec->y & 0x3f) << 10;
3406 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
3407 return;
3410 /***************************************************
3411 * According to the MSDN documentation on WideCharToMultiByte,
3412 * certain codepages cannot set the default_used parameter.
3413 * This returns TRUE if the codepage can set that parameter, false else
3414 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
3416 static BOOL codepage_sets_default_used(UINT codepage)
3418 switch (codepage)
3420 case CP_UTF7:
3421 case CP_UTF8:
3422 case CP_SYMBOL:
3423 return FALSE;
3424 default:
3425 return TRUE;
3429 static FT_UInt get_glyph_index(GdiFont *font, UINT glyph)
3431 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
3432 WCHAR wc = (WCHAR)glyph;
3433 BOOL default_used;
3434 BOOL *default_used_pointer;
3435 FT_UInt ret;
3436 char buf;
3437 default_used_pointer = NULL;
3438 default_used = FALSE;
3439 if (codepage_sets_default_used(font->codepage))
3440 default_used_pointer = &default_used;
3441 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
3442 ret = 0;
3443 else
3444 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
3445 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
3446 return ret;
3449 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
3450 glyph = glyph + 0xf000;
3451 return pFT_Get_Char_Index(font->ft_face, glyph);
3454 /*************************************************************
3455 * WineEngGetGlyphIndices
3457 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
3459 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
3460 LPWORD pgi, DWORD flags)
3462 int i;
3463 WCHAR default_char = 0;
3464 TEXTMETRICW textm;
3466 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0x001f; /* Indicate non existence */
3468 for(i = 0; i < count; i++)
3470 pgi[i] = get_glyph_index(font, lpstr[i]);
3471 if (pgi[i] == 0)
3473 if (!default_char)
3475 WineEngGetTextMetrics(font, &textm);
3476 default_char = textm.tmDefaultChar;
3478 pgi[i] = default_char;
3481 return count;
3484 /*************************************************************
3485 * WineEngGetGlyphOutline
3487 * Behaves in exactly the same way as the win32 api GetGlyphOutline
3488 * except that the first parameter is the HWINEENGFONT of the font in
3489 * question rather than an HDC.
3492 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
3493 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
3494 const MAT2* lpmat)
3496 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
3497 FT_Face ft_face = incoming_font->ft_face;
3498 GdiFont *font = incoming_font;
3499 FT_UInt glyph_index;
3500 DWORD width, height, pitch, needed = 0;
3501 FT_Bitmap ft_bitmap;
3502 FT_Error err;
3503 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
3504 FT_Angle angle = 0;
3505 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
3506 float widthRatio = 1.0;
3507 FT_Matrix transMat = identityMat;
3508 BOOL needsTransform = FALSE;
3511 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
3512 buflen, buf, lpmat);
3514 if(format & GGO_GLYPH_INDEX) {
3515 glyph_index = glyph;
3516 format &= ~GGO_GLYPH_INDEX;
3517 } else {
3518 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
3519 ft_face = font->ft_face;
3522 if(glyph_index >= font->gmsize * GM_BLOCK_SIZE) {
3523 font->gmsize = (glyph_index / GM_BLOCK_SIZE + 1);
3524 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
3525 font->gmsize * sizeof(GM*));
3526 } else {
3527 if(format == GGO_METRICS && font->gm[glyph_index / GM_BLOCK_SIZE] != NULL && FONT_GM(font,glyph_index)->init ) {
3528 *lpgm = FONT_GM(font,glyph_index)->gm;
3529 return 1; /* FIXME */
3533 if (!font->gm[glyph_index / GM_BLOCK_SIZE])
3534 font->gm[glyph_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3536 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP) || font->aveWidth || lpmat)
3537 load_flags |= FT_LOAD_NO_BITMAP;
3539 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
3541 if(err) {
3542 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
3543 return GDI_ERROR;
3546 /* Scaling factor */
3547 if (font->aveWidth && font->potm) {
3548 widthRatio = (float)font->aveWidth * font->font_desc.matrix.eM11 / (float) font->potm->otmTextMetrics.tmAveCharWidth;
3551 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
3552 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
3554 adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
3555 lsb = left >> 6;
3556 bbx = (right - left) >> 6;
3558 /* Scaling transform */
3559 if(font->aveWidth) {
3560 FT_Matrix scaleMat;
3561 scaleMat.xx = FT_FixedFromFloat(widthRatio);
3562 scaleMat.xy = 0;
3563 scaleMat.yx = 0;
3564 scaleMat.yy = (1 << 16);
3566 pFT_Matrix_Multiply(&scaleMat, &transMat);
3567 needsTransform = TRUE;
3570 /* Slant transform */
3571 if (font->fake_italic) {
3572 FT_Matrix slantMat;
3574 slantMat.xx = (1 << 16);
3575 slantMat.xy = ((1 << 16) >> 2);
3576 slantMat.yx = 0;
3577 slantMat.yy = (1 << 16);
3578 pFT_Matrix_Multiply(&slantMat, &transMat);
3579 needsTransform = TRUE;
3582 /* Rotation transform */
3583 if(font->orientation) {
3584 FT_Matrix rotationMat;
3585 FT_Vector vecAngle;
3586 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
3587 pFT_Vector_Unit(&vecAngle, angle);
3588 rotationMat.xx = vecAngle.x;
3589 rotationMat.xy = -vecAngle.y;
3590 rotationMat.yx = -rotationMat.xy;
3591 rotationMat.yy = rotationMat.xx;
3593 pFT_Matrix_Multiply(&rotationMat, &transMat);
3594 needsTransform = TRUE;
3597 /* Extra transformation specified by caller */
3598 if (lpmat) {
3599 FT_Matrix extraMat;
3600 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
3601 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
3602 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
3603 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
3604 pFT_Matrix_Multiply(&extraMat, &transMat);
3605 needsTransform = TRUE;
3608 if(!needsTransform) {
3609 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
3610 bottom = (ft_face->glyph->metrics.horiBearingY -
3611 ft_face->glyph->metrics.height) & -64;
3612 lpgm->gmCellIncX = adv;
3613 lpgm->gmCellIncY = 0;
3614 } else {
3615 INT xc, yc;
3616 FT_Vector vec;
3617 for(xc = 0; xc < 2; xc++) {
3618 for(yc = 0; yc < 2; yc++) {
3619 vec.x = (ft_face->glyph->metrics.horiBearingX +
3620 xc * ft_face->glyph->metrics.width);
3621 vec.y = ft_face->glyph->metrics.horiBearingY -
3622 yc * ft_face->glyph->metrics.height;
3623 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
3624 pFT_Vector_Transform(&vec, &transMat);
3625 if(xc == 0 && yc == 0) {
3626 left = right = vec.x;
3627 top = bottom = vec.y;
3628 } else {
3629 if(vec.x < left) left = vec.x;
3630 else if(vec.x > right) right = vec.x;
3631 if(vec.y < bottom) bottom = vec.y;
3632 else if(vec.y > top) top = vec.y;
3636 left = left & -64;
3637 right = (right + 63) & -64;
3638 bottom = bottom & -64;
3639 top = (top + 63) & -64;
3641 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
3642 vec.x = ft_face->glyph->metrics.horiAdvance;
3643 vec.y = 0;
3644 pFT_Vector_Transform(&vec, &transMat);
3645 lpgm->gmCellIncX = (vec.x+63) >> 6;
3646 lpgm->gmCellIncY = -((vec.y+63) >> 6);
3648 lpgm->gmBlackBoxX = (right - left) >> 6;
3649 lpgm->gmBlackBoxY = (top - bottom) >> 6;
3650 lpgm->gmptGlyphOrigin.x = left >> 6;
3651 lpgm->gmptGlyphOrigin.y = top >> 6;
3653 if(format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP)
3655 FONT_GM(font,glyph_index)->gm = *lpgm;
3656 FONT_GM(font,glyph_index)->adv = adv;
3657 FONT_GM(font,glyph_index)->lsb = lsb;
3658 FONT_GM(font,glyph_index)->bbx = bbx;
3659 FONT_GM(font,glyph_index)->init = TRUE;
3662 if(format == GGO_METRICS)
3663 return 1; /* FIXME */
3665 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP) {
3666 TRACE("loaded a bitmap\n");
3667 return GDI_ERROR;
3670 switch(format) {
3671 case GGO_BITMAP:
3672 width = lpgm->gmBlackBoxX;
3673 height = lpgm->gmBlackBoxY;
3674 pitch = ((width + 31) >> 5) << 2;
3675 needed = pitch * height;
3677 if(!buf || !buflen) break;
3679 switch(ft_face->glyph->format) {
3680 case ft_glyph_format_bitmap:
3682 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
3683 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
3684 INT h = ft_face->glyph->bitmap.rows;
3685 while(h--) {
3686 memcpy(dst, src, w);
3687 src += ft_face->glyph->bitmap.pitch;
3688 dst += pitch;
3690 break;
3693 case ft_glyph_format_outline:
3694 ft_bitmap.width = width;
3695 ft_bitmap.rows = height;
3696 ft_bitmap.pitch = pitch;
3697 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
3698 ft_bitmap.buffer = buf;
3700 if(needsTransform) {
3701 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3704 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3706 /* Note: FreeType will only set 'black' bits for us. */
3707 memset(buf, 0, needed);
3708 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3709 break;
3711 default:
3712 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
3713 return GDI_ERROR;
3715 break;
3717 case GGO_GRAY2_BITMAP:
3718 case GGO_GRAY4_BITMAP:
3719 case GGO_GRAY8_BITMAP:
3720 case WINE_GGO_GRAY16_BITMAP:
3722 unsigned int mult, row, col;
3723 BYTE *start, *ptr;
3725 width = lpgm->gmBlackBoxX;
3726 height = lpgm->gmBlackBoxY;
3727 pitch = (width + 3) / 4 * 4;
3728 needed = pitch * height;
3730 if(!buf || !buflen) break;
3732 switch(ft_face->glyph->format) {
3733 case ft_glyph_format_bitmap:
3735 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
3736 INT h = ft_face->glyph->bitmap.rows;
3737 INT x;
3738 while(h--) {
3739 for(x = 0; x < pitch; x++)
3740 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
3741 src += ft_face->glyph->bitmap.pitch;
3742 dst += pitch;
3744 return needed;
3746 case ft_glyph_format_outline:
3748 ft_bitmap.width = width;
3749 ft_bitmap.rows = height;
3750 ft_bitmap.pitch = pitch;
3751 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
3752 ft_bitmap.buffer = buf;
3754 if(needsTransform)
3755 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3757 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3759 memset(ft_bitmap.buffer, 0, buflen);
3761 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3763 if(format == GGO_GRAY2_BITMAP)
3764 mult = 4;
3765 else if(format == GGO_GRAY4_BITMAP)
3766 mult = 16;
3767 else if(format == GGO_GRAY8_BITMAP)
3768 mult = 64;
3769 else if(format == WINE_GGO_GRAY16_BITMAP)
3770 return needed;
3771 else {
3772 assert(0);
3773 break;
3776 default:
3777 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
3778 return GDI_ERROR;
3781 start = buf;
3782 for(row = 0; row < height; row++) {
3783 ptr = start;
3784 for(col = 0; col < width; col++, ptr++) {
3785 *ptr = (((int)*ptr) * mult + 128) / 256;
3787 start += pitch;
3789 break;
3792 case GGO_NATIVE:
3794 int contour, point = 0, first_pt;
3795 FT_Outline *outline = &ft_face->glyph->outline;
3796 TTPOLYGONHEADER *pph;
3797 TTPOLYCURVE *ppc;
3798 DWORD pph_start, cpfx, type;
3800 if(buflen == 0) buf = NULL;
3802 if (needsTransform && buf) {
3803 pFT_Outline_Transform(outline, &transMat);
3806 for(contour = 0; contour < outline->n_contours; contour++) {
3807 pph_start = needed;
3808 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3809 first_pt = point;
3810 if(buf) {
3811 pph->dwType = TT_POLYGON_TYPE;
3812 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3814 needed += sizeof(*pph);
3815 point++;
3816 while(point <= outline->contours[contour]) {
3817 ppc = (TTPOLYCURVE *)((char *)buf + needed);
3818 type = (outline->tags[point] & FT_Curve_Tag_On) ?
3819 TT_PRIM_LINE : TT_PRIM_QSPLINE;
3820 cpfx = 0;
3821 do {
3822 if(buf)
3823 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3824 cpfx++;
3825 point++;
3826 } while(point <= outline->contours[contour] &&
3827 (outline->tags[point] & FT_Curve_Tag_On) ==
3828 (outline->tags[point-1] & FT_Curve_Tag_On));
3829 /* At the end of a contour Windows adds the start point, but
3830 only for Beziers */
3831 if(point > outline->contours[contour] &&
3832 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
3833 if(buf)
3834 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
3835 cpfx++;
3836 } else if(point <= outline->contours[contour] &&
3837 outline->tags[point] & FT_Curve_Tag_On) {
3838 /* add closing pt for bezier */
3839 if(buf)
3840 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3841 cpfx++;
3842 point++;
3844 if(buf) {
3845 ppc->wType = type;
3846 ppc->cpfx = cpfx;
3848 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3850 if(buf)
3851 pph->cb = needed - pph_start;
3853 break;
3855 case GGO_BEZIER:
3857 /* Convert the quadratic Beziers to cubic Beziers.
3858 The parametric eqn for a cubic Bezier is, from PLRM:
3859 r(t) = at^3 + bt^2 + ct + r0
3860 with the control points:
3861 r1 = r0 + c/3
3862 r2 = r1 + (c + b)/3
3863 r3 = r0 + c + b + a
3865 A quadratic Beizer has the form:
3866 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3868 So equating powers of t leads to:
3869 r1 = 2/3 p1 + 1/3 p0
3870 r2 = 2/3 p1 + 1/3 p2
3871 and of course r0 = p0, r3 = p2
3874 int contour, point = 0, first_pt;
3875 FT_Outline *outline = &ft_face->glyph->outline;
3876 TTPOLYGONHEADER *pph;
3877 TTPOLYCURVE *ppc;
3878 DWORD pph_start, cpfx, type;
3879 FT_Vector cubic_control[4];
3880 if(buflen == 0) buf = NULL;
3882 if (needsTransform && buf) {
3883 pFT_Outline_Transform(outline, &transMat);
3886 for(contour = 0; contour < outline->n_contours; contour++) {
3887 pph_start = needed;
3888 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3889 first_pt = point;
3890 if(buf) {
3891 pph->dwType = TT_POLYGON_TYPE;
3892 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3894 needed += sizeof(*pph);
3895 point++;
3896 while(point <= outline->contours[contour]) {
3897 ppc = (TTPOLYCURVE *)((char *)buf + needed);
3898 type = (outline->tags[point] & FT_Curve_Tag_On) ?
3899 TT_PRIM_LINE : TT_PRIM_CSPLINE;
3900 cpfx = 0;
3901 do {
3902 if(type == TT_PRIM_LINE) {
3903 if(buf)
3904 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3905 cpfx++;
3906 point++;
3907 } else {
3908 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
3909 so cpfx = 3n */
3911 /* FIXME: Possible optimization in endpoint calculation
3912 if there are two consecutive curves */
3913 cubic_control[0] = outline->points[point-1];
3914 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
3915 cubic_control[0].x += outline->points[point].x + 1;
3916 cubic_control[0].y += outline->points[point].y + 1;
3917 cubic_control[0].x >>= 1;
3918 cubic_control[0].y >>= 1;
3920 if(point+1 > outline->contours[contour])
3921 cubic_control[3] = outline->points[first_pt];
3922 else {
3923 cubic_control[3] = outline->points[point+1];
3924 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
3925 cubic_control[3].x += outline->points[point].x + 1;
3926 cubic_control[3].y += outline->points[point].y + 1;
3927 cubic_control[3].x >>= 1;
3928 cubic_control[3].y >>= 1;
3931 /* r1 = 1/3 p0 + 2/3 p1
3932 r2 = 1/3 p2 + 2/3 p1 */
3933 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
3934 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
3935 cubic_control[2] = cubic_control[1];
3936 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
3937 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
3938 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
3939 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
3940 if(buf) {
3941 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
3942 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
3943 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
3945 cpfx += 3;
3946 point++;
3948 } while(point <= outline->contours[contour] &&
3949 (outline->tags[point] & FT_Curve_Tag_On) ==
3950 (outline->tags[point-1] & FT_Curve_Tag_On));
3951 /* At the end of a contour Windows adds the start point,
3952 but only for Beziers and we've already done that.
3954 if(point <= outline->contours[contour] &&
3955 outline->tags[point] & FT_Curve_Tag_On) {
3956 /* This is the closing pt of a bezier, but we've already
3957 added it, so just inc point and carry on */
3958 point++;
3960 if(buf) {
3961 ppc->wType = type;
3962 ppc->cpfx = cpfx;
3964 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3966 if(buf)
3967 pph->cb = needed - pph_start;
3969 break;
3972 default:
3973 FIXME("Unsupported format %d\n", format);
3974 return GDI_ERROR;
3976 return needed;
3979 static BOOL get_bitmap_text_metrics(GdiFont *font)
3981 FT_Face ft_face = font->ft_face;
3982 #ifdef HAVE_FREETYPE_FTWINFNT_H
3983 FT_WinFNT_HeaderRec winfnt_header;
3984 #endif
3985 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
3986 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
3987 font->potm->otmSize = size;
3989 #define TM font->potm->otmTextMetrics
3990 #ifdef HAVE_FREETYPE_FTWINFNT_H
3991 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
3993 TM.tmHeight = winfnt_header.pixel_height;
3994 TM.tmAscent = winfnt_header.ascent;
3995 TM.tmDescent = TM.tmHeight - TM.tmAscent;
3996 TM.tmInternalLeading = winfnt_header.internal_leading;
3997 TM.tmExternalLeading = winfnt_header.external_leading;
3998 TM.tmAveCharWidth = winfnt_header.avg_width;
3999 TM.tmMaxCharWidth = winfnt_header.max_width;
4000 TM.tmWeight = winfnt_header.weight;
4001 TM.tmOverhang = 0;
4002 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
4003 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
4004 TM.tmFirstChar = winfnt_header.first_char;
4005 TM.tmLastChar = winfnt_header.last_char;
4006 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
4007 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
4008 TM.tmItalic = winfnt_header.italic;
4009 TM.tmUnderlined = font->underline;
4010 TM.tmStruckOut = font->strikeout;
4011 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
4012 TM.tmCharSet = winfnt_header.charset;
4014 else
4015 #endif
4017 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
4018 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
4019 TM.tmHeight = TM.tmAscent + TM.tmDescent;
4020 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
4021 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
4022 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
4023 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
4024 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
4025 TM.tmOverhang = 0;
4026 TM.tmDigitizedAspectX = 96; /* FIXME */
4027 TM.tmDigitizedAspectY = 96; /* FIXME */
4028 TM.tmFirstChar = 1;
4029 TM.tmLastChar = 255;
4030 TM.tmDefaultChar = 32;
4031 TM.tmBreakChar = 32;
4032 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
4033 TM.tmUnderlined = font->underline;
4034 TM.tmStruckOut = font->strikeout;
4035 /* NB inverted meaning of TMPF_FIXED_PITCH */
4036 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
4037 TM.tmCharSet = font->charset;
4039 #undef TM
4041 return TRUE;
4044 /*************************************************************
4045 * WineEngGetTextMetrics
4048 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
4050 if(!font->potm) {
4051 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
4052 if(!get_bitmap_text_metrics(font))
4053 return FALSE;
4055 if(!font->potm) return FALSE;
4056 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
4058 if (font->aveWidth) {
4059 ptm->tmAveCharWidth = font->aveWidth * font->font_desc.matrix.eM11;
4061 return TRUE;
4065 /*************************************************************
4066 * WineEngGetOutlineTextMetrics
4069 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
4070 OUTLINETEXTMETRICW *potm)
4072 FT_Face ft_face = font->ft_face;
4073 UINT needed, lenfam, lensty, ret;
4074 TT_OS2 *pOS2;
4075 TT_HoriHeader *pHori;
4076 TT_Postscript *pPost;
4077 FT_Fixed x_scale, y_scale;
4078 WCHAR *family_nameW, *style_nameW;
4079 static const WCHAR spaceW[] = {' ', '\0'};
4080 char *cp;
4081 INT ascent, descent;
4083 TRACE("font=%p\n", font);
4085 if(!FT_IS_SCALABLE(ft_face))
4086 return 0;
4088 if(font->potm) {
4089 if(cbSize >= font->potm->otmSize)
4090 memcpy(potm, font->potm, font->potm->otmSize);
4091 return font->potm->otmSize;
4095 needed = sizeof(*potm);
4097 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
4098 family_nameW = strdupW(font->name);
4100 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
4101 * sizeof(WCHAR);
4102 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
4103 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
4104 style_nameW, lensty/sizeof(WCHAR));
4106 /* These names should be read from the TT name table */
4108 /* length of otmpFamilyName */
4109 needed += lenfam;
4111 /* length of otmpFaceName */
4112 if(!strcasecmp(ft_face->style_name, "regular")) {
4113 needed += lenfam; /* just the family name */
4114 } else {
4115 needed += lenfam + lensty; /* family + " " + style */
4118 /* length of otmpStyleName */
4119 needed += lensty;
4121 /* length of otmpFullName */
4122 needed += lenfam + lensty;
4125 x_scale = ft_face->size->metrics.x_scale;
4126 y_scale = ft_face->size->metrics.y_scale;
4128 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
4129 if(!pOS2) {
4130 FIXME("Can't find OS/2 table - not TT font?\n");
4131 ret = 0;
4132 goto end;
4135 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
4136 if(!pHori) {
4137 FIXME("Can't find HHEA table - not TT font?\n");
4138 ret = 0;
4139 goto end;
4142 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
4144 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",
4145 pOS2->usWinAscent, pOS2->usWinDescent,
4146 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
4147 ft_face->ascender, ft_face->descender, ft_face->height,
4148 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
4149 ft_face->bbox.yMax, ft_face->bbox.yMin);
4151 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
4152 font->potm->otmSize = needed;
4154 #define TM font->potm->otmTextMetrics
4156 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
4157 ascent = pHori->Ascender;
4158 descent = -pHori->Descender;
4159 } else {
4160 ascent = pOS2->usWinAscent;
4161 descent = pOS2->usWinDescent;
4164 if(font->yMax) {
4165 TM.tmAscent = font->yMax;
4166 TM.tmDescent = -font->yMin;
4167 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
4168 } else {
4169 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
4170 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
4171 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
4172 - ft_face->units_per_EM, y_scale) + 32) >> 6;
4175 TM.tmHeight = TM.tmAscent + TM.tmDescent;
4177 /* MSDN says:
4178 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
4180 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
4181 ((ascent + descent) -
4182 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
4184 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
4185 if (TM.tmAveCharWidth == 0) {
4186 TM.tmAveCharWidth = 1;
4188 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
4189 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
4190 TM.tmOverhang = 0;
4191 TM.tmDigitizedAspectX = 300;
4192 TM.tmDigitizedAspectY = 300;
4193 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
4194 * symbol range to 0 - f0ff
4196 if (font->charset == SYMBOL_CHARSET)
4197 TM.tmFirstChar = 0;
4198 else
4199 TM.tmFirstChar = pOS2->usFirstCharIndex;
4200 TM.tmLastChar = pOS2->usLastCharIndex;
4201 TM.tmDefaultChar = pOS2->usDefaultChar ? pOS2->usDefaultChar : 0x1f;
4202 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
4203 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
4204 TM.tmUnderlined = font->underline;
4205 TM.tmStruckOut = font->strikeout;
4207 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
4208 if(!FT_IS_FIXED_WIDTH(ft_face) &&
4209 (pOS2->version == 0xFFFFU ||
4210 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
4211 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
4212 else
4213 TM.tmPitchAndFamily = 0;
4215 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
4216 case PAN_FAMILY_SCRIPT:
4217 TM.tmPitchAndFamily |= FF_SCRIPT;
4218 break;
4219 case PAN_FAMILY_DECORATIVE:
4220 case PAN_FAMILY_PICTORIAL:
4221 TM.tmPitchAndFamily |= FF_DECORATIVE;
4222 break;
4223 case PAN_FAMILY_TEXT_DISPLAY:
4224 if(TM.tmPitchAndFamily == 0) /* fixed */
4225 TM.tmPitchAndFamily = FF_MODERN;
4226 else {
4227 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
4228 case PAN_SERIF_NORMAL_SANS:
4229 case PAN_SERIF_OBTUSE_SANS:
4230 case PAN_SERIF_PERP_SANS:
4231 TM.tmPitchAndFamily |= FF_SWISS;
4232 break;
4233 default:
4234 TM.tmPitchAndFamily |= FF_ROMAN;
4237 break;
4238 default:
4239 TM.tmPitchAndFamily |= FF_DONTCARE;
4242 if(FT_IS_SCALABLE(ft_face))
4243 TM.tmPitchAndFamily |= TMPF_VECTOR;
4245 if(FT_IS_SFNT(ft_face))
4247 if (font->ntmFlags & NTM_PS_OPENTYPE)
4248 TM.tmPitchAndFamily |= TMPF_DEVICE;
4249 else
4250 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
4253 TM.tmCharSet = font->charset;
4254 #undef TM
4256 font->potm->otmFiller = 0;
4257 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
4258 font->potm->otmfsSelection = pOS2->fsSelection;
4259 font->potm->otmfsType = pOS2->fsType;
4260 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
4261 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
4262 font->potm->otmItalicAngle = 0; /* POST table */
4263 font->potm->otmEMSquare = ft_face->units_per_EM;
4264 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
4265 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
4266 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
4267 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
4268 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
4269 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
4270 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
4271 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
4272 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
4273 font->potm->otmMacAscent = 0; /* where do these come from ? */
4274 font->potm->otmMacDescent = 0;
4275 font->potm->otmMacLineGap = 0;
4276 font->potm->otmusMinimumPPEM = 0; /* TT Header */
4277 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
4278 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
4279 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
4280 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
4281 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
4282 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
4283 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
4284 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
4285 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
4286 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
4287 if(!pPost) {
4288 font->potm->otmsUnderscoreSize = 0;
4289 font->potm->otmsUnderscorePosition = 0;
4290 } else {
4291 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
4292 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
4295 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
4296 cp = (char*)font->potm + sizeof(*font->potm);
4297 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
4298 strcpyW((WCHAR*)cp, family_nameW);
4299 cp += lenfam;
4300 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
4301 strcpyW((WCHAR*)cp, style_nameW);
4302 cp += lensty;
4303 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
4304 strcpyW((WCHAR*)cp, family_nameW);
4305 if(strcasecmp(ft_face->style_name, "regular")) {
4306 strcatW((WCHAR*)cp, spaceW);
4307 strcatW((WCHAR*)cp, style_nameW);
4308 cp += lenfam + lensty;
4309 } else
4310 cp += lenfam;
4311 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
4312 strcpyW((WCHAR*)cp, family_nameW);
4313 strcatW((WCHAR*)cp, spaceW);
4314 strcatW((WCHAR*)cp, style_nameW);
4315 ret = needed;
4317 if(potm && needed <= cbSize)
4318 memcpy(potm, font->potm, font->potm->otmSize);
4320 end:
4321 HeapFree(GetProcessHeap(), 0, style_nameW);
4322 HeapFree(GetProcessHeap(), 0, family_nameW);
4324 return ret;
4327 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
4329 HFONTLIST *hfontlist;
4330 child->font = alloc_font();
4331 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
4332 if(!child->font->ft_face)
4334 free_font(child->font);
4335 child->font = NULL;
4336 return FALSE;
4339 child->font->ntmFlags = child->face->ntmFlags;
4340 child->font->orientation = font->orientation;
4341 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
4342 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
4343 list_add_head(&child->font->hfontlist, &hfontlist->entry);
4344 child->font->base_font = font;
4345 list_add_head(&child_font_list, &child->font->entry);
4346 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
4347 return TRUE;
4350 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
4352 FT_UInt g;
4353 CHILD_FONT *child_font;
4355 if(font->base_font)
4356 font = font->base_font;
4358 *linked_font = font;
4360 if((*glyph = get_glyph_index(font, c)))
4361 return TRUE;
4363 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
4365 if(!child_font->font)
4366 if(!load_child_font(font, child_font))
4367 continue;
4369 if(!child_font->font->ft_face)
4370 continue;
4371 g = get_glyph_index(child_font->font, c);
4372 if(g)
4374 *glyph = g;
4375 *linked_font = child_font->font;
4376 return TRUE;
4379 return FALSE;
4382 /*************************************************************
4383 * WineEngGetCharWidth
4386 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
4387 LPINT buffer)
4389 UINT c;
4390 GLYPHMETRICS gm;
4391 FT_UInt glyph_index;
4392 GdiFont *linked_font;
4394 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
4396 for(c = firstChar; c <= lastChar; c++) {
4397 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
4398 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4399 &gm, 0, NULL, NULL);
4400 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
4402 return TRUE;
4405 /*************************************************************
4406 * WineEngGetCharABCWidths
4409 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
4410 LPABC buffer)
4412 UINT c;
4413 GLYPHMETRICS gm;
4414 FT_UInt glyph_index;
4415 GdiFont *linked_font;
4417 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
4419 if(!FT_IS_SCALABLE(font->ft_face))
4420 return FALSE;
4422 for(c = firstChar; c <= lastChar; c++) {
4423 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
4424 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4425 &gm, 0, NULL, NULL);
4426 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
4427 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
4428 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
4429 FONT_GM(linked_font,glyph_index)->bbx;
4431 return TRUE;
4434 /*************************************************************
4435 * WineEngGetCharABCWidthsI
4438 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
4439 LPABC buffer)
4441 UINT c;
4442 GLYPHMETRICS gm;
4443 FT_UInt glyph_index;
4444 GdiFont *linked_font;
4446 if(!FT_IS_SCALABLE(font->ft_face))
4447 return FALSE;
4449 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
4450 if (!pgi)
4451 for(c = firstChar; c < firstChar+count; c++) {
4452 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
4453 &gm, 0, NULL, NULL);
4454 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
4455 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
4456 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
4457 - FONT_GM(linked_font,c)->bbx;
4459 else
4460 for(c = 0; c < count; c++) {
4461 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
4462 &gm, 0, NULL, NULL);
4463 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
4464 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
4465 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
4466 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
4469 return TRUE;
4472 /*************************************************************
4473 * WineEngGetTextExtentExPoint
4476 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
4477 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
4479 INT idx;
4480 INT nfit = 0, ext;
4481 GLYPHMETRICS gm;
4482 TEXTMETRICW tm;
4483 FT_UInt glyph_index;
4484 GdiFont *linked_font;
4486 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
4487 max_ext, size);
4489 size->cx = 0;
4490 WineEngGetTextMetrics(font, &tm);
4491 size->cy = tm.tmHeight;
4493 for(idx = 0; idx < count; idx++) {
4494 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
4495 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4496 &gm, 0, NULL, NULL);
4497 size->cx += FONT_GM(linked_font,glyph_index)->adv;
4498 ext = size->cx;
4499 if (! pnfit || ext <= max_ext) {
4500 ++nfit;
4501 if (dxs)
4502 dxs[idx] = ext;
4506 if (pnfit)
4507 *pnfit = nfit;
4509 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
4510 return TRUE;
4513 /*************************************************************
4514 * WineEngGetTextExtentPointI
4517 BOOL WineEngGetTextExtentPointI(GdiFont *font, const WORD *indices, INT count,
4518 LPSIZE size)
4520 INT idx;
4521 GLYPHMETRICS gm;
4522 TEXTMETRICW tm;
4524 TRACE("%p, %p, %d, %p\n", font, indices, count, size);
4526 size->cx = 0;
4527 WineEngGetTextMetrics(font, &tm);
4528 size->cy = tm.tmHeight;
4530 for(idx = 0; idx < count; idx++) {
4531 WineEngGetGlyphOutline(font, indices[idx],
4532 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
4533 NULL);
4534 size->cx += FONT_GM(font,indices[idx])->adv;
4536 TRACE("return %d,%d\n", size->cx, size->cy);
4537 return TRUE;
4540 /*************************************************************
4541 * WineEngGetFontData
4544 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
4545 DWORD cbData)
4547 FT_Face ft_face = font->ft_face;
4548 FT_ULong len;
4549 FT_Error err;
4551 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
4552 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
4553 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
4555 if(!FT_IS_SFNT(ft_face))
4556 return GDI_ERROR;
4558 if(!buf || !cbData)
4559 len = 0;
4560 else
4561 len = cbData;
4563 if(table) { /* MS tags differ in endidness from FT ones */
4564 table = table >> 24 | table << 24 |
4565 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
4568 /* If the FT_Load_Sfnt_Table function is there we'll use it */
4569 if(pFT_Load_Sfnt_Table) {
4570 /* make sure value of len is the value freetype says it needs */
4571 if( buf && len) {
4572 FT_ULong needed = 0;
4573 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
4574 if( !err && needed < len) len = needed;
4576 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
4578 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
4579 else { /* Do it the hard way */
4580 TT_Face tt_face = (TT_Face) ft_face;
4581 SFNT_Interface *sfnt;
4582 if (FT_Version.major==2 && FT_Version.minor==0)
4584 /* 2.0.x */
4585 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
4587 else
4589 /* A field was added in the middle of the structure in 2.1.x */
4590 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
4592 /* make sure value of len is the value freetype says it needs */
4593 if( buf && len) {
4594 FT_ULong needed = 0;
4595 err = sfnt->load_any(tt_face, table, offset, NULL, &needed);
4596 if( !err && needed < len) len = needed;
4598 err = sfnt->load_any(tt_face, table, offset, buf, &len);
4600 #else
4601 else {
4602 static int msg;
4603 if(!msg) {
4604 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
4605 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
4606 "Please upgrade your freetype library.\n");
4607 msg++;
4609 err = FT_Err_Unimplemented_Feature;
4611 #endif
4612 if(err) {
4613 TRACE("Can't find table %c%c%c%c\n",
4614 /* bytes were reversed */
4615 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
4616 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
4617 return GDI_ERROR;
4619 return len;
4622 /*************************************************************
4623 * WineEngGetTextFace
4626 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
4628 if(str) {
4629 lstrcpynW(str, font->name, count);
4630 return strlenW(font->name);
4631 } else
4632 return strlenW(font->name) + 1;
4635 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
4637 if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
4638 return font->charset;
4641 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
4643 GdiFont *font = dc->gdiFont, *linked_font;
4644 struct list *first_hfont;
4645 BOOL ret;
4647 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
4648 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
4649 if(font == linked_font)
4650 *new_hfont = dc->hFont;
4651 else
4653 first_hfont = list_head(&linked_font->hfontlist);
4654 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
4657 return ret;
4660 /* Retrieve a list of supported Unicode ranges for a given font.
4661 * Can be called with NULL gs to calculate the buffer size. Returns
4662 * the number of ranges found.
4664 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
4666 DWORD num_ranges = 0;
4668 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
4670 FT_UInt glyph_code;
4671 FT_ULong char_code, char_code_prev;
4673 glyph_code = 0;
4674 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
4676 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
4677 face->num_glyphs, glyph_code, char_code);
4679 if (!glyph_code) return 0;
4681 if (gs)
4683 gs->ranges[0].wcLow = (USHORT)char_code;
4684 gs->ranges[0].cGlyphs = 0;
4685 gs->cGlyphsSupported = 0;
4688 num_ranges = 1;
4689 while (glyph_code)
4691 if (char_code < char_code_prev)
4693 ERR("expected increasing char code from FT_Get_Next_Char\n");
4694 return 0;
4696 if (char_code - char_code_prev > 1)
4698 num_ranges++;
4699 if (gs)
4701 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
4702 gs->ranges[num_ranges - 1].cGlyphs = 1;
4703 gs->cGlyphsSupported++;
4706 else if (gs)
4708 gs->ranges[num_ranges - 1].cGlyphs++;
4709 gs->cGlyphsSupported++;
4711 char_code_prev = char_code;
4712 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
4715 else
4716 FIXME("encoding %u not supported\n", face->charmap->encoding);
4718 return num_ranges;
4721 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
4723 DWORD size = 0;
4724 DWORD num_ranges = get_font_unicode_ranges(font->ft_face, glyphset);
4726 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
4727 if (glyphset)
4729 glyphset->cbThis = size;
4730 glyphset->cRanges = num_ranges;
4732 return size;
4735 /*************************************************************
4736 * FontIsLinked
4738 BOOL WineEngFontIsLinked(GdiFont *font)
4740 return !list_empty(&font->child_fonts);
4743 static BOOL is_hinting_enabled(void)
4745 /* Use the >= 2.2.0 function if available */
4746 if(pFT_Get_TrueType_Engine_Type)
4748 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
4749 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
4751 #ifdef FT_DRIVER_HAS_HINTER
4752 else
4754 FT_Module mod;
4756 /* otherwise if we've been compiled with < 2.2.0 headers
4757 use the internal macro */
4758 mod = pFT_Get_Module(library, "truetype");
4759 if(mod && FT_DRIVER_HAS_HINTER(mod))
4760 return TRUE;
4762 #endif
4764 return FALSE;
4767 /*************************************************************************
4768 * GetRasterizerCaps (GDI32.@)
4770 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
4772 static int hinting = -1;
4774 if(hinting == -1)
4776 hinting = is_hinting_enabled();
4777 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
4780 lprs->nSize = sizeof(RASTERIZER_STATUS);
4781 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
4782 lprs->nLanguageID = 0;
4783 return TRUE;
4786 /*************************************************************************
4787 * Kerning support for TrueType fonts
4789 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
4791 struct TT_kern_table
4793 USHORT version;
4794 USHORT nTables;
4797 struct TT_kern_subtable
4799 USHORT version;
4800 USHORT length;
4801 union
4803 USHORT word;
4804 struct
4806 USHORT horizontal : 1;
4807 USHORT minimum : 1;
4808 USHORT cross_stream: 1;
4809 USHORT override : 1;
4810 USHORT reserved1 : 4;
4811 USHORT format : 8;
4812 } bits;
4813 } coverage;
4816 struct TT_format0_kern_subtable
4818 USHORT nPairs;
4819 USHORT searchRange;
4820 USHORT entrySelector;
4821 USHORT rangeShift;
4824 struct TT_kern_pair
4826 USHORT left;
4827 USHORT right;
4828 short value;
4831 static DWORD parse_format0_kern_subtable(GdiFont *font,
4832 const struct TT_format0_kern_subtable *tt_f0_ks,
4833 const USHORT *glyph_to_char,
4834 KERNINGPAIR *kern_pair, DWORD cPairs)
4836 USHORT i, nPairs;
4837 const struct TT_kern_pair *tt_kern_pair;
4839 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
4841 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
4843 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
4844 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
4845 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
4847 if (!kern_pair || !cPairs)
4848 return nPairs;
4850 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
4852 nPairs = min(nPairs, cPairs);
4854 for (i = 0; i < nPairs; i++)
4856 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
4857 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
4858 /* this algorithm appears to better match what Windows does */
4859 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
4860 if (kern_pair->iKernAmount < 0)
4862 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
4863 kern_pair->iKernAmount -= font->ppem;
4865 else if (kern_pair->iKernAmount > 0)
4867 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
4868 kern_pair->iKernAmount += font->ppem;
4870 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
4872 TRACE("left %u right %u value %d\n",
4873 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
4875 kern_pair++;
4877 TRACE("copied %u entries\n", nPairs);
4878 return nPairs;
4881 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
4883 DWORD length;
4884 void *buf;
4885 const struct TT_kern_table *tt_kern_table;
4886 const struct TT_kern_subtable *tt_kern_subtable;
4887 USHORT i, nTables;
4888 USHORT *glyph_to_char;
4890 if (font->total_kern_pairs != (DWORD)-1)
4892 if (cPairs && kern_pair)
4894 cPairs = min(cPairs, font->total_kern_pairs);
4895 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
4896 return cPairs;
4898 return font->total_kern_pairs;
4901 font->total_kern_pairs = 0;
4903 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
4905 if (length == GDI_ERROR)
4907 TRACE("no kerning data in the font\n");
4908 return 0;
4911 buf = HeapAlloc(GetProcessHeap(), 0, length);
4912 if (!buf)
4914 WARN("Out of memory\n");
4915 return 0;
4918 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
4920 /* build a glyph index to char code map */
4921 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
4922 if (!glyph_to_char)
4924 WARN("Out of memory allocating a glyph index to char code map\n");
4925 HeapFree(GetProcessHeap(), 0, buf);
4926 return 0;
4929 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
4931 FT_UInt glyph_code;
4932 FT_ULong char_code;
4934 glyph_code = 0;
4935 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
4937 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
4938 font->ft_face->num_glyphs, glyph_code, char_code);
4940 while (glyph_code)
4942 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
4944 /* FIXME: This doesn't match what Windows does: it does some fancy
4945 * things with duplicate glyph index to char code mappings, while
4946 * we just avoid overriding existing entries.
4948 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
4949 glyph_to_char[glyph_code] = (USHORT)char_code;
4951 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
4954 else
4956 ULONG n;
4958 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
4959 for (n = 0; n <= 65535; n++)
4960 glyph_to_char[n] = (USHORT)n;
4963 tt_kern_table = buf;
4964 nTables = GET_BE_WORD(tt_kern_table->nTables);
4965 TRACE("version %u, nTables %u\n",
4966 GET_BE_WORD(tt_kern_table->version), nTables);
4968 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
4970 for (i = 0; i < nTables; i++)
4972 struct TT_kern_subtable tt_kern_subtable_copy;
4974 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
4975 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
4976 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
4978 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
4979 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
4980 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
4982 /* According to the TrueType specification this is the only format
4983 * that will be properly interpreted by Windows and OS/2
4985 if (tt_kern_subtable_copy.coverage.bits.format == 0)
4987 DWORD new_chunk, old_total = font->total_kern_pairs;
4989 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
4990 glyph_to_char, NULL, 0);
4991 font->total_kern_pairs += new_chunk;
4993 if (!font->kern_pairs)
4994 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
4995 font->total_kern_pairs * sizeof(*font->kern_pairs));
4996 else
4997 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
4998 font->total_kern_pairs * sizeof(*font->kern_pairs));
5000 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
5001 glyph_to_char, font->kern_pairs + old_total, new_chunk);
5003 else
5004 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
5006 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
5009 HeapFree(GetProcessHeap(), 0, glyph_to_char);
5010 HeapFree(GetProcessHeap(), 0, buf);
5012 if (cPairs && kern_pair)
5014 cPairs = min(cPairs, font->total_kern_pairs);
5015 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
5016 return cPairs;
5018 return font->total_kern_pairs;
5021 #else /* HAVE_FREETYPE */
5023 /*************************************************************************/
5025 BOOL WineEngInit(void)
5027 return FALSE;
5029 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
5031 return NULL;
5033 BOOL WineEngDestroyFontInstance(HFONT hfont)
5035 return FALSE;
5038 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
5040 return 1;
5043 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
5044 LPWORD pgi, DWORD flags)
5046 return GDI_ERROR;
5049 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
5050 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5051 const MAT2* lpmat)
5053 ERR("called but we don't have FreeType\n");
5054 return GDI_ERROR;
5057 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
5059 ERR("called but we don't have FreeType\n");
5060 return FALSE;
5063 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
5064 OUTLINETEXTMETRICW *potm)
5066 ERR("called but we don't have FreeType\n");
5067 return 0;
5070 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5071 LPINT buffer)
5073 ERR("called but we don't have FreeType\n");
5074 return FALSE;
5077 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5078 LPABC buffer)
5080 ERR("called but we don't have FreeType\n");
5081 return FALSE;
5084 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
5085 LPABC buffer)
5087 ERR("called but we don't have FreeType\n");
5088 return FALSE;
5091 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
5092 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
5094 ERR("called but we don't have FreeType\n");
5095 return FALSE;
5098 BOOL WineEngGetTextExtentPointI(GdiFont *font, const WORD *indices, INT count,
5099 LPSIZE size)
5101 ERR("called but we don't have FreeType\n");
5102 return FALSE;
5105 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
5106 DWORD cbData)
5108 ERR("called but we don't have FreeType\n");
5109 return GDI_ERROR;
5112 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
5114 ERR("called but we don't have FreeType\n");
5115 return 0;
5118 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
5120 FIXME(":stub\n");
5121 return 1;
5124 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
5126 FIXME(":stub\n");
5127 return TRUE;
5130 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
5132 FIXME(":stub\n");
5133 return NULL;
5136 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
5138 FIXME(":stub\n");
5139 return DEFAULT_CHARSET;
5142 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
5144 return FALSE;
5147 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
5149 FIXME("(%p, %p): stub\n", font, glyphset);
5150 return 0;
5153 BOOL WineEngFontIsLinked(GdiFont *font)
5155 return FALSE;
5158 /*************************************************************************
5159 * GetRasterizerCaps (GDI32.@)
5161 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
5163 lprs->nSize = sizeof(RASTERIZER_STATUS);
5164 lprs->wFlags = 0;
5165 lprs->nLanguageID = 0;
5166 return TRUE;
5169 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
5171 ERR("called but we don't have FreeType\n");
5172 return 0;
5175 #endif /* HAVE_FREETYPE */