gdi32: Handle errors in WineEngAddFontResourceEx.
[wine/wine-gecko.git] / dlls / gdi32 / freetype.c
blob793c1ad742ae45fa4978fc40f3842750e29feb9e
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_FTSNAMES_H
106 #include <freetype/ftsnames.h>
107 #else
108 # ifdef HAVE_FREETYPE_FTNAMES_H
109 # include <freetype/ftnames.h>
110 # endif
111 #endif
112 #ifdef HAVE_FREETYPE_TTNAMEID_H
113 #include <freetype/ttnameid.h>
114 #endif
115 #ifdef HAVE_FREETYPE_FTOUTLN_H
116 #include <freetype/ftoutln.h>
117 #endif
118 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
119 #include <freetype/internal/sfnt.h>
120 #endif
121 #ifdef HAVE_FREETYPE_FTTRIGON_H
122 #include <freetype/fttrigon.h>
123 #endif
124 #ifdef HAVE_FREETYPE_FTWINFNT_H
125 #include <freetype/ftwinfnt.h>
126 #endif
127 #ifdef HAVE_FREETYPE_FTMODAPI_H
128 #include <freetype/ftmodapi.h>
129 #endif
131 #ifndef SONAME_LIBFREETYPE
132 #define SONAME_LIBFREETYPE "libfreetype.so"
133 #endif
135 #ifndef HAVE_FT_TRUETYPEENGINETYPE
136 typedef enum
138 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
139 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
140 FT_TRUETYPE_ENGINE_TYPE_PATENTED
141 } FT_TrueTypeEngineType;
142 #endif
144 static FT_Library library = 0;
145 typedef struct
147 FT_Int major;
148 FT_Int minor;
149 FT_Int patch;
150 } FT_Version_t;
151 static FT_Version_t FT_Version;
152 static DWORD FT_SimpleVersion;
154 static void *ft_handle = NULL;
156 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
157 MAKE_FUNCPTR(FT_Vector_Unit);
158 MAKE_FUNCPTR(FT_Done_Face);
159 MAKE_FUNCPTR(FT_Get_Char_Index);
160 MAKE_FUNCPTR(FT_Get_Module);
161 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
163 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
164 MAKE_FUNCPTR(FT_Init_FreeType);
165 MAKE_FUNCPTR(FT_Load_Glyph);
166 MAKE_FUNCPTR(FT_Matrix_Multiply);
167 MAKE_FUNCPTR(FT_MulFix);
168 MAKE_FUNCPTR(FT_New_Face);
169 MAKE_FUNCPTR(FT_New_Memory_Face);
170 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
171 MAKE_FUNCPTR(FT_Outline_Transform);
172 MAKE_FUNCPTR(FT_Outline_Translate);
173 MAKE_FUNCPTR(FT_Select_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 HAVE_FONTCONFIG_FONTCONFIG_H
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 #ifndef SONAME_LIBFONTCONFIG
199 #define SONAME_LIBFONTCONFIG "libfontconfig.so"
200 #endif
201 #endif
203 #undef MAKE_FUNCPTR
205 #ifndef ft_encoding_none
206 #define FT_ENCODING_NONE ft_encoding_none
207 #endif
208 #ifndef ft_encoding_ms_symbol
209 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
210 #endif
211 #ifndef ft_encoding_unicode
212 #define FT_ENCODING_UNICODE ft_encoding_unicode
213 #endif
214 #ifndef ft_encoding_apple_roman
215 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
216 #endif
218 #ifdef WORDS_BIGENDIAN
219 #define GET_BE_WORD(x) (x)
220 #else
221 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
222 #endif
224 /* This is bascially a copy of FT_Bitmap_Size with an extra element added */
225 typedef struct {
226 FT_Short height;
227 FT_Short width;
228 FT_Pos size;
229 FT_Pos x_ppem;
230 FT_Pos y_ppem;
231 FT_Short internal_leading;
232 } Bitmap_Size;
234 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
235 So to let this compile on older versions of FreeType we'll define the
236 new structure here. */
237 typedef struct {
238 FT_Short height, width;
239 FT_Pos size, x_ppem, y_ppem;
240 } My_FT_Bitmap_Size;
242 typedef struct tagFace {
243 struct list entry;
244 WCHAR *StyleName;
245 char *file;
246 FT_Long face_index;
247 BOOL Italic;
248 BOOL Bold;
249 FONTSIGNATURE fs;
250 FONTSIGNATURE fs_links;
251 FT_Fixed font_version;
252 BOOL scalable;
253 Bitmap_Size size; /* set if face is a bitmap */
254 BOOL external; /* TRUE if we should manually add this font to the registry */
255 struct tagFamily *family;
256 } Face;
258 typedef struct tagFamily {
259 struct list entry;
260 const WCHAR *FamilyName;
261 struct list faces;
262 } Family;
264 typedef struct {
265 GLYPHMETRICS gm;
266 INT adv; /* These three hold to widths of the unrotated chars */
267 INT lsb;
268 INT bbx;
269 BOOL init;
270 } GM;
272 typedef struct {
273 FLOAT eM11, eM12;
274 FLOAT eM21, eM22;
275 } FMAT2;
277 typedef struct {
278 DWORD hash;
279 LOGFONTW lf;
280 FMAT2 matrix;
281 BOOL can_use_bitmap;
282 } FONT_DESC;
284 typedef struct tagHFONTLIST {
285 struct list entry;
286 HFONT hfont;
287 } HFONTLIST;
289 typedef struct {
290 struct list entry;
291 char *file_name;
292 INT index;
293 GdiFont *font;
294 } CHILD_FONT;
296 struct tagGdiFont {
297 struct list entry;
298 FT_Face ft_face;
299 struct font_mapping *mapping;
300 LPWSTR name;
301 int charset;
302 int codepage;
303 BOOL fake_italic;
304 BOOL fake_bold;
305 BYTE underline;
306 BYTE strikeout;
307 INT orientation;
308 GM *gm;
309 DWORD gmsize;
310 struct list hfontlist;
311 FONT_DESC font_desc;
312 LONG aveWidth;
313 SHORT yMax;
314 SHORT yMin;
315 OUTLINETEXTMETRICW *potm;
316 DWORD total_kern_pairs;
317 KERNINGPAIR *kern_pairs;
318 FONTSIGNATURE fs;
319 GdiFont *base_font;
320 struct list child_fonts;
321 LONG ppem;
324 typedef struct {
325 struct list entry;
326 const WCHAR *font_name;
327 struct list links;
328 } SYSTEM_LINKS;
330 #define INIT_GM_SIZE 128
332 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
333 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
334 #define UNUSED_CACHE_SIZE 10
335 static struct list child_font_list = LIST_INIT(child_font_list);
336 static struct list system_links = LIST_INIT(system_links);
338 static struct list font_subst_list = LIST_INIT(font_subst_list);
340 static struct list font_list = LIST_INIT(font_list);
342 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
343 static const WCHAR defSans[] = {'M','S',' ','S','a','n','s',' ','S','e','r','i','f','\0'};
344 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
346 static const WCHAR RegularW[] = {'R','e','g','u','l','a','r','\0'};
348 static const WCHAR fontsW[] = {'\\','F','o','n','t','s','\0'};
349 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
350 'W','i','n','d','o','w','s','\\',
351 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
352 'F','o','n','t','s','\0'};
354 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
355 'W','i','n','d','o','w','s',' ','N','T','\\',
356 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
357 'F','o','n','t','s','\0'};
359 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
360 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
361 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
362 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
364 static const WCHAR * const SystemFontValues[4] = {
365 System_Value,
366 OEMFont_Value,
367 FixedSys_Value,
368 NULL
371 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
372 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
374 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
375 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
376 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
377 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
378 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
379 'E','u','r','o','p','e','a','n','\0'};
380 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
381 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
382 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
383 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
384 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
385 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
386 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
387 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
388 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
389 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
390 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
391 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
393 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
394 WesternW, /*00*/
395 Central_EuropeanW,
396 CyrillicW,
397 GreekW,
398 TurkishW,
399 HebrewW,
400 ArabicW,
401 BalticW,
402 VietnameseW, /*08*/
403 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
404 ThaiW,
405 JapaneseW,
406 CHINESE_GB2312W,
407 HangulW,
408 CHINESE_BIG5W,
409 Hangul_Johab_W,
410 NULL, NULL, /*23*/
411 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
412 SymbolW /*31*/
415 typedef struct {
416 WCHAR *name;
417 INT charset;
418 } NameCs;
420 typedef struct tagFontSubst {
421 struct list entry;
422 NameCs from;
423 NameCs to;
424 } FontSubst;
426 struct font_mapping
428 struct list entry;
429 int refcount;
430 dev_t dev;
431 ino_t ino;
432 void *data;
433 size_t size;
436 static struct list mappings_list = LIST_INIT( mappings_list );
438 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
440 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
442 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
444 /****************************************
445 * Notes on .fon files
447 * The fonts System, FixedSys and Terminal are special. There are typically multiple
448 * versions installed for different resolutions and codepages. Windows stores which one to use
449 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
450 * Key Meaning
451 * FIXEDFON.FON FixedSys
452 * FONTS.FON System
453 * OEMFONT.FON Terminal
454 * LogPixels Current dpi set by the display control panel applet
455 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
456 * also has a LogPixels value that appears to mirror this)
458 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
459 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
460 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
461 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
462 * so that makes sense.
464 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
465 * to be mapped into the registry on Windows 2000 at least).
466 * I have
467 * woafont=app850.fon
468 * ega80woa.fon=ega80850.fon
469 * ega40woa.fon=ega40850.fon
470 * cga80woa.fon=cga80850.fon
471 * cga40woa.fon=cga40850.fon
474 #ifdef HAVE_CARBON_CARBON_H
475 static char *find_cache_dir(void)
477 FSRef ref;
478 OSErr err;
479 static char cached_path[MAX_PATH];
480 static const char *wine = "/Wine", *fonts = "/Fonts";
482 if(*cached_path) return cached_path;
484 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
485 if(err != noErr)
487 WARN("can't create cached data folder\n");
488 return NULL;
490 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
491 if(err != noErr)
493 WARN("can't create cached data path\n");
494 *cached_path = '\0';
495 return NULL;
497 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
499 ERR("Could not create full path\n");
500 *cached_path = '\0';
501 return NULL;
503 strcat(cached_path, wine);
505 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
507 WARN("Couldn't mkdir %s\n", cached_path);
508 *cached_path = '\0';
509 return NULL;
511 strcat(cached_path, fonts);
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 return cached_path;
521 /******************************************************************
522 * expand_mac_font
524 * Extracts individual TrueType font files from a Mac suitcase font
525 * and saves them into the user's caches directory (see
526 * find_cache_dir()).
527 * Returns a NULL terminated array of filenames.
529 * We do this because they are apps that try to read ttf files
530 * themselves and they don't like Mac suitcase files.
532 static char **expand_mac_font(const char *path)
534 FSRef ref;
535 SInt16 res_ref;
536 OSStatus s;
537 unsigned int idx;
538 const char *out_dir;
539 const char *filename;
540 int output_len;
541 struct {
542 char **array;
543 unsigned int size, max_size;
544 } ret;
546 TRACE("path %s\n", path);
548 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
549 if(s != noErr)
551 WARN("failed to get ref\n");
552 return NULL;
555 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
556 if(s != noErr)
558 TRACE("no data fork, so trying resource fork\n");
559 res_ref = FSOpenResFile(&ref, fsRdPerm);
560 if(res_ref == -1)
562 TRACE("unable to open resource fork\n");
563 return NULL;
567 ret.size = 0;
568 ret.max_size = 10;
569 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
570 if(!ret.array)
572 CloseResFile(res_ref);
573 return NULL;
576 out_dir = find_cache_dir();
578 filename = strrchr(path, '/');
579 if(!filename) filename = path;
580 else filename++;
582 /* output filename has the form out_dir/filename_%04x.ttf */
583 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
585 UseResFile(res_ref);
586 idx = 1;
587 while(1)
589 FamRec *fam_rec;
590 unsigned short *num_faces_ptr, num_faces, face;
591 AsscEntry *assoc;
592 Handle fond;
594 fond = Get1IndResource('FOND', idx);
595 if(!fond) break;
596 TRACE("got fond resource %d\n", idx);
597 HLock(fond);
599 fam_rec = *(FamRec**)fond;
600 num_faces_ptr = (unsigned short *)(fam_rec + 1);
601 num_faces = GET_BE_WORD(*num_faces_ptr);
602 num_faces++;
603 assoc = (AsscEntry*)(num_faces_ptr + 1);
604 TRACE("num faces %04x\n", num_faces);
605 for(face = 0; face < num_faces; face++, assoc++)
607 Handle sfnt;
608 unsigned short size, font_id;
609 char *output;
611 size = GET_BE_WORD(assoc->fontSize);
612 font_id = GET_BE_WORD(assoc->fontID);
613 if(size != 0)
615 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
616 continue;
619 TRACE("trying to load sfnt id %04x\n", font_id);
620 sfnt = GetResource('sfnt', font_id);
621 if(!sfnt)
623 TRACE("can't get sfnt resource %04x\n", font_id);
624 continue;
627 output = HeapAlloc(GetProcessHeap(), 0, output_len);
628 if(output)
630 int fd;
632 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
634 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
635 if(fd != -1 || errno == EEXIST)
637 if(fd != -1)
639 unsigned char *sfnt_data;
641 HLock(sfnt);
642 sfnt_data = *(unsigned char**)sfnt;
643 write(fd, sfnt_data, GetHandleSize(sfnt));
644 HUnlock(sfnt);
645 close(fd);
647 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
649 ret.max_size *= 2;
650 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
652 ret.array[ret.size++] = output;
654 else
656 WARN("unable to create %s\n", output);
657 HeapFree(GetProcessHeap(), 0, output);
660 ReleaseResource(sfnt);
662 HUnlock(fond);
663 ReleaseResource(fond);
664 idx++;
666 CloseResFile(res_ref);
668 return ret.array;
671 #endif /* HAVE_CARBON_CARBON_H */
673 static inline BOOL is_win9x(void)
675 return GetVersion() & 0x80000000;
678 This function builds an FT_Fixed from a float. It puts the integer part
679 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
680 It fails if the integer part of the float number is greater than SHORT_MAX.
682 static inline FT_Fixed FT_FixedFromFloat(float f)
684 short value = f;
685 unsigned short fract = (f - value) * 0xFFFF;
686 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
690 This function builds an FT_Fixed from a FIXED. It simply put f.value
691 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
693 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
695 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
699 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
701 Family *family;
702 Face *face;
703 const char *file;
704 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
705 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
707 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
708 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
710 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
712 if(face_name && strcmpiW(face_name, family->FamilyName))
713 continue;
714 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
716 file = strrchr(face->file, '/');
717 if(!file)
718 file = face->file;
719 else
720 file++;
721 if(!strcasecmp(file, file_nameA))
723 HeapFree(GetProcessHeap(), 0, file_nameA);
724 return face;
728 HeapFree(GetProcessHeap(), 0, file_nameA);
729 return NULL;
732 static Family *find_family_from_name(const WCHAR *name)
734 Family *family;
736 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
738 if(!strcmpiW(family->FamilyName, name))
739 return family;
742 return NULL;
745 static Face *find_face_from_path_index(const CHAR *file_name, const INT index)
747 Family *family;
748 Face *face;
750 TRACE("looking for file %s index %i\n", debugstr_a(file_name), index);
752 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
754 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
756 if(!strcasecmp(face->file, file_name) && face->face_index == index)
757 return face;
760 return NULL;
763 static void DumpSubstList(void)
765 FontSubst *psub;
767 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
769 if(psub->from.charset != -1 || psub->to.charset != -1)
770 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
771 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
772 else
773 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
774 debugstr_w(psub->to.name));
776 return;
779 static LPWSTR strdupW(LPCWSTR p)
781 LPWSTR ret;
782 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
783 ret = HeapAlloc(GetProcessHeap(), 0, len);
784 memcpy(ret, p, len);
785 return ret;
788 static LPSTR strdupA(LPCSTR p)
790 LPSTR ret;
791 DWORD len = (strlen(p) + 1);
792 ret = HeapAlloc(GetProcessHeap(), 0, len);
793 memcpy(ret, p, len);
794 return ret;
797 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
798 INT from_charset)
800 FontSubst *element;
802 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
804 if(!strcmpiW(element->from.name, from_name) &&
805 (element->from.charset == from_charset ||
806 element->from.charset == -1))
807 return element;
810 return NULL;
813 #define ADD_FONT_SUBST_FORCE 1
815 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
817 FontSubst *from_exist, *to_exist;
819 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
821 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
823 list_remove(&from_exist->entry);
824 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
825 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
826 HeapFree(GetProcessHeap(), 0, from_exist);
827 from_exist = NULL;
830 if(!from_exist)
832 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
834 if(to_exist)
836 HeapFree(GetProcessHeap(), 0, subst->to.name);
837 subst->to.name = strdupW(to_exist->to.name);
840 list_add_tail(subst_list, &subst->entry);
842 return TRUE;
845 HeapFree(GetProcessHeap(), 0, subst->from.name);
846 HeapFree(GetProcessHeap(), 0, subst->to.name);
847 HeapFree(GetProcessHeap(), 0, subst);
848 return FALSE;
851 static void split_subst_info(NameCs *nc, LPSTR str)
853 CHAR *p = strrchr(str, ',');
854 DWORD len;
856 nc->charset = -1;
857 if(p && *(p+1)) {
858 nc->charset = strtol(p+1, NULL, 10);
859 *p = '\0';
861 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
862 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
863 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
866 static void LoadSubstList(void)
868 FontSubst *psub;
869 HKEY hkey;
870 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
871 LPSTR value;
872 LPVOID data;
874 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
875 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
876 &hkey) == ERROR_SUCCESS) {
878 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
879 &valuelen, &datalen, NULL, NULL);
881 valuelen++; /* returned value doesn't include room for '\0' */
882 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
883 data = HeapAlloc(GetProcessHeap(), 0, datalen);
885 dlen = datalen;
886 vlen = valuelen;
887 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
888 &dlen) == ERROR_SUCCESS) {
889 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
891 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
892 split_subst_info(&psub->from, value);
893 split_subst_info(&psub->to, data);
895 /* Win 2000 doesn't allow mapping between different charsets
896 or mapping of DEFAULT_CHARSET */
897 if((psub->to.charset != psub->from.charset) ||
898 psub->to.charset == DEFAULT_CHARSET) {
899 HeapFree(GetProcessHeap(), 0, psub->to.name);
900 HeapFree(GetProcessHeap(), 0, psub->from.name);
901 HeapFree(GetProcessHeap(), 0, psub);
902 } else {
903 add_font_subst(&font_subst_list, psub, 0);
905 /* reset dlen and vlen */
906 dlen = datalen;
907 vlen = valuelen;
909 HeapFree(GetProcessHeap(), 0, data);
910 HeapFree(GetProcessHeap(), 0, value);
911 RegCloseKey(hkey);
915 static WCHAR *get_familyname(FT_Face ft_face)
917 WCHAR *family = NULL;
918 FT_SfntName name;
919 FT_UInt num_names, name_index, i;
921 if(FT_IS_SFNT(ft_face))
923 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
925 for(name_index = 0; name_index < num_names; name_index++)
927 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
929 if((name.name_id == TT_NAME_ID_FONT_FAMILY) &&
930 (name.language_id == GetUserDefaultLCID()) &&
931 (name.platform_id == TT_PLATFORM_MICROSOFT) &&
932 (name.encoding_id == TT_MS_ID_UNICODE_CS))
934 /* String is not nul terminated and string_len is a byte length. */
935 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
936 for(i = 0; i < name.string_len / 2; i++)
938 WORD *tmp = (WORD *)&name.string[i * 2];
939 family[i] = GET_BE_WORD(*tmp);
941 family[i] = 0;
943 TRACE("Got localised name %s\n", debugstr_w(family));
944 return family;
950 return NULL;
954 #define ADDFONT_EXTERNAL_FONT 0x01
955 #define ADDFONT_FORCE_BITMAP 0x02
956 static BOOL AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
958 FT_Face ft_face;
959 TT_OS2 *pOS2;
960 TT_Header *pHeader = NULL;
961 WCHAR *english_family, *localised_family, *StyleW;
962 DWORD len;
963 Family *family;
964 Face *face;
965 struct list *family_elem_ptr, *face_elem_ptr;
966 FT_Error err;
967 FT_Long face_index = 0, num_faces;
968 #ifdef HAVE_FREETYPE_FTWINFNT_H
969 FT_WinFNT_HeaderRec winfnt_header;
970 #endif
971 int i, bitmap_num, internal_leading;
972 FONTSIGNATURE fs;
974 #ifdef HAVE_CARBON_CARBON_H
975 if(!fake_family)
977 char **mac_list = expand_mac_font(file);
978 if(mac_list)
980 BOOL had_one = FALSE;
981 char **cursor;
982 for(cursor = mac_list; *cursor; cursor++)
984 had_one = TRUE;
985 AddFontFileToList(*cursor, NULL, NULL, flags);
986 HeapFree(GetProcessHeap(), 0, *cursor);
988 HeapFree(GetProcessHeap(), 0, mac_list);
989 if(had_one)
990 return TRUE;
993 #endif /* HAVE_CARBON_CARBON_H */
995 do {
996 char *family_name = fake_family;
998 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
999 if((err = pFT_New_Face(library, file, face_index, &ft_face)) != 0) {
1000 WARN("Unable to load font file %s err = %x\n", debugstr_a(file), err);
1001 return FALSE;
1004 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*/
1005 WARN("Ignoring font %s\n", debugstr_a(file));
1006 pFT_Done_Face(ft_face);
1007 return FALSE;
1010 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1011 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1012 WARN("FreeType version < 2.1.9, skipping bitmap font %s\n", debugstr_a(file));
1013 pFT_Done_Face(ft_face);
1014 return FALSE;
1017 if(FT_IS_SFNT(ft_face) && (!pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2) ||
1018 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1019 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))) {
1020 TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
1021 "Skipping this font.\n", debugstr_a(file));
1022 pFT_Done_Face(ft_face);
1023 return FALSE;
1026 if(!ft_face->family_name || !ft_face->style_name) {
1027 TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file));
1028 pFT_Done_Face(ft_face);
1029 return FALSE;
1032 if (target_family)
1034 localised_family = get_familyname(ft_face);
1035 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1037 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1038 HeapFree(GetProcessHeap(), 0, localised_family);
1039 num_faces = ft_face->num_faces;
1040 pFT_Done_Face(ft_face);
1041 continue;
1043 HeapFree(GetProcessHeap(), 0, localised_family);
1046 if(!family_name)
1047 family_name = ft_face->family_name;
1049 bitmap_num = 0;
1050 do {
1051 My_FT_Bitmap_Size *size = NULL;
1053 if(!FT_IS_SCALABLE(ft_face))
1054 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1056 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1057 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1058 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1060 localised_family = NULL;
1061 if(!fake_family) {
1062 localised_family = get_familyname(ft_face);
1063 if(localised_family && !strcmpW(localised_family, english_family)) {
1064 HeapFree(GetProcessHeap(), 0, localised_family);
1065 localised_family = NULL;
1069 family = NULL;
1070 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1071 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1072 if(!strcmpW(family->FamilyName, localised_family ? localised_family : english_family))
1073 break;
1074 family = NULL;
1076 if(!family) {
1077 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1078 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1079 list_init(&family->faces);
1080 list_add_tail(&font_list, &family->entry);
1082 if(localised_family) {
1083 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1084 subst->from.name = strdupW(english_family);
1085 subst->from.charset = -1;
1086 subst->to.name = strdupW(localised_family);
1087 subst->to.charset = -1;
1088 add_font_subst(&font_subst_list, subst, 0);
1091 HeapFree(GetProcessHeap(), 0, localised_family);
1092 HeapFree(GetProcessHeap(), 0, english_family);
1094 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1095 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1096 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1098 internal_leading = 0;
1099 memset(&fs, 0, sizeof(fs));
1101 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1102 if(pOS2) {
1103 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1104 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1105 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1106 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1107 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1108 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1109 if(pOS2->version == 0) {
1110 FT_UInt dummy;
1112 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1113 fs.fsCsb[0] |= 1;
1114 else
1115 fs.fsCsb[0] |= 1L << 31;
1118 #ifdef HAVE_FREETYPE_FTWINFNT_H
1119 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1120 CHARSETINFO csi;
1121 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1122 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1123 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1124 memcpy(&fs, &csi.fs, sizeof(csi.fs));
1125 internal_leading = winfnt_header.internal_leading;
1127 #endif
1129 face_elem_ptr = list_head(&family->faces);
1130 while(face_elem_ptr) {
1131 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1132 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1133 if(!strcmpW(face->StyleName, StyleW) &&
1134 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1135 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1136 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1137 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1139 if(fake_family) {
1140 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1141 HeapFree(GetProcessHeap(), 0, StyleW);
1142 pFT_Done_Face(ft_face);
1143 return FALSE;
1145 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1146 TRACE("Original font is newer so skipping this one\n");
1147 HeapFree(GetProcessHeap(), 0, StyleW);
1148 pFT_Done_Face(ft_face);
1149 return FALSE;
1150 } else {
1151 TRACE("Replacing original with this one\n");
1152 list_remove(&face->entry);
1153 HeapFree(GetProcessHeap(), 0, face->file);
1154 HeapFree(GetProcessHeap(), 0, face->StyleName);
1155 HeapFree(GetProcessHeap(), 0, face);
1156 break;
1160 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1161 list_add_tail(&family->faces, &face->entry);
1162 face->StyleName = StyleW;
1163 face->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
1164 strcpy(face->file, file);
1165 face->face_index = face_index;
1166 face->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
1167 face->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
1168 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1169 face->family = family;
1170 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1171 memcpy(&face->fs, &fs, sizeof(face->fs));
1172 memset(&face->fs_links, 0, sizeof(face->fs_links));
1174 if(FT_IS_SCALABLE(ft_face)) {
1175 memset(&face->size, 0, sizeof(face->size));
1176 face->scalable = TRUE;
1177 } else {
1178 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1179 size->height, size->width, size->size >> 6,
1180 size->x_ppem >> 6, size->y_ppem >> 6);
1181 face->size.height = size->height;
1182 face->size.width = size->width;
1183 face->size.size = size->size;
1184 face->size.x_ppem = size->x_ppem;
1185 face->size.y_ppem = size->y_ppem;
1186 face->size.internal_leading = internal_leading;
1187 face->scalable = FALSE;
1190 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1191 face->fs.fsCsb[0], face->fs.fsCsb[1],
1192 face->fs.fsUsb[0], face->fs.fsUsb[1],
1193 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1196 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1197 for(i = 0; i < ft_face->num_charmaps; i++) {
1198 switch(ft_face->charmaps[i]->encoding) {
1199 case FT_ENCODING_UNICODE:
1200 case FT_ENCODING_APPLE_ROMAN:
1201 face->fs.fsCsb[0] |= 1;
1202 break;
1203 case FT_ENCODING_MS_SYMBOL:
1204 face->fs.fsCsb[0] |= 1L << 31;
1205 break;
1206 default:
1207 break;
1212 if(face->fs.fsCsb[0] & ~(1L << 31))
1213 have_installed_roman_font = TRUE;
1214 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1216 num_faces = ft_face->num_faces;
1217 pFT_Done_Face(ft_face);
1218 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1219 debugstr_w(StyleW));
1220 } while(num_faces > ++face_index);
1221 return TRUE;
1224 static void DumpFontList(void)
1226 Family *family;
1227 Face *face;
1228 struct list *family_elem_ptr, *face_elem_ptr;
1230 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1231 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1232 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1233 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1234 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1235 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1236 if(!face->scalable)
1237 TRACE(" %d", face->size.height);
1238 TRACE("\n");
1241 return;
1244 /***********************************************************
1245 * The replacement list is a way to map an entire font
1246 * family onto another family. For example adding
1248 * [HKCU\Software\Wine\Fonts\Replacements]
1249 * "Wingdings"="Winedings"
1251 * would enumerate the Winedings font both as Winedings and
1252 * Wingdings. However if a real Wingdings font is present the
1253 * replacement does not take place.
1256 static void LoadReplaceList(void)
1258 HKEY hkey;
1259 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1260 LPWSTR value;
1261 LPVOID data;
1262 Family *family;
1263 Face *face;
1264 struct list *family_elem_ptr, *face_elem_ptr;
1265 CHAR familyA[400];
1267 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1268 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1270 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1271 &valuelen, &datalen, NULL, NULL);
1273 valuelen++; /* returned value doesn't include room for '\0' */
1274 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1275 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1277 dlen = datalen;
1278 vlen = valuelen;
1279 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1280 &dlen) == ERROR_SUCCESS) {
1281 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1282 /* "NewName"="Oldname" */
1283 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1285 /* Find the old family and hence all of the font files
1286 in that family */
1287 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1288 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1289 if(!strcmpiW(family->FamilyName, data)) {
1290 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1291 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1292 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1293 debugstr_w(face->StyleName), familyA);
1294 /* Now add a new entry with the new family name */
1295 AddFontFileToList(face->file, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1297 break;
1300 /* reset dlen and vlen */
1301 dlen = datalen;
1302 vlen = valuelen;
1304 HeapFree(GetProcessHeap(), 0, data);
1305 HeapFree(GetProcessHeap(), 0, value);
1306 RegCloseKey(hkey);
1310 /*************************************************************
1311 * init_system_links
1313 static BOOL init_system_links(void)
1315 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1316 'W','i','n','d','o','w','s',' ','N','T','\\',
1317 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1318 'S','y','s','t','e','m','L','i','n','k',0};
1319 HKEY hkey;
1320 BOOL ret = FALSE;
1321 DWORD type, max_val, max_data, val_len, data_len, index;
1322 WCHAR *value, *data;
1323 WCHAR *entry, *next;
1324 SYSTEM_LINKS *font_link, *system_font_link;
1325 CHILD_FONT *child_font;
1326 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
1327 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1328 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1329 FONTSIGNATURE fs;
1330 Family *family;
1331 Face *face;
1332 FontSubst *psub;
1334 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1336 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1337 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1338 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1339 val_len = max_val + 1;
1340 data_len = max_data;
1341 index = 0;
1342 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1344 TRACE("%s:\n", debugstr_w(value));
1346 memset(&fs, 0, sizeof(fs));
1347 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1348 psub = get_font_subst(&font_subst_list, value, -1);
1349 font_link->font_name = (psub)? strdupW(psub->to.name) : strdupW(value);
1350 list_init(&font_link->links);
1351 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1353 WCHAR *face_name;
1354 CHILD_FONT *child_font;
1356 TRACE("\t%s\n", debugstr_w(entry));
1358 next = entry + strlenW(entry) + 1;
1360 face_name = strchrW(entry, ',');
1361 if(face_name)
1363 *face_name++ = 0;
1364 while(isspaceW(*face_name))
1365 face_name++;
1367 psub = get_font_subst(&font_subst_list, face_name, -1);
1368 if(psub)
1369 face_name = psub->to.name;
1371 face = find_face_from_filename(entry, face_name);
1372 if(!face)
1374 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1375 continue;
1378 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1379 child_font->file_name = strdupA(face->file);
1380 child_font->index = face->face_index;
1381 child_font->font = NULL;
1382 fs.fsCsb[0] |= face->fs.fsCsb[0];
1383 fs.fsCsb[1] |= face->fs.fsCsb[1];
1384 TRACE("Adding file %s index %d\n", child_font->file_name, child_font->index);
1385 list_add_tail(&font_link->links, &child_font->entry);
1387 family = find_family_from_name(font_link->font_name);
1388 if(family)
1390 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1392 memcpy(&face->fs_links, &fs, sizeof(fs));
1395 list_add_tail(&system_links, &font_link->entry);
1396 val_len = max_val + 1;
1397 data_len = max_data;
1400 HeapFree(GetProcessHeap(), 0, value);
1401 HeapFree(GetProcessHeap(), 0, data);
1402 RegCloseKey(hkey);
1405 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1406 that Tahoma has */
1408 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1409 system_font_link->font_name = strdupW(System);
1410 list_init(&system_font_link->links);
1412 face = find_face_from_filename(tahoma_ttf, Tahoma);
1413 if(face)
1415 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1416 child_font->file_name = strdupA(face->file);
1417 child_font->index = face->face_index;
1418 child_font->font = NULL;
1419 TRACE("Found Tahoma in %s index %d\n", child_font->file_name, child_font->index);
1420 list_add_tail(&system_font_link->links, &child_font->entry);
1422 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1424 if(!strcmpiW(font_link->font_name, Tahoma))
1426 CHILD_FONT *font_link_entry;
1427 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1429 CHILD_FONT *new_child;
1430 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1431 new_child->file_name = strdupA(font_link_entry->file_name);
1432 new_child->index = font_link_entry->index;
1433 new_child->font = NULL;
1434 list_add_tail(&system_font_link->links, &new_child->entry);
1436 break;
1439 list_add_tail(&system_links, &system_font_link->entry);
1440 return ret;
1443 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1445 DIR *dir;
1446 struct dirent *dent;
1447 char path[MAX_PATH];
1449 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1451 dir = opendir(dirname);
1452 if(!dir) {
1453 WARN("Can't open directory %s\n", debugstr_a(dirname));
1454 return FALSE;
1456 while((dent = readdir(dir)) != NULL) {
1457 struct stat statbuf;
1459 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1460 continue;
1462 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1464 sprintf(path, "%s/%s", dirname, dent->d_name);
1466 if(stat(path, &statbuf) == -1)
1468 WARN("Can't stat %s\n", debugstr_a(path));
1469 continue;
1471 if(S_ISDIR(statbuf.st_mode))
1472 ReadFontDir(path, external_fonts);
1473 else
1474 AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1476 closedir(dir);
1477 return TRUE;
1480 static void load_fontconfig_fonts(void)
1482 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
1483 void *fc_handle = NULL;
1484 FcConfig *config;
1485 FcPattern *pat;
1486 FcObjectSet *os;
1487 FcFontSet *fontset;
1488 int i, len;
1489 char *file;
1490 const char *ext;
1492 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1493 if(!fc_handle) {
1494 TRACE("Wine cannot find the fontconfig library (%s).\n",
1495 SONAME_LIBFONTCONFIG);
1496 return;
1498 #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;}
1499 LOAD_FUNCPTR(FcConfigGetCurrent);
1500 LOAD_FUNCPTR(FcFontList);
1501 LOAD_FUNCPTR(FcFontSetDestroy);
1502 LOAD_FUNCPTR(FcInit);
1503 LOAD_FUNCPTR(FcObjectSetAdd);
1504 LOAD_FUNCPTR(FcObjectSetCreate);
1505 LOAD_FUNCPTR(FcObjectSetDestroy);
1506 LOAD_FUNCPTR(FcPatternCreate);
1507 LOAD_FUNCPTR(FcPatternDestroy);
1508 LOAD_FUNCPTR(FcPatternGetBool);
1509 LOAD_FUNCPTR(FcPatternGetString);
1510 #undef LOAD_FUNCPTR
1512 if(!pFcInit()) return;
1514 config = pFcConfigGetCurrent();
1515 pat = pFcPatternCreate();
1516 os = pFcObjectSetCreate();
1517 pFcObjectSetAdd(os, FC_FILE);
1518 pFcObjectSetAdd(os, FC_SCALABLE);
1519 fontset = pFcFontList(config, pat, os);
1520 if(!fontset) return;
1521 for(i = 0; i < fontset->nfont; i++) {
1522 FcBool scalable;
1524 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1525 continue;
1526 TRACE("fontconfig: %s\n", file);
1528 /* We're just interested in OT/TT fonts for now, so this hack just
1529 picks up the scalable fonts without extensions .pf[ab] to save time
1530 loading every other font */
1532 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1534 TRACE("not scalable\n");
1535 continue;
1538 len = strlen( file );
1539 if(len < 4) continue;
1540 ext = &file[ len - 3 ];
1541 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1542 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT);
1544 pFcFontSetDestroy(fontset);
1545 pFcObjectSetDestroy(os);
1546 pFcPatternDestroy(pat);
1547 sym_not_found:
1548 #endif
1549 return;
1552 static BOOL load_font_from_data_dir(LPCWSTR file)
1554 BOOL ret = FALSE;
1555 const char *data_dir = wine_get_data_dir();
1557 if (!data_dir) data_dir = wine_get_build_dir();
1559 if (data_dir)
1561 INT len;
1562 char *unix_name;
1564 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1566 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1568 strcpy(unix_name, data_dir);
1569 strcat(unix_name, "/fonts/");
1571 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1573 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1574 HeapFree(GetProcessHeap(), 0, unix_name);
1576 return ret;
1579 static void load_system_fonts(void)
1581 HKEY hkey;
1582 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1583 const WCHAR * const *value;
1584 DWORD dlen, type;
1585 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1586 char *unixname;
1588 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1589 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1590 strcatW(windowsdir, fontsW);
1591 for(value = SystemFontValues; *value; value++) {
1592 dlen = sizeof(data);
1593 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1594 type == REG_SZ) {
1595 BOOL added = FALSE;
1597 sprintfW(pathW, fmtW, windowsdir, data);
1598 if((unixname = wine_get_unix_file_name(pathW))) {
1599 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1600 HeapFree(GetProcessHeap(), 0, unixname);
1602 if (!added)
1603 load_font_from_data_dir(data);
1606 RegCloseKey(hkey);
1610 /*************************************************************
1612 * This adds registry entries for any externally loaded fonts
1613 * (fonts from fontconfig or FontDirs). It also deletes entries
1614 * of no longer existing fonts.
1617 static void update_reg_entries(void)
1619 HKEY winkey = 0, externalkey = 0;
1620 LPWSTR valueW;
1621 LPVOID data;
1622 DWORD dlen, vlen, datalen, valuelen, i, type, len, len_fam;
1623 Family *family;
1624 Face *face;
1625 struct list *family_elem_ptr, *face_elem_ptr;
1626 WCHAR *file;
1627 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1628 static const WCHAR spaceW[] = {' ', '\0'};
1629 char *path;
1631 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1632 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winkey, NULL) != ERROR_SUCCESS) {
1633 ERR("Can't create Windows font reg key\n");
1634 goto end;
1636 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1637 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &externalkey) != ERROR_SUCCESS) {
1638 ERR("Can't create external font reg key\n");
1639 goto end;
1642 /* Delete all external fonts added last time */
1644 RegQueryInfoKeyW(externalkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1645 &valuelen, &datalen, NULL, NULL);
1646 valuelen++; /* returned value doesn't include room for '\0' */
1647 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1648 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1650 dlen = datalen * sizeof(WCHAR);
1651 vlen = valuelen;
1652 i = 0;
1653 while(RegEnumValueW(externalkey, i++, valueW, &vlen, NULL, &type, data,
1654 &dlen) == ERROR_SUCCESS) {
1656 RegDeleteValueW(winkey, valueW);
1657 /* reset dlen and vlen */
1658 dlen = datalen;
1659 vlen = valuelen;
1661 HeapFree(GetProcessHeap(), 0, data);
1662 HeapFree(GetProcessHeap(), 0, valueW);
1664 /* Delete the old external fonts key */
1665 RegCloseKey(externalkey);
1666 externalkey = 0;
1667 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
1669 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1670 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1671 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
1672 ERR("Can't create external font reg key\n");
1673 goto end;
1676 /* enumerate the fonts and add external ones to the two keys */
1678 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1679 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1680 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1681 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1682 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1683 if(!face->external) continue;
1684 len = len_fam;
1685 if(strcmpiW(face->StyleName, RegularW))
1686 len = len_fam + strlenW(face->StyleName) + 1;
1687 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1688 strcpyW(valueW, family->FamilyName);
1689 if(len != len_fam) {
1690 strcatW(valueW, spaceW);
1691 strcatW(valueW, face->StyleName);
1693 strcatW(valueW, TrueType);
1694 if((path = strrchr(face->file, '/')) == NULL)
1695 path = face->file;
1696 else
1697 path++;
1698 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1700 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1701 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1702 RegSetValueExW(winkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1703 RegSetValueExW(externalkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1705 HeapFree(GetProcessHeap(), 0, file);
1706 HeapFree(GetProcessHeap(), 0, valueW);
1709 end:
1710 if(externalkey)
1711 RegCloseKey(externalkey);
1712 if(winkey)
1713 RegCloseKey(winkey);
1714 return;
1718 /*************************************************************
1719 * WineEngAddFontResourceEx
1722 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1724 if (ft_handle) /* do it only if we have freetype up and running */
1726 char *unixname;
1728 if(flags)
1729 FIXME("Ignoring flags %x\n", flags);
1731 if((unixname = wine_get_unix_file_name(file)))
1733 INT ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1734 HeapFree(GetProcessHeap(), 0, unixname);
1735 return ret;
1738 return 0;
1741 /*************************************************************
1742 * WineEngRemoveFontResourceEx
1745 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1747 FIXME(":stub\n");
1748 return TRUE;
1751 static const struct nls_update_font_list
1753 UINT ansi_cp, oem_cp;
1754 const char *oem, *fixed, *system;
1755 const char *courier, *serif, *small, *sserif;
1756 /* these are for font substitute */
1757 const char *shelldlg, *tmsrmn;
1758 } nls_update_font_list[] =
1760 /* Latin 1 (United States) */
1761 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
1762 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1763 "Tahoma","Times New Roman",
1765 /* Latin 1 (Multilingual) */
1766 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
1767 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1768 "Tahoma","Times New Roman", /* FIXME unverified */
1770 /* Eastern Europe */
1771 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
1772 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
1773 "Tahoma","Times New Roman", /* FIXME unverified */
1775 /* Cyrillic */
1776 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
1777 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
1778 "Tahoma","Times New Roman", /* FIXME unverified */
1780 /* Greek */
1781 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
1782 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
1783 "Tahoma","Times New Roman", /* FIXME unverified */
1785 /* Turkish */
1786 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
1787 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
1788 "Tahoma","Times New Roman", /* FIXME unverified */
1790 /* Hebrew */
1791 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
1792 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
1793 "Tahoma","Times New Roman", /* FIXME unverified */
1795 /* Arabic */
1796 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
1797 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
1798 "Tahoma","Times New Roman", /* FIXME unverified */
1800 /* Baltic */
1801 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
1802 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
1803 "Tahoma","Times New Roman", /* FIXME unverified */
1805 /* Vietnamese */
1806 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
1807 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1808 "Tahoma","Times New Roman", /* FIXME unverified */
1810 /* Thai */
1811 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
1812 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
1813 "Tahoma","Times New Roman", /* FIXME unverified */
1815 /* Japanese */
1816 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
1817 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
1818 "MS UI Gothic","MS Serif",
1820 /* Chinese Simplified */
1821 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
1822 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1823 "Tahoma", "Times New Roman", /* FIXME unverified */
1825 /* Korean */
1826 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
1827 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1828 "Gulim", "Batang",
1830 /* Chinese Traditional */
1831 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
1832 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1833 "Tahoma", "Times New Roman", /* FIXME unverified */
1837 static inline HKEY create_fonts_NT_registry_key(void)
1839 HKEY hkey = 0;
1841 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
1842 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1843 return hkey;
1846 static inline HKEY create_fonts_9x_registry_key(void)
1848 HKEY hkey = 0;
1850 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
1851 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1852 return hkey;
1855 static inline HKEY create_config_fonts_registry_key(void)
1857 HKEY hkey = 0;
1859 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
1860 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1861 return hkey;
1864 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
1866 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
1867 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
1868 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
1869 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
1872 static void update_font_info(void)
1874 char buf[40], cpbuf[40];
1875 DWORD len, type;
1876 HKEY hkey = 0;
1877 UINT i, ansi_cp = 0, oem_cp = 0;
1879 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
1880 return;
1882 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
1883 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
1884 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
1885 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
1886 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
1888 len = sizeof(buf);
1889 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
1891 if (!strcmp( buf, cpbuf )) /* already set correctly */
1893 RegCloseKey(hkey);
1894 return;
1896 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
1898 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
1900 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
1901 RegCloseKey(hkey);
1903 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
1905 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
1906 nls_update_font_list[i].oem_cp == oem_cp)
1908 HKEY hkey;
1910 hkey = create_config_fonts_registry_key();
1911 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
1912 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
1913 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
1914 RegCloseKey(hkey);
1916 hkey = create_fonts_NT_registry_key();
1917 add_font_list(hkey, &nls_update_font_list[i]);
1918 RegCloseKey(hkey);
1920 hkey = create_fonts_9x_registry_key();
1921 add_font_list(hkey, &nls_update_font_list[i]);
1922 RegCloseKey(hkey);
1924 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
1926 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
1927 strlen(nls_update_font_list[i].shelldlg)+1);
1928 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
1929 strlen(nls_update_font_list[i].tmsrmn)+1);
1930 RegCloseKey(hkey);
1932 return;
1935 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
1938 /*************************************************************
1939 * WineEngInit
1941 * Initialize FreeType library and create a list of available faces
1943 BOOL WineEngInit(void)
1945 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
1946 static const WCHAR pathW[] = {'P','a','t','h',0};
1947 HKEY hkey;
1948 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1949 LPVOID data;
1950 WCHAR windowsdir[MAX_PATH];
1951 char *unixname;
1952 HANDLE font_mutex;
1953 const char *data_dir;
1955 TRACE("\n");
1957 /* update locale dependent font info in registry */
1958 update_font_info();
1960 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
1961 if(!ft_handle) {
1962 WINE_MESSAGE(
1963 "Wine cannot find the FreeType font library. To enable Wine to\n"
1964 "use TrueType fonts please install a version of FreeType greater than\n"
1965 "or equal to 2.0.5.\n"
1966 "http://www.freetype.org\n");
1967 return FALSE;
1970 #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;}
1972 LOAD_FUNCPTR(FT_Vector_Unit)
1973 LOAD_FUNCPTR(FT_Done_Face)
1974 LOAD_FUNCPTR(FT_Get_Char_Index)
1975 LOAD_FUNCPTR(FT_Get_Module)
1976 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
1977 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
1978 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
1979 LOAD_FUNCPTR(FT_Init_FreeType)
1980 LOAD_FUNCPTR(FT_Load_Glyph)
1981 LOAD_FUNCPTR(FT_Matrix_Multiply)
1982 LOAD_FUNCPTR(FT_MulFix)
1983 LOAD_FUNCPTR(FT_New_Face)
1984 LOAD_FUNCPTR(FT_New_Memory_Face)
1985 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
1986 LOAD_FUNCPTR(FT_Outline_Transform)
1987 LOAD_FUNCPTR(FT_Outline_Translate)
1988 LOAD_FUNCPTR(FT_Select_Charmap)
1989 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
1990 LOAD_FUNCPTR(FT_Vector_Transform)
1992 #undef LOAD_FUNCPTR
1993 /* Don't warn if this one is missing */
1994 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
1995 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
1996 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
1997 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
1998 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
1999 #ifdef HAVE_FREETYPE_FTWINFNT_H
2000 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
2001 #endif
2002 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2003 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2004 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2005 <= 2.0.3 has FT_Sqrt64 */
2006 goto sym_not_found;
2009 if(pFT_Init_FreeType(&library) != 0) {
2010 ERR("Can't init FreeType library\n");
2011 wine_dlclose(ft_handle, NULL, 0);
2012 ft_handle = NULL;
2013 return FALSE;
2015 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
2016 if (pFT_Library_Version)
2018 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2020 if (FT_Version.major<=0)
2022 FT_Version.major=2;
2023 FT_Version.minor=0;
2024 FT_Version.patch=5;
2026 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2027 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2028 ((FT_Version.minor << 8) & 0x00ff00) |
2029 ((FT_Version.patch ) & 0x0000ff);
2031 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2032 ERR("Failed to create font mutex\n");
2033 return FALSE;
2035 WaitForSingleObject(font_mutex, INFINITE);
2037 /* load the system bitmap fonts */
2038 load_system_fonts();
2040 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2041 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2042 strcatW(windowsdir, fontsW);
2043 if((unixname = wine_get_unix_file_name(windowsdir)))
2045 ReadFontDir(unixname, FALSE);
2046 HeapFree(GetProcessHeap(), 0, unixname);
2049 /* load the system truetype fonts */
2050 data_dir = wine_get_data_dir();
2051 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2052 strcpy(unixname, data_dir);
2053 strcat(unixname, "/fonts/");
2054 ReadFontDir(unixname, FALSE);
2055 HeapFree(GetProcessHeap(), 0, unixname);
2058 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2059 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2060 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2061 will skip these. */
2062 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2063 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2064 &hkey) == ERROR_SUCCESS) {
2065 LPWSTR valueW;
2066 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2067 &valuelen, &datalen, NULL, NULL);
2069 valuelen++; /* returned value doesn't include room for '\0' */
2070 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2071 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2072 if (valueW && data)
2074 dlen = datalen * sizeof(WCHAR);
2075 vlen = valuelen;
2076 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
2077 &dlen) == ERROR_SUCCESS) {
2078 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
2080 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
2082 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2083 HeapFree(GetProcessHeap(), 0, unixname);
2086 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
2088 WCHAR pathW[MAX_PATH];
2089 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2090 BOOL added = FALSE;
2092 sprintfW(pathW, fmtW, windowsdir, data);
2093 if((unixname = wine_get_unix_file_name(pathW)))
2095 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2096 HeapFree(GetProcessHeap(), 0, unixname);
2098 if (!added)
2099 load_font_from_data_dir(data);
2101 /* reset dlen and vlen */
2102 dlen = datalen;
2103 vlen = valuelen;
2106 HeapFree(GetProcessHeap(), 0, data);
2107 HeapFree(GetProcessHeap(), 0, valueW);
2108 RegCloseKey(hkey);
2111 load_fontconfig_fonts();
2113 /* then look in any directories that we've specified in the config file */
2114 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2115 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2117 DWORD len;
2118 LPWSTR valueW;
2119 LPSTR valueA, ptr;
2121 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2123 len += sizeof(WCHAR);
2124 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2125 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2127 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2128 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2129 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2130 TRACE( "got font path %s\n", debugstr_a(valueA) );
2131 ptr = valueA;
2132 while (ptr)
2134 LPSTR next = strchr( ptr, ':' );
2135 if (next) *next++ = 0;
2136 ReadFontDir( ptr, TRUE );
2137 ptr = next;
2139 HeapFree( GetProcessHeap(), 0, valueA );
2141 HeapFree( GetProcessHeap(), 0, valueW );
2143 RegCloseKey(hkey);
2146 DumpFontList();
2147 LoadSubstList();
2148 DumpSubstList();
2149 LoadReplaceList();
2150 update_reg_entries();
2152 init_system_links();
2154 ReleaseMutex(font_mutex);
2155 return TRUE;
2156 sym_not_found:
2157 WINE_MESSAGE(
2158 "Wine cannot find certain functions that it needs inside the FreeType\n"
2159 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2160 "FreeType to at least version 2.0.5.\n"
2161 "http://www.freetype.org\n");
2162 wine_dlclose(ft_handle, NULL, 0);
2163 ft_handle = NULL;
2164 return FALSE;
2168 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2170 TT_OS2 *pOS2;
2171 TT_HoriHeader *pHori;
2173 LONG ppem;
2175 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2176 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2178 if(height == 0) height = 16;
2180 /* Calc. height of EM square:
2182 * For +ve lfHeight we have
2183 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2184 * Re-arranging gives:
2185 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2187 * For -ve lfHeight we have
2188 * |lfHeight| = ppem
2189 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2190 * with il = winAscent + winDescent - units_per_em]
2194 if(height > 0) {
2195 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2196 ppem = ft_face->units_per_EM * height /
2197 (pHori->Ascender - pHori->Descender);
2198 else
2199 ppem = ft_face->units_per_EM * height /
2200 (pOS2->usWinAscent + pOS2->usWinDescent);
2202 else
2203 ppem = -height;
2205 return ppem;
2208 static struct font_mapping *map_font( const char *name )
2210 struct font_mapping *mapping;
2211 struct stat st;
2212 int fd;
2214 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2215 if (fstat( fd, &st ) == -1) goto error;
2217 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2219 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2221 mapping->refcount++;
2222 close( fd );
2223 return mapping;
2226 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2227 goto error;
2229 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2230 close( fd );
2232 if (mapping->data == MAP_FAILED)
2234 HeapFree( GetProcessHeap(), 0, mapping );
2235 return NULL;
2237 mapping->refcount = 1;
2238 mapping->dev = st.st_dev;
2239 mapping->ino = st.st_ino;
2240 mapping->size = st.st_size;
2241 list_add_tail( &mappings_list, &mapping->entry );
2242 return mapping;
2244 error:
2245 close( fd );
2246 return NULL;
2249 static void unmap_font( struct font_mapping *mapping )
2251 if (!--mapping->refcount)
2253 list_remove( &mapping->entry );
2254 munmap( mapping->data, mapping->size );
2255 HeapFree( GetProcessHeap(), 0, mapping );
2259 static LONG load_VDMX(GdiFont*, LONG);
2261 static FT_Face OpenFontFile(GdiFont *font, char *file, FT_Long face_index, LONG width, LONG height)
2263 FT_Error err;
2264 FT_Face ft_face;
2266 TRACE("%s, %ld, %d x %d\n", debugstr_a(file), face_index, width, height);
2268 if (!(font->mapping = map_font( file )))
2270 WARN("failed to map %s\n", debugstr_a(file));
2271 return 0;
2274 err = pFT_New_Memory_Face(library, font->mapping->data, font->mapping->size, face_index, &ft_face);
2275 if(err) {
2276 ERR("FT_New_Face rets %d\n", err);
2277 return 0;
2280 /* set it here, as load_VDMX needs it */
2281 font->ft_face = ft_face;
2283 if(FT_IS_SCALABLE(ft_face)) {
2284 /* load the VDMX table if we have one */
2285 font->ppem = load_VDMX(font, height);
2286 if(font->ppem == 0)
2287 font->ppem = calc_ppem_for_height(ft_face, height);
2289 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
2290 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
2291 } else {
2292 font->ppem = height;
2293 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
2294 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
2296 return ft_face;
2300 static int get_nearest_charset(Face *face, int *cp)
2302 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2303 a single face with the requested charset. The idea is to check if
2304 the selected font supports the current ANSI codepage, if it does
2305 return the corresponding charset, else return the first charset */
2307 CHARSETINFO csi;
2308 int acp = GetACP(), i;
2309 DWORD fs0;
2311 *cp = acp;
2312 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
2313 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2314 return csi.ciCharset;
2316 for(i = 0; i < 32; i++) {
2317 fs0 = 1L << i;
2318 if(face->fs.fsCsb[0] & fs0) {
2319 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
2320 *cp = csi.ciACP;
2321 return csi.ciCharset;
2323 else
2324 FIXME("TCI failing on %x\n", fs0);
2328 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2329 face->fs.fsCsb[0], face->file);
2330 *cp = acp;
2331 return DEFAULT_CHARSET;
2334 static GdiFont *alloc_font(void)
2336 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
2337 ret->gmsize = INIT_GM_SIZE;
2338 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2339 ret->gmsize * sizeof(*ret->gm));
2340 ret->potm = NULL;
2341 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
2342 ret->total_kern_pairs = (DWORD)-1;
2343 ret->kern_pairs = NULL;
2344 list_init(&ret->hfontlist);
2345 list_init(&ret->child_fonts);
2346 return ret;
2349 static void free_font(GdiFont *font)
2351 struct list *cursor, *cursor2;
2353 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
2355 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
2356 struct list *first_hfont;
2357 HFONTLIST *hfontlist;
2358 list_remove(cursor);
2359 if(child->font)
2361 first_hfont = list_head(&child->font->hfontlist);
2362 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2363 DeleteObject(hfontlist->hfont);
2364 HeapFree(GetProcessHeap(), 0, hfontlist);
2365 free_font(child->font);
2367 HeapFree(GetProcessHeap(), 0, child->file_name);
2368 HeapFree(GetProcessHeap(), 0, child);
2371 if (font->ft_face) pFT_Done_Face(font->ft_face);
2372 if (font->mapping) unmap_font( font->mapping );
2373 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
2374 HeapFree(GetProcessHeap(), 0, font->potm);
2375 HeapFree(GetProcessHeap(), 0, font->name);
2376 HeapFree(GetProcessHeap(), 0, font->gm);
2377 HeapFree(GetProcessHeap(), 0, font);
2381 /*************************************************************
2382 * load_VDMX
2384 * load the vdmx entry for the specified height
2387 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2388 ( ( (FT_ULong)_x4 << 24 ) | \
2389 ( (FT_ULong)_x3 << 16 ) | \
2390 ( (FT_ULong)_x2 << 8 ) | \
2391 (FT_ULong)_x1 )
2393 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2395 typedef struct {
2396 BYTE bCharSet;
2397 BYTE xRatio;
2398 BYTE yStartRatio;
2399 BYTE yEndRatio;
2400 } Ratios;
2402 typedef struct {
2403 WORD recs;
2404 BYTE startsz;
2405 BYTE endsz;
2406 } VDMX_group;
2408 static LONG load_VDMX(GdiFont *font, LONG height)
2410 WORD hdr[3], tmp;
2411 VDMX_group group;
2412 BYTE devXRatio, devYRatio;
2413 USHORT numRecs, numRatios;
2414 DWORD result, offset = -1;
2415 LONG ppem = 0;
2416 int i;
2418 /* For documentation on VDMX records, see
2419 * http://www.microsoft.com/OpenType/OTSpec/vdmx.htm
2422 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
2424 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2425 return ppem;
2427 /* FIXME: need the real device aspect ratio */
2428 devXRatio = 1;
2429 devYRatio = 1;
2431 numRecs = GET_BE_WORD(hdr[1]);
2432 numRatios = GET_BE_WORD(hdr[2]);
2434 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
2435 for(i = 0; i < numRatios; i++) {
2436 Ratios ratio;
2438 offset = (3 * 2) + (i * sizeof(Ratios));
2439 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2440 offset = -1;
2442 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2444 if((ratio.xRatio == 0 &&
2445 ratio.yStartRatio == 0 &&
2446 ratio.yEndRatio == 0) ||
2447 (devXRatio == ratio.xRatio &&
2448 devYRatio >= ratio.yStartRatio &&
2449 devYRatio <= ratio.yEndRatio))
2451 offset = (3 * 2) + (numRatios * 4) + (i * 2);
2452 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
2453 offset = GET_BE_WORD(tmp);
2454 break;
2458 if(offset == -1) {
2459 FIXME("No suitable ratio found\n");
2460 return ppem;
2463 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
2464 USHORT recs;
2465 BYTE startsz, endsz;
2466 WORD *vTable;
2468 recs = GET_BE_WORD(group.recs);
2469 startsz = group.startsz;
2470 endsz = group.endsz;
2472 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
2474 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
2475 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
2476 if(result == GDI_ERROR) {
2477 FIXME("Failed to retrieve vTable\n");
2478 goto end;
2481 if(height > 0) {
2482 for(i = 0; i < recs; i++) {
2483 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2484 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2485 ppem = GET_BE_WORD(vTable[i * 3]);
2487 if(yMax + -yMin == height) {
2488 font->yMax = yMax;
2489 font->yMin = yMin;
2490 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2491 break;
2493 if(yMax + -yMin > height) {
2494 if(--i < 0) {
2495 ppem = 0;
2496 goto end; /* failed */
2498 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2499 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2500 ppem = GET_BE_WORD(vTable[i * 3]);
2501 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2502 break;
2505 if(!font->yMax) {
2506 ppem = 0;
2507 TRACE("ppem not found for height %d\n", height);
2509 } else {
2510 ppem = -height;
2511 if(ppem < startsz || ppem > endsz)
2512 goto end;
2514 for(i = 0; i < recs; i++) {
2515 USHORT yPelHeight;
2516 yPelHeight = GET_BE_WORD(vTable[i * 3]);
2518 if(yPelHeight > ppem)
2519 break; /* failed */
2521 if(yPelHeight == ppem) {
2522 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2523 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2524 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
2525 break;
2529 end:
2530 HeapFree(GetProcessHeap(), 0, vTable);
2533 return ppem;
2536 static BOOL fontcmp(GdiFont *font, FONT_DESC *fd)
2538 if(font->font_desc.hash != fd->hash) return TRUE;
2539 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
2540 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
2541 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
2542 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
2545 static void calc_hash(FONT_DESC *pfd)
2547 DWORD hash = 0, *ptr, two_chars;
2548 WORD *pwc;
2549 unsigned int i;
2551 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
2552 hash ^= *ptr;
2553 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
2554 hash ^= *ptr;
2555 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
2556 two_chars = *ptr;
2557 pwc = (WCHAR *)&two_chars;
2558 if(!*pwc) break;
2559 *pwc = toupperW(*pwc);
2560 pwc++;
2561 *pwc = toupperW(*pwc);
2562 hash ^= two_chars;
2563 if(!*pwc) break;
2565 hash ^= !pfd->can_use_bitmap;
2566 pfd->hash = hash;
2567 return;
2570 static GdiFont *find_in_cache(HFONT hfont, LOGFONTW *plf, XFORM *pxf, BOOL can_use_bitmap)
2572 GdiFont *ret;
2573 FONT_DESC fd;
2574 HFONTLIST *hflist;
2575 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2577 memcpy(&fd.lf, plf, sizeof(LOGFONTW));
2578 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
2579 fd.can_use_bitmap = can_use_bitmap;
2580 calc_hash(&fd);
2582 /* try the in-use list */
2583 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
2584 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2585 if(!fontcmp(ret, &fd)) {
2586 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2587 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
2588 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2589 if(hflist->hfont == hfont)
2590 return ret;
2592 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2593 hflist->hfont = hfont;
2594 list_add_head(&ret->hfontlist, &hflist->entry);
2595 return ret;
2599 /* then the unused list */
2600 font_elem_ptr = list_head(&unused_gdi_font_list);
2601 while(font_elem_ptr) {
2602 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2603 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2604 if(!fontcmp(ret, &fd)) {
2605 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2606 assert(list_empty(&ret->hfontlist));
2607 TRACE("Found %p in unused list\n", ret);
2608 list_remove(&ret->entry);
2609 list_add_head(&gdi_font_list, &ret->entry);
2610 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2611 hflist->hfont = hfont;
2612 list_add_head(&ret->hfontlist, &hflist->entry);
2613 return ret;
2616 return NULL;
2620 /*************************************************************
2621 * create_child_font_list
2623 static BOOL create_child_font_list(GdiFont *font)
2625 BOOL ret = FALSE;
2626 SYSTEM_LINKS *font_link;
2627 CHILD_FONT *font_link_entry, *new_child;
2629 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2631 if(!strcmpW(font_link->font_name, font->name))
2633 TRACE("found entry in system list\n");
2634 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2636 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2637 new_child->file_name = strdupA(font_link_entry->file_name);
2638 new_child->index = font_link_entry->index;
2639 new_child->font = NULL;
2640 list_add_tail(&font->child_fonts, &new_child->entry);
2641 TRACE("font %s %d\n", debugstr_a(new_child->file_name), new_child->index);
2643 ret = TRUE;
2644 break;
2648 return ret;
2651 /*************************************************************
2652 * WineEngCreateFontInstance
2655 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
2657 GdiFont *ret;
2658 Face *face, *best, *best_bitmap;
2659 Family *family, *last_resort_family;
2660 struct list *family_elem_ptr, *face_elem_ptr;
2661 INT height, width = 0;
2662 unsigned int score = 0, new_score;
2663 signed int diff = 0, newdiff;
2664 BOOL bd, it, can_use_bitmap;
2665 LOGFONTW lf;
2666 CHARSETINFO csi;
2667 HFONTLIST *hflist;
2669 LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry)
2671 struct list *first_hfont = list_head(&ret->hfontlist);
2672 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2673 if(hflist->hfont == hfont)
2674 return ret;
2677 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
2678 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
2680 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
2681 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
2682 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
2683 lf.lfEscapement);
2685 /* check the cache first */
2686 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
2687 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
2688 return ret;
2691 TRACE("not in cache\n");
2692 if(list_empty(&font_list)) /* No fonts installed */
2694 TRACE("No fonts installed\n");
2695 return NULL;
2697 if(!have_installed_roman_font)
2699 TRACE("No roman font installed\n");
2700 return NULL;
2703 ret = alloc_font();
2705 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
2706 memcpy(&ret->font_desc.lf, &lf, sizeof(LOGFONTW));
2707 ret->font_desc.can_use_bitmap = can_use_bitmap;
2708 calc_hash(&ret->font_desc);
2709 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2710 hflist->hfont = hfont;
2711 list_add_head(&ret->hfontlist, &hflist->entry);
2714 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
2715 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
2716 original value lfCharSet. Note this is a special case for
2717 Symbol and doesn't happen at least for "Wingdings*" */
2719 if(!strcmpiW(lf.lfFaceName, SymbolW))
2720 lf.lfCharSet = SYMBOL_CHARSET;
2722 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
2723 switch(lf.lfCharSet) {
2724 case DEFAULT_CHARSET:
2725 csi.fs.fsCsb[0] = 0;
2726 break;
2727 default:
2728 FIXME("Untranslated charset %d\n", lf.lfCharSet);
2729 csi.fs.fsCsb[0] = 0;
2730 break;
2734 family = NULL;
2735 if(lf.lfFaceName[0] != '\0') {
2736 FontSubst *psub;
2737 SYSTEM_LINKS *font_link;
2738 CHILD_FONT *font_link_entry;
2740 psub = get_font_subst(&font_subst_list, lf.lfFaceName, lf.lfCharSet);
2742 if(psub) {
2743 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
2744 debugstr_w(psub->to.name));
2745 strcpyW(lf.lfFaceName, psub->to.name);
2748 /* We want a match on name and charset or just name if
2749 charset was DEFAULT_CHARSET. If the latter then
2750 we fixup the returned charset later in get_nearest_charset
2751 where we'll either use the charset of the current ansi codepage
2752 or if that's unavailable the first charset that the font supports.
2754 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2755 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2756 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2757 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2758 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2759 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
2760 if(face->scalable || can_use_bitmap)
2761 goto found;
2767 * Try check the SystemLink list first for a replacement font.
2768 * We may find good replacements there.
2770 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2772 if(!strcmpiW(font_link->font_name, lf.lfFaceName))
2774 TRACE("found entry in system list\n");
2775 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2777 face = find_face_from_path_index(font_link_entry->file_name,
2778 font_link_entry->index);
2779 if (face)
2781 family = face->family;
2782 if(csi.fs.fsCsb[0] &
2783 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
2785 if(face->scalable || can_use_bitmap)
2786 goto found;
2794 /* If requested charset was DEFAULT_CHARSET then try using charset
2795 corresponding to the current ansi codepage */
2796 if(!csi.fs.fsCsb[0]) {
2797 INT acp = GetACP();
2798 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
2799 FIXME("TCI failed on codepage %d\n", acp);
2800 csi.fs.fsCsb[0] = 0;
2801 } else
2802 lf.lfCharSet = csi.ciCharset;
2805 /* Face families are in the top 4 bits of lfPitchAndFamily,
2806 so mask with 0xF0 before testing */
2808 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
2809 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
2810 strcpyW(lf.lfFaceName, defFixed);
2811 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
2812 strcpyW(lf.lfFaceName, defSerif);
2813 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
2814 strcpyW(lf.lfFaceName, defSans);
2815 else
2816 strcpyW(lf.lfFaceName, defSans);
2817 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2818 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2819 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2820 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2821 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2822 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2823 if(face->scalable || can_use_bitmap)
2824 goto found;
2829 last_resort_family = NULL;
2830 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2831 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2832 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2833 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2834 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
2835 if(face->scalable)
2836 goto found;
2837 if(can_use_bitmap && !last_resort_family)
2838 last_resort_family = family;
2843 if(last_resort_family) {
2844 family = last_resort_family;
2845 csi.fs.fsCsb[0] = 0;
2846 goto found;
2849 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2850 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2851 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2852 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2853 if(face->scalable) {
2854 csi.fs.fsCsb[0] = 0;
2855 WARN("just using first face for now\n");
2856 goto found;
2858 if(can_use_bitmap && !last_resort_family)
2859 last_resort_family = family;
2862 if(!last_resort_family) {
2863 FIXME("can't find a single appropriate font - bailing\n");
2864 free_font(ret);
2865 return NULL;
2868 WARN("could only find a bitmap font - this will probably look awful!\n");
2869 family = last_resort_family;
2870 csi.fs.fsCsb[0] = 0;
2872 found:
2873 it = lf.lfItalic ? 1 : 0;
2874 bd = lf.lfWeight > 550 ? 1 : 0;
2876 height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
2877 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
2879 face = best = best_bitmap = NULL;
2880 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2882 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
2884 new_score = (face->Italic ^ it) + (face->Bold ^ bd);
2885 if(!best || new_score <= score)
2887 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
2888 face->Italic, face->Bold, it, bd);
2889 score = new_score;
2890 best = face;
2891 if(best->scalable && score == 0) break;
2892 if(!best->scalable)
2894 if(height > 0)
2895 newdiff = height - (signed int)(best->size.height);
2896 else
2897 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
2898 if(!best_bitmap || new_score < score ||
2899 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
2901 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
2902 diff = newdiff;
2903 best_bitmap = best;
2904 if(score == 0 && diff == 0) break;
2910 if(best)
2911 face = best->scalable ? best : best_bitmap;
2912 ret->fake_italic = (it && !face->Italic);
2913 ret->fake_bold = (bd && !face->Bold);
2915 memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
2917 if(csi.fs.fsCsb[0]) {
2918 ret->charset = lf.lfCharSet;
2919 ret->codepage = csi.ciACP;
2921 else
2922 ret->charset = get_nearest_charset(face, &ret->codepage);
2924 TRACE("Chosen: %s %s (%s:%ld)\n", debugstr_w(family->FamilyName),
2925 debugstr_w(face->StyleName), face->file, face->face_index);
2927 if(!face->scalable) {
2928 width = face->size.x_ppem >> 6;
2929 height = face->size.y_ppem >> 6;
2931 ret->ft_face = OpenFontFile(ret, face->file, face->face_index, width, height);
2933 if (!ret->ft_face)
2935 free_font( ret );
2936 return 0;
2939 if (ret->charset == SYMBOL_CHARSET &&
2940 !pFT_Select_Charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
2941 /* No ops */
2943 else if (!pFT_Select_Charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
2944 /* No ops */
2946 else {
2947 pFT_Select_Charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
2950 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
2951 ret->name = strdupW(family->FamilyName);
2952 ret->underline = lf.lfUnderline ? 0xff : 0;
2953 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
2954 create_child_font_list(ret);
2956 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
2958 ret->aveWidth = FT_IS_SCALABLE(ret->ft_face) ? abs(lf.lfWidth) : 0;
2959 list_add_head(&gdi_font_list, &ret->entry);
2960 return ret;
2963 static void dump_gdi_font_list(void)
2965 GdiFont *gdiFont;
2966 struct list *elem_ptr;
2968 TRACE("---------- gdiFont Cache ----------\n");
2969 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
2970 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
2971 TRACE("gdiFont=%p %s %d\n",
2972 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
2975 TRACE("---------- Unused gdiFont Cache ----------\n");
2976 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
2977 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
2978 TRACE("gdiFont=%p %s %d\n",
2979 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
2983 /*************************************************************
2984 * WineEngDestroyFontInstance
2986 * free the gdiFont associated with this handle
2989 BOOL WineEngDestroyFontInstance(HFONT handle)
2991 GdiFont *gdiFont;
2992 HFONTLIST *hflist;
2993 BOOL ret = FALSE;
2994 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2995 int i = 0;
2997 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
2999 struct list *first_hfont = list_head(&gdiFont->hfontlist);
3000 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3001 if(hflist->hfont == handle)
3003 TRACE("removing child font %p from child list\n", gdiFont);
3004 list_remove(&gdiFont->entry);
3005 return TRUE;
3009 TRACE("destroying hfont=%p\n", handle);
3010 if(TRACE_ON(font))
3011 dump_gdi_font_list();
3013 font_elem_ptr = list_head(&gdi_font_list);
3014 while(font_elem_ptr) {
3015 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3016 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3018 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3019 while(hfontlist_elem_ptr) {
3020 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3021 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3022 if(hflist->hfont == handle) {
3023 list_remove(&hflist->entry);
3024 HeapFree(GetProcessHeap(), 0, hflist);
3025 ret = TRUE;
3028 if(list_empty(&gdiFont->hfontlist)) {
3029 TRACE("Moving to Unused list\n");
3030 list_remove(&gdiFont->entry);
3031 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3036 font_elem_ptr = list_head(&unused_gdi_font_list);
3037 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3038 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3039 while(font_elem_ptr) {
3040 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3041 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3042 TRACE("freeing %p\n", gdiFont);
3043 list_remove(&gdiFont->entry);
3044 free_font(gdiFont);
3046 return ret;
3049 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
3050 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
3052 OUTLINETEXTMETRICW *potm = NULL;
3053 UINT size;
3054 TEXTMETRICW tm, *ptm;
3055 GdiFont *font = alloc_font();
3056 LONG width, height;
3058 if(face->scalable) {
3059 height = 100;
3060 width = 0;
3061 } else {
3062 height = face->size.y_ppem >> 6;
3063 width = face->size.x_ppem >> 6;
3066 if (!(font->ft_face = OpenFontFile(font, face->file, face->face_index, width, height)))
3068 free_font(font);
3069 return;
3072 font->name = strdupW(face->family->FamilyName);
3074 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
3076 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
3077 if(size) {
3078 potm = HeapAlloc(GetProcessHeap(), 0, size);
3079 WineEngGetOutlineTextMetrics(font, size, potm);
3080 ptm = (TEXTMETRICW*)&potm->otmTextMetrics;
3081 } else {
3082 WineEngGetTextMetrics(font, &tm);
3083 ptm = &tm;
3086 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = ptm->tmHeight;
3087 pntm->ntmTm.tmAscent = ptm->tmAscent;
3088 pntm->ntmTm.tmDescent = ptm->tmDescent;
3089 pntm->ntmTm.tmInternalLeading = ptm->tmInternalLeading;
3090 pntm->ntmTm.tmExternalLeading = ptm->tmExternalLeading;
3091 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = ptm->tmAveCharWidth;
3092 pntm->ntmTm.tmMaxCharWidth = ptm->tmMaxCharWidth;
3093 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = ptm->tmWeight;
3094 pntm->ntmTm.tmOverhang = ptm->tmOverhang;
3095 pntm->ntmTm.tmDigitizedAspectX = ptm->tmDigitizedAspectX;
3096 pntm->ntmTm.tmDigitizedAspectY = ptm->tmDigitizedAspectY;
3097 pntm->ntmTm.tmFirstChar = ptm->tmFirstChar;
3098 pntm->ntmTm.tmLastChar = ptm->tmLastChar;
3099 pntm->ntmTm.tmDefaultChar = ptm->tmDefaultChar;
3100 pntm->ntmTm.tmBreakChar = ptm->tmBreakChar;
3101 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = ptm->tmItalic;
3102 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = ptm->tmUnderlined;
3103 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = ptm->tmStruckOut;
3104 pntm->ntmTm.tmPitchAndFamily = ptm->tmPitchAndFamily;
3105 pelf->elfLogFont.lfPitchAndFamily = (ptm->tmPitchAndFamily & 0xf1) + 1;
3106 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = ptm->tmCharSet;
3107 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
3108 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
3109 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
3111 *ptype = ptm->tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
3112 if(!(ptm->tmPitchAndFamily & TMPF_VECTOR))
3113 *ptype |= RASTER_FONTTYPE;
3115 pntm->ntmTm.ntmFlags = ptm->tmItalic ? NTM_ITALIC : 0;
3116 if(ptm->tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
3117 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
3119 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
3120 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
3121 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
3123 if(potm) {
3124 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
3126 lstrcpynW(pelf->elfLogFont.lfFaceName,
3127 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
3128 LF_FACESIZE);
3129 lstrcpynW(pelf->elfFullName,
3130 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
3131 LF_FULLFACESIZE);
3132 lstrcpynW(pelf->elfStyle,
3133 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
3134 LF_FACESIZE);
3136 HeapFree(GetProcessHeap(), 0, potm);
3137 } else {
3138 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
3140 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
3141 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FACESIZE);
3142 pelf->elfStyle[0] = '\0';
3145 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
3147 free_font(font);
3150 /*************************************************************
3151 * WineEngEnumFonts
3154 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3156 Family *family;
3157 Face *face;
3158 struct list *family_elem_ptr, *face_elem_ptr;
3159 ENUMLOGFONTEXW elf;
3160 NEWTEXTMETRICEXW ntm;
3161 DWORD type, ret = 1;
3162 FONTSIGNATURE fs;
3163 CHARSETINFO csi;
3164 LOGFONTW lf;
3165 int i;
3167 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
3169 if(plf->lfFaceName[0]) {
3170 FontSubst *psub;
3171 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
3173 if(psub) {
3174 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
3175 debugstr_w(psub->to.name));
3176 memcpy(&lf, plf, sizeof(lf));
3177 strcpyW(lf.lfFaceName, psub->to.name);
3178 plf = &lf;
3181 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3182 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3183 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
3184 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3185 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3186 GetEnumStructs(face, &elf, &ntm, &type);
3187 for(i = 0; i < 32; i++) {
3188 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3189 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3190 strcpyW(elf.elfScript, OEM_DOSW);
3191 i = 32; /* break out of loop */
3192 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3193 continue;
3194 else {
3195 fs.fsCsb[0] = 1L << i;
3196 fs.fsCsb[1] = 0;
3197 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3198 TCI_SRCFONTSIG))
3199 csi.ciCharset = DEFAULT_CHARSET;
3200 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3201 if(csi.ciCharset != DEFAULT_CHARSET) {
3202 elf.elfLogFont.lfCharSet =
3203 ntm.ntmTm.tmCharSet = csi.ciCharset;
3204 if(ElfScriptsW[i])
3205 strcpyW(elf.elfScript, ElfScriptsW[i]);
3206 else
3207 FIXME("Unknown elfscript for bit %d\n", i);
3210 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3211 debugstr_w(elf.elfLogFont.lfFaceName),
3212 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3213 csi.ciCharset, type, debugstr_w(elf.elfScript),
3214 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3215 ntm.ntmTm.ntmFlags);
3216 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
3217 if(!ret) goto end;
3222 } else {
3223 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3224 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3225 face_elem_ptr = list_head(&family->faces);
3226 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3227 GetEnumStructs(face, &elf, &ntm, &type);
3228 for(i = 0; i < 32; i++) {
3229 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3230 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3231 strcpyW(elf.elfScript, OEM_DOSW);
3232 i = 32; /* break out of loop */
3233 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3234 continue;
3235 else {
3236 fs.fsCsb[0] = 1L << i;
3237 fs.fsCsb[1] = 0;
3238 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3239 TCI_SRCFONTSIG))
3240 csi.ciCharset = DEFAULT_CHARSET;
3241 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3242 if(csi.ciCharset != DEFAULT_CHARSET) {
3243 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
3244 csi.ciCharset;
3245 if(ElfScriptsW[i])
3246 strcpyW(elf.elfScript, ElfScriptsW[i]);
3247 else
3248 FIXME("Unknown elfscript for bit %d\n", i);
3251 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3252 debugstr_w(elf.elfLogFont.lfFaceName),
3253 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3254 csi.ciCharset, type, debugstr_w(elf.elfScript),
3255 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3256 ntm.ntmTm.ntmFlags);
3257 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
3258 if(!ret) goto end;
3262 end:
3263 return ret;
3266 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
3268 pt->x.value = vec->x >> 6;
3269 pt->x.fract = (vec->x & 0x3f) << 10;
3270 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
3271 pt->y.value = vec->y >> 6;
3272 pt->y.fract = (vec->y & 0x3f) << 10;
3273 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
3274 return;
3277 /***************************************************
3278 * According to the MSDN documentation on WideCharToMultiByte,
3279 * certain codepages cannot set the default_used parameter.
3280 * This returns TRUE if the codepage can set that parameter, false else
3281 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
3283 static BOOL codepage_sets_default_used(UINT codepage)
3285 switch (codepage)
3287 case CP_UTF7:
3288 case CP_UTF8:
3289 case CP_SYMBOL:
3290 return FALSE;
3291 default:
3292 return TRUE;
3296 static FT_UInt get_glyph_index(GdiFont *font, UINT glyph)
3298 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
3299 WCHAR wc = (WCHAR)glyph;
3300 BOOL default_used;
3301 BOOL *default_used_pointer;
3302 FT_UInt ret;
3303 char buf;
3304 default_used_pointer = NULL;
3305 default_used = FALSE;
3306 if (codepage_sets_default_used(font->codepage))
3307 default_used_pointer = &default_used;
3308 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
3309 ret = 0;
3310 else
3311 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
3312 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
3313 return ret;
3316 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
3317 glyph = glyph + 0xf000;
3318 return pFT_Get_Char_Index(font->ft_face, glyph);
3321 /*************************************************************
3322 * WineEngGetGlyphIndices
3324 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
3326 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
3327 LPWORD pgi, DWORD flags)
3329 int i;
3330 WCHAR default_char = 0;
3331 TEXTMETRICW textm;
3333 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0x001f; /* Indicate non existence */
3335 for(i = 0; i < count; i++)
3337 pgi[i] = get_glyph_index(font, lpstr[i]);
3338 if (pgi[i] == 0)
3340 if (!default_char)
3342 WineEngGetTextMetrics(font, &textm);
3343 default_char = textm.tmDefaultChar;
3345 pgi[i] = default_char;
3348 return count;
3351 /*************************************************************
3352 * WineEngGetGlyphOutline
3354 * Behaves in exactly the same way as the win32 api GetGlyphOutline
3355 * except that the first parameter is the HWINEENGFONT of the font in
3356 * question rather than an HDC.
3359 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
3360 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
3361 const MAT2* lpmat)
3363 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
3364 FT_Face ft_face = incoming_font->ft_face;
3365 GdiFont *font = incoming_font;
3366 FT_UInt glyph_index;
3367 DWORD width, height, pitch, needed = 0;
3368 FT_Bitmap ft_bitmap;
3369 FT_Error err;
3370 INT left, right, top = 0, bottom = 0;
3371 FT_Angle angle = 0;
3372 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
3373 float widthRatio = 1.0;
3374 FT_Matrix transMat = identityMat;
3375 BOOL needsTransform = FALSE;
3378 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
3379 buflen, buf, lpmat);
3381 if(format & GGO_GLYPH_INDEX) {
3382 glyph_index = glyph;
3383 format &= ~GGO_GLYPH_INDEX;
3384 } else {
3385 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
3386 ft_face = font->ft_face;
3389 if(glyph_index >= font->gmsize) {
3390 font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
3391 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
3392 font->gmsize * sizeof(*font->gm));
3393 } else {
3394 if(format == GGO_METRICS && font->gm[glyph_index].init) {
3395 memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
3396 return 1; /* FIXME */
3400 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP) || font->aveWidth || lpmat)
3401 load_flags |= FT_LOAD_NO_BITMAP;
3403 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
3405 if(err) {
3406 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
3407 return GDI_ERROR;
3410 /* Scaling factor */
3411 if (font->aveWidth && font->potm) {
3412 widthRatio = (float)font->aveWidth * font->font_desc.matrix.eM11 / (float) font->potm->otmTextMetrics.tmAveCharWidth;
3415 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
3416 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
3418 font->gm[glyph_index].adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
3419 font->gm[glyph_index].lsb = left >> 6;
3420 font->gm[glyph_index].bbx = (right - left) >> 6;
3422 /* Scaling transform */
3423 if(font->aveWidth) {
3424 FT_Matrix scaleMat;
3425 scaleMat.xx = FT_FixedFromFloat(widthRatio);
3426 scaleMat.xy = 0;
3427 scaleMat.yx = 0;
3428 scaleMat.yy = (1 << 16);
3430 pFT_Matrix_Multiply(&scaleMat, &transMat);
3431 needsTransform = TRUE;
3434 /* Slant transform */
3435 if (font->fake_italic) {
3436 FT_Matrix slantMat;
3438 slantMat.xx = (1 << 16);
3439 slantMat.xy = ((1 << 16) >> 2);
3440 slantMat.yx = 0;
3441 slantMat.yy = (1 << 16);
3442 pFT_Matrix_Multiply(&slantMat, &transMat);
3443 needsTransform = TRUE;
3446 /* Rotation transform */
3447 if(font->orientation) {
3448 FT_Matrix rotationMat;
3449 FT_Vector vecAngle;
3450 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
3451 pFT_Vector_Unit(&vecAngle, angle);
3452 rotationMat.xx = vecAngle.x;
3453 rotationMat.xy = -vecAngle.y;
3454 rotationMat.yx = -rotationMat.xy;
3455 rotationMat.yy = rotationMat.xx;
3457 pFT_Matrix_Multiply(&rotationMat, &transMat);
3458 needsTransform = TRUE;
3461 /* Extra transformation specified by caller */
3462 if (lpmat) {
3463 FT_Matrix extraMat;
3464 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
3465 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
3466 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
3467 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
3468 pFT_Matrix_Multiply(&extraMat, &transMat);
3469 needsTransform = TRUE;
3472 if(!needsTransform) {
3473 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
3474 bottom = (ft_face->glyph->metrics.horiBearingY -
3475 ft_face->glyph->metrics.height) & -64;
3476 lpgm->gmCellIncX = font->gm[glyph_index].adv;
3477 lpgm->gmCellIncY = 0;
3478 } else {
3479 INT xc, yc;
3480 FT_Vector vec;
3481 for(xc = 0; xc < 2; xc++) {
3482 for(yc = 0; yc < 2; yc++) {
3483 vec.x = (ft_face->glyph->metrics.horiBearingX +
3484 xc * ft_face->glyph->metrics.width);
3485 vec.y = ft_face->glyph->metrics.horiBearingY -
3486 yc * ft_face->glyph->metrics.height;
3487 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
3488 pFT_Vector_Transform(&vec, &transMat);
3489 if(xc == 0 && yc == 0) {
3490 left = right = vec.x;
3491 top = bottom = vec.y;
3492 } else {
3493 if(vec.x < left) left = vec.x;
3494 else if(vec.x > right) right = vec.x;
3495 if(vec.y < bottom) bottom = vec.y;
3496 else if(vec.y > top) top = vec.y;
3500 left = left & -64;
3501 right = (right + 63) & -64;
3502 bottom = bottom & -64;
3503 top = (top + 63) & -64;
3505 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
3506 vec.x = ft_face->glyph->metrics.horiAdvance;
3507 vec.y = 0;
3508 pFT_Vector_Transform(&vec, &transMat);
3509 lpgm->gmCellIncX = (vec.x+63) >> 6;
3510 lpgm->gmCellIncY = -((vec.y+63) >> 6);
3512 lpgm->gmBlackBoxX = (right - left) >> 6;
3513 lpgm->gmBlackBoxY = (top - bottom) >> 6;
3514 lpgm->gmptGlyphOrigin.x = left >> 6;
3515 lpgm->gmptGlyphOrigin.y = top >> 6;
3517 memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
3518 font->gm[glyph_index].init = TRUE;
3520 if(format == GGO_METRICS)
3521 return 1; /* FIXME */
3523 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP) {
3524 TRACE("loaded a bitmap\n");
3525 return GDI_ERROR;
3528 switch(format) {
3529 case GGO_BITMAP:
3530 width = lpgm->gmBlackBoxX;
3531 height = lpgm->gmBlackBoxY;
3532 pitch = ((width + 31) >> 5) << 2;
3533 needed = pitch * height;
3535 if(!buf || !buflen) break;
3537 switch(ft_face->glyph->format) {
3538 case ft_glyph_format_bitmap:
3540 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
3541 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
3542 INT h = ft_face->glyph->bitmap.rows;
3543 while(h--) {
3544 memcpy(dst, src, w);
3545 src += ft_face->glyph->bitmap.pitch;
3546 dst += pitch;
3548 break;
3551 case ft_glyph_format_outline:
3552 ft_bitmap.width = width;
3553 ft_bitmap.rows = height;
3554 ft_bitmap.pitch = pitch;
3555 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
3556 ft_bitmap.buffer = buf;
3558 if(needsTransform) {
3559 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3562 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3564 /* Note: FreeType will only set 'black' bits for us. */
3565 memset(buf, 0, needed);
3566 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3567 break;
3569 default:
3570 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
3571 return GDI_ERROR;
3573 break;
3575 case GGO_GRAY2_BITMAP:
3576 case GGO_GRAY4_BITMAP:
3577 case GGO_GRAY8_BITMAP:
3578 case WINE_GGO_GRAY16_BITMAP:
3580 unsigned int mult, row, col;
3581 BYTE *start, *ptr;
3583 width = lpgm->gmBlackBoxX;
3584 height = lpgm->gmBlackBoxY;
3585 pitch = (width + 3) / 4 * 4;
3586 needed = pitch * height;
3588 if(!buf || !buflen) break;
3589 ft_bitmap.width = width;
3590 ft_bitmap.rows = height;
3591 ft_bitmap.pitch = pitch;
3592 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
3593 ft_bitmap.buffer = buf;
3595 if(needsTransform) {
3596 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3599 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3601 memset(ft_bitmap.buffer, 0, buflen);
3603 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3605 if(format == GGO_GRAY2_BITMAP)
3606 mult = 4;
3607 else if(format == GGO_GRAY4_BITMAP)
3608 mult = 16;
3609 else if(format == GGO_GRAY8_BITMAP)
3610 mult = 64;
3611 else if(format == WINE_GGO_GRAY16_BITMAP)
3612 break;
3613 else {
3614 assert(0);
3615 break;
3618 start = buf;
3619 for(row = 0; row < height; row++) {
3620 ptr = start;
3621 for(col = 0; col < width; col++, ptr++) {
3622 *ptr = (((int)*ptr) * mult + 128) / 256;
3624 start += pitch;
3626 break;
3629 case GGO_NATIVE:
3631 int contour, point = 0, first_pt;
3632 FT_Outline *outline = &ft_face->glyph->outline;
3633 TTPOLYGONHEADER *pph;
3634 TTPOLYCURVE *ppc;
3635 DWORD pph_start, cpfx, type;
3637 if(buflen == 0) buf = NULL;
3639 if (needsTransform && buf) {
3640 pFT_Outline_Transform(outline, &transMat);
3643 for(contour = 0; contour < outline->n_contours; contour++) {
3644 pph_start = needed;
3645 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3646 first_pt = point;
3647 if(buf) {
3648 pph->dwType = TT_POLYGON_TYPE;
3649 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3651 needed += sizeof(*pph);
3652 point++;
3653 while(point <= outline->contours[contour]) {
3654 ppc = (TTPOLYCURVE *)((char *)buf + needed);
3655 type = (outline->tags[point] & FT_Curve_Tag_On) ?
3656 TT_PRIM_LINE : TT_PRIM_QSPLINE;
3657 cpfx = 0;
3658 do {
3659 if(buf)
3660 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3661 cpfx++;
3662 point++;
3663 } while(point <= outline->contours[contour] &&
3664 (outline->tags[point] & FT_Curve_Tag_On) ==
3665 (outline->tags[point-1] & FT_Curve_Tag_On));
3666 /* At the end of a contour Windows adds the start point, but
3667 only for Beziers */
3668 if(point > outline->contours[contour] &&
3669 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
3670 if(buf)
3671 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
3672 cpfx++;
3673 } else if(point <= outline->contours[contour] &&
3674 outline->tags[point] & FT_Curve_Tag_On) {
3675 /* add closing pt for bezier */
3676 if(buf)
3677 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3678 cpfx++;
3679 point++;
3681 if(buf) {
3682 ppc->wType = type;
3683 ppc->cpfx = cpfx;
3685 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3687 if(buf)
3688 pph->cb = needed - pph_start;
3690 break;
3692 case GGO_BEZIER:
3694 /* Convert the quadratic Beziers to cubic Beziers.
3695 The parametric eqn for a cubic Bezier is, from PLRM:
3696 r(t) = at^3 + bt^2 + ct + r0
3697 with the control points:
3698 r1 = r0 + c/3
3699 r2 = r1 + (c + b)/3
3700 r3 = r0 + c + b + a
3702 A quadratic Beizer has the form:
3703 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3705 So equating powers of t leads to:
3706 r1 = 2/3 p1 + 1/3 p0
3707 r2 = 2/3 p1 + 1/3 p2
3708 and of course r0 = p0, r3 = p2
3711 int contour, point = 0, first_pt;
3712 FT_Outline *outline = &ft_face->glyph->outline;
3713 TTPOLYGONHEADER *pph;
3714 TTPOLYCURVE *ppc;
3715 DWORD pph_start, cpfx, type;
3716 FT_Vector cubic_control[4];
3717 if(buflen == 0) buf = NULL;
3719 if (needsTransform && buf) {
3720 pFT_Outline_Transform(outline, &transMat);
3723 for(contour = 0; contour < outline->n_contours; contour++) {
3724 pph_start = needed;
3725 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3726 first_pt = point;
3727 if(buf) {
3728 pph->dwType = TT_POLYGON_TYPE;
3729 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3731 needed += sizeof(*pph);
3732 point++;
3733 while(point <= outline->contours[contour]) {
3734 ppc = (TTPOLYCURVE *)((char *)buf + needed);
3735 type = (outline->tags[point] & FT_Curve_Tag_On) ?
3736 TT_PRIM_LINE : TT_PRIM_CSPLINE;
3737 cpfx = 0;
3738 do {
3739 if(type == TT_PRIM_LINE) {
3740 if(buf)
3741 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3742 cpfx++;
3743 point++;
3744 } else {
3745 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
3746 so cpfx = 3n */
3748 /* FIXME: Possible optimization in endpoint calculation
3749 if there are two consecutive curves */
3750 cubic_control[0] = outline->points[point-1];
3751 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
3752 cubic_control[0].x += outline->points[point].x + 1;
3753 cubic_control[0].y += outline->points[point].y + 1;
3754 cubic_control[0].x >>= 1;
3755 cubic_control[0].y >>= 1;
3757 if(point+1 > outline->contours[contour])
3758 cubic_control[3] = outline->points[first_pt];
3759 else {
3760 cubic_control[3] = outline->points[point+1];
3761 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
3762 cubic_control[3].x += outline->points[point].x + 1;
3763 cubic_control[3].y += outline->points[point].y + 1;
3764 cubic_control[3].x >>= 1;
3765 cubic_control[3].y >>= 1;
3768 /* r1 = 1/3 p0 + 2/3 p1
3769 r2 = 1/3 p2 + 2/3 p1 */
3770 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
3771 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
3772 cubic_control[2] = cubic_control[1];
3773 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
3774 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
3775 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
3776 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
3777 if(buf) {
3778 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
3779 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
3780 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
3782 cpfx += 3;
3783 point++;
3785 } while(point <= outline->contours[contour] &&
3786 (outline->tags[point] & FT_Curve_Tag_On) ==
3787 (outline->tags[point-1] & FT_Curve_Tag_On));
3788 /* At the end of a contour Windows adds the start point,
3789 but only for Beziers and we've already done that.
3791 if(point <= outline->contours[contour] &&
3792 outline->tags[point] & FT_Curve_Tag_On) {
3793 /* This is the closing pt of a bezier, but we've already
3794 added it, so just inc point and carry on */
3795 point++;
3797 if(buf) {
3798 ppc->wType = type;
3799 ppc->cpfx = cpfx;
3801 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3803 if(buf)
3804 pph->cb = needed - pph_start;
3806 break;
3809 default:
3810 FIXME("Unsupported format %d\n", format);
3811 return GDI_ERROR;
3813 return needed;
3816 static BOOL get_bitmap_text_metrics(GdiFont *font)
3818 FT_Face ft_face = font->ft_face;
3819 #ifdef HAVE_FREETYPE_FTWINFNT_H
3820 FT_WinFNT_HeaderRec winfnt_header;
3821 #endif
3822 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
3823 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
3824 font->potm->otmSize = size;
3826 #define TM font->potm->otmTextMetrics
3827 #ifdef HAVE_FREETYPE_FTWINFNT_H
3828 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
3830 TM.tmHeight = winfnt_header.pixel_height;
3831 TM.tmAscent = winfnt_header.ascent;
3832 TM.tmDescent = TM.tmHeight - TM.tmAscent;
3833 TM.tmInternalLeading = winfnt_header.internal_leading;
3834 TM.tmExternalLeading = winfnt_header.external_leading;
3835 TM.tmAveCharWidth = winfnt_header.avg_width;
3836 TM.tmMaxCharWidth = winfnt_header.max_width;
3837 TM.tmWeight = winfnt_header.weight;
3838 TM.tmOverhang = 0;
3839 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
3840 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
3841 TM.tmFirstChar = winfnt_header.first_char;
3842 TM.tmLastChar = winfnt_header.last_char;
3843 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
3844 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
3845 TM.tmItalic = winfnt_header.italic;
3846 TM.tmUnderlined = font->underline;
3847 TM.tmStruckOut = font->strikeout;
3848 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
3849 TM.tmCharSet = winfnt_header.charset;
3851 else
3852 #endif
3854 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
3855 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
3856 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3857 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
3858 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
3859 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
3860 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
3861 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
3862 TM.tmOverhang = 0;
3863 TM.tmDigitizedAspectX = 96; /* FIXME */
3864 TM.tmDigitizedAspectY = 96; /* FIXME */
3865 TM.tmFirstChar = 1;
3866 TM.tmLastChar = 255;
3867 TM.tmDefaultChar = 32;
3868 TM.tmBreakChar = 32;
3869 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
3870 TM.tmUnderlined = font->underline;
3871 TM.tmStruckOut = font->strikeout;
3872 /* NB inverted meaning of TMPF_FIXED_PITCH */
3873 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
3874 TM.tmCharSet = font->charset;
3876 #undef TM
3878 return TRUE;
3881 /*************************************************************
3882 * WineEngGetTextMetrics
3885 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
3887 if(!font->potm) {
3888 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
3889 if(!get_bitmap_text_metrics(font))
3890 return FALSE;
3892 if(!font->potm) return FALSE;
3893 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
3895 if (font->aveWidth) {
3896 ptm->tmAveCharWidth = font->aveWidth * font->font_desc.matrix.eM11;
3898 return TRUE;
3902 /*************************************************************
3903 * WineEngGetOutlineTextMetrics
3906 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
3907 OUTLINETEXTMETRICW *potm)
3909 FT_Face ft_face = font->ft_face;
3910 UINT needed, lenfam, lensty, ret;
3911 TT_OS2 *pOS2;
3912 TT_HoriHeader *pHori;
3913 TT_Postscript *pPost;
3914 FT_Fixed x_scale, y_scale;
3915 WCHAR *family_nameW, *style_nameW;
3916 static const WCHAR spaceW[] = {' ', '\0'};
3917 char *cp;
3918 INT ascent, descent;
3920 TRACE("font=%p\n", font);
3922 if(!FT_IS_SCALABLE(ft_face))
3923 return 0;
3925 if(font->potm) {
3926 if(cbSize >= font->potm->otmSize)
3927 memcpy(potm, font->potm, font->potm->otmSize);
3928 return font->potm->otmSize;
3932 needed = sizeof(*potm);
3934 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
3935 family_nameW = strdupW(font->name);
3937 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
3938 * sizeof(WCHAR);
3939 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
3940 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
3941 style_nameW, lensty/sizeof(WCHAR));
3943 /* These names should be read from the TT name table */
3945 /* length of otmpFamilyName */
3946 needed += lenfam;
3948 /* length of otmpFaceName */
3949 if(!strcasecmp(ft_face->style_name, "regular")) {
3950 needed += lenfam; /* just the family name */
3951 } else {
3952 needed += lenfam + lensty; /* family + " " + style */
3955 /* length of otmpStyleName */
3956 needed += lensty;
3958 /* length of otmpFullName */
3959 needed += lenfam + lensty;
3962 x_scale = ft_face->size->metrics.x_scale;
3963 y_scale = ft_face->size->metrics.y_scale;
3965 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3966 if(!pOS2) {
3967 FIXME("Can't find OS/2 table - not TT font?\n");
3968 ret = 0;
3969 goto end;
3972 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3973 if(!pHori) {
3974 FIXME("Can't find HHEA table - not TT font?\n");
3975 ret = 0;
3976 goto end;
3979 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
3981 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",
3982 pOS2->usWinAscent, pOS2->usWinDescent,
3983 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
3984 ft_face->ascender, ft_face->descender, ft_face->height,
3985 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
3986 ft_face->bbox.yMax, ft_face->bbox.yMin);
3988 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
3989 font->potm->otmSize = needed;
3991 #define TM font->potm->otmTextMetrics
3993 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
3994 ascent = pHori->Ascender;
3995 descent = -pHori->Descender;
3996 } else {
3997 ascent = pOS2->usWinAscent;
3998 descent = pOS2->usWinDescent;
4001 if(font->yMax) {
4002 TM.tmAscent = font->yMax;
4003 TM.tmDescent = -font->yMin;
4004 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
4005 } else {
4006 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
4007 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
4008 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
4009 - ft_face->units_per_EM, y_scale) + 32) >> 6;
4012 TM.tmHeight = TM.tmAscent + TM.tmDescent;
4014 /* MSDN says:
4015 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
4017 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
4018 ((ascent + descent) -
4019 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
4021 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
4022 if (TM.tmAveCharWidth == 0) {
4023 TM.tmAveCharWidth = 1;
4025 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
4026 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
4027 TM.tmOverhang = 0;
4028 TM.tmDigitizedAspectX = 300;
4029 TM.tmDigitizedAspectY = 300;
4030 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
4031 * symbol range to 0 - f0ff
4033 if (font->charset == SYMBOL_CHARSET)
4034 TM.tmFirstChar = 0;
4035 else
4036 TM.tmFirstChar = pOS2->usFirstCharIndex;
4037 TM.tmLastChar = pOS2->usLastCharIndex;
4038 TM.tmDefaultChar = pOS2->usDefaultChar ? pOS2->usDefaultChar : 0x1f;
4039 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
4040 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
4041 TM.tmUnderlined = font->underline;
4042 TM.tmStruckOut = font->strikeout;
4044 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
4045 if(!FT_IS_FIXED_WIDTH(ft_face) &&
4046 (pOS2->version == 0xFFFFU ||
4047 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
4048 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
4049 else
4050 TM.tmPitchAndFamily = 0;
4052 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
4053 case PAN_FAMILY_SCRIPT:
4054 TM.tmPitchAndFamily |= FF_SCRIPT;
4055 break;
4056 case PAN_FAMILY_DECORATIVE:
4057 case PAN_FAMILY_PICTORIAL:
4058 TM.tmPitchAndFamily |= FF_DECORATIVE;
4059 break;
4060 case PAN_FAMILY_TEXT_DISPLAY:
4061 if(TM.tmPitchAndFamily == 0) /* fixed */
4062 TM.tmPitchAndFamily = FF_MODERN;
4063 else {
4064 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
4065 case PAN_SERIF_NORMAL_SANS:
4066 case PAN_SERIF_OBTUSE_SANS:
4067 case PAN_SERIF_PERP_SANS:
4068 TM.tmPitchAndFamily |= FF_SWISS;
4069 break;
4070 default:
4071 TM.tmPitchAndFamily |= FF_ROMAN;
4074 break;
4075 default:
4076 TM.tmPitchAndFamily |= FF_DONTCARE;
4079 if(FT_IS_SCALABLE(ft_face))
4080 TM.tmPitchAndFamily |= TMPF_VECTOR;
4081 if(FT_IS_SFNT(ft_face))
4082 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
4084 TM.tmCharSet = font->charset;
4085 #undef TM
4087 font->potm->otmFiller = 0;
4088 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
4089 font->potm->otmfsSelection = pOS2->fsSelection;
4090 font->potm->otmfsType = pOS2->fsType;
4091 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
4092 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
4093 font->potm->otmItalicAngle = 0; /* POST table */
4094 font->potm->otmEMSquare = ft_face->units_per_EM;
4095 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
4096 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
4097 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
4098 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
4099 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
4100 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
4101 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
4102 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
4103 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
4104 font->potm->otmMacAscent = 0; /* where do these come from ? */
4105 font->potm->otmMacDescent = 0;
4106 font->potm->otmMacLineGap = 0;
4107 font->potm->otmusMinimumPPEM = 0; /* TT Header */
4108 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
4109 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
4110 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
4111 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
4112 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
4113 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
4114 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
4115 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
4116 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
4117 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
4118 if(!pPost) {
4119 font->potm->otmsUnderscoreSize = 0;
4120 font->potm->otmsUnderscorePosition = 0;
4121 } else {
4122 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
4123 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
4126 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
4127 cp = (char*)font->potm + sizeof(*font->potm);
4128 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
4129 strcpyW((WCHAR*)cp, family_nameW);
4130 cp += lenfam;
4131 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
4132 strcpyW((WCHAR*)cp, style_nameW);
4133 cp += lensty;
4134 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
4135 strcpyW((WCHAR*)cp, family_nameW);
4136 if(strcasecmp(ft_face->style_name, "regular")) {
4137 strcatW((WCHAR*)cp, spaceW);
4138 strcatW((WCHAR*)cp, style_nameW);
4139 cp += lenfam + lensty;
4140 } else
4141 cp += lenfam;
4142 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
4143 strcpyW((WCHAR*)cp, family_nameW);
4144 strcatW((WCHAR*)cp, spaceW);
4145 strcatW((WCHAR*)cp, style_nameW);
4146 ret = needed;
4148 if(potm && needed <= cbSize)
4149 memcpy(potm, font->potm, font->potm->otmSize);
4151 end:
4152 HeapFree(GetProcessHeap(), 0, style_nameW);
4153 HeapFree(GetProcessHeap(), 0, family_nameW);
4155 return ret;
4158 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
4160 HFONTLIST *hfontlist;
4161 child->font = alloc_font();
4162 child->font->ft_face = OpenFontFile(child->font, child->file_name, child->index, 0, -font->ppem);
4163 if(!child->font->ft_face)
4165 free_font(child->font);
4166 child->font = NULL;
4167 return FALSE;
4170 child->font->orientation = font->orientation;
4171 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
4172 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
4173 list_add_head(&child->font->hfontlist, &hfontlist->entry);
4174 child->font->base_font = font;
4175 list_add_head(&child_font_list, &child->font->entry);
4176 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
4177 return TRUE;
4180 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
4182 FT_UInt g;
4183 CHILD_FONT *child_font;
4185 if(font->base_font)
4186 font = font->base_font;
4188 *linked_font = font;
4190 if((*glyph = get_glyph_index(font, c)))
4191 return TRUE;
4193 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
4195 if(!child_font->font)
4196 if(!load_child_font(font, child_font))
4197 continue;
4199 if(!child_font->font->ft_face)
4200 continue;
4201 g = get_glyph_index(child_font->font, c);
4202 if(g)
4204 *glyph = g;
4205 *linked_font = child_font->font;
4206 return TRUE;
4209 return FALSE;
4212 /*************************************************************
4213 * WineEngGetCharWidth
4216 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
4217 LPINT buffer)
4219 UINT c;
4220 GLYPHMETRICS gm;
4221 FT_UInt glyph_index;
4222 GdiFont *linked_font;
4224 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
4226 for(c = firstChar; c <= lastChar; c++) {
4227 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
4228 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4229 &gm, 0, NULL, NULL);
4230 buffer[c - firstChar] = linked_font->gm[glyph_index].adv;
4232 return TRUE;
4235 /*************************************************************
4236 * WineEngGetCharABCWidths
4239 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
4240 LPABC buffer)
4242 UINT c;
4243 GLYPHMETRICS gm;
4244 FT_UInt glyph_index;
4245 GdiFont *linked_font;
4247 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
4249 if(!FT_IS_SCALABLE(font->ft_face))
4250 return FALSE;
4252 for(c = firstChar; c <= lastChar; c++) {
4253 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
4254 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4255 &gm, 0, NULL, NULL);
4256 buffer[c - firstChar].abcA = linked_font->gm[glyph_index].lsb;
4257 buffer[c - firstChar].abcB = linked_font->gm[glyph_index].bbx;
4258 buffer[c - firstChar].abcC = linked_font->gm[glyph_index].adv - linked_font->gm[glyph_index].lsb -
4259 linked_font->gm[glyph_index].bbx;
4261 return TRUE;
4264 /*************************************************************
4265 * WineEngGetCharABCWidthsI
4268 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
4269 LPABC buffer)
4271 UINT c;
4272 GLYPHMETRICS gm;
4273 FT_UInt glyph_index;
4274 GdiFont *linked_font;
4276 if(!FT_IS_SCALABLE(font->ft_face))
4277 return FALSE;
4279 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
4280 if (!pgi)
4281 for(c = firstChar; c < firstChar+count; c++) {
4282 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
4283 &gm, 0, NULL, NULL);
4284 buffer[c - firstChar].abcA = linked_font->gm[c].lsb;
4285 buffer[c - firstChar].abcB = linked_font->gm[c].bbx;
4286 buffer[c - firstChar].abcC = linked_font->gm[c].adv - linked_font->gm[c].lsb
4287 - linked_font->gm[c].bbx;
4289 else
4290 for(c = 0; c < count; c++) {
4291 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
4292 &gm, 0, NULL, NULL);
4293 buffer[c].abcA = linked_font->gm[pgi[c]].lsb;
4294 buffer[c].abcB = linked_font->gm[pgi[c]].bbx;
4295 buffer[c].abcC = linked_font->gm[pgi[c]].adv
4296 - linked_font->gm[pgi[c]].lsb - linked_font->gm[pgi[c]].bbx;
4299 return TRUE;
4302 /*************************************************************
4303 * WineEngGetTextExtentExPoint
4306 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
4307 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
4309 INT idx;
4310 INT nfit = 0, ext;
4311 GLYPHMETRICS gm;
4312 TEXTMETRICW tm;
4313 FT_UInt glyph_index;
4314 GdiFont *linked_font;
4316 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
4317 max_ext, size);
4319 size->cx = 0;
4320 WineEngGetTextMetrics(font, &tm);
4321 size->cy = tm.tmHeight;
4323 for(idx = 0; idx < count; idx++) {
4324 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
4325 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4326 &gm, 0, NULL, NULL);
4327 size->cx += linked_font->gm[glyph_index].adv;
4328 ext = size->cx;
4329 if (! pnfit || ext <= max_ext) {
4330 ++nfit;
4331 if (dxs)
4332 dxs[idx] = ext;
4336 if (pnfit)
4337 *pnfit = nfit;
4339 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
4340 return TRUE;
4343 /*************************************************************
4344 * WineEngGetTextExtentPointI
4347 BOOL WineEngGetTextExtentPointI(GdiFont *font, const WORD *indices, INT count,
4348 LPSIZE size)
4350 INT idx;
4351 GLYPHMETRICS gm;
4352 TEXTMETRICW tm;
4354 TRACE("%p, %p, %d, %p\n", font, indices, count, size);
4356 size->cx = 0;
4357 WineEngGetTextMetrics(font, &tm);
4358 size->cy = tm.tmHeight;
4360 for(idx = 0; idx < count; idx++) {
4361 WineEngGetGlyphOutline(font, indices[idx],
4362 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
4363 NULL);
4364 size->cx += font->gm[indices[idx]].adv;
4366 TRACE("return %d,%d\n", size->cx, size->cy);
4367 return TRUE;
4370 /*************************************************************
4371 * WineEngGetFontData
4374 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
4375 DWORD cbData)
4377 FT_Face ft_face = font->ft_face;
4378 FT_ULong len;
4379 FT_Error err;
4381 TRACE("font=%p, table=%08x, offset=%08x, buf=%p, cbData=%x\n",
4382 font, table, offset, buf, cbData);
4384 if(!FT_IS_SFNT(ft_face))
4385 return GDI_ERROR;
4387 if(!buf || !cbData)
4388 len = 0;
4389 else
4390 len = cbData;
4392 if(table) { /* MS tags differ in endidness from FT ones */
4393 table = table >> 24 | table << 24 |
4394 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
4397 /* If the FT_Load_Sfnt_Table function is there we'll use it */
4398 if(pFT_Load_Sfnt_Table) {
4399 /* make sure value of len is the value freetype says it needs */
4400 if( buf && len) {
4401 FT_ULong needed = 0;
4402 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
4403 if( !err && needed < len) len = needed;
4405 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
4407 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
4408 else { /* Do it the hard way */
4409 TT_Face tt_face = (TT_Face) ft_face;
4410 SFNT_Interface *sfnt;
4411 if (FT_Version.major==2 && FT_Version.minor==0)
4413 /* 2.0.x */
4414 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
4416 else
4418 /* A field was added in the middle of the structure in 2.1.x */
4419 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
4421 /* make sure value of len is the value freetype says it needs */
4422 if( buf && len) {
4423 FT_ULong needed = 0;
4424 err = sfnt->load_any(tt_face, table, offset, NULL, &needed);
4425 if( !err && needed < len) len = needed;
4427 err = sfnt->load_any(tt_face, table, offset, buf, &len);
4429 #else
4430 else {
4431 static int msg;
4432 if(!msg) {
4433 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
4434 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
4435 "Please upgrade your freetype library.\n");
4436 msg++;
4438 err = FT_Err_Unimplemented_Feature;
4440 #endif
4441 if(err) {
4442 TRACE("Can't find table %08x.\n", table);
4443 return GDI_ERROR;
4445 return len;
4448 /*************************************************************
4449 * WineEngGetTextFace
4452 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
4454 if(str) {
4455 lstrcpynW(str, font->name, count);
4456 return strlenW(font->name);
4457 } else
4458 return strlenW(font->name) + 1;
4461 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
4463 if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
4464 return font->charset;
4467 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
4469 GdiFont *font = dc->gdiFont, *linked_font;
4470 struct list *first_hfont;
4471 BOOL ret;
4473 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
4474 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
4475 if(font == linked_font)
4476 *new_hfont = dc->hFont;
4477 else
4479 first_hfont = list_head(&linked_font->hfontlist);
4480 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
4483 return ret;
4486 /* Retrieve a list of supported Unicode ranges for a given font.
4487 * Can be called with NULL gs to calculate the buffer size. Returns
4488 * the number of ranges found.
4490 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
4492 DWORD num_ranges = 0;
4494 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
4496 FT_UInt glyph_code;
4497 FT_ULong char_code, char_code_prev;
4499 glyph_code = 0;
4500 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
4502 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
4503 face->num_glyphs, glyph_code, char_code);
4505 if (!glyph_code) return 0;
4507 if (gs)
4509 gs->ranges[0].wcLow = (USHORT)char_code;
4510 gs->ranges[0].cGlyphs = 0;
4511 gs->cGlyphsSupported = 0;
4514 num_ranges = 1;
4515 while (glyph_code)
4517 if (char_code < char_code_prev)
4519 ERR("expected increasing char code from FT_Get_Next_Char\n");
4520 return 0;
4522 if (char_code - char_code_prev > 1)
4524 num_ranges++;
4525 if (gs)
4527 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
4528 gs->ranges[num_ranges - 1].cGlyphs = 1;
4529 gs->cGlyphsSupported++;
4532 else if (gs)
4534 gs->ranges[num_ranges - 1].cGlyphs++;
4535 gs->cGlyphsSupported++;
4537 char_code_prev = char_code;
4538 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
4541 else
4542 FIXME("encoding %u not supported\n", face->charmap->encoding);
4544 return num_ranges;
4547 DWORD WineEngGetFontUnicodeRanges(HDC hdc, LPGLYPHSET glyphset)
4549 DWORD size = 0;
4550 DC *dc = DC_GetDCPtr(hdc);
4552 TRACE("(%p, %p)\n", hdc, glyphset);
4554 if (!dc) return 0;
4556 if (dc->gdiFont)
4558 DWORD num_ranges = get_font_unicode_ranges(dc->gdiFont->ft_face, glyphset);
4560 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
4561 if (glyphset)
4563 glyphset->cbThis = size;
4564 glyphset->cRanges = num_ranges;
4568 GDI_ReleaseObj(hdc);
4569 return size;
4572 /*************************************************************
4573 * FontIsLinked
4575 BOOL WINAPI FontIsLinked(HDC hdc)
4577 DC *dc = DC_GetDCPtr(hdc);
4578 BOOL ret = FALSE;
4580 if(!dc) return FALSE;
4581 if(dc->gdiFont && !list_empty(&dc->gdiFont->child_fonts))
4582 ret = TRUE;
4583 GDI_ReleaseObj(hdc);
4584 TRACE("returning %d\n", ret);
4585 return ret;
4588 static BOOL is_hinting_enabled(void)
4590 /* Use the >= 2.2.0 function if available */
4591 if(pFT_Get_TrueType_Engine_Type)
4593 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
4594 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
4596 #ifdef FT_DRIVER_HAS_HINTER
4597 else
4599 FT_Module mod;
4601 /* otherwise if we've been compiled with < 2.2.0 headers
4602 use the internal macro */
4603 mod = pFT_Get_Module(library, "truetype");
4604 if(mod && FT_DRIVER_HAS_HINTER(mod))
4605 return TRUE;
4607 #endif
4609 return FALSE;
4612 /*************************************************************************
4613 * GetRasterizerCaps (GDI32.@)
4615 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
4617 static int hinting = -1;
4619 if(hinting == -1)
4621 hinting = is_hinting_enabled();
4622 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
4625 lprs->nSize = sizeof(RASTERIZER_STATUS);
4626 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
4627 lprs->nLanguageID = 0;
4628 return TRUE;
4631 /*************************************************************************
4632 * Kerning support for TrueType fonts
4634 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
4636 struct TT_kern_table
4638 USHORT version;
4639 USHORT nTables;
4642 struct TT_kern_subtable
4644 USHORT version;
4645 USHORT length;
4646 union
4648 USHORT word;
4649 struct
4651 USHORT horizontal : 1;
4652 USHORT minimum : 1;
4653 USHORT cross_stream: 1;
4654 USHORT override : 1;
4655 USHORT reserved1 : 4;
4656 USHORT format : 8;
4657 } bits;
4658 } coverage;
4661 struct TT_format0_kern_subtable
4663 USHORT nPairs;
4664 USHORT searchRange;
4665 USHORT entrySelector;
4666 USHORT rangeShift;
4669 struct TT_kern_pair
4671 USHORT left;
4672 USHORT right;
4673 short value;
4676 static DWORD parse_format0_kern_subtable(GdiFont *font,
4677 const struct TT_format0_kern_subtable *tt_f0_ks,
4678 const USHORT *glyph_to_char,
4679 KERNINGPAIR *kern_pair, DWORD cPairs)
4681 USHORT i, nPairs;
4682 const struct TT_kern_pair *tt_kern_pair;
4684 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
4686 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
4688 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
4689 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
4690 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
4692 if (!kern_pair || !cPairs)
4693 return nPairs;
4695 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
4697 nPairs = min(nPairs, cPairs);
4699 for (i = 0; i < nPairs; i++)
4701 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
4702 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
4703 /* this algorithm appears to better match what Windows does */
4704 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
4705 if (kern_pair->iKernAmount < 0)
4707 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
4708 kern_pair->iKernAmount -= font->ppem;
4710 else if (kern_pair->iKernAmount > 0)
4712 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
4713 kern_pair->iKernAmount += font->ppem;
4715 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
4717 TRACE("left %u right %u value %d\n",
4718 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
4720 kern_pair++;
4722 TRACE("copied %u entries\n", nPairs);
4723 return nPairs;
4726 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
4728 DWORD length;
4729 void *buf;
4730 const struct TT_kern_table *tt_kern_table;
4731 const struct TT_kern_subtable *tt_kern_subtable;
4732 USHORT i, nTables;
4733 USHORT *glyph_to_char;
4735 if (font->total_kern_pairs != (DWORD)-1)
4737 if (cPairs && kern_pair)
4739 cPairs = min(cPairs, font->total_kern_pairs);
4740 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
4741 return cPairs;
4743 return font->total_kern_pairs;
4746 font->total_kern_pairs = 0;
4748 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
4750 if (length == GDI_ERROR)
4752 TRACE("no kerning data in the font\n");
4753 return 0;
4756 buf = HeapAlloc(GetProcessHeap(), 0, length);
4757 if (!buf)
4759 WARN("Out of memory\n");
4760 return 0;
4763 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
4765 /* build a glyph index to char code map */
4766 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
4767 if (!glyph_to_char)
4769 WARN("Out of memory allocating a glyph index to char code map\n");
4770 HeapFree(GetProcessHeap(), 0, buf);
4771 return 0;
4774 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
4776 FT_UInt glyph_code;
4777 FT_ULong char_code;
4779 glyph_code = 0;
4780 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
4782 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
4783 font->ft_face->num_glyphs, glyph_code, char_code);
4785 while (glyph_code)
4787 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
4789 /* FIXME: This doesn't match what Windows does: it does some fancy
4790 * things with duplicate glyph index to char code mappings, while
4791 * we just avoid overriding existing entries.
4793 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
4794 glyph_to_char[glyph_code] = (USHORT)char_code;
4796 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
4799 else
4801 ULONG n;
4803 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
4804 for (n = 0; n <= 65535; n++)
4805 glyph_to_char[n] = (USHORT)n;
4808 tt_kern_table = buf;
4809 nTables = GET_BE_WORD(tt_kern_table->nTables);
4810 TRACE("version %u, nTables %u\n",
4811 GET_BE_WORD(tt_kern_table->version), nTables);
4813 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
4815 for (i = 0; i < nTables; i++)
4817 struct TT_kern_subtable tt_kern_subtable_copy;
4819 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
4820 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
4821 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
4823 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
4824 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
4825 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
4827 /* According to the TrueType specification this is the only format
4828 * that will be properly interpreted by Windows and OS/2
4830 if (tt_kern_subtable_copy.coverage.bits.format == 0)
4832 DWORD new_chunk, old_total = font->total_kern_pairs;
4834 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
4835 glyph_to_char, NULL, 0);
4836 font->total_kern_pairs += new_chunk;
4838 if (!font->kern_pairs)
4839 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
4840 font->total_kern_pairs * sizeof(*font->kern_pairs));
4841 else
4842 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
4843 font->total_kern_pairs * sizeof(*font->kern_pairs));
4845 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
4846 glyph_to_char, font->kern_pairs + old_total, new_chunk);
4848 else
4849 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
4851 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
4854 HeapFree(GetProcessHeap(), 0, glyph_to_char);
4855 HeapFree(GetProcessHeap(), 0, buf);
4857 if (cPairs && kern_pair)
4859 cPairs = min(cPairs, font->total_kern_pairs);
4860 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
4861 return cPairs;
4863 return font->total_kern_pairs;
4866 #else /* HAVE_FREETYPE */
4868 /*************************************************************************/
4870 BOOL WineEngInit(void)
4872 return FALSE;
4874 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
4876 return NULL;
4878 BOOL WineEngDestroyFontInstance(HFONT hfont)
4880 return FALSE;
4883 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
4885 return 1;
4888 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4889 LPWORD pgi, DWORD flags)
4891 return GDI_ERROR;
4894 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
4895 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4896 const MAT2* lpmat)
4898 ERR("called but we don't have FreeType\n");
4899 return GDI_ERROR;
4902 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
4904 ERR("called but we don't have FreeType\n");
4905 return FALSE;
4908 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
4909 OUTLINETEXTMETRICW *potm)
4911 ERR("called but we don't have FreeType\n");
4912 return 0;
4915 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
4916 LPINT buffer)
4918 ERR("called but we don't have FreeType\n");
4919 return FALSE;
4922 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
4923 LPABC buffer)
4925 ERR("called but we don't have FreeType\n");
4926 return FALSE;
4929 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
4930 LPABC buffer)
4932 ERR("called but we don't have FreeType\n");
4933 return FALSE;
4936 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
4937 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
4939 ERR("called but we don't have FreeType\n");
4940 return FALSE;
4943 BOOL WineEngGetTextExtentPointI(GdiFont *font, const WORD *indices, INT count,
4944 LPSIZE size)
4946 ERR("called but we don't have FreeType\n");
4947 return FALSE;
4950 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
4951 DWORD cbData)
4953 ERR("called but we don't have FreeType\n");
4954 return GDI_ERROR;
4957 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
4959 ERR("called but we don't have FreeType\n");
4960 return 0;
4963 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
4965 FIXME(":stub\n");
4966 return 1;
4969 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
4971 FIXME(":stub\n");
4972 return TRUE;
4975 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
4977 FIXME(":stub\n");
4978 return DEFAULT_CHARSET;
4981 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
4983 return FALSE;
4986 DWORD WineEngGetFontUnicodeRanges(HDC hdc, LPGLYPHSET glyphset)
4988 FIXME("(%p, %p): stub\n", hdc, glyphset);
4989 return 0;
4992 BOOL WINAPI FontIsLinked(HDC hdc)
4994 return FALSE;
4997 /*************************************************************************
4998 * GetRasterizerCaps (GDI32.@)
5000 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
5002 lprs->nSize = sizeof(RASTERIZER_STATUS);
5003 lprs->wFlags = 0;
5004 lprs->nLanguageID = 0;
5005 return TRUE;
5008 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
5010 ERR("called but we don't have FreeType\n");
5011 return 0;
5014 #endif /* HAVE_FREETYPE */