wined3d: Use the framebuffer blit extension to implement StretchRect.
[wine/hacks.git] / dlls / gdi32 / freetype.c
blobc37247725ac0c6c118ed8ffab4bab7fe2a9047a1
1 /*
2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
5 * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
7 * This file contains the WineEng* functions.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "config.h"
25 #include "wine/port.h"
27 #include <stdarg.h>
28 #include <stdlib.h>
29 #ifdef HAVE_SYS_STAT_H
30 # include <sys/stat.h>
31 #endif
32 #ifdef HAVE_SYS_MMAN_H
33 # include <sys/mman.h>
34 #endif
35 #include <string.h>
36 #include <dirent.h>
37 #include <stdio.h>
38 #include <assert.h>
40 #ifdef HAVE_CARBON_CARBON_H
41 #define LoadResource __carbon_LoadResource
42 #define CompareString __carbon_CompareString
43 #define GetCurrentThread __carbon_GetCurrentThread
44 #define GetCurrentProcess __carbon_GetCurrentProcess
45 #define AnimatePalette __carbon_AnimatePalette
46 #define EqualRgn __carbon_EqualRgn
47 #define FillRgn __carbon_FillRgn
48 #define FrameRgn __carbon_FrameRgn
49 #define GetPixel __carbon_GetPixel
50 #define InvertRgn __carbon_InvertRgn
51 #define LineTo __carbon_LineTo
52 #define OffsetRgn __carbon_OffsetRgn
53 #define PaintRgn __carbon_PaintRgn
54 #define Polygon __carbon_Polygon
55 #define ResizePalette __carbon_ResizePalette
56 #define SetRectRgn __carbon_SetRectRgn
57 #include <Carbon/Carbon.h>
58 #undef LoadResource
59 #undef CompareString
60 #undef GetCurrentThread
61 #undef _CDECL
62 #undef DPRINTF
63 #undef GetCurrentProcess
64 #undef AnimatePalette
65 #undef EqualRgn
66 #undef FillRgn
67 #undef FrameRgn
68 #undef GetPixel
69 #undef InvertRgn
70 #undef LineTo
71 #undef OffsetRgn
72 #undef PaintRgn
73 #undef Polygon
74 #undef ResizePalette
75 #undef SetRectRgn
76 #endif /* HAVE_CARBON_CARBON_H */
78 #include "windef.h"
79 #include "winbase.h"
80 #include "winternl.h"
81 #include "winerror.h"
82 #include "winreg.h"
83 #include "wingdi.h"
84 #include "gdi_private.h"
85 #include "wine/unicode.h"
86 #include "wine/debug.h"
87 #include "wine/list.h"
89 WINE_DEFAULT_DEBUG_CHANNEL(font);
91 #ifdef HAVE_FREETYPE
93 #ifdef HAVE_FT2BUILD_H
94 #include <ft2build.h>
95 #endif
96 #ifdef HAVE_FREETYPE_FREETYPE_H
97 #include <freetype/freetype.h>
98 #endif
99 #ifdef HAVE_FREETYPE_FTGLYPH_H
100 #include <freetype/ftglyph.h>
101 #endif
102 #ifdef HAVE_FREETYPE_TTTABLES_H
103 #include <freetype/tttables.h>
104 #endif
105 #ifdef HAVE_FREETYPE_FTSNAMES_H
106 #include <freetype/ftsnames.h>
107 #else
108 # ifdef HAVE_FREETYPE_FTNAMES_H
109 # include <freetype/ftnames.h>
110 # endif
111 #endif
112 #ifdef HAVE_FREETYPE_TTNAMEID_H
113 #include <freetype/ttnameid.h>
114 #endif
115 #ifdef HAVE_FREETYPE_FTOUTLN_H
116 #include <freetype/ftoutln.h>
117 #endif
118 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
119 #include <freetype/internal/sfnt.h>
120 #endif
121 #ifdef HAVE_FREETYPE_FTTRIGON_H
122 #include <freetype/fttrigon.h>
123 #endif
124 #ifdef HAVE_FREETYPE_FTWINFNT_H
125 #include <freetype/ftwinfnt.h>
126 #endif
127 #ifdef HAVE_FREETYPE_FTMODAPI_H
128 #include <freetype/ftmodapi.h>
129 #endif
131 #ifndef SONAME_LIBFREETYPE
132 #define SONAME_LIBFREETYPE "libfreetype.so"
133 #endif
135 #ifndef HAVE_FT_TRUETYPEENGINETYPE
136 typedef enum
138 FT_TRUETYPE_ENGINE_TYPE_NONE = 0,
139 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED,
140 FT_TRUETYPE_ENGINE_TYPE_PATENTED
141 } FT_TrueTypeEngineType;
142 #endif
144 static FT_Library library = 0;
145 typedef struct
147 FT_Int major;
148 FT_Int minor;
149 FT_Int patch;
150 } FT_Version_t;
151 static FT_Version_t FT_Version;
152 static DWORD FT_SimpleVersion;
154 static void *ft_handle = NULL;
156 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
157 MAKE_FUNCPTR(FT_Vector_Unit);
158 MAKE_FUNCPTR(FT_Done_Face);
159 MAKE_FUNCPTR(FT_Get_Char_Index);
160 MAKE_FUNCPTR(FT_Get_Module);
161 MAKE_FUNCPTR(FT_Get_Sfnt_Name);
162 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count);
163 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
164 MAKE_FUNCPTR(FT_Init_FreeType);
165 MAKE_FUNCPTR(FT_Load_Glyph);
166 MAKE_FUNCPTR(FT_Matrix_Multiply);
167 MAKE_FUNCPTR(FT_MulFix);
168 MAKE_FUNCPTR(FT_New_Face);
169 MAKE_FUNCPTR(FT_New_Memory_Face);
170 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
171 MAKE_FUNCPTR(FT_Outline_Transform);
172 MAKE_FUNCPTR(FT_Outline_Translate);
173 MAKE_FUNCPTR(FT_Select_Charmap);
174 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
175 MAKE_FUNCPTR(FT_Vector_Transform);
176 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
177 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
178 static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*);
179 static FT_ULong (*pFT_Get_Next_Char)(FT_Face,FT_ULong,FT_UInt*);
180 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
181 #ifdef HAVE_FREETYPE_FTWINFNT_H
182 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
183 #endif
185 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
186 #include <fontconfig/fontconfig.h>
187 MAKE_FUNCPTR(FcConfigGetCurrent);
188 MAKE_FUNCPTR(FcFontList);
189 MAKE_FUNCPTR(FcFontSetDestroy);
190 MAKE_FUNCPTR(FcInit);
191 MAKE_FUNCPTR(FcObjectSetAdd);
192 MAKE_FUNCPTR(FcObjectSetCreate);
193 MAKE_FUNCPTR(FcObjectSetDestroy);
194 MAKE_FUNCPTR(FcPatternCreate);
195 MAKE_FUNCPTR(FcPatternDestroy);
196 MAKE_FUNCPTR(FcPatternGetBool);
197 MAKE_FUNCPTR(FcPatternGetString);
198 #ifndef SONAME_LIBFONTCONFIG
199 #define SONAME_LIBFONTCONFIG "libfontconfig.so"
200 #endif
201 #endif
203 #undef MAKE_FUNCPTR
205 #ifndef ft_encoding_none
206 #define FT_ENCODING_NONE ft_encoding_none
207 #endif
208 #ifndef ft_encoding_ms_symbol
209 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
210 #endif
211 #ifndef ft_encoding_unicode
212 #define FT_ENCODING_UNICODE ft_encoding_unicode
213 #endif
214 #ifndef ft_encoding_apple_roman
215 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
216 #endif
218 #ifdef WORDS_BIGENDIAN
219 #define GET_BE_WORD(x) (x)
220 #else
221 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
222 #endif
224 /* This is bascially a copy of FT_Bitmap_Size with an extra element added */
225 typedef struct {
226 FT_Short height;
227 FT_Short width;
228 FT_Pos size;
229 FT_Pos x_ppem;
230 FT_Pos y_ppem;
231 FT_Short internal_leading;
232 } Bitmap_Size;
234 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
235 So to let this compile on older versions of FreeType we'll define the
236 new structure here. */
237 typedef struct {
238 FT_Short height, width;
239 FT_Pos size, x_ppem, y_ppem;
240 } My_FT_Bitmap_Size;
242 typedef struct tagFace {
243 struct list entry;
244 WCHAR *StyleName;
245 char *file;
246 FT_Long face_index;
247 BOOL Italic;
248 BOOL Bold;
249 FONTSIGNATURE fs;
250 FONTSIGNATURE fs_links;
251 FT_Fixed font_version;
252 BOOL scalable;
253 Bitmap_Size size; /* set if face is a bitmap */
254 BOOL external; /* TRUE if we should manually add this font to the registry */
255 struct tagFamily *family;
256 } Face;
258 typedef struct tagFamily {
259 struct list entry;
260 const WCHAR *FamilyName;
261 struct list faces;
262 } Family;
264 typedef struct {
265 GLYPHMETRICS gm;
266 INT adv; /* These three hold to widths of the unrotated chars */
267 INT lsb;
268 INT bbx;
269 BOOL init;
270 } GM;
272 typedef struct {
273 FLOAT eM11, eM12;
274 FLOAT eM21, eM22;
275 } FMAT2;
277 typedef struct {
278 DWORD hash;
279 LOGFONTW lf;
280 FMAT2 matrix;
281 BOOL can_use_bitmap;
282 } FONT_DESC;
284 typedef struct tagHFONTLIST {
285 struct list entry;
286 HFONT hfont;
287 } HFONTLIST;
289 typedef struct {
290 struct list entry;
291 char *file_name;
292 INT index;
293 GdiFont *font;
294 } CHILD_FONT;
296 struct tagGdiFont {
297 struct list entry;
298 FT_Face ft_face;
299 struct font_mapping *mapping;
300 LPWSTR name;
301 int charset;
302 int codepage;
303 BOOL fake_italic;
304 BOOL fake_bold;
305 BYTE underline;
306 BYTE strikeout;
307 INT orientation;
308 GM *gm;
309 DWORD gmsize;
310 struct list hfontlist;
311 FONT_DESC font_desc;
312 LONG aveWidth;
313 SHORT yMax;
314 SHORT yMin;
315 OUTLINETEXTMETRICW *potm;
316 DWORD total_kern_pairs;
317 KERNINGPAIR *kern_pairs;
318 FONTSIGNATURE fs;
319 GdiFont *base_font;
320 struct list child_fonts;
321 LONG ppem;
324 typedef struct {
325 struct list entry;
326 const WCHAR *font_name;
327 struct list links;
328 } SYSTEM_LINKS;
330 #define INIT_GM_SIZE 128
332 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
333 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
334 #define UNUSED_CACHE_SIZE 10
335 static struct list child_font_list = LIST_INIT(child_font_list);
336 static struct list system_links = LIST_INIT(system_links);
338 static struct list font_subst_list = LIST_INIT(font_subst_list);
340 static struct list font_list = LIST_INIT(font_list);
342 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
343 static const WCHAR defSans[] = {'M','S',' ','S','a','n','s',' ','S','e','r','i','f','\0'};
344 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
346 static const WCHAR RegularW[] = {'R','e','g','u','l','a','r','\0'};
348 static const WCHAR fontsW[] = {'\\','F','o','n','t','s','\0'};
349 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
350 'W','i','n','d','o','w','s','\\',
351 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
352 'F','o','n','t','s','\0'};
354 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
355 'W','i','n','d','o','w','s',' ','N','T','\\',
356 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
357 'F','o','n','t','s','\0'};
359 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
360 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
361 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
362 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
364 static const WCHAR * const SystemFontValues[4] = {
365 System_Value,
366 OEMFont_Value,
367 FixedSys_Value,
368 NULL
371 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
372 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
374 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
375 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
376 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
377 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
378 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
379 'E','u','r','o','p','e','a','n','\0'};
380 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
381 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
382 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
383 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
384 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
385 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
386 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
387 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
388 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
389 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
390 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
391 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
393 static const WCHAR * const ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
394 WesternW, /*00*/
395 Central_EuropeanW,
396 CyrillicW,
397 GreekW,
398 TurkishW,
399 HebrewW,
400 ArabicW,
401 BalticW,
402 VietnameseW, /*08*/
403 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
404 ThaiW,
405 JapaneseW,
406 CHINESE_GB2312W,
407 HangulW,
408 CHINESE_BIG5W,
409 Hangul_Johab_W,
410 NULL, NULL, /*23*/
411 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
412 SymbolW /*31*/
415 typedef struct {
416 WCHAR *name;
417 INT charset;
418 } NameCs;
420 typedef struct tagFontSubst {
421 struct list entry;
422 NameCs from;
423 NameCs to;
424 } FontSubst;
426 struct font_mapping
428 struct list entry;
429 int refcount;
430 dev_t dev;
431 ino_t ino;
432 void *data;
433 size_t size;
436 static struct list mappings_list = LIST_INIT( mappings_list );
438 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
440 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
443 /****************************************
444 * Notes on .fon files
446 * The fonts System, FixedSys and Terminal are special. There are typically multiple
447 * versions installed for different resolutions and codepages. Windows stores which one to use
448 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
449 * Key Meaning
450 * FIXEDFON.FON FixedSys
451 * FONTS.FON System
452 * OEMFONT.FON Terminal
453 * LogPixels Current dpi set by the display control panel applet
454 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
455 * also has a LogPixels value that appears to mirror this)
457 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
458 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
459 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
460 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
461 * so that makes sense.
463 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
464 * to be mapped into the registry on Windows 2000 at least).
465 * I have
466 * woafont=app850.fon
467 * ega80woa.fon=ega80850.fon
468 * ega40woa.fon=ega40850.fon
469 * cga80woa.fon=cga80850.fon
470 * cga40woa.fon=cga40850.fon
473 #ifdef HAVE_CARBON_CARBON_H
474 static char *find_cache_dir(void)
476 FSRef ref;
477 OSErr err;
478 static char cached_path[MAX_PATH];
479 static const char *wine = "/Wine", *fonts = "/Fonts";
481 if(*cached_path) return cached_path;
483 err = FSFindFolder(kUserDomain, kCachedDataFolderType, kCreateFolder, &ref);
484 if(err != noErr)
486 WARN("can't create cached data folder\n");
487 return NULL;
489 err = FSRefMakePath(&ref, (unsigned char*)cached_path, sizeof(cached_path));
490 if(err != noErr)
492 WARN("can't create cached data path\n");
493 *cached_path = '\0';
494 return NULL;
496 if(strlen(cached_path) + strlen(wine) + strlen(fonts) + 1 > sizeof(cached_path))
498 ERR("Could not create full path\n");
499 *cached_path = '\0';
500 return NULL;
502 strcat(cached_path, wine);
504 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
506 WARN("Couldn't mkdir %s\n", cached_path);
507 *cached_path = '\0';
508 return NULL;
510 strcat(cached_path, fonts);
511 if(mkdir(cached_path, 0700) == -1 && errno != EEXIST)
513 WARN("Couldn't mkdir %s\n", cached_path);
514 *cached_path = '\0';
515 return NULL;
517 return cached_path;
520 /******************************************************************
521 * expand_mac_font
523 * Extracts individual TrueType font files from a Mac suitcase font
524 * and saves them into the user's caches directory (see
525 * find_cache_dir()).
526 * Returns a NULL terminated array of filenames.
528 * We do this because they are apps that try to read ttf files
529 * themselves and they don't like Mac suitcase files.
531 static char **expand_mac_font(const char *path)
533 FSRef ref;
534 SInt16 res_ref;
535 OSStatus s;
536 unsigned int idx;
537 const char *out_dir;
538 const char *filename;
539 int output_len;
540 struct {
541 char **array;
542 unsigned int size, max_size;
543 } ret;
545 TRACE("path %s\n", path);
547 s = FSPathMakeRef((unsigned char*)path, &ref, FALSE);
548 if(s != noErr)
550 WARN("failed to get ref\n");
551 return NULL;
554 s = FSOpenResourceFile(&ref, 0, NULL, fsRdPerm, &res_ref);
555 if(s != noErr)
557 TRACE("no data fork, so trying resource fork\n");
558 res_ref = FSOpenResFile(&ref, fsRdPerm);
559 if(res_ref == -1)
561 TRACE("unable to open resource fork\n");
562 return NULL;
566 ret.size = 0;
567 ret.max_size = 10;
568 ret.array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.max_size * sizeof(*ret.array));
569 if(!ret.array)
571 CloseResFile(res_ref);
572 return NULL;
575 out_dir = find_cache_dir();
577 filename = strrchr(path, '/');
578 if(!filename) filename = path;
579 else filename++;
581 /* output filename has the form out_dir/filename_%04x.ttf */
582 output_len = strlen(out_dir) + 1 + strlen(filename) + 5 + 5;
584 UseResFile(res_ref);
585 idx = 1;
586 while(1)
588 FamRec *fam_rec;
589 unsigned short *num_faces_ptr, num_faces, face;
590 AsscEntry *assoc;
591 Handle fond;
593 fond = Get1IndResource('FOND', idx);
594 if(!fond) break;
595 TRACE("got fond resource %d\n", idx);
596 HLock(fond);
598 fam_rec = *(FamRec**)fond;
599 num_faces_ptr = (unsigned short *)(fam_rec + 1);
600 num_faces = GET_BE_WORD(*num_faces_ptr);
601 num_faces++;
602 assoc = (AsscEntry*)(num_faces_ptr + 1);
603 TRACE("num faces %04x\n", num_faces);
604 for(face = 0; face < num_faces; face++, assoc++)
606 Handle sfnt;
607 unsigned short size, font_id;
608 char *output;
610 size = GET_BE_WORD(assoc->fontSize);
611 font_id = GET_BE_WORD(assoc->fontID);
612 if(size != 0)
614 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id, size);
615 continue;
618 TRACE("trying to load sfnt id %04x\n", font_id);
619 sfnt = GetResource('sfnt', font_id);
620 if(!sfnt)
622 TRACE("can't get sfnt resource %04x\n", font_id);
623 continue;
626 output = HeapAlloc(GetProcessHeap(), 0, output_len);
627 if(output)
629 int fd;
631 sprintf(output, "%s/%s_%04x.ttf", out_dir, filename, font_id);
633 fd = open(output, O_CREAT | O_EXCL | O_WRONLY, 0600);
634 if(fd != -1 || errno == EEXIST)
636 if(fd != -1)
638 unsigned char *sfnt_data;
640 HLock(sfnt);
641 sfnt_data = *(unsigned char**)sfnt;
642 write(fd, sfnt_data, GetHandleSize(sfnt));
643 HUnlock(sfnt);
644 close(fd);
646 if(ret.size >= ret.max_size - 1) /* Always want the last element to be NULL */
648 ret.max_size *= 2;
649 ret.array = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ret.array, ret.max_size * sizeof(*ret.array));
651 ret.array[ret.size++] = output;
653 else
655 WARN("unable to create %s\n", output);
656 HeapFree(GetProcessHeap(), 0, output);
659 ReleaseResource(sfnt);
661 HUnlock(fond);
662 ReleaseResource(fond);
663 idx++;
665 CloseResFile(res_ref);
667 return ret.array;
670 #endif /* HAVE_CARBON_CARBON_H */
672 static inline BOOL is_win9x(void)
674 return GetVersion() & 0x80000000;
677 This function builds an FT_Fixed from a float. It puts the integer part
678 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
679 It fails if the integer part of the float number is greater than SHORT_MAX.
681 static inline FT_Fixed FT_FixedFromFloat(float f)
683 short value = f;
684 unsigned short fract = (f - value) * 0xFFFF;
685 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
689 This function builds an FT_Fixed from a FIXED. It simply put f.value
690 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
692 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
694 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
698 static Face *find_face_from_filename(const WCHAR *file_name, const WCHAR *face_name)
700 Family *family;
701 Face *face;
702 const char *file;
703 DWORD len = WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, NULL, 0, NULL, NULL);
704 char *file_nameA = HeapAlloc(GetProcessHeap(), 0, len);
706 WideCharToMultiByte(CP_UNIXCP, 0, file_name, -1, file_nameA, len, NULL, NULL);
707 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA), debugstr_w(face_name));
709 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
711 if(face_name && strcmpiW(face_name, family->FamilyName))
712 continue;
713 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
715 file = strrchr(face->file, '/');
716 if(!file)
717 file = face->file;
718 else
719 file++;
720 if(!strcasecmp(file, file_nameA))
722 HeapFree(GetProcessHeap(), 0, file_nameA);
723 return face;
727 HeapFree(GetProcessHeap(), 0, file_nameA);
728 return NULL;
731 static Family *find_family_from_name(const WCHAR *name)
733 Family *family;
735 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
737 if(!strcmpiW(family->FamilyName, name))
738 return family;
741 return NULL;
744 static Face *find_face_from_path_index(const CHAR *file_name, const INT index)
746 Family *family;
747 Face *face;
749 TRACE("looking for file %s index %i\n", debugstr_a(file_name), index);
751 LIST_FOR_EACH_ENTRY(family, &font_list, Family, entry)
753 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
755 if(!strcasecmp(face->file, file_name) && face->face_index == index)
756 return face;
759 return NULL;
762 static void DumpSubstList(void)
764 FontSubst *psub;
766 LIST_FOR_EACH_ENTRY(psub, &font_subst_list, FontSubst, entry)
768 if(psub->from.charset != -1 || psub->to.charset != -1)
769 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
770 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
771 else
772 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
773 debugstr_w(psub->to.name));
775 return;
778 static LPWSTR strdupW(LPCWSTR p)
780 LPWSTR ret;
781 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
782 ret = HeapAlloc(GetProcessHeap(), 0, len);
783 memcpy(ret, p, len);
784 return ret;
787 static LPSTR strdupA(LPCSTR p)
789 LPSTR ret;
790 DWORD len = (strlen(p) + 1);
791 ret = HeapAlloc(GetProcessHeap(), 0, len);
792 memcpy(ret, p, len);
793 return ret;
796 static FontSubst *get_font_subst(const struct list *subst_list, const WCHAR *from_name,
797 INT from_charset)
799 FontSubst *element;
801 LIST_FOR_EACH_ENTRY(element, subst_list, FontSubst, entry)
803 if(!strcmpiW(element->from.name, from_name) &&
804 (element->from.charset == from_charset ||
805 element->from.charset == -1))
806 return element;
809 return NULL;
812 #define ADD_FONT_SUBST_FORCE 1
814 static BOOL add_font_subst(struct list *subst_list, FontSubst *subst, INT flags)
816 FontSubst *from_exist, *to_exist;
818 from_exist = get_font_subst(subst_list, subst->from.name, subst->from.charset);
820 if(from_exist && (flags & ADD_FONT_SUBST_FORCE))
822 list_remove(&from_exist->entry);
823 HeapFree(GetProcessHeap(), 0, &from_exist->from.name);
824 HeapFree(GetProcessHeap(), 0, &from_exist->to.name);
825 HeapFree(GetProcessHeap(), 0, from_exist);
826 from_exist = NULL;
829 if(!from_exist)
831 to_exist = get_font_subst(subst_list, subst->to.name, subst->to.charset);
833 if(to_exist)
835 HeapFree(GetProcessHeap(), 0, subst->to.name);
836 subst->to.name = strdupW(to_exist->to.name);
839 list_add_tail(subst_list, &subst->entry);
841 return TRUE;
844 HeapFree(GetProcessHeap(), 0, subst->from.name);
845 HeapFree(GetProcessHeap(), 0, subst->to.name);
846 HeapFree(GetProcessHeap(), 0, subst);
847 return FALSE;
850 static void split_subst_info(NameCs *nc, LPSTR str)
852 CHAR *p = strrchr(str, ',');
853 DWORD len;
855 nc->charset = -1;
856 if(p && *(p+1)) {
857 nc->charset = strtol(p+1, NULL, 10);
858 *p = '\0';
860 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
861 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
862 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
865 static void LoadSubstList(void)
867 FontSubst *psub;
868 HKEY hkey;
869 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
870 LPSTR value;
871 LPVOID data;
873 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
874 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
875 &hkey) == ERROR_SUCCESS) {
877 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
878 &valuelen, &datalen, NULL, NULL);
880 valuelen++; /* returned value doesn't include room for '\0' */
881 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
882 data = HeapAlloc(GetProcessHeap(), 0, datalen);
884 dlen = datalen;
885 vlen = valuelen;
886 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
887 &dlen) == ERROR_SUCCESS) {
888 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
890 psub = HeapAlloc(GetProcessHeap(), 0, sizeof(*psub));
891 split_subst_info(&psub->from, value);
892 split_subst_info(&psub->to, data);
894 /* Win 2000 doesn't allow mapping between different charsets
895 or mapping of DEFAULT_CHARSET */
896 if((psub->to.charset != psub->from.charset) ||
897 psub->to.charset == DEFAULT_CHARSET) {
898 HeapFree(GetProcessHeap(), 0, psub->to.name);
899 HeapFree(GetProcessHeap(), 0, psub->from.name);
900 HeapFree(GetProcessHeap(), 0, psub);
901 } else {
902 add_font_subst(&font_subst_list, psub, 0);
904 /* reset dlen and vlen */
905 dlen = datalen;
906 vlen = valuelen;
908 HeapFree(GetProcessHeap(), 0, data);
909 HeapFree(GetProcessHeap(), 0, value);
910 RegCloseKey(hkey);
914 static WCHAR *get_familyname(FT_Face ft_face)
916 WCHAR *family = NULL;
917 FT_SfntName name;
918 FT_UInt num_names, name_index, i;
920 if(FT_IS_SFNT(ft_face))
922 num_names = pFT_Get_Sfnt_Name_Count(ft_face);
924 for(name_index = 0; name_index < num_names; name_index++)
926 if(!pFT_Get_Sfnt_Name(ft_face, name_index, &name))
928 if((name.name_id == TT_NAME_ID_FONT_FAMILY) &&
929 (name.language_id == GetUserDefaultLCID()) &&
930 (name.platform_id == TT_PLATFORM_MICROSOFT) &&
931 (name.encoding_id == TT_MS_ID_UNICODE_CS))
933 /* String is not nul terminated and string_len is a byte length. */
934 family = HeapAlloc(GetProcessHeap(), 0, name.string_len + 2);
935 for(i = 0; i < name.string_len / 2; i++)
937 WORD *tmp = (WORD *)&name.string[i * 2];
938 family[i] = GET_BE_WORD(*tmp);
940 family[i] = 0;
942 TRACE("Got localised name %s\n", debugstr_w(family));
943 return family;
949 return NULL;
953 #define ADDFONT_EXTERNAL_FONT 0x01
954 #define ADDFONT_FORCE_BITMAP 0x02
955 static BOOL AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags)
957 FT_Face ft_face;
958 TT_OS2 *pOS2;
959 TT_Header *pHeader = NULL;
960 WCHAR *english_family, *localised_family, *StyleW;
961 DWORD len;
962 Family *family;
963 Face *face;
964 struct list *family_elem_ptr, *face_elem_ptr;
965 FT_Error err;
966 FT_Long face_index = 0, num_faces;
967 #ifdef HAVE_FREETYPE_FTWINFNT_H
968 FT_WinFNT_HeaderRec winfnt_header;
969 #endif
970 int i, bitmap_num, internal_leading;
971 FONTSIGNATURE fs;
973 #ifdef HAVE_CARBON_CARBON_H
974 if(!fake_family)
976 char **mac_list = expand_mac_font(file);
977 if(mac_list)
979 BOOL had_one = FALSE;
980 char **cursor;
981 for(cursor = mac_list; *cursor; cursor++)
983 had_one = TRUE;
984 AddFontFileToList(*cursor, NULL, NULL, flags);
985 HeapFree(GetProcessHeap(), 0, *cursor);
987 HeapFree(GetProcessHeap(), 0, mac_list);
988 if(had_one)
989 return TRUE;
992 #endif /* HAVE_CARBON_CARBON_H */
994 do {
995 char *family_name = fake_family;
997 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
998 if((err = pFT_New_Face(library, file, face_index, &ft_face)) != 0) {
999 WARN("Unable to load font file %s err = %x\n", debugstr_a(file), err);
1000 return FALSE;
1003 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*/
1004 WARN("Ignoring font %s\n", debugstr_a(file));
1005 pFT_Done_Face(ft_face);
1006 return FALSE;
1009 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1010 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
1011 WARN("FreeType version < 2.1.9, skipping bitmap font %s\n", debugstr_a(file));
1012 pFT_Done_Face(ft_face);
1013 return FALSE;
1016 if(FT_IS_SFNT(ft_face) && (!pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2) ||
1017 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
1018 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))) {
1019 TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
1020 "Skipping this font.\n", debugstr_a(file));
1021 pFT_Done_Face(ft_face);
1022 return FALSE;
1025 if(!ft_face->family_name || !ft_face->style_name) {
1026 TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file));
1027 pFT_Done_Face(ft_face);
1028 return FALSE;
1031 if (target_family)
1033 localised_family = get_familyname(ft_face);
1034 if (localised_family && lstrcmpW(localised_family,target_family)!=0)
1036 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT)face_index);
1037 HeapFree(GetProcessHeap(), 0, localised_family);
1038 num_faces = ft_face->num_faces;
1039 pFT_Done_Face(ft_face);
1040 continue;
1042 HeapFree(GetProcessHeap(), 0, localised_family);
1045 if(!family_name)
1046 family_name = ft_face->family_name;
1048 bitmap_num = 0;
1049 do {
1050 My_FT_Bitmap_Size *size = NULL;
1052 if(!FT_IS_SCALABLE(ft_face))
1053 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
1055 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
1056 english_family = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1057 MultiByteToWideChar(CP_ACP, 0, family_name, -1, english_family, len);
1059 localised_family = NULL;
1060 if(!fake_family) {
1061 localised_family = get_familyname(ft_face);
1062 if(localised_family && !strcmpW(localised_family, english_family)) {
1063 HeapFree(GetProcessHeap(), 0, localised_family);
1064 localised_family = NULL;
1068 family = NULL;
1069 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1070 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1071 if(!strcmpW(family->FamilyName, localised_family ? localised_family : english_family))
1072 break;
1073 family = NULL;
1075 if(!family) {
1076 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
1077 family->FamilyName = strdupW(localised_family ? localised_family : english_family);
1078 list_init(&family->faces);
1079 list_add_tail(&font_list, &family->entry);
1081 if(localised_family) {
1082 FontSubst *subst = HeapAlloc(GetProcessHeap(), 0, sizeof(*subst));
1083 subst->from.name = strdupW(english_family);
1084 subst->from.charset = -1;
1085 subst->to.name = strdupW(localised_family);
1086 subst->to.charset = -1;
1087 add_font_subst(&font_subst_list, subst, 0);
1090 HeapFree(GetProcessHeap(), 0, localised_family);
1091 HeapFree(GetProcessHeap(), 0, english_family);
1093 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
1094 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1095 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
1097 internal_leading = 0;
1098 memset(&fs, 0, sizeof(fs));
1100 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1101 if(pOS2) {
1102 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1103 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1104 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1105 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1106 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1107 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1108 if(pOS2->version == 0) {
1109 FT_UInt dummy;
1111 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
1112 fs.fsCsb[0] |= 1;
1113 else
1114 fs.fsCsb[0] |= 1L << 31;
1117 #ifdef HAVE_FREETYPE_FTWINFNT_H
1118 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
1119 CHARSETINFO csi;
1120 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
1121 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
1122 if(TranslateCharsetInfo((DWORD*)(UINT_PTR)winfnt_header.charset, &csi, TCI_SRCCHARSET))
1123 memcpy(&fs, &csi.fs, sizeof(csi.fs));
1124 internal_leading = winfnt_header.internal_leading;
1126 #endif
1128 face_elem_ptr = list_head(&family->faces);
1129 while(face_elem_ptr) {
1130 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1131 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
1132 if(!strcmpW(face->StyleName, StyleW) &&
1133 (FT_IS_SCALABLE(ft_face) || ((size->y_ppem == face->size.y_ppem) && !memcmp(&fs, &face->fs, sizeof(fs)) ))) {
1134 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1135 debugstr_w(family->FamilyName), debugstr_w(StyleW),
1136 face->font_version, pHeader ? pHeader->Font_Revision : 0);
1138 if(fake_family) {
1139 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1140 HeapFree(GetProcessHeap(), 0, StyleW);
1141 pFT_Done_Face(ft_face);
1142 return FALSE;
1144 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
1145 TRACE("Original font is newer so skipping this one\n");
1146 HeapFree(GetProcessHeap(), 0, StyleW);
1147 pFT_Done_Face(ft_face);
1148 return FALSE;
1149 } else {
1150 TRACE("Replacing original with this one\n");
1151 list_remove(&face->entry);
1152 HeapFree(GetProcessHeap(), 0, face->file);
1153 HeapFree(GetProcessHeap(), 0, face->StyleName);
1154 HeapFree(GetProcessHeap(), 0, face);
1155 break;
1159 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
1160 list_add_tail(&family->faces, &face->entry);
1161 face->StyleName = StyleW;
1162 face->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
1163 strcpy(face->file, file);
1164 face->face_index = face_index;
1165 face->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
1166 face->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
1167 face->font_version = pHeader ? pHeader->Font_Revision : 0;
1168 face->family = family;
1169 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
1170 memcpy(&face->fs, &fs, sizeof(face->fs));
1171 memset(&face->fs_links, 0, sizeof(face->fs_links));
1173 if(FT_IS_SCALABLE(ft_face)) {
1174 memset(&face->size, 0, sizeof(face->size));
1175 face->scalable = TRUE;
1176 } else {
1177 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1178 size->height, size->width, size->size >> 6,
1179 size->x_ppem >> 6, size->y_ppem >> 6);
1180 face->size.height = size->height;
1181 face->size.width = size->width;
1182 face->size.size = size->size;
1183 face->size.x_ppem = size->x_ppem;
1184 face->size.y_ppem = size->y_ppem;
1185 face->size.internal_leading = internal_leading;
1186 face->scalable = FALSE;
1189 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1190 face->fs.fsCsb[0], face->fs.fsCsb[1],
1191 face->fs.fsUsb[0], face->fs.fsUsb[1],
1192 face->fs.fsUsb[2], face->fs.fsUsb[3]);
1195 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
1196 for(i = 0; i < ft_face->num_charmaps; i++) {
1197 switch(ft_face->charmaps[i]->encoding) {
1198 case FT_ENCODING_UNICODE:
1199 case FT_ENCODING_APPLE_ROMAN:
1200 face->fs.fsCsb[0] |= 1;
1201 break;
1202 case FT_ENCODING_MS_SYMBOL:
1203 face->fs.fsCsb[0] |= 1L << 31;
1204 break;
1205 default:
1206 break;
1211 if(face->fs.fsCsb[0] & ~(1L << 31))
1212 have_installed_roman_font = TRUE;
1213 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
1215 num_faces = ft_face->num_faces;
1216 pFT_Done_Face(ft_face);
1217 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
1218 debugstr_w(StyleW));
1219 } while(num_faces > ++face_index);
1220 return TRUE;
1223 static void DumpFontList(void)
1225 Family *family;
1226 Face *face;
1227 struct list *family_elem_ptr, *face_elem_ptr;
1229 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1230 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1231 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
1232 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1233 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1234 TRACE("\t%s\t%08x", debugstr_w(face->StyleName), face->fs.fsCsb[0]);
1235 if(!face->scalable)
1236 TRACE(" %d", face->size.height);
1237 TRACE("\n");
1240 return;
1243 /***********************************************************
1244 * The replacement list is a way to map an entire font
1245 * family onto another family. For example adding
1247 * [HKCU\Software\Wine\Fonts\Replacements]
1248 * "Wingdings"="Winedings"
1250 * would enumerate the Winedings font both as Winedings and
1251 * Wingdings. However if a real Wingdings font is present the
1252 * replacement does not take place.
1255 static void LoadReplaceList(void)
1257 HKEY hkey;
1258 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1259 LPWSTR value;
1260 LPVOID data;
1261 Family *family;
1262 Face *face;
1263 struct list *family_elem_ptr, *face_elem_ptr;
1264 CHAR familyA[400];
1266 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1267 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey) == ERROR_SUCCESS)
1269 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1270 &valuelen, &datalen, NULL, NULL);
1272 valuelen++; /* returned value doesn't include room for '\0' */
1273 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1274 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1276 dlen = datalen;
1277 vlen = valuelen;
1278 while(RegEnumValueW(hkey, i++, value, &vlen, NULL, &type, data,
1279 &dlen) == ERROR_SUCCESS) {
1280 TRACE("Got %s=%s\n", debugstr_w(value), debugstr_w(data));
1281 /* "NewName"="Oldname" */
1282 WideCharToMultiByte(CP_ACP, 0, value, -1, familyA, sizeof(familyA), NULL, NULL);
1284 /* Find the old family and hence all of the font files
1285 in that family */
1286 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1287 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1288 if(!strcmpiW(family->FamilyName, data)) {
1289 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1290 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1291 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
1292 debugstr_w(face->StyleName), familyA);
1293 /* Now add a new entry with the new family name */
1294 AddFontFileToList(face->file, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
1296 break;
1299 /* reset dlen and vlen */
1300 dlen = datalen;
1301 vlen = valuelen;
1303 HeapFree(GetProcessHeap(), 0, data);
1304 HeapFree(GetProcessHeap(), 0, value);
1305 RegCloseKey(hkey);
1309 /*************************************************************
1310 * init_system_links
1312 static BOOL init_system_links(void)
1314 static const WCHAR system_link[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1315 'W','i','n','d','o','w','s',' ','N','T','\\',
1316 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1317 'S','y','s','t','e','m','L','i','n','k',0};
1318 HKEY hkey;
1319 BOOL ret = FALSE;
1320 DWORD type, max_val, max_data, val_len, data_len, index;
1321 WCHAR *value, *data;
1322 WCHAR *entry, *next;
1323 SYSTEM_LINKS *font_link, *system_font_link;
1324 CHILD_FONT *child_font;
1325 static const WCHAR Tahoma[] = {'T','a','h','o','m','a',0};
1326 static const WCHAR tahoma_ttf[] = {'t','a','h','o','m','a','.','t','t','f',0};
1327 static const WCHAR System[] = {'S','y','s','t','e','m',0};
1328 FONTSIGNATURE fs;
1329 Family *family;
1330 Face *face;
1331 FontSubst *psub;
1333 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
1335 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val, &max_data, NULL, NULL);
1336 value = HeapAlloc(GetProcessHeap(), 0, (max_val + 1) * sizeof(WCHAR));
1337 data = HeapAlloc(GetProcessHeap(), 0, max_data);
1338 val_len = max_val + 1;
1339 data_len = max_data;
1340 index = 0;
1341 while(RegEnumValueW(hkey, index++, value, &val_len, NULL, &type, (LPBYTE)data, &data_len) == ERROR_SUCCESS)
1343 TRACE("%s:\n", debugstr_w(value));
1345 memset(&fs, 0, sizeof(fs));
1346 font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link));
1347 psub = get_font_subst(&font_subst_list, value, -1);
1348 font_link->font_name = (psub)? strdupW(psub->to.name) : strdupW(value);
1349 list_init(&font_link->links);
1350 for(entry = data; (char*)entry < (char*)data + data_len && *entry != 0; entry = next)
1352 WCHAR *face_name;
1353 CHILD_FONT *child_font;
1355 TRACE("\t%s\n", debugstr_w(entry));
1357 next = entry + strlenW(entry) + 1;
1359 face_name = strchrW(entry, ',');
1360 if(face_name)
1362 *face_name++ = 0;
1363 while(isspaceW(*face_name))
1364 face_name++;
1366 psub = get_font_subst(&font_subst_list, face_name, -1);
1367 if(psub)
1368 face_name = psub->to.name;
1370 face = find_face_from_filename(entry, face_name);
1371 if(!face)
1373 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry), debugstr_w(face_name));
1374 continue;
1377 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1378 child_font->file_name = strdupA(face->file);
1379 child_font->index = face->face_index;
1380 child_font->font = NULL;
1381 fs.fsCsb[0] |= face->fs.fsCsb[0];
1382 fs.fsCsb[1] |= face->fs.fsCsb[1];
1383 TRACE("Adding file %s index %d\n", child_font->file_name, child_font->index);
1384 list_add_tail(&font_link->links, &child_font->entry);
1386 family = find_family_from_name(font_link->font_name);
1387 if(family)
1389 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
1391 memcpy(&face->fs_links, &fs, sizeof(fs));
1394 list_add_tail(&system_links, &font_link->entry);
1395 val_len = max_val + 1;
1396 data_len = max_data;
1399 HeapFree(GetProcessHeap(), 0, value);
1400 HeapFree(GetProcessHeap(), 0, data);
1401 RegCloseKey(hkey);
1404 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1405 that Tahoma has */
1407 system_font_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link));
1408 system_font_link->font_name = strdupW(System);
1409 list_init(&system_font_link->links);
1411 face = find_face_from_filename(tahoma_ttf, Tahoma);
1412 if(face)
1414 child_font = HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font));
1415 child_font->file_name = strdupA(face->file);
1416 child_font->index = face->face_index;
1417 child_font->font = NULL;
1418 TRACE("Found Tahoma in %s index %d\n", child_font->file_name, child_font->index);
1419 list_add_tail(&system_font_link->links, &child_font->entry);
1421 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
1423 if(!strcmpiW(font_link->font_name, Tahoma))
1425 CHILD_FONT *font_link_entry;
1426 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
1428 CHILD_FONT *new_child;
1429 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
1430 new_child->file_name = strdupA(font_link_entry->file_name);
1431 new_child->index = font_link_entry->index;
1432 new_child->font = NULL;
1433 list_add_tail(&system_font_link->links, &new_child->entry);
1435 break;
1438 list_add_tail(&system_links, &system_font_link->entry);
1439 return ret;
1442 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
1444 DIR *dir;
1445 struct dirent *dent;
1446 char path[MAX_PATH];
1448 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
1450 dir = opendir(dirname);
1451 if(!dir) {
1452 WARN("Can't open directory %s\n", debugstr_a(dirname));
1453 return FALSE;
1455 while((dent = readdir(dir)) != NULL) {
1456 struct stat statbuf;
1458 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1459 continue;
1461 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
1463 sprintf(path, "%s/%s", dirname, dent->d_name);
1465 if(stat(path, &statbuf) == -1)
1467 WARN("Can't stat %s\n", debugstr_a(path));
1468 continue;
1470 if(S_ISDIR(statbuf.st_mode))
1471 ReadFontDir(path, external_fonts);
1472 else
1473 AddFontFileToList(path, NULL, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
1475 closedir(dir);
1476 return TRUE;
1479 static void load_fontconfig_fonts(void)
1481 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
1482 void *fc_handle = NULL;
1483 FcConfig *config;
1484 FcPattern *pat;
1485 FcObjectSet *os;
1486 FcFontSet *fontset;
1487 int i, len;
1488 char *file;
1489 const char *ext;
1491 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
1492 if(!fc_handle) {
1493 TRACE("Wine cannot find the fontconfig library (%s).\n",
1494 SONAME_LIBFONTCONFIG);
1495 return;
1497 #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;}
1498 LOAD_FUNCPTR(FcConfigGetCurrent);
1499 LOAD_FUNCPTR(FcFontList);
1500 LOAD_FUNCPTR(FcFontSetDestroy);
1501 LOAD_FUNCPTR(FcInit);
1502 LOAD_FUNCPTR(FcObjectSetAdd);
1503 LOAD_FUNCPTR(FcObjectSetCreate);
1504 LOAD_FUNCPTR(FcObjectSetDestroy);
1505 LOAD_FUNCPTR(FcPatternCreate);
1506 LOAD_FUNCPTR(FcPatternDestroy);
1507 LOAD_FUNCPTR(FcPatternGetBool);
1508 LOAD_FUNCPTR(FcPatternGetString);
1509 #undef LOAD_FUNCPTR
1511 if(!pFcInit()) return;
1513 config = pFcConfigGetCurrent();
1514 pat = pFcPatternCreate();
1515 os = pFcObjectSetCreate();
1516 pFcObjectSetAdd(os, FC_FILE);
1517 pFcObjectSetAdd(os, FC_SCALABLE);
1518 fontset = pFcFontList(config, pat, os);
1519 if(!fontset) return;
1520 for(i = 0; i < fontset->nfont; i++) {
1521 FcBool scalable;
1523 if(pFcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch)
1524 continue;
1525 TRACE("fontconfig: %s\n", file);
1527 /* We're just interested in OT/TT fonts for now, so this hack just
1528 picks up the scalable fonts without extensions .pf[ab] to save time
1529 loading every other font */
1531 if(pFcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable)
1533 TRACE("not scalable\n");
1534 continue;
1537 len = strlen( file );
1538 if(len < 4) continue;
1539 ext = &file[ len - 3 ];
1540 if(strcasecmp(ext, "pfa") && strcasecmp(ext, "pfb"))
1541 AddFontFileToList(file, NULL, NULL, ADDFONT_EXTERNAL_FONT);
1543 pFcFontSetDestroy(fontset);
1544 pFcObjectSetDestroy(os);
1545 pFcPatternDestroy(pat);
1546 sym_not_found:
1547 #endif
1548 return;
1551 static BOOL load_font_from_data_dir(LPCWSTR file)
1553 BOOL ret = FALSE;
1554 const char *data_dir = wine_get_data_dir();
1556 if (!data_dir) data_dir = wine_get_build_dir();
1558 if (data_dir)
1560 INT len;
1561 char *unix_name;
1563 len = WideCharToMultiByte(CP_UNIXCP, 0, file, -1, NULL, 0, NULL, NULL);
1565 unix_name = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + len + sizeof("/fonts/"));
1567 strcpy(unix_name, data_dir);
1568 strcat(unix_name, "/fonts/");
1570 WideCharToMultiByte(CP_UNIXCP, 0, file, -1, unix_name + strlen(unix_name), len, NULL, NULL);
1572 ret = AddFontFileToList(unix_name, NULL, NULL, ADDFONT_FORCE_BITMAP);
1573 HeapFree(GetProcessHeap(), 0, unix_name);
1575 return ret;
1578 static void load_system_fonts(void)
1580 HKEY hkey;
1581 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
1582 const WCHAR * const *value;
1583 DWORD dlen, type;
1584 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1585 char *unixname;
1587 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
1588 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1589 strcatW(windowsdir, fontsW);
1590 for(value = SystemFontValues; *value; value++) {
1591 dlen = sizeof(data);
1592 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
1593 type == REG_SZ) {
1594 BOOL added = FALSE;
1596 sprintfW(pathW, fmtW, windowsdir, data);
1597 if((unixname = wine_get_unix_file_name(pathW))) {
1598 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1599 HeapFree(GetProcessHeap(), 0, unixname);
1601 if (!added)
1602 load_font_from_data_dir(data);
1605 RegCloseKey(hkey);
1609 /*************************************************************
1611 * This adds registry entries for any externally loaded fonts
1612 * (fonts from fontconfig or FontDirs). It also deletes entries
1613 * of no longer existing fonts.
1616 static void update_reg_entries(void)
1618 HKEY winkey = 0, externalkey = 0;
1619 LPWSTR valueW;
1620 LPVOID data;
1621 DWORD dlen, vlen, datalen, valuelen, i, type, len, len_fam;
1622 Family *family;
1623 Face *face;
1624 struct list *family_elem_ptr, *face_elem_ptr;
1625 WCHAR *file;
1626 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1627 static const WCHAR spaceW[] = {' ', '\0'};
1628 char *path;
1630 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1631 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winkey, NULL) != ERROR_SUCCESS) {
1632 ERR("Can't create Windows font reg key\n");
1633 goto end;
1635 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1636 if(RegCreateKeyW(HKEY_CURRENT_USER, external_fonts_reg_key, &externalkey) != ERROR_SUCCESS) {
1637 ERR("Can't create external font reg key\n");
1638 goto end;
1641 /* Delete all external fonts added last time */
1643 RegQueryInfoKeyW(externalkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1644 &valuelen, &datalen, NULL, NULL);
1645 valuelen++; /* returned value doesn't include room for '\0' */
1646 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1647 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1649 dlen = datalen * sizeof(WCHAR);
1650 vlen = valuelen;
1651 i = 0;
1652 while(RegEnumValueW(externalkey, i++, valueW, &vlen, NULL, &type, data,
1653 &dlen) == ERROR_SUCCESS) {
1655 RegDeleteValueW(winkey, valueW);
1656 /* reset dlen and vlen */
1657 dlen = datalen;
1658 vlen = valuelen;
1660 HeapFree(GetProcessHeap(), 0, data);
1661 HeapFree(GetProcessHeap(), 0, valueW);
1663 /* Delete the old external fonts key */
1664 RegCloseKey(externalkey);
1665 externalkey = 0;
1666 RegDeleteKeyW(HKEY_CURRENT_USER, external_fonts_reg_key);
1668 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1669 if(RegCreateKeyExW(HKEY_CURRENT_USER, external_fonts_reg_key,
1670 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
1671 ERR("Can't create external font reg key\n");
1672 goto end;
1675 /* enumerate the fonts and add external ones to the two keys */
1677 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1678 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1679 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1680 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1681 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1682 if(!face->external) continue;
1683 len = len_fam;
1684 if(strcmpiW(face->StyleName, RegularW))
1685 len = len_fam + strlenW(face->StyleName) + 1;
1686 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1687 strcpyW(valueW, family->FamilyName);
1688 if(len != len_fam) {
1689 strcatW(valueW, spaceW);
1690 strcatW(valueW, face->StyleName);
1692 strcatW(valueW, TrueType);
1693 if((path = strrchr(face->file, '/')) == NULL)
1694 path = face->file;
1695 else
1696 path++;
1697 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1699 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1700 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1701 RegSetValueExW(winkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1702 RegSetValueExW(externalkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1704 HeapFree(GetProcessHeap(), 0, file);
1705 HeapFree(GetProcessHeap(), 0, valueW);
1708 end:
1709 if(externalkey)
1710 RegCloseKey(externalkey);
1711 if(winkey)
1712 RegCloseKey(winkey);
1713 return;
1717 /*************************************************************
1718 * WineEngAddFontResourceEx
1721 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1723 if (ft_handle) /* do it only if we have freetype up and running */
1725 char *unixname;
1727 if(flags)
1728 FIXME("Ignoring flags %x\n", flags);
1730 if((unixname = wine_get_unix_file_name(file)))
1732 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
1733 HeapFree(GetProcessHeap(), 0, unixname);
1736 return 1;
1739 /*************************************************************
1740 * WineEngRemoveFontResourceEx
1743 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1745 FIXME(":stub\n");
1746 return TRUE;
1749 static const struct nls_update_font_list
1751 UINT ansi_cp, oem_cp;
1752 const char *oem, *fixed, *system;
1753 const char *courier, *serif, *small, *sserif;
1754 /* these are for font substitute */
1755 const char *shelldlg, *tmsrmn;
1756 } nls_update_font_list[] =
1758 /* Latin 1 (United States) */
1759 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
1760 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1761 "Tahoma","Times New Roman",
1763 /* Latin 1 (Multilingual) */
1764 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
1765 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1766 "Tahoma","Times New Roman", /* FIXME unverified */
1768 /* Eastern Europe */
1769 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
1770 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
1771 "Tahoma","Times New Roman", /* FIXME unverified */
1773 /* Cyrillic */
1774 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
1775 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
1776 "Tahoma","Times New Roman", /* FIXME unverified */
1778 /* Greek */
1779 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
1780 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
1781 "Tahoma","Times New Roman", /* FIXME unverified */
1783 /* Turkish */
1784 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
1785 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
1786 "Tahoma","Times New Roman", /* FIXME unverified */
1788 /* Hebrew */
1789 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
1790 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
1791 "Tahoma","Times New Roman", /* FIXME unverified */
1793 /* Arabic */
1794 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
1795 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
1796 "Tahoma","Times New Roman", /* FIXME unverified */
1798 /* Baltic */
1799 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
1800 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
1801 "Tahoma","Times New Roman", /* FIXME unverified */
1803 /* Vietnamese */
1804 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
1805 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1806 "Tahoma","Times New Roman", /* FIXME unverified */
1808 /* Thai */
1809 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
1810 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
1811 "Tahoma","Times New Roman", /* FIXME unverified */
1813 /* Japanese */
1814 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
1815 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
1816 "MS UI Gothic","MS Serif",
1818 /* Chinese Simplified */
1819 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
1820 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1821 "Tahoma", "Times New Roman", /* FIXME unverified */
1823 /* Korean */
1824 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
1825 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1826 "Gulim", "Batang",
1828 /* Chinese Traditional */
1829 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
1830 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1831 "Tahoma", "Times New Roman", /* FIXME unverified */
1835 static inline HKEY create_fonts_NT_registry_key(void)
1837 HKEY hkey = 0;
1839 RegCreateKeyExW(HKEY_LOCAL_MACHINE, winnt_font_reg_key, 0, NULL,
1840 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1841 return hkey;
1844 static inline HKEY create_fonts_9x_registry_key(void)
1846 HKEY hkey = 0;
1848 RegCreateKeyExW(HKEY_LOCAL_MACHINE, win9x_font_reg_key, 0, NULL,
1849 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1850 return hkey;
1853 static inline HKEY create_config_fonts_registry_key(void)
1855 HKEY hkey = 0;
1857 RegCreateKeyExW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, 0, NULL,
1858 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
1859 return hkey;
1862 static void add_font_list(HKEY hkey, const struct nls_update_font_list *fl)
1864 RegSetValueExA(hkey, "Courier", 0, REG_SZ, (const BYTE *)fl->courier, strlen(fl->courier)+1);
1865 RegSetValueExA(hkey, "MS Serif", 0, REG_SZ, (const BYTE *)fl->serif, strlen(fl->serif)+1);
1866 RegSetValueExA(hkey, "MS Sans Serif", 0, REG_SZ, (const BYTE *)fl->sserif, strlen(fl->sserif)+1);
1867 RegSetValueExA(hkey, "Small Fonts", 0, REG_SZ, (const BYTE *)fl->small, strlen(fl->small)+1);
1870 static void update_font_info(void)
1872 char buf[40], cpbuf[40];
1873 DWORD len, type;
1874 HKEY hkey = 0;
1875 UINT i, ansi_cp = 0, oem_cp = 0;
1877 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL) != ERROR_SUCCESS)
1878 return;
1880 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
1881 (WCHAR *)&ansi_cp, sizeof(ansi_cp)/sizeof(WCHAR));
1882 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE|LOCALE_RETURN_NUMBER|LOCALE_NOUSEROVERRIDE,
1883 (WCHAR *)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR));
1884 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
1886 len = sizeof(buf);
1887 if (RegQueryValueExA(hkey, "Codepages", 0, &type, (BYTE *)buf, &len) == ERROR_SUCCESS && type == REG_SZ)
1889 if (!strcmp( buf, cpbuf )) /* already set correctly */
1891 RegCloseKey(hkey);
1892 return;
1894 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf, ansi_cp, oem_cp);
1896 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp, oem_cp);
1898 RegSetValueExA(hkey, "Codepages", 0, REG_SZ, (const BYTE *)cpbuf, strlen(cpbuf)+1);
1899 RegCloseKey(hkey);
1901 for (i = 0; i < sizeof(nls_update_font_list)/sizeof(nls_update_font_list[0]); i++)
1903 if (nls_update_font_list[i].ansi_cp == ansi_cp &&
1904 nls_update_font_list[i].oem_cp == oem_cp)
1906 HKEY hkey;
1908 hkey = create_config_fonts_registry_key();
1909 RegSetValueExA(hkey, "OEMFONT.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].oem, strlen(nls_update_font_list[i].oem)+1);
1910 RegSetValueExA(hkey, "FIXEDFON.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].fixed, strlen(nls_update_font_list[i].fixed)+1);
1911 RegSetValueExA(hkey, "FONTS.FON", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].system, strlen(nls_update_font_list[i].system)+1);
1912 RegCloseKey(hkey);
1914 hkey = create_fonts_NT_registry_key();
1915 add_font_list(hkey, &nls_update_font_list[i]);
1916 RegCloseKey(hkey);
1918 hkey = create_fonts_9x_registry_key();
1919 add_font_list(hkey, &nls_update_font_list[i]);
1920 RegCloseKey(hkey);
1922 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey ))
1924 RegSetValueExA(hkey, "MS Shell Dlg", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].shelldlg,
1925 strlen(nls_update_font_list[i].shelldlg)+1);
1926 RegSetValueExA(hkey, "Tms Rmn", 0, REG_SZ, (const BYTE *)nls_update_font_list[i].tmsrmn,
1927 strlen(nls_update_font_list[i].tmsrmn)+1);
1928 RegCloseKey(hkey);
1930 return;
1933 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp, oem_cp);
1936 /*************************************************************
1937 * WineEngInit
1939 * Initialize FreeType library and create a list of available faces
1941 BOOL WineEngInit(void)
1943 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
1944 static const WCHAR pathW[] = {'P','a','t','h',0};
1945 HKEY hkey;
1946 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1947 LPVOID data;
1948 WCHAR windowsdir[MAX_PATH];
1949 char *unixname;
1950 HANDLE font_mutex;
1951 const char *data_dir;
1953 TRACE("\n");
1955 /* update locale dependent font info in registry */
1956 update_font_info();
1958 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
1959 if(!ft_handle) {
1960 WINE_MESSAGE(
1961 "Wine cannot find the FreeType font library. To enable Wine to\n"
1962 "use TrueType fonts please install a version of FreeType greater than\n"
1963 "or equal to 2.0.5.\n"
1964 "http://www.freetype.org\n");
1965 return FALSE;
1968 #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;}
1970 LOAD_FUNCPTR(FT_Vector_Unit)
1971 LOAD_FUNCPTR(FT_Done_Face)
1972 LOAD_FUNCPTR(FT_Get_Char_Index)
1973 LOAD_FUNCPTR(FT_Get_Module)
1974 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
1975 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
1976 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
1977 LOAD_FUNCPTR(FT_Init_FreeType)
1978 LOAD_FUNCPTR(FT_Load_Glyph)
1979 LOAD_FUNCPTR(FT_Matrix_Multiply)
1980 LOAD_FUNCPTR(FT_MulFix)
1981 LOAD_FUNCPTR(FT_New_Face)
1982 LOAD_FUNCPTR(FT_New_Memory_Face)
1983 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
1984 LOAD_FUNCPTR(FT_Outline_Transform)
1985 LOAD_FUNCPTR(FT_Outline_Translate)
1986 LOAD_FUNCPTR(FT_Select_Charmap)
1987 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
1988 LOAD_FUNCPTR(FT_Vector_Transform)
1990 #undef LOAD_FUNCPTR
1991 /* Don't warn if this one is missing */
1992 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
1993 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
1994 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
1995 pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
1996 pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
1997 #ifdef HAVE_FREETYPE_FTWINFNT_H
1998 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
1999 #endif
2000 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
2001 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
2002 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2003 <= 2.0.3 has FT_Sqrt64 */
2004 goto sym_not_found;
2007 if(pFT_Init_FreeType(&library) != 0) {
2008 ERR("Can't init FreeType library\n");
2009 wine_dlclose(ft_handle, NULL, 0);
2010 ft_handle = NULL;
2011 return FALSE;
2013 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
2014 if (pFT_Library_Version)
2016 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
2018 if (FT_Version.major<=0)
2020 FT_Version.major=2;
2021 FT_Version.minor=0;
2022 FT_Version.patch=5;
2024 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
2025 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
2026 ((FT_Version.minor << 8) & 0x00ff00) |
2027 ((FT_Version.patch ) & 0x0000ff);
2029 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
2030 ERR("Failed to create font mutex\n");
2031 return FALSE;
2033 WaitForSingleObject(font_mutex, INFINITE);
2035 /* load the system bitmap fonts */
2036 load_system_fonts();
2038 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2039 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
2040 strcatW(windowsdir, fontsW);
2041 if((unixname = wine_get_unix_file_name(windowsdir)))
2043 ReadFontDir(unixname, FALSE);
2044 HeapFree(GetProcessHeap(), 0, unixname);
2047 /* load the system truetype fonts */
2048 data_dir = wine_get_data_dir();
2049 if (data_dir && (unixname = HeapAlloc(GetProcessHeap(), 0, strlen(data_dir) + sizeof("/fonts/")))) {
2050 strcpy(unixname, data_dir);
2051 strcat(unixname, "/fonts/");
2052 ReadFontDir(unixname, FALSE);
2053 HeapFree(GetProcessHeap(), 0, unixname);
2056 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2057 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2058 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2059 will skip these. */
2060 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
2061 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
2062 &hkey) == ERROR_SUCCESS) {
2063 LPWSTR valueW;
2064 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
2065 &valuelen, &datalen, NULL, NULL);
2067 valuelen++; /* returned value doesn't include room for '\0' */
2068 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
2069 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
2070 if (valueW && data)
2072 dlen = datalen * sizeof(WCHAR);
2073 vlen = valuelen;
2074 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
2075 &dlen) == ERROR_SUCCESS) {
2076 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
2078 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
2080 AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2081 HeapFree(GetProcessHeap(), 0, unixname);
2084 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
2086 WCHAR pathW[MAX_PATH];
2087 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
2088 BOOL added = FALSE;
2090 sprintfW(pathW, fmtW, windowsdir, data);
2091 if((unixname = wine_get_unix_file_name(pathW)))
2093 added = AddFontFileToList(unixname, NULL, NULL, ADDFONT_FORCE_BITMAP);
2094 HeapFree(GetProcessHeap(), 0, unixname);
2096 if (!added)
2097 load_font_from_data_dir(data);
2099 /* reset dlen and vlen */
2100 dlen = datalen;
2101 vlen = valuelen;
2104 HeapFree(GetProcessHeap(), 0, data);
2105 HeapFree(GetProcessHeap(), 0, valueW);
2106 RegCloseKey(hkey);
2109 load_fontconfig_fonts();
2111 /* then look in any directories that we've specified in the config file */
2112 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2113 if(RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) == ERROR_SUCCESS)
2115 DWORD len;
2116 LPWSTR valueW;
2117 LPSTR valueA, ptr;
2119 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
2121 len += sizeof(WCHAR);
2122 valueW = HeapAlloc( GetProcessHeap(), 0, len );
2123 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
2125 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
2126 valueA = HeapAlloc( GetProcessHeap(), 0, len );
2127 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
2128 TRACE( "got font path %s\n", debugstr_a(valueA) );
2129 ptr = valueA;
2130 while (ptr)
2132 LPSTR next = strchr( ptr, ':' );
2133 if (next) *next++ = 0;
2134 ReadFontDir( ptr, TRUE );
2135 ptr = next;
2137 HeapFree( GetProcessHeap(), 0, valueA );
2139 HeapFree( GetProcessHeap(), 0, valueW );
2141 RegCloseKey(hkey);
2144 DumpFontList();
2145 LoadSubstList();
2146 DumpSubstList();
2147 LoadReplaceList();
2148 update_reg_entries();
2150 init_system_links();
2152 ReleaseMutex(font_mutex);
2153 return TRUE;
2154 sym_not_found:
2155 WINE_MESSAGE(
2156 "Wine cannot find certain functions that it needs inside the FreeType\n"
2157 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2158 "FreeType to at least version 2.0.5.\n"
2159 "http://www.freetype.org\n");
2160 wine_dlclose(ft_handle, NULL, 0);
2161 ft_handle = NULL;
2162 return FALSE;
2166 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
2168 TT_OS2 *pOS2;
2169 TT_HoriHeader *pHori;
2171 LONG ppem;
2173 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2174 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2176 if(height == 0) height = 16;
2178 /* Calc. height of EM square:
2180 * For +ve lfHeight we have
2181 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2182 * Re-arranging gives:
2183 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2185 * For -ve lfHeight we have
2186 * |lfHeight| = ppem
2187 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2188 * with il = winAscent + winDescent - units_per_em]
2192 if(height > 0) {
2193 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
2194 ppem = ft_face->units_per_EM * height /
2195 (pHori->Ascender - pHori->Descender);
2196 else
2197 ppem = ft_face->units_per_EM * height /
2198 (pOS2->usWinAscent + pOS2->usWinDescent);
2200 else
2201 ppem = -height;
2203 return ppem;
2206 static struct font_mapping *map_font( const char *name )
2208 struct font_mapping *mapping;
2209 struct stat st;
2210 int fd;
2212 if ((fd = open( name, O_RDONLY )) == -1) return NULL;
2213 if (fstat( fd, &st ) == -1) goto error;
2215 LIST_FOR_EACH_ENTRY( mapping, &mappings_list, struct font_mapping, entry )
2217 if (mapping->dev == st.st_dev && mapping->ino == st.st_ino)
2219 mapping->refcount++;
2220 close( fd );
2221 return mapping;
2224 if (!(mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping) )))
2225 goto error;
2227 mapping->data = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
2228 close( fd );
2230 if (mapping->data == MAP_FAILED)
2232 HeapFree( GetProcessHeap(), 0, mapping );
2233 return NULL;
2235 mapping->refcount = 1;
2236 mapping->dev = st.st_dev;
2237 mapping->ino = st.st_ino;
2238 mapping->size = st.st_size;
2239 list_add_tail( &mappings_list, &mapping->entry );
2240 return mapping;
2242 error:
2243 close( fd );
2244 return NULL;
2247 static void unmap_font( struct font_mapping *mapping )
2249 if (!--mapping->refcount)
2251 list_remove( &mapping->entry );
2252 munmap( mapping->data, mapping->size );
2253 HeapFree( GetProcessHeap(), 0, mapping );
2257 static LONG load_VDMX(GdiFont*, LONG);
2259 static FT_Face OpenFontFile(GdiFont *font, char *file, FT_Long face_index, LONG width, LONG height)
2261 FT_Error err;
2262 FT_Face ft_face;
2264 TRACE("%s, %ld, %d x %d\n", debugstr_a(file), face_index, width, height);
2266 if (!(font->mapping = map_font( file )))
2268 WARN("failed to map %s\n", debugstr_a(file));
2269 return 0;
2272 err = pFT_New_Memory_Face(library, font->mapping->data, font->mapping->size, face_index, &ft_face);
2273 if(err) {
2274 ERR("FT_New_Face rets %d\n", err);
2275 return 0;
2278 /* set it here, as load_VDMX needs it */
2279 font->ft_face = ft_face;
2281 if(FT_IS_SCALABLE(ft_face)) {
2282 /* load the VDMX table if we have one */
2283 font->ppem = load_VDMX(font, height);
2284 if(font->ppem == 0)
2285 font->ppem = calc_ppem_for_height(ft_face, height);
2287 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, font->ppem)) != 0)
2288 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font->ppem, err);
2289 } else {
2290 font->ppem = height;
2291 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
2292 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width, height, err);
2294 return ft_face;
2298 static int get_nearest_charset(Face *face, int *cp)
2300 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2301 a single face with the requested charset. The idea is to check if
2302 the selected font supports the current ANSI codepage, if it does
2303 return the corresponding charset, else return the first charset */
2305 CHARSETINFO csi;
2306 int acp = GetACP(), i;
2307 DWORD fs0;
2309 *cp = acp;
2310 if(TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE))
2311 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2312 return csi.ciCharset;
2314 for(i = 0; i < 32; i++) {
2315 fs0 = 1L << i;
2316 if(face->fs.fsCsb[0] & fs0) {
2317 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
2318 *cp = csi.ciACP;
2319 return csi.ciCharset;
2321 else
2322 FIXME("TCI failing on %x\n", fs0);
2326 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2327 face->fs.fsCsb[0], face->file);
2328 *cp = acp;
2329 return DEFAULT_CHARSET;
2332 static GdiFont *alloc_font(void)
2334 GdiFont *ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
2335 ret->gmsize = INIT_GM_SIZE;
2336 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2337 ret->gmsize * sizeof(*ret->gm));
2338 ret->potm = NULL;
2339 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
2340 ret->total_kern_pairs = (DWORD)-1;
2341 ret->kern_pairs = NULL;
2342 list_init(&ret->hfontlist);
2343 list_init(&ret->child_fonts);
2344 return ret;
2347 static void free_font(GdiFont *font)
2349 struct list *cursor, *cursor2;
2351 LIST_FOR_EACH_SAFE(cursor, cursor2, &font->child_fonts)
2353 CHILD_FONT *child = LIST_ENTRY(cursor, CHILD_FONT, entry);
2354 struct list *first_hfont;
2355 HFONTLIST *hfontlist;
2356 list_remove(cursor);
2357 if(child->font)
2359 first_hfont = list_head(&child->font->hfontlist);
2360 hfontlist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2361 DeleteObject(hfontlist->hfont);
2362 HeapFree(GetProcessHeap(), 0, hfontlist);
2363 free_font(child->font);
2365 HeapFree(GetProcessHeap(), 0, child->file_name);
2366 HeapFree(GetProcessHeap(), 0, child);
2369 if (font->ft_face) pFT_Done_Face(font->ft_face);
2370 if (font->mapping) unmap_font( font->mapping );
2371 HeapFree(GetProcessHeap(), 0, font->kern_pairs);
2372 HeapFree(GetProcessHeap(), 0, font->potm);
2373 HeapFree(GetProcessHeap(), 0, font->name);
2374 HeapFree(GetProcessHeap(), 0, font->gm);
2375 HeapFree(GetProcessHeap(), 0, font);
2379 /*************************************************************
2380 * load_VDMX
2382 * load the vdmx entry for the specified height
2385 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2386 ( ( (FT_ULong)_x4 << 24 ) | \
2387 ( (FT_ULong)_x3 << 16 ) | \
2388 ( (FT_ULong)_x2 << 8 ) | \
2389 (FT_ULong)_x1 )
2391 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2393 typedef struct {
2394 BYTE bCharSet;
2395 BYTE xRatio;
2396 BYTE yStartRatio;
2397 BYTE yEndRatio;
2398 } Ratios;
2400 typedef struct {
2401 WORD recs;
2402 BYTE startsz;
2403 BYTE endsz;
2404 } VDMX_group;
2406 static LONG load_VDMX(GdiFont *font, LONG height)
2408 WORD hdr[3], tmp;
2409 VDMX_group group;
2410 BYTE devXRatio, devYRatio;
2411 USHORT numRecs, numRatios;
2412 DWORD result, offset = -1;
2413 LONG ppem = 0;
2414 int i;
2416 /* For documentation on VDMX records, see
2417 * http://www.microsoft.com/OpenType/OTSpec/vdmx.htm
2420 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
2422 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
2423 return ppem;
2425 /* FIXME: need the real device aspect ratio */
2426 devXRatio = 1;
2427 devYRatio = 1;
2429 numRecs = GET_BE_WORD(hdr[1]);
2430 numRatios = GET_BE_WORD(hdr[2]);
2432 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
2433 for(i = 0; i < numRatios; i++) {
2434 Ratios ratio;
2436 offset = (3 * 2) + (i * sizeof(Ratios));
2437 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
2438 offset = -1;
2440 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
2442 if((ratio.xRatio == 0 &&
2443 ratio.yStartRatio == 0 &&
2444 ratio.yEndRatio == 0) ||
2445 (devXRatio == ratio.xRatio &&
2446 devYRatio >= ratio.yStartRatio &&
2447 devYRatio <= ratio.yEndRatio))
2449 offset = (3 * 2) + (numRatios * 4) + (i * 2);
2450 WineEngGetFontData(font, MS_VDMX_TAG, offset, &tmp, 2);
2451 offset = GET_BE_WORD(tmp);
2452 break;
2456 if(offset == -1) {
2457 FIXME("No suitable ratio found\n");
2458 return ppem;
2461 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, &group, 4) != GDI_ERROR) {
2462 USHORT recs;
2463 BYTE startsz, endsz;
2464 WORD *vTable;
2466 recs = GET_BE_WORD(group.recs);
2467 startsz = group.startsz;
2468 endsz = group.endsz;
2470 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
2472 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
2473 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
2474 if(result == GDI_ERROR) {
2475 FIXME("Failed to retrieve vTable\n");
2476 goto end;
2479 if(height > 0) {
2480 for(i = 0; i < recs; i++) {
2481 SHORT yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2482 SHORT yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2483 ppem = GET_BE_WORD(vTable[i * 3]);
2485 if(yMax + -yMin == height) {
2486 font->yMax = yMax;
2487 font->yMin = yMin;
2488 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2489 break;
2491 if(yMax + -yMin > height) {
2492 if(--i < 0) {
2493 ppem = 0;
2494 goto end; /* failed */
2496 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2497 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2498 ppem = GET_BE_WORD(vTable[i * 3]);
2499 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
2500 break;
2503 if(!font->yMax) {
2504 ppem = 0;
2505 TRACE("ppem not found for height %d\n", height);
2507 } else {
2508 ppem = -height;
2509 if(ppem < startsz || ppem > endsz)
2510 goto end;
2512 for(i = 0; i < recs; i++) {
2513 USHORT yPelHeight;
2514 yPelHeight = GET_BE_WORD(vTable[i * 3]);
2516 if(yPelHeight > ppem)
2517 break; /* failed */
2519 if(yPelHeight == ppem) {
2520 font->yMax = GET_BE_WORD(vTable[(i * 3) + 1]);
2521 font->yMin = GET_BE_WORD(vTable[(i * 3) + 2]);
2522 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
2523 break;
2527 end:
2528 HeapFree(GetProcessHeap(), 0, vTable);
2531 return ppem;
2534 static BOOL fontcmp(GdiFont *font, FONT_DESC *fd)
2536 if(font->font_desc.hash != fd->hash) return TRUE;
2537 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
2538 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
2539 if(!font->font_desc.can_use_bitmap != !fd->can_use_bitmap) return TRUE;
2540 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
2543 static void calc_hash(FONT_DESC *pfd)
2545 DWORD hash = 0, *ptr, two_chars;
2546 WORD *pwc;
2547 unsigned int i;
2549 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
2550 hash ^= *ptr;
2551 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
2552 hash ^= *ptr;
2553 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
2554 two_chars = *ptr;
2555 pwc = (WCHAR *)&two_chars;
2556 if(!*pwc) break;
2557 *pwc = toupperW(*pwc);
2558 pwc++;
2559 *pwc = toupperW(*pwc);
2560 hash ^= two_chars;
2561 if(!*pwc) break;
2563 hash ^= !pfd->can_use_bitmap;
2564 pfd->hash = hash;
2565 return;
2568 static GdiFont *find_in_cache(HFONT hfont, LOGFONTW *plf, XFORM *pxf, BOOL can_use_bitmap)
2570 GdiFont *ret;
2571 FONT_DESC fd;
2572 HFONTLIST *hflist;
2573 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2575 memcpy(&fd.lf, plf, sizeof(LOGFONTW));
2576 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
2577 fd.can_use_bitmap = can_use_bitmap;
2578 calc_hash(&fd);
2580 /* try the in-use list */
2581 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
2582 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2583 if(!fontcmp(ret, &fd)) {
2584 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2585 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
2586 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
2587 if(hflist->hfont == hfont)
2588 return ret;
2590 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2591 hflist->hfont = hfont;
2592 list_add_head(&ret->hfontlist, &hflist->entry);
2593 return ret;
2597 /* then the unused list */
2598 font_elem_ptr = list_head(&unused_gdi_font_list);
2599 while(font_elem_ptr) {
2600 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
2601 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
2602 if(!fontcmp(ret, &fd)) {
2603 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
2604 assert(list_empty(&ret->hfontlist));
2605 TRACE("Found %p in unused list\n", ret);
2606 list_remove(&ret->entry);
2607 list_add_head(&gdi_font_list, &ret->entry);
2608 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2609 hflist->hfont = hfont;
2610 list_add_head(&ret->hfontlist, &hflist->entry);
2611 return ret;
2614 return NULL;
2618 /*************************************************************
2619 * create_child_font_list
2621 static BOOL create_child_font_list(GdiFont *font)
2623 BOOL ret = FALSE;
2624 SYSTEM_LINKS *font_link;
2625 CHILD_FONT *font_link_entry, *new_child;
2627 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2629 if(!strcmpW(font_link->font_name, font->name))
2631 TRACE("found entry in system list\n");
2632 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2634 new_child = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child));
2635 new_child->file_name = strdupA(font_link_entry->file_name);
2636 new_child->index = font_link_entry->index;
2637 new_child->font = NULL;
2638 list_add_tail(&font->child_fonts, &new_child->entry);
2639 TRACE("font %s %d\n", debugstr_a(new_child->file_name), new_child->index);
2641 ret = TRUE;
2642 break;
2646 return ret;
2649 /*************************************************************
2650 * WineEngCreateFontInstance
2653 GdiFont *WineEngCreateFontInstance(DC *dc, HFONT hfont)
2655 GdiFont *ret;
2656 Face *face, *best, *best_bitmap;
2657 Family *family, *last_resort_family;
2658 struct list *family_elem_ptr, *face_elem_ptr;
2659 INT height, width = 0;
2660 unsigned int score = 0, new_score;
2661 signed int diff = 0, newdiff;
2662 BOOL bd, it, can_use_bitmap;
2663 LOGFONTW lf;
2664 CHARSETINFO csi;
2665 HFONTLIST *hflist;
2667 LIST_FOR_EACH_ENTRY(ret, &child_font_list, struct tagGdiFont, entry)
2669 struct list *first_hfont = list_head(&ret->hfontlist);
2670 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2671 if(hflist->hfont == hfont)
2672 return ret;
2675 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
2676 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
2678 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
2679 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
2680 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
2681 lf.lfEscapement);
2683 /* check the cache first */
2684 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
2685 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
2686 return ret;
2689 TRACE("not in cache\n");
2690 if(list_empty(&font_list)) /* No fonts installed */
2692 TRACE("No fonts installed\n");
2693 return NULL;
2695 if(!have_installed_roman_font)
2697 TRACE("No roman font installed\n");
2698 return NULL;
2701 ret = alloc_font();
2703 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
2704 memcpy(&ret->font_desc.lf, &lf, sizeof(LOGFONTW));
2705 ret->font_desc.can_use_bitmap = can_use_bitmap;
2706 calc_hash(&ret->font_desc);
2707 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
2708 hflist->hfont = hfont;
2709 list_add_head(&ret->hfontlist, &hflist->entry);
2712 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
2713 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
2714 original value lfCharSet. Note this is a special case for
2715 Symbol and doesn't happen at least for "Wingdings*" */
2717 if(!strcmpiW(lf.lfFaceName, SymbolW))
2718 lf.lfCharSet = SYMBOL_CHARSET;
2720 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
2721 switch(lf.lfCharSet) {
2722 case DEFAULT_CHARSET:
2723 csi.fs.fsCsb[0] = 0;
2724 break;
2725 default:
2726 FIXME("Untranslated charset %d\n", lf.lfCharSet);
2727 csi.fs.fsCsb[0] = 0;
2728 break;
2732 family = NULL;
2733 if(lf.lfFaceName[0] != '\0') {
2734 FontSubst *psub;
2735 SYSTEM_LINKS *font_link;
2736 CHILD_FONT *font_link_entry;
2738 psub = get_font_subst(&font_subst_list, lf.lfFaceName, lf.lfCharSet);
2740 if(psub) {
2741 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
2742 debugstr_w(psub->to.name));
2743 strcpyW(lf.lfFaceName, psub->to.name);
2746 /* We want a match on name and charset or just name if
2747 charset was DEFAULT_CHARSET. If the latter then
2748 we fixup the returned charset later in get_nearest_charset
2749 where we'll either use the charset of the current ansi codepage
2750 or if that's unavailable the first charset that the font supports.
2752 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2753 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2754 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2755 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2756 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2757 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
2758 if(face->scalable || can_use_bitmap)
2759 goto found;
2765 * Try check the SystemLink list first for a replacement font.
2766 * We may find good replacements there.
2768 LIST_FOR_EACH_ENTRY(font_link, &system_links, SYSTEM_LINKS, entry)
2770 if(!strcmpW(font_link->font_name, lf.lfFaceName))
2772 TRACE("found entry in system list\n");
2773 LIST_FOR_EACH_ENTRY(font_link_entry, &font_link->links, CHILD_FONT, entry)
2775 face = find_face_from_path_index(font_link_entry->file_name,
2776 font_link_entry->index);
2777 if (face)
2779 family = face->family;
2780 if(csi.fs.fsCsb[0] &
2781 (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2783 if(face->scalable || can_use_bitmap)
2784 goto found;
2792 /* If requested charset was DEFAULT_CHARSET then try using charset
2793 corresponding to the current ansi codepage */
2794 if(!csi.fs.fsCsb[0]) {
2795 INT acp = GetACP();
2796 if(!TranslateCharsetInfo((DWORD*)(INT_PTR)acp, &csi, TCI_SRCCODEPAGE)) {
2797 FIXME("TCI failed on codepage %d\n", acp);
2798 csi.fs.fsCsb[0] = 0;
2799 } else
2800 lf.lfCharSet = csi.ciCharset;
2803 /* Face families are in the top 4 bits of lfPitchAndFamily,
2804 so mask with 0xF0 before testing */
2806 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
2807 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
2808 strcpyW(lf.lfFaceName, defFixed);
2809 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
2810 strcpyW(lf.lfFaceName, defSerif);
2811 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
2812 strcpyW(lf.lfFaceName, defSans);
2813 else
2814 strcpyW(lf.lfFaceName, defSans);
2815 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2816 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2817 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
2818 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2819 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2820 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0]))
2821 if(face->scalable || can_use_bitmap)
2822 goto found;
2827 last_resort_family = NULL;
2828 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2829 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2830 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2831 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2832 if(csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) {
2833 if(face->scalable)
2834 goto found;
2835 if(can_use_bitmap && !last_resort_family)
2836 last_resort_family = family;
2841 if(last_resort_family) {
2842 family = last_resort_family;
2843 csi.fs.fsCsb[0] = 0;
2844 goto found;
2847 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2848 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2849 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2850 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2851 if(face->scalable) {
2852 csi.fs.fsCsb[0] = 0;
2853 WARN("just using first face for now\n");
2854 goto found;
2856 if(can_use_bitmap && !last_resort_family)
2857 last_resort_family = family;
2860 if(!last_resort_family) {
2861 FIXME("can't find a single appropriate font - bailing\n");
2862 free_font(ret);
2863 return NULL;
2866 WARN("could only find a bitmap font - this will probably look awful!\n");
2867 family = last_resort_family;
2868 csi.fs.fsCsb[0] = 0;
2870 found:
2871 it = lf.lfItalic ? 1 : 0;
2872 bd = lf.lfWeight > 550 ? 1 : 0;
2874 height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
2875 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
2877 face = best = best_bitmap = NULL;
2878 LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry)
2880 if((csi.fs.fsCsb[0] & (face->fs.fsCsb[0] | face->fs_links.fsCsb[0])) || !csi.fs.fsCsb[0])
2882 new_score = (face->Italic ^ it) + (face->Bold ^ bd);
2883 if(!best || new_score <= score)
2885 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
2886 face->Italic, face->Bold, it, bd);
2887 score = new_score;
2888 best = face;
2889 if(best->scalable && score == 0) break;
2890 if(!best->scalable)
2892 if(height > 0)
2893 newdiff = height - (signed int)(best->size.height);
2894 else
2895 newdiff = -height - ((signed int)(best->size.height) - best->size.internal_leading);
2896 if(!best_bitmap || new_score < score ||
2897 (diff > 0 && newdiff < diff && newdiff >= 0) || (diff < 0 && newdiff > diff))
2899 TRACE("%d is better for %d diff was %d\n", best->size.height, height, diff);
2900 diff = newdiff;
2901 best_bitmap = best;
2902 if(score == 0 && diff == 0) break;
2908 if(best)
2909 face = best->scalable ? best : best_bitmap;
2910 ret->fake_italic = (it && !face->Italic);
2911 ret->fake_bold = (bd && !face->Bold);
2913 memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
2915 if(csi.fs.fsCsb[0]) {
2916 ret->charset = lf.lfCharSet;
2917 ret->codepage = csi.ciACP;
2919 else
2920 ret->charset = get_nearest_charset(face, &ret->codepage);
2922 TRACE("Chosen: %s %s (%s:%ld)\n", debugstr_w(family->FamilyName),
2923 debugstr_w(face->StyleName), face->file, face->face_index);
2925 if(!face->scalable) {
2926 width = face->size.x_ppem >> 6;
2927 height = face->size.y_ppem >> 6;
2929 ret->ft_face = OpenFontFile(ret, face->file, face->face_index, width, height);
2931 if (!ret->ft_face)
2933 free_font( ret );
2934 return 0;
2937 if (ret->charset == SYMBOL_CHARSET &&
2938 !pFT_Select_Charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
2939 /* No ops */
2941 else if (!pFT_Select_Charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
2942 /* No ops */
2944 else {
2945 pFT_Select_Charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
2948 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
2949 ret->name = strdupW(family->FamilyName);
2950 ret->underline = lf.lfUnderline ? 0xff : 0;
2951 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
2952 create_child_font_list(ret);
2954 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
2956 ret->aveWidth = FT_IS_SCALABLE(ret->ft_face) ? abs(lf.lfWidth) : 0;
2957 list_add_head(&gdi_font_list, &ret->entry);
2958 return ret;
2961 static void dump_gdi_font_list(void)
2963 GdiFont *gdiFont;
2964 struct list *elem_ptr;
2966 TRACE("---------- gdiFont Cache ----------\n");
2967 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
2968 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
2969 TRACE("gdiFont=%p %s %d\n",
2970 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
2973 TRACE("---------- Unused gdiFont Cache ----------\n");
2974 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
2975 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
2976 TRACE("gdiFont=%p %s %d\n",
2977 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
2981 /*************************************************************
2982 * WineEngDestroyFontInstance
2984 * free the gdiFont associated with this handle
2987 BOOL WineEngDestroyFontInstance(HFONT handle)
2989 GdiFont *gdiFont;
2990 HFONTLIST *hflist;
2991 BOOL ret = FALSE;
2992 struct list *font_elem_ptr, *hfontlist_elem_ptr;
2993 int i = 0;
2995 LIST_FOR_EACH_ENTRY(gdiFont, &child_font_list, struct tagGdiFont, entry)
2997 struct list *first_hfont = list_head(&gdiFont->hfontlist);
2998 hflist = LIST_ENTRY(first_hfont, HFONTLIST, entry);
2999 if(hflist->hfont == handle)
3001 TRACE("removing child font %p from child list\n", gdiFont);
3002 list_remove(&gdiFont->entry);
3003 return TRUE;
3007 TRACE("destroying hfont=%p\n", handle);
3008 if(TRACE_ON(font))
3009 dump_gdi_font_list();
3011 font_elem_ptr = list_head(&gdi_font_list);
3012 while(font_elem_ptr) {
3013 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3014 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
3016 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
3017 while(hfontlist_elem_ptr) {
3018 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
3019 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
3020 if(hflist->hfont == handle) {
3021 list_remove(&hflist->entry);
3022 HeapFree(GetProcessHeap(), 0, hflist);
3023 ret = TRUE;
3026 if(list_empty(&gdiFont->hfontlist)) {
3027 TRACE("Moving to Unused list\n");
3028 list_remove(&gdiFont->entry);
3029 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
3034 font_elem_ptr = list_head(&unused_gdi_font_list);
3035 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
3036 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3037 while(font_elem_ptr) {
3038 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
3039 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
3040 TRACE("freeing %p\n", gdiFont);
3041 list_remove(&gdiFont->entry);
3042 free_font(gdiFont);
3044 return ret;
3047 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
3048 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
3050 OUTLINETEXTMETRICW *potm = NULL;
3051 UINT size;
3052 TEXTMETRICW tm, *ptm;
3053 GdiFont *font = alloc_font();
3054 LONG width, height;
3056 if(face->scalable) {
3057 height = 100;
3058 width = 0;
3059 } else {
3060 height = face->size.y_ppem >> 6;
3061 width = face->size.x_ppem >> 6;
3064 if (!(font->ft_face = OpenFontFile(font, face->file, face->face_index, width, height)))
3066 free_font(font);
3067 return;
3070 font->name = strdupW(face->family->FamilyName);
3072 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
3074 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
3075 if(size) {
3076 potm = HeapAlloc(GetProcessHeap(), 0, size);
3077 WineEngGetOutlineTextMetrics(font, size, potm);
3078 ptm = (TEXTMETRICW*)&potm->otmTextMetrics;
3079 } else {
3080 WineEngGetTextMetrics(font, &tm);
3081 ptm = &tm;
3084 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = ptm->tmHeight;
3085 pntm->ntmTm.tmAscent = ptm->tmAscent;
3086 pntm->ntmTm.tmDescent = ptm->tmDescent;
3087 pntm->ntmTm.tmInternalLeading = ptm->tmInternalLeading;
3088 pntm->ntmTm.tmExternalLeading = ptm->tmExternalLeading;
3089 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = ptm->tmAveCharWidth;
3090 pntm->ntmTm.tmMaxCharWidth = ptm->tmMaxCharWidth;
3091 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = ptm->tmWeight;
3092 pntm->ntmTm.tmOverhang = ptm->tmOverhang;
3093 pntm->ntmTm.tmDigitizedAspectX = ptm->tmDigitizedAspectX;
3094 pntm->ntmTm.tmDigitizedAspectY = ptm->tmDigitizedAspectY;
3095 pntm->ntmTm.tmFirstChar = ptm->tmFirstChar;
3096 pntm->ntmTm.tmLastChar = ptm->tmLastChar;
3097 pntm->ntmTm.tmDefaultChar = ptm->tmDefaultChar;
3098 pntm->ntmTm.tmBreakChar = ptm->tmBreakChar;
3099 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = ptm->tmItalic;
3100 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = ptm->tmUnderlined;
3101 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = ptm->tmStruckOut;
3102 pntm->ntmTm.tmPitchAndFamily = ptm->tmPitchAndFamily;
3103 pelf->elfLogFont.lfPitchAndFamily = (ptm->tmPitchAndFamily & 0xf1) + 1;
3104 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = ptm->tmCharSet;
3105 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
3106 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
3107 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
3109 *ptype = ptm->tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
3110 if(!(ptm->tmPitchAndFamily & TMPF_VECTOR))
3111 *ptype |= RASTER_FONTTYPE;
3113 pntm->ntmTm.ntmFlags = ptm->tmItalic ? NTM_ITALIC : 0;
3114 if(ptm->tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
3115 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
3117 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
3118 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
3119 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
3121 if(potm) {
3122 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
3124 lstrcpynW(pelf->elfLogFont.lfFaceName,
3125 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
3126 LF_FACESIZE);
3127 lstrcpynW(pelf->elfFullName,
3128 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
3129 LF_FULLFACESIZE);
3130 lstrcpynW(pelf->elfStyle,
3131 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
3132 LF_FACESIZE);
3134 HeapFree(GetProcessHeap(), 0, potm);
3135 } else {
3136 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
3138 lstrcpynW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
3139 lstrcpynW(pelf->elfFullName, face->family->FamilyName, LF_FACESIZE);
3140 pelf->elfStyle[0] = '\0';
3143 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
3145 free_font(font);
3148 /*************************************************************
3149 * WineEngEnumFonts
3152 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3154 Family *family;
3155 Face *face;
3156 struct list *family_elem_ptr, *face_elem_ptr;
3157 ENUMLOGFONTEXW elf;
3158 NEWTEXTMETRICEXW ntm;
3159 DWORD type, ret = 1;
3160 FONTSIGNATURE fs;
3161 CHARSETINFO csi;
3162 LOGFONTW lf;
3163 int i;
3165 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
3167 if(plf->lfFaceName[0]) {
3168 FontSubst *psub;
3169 psub = get_font_subst(&font_subst_list, plf->lfFaceName, plf->lfCharSet);
3171 if(psub) {
3172 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
3173 debugstr_w(psub->to.name));
3174 memcpy(&lf, plf, sizeof(lf));
3175 strcpyW(lf.lfFaceName, psub->to.name);
3176 plf = &lf;
3179 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3180 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3181 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
3182 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
3183 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3184 GetEnumStructs(face, &elf, &ntm, &type);
3185 for(i = 0; i < 32; i++) {
3186 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3187 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3188 strcpyW(elf.elfScript, OEM_DOSW);
3189 i = 32; /* break out of loop */
3190 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3191 continue;
3192 else {
3193 fs.fsCsb[0] = 1L << i;
3194 fs.fsCsb[1] = 0;
3195 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3196 TCI_SRCFONTSIG))
3197 csi.ciCharset = DEFAULT_CHARSET;
3198 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3199 if(csi.ciCharset != DEFAULT_CHARSET) {
3200 elf.elfLogFont.lfCharSet =
3201 ntm.ntmTm.tmCharSet = csi.ciCharset;
3202 if(ElfScriptsW[i])
3203 strcpyW(elf.elfScript, ElfScriptsW[i]);
3204 else
3205 FIXME("Unknown elfscript for bit %d\n", i);
3208 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3209 debugstr_w(elf.elfLogFont.lfFaceName),
3210 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3211 csi.ciCharset, type, debugstr_w(elf.elfScript),
3212 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3213 ntm.ntmTm.ntmFlags);
3214 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
3215 if(!ret) goto end;
3220 } else {
3221 LIST_FOR_EACH(family_elem_ptr, &font_list) {
3222 family = LIST_ENTRY(family_elem_ptr, Family, entry);
3223 face_elem_ptr = list_head(&family->faces);
3224 face = LIST_ENTRY(face_elem_ptr, Face, entry);
3225 GetEnumStructs(face, &elf, &ntm, &type);
3226 for(i = 0; i < 32; i++) {
3227 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
3228 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
3229 strcpyW(elf.elfScript, OEM_DOSW);
3230 i = 32; /* break out of loop */
3231 } else if(!(face->fs.fsCsb[0] & (1L << i)))
3232 continue;
3233 else {
3234 fs.fsCsb[0] = 1L << i;
3235 fs.fsCsb[1] = 0;
3236 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
3237 TCI_SRCFONTSIG))
3238 csi.ciCharset = DEFAULT_CHARSET;
3239 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
3240 if(csi.ciCharset != DEFAULT_CHARSET) {
3241 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
3242 csi.ciCharset;
3243 if(ElfScriptsW[i])
3244 strcpyW(elf.elfScript, ElfScriptsW[i]);
3245 else
3246 FIXME("Unknown elfscript for bit %d\n", i);
3249 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3250 debugstr_w(elf.elfLogFont.lfFaceName),
3251 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
3252 csi.ciCharset, type, debugstr_w(elf.elfScript),
3253 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
3254 ntm.ntmTm.ntmFlags);
3255 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
3256 if(!ret) goto end;
3260 end:
3261 return ret;
3264 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
3266 pt->x.value = vec->x >> 6;
3267 pt->x.fract = (vec->x & 0x3f) << 10;
3268 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
3269 pt->y.value = vec->y >> 6;
3270 pt->y.fract = (vec->y & 0x3f) << 10;
3271 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
3272 return;
3275 /***************************************************
3276 * According to the MSDN documentation on WideCharToMultiByte,
3277 * certain codepages cannot set the default_used parameter.
3278 * This returns TRUE if the codepage can set that parameter, false else
3279 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
3281 static BOOL codepage_sets_default_used(UINT codepage)
3283 switch (codepage)
3285 case CP_UTF7:
3286 case CP_UTF8:
3287 case CP_SYMBOL:
3288 return FALSE;
3289 default:
3290 return TRUE;
3294 static FT_UInt get_glyph_index(GdiFont *font, UINT glyph)
3296 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
3297 WCHAR wc = (WCHAR)glyph;
3298 BOOL default_used;
3299 BOOL *default_used_pointer;
3300 FT_UInt ret;
3301 char buf;
3302 default_used_pointer = NULL;
3303 default_used = FALSE;
3304 if (codepage_sets_default_used(font->codepage))
3305 default_used_pointer = &default_used;
3306 if(!WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), NULL, default_used_pointer) || default_used)
3307 ret = 0;
3308 else
3309 ret = pFT_Get_Char_Index(font->ft_face, (unsigned char)buf);
3310 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph, buf, ret, default_used);
3311 return ret;
3314 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
3315 glyph = glyph + 0xf000;
3316 return pFT_Get_Char_Index(font->ft_face, glyph);
3319 /*************************************************************
3320 * WineEngGetGlyphIndices
3322 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
3324 DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count,
3325 LPWORD pgi, DWORD flags)
3327 int i;
3328 WCHAR default_char = 0;
3329 TEXTMETRICW textm;
3331 if (flags & GGI_MARK_NONEXISTING_GLYPHS) default_char = 0x001f; /* Indicate non existence */
3333 for(i = 0; i < count; i++)
3335 pgi[i] = get_glyph_index(font, lpstr[i]);
3336 if (pgi[i] == 0)
3338 if (!default_char)
3340 WineEngGetTextMetrics(font, &textm);
3341 default_char = textm.tmDefaultChar;
3343 pgi[i] = default_char;
3346 return count;
3349 /*************************************************************
3350 * WineEngGetGlyphOutline
3352 * Behaves in exactly the same way as the win32 api GetGlyphOutline
3353 * except that the first parameter is the HWINEENGFONT of the font in
3354 * question rather than an HDC.
3357 DWORD WineEngGetGlyphOutline(GdiFont *font, UINT glyph, UINT format,
3358 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
3359 const MAT2* lpmat)
3361 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
3362 FT_Face ft_face = font->ft_face;
3363 FT_UInt glyph_index;
3364 DWORD width, height, pitch, needed = 0;
3365 FT_Bitmap ft_bitmap;
3366 FT_Error err;
3367 INT left, right, top = 0, bottom = 0;
3368 FT_Angle angle = 0;
3369 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
3370 float widthRatio = 1.0;
3371 FT_Matrix transMat = identityMat;
3372 BOOL needsTransform = FALSE;
3375 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm,
3376 buflen, buf, lpmat);
3378 if(format & GGO_GLYPH_INDEX) {
3379 glyph_index = glyph;
3380 format &= ~GGO_GLYPH_INDEX;
3381 } else
3382 glyph_index = get_glyph_index(font, glyph);
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 */