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