gdi32: Store child font links as pointers to struct Face instead of filename/index.
[wine/wine64.git] / dlls / gdi32 / freetype.c
blobb7182e0204da2ca9eb181bd1cd86b009ac7b6f23
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 Face *face;
285 GdiFont *font;
286 } CHILD_FONT;
288 struct tagGdiFont {
289 struct list entry;
290 FT_Face ft_face;
291 struct font_mapping *mapping;
292 LPWSTR name;
293 int charset;
294 int codepage;
295 BOOL fake_italic;
296 BOOL fake_bold;
297 BYTE underline;
298 BYTE strikeout;
299 INT orientation;
300 GM **gm;
301 DWORD gmsize;
302 struct list hfontlist;
303 FONT_DESC font_desc;
304 LONG aveWidth;
305 SHORT yMax;
306 SHORT yMin;
307 OUTLINETEXTMETRICW *potm;
308 DWORD total_kern_pairs;
309 KERNINGPAIR *kern_pairs;
310 FONTSIGNATURE fs;
311 GdiFont *base_font;
312 struct list child_fonts;
313 LONG ppem;
316 typedef struct {
317 struct list entry;
318 const WCHAR *font_name;
319 struct list links;
320 } SYSTEM_LINKS;
322 #define GM_BLOCK_SIZE 128
323 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
325 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
326 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
327 #define UNUSED_CACHE_SIZE 10
328 static struct list child_font_list = LIST_INIT(child_font_list);
329 static struct list system_links = LIST_INIT(system_links);
331 static struct list font_subst_list = LIST_INIT(font_subst_list);
333 static struct list font_list = LIST_INIT(font_list);
335 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
336 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
337 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
339 static const WCHAR RegularW[] = {'R','e','g','u','l','a','r','\0'};
341 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\0'};
342 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
343 'W','i','n','d','o','w','s','\\',
344 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
345 'F','o','n','t','s','\0'};
347 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
348 'W','i','n','d','o','w','s',' ','N','T','\\',
349 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
350 'F','o','n','t','s','\0'};
352 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
353 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
354 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
355 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
357 static const WCHAR * const SystemFontValues[4] = {
358 System_Value,
359 OEMFont_Value,
360 FixedSys_Value,
361 NULL
364 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
365 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
367 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
368 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
369 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
370 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
371 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
372 'E','u','r','o','p','e','a','n','\0'};
373 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
374 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
375 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
376 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
377 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
378 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
379 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
380 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
381 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
382 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
383 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
384 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
386 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
387 WesternW, /*00*/
388 Central_EuropeanW,
389 CyrillicW,
390 GreekW,
391 TurkishW,
392 HebrewW,
393 ArabicW,
394 BalticW,
395 VietnameseW, /*08*/
396 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
397 ThaiW,
398 JapaneseW,
399 CHINESE_GB2312W,
400 HangulW,
401 CHINESE_BIG5W,
402 Hangul_Johab_W,
403 NULL, NULL, /*23*/
404 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
405 SymbolW /*31*/
408 typedef struct {
409 WCHAR *name;
410 INT charset;
411 } NameCs;
413 typedef struct tagFontSubst {
414 struct list entry;
415 NameCs from;
416 NameCs to;
417 } FontSubst;
419 struct font_mapping
421 struct list entry;
422 int refcount;
423 dev_t dev;
424 ino_t ino;
425 void *data;
426 size_t size;
429 static struct list mappings_list = LIST_INIT( mappings_list );
431 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
433 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
435 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph);
437 /****************************************
438 * Notes on .fon files
440 * The fonts System, FixedSys and Terminal are special. There are typically multiple
441 * versions installed for different resolutions and codepages. Windows stores which one to use
442 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
443 * Key Meaning
444 * FIXEDFON.FON FixedSys
445 * FONTS.FON System
446 * OEMFONT.FON Terminal
447 * LogPixels Current dpi set by the display control panel applet
448 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
449 * also has a LogPixels value that appears to mirror this)
451 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
452 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
453 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
454 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
455 * so that makes sense.
457 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
458 * to be mapped into the registry on Windows 2000 at least).
459 * I have
460 * woafont=app850.fon
461 * ega80woa.fon=ega80850.fon
462 * ega40woa.fon=ega40850.fon
463 * cga80woa.fon=cga80850.fon
464 * cga40woa.fon=cga40850.fon
467 #ifdef HAVE_CARBON_CARBON_H
468 static char *find_cache_dir(void)
470 FSRef ref;
471 OSErr err;
472 static char cached_path[MAX_PATH];
473 static const char *wine = "/Wine", *fonts = "/Fonts";
475 if(*cached_path) return cached_path;
477 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
478 if(err != noErr)
480 WARN("can't create cached data folder\n");
481 return NULL;
483 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
484 if(err != noErr)
486 WARN("can't create cached data path\n");
487 *cached_path = '\0';
488 return NULL;
490 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
492 ERR("Could not create full path\n");
493 *cached_path = '\0';
494 return NULL;
496 strcat(cached_path, wine);
498 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
500 WARN("Couldn't mkdir %s\n", cached_path);
501 *cached_path = '\0';
502 return NULL;
504 strcat(cached_path, fonts);
505 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
507 WARN("Couldn't mkdir %s\n", cached_path);
508 *cached_path = '\0';
509 return NULL;
511 return cached_path;
514 /******************************************************************
515 * expand_mac_font
517 * Extracts individual TrueType font files from a Mac suitcase font
518 * and saves them into the user's caches directory (see
519 * find_cache_dir()).
520 * Returns a NULL terminated array of filenames.
522 * We do this because they are apps that try to read ttf files
523 * themselves and they don't like Mac suitcase files.
525 static char **expand_mac_font(const char *path)
527 FSRef ref;
528 SInt16 res_ref;
529 OSStatus s;
530 unsigned int idx;
531 const char *out_dir;
532 const char *filename;
533 int output_len;
534 struct {
535 char **array;
536 unsigned int size, max_size;
537 } ret;
539 TRACE("path %s\n", path);
541 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
542 if(s != noErr)
544 WARN("failed to get ref\n");
545 return NULL;
548 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
549 if(s != noErr)
551 TRACE("no data fork, so trying resource fork\n");
552 res_ref = FSOpenResFile(&ref, fsRdPerm);
553 if(res_ref == -1)
555 TRACE("unable to open resource fork\n");
556 return NULL;
560 ret.size = 0;
561 ret.max_size = 10;
562 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
563 if(!ret.array)
565 CloseResFile(res_ref);
566 return NULL;
569 out_dir = find_cache_dir();
571 filename = strrchr(path, '/');
572 if(!filename) filename = path;
573 else filename++;
575 /* output filename has the form out_dir/filename_%04x.ttf */
576 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
578 UseResFile(res_ref);
579 idx = 1;
580 while(1)
582 FamRec *fam_rec;
583 unsigned short *num_faces_ptr, num_faces, face;
584 AsscEntry *assoc;
585 Handle fond;
586 ResType fond_res = 0x464f4e44; /* 'FOND' */
588 fond = Get1IndResource(fond_res, idx);
589 if(!fond) break;
590 TRACE("got fond resource %d\n", idx);
591 HLock(fond);
593 fam_rec = *(FamRec**)fond;
594 num_faces_ptr = (unsigned short *)(fam_rec + 1);
595 num_faces = GET_BE_WORD(*num_faces_ptr);
596 num_faces++;
597 assoc = (AsscEntry*)(num_faces_ptr + 1);
598 TRACE("num faces %04x\n", num_faces);
599 for(face = 0; face < num_faces; face++, assoc++)
601 Handle sfnt;
602 ResType sfnt_res = 0x73666e74; /* 'sfnt' */
603 unsigned short size, font_id;
604 char *output;
606 size = GET_BE_WORD(assoc->fontSize);
607 font_id = GET_BE_WORD(assoc->fontID);
608 if(size != 0)
610 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
611 continue;
614 TRACE("trying to load sfnt id %04x\n", font_id);
615 sfnt = GetResource(sfnt_res, font_id);
616 if(!sfnt)
618 TRACE("can't get sfnt resource %04x\n", font_id);
619 continue;
622 output = HeapAlloc(GetProcessHeap(), 0, output_len);
623 if(output)
625 int fd;
627 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
629 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
630 if(fd != -1 || errno == EEXIST)
632 if(fd != -1)
634 unsigned char *sfnt_data;
636 HLock(sfnt);
637 sfnt_data = *(unsigned char**)sfnt;
638 write(fd, sfnt_data, GetHandleSize(sfnt));
639 HUnlock(sfnt);
640 close(fd);
642 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
644 ret.max_size *= 2;
645 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
647 ret.array[ret.size++] = output;
649 else
651 WARN("unable to create %s\n", output);
652 HeapFree(GetProcessHeap(), 0, output);
655 ReleaseResource(sfnt);
657 HUnlock(fond);
658 ReleaseResource(fond);
659 idx++;
661 CloseResFile(res_ref);
663 return ret.array;
666 #endif /* HAVE_CARBON_CARBON_H */
668 static inline BOOL is_win9x(void)
670 return GetVersion() & 0x80000000;
673 This function builds an FT_Fixed from a float. It puts the integer part
674 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
675 It fails if the integer part of the float number is greater than SHORT_MAX.
677 static inline FT_Fixed FT_FixedFromFloat(float f)
679 short value = f;
680 unsigned short fract = (f - value) * 0xFFFF;
681 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
685 This function builds an FT_Fixed from a FIXED. It simply put f.value
686 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
688 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
690 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
694 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
696 Family *family;
697 Face *face;
698 const char *file;
699 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
700 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
702 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
703 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
705 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
707 if(face_name && strcmpiW(face_name, family->FamilyName))
708 continue;
709 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
711 file = strrchr(face->file, '/');
712 if(!file)
713 file = face->file;
714 else
715 file++;
716 if(!strcasecmp(file, file_nameA))
718 HeapFree(GetProcessHeap(), 0, file_nameA);
719 return face;
723 HeapFree(GetProcessHeap(), 0, file_nameA);
724 return NULL;
727 static Family *find_family_from_name(const WCHAR *name)
729 Family *family;
731 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
733 if(!strcmpiW(family->FamilyName, name))
734 return family;
737 return NULL;
740 static void DumpSubstList(void)
742 FontSubst *psub;
744 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
746 if(psub->from.charset != -1 || psub->to.charset != -1)
747 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
748 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
749 else
750 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
751 debugstr_w(psub->to.name));
753 return;
756 static LPWSTR strdupW(LPCWSTR p)
758 LPWSTR ret;
759 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
760 ret = HeapAlloc(GetProcessHeap(), 0, len);
761 memcpy(ret, p, len);
762 return ret;
765 static LPSTR strdupA(LPCSTR p)
767 LPSTR ret;
768 DWORD len = (strlen(p) + 1);
769 ret = HeapAlloc(GetProcessHeap(), 0, len);
770 memcpy(ret, p, len);
771 return ret;
774 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
775 INT from_charset)
777 FontSubst *element;
779 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
781 if(!strcmpiW(element->from.name, from_name) &&
782 (element->from.charset == from_charset ||
783 element->from.charset == -1))
784 return element;
787 return NULL;
790 #define ADD_FONT_SUBST_FORCE 1
792 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
794 FontSubst *from_exist, *to_exist;
796 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
798 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
800 list_remove(&from_exist->entry);
801 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
802 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
803 HeapFree(GetProcessHeap(), 0, from_exist);
804 from_exist = NULL;
807 if(!from_exist)
809 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
811 if(to_exist)
813 HeapFree(GetProcessHeap(), 0, subst->to.name);
814 subst->to.name = strdupW(to_exist->to.name);
817 list_add_tail(subst_list, &subst->entry);
819 return TRUE;
822 HeapFree(GetProcessHeap(), 0, subst->from.name);
823 HeapFree(GetProcessHeap(), 0, subst->to.name);
824 HeapFree(GetProcessHeap(), 0, subst);
825 return FALSE;
828 static void split_subst_info(NameCs *nc, LPSTR str)
830 CHAR *p = strrchr(str, ',');
831 DWORD len;
833 nc->charset = -1;
834 if(p && *(p+1)) {
835 nc->charset = strtol(p+1, NULL, 10);
836 *p = '\0';
838 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
839 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
840 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
843 static void LoadSubstList(void)
845 FontSubst *psub;
846 HKEY hkey;
847 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
848 LPSTR value;
849 LPVOID data;
851 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
852 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
853 &hkey) == ERROR_SUCCESS) {
855 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
856 &valuelen, &datalen, NULL, NULL);
858 valuelen++; /* returned value doesn't include room for '\0' */
859 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
860 data = HeapAlloc(GetProcessHeap(), 0, datalen);
862 dlen = datalen;
863 vlen = valuelen;
864 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
865 &dlen) == ERROR_SUCCESS) {
866 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
868 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
869 split_subst_info(&psub->from, value);
870 split_subst_info(&psub->to, data);
872 /* Win 2000 doesn't allow mapping between different charsets
873 or mapping of DEFAULT_CHARSET */
874 if((psub->to.charset != psub->from.charset) ||
875 psub->to.charset == DEFAULT_CHARSET) {
876 HeapFree(GetProcessHeap(), 0, psub->to.name);
877 HeapFree(GetProcessHeap(), 0, psub->from.name);
878 HeapFree(GetProcessHeap(), 0, psub);
879 } else {
880 add_font_subst(&font_subst_list, psub, 0);
882 /* reset dlen and vlen */
883 dlen = datalen;
884 vlen = valuelen;
886 HeapFree(GetProcessHeap(), 0, data);
887 HeapFree(GetProcessHeap(), 0, value);
888 RegCloseKey(hkey);
892 static WCHAR *get_familyname(FT_Face ft_face)
894 WCHAR *family = NULL;
895 FT_SfntName name;
896 FT_UInt num_names, name_index, i;
898 if(FT_IS_SFNT(ft_face))
900 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
902 for(name_index = 0; name_index < num_names; name_index++)
904 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
906 if((name.name_id == TT_NAME_ID_FONT_FAMILY) &&
907 (name.language_id == GetUserDefaultLCID()) &&
908 (name.platform_id == TT_PLATFORM_MICROSOFT) &&
909 (name.encoding_id == TT_MS_ID_UNICODE_CS))
911 /* String is not nul terminated and string_len is a byte length. */
912 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
913 for(i = 0; i < name.string_len / 2; i++)
915 WORD *tmp = (WORD *)&name.string[i * 2];
916 family[i] = GET_BE_WORD(*tmp);
918 family[i] = 0;
920 TRACE("Got localised name %s\n", debugstr_w(family));
921 return family;
927 return NULL;
931 #define ADDFONT_EXTERNAL_FONT 0x01
932 #define ADDFONT_FORCE_BITMAP 0x02
933 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
935 FT_Face ft_face;
936 TT_OS2 *pOS2;
937 TT_Header *pHeader = NULL;
938 WCHAR *english_family, *localised_family, *StyleW;
939 DWORD len;
940 Family *family;
941 Face *face;
942 struct list *family_elem_ptr, *face_elem_ptr;
943 FT_Error err;
944 FT_Long face_index = 0, num_faces;
945 #ifdef HAVE_FREETYPE_FTWINFNT_H
946 FT_WinFNT_HeaderRec winfnt_header;
947 #endif
948 int i, bitmap_num, internal_leading;
949 FONTSIGNATURE fs;
951 #ifdef HAVE_CARBON_CARBON_H
952 if(!fake_family)
954 char **mac_list = expand_mac_font(file);
955 if(mac_list)
957 BOOL had_one = FALSE;
958 char **cursor;
959 for(cursor = mac_list; *cursor; cursor++)
961 had_one = TRUE;
962 AddFontFileToList(*cursor, NULL, NULL, flags);
963 HeapFree(GetProcessHeap(), 0, *cursor);
965 HeapFree(GetProcessHeap(), 0, mac_list);
966 if(had_one)
967 return 1;
970 #endif /* HAVE_CARBON_CARBON_H */
972 do {
973 char *family_name = fake_family;
975 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
976 if((err = pFT_New_Face(library, file, face_index, &ft_face)) != 0) {
977 WARN("Unable to load font file %s err = %x\n", debugstr_a(file), err);
978 return 0;
981 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*/
982 WARN("Ignoring font %s\n", debugstr_a(file));
983 pFT_Done_Face(ft_face);
984 return 0;
987 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
988 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
989 WARN("FreeType version < 2.1.9, skipping bitmap font %s\n", debugstr_a(file));
990 pFT_Done_Face(ft_face);
991 return 0;
994 if(FT_IS_SFNT(ft_face) && (!pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2) ||
995 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
996 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))) {
997 TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
998 "Skipping this font.\n", debugstr_a(file));
999 pFT_Done_Face(ft_face);
1000 return 0;
1003 if(!ft_face->family_name || !ft_face->style_name) {
1004 TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file));
1005 pFT_Done_Face(ft_face);
1006 return 0;
1009 if (target_family)
1011 localised_family = get_familyname(ft_face);
1012 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1014 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1015 HeapFree(GetProcessHeap(), 0, localised_family);
1016 num_faces = ft_face->num_faces;
1017 pFT_Done_Face(ft_face);
1018 continue;
1020 HeapFree(GetProcessHeap(), 0, localised_family);
1023 if(!family_name)
1024 family_name = ft_face->family_name;
1026 bitmap_num = 0;
1027 do {
1028 My_FT_Bitmap_Size *size = NULL;
1030 if(!FT_IS_SCALABLE(ft_face))
1031 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1033 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1034 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1035 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1037 localised_family = NULL;
1038 if(!fake_family) {
1039 localised_family = get_familyname(ft_face);
1040 if(localised_family && !strcmpW(localised_family, english_family)) {
1041 HeapFree(GetProcessHeap(), 0, localised_family);
1042 localised_family = NULL;
1046 family = NULL;
1047 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1048 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1049 if(!strcmpW(family->FamilyName, localised_family ? localised_family : english_family))
1050 break;
1051 family = NULL;
1053 if(!family) {
1054 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1055 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1056 list_init(&family->faces);
1057 list_add_tail(&font_list, &family->entry);
1059 if(localised_family) {
1060 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1061 subst->from.name = strdupW(english_family);
1062 subst->from.charset = -1;
1063 subst->to.name = strdupW(localised_family);
1064 subst->to.charset = -1;
1065 add_font_subst(&font_subst_list, subst, 0);
1068 HeapFree(GetProcessHeap(), 0, localised_family);
1069 HeapFree(GetProcessHeap(), 0, english_family);
1071 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1072 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1073 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1075 internal_leading = 0;
1076 memset(&fs, 0, sizeof(fs));
1078 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1079 if(pOS2) {
1080 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1081 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1082 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1083 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1084 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1085 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1086 if(pOS2->version == 0) {
1087 FT_UInt dummy;
1089 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1090 fs.fsCsb[0] |= 1;
1091 else
1092 fs.fsCsb[0] |= 1L << 31;
1095 #ifdef HAVE_FREETYPE_FTWINFNT_H
1096 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1097 CHARSETINFO csi;
1098 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1099 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1100 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1101 memcpy(&fs, &csi.fs, sizeof(csi.fs));
1102 internal_leading = winfnt_header.internal_leading;
1104 #endif
1106 face_elem_ptr = list_head(&family->faces);
1107 while(face_elem_ptr) {
1108 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1109 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1110 if(!strcmpW(face->StyleName, StyleW) &&
1111 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1112 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1113 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1114 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1116 if(fake_family) {
1117 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1118 HeapFree(GetProcessHeap(), 0, StyleW);
1119 pFT_Done_Face(ft_face);
1120 return 1;
1122 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1123 TRACE("Original font is newer so skipping this one\n");
1124 HeapFree(GetProcessHeap(), 0, StyleW);
1125 pFT_Done_Face(ft_face);
1126 return 1;
1127 } else {
1128 TRACE("Replacing original with this one\n");
1129 list_remove(&face->entry);
1130 HeapFree(GetProcessHeap(), 0, face->file);
1131 HeapFree(GetProcessHeap(), 0, face->StyleName);
1132 HeapFree(GetProcessHeap(), 0, face);
1133 break;
1137 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1138 list_add_tail(&family->faces, &face->entry);
1139 face->StyleName = StyleW;
1140 face->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
1141 strcpy(face->file, file);
1142 face->face_index = face_index;
1143 face->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
1144 face->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
1145 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1146 face->family = family;
1147 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1148 memcpy(&face->fs, &fs, sizeof(face->fs));
1149 memset(&face->fs_links, 0, sizeof(face->fs_links));
1151 if(FT_IS_SCALABLE(ft_face)) {
1152 memset(&face->size, 0, sizeof(face->size));
1153 face->scalable = TRUE;
1154 } else {
1155 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1156 size->height, size->width, size->size >> 6,
1157 size->x_ppem >> 6, size->y_ppem >> 6);
1158 face->size.height = size->height;
1159 face->size.width = size->width;
1160 face->size.size = size->size;
1161 face->size.x_ppem = size->x_ppem;
1162 face->size.y_ppem = size->y_ppem;
1163 face->size.internal_leading = internal_leading;
1164 face->scalable = FALSE;
1167 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1168 face->fs.fsCsb[0], face->fs.fsCsb[1],
1169 face->fs.fsUsb[0], face->fs.fsUsb[1],
1170 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1173 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1174 for(i = 0; i < ft_face->num_charmaps; i++) {
1175 switch(ft_face->charmaps[i]->encoding) {
1176 case FT_ENCODING_UNICODE:
1177 case FT_ENCODING_APPLE_ROMAN:
1178 face->fs.fsCsb[0] |= 1;
1179 break;
1180 case FT_ENCODING_MS_SYMBOL:
1181 face->fs.fsCsb[0] |= 1L << 31;
1182 break;
1183 default:
1184 break;
1189 if(face->fs.fsCsb[0] & ~(1L << 31))
1190 have_installed_roman_font = TRUE;
1191 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1193 num_faces = ft_face->num_faces;
1194 pFT_Done_Face(ft_face);
1195 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1196 debugstr_w(StyleW));
1197 } while(num_faces > ++face_index);
1198 return num_faces;
1201 static void DumpFontList(void)
1203 Family *family;
1204 Face *face;
1205 struct list *family_elem_ptr, *face_elem_ptr;
1207 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1208 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1209 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1210 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1211 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1212 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1213 if(!face->scalable)
1214 TRACE(" %d", face->size.height);
1215 TRACE("\n");
1218 return;
1221 /***********************************************************
1222 * The replacement list is a way to map an entire font
1223 * family onto another family. For example adding
1225 * [HKCU\Software\Wine\Fonts\Replacements]
1226 * "Wingdings"="Winedings"
1228 * would enumerate the Winedings font both as Winedings and
1229 * Wingdings. However if a real Wingdings font is present the
1230 * replacement does not take place.
1233 static void LoadReplaceList(void)
1235 HKEY hkey;
1236 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1237 LPWSTR value;
1238 LPVOID data;
1239 Family *family;
1240 Face *face;
1241 struct list *family_elem_ptr, *face_elem_ptr;
1242 CHAR familyA[400];
1244 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1245 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1247 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1248 &valuelen, &datalen, NULL, NULL);
1250 valuelen++; /* returned value doesn't include room for '\0' */
1251 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1252 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1254 dlen = datalen;
1255 vlen = valuelen;
1256 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1257 &dlen) == ERROR_SUCCESS) {
1258 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1259 /* "NewName"="Oldname" */
1260 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1262 /* Find the old family and hence all of the font files
1263 in that family */
1264 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1265 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1266 if(!strcmpiW(family->FamilyName, data)) {
1267 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1268 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1269 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1270 debugstr_w(face->StyleName), familyA);
1271 /* Now add a new entry with the new family name */
1272 AddFontFileToList(face->file, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1274 break;
1277 /* reset dlen and vlen */
1278 dlen = datalen;
1279 vlen = valuelen;
1281 HeapFree(GetProcessHeap(), 0, data);
1282 HeapFree(GetProcessHeap(), 0, value);
1283 RegCloseKey(hkey);
1287 /*************************************************************
1288 * init_system_links
1290 static BOOL init_system_links(void)
1292 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1293 'W','i','n','d','o','w','s',' ','N','T','\\',
1294 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1295 'S','y','s','t','e','m','L','i','n','k',0};
1296 HKEY hkey;
1297 BOOL ret = FALSE;
1298 DWORD type, max_val, max_data, val_len, data_len, index;
1299 WCHAR *value, *data;
1300 WCHAR *entry, *next;
1301 SYSTEM_LINKS *font_link, *system_font_link;
1302 CHILD_FONT *child_font;
1303 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
1304 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1305 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1306 FONTSIGNATURE fs;
1307 Family *family;
1308 Face *face;
1309 FontSubst *psub;
1311 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1313 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1314 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1315 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1316 val_len = max_val + 1;
1317 data_len = max_data;
1318 index = 0;
1319 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1321 TRACE("%s:\n", debugstr_w(value));
1323 memset(&fs, 0, sizeof(fs));
1324 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1325 psub = get_font_subst(&font_subst_list, value, -1);
1326 font_link->font_name = (psub)? strdupW(psub->to.name) : strdupW(value);
1327 list_init(&font_link->links);
1328 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1330 WCHAR *face_name;
1331 CHILD_FONT *child_font;
1333 TRACE("\t%s\n", debugstr_w(entry));
1335 next = entry + strlenW(entry) + 1;
1337 face_name = strchrW(entry, ',');
1338 if(face_name)
1340 *face_name++ = 0;
1341 while(isspaceW(*face_name))
1342 face_name++;
1344 psub = get_font_subst(&font_subst_list, face_name, -1);
1345 if(psub)
1346 face_name = psub->to.name;
1348 face = find_face_from_filename(entry, face_name);
1349 if(!face)
1351 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1352 continue;
1355 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1356 child_font->face = face;
1357 child_font->font = NULL;
1358 fs.fsCsb[0] |= face->fs.fsCsb[0];
1359 fs.fsCsb[1] |= face->fs.fsCsb[1];
1360 TRACE("Adding file %s index %ld\n", child_font->face->file, child_font->face->face_index);
1361 list_add_tail(&font_link->links, &child_font->entry);
1363 family = find_family_from_name(font_link->font_name);
1364 if(family)
1366 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1368 memcpy(&face->fs_links, &fs, sizeof(fs));
1371 list_add_tail(&system_links, &font_link->entry);
1372 val_len = max_val + 1;
1373 data_len = max_data;
1376 HeapFree(GetProcessHeap(), 0, value);
1377 HeapFree(GetProcessHeap(), 0, data);
1378 RegCloseKey(hkey);
1381 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1382 that Tahoma has */
1384 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1385 system_font_link->font_name = strdupW(System);
1386 list_init(&system_font_link->links);
1388 face = find_face_from_filename(tahoma_ttf, Tahoma);
1389 if(face)
1391 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1392 child_font->face = face;
1393 child_font->font = NULL;
1394 TRACE("Found Tahoma in %s index %ld\n", child_font->face->file, child_font->face->face_index);
1395 list_add_tail(&system_font_link->links, &child_font->entry);
1397 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1399 if(!strcmpiW(font_link->font_name, Tahoma))
1401 CHILD_FONT *font_link_entry;
1402 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1404 CHILD_FONT *new_child;
1405 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1406 new_child->face = font_link_entry->face;
1407 new_child->font = NULL;
1408 list_add_tail(&system_font_link->links, &new_child->entry);
1410 break;
1413 list_add_tail(&system_links, &system_font_link->entry);
1414 return ret;
1417 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1419 DIR *dir;
1420 struct dirent *dent;
1421 char path[MAX_PATH];
1423 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1425 dir = opendir(dirname);
1426 if(!dir) {
1427 WARN("Can't open directory %s\n", debugstr_a(dirname));
1428 return FALSE;
1430 while((dent = readdir(dir)) != NULL) {
1431 struct stat statbuf;
1433 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1434 continue;
1436 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1438 sprintf(path, "%s/%s", dirname, dent->d_name);
1440 if(stat(path, &statbuf) == -1)
1442 WARN("Can't stat %s\n", debugstr_a(path));
1443 continue;
1445 if(S_ISDIR(statbuf.st_mode))
1446 ReadFontDir(path, external_fonts);
1447 else
1448 AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1450 closedir(dir);
1451 return TRUE;
1454 static void load_fontconfig_fonts(void)
1456 #ifdef SONAME_LIBFONTCONFIG
1457 void *fc_handle = NULL;
1458 FcConfig *config;
1459 FcPattern *pat;
1460 FcObjectSet *os;
1461 FcFontSet *fontset;
1462 int i, len;
1463 char *file;
1464 const char *ext;
1466 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1467 if(!fc_handle) {
1468 TRACE("Wine cannot find the fontconfig library (%s).\n",
1469 SONAME_LIBFONTCONFIG);
1470 return;
1472 #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;}
1473 LOAD_FUNCPTR(FcConfigGetCurrent);
1474 LOAD_FUNCPTR(FcFontList);
1475 LOAD_FUNCPTR(FcFontSetDestroy);
1476 LOAD_FUNCPTR(FcInit);
1477 LOAD_FUNCPTR(FcObjectSetAdd);
1478 LOAD_FUNCPTR(FcObjectSetCreate);
1479 LOAD_FUNCPTR(FcObjectSetDestroy);
1480 LOAD_FUNCPTR(FcPatternCreate);
1481 LOAD_FUNCPTR(FcPatternDestroy);
1482 LOAD_FUNCPTR(FcPatternGetBool);
1483 LOAD_FUNCPTR(FcPatternGetString);
1484 #undef LOAD_FUNCPTR
1486 if(!pFcInit()) return;
1488 config = pFcConfigGetCurrent();
1489 pat = pFcPatternCreate();
1490 os = pFcObjectSetCreate();
1491 pFcObjectSetAdd(os, FC_FILE);
1492 pFcObjectSetAdd(os, FC_SCALABLE);
1493 fontset = pFcFontList(config, pat, os);
1494 if(!fontset) return;
1495 for(i = 0; i < fontset->nfont; i++) {
1496 FcBool scalable;
1498 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1499 continue;
1500 TRACE("fontconfig: %s\n", file);
1502 /* We're just interested in OT/TT fonts for now, so this hack just
1503 picks up the scalable fonts without extensions .pf[ab] to save time
1504 loading every other font */
1506 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1508 TRACE("not scalable\n");
1509 continue;
1512 len = strlen( file );
1513 if(len < 4) continue;
1514 ext = &file[ len - 3 ];
1515 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1516 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT);
1518 pFcFontSetDestroy(fontset);
1519 pFcObjectSetDestroy(os);
1520 pFcPatternDestroy(pat);
1521 sym_not_found:
1522 #endif
1523 return;
1526 static BOOL load_font_from_data_dir(LPCWSTR file)
1528 BOOL ret = FALSE;
1529 const char *data_dir = wine_get_data_dir();
1531 if (!data_dir) data_dir = wine_get_build_dir();
1533 if (data_dir)
1535 INT len;
1536 char *unix_name;
1538 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1540 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1542 strcpy(unix_name, data_dir);
1543 strcat(unix_name, "/fonts/");
1545 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1547 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1548 HeapFree(GetProcessHeap(), 0, unix_name);
1550 return ret;
1553 static void load_system_fonts(void)
1555 HKEY hkey;
1556 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1557 const WCHAR * const *value;
1558 DWORD dlen, type;
1559 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1560 char *unixname;
1562 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1563 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1564 strcatW(windowsdir, fontsW);
1565 for(value = SystemFontValues; *value; value++) {
1566 dlen = sizeof(data);
1567 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1568 type == REG_SZ) {
1569 BOOL added = FALSE;
1571 sprintfW(pathW, fmtW, windowsdir, data);
1572 if((unixname = wine_get_unix_file_name(pathW))) {
1573 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1574 HeapFree(GetProcessHeap(), 0, unixname);
1576 if (!added)
1577 load_font_from_data_dir(data);
1580 RegCloseKey(hkey);
1584 /*************************************************************
1586 * This adds registry entries for any externally loaded fonts
1587 * (fonts from fontconfig or FontDirs). It also deletes entries
1588 * of no longer existing fonts.
1591 static void update_reg_entries(void)
1593 HKEY winkey = 0, externalkey = 0;
1594 LPWSTR valueW;
1595 LPVOID data;
1596 DWORD dlen, vlen, datalen, valuelen, i, type, len, len_fam;
1597 Family *family;
1598 Face *face;
1599 struct list *family_elem_ptr, *face_elem_ptr;
1600 WCHAR *file;
1601 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1602 static const WCHAR spaceW[] = {' ', '\0'};
1603 char *path;
1605 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1606 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winkey, NULL) != ERROR_SUCCESS) {
1607 ERR("Can't create Windows font reg key\n");
1608 goto end;
1610 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1611 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &externalkey) != ERROR_SUCCESS) {
1612 ERR("Can't create external font reg key\n");
1613 goto end;
1616 /* Delete all external fonts added last time */
1618 RegQueryInfoKeyW(externalkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1619 &valuelen, &datalen, NULL, NULL);
1620 valuelen++; /* returned value doesn't include room for '\0' */
1621 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1622 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1624 dlen = datalen * sizeof(WCHAR);
1625 vlen = valuelen;
1626 i = 0;
1627 while(RegEnumValueW(externalkey, i++, valueW, &vlen, NULL, &type, data,
1628 &dlen) == ERROR_SUCCESS) {
1630 RegDeleteValueW(winkey, valueW);
1631 /* reset dlen and vlen */
1632 dlen = datalen;
1633 vlen = valuelen;
1635 HeapFree(GetProcessHeap(), 0, data);
1636 HeapFree(GetProcessHeap(), 0, valueW);
1638 /* Delete the old external fonts key */
1639 RegCloseKey(externalkey);
1640 externalkey = 0;
1641 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
1643 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1644 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1645 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
1646 ERR("Can't create external font reg key\n");
1647 goto end;
1650 /* enumerate the fonts and add external ones to the two keys */
1652 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1653 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1654 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1655 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1656 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1657 if(!face->external) continue;
1658 len = len_fam;
1659 if(strcmpiW(face->StyleName, RegularW))
1660 len = len_fam + strlenW(face->StyleName) + 1;
1661 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1662 strcpyW(valueW, family->FamilyName);
1663 if(len != len_fam) {
1664 strcatW(valueW, spaceW);
1665 strcatW(valueW, face->StyleName);
1667 strcatW(valueW, TrueType);
1668 if((path = strrchr(face->file, '/')) == NULL)
1669 path = face->file;
1670 else
1671 path++;
1672 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1674 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1675 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1676 RegSetValueExW(winkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1677 RegSetValueExW(externalkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1679 HeapFree(GetProcessHeap(), 0, file);
1680 HeapFree(GetProcessHeap(), 0, valueW);
1683 end:
1684 if(externalkey)
1685 RegCloseKey(externalkey);
1686 if(winkey)
1687 RegCloseKey(winkey);
1688 return;
1692 /*************************************************************
1693 * WineEngAddFontResourceEx
1696 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1698 if (ft_handle) /* do it only if we have freetype up and running */
1700 char *unixname;
1702 if(flags)
1703 FIXME("Ignoring flags %x\n", flags);
1705 if((unixname = wine_get_unix_file_name(file)))
1707 INT ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1708 HeapFree(GetProcessHeap(), 0, unixname);
1709 return ret;
1712 return 0;
1715 /*************************************************************
1716 * WineEngRemoveFontResourceEx
1719 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1721 FIXME(":stub\n");
1722 return TRUE;
1725 static const struct nls_update_font_list
1727 UINT ansi_cp, oem_cp;
1728 const char *oem, *fixed, *system;
1729 const char *courier, *serif, *small, *sserif;
1730 /* these are for font substitute */
1731 const char *shelldlg, *tmsrmn;
1732 } nls_update_font_list[] =
1734 /* Latin 1 (United States) */
1735 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
1736 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1737 "Tahoma","Times New Roman",
1739 /* Latin 1 (Multilingual) */
1740 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
1741 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1742 "Tahoma","Times New Roman", /* FIXME unverified */
1744 /* Eastern Europe */
1745 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
1746 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
1747 "Tahoma","Times New Roman", /* FIXME unverified */
1749 /* Cyrillic */
1750 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
1751 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
1752 "Tahoma","Times New Roman", /* FIXME unverified */
1754 /* Greek */
1755 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
1756 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
1757 "Tahoma","Times New Roman", /* FIXME unverified */
1759 /* Turkish */
1760 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
1761 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
1762 "Tahoma","Times New Roman", /* FIXME unverified */
1764 /* Hebrew */
1765 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
1766 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
1767 "Tahoma","Times New Roman", /* FIXME unverified */
1769 /* Arabic */
1770 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
1771 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
1772 "Tahoma","Times New Roman", /* FIXME unverified */
1774 /* Baltic */
1775 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
1776 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
1777 "Tahoma","Times New Roman", /* FIXME unverified */
1779 /* Vietnamese */
1780 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
1781 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1782 "Tahoma","Times New Roman", /* FIXME unverified */
1784 /* Thai */
1785 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
1786 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
1787 "Tahoma","Times New Roman", /* FIXME unverified */
1789 /* Japanese */
1790 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
1791 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
1792 "MS UI Gothic","MS Serif",
1794 /* Chinese Simplified */
1795 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
1796 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1797 "Tahoma", "Times New Roman", /* FIXME unverified */
1799 /* Korean */
1800 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
1801 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1802 "Gulim", "Batang",
1804 /* Chinese Traditional */
1805 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
1806 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1807 "Tahoma", "Times New Roman", /* FIXME unverified */
1811 static inline HKEY create_fonts_NT_registry_key(void)
1813 HKEY hkey = 0;
1815 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
1816 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1817 return hkey;
1820 static inline HKEY create_fonts_9x_registry_key(void)
1822 HKEY hkey = 0;
1824 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
1825 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1826 return hkey;
1829 static inline HKEY create_config_fonts_registry_key(void)
1831 HKEY hkey = 0;
1833 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
1834 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1835 return hkey;
1838 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
1840 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
1841 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
1842 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
1843 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
1846 static void update_font_info(void)
1848 char buf[40], cpbuf[40];
1849 DWORD len, type;
1850 HKEY hkey = 0;
1851 UINT i, ansi_cp = 0, oem_cp = 0;
1853 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
1854 return;
1856 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
1857 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
1858 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
1859 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
1860 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
1862 len = sizeof(buf);
1863 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
1865 if (!strcmp( buf, cpbuf )) /* already set correctly */
1867 RegCloseKey(hkey);
1868 return;
1870 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
1872 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
1874 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
1875 RegCloseKey(hkey);
1877 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
1879 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
1880 nls_update_font_list[i].oem_cp == oem_cp)
1882 HKEY hkey;
1884 hkey = create_config_fonts_registry_key();
1885 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
1886 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
1887 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
1888 RegCloseKey(hkey);
1890 hkey = create_fonts_NT_registry_key();
1891 add_font_list(hkey, &nls_update_font_list[i]);
1892 RegCloseKey(hkey);
1894 hkey = create_fonts_9x_registry_key();
1895 add_font_list(hkey, &nls_update_font_list[i]);
1896 RegCloseKey(hkey);
1898 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
1900 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
1901 strlen(nls_update_font_list[i].shelldlg)+1);
1902 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
1903 strlen(nls_update_font_list[i].tmsrmn)+1);
1904 RegCloseKey(hkey);
1906 return;
1909 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
1912 /*************************************************************
1913 * WineEngInit
1915 * Initialize FreeType library and create a list of available faces
1917 BOOL WineEngInit(void)
1919 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
1920 static const WCHAR pathW[] = {'P','a','t','h',0};
1921 HKEY hkey;
1922 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1923 LPVOID data;
1924 WCHAR windowsdir[MAX_PATH];
1925 char *unixname;
1926 HANDLE font_mutex;
1927 const char *data_dir;
1929 TRACE("\n");
1931 /* update locale dependent font info in registry */
1932 update_font_info();
1934 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
1935 if(!ft_handle) {
1936 WINE_MESSAGE(
1937 "Wine cannot find the FreeType font library. To enable Wine to\n"
1938 "use TrueType fonts please install a version of FreeType greater than\n"
1939 "or equal to 2.0.5.\n"
1940 "http://www.freetype.org\n");
1941 return FALSE;
1944 #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;}
1946 LOAD_FUNCPTR(FT_Vector_Unit)
1947 LOAD_FUNCPTR(FT_Done_Face)
1948 LOAD_FUNCPTR(FT_Get_Char_Index)
1949 LOAD_FUNCPTR(FT_Get_Module)
1950 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
1951 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
1952 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
1953 LOAD_FUNCPTR(FT_Init_FreeType)
1954 LOAD_FUNCPTR(FT_Load_Glyph)
1955 LOAD_FUNCPTR(FT_Matrix_Multiply)
1956 LOAD_FUNCPTR(FT_MulFix)
1957 LOAD_FUNCPTR(FT_New_Face)
1958 LOAD_FUNCPTR(FT_New_Memory_Face)
1959 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
1960 LOAD_FUNCPTR(FT_Outline_Transform)
1961 LOAD_FUNCPTR(FT_Outline_Translate)
1962 LOAD_FUNCPTR(FT_Select_Charmap)
1963 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
1964 LOAD_FUNCPTR(FT_Vector_Transform)
1966 #undef LOAD_FUNCPTR
1967 /* Don't warn if this one is missing */
1968 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
1969 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
1970 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
1971 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
1972 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
1973 #ifdef HAVE_FREETYPE_FTWINFNT_H
1974 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
1975 #endif
1976 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
1977 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
1978 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
1979 <= 2.0.3 has FT_Sqrt64 */
1980 goto sym_not_found;
1983 if(pFT_Init_FreeType(&library) != 0) {
1984 ERR("Can't init FreeType library\n");
1985 wine_dlclose(ft_handle, NULL, 0);
1986 ft_handle = NULL;
1987 return FALSE;
1989 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
1990 if (pFT_Library_Version)
1992 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
1994 if (FT_Version.major<=0)
1996 FT_Version.major=2;
1997 FT_Version.minor=0;
1998 FT_Version.patch=5;
2000 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2001 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2002 ((FT_Version.minor << 8) & 0x00ff00) |
2003 ((FT_Version.patch ) & 0x0000ff);
2005 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2006 ERR("Failed to create font mutex\n");
2007 return FALSE;
2009 WaitForSingleObject(font_mutex, INFINITE);
2011 /* load the system bitmap fonts */
2012 load_system_fonts();
2014 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2015 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2016 strcatW(windowsdir, fontsW);
2017 if((unixname = wine_get_unix_file_name(windowsdir)))
2019 ReadFontDir(unixname, FALSE);
2020 HeapFree(GetProcessHeap(), 0, unixname);
2023 /* load the system truetype fonts */
2024 data_dir = wine_get_data_dir();
2025 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2026 strcpy(unixname, data_dir);
2027 strcat(unixname, "/fonts/");
2028 ReadFontDir(unixname, FALSE);
2029 HeapFree(GetProcessHeap(), 0, unixname);
2032 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2033 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2034 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2035 will skip these. */
2036 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2037 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2038 &hkey) == ERROR_SUCCESS) {
2039 LPWSTR valueW;
2040 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2041 &valuelen, &datalen, NULL, NULL);
2043 valuelen++; /* returned value doesn't include room for '\0' */
2044 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2045 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2046 if (valueW && data)
2048 dlen = datalen * sizeof(WCHAR);
2049 vlen = valuelen;
2050 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
2051 &dlen) == ERROR_SUCCESS) {
2052 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
2054 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
2056 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2057 HeapFree(GetProcessHeap(), 0, unixname);
2060 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
2062 WCHAR pathW[MAX_PATH];
2063 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2064 BOOL added = FALSE;
2066 sprintfW(pathW, fmtW, windowsdir, data);
2067 if((unixname = wine_get_unix_file_name(pathW)))
2069 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2070 HeapFree(GetProcessHeap(), 0, unixname);
2072 if (!added)
2073 load_font_from_data_dir(data);
2075 /* reset dlen and vlen */
2076 dlen = datalen;
2077 vlen = valuelen;
2080 HeapFree(GetProcessHeap(), 0, data);
2081 HeapFree(GetProcessHeap(), 0, valueW);
2082 RegCloseKey(hkey);
2085 load_fontconfig_fonts();
2087 /* then look in any directories that we've specified in the config file */
2088 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2089 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2091 DWORD len;
2092 LPWSTR valueW;
2093 LPSTR valueA, ptr;
2095 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2097 len += sizeof(WCHAR);
2098 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2099 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2101 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2102 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2103 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2104 TRACE( "got font path %s\n", debugstr_a(valueA) );
2105 ptr = valueA;
2106 while (ptr)
2108 LPSTR next = strchr( ptr, ':' );
2109 if (next) *next++ = 0;
2110 ReadFontDir( ptr, TRUE );
2111 ptr = next;
2113 HeapFree( GetProcessHeap(), 0, valueA );
2115 HeapFree( GetProcessHeap(), 0, valueW );
2117 RegCloseKey(hkey);
2120 DumpFontList();
2121 LoadSubstList();
2122 DumpSubstList();
2123 LoadReplaceList();
2124 update_reg_entries();
2126 init_system_links();
2128 ReleaseMutex(font_mutex);
2129 return TRUE;
2130 sym_not_found:
2131 WINE_MESSAGE(
2132 "Wine cannot find certain functions that it needs inside the FreeType\n"
2133 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2134 "FreeType to at least version 2.0.5.\n"
2135 "http://www.freetype.org\n");
2136 wine_dlclose(ft_handle, NULL, 0);
2137 ft_handle = NULL;
2138 return FALSE;
2142 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2144 TT_OS2 *pOS2;
2145 TT_HoriHeader *pHori;
2147 LONG ppem;
2149 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2150 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2152 if(height == 0) height = 16;
2154 /* Calc. height of EM square:
2156 * For +ve lfHeight we have
2157 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2158 * Re-arranging gives:
2159 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2161 * For -ve lfHeight we have
2162 * |lfHeight| = ppem
2163 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2164 * with il = winAscent + winDescent - units_per_em]
2168 if(height > 0) {
2169 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2170 ppem = ft_face->units_per_EM * height /
2171 (pHori->Ascender - pHori->Descender);
2172 else
2173 ppem = ft_face->units_per_EM * height /
2174 (pOS2->usWinAscent + pOS2->usWinDescent);
2176 else
2177 ppem = -height;
2179 return ppem;
2182 static struct font_mapping *map_font( const char *name )
2184 struct font_mapping *mapping;
2185 struct stat st;
2186 int fd;
2188 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2189 if (fstat( fd, &st ) == -1) goto error;
2191 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2193 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2195 mapping->refcount++;
2196 close( fd );
2197 return mapping;
2200 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2201 goto error;
2203 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2204 close( fd );
2206 if (mapping->data == MAP_FAILED)
2208 HeapFree( GetProcessHeap(), 0, mapping );
2209 return NULL;
2211 mapping->refcount = 1;
2212 mapping->dev = st.st_dev;
2213 mapping->ino = st.st_ino;
2214 mapping->size = st.st_size;
2215 list_add_tail( &mappings_list, &mapping->entry );
2216 return mapping;
2218 error:
2219 close( fd );
2220 return NULL;
2223 static void unmap_font( struct font_mapping *mapping )
2225 if (!--mapping->refcount)
2227 list_remove( &mapping->entry );
2228 munmap( mapping->data, mapping->size );
2229 HeapFree( GetProcessHeap(), 0, mapping );
2233 static LONG load_VDMX(GdiFont*, LONG);
2235 static FT_Face OpenFontFile(GdiFont *font, char *file, FT_Long face_index, LONG width, LONG height)
2237 FT_Error err;
2238 FT_Face ft_face;
2240 TRACE("%s, %ld, %d x %d\n", debugstr_a(file), face_index, width, height);
2242 if (!(font->mapping = map_font( file )))
2244 WARN("failed to map %s\n", debugstr_a(file));
2245 return 0;
2248 err = pFT_New_Memory_Face(library, font->mapping->data, font->mapping->size, face_index, &ft_face);
2249 if(err) {
2250 ERR("FT_New_Face rets %d\n", err);
2251 return 0;
2254 /* set it here, as load_VDMX needs it */
2255 font->ft_face = ft_face;
2257 if(FT_IS_SCALABLE(ft_face)) {
2258 /* load the VDMX table if we have one */
2259 font->ppem = load_VDMX(font, height);
2260 if(font->ppem == 0)
2261 font->ppem = calc_ppem_for_height(ft_face, height);
2263 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
2264 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
2265 } else {
2266 font->ppem = height;
2267 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
2268 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
2270 return ft_face;
2274 static int get_nearest_charset(Face *face, int *cp)
2276 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2277 a single face with the requested charset. The idea is to check if
2278 the selected font supports the current ANSI codepage, if it does
2279 return the corresponding charset, else return the first charset */
2281 CHARSETINFO csi;
2282 int acp = GetACP(), i;
2283 DWORD fs0;
2285 *cp = acp;
2286 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
2287 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2288 return csi.ciCharset;
2290 for(i = 0; i < 32; i++) {
2291 fs0 = 1L << i;
2292 if(face->fs.fsCsb[0] & fs0) {
2293 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
2294 *cp = csi.ciACP;
2295 return csi.ciCharset;
2297 else
2298 FIXME("TCI failing on %x\n", fs0);
2302 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2303 face->fs.fsCsb[0], face->file);
2304 *cp = acp;
2305 return DEFAULT_CHARSET;
2308 static GdiFont *alloc_font(void)
2310 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
2311 ret->gmsize = 1;
2312 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM*));
2313 ret->gm[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
2314 ret->potm = NULL;
2315 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
2316 ret->total_kern_pairs = (DWORD)-1;
2317 ret->kern_pairs = NULL;
2318 list_init(&ret->hfontlist);
2319 list_init(&ret->child_fonts);
2320 return ret;
2323 static void free_font(GdiFont *font)
2325 struct list *cursor, *cursor2;
2326 int i;
2328 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
2330 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
2331 struct list *first_hfont;
2332 HFONTLIST *hfontlist;
2333 list_remove(cursor);
2334 if(child->font)
2336 first_hfont = list_head(&child->font->hfontlist);
2337 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2338 DeleteObject(hfontlist->hfont);
2339 HeapFree(GetProcessHeap(), 0, hfontlist);
2340 free_font(child->font);
2342 HeapFree(GetProcessHeap(), 0, child);
2345 if (font->ft_face) pFT_Done_Face(font->ft_face);
2346 if (font->mapping) unmap_font( font->mapping );
2347 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
2348 HeapFree(GetProcessHeap(), 0, font->potm);
2349 HeapFree(GetProcessHeap(), 0, font->name);
2350 for (i = 0; i < font->gmsize; i++)
2351 HeapFree(GetProcessHeap(),0,font->gm[i]);
2352 HeapFree(GetProcessHeap(), 0, font->gm);
2353 HeapFree(GetProcessHeap(), 0, font);
2357 /*************************************************************
2358 * load_VDMX
2360 * load the vdmx entry for the specified height
2363 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2364 ( ( (FT_ULong)_x4 << 24 ) | \
2365 ( (FT_ULong)_x3 << 16 ) | \
2366 ( (FT_ULong)_x2 << 8 ) | \
2367 (FT_ULong)_x1 )
2369 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2371 typedef struct {
2372 BYTE bCharSet;
2373 BYTE xRatio;
2374 BYTE yStartRatio;
2375 BYTE yEndRatio;
2376 } Ratios;
2378 typedef struct {
2379 WORD recs;
2380 BYTE startsz;
2381 BYTE endsz;
2382 } VDMX_group;
2384 static LONG load_VDMX(GdiFont *font, LONG height)
2386 WORD hdr[3], tmp;
2387 VDMX_group group;
2388 BYTE devXRatio, devYRatio;
2389 USHORT numRecs, numRatios;
2390 DWORD result, offset = -1;
2391 LONG ppem = 0;
2392 int i;
2394 /* For documentation on VDMX records, see
2395 * http://www.microsoft.com/OpenType/OTSpec/vdmx.htm
2398 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
2400 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2401 return ppem;
2403 /* FIXME: need the real device aspect ratio */
2404 devXRatio = 1;
2405 devYRatio = 1;
2407 numRecs = GET_BE_WORD(hdr[1]);
2408 numRatios = GET_BE_WORD(hdr[2]);
2410 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
2411 for(i = 0; i < numRatios; i++) {
2412 Ratios ratio;
2414 offset = (3 * 2) + (i * sizeof(Ratios));
2415 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2416 offset = -1;
2418 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2420 if((ratio.xRatio == 0 &&
2421 ratio.yStartRatio == 0 &&
2422 ratio.yEndRatio == 0) ||
2423 (devXRatio == ratio.xRatio &&
2424 devYRatio >= ratio.yStartRatio &&
2425 devYRatio <= ratio.yEndRatio))
2427 offset = (3 * 2) + (numRatios * 4) + (i * 2);
2428 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
2429 offset = GET_BE_WORD(tmp);
2430 break;
2434 if(offset == -1) {
2435 FIXME("No suitable ratio found\n");
2436 return ppem;
2439 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
2440 USHORT recs;
2441 BYTE startsz, endsz;
2442 WORD *vTable;
2444 recs = GET_BE_WORD(group.recs);
2445 startsz = group.startsz;
2446 endsz = group.endsz;
2448 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
2450 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
2451 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
2452 if(result == GDI_ERROR) {
2453 FIXME("Failed to retrieve vTable\n");
2454 goto end;
2457 if(height > 0) {
2458 for(i = 0; i < recs; i++) {
2459 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2460 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2461 ppem = GET_BE_WORD(vTable[i * 3]);
2463 if(yMax + -yMin == height) {
2464 font->yMax = yMax;
2465 font->yMin = yMin;
2466 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2467 break;
2469 if(yMax + -yMin > height) {
2470 if(--i < 0) {
2471 ppem = 0;
2472 goto end; /* failed */
2474 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2475 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2476 ppem = GET_BE_WORD(vTable[i * 3]);
2477 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2478 break;
2481 if(!font->yMax) {
2482 ppem = 0;
2483 TRACE("ppem not found for height %d\n", height);
2485 } else {
2486 ppem = -height;
2487 if(ppem < startsz || ppem > endsz)
2488 goto end;
2490 for(i = 0; i < recs; i++) {
2491 USHORT yPelHeight;
2492 yPelHeight = GET_BE_WORD(vTable[i * 3]);
2494 if(yPelHeight > ppem)
2495 break; /* failed */
2497 if(yPelHeight == ppem) {
2498 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2499 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2500 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
2501 break;
2505 end:
2506 HeapFree(GetProcessHeap(), 0, vTable);
2509 return ppem;
2512 static BOOL fontcmp(GdiFont *font, FONT_DESC *fd)
2514 if(font->font_desc.hash != fd->hash) return TRUE;
2515 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
2516 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
2517 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
2518 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
2521 static void calc_hash(FONT_DESC *pfd)
2523 DWORD hash = 0, *ptr, two_chars;
2524 WORD *pwc;
2525 unsigned int i;
2527 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
2528 hash ^= *ptr;
2529 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
2530 hash ^= *ptr;
2531 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
2532 two_chars = *ptr;
2533 pwc = (WCHAR *)&two_chars;
2534 if(!*pwc) break;
2535 *pwc = toupperW(*pwc);
2536 pwc++;
2537 *pwc = toupperW(*pwc);
2538 hash ^= two_chars;
2539 if(!*pwc) break;
2541 hash ^= !pfd->can_use_bitmap;
2542 pfd->hash = hash;
2543 return;
2546 static GdiFont *find_in_cache(HFONT hfont, LOGFONTW *plf, XFORM *pxf, BOOL can_use_bitmap)
2548 GdiFont *ret;
2549 FONT_DESC fd;
2550 HFONTLIST *hflist;
2551 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2553 memcpy(&fd.lf, plf, sizeof(LOGFONTW));
2554 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
2555 fd.can_use_bitmap = can_use_bitmap;
2556 calc_hash(&fd);
2558 /* try the in-use list */
2559 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
2560 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2561 if(!fontcmp(ret, &fd)) {
2562 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2563 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
2564 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2565 if(hflist->hfont == hfont)
2566 return ret;
2568 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2569 hflist->hfont = hfont;
2570 list_add_head(&ret->hfontlist, &hflist->entry);
2571 return ret;
2575 /* then the unused list */
2576 font_elem_ptr = list_head(&unused_gdi_font_list);
2577 while(font_elem_ptr) {
2578 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2579 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2580 if(!fontcmp(ret, &fd)) {
2581 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2582 assert(list_empty(&ret->hfontlist));
2583 TRACE("Found %p in unused list\n", ret);
2584 list_remove(&ret->entry);
2585 list_add_head(&gdi_font_list, &ret->entry);
2586 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2587 hflist->hfont = hfont;
2588 list_add_head(&ret->hfontlist, &hflist->entry);
2589 return ret;
2592 return NULL;
2596 /*************************************************************
2597 * create_child_font_list
2599 static BOOL create_child_font_list(GdiFont *font)
2601 BOOL ret = FALSE;
2602 SYSTEM_LINKS *font_link;
2603 CHILD_FONT *font_link_entry, *new_child;
2605 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2607 if(!strcmpW(font_link->font_name, font->name))
2609 TRACE("found entry in system list\n");
2610 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2612 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2613 new_child->face = font_link_entry->face;
2614 new_child->font = NULL;
2615 list_add_tail(&font->child_fonts, &new_child->entry);
2616 TRACE("font %s %ld\n", debugstr_a(new_child->face->file), new_child->face->face_index);
2618 ret = TRUE;
2619 break;
2623 return ret;
2626 /*************************************************************
2627 * WineEngCreateFontInstance
2630 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
2632 GdiFont *ret;
2633 Face *face, *best, *best_bitmap;
2634 Family *family, *last_resort_family;
2635 struct list *family_elem_ptr, *face_elem_ptr;
2636 INT height, width = 0;
2637 unsigned int score = 0, new_score;
2638 signed int diff = 0, newdiff;
2639 BOOL bd, it, can_use_bitmap;
2640 LOGFONTW lf;
2641 CHARSETINFO csi;
2642 HFONTLIST *hflist;
2644 LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry)
2646 struct list *first_hfont = list_head(&ret->hfontlist);
2647 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2648 if(hflist->hfont == hfont)
2649 return ret;
2652 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
2653 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
2655 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
2656 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
2657 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
2658 lf.lfEscapement);
2660 /* check the cache first */
2661 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
2662 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
2663 return ret;
2666 TRACE("not in cache\n");
2667 if(list_empty(&font_list)) /* No fonts installed */
2669 TRACE("No fonts installed\n");
2670 return NULL;
2672 if(!have_installed_roman_font)
2674 TRACE("No roman font installed\n");
2675 return NULL;
2678 ret = alloc_font();
2680 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
2681 memcpy(&ret->font_desc.lf, &lf, sizeof(LOGFONTW));
2682 ret->font_desc.can_use_bitmap = can_use_bitmap;
2683 calc_hash(&ret->font_desc);
2684 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2685 hflist->hfont = hfont;
2686 list_add_head(&ret->hfontlist, &hflist->entry);
2689 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
2690 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
2691 original value lfCharSet. Note this is a special case for
2692 Symbol and doesn't happen at least for "Wingdings*" */
2694 if(!strcmpiW(lf.lfFaceName, SymbolW))
2695 lf.lfCharSet = SYMBOL_CHARSET;
2697 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
2698 switch(lf.lfCharSet) {
2699 case DEFAULT_CHARSET:
2700 csi.fs.fsCsb[0] = 0;
2701 break;
2702 default:
2703 FIXME("Untranslated charset %d\n", lf.lfCharSet);
2704 csi.fs.fsCsb[0] = 0;
2705 break;
2709 family = NULL;
2710 if(lf.lfFaceName[0] != '\0') {
2711 FontSubst *psub;
2712 SYSTEM_LINKS *font_link;
2713 CHILD_FONT *font_link_entry;
2715 psub = get_font_subst(&font_subst_list, lf.lfFaceName, lf.lfCharSet);
2717 if(psub) {
2718 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
2719 debugstr_w(psub->to.name));
2720 strcpyW(lf.lfFaceName, psub->to.name);
2723 /* We want a match on name and charset or just name if
2724 charset was DEFAULT_CHARSET. If the latter then
2725 we fixup the returned charset later in get_nearest_charset
2726 where we'll either use the charset of the current ansi codepage
2727 or if that's unavailable the first charset that the font supports.
2729 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2730 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2731 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2732 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2733 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2734 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
2735 if(face->scalable || can_use_bitmap)
2736 goto found;
2742 * Try check the SystemLink list first for a replacement font.
2743 * We may find good replacements there.
2745 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2747 if(!strcmpiW(font_link->font_name, lf.lfFaceName))
2749 TRACE("found entry in system list\n");
2750 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2752 face = font_link_entry->face;
2753 family = face->family;
2754 if(csi.fs.fsCsb[0] &
2755 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
2757 if(face->scalable || can_use_bitmap)
2758 goto found;
2765 /* If requested charset was DEFAULT_CHARSET then try using charset
2766 corresponding to the current ansi codepage */
2767 if(!csi.fs.fsCsb[0]) {
2768 INT acp = GetACP();
2769 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
2770 FIXME("TCI failed on codepage %d\n", acp);
2771 csi.fs.fsCsb[0] = 0;
2772 } else
2773 lf.lfCharSet = csi.ciCharset;
2776 /* Face families are in the top 4 bits of lfPitchAndFamily,
2777 so mask with 0xF0 before testing */
2779 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
2780 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
2781 strcpyW(lf.lfFaceName, defFixed);
2782 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
2783 strcpyW(lf.lfFaceName, defSerif);
2784 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
2785 strcpyW(lf.lfFaceName, defSans);
2786 else
2787 strcpyW(lf.lfFaceName, defSans);
2788 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2789 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2790 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2791 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2792 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2793 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2794 if(face->scalable || can_use_bitmap)
2795 goto found;
2800 last_resort_family = NULL;
2801 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2802 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2803 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2804 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2805 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
2806 if(face->scalable)
2807 goto found;
2808 if(can_use_bitmap && !last_resort_family)
2809 last_resort_family = family;
2814 if(last_resort_family) {
2815 family = last_resort_family;
2816 csi.fs.fsCsb[0] = 0;
2817 goto found;
2820 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2821 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2822 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2823 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2824 if(face->scalable) {
2825 csi.fs.fsCsb[0] = 0;
2826 WARN("just using first face for now\n");
2827 goto found;
2829 if(can_use_bitmap && !last_resort_family)
2830 last_resort_family = family;
2833 if(!last_resort_family) {
2834 FIXME("can't find a single appropriate font - bailing\n");
2835 free_font(ret);
2836 return NULL;
2839 WARN("could only find a bitmap font - this will probably look awful!\n");
2840 family = last_resort_family;
2841 csi.fs.fsCsb[0] = 0;
2843 found:
2844 it = lf.lfItalic ? 1 : 0;
2845 bd = lf.lfWeight > 550 ? 1 : 0;
2847 height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
2848 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
2850 face = best = best_bitmap = NULL;
2851 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2853 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
2855 new_score = (face->Italic ^ it) + (face->Bold ^ bd);
2856 if(!best || new_score <= score)
2858 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
2859 face->Italic, face->Bold, it, bd);
2860 score = new_score;
2861 best = face;
2862 if(best->scalable && score == 0) break;
2863 if(!best->scalable)
2865 if(height > 0)
2866 newdiff = height - (signed int)(best->size.height);
2867 else
2868 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
2869 if(!best_bitmap || new_score < score ||
2870 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
2872 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
2873 diff = newdiff;
2874 best_bitmap = best;
2875 if(score == 0 && diff == 0) break;
2881 if(best)
2882 face = best->scalable ? best : best_bitmap;
2883 ret->fake_italic = (it && !face->Italic);
2884 ret->fake_bold = (bd && !face->Bold);
2886 memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
2888 if(csi.fs.fsCsb[0]) {
2889 ret->charset = lf.lfCharSet;
2890 ret->codepage = csi.ciACP;
2892 else
2893 ret->charset = get_nearest_charset(face, &ret->codepage);
2895 TRACE("Chosen: %s %s (%s:%ld)\n", debugstr_w(family->FamilyName),
2896 debugstr_w(face->StyleName), face->file, face->face_index);
2898 if(!face->scalable) {
2899 width = face->size.x_ppem >> 6;
2900 height = face->size.y_ppem >> 6;
2902 ret->ft_face = OpenFontFile(ret, face->file, face->face_index, width, height);
2904 if (!ret->ft_face)
2906 free_font( ret );
2907 return 0;
2910 if (ret->charset == SYMBOL_CHARSET &&
2911 !pFT_Select_Charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
2912 /* No ops */
2914 else if (!pFT_Select_Charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
2915 /* No ops */
2917 else {
2918 pFT_Select_Charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
2921 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
2922 ret->name = strdupW(family->FamilyName);
2923 ret->underline = lf.lfUnderline ? 0xff : 0;
2924 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
2925 create_child_font_list(ret);
2927 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
2929 ret->aveWidth = FT_IS_SCALABLE(ret->ft_face) ? abs(lf.lfWidth) : 0;
2930 list_add_head(&gdi_font_list, &ret->entry);
2931 return ret;
2934 static void dump_gdi_font_list(void)
2936 GdiFont *gdiFont;
2937 struct list *elem_ptr;
2939 TRACE("---------- gdiFont Cache ----------\n");
2940 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
2941 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
2942 TRACE("gdiFont=%p %s %d\n",
2943 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
2946 TRACE("---------- Unused gdiFont Cache ----------\n");
2947 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
2948 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
2949 TRACE("gdiFont=%p %s %d\n",
2950 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
2954 /*************************************************************
2955 * WineEngDestroyFontInstance
2957 * free the gdiFont associated with this handle
2960 BOOL WineEngDestroyFontInstance(HFONT handle)
2962 GdiFont *gdiFont;
2963 HFONTLIST *hflist;
2964 BOOL ret = FALSE;
2965 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2966 int i = 0;
2968 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
2970 struct list *first_hfont = list_head(&gdiFont->hfontlist);
2971 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2972 if(hflist->hfont == handle)
2974 TRACE("removing child font %p from child list\n", gdiFont);
2975 list_remove(&gdiFont->entry);
2976 return TRUE;
2980 TRACE("destroying hfont=%p\n", handle);
2981 if(TRACE_ON(font))
2982 dump_gdi_font_list();
2984 font_elem_ptr = list_head(&gdi_font_list);
2985 while(font_elem_ptr) {
2986 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2987 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
2989 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
2990 while(hfontlist_elem_ptr) {
2991 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2992 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
2993 if(hflist->hfont == handle) {
2994 list_remove(&hflist->entry);
2995 HeapFree(GetProcessHeap(), 0, hflist);
2996 ret = TRUE;
2999 if(list_empty(&gdiFont->hfontlist)) {
3000 TRACE("Moving to Unused list\n");
3001 list_remove(&gdiFont->entry);
3002 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3007 font_elem_ptr = list_head(&unused_gdi_font_list);
3008 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3009 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3010 while(font_elem_ptr) {
3011 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3012 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3013 TRACE("freeing %p\n", gdiFont);
3014 list_remove(&gdiFont->entry);
3015 free_font(gdiFont);
3017 return ret;
3020 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
3021 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
3023 OUTLINETEXTMETRICW *potm = NULL;
3024 UINT size;
3025 TEXTMETRICW tm, *ptm;
3026 GdiFont *font = alloc_font();
3027 LONG width, height;
3029 if(face->scalable) {
3030 height = 100;
3031 width = 0;
3032 } else {
3033 height = face->size.y_ppem >> 6;
3034 width = face->size.x_ppem >> 6;
3037 if (!(font->ft_face = OpenFontFile(font, face->file, face->face_index, width, height)))
3039 free_font(font);
3040 return;
3043 font->name = strdupW(face->family->FamilyName);
3045 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
3047 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
3048 if(size) {
3049 potm = HeapAlloc(GetProcessHeap(), 0, size);
3050 WineEngGetOutlineTextMetrics(font, size, potm);
3051 ptm = (TEXTMETRICW*)&potm->otmTextMetrics;
3052 } else {
3053 WineEngGetTextMetrics(font, &tm);
3054 ptm = &tm;
3057 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = ptm->tmHeight;
3058 pntm->ntmTm.tmAscent = ptm->tmAscent;
3059 pntm->ntmTm.tmDescent = ptm->tmDescent;
3060 pntm->ntmTm.tmInternalLeading = ptm->tmInternalLeading;
3061 pntm->ntmTm.tmExternalLeading = ptm->tmExternalLeading;
3062 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = ptm->tmAveCharWidth;
3063 pntm->ntmTm.tmMaxCharWidth = ptm->tmMaxCharWidth;
3064 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = ptm->tmWeight;
3065 pntm->ntmTm.tmOverhang = ptm->tmOverhang;
3066 pntm->ntmTm.tmDigitizedAspectX = ptm->tmDigitizedAspectX;
3067 pntm->ntmTm.tmDigitizedAspectY = ptm->tmDigitizedAspectY;
3068 pntm->ntmTm.tmFirstChar = ptm->tmFirstChar;
3069 pntm->ntmTm.tmLastChar = ptm->tmLastChar;
3070 pntm->ntmTm.tmDefaultChar = ptm->tmDefaultChar;
3071 pntm->ntmTm.tmBreakChar = ptm->tmBreakChar;
3072 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = ptm->tmItalic;
3073 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = ptm->tmUnderlined;
3074 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = ptm->tmStruckOut;
3075 pntm->ntmTm.tmPitchAndFamily = ptm->tmPitchAndFamily;
3076 pelf->elfLogFont.lfPitchAndFamily = (ptm->tmPitchAndFamily & 0xf1) + 1;
3077 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = ptm->tmCharSet;
3078 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
3079 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
3080 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
3082 *ptype = ptm->tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
3083 if(!(ptm->tmPitchAndFamily & TMPF_VECTOR))
3084 *ptype |= RASTER_FONTTYPE;
3086 pntm->ntmTm.ntmFlags = ptm->tmItalic ? NTM_ITALIC : 0;
3087 if(ptm->tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
3088 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
3090 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
3091 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
3092 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
3094 if(potm) {
3095 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
3097 lstrcpynW(pelf->elfLogFont.lfFaceName,
3098 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
3099 LF_FACESIZE);
3100 lstrcpynW(pelf->elfFullName,
3101 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
3102 LF_FULLFACESIZE);
3103 lstrcpynW(pelf->elfStyle,
3104 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
3105 LF_FACESIZE);
3107 HeapFree(GetProcessHeap(), 0, potm);
3108 } else {
3109 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
3111 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
3112 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FACESIZE);
3113 pelf->elfStyle[0] = '\0';
3116 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
3118 free_font(font);
3121 /*************************************************************
3122 * WineEngEnumFonts
3125 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3127 Family *family;
3128 Face *face;
3129 struct list *family_elem_ptr, *face_elem_ptr;
3130 ENUMLOGFONTEXW elf;
3131 NEWTEXTMETRICEXW ntm;
3132 DWORD type, ret = 1;
3133 FONTSIGNATURE fs;
3134 CHARSETINFO csi;
3135 LOGFONTW lf;
3136 int i;
3138 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
3140 if(plf->lfFaceName[0]) {
3141 FontSubst *psub;
3142 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
3144 if(psub) {
3145 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
3146 debugstr_w(psub->to.name));
3147 memcpy(&lf, plf, sizeof(lf));
3148 strcpyW(lf.lfFaceName, psub->to.name);
3149 plf = &lf;
3152 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3153 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3154 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
3155 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3156 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3157 GetEnumStructs(face, &elf, &ntm, &type);
3158 for(i = 0; i < 32; i++) {
3159 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3160 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3161 strcpyW(elf.elfScript, OEM_DOSW);
3162 i = 32; /* break out of loop */
3163 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3164 continue;
3165 else {
3166 fs.fsCsb[0] = 1L << i;
3167 fs.fsCsb[1] = 0;
3168 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3169 TCI_SRCFONTSIG))
3170 csi.ciCharset = DEFAULT_CHARSET;
3171 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3172 if(csi.ciCharset != DEFAULT_CHARSET) {
3173 elf.elfLogFont.lfCharSet =
3174 ntm.ntmTm.tmCharSet = csi.ciCharset;
3175 if(ElfScriptsW[i])
3176 strcpyW(elf.elfScript, ElfScriptsW[i]);
3177 else
3178 FIXME("Unknown elfscript for bit %d\n", i);
3181 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3182 debugstr_w(elf.elfLogFont.lfFaceName),
3183 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3184 csi.ciCharset, type, debugstr_w(elf.elfScript),
3185 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3186 ntm.ntmTm.ntmFlags);
3187 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
3188 if(!ret) goto end;
3193 } else {
3194 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3195 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3196 face_elem_ptr = list_head(&family->faces);
3197 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3198 GetEnumStructs(face, &elf, &ntm, &type);
3199 for(i = 0; i < 32; i++) {
3200 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3201 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3202 strcpyW(elf.elfScript, OEM_DOSW);
3203 i = 32; /* break out of loop */
3204 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3205 continue;
3206 else {
3207 fs.fsCsb[0] = 1L << i;
3208 fs.fsCsb[1] = 0;
3209 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3210 TCI_SRCFONTSIG))
3211 csi.ciCharset = DEFAULT_CHARSET;
3212 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3213 if(csi.ciCharset != DEFAULT_CHARSET) {
3214 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
3215 csi.ciCharset;
3216 if(ElfScriptsW[i])
3217 strcpyW(elf.elfScript, ElfScriptsW[i]);
3218 else
3219 FIXME("Unknown elfscript for bit %d\n", i);
3222 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3223 debugstr_w(elf.elfLogFont.lfFaceName),
3224 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3225 csi.ciCharset, type, debugstr_w(elf.elfScript),
3226 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3227 ntm.ntmTm.ntmFlags);
3228 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
3229 if(!ret) goto end;
3233 end:
3234 return ret;
3237 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
3239 pt->x.value = vec->x >> 6;
3240 pt->x.fract = (vec->x & 0x3f) << 10;
3241 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
3242 pt->y.value = vec->y >> 6;
3243 pt->y.fract = (vec->y & 0x3f) << 10;
3244 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
3245 return;
3248 /***************************************************
3249 * According to the MSDN documentation on WideCharToMultiByte,
3250 * certain codepages cannot set the default_used parameter.
3251 * This returns TRUE if the codepage can set that parameter, false else
3252 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
3254 static BOOL codepage_sets_default_used(UINT codepage)
3256 switch (codepage)
3258 case CP_UTF7:
3259 case CP_UTF8:
3260 case CP_SYMBOL:
3261 return FALSE;
3262 default:
3263 return TRUE;
3267 static FT_UInt get_glyph_index(GdiFont *font, UINT glyph)
3269 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
3270 WCHAR wc = (WCHAR)glyph;
3271 BOOL default_used;
3272 BOOL *default_used_pointer;
3273 FT_UInt ret;
3274 char buf;
3275 default_used_pointer = NULL;
3276 default_used = FALSE;
3277 if (codepage_sets_default_used(font->codepage))
3278 default_used_pointer = &default_used;
3279 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
3280 ret = 0;
3281 else
3282 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
3283 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
3284 return ret;
3287 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
3288 glyph = glyph + 0xf000;
3289 return pFT_Get_Char_Index(font->ft_face, glyph);
3292 /*************************************************************
3293 * WineEngGetGlyphIndices
3295 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
3297 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
3298 LPWORD pgi, DWORD flags)
3300 int i;
3301 WCHAR default_char = 0;
3302 TEXTMETRICW textm;
3304 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0x001f; /* Indicate non existence */
3306 for(i = 0; i < count; i++)
3308 pgi[i] = get_glyph_index(font, lpstr[i]);
3309 if (pgi[i] == 0)
3311 if (!default_char)
3313 WineEngGetTextMetrics(font, &textm);
3314 default_char = textm.tmDefaultChar;
3316 pgi[i] = default_char;
3319 return count;
3322 /*************************************************************
3323 * WineEngGetGlyphOutline
3325 * Behaves in exactly the same way as the win32 api GetGlyphOutline
3326 * except that the first parameter is the HWINEENGFONT of the font in
3327 * question rather than an HDC.
3330 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
3331 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
3332 const MAT2* lpmat)
3334 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
3335 FT_Face ft_face = incoming_font->ft_face;
3336 GdiFont *font = incoming_font;
3337 FT_UInt glyph_index;
3338 DWORD width, height, pitch, needed = 0;
3339 FT_Bitmap ft_bitmap;
3340 FT_Error err;
3341 INT left, right, top = 0, bottom = 0;
3342 FT_Angle angle = 0;
3343 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
3344 float widthRatio = 1.0;
3345 FT_Matrix transMat = identityMat;
3346 BOOL needsTransform = FALSE;
3349 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
3350 buflen, buf, lpmat);
3352 if(format & GGO_GLYPH_INDEX) {
3353 glyph_index = glyph;
3354 format &= ~GGO_GLYPH_INDEX;
3355 } else {
3356 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
3357 ft_face = font->ft_face;
3360 if(glyph_index >= font->gmsize * GM_BLOCK_SIZE) {
3361 font->gmsize = (glyph_index / GM_BLOCK_SIZE + 1);
3362 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
3363 font->gmsize * sizeof(GM*));
3364 } else {
3365 if(format == GGO_METRICS && font->gm[glyph_index / GM_BLOCK_SIZE] != NULL && FONT_GM(font,glyph_index)->init ) {
3366 *lpgm = FONT_GM(font,glyph_index)->gm;
3367 return 1; /* FIXME */
3371 if (!font->gm[glyph_index / GM_BLOCK_SIZE])
3372 font->gm[glyph_index / GM_BLOCK_SIZE] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, sizeof(GM) * GM_BLOCK_SIZE);
3374 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP) || font->aveWidth || lpmat)
3375 load_flags |= FT_LOAD_NO_BITMAP;
3377 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
3379 if(err) {
3380 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
3381 return GDI_ERROR;
3384 /* Scaling factor */
3385 if (font->aveWidth && font->potm) {
3386 widthRatio = (float)font->aveWidth * font->font_desc.matrix.eM11 / (float) font->potm->otmTextMetrics.tmAveCharWidth;
3389 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
3390 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
3392 FONT_GM(font,glyph_index)->adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
3393 FONT_GM(font,glyph_index)->lsb = left >> 6;
3394 FONT_GM(font,glyph_index)->bbx = (right - left) >> 6;
3396 /* Scaling transform */
3397 if(font->aveWidth) {
3398 FT_Matrix scaleMat;
3399 scaleMat.xx = FT_FixedFromFloat(widthRatio);
3400 scaleMat.xy = 0;
3401 scaleMat.yx = 0;
3402 scaleMat.yy = (1 << 16);
3404 pFT_Matrix_Multiply(&scaleMat, &transMat);
3405 needsTransform = TRUE;
3408 /* Slant transform */
3409 if (font->fake_italic) {
3410 FT_Matrix slantMat;
3412 slantMat.xx = (1 << 16);
3413 slantMat.xy = ((1 << 16) >> 2);
3414 slantMat.yx = 0;
3415 slantMat.yy = (1 << 16);
3416 pFT_Matrix_Multiply(&slantMat, &transMat);
3417 needsTransform = TRUE;
3420 /* Rotation transform */
3421 if(font->orientation) {
3422 FT_Matrix rotationMat;
3423 FT_Vector vecAngle;
3424 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
3425 pFT_Vector_Unit(&vecAngle, angle);
3426 rotationMat.xx = vecAngle.x;
3427 rotationMat.xy = -vecAngle.y;
3428 rotationMat.yx = -rotationMat.xy;
3429 rotationMat.yy = rotationMat.xx;
3431 pFT_Matrix_Multiply(&rotationMat, &transMat);
3432 needsTransform = TRUE;
3435 /* Extra transformation specified by caller */
3436 if (lpmat) {
3437 FT_Matrix extraMat;
3438 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
3439 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
3440 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
3441 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
3442 pFT_Matrix_Multiply(&extraMat, &transMat);
3443 needsTransform = TRUE;
3446 if(!needsTransform) {
3447 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
3448 bottom = (ft_face->glyph->metrics.horiBearingY -
3449 ft_face->glyph->metrics.height) & -64;
3450 lpgm->gmCellIncX = FONT_GM(font,glyph_index)->adv;
3451 lpgm->gmCellIncY = 0;
3452 } else {
3453 INT xc, yc;
3454 FT_Vector vec;
3455 for(xc = 0; xc < 2; xc++) {
3456 for(yc = 0; yc < 2; yc++) {
3457 vec.x = (ft_face->glyph->metrics.horiBearingX +
3458 xc * ft_face->glyph->metrics.width);
3459 vec.y = ft_face->glyph->metrics.horiBearingY -
3460 yc * ft_face->glyph->metrics.height;
3461 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
3462 pFT_Vector_Transform(&vec, &transMat);
3463 if(xc == 0 && yc == 0) {
3464 left = right = vec.x;
3465 top = bottom = vec.y;
3466 } else {
3467 if(vec.x < left) left = vec.x;
3468 else if(vec.x > right) right = vec.x;
3469 if(vec.y < bottom) bottom = vec.y;
3470 else if(vec.y > top) top = vec.y;
3474 left = left & -64;
3475 right = (right + 63) & -64;
3476 bottom = bottom & -64;
3477 top = (top + 63) & -64;
3479 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
3480 vec.x = ft_face->glyph->metrics.horiAdvance;
3481 vec.y = 0;
3482 pFT_Vector_Transform(&vec, &transMat);
3483 lpgm->gmCellIncX = (vec.x+63) >> 6;
3484 lpgm->gmCellIncY = -((vec.y+63) >> 6);
3486 lpgm->gmBlackBoxX = (right - left) >> 6;
3487 lpgm->gmBlackBoxY = (top - bottom) >> 6;
3488 lpgm->gmptGlyphOrigin.x = left >> 6;
3489 lpgm->gmptGlyphOrigin.y = top >> 6;
3491 FONT_GM(font,glyph_index)->gm = *lpgm;
3492 FONT_GM(font,glyph_index)->init = TRUE;
3494 if(format == GGO_METRICS)
3495 return 1; /* FIXME */
3497 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP) {
3498 TRACE("loaded a bitmap\n");
3499 return GDI_ERROR;
3502 switch(format) {
3503 case GGO_BITMAP:
3504 width = lpgm->gmBlackBoxX;
3505 height = lpgm->gmBlackBoxY;
3506 pitch = ((width + 31) >> 5) << 2;
3507 needed = pitch * height;
3509 if(!buf || !buflen) break;
3511 switch(ft_face->glyph->format) {
3512 case ft_glyph_format_bitmap:
3514 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
3515 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
3516 INT h = ft_face->glyph->bitmap.rows;
3517 while(h--) {
3518 memcpy(dst, src, w);
3519 src += ft_face->glyph->bitmap.pitch;
3520 dst += pitch;
3522 break;
3525 case ft_glyph_format_outline:
3526 ft_bitmap.width = width;
3527 ft_bitmap.rows = height;
3528 ft_bitmap.pitch = pitch;
3529 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
3530 ft_bitmap.buffer = buf;
3532 if(needsTransform) {
3533 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3536 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3538 /* Note: FreeType will only set 'black' bits for us. */
3539 memset(buf, 0, needed);
3540 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3541 break;
3543 default:
3544 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
3545 return GDI_ERROR;
3547 break;
3549 case GGO_GRAY2_BITMAP:
3550 case GGO_GRAY4_BITMAP:
3551 case GGO_GRAY8_BITMAP:
3552 case WINE_GGO_GRAY16_BITMAP:
3554 unsigned int mult, row, col;
3555 BYTE *start, *ptr;
3557 width = lpgm->gmBlackBoxX;
3558 height = lpgm->gmBlackBoxY;
3559 pitch = (width + 3) / 4 * 4;
3560 needed = pitch * height;
3562 if(!buf || !buflen) break;
3563 ft_bitmap.width = width;
3564 ft_bitmap.rows = height;
3565 ft_bitmap.pitch = pitch;
3566 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
3567 ft_bitmap.buffer = buf;
3569 if(needsTransform) {
3570 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3573 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3575 memset(ft_bitmap.buffer, 0, buflen);
3577 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3579 if(format == GGO_GRAY2_BITMAP)
3580 mult = 4;
3581 else if(format == GGO_GRAY4_BITMAP)
3582 mult = 16;
3583 else if(format == GGO_GRAY8_BITMAP)
3584 mult = 64;
3585 else if(format == WINE_GGO_GRAY16_BITMAP)
3586 break;
3587 else {
3588 assert(0);
3589 break;
3592 start = buf;
3593 for(row = 0; row < height; row++) {
3594 ptr = start;
3595 for(col = 0; col < width; col++, ptr++) {
3596 *ptr = (((int)*ptr) * mult + 128) / 256;
3598 start += pitch;
3600 break;
3603 case GGO_NATIVE:
3605 int contour, point = 0, first_pt;
3606 FT_Outline *outline = &ft_face->glyph->outline;
3607 TTPOLYGONHEADER *pph;
3608 TTPOLYCURVE *ppc;
3609 DWORD pph_start, cpfx, type;
3611 if(buflen == 0) buf = NULL;
3613 if (needsTransform && buf) {
3614 pFT_Outline_Transform(outline, &transMat);
3617 for(contour = 0; contour < outline->n_contours; contour++) {
3618 pph_start = needed;
3619 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3620 first_pt = point;
3621 if(buf) {
3622 pph->dwType = TT_POLYGON_TYPE;
3623 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3625 needed += sizeof(*pph);
3626 point++;
3627 while(point <= outline->contours[contour]) {
3628 ppc = (TTPOLYCURVE *)((char *)buf + needed);
3629 type = (outline->tags[point] & FT_Curve_Tag_On) ?
3630 TT_PRIM_LINE : TT_PRIM_QSPLINE;
3631 cpfx = 0;
3632 do {
3633 if(buf)
3634 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3635 cpfx++;
3636 point++;
3637 } while(point <= outline->contours[contour] &&
3638 (outline->tags[point] & FT_Curve_Tag_On) ==
3639 (outline->tags[point-1] & FT_Curve_Tag_On));
3640 /* At the end of a contour Windows adds the start point, but
3641 only for Beziers */
3642 if(point > outline->contours[contour] &&
3643 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
3644 if(buf)
3645 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
3646 cpfx++;
3647 } else if(point <= outline->contours[contour] &&
3648 outline->tags[point] & FT_Curve_Tag_On) {
3649 /* add closing pt for bezier */
3650 if(buf)
3651 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3652 cpfx++;
3653 point++;
3655 if(buf) {
3656 ppc->wType = type;
3657 ppc->cpfx = cpfx;
3659 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3661 if(buf)
3662 pph->cb = needed - pph_start;
3664 break;
3666 case GGO_BEZIER:
3668 /* Convert the quadratic Beziers to cubic Beziers.
3669 The parametric eqn for a cubic Bezier is, from PLRM:
3670 r(t) = at^3 + bt^2 + ct + r0
3671 with the control points:
3672 r1 = r0 + c/3
3673 r2 = r1 + (c + b)/3
3674 r3 = r0 + c + b + a
3676 A quadratic Beizer has the form:
3677 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3679 So equating powers of t leads to:
3680 r1 = 2/3 p1 + 1/3 p0
3681 r2 = 2/3 p1 + 1/3 p2
3682 and of course r0 = p0, r3 = p2
3685 int contour, point = 0, first_pt;
3686 FT_Outline *outline = &ft_face->glyph->outline;
3687 TTPOLYGONHEADER *pph;
3688 TTPOLYCURVE *ppc;
3689 DWORD pph_start, cpfx, type;
3690 FT_Vector cubic_control[4];
3691 if(buflen == 0) buf = NULL;
3693 if (needsTransform && buf) {
3694 pFT_Outline_Transform(outline, &transMat);
3697 for(contour = 0; contour < outline->n_contours; contour++) {
3698 pph_start = needed;
3699 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3700 first_pt = point;
3701 if(buf) {
3702 pph->dwType = TT_POLYGON_TYPE;
3703 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3705 needed += sizeof(*pph);
3706 point++;
3707 while(point <= outline->contours[contour]) {
3708 ppc = (TTPOLYCURVE *)((char *)buf + needed);
3709 type = (outline->tags[point] & FT_Curve_Tag_On) ?
3710 TT_PRIM_LINE : TT_PRIM_CSPLINE;
3711 cpfx = 0;
3712 do {
3713 if(type == TT_PRIM_LINE) {
3714 if(buf)
3715 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3716 cpfx++;
3717 point++;
3718 } else {
3719 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
3720 so cpfx = 3n */
3722 /* FIXME: Possible optimization in endpoint calculation
3723 if there are two consecutive curves */
3724 cubic_control[0] = outline->points[point-1];
3725 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
3726 cubic_control[0].x += outline->points[point].x + 1;
3727 cubic_control[0].y += outline->points[point].y + 1;
3728 cubic_control[0].x >>= 1;
3729 cubic_control[0].y >>= 1;
3731 if(point+1 > outline->contours[contour])
3732 cubic_control[3] = outline->points[first_pt];
3733 else {
3734 cubic_control[3] = outline->points[point+1];
3735 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
3736 cubic_control[3].x += outline->points[point].x + 1;
3737 cubic_control[3].y += outline->points[point].y + 1;
3738 cubic_control[3].x >>= 1;
3739 cubic_control[3].y >>= 1;
3742 /* r1 = 1/3 p0 + 2/3 p1
3743 r2 = 1/3 p2 + 2/3 p1 */
3744 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
3745 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
3746 cubic_control[2] = cubic_control[1];
3747 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
3748 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
3749 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
3750 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
3751 if(buf) {
3752 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
3753 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
3754 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
3756 cpfx += 3;
3757 point++;
3759 } while(point <= outline->contours[contour] &&
3760 (outline->tags[point] & FT_Curve_Tag_On) ==
3761 (outline->tags[point-1] & FT_Curve_Tag_On));
3762 /* At the end of a contour Windows adds the start point,
3763 but only for Beziers and we've already done that.
3765 if(point <= outline->contours[contour] &&
3766 outline->tags[point] & FT_Curve_Tag_On) {
3767 /* This is the closing pt of a bezier, but we've already
3768 added it, so just inc point and carry on */
3769 point++;
3771 if(buf) {
3772 ppc->wType = type;
3773 ppc->cpfx = cpfx;
3775 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3777 if(buf)
3778 pph->cb = needed - pph_start;
3780 break;
3783 default:
3784 FIXME("Unsupported format %d\n", format);
3785 return GDI_ERROR;
3787 return needed;
3790 static BOOL get_bitmap_text_metrics(GdiFont *font)
3792 FT_Face ft_face = font->ft_face;
3793 #ifdef HAVE_FREETYPE_FTWINFNT_H
3794 FT_WinFNT_HeaderRec winfnt_header;
3795 #endif
3796 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
3797 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
3798 font->potm->otmSize = size;
3800 #define TM font->potm->otmTextMetrics
3801 #ifdef HAVE_FREETYPE_FTWINFNT_H
3802 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
3804 TM.tmHeight = winfnt_header.pixel_height;
3805 TM.tmAscent = winfnt_header.ascent;
3806 TM.tmDescent = TM.tmHeight - TM.tmAscent;
3807 TM.tmInternalLeading = winfnt_header.internal_leading;
3808 TM.tmExternalLeading = winfnt_header.external_leading;
3809 TM.tmAveCharWidth = winfnt_header.avg_width;
3810 TM.tmMaxCharWidth = winfnt_header.max_width;
3811 TM.tmWeight = winfnt_header.weight;
3812 TM.tmOverhang = 0;
3813 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
3814 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
3815 TM.tmFirstChar = winfnt_header.first_char;
3816 TM.tmLastChar = winfnt_header.last_char;
3817 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
3818 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
3819 TM.tmItalic = winfnt_header.italic;
3820 TM.tmUnderlined = font->underline;
3821 TM.tmStruckOut = font->strikeout;
3822 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
3823 TM.tmCharSet = winfnt_header.charset;
3825 else
3826 #endif
3828 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
3829 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
3830 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3831 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
3832 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
3833 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
3834 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
3835 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
3836 TM.tmOverhang = 0;
3837 TM.tmDigitizedAspectX = 96; /* FIXME */
3838 TM.tmDigitizedAspectY = 96; /* FIXME */
3839 TM.tmFirstChar = 1;
3840 TM.tmLastChar = 255;
3841 TM.tmDefaultChar = 32;
3842 TM.tmBreakChar = 32;
3843 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
3844 TM.tmUnderlined = font->underline;
3845 TM.tmStruckOut = font->strikeout;
3846 /* NB inverted meaning of TMPF_FIXED_PITCH */
3847 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
3848 TM.tmCharSet = font->charset;
3850 #undef TM
3852 return TRUE;
3855 /*************************************************************
3856 * WineEngGetTextMetrics
3859 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
3861 if(!font->potm) {
3862 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
3863 if(!get_bitmap_text_metrics(font))
3864 return FALSE;
3866 if(!font->potm) return FALSE;
3867 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
3869 if (font->aveWidth) {
3870 ptm->tmAveCharWidth = font->aveWidth * font->font_desc.matrix.eM11;
3872 return TRUE;
3876 /*************************************************************
3877 * WineEngGetOutlineTextMetrics
3880 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
3881 OUTLINETEXTMETRICW *potm)
3883 FT_Face ft_face = font->ft_face;
3884 UINT needed, lenfam, lensty, ret;
3885 TT_OS2 *pOS2;
3886 TT_HoriHeader *pHori;
3887 TT_Postscript *pPost;
3888 FT_Fixed x_scale, y_scale;
3889 WCHAR *family_nameW, *style_nameW;
3890 static const WCHAR spaceW[] = {' ', '\0'};
3891 char *cp;
3892 INT ascent, descent;
3894 TRACE("font=%p\n", font);
3896 if(!FT_IS_SCALABLE(ft_face))
3897 return 0;
3899 if(font->potm) {
3900 if(cbSize >= font->potm->otmSize)
3901 memcpy(potm, font->potm, font->potm->otmSize);
3902 return font->potm->otmSize;
3906 needed = sizeof(*potm);
3908 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
3909 family_nameW = strdupW(font->name);
3911 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
3912 * sizeof(WCHAR);
3913 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
3914 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
3915 style_nameW, lensty/sizeof(WCHAR));
3917 /* These names should be read from the TT name table */
3919 /* length of otmpFamilyName */
3920 needed += lenfam;
3922 /* length of otmpFaceName */
3923 if(!strcasecmp(ft_face->style_name, "regular")) {
3924 needed += lenfam; /* just the family name */
3925 } else {
3926 needed += lenfam + lensty; /* family + " " + style */
3929 /* length of otmpStyleName */
3930 needed += lensty;
3932 /* length of otmpFullName */
3933 needed += lenfam + lensty;
3936 x_scale = ft_face->size->metrics.x_scale;
3937 y_scale = ft_face->size->metrics.y_scale;
3939 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3940 if(!pOS2) {
3941 FIXME("Can't find OS/2 table - not TT font?\n");
3942 ret = 0;
3943 goto end;
3946 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3947 if(!pHori) {
3948 FIXME("Can't find HHEA table - not TT font?\n");
3949 ret = 0;
3950 goto end;
3953 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
3955 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",
3956 pOS2->usWinAscent, pOS2->usWinDescent,
3957 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
3958 ft_face->ascender, ft_face->descender, ft_face->height,
3959 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
3960 ft_face->bbox.yMax, ft_face->bbox.yMin);
3962 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
3963 font->potm->otmSize = needed;
3965 #define TM font->potm->otmTextMetrics
3967 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
3968 ascent = pHori->Ascender;
3969 descent = -pHori->Descender;
3970 } else {
3971 ascent = pOS2->usWinAscent;
3972 descent = pOS2->usWinDescent;
3975 if(font->yMax) {
3976 TM.tmAscent = font->yMax;
3977 TM.tmDescent = -font->yMin;
3978 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
3979 } else {
3980 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
3981 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
3982 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
3983 - ft_face->units_per_EM, y_scale) + 32) >> 6;
3986 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3988 /* MSDN says:
3989 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
3991 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
3992 ((ascent + descent) -
3993 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
3995 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
3996 if (TM.tmAveCharWidth == 0) {
3997 TM.tmAveCharWidth = 1;
3999 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
4000 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
4001 TM.tmOverhang = 0;
4002 TM.tmDigitizedAspectX = 300;
4003 TM.tmDigitizedAspectY = 300;
4004 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
4005 * symbol range to 0 - f0ff
4007 if (font->charset == SYMBOL_CHARSET)
4008 TM.tmFirstChar = 0;
4009 else
4010 TM.tmFirstChar = pOS2->usFirstCharIndex;
4011 TM.tmLastChar = pOS2->usLastCharIndex;
4012 TM.tmDefaultChar = pOS2->usDefaultChar ? pOS2->usDefaultChar : 0x1f;
4013 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
4014 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
4015 TM.tmUnderlined = font->underline;
4016 TM.tmStruckOut = font->strikeout;
4018 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
4019 if(!FT_IS_FIXED_WIDTH(ft_face) &&
4020 (pOS2->version == 0xFFFFU ||
4021 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
4022 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
4023 else
4024 TM.tmPitchAndFamily = 0;
4026 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
4027 case PAN_FAMILY_SCRIPT:
4028 TM.tmPitchAndFamily |= FF_SCRIPT;
4029 break;
4030 case PAN_FAMILY_DECORATIVE:
4031 case PAN_FAMILY_PICTORIAL:
4032 TM.tmPitchAndFamily |= FF_DECORATIVE;
4033 break;
4034 case PAN_FAMILY_TEXT_DISPLAY:
4035 if(TM.tmPitchAndFamily == 0) /* fixed */
4036 TM.tmPitchAndFamily = FF_MODERN;
4037 else {
4038 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
4039 case PAN_SERIF_NORMAL_SANS:
4040 case PAN_SERIF_OBTUSE_SANS:
4041 case PAN_SERIF_PERP_SANS:
4042 TM.tmPitchAndFamily |= FF_SWISS;
4043 break;
4044 default:
4045 TM.tmPitchAndFamily |= FF_ROMAN;
4048 break;
4049 default:
4050 TM.tmPitchAndFamily |= FF_DONTCARE;
4053 if(FT_IS_SCALABLE(ft_face))
4054 TM.tmPitchAndFamily |= TMPF_VECTOR;
4055 if(FT_IS_SFNT(ft_face))
4056 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
4058 TM.tmCharSet = font->charset;
4059 #undef TM
4061 font->potm->otmFiller = 0;
4062 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
4063 font->potm->otmfsSelection = pOS2->fsSelection;
4064 font->potm->otmfsType = pOS2->fsType;
4065 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
4066 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
4067 font->potm->otmItalicAngle = 0; /* POST table */
4068 font->potm->otmEMSquare = ft_face->units_per_EM;
4069 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
4070 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
4071 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
4072 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
4073 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
4074 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
4075 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
4076 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
4077 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
4078 font->potm->otmMacAscent = 0; /* where do these come from ? */
4079 font->potm->otmMacDescent = 0;
4080 font->potm->otmMacLineGap = 0;
4081 font->potm->otmusMinimumPPEM = 0; /* TT Header */
4082 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
4083 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
4084 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
4085 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
4086 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
4087 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
4088 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
4089 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
4090 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
4091 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
4092 if(!pPost) {
4093 font->potm->otmsUnderscoreSize = 0;
4094 font->potm->otmsUnderscorePosition = 0;
4095 } else {
4096 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
4097 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
4100 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
4101 cp = (char*)font->potm + sizeof(*font->potm);
4102 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
4103 strcpyW((WCHAR*)cp, family_nameW);
4104 cp += lenfam;
4105 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
4106 strcpyW((WCHAR*)cp, style_nameW);
4107 cp += lensty;
4108 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
4109 strcpyW((WCHAR*)cp, family_nameW);
4110 if(strcasecmp(ft_face->style_name, "regular")) {
4111 strcatW((WCHAR*)cp, spaceW);
4112 strcatW((WCHAR*)cp, style_nameW);
4113 cp += lenfam + lensty;
4114 } else
4115 cp += lenfam;
4116 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
4117 strcpyW((WCHAR*)cp, family_nameW);
4118 strcatW((WCHAR*)cp, spaceW);
4119 strcatW((WCHAR*)cp, style_nameW);
4120 ret = needed;
4122 if(potm && needed <= cbSize)
4123 memcpy(potm, font->potm, font->potm->otmSize);
4125 end:
4126 HeapFree(GetProcessHeap(), 0, style_nameW);
4127 HeapFree(GetProcessHeap(), 0, family_nameW);
4129 return ret;
4132 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
4134 HFONTLIST *hfontlist;
4135 child->font = alloc_font();
4136 child->font->ft_face = OpenFontFile(child->font, child->face->file, child->face->face_index, 0, -font->ppem);
4137 if(!child->font->ft_face)
4139 free_font(child->font);
4140 child->font = NULL;
4141 return FALSE;
4144 child->font->orientation = font->orientation;
4145 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
4146 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
4147 list_add_head(&child->font->hfontlist, &hfontlist->entry);
4148 child->font->base_font = font;
4149 list_add_head(&child_font_list, &child->font->entry);
4150 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
4151 return TRUE;
4154 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
4156 FT_UInt g;
4157 CHILD_FONT *child_font;
4159 if(font->base_font)
4160 font = font->base_font;
4162 *linked_font = font;
4164 if((*glyph = get_glyph_index(font, c)))
4165 return TRUE;
4167 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
4169 if(!child_font->font)
4170 if(!load_child_font(font, child_font))
4171 continue;
4173 if(!child_font->font->ft_face)
4174 continue;
4175 g = get_glyph_index(child_font->font, c);
4176 if(g)
4178 *glyph = g;
4179 *linked_font = child_font->font;
4180 return TRUE;
4183 return FALSE;
4186 /*************************************************************
4187 * WineEngGetCharWidth
4190 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
4191 LPINT buffer)
4193 UINT c;
4194 GLYPHMETRICS gm;
4195 FT_UInt glyph_index;
4196 GdiFont *linked_font;
4198 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
4200 for(c = firstChar; c <= lastChar; c++) {
4201 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
4202 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4203 &gm, 0, NULL, NULL);
4204 buffer[c - firstChar] = FONT_GM(linked_font,glyph_index)->adv;
4206 return TRUE;
4209 /*************************************************************
4210 * WineEngGetCharABCWidths
4213 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
4214 LPABC buffer)
4216 UINT c;
4217 GLYPHMETRICS gm;
4218 FT_UInt glyph_index;
4219 GdiFont *linked_font;
4221 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
4223 if(!FT_IS_SCALABLE(font->ft_face))
4224 return FALSE;
4226 for(c = firstChar; c <= lastChar; c++) {
4227 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
4228 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4229 &gm, 0, NULL, NULL);
4230 buffer[c - firstChar].abcA = FONT_GM(linked_font,glyph_index)->lsb;
4231 buffer[c - firstChar].abcB = FONT_GM(linked_font,glyph_index)->bbx;
4232 buffer[c - firstChar].abcC = FONT_GM(linked_font,glyph_index)->adv - FONT_GM(linked_font,glyph_index)->lsb -
4233 FONT_GM(linked_font,glyph_index)->bbx;
4235 return TRUE;
4238 /*************************************************************
4239 * WineEngGetCharABCWidthsI
4242 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
4243 LPABC buffer)
4245 UINT c;
4246 GLYPHMETRICS gm;
4247 FT_UInt glyph_index;
4248 GdiFont *linked_font;
4250 if(!FT_IS_SCALABLE(font->ft_face))
4251 return FALSE;
4253 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
4254 if (!pgi)
4255 for(c = firstChar; c < firstChar+count; c++) {
4256 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
4257 &gm, 0, NULL, NULL);
4258 buffer[c - firstChar].abcA = FONT_GM(linked_font,c)->lsb;
4259 buffer[c - firstChar].abcB = FONT_GM(linked_font,c)->bbx;
4260 buffer[c - firstChar].abcC = FONT_GM(linked_font,c)->adv - FONT_GM(linked_font,c)->lsb
4261 - FONT_GM(linked_font,c)->bbx;
4263 else
4264 for(c = 0; c < count; c++) {
4265 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
4266 &gm, 0, NULL, NULL);
4267 buffer[c].abcA = FONT_GM(linked_font,pgi[c])->lsb;
4268 buffer[c].abcB = FONT_GM(linked_font,pgi[c])->bbx;
4269 buffer[c].abcC = FONT_GM(linked_font,pgi[c])->adv
4270 - FONT_GM(linked_font,pgi[c])->lsb - FONT_GM(linked_font,pgi[c])->bbx;
4273 return TRUE;
4276 /*************************************************************
4277 * WineEngGetTextExtentExPoint
4280 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
4281 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
4283 INT idx;
4284 INT nfit = 0, ext;
4285 GLYPHMETRICS gm;
4286 TEXTMETRICW tm;
4287 FT_UInt glyph_index;
4288 GdiFont *linked_font;
4290 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
4291 max_ext, size);
4293 size->cx = 0;
4294 WineEngGetTextMetrics(font, &tm);
4295 size->cy = tm.tmHeight;
4297 for(idx = 0; idx < count; idx++) {
4298 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
4299 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4300 &gm, 0, NULL, NULL);
4301 size->cx += FONT_GM(linked_font,glyph_index)->adv;
4302 ext = size->cx;
4303 if (! pnfit || ext <= max_ext) {
4304 ++nfit;
4305 if (dxs)
4306 dxs[idx] = ext;
4310 if (pnfit)
4311 *pnfit = nfit;
4313 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
4314 return TRUE;
4317 /*************************************************************
4318 * WineEngGetTextExtentPointI
4321 BOOL WineEngGetTextExtentPointI(GdiFont *font, const WORD *indices, INT count,
4322 LPSIZE size)
4324 INT idx;
4325 GLYPHMETRICS gm;
4326 TEXTMETRICW tm;
4328 TRACE("%p, %p, %d, %p\n", font, indices, count, size);
4330 size->cx = 0;
4331 WineEngGetTextMetrics(font, &tm);
4332 size->cy = tm.tmHeight;
4334 for(idx = 0; idx < count; idx++) {
4335 WineEngGetGlyphOutline(font, indices[idx],
4336 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
4337 NULL);
4338 size->cx += FONT_GM(font,indices[idx])->adv;
4340 TRACE("return %d,%d\n", size->cx, size->cy);
4341 return TRUE;
4344 /*************************************************************
4345 * WineEngGetFontData
4348 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
4349 DWORD cbData)
4351 FT_Face ft_face = font->ft_face;
4352 FT_ULong len;
4353 FT_Error err;
4355 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
4356 font, LOBYTE(LOWORD(table)), HIBYTE(LOWORD(table)),
4357 LOBYTE(HIWORD(table)), HIBYTE(HIWORD(table)), offset, buf, cbData);
4359 if(!FT_IS_SFNT(ft_face))
4360 return GDI_ERROR;
4362 if(!buf || !cbData)
4363 len = 0;
4364 else
4365 len = cbData;
4367 if(table) { /* MS tags differ in endidness from FT ones */
4368 table = table >> 24 | table << 24 |
4369 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
4372 /* If the FT_Load_Sfnt_Table function is there we'll use it */
4373 if(pFT_Load_Sfnt_Table) {
4374 /* make sure value of len is the value freetype says it needs */
4375 if( buf && len) {
4376 FT_ULong needed = 0;
4377 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
4378 if( !err && needed < len) len = needed;
4380 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
4382 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
4383 else { /* Do it the hard way */
4384 TT_Face tt_face = (TT_Face) ft_face;
4385 SFNT_Interface *sfnt;
4386 if (FT_Version.major==2 && FT_Version.minor==0)
4388 /* 2.0.x */
4389 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
4391 else
4393 /* A field was added in the middle of the structure in 2.1.x */
4394 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
4396 /* make sure value of len is the value freetype says it needs */
4397 if( buf && len) {
4398 FT_ULong needed = 0;
4399 err = sfnt->load_any(tt_face, table, offset, NULL, &needed);
4400 if( !err && needed < len) len = needed;
4402 err = sfnt->load_any(tt_face, table, offset, buf, &len);
4404 #else
4405 else {
4406 static int msg;
4407 if(!msg) {
4408 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
4409 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
4410 "Please upgrade your freetype library.\n");
4411 msg++;
4413 err = FT_Err_Unimplemented_Feature;
4415 #endif
4416 if(err) {
4417 TRACE("Can't find table %c%c%c%c\n",
4418 /* bytes were reversed */
4419 HIBYTE(HIWORD(table)), LOBYTE(HIWORD(table)),
4420 HIBYTE(LOWORD(table)), LOBYTE(LOWORD(table)));
4421 return GDI_ERROR;
4423 return len;
4426 /*************************************************************
4427 * WineEngGetTextFace
4430 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
4432 if(str) {
4433 lstrcpynW(str, font->name, count);
4434 return strlenW(font->name);
4435 } else
4436 return strlenW(font->name) + 1;
4439 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
4441 if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
4442 return font->charset;
4445 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
4447 GdiFont *font = dc->gdiFont, *linked_font;
4448 struct list *first_hfont;
4449 BOOL ret;
4451 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
4452 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
4453 if(font == linked_font)
4454 *new_hfont = dc->hFont;
4455 else
4457 first_hfont = list_head(&linked_font->hfontlist);
4458 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
4461 return ret;
4464 /* Retrieve a list of supported Unicode ranges for a given font.
4465 * Can be called with NULL gs to calculate the buffer size. Returns
4466 * the number of ranges found.
4468 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
4470 DWORD num_ranges = 0;
4472 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
4474 FT_UInt glyph_code;
4475 FT_ULong char_code, char_code_prev;
4477 glyph_code = 0;
4478 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
4480 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
4481 face->num_glyphs, glyph_code, char_code);
4483 if (!glyph_code) return 0;
4485 if (gs)
4487 gs->ranges[0].wcLow = (USHORT)char_code;
4488 gs->ranges[0].cGlyphs = 0;
4489 gs->cGlyphsSupported = 0;
4492 num_ranges = 1;
4493 while (glyph_code)
4495 if (char_code < char_code_prev)
4497 ERR("expected increasing char code from FT_Get_Next_Char\n");
4498 return 0;
4500 if (char_code - char_code_prev > 1)
4502 num_ranges++;
4503 if (gs)
4505 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
4506 gs->ranges[num_ranges - 1].cGlyphs = 1;
4507 gs->cGlyphsSupported++;
4510 else if (gs)
4512 gs->ranges[num_ranges - 1].cGlyphs++;
4513 gs->cGlyphsSupported++;
4515 char_code_prev = char_code;
4516 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
4519 else
4520 FIXME("encoding %u not supported\n", face->charmap->encoding);
4522 return num_ranges;
4525 DWORD WineEngGetFontUnicodeRanges(HDC hdc, LPGLYPHSET glyphset)
4527 DWORD size = 0;
4528 DC *dc = DC_GetDCPtr(hdc);
4530 TRACE("(%p, %p)\n", hdc, glyphset);
4532 if (!dc) return 0;
4534 if (dc->gdiFont)
4536 DWORD num_ranges = get_font_unicode_ranges(dc->gdiFont->ft_face, glyphset);
4538 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
4539 if (glyphset)
4541 glyphset->cbThis = size;
4542 glyphset->cRanges = num_ranges;
4546 DC_ReleaseDCPtr(dc);
4547 return size;
4550 /*************************************************************
4551 * FontIsLinked
4553 BOOL WINAPI FontIsLinked(HDC hdc)
4555 DC *dc = DC_GetDCPtr(hdc);
4556 BOOL ret = FALSE;
4558 if(!dc) return FALSE;
4559 if(dc->gdiFont && !list_empty(&dc->gdiFont->child_fonts))
4560 ret = TRUE;
4561 DC_ReleaseDCPtr(dc);
4562 TRACE("returning %d\n", ret);
4563 return ret;
4566 static BOOL is_hinting_enabled(void)
4568 /* Use the >= 2.2.0 function if available */
4569 if(pFT_Get_TrueType_Engine_Type)
4571 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
4572 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
4574 #ifdef FT_DRIVER_HAS_HINTER
4575 else
4577 FT_Module mod;
4579 /* otherwise if we've been compiled with < 2.2.0 headers
4580 use the internal macro */
4581 mod = pFT_Get_Module(library, "truetype");
4582 if(mod && FT_DRIVER_HAS_HINTER(mod))
4583 return TRUE;
4585 #endif
4587 return FALSE;
4590 /*************************************************************************
4591 * GetRasterizerCaps (GDI32.@)
4593 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
4595 static int hinting = -1;
4597 if(hinting == -1)
4599 hinting = is_hinting_enabled();
4600 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
4603 lprs->nSize = sizeof(RASTERIZER_STATUS);
4604 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
4605 lprs->nLanguageID = 0;
4606 return TRUE;
4609 /*************************************************************************
4610 * Kerning support for TrueType fonts
4612 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
4614 struct TT_kern_table
4616 USHORT version;
4617 USHORT nTables;
4620 struct TT_kern_subtable
4622 USHORT version;
4623 USHORT length;
4624 union
4626 USHORT word;
4627 struct
4629 USHORT horizontal : 1;
4630 USHORT minimum : 1;
4631 USHORT cross_stream: 1;
4632 USHORT override : 1;
4633 USHORT reserved1 : 4;
4634 USHORT format : 8;
4635 } bits;
4636 } coverage;
4639 struct TT_format0_kern_subtable
4641 USHORT nPairs;
4642 USHORT searchRange;
4643 USHORT entrySelector;
4644 USHORT rangeShift;
4647 struct TT_kern_pair
4649 USHORT left;
4650 USHORT right;
4651 short value;
4654 static DWORD parse_format0_kern_subtable(GdiFont *font,
4655 const struct TT_format0_kern_subtable *tt_f0_ks,
4656 const USHORT *glyph_to_char,
4657 KERNINGPAIR *kern_pair, DWORD cPairs)
4659 USHORT i, nPairs;
4660 const struct TT_kern_pair *tt_kern_pair;
4662 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
4664 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
4666 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
4667 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
4668 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
4670 if (!kern_pair || !cPairs)
4671 return nPairs;
4673 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
4675 nPairs = min(nPairs, cPairs);
4677 for (i = 0; i < nPairs; i++)
4679 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
4680 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
4681 /* this algorithm appears to better match what Windows does */
4682 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
4683 if (kern_pair->iKernAmount < 0)
4685 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
4686 kern_pair->iKernAmount -= font->ppem;
4688 else if (kern_pair->iKernAmount > 0)
4690 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
4691 kern_pair->iKernAmount += font->ppem;
4693 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
4695 TRACE("left %u right %u value %d\n",
4696 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
4698 kern_pair++;
4700 TRACE("copied %u entries\n", nPairs);
4701 return nPairs;
4704 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
4706 DWORD length;
4707 void *buf;
4708 const struct TT_kern_table *tt_kern_table;
4709 const struct TT_kern_subtable *tt_kern_subtable;
4710 USHORT i, nTables;
4711 USHORT *glyph_to_char;
4713 if (font->total_kern_pairs != (DWORD)-1)
4715 if (cPairs && kern_pair)
4717 cPairs = min(cPairs, font->total_kern_pairs);
4718 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
4719 return cPairs;
4721 return font->total_kern_pairs;
4724 font->total_kern_pairs = 0;
4726 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
4728 if (length == GDI_ERROR)
4730 TRACE("no kerning data in the font\n");
4731 return 0;
4734 buf = HeapAlloc(GetProcessHeap(), 0, length);
4735 if (!buf)
4737 WARN("Out of memory\n");
4738 return 0;
4741 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
4743 /* build a glyph index to char code map */
4744 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
4745 if (!glyph_to_char)
4747 WARN("Out of memory allocating a glyph index to char code map\n");
4748 HeapFree(GetProcessHeap(), 0, buf);
4749 return 0;
4752 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
4754 FT_UInt glyph_code;
4755 FT_ULong char_code;
4757 glyph_code = 0;
4758 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
4760 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
4761 font->ft_face->num_glyphs, glyph_code, char_code);
4763 while (glyph_code)
4765 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
4767 /* FIXME: This doesn't match what Windows does: it does some fancy
4768 * things with duplicate glyph index to char code mappings, while
4769 * we just avoid overriding existing entries.
4771 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
4772 glyph_to_char[glyph_code] = (USHORT)char_code;
4774 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
4777 else
4779 ULONG n;
4781 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
4782 for (n = 0; n <= 65535; n++)
4783 glyph_to_char[n] = (USHORT)n;
4786 tt_kern_table = buf;
4787 nTables = GET_BE_WORD(tt_kern_table->nTables);
4788 TRACE("version %u, nTables %u\n",
4789 GET_BE_WORD(tt_kern_table->version), nTables);
4791 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
4793 for (i = 0; i < nTables; i++)
4795 struct TT_kern_subtable tt_kern_subtable_copy;
4797 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
4798 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
4799 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
4801 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
4802 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
4803 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
4805 /* According to the TrueType specification this is the only format
4806 * that will be properly interpreted by Windows and OS/2
4808 if (tt_kern_subtable_copy.coverage.bits.format == 0)
4810 DWORD new_chunk, old_total = font->total_kern_pairs;
4812 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
4813 glyph_to_char, NULL, 0);
4814 font->total_kern_pairs += new_chunk;
4816 if (!font->kern_pairs)
4817 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
4818 font->total_kern_pairs * sizeof(*font->kern_pairs));
4819 else
4820 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
4821 font->total_kern_pairs * sizeof(*font->kern_pairs));
4823 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
4824 glyph_to_char, font->kern_pairs + old_total, new_chunk);
4826 else
4827 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
4829 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
4832 HeapFree(GetProcessHeap(), 0, glyph_to_char);
4833 HeapFree(GetProcessHeap(), 0, buf);
4835 if (cPairs && kern_pair)
4837 cPairs = min(cPairs, font->total_kern_pairs);
4838 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
4839 return cPairs;
4841 return font->total_kern_pairs;
4844 #else /* HAVE_FREETYPE */
4846 /*************************************************************************/
4848 BOOL WineEngInit(void)
4850 return FALSE;
4852 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
4854 return NULL;
4856 BOOL WineEngDestroyFontInstance(HFONT hfont)
4858 return FALSE;
4861 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
4863 return 1;
4866 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4867 LPWORD pgi, DWORD flags)
4869 return GDI_ERROR;
4872 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
4873 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4874 const MAT2* lpmat)
4876 ERR("called but we don't have FreeType\n");
4877 return GDI_ERROR;
4880 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
4882 ERR("called but we don't have FreeType\n");
4883 return FALSE;
4886 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
4887 OUTLINETEXTMETRICW *potm)
4889 ERR("called but we don't have FreeType\n");
4890 return 0;
4893 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
4894 LPINT buffer)
4896 ERR("called but we don't have FreeType\n");
4897 return FALSE;
4900 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
4901 LPABC buffer)
4903 ERR("called but we don't have FreeType\n");
4904 return FALSE;
4907 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
4908 LPABC buffer)
4910 ERR("called but we don't have FreeType\n");
4911 return FALSE;
4914 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
4915 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
4917 ERR("called but we don't have FreeType\n");
4918 return FALSE;
4921 BOOL WineEngGetTextExtentPointI(GdiFont *font, const WORD *indices, INT count,
4922 LPSIZE size)
4924 ERR("called but we don't have FreeType\n");
4925 return FALSE;
4928 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
4929 DWORD cbData)
4931 ERR("called but we don't have FreeType\n");
4932 return GDI_ERROR;
4935 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
4937 ERR("called but we don't have FreeType\n");
4938 return 0;
4941 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
4943 FIXME(":stub\n");
4944 return 1;
4947 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
4949 FIXME(":stub\n");
4950 return TRUE;
4953 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
4955 FIXME(":stub\n");
4956 return DEFAULT_CHARSET;
4959 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
4961 return FALSE;
4964 DWORD WineEngGetFontUnicodeRanges(HDC hdc, LPGLYPHSET glyphset)
4966 FIXME("(%p, %p): stub\n", hdc, glyphset);
4967 return 0;
4970 BOOL WINAPI FontIsLinked(HDC hdc)
4972 return FALSE;
4975 /*************************************************************************
4976 * GetRasterizerCaps (GDI32.@)
4978 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
4980 lprs->nSize = sizeof(RASTERIZER_STATUS);
4981 lprs->wFlags = 0;
4982 lprs->nLanguageID = 0;
4983 return TRUE;
4986 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
4988 ERR("called but we don't have FreeType\n");
4989 return 0;
4992 #endif /* HAVE_FREETYPE */