gdiplus/tests: Added pen dash array tests.
[wine.git] / dlls / gdi32 / freetype.c
blobcdd23ef68d09c431d0f2b832fd54864ed7ad9dad
1 /*
2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
5 * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
7 * This file contains the WineEng* functions.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "config.h"
25 #include "wine/port.h"
27 #include <stdarg.h>
28 #include <stdlib.h>
29 #ifdef HAVE_SYS_STAT_H
30 # include <sys/stat.h>
31 #endif
32 #ifdef HAVE_SYS_MMAN_H
33 # include <sys/mman.h>
34 #endif
35 #include <string.h>
36 #include <dirent.h>
37 #include <stdio.h>
38 #include <assert.h>
40 #ifdef HAVE_CARBON_CARBON_H
41 #define LoadResource __carbon_LoadResource
42 #define CompareString __carbon_CompareString
43 #define GetCurrentThread __carbon_GetCurrentThread
44 #define GetCurrentProcess __carbon_GetCurrentProcess
45 #define AnimatePalette __carbon_AnimatePalette
46 #define EqualRgn __carbon_EqualRgn
47 #define FillRgn __carbon_FillRgn
48 #define FrameRgn __carbon_FrameRgn
49 #define GetPixel __carbon_GetPixel
50 #define InvertRgn __carbon_InvertRgn
51 #define LineTo __carbon_LineTo
52 #define OffsetRgn __carbon_OffsetRgn
53 #define PaintRgn __carbon_PaintRgn
54 #define Polygon __carbon_Polygon
55 #define ResizePalette __carbon_ResizePalette
56 #define SetRectRgn __carbon_SetRectRgn
57 #include <Carbon/Carbon.h>
58 #undef LoadResource
59 #undef CompareString
60 #undef GetCurrentThread
61 #undef _CDECL
62 #undef DPRINTF
63 #undef GetCurrentProcess
64 #undef AnimatePalette
65 #undef EqualRgn
66 #undef FillRgn
67 #undef FrameRgn
68 #undef GetPixel
69 #undef InvertRgn
70 #undef LineTo
71 #undef OffsetRgn
72 #undef PaintRgn
73 #undef Polygon
74 #undef ResizePalette
75 #undef SetRectRgn
76 #endif /* HAVE_CARBON_CARBON_H */
78 #include "windef.h"
79 #include "winbase.h"
80 #include "winternl.h"
81 #include "winerror.h"
82 #include "winreg.h"
83 #include "wingdi.h"
84 #include "gdi_private.h"
85 #include "wine/unicode.h"
86 #include "wine/debug.h"
87 #include "wine/list.h"
89 WINE_DEFAULT_DEBUG_CHANNEL(font);
91 #ifdef HAVE_FREETYPE
93 #ifdef HAVE_FT2BUILD_H
94 #include <ft2build.h>
95 #endif
96 #ifdef HAVE_FREETYPE_FREETYPE_H
97 #include <freetype/freetype.h>
98 #endif
99 #ifdef HAVE_FREETYPE_FTGLYPH_H
100 #include <freetype/ftglyph.h>
101 #endif
102 #ifdef HAVE_FREETYPE_TTTABLES_H
103 #include <freetype/tttables.h>
104 #endif
105 #ifdef HAVE_FREETYPE_FTSNAMES_H
106 #include <freetype/ftsnames.h>
107 #else
108 # ifdef HAVE_FREETYPE_FTNAMES_H
109 # include <freetype/ftnames.h>
110 # endif
111 #endif
112 #ifdef HAVE_FREETYPE_TTNAMEID_H
113 #include <freetype/ttnameid.h>
114 #endif
115 #ifdef HAVE_FREETYPE_FTOUTLN_H
116 #include <freetype/ftoutln.h>
117 #endif
118 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
119 #include <freetype/internal/sfnt.h>
120 #endif
121 #ifdef HAVE_FREETYPE_FTTRIGON_H
122 #include <freetype/fttrigon.h>
123 #endif
124 #ifdef HAVE_FREETYPE_FTWINFNT_H
125 #include <freetype/ftwinfnt.h>
126 #endif
127 #ifdef HAVE_FREETYPE_FTMODAPI_H
128 #include <freetype/ftmodapi.h>
129 #endif
131 #ifndef HAVE_FT_TRUETYPEENGINETYPE
132 typedef enum
134 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
135 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
136 FT_TRUETYPE_ENGINE_TYPE_PATENTED
137 } FT_TrueTypeEngineType;
138 #endif
140 static FT_Library library = 0;
141 typedef struct
143 FT_Int major;
144 FT_Int minor;
145 FT_Int patch;
146 } FT_Version_t;
147 static FT_Version_t FT_Version;
148 static DWORD FT_SimpleVersion;
150 static void *ft_handle = NULL;
152 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
153 MAKE_FUNCPTR(FT_Vector_Unit);
154 MAKE_FUNCPTR(FT_Done_Face);
155 MAKE_FUNCPTR(FT_Get_Char_Index);
156 MAKE_FUNCPTR(FT_Get_Module);
157 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
158 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
159 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
160 MAKE_FUNCPTR(FT_Init_FreeType);
161 MAKE_FUNCPTR(FT_Load_Glyph);
162 MAKE_FUNCPTR(FT_Matrix_Multiply);
163 MAKE_FUNCPTR(FT_MulFix);
164 MAKE_FUNCPTR(FT_New_Face);
165 MAKE_FUNCPTR(FT_New_Memory_Face);
166 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
167 MAKE_FUNCPTR(FT_Outline_Transform);
168 MAKE_FUNCPTR(FT_Outline_Translate);
169 MAKE_FUNCPTR(FT_Select_Charmap);
170 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
171 MAKE_FUNCPTR(FT_Vector_Transform);
172 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
173 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
174 static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*);
175 static FT_ULong (*pFT_Get_Next_Char)(FT_Face,FT_ULong,FT_UInt*);
176 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
177 #ifdef HAVE_FREETYPE_FTWINFNT_H
178 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
179 #endif
181 #ifdef SONAME_LIBFONTCONFIG
182 #include <fontconfig/fontconfig.h>
183 MAKE_FUNCPTR(FcConfigGetCurrent);
184 MAKE_FUNCPTR(FcFontList);
185 MAKE_FUNCPTR(FcFontSetDestroy);
186 MAKE_FUNCPTR(FcInit);
187 MAKE_FUNCPTR(FcObjectSetAdd);
188 MAKE_FUNCPTR(FcObjectSetCreate);
189 MAKE_FUNCPTR(FcObjectSetDestroy);
190 MAKE_FUNCPTR(FcPatternCreate);
191 MAKE_FUNCPTR(FcPatternDestroy);
192 MAKE_FUNCPTR(FcPatternGetBool);
193 MAKE_FUNCPTR(FcPatternGetString);
194 #endif
196 #undef MAKE_FUNCPTR
198 #ifndef ft_encoding_none
199 #define FT_ENCODING_NONE ft_encoding_none
200 #endif
201 #ifndef ft_encoding_ms_symbol
202 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
203 #endif
204 #ifndef ft_encoding_unicode
205 #define FT_ENCODING_UNICODE ft_encoding_unicode
206 #endif
207 #ifndef ft_encoding_apple_roman
208 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
209 #endif
211 #ifdef WORDS_BIGENDIAN
212 #define GET_BE_WORD(x) (x)
213 #else
214 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
215 #endif
217 /* This is bascially a copy of FT_Bitmap_Size with an extra element added */
218 typedef struct {
219 FT_Short height;
220 FT_Short width;
221 FT_Pos size;
222 FT_Pos x_ppem;
223 FT_Pos y_ppem;
224 FT_Short internal_leading;
225 } Bitmap_Size;
227 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
228 So to let this compile on older versions of FreeType we'll define the
229 new structure here. */
230 typedef struct {
231 FT_Short height, width;
232 FT_Pos size, x_ppem, y_ppem;
233 } My_FT_Bitmap_Size;
235 typedef struct tagFace {
236 struct list entry;
237 WCHAR *StyleName;
238 char *file;
239 FT_Long face_index;
240 BOOL Italic;
241 BOOL Bold;
242 FONTSIGNATURE fs;
243 FONTSIGNATURE fs_links;
244 FT_Fixed font_version;
245 BOOL scalable;
246 Bitmap_Size size; /* set if face is a bitmap */
247 BOOL external; /* TRUE if we should manually add this font to the registry */
248 struct tagFamily *family;
249 } Face;
251 typedef struct tagFamily {
252 struct list entry;
253 const WCHAR *FamilyName;
254 struct list faces;
255 } Family;
257 typedef struct {
258 GLYPHMETRICS gm;
259 INT adv; /* These three hold to widths of the unrotated chars */
260 INT lsb;
261 INT bbx;
262 BOOL init;
263 } GM;
265 typedef struct {
266 FLOAT eM11, eM12;
267 FLOAT eM21, eM22;
268 } FMAT2;
270 typedef struct {
271 DWORD hash;
272 LOGFONTW lf;
273 FMAT2 matrix;
274 BOOL can_use_bitmap;
275 } FONT_DESC;
277 typedef struct tagHFONTLIST {
278 struct list entry;
279 HFONT hfont;
280 } HFONTLIST;
282 typedef struct {
283 struct list entry;
284 char *file_name;
285 INT index;
286 GdiFont *font;
287 } CHILD_FONT;
289 struct tagGdiFont {
290 struct list entry;
291 FT_Face ft_face;
292 struct font_mapping *mapping;
293 LPWSTR name;
294 int charset;
295 int codepage;
296 BOOL fake_italic;
297 BOOL fake_bold;
298 BYTE underline;
299 BYTE strikeout;
300 INT orientation;
301 GM *gm;
302 DWORD gmsize;
303 struct list hfontlist;
304 FONT_DESC font_desc;
305 LONG aveWidth;
306 SHORT yMax;
307 SHORT yMin;
308 OUTLINETEXTMETRICW *potm;
309 DWORD total_kern_pairs;
310 KERNINGPAIR *kern_pairs;
311 FONTSIGNATURE fs;
312 GdiFont *base_font;
313 struct list child_fonts;
314 LONG ppem;
317 typedef struct {
318 struct list entry;
319 const WCHAR *font_name;
320 struct list links;
321 } SYSTEM_LINKS;
323 #define INIT_GM_SIZE 128
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 Face *find_face_from_path_index(const CHAR *file_name, const INT index)
742 Family *family;
743 Face *face;
745 TRACE("looking for file %s index %i\n", debugstr_a(file_name), index);
747 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
749 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
751 if(!strcasecmp(face->file, file_name) && face->face_index == index)
752 return face;
755 return NULL;
758 static void DumpSubstList(void)
760 FontSubst *psub;
762 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
764 if(psub->from.charset != -1 || psub->to.charset != -1)
765 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
766 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
767 else
768 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
769 debugstr_w(psub->to.name));
771 return;
774 static LPWSTR strdupW(LPCWSTR p)
776 LPWSTR ret;
777 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
778 ret = HeapAlloc(GetProcessHeap(), 0, len);
779 memcpy(ret, p, len);
780 return ret;
783 static LPSTR strdupA(LPCSTR p)
785 LPSTR ret;
786 DWORD len = (strlen(p) + 1);
787 ret = HeapAlloc(GetProcessHeap(), 0, len);
788 memcpy(ret, p, len);
789 return ret;
792 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
793 INT from_charset)
795 FontSubst *element;
797 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
799 if(!strcmpiW(element->from.name, from_name) &&
800 (element->from.charset == from_charset ||
801 element->from.charset == -1))
802 return element;
805 return NULL;
808 #define ADD_FONT_SUBST_FORCE 1
810 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
812 FontSubst *from_exist, *to_exist;
814 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
816 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
818 list_remove(&from_exist->entry);
819 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
820 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
821 HeapFree(GetProcessHeap(), 0, from_exist);
822 from_exist = NULL;
825 if(!from_exist)
827 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
829 if(to_exist)
831 HeapFree(GetProcessHeap(), 0, subst->to.name);
832 subst->to.name = strdupW(to_exist->to.name);
835 list_add_tail(subst_list, &subst->entry);
837 return TRUE;
840 HeapFree(GetProcessHeap(), 0, subst->from.name);
841 HeapFree(GetProcessHeap(), 0, subst->to.name);
842 HeapFree(GetProcessHeap(), 0, subst);
843 return FALSE;
846 static void split_subst_info(NameCs *nc, LPSTR str)
848 CHAR *p = strrchr(str, ',');
849 DWORD len;
851 nc->charset = -1;
852 if(p && *(p+1)) {
853 nc->charset = strtol(p+1, NULL, 10);
854 *p = '\0';
856 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
857 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
858 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
861 static void LoadSubstList(void)
863 FontSubst *psub;
864 HKEY hkey;
865 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
866 LPSTR value;
867 LPVOID data;
869 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
870 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
871 &hkey) == ERROR_SUCCESS) {
873 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
874 &valuelen, &datalen, NULL, NULL);
876 valuelen++; /* returned value doesn't include room for '\0' */
877 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
878 data = HeapAlloc(GetProcessHeap(), 0, datalen);
880 dlen = datalen;
881 vlen = valuelen;
882 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
883 &dlen) == ERROR_SUCCESS) {
884 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
886 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
887 split_subst_info(&psub->from, value);
888 split_subst_info(&psub->to, data);
890 /* Win 2000 doesn't allow mapping between different charsets
891 or mapping of DEFAULT_CHARSET */
892 if((psub->to.charset != psub->from.charset) ||
893 psub->to.charset == DEFAULT_CHARSET) {
894 HeapFree(GetProcessHeap(), 0, psub->to.name);
895 HeapFree(GetProcessHeap(), 0, psub->from.name);
896 HeapFree(GetProcessHeap(), 0, psub);
897 } else {
898 add_font_subst(&font_subst_list, psub, 0);
900 /* reset dlen and vlen */
901 dlen = datalen;
902 vlen = valuelen;
904 HeapFree(GetProcessHeap(), 0, data);
905 HeapFree(GetProcessHeap(), 0, value);
906 RegCloseKey(hkey);
910 static WCHAR *get_familyname(FT_Face ft_face)
912 WCHAR *family = NULL;
913 FT_SfntName name;
914 FT_UInt num_names, name_index, i;
916 if(FT_IS_SFNT(ft_face))
918 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
920 for(name_index = 0; name_index < num_names; name_index++)
922 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
924 if((name.name_id == TT_NAME_ID_FONT_FAMILY) &&
925 (name.language_id == GetUserDefaultLCID()) &&
926 (name.platform_id == TT_PLATFORM_MICROSOFT) &&
927 (name.encoding_id == TT_MS_ID_UNICODE_CS))
929 /* String is not nul terminated and string_len is a byte length. */
930 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
931 for(i = 0; i < name.string_len / 2; i++)
933 WORD *tmp = (WORD *)&name.string[i * 2];
934 family[i] = GET_BE_WORD(*tmp);
936 family[i] = 0;
938 TRACE("Got localised name %s\n", debugstr_w(family));
939 return family;
945 return NULL;
949 #define ADDFONT_EXTERNAL_FONT 0x01
950 #define ADDFONT_FORCE_BITMAP 0x02
951 static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
953 FT_Face ft_face;
954 TT_OS2 *pOS2;
955 TT_Header *pHeader = NULL;
956 WCHAR *english_family, *localised_family, *StyleW;
957 DWORD len;
958 Family *family;
959 Face *face;
960 struct list *family_elem_ptr, *face_elem_ptr;
961 FT_Error err;
962 FT_Long face_index = 0, num_faces;
963 #ifdef HAVE_FREETYPE_FTWINFNT_H
964 FT_WinFNT_HeaderRec winfnt_header;
965 #endif
966 int i, bitmap_num, internal_leading;
967 FONTSIGNATURE fs;
969 #ifdef HAVE_CARBON_CARBON_H
970 if(!fake_family)
972 char **mac_list = expand_mac_font(file);
973 if(mac_list)
975 BOOL had_one = FALSE;
976 char **cursor;
977 for(cursor = mac_list; *cursor; cursor++)
979 had_one = TRUE;
980 AddFontFileToList(*cursor, NULL, NULL, flags);
981 HeapFree(GetProcessHeap(), 0, *cursor);
983 HeapFree(GetProcessHeap(), 0, mac_list);
984 if(had_one)
985 return 1;
988 #endif /* HAVE_CARBON_CARBON_H */
990 do {
991 char *family_name = fake_family;
993 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
994 if((err = pFT_New_Face(library, file, face_index, &ft_face)) != 0) {
995 WARN("Unable to load font file %s err = %x\n", debugstr_a(file), err);
996 return 0;
999 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*/
1000 WARN("Ignoring font %s\n", debugstr_a(file));
1001 pFT_Done_Face(ft_face);
1002 return 0;
1005 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1006 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1007 WARN("FreeType version < 2.1.9, skipping bitmap font %s\n", debugstr_a(file));
1008 pFT_Done_Face(ft_face);
1009 return 0;
1012 if(FT_IS_SFNT(ft_face) && (!pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2) ||
1013 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1014 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))) {
1015 TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
1016 "Skipping this font.\n", debugstr_a(file));
1017 pFT_Done_Face(ft_face);
1018 return 0;
1021 if(!ft_face->family_name || !ft_face->style_name) {
1022 TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file));
1023 pFT_Done_Face(ft_face);
1024 return 0;
1027 if (target_family)
1029 localised_family = get_familyname(ft_face);
1030 if (localised_family && strcmpiW(localised_family,target_family)!=0)
1032 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1033 HeapFree(GetProcessHeap(), 0, localised_family);
1034 num_faces = ft_face->num_faces;
1035 pFT_Done_Face(ft_face);
1036 continue;
1038 HeapFree(GetProcessHeap(), 0, localised_family);
1041 if(!family_name)
1042 family_name = ft_face->family_name;
1044 bitmap_num = 0;
1045 do {
1046 My_FT_Bitmap_Size *size = NULL;
1048 if(!FT_IS_SCALABLE(ft_face))
1049 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1051 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1052 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1053 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1055 localised_family = NULL;
1056 if(!fake_family) {
1057 localised_family = get_familyname(ft_face);
1058 if(localised_family && !strcmpW(localised_family, english_family)) {
1059 HeapFree(GetProcessHeap(), 0, localised_family);
1060 localised_family = NULL;
1064 family = NULL;
1065 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1066 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1067 if(!strcmpW(family->FamilyName, localised_family ? localised_family : english_family))
1068 break;
1069 family = NULL;
1071 if(!family) {
1072 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1073 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1074 list_init(&family->faces);
1075 list_add_tail(&font_list, &family->entry);
1077 if(localised_family) {
1078 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1079 subst->from.name = strdupW(english_family);
1080 subst->from.charset = -1;
1081 subst->to.name = strdupW(localised_family);
1082 subst->to.charset = -1;
1083 add_font_subst(&font_subst_list, subst, 0);
1086 HeapFree(GetProcessHeap(), 0, localised_family);
1087 HeapFree(GetProcessHeap(), 0, english_family);
1089 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1090 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1091 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1093 internal_leading = 0;
1094 memset(&fs, 0, sizeof(fs));
1096 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1097 if(pOS2) {
1098 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1099 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1100 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1101 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1102 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1103 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1104 if(pOS2->version == 0) {
1105 FT_UInt dummy;
1107 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1108 fs.fsCsb[0] |= 1;
1109 else
1110 fs.fsCsb[0] |= 1L << 31;
1113 #ifdef HAVE_FREETYPE_FTWINFNT_H
1114 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1115 CHARSETINFO csi;
1116 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1117 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1118 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1119 memcpy(&fs, &csi.fs, sizeof(csi.fs));
1120 internal_leading = winfnt_header.internal_leading;
1122 #endif
1124 face_elem_ptr = list_head(&family->faces);
1125 while(face_elem_ptr) {
1126 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1127 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1128 if(!strcmpW(face->StyleName, StyleW) &&
1129 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1130 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1131 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1132 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1134 if(fake_family) {
1135 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1136 HeapFree(GetProcessHeap(), 0, StyleW);
1137 pFT_Done_Face(ft_face);
1138 return 1;
1140 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1141 TRACE("Original font is newer so skipping this one\n");
1142 HeapFree(GetProcessHeap(), 0, StyleW);
1143 pFT_Done_Face(ft_face);
1144 return 1;
1145 } else {
1146 TRACE("Replacing original with this one\n");
1147 list_remove(&face->entry);
1148 HeapFree(GetProcessHeap(), 0, face->file);
1149 HeapFree(GetProcessHeap(), 0, face->StyleName);
1150 HeapFree(GetProcessHeap(), 0, face);
1151 break;
1155 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1156 list_add_tail(&family->faces, &face->entry);
1157 face->StyleName = StyleW;
1158 face->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
1159 strcpy(face->file, file);
1160 face->face_index = face_index;
1161 face->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
1162 face->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
1163 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1164 face->family = family;
1165 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1166 memcpy(&face->fs, &fs, sizeof(face->fs));
1167 memset(&face->fs_links, 0, sizeof(face->fs_links));
1169 if(FT_IS_SCALABLE(ft_face)) {
1170 memset(&face->size, 0, sizeof(face->size));
1171 face->scalable = TRUE;
1172 } else {
1173 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1174 size->height, size->width, size->size >> 6,
1175 size->x_ppem >> 6, size->y_ppem >> 6);
1176 face->size.height = size->height;
1177 face->size.width = size->width;
1178 face->size.size = size->size;
1179 face->size.x_ppem = size->x_ppem;
1180 face->size.y_ppem = size->y_ppem;
1181 face->size.internal_leading = internal_leading;
1182 face->scalable = FALSE;
1185 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1186 face->fs.fsCsb[0], face->fs.fsCsb[1],
1187 face->fs.fsUsb[0], face->fs.fsUsb[1],
1188 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1191 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1192 for(i = 0; i < ft_face->num_charmaps; i++) {
1193 switch(ft_face->charmaps[i]->encoding) {
1194 case FT_ENCODING_UNICODE:
1195 case FT_ENCODING_APPLE_ROMAN:
1196 face->fs.fsCsb[0] |= 1;
1197 break;
1198 case FT_ENCODING_MS_SYMBOL:
1199 face->fs.fsCsb[0] |= 1L << 31;
1200 break;
1201 default:
1202 break;
1207 if(face->fs.fsCsb[0] & ~(1L << 31))
1208 have_installed_roman_font = TRUE;
1209 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1211 num_faces = ft_face->num_faces;
1212 pFT_Done_Face(ft_face);
1213 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1214 debugstr_w(StyleW));
1215 } while(num_faces > ++face_index);
1216 return num_faces;
1219 static void DumpFontList(void)
1221 Family *family;
1222 Face *face;
1223 struct list *family_elem_ptr, *face_elem_ptr;
1225 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1226 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1227 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1228 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1229 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1230 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1231 if(!face->scalable)
1232 TRACE(" %d", face->size.height);
1233 TRACE("\n");
1236 return;
1239 /***********************************************************
1240 * The replacement list is a way to map an entire font
1241 * family onto another family. For example adding
1243 * [HKCU\Software\Wine\Fonts\Replacements]
1244 * "Wingdings"="Winedings"
1246 * would enumerate the Winedings font both as Winedings and
1247 * Wingdings. However if a real Wingdings font is present the
1248 * replacement does not take place.
1251 static void LoadReplaceList(void)
1253 HKEY hkey;
1254 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1255 LPWSTR value;
1256 LPVOID data;
1257 Family *family;
1258 Face *face;
1259 struct list *family_elem_ptr, *face_elem_ptr;
1260 CHAR familyA[400];
1262 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1263 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1265 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1266 &valuelen, &datalen, NULL, NULL);
1268 valuelen++; /* returned value doesn't include room for '\0' */
1269 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1270 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1272 dlen = datalen;
1273 vlen = valuelen;
1274 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1275 &dlen) == ERROR_SUCCESS) {
1276 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1277 /* "NewName"="Oldname" */
1278 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1280 /* Find the old family and hence all of the font files
1281 in that family */
1282 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1283 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1284 if(!strcmpiW(family->FamilyName, data)) {
1285 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1286 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1287 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1288 debugstr_w(face->StyleName), familyA);
1289 /* Now add a new entry with the new family name */
1290 AddFontFileToList(face->file, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1292 break;
1295 /* reset dlen and vlen */
1296 dlen = datalen;
1297 vlen = valuelen;
1299 HeapFree(GetProcessHeap(), 0, data);
1300 HeapFree(GetProcessHeap(), 0, value);
1301 RegCloseKey(hkey);
1305 /*************************************************************
1306 * init_system_links
1308 static BOOL init_system_links(void)
1310 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1311 'W','i','n','d','o','w','s',' ','N','T','\\',
1312 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1313 'S','y','s','t','e','m','L','i','n','k',0};
1314 HKEY hkey;
1315 BOOL ret = FALSE;
1316 DWORD type, max_val, max_data, val_len, data_len, index;
1317 WCHAR *value, *data;
1318 WCHAR *entry, *next;
1319 SYSTEM_LINKS *font_link, *system_font_link;
1320 CHILD_FONT *child_font;
1321 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
1322 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1323 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1324 FONTSIGNATURE fs;
1325 Family *family;
1326 Face *face;
1327 FontSubst *psub;
1329 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1331 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1332 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1333 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1334 val_len = max_val + 1;
1335 data_len = max_data;
1336 index = 0;
1337 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1339 TRACE("%s:\n", debugstr_w(value));
1341 memset(&fs, 0, sizeof(fs));
1342 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1343 psub = get_font_subst(&font_subst_list, value, -1);
1344 font_link->font_name = (psub)? strdupW(psub->to.name) : strdupW(value);
1345 list_init(&font_link->links);
1346 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1348 WCHAR *face_name;
1349 CHILD_FONT *child_font;
1351 TRACE("\t%s\n", debugstr_w(entry));
1353 next = entry + strlenW(entry) + 1;
1355 face_name = strchrW(entry, ',');
1356 if(face_name)
1358 *face_name++ = 0;
1359 while(isspaceW(*face_name))
1360 face_name++;
1362 psub = get_font_subst(&font_subst_list, face_name, -1);
1363 if(psub)
1364 face_name = psub->to.name;
1366 face = find_face_from_filename(entry, face_name);
1367 if(!face)
1369 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1370 continue;
1373 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1374 child_font->file_name = strdupA(face->file);
1375 child_font->index = face->face_index;
1376 child_font->font = NULL;
1377 fs.fsCsb[0] |= face->fs.fsCsb[0];
1378 fs.fsCsb[1] |= face->fs.fsCsb[1];
1379 TRACE("Adding file %s index %d\n", child_font->file_name, child_font->index);
1380 list_add_tail(&font_link->links, &child_font->entry);
1382 family = find_family_from_name(font_link->font_name);
1383 if(family)
1385 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1387 memcpy(&face->fs_links, &fs, sizeof(fs));
1390 list_add_tail(&system_links, &font_link->entry);
1391 val_len = max_val + 1;
1392 data_len = max_data;
1395 HeapFree(GetProcessHeap(), 0, value);
1396 HeapFree(GetProcessHeap(), 0, data);
1397 RegCloseKey(hkey);
1400 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1401 that Tahoma has */
1403 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1404 system_font_link->font_name = strdupW(System);
1405 list_init(&system_font_link->links);
1407 face = find_face_from_filename(tahoma_ttf, Tahoma);
1408 if(face)
1410 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1411 child_font->file_name = strdupA(face->file);
1412 child_font->index = face->face_index;
1413 child_font->font = NULL;
1414 TRACE("Found Tahoma in %s index %d\n", child_font->file_name, child_font->index);
1415 list_add_tail(&system_font_link->links, &child_font->entry);
1417 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1419 if(!strcmpiW(font_link->font_name, Tahoma))
1421 CHILD_FONT *font_link_entry;
1422 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1424 CHILD_FONT *new_child;
1425 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1426 new_child->file_name = strdupA(font_link_entry->file_name);
1427 new_child->index = font_link_entry->index;
1428 new_child->font = NULL;
1429 list_add_tail(&system_font_link->links, &new_child->entry);
1431 break;
1434 list_add_tail(&system_links, &system_font_link->entry);
1435 return ret;
1438 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1440 DIR *dir;
1441 struct dirent *dent;
1442 char path[MAX_PATH];
1444 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1446 dir = opendir(dirname);
1447 if(!dir) {
1448 WARN("Can't open directory %s\n", debugstr_a(dirname));
1449 return FALSE;
1451 while((dent = readdir(dir)) != NULL) {
1452 struct stat statbuf;
1454 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1455 continue;
1457 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1459 sprintf(path, "%s/%s", dirname, dent->d_name);
1461 if(stat(path, &statbuf) == -1)
1463 WARN("Can't stat %s\n", debugstr_a(path));
1464 continue;
1466 if(S_ISDIR(statbuf.st_mode))
1467 ReadFontDir(path, external_fonts);
1468 else
1469 AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1471 closedir(dir);
1472 return TRUE;
1475 static void load_fontconfig_fonts(void)
1477 #ifdef SONAME_LIBFONTCONFIG
1478 void *fc_handle = NULL;
1479 FcConfig *config;
1480 FcPattern *pat;
1481 FcObjectSet *os;
1482 FcFontSet *fontset;
1483 int i, len;
1484 char *file;
1485 const char *ext;
1487 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1488 if(!fc_handle) {
1489 TRACE("Wine cannot find the fontconfig library (%s).\n",
1490 SONAME_LIBFONTCONFIG);
1491 return;
1493 #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;}
1494 LOAD_FUNCPTR(FcConfigGetCurrent);
1495 LOAD_FUNCPTR(FcFontList);
1496 LOAD_FUNCPTR(FcFontSetDestroy);
1497 LOAD_FUNCPTR(FcInit);
1498 LOAD_FUNCPTR(FcObjectSetAdd);
1499 LOAD_FUNCPTR(FcObjectSetCreate);
1500 LOAD_FUNCPTR(FcObjectSetDestroy);
1501 LOAD_FUNCPTR(FcPatternCreate);
1502 LOAD_FUNCPTR(FcPatternDestroy);
1503 LOAD_FUNCPTR(FcPatternGetBool);
1504 LOAD_FUNCPTR(FcPatternGetString);
1505 #undef LOAD_FUNCPTR
1507 if(!pFcInit()) return;
1509 config = pFcConfigGetCurrent();
1510 pat = pFcPatternCreate();
1511 os = pFcObjectSetCreate();
1512 pFcObjectSetAdd(os, FC_FILE);
1513 pFcObjectSetAdd(os, FC_SCALABLE);
1514 fontset = pFcFontList(config, pat, os);
1515 if(!fontset) return;
1516 for(i = 0; i < fontset->nfont; i++) {
1517 FcBool scalable;
1519 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1520 continue;
1521 TRACE("fontconfig: %s\n", file);
1523 /* We're just interested in OT/TT fonts for now, so this hack just
1524 picks up the scalable fonts without extensions .pf[ab] to save time
1525 loading every other font */
1527 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1529 TRACE("not scalable\n");
1530 continue;
1533 len = strlen( file );
1534 if(len < 4) continue;
1535 ext = &file[ len - 3 ];
1536 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1537 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT);
1539 pFcFontSetDestroy(fontset);
1540 pFcObjectSetDestroy(os);
1541 pFcPatternDestroy(pat);
1542 sym_not_found:
1543 #endif
1544 return;
1547 static BOOL load_font_from_data_dir(LPCWSTR file)
1549 BOOL ret = FALSE;
1550 const char *data_dir = wine_get_data_dir();
1552 if (!data_dir) data_dir = wine_get_build_dir();
1554 if (data_dir)
1556 INT len;
1557 char *unix_name;
1559 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1561 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1563 strcpy(unix_name, data_dir);
1564 strcat(unix_name, "/fonts/");
1566 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1568 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1569 HeapFree(GetProcessHeap(), 0, unix_name);
1571 return ret;
1574 static void load_system_fonts(void)
1576 HKEY hkey;
1577 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1578 const WCHAR * const *value;
1579 DWORD dlen, type;
1580 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1581 char *unixname;
1583 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1584 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1585 strcatW(windowsdir, fontsW);
1586 for(value = SystemFontValues; *value; value++) {
1587 dlen = sizeof(data);
1588 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1589 type == REG_SZ) {
1590 BOOL added = FALSE;
1592 sprintfW(pathW, fmtW, windowsdir, data);
1593 if((unixname = wine_get_unix_file_name(pathW))) {
1594 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1595 HeapFree(GetProcessHeap(), 0, unixname);
1597 if (!added)
1598 load_font_from_data_dir(data);
1601 RegCloseKey(hkey);
1605 /*************************************************************
1607 * This adds registry entries for any externally loaded fonts
1608 * (fonts from fontconfig or FontDirs). It also deletes entries
1609 * of no longer existing fonts.
1612 static void update_reg_entries(void)
1614 HKEY winkey = 0, externalkey = 0;
1615 LPWSTR valueW;
1616 LPVOID data;
1617 DWORD dlen, vlen, datalen, valuelen, i, type, len, len_fam;
1618 Family *family;
1619 Face *face;
1620 struct list *family_elem_ptr, *face_elem_ptr;
1621 WCHAR *file;
1622 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1623 static const WCHAR spaceW[] = {' ', '\0'};
1624 char *path;
1626 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1627 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winkey, NULL) != ERROR_SUCCESS) {
1628 ERR("Can't create Windows font reg key\n");
1629 goto end;
1631 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1632 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &externalkey) != ERROR_SUCCESS) {
1633 ERR("Can't create external font reg key\n");
1634 goto end;
1637 /* Delete all external fonts added last time */
1639 RegQueryInfoKeyW(externalkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1640 &valuelen, &datalen, NULL, NULL);
1641 valuelen++; /* returned value doesn't include room for '\0' */
1642 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1643 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1645 dlen = datalen * sizeof(WCHAR);
1646 vlen = valuelen;
1647 i = 0;
1648 while(RegEnumValueW(externalkey, i++, valueW, &vlen, NULL, &type, data,
1649 &dlen) == ERROR_SUCCESS) {
1651 RegDeleteValueW(winkey, valueW);
1652 /* reset dlen and vlen */
1653 dlen = datalen;
1654 vlen = valuelen;
1656 HeapFree(GetProcessHeap(), 0, data);
1657 HeapFree(GetProcessHeap(), 0, valueW);
1659 /* Delete the old external fonts key */
1660 RegCloseKey(externalkey);
1661 externalkey = 0;
1662 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
1664 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1665 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1666 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
1667 ERR("Can't create external font reg key\n");
1668 goto end;
1671 /* enumerate the fonts and add external ones to the two keys */
1673 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1674 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1675 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1676 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1677 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1678 if(!face->external) continue;
1679 len = len_fam;
1680 if(strcmpiW(face->StyleName, RegularW))
1681 len = len_fam + strlenW(face->StyleName) + 1;
1682 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1683 strcpyW(valueW, family->FamilyName);
1684 if(len != len_fam) {
1685 strcatW(valueW, spaceW);
1686 strcatW(valueW, face->StyleName);
1688 strcatW(valueW, TrueType);
1689 if((path = strrchr(face->file, '/')) == NULL)
1690 path = face->file;
1691 else
1692 path++;
1693 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1695 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1696 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1697 RegSetValueExW(winkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1698 RegSetValueExW(externalkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1700 HeapFree(GetProcessHeap(), 0, file);
1701 HeapFree(GetProcessHeap(), 0, valueW);
1704 end:
1705 if(externalkey)
1706 RegCloseKey(externalkey);
1707 if(winkey)
1708 RegCloseKey(winkey);
1709 return;
1713 /*************************************************************
1714 * WineEngAddFontResourceEx
1717 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1719 if (ft_handle) /* do it only if we have freetype up and running */
1721 char *unixname;
1723 if(flags)
1724 FIXME("Ignoring flags %x\n", flags);
1726 if((unixname = wine_get_unix_file_name(file)))
1728 INT ret = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1729 HeapFree(GetProcessHeap(), 0, unixname);
1730 return ret;
1733 return 0;
1736 /*************************************************************
1737 * WineEngRemoveFontResourceEx
1740 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1742 FIXME(":stub\n");
1743 return TRUE;
1746 static const struct nls_update_font_list
1748 UINT ansi_cp, oem_cp;
1749 const char *oem, *fixed, *system;
1750 const char *courier, *serif, *small, *sserif;
1751 /* these are for font substitute */
1752 const char *shelldlg, *tmsrmn;
1753 } nls_update_font_list[] =
1755 /* Latin 1 (United States) */
1756 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
1757 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1758 "Tahoma","Times New Roman",
1760 /* Latin 1 (Multilingual) */
1761 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
1762 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1763 "Tahoma","Times New Roman", /* FIXME unverified */
1765 /* Eastern Europe */
1766 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
1767 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
1768 "Tahoma","Times New Roman", /* FIXME unverified */
1770 /* Cyrillic */
1771 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
1772 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
1773 "Tahoma","Times New Roman", /* FIXME unverified */
1775 /* Greek */
1776 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
1777 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
1778 "Tahoma","Times New Roman", /* FIXME unverified */
1780 /* Turkish */
1781 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
1782 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
1783 "Tahoma","Times New Roman", /* FIXME unverified */
1785 /* Hebrew */
1786 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
1787 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
1788 "Tahoma","Times New Roman", /* FIXME unverified */
1790 /* Arabic */
1791 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
1792 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
1793 "Tahoma","Times New Roman", /* FIXME unverified */
1795 /* Baltic */
1796 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
1797 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
1798 "Tahoma","Times New Roman", /* FIXME unverified */
1800 /* Vietnamese */
1801 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
1802 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1803 "Tahoma","Times New Roman", /* FIXME unverified */
1805 /* Thai */
1806 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
1807 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
1808 "Tahoma","Times New Roman", /* FIXME unverified */
1810 /* Japanese */
1811 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
1812 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
1813 "MS UI Gothic","MS Serif",
1815 /* Chinese Simplified */
1816 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
1817 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1818 "Tahoma", "Times New Roman", /* FIXME unverified */
1820 /* Korean */
1821 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
1822 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1823 "Gulim", "Batang",
1825 /* Chinese Traditional */
1826 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
1827 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1828 "Tahoma", "Times New Roman", /* FIXME unverified */
1832 static inline HKEY create_fonts_NT_registry_key(void)
1834 HKEY hkey = 0;
1836 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
1837 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1838 return hkey;
1841 static inline HKEY create_fonts_9x_registry_key(void)
1843 HKEY hkey = 0;
1845 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
1846 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1847 return hkey;
1850 static inline HKEY create_config_fonts_registry_key(void)
1852 HKEY hkey = 0;
1854 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
1855 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1856 return hkey;
1859 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
1861 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
1862 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
1863 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
1864 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
1867 static void update_font_info(void)
1869 char buf[40], cpbuf[40];
1870 DWORD len, type;
1871 HKEY hkey = 0;
1872 UINT i, ansi_cp = 0, oem_cp = 0;
1874 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
1875 return;
1877 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
1878 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
1879 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
1880 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
1881 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
1883 len = sizeof(buf);
1884 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
1886 if (!strcmp( buf, cpbuf )) /* already set correctly */
1888 RegCloseKey(hkey);
1889 return;
1891 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
1893 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
1895 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
1896 RegCloseKey(hkey);
1898 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
1900 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
1901 nls_update_font_list[i].oem_cp == oem_cp)
1903 HKEY hkey;
1905 hkey = create_config_fonts_registry_key();
1906 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
1907 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
1908 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
1909 RegCloseKey(hkey);
1911 hkey = create_fonts_NT_registry_key();
1912 add_font_list(hkey, &nls_update_font_list[i]);
1913 RegCloseKey(hkey);
1915 hkey = create_fonts_9x_registry_key();
1916 add_font_list(hkey, &nls_update_font_list[i]);
1917 RegCloseKey(hkey);
1919 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
1921 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
1922 strlen(nls_update_font_list[i].shelldlg)+1);
1923 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
1924 strlen(nls_update_font_list[i].tmsrmn)+1);
1925 RegCloseKey(hkey);
1927 return;
1930 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
1933 /*************************************************************
1934 * WineEngInit
1936 * Initialize FreeType library and create a list of available faces
1938 BOOL WineEngInit(void)
1940 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
1941 static const WCHAR pathW[] = {'P','a','t','h',0};
1942 HKEY hkey;
1943 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1944 LPVOID data;
1945 WCHAR windowsdir[MAX_PATH];
1946 char *unixname;
1947 HANDLE font_mutex;
1948 const char *data_dir;
1950 TRACE("\n");
1952 /* update locale dependent font info in registry */
1953 update_font_info();
1955 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
1956 if(!ft_handle) {
1957 WINE_MESSAGE(
1958 "Wine cannot find the FreeType font library. To enable Wine to\n"
1959 "use TrueType fonts please install a version of FreeType greater than\n"
1960 "or equal to 2.0.5.\n"
1961 "http://www.freetype.org\n");
1962 return FALSE;
1965 #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;}
1967 LOAD_FUNCPTR(FT_Vector_Unit)
1968 LOAD_FUNCPTR(FT_Done_Face)
1969 LOAD_FUNCPTR(FT_Get_Char_Index)
1970 LOAD_FUNCPTR(FT_Get_Module)
1971 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
1972 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
1973 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
1974 LOAD_FUNCPTR(FT_Init_FreeType)
1975 LOAD_FUNCPTR(FT_Load_Glyph)
1976 LOAD_FUNCPTR(FT_Matrix_Multiply)
1977 LOAD_FUNCPTR(FT_MulFix)
1978 LOAD_FUNCPTR(FT_New_Face)
1979 LOAD_FUNCPTR(FT_New_Memory_Face)
1980 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
1981 LOAD_FUNCPTR(FT_Outline_Transform)
1982 LOAD_FUNCPTR(FT_Outline_Translate)
1983 LOAD_FUNCPTR(FT_Select_Charmap)
1984 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
1985 LOAD_FUNCPTR(FT_Vector_Transform)
1987 #undef LOAD_FUNCPTR
1988 /* Don't warn if this one is missing */
1989 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
1990 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
1991 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
1992 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
1993 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
1994 #ifdef HAVE_FREETYPE_FTWINFNT_H
1995 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
1996 #endif
1997 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
1998 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
1999 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2000 <= 2.0.3 has FT_Sqrt64 */
2001 goto sym_not_found;
2004 if(pFT_Init_FreeType(&library) != 0) {
2005 ERR("Can't init FreeType library\n");
2006 wine_dlclose(ft_handle, NULL, 0);
2007 ft_handle = NULL;
2008 return FALSE;
2010 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
2011 if (pFT_Library_Version)
2013 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2015 if (FT_Version.major<=0)
2017 FT_Version.major=2;
2018 FT_Version.minor=0;
2019 FT_Version.patch=5;
2021 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2022 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2023 ((FT_Version.minor << 8) & 0x00ff00) |
2024 ((FT_Version.patch ) & 0x0000ff);
2026 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2027 ERR("Failed to create font mutex\n");
2028 return FALSE;
2030 WaitForSingleObject(font_mutex, INFINITE);
2032 /* load the system bitmap fonts */
2033 load_system_fonts();
2035 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2036 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2037 strcatW(windowsdir, fontsW);
2038 if((unixname = wine_get_unix_file_name(windowsdir)))
2040 ReadFontDir(unixname, FALSE);
2041 HeapFree(GetProcessHeap(), 0, unixname);
2044 /* load the system truetype fonts */
2045 data_dir = wine_get_data_dir();
2046 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2047 strcpy(unixname, data_dir);
2048 strcat(unixname, "/fonts/");
2049 ReadFontDir(unixname, FALSE);
2050 HeapFree(GetProcessHeap(), 0, unixname);
2053 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2054 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2055 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2056 will skip these. */
2057 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2058 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2059 &hkey) == ERROR_SUCCESS) {
2060 LPWSTR valueW;
2061 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2062 &valuelen, &datalen, NULL, NULL);
2064 valuelen++; /* returned value doesn't include room for '\0' */
2065 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2066 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2067 if (valueW && data)
2069 dlen = datalen * sizeof(WCHAR);
2070 vlen = valuelen;
2071 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
2072 &dlen) == ERROR_SUCCESS) {
2073 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
2075 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
2077 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2078 HeapFree(GetProcessHeap(), 0, unixname);
2081 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
2083 WCHAR pathW[MAX_PATH];
2084 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2085 BOOL added = FALSE;
2087 sprintfW(pathW, fmtW, windowsdir, data);
2088 if((unixname = wine_get_unix_file_name(pathW)))
2090 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2091 HeapFree(GetProcessHeap(), 0, unixname);
2093 if (!added)
2094 load_font_from_data_dir(data);
2096 /* reset dlen and vlen */
2097 dlen = datalen;
2098 vlen = valuelen;
2101 HeapFree(GetProcessHeap(), 0, data);
2102 HeapFree(GetProcessHeap(), 0, valueW);
2103 RegCloseKey(hkey);
2106 load_fontconfig_fonts();
2108 /* then look in any directories that we've specified in the config file */
2109 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2110 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2112 DWORD len;
2113 LPWSTR valueW;
2114 LPSTR valueA, ptr;
2116 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2118 len += sizeof(WCHAR);
2119 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2120 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2122 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2123 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2124 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2125 TRACE( "got font path %s\n", debugstr_a(valueA) );
2126 ptr = valueA;
2127 while (ptr)
2129 LPSTR next = strchr( ptr, ':' );
2130 if (next) *next++ = 0;
2131 ReadFontDir( ptr, TRUE );
2132 ptr = next;
2134 HeapFree( GetProcessHeap(), 0, valueA );
2136 HeapFree( GetProcessHeap(), 0, valueW );
2138 RegCloseKey(hkey);
2141 DumpFontList();
2142 LoadSubstList();
2143 DumpSubstList();
2144 LoadReplaceList();
2145 update_reg_entries();
2147 init_system_links();
2149 ReleaseMutex(font_mutex);
2150 return TRUE;
2151 sym_not_found:
2152 WINE_MESSAGE(
2153 "Wine cannot find certain functions that it needs inside the FreeType\n"
2154 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2155 "FreeType to at least version 2.0.5.\n"
2156 "http://www.freetype.org\n");
2157 wine_dlclose(ft_handle, NULL, 0);
2158 ft_handle = NULL;
2159 return FALSE;
2163 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2165 TT_OS2 *pOS2;
2166 TT_HoriHeader *pHori;
2168 LONG ppem;
2170 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2171 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2173 if(height == 0) height = 16;
2175 /* Calc. height of EM square:
2177 * For +ve lfHeight we have
2178 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2179 * Re-arranging gives:
2180 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2182 * For -ve lfHeight we have
2183 * |lfHeight| = ppem
2184 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2185 * with il = winAscent + winDescent - units_per_em]
2189 if(height > 0) {
2190 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2191 ppem = ft_face->units_per_EM * height /
2192 (pHori->Ascender - pHori->Descender);
2193 else
2194 ppem = ft_face->units_per_EM * height /
2195 (pOS2->usWinAscent + pOS2->usWinDescent);
2197 else
2198 ppem = -height;
2200 return ppem;
2203 static struct font_mapping *map_font( const char *name )
2205 struct font_mapping *mapping;
2206 struct stat st;
2207 int fd;
2209 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2210 if (fstat( fd, &st ) == -1) goto error;
2212 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2214 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2216 mapping->refcount++;
2217 close( fd );
2218 return mapping;
2221 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2222 goto error;
2224 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2225 close( fd );
2227 if (mapping->data == MAP_FAILED)
2229 HeapFree( GetProcessHeap(), 0, mapping );
2230 return NULL;
2232 mapping->refcount = 1;
2233 mapping->dev = st.st_dev;
2234 mapping->ino = st.st_ino;
2235 mapping->size = st.st_size;
2236 list_add_tail( &mappings_list, &mapping->entry );
2237 return mapping;
2239 error:
2240 close( fd );
2241 return NULL;
2244 static void unmap_font( struct font_mapping *mapping )
2246 if (!--mapping->refcount)
2248 list_remove( &mapping->entry );
2249 munmap( mapping->data, mapping->size );
2250 HeapFree( GetProcessHeap(), 0, mapping );
2254 static LONG load_VDMX(GdiFont*, LONG);
2256 static FT_Face OpenFontFile(GdiFont *font, char *file, FT_Long face_index, LONG width, LONG height)
2258 FT_Error err;
2259 FT_Face ft_face;
2261 TRACE("%s, %ld, %d x %d\n", debugstr_a(file), face_index, width, height);
2263 if (!(font->mapping = map_font( file )))
2265 WARN("failed to map %s\n", debugstr_a(file));
2266 return 0;
2269 err = pFT_New_Memory_Face(library, font->mapping->data, font->mapping->size, face_index, &ft_face);
2270 if(err) {
2271 ERR("FT_New_Face rets %d\n", err);
2272 return 0;
2275 /* set it here, as load_VDMX needs it */
2276 font->ft_face = ft_face;
2278 if(FT_IS_SCALABLE(ft_face)) {
2279 /* load the VDMX table if we have one */
2280 font->ppem = load_VDMX(font, height);
2281 if(font->ppem == 0)
2282 font->ppem = calc_ppem_for_height(ft_face, height);
2284 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
2285 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
2286 } else {
2287 font->ppem = height;
2288 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
2289 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
2291 return ft_face;
2295 static int get_nearest_charset(Face *face, int *cp)
2297 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2298 a single face with the requested charset. The idea is to check if
2299 the selected font supports the current ANSI codepage, if it does
2300 return the corresponding charset, else return the first charset */
2302 CHARSETINFO csi;
2303 int acp = GetACP(), i;
2304 DWORD fs0;
2306 *cp = acp;
2307 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
2308 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2309 return csi.ciCharset;
2311 for(i = 0; i < 32; i++) {
2312 fs0 = 1L << i;
2313 if(face->fs.fsCsb[0] & fs0) {
2314 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
2315 *cp = csi.ciACP;
2316 return csi.ciCharset;
2318 else
2319 FIXME("TCI failing on %x\n", fs0);
2323 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2324 face->fs.fsCsb[0], face->file);
2325 *cp = acp;
2326 return DEFAULT_CHARSET;
2329 static GdiFont *alloc_font(void)
2331 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
2332 ret->gmsize = INIT_GM_SIZE;
2333 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2334 ret->gmsize * sizeof(*ret->gm));
2335 ret->potm = NULL;
2336 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
2337 ret->total_kern_pairs = (DWORD)-1;
2338 ret->kern_pairs = NULL;
2339 list_init(&ret->hfontlist);
2340 list_init(&ret->child_fonts);
2341 return ret;
2344 static void free_font(GdiFont *font)
2346 struct list *cursor, *cursor2;
2348 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
2350 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
2351 struct list *first_hfont;
2352 HFONTLIST *hfontlist;
2353 list_remove(cursor);
2354 if(child->font)
2356 first_hfont = list_head(&child->font->hfontlist);
2357 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2358 DeleteObject(hfontlist->hfont);
2359 HeapFree(GetProcessHeap(), 0, hfontlist);
2360 free_font(child->font);
2362 HeapFree(GetProcessHeap(), 0, child->file_name);
2363 HeapFree(GetProcessHeap(), 0, child);
2366 if (font->ft_face) pFT_Done_Face(font->ft_face);
2367 if (font->mapping) unmap_font( font->mapping );
2368 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
2369 HeapFree(GetProcessHeap(), 0, font->potm);
2370 HeapFree(GetProcessHeap(), 0, font->name);
2371 HeapFree(GetProcessHeap(), 0, font->gm);
2372 HeapFree(GetProcessHeap(), 0, font);
2376 /*************************************************************
2377 * load_VDMX
2379 * load the vdmx entry for the specified height
2382 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2383 ( ( (FT_ULong)_x4 << 24 ) | \
2384 ( (FT_ULong)_x3 << 16 ) | \
2385 ( (FT_ULong)_x2 << 8 ) | \
2386 (FT_ULong)_x1 )
2388 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2390 typedef struct {
2391 BYTE bCharSet;
2392 BYTE xRatio;
2393 BYTE yStartRatio;
2394 BYTE yEndRatio;
2395 } Ratios;
2397 typedef struct {
2398 WORD recs;
2399 BYTE startsz;
2400 BYTE endsz;
2401 } VDMX_group;
2403 static LONG load_VDMX(GdiFont *font, LONG height)
2405 WORD hdr[3], tmp;
2406 VDMX_group group;
2407 BYTE devXRatio, devYRatio;
2408 USHORT numRecs, numRatios;
2409 DWORD result, offset = -1;
2410 LONG ppem = 0;
2411 int i;
2413 /* For documentation on VDMX records, see
2414 * http://www.microsoft.com/OpenType/OTSpec/vdmx.htm
2417 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
2419 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2420 return ppem;
2422 /* FIXME: need the real device aspect ratio */
2423 devXRatio = 1;
2424 devYRatio = 1;
2426 numRecs = GET_BE_WORD(hdr[1]);
2427 numRatios = GET_BE_WORD(hdr[2]);
2429 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
2430 for(i = 0; i < numRatios; i++) {
2431 Ratios ratio;
2433 offset = (3 * 2) + (i * sizeof(Ratios));
2434 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2435 offset = -1;
2437 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2439 if((ratio.xRatio == 0 &&
2440 ratio.yStartRatio == 0 &&
2441 ratio.yEndRatio == 0) ||
2442 (devXRatio == ratio.xRatio &&
2443 devYRatio >= ratio.yStartRatio &&
2444 devYRatio <= ratio.yEndRatio))
2446 offset = (3 * 2) + (numRatios * 4) + (i * 2);
2447 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
2448 offset = GET_BE_WORD(tmp);
2449 break;
2453 if(offset == -1) {
2454 FIXME("No suitable ratio found\n");
2455 return ppem;
2458 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
2459 USHORT recs;
2460 BYTE startsz, endsz;
2461 WORD *vTable;
2463 recs = GET_BE_WORD(group.recs);
2464 startsz = group.startsz;
2465 endsz = group.endsz;
2467 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
2469 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
2470 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
2471 if(result == GDI_ERROR) {
2472 FIXME("Failed to retrieve vTable\n");
2473 goto end;
2476 if(height > 0) {
2477 for(i = 0; i < recs; i++) {
2478 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2479 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2480 ppem = GET_BE_WORD(vTable[i * 3]);
2482 if(yMax + -yMin == height) {
2483 font->yMax = yMax;
2484 font->yMin = yMin;
2485 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2486 break;
2488 if(yMax + -yMin > height) {
2489 if(--i < 0) {
2490 ppem = 0;
2491 goto end; /* failed */
2493 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2494 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2495 ppem = GET_BE_WORD(vTable[i * 3]);
2496 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2497 break;
2500 if(!font->yMax) {
2501 ppem = 0;
2502 TRACE("ppem not found for height %d\n", height);
2504 } else {
2505 ppem = -height;
2506 if(ppem < startsz || ppem > endsz)
2507 goto end;
2509 for(i = 0; i < recs; i++) {
2510 USHORT yPelHeight;
2511 yPelHeight = GET_BE_WORD(vTable[i * 3]);
2513 if(yPelHeight > ppem)
2514 break; /* failed */
2516 if(yPelHeight == ppem) {
2517 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2518 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2519 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
2520 break;
2524 end:
2525 HeapFree(GetProcessHeap(), 0, vTable);
2528 return ppem;
2531 static BOOL fontcmp(GdiFont *font, FONT_DESC *fd)
2533 if(font->font_desc.hash != fd->hash) return TRUE;
2534 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
2535 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
2536 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
2537 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
2540 static void calc_hash(FONT_DESC *pfd)
2542 DWORD hash = 0, *ptr, two_chars;
2543 WORD *pwc;
2544 unsigned int i;
2546 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
2547 hash ^= *ptr;
2548 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
2549 hash ^= *ptr;
2550 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
2551 two_chars = *ptr;
2552 pwc = (WCHAR *)&two_chars;
2553 if(!*pwc) break;
2554 *pwc = toupperW(*pwc);
2555 pwc++;
2556 *pwc = toupperW(*pwc);
2557 hash ^= two_chars;
2558 if(!*pwc) break;
2560 hash ^= !pfd->can_use_bitmap;
2561 pfd->hash = hash;
2562 return;
2565 static GdiFont *find_in_cache(HFONT hfont, LOGFONTW *plf, XFORM *pxf, BOOL can_use_bitmap)
2567 GdiFont *ret;
2568 FONT_DESC fd;
2569 HFONTLIST *hflist;
2570 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2572 memcpy(&fd.lf, plf, sizeof(LOGFONTW));
2573 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
2574 fd.can_use_bitmap = can_use_bitmap;
2575 calc_hash(&fd);
2577 /* try the in-use list */
2578 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
2579 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2580 if(!fontcmp(ret, &fd)) {
2581 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2582 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
2583 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2584 if(hflist->hfont == hfont)
2585 return ret;
2587 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2588 hflist->hfont = hfont;
2589 list_add_head(&ret->hfontlist, &hflist->entry);
2590 return ret;
2594 /* then the unused list */
2595 font_elem_ptr = list_head(&unused_gdi_font_list);
2596 while(font_elem_ptr) {
2597 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2598 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2599 if(!fontcmp(ret, &fd)) {
2600 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2601 assert(list_empty(&ret->hfontlist));
2602 TRACE("Found %p in unused list\n", ret);
2603 list_remove(&ret->entry);
2604 list_add_head(&gdi_font_list, &ret->entry);
2605 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2606 hflist->hfont = hfont;
2607 list_add_head(&ret->hfontlist, &hflist->entry);
2608 return ret;
2611 return NULL;
2615 /*************************************************************
2616 * create_child_font_list
2618 static BOOL create_child_font_list(GdiFont *font)
2620 BOOL ret = FALSE;
2621 SYSTEM_LINKS *font_link;
2622 CHILD_FONT *font_link_entry, *new_child;
2624 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2626 if(!strcmpW(font_link->font_name, font->name))
2628 TRACE("found entry in system list\n");
2629 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2631 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2632 new_child->file_name = strdupA(font_link_entry->file_name);
2633 new_child->index = font_link_entry->index;
2634 new_child->font = NULL;
2635 list_add_tail(&font->child_fonts, &new_child->entry);
2636 TRACE("font %s %d\n", debugstr_a(new_child->file_name), new_child->index);
2638 ret = TRUE;
2639 break;
2643 return ret;
2646 /*************************************************************
2647 * WineEngCreateFontInstance
2650 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
2652 GdiFont *ret;
2653 Face *face, *best, *best_bitmap;
2654 Family *family, *last_resort_family;
2655 struct list *family_elem_ptr, *face_elem_ptr;
2656 INT height, width = 0;
2657 unsigned int score = 0, new_score;
2658 signed int diff = 0, newdiff;
2659 BOOL bd, it, can_use_bitmap;
2660 LOGFONTW lf;
2661 CHARSETINFO csi;
2662 HFONTLIST *hflist;
2664 LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry)
2666 struct list *first_hfont = list_head(&ret->hfontlist);
2667 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2668 if(hflist->hfont == hfont)
2669 return ret;
2672 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
2673 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
2675 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
2676 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
2677 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
2678 lf.lfEscapement);
2680 /* check the cache first */
2681 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
2682 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
2683 return ret;
2686 TRACE("not in cache\n");
2687 if(list_empty(&font_list)) /* No fonts installed */
2689 TRACE("No fonts installed\n");
2690 return NULL;
2692 if(!have_installed_roman_font)
2694 TRACE("No roman font installed\n");
2695 return NULL;
2698 ret = alloc_font();
2700 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
2701 memcpy(&ret->font_desc.lf, &lf, sizeof(LOGFONTW));
2702 ret->font_desc.can_use_bitmap = can_use_bitmap;
2703 calc_hash(&ret->font_desc);
2704 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2705 hflist->hfont = hfont;
2706 list_add_head(&ret->hfontlist, &hflist->entry);
2709 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
2710 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
2711 original value lfCharSet. Note this is a special case for
2712 Symbol and doesn't happen at least for "Wingdings*" */
2714 if(!strcmpiW(lf.lfFaceName, SymbolW))
2715 lf.lfCharSet = SYMBOL_CHARSET;
2717 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
2718 switch(lf.lfCharSet) {
2719 case DEFAULT_CHARSET:
2720 csi.fs.fsCsb[0] = 0;
2721 break;
2722 default:
2723 FIXME("Untranslated charset %d\n", lf.lfCharSet);
2724 csi.fs.fsCsb[0] = 0;
2725 break;
2729 family = NULL;
2730 if(lf.lfFaceName[0] != '\0') {
2731 FontSubst *psub;
2732 SYSTEM_LINKS *font_link;
2733 CHILD_FONT *font_link_entry;
2735 psub = get_font_subst(&font_subst_list, lf.lfFaceName, lf.lfCharSet);
2737 if(psub) {
2738 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
2739 debugstr_w(psub->to.name));
2740 strcpyW(lf.lfFaceName, psub->to.name);
2743 /* We want a match on name and charset or just name if
2744 charset was DEFAULT_CHARSET. If the latter then
2745 we fixup the returned charset later in get_nearest_charset
2746 where we'll either use the charset of the current ansi codepage
2747 or if that's unavailable the first charset that the font supports.
2749 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2750 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2751 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2752 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2753 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2754 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
2755 if(face->scalable || can_use_bitmap)
2756 goto found;
2762 * Try check the SystemLink list first for a replacement font.
2763 * We may find good replacements there.
2765 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2767 if(!strcmpiW(font_link->font_name, lf.lfFaceName))
2769 TRACE("found entry in system list\n");
2770 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2772 face = find_face_from_path_index(font_link_entry->file_name,
2773 font_link_entry->index);
2774 if (face)
2776 family = face->family;
2777 if(csi.fs.fsCsb[0] &
2778 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]) || !csi.fs.fsCsb[0])
2780 if(face->scalable || can_use_bitmap)
2781 goto found;
2789 /* If requested charset was DEFAULT_CHARSET then try using charset
2790 corresponding to the current ansi codepage */
2791 if(!csi.fs.fsCsb[0]) {
2792 INT acp = GetACP();
2793 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
2794 FIXME("TCI failed on codepage %d\n", acp);
2795 csi.fs.fsCsb[0] = 0;
2796 } else
2797 lf.lfCharSet = csi.ciCharset;
2800 /* Face families are in the top 4 bits of lfPitchAndFamily,
2801 so mask with 0xF0 before testing */
2803 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
2804 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
2805 strcpyW(lf.lfFaceName, defFixed);
2806 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
2807 strcpyW(lf.lfFaceName, defSerif);
2808 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
2809 strcpyW(lf.lfFaceName, defSans);
2810 else
2811 strcpyW(lf.lfFaceName, defSans);
2812 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2813 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2814 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2815 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2816 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2817 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2818 if(face->scalable || can_use_bitmap)
2819 goto found;
2824 last_resort_family = NULL;
2825 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2826 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2827 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2828 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2829 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
2830 if(face->scalable)
2831 goto found;
2832 if(can_use_bitmap && !last_resort_family)
2833 last_resort_family = family;
2838 if(last_resort_family) {
2839 family = last_resort_family;
2840 csi.fs.fsCsb[0] = 0;
2841 goto found;
2844 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2845 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2846 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2847 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2848 if(face->scalable) {
2849 csi.fs.fsCsb[0] = 0;
2850 WARN("just using first face for now\n");
2851 goto found;
2853 if(can_use_bitmap && !last_resort_family)
2854 last_resort_family = family;
2857 if(!last_resort_family) {
2858 FIXME("can't find a single appropriate font - bailing\n");
2859 free_font(ret);
2860 return NULL;
2863 WARN("could only find a bitmap font - this will probably look awful!\n");
2864 family = last_resort_family;
2865 csi.fs.fsCsb[0] = 0;
2867 found:
2868 it = lf.lfItalic ? 1 : 0;
2869 bd = lf.lfWeight > 550 ? 1 : 0;
2871 height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
2872 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
2874 face = best = best_bitmap = NULL;
2875 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2877 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
2879 new_score = (face->Italic ^ it) + (face->Bold ^ bd);
2880 if(!best || new_score <= score)
2882 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
2883 face->Italic, face->Bold, it, bd);
2884 score = new_score;
2885 best = face;
2886 if(best->scalable && score == 0) break;
2887 if(!best->scalable)
2889 if(height > 0)
2890 newdiff = height - (signed int)(best->size.height);
2891 else
2892 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
2893 if(!best_bitmap || new_score < score ||
2894 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
2896 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
2897 diff = newdiff;
2898 best_bitmap = best;
2899 if(score == 0 && diff == 0) break;
2905 if(best)
2906 face = best->scalable ? best : best_bitmap;
2907 ret->fake_italic = (it && !face->Italic);
2908 ret->fake_bold = (bd && !face->Bold);
2910 memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
2912 if(csi.fs.fsCsb[0]) {
2913 ret->charset = lf.lfCharSet;
2914 ret->codepage = csi.ciACP;
2916 else
2917 ret->charset = get_nearest_charset(face, &ret->codepage);
2919 TRACE("Chosen: %s %s (%s:%ld)\n", debugstr_w(family->FamilyName),
2920 debugstr_w(face->StyleName), face->file, face->face_index);
2922 if(!face->scalable) {
2923 width = face->size.x_ppem >> 6;
2924 height = face->size.y_ppem >> 6;
2926 ret->ft_face = OpenFontFile(ret, face->file, face->face_index, width, height);
2928 if (!ret->ft_face)
2930 free_font( ret );
2931 return 0;
2934 if (ret->charset == SYMBOL_CHARSET &&
2935 !pFT_Select_Charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
2936 /* No ops */
2938 else if (!pFT_Select_Charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
2939 /* No ops */
2941 else {
2942 pFT_Select_Charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
2945 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
2946 ret->name = strdupW(family->FamilyName);
2947 ret->underline = lf.lfUnderline ? 0xff : 0;
2948 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
2949 create_child_font_list(ret);
2951 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
2953 ret->aveWidth = FT_IS_SCALABLE(ret->ft_face) ? abs(lf.lfWidth) : 0;
2954 list_add_head(&gdi_font_list, &ret->entry);
2955 return ret;
2958 static void dump_gdi_font_list(void)
2960 GdiFont *gdiFont;
2961 struct list *elem_ptr;
2963 TRACE("---------- gdiFont Cache ----------\n");
2964 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
2965 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
2966 TRACE("gdiFont=%p %s %d\n",
2967 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
2970 TRACE("---------- Unused gdiFont Cache ----------\n");
2971 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
2972 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
2973 TRACE("gdiFont=%p %s %d\n",
2974 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
2978 /*************************************************************
2979 * WineEngDestroyFontInstance
2981 * free the gdiFont associated with this handle
2984 BOOL WineEngDestroyFontInstance(HFONT handle)
2986 GdiFont *gdiFont;
2987 HFONTLIST *hflist;
2988 BOOL ret = FALSE;
2989 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2990 int i = 0;
2992 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
2994 struct list *first_hfont = list_head(&gdiFont->hfontlist);
2995 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2996 if(hflist->hfont == handle)
2998 TRACE("removing child font %p from child list\n", gdiFont);
2999 list_remove(&gdiFont->entry);
3000 return TRUE;
3004 TRACE("destroying hfont=%p\n", handle);
3005 if(TRACE_ON(font))
3006 dump_gdi_font_list();
3008 font_elem_ptr = list_head(&gdi_font_list);
3009 while(font_elem_ptr) {
3010 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3011 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3013 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3014 while(hfontlist_elem_ptr) {
3015 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3016 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3017 if(hflist->hfont == handle) {
3018 list_remove(&hflist->entry);
3019 HeapFree(GetProcessHeap(), 0, hflist);
3020 ret = TRUE;
3023 if(list_empty(&gdiFont->hfontlist)) {
3024 TRACE("Moving to Unused list\n");
3025 list_remove(&gdiFont->entry);
3026 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3031 font_elem_ptr = list_head(&unused_gdi_font_list);
3032 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3033 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3034 while(font_elem_ptr) {
3035 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3036 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3037 TRACE("freeing %p\n", gdiFont);
3038 list_remove(&gdiFont->entry);
3039 free_font(gdiFont);
3041 return ret;
3044 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
3045 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
3047 OUTLINETEXTMETRICW *potm = NULL;
3048 UINT size;
3049 TEXTMETRICW tm, *ptm;
3050 GdiFont *font = alloc_font();
3051 LONG width, height;
3053 if(face->scalable) {
3054 height = 100;
3055 width = 0;
3056 } else {
3057 height = face->size.y_ppem >> 6;
3058 width = face->size.x_ppem >> 6;
3061 if (!(font->ft_face = OpenFontFile(font, face->file, face->face_index, width, height)))
3063 free_font(font);
3064 return;
3067 font->name = strdupW(face->family->FamilyName);
3069 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
3071 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
3072 if(size) {
3073 potm = HeapAlloc(GetProcessHeap(), 0, size);
3074 WineEngGetOutlineTextMetrics(font, size, potm);
3075 ptm = (TEXTMETRICW*)&potm->otmTextMetrics;
3076 } else {
3077 WineEngGetTextMetrics(font, &tm);
3078 ptm = &tm;
3081 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = ptm->tmHeight;
3082 pntm->ntmTm.tmAscent = ptm->tmAscent;
3083 pntm->ntmTm.tmDescent = ptm->tmDescent;
3084 pntm->ntmTm.tmInternalLeading = ptm->tmInternalLeading;
3085 pntm->ntmTm.tmExternalLeading = ptm->tmExternalLeading;
3086 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = ptm->tmAveCharWidth;
3087 pntm->ntmTm.tmMaxCharWidth = ptm->tmMaxCharWidth;
3088 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = ptm->tmWeight;
3089 pntm->ntmTm.tmOverhang = ptm->tmOverhang;
3090 pntm->ntmTm.tmDigitizedAspectX = ptm->tmDigitizedAspectX;
3091 pntm->ntmTm.tmDigitizedAspectY = ptm->tmDigitizedAspectY;
3092 pntm->ntmTm.tmFirstChar = ptm->tmFirstChar;
3093 pntm->ntmTm.tmLastChar = ptm->tmLastChar;
3094 pntm->ntmTm.tmDefaultChar = ptm->tmDefaultChar;
3095 pntm->ntmTm.tmBreakChar = ptm->tmBreakChar;
3096 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = ptm->tmItalic;
3097 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = ptm->tmUnderlined;
3098 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = ptm->tmStruckOut;
3099 pntm->ntmTm.tmPitchAndFamily = ptm->tmPitchAndFamily;
3100 pelf->elfLogFont.lfPitchAndFamily = (ptm->tmPitchAndFamily & 0xf1) + 1;
3101 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = ptm->tmCharSet;
3102 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
3103 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
3104 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
3106 *ptype = ptm->tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
3107 if(!(ptm->tmPitchAndFamily & TMPF_VECTOR))
3108 *ptype |= RASTER_FONTTYPE;
3110 pntm->ntmTm.ntmFlags = ptm->tmItalic ? NTM_ITALIC : 0;
3111 if(ptm->tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
3112 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
3114 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
3115 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
3116 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
3118 if(potm) {
3119 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
3121 lstrcpynW(pelf->elfLogFont.lfFaceName,
3122 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
3123 LF_FACESIZE);
3124 lstrcpynW(pelf->elfFullName,
3125 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
3126 LF_FULLFACESIZE);
3127 lstrcpynW(pelf->elfStyle,
3128 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
3129 LF_FACESIZE);
3131 HeapFree(GetProcessHeap(), 0, potm);
3132 } else {
3133 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
3135 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
3136 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FACESIZE);
3137 pelf->elfStyle[0] = '\0';
3140 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
3142 free_font(font);
3145 /*************************************************************
3146 * WineEngEnumFonts
3149 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3151 Family *family;
3152 Face *face;
3153 struct list *family_elem_ptr, *face_elem_ptr;
3154 ENUMLOGFONTEXW elf;
3155 NEWTEXTMETRICEXW ntm;
3156 DWORD type, ret = 1;
3157 FONTSIGNATURE fs;
3158 CHARSETINFO csi;
3159 LOGFONTW lf;
3160 int i;
3162 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
3164 if(plf->lfFaceName[0]) {
3165 FontSubst *psub;
3166 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
3168 if(psub) {
3169 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
3170 debugstr_w(psub->to.name));
3171 memcpy(&lf, plf, sizeof(lf));
3172 strcpyW(lf.lfFaceName, psub->to.name);
3173 plf = &lf;
3176 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3177 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3178 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
3179 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3180 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3181 GetEnumStructs(face, &elf, &ntm, &type);
3182 for(i = 0; i < 32; i++) {
3183 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3184 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3185 strcpyW(elf.elfScript, OEM_DOSW);
3186 i = 32; /* break out of loop */
3187 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3188 continue;
3189 else {
3190 fs.fsCsb[0] = 1L << i;
3191 fs.fsCsb[1] = 0;
3192 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3193 TCI_SRCFONTSIG))
3194 csi.ciCharset = DEFAULT_CHARSET;
3195 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3196 if(csi.ciCharset != DEFAULT_CHARSET) {
3197 elf.elfLogFont.lfCharSet =
3198 ntm.ntmTm.tmCharSet = csi.ciCharset;
3199 if(ElfScriptsW[i])
3200 strcpyW(elf.elfScript, ElfScriptsW[i]);
3201 else
3202 FIXME("Unknown elfscript for bit %d\n", i);
3205 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3206 debugstr_w(elf.elfLogFont.lfFaceName),
3207 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3208 csi.ciCharset, type, debugstr_w(elf.elfScript),
3209 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3210 ntm.ntmTm.ntmFlags);
3211 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
3212 if(!ret) goto end;
3217 } else {
3218 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3219 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3220 face_elem_ptr = list_head(&family->faces);
3221 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3222 GetEnumStructs(face, &elf, &ntm, &type);
3223 for(i = 0; i < 32; i++) {
3224 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3225 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3226 strcpyW(elf.elfScript, OEM_DOSW);
3227 i = 32; /* break out of loop */
3228 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3229 continue;
3230 else {
3231 fs.fsCsb[0] = 1L << i;
3232 fs.fsCsb[1] = 0;
3233 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3234 TCI_SRCFONTSIG))
3235 csi.ciCharset = DEFAULT_CHARSET;
3236 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3237 if(csi.ciCharset != DEFAULT_CHARSET) {
3238 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
3239 csi.ciCharset;
3240 if(ElfScriptsW[i])
3241 strcpyW(elf.elfScript, ElfScriptsW[i]);
3242 else
3243 FIXME("Unknown elfscript for bit %d\n", i);
3246 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3247 debugstr_w(elf.elfLogFont.lfFaceName),
3248 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3249 csi.ciCharset, type, debugstr_w(elf.elfScript),
3250 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3251 ntm.ntmTm.ntmFlags);
3252 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
3253 if(!ret) goto end;
3257 end:
3258 return ret;
3261 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
3263 pt->x.value = vec->x >> 6;
3264 pt->x.fract = (vec->x & 0x3f) << 10;
3265 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
3266 pt->y.value = vec->y >> 6;
3267 pt->y.fract = (vec->y & 0x3f) << 10;
3268 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
3269 return;
3272 /***************************************************
3273 * According to the MSDN documentation on WideCharToMultiByte,
3274 * certain codepages cannot set the default_used parameter.
3275 * This returns TRUE if the codepage can set that parameter, false else
3276 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
3278 static BOOL codepage_sets_default_used(UINT codepage)
3280 switch (codepage)
3282 case CP_UTF7:
3283 case CP_UTF8:
3284 case CP_SYMBOL:
3285 return FALSE;
3286 default:
3287 return TRUE;
3291 static FT_UInt get_glyph_index(GdiFont *font, UINT glyph)
3293 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
3294 WCHAR wc = (WCHAR)glyph;
3295 BOOL default_used;
3296 BOOL *default_used_pointer;
3297 FT_UInt ret;
3298 char buf;
3299 default_used_pointer = NULL;
3300 default_used = FALSE;
3301 if (codepage_sets_default_used(font->codepage))
3302 default_used_pointer = &default_used;
3303 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
3304 ret = 0;
3305 else
3306 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
3307 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
3308 return ret;
3311 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
3312 glyph = glyph + 0xf000;
3313 return pFT_Get_Char_Index(font->ft_face, glyph);
3316 /*************************************************************
3317 * WineEngGetGlyphIndices
3319 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
3321 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
3322 LPWORD pgi, DWORD flags)
3324 int i;
3325 WCHAR default_char = 0;
3326 TEXTMETRICW textm;
3328 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0x001f; /* Indicate non existence */
3330 for(i = 0; i < count; i++)
3332 pgi[i] = get_glyph_index(font, lpstr[i]);
3333 if (pgi[i] == 0)
3335 if (!default_char)
3337 WineEngGetTextMetrics(font, &textm);
3338 default_char = textm.tmDefaultChar;
3340 pgi[i] = default_char;
3343 return count;
3346 /*************************************************************
3347 * WineEngGetGlyphOutline
3349 * Behaves in exactly the same way as the win32 api GetGlyphOutline
3350 * except that the first parameter is the HWINEENGFONT of the font in
3351 * question rather than an HDC.
3354 DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
3355 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
3356 const MAT2* lpmat)
3358 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
3359 FT_Face ft_face = incoming_font->ft_face;
3360 GdiFont *font = incoming_font;
3361 FT_UInt glyph_index;
3362 DWORD width, height, pitch, needed = 0;
3363 FT_Bitmap ft_bitmap;
3364 FT_Error err;
3365 INT left, right, top = 0, bottom = 0;
3366 FT_Angle angle = 0;
3367 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
3368 float widthRatio = 1.0;
3369 FT_Matrix transMat = identityMat;
3370 BOOL needsTransform = FALSE;
3373 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
3374 buflen, buf, lpmat);
3376 if(format & GGO_GLYPH_INDEX) {
3377 glyph_index = glyph;
3378 format &= ~GGO_GLYPH_INDEX;
3379 } else {
3380 get_glyph_index_linked(incoming_font, glyph, &font, &glyph_index);
3381 ft_face = font->ft_face;
3384 if(glyph_index >= font->gmsize) {
3385 font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
3386 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
3387 font->gmsize * sizeof(*font->gm));
3388 } else {
3389 if(format == GGO_METRICS && font->gm[glyph_index].init) {
3390 memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
3391 return 1; /* FIXME */
3395 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP) || font->aveWidth || lpmat)
3396 load_flags |= FT_LOAD_NO_BITMAP;
3398 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
3400 if(err) {
3401 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
3402 return GDI_ERROR;
3405 /* Scaling factor */
3406 if (font->aveWidth && font->potm) {
3407 widthRatio = (float)font->aveWidth * font->font_desc.matrix.eM11 / (float) font->potm->otmTextMetrics.tmAveCharWidth;
3410 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
3411 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
3413 font->gm[glyph_index].adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
3414 font->gm[glyph_index].lsb = left >> 6;
3415 font->gm[glyph_index].bbx = (right - left) >> 6;
3417 /* Scaling transform */
3418 if(font->aveWidth) {
3419 FT_Matrix scaleMat;
3420 scaleMat.xx = FT_FixedFromFloat(widthRatio);
3421 scaleMat.xy = 0;
3422 scaleMat.yx = 0;
3423 scaleMat.yy = (1 << 16);
3425 pFT_Matrix_Multiply(&scaleMat, &transMat);
3426 needsTransform = TRUE;
3429 /* Slant transform */
3430 if (font->fake_italic) {
3431 FT_Matrix slantMat;
3433 slantMat.xx = (1 << 16);
3434 slantMat.xy = ((1 << 16) >> 2);
3435 slantMat.yx = 0;
3436 slantMat.yy = (1 << 16);
3437 pFT_Matrix_Multiply(&slantMat, &transMat);
3438 needsTransform = TRUE;
3441 /* Rotation transform */
3442 if(font->orientation) {
3443 FT_Matrix rotationMat;
3444 FT_Vector vecAngle;
3445 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
3446 pFT_Vector_Unit(&vecAngle, angle);
3447 rotationMat.xx = vecAngle.x;
3448 rotationMat.xy = -vecAngle.y;
3449 rotationMat.yx = -rotationMat.xy;
3450 rotationMat.yy = rotationMat.xx;
3452 pFT_Matrix_Multiply(&rotationMat, &transMat);
3453 needsTransform = TRUE;
3456 /* Extra transformation specified by caller */
3457 if (lpmat) {
3458 FT_Matrix extraMat;
3459 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
3460 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
3461 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
3462 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
3463 pFT_Matrix_Multiply(&extraMat, &transMat);
3464 needsTransform = TRUE;
3467 if(!needsTransform) {
3468 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
3469 bottom = (ft_face->glyph->metrics.horiBearingY -
3470 ft_face->glyph->metrics.height) & -64;
3471 lpgm->gmCellIncX = font->gm[glyph_index].adv;
3472 lpgm->gmCellIncY = 0;
3473 } else {
3474 INT xc, yc;
3475 FT_Vector vec;
3476 for(xc = 0; xc < 2; xc++) {
3477 for(yc = 0; yc < 2; yc++) {
3478 vec.x = (ft_face->glyph->metrics.horiBearingX +
3479 xc * ft_face->glyph->metrics.width);
3480 vec.y = ft_face->glyph->metrics.horiBearingY -
3481 yc * ft_face->glyph->metrics.height;
3482 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
3483 pFT_Vector_Transform(&vec, &transMat);
3484 if(xc == 0 && yc == 0) {
3485 left = right = vec.x;
3486 top = bottom = vec.y;
3487 } else {
3488 if(vec.x < left) left = vec.x;
3489 else if(vec.x > right) right = vec.x;
3490 if(vec.y < bottom) bottom = vec.y;
3491 else if(vec.y > top) top = vec.y;
3495 left = left & -64;
3496 right = (right + 63) & -64;
3497 bottom = bottom & -64;
3498 top = (top + 63) & -64;
3500 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
3501 vec.x = ft_face->glyph->metrics.horiAdvance;
3502 vec.y = 0;
3503 pFT_Vector_Transform(&vec, &transMat);
3504 lpgm->gmCellIncX = (vec.x+63) >> 6;
3505 lpgm->gmCellIncY = -((vec.y+63) >> 6);
3507 lpgm->gmBlackBoxX = (right - left) >> 6;
3508 lpgm->gmBlackBoxY = (top - bottom) >> 6;
3509 lpgm->gmptGlyphOrigin.x = left >> 6;
3510 lpgm->gmptGlyphOrigin.y = top >> 6;
3512 memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
3513 font->gm[glyph_index].init = TRUE;
3515 if(format == GGO_METRICS)
3516 return 1; /* FIXME */
3518 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP) {
3519 TRACE("loaded a bitmap\n");
3520 return GDI_ERROR;
3523 switch(format) {
3524 case GGO_BITMAP:
3525 width = lpgm->gmBlackBoxX;
3526 height = lpgm->gmBlackBoxY;
3527 pitch = ((width + 31) >> 5) << 2;
3528 needed = pitch * height;
3530 if(!buf || !buflen) break;
3532 switch(ft_face->glyph->format) {
3533 case ft_glyph_format_bitmap:
3535 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
3536 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
3537 INT h = ft_face->glyph->bitmap.rows;
3538 while(h--) {
3539 memcpy(dst, src, w);
3540 src += ft_face->glyph->bitmap.pitch;
3541 dst += pitch;
3543 break;
3546 case ft_glyph_format_outline:
3547 ft_bitmap.width = width;
3548 ft_bitmap.rows = height;
3549 ft_bitmap.pitch = pitch;
3550 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
3551 ft_bitmap.buffer = buf;
3553 if(needsTransform) {
3554 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3557 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3559 /* Note: FreeType will only set 'black' bits for us. */
3560 memset(buf, 0, needed);
3561 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3562 break;
3564 default:
3565 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
3566 return GDI_ERROR;
3568 break;
3570 case GGO_GRAY2_BITMAP:
3571 case GGO_GRAY4_BITMAP:
3572 case GGO_GRAY8_BITMAP:
3573 case WINE_GGO_GRAY16_BITMAP:
3575 unsigned int mult, row, col;
3576 BYTE *start, *ptr;
3578 width = lpgm->gmBlackBoxX;
3579 height = lpgm->gmBlackBoxY;
3580 pitch = (width + 3) / 4 * 4;
3581 needed = pitch * height;
3583 if(!buf || !buflen) break;
3584 ft_bitmap.width = width;
3585 ft_bitmap.rows = height;
3586 ft_bitmap.pitch = pitch;
3587 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
3588 ft_bitmap.buffer = buf;
3590 if(needsTransform) {
3591 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3594 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3596 memset(ft_bitmap.buffer, 0, buflen);
3598 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3600 if(format == GGO_GRAY2_BITMAP)
3601 mult = 4;
3602 else if(format == GGO_GRAY4_BITMAP)
3603 mult = 16;
3604 else if(format == GGO_GRAY8_BITMAP)
3605 mult = 64;
3606 else if(format == WINE_GGO_GRAY16_BITMAP)
3607 break;
3608 else {
3609 assert(0);
3610 break;
3613 start = buf;
3614 for(row = 0; row < height; row++) {
3615 ptr = start;
3616 for(col = 0; col < width; col++, ptr++) {
3617 *ptr = (((int)*ptr) * mult + 128) / 256;
3619 start += pitch;
3621 break;
3624 case GGO_NATIVE:
3626 int contour, point = 0, first_pt;
3627 FT_Outline *outline = &ft_face->glyph->outline;
3628 TTPOLYGONHEADER *pph;
3629 TTPOLYCURVE *ppc;
3630 DWORD pph_start, cpfx, type;
3632 if(buflen == 0) buf = NULL;
3634 if (needsTransform && buf) {
3635 pFT_Outline_Transform(outline, &transMat);
3638 for(contour = 0; contour < outline->n_contours; contour++) {
3639 pph_start = needed;
3640 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3641 first_pt = point;
3642 if(buf) {
3643 pph->dwType = TT_POLYGON_TYPE;
3644 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3646 needed += sizeof(*pph);
3647 point++;
3648 while(point <= outline->contours[contour]) {
3649 ppc = (TTPOLYCURVE *)((char *)buf + needed);
3650 type = (outline->tags[point] & FT_Curve_Tag_On) ?
3651 TT_PRIM_LINE : TT_PRIM_QSPLINE;
3652 cpfx = 0;
3653 do {
3654 if(buf)
3655 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3656 cpfx++;
3657 point++;
3658 } while(point <= outline->contours[contour] &&
3659 (outline->tags[point] & FT_Curve_Tag_On) ==
3660 (outline->tags[point-1] & FT_Curve_Tag_On));
3661 /* At the end of a contour Windows adds the start point, but
3662 only for Beziers */
3663 if(point > outline->contours[contour] &&
3664 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
3665 if(buf)
3666 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
3667 cpfx++;
3668 } else if(point <= outline->contours[contour] &&
3669 outline->tags[point] & FT_Curve_Tag_On) {
3670 /* add closing pt for bezier */
3671 if(buf)
3672 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3673 cpfx++;
3674 point++;
3676 if(buf) {
3677 ppc->wType = type;
3678 ppc->cpfx = cpfx;
3680 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3682 if(buf)
3683 pph->cb = needed - pph_start;
3685 break;
3687 case GGO_BEZIER:
3689 /* Convert the quadratic Beziers to cubic Beziers.
3690 The parametric eqn for a cubic Bezier is, from PLRM:
3691 r(t) = at^3 + bt^2 + ct + r0
3692 with the control points:
3693 r1 = r0 + c/3
3694 r2 = r1 + (c + b)/3
3695 r3 = r0 + c + b + a
3697 A quadratic Beizer has the form:
3698 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3700 So equating powers of t leads to:
3701 r1 = 2/3 p1 + 1/3 p0
3702 r2 = 2/3 p1 + 1/3 p2
3703 and of course r0 = p0, r3 = p2
3706 int contour, point = 0, first_pt;
3707 FT_Outline *outline = &ft_face->glyph->outline;
3708 TTPOLYGONHEADER *pph;
3709 TTPOLYCURVE *ppc;
3710 DWORD pph_start, cpfx, type;
3711 FT_Vector cubic_control[4];
3712 if(buflen == 0) buf = NULL;
3714 if (needsTransform && buf) {
3715 pFT_Outline_Transform(outline, &transMat);
3718 for(contour = 0; contour < outline->n_contours; contour++) {
3719 pph_start = needed;
3720 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
3721 first_pt = point;
3722 if(buf) {
3723 pph->dwType = TT_POLYGON_TYPE;
3724 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3726 needed += sizeof(*pph);
3727 point++;
3728 while(point <= outline->contours[contour]) {
3729 ppc = (TTPOLYCURVE *)((char *)buf + needed);
3730 type = (outline->tags[point] & FT_Curve_Tag_On) ?
3731 TT_PRIM_LINE : TT_PRIM_CSPLINE;
3732 cpfx = 0;
3733 do {
3734 if(type == TT_PRIM_LINE) {
3735 if(buf)
3736 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3737 cpfx++;
3738 point++;
3739 } else {
3740 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
3741 so cpfx = 3n */
3743 /* FIXME: Possible optimization in endpoint calculation
3744 if there are two consecutive curves */
3745 cubic_control[0] = outline->points[point-1];
3746 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
3747 cubic_control[0].x += outline->points[point].x + 1;
3748 cubic_control[0].y += outline->points[point].y + 1;
3749 cubic_control[0].x >>= 1;
3750 cubic_control[0].y >>= 1;
3752 if(point+1 > outline->contours[contour])
3753 cubic_control[3] = outline->points[first_pt];
3754 else {
3755 cubic_control[3] = outline->points[point+1];
3756 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
3757 cubic_control[3].x += outline->points[point].x + 1;
3758 cubic_control[3].y += outline->points[point].y + 1;
3759 cubic_control[3].x >>= 1;
3760 cubic_control[3].y >>= 1;
3763 /* r1 = 1/3 p0 + 2/3 p1
3764 r2 = 1/3 p2 + 2/3 p1 */
3765 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
3766 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
3767 cubic_control[2] = cubic_control[1];
3768 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
3769 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
3770 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
3771 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
3772 if(buf) {
3773 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
3774 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
3775 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
3777 cpfx += 3;
3778 point++;
3780 } while(point <= outline->contours[contour] &&
3781 (outline->tags[point] & FT_Curve_Tag_On) ==
3782 (outline->tags[point-1] & FT_Curve_Tag_On));
3783 /* At the end of a contour Windows adds the start point,
3784 but only for Beziers and we've already done that.
3786 if(point <= outline->contours[contour] &&
3787 outline->tags[point] & FT_Curve_Tag_On) {
3788 /* This is the closing pt of a bezier, but we've already
3789 added it, so just inc point and carry on */
3790 point++;
3792 if(buf) {
3793 ppc->wType = type;
3794 ppc->cpfx = cpfx;
3796 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3798 if(buf)
3799 pph->cb = needed - pph_start;
3801 break;
3804 default:
3805 FIXME("Unsupported format %d\n", format);
3806 return GDI_ERROR;
3808 return needed;
3811 static BOOL get_bitmap_text_metrics(GdiFont *font)
3813 FT_Face ft_face = font->ft_face;
3814 #ifdef HAVE_FREETYPE_FTWINFNT_H
3815 FT_WinFNT_HeaderRec winfnt_header;
3816 #endif
3817 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
3818 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
3819 font->potm->otmSize = size;
3821 #define TM font->potm->otmTextMetrics
3822 #ifdef HAVE_FREETYPE_FTWINFNT_H
3823 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
3825 TM.tmHeight = winfnt_header.pixel_height;
3826 TM.tmAscent = winfnt_header.ascent;
3827 TM.tmDescent = TM.tmHeight - TM.tmAscent;
3828 TM.tmInternalLeading = winfnt_header.internal_leading;
3829 TM.tmExternalLeading = winfnt_header.external_leading;
3830 TM.tmAveCharWidth = winfnt_header.avg_width;
3831 TM.tmMaxCharWidth = winfnt_header.max_width;
3832 TM.tmWeight = winfnt_header.weight;
3833 TM.tmOverhang = 0;
3834 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
3835 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
3836 TM.tmFirstChar = winfnt_header.first_char;
3837 TM.tmLastChar = winfnt_header.last_char;
3838 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
3839 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
3840 TM.tmItalic = winfnt_header.italic;
3841 TM.tmUnderlined = font->underline;
3842 TM.tmStruckOut = font->strikeout;
3843 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
3844 TM.tmCharSet = winfnt_header.charset;
3846 else
3847 #endif
3849 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
3850 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
3851 TM.tmHeight = TM.tmAscent + TM.tmDescent;
3852 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
3853 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
3854 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
3855 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
3856 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
3857 TM.tmOverhang = 0;
3858 TM.tmDigitizedAspectX = 96; /* FIXME */
3859 TM.tmDigitizedAspectY = 96; /* FIXME */
3860 TM.tmFirstChar = 1;
3861 TM.tmLastChar = 255;
3862 TM.tmDefaultChar = 32;
3863 TM.tmBreakChar = 32;
3864 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
3865 TM.tmUnderlined = font->underline;
3866 TM.tmStruckOut = font->strikeout;
3867 /* NB inverted meaning of TMPF_FIXED_PITCH */
3868 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
3869 TM.tmCharSet = font->charset;
3871 #undef TM
3873 return TRUE;
3876 /*************************************************************
3877 * WineEngGetTextMetrics
3880 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
3882 if(!font->potm) {
3883 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
3884 if(!get_bitmap_text_metrics(font))
3885 return FALSE;
3887 if(!font->potm) return FALSE;
3888 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
3890 if (font->aveWidth) {
3891 ptm->tmAveCharWidth = font->aveWidth * font->font_desc.matrix.eM11;
3893 return TRUE;
3897 /*************************************************************
3898 * WineEngGetOutlineTextMetrics
3901 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
3902 OUTLINETEXTMETRICW *potm)
3904 FT_Face ft_face = font->ft_face;
3905 UINT needed, lenfam, lensty, ret;
3906 TT_OS2 *pOS2;
3907 TT_HoriHeader *pHori;
3908 TT_Postscript *pPost;
3909 FT_Fixed x_scale, y_scale;
3910 WCHAR *family_nameW, *style_nameW;
3911 static const WCHAR spaceW[] = {' ', '\0'};
3912 char *cp;
3913 INT ascent, descent;
3915 TRACE("font=%p\n", font);
3917 if(!FT_IS_SCALABLE(ft_face))
3918 return 0;
3920 if(font->potm) {
3921 if(cbSize >= font->potm->otmSize)
3922 memcpy(potm, font->potm, font->potm->otmSize);
3923 return font->potm->otmSize;
3927 needed = sizeof(*potm);
3929 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
3930 family_nameW = strdupW(font->name);
3932 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
3933 * sizeof(WCHAR);
3934 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
3935 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
3936 style_nameW, lensty/sizeof(WCHAR));
3938 /* These names should be read from the TT name table */
3940 /* length of otmpFamilyName */
3941 needed += lenfam;
3943 /* length of otmpFaceName */
3944 if(!strcasecmp(ft_face->style_name, "regular")) {
3945 needed += lenfam; /* just the family name */
3946 } else {
3947 needed += lenfam + lensty; /* family + " " + style */
3950 /* length of otmpStyleName */
3951 needed += lensty;
3953 /* length of otmpFullName */
3954 needed += lenfam + lensty;
3957 x_scale = ft_face->size->metrics.x_scale;
3958 y_scale = ft_face->size->metrics.y_scale;
3960 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
3961 if(!pOS2) {
3962 FIXME("Can't find OS/2 table - not TT font?\n");
3963 ret = 0;
3964 goto end;
3967 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
3968 if(!pHori) {
3969 FIXME("Can't find HHEA table - not TT font?\n");
3970 ret = 0;
3971 goto end;
3974 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
3976 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",
3977 pOS2->usWinAscent, pOS2->usWinDescent,
3978 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
3979 ft_face->ascender, ft_face->descender, ft_face->height,
3980 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
3981 ft_face->bbox.yMax, ft_face->bbox.yMin);
3983 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
3984 font->potm->otmSize = needed;
3986 #define TM font->potm->otmTextMetrics
3988 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
3989 ascent = pHori->Ascender;
3990 descent = -pHori->Descender;
3991 } else {
3992 ascent = pOS2->usWinAscent;
3993 descent = pOS2->usWinDescent;
3996 if(font->yMax) {
3997 TM.tmAscent = font->yMax;
3998 TM.tmDescent = -font->yMin;
3999 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
4000 } else {
4001 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
4002 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
4003 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
4004 - ft_face->units_per_EM, y_scale) + 32) >> 6;
4007 TM.tmHeight = TM.tmAscent + TM.tmDescent;
4009 /* MSDN says:
4010 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
4012 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
4013 ((ascent + descent) -
4014 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
4016 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
4017 if (TM.tmAveCharWidth == 0) {
4018 TM.tmAveCharWidth = 1;
4020 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
4021 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
4022 TM.tmOverhang = 0;
4023 TM.tmDigitizedAspectX = 300;
4024 TM.tmDigitizedAspectY = 300;
4025 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
4026 * symbol range to 0 - f0ff
4028 if (font->charset == SYMBOL_CHARSET)
4029 TM.tmFirstChar = 0;
4030 else
4031 TM.tmFirstChar = pOS2->usFirstCharIndex;
4032 TM.tmLastChar = pOS2->usLastCharIndex;
4033 TM.tmDefaultChar = pOS2->usDefaultChar ? pOS2->usDefaultChar : 0x1f;
4034 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
4035 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
4036 TM.tmUnderlined = font->underline;
4037 TM.tmStruckOut = font->strikeout;
4039 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
4040 if(!FT_IS_FIXED_WIDTH(ft_face) &&
4041 (pOS2->version == 0xFFFFU ||
4042 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
4043 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
4044 else
4045 TM.tmPitchAndFamily = 0;
4047 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
4048 case PAN_FAMILY_SCRIPT:
4049 TM.tmPitchAndFamily |= FF_SCRIPT;
4050 break;
4051 case PAN_FAMILY_DECORATIVE:
4052 case PAN_FAMILY_PICTORIAL:
4053 TM.tmPitchAndFamily |= FF_DECORATIVE;
4054 break;
4055 case PAN_FAMILY_TEXT_DISPLAY:
4056 if(TM.tmPitchAndFamily == 0) /* fixed */
4057 TM.tmPitchAndFamily = FF_MODERN;
4058 else {
4059 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
4060 case PAN_SERIF_NORMAL_SANS:
4061 case PAN_SERIF_OBTUSE_SANS:
4062 case PAN_SERIF_PERP_SANS:
4063 TM.tmPitchAndFamily |= FF_SWISS;
4064 break;
4065 default:
4066 TM.tmPitchAndFamily |= FF_ROMAN;
4069 break;
4070 default:
4071 TM.tmPitchAndFamily |= FF_DONTCARE;
4074 if(FT_IS_SCALABLE(ft_face))
4075 TM.tmPitchAndFamily |= TMPF_VECTOR;
4076 if(FT_IS_SFNT(ft_face))
4077 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
4079 TM.tmCharSet = font->charset;
4080 #undef TM
4082 font->potm->otmFiller = 0;
4083 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
4084 font->potm->otmfsSelection = pOS2->fsSelection;
4085 font->potm->otmfsType = pOS2->fsType;
4086 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
4087 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
4088 font->potm->otmItalicAngle = 0; /* POST table */
4089 font->potm->otmEMSquare = ft_face->units_per_EM;
4090 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
4091 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
4092 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
4093 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
4094 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
4095 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
4096 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
4097 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
4098 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
4099 font->potm->otmMacAscent = 0; /* where do these come from ? */
4100 font->potm->otmMacDescent = 0;
4101 font->potm->otmMacLineGap = 0;
4102 font->potm->otmusMinimumPPEM = 0; /* TT Header */
4103 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
4104 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
4105 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
4106 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
4107 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
4108 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
4109 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
4110 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
4111 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
4112 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
4113 if(!pPost) {
4114 font->potm->otmsUnderscoreSize = 0;
4115 font->potm->otmsUnderscorePosition = 0;
4116 } else {
4117 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
4118 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
4121 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
4122 cp = (char*)font->potm + sizeof(*font->potm);
4123 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
4124 strcpyW((WCHAR*)cp, family_nameW);
4125 cp += lenfam;
4126 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
4127 strcpyW((WCHAR*)cp, style_nameW);
4128 cp += lensty;
4129 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
4130 strcpyW((WCHAR*)cp, family_nameW);
4131 if(strcasecmp(ft_face->style_name, "regular")) {
4132 strcatW((WCHAR*)cp, spaceW);
4133 strcatW((WCHAR*)cp, style_nameW);
4134 cp += lenfam + lensty;
4135 } else
4136 cp += lenfam;
4137 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
4138 strcpyW((WCHAR*)cp, family_nameW);
4139 strcatW((WCHAR*)cp, spaceW);
4140 strcatW((WCHAR*)cp, style_nameW);
4141 ret = needed;
4143 if(potm && needed <= cbSize)
4144 memcpy(potm, font->potm, font->potm->otmSize);
4146 end:
4147 HeapFree(GetProcessHeap(), 0, style_nameW);
4148 HeapFree(GetProcessHeap(), 0, family_nameW);
4150 return ret;
4153 static BOOL load_child_font(GdiFont *font, CHILD_FONT *child)
4155 HFONTLIST *hfontlist;
4156 child->font = alloc_font();
4157 child->font->ft_face = OpenFontFile(child->font, child->file_name, child->index, 0, -font->ppem);
4158 if(!child->font->ft_face)
4160 free_font(child->font);
4161 child->font = NULL;
4162 return FALSE;
4165 child->font->orientation = font->orientation;
4166 hfontlist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist));
4167 hfontlist->hfont = CreateFontIndirectW(&font->font_desc.lf);
4168 list_add_head(&child->font->hfontlist, &hfontlist->entry);
4169 child->font->base_font = font;
4170 list_add_head(&child_font_list, &child->font->entry);
4171 TRACE("created child font hfont %p for base %p child %p\n", hfontlist->hfont, font, child->font);
4172 return TRUE;
4175 static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font, FT_UInt *glyph)
4177 FT_UInt g;
4178 CHILD_FONT *child_font;
4180 if(font->base_font)
4181 font = font->base_font;
4183 *linked_font = font;
4185 if((*glyph = get_glyph_index(font, c)))
4186 return TRUE;
4188 LIST_FOR_EACH_ENTRY(child_font, &font->child_fonts, CHILD_FONT, entry)
4190 if(!child_font->font)
4191 if(!load_child_font(font, child_font))
4192 continue;
4194 if(!child_font->font->ft_face)
4195 continue;
4196 g = get_glyph_index(child_font->font, c);
4197 if(g)
4199 *glyph = g;
4200 *linked_font = child_font->font;
4201 return TRUE;
4204 return FALSE;
4207 /*************************************************************
4208 * WineEngGetCharWidth
4211 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
4212 LPINT buffer)
4214 UINT c;
4215 GLYPHMETRICS gm;
4216 FT_UInt glyph_index;
4217 GdiFont *linked_font;
4219 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
4221 for(c = firstChar; c <= lastChar; c++) {
4222 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
4223 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4224 &gm, 0, NULL, NULL);
4225 buffer[c - firstChar] = linked_font->gm[glyph_index].adv;
4227 return TRUE;
4230 /*************************************************************
4231 * WineEngGetCharABCWidths
4234 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
4235 LPABC buffer)
4237 UINT c;
4238 GLYPHMETRICS gm;
4239 FT_UInt glyph_index;
4240 GdiFont *linked_font;
4242 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
4244 if(!FT_IS_SCALABLE(font->ft_face))
4245 return FALSE;
4247 for(c = firstChar; c <= lastChar; c++) {
4248 get_glyph_index_linked(font, c, &linked_font, &glyph_index);
4249 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4250 &gm, 0, NULL, NULL);
4251 buffer[c - firstChar].abcA = linked_font->gm[glyph_index].lsb;
4252 buffer[c - firstChar].abcB = linked_font->gm[glyph_index].bbx;
4253 buffer[c - firstChar].abcC = linked_font->gm[glyph_index].adv - linked_font->gm[glyph_index].lsb -
4254 linked_font->gm[glyph_index].bbx;
4256 return TRUE;
4259 /*************************************************************
4260 * WineEngGetCharABCWidthsI
4263 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
4264 LPABC buffer)
4266 UINT c;
4267 GLYPHMETRICS gm;
4268 FT_UInt glyph_index;
4269 GdiFont *linked_font;
4271 if(!FT_IS_SCALABLE(font->ft_face))
4272 return FALSE;
4274 get_glyph_index_linked(font, 'a', &linked_font, &glyph_index);
4275 if (!pgi)
4276 for(c = firstChar; c < firstChar+count; c++) {
4277 WineEngGetGlyphOutline(linked_font, c, GGO_METRICS | GGO_GLYPH_INDEX,
4278 &gm, 0, NULL, NULL);
4279 buffer[c - firstChar].abcA = linked_font->gm[c].lsb;
4280 buffer[c - firstChar].abcB = linked_font->gm[c].bbx;
4281 buffer[c - firstChar].abcC = linked_font->gm[c].adv - linked_font->gm[c].lsb
4282 - linked_font->gm[c].bbx;
4284 else
4285 for(c = 0; c < count; c++) {
4286 WineEngGetGlyphOutline(linked_font, pgi[c], GGO_METRICS | GGO_GLYPH_INDEX,
4287 &gm, 0, NULL, NULL);
4288 buffer[c].abcA = linked_font->gm[pgi[c]].lsb;
4289 buffer[c].abcB = linked_font->gm[pgi[c]].bbx;
4290 buffer[c].abcC = linked_font->gm[pgi[c]].adv
4291 - linked_font->gm[pgi[c]].lsb - linked_font->gm[pgi[c]].bbx;
4294 return TRUE;
4297 /*************************************************************
4298 * WineEngGetTextExtentExPoint
4301 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
4302 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
4304 INT idx;
4305 INT nfit = 0, ext;
4306 GLYPHMETRICS gm;
4307 TEXTMETRICW tm;
4308 FT_UInt glyph_index;
4309 GdiFont *linked_font;
4311 TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count), count,
4312 max_ext, size);
4314 size->cx = 0;
4315 WineEngGetTextMetrics(font, &tm);
4316 size->cy = tm.tmHeight;
4318 for(idx = 0; idx < count; idx++) {
4319 get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
4320 WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
4321 &gm, 0, NULL, NULL);
4322 size->cx += linked_font->gm[glyph_index].adv;
4323 ext = size->cx;
4324 if (! pnfit || ext <= max_ext) {
4325 ++nfit;
4326 if (dxs)
4327 dxs[idx] = ext;
4331 if (pnfit)
4332 *pnfit = nfit;
4334 TRACE("return %d, %d, %d\n", size->cx, size->cy, nfit);
4335 return TRUE;
4338 /*************************************************************
4339 * WineEngGetTextExtentPointI
4342 BOOL WineEngGetTextExtentPointI(GdiFont *font, const WORD *indices, INT count,
4343 LPSIZE size)
4345 INT idx;
4346 GLYPHMETRICS gm;
4347 TEXTMETRICW tm;
4349 TRACE("%p, %p, %d, %p\n", font, indices, count, size);
4351 size->cx = 0;
4352 WineEngGetTextMetrics(font, &tm);
4353 size->cy = tm.tmHeight;
4355 for(idx = 0; idx < count; idx++) {
4356 WineEngGetGlyphOutline(font, indices[idx],
4357 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
4358 NULL);
4359 size->cx += font->gm[indices[idx]].adv;
4361 TRACE("return %d,%d\n", size->cx, size->cy);
4362 return TRUE;
4365 /*************************************************************
4366 * WineEngGetFontData
4369 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
4370 DWORD cbData)
4372 FT_Face ft_face = font->ft_face;
4373 FT_ULong len;
4374 FT_Error err;
4376 TRACE("font=%p, table=%08x, offset=%08x, buf=%p, cbData=%x\n",
4377 font, table, offset, buf, cbData);
4379 if(!FT_IS_SFNT(ft_face))
4380 return GDI_ERROR;
4382 if(!buf || !cbData)
4383 len = 0;
4384 else
4385 len = cbData;
4387 if(table) { /* MS tags differ in endidness from FT ones */
4388 table = table >> 24 | table << 24 |
4389 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
4392 /* If the FT_Load_Sfnt_Table function is there we'll use it */
4393 if(pFT_Load_Sfnt_Table) {
4394 /* make sure value of len is the value freetype says it needs */
4395 if( buf && len) {
4396 FT_ULong needed = 0;
4397 err = pFT_Load_Sfnt_Table(ft_face, table, offset, NULL, &needed);
4398 if( !err && needed < len) len = needed;
4400 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
4402 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
4403 else { /* Do it the hard way */
4404 TT_Face tt_face = (TT_Face) ft_face;
4405 SFNT_Interface *sfnt;
4406 if (FT_Version.major==2 && FT_Version.minor==0)
4408 /* 2.0.x */
4409 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
4411 else
4413 /* A field was added in the middle of the structure in 2.1.x */
4414 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
4416 /* make sure value of len is the value freetype says it needs */
4417 if( buf && len) {
4418 FT_ULong needed = 0;
4419 err = sfnt->load_any(tt_face, table, offset, NULL, &needed);
4420 if( !err && needed < len) len = needed;
4422 err = sfnt->load_any(tt_face, table, offset, buf, &len);
4424 #else
4425 else {
4426 static int msg;
4427 if(!msg) {
4428 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
4429 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
4430 "Please upgrade your freetype library.\n");
4431 msg++;
4433 err = FT_Err_Unimplemented_Feature;
4435 #endif
4436 if(err) {
4437 TRACE("Can't find table %08x.\n", table);
4438 return GDI_ERROR;
4440 return len;
4443 /*************************************************************
4444 * WineEngGetTextFace
4447 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
4449 if(str) {
4450 lstrcpynW(str, font->name, count);
4451 return strlenW(font->name);
4452 } else
4453 return strlenW(font->name) + 1;
4456 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
4458 if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
4459 return font->charset;
4462 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
4464 GdiFont *font = dc->gdiFont, *linked_font;
4465 struct list *first_hfont;
4466 BOOL ret;
4468 ret = get_glyph_index_linked(font, c, &linked_font, glyph);
4469 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph, linked_font);
4470 if(font == linked_font)
4471 *new_hfont = dc->hFont;
4472 else
4474 first_hfont = list_head(&linked_font->hfontlist);
4475 *new_hfont = LIST_ENTRY(first_hfont, struct tagHFONTLIST, entry)->hfont;
4478 return ret;
4481 /* Retrieve a list of supported Unicode ranges for a given font.
4482 * Can be called with NULL gs to calculate the buffer size. Returns
4483 * the number of ranges found.
4485 static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs)
4487 DWORD num_ranges = 0;
4489 if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
4491 FT_UInt glyph_code;
4492 FT_ULong char_code, char_code_prev;
4494 glyph_code = 0;
4495 char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code);
4497 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
4498 face->num_glyphs, glyph_code, char_code);
4500 if (!glyph_code) return 0;
4502 if (gs)
4504 gs->ranges[0].wcLow = (USHORT)char_code;
4505 gs->ranges[0].cGlyphs = 0;
4506 gs->cGlyphsSupported = 0;
4509 num_ranges = 1;
4510 while (glyph_code)
4512 if (char_code < char_code_prev)
4514 ERR("expected increasing char code from FT_Get_Next_Char\n");
4515 return 0;
4517 if (char_code - char_code_prev > 1)
4519 num_ranges++;
4520 if (gs)
4522 gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
4523 gs->ranges[num_ranges - 1].cGlyphs = 1;
4524 gs->cGlyphsSupported++;
4527 else if (gs)
4529 gs->ranges[num_ranges - 1].cGlyphs++;
4530 gs->cGlyphsSupported++;
4532 char_code_prev = char_code;
4533 char_code = pFT_Get_Next_Char(face, char_code, &glyph_code);
4536 else
4537 FIXME("encoding %u not supported\n", face->charmap->encoding);
4539 return num_ranges;
4542 DWORD WineEngGetFontUnicodeRanges(HDC hdc, LPGLYPHSET glyphset)
4544 DWORD size = 0;
4545 DC *dc = DC_GetDCPtr(hdc);
4547 TRACE("(%p, %p)\n", hdc, glyphset);
4549 if (!dc) return 0;
4551 if (dc->gdiFont)
4553 DWORD num_ranges = get_font_unicode_ranges(dc->gdiFont->ft_face, glyphset);
4555 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
4556 if (glyphset)
4558 glyphset->cbThis = size;
4559 glyphset->cRanges = num_ranges;
4563 GDI_ReleaseObj(hdc);
4564 return size;
4567 /*************************************************************
4568 * FontIsLinked
4570 BOOL WINAPI FontIsLinked(HDC hdc)
4572 DC *dc = DC_GetDCPtr(hdc);
4573 BOOL ret = FALSE;
4575 if(!dc) return FALSE;
4576 if(dc->gdiFont && !list_empty(&dc->gdiFont->child_fonts))
4577 ret = TRUE;
4578 GDI_ReleaseObj(hdc);
4579 TRACE("returning %d\n", ret);
4580 return ret;
4583 static BOOL is_hinting_enabled(void)
4585 /* Use the >= 2.2.0 function if available */
4586 if(pFT_Get_TrueType_Engine_Type)
4588 FT_TrueTypeEngineType type = pFT_Get_TrueType_Engine_Type(library);
4589 return type == FT_TRUETYPE_ENGINE_TYPE_PATENTED;
4591 #ifdef FT_DRIVER_HAS_HINTER
4592 else
4594 FT_Module mod;
4596 /* otherwise if we've been compiled with < 2.2.0 headers
4597 use the internal macro */
4598 mod = pFT_Get_Module(library, "truetype");
4599 if(mod && FT_DRIVER_HAS_HINTER(mod))
4600 return TRUE;
4602 #endif
4604 return FALSE;
4607 /*************************************************************************
4608 * GetRasterizerCaps (GDI32.@)
4610 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
4612 static int hinting = -1;
4614 if(hinting == -1)
4616 hinting = is_hinting_enabled();
4617 TRACE("hinting is %senabled\n", hinting ? "" : "NOT ");
4620 lprs->nSize = sizeof(RASTERIZER_STATUS);
4621 lprs->wFlags = TT_AVAILABLE | TT_ENABLED | (hinting ? WINE_TT_HINTER_ENABLED : 0);
4622 lprs->nLanguageID = 0;
4623 return TRUE;
4626 /*************************************************************************
4627 * Kerning support for TrueType fonts
4629 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
4631 struct TT_kern_table
4633 USHORT version;
4634 USHORT nTables;
4637 struct TT_kern_subtable
4639 USHORT version;
4640 USHORT length;
4641 union
4643 USHORT word;
4644 struct
4646 USHORT horizontal : 1;
4647 USHORT minimum : 1;
4648 USHORT cross_stream: 1;
4649 USHORT override : 1;
4650 USHORT reserved1 : 4;
4651 USHORT format : 8;
4652 } bits;
4653 } coverage;
4656 struct TT_format0_kern_subtable
4658 USHORT nPairs;
4659 USHORT searchRange;
4660 USHORT entrySelector;
4661 USHORT rangeShift;
4664 struct TT_kern_pair
4666 USHORT left;
4667 USHORT right;
4668 short value;
4671 static DWORD parse_format0_kern_subtable(GdiFont *font,
4672 const struct TT_format0_kern_subtable *tt_f0_ks,
4673 const USHORT *glyph_to_char,
4674 KERNINGPAIR *kern_pair, DWORD cPairs)
4676 USHORT i, nPairs;
4677 const struct TT_kern_pair *tt_kern_pair;
4679 TRACE("font height %d, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
4681 nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
4683 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
4684 nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
4685 GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
4687 if (!kern_pair || !cPairs)
4688 return nPairs;
4690 tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
4692 nPairs = min(nPairs, cPairs);
4694 for (i = 0; i < nPairs; i++)
4696 kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
4697 kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
4698 /* this algorithm appears to better match what Windows does */
4699 kern_pair->iKernAmount = (short)GET_BE_WORD(tt_kern_pair[i].value) * font->ppem;
4700 if (kern_pair->iKernAmount < 0)
4702 kern_pair->iKernAmount -= font->ft_face->units_per_EM / 2;
4703 kern_pair->iKernAmount -= font->ppem;
4705 else if (kern_pair->iKernAmount > 0)
4707 kern_pair->iKernAmount += font->ft_face->units_per_EM / 2;
4708 kern_pair->iKernAmount += font->ppem;
4710 kern_pair->iKernAmount /= font->ft_face->units_per_EM;
4712 TRACE("left %u right %u value %d\n",
4713 kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
4715 kern_pair++;
4717 TRACE("copied %u entries\n", nPairs);
4718 return nPairs;
4721 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
4723 DWORD length;
4724 void *buf;
4725 const struct TT_kern_table *tt_kern_table;
4726 const struct TT_kern_subtable *tt_kern_subtable;
4727 USHORT i, nTables;
4728 USHORT *glyph_to_char;
4730 if (font->total_kern_pairs != (DWORD)-1)
4732 if (cPairs && kern_pair)
4734 cPairs = min(cPairs, font->total_kern_pairs);
4735 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
4736 return cPairs;
4738 return font->total_kern_pairs;
4741 font->total_kern_pairs = 0;
4743 length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
4745 if (length == GDI_ERROR)
4747 TRACE("no kerning data in the font\n");
4748 return 0;
4751 buf = HeapAlloc(GetProcessHeap(), 0, length);
4752 if (!buf)
4754 WARN("Out of memory\n");
4755 return 0;
4758 WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
4760 /* build a glyph index to char code map */
4761 glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
4762 if (!glyph_to_char)
4764 WARN("Out of memory allocating a glyph index to char code map\n");
4765 HeapFree(GetProcessHeap(), 0, buf);
4766 return 0;
4769 if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
4771 FT_UInt glyph_code;
4772 FT_ULong char_code;
4774 glyph_code = 0;
4775 char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
4777 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
4778 font->ft_face->num_glyphs, glyph_code, char_code);
4780 while (glyph_code)
4782 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
4784 /* FIXME: This doesn't match what Windows does: it does some fancy
4785 * things with duplicate glyph index to char code mappings, while
4786 * we just avoid overriding existing entries.
4788 if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
4789 glyph_to_char[glyph_code] = (USHORT)char_code;
4791 char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
4794 else
4796 ULONG n;
4798 FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
4799 for (n = 0; n <= 65535; n++)
4800 glyph_to_char[n] = (USHORT)n;
4803 tt_kern_table = buf;
4804 nTables = GET_BE_WORD(tt_kern_table->nTables);
4805 TRACE("version %u, nTables %u\n",
4806 GET_BE_WORD(tt_kern_table->version), nTables);
4808 tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
4810 for (i = 0; i < nTables; i++)
4812 struct TT_kern_subtable tt_kern_subtable_copy;
4814 tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
4815 tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
4816 tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
4818 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
4819 tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
4820 tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
4822 /* According to the TrueType specification this is the only format
4823 * that will be properly interpreted by Windows and OS/2
4825 if (tt_kern_subtable_copy.coverage.bits.format == 0)
4827 DWORD new_chunk, old_total = font->total_kern_pairs;
4829 new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
4830 glyph_to_char, NULL, 0);
4831 font->total_kern_pairs += new_chunk;
4833 if (!font->kern_pairs)
4834 font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
4835 font->total_kern_pairs * sizeof(*font->kern_pairs));
4836 else
4837 font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
4838 font->total_kern_pairs * sizeof(*font->kern_pairs));
4840 parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
4841 glyph_to_char, font->kern_pairs + old_total, new_chunk);
4843 else
4844 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
4846 tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
4849 HeapFree(GetProcessHeap(), 0, glyph_to_char);
4850 HeapFree(GetProcessHeap(), 0, buf);
4852 if (cPairs && kern_pair)
4854 cPairs = min(cPairs, font->total_kern_pairs);
4855 memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
4856 return cPairs;
4858 return font->total_kern_pairs;
4861 #else /* HAVE_FREETYPE */
4863 /*************************************************************************/
4865 BOOL WineEngInit(void)
4867 return FALSE;
4869 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
4871 return NULL;
4873 BOOL WineEngDestroyFontInstance(HFONT hfont)
4875 return FALSE;
4878 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
4880 return 1;
4883 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
4884 LPWORD pgi, DWORD flags)
4886 return GDI_ERROR;
4889 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
4890 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
4891 const MAT2* lpmat)
4893 ERR("called but we don't have FreeType\n");
4894 return GDI_ERROR;
4897 BOOL WineEngGetTextMetrics(GdiFont *font, LPTEXTMETRICW ptm)
4899 ERR("called but we don't have FreeType\n");
4900 return FALSE;
4903 UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
4904 OUTLINETEXTMETRICW *potm)
4906 ERR("called but we don't have FreeType\n");
4907 return 0;
4910 BOOL WineEngGetCharWidth(GdiFont *font, UINT firstChar, UINT lastChar,
4911 LPINT buffer)
4913 ERR("called but we don't have FreeType\n");
4914 return FALSE;
4917 BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar, UINT lastChar,
4918 LPABC buffer)
4920 ERR("called but we don't have FreeType\n");
4921 return FALSE;
4924 BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi,
4925 LPABC buffer)
4927 ERR("called but we don't have FreeType\n");
4928 return FALSE;
4931 BOOL WineEngGetTextExtentExPoint(GdiFont *font, LPCWSTR wstr, INT count,
4932 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
4934 ERR("called but we don't have FreeType\n");
4935 return FALSE;
4938 BOOL WineEngGetTextExtentPointI(GdiFont *font, const WORD *indices, INT count,
4939 LPSIZE size)
4941 ERR("called but we don't have FreeType\n");
4942 return FALSE;
4945 DWORD WineEngGetFontData(GdiFont *font, DWORD table, DWORD offset, LPVOID buf,
4946 DWORD cbData)
4948 ERR("called but we don't have FreeType\n");
4949 return GDI_ERROR;
4952 INT WineEngGetTextFace(GdiFont *font, INT count, LPWSTR str)
4954 ERR("called but we don't have FreeType\n");
4955 return 0;
4958 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
4960 FIXME(":stub\n");
4961 return 1;
4964 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
4966 FIXME(":stub\n");
4967 return TRUE;
4970 UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags)
4972 FIXME(":stub\n");
4973 return DEFAULT_CHARSET;
4976 BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph)
4978 return FALSE;
4981 DWORD WineEngGetFontUnicodeRanges(HDC hdc, LPGLYPHSET glyphset)
4983 FIXME("(%p, %p): stub\n", hdc, glyphset);
4984 return 0;
4987 BOOL WINAPI FontIsLinked(HDC hdc)
4989 return FALSE;
4992 /*************************************************************************
4993 * GetRasterizerCaps (GDI32.@)
4995 BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
4997 lprs->nSize = sizeof(RASTERIZER_STATUS);
4998 lprs->wFlags = 0;
4999 lprs->nLanguageID = 0;
5000 return TRUE;
5003 DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair)
5005 ERR("called but we don't have FreeType\n");
5006 return 0;
5009 #endif /* HAVE_FREETYPE */