wintrust: Don't prefer native version.
[wine/multimedia.git] / dlls / gdi32 / freetype.c
blobb978d35fa789bf5d6b50ed4aa4506f5b7ca1852b
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 HAVE_FT_TRUETYPEENGINETYPE
132 typedef enum
134 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
135 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
136 FT_TRUETYPE_ENGINE_TYPE_PATENTED
137 } FT_TrueTypeEngineType;
138 #endif
140 static FT_Library library = 0;
141 typedef struct
143 FT_Int major;
144 FT_Int minor;
145 FT_Int patch;
146 } FT_Version_t;
147 static FT_Version_t FT_Version;
148 static DWORD FT_SimpleVersion;
150 static void *ft_handle = NULL;
152 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
153 MAKE_FUNCPTR(FT_Vector_Unit);
154 MAKE_FUNCPTR(FT_Done_Face);
155 MAKE_FUNCPTR(FT_Get_Char_Index);
156 MAKE_FUNCPTR(FT_Get_Module);
157 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
158 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
159 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
160 MAKE_FUNCPTR(FT_Init_FreeType);
161 MAKE_FUNCPTR(FT_Load_Glyph);
162 MAKE_FUNCPTR(FT_Matrix_Multiply);
163 MAKE_FUNCPTR(FT_MulFix);
164 MAKE_FUNCPTR(FT_New_Face);
165 MAKE_FUNCPTR(FT_New_Memory_Face);
166 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
167 MAKE_FUNCPTR(FT_Outline_Transform);
168 MAKE_FUNCPTR(FT_Outline_Translate);
169 MAKE_FUNCPTR(FT_Select_Charmap);
170 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
171 MAKE_FUNCPTR(FT_Vector_Transform);
172 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
173 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
174 static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*);
175 static FT_ULong (*pFT_Get_Next_Char)(FT_Face,FT_ULong,FT_UInt*);
176 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
177 #ifdef HAVE_FREETYPE_FTWINFNT_H
178 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
179 #endif
181 #ifdef SONAME_LIBFONTCONFIG
182 #include <fontconfig/fontconfig.h>
183 MAKE_FUNCPTR(FcConfigGetCurrent);
184 MAKE_FUNCPTR(FcFontList);
185 MAKE_FUNCPTR(FcFontSetDestroy);
186 MAKE_FUNCPTR(FcInit);
187 MAKE_FUNCPTR(FcObjectSetAdd);
188 MAKE_FUNCPTR(FcObjectSetCreate);
189 MAKE_FUNCPTR(FcObjectSetDestroy);
190 MAKE_FUNCPTR(FcPatternCreate);
191 MAKE_FUNCPTR(FcPatternDestroy);
192 MAKE_FUNCPTR(FcPatternGetBool);
193 MAKE_FUNCPTR(FcPatternGetString);
194 #endif
196 #undef MAKE_FUNCPTR
198 #ifndef ft_encoding_none
199 #define FT_ENCODING_NONE ft_encoding_none
200 #endif
201 #ifndef ft_encoding_ms_symbol
202 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
203 #endif
204 #ifndef ft_encoding_unicode
205 #define FT_ENCODING_UNICODE ft_encoding_unicode
206 #endif
207 #ifndef ft_encoding_apple_roman
208 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
209 #endif
211 #ifdef WORDS_BIGENDIAN
212 #define GET_BE_WORD(x) (x)
213 #else
214 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
215 #endif
217 /* This is bascially a copy of FT_Bitmap_Size with an extra element added */
218 typedef struct {
219 FT_Short height;
220 FT_Short width;
221 FT_Pos size;
222 FT_Pos x_ppem;
223 FT_Pos y_ppem;
224 FT_Short internal_leading;
225 } Bitmap_Size;
227 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
228 So to let this compile on older versions of FreeType we'll define the
229 new structure here. */
230 typedef struct {
231 FT_Short height, width;
232 FT_Pos size, x_ppem, y_ppem;
233 } My_FT_Bitmap_Size;
235 typedef struct tagFace {
236 struct list entry;
237 WCHAR *StyleName;
238 char *file;
239 FT_Long face_index;
240 BOOL Italic;
241 BOOL Bold;
242 FONTSIGNATURE fs;
243 FONTSIGNATURE fs_links;
244 FT_Fixed font_version;
245 BOOL scalable;
246 Bitmap_Size size; /* set if face is a bitmap */
247 BOOL external; /* TRUE if we should manually add this font to the registry */
248 struct tagFamily *family;
249 } Face;
251 typedef struct tagFamily {
252 struct list entry;
253 const WCHAR *FamilyName;
254 struct list faces;
255 } Family;
257 typedef struct {
258 GLYPHMETRICS gm;
259 INT adv; /* These three hold to widths of the unrotated chars */
260 INT lsb;
261 INT bbx;
262 BOOL init;
263 } GM;
265 typedef struct {
266 FLOAT eM11, eM12;
267 FLOAT eM21, eM22;
268 } FMAT2;
270 typedef struct {
271 DWORD hash;
272 LOGFONTW lf;
273 FMAT2 matrix;
274 BOOL can_use_bitmap;
275 } FONT_DESC;
277 typedef struct tagHFONTLIST {
278 struct list entry;
279 HFONT hfont;
280 } HFONTLIST;
282 typedef struct {
283 struct list entry;
284 char *file_name;
285 INT index;
286 GdiFont *font;
287 } CHILD_FONT;
289 struct tagGdiFont {
290 struct list entry;
291 FT_Face ft_face;
292 struct font_mapping *mapping;
293 LPWSTR name;
294 int charset;
295 int codepage;
296 BOOL fake_italic;
297 BOOL fake_bold;
298 BYTE underline;
299 BYTE strikeout;
300 INT orientation;
301 GM **gm;
302 DWORD gmsize;
303 struct list hfontlist;
304 FONT_DESC font_desc;
305 LONG aveWidth;
306 SHORT yMax;
307 SHORT yMin;
308 OUTLINETEXTMETRICW *potm;
309 DWORD total_kern_pairs;
310 KERNINGPAIR *kern_pairs;
311 FONTSIGNATURE fs;
312 GdiFont *base_font;
313 struct list child_fonts;
314 LONG ppem;
317 typedef struct {
318 struct list entry;
319 const WCHAR *font_name;
320 struct list links;
321 } SYSTEM_LINKS;
323 #define GM_BLOCK_SIZE 128
324 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
326 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
327 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
328 #define UNUSED_CACHE_SIZE 10
329 static struct list child_font_list = LIST_INIT(child_font_list);
330 static struct list system_links = LIST_INIT(system_links);
332 static struct list font_subst_list = LIST_INIT(font_subst_list);
334 static struct list font_list = LIST_INIT(font_list);
336 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
337 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
338 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
340 static const WCHAR RegularW[] = {'R','e','g','u','l','a','r','\0'};
342 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
343 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
344 'W','i','n','d','o','w','s','\\',
345 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
346 'F','o','n','t','s','\0'};
348 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
349 'W','i','n','d','o','w','s',' ','N','T','\\',
350 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
351 'F','o','n','t','s','\0'};
353 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
354 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
355 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
356 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
358 static const WCHAR * const SystemFontValues[4] = {
359 System_Value,
360 OEMFont_Value,
361 FixedSys_Value,
362 NULL
365 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
366 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
368 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
369 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
370 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
371 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
372 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
373 'E','u','r','o','p','e','a','n','\0'};
374 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
375 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
376 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
377 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
378 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
379 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
380 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
381 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
382 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
383 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
384 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
385 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
387 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
388 WesternW, /*00*/
389 Central_EuropeanW,
390 CyrillicW,
391 GreekW,
392 TurkishW,
393 HebrewW,
394 ArabicW,
395 BalticW,
396 VietnameseW, /*08*/
397 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
398 ThaiW,
399 JapaneseW,
400 CHINESE_GB2312W,
401 HangulW,
402 CHINESE_BIG5W,
403 Hangul_Johab_W,
404 NULL, NULL, /*23*/
405 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
406 SymbolW /*31*/
409 typedef struct {
410 WCHAR *name;
411 INT charset;
412 } NameCs;
414 typedef struct tagFontSubst {
415 struct list entry;
416 NameCs from;
417 NameCs to;
418 } FontSubst;
420 struct font_mapping
422 struct list entry;
423 int refcount;
424 dev_t dev;
425 ino_t ino;
426 void *data;
427 size_t size;
430 static struct list mappings_list = LIST_INIT( mappings_list );
432 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
434 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
436 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
438 /****************************************
439 * Notes on .fon files
441 * The fonts System, FixedSys and Terminal are special. There are typically multiple
442 * versions installed for different resolutions and codepages. Windows stores which one to use
443 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
444 * Key Meaning
445 * FIXEDFON.FON FixedSys
446 * FONTS.FON System
447 * OEMFONT.FON Terminal
448 * LogPixels Current dpi set by the display control panel applet
449 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
450 * also has a LogPixels value that appears to mirror this)
452 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
453 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
454 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
455 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
456 * so that makes sense.
458 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
459 * to be mapped into the registry on Windows 2000 at least).
460 * I have
461 * woafont=app850.fon
462 * ega80woa.fon=ega80850.fon
463 * ega40woa.fon=ega40850.fon
464 * cga80woa.fon=cga80850.fon
465 * cga40woa.fon=cga40850.fon
468 #ifdef HAVE_CARBON_CARBON_H
469 static char *find_cache_dir(void)
471 FSRef ref;
472 OSErr err;
473 static char cached_path[MAX_PATH];
474 static const char *wine = "/Wine", *fonts = "/Fonts";
476 if(*cached_path) return cached_path;
478 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
479 if(err != noErr)
481 WARN("can't create cached data folder\n");
482 return NULL;
484 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
485 if(err != noErr)
487 WARN("can't create cached data path\n");
488 *cached_path = '\0';
489 return NULL;
491 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
493 ERR("Could not create full path\n");
494 *cached_path = '\0';
495 return NULL;
497 strcat(cached_path, wine);
499 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
501 WARN("Couldn't mkdir %s\n", cached_path);
502 *cached_path = '\0';
503 return NULL;
505 strcat(cached_path, fonts);
506 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
508 WARN("Couldn't mkdir %s\n", cached_path);
509 *cached_path = '\0';
510 return NULL;
512 return cached_path;
515 /******************************************************************
516 * expand_mac_font
518 * Extracts individual TrueType font files from a Mac suitcase font
519 * and saves them into the user's caches directory (see
520 * find_cache_dir()).
521 * Returns a NULL terminated array of filenames.
523 * We do this because they are apps that try to read ttf files
524 * themselves and they don't like Mac suitcase files.
526 static char **expand_mac_font(const char *path)
528 FSRef ref;
529 SInt16 res_ref;
530 OSStatus s;
531 unsigned int idx;
532 const char *out_dir;
533 const char *filename;
534 int output_len;
535 struct {
536 char **array;
537 unsigned int size, max_size;
538 } ret;
540 TRACE("path %s\n", path);
542 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
543 if(s != noErr)
545 WARN("failed to get ref\n");
546 return NULL;
549 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
550 if(s != noErr)
552 TRACE("no data fork, so trying resource fork\n");
553 res_ref = FSOpenResFile(&ref, fsRdPerm);
554 if(res_ref == -1)
556 TRACE("unable to open resource fork\n");
557 return NULL;
561 ret.size = 0;
562 ret.max_size = 10;
563 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
564 if(!ret.array)
566 CloseResFile(res_ref);
567 return NULL;
570 out_dir = find_cache_dir();
572 filename = strrchr(path, '/');
573 if(!filename) filename = path;
574 else filename++;
576 /* output filename has the form out_dir/filename_%04x.ttf */
577 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
579 UseResFile(res_ref);
580 idx = 1;
581 while(1)
583 FamRec *fam_rec;
584 unsigned short *num_faces_ptr, num_faces, face;
585 AsscEntry *assoc;
586 Handle fond;
587 ResType fond_res = 0x464f4e44; /* 'FOND' */
589 fond = Get1IndResource(fond_res, idx);
590 if(!fond) break;
591 TRACE("got fond resource %d\n", idx);
592 HLock(fond);
594 fam_rec = *(FamRec**)fond;
595 num_faces_ptr = (unsigned short *)(fam_rec + 1);
596 num_faces = GET_BE_WORD(*num_faces_ptr);
597 num_faces++;
598 assoc = (AsscEntry*)(num_faces_ptr + 1);
599 TRACE("num faces %04x\n", num_faces);
600 for(face = 0; face < num_faces; face++, assoc++)
602 Handle sfnt;
603 ResType sfnt_res = 0x73666e74; /* 'sfnt' */
604 unsigned short size, font_id;
605 char *output;
607 size = GET_BE_WORD(assoc->fontSize);
608 font_id = GET_BE_WORD(assoc->fontID);
609 if(size != 0)
611 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
612 continue;
615 TRACE("trying to load sfnt id %04x\n", font_id);
616 sfnt = GetResource(sfnt_res, font_id);
617 if(!sfnt)
619 TRACE("can't get sfnt resource %04x\n", font_id);
620 continue;
623 output = HeapAlloc(GetProcessHeap(), 0, output_len);
624 if(output)
626 int fd;
628 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
630 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
631 if(fd != -1 || errno == EEXIST)
633 if(fd != -1)
635 unsigned char *sfnt_data;
637 HLock(sfnt);
638 sfnt_data = *(unsigned char**)sfnt;
639 write(fd, sfnt_data, GetHandleSize(sfnt));
640 HUnlock(sfnt);
641 close(fd);
643 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
645 ret.max_size *= 2;
646 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
648 ret.array[ret.size++] = output;
650 else
652 WARN("unable to create %s\n", output);
653 HeapFree(GetProcessHeap(), 0, output);
656 ReleaseResource(sfnt);
658 HUnlock(fond);
659 ReleaseResource(fond);
660 idx++;
662 CloseResFile(res_ref);
664 return ret.array;
667 #endif /* HAVE_CARBON_CARBON_H */
669 static inline BOOL is_win9x(void)
671 return GetVersion() & 0x80000000;
674 This function builds an FT_Fixed from a float. It puts the integer part
675 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
676 It fails if the integer part of the float number is greater than SHORT_MAX.
678 static inline FT_Fixed FT_FixedFromFloat(float f)
680 short value = f;
681 unsigned short fract = (f - value) * 0xFFFF;
682 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
686 This function builds an FT_Fixed from a FIXED. It simply put f.value
687 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
689 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
691 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
695 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
697 Family *family;
698 Face *face;
699 const char *file;
700 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
701 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
703 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
704 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
706 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
708 if(face_name && strcmpiW(face_name, family->FamilyName))
709 continue;
710 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
712 file = strrchr(face->file, '/');
713 if(!file)
714 file = face->file;
715 else
716 file++;
717 if(!strcasecmp(file, file_nameA))
719 HeapFree(GetProcessHeap(), 0, file_nameA);
720 return face;
724 HeapFree(GetProcessHeap(), 0, file_nameA);
725 return NULL;
728 static Family *find_family_from_name(const WCHAR *name)
730 Family *family;
732 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
734 if(!strcmpiW(family->FamilyName, name))
735 return family;
738 return NULL;
741 static Face *find_face_from_path_index(const CHAR *file_name, const INT index)
743 Family *family;
744 Face *face;
746 TRACE("looking for file %s index %i\n", debugstr_a(file_name), index);
748 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
750 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
752 if(!strcasecmp(face->file, file_name) && face->face_index == index)
753 return face;
756 return NULL;
759 static void DumpSubstList(void)
761 FontSubst *psub;
763 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
765 if(psub->from.charset != -1 || psub->to.charset != -1)
766 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
767 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
768 else
769 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
770 debugstr_w(psub->to.name));
772 return;
775 static LPWSTR strdupW(LPCWSTR p)
777 LPWSTR ret;
778 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
779 ret = HeapAlloc(GetProcessHeap(), 0, len);
780 memcpy(ret, p, len);
781 return ret;
784 static LPSTR strdupA(LPCSTR p)
786 LPSTR ret;
787 DWORD len = (strlen(p) + 1);
788 ret = HeapAlloc(GetProcessHeap(), 0, len);
789 memcpy(ret, p, len);
790 return ret;
793 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
794 INT from_charset)
796 FontSubst *element;
798 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
800 if(!strcmpiW(element->from.name, from_name) &&
801 (element->from.charset == from_charset ||
802 element->from.charset == -1))
803 return element;
806 return NULL;
809 #define ADD_FONT_SUBST_FORCE 1
811 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
813 FontSubst *from_exist, *to_exist;
815 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
817 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
819 list_remove(&from_exist->entry);
820 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
821 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
822 HeapFree(GetProcessHeap(), 0, from_exist);
823 from_exist = NULL;
826 if(!from_exist)
828 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
830 if(to_exist)
832 HeapFree(GetProcessHeap(), 0, subst->to.name);
833 subst->to.name = strdupW(to_exist->to.name);
836 list_add_tail(subst_list, &subst->entry);
838 return TRUE;
841 HeapFree(GetProcessHeap(), 0, subst->from.name);
842 HeapFree(GetProcessHeap(), 0, subst->to.name);
843 HeapFree(GetProcessHeap(), 0, subst);
844 return FALSE;
847 static void split_subst_info(NameCs *nc, LPSTR str)
849 CHAR *p = strrchr(str, ',');
850 DWORD len;
852 nc->charset = -1;
853 if(p && *(p+1)) {
854 nc->charset = strtol(p+1, NULL, 10);
855 *p = '\0';
857 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
858 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
859 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
862 static void LoadSubstList(void)
864 FontSubst *psub;
865 HKEY hkey;
866 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
867 LPSTR value;
868 LPVOID data;
870 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
871 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
872 &hkey) == ERROR_SUCCESS) {
874 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
875 &valuelen, &datalen, NULL, NULL);
877 valuelen++; /* returned value doesn't include room for '\0' */
878 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
879 data = HeapAlloc(GetProcessHeap(), 0, datalen);
881 dlen = datalen;
882 vlen = valuelen;
883 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
884 &dlen) == ERROR_SUCCESS) {
885 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
887 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
888 split_subst_info(&psub->from, value);
889 split_subst_info(&psub->to, data);
891 /* Win 2000 doesn't allow mapping between different charsets
892 or mapping of DEFAULT_CHARSET */
893 if((psub->to.charset != psub->from.charset) ||
894 psub->to.charset == DEFAULT_CHARSET) {
895 HeapFree(GetProcessHeap(), 0, psub->to.name);
896 HeapFree(GetProcessHeap(), 0, psub->from.name);
897 HeapFree(GetProcessHeap(), 0, psub);
898 } else {
899 add_font_subst(&font_subst_list, psub, 0);
901 /* reset dlen and vlen */
902 dlen = datalen;
903 vlen = valuelen;
905 HeapFree(GetProcessHeap(), 0, data);
906 HeapFree(GetProcessHeap(), 0, value);
907 RegCloseKey(hkey);
911 static WCHAR *get_familyname(FT_Face ft_face)
913 WCHAR *family = NULL;
914 FT_SfntName name;
915 FT_UInt num_names, name_index, i;
917 if(FT_IS_SFNT(ft_face))
919 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
921 for(name_index = 0; name_index < num_names; name_index++)
923 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
925 if((name.name_id == TT_NAME_ID_FONT_FAMILY) &&
926 (name.language_id == GetUserDefaultLCID()) &&
927 (name.platform_id == TT_PLATFORM_MICROSOFT) &&
928 (name.encoding_id == TT_MS_ID_UNICODE_CS))
930 /* String is not nul terminated and string_len is a byte length. */
931 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
932 for(i = 0; i < name.string_len / 2; i++)
934 WORD *tmp = (WORD *)&name.string[i * 2];
935 family[i] = GET_BE_WORD(*tmp);
937 family[i] = 0;
939 TRACE("Got localised name %s\n", debugstr_w(family));
940 return family;
946 return NULL;
950 #define ADDFONT_EXTERNAL_FONT 0x01
951 #define ADDFONT_FORCE_BITMAP 0x02
952 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
954 FT_Face ft_face;
955 TT_OS2 *pOS2;
956 TT_Header *pHeader = NULL;
957 WCHAR *english_family, *localised_family, *StyleW;
958 DWORD len;
959 Family *family;
960 Face *face;
961 struct list *family_elem_ptr, *face_elem_ptr;
962 FT_Error err;
963 FT_Long face_index = 0, num_faces;
964 #ifdef HAVE_FREETYPE_FTWINFNT_H
965 FT_WinFNT_HeaderRec winfnt_header;
966 #endif
967 int i, bitmap_num, internal_leading;
968 FONTSIGNATURE fs;
970 #ifdef HAVE_CARBON_CARBON_H
971 if(!fake_family)
973 char **mac_list = expand_mac_font(file);
974 if(mac_list)
976 BOOL had_one = FALSE;
977 char **cursor;
978 for(cursor = mac_list; *cursor; cursor++)
980 had_one = TRUE;
981 AddFontFileToList(*cursor, NULL, NULL, flags);
982 HeapFree(GetProcessHeap(), 0, *cursor);
984 HeapFree(GetProcessHeap(), 0, mac_list);
985 if(had_one)
986 return 1;
989 #endif /* HAVE_CARBON_CARBON_H */
991 do {
992 char *family_name = fake_family;
994 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
995 if((err = pFT_New_Face(library, file, face_index, &ft_face)) != 0) {
996 WARN("Unable to load font file %s err = %x\n", debugstr_a(file), err);
997 return 0;
1000 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*/
1001 WARN("Ignoring font %s\n", debugstr_a(file));
1002 pFT_Done_Face(ft_face);
1003 return 0;
1006 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1007 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1008 WARN("FreeType version < 2.1.9, skipping bitmap font %s\n", debugstr_a(file));
1009 pFT_Done_Face(ft_face);
1010 return 0;
1013 if(FT_IS_SFNT(ft_face) && (!pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2) ||
1014 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1015 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))) {
1016 TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
1017 "Skipping this font.\n", debugstr_a(file));
1018 pFT_Done_Face(ft_face);
1019 return 0;
1022 if(!ft_face->family_name || !ft_face->style_name) {
1023 TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file));
1024 pFT_Done_Face(ft_face);
1025 return 0;
1028 if (target_family)
1030 localised_family = get_familyname(ft_face);
1031 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1033 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1034 HeapFree(GetProcessHeap(), 0, localised_family);
1035 num_faces = ft_face->num_faces;
1036 pFT_Done_Face(ft_face);
1037 continue;
1039 HeapFree(GetProcessHeap(), 0, localised_family);
1042 if(!family_name)
1043 family_name = ft_face->family_name;
1045 bitmap_num = 0;
1046 do {
1047 My_FT_Bitmap_Size *size = NULL;
1049 if(!FT_IS_SCALABLE(ft_face))
1050 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1052 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1053 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1054 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1056 localised_family = NULL;
1057 if(!fake_family) {
1058 localised_family = get_familyname(ft_face);
1059 if(localised_family && !strcmpW(localised_family, english_family)) {
1060 HeapFree(GetProcessHeap(), 0, localised_family);
1061 localised_family = NULL;
1065 family = NULL;
1066 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1067 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1068 if(!strcmpW(family->FamilyName, localised_family ? localised_family : english_family))
1069 break;
1070 family = NULL;
1072 if(!family) {
1073 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1074 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1075 list_init(&family->faces);
1076 list_add_tail(&font_list, &family->entry);
1078 if(localised_family) {
1079 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1080 subst->from.name = strdupW(english_family);
1081 subst->from.charset = -1;
1082 subst->to.name = strdupW(localised_family);
1083 subst->to.charset = -1;
1084 add_font_subst(&font_subst_list, subst, 0);
1087 HeapFree(GetProcessHeap(), 0, localised_family);
1088 HeapFree(GetProcessHeap(), 0, english_family);
1090 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1091 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1092 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1094 internal_leading = 0;
1095 memset(&fs, 0, sizeof(fs));
1097 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1098 if(pOS2) {
1099 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1100 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1101 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1102 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1103 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1104 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1105 if(pOS2->version == 0) {
1106 FT_UInt dummy;
1108 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1109 fs.fsCsb[0] |= 1;
1110 else
1111 fs.fsCsb[0] |= 1L << 31;
1114 #ifdef HAVE_FREETYPE_FTWINFNT_H
1115 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1116 CHARSETINFO csi;
1117 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1118 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1119 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1120 memcpy(&fs, &csi.fs, sizeof(csi.fs));
1121 internal_leading = winfnt_header.internal_leading;
1123 #endif
1125 face_elem_ptr = list_head(&family->faces);
1126 while(face_elem_ptr) {
1127 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1128 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1129 if(!strcmpW(face->StyleName, StyleW) &&
1130 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1131 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1132 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1133 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1135 if(fake_family) {
1136 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1137 HeapFree(GetProcessHeap(), 0, StyleW);
1138 pFT_Done_Face(ft_face);
1139 return 1;
1141 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1142 TRACE("Original font is newer so skipping this one\n");
1143 HeapFree(GetProcessHeap(), 0, StyleW);
1144 pFT_Done_Face(ft_face);
1145 return 1;
1146 } else {
1147 TRACE("Replacing original with this one\n");
1148 list_remove(&face->entry);
1149 HeapFree(GetProcessHeap(), 0, face->file);
1150 HeapFree(GetProcessHeap(), 0, face->StyleName);
1151 HeapFree(GetProcessHeap(), 0, face);
1152 break;
1156 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1157 list_add_tail(&family->faces, &face->entry);
1158 face->StyleName = StyleW;
1159 face->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
1160 strcpy(face->file, file);
1161 face->face_index = face_index;
1162 face->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
1163 face->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
1164 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1165 face->family = family;
1166 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1167 memcpy(&face->fs, &fs, sizeof(face->fs));
1168 memset(&face->fs_links, 0, sizeof(face->fs_links));
1170 if(FT_IS_SCALABLE(ft_face)) {
1171 memset(&face->size, 0, sizeof(face->size));
1172 face->scalable = TRUE;
1173 } else {
1174 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1175 size->height, size->width, size->size >> 6,
1176 size->x_ppem >> 6, size->y_ppem >> 6);
1177 face->size.height = size->height;
1178 face->size.width = size->width;
1179 face->size.size = size->size;
1180 face->size.x_ppem = size->x_ppem;
1181 face->size.y_ppem = size->y_ppem;
1182 face->size.internal_leading = internal_leading;
1183 face->scalable = FALSE;
1186 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1187 face->fs.fsCsb[0], face->fs.fsCsb[1],
1188 face->fs.fsUsb[0], face->fs.fsUsb[1],
1189 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1192 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1193 for(i = 0; i < ft_face->num_charmaps; i++) {
1194 switch(ft_face->charmaps[i]->encoding) {
1195 case FT_ENCODING_UNICODE:
1196 case FT_ENCODING_APPLE_ROMAN:
1197 face->fs.fsCsb[0] |= 1;
1198 break;
1199 case FT_ENCODING_MS_SYMBOL:
1200 face->fs.fsCsb[0] |= 1L << 31;
1201 break;
1202 default:
1203 break;
1208 if(face->fs.fsCsb[0] & ~(1L << 31))
1209 have_installed_roman_font = TRUE;
1210 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1212 num_faces = ft_face->num_faces;
1213 pFT_Done_Face(ft_face);
1214 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1215 debugstr_w(StyleW));
1216 } while(num_faces > ++face_index);
1217 return num_faces;
1220 static void DumpFontList(void)
1222 Family *family;
1223 Face *face;
1224 struct list *family_elem_ptr, *face_elem_ptr;
1226 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1227 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1228 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1229 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1230 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1231 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1232 if(!face->scalable)
1233 TRACE(" %d", face->size.height);
1234 TRACE("\n");
1237 return;
1240 /***********************************************************
1241 * The replacement list is a way to map an entire font
1242 * family onto another family. For example adding
1244 * [HKCU\Software\Wine\Fonts\Replacements]
1245 * "Wingdings"="Winedings"
1247 * would enumerate the Winedings font both as Winedings and
1248 * Wingdings. However if a real Wingdings font is present the
1249 * replacement does not take place.
1252 static void LoadReplaceList(void)
1254 HKEY hkey;
1255 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1256 LPWSTR value;
1257 LPVOID data;
1258 Family *family;
1259 Face *face;
1260 struct list *family_elem_ptr, *face_elem_ptr;
1261 CHAR familyA[400];
1263 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1264 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1266 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1267 &valuelen, &datalen, NULL, NULL);
1269 valuelen++; /* returned value doesn't include room for '\0' */
1270 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1271 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1273 dlen = datalen;
1274 vlen = valuelen;
1275 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1276 &dlen) == ERROR_SUCCESS) {
1277 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1278 /* "NewName"="Oldname" */
1279 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1281 /* Find the old family and hence all of the font files
1282 in that family */
1283 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1284 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1285 if(!strcmpiW(family->FamilyName, data)) {
1286 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1287 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1288 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1289 debugstr_w(face->StyleName), familyA);
1290 /* Now add a new entry with the new family name */
1291 AddFontFileToList(face->file, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1293 break;
1296 /* reset dlen and vlen */
1297 dlen = datalen;
1298 vlen = valuelen;
1300 HeapFree(GetProcessHeap(), 0, data);
1301 HeapFree(GetProcessHeap(), 0, value);
1302 RegCloseKey(hkey);
1306 /*************************************************************
1307 * init_system_links
1309 static BOOL init_system_links(void)
1311 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1312 'W','i','n','d','o','w','s',' ','N','T','\\',
1313 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1314 'S','y','s','t','e','m','L','i','n','k',0};
1315 HKEY hkey;
1316 BOOL ret = FALSE;
1317 DWORD type, max_val, max_data, val_len, data_len, index;
1318 WCHAR *value, *data;
1319 WCHAR *entry, *next;
1320 SYSTEM_LINKS *font_link, *system_font_link;
1321 CHILD_FONT *child_font;
1322 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
1323 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1324 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1325 FONTSIGNATURE fs;
1326 Family *family;
1327 Face *face;
1328 FontSubst *psub;
1330 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1332 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1333 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1334 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1335 val_len = max_val + 1;
1336 data_len = max_data;
1337 index = 0;
1338 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1340 TRACE("%s:\n", debugstr_w(value));
1342 memset(&fs, 0, sizeof(fs));
1343 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1344 psub = get_font_subst(&font_subst_list, value, -1);
1345 font_link->font_name = (psub)? strdupW(psub->to.name) : strdupW(value);
1346 list_init(&font_link->links);
1347 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1349 WCHAR *face_name;
1350 CHILD_FONT *child_font;
1352 TRACE("\t%s\n", debugstr_w(entry));
1354 next = entry + strlenW(entry) + 1;
1356 face_name = strchrW(entry, ',');
1357 if(face_name)
1359 *face_name++ = 0;
1360 while(isspaceW(*face_name))
1361 face_name++;
1363 psub = get_font_subst(&font_subst_list, face_name, -1);
1364 if(psub)
1365 face_name = psub->to.name;
1367 face = find_face_from_filename(entry, face_name);
1368 if(!face)
1370 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1371 continue;
1374 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1375 child_font->file_name = strdupA(face->file);
1376 child_font->index = face->face_index;
1377 child_font->font = NULL;
1378 fs.fsCsb[0] |= face->fs.fsCsb[0];
1379 fs.fsCsb[1] |= face->fs.fsCsb[1];
1380 TRACE("Adding file %s index %d\n", child_font->file_name, child_font->index);
1381 list_add_tail(&font_link->links, &child_font->entry);
1383 family = find_family_from_name(font_link->font_name);
1384 if(family)
1386 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1388 memcpy(&face->fs_links, &fs, sizeof(fs));
1391 list_add_tail(&system_links, &font_link->entry);
1392 val_len = max_val + 1;
1393 data_len = max_data;
1396 HeapFree(GetProcessHeap(), 0, value);
1397 HeapFree(GetProcessHeap(), 0, data);
1398 RegCloseKey(hkey);
1401 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1402 that Tahoma has */
1404 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1405 system_font_link->font_name = strdupW(System);
1406 list_init(&system_font_link->links);
1408 face = find_face_from_filename(tahoma_ttf, Tahoma);
1409 if(face)
1411 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1412 child_font->file_name = strdupA(face->file);
1413 child_font->index = face->face_index;
1414 child_font->font = NULL;
1415 TRACE("Found Tahoma in %s index %d\n", child_font->file_name, child_font->index);
1416 list_add_tail(&system_font_link->links, &child_font->entry);
1418 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1420 if(!strcmpiW(font_link->font_name, Tahoma))
1422 CHILD_FONT *font_link_entry;
1423 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1425 CHILD_FONT *new_child;
1426 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1427 new_child->file_name = strdupA(font_link_entry->file_name);
1428 new_child->index = font_link_entry->index;
1429 new_child->font = NULL;
1430 list_add_tail(&system_font_link->links, &new_child->entry);
1432 break;
1435 list_add_tail(&system_links, &system_font_link->entry);
1436 return ret;
1439 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1441 DIR *dir;
1442 struct dirent *dent;
1443 char path[MAX_PATH];
1445 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1447 dir = opendir(dirname);
1448 if(!dir) {
1449 WARN("Can't open directory %s\n", debugstr_a(dirname));
1450 return FALSE;
1452 while((dent = readdir(dir)) != NULL) {
1453 struct stat statbuf;
1455 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1456 continue;
1458 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1460 sprintf(path, "%s/%s", dirname, dent->d_name);
1462 if(stat(path, &statbuf) == -1)
1464 WARN("Can't stat %s\n", debugstr_a(path));
1465 continue;
1467 if(S_ISDIR(statbuf.st_mode))
1468 ReadFontDir(path, external_fonts);
1469 else
1470 AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1472 closedir(dir);
1473 return TRUE;
1476 static void load_fontconfig_fonts(void)
1478 #ifdef SONAME_LIBFONTCONFIG
1479 void *fc_handle = NULL;
1480 FcConfig *config;
1481 FcPattern *pat;
1482 FcObjectSet *os;
1483 FcFontSet *fontset;
1484 int i, len;
1485 char *file;
1486 const char *ext;
1488 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1489 if(!fc_handle) {
1490 TRACE("Wine cannot find the fontconfig library (%s).\n",
1491 SONAME_LIBFONTCONFIG);
1492 return;
1494 #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;}
1495 LOAD_FUNCPTR(FcConfigGetCurrent);
1496 LOAD_FUNCPTR(FcFontList);
1497 LOAD_FUNCPTR(FcFontSetDestroy);
1498 LOAD_FUNCPTR(FcInit);
1499 LOAD_FUNCPTR(FcObjectSetAdd);
1500 LOAD_FUNCPTR(FcObjectSetCreate);
1501 LOAD_FUNCPTR(FcObjectSetDestroy);
1502 LOAD_FUNCPTR(FcPatternCreate);
1503 LOAD_FUNCPTR(FcPatternDestroy);
1504 LOAD_FUNCPTR(FcPatternGetBool);
1505 LOAD_FUNCPTR(FcPatternGetString);
1506 #undef LOAD_FUNCPTR
1508 if(!pFcInit()) return;
1510 config = pFcConfigGetCurrent();
1511 pat = pFcPatternCreate();
1512 os = pFcObjectSetCreate();
1513 pFcObjectSetAdd(os, FC_FILE);
1514 pFcObjectSetAdd(os, FC_SCALABLE);
1515 fontset = pFcFontList(config, pat, os);
1516 if(!fontset) return;
1517 for(i = 0; i < fontset->nfont; i++) {
1518 FcBool scalable;
1520 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1521 continue;
1522 TRACE("fontconfig: %s\n", file);
1524 /* We're just interested in OT/TT fonts for now, so this hack just
1525 picks up the scalable fonts without extensions .pf[ab] to save time
1526 loading every other font */
1528 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1530 TRACE("not scalable\n");
1531 continue;
1534 len = strlen( file );
1535 if(len < 4) continue;
1536 ext = &file[ len - 3 ];
1537 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1538 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT);
1540 pFcFontSetDestroy(fontset);
1541 pFcObjectSetDestroy(os);
1542 pFcPatternDestroy(pat);
1543 sym_not_found:
1544 #endif
1545 return;
1548 static BOOL load_font_from_data_dir(LPCWSTR file)
1550 BOOL ret = FALSE;
1551 const char *data_dir = wine_get_data_dir();
1553 if (!data_dir) data_dir = wine_get_build_dir();
1555 if (data_dir)
1557 INT len;
1558 char *unix_name;
1560 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1562 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1564 strcpy(unix_name, data_dir);
1565 strcat(unix_name, "/fonts/");
1567 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1569 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1570 HeapFree(GetProcessHeap(), 0, unix_name);
1572 return ret;
1575 static void load_system_fonts(void)
1577 HKEY hkey;
1578 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1579 const WCHAR * const *value;
1580 DWORD dlen, type;
1581 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1582 char *unixname;
1584 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1585 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1586 strcatW(windowsdir, fontsW);
1587 for(value = SystemFontValues; *value; value++) {
1588 dlen = sizeof(data);
1589 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1590 type == REG_SZ) {
1591 BOOL added = FALSE;
1593 sprintfW(pathW, fmtW, windowsdir, data);
1594 if((unixname = wine_get_unix_file_name(pathW))) {
1595 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1596 HeapFree(GetProcessHeap(), 0, unixname);
1598 if (!added)
1599 load_font_from_data_dir(data);
1602 RegCloseKey(hkey);
1606 /*************************************************************
1608 * This adds registry entries for any externally loaded fonts
1609 * (fonts from fontconfig or FontDirs). It also deletes entries
1610 * of no longer existing fonts.
1613 static void update_reg_entries(void)
1615 HKEY winkey = 0, externalkey = 0;
1616 LPWSTR valueW;
1617 LPVOID data;
1618 DWORD dlen, vlen, datalen, valuelen, i, type, len, len_fam;
1619 Family *family;
1620 Face *face;
1621 struct list *family_elem_ptr, *face_elem_ptr;
1622 WCHAR *file;
1623 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1624 static const WCHAR spaceW[] = {' ', '\0'};
1625 char *path;
1627 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1628 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winkey, NULL) != ERROR_SUCCESS) {
1629 ERR("Can't create Windows font reg key\n");
1630 goto end;
1632 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1633 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &externalkey) != ERROR_SUCCESS) {
1634 ERR("Can't create external font reg key\n");
1635 goto end;
1638 /* Delete all external fonts added last time */
1640 RegQueryInfoKeyW(externalkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1641 &valuelen, &datalen, NULL, NULL);
1642 valuelen++; /* returned value doesn't include room for '\0' */
1643 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1644 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1646 dlen = datalen * sizeof(WCHAR);
1647 vlen = valuelen;
1648 i = 0;
1649 while(RegEnumValueW(externalkey, i++, valueW, &vlen, NULL, &type, data,
1650 &dlen) == ERROR_SUCCESS) {
1652 RegDeleteValueW(winkey, valueW);
1653 /* reset dlen and vlen */
1654 dlen = datalen;
1655 vlen = valuelen;
1657 HeapFree(GetProcessHeap(), 0, data);
1658 HeapFree(GetProcessHeap(), 0, valueW);
1660 /* Delete the old external fonts key */
1661 RegCloseKey(externalkey);
1662 externalkey = 0;
1663 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
1665 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1666 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1667 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
1668 ERR("Can't create external font reg key\n");
1669 goto end;
1672 /* enumerate the fonts and add external ones to the two keys */
1674 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1675 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1676 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1677 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1678 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1679 if(!face->external) continue;
1680 len = len_fam;
1681 if(strcmpiW(face->StyleName, RegularW))
1682 len = len_fam + strlenW(face->StyleName) + 1;
1683 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1684 strcpyW(valueW, family->FamilyName);
1685 if(len != len_fam) {
1686 strcatW(valueW, spaceW);
1687 strcatW(valueW, face->StyleName);
1689 strcatW(valueW, TrueType);
1690 if((path = strrchr(face->file, '/')) == NULL)
1691 path = face->file;
1692 else
1693 path++;
1694 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1696 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1697 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1698 RegSetValueExW(winkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1699 RegSetValueExW(externalkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1701 HeapFree(GetProcessHeap(), 0, file);
1702 HeapFree(GetProcessHeap(), 0, valueW);
1705 end:
1706 if(externalkey)
1707 RegCloseKey(externalkey);
1708 if(winkey)
1709 RegCloseKey(winkey);
1710 return;
1714 /*************************************************************
1715 * WineEngAddFontResourceEx
1718 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1720 if (ft_handle) /* do it only if we have freetype up and running */
1722 char *unixname;
1724 if(flags)
1725 FIXME("Ignoring flags %x\n", flags);
1727 if((unixname = wine_get_unix_file_name(file)))
1729 INT ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1730 HeapFree(GetProcessHeap(), 0, unixname);
1731 return ret;
1734 return 0;
1737 /*************************************************************
1738 * WineEngRemoveFontResourceEx
1741 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1743 FIXME(":stub\n");
1744 return TRUE;
1747 static const struct nls_update_font_list
1749 UINT ansi_cp, oem_cp;
1750 const char *oem, *fixed, *system;
1751 const char *courier, *serif, *small, *sserif;
1752 /* these are for font substitute */
1753 const char *shelldlg, *tmsrmn;
1754 } nls_update_font_list[] =
1756 /* Latin 1 (United States) */
1757 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
1758 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1759 "Tahoma","Times New Roman",
1761 /* Latin 1 (Multilingual) */
1762 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
1763 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1764 "Tahoma","Times New Roman", /* FIXME unverified */
1766 /* Eastern Europe */
1767 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
1768 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
1769 "Tahoma","Times New Roman", /* FIXME unverified */
1771 /* Cyrillic */
1772 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
1773 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
1774 "Tahoma","Times New Roman", /* FIXME unverified */
1776 /* Greek */
1777 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
1778 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
1779 "Tahoma","Times New Roman", /* FIXME unverified */
1781 /* Turkish */
1782 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
1783 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
1784 "Tahoma","Times New Roman", /* FIXME unverified */
1786 /* Hebrew */
1787 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
1788 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
1789 "Tahoma","Times New Roman", /* FIXME unverified */
1791 /* Arabic */
1792 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
1793 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
1794 "Tahoma","Times New Roman", /* FIXME unverified */
1796 /* Baltic */
1797 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
1798 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
1799 "Tahoma","Times New Roman", /* FIXME unverified */
1801 /* Vietnamese */
1802 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
1803 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1804 "Tahoma","Times New Roman", /* FIXME unverified */
1806 /* Thai */
1807 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
1808 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
1809 "Tahoma","Times New Roman", /* FIXME unverified */
1811 /* Japanese */
1812 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
1813 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
1814 "MS UI Gothic","MS Serif",
1816 /* Chinese Simplified */
1817 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
1818 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1819 "Tahoma", "Times New Roman", /* FIXME unverified */
1821 /* Korean */
1822 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
1823 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1824 "Gulim", "Batang",
1826 /* Chinese Traditional */
1827 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
1828 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1829 "Tahoma", "Times New Roman", /* FIXME unverified */
1833 static inline HKEY create_fonts_NT_registry_key(void)
1835 HKEY hkey = 0;
1837 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
1838 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1839 return hkey;
1842 static inline HKEY create_fonts_9x_registry_key(void)
1844 HKEY hkey = 0;
1846 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
1847 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1848 return hkey;
1851 static inline HKEY create_config_fonts_registry_key(void)
1853 HKEY hkey = 0;
1855 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
1856 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1857 return hkey;
1860 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
1862 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
1863 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
1864 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
1865 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
1868 static void update_font_info(void)
1870 char buf[40], cpbuf[40];
1871 DWORD len, type;
1872 HKEY hkey = 0;
1873 UINT i, ansi_cp = 0, oem_cp = 0;
1875 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
1876 return;
1878 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
1879 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
1880 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
1881 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
1882 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
1884 len = sizeof(buf);
1885 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
1887 if (!strcmp( buf, cpbuf )) /* already set correctly */
1889 RegCloseKey(hkey);
1890 return;
1892 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
1894 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
1896 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
1897 RegCloseKey(hkey);
1899 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
1901 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
1902 nls_update_font_list[i].oem_cp == oem_cp)
1904 HKEY hkey;
1906 hkey = create_config_fonts_registry_key();
1907 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
1908 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
1909 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
1910 RegCloseKey(hkey);
1912 hkey = create_fonts_NT_registry_key();
1913 add_font_list(hkey, &nls_update_font_list[i]);
1914 RegCloseKey(hkey);
1916 hkey = create_fonts_9x_registry_key();
1917 add_font_list(hkey, &nls_update_font_list[i]);
1918 RegCloseKey(hkey);
1920 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
1922 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
1923 strlen(nls_update_font_list[i].shelldlg)+1);
1924 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
1925 strlen(nls_update_font_list[i].tmsrmn)+1);
1926 RegCloseKey(hkey);
1928 return;
1931 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
1934 /*************************************************************
1935 * WineEngInit
1937 * Initialize FreeType library and create a list of available faces
1939 BOOL WineEngInit(void)
1941 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
1942 static const WCHAR pathW[] = {'P','a','t','h',0};
1943 HKEY hkey;
1944 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1945 LPVOID data;
1946 WCHAR windowsdir[MAX_PATH];
1947 char *unixname;
1948 HANDLE font_mutex;
1949 const char *data_dir;
1951 TRACE("\n");
1953 /* update locale dependent font info in registry */
1954 update_font_info();
1956 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
1957 if(!ft_handle) {
1958 WINE_MESSAGE(
1959 "Wine cannot find the FreeType font library. To enable Wine to\n"
1960 "use TrueType fonts please install a version of FreeType greater than\n"
1961 "or equal to 2.0.5.\n"
1962 "http://www.freetype.org\n");
1963 return FALSE;
1966 #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;}
1968 LOAD_FUNCPTR(FT_Vector_Unit)
1969 LOAD_FUNCPTR(FT_Done_Face)
1970 LOAD_FUNCPTR(FT_Get_Char_Index)
1971 LOAD_FUNCPTR(FT_Get_Module)
1972 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
1973 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
1974 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
1975 LOAD_FUNCPTR(FT_Init_FreeType)
1976 LOAD_FUNCPTR(FT_Load_Glyph)
1977 LOAD_FUNCPTR(FT_Matrix_Multiply)
1978 LOAD_FUNCPTR(FT_MulFix)
1979 LOAD_FUNCPTR(FT_New_Face)
1980 LOAD_FUNCPTR(FT_New_Memory_Face)
1981 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
1982 LOAD_FUNCPTR(FT_Outline_Transform)
1983 LOAD_FUNCPTR(FT_Outline_Translate)
1984 LOAD_FUNCPTR(FT_Select_Charmap)
1985 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
1986 LOAD_FUNCPTR(FT_Vector_Transform)
1988 #undef LOAD_FUNCPTR
1989 /* Don't warn if this one is missing */
1990 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
1991 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
1992 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
1993 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
1994 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
1995 #ifdef HAVE_FREETYPE_FTWINFNT_H
1996 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
1997 #endif
1998 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
1999 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2000 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2001 <= 2.0.3 has FT_Sqrt64 */
2002 goto sym_not_found;
2005 if(pFT_Init_FreeType(&library) != 0) {
2006 ERR("Can't init FreeType library\n");
2007 wine_dlclose(ft_handle, NULL, 0);
2008 ft_handle = NULL;
2009 return FALSE;
2011 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
2012 if (pFT_Library_Version)
2014 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2016 if (FT_Version.major<=0)
2018 FT_Version.major=2;
2019 FT_Version.minor=0;
2020 FT_Version.patch=5;
2022 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2023 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2024 ((FT_Version.minor << 8) & 0x00ff00) |
2025 ((FT_Version.patch ) & 0x0000ff);
2027 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2028 ERR("Failed to create font mutex\n");
2029 return FALSE;
2031 WaitForSingleObject(font_mutex, INFINITE);
2033 /* load the system bitmap fonts */
2034 load_system_fonts();
2036 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2037 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2038 strcatW(windowsdir, fontsW);
2039 if((unixname = wine_get_unix_file_name(windowsdir)))
2041 ReadFontDir(unixname, FALSE);
2042 HeapFree(GetProcessHeap(), 0, unixname);
2045 /* load the system truetype fonts */
2046 data_dir = wine_get_data_dir();
2047 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2048 strcpy(unixname, data_dir);
2049 strcat(unixname, "/fonts/");
2050 ReadFontDir(unixname, FALSE);
2051 HeapFree(GetProcessHeap(), 0, unixname);
2054 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2055 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2056 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2057 will skip these. */
2058 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2059 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2060 &hkey) == ERROR_SUCCESS) {
2061 LPWSTR valueW;
2062 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2063 &valuelen, &datalen, NULL, NULL);
2065 valuelen++; /* returned value doesn't include room for '\0' */
2066 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2067 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2068 if (valueW && data)
2070 dlen = datalen * sizeof(WCHAR);
2071 vlen = valuelen;
2072 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
2073 &dlen) == ERROR_SUCCESS) {
2074 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
2076 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
2078 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2079 HeapFree(GetProcessHeap(), 0, unixname);
2082 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
2084 WCHAR pathW[MAX_PATH];
2085 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2086 BOOL added = FALSE;
2088 sprintfW(pathW, fmtW, windowsdir, data);
2089 if((unixname = wine_get_unix_file_name(pathW)))
2091 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2092 HeapFree(GetProcessHeap(), 0, unixname);
2094 if (!added)
2095 load_font_from_data_dir(data);
2097 /* reset dlen and vlen */
2098 dlen = datalen;
2099 vlen = valuelen;
2102 HeapFree(GetProcessHeap(), 0, data);
2103 HeapFree(GetProcessHeap(), 0, valueW);
2104 RegCloseKey(hkey);
2107 load_fontconfig_fonts();
2109 /* then look in any directories that we've specified in the config file */
2110 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2111 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2113 DWORD len;
2114 LPWSTR valueW;
2115 LPSTR valueA, ptr;
2117 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2119 len += sizeof(WCHAR);
2120 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2121 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2123 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2124 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2125 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2126 TRACE( "got font path %s\n", debugstr_a(valueA) );
2127 ptr = valueA;
2128 while (ptr)
2130 LPSTR next = strchr( ptr, ':' );
2131 if (next) *next++ = 0;
2132 ReadFontDir( ptr, TRUE );
2133 ptr = next;
2135 HeapFree( GetProcessHeap(), 0, valueA );
2137 HeapFree( GetProcessHeap(), 0, valueW );
2139 RegCloseKey(hkey);
2142 DumpFontList();
2143 LoadSubstList();
2144 DumpSubstList();
2145 LoadReplaceList();
2146 update_reg_entries();
2148 init_system_links();
2150 ReleaseMutex(font_mutex);
2151 return TRUE;
2152 sym_not_found:
2153 WINE_MESSAGE(
2154 "Wine cannot find certain functions that it needs inside the FreeType\n"
2155 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2156 "FreeType to at least version 2.0.5.\n"
2157 "http://www.freetype.org\n");
2158 wine_dlclose(ft_handle, NULL, 0);
2159 ft_handle = NULL;
2160 return FALSE;
2164 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2166 TT_OS2 *pOS2;
2167 TT_HoriHeader *pHori;
2169 LONG ppem;
2171 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2172 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2174 if(height == 0) height = 16;
2176 /* Calc. height of EM square:
2178 * For +ve lfHeight we have
2179 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2180 * Re-arranging gives:
2181 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2183 * For -ve lfHeight we have
2184 * |lfHeight| = ppem
2185 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2186 * with il = winAscent + winDescent - units_per_em]
2190 if(height > 0) {
2191 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2192 ppem = ft_face->units_per_EM * height /
2193 (pHori->Ascender - pHori->Descender);
2194 else
2195 ppem = ft_face->units_per_EM * height /
2196 (pOS2->usWinAscent + pOS2->usWinDescent);
2198 else
2199 ppem = -height;
2201 return ppem;
2204 static struct font_mapping *map_font( const char *name )
2206 struct font_mapping *mapping;
2207 struct stat st;
2208 int fd;
2210 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2211 if (fstat( fd, &st ) == -1) goto error;
2213 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2215 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2217 mapping->refcount++;
2218 close( fd );
2219 return mapping;
2222 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2223 goto error;
2225 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2226 close( fd );
2228 if (mapping->data == MAP_FAILED)
2230 HeapFree( GetProcessHeap(), 0, mapping );
2231 return NULL;
2233 mapping->refcount = 1;
2234 mapping->dev = st.st_dev;
2235 mapping->ino = st.st_ino;
2236 mapping->size = st.st_size;
2237 list_add_tail( &mappings_list, &mapping->entry );
2238 return mapping;
2240 error:
2241 close( fd );
2242 return NULL;
2245 static void unmap_font( struct font_mapping *mapping )
2247 if (!--mapping->refcount)
2249 list_remove( &mapping->entry );
2250 munmap( mapping->data, mapping->size );
2251 HeapFree( GetProcessHeap(), 0, mapping );
2255 static LONG load_VDMX(GdiFont*, LONG);
2257 static FT_Face OpenFontFile(GdiFont *font, char *file, FT_Long face_index, LONG width, LONG height)
2259 FT_Error err;
2260 FT_Face ft_face;
2262 TRACE("%s, %ld, %d x %d\n", debugstr_a(file), face_index, width, height);
2264 if (!(font->mapping = map_font( file )))
2266 WARN("failed to map %s\n", debugstr_a(file));
2267 return 0;
2270 err = pFT_New_Memory_Face(library, font->mapping->data, font->mapping->size, face_index, &ft_face);
2271 if(err) {
2272 ERR("FT_New_Face rets %d\n", err);
2273 return 0;
2276 /* set it here, as load_VDMX needs it */
2277 font->ft_face = ft_face;
2279 if(FT_IS_SCALABLE(ft_face)) {
2280 /* load the VDMX table if we have one */
2281 font->ppem = load_VDMX(font, height);
2282 if(font->ppem == 0)
2283 font->ppem = calc_ppem_for_height(ft_face, height);
2285 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
2286 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
2287 } else {
2288 font->ppem = height;
2289 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
2290 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
2292 return ft_face;
2296 static int get_nearest_charset(Face *face, int *cp)
2298 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2299 a single face with the requested charset. The idea is to check if
2300 the selected font supports the current ANSI codepage, if it does
2301 return the corresponding charset, else return the first charset */
2303 CHARSETINFO csi;
2304 int acp = GetACP(), i;
2305 DWORD fs0;
2307 *cp = acp;
2308 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
2309 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2310 return csi.ciCharset;
2312 for(i = 0; i < 32; i++) {
2313 fs0 = 1L << i;
2314 if(face->fs.fsCsb[0] & fs0) {
2315 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
2316 *cp = csi.ciACP;
2317 return csi.ciCharset;
2319 else
2320 FIXME("TCI failing on %x\n", fs0);
2324 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2325 face->fs.fsCsb[0], face->file);
2326 *cp = acp;
2327 return DEFAULT_CHARSET;
2330 static GdiFont *alloc_font(void)
2332 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
2333 ret->gmsize = 1;
2334 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
2335 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
2336 ret->potm = NULL;
2337 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
2338 ret->total_kern_pairs = (DWORD)-1;
2339 ret->kern_pairs = NULL;
2340 list_init(&ret->hfontlist);
2341 list_init(&ret->child_fonts);
2342 return ret;
2345 static void free_font(GdiFont *font)
2347 struct list *cursor, *cursor2;
2348 int i;
2350 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
2352 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
2353 struct list *first_hfont;
2354 HFONTLIST *hfontlist;
2355 list_remove(cursor);
2356 if(child->font)
2358 first_hfont = list_head(&child->font->hfontlist);
2359 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2360 DeleteObject(hfontlist->hfont);
2361 HeapFree(GetProcessHeap(), 0, hfontlist);
2362 free_font(child->font);
2364 HeapFree(GetProcessHeap(), 0, child->file_name);
2365 HeapFree(GetProcessHeap(), 0, child);
2368 if (font->ft_face) pFT_Done_Face(font->ft_face);
2369 if (font->mapping) unmap_font( font->mapping );
2370 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
2371 HeapFree(GetProcessHeap(), 0, font->potm);
2372 HeapFree(GetProcessHeap(), 0, font->name);
2373 for (i = 0; i < font->gmsize; i++)
2374 HeapFree(GetProcessHeap(),0,font->gm[i]);
2375 HeapFree(GetProcessHeap(), 0, font->gm);
2376 HeapFree(GetProcessHeap(), 0, font);
2380 /*************************************************************
2381 * load_VDMX
2383 * load the vdmx entry for the specified height
2386 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2387 ( ( (FT_ULong)_x4 << 24 ) | \
2388 ( (FT_ULong)_x3 << 16 ) | \
2389 ( (FT_ULong)_x2 << 8 ) | \
2390 (FT_ULong)_x1 )
2392 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2394 typedef struct {
2395 BYTE bCharSet;
2396 BYTE xRatio;
2397 BYTE yStartRatio;
2398 BYTE yEndRatio;
2399 } Ratios;
2401 typedef struct {
2402 WORD recs;
2403 BYTE startsz;
2404 BYTE endsz;
2405 } VDMX_group;
2407 static LONG load_VDMX(GdiFont *font, LONG height)
2409 WORD hdr[3], tmp;
2410 VDMX_group group;
2411 BYTE devXRatio, devYRatio;
2412 USHORT numRecs, numRatios;
2413 DWORD result, offset = -1;
2414 LONG ppem = 0;
2415 int i;
2417 /* For documentation on VDMX records, see
2418 * http://www.microsoft.com/OpenType/OTSpec/vdmx.htm
2421 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
2423 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2424 return ppem;
2426 /* FIXME: need the real device aspect ratio */
2427 devXRatio = 1;
2428 devYRatio = 1;
2430 numRecs = GET_BE_WORD(hdr[1]);
2431 numRatios = GET_BE_WORD(hdr[2]);
2433 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
2434 for(i = 0; i < numRatios; i++) {
2435 Ratios ratio;
2437 offset = (3 * 2) + (i * sizeof(Ratios));
2438 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2439 offset = -1;
2441 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2443 if((ratio.xRatio == 0 &&
2444 ratio.yStartRatio == 0 &&
2445 ratio.yEndRatio == 0) ||
2446 (devXRatio == ratio.xRatio &&
2447 devYRatio >= ratio.yStartRatio &&
2448 devYRatio <= ratio.yEndRatio))
2450 offset = (3 * 2) + (numRatios * 4) + (i * 2);
2451 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
2452 offset = GET_BE_WORD(tmp);
2453 break;
2457 if(offset == -1) {
2458 FIXME("No suitable ratio found\n");
2459 return ppem;
2462 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
2463 USHORT recs;
2464 BYTE startsz, endsz;
2465 WORD *vTable;
2467 recs = GET_BE_WORD(group.recs);
2468 startsz = group.startsz;
2469 endsz = group.endsz;
2471 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
2473 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
2474 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
2475 if(result == GDI_ERROR) {
2476 FIXME("Failed to retrieve vTable\n");
2477 goto end;
2480 if(height > 0) {
2481 for(i = 0; i < recs; i++) {
2482 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2483 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2484 ppem = GET_BE_WORD(vTable[i * 3]);
2486 if(yMax + -yMin == height) {
2487 font->yMax = yMax;
2488 font->yMin = yMin;
2489 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2490 break;
2492 if(yMax + -yMin > height) {
2493 if(--i < 0) {
2494 ppem = 0;
2495 goto end; /* failed */
2497 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2498 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2499 ppem = GET_BE_WORD(vTable[i * 3]);
2500 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2501 break;
2504 if(!font->yMax) {
2505 ppem = 0;
2506 TRACE("ppem not found for height %d\n", height);
2508 } else {
2509 ppem = -height;
2510 if(ppem < startsz || ppem > endsz)
2511 goto end;
2513 for(i = 0; i < recs; i++) {
2514 USHORT yPelHeight;
2515 yPelHeight = GET_BE_WORD(vTable[i * 3]);
2517 if(yPelHeight > ppem)
2518 break; /* failed */
2520 if(yPelHeight == ppem) {
2521 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2522 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2523 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
2524 break;
2528 end:
2529 HeapFree(GetProcessHeap(), 0, vTable);
2532 return ppem;
2535 static BOOL fontcmp(GdiFont *font, FONT_DESC *fd)
2537 if(font->font_desc.hash != fd->hash) return TRUE;
2538 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
2539 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
2540 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
2541 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
2544 static void calc_hash(FONT_DESC *pfd)
2546 DWORD hash = 0, *ptr, two_chars;
2547 WORD *pwc;
2548 unsigned int i;
2550 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
2551 hash ^= *ptr;
2552 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
2553 hash ^= *ptr;
2554 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
2555 two_chars = *ptr;
2556 pwc = (WCHAR *)&two_chars;
2557 if(!*pwc) break;
2558 *pwc = toupperW(*pwc);
2559 pwc++;
2560 *pwc = toupperW(*pwc);
2561 hash ^= two_chars;
2562 if(!*pwc) break;
2564 hash ^= !pfd->can_use_bitmap;
2565 pfd->hash = hash;
2566 return;
2569 static GdiFont *find_in_cache(HFONT hfont, LOGFONTW *plf, XFORM *pxf, BOOL can_use_bitmap)
2571 GdiFont *ret;
2572 FONT_DESC fd;
2573 HFONTLIST *hflist;
2574 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2576 memcpy(&fd.lf, plf, sizeof(LOGFONTW));
2577 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
2578 fd.can_use_bitmap = can_use_bitmap;
2579 calc_hash(&fd);
2581 /* try the in-use list */
2582 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
2583 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2584 if(!fontcmp(ret, &fd)) {
2585 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2586 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
2587 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2588 if(hflist->hfont == hfont)
2589 return ret;
2591 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2592 hflist->hfont = hfont;
2593 list_add_head(&ret->hfontlist, &hflist->entry);
2594 return ret;
2598 /* then the unused list */
2599 font_elem_ptr = list_head(&unused_gdi_font_list);
2600 while(font_elem_ptr) {
2601 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2602 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2603 if(!fontcmp(ret, &fd)) {
2604 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2605 assert(list_empty(&ret->hfontlist));
2606 TRACE("Found %p in unused list\n", ret);
2607 list_remove(&ret->entry);
2608 list_add_head(&gdi_font_list, &ret->entry);
2609 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2610 hflist->hfont = hfont;
2611 list_add_head(&ret->hfontlist, &hflist->entry);
2612 return ret;
2615 return NULL;
2619 /*************************************************************
2620 * create_child_font_list
2622 static BOOL create_child_font_list(GdiFont *font)
2624 BOOL ret = FALSE;
2625 SYSTEM_LINKS *font_link;
2626 CHILD_FONT *font_link_entry, *new_child;
2628 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2630 if(!strcmpW(font_link->font_name, font->name))
2632 TRACE("found entry in system list\n");
2633 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2635 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2636 new_child->file_name = strdupA(font_link_entry->file_name);
2637 new_child->index = font_link_entry->index;
2638 new_child->font = NULL;
2639 list_add_tail(&font->child_fonts, &new_child->entry);
2640 TRACE("font %s %d\n", debugstr_a(new_child->file_name), new_child->index);
2642 ret = TRUE;
2643 break;
2647 return ret;
2650 /*************************************************************
2651 * WineEngCreateFontInstance
2654 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
2656 GdiFont *ret;
2657 Face *face, *best, *best_bitmap;
2658 Family *family, *last_resort_family;
2659 struct list *family_elem_ptr, *face_elem_ptr;
2660 INT height, width = 0;
2661 unsigned int score = 0, new_score;
2662 signed int diff = 0, newdiff;
2663 BOOL bd, it, can_use_bitmap;
2664 LOGFONTW lf;
2665 CHARSETINFO csi;
2666 HFONTLIST *hflist;
2668 LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry)
2670 struct list *first_hfont = list_head(&ret->hfontlist);
2671 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2672 if(hflist->hfont == hfont)
2673 return ret;
2676 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
2677 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
2679 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
2680 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
2681 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
2682 lf.lfEscapement);
2684 /* check the cache first */
2685 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
2686 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
2687 return ret;
2690 TRACE("not in cache\n");
2691 if(list_empty(&font_list)) /* No fonts installed */
2693 TRACE("No fonts installed\n");
2694 return NULL;
2696 if(!have_installed_roman_font)
2698 TRACE("No roman font installed\n");
2699 return NULL;
2702 ret = alloc_font();
2704 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
2705 memcpy(&ret->font_desc.lf, &lf, sizeof(LOGFONTW));
2706 ret->font_desc.can_use_bitmap = can_use_bitmap;
2707 calc_hash(&ret->font_desc);
2708 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2709 hflist->hfont = hfont;
2710 list_add_head(&ret->hfontlist, &hflist->entry);
2713 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
2714 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
2715 original value lfCharSet. Note this is a special case for
2716 Symbol and doesn't happen at least for "Wingdings*" */
2718 if(!strcmpiW(lf.lfFaceName, SymbolW))
2719 lf.lfCharSet = SYMBOL_CHARSET;
2721 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
2722 switch(lf.lfCharSet) {
2723 case DEFAULT_CHARSET:
2724 csi.fs.fsCsb[0] = 0;
2725 break;
2726 default:
2727 FIXME("Untranslated charset %d\n", lf.lfCharSet);
2728 csi.fs.fsCsb[0] = 0;
2729 break;
2733 family = NULL;
2734 if(lf.lfFaceName[0] != '\0') {
2735 FontSubst *psub;
2736 SYSTEM_LINKS *font_link;
2737 CHILD_FONT *font_link_entry;
2739 psub = get_font_subst(&font_subst_list, lf.lfFaceName, lf.lfCharSet);
2741 if(psub) {
2742 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
2743 debugstr_w(psub->to.name));
2744 strcpyW(lf.lfFaceName, psub->to.name);
2747 /* We want a match on name and charset or just name if
2748 charset was DEFAULT_CHARSET. If the latter then
2749 we fixup the returned charset later in get_nearest_charset
2750 where we'll either use the charset of the current ansi codepage
2751 or if that's unavailable the first charset that the font supports.
2753 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2754 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2755 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2756 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2757 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2758 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
2759 if(face->scalable || can_use_bitmap)
2760 goto found;
2766 * Try check the SystemLink list first for a replacement font.
2767 * We may find good replacements there.
2769 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2771 if(!strcmpiW(font_link->font_name, lf.lfFaceName))
2773 TRACE("found entry in system list\n");
2774 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2776 face = find_face_from_path_index(font_link_entry->file_name,
2777 font_link_entry->index);
2778 if (face)
2780 family = face->family;
2781 if(csi.fs.fsCsb[0] &
2782 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
2784 if(face->scalable || can_use_bitmap)
2785 goto found;
2793 /* If requested charset was DEFAULT_CHARSET then try using charset
2794 corresponding to the current ansi codepage */
2795 if(!csi.fs.fsCsb[0]) {
2796 INT acp = GetACP();
2797 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
2798 FIXME("TCI failed on codepage %d\n", acp);
2799 csi.fs.fsCsb[0] = 0;
2800 } else
2801 lf.lfCharSet = csi.ciCharset;
2804 /* Face families are in the top 4 bits of lfPitchAndFamily,
2805 so mask with 0xF0 before testing */
2807 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
2808 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
2809 strcpyW(lf.lfFaceName, defFixed);
2810 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
2811 strcpyW(lf.lfFaceName, defSerif);
2812 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
2813 strcpyW(lf.lfFaceName, defSans);
2814 else
2815 strcpyW(lf.lfFaceName, defSans);
2816 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2817 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2818 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2819 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2820 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2821 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2822 if(face->scalable || can_use_bitmap)
2823 goto found;
2828 last_resort_family = NULL;
2829 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2830 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2831 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2832 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2833 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
2834 if(face->scalable)
2835 goto found;
2836 if(can_use_bitmap && !last_resort_family)
2837 last_resort_family = family;
2842 if(last_resort_family) {
2843 family = last_resort_family;
2844 csi.fs.fsCsb[0] = 0;
2845 goto found;
2848 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2849 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2850 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2851 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2852 if(face->scalable) {
2853 csi.fs.fsCsb[0] = 0;
2854 WARN("just using first face for now\n");
2855 goto found;
2857 if(can_use_bitmap && !last_resort_family)
2858 last_resort_family = family;
2861 if(!last_resort_family) {
2862 FIXME("can't find a single appropriate font - bailing\n");
2863 free_font(ret);
2864 return NULL;
2867 WARN("could only find a bitmap font - this will probably look awful!\n");
2868 family = last_resort_family;
2869 csi.fs.fsCsb[0] = 0;
2871 found:
2872 it = lf.lfItalic ? 1 : 0;
2873 bd = lf.lfWeight > 550 ? 1 : 0;
2875 height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
2876 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
2878 face = best = best_bitmap = NULL;
2879 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2881 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
2883 new_score = (face->Italic ^ it) + (face->Bold ^ bd);
2884 if(!best || new_score <= score)
2886 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
2887 face->Italic, face->Bold, it, bd);
2888 score = new_score;
2889 best = face;
2890 if(best->scalable && score == 0) break;
2891 if(!best->scalable)
2893 if(height > 0)
2894 newdiff = height - (signed int)(best->size.height);
2895 else
2896 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
2897 if(!best_bitmap || new_score < score ||
2898 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
2900 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
2901 diff = newdiff;
2902 best_bitmap = best;
2903 if(score == 0 && diff == 0) break;
2909 if(best)
2910 face = best->scalable ? best : best_bitmap;
2911 ret->fake_italic = (it && !face->Italic);
2912 ret->fake_bold = (bd && !face->Bold);
2914 memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
2916 if(csi.fs.fsCsb[0]) {
2917 ret->charset = lf.lfCharSet;
2918 ret->codepage = csi.ciACP;
2920 else
2921 ret->charset = get_nearest_charset(face, &ret->codepage);
2923 TRACE("Chosen: %s %s (%s:%ld)\n", debugstr_w(family->FamilyName),
2924 debugstr_w(face->StyleName), face->file, face->face_index);
2926 if(!face->scalable) {
2927 width = face->size.x_ppem >> 6;
2928 height = face->size.y_ppem >> 6;
2930 ret->ft_face = OpenFontFile(ret, face->file, face->face_index, width, height);
2932 if (!ret->ft_face)
2934 free_font( ret );
2935 return 0;
2938 if (ret->charset == SYMBOL_CHARSET &&
2939 !pFT_Select_Charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
2940 /* No ops */
2942 else if (!pFT_Select_Charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
2943 /* No ops */
2945 else {
2946 pFT_Select_Charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
2949 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
2950 ret->name = strdupW(family->FamilyName);
2951 ret->underline = lf.lfUnderline ? 0xff : 0;
2952 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
2953 create_child_font_list(ret);
2955 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
2957 ret->aveWidth = FT_IS_SCALABLE(ret->ft_face) ? abs(lf.lfWidth) : 0;
2958 list_add_head(&gdi_font_list, &ret->entry);
2959 return ret;
2962 static void dump_gdi_font_list(void)
2964 GdiFont *gdiFont;
2965 struct list *elem_ptr;
2967 TRACE("---------- gdiFont Cache ----------\n");
2968 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
2969 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
2970 TRACE("gdiFont=%p %s %d\n",
2971 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
2974 TRACE("---------- Unused gdiFont Cache ----------\n");
2975 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
2976 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
2977 TRACE("gdiFont=%p %s %d\n",
2978 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
2982 /*************************************************************
2983 * WineEngDestroyFontInstance
2985 * free the gdiFont associated with this handle
2988 BOOL WineEngDestroyFontInstance(HFONT handle)
2990 GdiFont *gdiFont;
2991 HFONTLIST *hflist;
2992 BOOL ret = FALSE;
2993 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2994 int i = 0;
2996 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
2998 struct list *first_hfont = list_head(&gdiFont->hfontlist);
2999 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
3000 if(hflist->hfont == handle)
3002 TRACE("removing child font %p from child list\n", gdiFont);
3003 list_remove(&gdiFont->entry);
3004 return TRUE;
3008 TRACE("destroying hfont=%p\n", handle);
3009 if(TRACE_ON(font))
3010 dump_gdi_font_list();
3012 font_elem_ptr = list_head(&gdi_font_list);
3013 while(font_elem_ptr) {
3014 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3015 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3017 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3018 while(hfontlist_elem_ptr) {
3019 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3020 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3021 if(hflist->hfont == handle) {
3022 list_remove(&hflist->entry);
3023 HeapFree(GetProcessHeap(), 0, hflist);
3024 ret = TRUE;
3027 if(list_empty(&gdiFont->hfontlist)) {
3028 TRACE("Moving to Unused list\n");
3029 list_remove(&gdiFont->entry);
3030 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3035 font_elem_ptr = list_head(&unused_gdi_font_list);
3036 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3037 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3038 while(font_elem_ptr) {
3039 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3040 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3041 TRACE("freeing %p\n", gdiFont);
3042 list_remove(&gdiFont->entry);
3043 free_font(gdiFont);
3045 return ret;
3048 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
3049 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
3051 OUTLINETEXTMETRICW *potm = NULL;
3052 UINT size;
3053 TEXTMETRICW tm, *ptm;
3054 GdiFont *font = alloc_font();
3055 LONG width, height;
3057 if(face->scalable) {
3058 height = 100;
3059 width = 0;
3060 } else {
3061 height = face->size.y_ppem >> 6;
3062 width = face->size.x_ppem >> 6;
3065 if (!(font->ft_face = OpenFontFile(font, face->file, face->face_index, width, height)))
3067 free_font(font);
3068 return;
3071 font->name = strdupW(face->family->FamilyName);
3073 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
3075 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
3076 if(size) {
3077 potm = HeapAlloc(GetProcessHeap(), 0, size);
3078 WineEngGetOutlineTextMetrics(font, size, potm);
3079 ptm = (TEXTMETRICW*)&potm->otmTextMetrics;
3080 } else {
3081 WineEngGetTextMetrics(font, &tm);
3082 ptm = &tm;
3085 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = ptm->tmHeight;
3086 pntm->ntmTm.tmAscent = ptm->tmAscent;
3087 pntm->ntmTm.tmDescent = ptm->tmDescent;
3088 pntm->ntmTm.tmInternalLeading = ptm->tmInternalLeading;
3089 pntm->ntmTm.tmExternalLeading = ptm->tmExternalLeading;
3090 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = ptm->tmAveCharWidth;
3091 pntm->ntmTm.tmMaxCharWidth = ptm->tmMaxCharWidth;
3092 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = ptm->tmWeight;
3093 pntm->ntmTm.tmOverhang = ptm->tmOverhang;
3094 pntm->ntmTm.tmDigitizedAspectX = ptm->tmDigitizedAspectX;
3095 pntm->ntmTm.tmDigitizedAspectY = ptm->tmDigitizedAspectY;
3096 pntm->ntmTm.tmFirstChar = ptm->tmFirstChar;
3097 pntm->ntmTm.tmLastChar = ptm->tmLastChar;
3098 pntm->ntmTm.tmDefaultChar = ptm->tmDefaultChar;
3099 pntm->ntmTm.tmBreakChar = ptm->tmBreakChar;
3100 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = ptm->tmItalic;
3101 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = ptm->tmUnderlined;
3102 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = ptm->tmStruckOut;
3103 pntm->ntmTm.tmPitchAndFamily = ptm->tmPitchAndFamily;
3104 pelf->elfLogFont.lfPitchAndFamily = (ptm->tmPitchAndFamily & 0xf1) + 1;
3105 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = ptm->tmCharSet;
3106 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
3107 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
3108 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
3110 *ptype = ptm->tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
3111 if(!(ptm->tmPitchAndFamily & TMPF_VECTOR))
3112 *ptype |= RASTER_FONTTYPE;
3114 pntm->ntmTm.ntmFlags = ptm->tmItalic ? NTM_ITALIC : 0;
3115 if(ptm->tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
3116 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
3118 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
3119 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
3120 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
3122 if(potm) {
3123 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
3125 lstrcpynW(pelf->elfLogFont.lfFaceName,
3126 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
3127 LF_FACESIZE);
3128 lstrcpynW(pelf->elfFullName,
3129 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
3130 LF_FULLFACESIZE);
3131 lstrcpynW(pelf->elfStyle,
3132 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
3133 LF_FACESIZE);
3135 HeapFree(GetProcessHeap(), 0, potm);
3136 } else {
3137 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
3139 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
3140 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FACESIZE);
3141 pelf->elfStyle[0] = '\0';
3144 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
3146 free_font(font);
3149 /*************************************************************
3150 * WineEngEnumFonts
3153 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3155 Family *family;
3156 Face *face;
3157 struct list *family_elem_ptr, *face_elem_ptr;
3158 ENUMLOGFONTEXW elf;
3159 NEWTEXTMETRICEXW ntm;
3160 DWORD type, ret = 1;
3161 FONTSIGNATURE fs;
3162 CHARSETINFO csi;
3163 LOGFONTW lf;
3164 int i;
3166 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
3168 if(plf->lfFaceName[0]) {
3169 FontSubst *psub;
3170 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
3172 if(psub) {
3173 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
3174 debugstr_w(psub->to.name));
3175 memcpy(&lf, plf, sizeof(lf));
3176 strcpyW(lf.lfFaceName, psub->to.name);
3177 plf = &lf;
3180 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3181 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3182 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
3183 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3184 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3185 GetEnumStructs(face, &elf, &ntm, &type);
3186 for(i = 0; i < 32; i++) {
3187 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3188 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3189 strcpyW(elf.elfScript, OEM_DOSW);
3190 i = 32; /* break out of loop */
3191 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3192 continue;
3193 else {
3194 fs.fsCsb[0] = 1L << i;
3195 fs.fsCsb[1] = 0;
3196 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3197 TCI_SRCFONTSIG))
3198 csi.ciCharset = DEFAULT_CHARSET;
3199 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3200 if(csi.ciCharset != DEFAULT_CHARSET) {
3201 elf.elfLogFont.lfCharSet =
3202 ntm.ntmTm.tmCharSet = csi.ciCharset;
3203 if(ElfScriptsW[i])
3204 strcpyW(elf.elfScript, ElfScriptsW[i]);
3205 else
3206 FIXME("Unknown elfscript for bit %d\n", i);
3209 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3210 debugstr_w(elf.elfLogFont.lfFaceName),
3211 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3212 csi.ciCharset, type, debugstr_w(elf.elfScript),
3213 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3214 ntm.ntmTm.ntmFlags);
3215 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
3216 if(!ret) goto end;
3221 } else {
3222 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3223 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3224 face_elem_ptr = list_head(&family->faces);
3225 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3226 GetEnumStructs(face, &elf, &ntm, &type);
3227 for(i = 0; i < 32; i++) {
3228 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3229 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3230 strcpyW(elf.elfScript, OEM_DOSW);
3231 i = 32; /* break out of loop */
3232 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3233 continue;
3234 else {
3235 fs.fsCsb[0] = 1L << i;
3236 fs.fsCsb[1] = 0;
3237 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3238 TCI_SRCFONTSIG))
3239 csi.ciCharset = DEFAULT_CHARSET;
3240 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3241 if(csi.ciCharset != DEFAULT_CHARSET) {
3242 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
3243 csi.ciCharset;
3244 if(ElfScriptsW[i])
3245 strcpyW(elf.elfScript, ElfScriptsW[i]);
3246 else
3247 FIXME("Unknown elfscript for bit %d\n", i);
3250 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3251 debugstr_w(elf.elfLogFont.lfFaceName),
3252 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3253 csi.ciCharset, type, debugstr_w(elf.elfScript),
3254 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3255 ntm.ntmTm.ntmFlags);
3256 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
3257 if(!ret) goto end;
3261 end:
3262 return ret;
3265 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
3267 pt->x.value = vec->x >> 6;
3268 pt->x.fract = (vec->x & 0x3f) << 10;
3269 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
3270 pt->y.value = vec->y >> 6;
3271 pt->y.fract = (vec->y & 0x3f) << 10;
3272 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
3273 return;
3276 /***************************************************
3277 * According to the MSDN documentation on WideCharToMultiByte,
3278 * certain codepages cannot set the default_used parameter.
3279 * This returns TRUE if the codepage can set that parameter, false else
3280 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
3282 static BOOL codepage_sets_default_used(UINT codepage)
3284 switch (codepage)
3286 case CP_UTF7:
3287 case CP_UTF8:
3288 case CP_SYMBOL:
3289 return FALSE;
3290 default:
3291 return TRUE;
3295 static FT_UInt get_glyph_index(GdiFont *font, UINT glyph)
3297 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
3298 WCHAR wc = (WCHAR)glyph;
3299 BOOL default_used;
3300 BOOL *default_used_pointer;
3301 FT_UInt ret;
3302 char buf;
3303 default_used_pointer = NULL;
3304 default_used = FALSE;
3305 if (codepage_sets_default_used(font->codepage))
3306 default_used_pointer = &default_used;
3307 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
3308 ret = 0;
3309 else
3310 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
3311 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
3312 return ret;
3315 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
3316 glyph = glyph + 0xf000;
3317 return pFT_Get_Char_Index(font->ft_face, glyph);
3320 /*************************************************************
3321 * WineEngGetGlyphIndices
3323 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
3325 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
3326 LPWORD pgi, DWORD flags)
3328 int i;
3329 WCHAR default_char = 0;
3330 TEXTMETRICW textm;
3332 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0x001f; /* Indicate non existence */
3334 for(i = 0; i < count; i++)
3336 pgi[i] = get_glyph_index(font, lpstr[i]);
3337 if (pgi[i] == 0)
3339 if (!default_char)
3341 WineEngGetTextMetrics(font, &textm);
3342 default_char = textm.tmDefaultChar;
3344 pgi[i] = default_char;
3347 return count;
3350 /*************************************************************
3351 * WineEngGetGlyphOutline
3353 * Behaves in exactly the same way as the win32 api GetGlyphOutline
3354 * except that the first parameter is the HWINEENGFONT of the font in
3355 * question rather than an HDC.
3358 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
3359 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
3360 const MAT2* lpmat)
3362 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
3363 FT_Face ft_face = incoming_font->ft_face;
3364 GdiFont *font = incoming_font;
3365 FT_UInt glyph_index;
3366 DWORD width, height, pitch, needed = 0;
3367 FT_Bitmap ft_bitmap;
3368 FT_Error err;
3369 INT left, right, top = 0, bottom = 0;
3370 FT_Angle angle = 0;
3371 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
3372 float widthRatio = 1.0;
3373 FT_Matrix transMat = identityMat;
3374 BOOL needsTransform = FALSE;
3377 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
3378 buflen, buf, lpmat);
3380 if(format & GGO_GLYPH_INDEX) {
3381 glyph_index = glyph;
3382 format &= ~GGO_GLYPH_INDEX;
3383 } else {
3384 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
3385 ft_face = font->ft_face;
3388 if(glyph_index >= font->gmsize * GM_BLOCK_SIZE) {
3389 font->gmsize = (glyph_index / GM_BLOCK_SIZE + 1);
3390 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
3391 font->gmsize * sizeof(GM*));
3392 } else {
3393 if(format == GGO_METRICS && font->gm[glyph_index / GM_BLOCK_SIZE] != NULL && FONT_GM(font,glyph_index)->init ) {
3394 *lpgm = FONT_GM(font,glyph_index)->gm;
3395 return 1; /* FIXME */
3399 if (!font->gm[glyph_index / GM_BLOCK_SIZE])
3400 font->gm[glyph_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3402 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP) || font->aveWidth || lpmat)
3403 load_flags |= FT_LOAD_NO_BITMAP;
3405 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
3407 if(err) {
3408 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
3409 return GDI_ERROR;
3412 /* Scaling factor */
3413 if (font->aveWidth && font->potm) {
3414 widthRatio = (float)font->aveWidth * font->font_desc.matrix.eM11 / (float) font->potm->otmTextMetrics.tmAveCharWidth;
3417 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
3418 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
3420 FONT_GM(font,glyph_index)->adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
3421 FONT_GM(font,glyph_index)->lsb = left >> 6;
3422 FONT_GM(font,glyph_index)->bbx = (right - left) >> 6;
3424 /* Scaling transform */
3425 if(font->aveWidth) {
3426 FT_Matrix scaleMat;
3427 scaleMat.xx = FT_FixedFromFloat(widthRatio);
3428 scaleMat.xy = 0;
3429 scaleMat.yx = 0;
3430 scaleMat.yy = (1 << 16);
3432 pFT_Matrix_Multiply(&scaleMat, &transMat);
3433 needsTransform = TRUE;
3436 /* Slant transform */
3437 if (font->fake_italic) {
3438 FT_Matrix slantMat;
3440 slantMat.xx = (1 << 16);
3441 slantMat.xy = ((1 << 16) >> 2);
3442 slantMat.yx = 0;
3443 slantMat.yy = (1 << 16);
3444 pFT_Matrix_Multiply(&slantMat, &transMat);
3445 needsTransform = TRUE;
3448 /* Rotation transform */
3449 if(font->orientation) {
3450 FT_Matrix rotationMat;
3451 FT_Vector vecAngle;
3452 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
3453 pFT_Vector_Unit(&vecAngle, angle);
3454 rotationMat.xx = vecAngle.x;
3455 rotationMat.xy = -vecAngle.y;
3456 rotationMat.yx = -rotationMat.xy;
3457 rotationMat.yy = rotationMat.xx;
3459 pFT_Matrix_Multiply(&rotationMat, &transMat);
3460 needsTransform = TRUE;
3463 /* Extra transformation specified by caller */
3464 if (lpmat) {
3465 FT_Matrix extraMat;
3466 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
3467 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
3468 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
3469 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
3470 pFT_Matrix_Multiply(&extraMat, &transMat);
3471 needsTransform = TRUE;
3474 if(!needsTransform) {
3475 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
3476 bottom = (ft_face->glyph->metrics.horiBearingY -
3477 ft_face->glyph->metrics.height) & -64;
3478 lpgm->gmCellIncX = FONT_GM(font,glyph_index)->adv;
3479 lpgm->gmCellIncY = 0;
3480 } else {
3481 INT xc, yc;
3482 FT_Vector vec;
3483 for(xc = 0; xc < 2; xc++) {
3484 for(yc = 0; yc < 2; yc++) {
3485 vec.x = (ft_face->glyph->metrics.horiBearingX +
3486 xc * ft_face->glyph->metrics.width);
3487 vec.y = ft_face->glyph->metrics.horiBearingY -
3488 yc * ft_face->glyph->metrics.height;
3489 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
3490 pFT_Vector_Transform(&vec, &transMat);
3491 if(xc == 0 && yc == 0) {
3492 left = right = vec.x;
3493 top = bottom = vec.y;
3494 } else {
3495 if(vec.x < left) left = vec.x;
3496 else if(vec.x > right) right = vec.x;
3497 if(vec.y < bottom) bottom = vec.y;
3498 else if(vec.y > top) top = vec.y;
3502 left = left & -64;
3503 right = (right + 63) & -64;
3504 bottom = bottom & -64;
3505 top = (top + 63) & -64;
3507 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
3508 vec.x = ft_face->glyph->metrics.horiAdvance;
3509 vec.y = 0;
3510 pFT_Vector_Transform(&vec, &transMat);
3511 lpgm->gmCellIncX = (vec.x+63) >> 6;
3512 lpgm->gmCellIncY = -((vec.y+63) >> 6);
3514 lpgm->gmBlackBoxX = (right - left) >> 6;
3515 lpgm->gmBlackBoxY = (top - bottom) >> 6;
3516 lpgm->gmptGlyphOrigin.x = left >> 6;
3517 lpgm->gmptGlyphOrigin.y = top >> 6;
3519 FONT_GM(font,glyph_index)->gm = *lpgm;
3520 FONT_GM(font,glyph_index)->init = TRUE;
3522 if(format == GGO_METRICS)
3523 return 1; /* FIXME */
3525 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP) {
3526 TRACE("loaded a bitmap\n");
3527 return GDI_ERROR;
3530 switch(format) {
3531 case GGO_BITMAP:
3532 width = lpgm->gmBlackBoxX;
3533 height = lpgm->gmBlackBoxY;
3534 pitch = ((width + 31) >> 5) << 2;
3535 needed = pitch * height;
3537 if(!buf || !buflen) break;
3539 switch(ft_face->glyph->format) {
3540 case ft_glyph_format_bitmap:
3542 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
3543 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
3544 INT h = ft_face->glyph->bitmap.rows;
3545 while(h--) {
3546 memcpy(dst, src, w);
3547 src += ft_face->glyph->bitmap.pitch;
3548 dst += pitch;
3550 break;
3553 case ft_glyph_format_outline:
3554 ft_bitmap.width = width;
3555 ft_bitmap.rows = height;
3556 ft_bitmap.pitch = pitch;
3557 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
3558 ft_bitmap.buffer = buf;
3560 if(needsTransform) {
3561 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3564 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3566 /* Note: FreeType will only set 'black' bits for us. */
3567 memset(buf, 0, needed);
3568 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3569 break;
3571 default:
3572 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
3573 return GDI_ERROR;
3575 break;
3577 case GGO_GRAY2_BITMAP:
3578 case GGO_GRAY4_BITMAP:
3579 case GGO_GRAY8_BITMAP:
3580 case WINE_GGO_GRAY16_BITMAP:
3582 unsigned int mult, row, col;
3583 BYTE *start, *ptr;
3585 width = lpgm->gmBlackBoxX;
3586 height = lpgm->gmBlackBoxY;
3587 pitch = (width + 3) / 4 * 4;
3588 needed = pitch * height;
3590 if(!buf || !buflen) break;
3591 ft_bitmap.width = width;
3592 ft_bitmap.rows = height;
3593 ft_bitmap.pitch = pitch;
3594 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
3595 ft_bitmap.buffer = buf;
3597 if(needsTransform) {
3598 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3601 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3603 memset(ft_bitmap.buffer, 0, buflen);
3605 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3607 if(format == GGO_GRAY2_BITMAP)
3608 mult = 4;
3609 else if(format == GGO_GRAY4_BITMAP)
3610 mult = 16;
3611 else if(format == GGO_GRAY8_BITMAP)
3612 mult = 64;
3613 else if(format == WINE_GGO_GRAY16_BITMAP)
3614 break;
3615 else {
3616 assert(0);
3617 break;
3620 start = buf;
3621 for(row = 0; row < height; row++) {
3622 ptr = start;
3623 for(col = 0; col < width; col++, ptr++) {
3624 *ptr = (((int)*ptr) * mult + 128) / 256;
3626 start += pitch;
3628 break;
3631 case GGO_NATIVE:
3633 int contour, point = 0, first_pt;
3634 FT_Outline *outline = &ft_face->glyph->outline;
3635 TTPOLYGONHEADER *pph;
3636 TTPOLYCURVE *ppc;
3637 DWORD pph_start, cpfx, type;
3639 if(buflen == 0) buf = NULL;
3641 if (needsTransform && buf) {
3642 pFT_Outline_Transform(outline, &transMat);
3645 for(contour = 0; contour < outline->n_contours; contour++) {
3646 pph_start = needed;
3647 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3648 first_pt = point;
3649 if(buf) {
3650 pph->dwType = TT_POLYGON_TYPE;
3651 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3653 needed += sizeof(*pph);
3654 point++;
3655 while(point <= outline->contours[contour]) {
3656 ppc = (TTPOLYCURVE *)((char *)buf + needed);
3657 type = (outline->tags[point] & FT_Curve_Tag_On) ?
3658 TT_PRIM_LINE : TT_PRIM_QSPLINE;
3659 cpfx = 0;
3660 do {
3661 if(buf)
3662 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3663 cpfx++;
3664 point++;
3665 } while(point <= outline->contours[contour] &&
3666 (outline->tags[point] & FT_Curve_Tag_On) ==
3667 (outline->tags[point-1] & FT_Curve_Tag_On));
3668 /* At the end of a contour Windows adds the start point, but
3669 only for Beziers */
3670 if(point > outline->contours[contour] &&
3671 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
3672 if(buf)
3673 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
3674 cpfx++;
3675 } else if(point <= outline->contours[contour] &&
3676 outline->tags[point] & FT_Curve_Tag_On) {
3677 /* add closing pt for bezier */
3678 if(buf)
3679 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3680 cpfx++;
3681 point++;
3683 if(buf) {
3684 ppc->wType = type;
3685 ppc->cpfx = cpfx;
3687 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3689 if(buf)
3690 pph->cb = needed - pph_start;
3692 break;
3694 case GGO_BEZIER:
3696 /* Convert the quadratic Beziers to cubic Beziers.
3697 The parametric eqn for a cubic Bezier is, from PLRM:
3698 r(t) = at^3 + bt^2 + ct + r0
3699 with the control points:
3700 r1 = r0 + c/3
3701 r2 = r1 + (c + b)/3
3702 r3 = r0 + c + b + a
3704 A quadratic Beizer has the form:
3705 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3707 So equating powers of t leads to:
3708 r1 = 2/3 p1 + 1/3 p0
3709 r2 = 2/3 p1 + 1/3 p2
3710 and of course r0 = p0, r3 = p2
3713 int contour, point = 0, first_pt;
3714 FT_Outline *outline = &ft_face->glyph->outline;
3715 TTPOLYGONHEADER *pph;
3716 TTPOLYCURVE *ppc;
3717 DWORD pph_start, cpfx, type;
3718 FT_Vector cubic_control[4];
3719 if(buflen == 0) buf = NULL;
3721 if (needsTransform && buf) {
3722 pFT_Outline_Transform(outline, &transMat);
3725 for(contour = 0; contour < outline->n_contours; contour++) {
3726 pph_start = needed;
3727 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3728 first_pt = point;
3729 if(buf) {
3730 pph->dwType = TT_POLYGON_TYPE;
3731 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3733 needed += sizeof(*pph);
3734 point++;
3735 while(point <= outline->contours[contour]) {
3736 ppc = (TTPOLYCURVE *)((char *)buf + needed);
3737 type = (outline->tags[point] & FT_Curve_Tag_On) ?
3738 TT_PRIM_LINE : TT_PRIM_CSPLINE;
3739 cpfx = 0;
3740 do {
3741 if(type == TT_PRIM_LINE) {
3742 if(buf)
3743 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3744 cpfx++;
3745 point++;
3746 } else {
3747 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
3748 so cpfx = 3n */
3750 /* FIXME: Possible optimization in endpoint calculation
3751 if there are two consecutive curves */
3752 cubic_control[0] = outline->points[point-1];
3753 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
3754 cubic_control[0].x += outline->points[point].x + 1;
3755 cubic_control[0].y += outline->points[point].y + 1;
3756 cubic_control[0].x >>= 1;
3757 cubic_control[0].y >>= 1;
3759 if(point+1 > outline->contours[contour])
3760 cubic_control[3] = outline->points[first_pt];
3761 else {
3762 cubic_control[3] = outline->points[point+1];
3763 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
3764 cubic_control[3].x += outline->points[point].x + 1;
3765 cubic_control[3].y += outline->points[point].y + 1;
3766 cubic_control[3].x >>= 1;
3767 cubic_control[3].y >>= 1;
3770 /* r1 = 1/3 p0 + 2/3 p1
3771 r2 = 1/3 p2 + 2/3 p1 */
3772 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
3773 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
3774 cubic_control[2] = cubic_control[1];
3775 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
3776 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
3777 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
3778 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
3779 if(buf) {
3780 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
3781 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
3782 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
3784 cpfx += 3;
3785 point++;
3787 } while(point <= outline->contours[contour] &&
3788 (outline->tags[point] & FT_Curve_Tag_On) ==
3789 (outline->tags[point-1] & FT_Curve_Tag_On));
3790 /* At the end of a contour Windows adds the start point,
3791 but only for Beziers and we've already done that.
3793 if(point <= outline->contours[contour] &&
3794 outline->tags[point] & FT_Curve_Tag_On) {
3795 /* This is the closing pt of a bezier, but we've already
3796 added it, so just inc point and carry on */
3797 point++;
3799 if(buf) {
3800 ppc->wType = type;
3801 ppc->cpfx = cpfx;
3803 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3805 if(buf)
3806 pph->cb = needed - pph_start;
3808 break;
3811 default:
3812 FIXME("Unsupported format %d\n", format);
3813 return GDI_ERROR;
3815 return needed;
3818 static BOOL get_bitmap_text_metrics(GdiFont *font)
3820 FT_Face ft_face = font->ft_face;
3821 #ifdef HAVE_FREETYPE_FTWINFNT_H
3822 FT_WinFNT_HeaderRec winfnt_header;
3823 #endif
3824 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
3825 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
3826 font->potm->otmSize = size;
3828 #define TM font->potm->otmTextMetrics
3829 #ifdef HAVE_FREETYPE_FTWINFNT_H
3830 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
3832 TM.tmHeight = winfnt_header.pixel_height;
3833 TM.tmAscent = winfnt_header.ascent;
3834 TM.tmDescent = TM.tmHeight - TM.tmAscent;
3835 TM.tmInternalLeading = winfnt_header.internal_leading;
3836 TM.tmExternalLeading = winfnt_header.external_leading;
3837 TM.tmAveCharWidth = winfnt_header.avg_width;
3838 TM.tmMaxCharWidth = winfnt_header.max_width;
3839 TM.tmWeight = winfnt_header.weight;
3840 TM.tmOverhang = 0;
3841 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
3842 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
3843 TM.tmFirstChar = winfnt_header.first_char;
3844 TM.tmLastChar = winfnt_header.last_char;
3845 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
3846 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
3847 TM.tmItalic = winfnt_header.italic;
3848 TM.tmUnderlined = font->underline;
3849 TM.tmStruckOut = font->strikeout;
3850 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
3851 TM.tmCharSet = winfnt_header.charset;
3853 else
3854 #endif
3856 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
3857 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
3858 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3859 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
3860 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
3861 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
3862 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
3863 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
3864 TM.tmOverhang = 0;
3865 TM.tmDigitizedAspectX = 96; /* FIXME */
3866 TM.tmDigitizedAspectY = 96; /* FIXME */
3867 TM.tmFirstChar = 1;
3868 TM.tmLastChar = 255;
3869 TM.tmDefaultChar = 32;
3870 TM.tmBreakChar = 32;
3871 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
3872 TM.tmUnderlined = font->underline;
3873 TM.tmStruckOut = font->strikeout;
3874 /* NB inverted meaning of TMPF_FIXED_PITCH */
3875 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
3876 TM.tmCharSet = font->charset;
3878 #undef TM
3880 return TRUE;
3883 /*************************************************************
3884 * WineEngGetTextMetrics
3887 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
3889 if(!font->potm) {
3890 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
3891 if(!get_bitmap_text_metrics(font))
3892 return FALSE;
3894 if(!font->potm) return FALSE;
3895 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
3897 if (font->aveWidth) {
3898 ptm->tmAveCharWidth = font->aveWidth * font->font_desc.matrix.eM11;
3900 return TRUE;
3904 /*************************************************************
3905 * WineEngGetOutlineTextMetrics
3908 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
3909 OUTLINETEXTMETRICW *potm)
3911 FT_Face ft_face = font->ft_face;
3912 UINT needed, lenfam, lensty, ret;
3913 TT_OS2 *pOS2;
3914 TT_HoriHeader *pHori;
3915 TT_Postscript *pPost;
3916 FT_Fixed x_scale, y_scale;
3917 WCHAR *family_nameW, *style_nameW;
3918 static const WCHAR spaceW[] = {' ', '\0'};
3919 char *cp;
3920 INT ascent, descent;
3922 TRACE("font=%p\n", font);
3924 if(!FT_IS_SCALABLE(ft_face))
3925 return 0;
3927 if(font->potm) {
3928 if(cbSize >= font->potm->otmSize)
3929 memcpy(potm, font->potm, font->potm->otmSize);
3930 return font->potm->otmSize;
3934 needed = sizeof(*potm);
3936 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
3937 family_nameW = strdupW(font->name);
3939 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
3940 * sizeof(WCHAR);
3941 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
3942 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
3943 style_nameW, lensty/sizeof(WCHAR));
3945 /* These names should be read from the TT name table */
3947 /* length of otmpFamilyName */
3948 needed += lenfam;
3950 /* length of otmpFaceName */
3951 if(!strcasecmp(ft_face->style_name, "regular")) {
3952 needed += lenfam; /* just the family name */
3953 } else {
3954 needed += lenfam + lensty; /* family + " " + style */
3957 /* length of otmpStyleName */
3958 needed += lensty;
3960 /* length of otmpFullName */
3961 needed += lenfam + lensty;
3964 x_scale = ft_face->size->metrics.x_scale;
3965 y_scale = ft_face->size->metrics.y_scale;
3967 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3968 if(!pOS2) {
3969 FIXME("Can't find OS/2 table - not TT font?\n");
3970 ret = 0;
3971 goto end;
3974 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3975 if(!pHori) {
3976 FIXME("Can't find HHEA table - not TT font?\n");
3977 ret = 0;
3978 goto end;
3981 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
3983 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",
3984 pOS2->usWinAscent, pOS2->usWinDescent,
3985 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
3986 ft_face->ascender, ft_face->descender, ft_face->height,
3987 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
3988 ft_face->bbox.yMax, ft_face->bbox.yMin);
3990 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
3991 font->potm->otmSize = needed;
3993 #define TM font->potm->otmTextMetrics
3995 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
3996 ascent = pHori->Ascender;
3997 descent = -pHori->Descender;
3998 } else {
3999 ascent = pOS2->usWinAscent;
4000 descent = pOS2->usWinDescent;
4003 if(font->yMax) {
4004 TM.tmAscent = font->yMax;
4005 TM.tmDescent = -font->yMin;
4006 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
4007 } else {
4008 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
4009 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
4010 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
4011 - ft_face->units_per_EM, y_scale) + 32) >> 6;
4014 TM.tmHeight = TM.tmAscent + TM.tmDescent;
4016 /* MSDN says:
4017 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
4019 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
4020 ((ascent + descent) -
4021 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
4023 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
4024 if (TM.tmAveCharWidth == 0) {
4025 TM.tmAveCharWidth = 1;
4027 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
4028 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
4029 TM.tmOverhang = 0;
4030 TM.tmDigitizedAspectX = 300;
4031 TM.tmDigitizedAspectY = 300;
4032 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
4033 * symbol range to 0 - f0ff
4035 if (font->charset == SYMBOL_CHARSET)
4036 TM.tmFirstChar = 0;
4037 else
4038 TM.tmFirstChar = pOS2->usFirstCharIndex;
4039 TM.tmLastChar = pOS2->usLastCharIndex;
4040 TM.tmDefaultChar = pOS2->usDefaultChar ? pOS2->usDefaultChar : 0x1f;
4041 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
4042 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
4043 TM.tmUnderlined = font->underline;
4044 TM.tmStruckOut = font->strikeout;
4046 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
4047 if(!FT_IS_FIXED_WIDTH(ft_face) &&
4048 (pOS2->version == 0xFFFFU ||
4049 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
4050 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
4051 else
4052 TM.tmPitchAndFamily = 0;
4054 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
4055 case PAN_FAMILY_SCRIPT:
4056 TM.tmPitchAndFamily |= FF_SCRIPT;
4057 break;
4058 case PAN_FAMILY_DECORATIVE:
4059 case PAN_FAMILY_PICTORIAL:
4060 TM.tmPitchAndFamily |= FF_DECORATIVE;
4061 break;
4062 case PAN_FAMILY_TEXT_DISPLAY:
4063 if(TM.tmPitchAndFamily == 0) /* fixed */
4064 TM.tmPitchAndFamily = FF_MODERN;
4065 else {
4066 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
4067 case PAN_SERIF_NORMAL_SANS:
4068 case PAN_SERIF_OBTUSE_SANS:
4069 case PAN_SERIF_PERP_SANS:
4070 TM.tmPitchAndFamily |= FF_SWISS;
4071 break;
4072 default:
4073 TM.tmPitchAndFamily |= FF_ROMAN;
4076 break;
4077 default:
4078 TM.tmPitchAndFamily |= FF_DONTCARE;
4081 if(FT_IS_SCALABLE(ft_face))
4082 TM.tmPitchAndFamily |= TMPF_VECTOR;
4083 if(FT_IS_SFNT(ft_face))
4084 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
4086 TM.tmCharSet = font->charset;
4087 #undef TM
4089 font->potm->otmFiller = 0;
4090 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
4091 font->potm->otmfsSelection = pOS2->fsSelection;
4092 font->potm->otmfsType = pOS2->fsType;
4093 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
4094 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
4095 font->potm->otmItalicAngle = 0; /* POST table */
4096 font->potm->otmEMSquare = ft_face->units_per_EM;
4097 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
4098 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
4099 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
4100 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
4101 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
4102 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
4103 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
4104 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
4105 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
4106 font->potm->otmMacAscent = 0; /* where do these come from ? */
4107 font->potm->otmMacDescent = 0;
4108 font->potm->otmMacLineGap = 0;
4109 font->potm->otmusMinimumPPEM = 0; /* TT Header */
4110 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
4111 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
4112 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
4113 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
4114 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
4115 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
4116 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
4117 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
4118 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
4119 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
4120 if(!pPost) {
4121 font->potm->otmsUnderscoreSize = 0;
4122 font->potm->otmsUnderscorePosition = 0;
4123 } else {
4124 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
4125 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
4128 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
4129 cp = (char*)font->potm + sizeof(*font->potm);
4130 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
4131 strcpyW((WCHAR*)cp, family_nameW);
4132 cp += lenfam;
4133 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
4134 strcpyW((WCHAR*)cp, style_nameW);
4135 cp += lensty;
4136 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
4137 strcpyW((WCHAR*)cp, family_nameW);
4138 if(strcasecmp(ft_face->style_name, "regular")) {
4139 strcatW((WCHAR*)cp, spaceW);
4140 strcatW((WCHAR*)cp, style_nameW);
4141 cp += lenfam + lensty;
4142 } else
4143 cp += lenfam;
4144 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
4145 strcpyW((WCHAR*)cp, family_nameW);
4146 strcatW((WCHAR*)cp, spaceW);
4147 strcatW((WCHAR*)cp, style_nameW);
4148 ret = needed;
4150 if(potm && needed <= cbSize)
4151 memcpy(potm, font->potm, font->potm->otmSize);
4153 end:
4154 HeapFree(GetProcessHeap(), 0, style_nameW);
4155 HeapFree(GetProcessHeap(), 0, family_nameW);
4157 return ret;
4160 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
4162 HFONTLIST *hfontlist;
4163 child->font = alloc_font();
4164 child->font->ft_face = OpenFontFile(child->font, child->file_name, child->index, 0, -font->ppem);
4165 if(!child->font->ft_face)
4167 free_font(child->font);
4168 child->font = NULL;
4169 return FALSE;
4172 child->font->orientation = font->orientation;
4173 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
4174 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
4175 list_add_head(&child->font->hfontlist, &hfontlist->entry);
4176 child->font->base_font = font;
4177 list_add_head(&child_font_list, &child->font->entry);
4178 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
4179 return TRUE;
4182 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
4184 FT_UInt g;
4185 CHILD_FONT *child_font;
4187 if(font->base_font)
4188 font = font->base_font;
4190 *linked_font = font;
4192 if((*glyph = get_glyph_index(font, c)))
4193 return TRUE;
4195 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
4197 if(!child_font->font)
4198 if(!load_child_font(font, child_font))
4199 continue;
4201 if(!child_font->font->ft_face)
4202 continue;
4203 g = get_glyph_index(child_font->font, c);
4204 if(g)
4206 *glyph = g;
4207 *linked_font = child_font->font;
4208 return TRUE;
4211 return FALSE;
4214 /*************************************************************
4215 * WineEngGetCharWidth
4218 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
4219 LPINT buffer)
4221 UINT c;
4222 GLYPHMETRICS gm;
4223 FT_UInt glyph_index;
4224 GdiFont *linked_font;
4226 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
4228 for(c = firstChar; c <= lastChar; c++) {
4229 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
4230 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4231 &gm, 0, NULL, NULL);
4232 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
4234 return TRUE;
4237 /*************************************************************
4238 * WineEngGetCharABCWidths
4241 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
4242 LPABC buffer)
4244 UINT c;
4245 GLYPHMETRICS gm;
4246 FT_UInt glyph_index;
4247 GdiFont *linked_font;
4249 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
4251 if(!FT_IS_SCALABLE(font->ft_face))
4252 return FALSE;
4254 for(c = firstChar; c <= lastChar; c++) {
4255 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
4256 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4257 &gm, 0, NULL, NULL);
4258 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
4259 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
4260 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
4261 FONT_GM(linked_font,glyph_index)->bbx;
4263 return TRUE;
4266 /*************************************************************
4267 * WineEngGetCharABCWidthsI
4270 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
4271 LPABC buffer)
4273 UINT c;
4274 GLYPHMETRICS gm;
4275 FT_UInt glyph_index;
4276 GdiFont *linked_font;
4278 if(!FT_IS_SCALABLE(font->ft_face))
4279 return FALSE;
4281 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
4282 if (!pgi)
4283 for(c = firstChar; c < firstChar+count; c++) {
4284 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
4285 &gm, 0, NULL, NULL);
4286 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
4287 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
4288 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
4289 - FONT_GM(linked_font,c)->bbx;
4291 else
4292 for(c = 0; c < count; c++) {
4293 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
4294 &gm, 0, NULL, NULL);
4295 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
4296 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
4297 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
4298 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
4301 return TRUE;
4304 /*************************************************************
4305 * WineEngGetTextExtentExPoint
4308 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
4309 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
4311 INT idx;
4312 INT nfit = 0, ext;
4313 GLYPHMETRICS gm;
4314 TEXTMETRICW tm;
4315 FT_UInt glyph_index;
4316 GdiFont *linked_font;
4318 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
4319 max_ext, size);
4321 size->cx = 0;
4322 WineEngGetTextMetrics(font, &tm);
4323 size->cy = tm.tmHeight;
4325 for(idx = 0; idx < count; idx++) {
4326 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
4327 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4328 &gm, 0, NULL, NULL);
4329 size->cx += FONT_GM(linked_font,glyph_index)->adv;
4330 ext = size->cx;
4331 if (! pnfit || ext <= max_ext) {
4332 ++nfit;
4333 if (dxs)
4334 dxs[idx] = ext;
4338 if (pnfit)
4339 *pnfit = nfit;
4341 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
4342 return TRUE;
4345 /*************************************************************
4346 * WineEngGetTextExtentPointI
4349 BOOL WineEngGetTextExtentPointI(GdiFont *font, const WORD *indices, INT count,
4350 LPSIZE size)
4352 INT idx;
4353 GLYPHMETRICS gm;
4354 TEXTMETRICW tm;
4356 TRACE("%p, %p, %d, %p\n", font, indices, count, size);
4358 size->cx = 0;
4359 WineEngGetTextMetrics(font, &tm);
4360 size->cy = tm.tmHeight;
4362 for(idx = 0; idx < count; idx++) {
4363 WineEngGetGlyphOutline(font, indices[idx],
4364 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
4365 NULL);
4366 size->cx += FONT_GM(font,indices[idx])->adv;
4368 TRACE("return %d,%d\n", size->cx, size->cy);
4369 return TRUE;
4372 /*************************************************************
4373 * WineEngGetFontData
4376 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
4377 DWORD cbData)
4379 FT_Face ft_face = font->ft_face;
4380 FT_ULong len;
4381 FT_Error err;
4383 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
4384 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
4385 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
4387 if(!FT_IS_SFNT(ft_face))
4388 return GDI_ERROR;
4390 if(!buf || !cbData)
4391 len = 0;
4392 else
4393 len = cbData;
4395 if(table) { /* MS tags differ in endidness from FT ones */
4396 table = table >> 24 | table << 24 |
4397 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
4400 /* If the FT_Load_Sfnt_Table function is there we'll use it */
4401 if(pFT_Load_Sfnt_Table) {
4402 /* make sure value of len is the value freetype says it needs */
4403 if( buf && len) {
4404 FT_ULong needed = 0;
4405 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
4406 if( !err && needed < len) len = needed;
4408 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
4410 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
4411 else { /* Do it the hard way */
4412 TT_Face tt_face = (TT_Face) ft_face;
4413 SFNT_Interface *sfnt;
4414 if (FT_Version.major==2 && FT_Version.minor==0)
4416 /* 2.0.x */
4417 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
4419 else
4421 /* A field was added in the middle of the structure in 2.1.x */
4422 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
4424 /* make sure value of len is the value freetype says it needs */
4425 if( buf && len) {
4426 FT_ULong needed = 0;
4427 err = sfnt->load_any(tt_face, table, offset, NULL, &needed);
4428 if( !err && needed < len) len = needed;
4430 err = sfnt->load_any(tt_face, table, offset, buf, &len);
4432 #else
4433 else {
4434 static int msg;
4435 if(!msg) {
4436 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
4437 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
4438 "Please upgrade your freetype library.\n");
4439 msg++;
4441 err = FT_Err_Unimplemented_Feature;
4443 #endif
4444 if(err) {
4445 TRACE("Can't find table %c%c%c%c\n",
4446 /* bytes were reversed */
4447 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
4448 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
4449 return GDI_ERROR;
4451 return len;
4454 /*************************************************************
4455 * WineEngGetTextFace
4458 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
4460 if(str) {
4461 lstrcpynW(str, font->name, count);
4462 return strlenW(font->name);
4463 } else
4464 return strlenW(font->name) + 1;
4467 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
4469 if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
4470 return font->charset;
4473 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
4475 GdiFont *font = dc->gdiFont, *linked_font;
4476 struct list *first_hfont;
4477 BOOL ret;
4479 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
4480 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
4481 if(font == linked_font)
4482 *new_hfont = dc->hFont;
4483 else
4485 first_hfont = list_head(&linked_font->hfontlist);
4486 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
4489 return ret;
4492 /* Retrieve a list of supported Unicode ranges for a given font.
4493 * Can be called with NULL gs to calculate the buffer size. Returns
4494 * the number of ranges found.
4496 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
4498 DWORD num_ranges = 0;
4500 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
4502 FT_UInt glyph_code;
4503 FT_ULong char_code, char_code_prev;
4505 glyph_code = 0;
4506 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
4508 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
4509 face->num_glyphs, glyph_code, char_code);
4511 if (!glyph_code) return 0;
4513 if (gs)
4515 gs->ranges[0].wcLow = (USHORT)char_code;
4516 gs->ranges[0].cGlyphs = 0;
4517 gs->cGlyphsSupported = 0;
4520 num_ranges = 1;
4521 while (glyph_code)
4523 if (char_code < char_code_prev)
4525 ERR("expected increasing char code from FT_Get_Next_Char\n");
4526 return 0;
4528 if (char_code - char_code_prev > 1)
4530 num_ranges++;
4531 if (gs)
4533 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
4534 gs->ranges[num_ranges - 1].cGlyphs = 1;
4535 gs->cGlyphsSupported++;
4538 else if (gs)
4540 gs->ranges[num_ranges - 1].cGlyphs++;
4541 gs->cGlyphsSupported++;
4543 char_code_prev = char_code;
4544 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
4547 else
4548 FIXME("encoding %u not supported\n", face->charmap->encoding);
4550 return num_ranges;
4553 DWORD WineEngGetFontUnicodeRanges(HDC hdc, LPGLYPHSET glyphset)
4555 DWORD size = 0;
4556 DC *dc = DC_GetDCPtr(hdc);
4558 TRACE("(%p, %p)\n", hdc, glyphset);
4560 if (!dc) return 0;
4562 if (dc->gdiFont)
4564 DWORD num_ranges = get_font_unicode_ranges(dc->gdiFont->ft_face, glyphset);
4566 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
4567 if (glyphset)
4569 glyphset->cbThis = size;
4570 glyphset->cRanges = num_ranges;
4574 DC_ReleaseDCPtr(dc);
4575 return size;
4578 /*************************************************************
4579 * FontIsLinked
4581 BOOL WINAPI FontIsLinked(HDC hdc)
4583 DC *dc = DC_GetDCPtr(hdc);
4584 BOOL ret = FALSE;
4586 if(!dc) return FALSE;
4587 if(dc->gdiFont && !list_empty(&dc->gdiFont->child_fonts))
4588 ret = TRUE;
4589 DC_ReleaseDCPtr(dc);
4590 TRACE("returning %d\n", ret);
4591 return ret;
4594 static BOOL is_hinting_enabled(void)
4596 /* Use the >= 2.2.0 function if available */
4597 if(pFT_Get_TrueType_Engine_Type)
4599 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
4600 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
4602 #ifdef FT_DRIVER_HAS_HINTER
4603 else
4605 FT_Module mod;
4607 /* otherwise if we've been compiled with < 2.2.0 headers
4608 use the internal macro */
4609 mod = pFT_Get_Module(library, "truetype");
4610 if(mod && FT_DRIVER_HAS_HINTER(mod))
4611 return TRUE;
4613 #endif
4615 return FALSE;
4618 /*************************************************************************
4619 * GetRasterizerCaps (GDI32.@)
4621 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
4623 static int hinting = -1;
4625 if(hinting == -1)
4627 hinting = is_hinting_enabled();
4628 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
4631 lprs->nSize = sizeof(RASTERIZER_STATUS);
4632 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
4633 lprs->nLanguageID = 0;
4634 return TRUE;
4637 /*************************************************************************
4638 * Kerning support for TrueType fonts
4640 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
4642 struct TT_kern_table
4644 USHORT version;
4645 USHORT nTables;
4648 struct TT_kern_subtable
4650 USHORT version;
4651 USHORT length;
4652 union
4654 USHORT word;
4655 struct
4657 USHORT horizontal : 1;
4658 USHORT minimum : 1;
4659 USHORT cross_stream: 1;
4660 USHORT override : 1;
4661 USHORT reserved1 : 4;
4662 USHORT format : 8;
4663 } bits;
4664 } coverage;
4667 struct TT_format0_kern_subtable
4669 USHORT nPairs;
4670 USHORT searchRange;
4671 USHORT entrySelector;
4672 USHORT rangeShift;
4675 struct TT_kern_pair
4677 USHORT left;
4678 USHORT right;
4679 short value;
4682 static DWORD parse_format0_kern_subtable(GdiFont *font,
4683 const struct TT_format0_kern_subtable *tt_f0_ks,
4684 const USHORT *glyph_to_char,
4685 KERNINGPAIR *kern_pair, DWORD cPairs)
4687 USHORT i, nPairs;
4688 const struct TT_kern_pair *tt_kern_pair;
4690 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
4692 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
4694 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
4695 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
4696 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
4698 if (!kern_pair || !cPairs)
4699 return nPairs;
4701 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
4703 nPairs = min(nPairs, cPairs);
4705 for (i = 0; i < nPairs; i++)
4707 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
4708 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
4709 /* this algorithm appears to better match what Windows does */
4710 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
4711 if (kern_pair->iKernAmount < 0)
4713 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
4714 kern_pair->iKernAmount -= font->ppem;
4716 else if (kern_pair->iKernAmount > 0)
4718 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
4719 kern_pair->iKernAmount += font->ppem;
4721 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
4723 TRACE("left %u right %u value %d\n",
4724 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
4726 kern_pair++;
4728 TRACE("copied %u entries\n", nPairs);
4729 return nPairs;
4732 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
4734 DWORD length;
4735 void *buf;
4736 const struct TT_kern_table *tt_kern_table;
4737 const struct TT_kern_subtable *tt_kern_subtable;
4738 USHORT i, nTables;
4739 USHORT *glyph_to_char;
4741 if (font->total_kern_pairs != (DWORD)-1)
4743 if (cPairs && kern_pair)
4745 cPairs = min(cPairs, font->total_kern_pairs);
4746 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
4747 return cPairs;
4749 return font->total_kern_pairs;
4752 font->total_kern_pairs = 0;
4754 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
4756 if (length == GDI_ERROR)
4758 TRACE("no kerning data in the font\n");
4759 return 0;
4762 buf = HeapAlloc(GetProcessHeap(), 0, length);
4763 if (!buf)
4765 WARN("Out of memory\n");
4766 return 0;
4769 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
4771 /* build a glyph index to char code map */
4772 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
4773 if (!glyph_to_char)
4775 WARN("Out of memory allocating a glyph index to char code map\n");
4776 HeapFree(GetProcessHeap(), 0, buf);
4777 return 0;
4780 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
4782 FT_UInt glyph_code;
4783 FT_ULong char_code;
4785 glyph_code = 0;
4786 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
4788 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
4789 font->ft_face->num_glyphs, glyph_code, char_code);
4791 while (glyph_code)
4793 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
4795 /* FIXME: This doesn't match what Windows does: it does some fancy
4796 * things with duplicate glyph index to char code mappings, while
4797 * we just avoid overriding existing entries.
4799 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
4800 glyph_to_char[glyph_code] = (USHORT)char_code;
4802 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
4805 else
4807 ULONG n;
4809 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
4810 for (n = 0; n <= 65535; n++)
4811 glyph_to_char[n] = (USHORT)n;
4814 tt_kern_table = buf;
4815 nTables = GET_BE_WORD(tt_kern_table->nTables);
4816 TRACE("version %u, nTables %u\n",
4817 GET_BE_WORD(tt_kern_table->version), nTables);
4819 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
4821 for (i = 0; i < nTables; i++)
4823 struct TT_kern_subtable tt_kern_subtable_copy;
4825 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
4826 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
4827 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
4829 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
4830 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
4831 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
4833 /* According to the TrueType specification this is the only format
4834 * that will be properly interpreted by Windows and OS/2
4836 if (tt_kern_subtable_copy.coverage.bits.format == 0)
4838 DWORD new_chunk, old_total = font->total_kern_pairs;
4840 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
4841 glyph_to_char, NULL, 0);
4842 font->total_kern_pairs += new_chunk;
4844 if (!font->kern_pairs)
4845 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
4846 font->total_kern_pairs * sizeof(*font->kern_pairs));
4847 else
4848 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
4849 font->total_kern_pairs * sizeof(*font->kern_pairs));
4851 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
4852 glyph_to_char, font->kern_pairs + old_total, new_chunk);
4854 else
4855 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
4857 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
4860 HeapFree(GetProcessHeap(), 0, glyph_to_char);
4861 HeapFree(GetProcessHeap(), 0, buf);
4863 if (cPairs && kern_pair)
4865 cPairs = min(cPairs, font->total_kern_pairs);
4866 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
4867 return cPairs;
4869 return font->total_kern_pairs;
4872 #else /* HAVE_FREETYPE */
4874 /*************************************************************************/
4876 BOOL WineEngInit(void)
4878 return FALSE;
4880 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
4882 return NULL;
4884 BOOL WineEngDestroyFontInstance(HFONT hfont)
4886 return FALSE;
4889 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
4891 return 1;
4894 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4895 LPWORD pgi, DWORD flags)
4897 return GDI_ERROR;
4900 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
4901 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4902 const MAT2* lpmat)
4904 ERR("called but we don't have FreeType\n");
4905 return GDI_ERROR;
4908 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
4910 ERR("called but we don't have FreeType\n");
4911 return FALSE;
4914 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
4915 OUTLINETEXTMETRICW *potm)
4917 ERR("called but we don't have FreeType\n");
4918 return 0;
4921 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
4922 LPINT buffer)
4924 ERR("called but we don't have FreeType\n");
4925 return FALSE;
4928 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
4929 LPABC buffer)
4931 ERR("called but we don't have FreeType\n");
4932 return FALSE;
4935 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
4936 LPABC buffer)
4938 ERR("called but we don't have FreeType\n");
4939 return FALSE;
4942 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
4943 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
4945 ERR("called but we don't have FreeType\n");
4946 return FALSE;
4949 BOOL WineEngGetTextExtentPointI(GdiFont *font, const WORD *indices, INT count,
4950 LPSIZE size)
4952 ERR("called but we don't have FreeType\n");
4953 return FALSE;
4956 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
4957 DWORD cbData)
4959 ERR("called but we don't have FreeType\n");
4960 return GDI_ERROR;
4963 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
4965 ERR("called but we don't have FreeType\n");
4966 return 0;
4969 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
4971 FIXME(":stub\n");
4972 return 1;
4975 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
4977 FIXME(":stub\n");
4978 return TRUE;
4981 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
4983 FIXME(":stub\n");
4984 return DEFAULT_CHARSET;
4987 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
4989 return FALSE;
4992 DWORD WineEngGetFontUnicodeRanges(HDC hdc, LPGLYPHSET glyphset)
4994 FIXME("(%p, %p): stub\n", hdc, glyphset);
4995 return 0;
4998 BOOL WINAPI FontIsLinked(HDC hdc)
5000 return FALSE;
5003 /*************************************************************************
5004 * GetRasterizerCaps (GDI32.@)
5006 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
5008 lprs->nSize = sizeof(RASTERIZER_STATUS);
5009 lprs->wFlags = 0;
5010 lprs->nLanguageID = 0;
5011 return TRUE;
5014 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
5016 ERR("called but we don't have FreeType\n");
5017 return 0;
5020 #endif /* HAVE_FREETYPE */