d3d9: Initialize the test rectangle correctly.
[wine/multimedia.git] / dlls / gdi32 / freetype.c
bloba79f41d8b86e752d3655c7978d734a4441d00ef0
1 /*
2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
5 * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
7 * This file contains the WineEng* functions.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "config.h"
25 #include "wine/port.h"
27 #include <stdarg.h>
28 #include <stdlib.h>
29 #ifdef HAVE_SYS_STAT_H
30 # include <sys/stat.h>
31 #endif
32 #ifdef HAVE_SYS_MMAN_H
33 # include <sys/mman.h>
34 #endif
35 #include <string.h>
36 #include <dirent.h>
37 #include <stdio.h>
38 #include <assert.h>
40 #ifdef HAVE_CARBON_CARBON_H
41 #define LoadResource __carbon_LoadResource
42 #define CompareString __carbon_CompareString
43 #define GetCurrentThread __carbon_GetCurrentThread
44 #define GetCurrentProcess __carbon_GetCurrentProcess
45 #define AnimatePalette __carbon_AnimatePalette
46 #define EqualRgn __carbon_EqualRgn
47 #define FillRgn __carbon_FillRgn
48 #define FrameRgn __carbon_FrameRgn
49 #define GetPixel __carbon_GetPixel
50 #define InvertRgn __carbon_InvertRgn
51 #define LineTo __carbon_LineTo
52 #define OffsetRgn __carbon_OffsetRgn
53 #define PaintRgn __carbon_PaintRgn
54 #define Polygon __carbon_Polygon
55 #define ResizePalette __carbon_ResizePalette
56 #define SetRectRgn __carbon_SetRectRgn
57 #include <Carbon/Carbon.h>
58 #undef LoadResource
59 #undef CompareString
60 #undef GetCurrentThread
61 #undef _CDECL
62 #undef DPRINTF
63 #undef GetCurrentProcess
64 #undef AnimatePalette
65 #undef EqualRgn
66 #undef FillRgn
67 #undef FrameRgn
68 #undef GetPixel
69 #undef InvertRgn
70 #undef LineTo
71 #undef OffsetRgn
72 #undef PaintRgn
73 #undef Polygon
74 #undef ResizePalette
75 #undef SetRectRgn
76 #endif /* HAVE_CARBON_CARBON_H */
78 #include "windef.h"
79 #include "winbase.h"
80 #include "winternl.h"
81 #include "winerror.h"
82 #include "winreg.h"
83 #include "wingdi.h"
84 #include "gdi_private.h"
85 #include "wine/unicode.h"
86 #include "wine/debug.h"
87 #include "wine/list.h"
89 WINE_DEFAULT_DEBUG_CHANNEL(font);
91 #ifdef HAVE_FREETYPE
93 #ifdef HAVE_FT2BUILD_H
94 #include <ft2build.h>
95 #endif
96 #ifdef HAVE_FREETYPE_FREETYPE_H
97 #include <freetype/freetype.h>
98 #endif
99 #ifdef HAVE_FREETYPE_FTGLYPH_H
100 #include <freetype/ftglyph.h>
101 #endif
102 #ifdef HAVE_FREETYPE_TTTABLES_H
103 #include <freetype/tttables.h>
104 #endif
105 #ifdef HAVE_FREETYPE_FTTYPES_H
106 #include <freetype/fttypes.h>
107 #endif
108 #ifdef HAVE_FREETYPE_FTSNAMES_H
109 #include <freetype/ftsnames.h>
110 #else
111 # ifdef HAVE_FREETYPE_FTNAMES_H
112 # include <freetype/ftnames.h>
113 # endif
114 #endif
115 #ifdef HAVE_FREETYPE_TTNAMEID_H
116 #include <freetype/ttnameid.h>
117 #endif
118 #ifdef HAVE_FREETYPE_FTOUTLN_H
119 #include <freetype/ftoutln.h>
120 #endif
121 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
122 #include <freetype/internal/sfnt.h>
123 #endif
124 #ifdef HAVE_FREETYPE_FTTRIGON_H
125 #include <freetype/fttrigon.h>
126 #endif
127 #ifdef HAVE_FREETYPE_FTWINFNT_H
128 #include <freetype/ftwinfnt.h>
129 #endif
130 #ifdef HAVE_FREETYPE_FTMODAPI_H
131 #include <freetype/ftmodapi.h>
132 #endif
134 #ifndef HAVE_FT_TRUETYPEENGINETYPE
135 typedef enum
137 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
138 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
139 FT_TRUETYPE_ENGINE_TYPE_PATENTED
140 } FT_TrueTypeEngineType;
141 #endif
143 static FT_Library library = 0;
144 typedef struct
146 FT_Int major;
147 FT_Int minor;
148 FT_Int patch;
149 } FT_Version_t;
150 static FT_Version_t FT_Version;
151 static DWORD FT_SimpleVersion;
153 static void *ft_handle = NULL;
155 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
156 MAKE_FUNCPTR(FT_Vector_Unit);
157 MAKE_FUNCPTR(FT_Done_Face);
158 MAKE_FUNCPTR(FT_Get_Char_Index);
159 MAKE_FUNCPTR(FT_Get_Module);
160 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
161 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
163 MAKE_FUNCPTR(FT_Init_FreeType);
164 MAKE_FUNCPTR(FT_Load_Glyph);
165 MAKE_FUNCPTR(FT_Matrix_Multiply);
166 MAKE_FUNCPTR(FT_MulFix);
167 MAKE_FUNCPTR(FT_New_Face);
168 MAKE_FUNCPTR(FT_New_Memory_Face);
169 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
170 MAKE_FUNCPTR(FT_Outline_Transform);
171 MAKE_FUNCPTR(FT_Outline_Translate);
172 MAKE_FUNCPTR(FT_Select_Charmap);
173 MAKE_FUNCPTR(FT_Set_Charmap);
174 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
175 MAKE_FUNCPTR(FT_Vector_Transform);
176 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
177 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
178 static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*);
179 static FT_ULong (*pFT_Get_Next_Char)(FT_Face,FT_ULong,FT_UInt*);
180 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
181 #ifdef HAVE_FREETYPE_FTWINFNT_H
182 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
183 #endif
185 #ifdef SONAME_LIBFONTCONFIG
186 #include <fontconfig/fontconfig.h>
187 MAKE_FUNCPTR(FcConfigGetCurrent);
188 MAKE_FUNCPTR(FcFontList);
189 MAKE_FUNCPTR(FcFontSetDestroy);
190 MAKE_FUNCPTR(FcInit);
191 MAKE_FUNCPTR(FcObjectSetAdd);
192 MAKE_FUNCPTR(FcObjectSetCreate);
193 MAKE_FUNCPTR(FcObjectSetDestroy);
194 MAKE_FUNCPTR(FcPatternCreate);
195 MAKE_FUNCPTR(FcPatternDestroy);
196 MAKE_FUNCPTR(FcPatternGetBool);
197 MAKE_FUNCPTR(FcPatternGetString);
198 #endif
200 #undef MAKE_FUNCPTR
202 #ifndef FT_MAKE_TAG
203 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
204 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
205 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
206 #endif
208 #ifndef ft_encoding_none
209 #define FT_ENCODING_NONE ft_encoding_none
210 #endif
211 #ifndef ft_encoding_ms_symbol
212 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
213 #endif
214 #ifndef ft_encoding_unicode
215 #define FT_ENCODING_UNICODE ft_encoding_unicode
216 #endif
217 #ifndef ft_encoding_apple_roman
218 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
219 #endif
221 #ifdef WORDS_BIGENDIAN
222 #define GET_BE_WORD(x) (x)
223 #else
224 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
225 #endif
227 /* This is bascially a copy of FT_Bitmap_Size with an extra element added */
228 typedef struct {
229 FT_Short height;
230 FT_Short width;
231 FT_Pos size;
232 FT_Pos x_ppem;
233 FT_Pos y_ppem;
234 FT_Short internal_leading;
235 } Bitmap_Size;
237 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
238 So to let this compile on older versions of FreeType we'll define the
239 new structure here. */
240 typedef struct {
241 FT_Short height, width;
242 FT_Pos size, x_ppem, y_ppem;
243 } My_FT_Bitmap_Size;
245 typedef struct tagFace {
246 struct list entry;
247 WCHAR *StyleName;
248 char *file;
249 void *font_data_ptr;
250 DWORD font_data_size;
251 FT_Long face_index;
252 BOOL Italic;
253 BOOL Bold;
254 FONTSIGNATURE fs;
255 FONTSIGNATURE fs_links;
256 DWORD ntmFlags; /* Only some bits stored here. Others are computed on the fly */
257 FT_Fixed font_version;
258 BOOL scalable;
259 Bitmap_Size size; /* set if face is a bitmap */
260 BOOL external; /* TRUE if we should manually add this font to the registry */
261 struct tagFamily *family;
262 } Face;
264 typedef struct tagFamily {
265 struct list entry;
266 const WCHAR *FamilyName;
267 struct list faces;
268 } Family;
270 typedef struct {
271 GLYPHMETRICS gm;
272 INT adv; /* These three hold to widths of the unrotated chars */
273 INT lsb;
274 INT bbx;
275 BOOL init;
276 } GM;
278 typedef struct {
279 FLOAT eM11, eM12;
280 FLOAT eM21, eM22;
281 } FMAT2;
283 typedef struct {
284 DWORD hash;
285 LOGFONTW lf;
286 FMAT2 matrix;
287 BOOL can_use_bitmap;
288 } FONT_DESC;
290 typedef struct tagHFONTLIST {
291 struct list entry;
292 HFONT hfont;
293 } HFONTLIST;
295 typedef struct {
296 struct list entry;
297 Face *face;
298 GdiFont *font;
299 } CHILD_FONT;
301 struct tagGdiFont {
302 struct list entry;
303 FT_Face ft_face;
304 struct font_mapping *mapping;
305 LPWSTR name;
306 int charset;
307 int codepage;
308 BOOL fake_italic;
309 BOOL fake_bold;
310 BYTE underline;
311 BYTE strikeout;
312 INT orientation;
313 GM **gm;
314 DWORD gmsize;
315 struct list hfontlist;
316 FONT_DESC font_desc;
317 LONG aveWidth;
318 SHORT yMax;
319 SHORT yMin;
320 OUTLINETEXTMETRICW *potm;
321 DWORD ntmFlags;
322 DWORD total_kern_pairs;
323 KERNINGPAIR *kern_pairs;
324 FONTSIGNATURE fs;
325 GdiFont *base_font;
326 struct list child_fonts;
327 LONG ppem;
330 typedef struct {
331 struct list entry;
332 const WCHAR *font_name;
333 struct list links;
334 } SYSTEM_LINKS;
336 #define GM_BLOCK_SIZE 128
337 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
339 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
340 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
341 #define UNUSED_CACHE_SIZE 10
342 static struct list child_font_list = LIST_INIT(child_font_list);
343 static struct list system_links = LIST_INIT(system_links);
345 static struct list font_subst_list = LIST_INIT(font_subst_list);
347 static struct list font_list = LIST_INIT(font_list);
349 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
350 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
351 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
353 static const WCHAR RegularW[] = {'R','e','g','u','l','a','r','\0'};
355 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
356 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
357 'W','i','n','d','o','w','s','\\',
358 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
359 'F','o','n','t','s','\0'};
361 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
362 'W','i','n','d','o','w','s',' ','N','T','\\',
363 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
364 'F','o','n','t','s','\0'};
366 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
367 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
368 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
369 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
371 static const WCHAR * const SystemFontValues[4] = {
372 System_Value,
373 OEMFont_Value,
374 FixedSys_Value,
375 NULL
378 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
379 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
381 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
382 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
383 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
384 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
385 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
386 'E','u','r','o','p','e','a','n','\0'};
387 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
388 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
389 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
390 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
391 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
392 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
393 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
394 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
395 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
396 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
397 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
398 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
400 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
401 WesternW, /*00*/
402 Central_EuropeanW,
403 CyrillicW,
404 GreekW,
405 TurkishW,
406 HebrewW,
407 ArabicW,
408 BalticW,
409 VietnameseW, /*08*/
410 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
411 ThaiW,
412 JapaneseW,
413 CHINESE_GB2312W,
414 HangulW,
415 CHINESE_BIG5W,
416 Hangul_Johab_W,
417 NULL, NULL, /*23*/
418 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
419 SymbolW /*31*/
422 typedef struct {
423 WCHAR *name;
424 INT charset;
425 } NameCs;
427 typedef struct tagFontSubst {
428 struct list entry;
429 NameCs from;
430 NameCs to;
431 } FontSubst;
433 struct font_mapping
435 struct list entry;
436 int refcount;
437 dev_t dev;
438 ino_t ino;
439 void *data;
440 size_t size;
443 static struct list mappings_list = LIST_INIT( mappings_list );
445 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
447 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
449 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
451 /****************************************
452 * Notes on .fon files
454 * The fonts System, FixedSys and Terminal are special. There are typically multiple
455 * versions installed for different resolutions and codepages. Windows stores which one to use
456 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
457 * Key Meaning
458 * FIXEDFON.FON FixedSys
459 * FONTS.FON System
460 * OEMFONT.FON Terminal
461 * LogPixels Current dpi set by the display control panel applet
462 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
463 * also has a LogPixels value that appears to mirror this)
465 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
466 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
467 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
468 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
469 * so that makes sense.
471 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
472 * to be mapped into the registry on Windows 2000 at least).
473 * I have
474 * woafont=app850.fon
475 * ega80woa.fon=ega80850.fon
476 * ega40woa.fon=ega40850.fon
477 * cga80woa.fon=cga80850.fon
478 * cga40woa.fon=cga40850.fon
481 #ifdef HAVE_CARBON_CARBON_H
482 static char *find_cache_dir(void)
484 FSRef ref;
485 OSErr err;
486 static char cached_path[MAX_PATH];
487 static const char *wine = "/Wine", *fonts = "/Fonts";
489 if(*cached_path) return cached_path;
491 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
492 if(err != noErr)
494 WARN("can't create cached data folder\n");
495 return NULL;
497 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
498 if(err != noErr)
500 WARN("can't create cached data path\n");
501 *cached_path = '\0';
502 return NULL;
504 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
506 ERR("Could not create full path\n");
507 *cached_path = '\0';
508 return NULL;
510 strcat(cached_path, wine);
512 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
514 WARN("Couldn't mkdir %s\n", cached_path);
515 *cached_path = '\0';
516 return NULL;
518 strcat(cached_path, fonts);
519 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
521 WARN("Couldn't mkdir %s\n", cached_path);
522 *cached_path = '\0';
523 return NULL;
525 return cached_path;
528 /******************************************************************
529 * expand_mac_font
531 * Extracts individual TrueType font files from a Mac suitcase font
532 * and saves them into the user's caches directory (see
533 * find_cache_dir()).
534 * Returns a NULL terminated array of filenames.
536 * We do this because they are apps that try to read ttf files
537 * themselves and they don't like Mac suitcase files.
539 static char **expand_mac_font(const char *path)
541 FSRef ref;
542 SInt16 res_ref;
543 OSStatus s;
544 unsigned int idx;
545 const char *out_dir;
546 const char *filename;
547 int output_len;
548 struct {
549 char **array;
550 unsigned int size, max_size;
551 } ret;
553 TRACE("path %s\n", path);
555 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
556 if(s != noErr)
558 WARN("failed to get ref\n");
559 return NULL;
562 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
563 if(s != noErr)
565 TRACE("no data fork, so trying resource fork\n");
566 res_ref = FSOpenResFile(&ref, fsRdPerm);
567 if(res_ref == -1)
569 TRACE("unable to open resource fork\n");
570 return NULL;
574 ret.size = 0;
575 ret.max_size = 10;
576 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
577 if(!ret.array)
579 CloseResFile(res_ref);
580 return NULL;
583 out_dir = find_cache_dir();
585 filename = strrchr(path, '/');
586 if(!filename) filename = path;
587 else filename++;
589 /* output filename has the form out_dir/filename_%04x.ttf */
590 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
592 UseResFile(res_ref);
593 idx = 1;
594 while(1)
596 FamRec *fam_rec;
597 unsigned short *num_faces_ptr, num_faces, face;
598 AsscEntry *assoc;
599 Handle fond;
600 ResType fond_res = FT_MAKE_TAG('F','O','N','D');
602 fond = Get1IndResource(fond_res, idx);
603 if(!fond) break;
604 TRACE("got fond resource %d\n", idx);
605 HLock(fond);
607 fam_rec = *(FamRec**)fond;
608 num_faces_ptr = (unsigned short *)(fam_rec + 1);
609 num_faces = GET_BE_WORD(*num_faces_ptr);
610 num_faces++;
611 assoc = (AsscEntry*)(num_faces_ptr + 1);
612 TRACE("num faces %04x\n", num_faces);
613 for(face = 0; face < num_faces; face++, assoc++)
615 Handle sfnt;
616 ResType sfnt_res = FT_MAKE_TAG('s','f','n','t');
617 unsigned short size, font_id;
618 char *output;
620 size = GET_BE_WORD(assoc->fontSize);
621 font_id = GET_BE_WORD(assoc->fontID);
622 if(size != 0)
624 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
625 continue;
628 TRACE("trying to load sfnt id %04x\n", font_id);
629 sfnt = GetResource(sfnt_res, font_id);
630 if(!sfnt)
632 TRACE("can't get sfnt resource %04x\n", font_id);
633 continue;
636 output = HeapAlloc(GetProcessHeap(), 0, output_len);
637 if(output)
639 int fd;
641 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
643 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
644 if(fd != -1 || errno == EEXIST)
646 if(fd != -1)
648 unsigned char *sfnt_data;
650 HLock(sfnt);
651 sfnt_data = *(unsigned char**)sfnt;
652 write(fd, sfnt_data, GetHandleSize(sfnt));
653 HUnlock(sfnt);
654 close(fd);
656 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
658 ret.max_size *= 2;
659 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
661 ret.array[ret.size++] = output;
663 else
665 WARN("unable to create %s\n", output);
666 HeapFree(GetProcessHeap(), 0, output);
669 ReleaseResource(sfnt);
671 HUnlock(fond);
672 ReleaseResource(fond);
673 idx++;
675 CloseResFile(res_ref);
677 return ret.array;
680 #endif /* HAVE_CARBON_CARBON_H */
682 static inline BOOL is_win9x(void)
684 return GetVersion() & 0x80000000;
687 This function builds an FT_Fixed from a float. It puts the integer part
688 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
689 It fails if the integer part of the float number is greater than SHORT_MAX.
691 static inline FT_Fixed FT_FixedFromFloat(float f)
693 short value = f;
694 unsigned short fract = (f - value) * 0xFFFF;
695 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
699 This function builds an FT_Fixed from a FIXED. It simply put f.value
700 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
702 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
704 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
708 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
710 Family *family;
711 Face *face;
712 const char *file;
713 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
714 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
716 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
717 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
719 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
721 if(face_name && strcmpiW(face_name, family->FamilyName))
722 continue;
723 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
725 if (!face->file)
726 continue;
727 file = strrchr(face->file, '/');
728 if(!file)
729 file = face->file;
730 else
731 file++;
732 if(!strcasecmp(file, file_nameA))
734 HeapFree(GetProcessHeap(), 0, file_nameA);
735 return face;
739 HeapFree(GetProcessHeap(), 0, file_nameA);
740 return NULL;
743 static Family *find_family_from_name(const WCHAR *name)
745 Family *family;
747 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
749 if(!strcmpiW(family->FamilyName, name))
750 return family;
753 return NULL;
756 static void DumpSubstList(void)
758 FontSubst *psub;
760 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
762 if(psub->from.charset != -1 || psub->to.charset != -1)
763 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
764 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
765 else
766 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
767 debugstr_w(psub->to.name));
769 return;
772 static LPWSTR strdupW(LPCWSTR p)
774 LPWSTR ret;
775 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
776 ret = HeapAlloc(GetProcessHeap(), 0, len);
777 memcpy(ret, p, len);
778 return ret;
781 static LPSTR strdupA(LPCSTR p)
783 LPSTR ret;
784 DWORD len = (strlen(p) + 1);
785 ret = HeapAlloc(GetProcessHeap(), 0, len);
786 memcpy(ret, p, len);
787 return ret;
790 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
791 INT from_charset)
793 FontSubst *element;
795 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
797 if(!strcmpiW(element->from.name, from_name) &&
798 (element->from.charset == from_charset ||
799 element->from.charset == -1))
800 return element;
803 return NULL;
806 #define ADD_FONT_SUBST_FORCE 1
808 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
810 FontSubst *from_exist, *to_exist;
812 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
814 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
816 list_remove(&from_exist->entry);
817 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
818 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
819 HeapFree(GetProcessHeap(), 0, from_exist);
820 from_exist = NULL;
823 if(!from_exist)
825 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
827 if(to_exist)
829 HeapFree(GetProcessHeap(), 0, subst->to.name);
830 subst->to.name = strdupW(to_exist->to.name);
833 list_add_tail(subst_list, &subst->entry);
835 return TRUE;
838 HeapFree(GetProcessHeap(), 0, subst->from.name);
839 HeapFree(GetProcessHeap(), 0, subst->to.name);
840 HeapFree(GetProcessHeap(), 0, subst);
841 return FALSE;
844 static void split_subst_info(NameCs *nc, LPSTR str)
846 CHAR *p = strrchr(str, ',');
847 DWORD len;
849 nc->charset = -1;
850 if(p && *(p+1)) {
851 nc->charset = strtol(p+1, NULL, 10);
852 *p = '\0';
854 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
855 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
856 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
859 static void LoadSubstList(void)
861 FontSubst *psub;
862 HKEY hkey;
863 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
864 LPSTR value;
865 LPVOID data;
867 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
868 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
869 &hkey) == ERROR_SUCCESS) {
871 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
872 &valuelen, &datalen, NULL, NULL);
874 valuelen++; /* returned value doesn't include room for '\0' */
875 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
876 data = HeapAlloc(GetProcessHeap(), 0, datalen);
878 dlen = datalen;
879 vlen = valuelen;
880 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
881 &dlen) == ERROR_SUCCESS) {
882 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
884 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
885 split_subst_info(&psub->from, value);
886 split_subst_info(&psub->to, data);
888 /* Win 2000 doesn't allow mapping between different charsets
889 or mapping of DEFAULT_CHARSET */
890 if((psub->to.charset != psub->from.charset) ||
891 psub->to.charset == DEFAULT_CHARSET) {
892 HeapFree(GetProcessHeap(), 0, psub->to.name);
893 HeapFree(GetProcessHeap(), 0, psub->from.name);
894 HeapFree(GetProcessHeap(), 0, psub);
895 } else {
896 add_font_subst(&font_subst_list, psub, 0);
898 /* reset dlen and vlen */
899 dlen = datalen;
900 vlen = valuelen;
902 HeapFree(GetProcessHeap(), 0, data);
903 HeapFree(GetProcessHeap(), 0, value);
904 RegCloseKey(hkey);
908 static WCHAR *get_familyname(FT_Face ft_face)
910 WCHAR *family = NULL;
911 FT_SfntName name;
912 FT_UInt num_names, name_index, i;
914 if(FT_IS_SFNT(ft_face))
916 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
918 for(name_index = 0; name_index < num_names; name_index++)
920 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
922 if((name.name_id == TT_NAME_ID_FONT_FAMILY) &&
923 (name.language_id == GetUserDefaultLCID()) &&
924 (name.platform_id == TT_PLATFORM_MICROSOFT) &&
925 (name.encoding_id == TT_MS_ID_UNICODE_CS))
927 /* String is not nul terminated and string_len is a byte length. */
928 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
929 for(i = 0; i < name.string_len / 2; i++)
931 WORD *tmp = (WORD *)&name.string[i * 2];
932 family[i] = GET_BE_WORD(*tmp);
934 family[i] = 0;
936 TRACE("Got localised name %s\n", debugstr_w(family));
937 return family;
943 return NULL;
947 /*****************************************************************
948 * load_sfnt_table
950 * Wrapper around FT_Load_Sfnt_Table to cope with older versions
951 * of FreeType that don't export this function.
954 static FT_Error load_sfnt_table(FT_Face ft_face, FT_ULong table, FT_Long offset, FT_Byte *buf, FT_ULong *len)
957 FT_Error err;
959 /* If the FT_Load_Sfnt_Table function is there we'll use it */
960 if(pFT_Load_Sfnt_Table)
962 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, len);
964 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
965 else /* Do it the hard way */
967 TT_Face tt_face = (TT_Face) ft_face;
968 SFNT_Interface *sfnt;
969 if (FT_Version.major==2 && FT_Version.minor==0)
971 /* 2.0.x */
972 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
974 else
976 /* A field was added in the middle of the structure in 2.1.x */
977 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
979 err = sfnt->load_any(tt_face, table, offset, buf, len);
981 #else
982 else
984 static int msg;
985 if(!msg)
987 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
988 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
989 "Please upgrade your freetype library.\n");
990 msg++;
992 err = FT_Err_Unimplemented_Feature;
994 #endif
995 return err;
999 #define ADDFONT_EXTERNAL_FONT 0x01
1000 #define ADDFONT_FORCE_BITMAP 0x02
1001 static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags)
1003 FT_Face ft_face;
1004 TT_OS2 *pOS2;
1005 TT_Header *pHeader = NULL;
1006 WCHAR *english_family, *localised_family, *StyleW;
1007 DWORD len;
1008 Family *family;
1009 Face *face;
1010 struct list *family_elem_ptr, *face_elem_ptr;
1011 FT_Error err;
1012 FT_Long face_index = 0, num_faces;
1013 #ifdef HAVE_FREETYPE_FTWINFNT_H
1014 FT_WinFNT_HeaderRec winfnt_header;
1015 #endif
1016 int i, bitmap_num, internal_leading;
1017 FONTSIGNATURE fs;
1019 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
1020 assert(file || !(flags & ADDFONT_EXTERNAL_FONT));
1022 #ifdef HAVE_CARBON_CARBON_H
1023 if(file && !fake_family)
1025 char **mac_list = expand_mac_font(file);
1026 if(mac_list)
1028 BOOL had_one = FALSE;
1029 char **cursor;
1030 for(cursor = mac_list; *cursor; cursor++)
1032 had_one = TRUE;
1033 AddFontToList(*cursor, NULL, 0, NULL, NULL, flags);
1034 HeapFree(GetProcessHeap(), 0, *cursor);
1036 HeapFree(GetProcessHeap(), 0, mac_list);
1037 if(had_one)
1038 return 1;
1041 #endif /* HAVE_CARBON_CARBON_H */
1043 do {
1044 char *family_name = fake_family;
1046 if (file)
1048 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
1049 err = pFT_New_Face(library, file, face_index, &ft_face);
1050 } else
1052 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index);
1053 err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face);
1056 if(err != 0) {
1057 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err);
1058 return 0;
1061 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*/
1062 WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr);
1063 pFT_Done_Face(ft_face);
1064 return 0;
1067 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1068 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1069 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr);
1070 pFT_Done_Face(ft_face);
1071 return 0;
1074 if(FT_IS_SFNT(ft_face))
1076 if(!(pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2)) ||
1077 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1078 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))
1080 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
1081 "Skipping this font.\n", debugstr_a(file), font_data_ptr);
1082 pFT_Done_Face(ft_face);
1083 return 0;
1086 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
1087 we don't want to load these. */
1088 if(!memcmp(pOS2->achVendID, "Wine", sizeof(pOS2->achVendID)))
1090 FT_ULong len = 0;
1092 if(!load_sfnt_table(ft_face, FT_MAKE_TAG('E','B','S','C'), 0, NULL, &len))
1094 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file));
1095 pFT_Done_Face(ft_face);
1096 return 0;
1101 if(!ft_face->family_name || !ft_face->style_name) {
1102 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr);
1103 pFT_Done_Face(ft_face);
1104 return 0;
1107 if (target_family)
1109 localised_family = get_familyname(ft_face);
1110 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1112 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1113 HeapFree(GetProcessHeap(), 0, localised_family);
1114 num_faces = ft_face->num_faces;
1115 pFT_Done_Face(ft_face);
1116 continue;
1118 HeapFree(GetProcessHeap(), 0, localised_family);
1121 if(!family_name)
1122 family_name = ft_face->family_name;
1124 bitmap_num = 0;
1125 do {
1126 My_FT_Bitmap_Size *size = NULL;
1127 FT_ULong tmp_size;
1129 if(!FT_IS_SCALABLE(ft_face))
1130 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1132 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1133 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1134 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1136 localised_family = NULL;
1137 if(!fake_family) {
1138 localised_family = get_familyname(ft_face);
1139 if(localised_family && !strcmpW(localised_family, english_family)) {
1140 HeapFree(GetProcessHeap(), 0, localised_family);
1141 localised_family = NULL;
1145 family = NULL;
1146 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1147 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1148 if(!strcmpW(family->FamilyName, localised_family ? localised_family : english_family))
1149 break;
1150 family = NULL;
1152 if(!family) {
1153 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1154 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1155 list_init(&family->faces);
1156 list_add_tail(&font_list, &family->entry);
1158 if(localised_family) {
1159 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1160 subst->from.name = strdupW(english_family);
1161 subst->from.charset = -1;
1162 subst->to.name = strdupW(localised_family);
1163 subst->to.charset = -1;
1164 add_font_subst(&font_subst_list, subst, 0);
1167 HeapFree(GetProcessHeap(), 0, localised_family);
1168 HeapFree(GetProcessHeap(), 0, english_family);
1170 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1171 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1172 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1174 internal_leading = 0;
1175 memset(&fs, 0, sizeof(fs));
1177 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1178 if(pOS2) {
1179 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1180 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1181 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1182 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1183 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1184 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1185 if(pOS2->version == 0) {
1186 FT_UInt dummy;
1188 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1189 fs.fsCsb[0] |= 1;
1190 else
1191 fs.fsCsb[0] |= 1L << 31;
1194 #ifdef HAVE_FREETYPE_FTWINFNT_H
1195 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1196 CHARSETINFO csi;
1197 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1198 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1199 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1200 memcpy(&fs, &csi.fs, sizeof(csi.fs));
1201 internal_leading = winfnt_header.internal_leading;
1203 #endif
1205 face_elem_ptr = list_head(&family->faces);
1206 while(face_elem_ptr) {
1207 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1208 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1209 if(!strcmpW(face->StyleName, StyleW) &&
1210 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1211 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1212 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1213 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1215 if(fake_family) {
1216 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1217 HeapFree(GetProcessHeap(), 0, StyleW);
1218 pFT_Done_Face(ft_face);
1219 return 1;
1221 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1222 TRACE("Original font is newer so skipping this one\n");
1223 HeapFree(GetProcessHeap(), 0, StyleW);
1224 pFT_Done_Face(ft_face);
1225 return 1;
1226 } else {
1227 TRACE("Replacing original with this one\n");
1228 list_remove(&face->entry);
1229 HeapFree(GetProcessHeap(), 0, face->file);
1230 HeapFree(GetProcessHeap(), 0, face->StyleName);
1231 HeapFree(GetProcessHeap(), 0, face);
1232 break;
1236 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1237 list_add_tail(&family->faces, &face->entry);
1238 face->StyleName = StyleW;
1239 if (file)
1241 face->file = strdupA(file);
1242 face->font_data_ptr = NULL;
1243 face->font_data_size = 0;
1245 else
1247 face->file = NULL;
1248 face->font_data_ptr = font_data_ptr;
1249 face->font_data_size = font_data_size;
1251 face->face_index = face_index;
1252 face->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
1253 face->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
1254 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1255 face->family = family;
1256 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1257 memcpy(&face->fs, &fs, sizeof(face->fs));
1258 memset(&face->fs_links, 0, sizeof(face->fs_links));
1260 if(FT_IS_SCALABLE(ft_face)) {
1261 memset(&face->size, 0, sizeof(face->size));
1262 face->scalable = TRUE;
1263 } else {
1264 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1265 size->height, size->width, size->size >> 6,
1266 size->x_ppem >> 6, size->y_ppem >> 6);
1267 face->size.height = size->height;
1268 face->size.width = size->width;
1269 face->size.size = size->size;
1270 face->size.x_ppem = size->x_ppem;
1271 face->size.y_ppem = size->y_ppem;
1272 face->size.internal_leading = internal_leading;
1273 face->scalable = FALSE;
1276 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
1277 tmp_size = 0;
1278 if (pFT_Load_Sfnt_Table && !pFT_Load_Sfnt_Table(ft_face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
1280 TRACE("Font %s/%p is OTF Type1\n", wine_dbgstr_a(file), font_data_ptr);
1281 face->ntmFlags = NTM_PS_OPENTYPE;
1283 else
1284 face->ntmFlags = 0;
1286 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1287 face->fs.fsCsb[0], face->fs.fsCsb[1],
1288 face->fs.fsUsb[0], face->fs.fsUsb[1],
1289 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1292 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1293 for(i = 0; i < ft_face->num_charmaps; i++) {
1294 switch(ft_face->charmaps[i]->encoding) {
1295 case FT_ENCODING_UNICODE:
1296 case FT_ENCODING_APPLE_ROMAN:
1297 face->fs.fsCsb[0] |= 1;
1298 break;
1299 case FT_ENCODING_MS_SYMBOL:
1300 face->fs.fsCsb[0] |= 1L << 31;
1301 break;
1302 default:
1303 break;
1308 if(face->fs.fsCsb[0] & ~(1L << 31))
1309 have_installed_roman_font = TRUE;
1310 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1312 num_faces = ft_face->num_faces;
1313 pFT_Done_Face(ft_face);
1314 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1315 debugstr_w(StyleW));
1316 } while(num_faces > ++face_index);
1317 return num_faces;
1320 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
1322 return AddFontToList(file, NULL, 0, fake_family, target_family, flags);
1325 static void DumpFontList(void)
1327 Family *family;
1328 Face *face;
1329 struct list *family_elem_ptr, *face_elem_ptr;
1331 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1332 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1333 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1334 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1335 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1336 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1337 if(!face->scalable)
1338 TRACE(" %d", face->size.height);
1339 TRACE("\n");
1342 return;
1345 /***********************************************************
1346 * The replacement list is a way to map an entire font
1347 * family onto another family. For example adding
1349 * [HKCU\Software\Wine\Fonts\Replacements]
1350 * "Wingdings"="Winedings"
1352 * would enumerate the Winedings font both as Winedings and
1353 * Wingdings. However if a real Wingdings font is present the
1354 * replacement does not take place.
1357 static void LoadReplaceList(void)
1359 HKEY hkey;
1360 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1361 LPWSTR value;
1362 LPVOID data;
1363 Family *family;
1364 Face *face;
1365 struct list *family_elem_ptr, *face_elem_ptr;
1366 CHAR familyA[400];
1368 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1369 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1371 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1372 &valuelen, &datalen, NULL, NULL);
1374 valuelen++; /* returned value doesn't include room for '\0' */
1375 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1376 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1378 dlen = datalen;
1379 vlen = valuelen;
1380 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1381 &dlen) == ERROR_SUCCESS) {
1382 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1383 /* "NewName"="Oldname" */
1384 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1386 /* Find the old family and hence all of the font files
1387 in that family */
1388 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1389 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1390 if(!strcmpiW(family->FamilyName, data)) {
1391 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1392 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1393 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1394 debugstr_w(face->StyleName), familyA);
1395 /* Now add a new entry with the new family name */
1396 AddFontToList(face->file, face->font_data_ptr, face->font_data_size, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1398 break;
1401 /* reset dlen and vlen */
1402 dlen = datalen;
1403 vlen = valuelen;
1405 HeapFree(GetProcessHeap(), 0, data);
1406 HeapFree(GetProcessHeap(), 0, value);
1407 RegCloseKey(hkey);
1411 /*************************************************************
1412 * init_system_links
1414 static BOOL init_system_links(void)
1416 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1417 'W','i','n','d','o','w','s',' ','N','T','\\',
1418 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1419 'S','y','s','t','e','m','L','i','n','k',0};
1420 HKEY hkey;
1421 BOOL ret = FALSE;
1422 DWORD type, max_val, max_data, val_len, data_len, index;
1423 WCHAR *value, *data;
1424 WCHAR *entry, *next;
1425 SYSTEM_LINKS *font_link, *system_font_link;
1426 CHILD_FONT *child_font;
1427 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
1428 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1429 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1430 FONTSIGNATURE fs;
1431 Family *family;
1432 Face *face;
1433 FontSubst *psub;
1435 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1437 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1438 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1439 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1440 val_len = max_val + 1;
1441 data_len = max_data;
1442 index = 0;
1443 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1445 TRACE("%s:\n", debugstr_w(value));
1447 memset(&fs, 0, sizeof(fs));
1448 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1449 psub = get_font_subst(&font_subst_list, value, -1);
1450 font_link->font_name = (psub)? strdupW(psub->to.name) : strdupW(value);
1451 list_init(&font_link->links);
1452 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1454 WCHAR *face_name;
1455 CHILD_FONT *child_font;
1457 TRACE("\t%s\n", debugstr_w(entry));
1459 next = entry + strlenW(entry) + 1;
1461 face_name = strchrW(entry, ',');
1462 if(face_name)
1464 *face_name++ = 0;
1465 while(isspaceW(*face_name))
1466 face_name++;
1468 psub = get_font_subst(&font_subst_list, face_name, -1);
1469 if(psub)
1470 face_name = psub->to.name;
1472 face = find_face_from_filename(entry, face_name);
1473 if(!face)
1475 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1476 continue;
1479 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1480 child_font->face = face;
1481 child_font->font = NULL;
1482 fs.fsCsb[0] |= face->fs.fsCsb[0];
1483 fs.fsCsb[1] |= face->fs.fsCsb[1];
1484 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1485 list_add_tail(&font_link->links, &child_font->entry);
1487 family = find_family_from_name(font_link->font_name);
1488 if(family)
1490 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1492 memcpy(&face->fs_links, &fs, sizeof(fs));
1495 list_add_tail(&system_links, &font_link->entry);
1496 val_len = max_val + 1;
1497 data_len = max_data;
1500 HeapFree(GetProcessHeap(), 0, value);
1501 HeapFree(GetProcessHeap(), 0, data);
1502 RegCloseKey(hkey);
1505 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1506 that Tahoma has */
1508 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1509 system_font_link->font_name = strdupW(System);
1510 list_init(&system_font_link->links);
1512 face = find_face_from_filename(tahoma_ttf, Tahoma);
1513 if(face)
1515 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1516 child_font->face = face;
1517 child_font->font = NULL;
1518 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
1519 list_add_tail(&system_font_link->links, &child_font->entry);
1521 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1523 if(!strcmpiW(font_link->font_name, Tahoma))
1525 CHILD_FONT *font_link_entry;
1526 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1528 CHILD_FONT *new_child;
1529 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1530 new_child->face = font_link_entry->face;
1531 new_child->font = NULL;
1532 list_add_tail(&system_font_link->links, &new_child->entry);
1534 break;
1537 list_add_tail(&system_links, &system_font_link->entry);
1538 return ret;
1541 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1543 DIR *dir;
1544 struct dirent *dent;
1545 char path[MAX_PATH];
1547 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1549 dir = opendir(dirname);
1550 if(!dir) {
1551 WARN("Can't open directory %s\n", debugstr_a(dirname));
1552 return FALSE;
1554 while((dent = readdir(dir)) != NULL) {
1555 struct stat statbuf;
1557 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1558 continue;
1560 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1562 sprintf(path, "%s/%s", dirname, dent->d_name);
1564 if(stat(path, &statbuf) == -1)
1566 WARN("Can't stat %s\n", debugstr_a(path));
1567 continue;
1569 if(S_ISDIR(statbuf.st_mode))
1570 ReadFontDir(path, external_fonts);
1571 else
1572 AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1574 closedir(dir);
1575 return TRUE;
1578 static void load_fontconfig_fonts(void)
1580 #ifdef SONAME_LIBFONTCONFIG
1581 void *fc_handle = NULL;
1582 FcConfig *config;
1583 FcPattern *pat;
1584 FcObjectSet *os;
1585 FcFontSet *fontset;
1586 int i, len;
1587 char *file;
1588 const char *ext;
1590 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1591 if(!fc_handle) {
1592 TRACE("Wine cannot find the fontconfig library (%s).\n",
1593 SONAME_LIBFONTCONFIG);
1594 return;
1596 #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;}
1597 LOAD_FUNCPTR(FcConfigGetCurrent);
1598 LOAD_FUNCPTR(FcFontList);
1599 LOAD_FUNCPTR(FcFontSetDestroy);
1600 LOAD_FUNCPTR(FcInit);
1601 LOAD_FUNCPTR(FcObjectSetAdd);
1602 LOAD_FUNCPTR(FcObjectSetCreate);
1603 LOAD_FUNCPTR(FcObjectSetDestroy);
1604 LOAD_FUNCPTR(FcPatternCreate);
1605 LOAD_FUNCPTR(FcPatternDestroy);
1606 LOAD_FUNCPTR(FcPatternGetBool);
1607 LOAD_FUNCPTR(FcPatternGetString);
1608 #undef LOAD_FUNCPTR
1610 if(!pFcInit()) return;
1612 config = pFcConfigGetCurrent();
1613 pat = pFcPatternCreate();
1614 os = pFcObjectSetCreate();
1615 pFcObjectSetAdd(os, FC_FILE);
1616 pFcObjectSetAdd(os, FC_SCALABLE);
1617 fontset = pFcFontList(config, pat, os);
1618 if(!fontset) return;
1619 for(i = 0; i < fontset->nfont; i++) {
1620 FcBool scalable;
1622 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1623 continue;
1624 TRACE("fontconfig: %s\n", file);
1626 /* We're just interested in OT/TT fonts for now, so this hack just
1627 picks up the scalable fonts without extensions .pf[ab] to save time
1628 loading every other font */
1630 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1632 TRACE("not scalable\n");
1633 continue;
1636 len = strlen( file );
1637 if(len < 4) continue;
1638 ext = &file[ len - 3 ];
1639 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1640 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT);
1642 pFcFontSetDestroy(fontset);
1643 pFcObjectSetDestroy(os);
1644 pFcPatternDestroy(pat);
1645 sym_not_found:
1646 #endif
1647 return;
1650 static BOOL load_font_from_data_dir(LPCWSTR file)
1652 BOOL ret = FALSE;
1653 const char *data_dir = wine_get_data_dir();
1655 if (!data_dir) data_dir = wine_get_build_dir();
1657 if (data_dir)
1659 INT len;
1660 char *unix_name;
1662 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1664 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1666 strcpy(unix_name, data_dir);
1667 strcat(unix_name, "/fonts/");
1669 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1671 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1672 HeapFree(GetProcessHeap(), 0, unix_name);
1674 return ret;
1677 static void load_system_fonts(void)
1679 HKEY hkey;
1680 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1681 const WCHAR * const *value;
1682 DWORD dlen, type;
1683 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1684 char *unixname;
1686 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1687 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1688 strcatW(windowsdir, fontsW);
1689 for(value = SystemFontValues; *value; value++) {
1690 dlen = sizeof(data);
1691 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1692 type == REG_SZ) {
1693 BOOL added = FALSE;
1695 sprintfW(pathW, fmtW, windowsdir, data);
1696 if((unixname = wine_get_unix_file_name(pathW))) {
1697 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1698 HeapFree(GetProcessHeap(), 0, unixname);
1700 if (!added)
1701 load_font_from_data_dir(data);
1704 RegCloseKey(hkey);
1708 /*************************************************************
1710 * This adds registry entries for any externally loaded fonts
1711 * (fonts from fontconfig or FontDirs). It also deletes entries
1712 * of no longer existing fonts.
1715 static void update_reg_entries(void)
1717 HKEY winkey = 0, externalkey = 0;
1718 LPWSTR valueW;
1719 LPVOID data;
1720 DWORD dlen, vlen, datalen, valuelen, i, type, len, len_fam;
1721 Family *family;
1722 Face *face;
1723 struct list *family_elem_ptr, *face_elem_ptr;
1724 WCHAR *file;
1725 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1726 static const WCHAR spaceW[] = {' ', '\0'};
1727 char *path;
1729 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1730 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winkey, NULL) != ERROR_SUCCESS) {
1731 ERR("Can't create Windows font reg key\n");
1732 goto end;
1734 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1735 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &externalkey) != ERROR_SUCCESS) {
1736 ERR("Can't create external font reg key\n");
1737 goto end;
1740 /* Delete all external fonts added last time */
1742 RegQueryInfoKeyW(externalkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1743 &valuelen, &datalen, NULL, NULL);
1744 valuelen++; /* returned value doesn't include room for '\0' */
1745 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1746 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1748 dlen = datalen * sizeof(WCHAR);
1749 vlen = valuelen;
1750 i = 0;
1751 while(RegEnumValueW(externalkey, i++, valueW, &vlen, NULL, &type, data,
1752 &dlen) == ERROR_SUCCESS) {
1754 RegDeleteValueW(winkey, valueW);
1755 /* reset dlen and vlen */
1756 dlen = datalen;
1757 vlen = valuelen;
1759 HeapFree(GetProcessHeap(), 0, data);
1760 HeapFree(GetProcessHeap(), 0, valueW);
1762 /* Delete the old external fonts key */
1763 RegCloseKey(externalkey);
1764 externalkey = 0;
1765 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
1767 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1768 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1769 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
1770 ERR("Can't create external font reg key\n");
1771 goto end;
1774 /* enumerate the fonts and add external ones to the two keys */
1776 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1777 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1778 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1779 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1780 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1781 if(!face->external) continue;
1782 len = len_fam;
1783 if(strcmpiW(face->StyleName, RegularW))
1784 len = len_fam + strlenW(face->StyleName) + 1;
1785 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1786 strcpyW(valueW, family->FamilyName);
1787 if(len != len_fam) {
1788 strcatW(valueW, spaceW);
1789 strcatW(valueW, face->StyleName);
1791 strcatW(valueW, TrueType);
1792 if((path = strrchr(face->file, '/')) == NULL)
1793 path = face->file;
1794 else
1795 path++;
1796 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1798 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1799 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1800 RegSetValueExW(winkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1801 RegSetValueExW(externalkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1803 HeapFree(GetProcessHeap(), 0, file);
1804 HeapFree(GetProcessHeap(), 0, valueW);
1807 end:
1808 if(externalkey)
1809 RegCloseKey(externalkey);
1810 if(winkey)
1811 RegCloseKey(winkey);
1812 return;
1816 /*************************************************************
1817 * WineEngAddFontResourceEx
1820 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1822 if (ft_handle) /* do it only if we have freetype up and running */
1824 char *unixname;
1826 if(flags)
1827 FIXME("Ignoring flags %x\n", flags);
1829 if((unixname = wine_get_unix_file_name(file)))
1831 INT ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1832 HeapFree(GetProcessHeap(), 0, unixname);
1833 return ret;
1836 return 0;
1839 /*************************************************************
1840 * WineEngAddFontMemResourceEx
1843 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
1845 if (ft_handle) /* do it only if we have freetype up and running */
1847 PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont);
1849 TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy);
1850 memcpy(pFontCopy, pbFont, cbFont);
1852 *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP);
1854 if (*pcFonts == 0)
1856 TRACE("AddFontToList failed\n");
1857 HeapFree(GetProcessHeap(), 0, pFontCopy);
1858 return NULL;
1860 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
1861 * For now return something unique but quite random
1863 TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321);
1864 return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321);
1867 *pcFonts = 0;
1868 return 0;
1871 /*************************************************************
1872 * WineEngRemoveFontResourceEx
1875 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1877 FIXME(":stub\n");
1878 return TRUE;
1881 static const struct nls_update_font_list
1883 UINT ansi_cp, oem_cp;
1884 const char *oem, *fixed, *system;
1885 const char *courier, *serif, *small, *sserif;
1886 /* these are for font substitute */
1887 const char *shelldlg, *tmsrmn;
1888 } nls_update_font_list[] =
1890 /* Latin 1 (United States) */
1891 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
1892 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1893 "Tahoma","Times New Roman",
1895 /* Latin 1 (Multilingual) */
1896 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
1897 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1898 "Tahoma","Times New Roman", /* FIXME unverified */
1900 /* Eastern Europe */
1901 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
1902 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
1903 "Tahoma","Times New Roman", /* FIXME unverified */
1905 /* Cyrillic */
1906 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
1907 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
1908 "Tahoma","Times New Roman", /* FIXME unverified */
1910 /* Greek */
1911 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
1912 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
1913 "Tahoma","Times New Roman", /* FIXME unverified */
1915 /* Turkish */
1916 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
1917 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
1918 "Tahoma","Times New Roman", /* FIXME unverified */
1920 /* Hebrew */
1921 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
1922 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
1923 "Tahoma","Times New Roman", /* FIXME unverified */
1925 /* Arabic */
1926 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
1927 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
1928 "Tahoma","Times New Roman", /* FIXME unverified */
1930 /* Baltic */
1931 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
1932 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
1933 "Tahoma","Times New Roman", /* FIXME unverified */
1935 /* Vietnamese */
1936 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
1937 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1938 "Tahoma","Times New Roman", /* FIXME unverified */
1940 /* Thai */
1941 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
1942 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
1943 "Tahoma","Times New Roman", /* FIXME unverified */
1945 /* Japanese */
1946 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
1947 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
1948 "MS UI Gothic","MS Serif",
1950 /* Chinese Simplified */
1951 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
1952 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1953 "Tahoma", "Times New Roman", /* FIXME unverified */
1955 /* Korean */
1956 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
1957 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1958 "Gulim", "Batang",
1960 /* Chinese Traditional */
1961 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
1962 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1963 "Tahoma", "Times New Roman", /* FIXME unverified */
1967 static inline HKEY create_fonts_NT_registry_key(void)
1969 HKEY hkey = 0;
1971 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
1972 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1973 return hkey;
1976 static inline HKEY create_fonts_9x_registry_key(void)
1978 HKEY hkey = 0;
1980 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
1981 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1982 return hkey;
1985 static inline HKEY create_config_fonts_registry_key(void)
1987 HKEY hkey = 0;
1989 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
1990 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1991 return hkey;
1994 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
1996 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
1997 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
1998 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
1999 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
2002 static void update_font_info(void)
2004 char buf[40], cpbuf[40];
2005 DWORD len, type;
2006 HKEY hkey = 0;
2007 UINT i, ansi_cp = 0, oem_cp = 0;
2009 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
2010 return;
2012 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2013 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
2014 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
2015 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
2016 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
2018 len = sizeof(buf);
2019 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
2021 if (!strcmp( buf, cpbuf )) /* already set correctly */
2023 RegCloseKey(hkey);
2024 return;
2026 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
2028 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
2030 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
2031 RegCloseKey(hkey);
2033 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
2035 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
2036 nls_update_font_list[i].oem_cp == oem_cp)
2038 HKEY hkey;
2040 hkey = create_config_fonts_registry_key();
2041 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
2042 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
2043 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
2044 RegCloseKey(hkey);
2046 hkey = create_fonts_NT_registry_key();
2047 add_font_list(hkey, &nls_update_font_list[i]);
2048 RegCloseKey(hkey);
2050 hkey = create_fonts_9x_registry_key();
2051 add_font_list(hkey, &nls_update_font_list[i]);
2052 RegCloseKey(hkey);
2054 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
2056 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
2057 strlen(nls_update_font_list[i].shelldlg)+1);
2058 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
2059 strlen(nls_update_font_list[i].tmsrmn)+1);
2060 RegCloseKey(hkey);
2062 return;
2065 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
2068 /*************************************************************
2069 * WineEngInit
2071 * Initialize FreeType library and create a list of available faces
2073 BOOL WineEngInit(void)
2075 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
2076 static const WCHAR pathW[] = {'P','a','t','h',0};
2077 HKEY hkey;
2078 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
2079 LPVOID data;
2080 WCHAR windowsdir[MAX_PATH];
2081 char *unixname;
2082 HANDLE font_mutex;
2083 const char *data_dir;
2085 TRACE("\n");
2087 /* update locale dependent font info in registry */
2088 update_font_info();
2090 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
2091 if(!ft_handle) {
2092 WINE_MESSAGE(
2093 "Wine cannot find the FreeType font library. To enable Wine to\n"
2094 "use TrueType fonts please install a version of FreeType greater than\n"
2095 "or equal to 2.0.5.\n"
2096 "http://www.freetype.org\n");
2097 return FALSE;
2100 #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;}
2102 LOAD_FUNCPTR(FT_Vector_Unit)
2103 LOAD_FUNCPTR(FT_Done_Face)
2104 LOAD_FUNCPTR(FT_Get_Char_Index)
2105 LOAD_FUNCPTR(FT_Get_Module)
2106 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
2107 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
2108 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
2109 LOAD_FUNCPTR(FT_Init_FreeType)
2110 LOAD_FUNCPTR(FT_Load_Glyph)
2111 LOAD_FUNCPTR(FT_Matrix_Multiply)
2112 LOAD_FUNCPTR(FT_MulFix)
2113 LOAD_FUNCPTR(FT_New_Face)
2114 LOAD_FUNCPTR(FT_New_Memory_Face)
2115 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
2116 LOAD_FUNCPTR(FT_Outline_Transform)
2117 LOAD_FUNCPTR(FT_Outline_Translate)
2118 LOAD_FUNCPTR(FT_Select_Charmap)
2119 LOAD_FUNCPTR(FT_Set_Charmap)
2120 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
2121 LOAD_FUNCPTR(FT_Vector_Transform)
2123 #undef LOAD_FUNCPTR
2124 /* Don't warn if this one is missing */
2125 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
2126 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
2127 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
2128 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
2129 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
2130 #ifdef HAVE_FREETYPE_FTWINFNT_H
2131 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2132 #endif
2133 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2134 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2135 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2136 <= 2.0.3 has FT_Sqrt64 */
2137 goto sym_not_found;
2140 if(pFT_Init_FreeType(&library) != 0) {
2141 ERR("Can't init FreeType library\n");
2142 wine_dlclose(ft_handle, NULL, 0);
2143 ft_handle = NULL;
2144 return FALSE;
2146 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
2147 if (pFT_Library_Version)
2149 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2151 if (FT_Version.major<=0)
2153 FT_Version.major=2;
2154 FT_Version.minor=0;
2155 FT_Version.patch=5;
2157 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2158 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2159 ((FT_Version.minor << 8) & 0x00ff00) |
2160 ((FT_Version.patch ) & 0x0000ff);
2162 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2163 ERR("Failed to create font mutex\n");
2164 return FALSE;
2166 WaitForSingleObject(font_mutex, INFINITE);
2168 /* load the system bitmap fonts */
2169 load_system_fonts();
2171 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2172 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2173 strcatW(windowsdir, fontsW);
2174 if((unixname = wine_get_unix_file_name(windowsdir)))
2176 ReadFontDir(unixname, FALSE);
2177 HeapFree(GetProcessHeap(), 0, unixname);
2180 /* load the system truetype fonts */
2181 data_dir = wine_get_data_dir();
2182 if (!data_dir) data_dir = wine_get_build_dir();
2183 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2184 strcpy(unixname, data_dir);
2185 strcat(unixname, "/fonts/");
2186 ReadFontDir(unixname, TRUE);
2187 HeapFree(GetProcessHeap(), 0, unixname);
2190 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2191 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2192 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2193 will skip these. */
2194 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2195 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2196 &hkey) == ERROR_SUCCESS) {
2197 LPWSTR valueW;
2198 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2199 &valuelen, &datalen, NULL, NULL);
2201 valuelen++; /* returned value doesn't include room for '\0' */
2202 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2203 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2204 if (valueW && data)
2206 dlen = datalen * sizeof(WCHAR);
2207 vlen = valuelen;
2208 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
2209 &dlen) == ERROR_SUCCESS) {
2210 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
2212 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
2214 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2215 HeapFree(GetProcessHeap(), 0, unixname);
2218 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
2220 WCHAR pathW[MAX_PATH];
2221 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2222 BOOL added = FALSE;
2224 sprintfW(pathW, fmtW, windowsdir, data);
2225 if((unixname = wine_get_unix_file_name(pathW)))
2227 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2228 HeapFree(GetProcessHeap(), 0, unixname);
2230 if (!added)
2231 load_font_from_data_dir(data);
2233 /* reset dlen and vlen */
2234 dlen = datalen;
2235 vlen = valuelen;
2238 HeapFree(GetProcessHeap(), 0, data);
2239 HeapFree(GetProcessHeap(), 0, valueW);
2240 RegCloseKey(hkey);
2243 load_fontconfig_fonts();
2245 /* then look in any directories that we've specified in the config file */
2246 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2247 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2249 DWORD len;
2250 LPWSTR valueW;
2251 LPSTR valueA, ptr;
2253 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2255 len += sizeof(WCHAR);
2256 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2257 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2259 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2260 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2261 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2262 TRACE( "got font path %s\n", debugstr_a(valueA) );
2263 ptr = valueA;
2264 while (ptr)
2266 LPSTR next = strchr( ptr, ':' );
2267 if (next) *next++ = 0;
2268 ReadFontDir( ptr, TRUE );
2269 ptr = next;
2271 HeapFree( GetProcessHeap(), 0, valueA );
2273 HeapFree( GetProcessHeap(), 0, valueW );
2275 RegCloseKey(hkey);
2278 DumpFontList();
2279 LoadSubstList();
2280 DumpSubstList();
2281 LoadReplaceList();
2282 update_reg_entries();
2284 init_system_links();
2286 ReleaseMutex(font_mutex);
2287 return TRUE;
2288 sym_not_found:
2289 WINE_MESSAGE(
2290 "Wine cannot find certain functions that it needs inside the FreeType\n"
2291 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2292 "FreeType to at least version 2.0.5.\n"
2293 "http://www.freetype.org\n");
2294 wine_dlclose(ft_handle, NULL, 0);
2295 ft_handle = NULL;
2296 return FALSE;
2300 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2302 TT_OS2 *pOS2;
2303 TT_HoriHeader *pHori;
2305 LONG ppem;
2307 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2308 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2310 if(height == 0) height = 16;
2312 /* Calc. height of EM square:
2314 * For +ve lfHeight we have
2315 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2316 * Re-arranging gives:
2317 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2319 * For -ve lfHeight we have
2320 * |lfHeight| = ppem
2321 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2322 * with il = winAscent + winDescent - units_per_em]
2326 if(height > 0) {
2327 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2328 ppem = ft_face->units_per_EM * height /
2329 (pHori->Ascender - pHori->Descender);
2330 else
2331 ppem = ft_face->units_per_EM * height /
2332 (pOS2->usWinAscent + pOS2->usWinDescent);
2334 else
2335 ppem = -height;
2337 return ppem;
2340 static struct font_mapping *map_font_file( const char *name )
2342 struct font_mapping *mapping;
2343 struct stat st;
2344 int fd;
2346 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2347 if (fstat( fd, &st ) == -1) goto error;
2349 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2351 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2353 mapping->refcount++;
2354 close( fd );
2355 return mapping;
2358 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2359 goto error;
2361 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2362 close( fd );
2364 if (mapping->data == MAP_FAILED)
2366 HeapFree( GetProcessHeap(), 0, mapping );
2367 return NULL;
2369 mapping->refcount = 1;
2370 mapping->dev = st.st_dev;
2371 mapping->ino = st.st_ino;
2372 mapping->size = st.st_size;
2373 list_add_tail( &mappings_list, &mapping->entry );
2374 return mapping;
2376 error:
2377 close( fd );
2378 return NULL;
2381 static void unmap_font_file( struct font_mapping *mapping )
2383 if (!--mapping->refcount)
2385 list_remove( &mapping->entry );
2386 munmap( mapping->data, mapping->size );
2387 HeapFree( GetProcessHeap(), 0, mapping );
2391 static LONG load_VDMX(GdiFont*, LONG);
2393 static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height)
2395 FT_Error err;
2396 FT_Face ft_face;
2397 void *data_ptr;
2398 DWORD data_size;
2400 TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height);
2402 if (face->file)
2404 if (!(font->mapping = map_font_file( face->file )))
2406 WARN("failed to map %s\n", debugstr_a(face->file));
2407 return 0;
2409 data_ptr = font->mapping->data;
2410 data_size = font->mapping->size;
2412 else
2414 data_ptr = face->font_data_ptr;
2415 data_size = face->font_data_size;
2418 err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face);
2419 if(err) {
2420 ERR("FT_New_Face rets %d\n", err);
2421 return 0;
2424 /* set it here, as load_VDMX needs it */
2425 font->ft_face = ft_face;
2427 if(FT_IS_SCALABLE(ft_face)) {
2428 /* load the VDMX table if we have one */
2429 font->ppem = load_VDMX(font, height);
2430 if(font->ppem == 0)
2431 font->ppem = calc_ppem_for_height(ft_face, height);
2433 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
2434 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
2435 } else {
2436 font->ppem = height;
2437 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
2438 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
2440 return ft_face;
2444 static int get_nearest_charset(Face *face, int *cp)
2446 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2447 a single face with the requested charset. The idea is to check if
2448 the selected font supports the current ANSI codepage, if it does
2449 return the corresponding charset, else return the first charset */
2451 CHARSETINFO csi;
2452 int acp = GetACP(), i;
2453 DWORD fs0;
2455 *cp = acp;
2456 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
2457 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2458 return csi.ciCharset;
2460 for(i = 0; i < 32; i++) {
2461 fs0 = 1L << i;
2462 if(face->fs.fsCsb[0] & fs0) {
2463 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
2464 *cp = csi.ciACP;
2465 return csi.ciCharset;
2467 else
2468 FIXME("TCI failing on %x\n", fs0);
2472 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2473 face->fs.fsCsb[0], face->file);
2474 *cp = acp;
2475 return DEFAULT_CHARSET;
2478 static GdiFont *alloc_font(void)
2480 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
2481 ret->gmsize = 1;
2482 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
2483 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
2484 ret->potm = NULL;
2485 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
2486 ret->total_kern_pairs = (DWORD)-1;
2487 ret->kern_pairs = NULL;
2488 list_init(&ret->hfontlist);
2489 list_init(&ret->child_fonts);
2490 return ret;
2493 static void free_font(GdiFont *font)
2495 struct list *cursor, *cursor2;
2496 int i;
2498 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
2500 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
2501 struct list *first_hfont;
2502 HFONTLIST *hfontlist;
2503 list_remove(cursor);
2504 if(child->font)
2506 first_hfont = list_head(&child->font->hfontlist);
2507 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2508 DeleteObject(hfontlist->hfont);
2509 HeapFree(GetProcessHeap(), 0, hfontlist);
2510 free_font(child->font);
2512 HeapFree(GetProcessHeap(), 0, child);
2515 if (font->ft_face) pFT_Done_Face(font->ft_face);
2516 if (font->mapping) unmap_font_file( font->mapping );
2517 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
2518 HeapFree(GetProcessHeap(), 0, font->potm);
2519 HeapFree(GetProcessHeap(), 0, font->name);
2520 for (i = 0; i < font->gmsize; i++)
2521 HeapFree(GetProcessHeap(),0,font->gm[i]);
2522 HeapFree(GetProcessHeap(), 0, font->gm);
2523 HeapFree(GetProcessHeap(), 0, font);
2527 /*************************************************************
2528 * load_VDMX
2530 * load the vdmx entry for the specified height
2533 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2534 ( ( (FT_ULong)_x4 << 24 ) | \
2535 ( (FT_ULong)_x3 << 16 ) | \
2536 ( (FT_ULong)_x2 << 8 ) | \
2537 (FT_ULong)_x1 )
2539 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2541 typedef struct {
2542 BYTE bCharSet;
2543 BYTE xRatio;
2544 BYTE yStartRatio;
2545 BYTE yEndRatio;
2546 } Ratios;
2548 typedef struct {
2549 WORD recs;
2550 BYTE startsz;
2551 BYTE endsz;
2552 } VDMX_group;
2554 static LONG load_VDMX(GdiFont *font, LONG height)
2556 WORD hdr[3], tmp;
2557 VDMX_group group;
2558 BYTE devXRatio, devYRatio;
2559 USHORT numRecs, numRatios;
2560 DWORD result, offset = -1;
2561 LONG ppem = 0;
2562 int i;
2564 /* For documentation on VDMX records, see
2565 * http://www.microsoft.com/OpenType/OTSpec/vdmx.htm
2568 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
2570 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2571 return ppem;
2573 /* FIXME: need the real device aspect ratio */
2574 devXRatio = 1;
2575 devYRatio = 1;
2577 numRecs = GET_BE_WORD(hdr[1]);
2578 numRatios = GET_BE_WORD(hdr[2]);
2580 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
2581 for(i = 0; i < numRatios; i++) {
2582 Ratios ratio;
2584 offset = (3 * 2) + (i * sizeof(Ratios));
2585 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2586 offset = -1;
2588 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2590 if((ratio.xRatio == 0 &&
2591 ratio.yStartRatio == 0 &&
2592 ratio.yEndRatio == 0) ||
2593 (devXRatio == ratio.xRatio &&
2594 devYRatio >= ratio.yStartRatio &&
2595 devYRatio <= ratio.yEndRatio))
2597 offset = (3 * 2) + (numRatios * 4) + (i * 2);
2598 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
2599 offset = GET_BE_WORD(tmp);
2600 break;
2604 if(offset == -1) {
2605 FIXME("No suitable ratio found\n");
2606 return ppem;
2609 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
2610 USHORT recs;
2611 BYTE startsz, endsz;
2612 WORD *vTable;
2614 recs = GET_BE_WORD(group.recs);
2615 startsz = group.startsz;
2616 endsz = group.endsz;
2618 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
2620 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
2621 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
2622 if(result == GDI_ERROR) {
2623 FIXME("Failed to retrieve vTable\n");
2624 goto end;
2627 if(height > 0) {
2628 for(i = 0; i < recs; i++) {
2629 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2630 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2631 ppem = GET_BE_WORD(vTable[i * 3]);
2633 if(yMax + -yMin == height) {
2634 font->yMax = yMax;
2635 font->yMin = yMin;
2636 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2637 break;
2639 if(yMax + -yMin > height) {
2640 if(--i < 0) {
2641 ppem = 0;
2642 goto end; /* failed */
2644 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2645 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2646 ppem = GET_BE_WORD(vTable[i * 3]);
2647 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2648 break;
2651 if(!font->yMax) {
2652 ppem = 0;
2653 TRACE("ppem not found for height %d\n", height);
2655 } else {
2656 ppem = -height;
2657 if(ppem < startsz || ppem > endsz)
2658 goto end;
2660 for(i = 0; i < recs; i++) {
2661 USHORT yPelHeight;
2662 yPelHeight = GET_BE_WORD(vTable[i * 3]);
2664 if(yPelHeight > ppem)
2665 break; /* failed */
2667 if(yPelHeight == ppem) {
2668 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2669 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2670 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
2671 break;
2675 end:
2676 HeapFree(GetProcessHeap(), 0, vTable);
2679 return ppem;
2682 static BOOL fontcmp(GdiFont *font, FONT_DESC *fd)
2684 if(font->font_desc.hash != fd->hash) return TRUE;
2685 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
2686 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
2687 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
2688 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
2691 static void calc_hash(FONT_DESC *pfd)
2693 DWORD hash = 0, *ptr, two_chars;
2694 WORD *pwc;
2695 unsigned int i;
2697 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
2698 hash ^= *ptr;
2699 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
2700 hash ^= *ptr;
2701 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
2702 two_chars = *ptr;
2703 pwc = (WCHAR *)&two_chars;
2704 if(!*pwc) break;
2705 *pwc = toupperW(*pwc);
2706 pwc++;
2707 *pwc = toupperW(*pwc);
2708 hash ^= two_chars;
2709 if(!*pwc) break;
2711 hash ^= !pfd->can_use_bitmap;
2712 pfd->hash = hash;
2713 return;
2716 static GdiFont *find_in_cache(HFONT hfont, LOGFONTW *plf, XFORM *pxf, BOOL can_use_bitmap)
2718 GdiFont *ret;
2719 FONT_DESC fd;
2720 HFONTLIST *hflist;
2721 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2723 memcpy(&fd.lf, plf, sizeof(LOGFONTW));
2724 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
2725 fd.can_use_bitmap = can_use_bitmap;
2726 calc_hash(&fd);
2728 /* try the in-use list */
2729 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
2730 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2731 if(!fontcmp(ret, &fd)) {
2732 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2733 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
2734 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2735 if(hflist->hfont == hfont)
2736 return ret;
2738 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2739 hflist->hfont = hfont;
2740 list_add_head(&ret->hfontlist, &hflist->entry);
2741 return ret;
2745 /* then the unused list */
2746 font_elem_ptr = list_head(&unused_gdi_font_list);
2747 while(font_elem_ptr) {
2748 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2749 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2750 if(!fontcmp(ret, &fd)) {
2751 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2752 assert(list_empty(&ret->hfontlist));
2753 TRACE("Found %p in unused list\n", ret);
2754 list_remove(&ret->entry);
2755 list_add_head(&gdi_font_list, &ret->entry);
2756 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2757 hflist->hfont = hfont;
2758 list_add_head(&ret->hfontlist, &hflist->entry);
2759 return ret;
2762 return NULL;
2766 /*************************************************************
2767 * create_child_font_list
2769 static BOOL create_child_font_list(GdiFont *font)
2771 BOOL ret = FALSE;
2772 SYSTEM_LINKS *font_link;
2773 CHILD_FONT *font_link_entry, *new_child;
2775 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2777 if(!strcmpW(font_link->font_name, font->name))
2779 TRACE("found entry in system list\n");
2780 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2782 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2783 new_child->face = font_link_entry->face;
2784 new_child->font = NULL;
2785 list_add_tail(&font->child_fonts, &new_child->entry);
2786 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
2788 ret = TRUE;
2789 break;
2793 return ret;
2796 static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding)
2798 FT_Error ft_err = FT_Err_Invalid_CharMap_Handle;
2800 if (pFT_Set_Charmap)
2802 FT_Int i;
2803 FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def;
2805 cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL;
2807 for (i = 0; i < ft_face->num_charmaps; i++)
2809 if (ft_face->charmaps[i]->encoding == encoding)
2811 TRACE("found cmap with platform_id %u, encoding_id %u\n",
2812 ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id);
2814 switch (ft_face->charmaps[i]->platform_id)
2816 default:
2817 cmap_def = ft_face->charmaps[i];
2818 break;
2819 case 0: /* Apple Unicode */
2820 cmap0 = ft_face->charmaps[i];
2821 break;
2822 case 1: /* Macintosh */
2823 cmap1 = ft_face->charmaps[i];
2824 break;
2825 case 2: /* ISO */
2826 cmap2 = ft_face->charmaps[i];
2827 break;
2828 case 3: /* Microsoft */
2829 cmap3 = ft_face->charmaps[i];
2830 break;
2834 if (cmap3) /* prefer Microsoft cmap table */
2835 ft_err = pFT_Set_Charmap(ft_face, cmap3);
2836 else if (cmap1)
2837 ft_err = pFT_Set_Charmap(ft_face, cmap1);
2838 else if (cmap2)
2839 ft_err = pFT_Set_Charmap(ft_face, cmap2);
2840 else if (cmap0)
2841 ft_err = pFT_Set_Charmap(ft_face, cmap0);
2842 else if (cmap_def)
2843 ft_err = pFT_Set_Charmap(ft_face, cmap_def);
2845 return ft_err == FT_Err_Ok;
2848 return pFT_Select_Charmap(ft_face, encoding) == FT_Err_Ok;
2851 /*************************************************************
2852 * WineEngCreateFontInstance
2855 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
2857 GdiFont *ret;
2858 Face *face, *best, *best_bitmap;
2859 Family *family, *last_resort_family;
2860 struct list *family_elem_ptr, *face_elem_ptr;
2861 INT height, width = 0;
2862 unsigned int score = 0, new_score;
2863 signed int diff = 0, newdiff;
2864 BOOL bd, it, can_use_bitmap;
2865 LOGFONTW lf;
2866 CHARSETINFO csi;
2867 HFONTLIST *hflist;
2869 LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry)
2871 struct list *first_hfont = list_head(&ret->hfontlist);
2872 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2873 if(hflist->hfont == hfont)
2874 return ret;
2877 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
2878 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
2880 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
2881 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
2882 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
2883 lf.lfEscapement);
2885 /* check the cache first */
2886 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
2887 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
2888 return ret;
2891 TRACE("not in cache\n");
2892 if(list_empty(&font_list)) /* No fonts installed */
2894 TRACE("No fonts installed\n");
2895 return NULL;
2897 if(!have_installed_roman_font)
2899 TRACE("No roman font installed\n");
2900 return NULL;
2903 ret = alloc_font();
2905 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
2906 memcpy(&ret->font_desc.lf, &lf, sizeof(LOGFONTW));
2907 ret->font_desc.can_use_bitmap = can_use_bitmap;
2908 calc_hash(&ret->font_desc);
2909 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2910 hflist->hfont = hfont;
2911 list_add_head(&ret->hfontlist, &hflist->entry);
2914 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
2915 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
2916 original value lfCharSet. Note this is a special case for
2917 Symbol and doesn't happen at least for "Wingdings*" */
2919 if(!strcmpiW(lf.lfFaceName, SymbolW))
2920 lf.lfCharSet = SYMBOL_CHARSET;
2922 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
2923 switch(lf.lfCharSet) {
2924 case DEFAULT_CHARSET:
2925 csi.fs.fsCsb[0] = 0;
2926 break;
2927 default:
2928 FIXME("Untranslated charset %d\n", lf.lfCharSet);
2929 csi.fs.fsCsb[0] = 0;
2930 break;
2934 family = NULL;
2935 if(lf.lfFaceName[0] != '\0') {
2936 FontSubst *psub;
2937 SYSTEM_LINKS *font_link;
2938 CHILD_FONT *font_link_entry;
2940 psub = get_font_subst(&font_subst_list, lf.lfFaceName, lf.lfCharSet);
2942 if(psub) {
2943 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
2944 debugstr_w(psub->to.name));
2945 strcpyW(lf.lfFaceName, psub->to.name);
2948 /* We want a match on name and charset or just name if
2949 charset was DEFAULT_CHARSET. If the latter then
2950 we fixup the returned charset later in get_nearest_charset
2951 where we'll either use the charset of the current ansi codepage
2952 or if that's unavailable the first charset that the font supports.
2954 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2955 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2956 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2957 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2958 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2959 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
2960 if(face->scalable || can_use_bitmap)
2961 goto found;
2967 * Try check the SystemLink list first for a replacement font.
2968 * We may find good replacements there.
2970 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2972 if(!strcmpiW(font_link->font_name, lf.lfFaceName))
2974 TRACE("found entry in system list\n");
2975 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2977 face = font_link_entry->face;
2978 family = face->family;
2979 if(csi.fs.fsCsb[0] &
2980 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
2982 if(face->scalable || can_use_bitmap)
2983 goto found;
2990 /* If requested charset was DEFAULT_CHARSET then try using charset
2991 corresponding to the current ansi codepage */
2992 if(!csi.fs.fsCsb[0]) {
2993 INT acp = GetACP();
2994 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
2995 FIXME("TCI failed on codepage %d\n", acp);
2996 csi.fs.fsCsb[0] = 0;
2997 } else
2998 lf.lfCharSet = csi.ciCharset;
3001 /* Face families are in the top 4 bits of lfPitchAndFamily,
3002 so mask with 0xF0 before testing */
3004 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
3005 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
3006 strcpyW(lf.lfFaceName, defFixed);
3007 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
3008 strcpyW(lf.lfFaceName, defSerif);
3009 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
3010 strcpyW(lf.lfFaceName, defSans);
3011 else
3012 strcpyW(lf.lfFaceName, defSans);
3013 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3014 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3015 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
3016 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3017 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3018 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
3019 if(face->scalable || can_use_bitmap)
3020 goto found;
3025 last_resort_family = NULL;
3026 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3027 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3028 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3029 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3030 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
3031 if(face->scalable)
3032 goto found;
3033 if(can_use_bitmap && !last_resort_family)
3034 last_resort_family = family;
3039 if(last_resort_family) {
3040 family = last_resort_family;
3041 csi.fs.fsCsb[0] = 0;
3042 goto found;
3045 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3046 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3047 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3048 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3049 if(face->scalable) {
3050 csi.fs.fsCsb[0] = 0;
3051 WARN("just using first face for now\n");
3052 goto found;
3054 if(can_use_bitmap && !last_resort_family)
3055 last_resort_family = family;
3058 if(!last_resort_family) {
3059 FIXME("can't find a single appropriate font - bailing\n");
3060 free_font(ret);
3061 return NULL;
3064 WARN("could only find a bitmap font - this will probably look awful!\n");
3065 family = last_resort_family;
3066 csi.fs.fsCsb[0] = 0;
3068 found:
3069 it = lf.lfItalic ? 1 : 0;
3070 bd = lf.lfWeight > 550 ? 1 : 0;
3072 height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
3073 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
3075 face = best = best_bitmap = NULL;
3076 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
3078 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
3080 new_score = (face->Italic ^ it) + (face->Bold ^ bd);
3081 if(!best || new_score <= score)
3083 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
3084 face->Italic, face->Bold, it, bd);
3085 score = new_score;
3086 best = face;
3087 if(best->scalable && score == 0) break;
3088 if(!best->scalable)
3090 if(height > 0)
3091 newdiff = height - (signed int)(best->size.height);
3092 else
3093 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
3094 if(!best_bitmap || new_score < score ||
3095 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
3097 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
3098 diff = newdiff;
3099 best_bitmap = best;
3100 if(score == 0 && diff == 0) break;
3106 if(best)
3107 face = best->scalable ? best : best_bitmap;
3108 ret->fake_italic = (it && !face->Italic);
3109 ret->fake_bold = (bd && !face->Bold);
3111 memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
3113 if(csi.fs.fsCsb[0]) {
3114 ret->charset = lf.lfCharSet;
3115 ret->codepage = csi.ciACP;
3117 else
3118 ret->charset = get_nearest_charset(face, &ret->codepage);
3120 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName),
3121 debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index);
3123 if(!face->scalable) {
3124 width = face->size.x_ppem >> 6;
3125 height = face->size.y_ppem >> 6;
3127 ret->ft_face = OpenFontFace(ret, face, width, height);
3129 if (!ret->ft_face)
3131 free_font( ret );
3132 return 0;
3135 ret->ntmFlags = face->ntmFlags;
3137 if (ret->charset == SYMBOL_CHARSET &&
3138 select_charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
3139 /* No ops */
3141 else if (select_charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
3142 /* No ops */
3144 else {
3145 select_charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
3148 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
3149 ret->name = strdupW(family->FamilyName);
3150 ret->underline = lf.lfUnderline ? 0xff : 0;
3151 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
3152 create_child_font_list(ret);
3154 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
3156 ret->aveWidth = FT_IS_SCALABLE(ret->ft_face) ? abs(lf.lfWidth) : 0;
3157 list_add_head(&gdi_font_list, &ret->entry);
3158 return ret;
3161 static void dump_gdi_font_list(void)
3163 GdiFont *gdiFont;
3164 struct list *elem_ptr;
3166 TRACE("---------- gdiFont Cache ----------\n");
3167 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
3168 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3169 TRACE("gdiFont=%p %s %d\n",
3170 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3173 TRACE("---------- Unused gdiFont Cache ----------\n");
3174 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
3175 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
3176 TRACE("gdiFont=%p %s %d\n",
3177 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
3181 /*************************************************************
3182 * WineEngDestroyFontInstance
3184 * free the gdiFont associated with this handle
3187 BOOL WineEngDestroyFontInstance(HFONT handle)
3189 GdiFont *gdiFont;
3190 HFONTLIST *hflist;
3191 BOOL ret = FALSE;
3192 struct list *font_elem_ptr, *hfontlist_elem_ptr;
3193 int i = 0;
3195 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
3197 struct list *first_hfont = list_head(&gdiFont->hfontlist);
3198 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3199 if(hflist->hfont == handle)
3201 TRACE("removing child font %p from child list\n", gdiFont);
3202 list_remove(&gdiFont->entry);
3203 return TRUE;
3207 TRACE("destroying hfont=%p\n", handle);
3208 if(TRACE_ON(font))
3209 dump_gdi_font_list();
3211 font_elem_ptr = list_head(&gdi_font_list);
3212 while(font_elem_ptr) {
3213 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3214 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3216 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3217 while(hfontlist_elem_ptr) {
3218 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3219 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3220 if(hflist->hfont == handle) {
3221 list_remove(&hflist->entry);
3222 HeapFree(GetProcessHeap(), 0, hflist);
3223 ret = TRUE;
3226 if(list_empty(&gdiFont->hfontlist)) {
3227 TRACE("Moving to Unused list\n");
3228 list_remove(&gdiFont->entry);
3229 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3234 font_elem_ptr = list_head(&unused_gdi_font_list);
3235 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3236 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3237 while(font_elem_ptr) {
3238 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3239 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3240 TRACE("freeing %p\n", gdiFont);
3241 list_remove(&gdiFont->entry);
3242 free_font(gdiFont);
3244 return ret;
3247 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
3248 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
3250 OUTLINETEXTMETRICW *potm = NULL;
3251 UINT size;
3252 TEXTMETRICW tm, *ptm;
3253 GdiFont *font = alloc_font();
3254 LONG width, height;
3256 if(face->scalable) {
3257 height = 100;
3258 width = 0;
3259 } else {
3260 height = face->size.y_ppem >> 6;
3261 width = face->size.x_ppem >> 6;
3264 if (!(font->ft_face = OpenFontFace(font, face, width, height)))
3266 free_font(font);
3267 return;
3270 font->name = strdupW(face->family->FamilyName);
3271 font->ntmFlags = face->ntmFlags;
3273 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
3275 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
3276 if(size) {
3277 potm = HeapAlloc(GetProcessHeap(), 0, size);
3278 WineEngGetOutlineTextMetrics(font, size, potm);
3279 ptm = (TEXTMETRICW*)&potm->otmTextMetrics;
3280 } else {
3281 WineEngGetTextMetrics(font, &tm);
3282 ptm = &tm;
3285 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = ptm->tmHeight;
3286 pntm->ntmTm.tmAscent = ptm->tmAscent;
3287 pntm->ntmTm.tmDescent = ptm->tmDescent;
3288 pntm->ntmTm.tmInternalLeading = ptm->tmInternalLeading;
3289 pntm->ntmTm.tmExternalLeading = ptm->tmExternalLeading;
3290 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = ptm->tmAveCharWidth;
3291 pntm->ntmTm.tmMaxCharWidth = ptm->tmMaxCharWidth;
3292 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = ptm->tmWeight;
3293 pntm->ntmTm.tmOverhang = ptm->tmOverhang;
3294 pntm->ntmTm.tmDigitizedAspectX = ptm->tmDigitizedAspectX;
3295 pntm->ntmTm.tmDigitizedAspectY = ptm->tmDigitizedAspectY;
3296 pntm->ntmTm.tmFirstChar = ptm->tmFirstChar;
3297 pntm->ntmTm.tmLastChar = ptm->tmLastChar;
3298 pntm->ntmTm.tmDefaultChar = ptm->tmDefaultChar;
3299 pntm->ntmTm.tmBreakChar = ptm->tmBreakChar;
3300 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = ptm->tmItalic;
3301 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = ptm->tmUnderlined;
3302 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = ptm->tmStruckOut;
3303 pntm->ntmTm.tmPitchAndFamily = ptm->tmPitchAndFamily;
3304 pelf->elfLogFont.lfPitchAndFamily = (ptm->tmPitchAndFamily & 0xf1) + 1;
3305 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = ptm->tmCharSet;
3306 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
3307 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
3308 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
3310 *ptype = 0;
3311 if (ptm->tmPitchAndFamily & TMPF_TRUETYPE)
3312 *ptype |= TRUETYPE_FONTTYPE;
3313 if (ptm->tmPitchAndFamily & TMPF_DEVICE)
3314 *ptype |= DEVICE_FONTTYPE;
3315 if(!(ptm->tmPitchAndFamily & TMPF_VECTOR))
3316 *ptype |= RASTER_FONTTYPE;
3318 pntm->ntmTm.ntmFlags = ptm->tmItalic ? NTM_ITALIC : 0;
3319 if(ptm->tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
3320 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
3321 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 if(potm) {
3328 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
3330 lstrcpynW(pelf->elfLogFont.lfFaceName,
3331 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
3332 LF_FACESIZE);
3333 lstrcpynW(pelf->elfFullName,
3334 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
3335 LF_FULLFACESIZE);
3336 lstrcpynW(pelf->elfStyle,
3337 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
3338 LF_FACESIZE);
3340 HeapFree(GetProcessHeap(), 0, potm);
3341 } else {
3342 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
3344 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
3345 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FACESIZE);
3346 pelf->elfStyle[0] = '\0';
3349 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
3351 free_font(font);
3354 /*************************************************************
3355 * WineEngEnumFonts
3358 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3360 Family *family;
3361 Face *face;
3362 struct list *family_elem_ptr, *face_elem_ptr;
3363 ENUMLOGFONTEXW elf;
3364 NEWTEXTMETRICEXW ntm;
3365 DWORD type, ret = 1;
3366 FONTSIGNATURE fs;
3367 CHARSETINFO csi;
3368 LOGFONTW lf;
3369 int i;
3371 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
3373 if(plf->lfFaceName[0]) {
3374 FontSubst *psub;
3375 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
3377 if(psub) {
3378 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
3379 debugstr_w(psub->to.name));
3380 memcpy(&lf, plf, sizeof(lf));
3381 strcpyW(lf.lfFaceName, psub->to.name);
3382 plf = &lf;
3385 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3386 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3387 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
3388 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3389 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3390 GetEnumStructs(face, &elf, &ntm, &type);
3391 for(i = 0; i < 32; i++) {
3392 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3393 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3394 strcpyW(elf.elfScript, OEM_DOSW);
3395 i = 32; /* break out of loop */
3396 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3397 continue;
3398 else {
3399 fs.fsCsb[0] = 1L << i;
3400 fs.fsCsb[1] = 0;
3401 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3402 TCI_SRCFONTSIG))
3403 csi.ciCharset = DEFAULT_CHARSET;
3404 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3405 if(csi.ciCharset != DEFAULT_CHARSET) {
3406 elf.elfLogFont.lfCharSet =
3407 ntm.ntmTm.tmCharSet = csi.ciCharset;
3408 if(ElfScriptsW[i])
3409 strcpyW(elf.elfScript, ElfScriptsW[i]);
3410 else
3411 FIXME("Unknown elfscript for bit %d\n", i);
3414 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3415 debugstr_w(elf.elfLogFont.lfFaceName),
3416 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3417 csi.ciCharset, type, debugstr_w(elf.elfScript),
3418 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3419 ntm.ntmTm.ntmFlags);
3420 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
3421 if(!ret) goto end;
3426 } else {
3427 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3428 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3429 face_elem_ptr = list_head(&family->faces);
3430 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3431 GetEnumStructs(face, &elf, &ntm, &type);
3432 for(i = 0; i < 32; i++) {
3433 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3434 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3435 strcpyW(elf.elfScript, OEM_DOSW);
3436 i = 32; /* break out of loop */
3437 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3438 continue;
3439 else {
3440 fs.fsCsb[0] = 1L << i;
3441 fs.fsCsb[1] = 0;
3442 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3443 TCI_SRCFONTSIG))
3444 csi.ciCharset = DEFAULT_CHARSET;
3445 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3446 if(csi.ciCharset != DEFAULT_CHARSET) {
3447 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
3448 csi.ciCharset;
3449 if(ElfScriptsW[i])
3450 strcpyW(elf.elfScript, ElfScriptsW[i]);
3451 else
3452 FIXME("Unknown elfscript for bit %d\n", i);
3455 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3456 debugstr_w(elf.elfLogFont.lfFaceName),
3457 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3458 csi.ciCharset, type, debugstr_w(elf.elfScript),
3459 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3460 ntm.ntmTm.ntmFlags);
3461 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
3462 if(!ret) goto end;
3466 end:
3467 return ret;
3470 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
3472 pt->x.value = vec->x >> 6;
3473 pt->x.fract = (vec->x & 0x3f) << 10;
3474 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
3475 pt->y.value = vec->y >> 6;
3476 pt->y.fract = (vec->y & 0x3f) << 10;
3477 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
3478 return;
3481 /***************************************************
3482 * According to the MSDN documentation on WideCharToMultiByte,
3483 * certain codepages cannot set the default_used parameter.
3484 * This returns TRUE if the codepage can set that parameter, false else
3485 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
3487 static BOOL codepage_sets_default_used(UINT codepage)
3489 switch (codepage)
3491 case CP_UTF7:
3492 case CP_UTF8:
3493 case CP_SYMBOL:
3494 return FALSE;
3495 default:
3496 return TRUE;
3500 static FT_UInt get_glyph_index(GdiFont *font, UINT glyph)
3502 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
3503 WCHAR wc = (WCHAR)glyph;
3504 BOOL default_used;
3505 BOOL *default_used_pointer;
3506 FT_UInt ret;
3507 char buf;
3508 default_used_pointer = NULL;
3509 default_used = FALSE;
3510 if (codepage_sets_default_used(font->codepage))
3511 default_used_pointer = &default_used;
3512 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
3513 ret = 0;
3514 else
3515 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
3516 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
3517 return ret;
3520 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
3521 glyph = glyph + 0xf000;
3522 return pFT_Get_Char_Index(font->ft_face, glyph);
3525 /*************************************************************
3526 * WineEngGetGlyphIndices
3528 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
3530 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
3531 LPWORD pgi, DWORD flags)
3533 int i;
3534 WCHAR default_char = 0;
3535 TEXTMETRICW textm;
3537 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0x001f; /* Indicate non existence */
3539 for(i = 0; i < count; i++)
3541 pgi[i] = get_glyph_index(font, lpstr[i]);
3542 if (pgi[i] == 0)
3544 if (!default_char)
3546 WineEngGetTextMetrics(font, &textm);
3547 default_char = textm.tmDefaultChar;
3549 pgi[i] = default_char;
3552 return count;
3555 /*************************************************************
3556 * WineEngGetGlyphOutline
3558 * Behaves in exactly the same way as the win32 api GetGlyphOutline
3559 * except that the first parameter is the HWINEENGFONT of the font in
3560 * question rather than an HDC.
3563 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
3564 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
3565 const MAT2* lpmat)
3567 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
3568 FT_Face ft_face = incoming_font->ft_face;
3569 GdiFont *font = incoming_font;
3570 FT_UInt glyph_index;
3571 DWORD width, height, pitch, needed = 0;
3572 FT_Bitmap ft_bitmap;
3573 FT_Error err;
3574 INT left, right, top = 0, bottom = 0, adv, lsb, bbx;
3575 FT_Angle angle = 0;
3576 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
3577 float widthRatio = 1.0;
3578 FT_Matrix transMat = identityMat;
3579 BOOL needsTransform = FALSE;
3582 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
3583 buflen, buf, lpmat);
3585 if(format & GGO_GLYPH_INDEX) {
3586 glyph_index = glyph;
3587 format &= ~GGO_GLYPH_INDEX;
3588 } else {
3589 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
3590 ft_face = font->ft_face;
3593 if(glyph_index >= font->gmsize * GM_BLOCK_SIZE) {
3594 font->gmsize = (glyph_index / GM_BLOCK_SIZE + 1);
3595 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
3596 font->gmsize * sizeof(GM*));
3597 } else {
3598 if(format == GGO_METRICS && font->gm[glyph_index / GM_BLOCK_SIZE] != NULL && FONT_GM(font,glyph_index)->init ) {
3599 *lpgm = FONT_GM(font,glyph_index)->gm;
3600 return 1; /* FIXME */
3604 if (!font->gm[glyph_index / GM_BLOCK_SIZE])
3605 font->gm[glyph_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3607 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP) || font->aveWidth || lpmat)
3608 load_flags |= FT_LOAD_NO_BITMAP;
3610 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
3612 if(err) {
3613 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
3614 return GDI_ERROR;
3617 /* Scaling factor */
3618 if (font->aveWidth && font->potm) {
3619 widthRatio = (float)font->aveWidth * font->font_desc.matrix.eM11 / (float) font->potm->otmTextMetrics.tmAveCharWidth;
3622 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
3623 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
3625 adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
3626 lsb = left >> 6;
3627 bbx = (right - left) >> 6;
3629 /* Scaling transform */
3630 if(font->aveWidth) {
3631 FT_Matrix scaleMat;
3632 scaleMat.xx = FT_FixedFromFloat(widthRatio);
3633 scaleMat.xy = 0;
3634 scaleMat.yx = 0;
3635 scaleMat.yy = (1 << 16);
3637 pFT_Matrix_Multiply(&scaleMat, &transMat);
3638 needsTransform = TRUE;
3641 /* Slant transform */
3642 if (font->fake_italic) {
3643 FT_Matrix slantMat;
3645 slantMat.xx = (1 << 16);
3646 slantMat.xy = ((1 << 16) >> 2);
3647 slantMat.yx = 0;
3648 slantMat.yy = (1 << 16);
3649 pFT_Matrix_Multiply(&slantMat, &transMat);
3650 needsTransform = TRUE;
3653 /* Rotation transform */
3654 if(font->orientation) {
3655 FT_Matrix rotationMat;
3656 FT_Vector vecAngle;
3657 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
3658 pFT_Vector_Unit(&vecAngle, angle);
3659 rotationMat.xx = vecAngle.x;
3660 rotationMat.xy = -vecAngle.y;
3661 rotationMat.yx = -rotationMat.xy;
3662 rotationMat.yy = rotationMat.xx;
3664 pFT_Matrix_Multiply(&rotationMat, &transMat);
3665 needsTransform = TRUE;
3668 /* Extra transformation specified by caller */
3669 if (lpmat) {
3670 FT_Matrix extraMat;
3671 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
3672 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
3673 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
3674 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
3675 pFT_Matrix_Multiply(&extraMat, &transMat);
3676 needsTransform = TRUE;
3679 if(!needsTransform) {
3680 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
3681 bottom = (ft_face->glyph->metrics.horiBearingY -
3682 ft_face->glyph->metrics.height) & -64;
3683 lpgm->gmCellIncX = adv;
3684 lpgm->gmCellIncY = 0;
3685 } else {
3686 INT xc, yc;
3687 FT_Vector vec;
3688 for(xc = 0; xc < 2; xc++) {
3689 for(yc = 0; yc < 2; yc++) {
3690 vec.x = (ft_face->glyph->metrics.horiBearingX +
3691 xc * ft_face->glyph->metrics.width);
3692 vec.y = ft_face->glyph->metrics.horiBearingY -
3693 yc * ft_face->glyph->metrics.height;
3694 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
3695 pFT_Vector_Transform(&vec, &transMat);
3696 if(xc == 0 && yc == 0) {
3697 left = right = vec.x;
3698 top = bottom = vec.y;
3699 } else {
3700 if(vec.x < left) left = vec.x;
3701 else if(vec.x > right) right = vec.x;
3702 if(vec.y < bottom) bottom = vec.y;
3703 else if(vec.y > top) top = vec.y;
3707 left = left & -64;
3708 right = (right + 63) & -64;
3709 bottom = bottom & -64;
3710 top = (top + 63) & -64;
3712 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
3713 vec.x = ft_face->glyph->metrics.horiAdvance;
3714 vec.y = 0;
3715 pFT_Vector_Transform(&vec, &transMat);
3716 lpgm->gmCellIncX = (vec.x+63) >> 6;
3717 lpgm->gmCellIncY = -((vec.y+63) >> 6);
3719 lpgm->gmBlackBoxX = (right - left) >> 6;
3720 lpgm->gmBlackBoxY = (top - bottom) >> 6;
3721 lpgm->gmptGlyphOrigin.x = left >> 6;
3722 lpgm->gmptGlyphOrigin.y = top >> 6;
3724 if(format == GGO_METRICS || format == GGO_BITMAP || format == WINE_GGO_GRAY16_BITMAP)
3726 FONT_GM(font,glyph_index)->gm = *lpgm;
3727 FONT_GM(font,glyph_index)->adv = adv;
3728 FONT_GM(font,glyph_index)->lsb = lsb;
3729 FONT_GM(font,glyph_index)->bbx = bbx;
3730 FONT_GM(font,glyph_index)->init = TRUE;
3733 if(format == GGO_METRICS)
3734 return 1; /* FIXME */
3736 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP && format != WINE_GGO_GRAY16_BITMAP) {
3737 TRACE("loaded a bitmap\n");
3738 return GDI_ERROR;
3741 switch(format) {
3742 case GGO_BITMAP:
3743 width = lpgm->gmBlackBoxX;
3744 height = lpgm->gmBlackBoxY;
3745 pitch = ((width + 31) >> 5) << 2;
3746 needed = pitch * height;
3748 if(!buf || !buflen) break;
3750 switch(ft_face->glyph->format) {
3751 case ft_glyph_format_bitmap:
3753 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
3754 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
3755 INT h = ft_face->glyph->bitmap.rows;
3756 while(h--) {
3757 memcpy(dst, src, w);
3758 src += ft_face->glyph->bitmap.pitch;
3759 dst += pitch;
3761 break;
3764 case ft_glyph_format_outline:
3765 ft_bitmap.width = width;
3766 ft_bitmap.rows = height;
3767 ft_bitmap.pitch = pitch;
3768 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
3769 ft_bitmap.buffer = buf;
3771 if(needsTransform) {
3772 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3775 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3777 /* Note: FreeType will only set 'black' bits for us. */
3778 memset(buf, 0, needed);
3779 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3780 break;
3782 default:
3783 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
3784 return GDI_ERROR;
3786 break;
3788 case GGO_GRAY2_BITMAP:
3789 case GGO_GRAY4_BITMAP:
3790 case GGO_GRAY8_BITMAP:
3791 case WINE_GGO_GRAY16_BITMAP:
3793 unsigned int mult, row, col;
3794 BYTE *start, *ptr;
3796 width = lpgm->gmBlackBoxX;
3797 height = lpgm->gmBlackBoxY;
3798 pitch = (width + 3) / 4 * 4;
3799 needed = pitch * height;
3801 if(!buf || !buflen) break;
3803 switch(ft_face->glyph->format) {
3804 case ft_glyph_format_bitmap:
3806 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
3807 INT h = ft_face->glyph->bitmap.rows;
3808 INT x;
3809 while(h--) {
3810 for(x = 0; x < pitch; x++)
3811 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
3812 src += ft_face->glyph->bitmap.pitch;
3813 dst += pitch;
3815 return needed;
3817 case ft_glyph_format_outline:
3819 ft_bitmap.width = width;
3820 ft_bitmap.rows = height;
3821 ft_bitmap.pitch = pitch;
3822 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
3823 ft_bitmap.buffer = buf;
3825 if(needsTransform)
3826 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3828 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3830 memset(ft_bitmap.buffer, 0, buflen);
3832 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3834 if(format == GGO_GRAY2_BITMAP)
3835 mult = 4;
3836 else if(format == GGO_GRAY4_BITMAP)
3837 mult = 16;
3838 else if(format == GGO_GRAY8_BITMAP)
3839 mult = 64;
3840 else /* format == WINE_GGO_GRAY16_BITMAP */
3841 return needed;
3843 break;
3845 default:
3846 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
3847 return GDI_ERROR;
3850 start = buf;
3851 for(row = 0; row < height; row++) {
3852 ptr = start;
3853 for(col = 0; col < width; col++, ptr++) {
3854 *ptr = (((int)*ptr) * mult + 128) / 256;
3856 start += pitch;
3858 break;
3861 case GGO_NATIVE:
3863 int contour, point = 0, first_pt;
3864 FT_Outline *outline = &ft_face->glyph->outline;
3865 TTPOLYGONHEADER *pph;
3866 TTPOLYCURVE *ppc;
3867 DWORD pph_start, cpfx, type;
3869 if(buflen == 0) buf = NULL;
3871 if (needsTransform && buf) {
3872 pFT_Outline_Transform(outline, &transMat);
3875 for(contour = 0; contour < outline->n_contours; contour++) {
3876 pph_start = needed;
3877 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3878 first_pt = point;
3879 if(buf) {
3880 pph->dwType = TT_POLYGON_TYPE;
3881 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3883 needed += sizeof(*pph);
3884 point++;
3885 while(point <= outline->contours[contour]) {
3886 ppc = (TTPOLYCURVE *)((char *)buf + needed);
3887 type = (outline->tags[point] & FT_Curve_Tag_On) ?
3888 TT_PRIM_LINE : TT_PRIM_QSPLINE;
3889 cpfx = 0;
3890 do {
3891 if(buf)
3892 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3893 cpfx++;
3894 point++;
3895 } while(point <= outline->contours[contour] &&
3896 (outline->tags[point] & FT_Curve_Tag_On) ==
3897 (outline->tags[point-1] & FT_Curve_Tag_On));
3898 /* At the end of a contour Windows adds the start point, but
3899 only for Beziers */
3900 if(point > outline->contours[contour] &&
3901 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
3902 if(buf)
3903 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
3904 cpfx++;
3905 } else if(point <= outline->contours[contour] &&
3906 outline->tags[point] & FT_Curve_Tag_On) {
3907 /* add closing pt for bezier */
3908 if(buf)
3909 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3910 cpfx++;
3911 point++;
3913 if(buf) {
3914 ppc->wType = type;
3915 ppc->cpfx = cpfx;
3917 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3919 if(buf)
3920 pph->cb = needed - pph_start;
3922 break;
3924 case GGO_BEZIER:
3926 /* Convert the quadratic Beziers to cubic Beziers.
3927 The parametric eqn for a cubic Bezier is, from PLRM:
3928 r(t) = at^3 + bt^2 + ct + r0
3929 with the control points:
3930 r1 = r0 + c/3
3931 r2 = r1 + (c + b)/3
3932 r3 = r0 + c + b + a
3934 A quadratic Beizer has the form:
3935 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3937 So equating powers of t leads to:
3938 r1 = 2/3 p1 + 1/3 p0
3939 r2 = 2/3 p1 + 1/3 p2
3940 and of course r0 = p0, r3 = p2
3943 int contour, point = 0, first_pt;
3944 FT_Outline *outline = &ft_face->glyph->outline;
3945 TTPOLYGONHEADER *pph;
3946 TTPOLYCURVE *ppc;
3947 DWORD pph_start, cpfx, type;
3948 FT_Vector cubic_control[4];
3949 if(buflen == 0) buf = NULL;
3951 if (needsTransform && buf) {
3952 pFT_Outline_Transform(outline, &transMat);
3955 for(contour = 0; contour < outline->n_contours; contour++) {
3956 pph_start = needed;
3957 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3958 first_pt = point;
3959 if(buf) {
3960 pph->dwType = TT_POLYGON_TYPE;
3961 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3963 needed += sizeof(*pph);
3964 point++;
3965 while(point <= outline->contours[contour]) {
3966 ppc = (TTPOLYCURVE *)((char *)buf + needed);
3967 type = (outline->tags[point] & FT_Curve_Tag_On) ?
3968 TT_PRIM_LINE : TT_PRIM_CSPLINE;
3969 cpfx = 0;
3970 do {
3971 if(type == TT_PRIM_LINE) {
3972 if(buf)
3973 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3974 cpfx++;
3975 point++;
3976 } else {
3977 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
3978 so cpfx = 3n */
3980 /* FIXME: Possible optimization in endpoint calculation
3981 if there are two consecutive curves */
3982 cubic_control[0] = outline->points[point-1];
3983 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
3984 cubic_control[0].x += outline->points[point].x + 1;
3985 cubic_control[0].y += outline->points[point].y + 1;
3986 cubic_control[0].x >>= 1;
3987 cubic_control[0].y >>= 1;
3989 if(point+1 > outline->contours[contour])
3990 cubic_control[3] = outline->points[first_pt];
3991 else {
3992 cubic_control[3] = outline->points[point+1];
3993 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
3994 cubic_control[3].x += outline->points[point].x + 1;
3995 cubic_control[3].y += outline->points[point].y + 1;
3996 cubic_control[3].x >>= 1;
3997 cubic_control[3].y >>= 1;
4000 /* r1 = 1/3 p0 + 2/3 p1
4001 r2 = 1/3 p2 + 2/3 p1 */
4002 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
4003 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
4004 cubic_control[2] = cubic_control[1];
4005 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
4006 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
4007 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
4008 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
4009 if(buf) {
4010 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
4011 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
4012 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
4014 cpfx += 3;
4015 point++;
4017 } while(point <= outline->contours[contour] &&
4018 (outline->tags[point] & FT_Curve_Tag_On) ==
4019 (outline->tags[point-1] & FT_Curve_Tag_On));
4020 /* At the end of a contour Windows adds the start point,
4021 but only for Beziers and we've already done that.
4023 if(point <= outline->contours[contour] &&
4024 outline->tags[point] & FT_Curve_Tag_On) {
4025 /* This is the closing pt of a bezier, but we've already
4026 added it, so just inc point and carry on */
4027 point++;
4029 if(buf) {
4030 ppc->wType = type;
4031 ppc->cpfx = cpfx;
4033 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
4035 if(buf)
4036 pph->cb = needed - pph_start;
4038 break;
4041 default:
4042 FIXME("Unsupported format %d\n", format);
4043 return GDI_ERROR;
4045 return needed;
4048 static BOOL get_bitmap_text_metrics(GdiFont *font)
4050 FT_Face ft_face = font->ft_face;
4051 #ifdef HAVE_FREETYPE_FTWINFNT_H
4052 FT_WinFNT_HeaderRec winfnt_header;
4053 #endif
4054 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
4055 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
4056 font->potm->otmSize = size;
4058 #define TM font->potm->otmTextMetrics
4059 #ifdef HAVE_FREETYPE_FTWINFNT_H
4060 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
4062 TM.tmHeight = winfnt_header.pixel_height;
4063 TM.tmAscent = winfnt_header.ascent;
4064 TM.tmDescent = TM.tmHeight - TM.tmAscent;
4065 TM.tmInternalLeading = winfnt_header.internal_leading;
4066 TM.tmExternalLeading = winfnt_header.external_leading;
4067 TM.tmAveCharWidth = winfnt_header.avg_width;
4068 TM.tmMaxCharWidth = winfnt_header.max_width;
4069 TM.tmWeight = winfnt_header.weight;
4070 TM.tmOverhang = 0;
4071 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
4072 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
4073 TM.tmFirstChar = winfnt_header.first_char;
4074 TM.tmLastChar = winfnt_header.last_char;
4075 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
4076 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
4077 TM.tmItalic = winfnt_header.italic;
4078 TM.tmUnderlined = font->underline;
4079 TM.tmStruckOut = font->strikeout;
4080 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
4081 TM.tmCharSet = winfnt_header.charset;
4083 else
4084 #endif
4086 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
4087 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
4088 TM.tmHeight = TM.tmAscent + TM.tmDescent;
4089 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
4090 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
4091 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
4092 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
4093 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
4094 TM.tmOverhang = 0;
4095 TM.tmDigitizedAspectX = 96; /* FIXME */
4096 TM.tmDigitizedAspectY = 96; /* FIXME */
4097 TM.tmFirstChar = 1;
4098 TM.tmLastChar = 255;
4099 TM.tmDefaultChar = 32;
4100 TM.tmBreakChar = 32;
4101 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
4102 TM.tmUnderlined = font->underline;
4103 TM.tmStruckOut = font->strikeout;
4104 /* NB inverted meaning of TMPF_FIXED_PITCH */
4105 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
4106 TM.tmCharSet = font->charset;
4108 #undef TM
4110 return TRUE;
4113 /*************************************************************
4114 * WineEngGetTextMetrics
4117 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
4119 if(!font->potm) {
4120 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
4121 if(!get_bitmap_text_metrics(font))
4122 return FALSE;
4124 if(!font->potm) return FALSE;
4125 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
4127 if (font->aveWidth) {
4128 ptm->tmAveCharWidth = font->aveWidth * font->font_desc.matrix.eM11;
4130 return TRUE;
4134 /*************************************************************
4135 * WineEngGetOutlineTextMetrics
4138 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
4139 OUTLINETEXTMETRICW *potm)
4141 FT_Face ft_face = font->ft_face;
4142 UINT needed, lenfam, lensty, ret;
4143 TT_OS2 *pOS2;
4144 TT_HoriHeader *pHori;
4145 TT_Postscript *pPost;
4146 FT_Fixed x_scale, y_scale;
4147 WCHAR *family_nameW, *style_nameW;
4148 static const WCHAR spaceW[] = {' ', '\0'};
4149 char *cp;
4150 INT ascent, descent;
4152 TRACE("font=%p\n", font);
4154 if(!FT_IS_SCALABLE(ft_face))
4155 return 0;
4157 if(font->potm) {
4158 if(cbSize >= font->potm->otmSize)
4159 memcpy(potm, font->potm, font->potm->otmSize);
4160 return font->potm->otmSize;
4164 needed = sizeof(*potm);
4166 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
4167 family_nameW = strdupW(font->name);
4169 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
4170 * sizeof(WCHAR);
4171 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
4172 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
4173 style_nameW, lensty/sizeof(WCHAR));
4175 /* These names should be read from the TT name table */
4177 /* length of otmpFamilyName */
4178 needed += lenfam;
4180 /* length of otmpFaceName */
4181 if(!strcasecmp(ft_face->style_name, "regular")) {
4182 needed += lenfam; /* just the family name */
4183 } else {
4184 needed += lenfam + lensty; /* family + " " + style */
4187 /* length of otmpStyleName */
4188 needed += lensty;
4190 /* length of otmpFullName */
4191 needed += lenfam + lensty;
4194 x_scale = ft_face->size->metrics.x_scale;
4195 y_scale = ft_face->size->metrics.y_scale;
4197 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
4198 if(!pOS2) {
4199 FIXME("Can't find OS/2 table - not TT font?\n");
4200 ret = 0;
4201 goto end;
4204 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
4205 if(!pHori) {
4206 FIXME("Can't find HHEA table - not TT font?\n");
4207 ret = 0;
4208 goto end;
4211 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
4213 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",
4214 pOS2->usWinAscent, pOS2->usWinDescent,
4215 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
4216 ft_face->ascender, ft_face->descender, ft_face->height,
4217 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
4218 ft_face->bbox.yMax, ft_face->bbox.yMin);
4220 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
4221 font->potm->otmSize = needed;
4223 #define TM font->potm->otmTextMetrics
4225 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
4226 ascent = pHori->Ascender;
4227 descent = -pHori->Descender;
4228 } else {
4229 ascent = pOS2->usWinAscent;
4230 descent = pOS2->usWinDescent;
4233 if(font->yMax) {
4234 TM.tmAscent = font->yMax;
4235 TM.tmDescent = -font->yMin;
4236 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
4237 } else {
4238 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
4239 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
4240 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
4241 - ft_face->units_per_EM, y_scale) + 32) >> 6;
4244 TM.tmHeight = TM.tmAscent + TM.tmDescent;
4246 /* MSDN says:
4247 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
4249 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
4250 ((ascent + descent) -
4251 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
4253 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
4254 if (TM.tmAveCharWidth == 0) {
4255 TM.tmAveCharWidth = 1;
4257 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
4258 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
4259 TM.tmOverhang = 0;
4260 TM.tmDigitizedAspectX = 300;
4261 TM.tmDigitizedAspectY = 300;
4262 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
4263 * symbol range to 0 - f0ff
4265 if (font->charset == SYMBOL_CHARSET)
4266 TM.tmFirstChar = 0;
4267 else
4268 TM.tmFirstChar = pOS2->usFirstCharIndex;
4269 TM.tmLastChar = pOS2->usLastCharIndex;
4270 TM.tmDefaultChar = pOS2->usDefaultChar ? pOS2->usDefaultChar : 0x1f;
4271 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
4272 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
4273 TM.tmUnderlined = font->underline;
4274 TM.tmStruckOut = font->strikeout;
4276 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
4277 if(!FT_IS_FIXED_WIDTH(ft_face) &&
4278 (pOS2->version == 0xFFFFU ||
4279 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
4280 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
4281 else
4282 TM.tmPitchAndFamily = 0;
4284 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
4285 case PAN_FAMILY_SCRIPT:
4286 TM.tmPitchAndFamily |= FF_SCRIPT;
4287 break;
4288 case PAN_FAMILY_DECORATIVE:
4289 case PAN_FAMILY_PICTORIAL:
4290 TM.tmPitchAndFamily |= FF_DECORATIVE;
4291 break;
4292 case PAN_FAMILY_TEXT_DISPLAY:
4293 if(TM.tmPitchAndFamily == 0) /* fixed */
4294 TM.tmPitchAndFamily = FF_MODERN;
4295 else {
4296 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
4297 case PAN_SERIF_NORMAL_SANS:
4298 case PAN_SERIF_OBTUSE_SANS:
4299 case PAN_SERIF_PERP_SANS:
4300 TM.tmPitchAndFamily |= FF_SWISS;
4301 break;
4302 default:
4303 TM.tmPitchAndFamily |= FF_ROMAN;
4306 break;
4307 default:
4308 TM.tmPitchAndFamily |= FF_DONTCARE;
4311 if(FT_IS_SCALABLE(ft_face))
4312 TM.tmPitchAndFamily |= TMPF_VECTOR;
4314 if(FT_IS_SFNT(ft_face))
4316 if (font->ntmFlags & NTM_PS_OPENTYPE)
4317 TM.tmPitchAndFamily |= TMPF_DEVICE;
4318 else
4319 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
4322 TM.tmCharSet = font->charset;
4323 #undef TM
4325 font->potm->otmFiller = 0;
4326 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
4327 font->potm->otmfsSelection = pOS2->fsSelection;
4328 font->potm->otmfsType = pOS2->fsType;
4329 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
4330 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
4331 font->potm->otmItalicAngle = 0; /* POST table */
4332 font->potm->otmEMSquare = ft_face->units_per_EM;
4333 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
4334 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
4335 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
4336 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
4337 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
4338 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
4339 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
4340 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
4341 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
4342 font->potm->otmMacAscent = 0; /* where do these come from ? */
4343 font->potm->otmMacDescent = 0;
4344 font->potm->otmMacLineGap = 0;
4345 font->potm->otmusMinimumPPEM = 0; /* TT Header */
4346 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
4347 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
4348 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
4349 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
4350 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
4351 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
4352 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
4353 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
4354 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
4355 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
4356 if(!pPost) {
4357 font->potm->otmsUnderscoreSize = 0;
4358 font->potm->otmsUnderscorePosition = 0;
4359 } else {
4360 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
4361 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
4364 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
4365 cp = (char*)font->potm + sizeof(*font->potm);
4366 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
4367 strcpyW((WCHAR*)cp, family_nameW);
4368 cp += lenfam;
4369 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
4370 strcpyW((WCHAR*)cp, style_nameW);
4371 cp += lensty;
4372 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
4373 strcpyW((WCHAR*)cp, family_nameW);
4374 if(strcasecmp(ft_face->style_name, "regular")) {
4375 strcatW((WCHAR*)cp, spaceW);
4376 strcatW((WCHAR*)cp, style_nameW);
4377 cp += lenfam + lensty;
4378 } else
4379 cp += lenfam;
4380 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
4381 strcpyW((WCHAR*)cp, family_nameW);
4382 strcatW((WCHAR*)cp, spaceW);
4383 strcatW((WCHAR*)cp, style_nameW);
4384 ret = needed;
4386 if(potm && needed <= cbSize)
4387 memcpy(potm, font->potm, font->potm->otmSize);
4389 end:
4390 HeapFree(GetProcessHeap(), 0, style_nameW);
4391 HeapFree(GetProcessHeap(), 0, family_nameW);
4393 return ret;
4396 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
4398 HFONTLIST *hfontlist;
4399 child->font = alloc_font();
4400 child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem);
4401 if(!child->font->ft_face)
4403 free_font(child->font);
4404 child->font = NULL;
4405 return FALSE;
4408 child->font->ntmFlags = child->face->ntmFlags;
4409 child->font->orientation = font->orientation;
4410 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
4411 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
4412 list_add_head(&child->font->hfontlist, &hfontlist->entry);
4413 child->font->base_font = font;
4414 list_add_head(&child_font_list, &child->font->entry);
4415 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
4416 return TRUE;
4419 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
4421 FT_UInt g;
4422 CHILD_FONT *child_font;
4424 if(font->base_font)
4425 font = font->base_font;
4427 *linked_font = font;
4429 if((*glyph = get_glyph_index(font, c)))
4430 return TRUE;
4432 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
4434 if(!child_font->font)
4435 if(!load_child_font(font, child_font))
4436 continue;
4438 if(!child_font->font->ft_face)
4439 continue;
4440 g = get_glyph_index(child_font->font, c);
4441 if(g)
4443 *glyph = g;
4444 *linked_font = child_font->font;
4445 return TRUE;
4448 return FALSE;
4451 /*************************************************************
4452 * WineEngGetCharWidth
4455 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
4456 LPINT buffer)
4458 UINT c;
4459 GLYPHMETRICS gm;
4460 FT_UInt glyph_index;
4461 GdiFont *linked_font;
4463 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
4465 for(c = firstChar; c <= lastChar; c++) {
4466 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
4467 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4468 &gm, 0, NULL, NULL);
4469 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
4471 return TRUE;
4474 /*************************************************************
4475 * WineEngGetCharABCWidths
4478 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
4479 LPABC buffer)
4481 UINT c;
4482 GLYPHMETRICS gm;
4483 FT_UInt glyph_index;
4484 GdiFont *linked_font;
4486 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
4488 if(!FT_IS_SCALABLE(font->ft_face))
4489 return FALSE;
4491 for(c = firstChar; c <= lastChar; c++) {
4492 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
4493 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4494 &gm, 0, NULL, NULL);
4495 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
4496 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
4497 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
4498 FONT_GM(linked_font,glyph_index)->bbx;
4500 return TRUE;
4503 /*************************************************************
4504 * WineEngGetCharABCWidthsI
4507 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
4508 LPABC buffer)
4510 UINT c;
4511 GLYPHMETRICS gm;
4512 FT_UInt glyph_index;
4513 GdiFont *linked_font;
4515 if(!FT_IS_SCALABLE(font->ft_face))
4516 return FALSE;
4518 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
4519 if (!pgi)
4520 for(c = firstChar; c < firstChar+count; c++) {
4521 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
4522 &gm, 0, NULL, NULL);
4523 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
4524 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
4525 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
4526 - FONT_GM(linked_font,c)->bbx;
4528 else
4529 for(c = 0; c < count; c++) {
4530 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
4531 &gm, 0, NULL, NULL);
4532 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
4533 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
4534 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
4535 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
4538 return TRUE;
4541 /*************************************************************
4542 * WineEngGetTextExtentExPoint
4545 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
4546 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
4548 INT idx;
4549 INT nfit = 0, ext;
4550 GLYPHMETRICS gm;
4551 TEXTMETRICW tm;
4552 FT_UInt glyph_index;
4553 GdiFont *linked_font;
4555 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
4556 max_ext, size);
4558 size->cx = 0;
4559 WineEngGetTextMetrics(font, &tm);
4560 size->cy = tm.tmHeight;
4562 for(idx = 0; idx < count; idx++) {
4563 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
4564 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4565 &gm, 0, NULL, NULL);
4566 size->cx += FONT_GM(linked_font,glyph_index)->adv;
4567 ext = size->cx;
4568 if (! pnfit || ext <= max_ext) {
4569 ++nfit;
4570 if (dxs)
4571 dxs[idx] = ext;
4575 if (pnfit)
4576 *pnfit = nfit;
4578 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
4579 return TRUE;
4582 /*************************************************************
4583 * WineEngGetTextExtentPointI
4586 BOOL WineEngGetTextExtentPointI(GdiFont *font, const WORD *indices, INT count,
4587 LPSIZE size)
4589 INT idx;
4590 GLYPHMETRICS gm;
4591 TEXTMETRICW tm;
4593 TRACE("%p, %p, %d, %p\n", font, indices, count, size);
4595 size->cx = 0;
4596 WineEngGetTextMetrics(font, &tm);
4597 size->cy = tm.tmHeight;
4599 for(idx = 0; idx < count; idx++) {
4600 WineEngGetGlyphOutline(font, indices[idx],
4601 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
4602 NULL);
4603 size->cx += FONT_GM(font,indices[idx])->adv;
4605 TRACE("return %d,%d\n", size->cx, size->cy);
4606 return TRUE;
4609 /*************************************************************
4610 * WineEngGetFontData
4613 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
4614 DWORD cbData)
4616 FT_Face ft_face = font->ft_face;
4617 FT_ULong len;
4618 FT_Error err;
4620 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
4621 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
4622 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
4624 if(!FT_IS_SFNT(ft_face))
4625 return GDI_ERROR;
4627 if(!buf || !cbData)
4628 len = 0;
4629 else
4630 len = cbData;
4632 if(table) { /* MS tags differ in endidness from FT ones */
4633 table = table >> 24 | table << 24 |
4634 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
4637 /* make sure value of len is the value freetype says it needs */
4638 if(buf && len)
4640 FT_ULong needed = 0;
4641 err = load_sfnt_table(ft_face, table, offset, NULL, &needed);
4642 if( !err && needed < len) len = needed;
4644 err = load_sfnt_table(ft_face, table, offset, buf, &len);
4646 if(err) {
4647 TRACE("Can't find table %c%c%c%c\n",
4648 /* bytes were reversed */
4649 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
4650 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
4651 return GDI_ERROR;
4653 return len;
4656 /*************************************************************
4657 * WineEngGetTextFace
4660 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
4662 if(str) {
4663 lstrcpynW(str, font->name, count);
4664 return strlenW(font->name);
4665 } else
4666 return strlenW(font->name) + 1;
4669 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
4671 if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
4672 return font->charset;
4675 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
4677 GdiFont *font = dc->gdiFont, *linked_font;
4678 struct list *first_hfont;
4679 BOOL ret;
4681 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
4682 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
4683 if(font == linked_font)
4684 *new_hfont = dc->hFont;
4685 else
4687 first_hfont = list_head(&linked_font->hfontlist);
4688 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
4691 return ret;
4694 /* Retrieve a list of supported Unicode ranges for a given font.
4695 * Can be called with NULL gs to calculate the buffer size. Returns
4696 * the number of ranges found.
4698 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
4700 DWORD num_ranges = 0;
4702 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
4704 FT_UInt glyph_code;
4705 FT_ULong char_code, char_code_prev;
4707 glyph_code = 0;
4708 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
4710 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
4711 face->num_glyphs, glyph_code, char_code);
4713 if (!glyph_code) return 0;
4715 if (gs)
4717 gs->ranges[0].wcLow = (USHORT)char_code;
4718 gs->ranges[0].cGlyphs = 0;
4719 gs->cGlyphsSupported = 0;
4722 num_ranges = 1;
4723 while (glyph_code)
4725 if (char_code < char_code_prev)
4727 ERR("expected increasing char code from FT_Get_Next_Char\n");
4728 return 0;
4730 if (char_code - char_code_prev > 1)
4732 num_ranges++;
4733 if (gs)
4735 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
4736 gs->ranges[num_ranges - 1].cGlyphs = 1;
4737 gs->cGlyphsSupported++;
4740 else if (gs)
4742 gs->ranges[num_ranges - 1].cGlyphs++;
4743 gs->cGlyphsSupported++;
4745 char_code_prev = char_code;
4746 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
4749 else
4750 FIXME("encoding %u not supported\n", face->charmap->encoding);
4752 return num_ranges;
4755 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
4757 DWORD size = 0;
4758 DWORD num_ranges = get_font_unicode_ranges(font->ft_face, glyphset);
4760 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
4761 if (glyphset)
4763 glyphset->cbThis = size;
4764 glyphset->cRanges = num_ranges;
4766 return size;
4769 /*************************************************************
4770 * FontIsLinked
4772 BOOL WineEngFontIsLinked(GdiFont *font)
4774 return !list_empty(&font->child_fonts);
4777 static BOOL is_hinting_enabled(void)
4779 /* Use the >= 2.2.0 function if available */
4780 if(pFT_Get_TrueType_Engine_Type)
4782 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
4783 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
4785 #ifdef FT_DRIVER_HAS_HINTER
4786 else
4788 FT_Module mod;
4790 /* otherwise if we've been compiled with < 2.2.0 headers
4791 use the internal macro */
4792 mod = pFT_Get_Module(library, "truetype");
4793 if(mod && FT_DRIVER_HAS_HINTER(mod))
4794 return TRUE;
4796 #endif
4798 return FALSE;
4801 /*************************************************************************
4802 * GetRasterizerCaps (GDI32.@)
4804 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
4806 static int hinting = -1;
4808 if(hinting == -1)
4810 hinting = is_hinting_enabled();
4811 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
4814 lprs->nSize = sizeof(RASTERIZER_STATUS);
4815 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
4816 lprs->nLanguageID = 0;
4817 return TRUE;
4820 /*************************************************************************
4821 * Kerning support for TrueType fonts
4823 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
4825 struct TT_kern_table
4827 USHORT version;
4828 USHORT nTables;
4831 struct TT_kern_subtable
4833 USHORT version;
4834 USHORT length;
4835 union
4837 USHORT word;
4838 struct
4840 USHORT horizontal : 1;
4841 USHORT minimum : 1;
4842 USHORT cross_stream: 1;
4843 USHORT override : 1;
4844 USHORT reserved1 : 4;
4845 USHORT format : 8;
4846 } bits;
4847 } coverage;
4850 struct TT_format0_kern_subtable
4852 USHORT nPairs;
4853 USHORT searchRange;
4854 USHORT entrySelector;
4855 USHORT rangeShift;
4858 struct TT_kern_pair
4860 USHORT left;
4861 USHORT right;
4862 short value;
4865 static DWORD parse_format0_kern_subtable(GdiFont *font,
4866 const struct TT_format0_kern_subtable *tt_f0_ks,
4867 const USHORT *glyph_to_char,
4868 KERNINGPAIR *kern_pair, DWORD cPairs)
4870 USHORT i, nPairs;
4871 const struct TT_kern_pair *tt_kern_pair;
4873 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
4875 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
4877 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
4878 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
4879 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
4881 if (!kern_pair || !cPairs)
4882 return nPairs;
4884 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
4886 nPairs = min(nPairs, cPairs);
4888 for (i = 0; i < nPairs; i++)
4890 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
4891 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
4892 /* this algorithm appears to better match what Windows does */
4893 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
4894 if (kern_pair->iKernAmount < 0)
4896 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
4897 kern_pair->iKernAmount -= font->ppem;
4899 else if (kern_pair->iKernAmount > 0)
4901 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
4902 kern_pair->iKernAmount += font->ppem;
4904 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
4906 TRACE("left %u right %u value %d\n",
4907 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
4909 kern_pair++;
4911 TRACE("copied %u entries\n", nPairs);
4912 return nPairs;
4915 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
4917 DWORD length;
4918 void *buf;
4919 const struct TT_kern_table *tt_kern_table;
4920 const struct TT_kern_subtable *tt_kern_subtable;
4921 USHORT i, nTables;
4922 USHORT *glyph_to_char;
4924 if (font->total_kern_pairs != (DWORD)-1)
4926 if (cPairs && kern_pair)
4928 cPairs = min(cPairs, font->total_kern_pairs);
4929 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
4930 return cPairs;
4932 return font->total_kern_pairs;
4935 font->total_kern_pairs = 0;
4937 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
4939 if (length == GDI_ERROR)
4941 TRACE("no kerning data in the font\n");
4942 return 0;
4945 buf = HeapAlloc(GetProcessHeap(), 0, length);
4946 if (!buf)
4948 WARN("Out of memory\n");
4949 return 0;
4952 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
4954 /* build a glyph index to char code map */
4955 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
4956 if (!glyph_to_char)
4958 WARN("Out of memory allocating a glyph index to char code map\n");
4959 HeapFree(GetProcessHeap(), 0, buf);
4960 return 0;
4963 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
4965 FT_UInt glyph_code;
4966 FT_ULong char_code;
4968 glyph_code = 0;
4969 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
4971 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
4972 font->ft_face->num_glyphs, glyph_code, char_code);
4974 while (glyph_code)
4976 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
4978 /* FIXME: This doesn't match what Windows does: it does some fancy
4979 * things with duplicate glyph index to char code mappings, while
4980 * we just avoid overriding existing entries.
4982 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
4983 glyph_to_char[glyph_code] = (USHORT)char_code;
4985 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
4988 else
4990 ULONG n;
4992 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
4993 for (n = 0; n <= 65535; n++)
4994 glyph_to_char[n] = (USHORT)n;
4997 tt_kern_table = buf;
4998 nTables = GET_BE_WORD(tt_kern_table->nTables);
4999 TRACE("version %u, nTables %u\n",
5000 GET_BE_WORD(tt_kern_table->version), nTables);
5002 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
5004 for (i = 0; i < nTables; i++)
5006 struct TT_kern_subtable tt_kern_subtable_copy;
5008 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
5009 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
5010 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
5012 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
5013 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
5014 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
5016 /* According to the TrueType specification this is the only format
5017 * that will be properly interpreted by Windows and OS/2
5019 if (tt_kern_subtable_copy.coverage.bits.format == 0)
5021 DWORD new_chunk, old_total = font->total_kern_pairs;
5023 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
5024 glyph_to_char, NULL, 0);
5025 font->total_kern_pairs += new_chunk;
5027 if (!font->kern_pairs)
5028 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
5029 font->total_kern_pairs * sizeof(*font->kern_pairs));
5030 else
5031 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
5032 font->total_kern_pairs * sizeof(*font->kern_pairs));
5034 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
5035 glyph_to_char, font->kern_pairs + old_total, new_chunk);
5037 else
5038 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
5040 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
5043 HeapFree(GetProcessHeap(), 0, glyph_to_char);
5044 HeapFree(GetProcessHeap(), 0, buf);
5046 if (cPairs && kern_pair)
5048 cPairs = min(cPairs, font->total_kern_pairs);
5049 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
5050 return cPairs;
5052 return font->total_kern_pairs;
5055 #else /* HAVE_FREETYPE */
5057 /*************************************************************************/
5059 BOOL WineEngInit(void)
5061 return FALSE;
5063 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
5065 return NULL;
5067 BOOL WineEngDestroyFontInstance(HFONT hfont)
5069 return FALSE;
5072 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
5074 return 1;
5077 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
5078 LPWORD pgi, DWORD flags)
5080 return GDI_ERROR;
5083 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
5084 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
5085 const MAT2* lpmat)
5087 ERR("called but we don't have FreeType\n");
5088 return GDI_ERROR;
5091 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
5093 ERR("called but we don't have FreeType\n");
5094 return FALSE;
5097 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
5098 OUTLINETEXTMETRICW *potm)
5100 ERR("called but we don't have FreeType\n");
5101 return 0;
5104 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
5105 LPINT buffer)
5107 ERR("called but we don't have FreeType\n");
5108 return FALSE;
5111 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
5112 LPABC buffer)
5114 ERR("called but we don't have FreeType\n");
5115 return FALSE;
5118 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
5119 LPABC buffer)
5121 ERR("called but we don't have FreeType\n");
5122 return FALSE;
5125 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
5126 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
5128 ERR("called but we don't have FreeType\n");
5129 return FALSE;
5132 BOOL WineEngGetTextExtentPointI(GdiFont *font, const WORD *indices, INT count,
5133 LPSIZE size)
5135 ERR("called but we don't have FreeType\n");
5136 return FALSE;
5139 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
5140 DWORD cbData)
5142 ERR("called but we don't have FreeType\n");
5143 return GDI_ERROR;
5146 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
5148 ERR("called but we don't have FreeType\n");
5149 return 0;
5152 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
5154 FIXME(":stub\n");
5155 return 1;
5158 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
5160 FIXME(":stub\n");
5161 return TRUE;
5164 HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
5166 FIXME(":stub\n");
5167 return NULL;
5170 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
5172 FIXME(":stub\n");
5173 return DEFAULT_CHARSET;
5176 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
5178 return FALSE;
5181 DWORD WineEngGetFontUnicodeRanges(GdiFont *font, LPGLYPHSET glyphset)
5183 FIXME("(%p, %p): stub\n", font, glyphset);
5184 return 0;
5187 BOOL WineEngFontIsLinked(GdiFont *font)
5189 return FALSE;
5192 /*************************************************************************
5193 * GetRasterizerCaps (GDI32.@)
5195 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
5197 lprs->nSize = sizeof(RASTERIZER_STATUS);
5198 lprs->wFlags = 0;
5199 lprs->nLanguageID = 0;
5200 return TRUE;
5203 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
5205 ERR("called but we don't have FreeType\n");
5206 return 0;
5209 #endif /* HAVE_FREETYPE */