Convert gdi font list to use list.h.
[wine.git] / dlls / gdi / freetype.c
blob1adfd08c70f57523b11560a10559c9e5bc559e05
1 /*
2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
6 * This file contains the WineEng* functions.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "config.h"
24 #include "wine/port.h"
26 #include <stdarg.h>
27 #include <stdlib.h>
28 #include <sys/stat.h>
29 #include <string.h>
30 #include <dirent.h>
31 #include <stdio.h>
32 #include <assert.h>
34 #include "windef.h"
35 #include "winbase.h"
36 #include "winerror.h"
37 #include "winreg.h"
38 #include "wingdi.h"
39 #include "gdi.h"
40 #include "gdi_private.h"
41 #include "wine/unicode.h"
42 #include "wine/debug.h"
43 #include "wine/list.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(font);
47 #ifdef HAVE_FREETYPE
49 #ifdef HAVE_FT2BUILD_H
50 #include <ft2build.h>
51 #endif
52 #ifdef HAVE_FREETYPE_FREETYPE_H
53 #include <freetype/freetype.h>
54 #endif
55 #ifdef HAVE_FREETYPE_FTGLYPH_H
56 #include <freetype/ftglyph.h>
57 #endif
58 #ifdef HAVE_FREETYPE_TTTABLES_H
59 #include <freetype/tttables.h>
60 #endif
61 #ifdef HAVE_FREETYPE_FTSNAMES_H
62 #include <freetype/ftsnames.h>
63 #else
64 # ifdef HAVE_FREETYPE_FTNAMES_H
65 # include <freetype/ftnames.h>
66 # endif
67 #endif
68 #ifdef HAVE_FREETYPE_TTNAMEID_H
69 #include <freetype/ttnameid.h>
70 #endif
71 #ifdef HAVE_FREETYPE_FTOUTLN_H
72 #include <freetype/ftoutln.h>
73 #endif
74 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
75 #include <freetype/internal/sfnt.h>
76 #endif
77 #ifdef HAVE_FREETYPE_FTTRIGON_H
78 #include <freetype/fttrigon.h>
79 #endif
80 #ifdef HAVE_FREETYPE_FTWINFNT_H
81 #include <freetype/ftwinfnt.h>
82 #endif
84 #ifndef SONAME_LIBFREETYPE
85 #define SONAME_LIBFREETYPE "libfreetype.so"
86 #endif
88 static FT_Library library = 0;
89 typedef struct
91 FT_Int major;
92 FT_Int minor;
93 FT_Int patch;
94 } FT_Version_t;
95 static FT_Version_t FT_Version;
96 static DWORD FT_SimpleVersion;
98 static void *ft_handle = NULL;
100 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
101 MAKE_FUNCPTR(FT_Vector_Unit);
102 MAKE_FUNCPTR(FT_Done_Face);
103 MAKE_FUNCPTR(FT_Get_Char_Index);
104 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
105 MAKE_FUNCPTR(FT_Init_FreeType);
106 MAKE_FUNCPTR(FT_Load_Glyph);
107 MAKE_FUNCPTR(FT_Matrix_Multiply);
108 MAKE_FUNCPTR(FT_MulFix);
109 MAKE_FUNCPTR(FT_New_Face);
110 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
111 MAKE_FUNCPTR(FT_Outline_Transform);
112 MAKE_FUNCPTR(FT_Outline_Translate);
113 MAKE_FUNCPTR(FT_Select_Charmap);
114 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
115 MAKE_FUNCPTR(FT_Vector_Transform);
116 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
117 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
118 static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*);
119 #ifdef HAVE_FREETYPE_FTWINFNT_H
120 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
121 #endif
123 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
124 #include <fontconfig/fontconfig.h>
125 MAKE_FUNCPTR(FcConfigGetCurrent);
126 MAKE_FUNCPTR(FcFontList);
127 MAKE_FUNCPTR(FcFontSetDestroy);
128 MAKE_FUNCPTR(FcInit);
129 MAKE_FUNCPTR(FcObjectSetAdd);
130 MAKE_FUNCPTR(FcObjectSetCreate);
131 MAKE_FUNCPTR(FcObjectSetDestroy);
132 MAKE_FUNCPTR(FcPatternCreate);
133 MAKE_FUNCPTR(FcPatternDestroy);
134 MAKE_FUNCPTR(FcPatternGet);
135 #ifndef SONAME_LIBFONTCONFIG
136 #define SONAME_LIBFONTCONFIG "libfontconfig.so"
137 #endif
138 #endif
140 #undef MAKE_FUNCPTR
143 #define GET_BE_WORD(ptr) MAKEWORD( ((BYTE *)(ptr))[1], ((BYTE *)(ptr))[0] )
145 /* This is bascially a copy of FT_Bitmap_Size with an extra element added */
146 typedef struct {
147 FT_Short height;
148 FT_Short width;
149 FT_Pos size;
150 FT_Pos x_ppem;
151 FT_Pos y_ppem;
152 FT_Short internal_leading;
153 } Bitmap_Size;
155 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
156 So to let this compile on older versions of FreeType we'll define the
157 new structure here. */
158 typedef struct {
159 FT_Short height, width;
160 FT_Pos size, x_ppem, y_ppem;
161 } My_FT_Bitmap_Size;
163 typedef struct tagFace {
164 WCHAR *StyleName;
165 char *file;
166 FT_Long face_index;
167 BOOL Italic;
168 BOOL Bold;
169 FONTSIGNATURE fs;
170 FT_Fixed font_version;
171 BOOL scalable;
172 Bitmap_Size size; /* set if face is a bitmap */
173 BOOL external; /* TRUE if we should manually add this font to the registry */
174 struct tagFace *next;
175 struct tagFamily *family;
176 } Face;
178 typedef struct tagFamily {
179 WCHAR *FamilyName;
180 Face *FirstFace;
181 struct tagFamily *next;
182 } Family;
184 typedef struct {
185 GLYPHMETRICS gm;
186 INT adv; /* These three hold to widths of the unrotated chars */
187 INT lsb;
188 INT bbx;
189 BOOL init;
190 } GM;
192 struct tagGdiFont {
193 struct list entry;
194 FT_Face ft_face;
195 XFORM xform;
196 LPWSTR name;
197 int charset;
198 BOOL fake_italic;
199 BOOL fake_bold;
200 BYTE underline;
201 BYTE strikeout;
202 INT orientation;
203 GM *gm;
204 DWORD gmsize;
205 HFONT hfont;
206 LONG aveWidth;
207 SHORT yMax;
208 SHORT yMin;
209 OUTLINETEXTMETRICW *potm;
210 FONTSIGNATURE fs;
213 #define INIT_GM_SIZE 128
215 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
217 static Family *FontList = NULL;
219 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ',
220 'R','o','m','a','n','\0'};
221 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
222 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
224 static const WCHAR defSystem[] = {'A','r','i','a','l','\0'};
225 static const WCHAR SystemW[] = {'S','y','s','t','e','m','\0'};
226 static const WCHAR MSSansSerifW[] = {'M','S',' ','S','a','n','s',' ',
227 'S','e','r','i','f','\0'};
228 static const WCHAR HelvW[] = {'H','e','l','v','\0'};
229 static const WCHAR RegularW[] = {'R','e','g','u','l','a','r','\0'};
231 static const WCHAR fontsW[] = {'\\','F','o','n','t','s','\0'};
232 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
233 'W','i','n','d','o','w','s','\\',
234 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
235 'F','o','n','t','s','\0'};
237 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
238 'W','i','n','d','o','w','s',' ','N','T','\\',
239 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
240 'F','o','n','t','s','\0'};
242 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
243 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
244 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
245 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
247 static const WCHAR *SystemFontValues[4] = {
248 System_Value,
249 OEMFont_Value,
250 FixedSys_Value,
251 NULL
254 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\','W','i','n','e','\\',
255 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
257 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
258 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
259 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
260 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
261 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
262 'E','u','r','o','p','e','a','n','\0'};
263 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
264 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
265 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
266 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
267 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
268 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
269 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
270 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
271 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
272 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
273 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
274 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
276 static const WCHAR *ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
277 WesternW, /*00*/
278 Central_EuropeanW,
279 CyrillicW,
280 GreekW,
281 TurkishW,
282 HebrewW,
283 ArabicW,
284 BalticW,
285 VietnameseW, /*08*/
286 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
287 ThaiW,
288 JapaneseW,
289 CHINESE_GB2312W,
290 HangulW,
291 CHINESE_BIG5W,
292 Hangul_Johab_W,
293 NULL, NULL, /*23*/
294 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
295 SymbolW /*31*/
298 typedef struct {
299 WCHAR *name;
300 INT charset;
301 } NameCs;
303 typedef struct tagFontSubst {
304 NameCs from;
305 NameCs to;
306 struct tagFontSubst *next;
307 } FontSubst;
309 static FontSubst *substlist = NULL;
310 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
312 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
315 /****************************************
316 * Notes on .fon files
318 * The fonts System, FixedSys and Terminal are special. There are typically multiple
319 * versions installed for different resolutions and codepages. Windows stores which one to use
320 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
321 * Key Meaning
322 * FIXEDFON.FON FixedSys
323 * FONTS.FON System
324 * OEMFONT.FON Termial
325 * LogPixels Current dpi set by the display control panel applet
326 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
327 * also has a LogPixels value that appears to mirror this)
329 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
330 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
331 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
332 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
333 * so that makes sense.
335 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
336 * to be mapped into the registry on Windows 2000 at least).
337 * I have
338 * woafont=app850.fon
339 * ega80woa.fon=ega80850.fon
340 * ega40woa.fon=ega40850.fon
341 * cga80woa.fon=cga80850.fon
342 * cga40woa.fon=cga40850.fon
346 static inline BOOL is_win9x(void)
348 return GetVersion() & 0x80000000;
351 This function builds an FT_Fixed from a float. It puts the integer part
352 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
353 It fails if the integer part of the float number is greater than SHORT_MAX.
355 static inline FT_Fixed FT_FixedFromFloat(float f)
357 short value = f;
358 unsigned short fract = (f - value) * 0xFFFF;
359 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
363 This function builds an FT_Fixed from a FIXED. It simply put f.value
364 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
366 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
368 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
371 #define ADDFONT_EXTERNAL_FONT 0x01
372 #define ADDFONT_FORCE_BITMAP 0x02
373 static BOOL AddFontFileToList(const char *file, char *fake_family, DWORD flags)
375 FT_Face ft_face;
376 TT_OS2 *pOS2;
377 TT_Header *pHeader = NULL;
378 WCHAR *FamilyW, *StyleW;
379 DWORD len;
380 Family **pfamily;
381 Face **insertface, *next;
382 FT_Error err;
383 FT_Long face_index = 0, num_faces;
384 #ifdef HAVE_FREETYPE_FTWINFNT_H
385 FT_WinFNT_HeaderRec winfnt_header;
386 #endif
387 int i, bitmap_num;
389 do {
390 char *family_name = fake_family;
392 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
393 if((err = pFT_New_Face(library, file, face_index, &ft_face)) != 0) {
394 WARN("Unable to load font file %s err = %x\n", debugstr_a(file), err);
395 return FALSE;
398 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*/
399 pFT_Done_Face(ft_face);
400 return FALSE;
403 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
404 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
405 pFT_Done_Face(ft_face);
406 return FALSE;
409 if(FT_IS_SFNT(ft_face) && (!pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2) ||
410 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
411 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))) {
412 TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
413 "Skipping this font.\n", debugstr_a(file));
414 pFT_Done_Face(ft_face);
415 return FALSE;
418 if(!ft_face->family_name || !ft_face->style_name) {
419 TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file));
420 pFT_Done_Face(ft_face);
421 return FALSE;
424 if(!family_name)
425 family_name = ft_face->family_name;
427 bitmap_num = 0;
428 do {
429 My_FT_Bitmap_Size *size = NULL;
431 if(!FT_IS_SCALABLE(ft_face))
432 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
434 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
435 FamilyW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
436 MultiByteToWideChar(CP_ACP, 0, family_name, -1, FamilyW, len);
438 pfamily = &FontList;
439 while(*pfamily) {
440 if(!strcmpW((*pfamily)->FamilyName, FamilyW))
441 break;
442 pfamily = &(*pfamily)->next;
444 if(!*pfamily) {
445 *pfamily = HeapAlloc(GetProcessHeap(), 0, sizeof(**pfamily));
446 (*pfamily)->FamilyName = FamilyW;
447 (*pfamily)->FirstFace = NULL;
448 (*pfamily)->next = NULL;
449 } else {
450 HeapFree(GetProcessHeap(), 0, FamilyW);
453 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
454 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
455 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
457 next = NULL;
458 for(insertface = &(*pfamily)->FirstFace; *insertface;
459 insertface = &(*insertface)->next) {
460 if(!strcmpW((*insertface)->StyleName, StyleW) && (FT_IS_SCALABLE(ft_face) || (size->y_ppem == (*insertface)->size.y_ppem))) {
461 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
462 debugstr_w((*pfamily)->FamilyName), debugstr_w(StyleW),
463 (*insertface)->font_version, pHeader ? pHeader->Font_Revision : 0);
465 if(fake_family) {
466 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
467 HeapFree(GetProcessHeap(), 0, StyleW);
468 pFT_Done_Face(ft_face);
469 return FALSE;
471 if(!pHeader || pHeader->Font_Revision <= (*insertface)->font_version) {
472 TRACE("Original font is newer so skipping this one\n");
473 HeapFree(GetProcessHeap(), 0, StyleW);
474 pFT_Done_Face(ft_face);
475 return FALSE;
476 } else {
477 TRACE("Replacing original with this one\n");
478 next = (*insertface)->next;
479 HeapFree(GetProcessHeap(), 0, (*insertface)->file);
480 HeapFree(GetProcessHeap(), 0, (*insertface)->StyleName);
481 HeapFree(GetProcessHeap(), 0, *insertface);
482 break;
486 *insertface = HeapAlloc(GetProcessHeap(), 0, sizeof(**insertface));
487 (*insertface)->StyleName = StyleW;
488 (*insertface)->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
489 strcpy((*insertface)->file, file);
490 (*insertface)->face_index = face_index;
491 (*insertface)->next = next;
492 (*insertface)->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
493 (*insertface)->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
494 (*insertface)->font_version = pHeader ? pHeader->Font_Revision : 0;
495 (*insertface)->family = *pfamily;
496 (*insertface)->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
498 if(FT_IS_SCALABLE(ft_face)) {
499 memset(&(*insertface)->size, 0, sizeof((*insertface)->size));
500 (*insertface)->scalable = TRUE;
501 } else {
502 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
503 size->height, size->width, size->size >> 6,
504 size->x_ppem >> 6, size->y_ppem >> 6);
505 (*insertface)->size.height = size->height;
506 (*insertface)->size.width = size->width;
507 (*insertface)->size.size = size->size;
508 (*insertface)->size.x_ppem = size->x_ppem;
509 (*insertface)->size.y_ppem = size->y_ppem;
510 (*insertface)->size.internal_leading = 0;
511 (*insertface)->scalable = FALSE;
514 memset(&(*insertface)->fs, 0, sizeof((*insertface)->fs));
516 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
517 if(pOS2) {
518 (*insertface)->fs.fsCsb[0] = pOS2->ulCodePageRange1;
519 (*insertface)->fs.fsCsb[1] = pOS2->ulCodePageRange2;
520 (*insertface)->fs.fsUsb[0] = pOS2->ulUnicodeRange1;
521 (*insertface)->fs.fsUsb[1] = pOS2->ulUnicodeRange2;
522 (*insertface)->fs.fsUsb[2] = pOS2->ulUnicodeRange3;
523 (*insertface)->fs.fsUsb[3] = pOS2->ulUnicodeRange4;
524 if(pOS2->version == 0) {
525 FT_UInt dummy;
527 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
528 (*insertface)->fs.fsCsb[0] |= 1;
529 else
530 (*insertface)->fs.fsCsb[0] |= 1L << 31;
533 #ifdef HAVE_FREETYPE_FTWINFNT_H
534 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
535 CHARSETINFO csi;
536 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
537 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
538 if(TranslateCharsetInfo((DWORD*)(UINT)winfnt_header.charset, &csi, TCI_SRCCHARSET))
539 memcpy(&(*insertface)->fs, &csi.fs, sizeof(csi.fs));
540 (*insertface)->size.internal_leading = winfnt_header.internal_leading;
542 #endif
543 TRACE("fsCsb = %08lx %08lx/%08lx %08lx %08lx %08lx\n",
544 (*insertface)->fs.fsCsb[0], (*insertface)->fs.fsCsb[1],
545 (*insertface)->fs.fsUsb[0], (*insertface)->fs.fsUsb[1],
546 (*insertface)->fs.fsUsb[2], (*insertface)->fs.fsUsb[3]);
549 if((*insertface)->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
550 for(i = 0; i < ft_face->num_charmaps; i++) {
551 switch(ft_face->charmaps[i]->encoding) {
552 case ft_encoding_unicode:
553 case ft_encoding_apple_roman:
554 (*insertface)->fs.fsCsb[0] |= 1;
555 break;
556 case ft_encoding_symbol:
557 (*insertface)->fs.fsCsb[0] |= 1L << 31;
558 break;
559 default:
560 break;
565 if((*insertface)->fs.fsCsb[0] & ~(1L << 31))
566 have_installed_roman_font = TRUE;
567 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
569 num_faces = ft_face->num_faces;
570 pFT_Done_Face(ft_face);
571 TRACE("Added font %s %s\n", debugstr_w((*pfamily)->FamilyName),
572 debugstr_w(StyleW));
573 } while(num_faces > ++face_index);
574 return TRUE;
577 static void DumpFontList(void)
579 Family *family;
580 Face *face;
582 for(family = FontList; family; family = family->next) {
583 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
584 for(face = family->FirstFace; face; face = face->next) {
585 TRACE("\t%s", debugstr_w(face->StyleName));
586 if(!face->scalable)
587 TRACE(" %ld", face->size.y_ppem >> 6);
588 TRACE("\n");
591 return;
594 static void DumpSubstList(void)
596 FontSubst *psub;
598 for(psub = substlist; psub; psub = psub->next)
599 if(psub->from.charset != -1 || psub->to.charset != -1)
600 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
601 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
602 else
603 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
604 debugstr_w(psub->to.name));
605 return;
608 static LPWSTR strdupW(LPWSTR p)
610 LPWSTR ret;
611 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
612 ret = HeapAlloc(GetProcessHeap(), 0, len);
613 memcpy(ret, p, len);
614 return ret;
617 static void split_subst_info(NameCs *nc, LPSTR str)
619 CHAR *p = strrchr(str, ',');
620 DWORD len;
622 nc->charset = -1;
623 if(p && *(p+1)) {
624 nc->charset = strtol(p+1, NULL, 10);
625 *p = '\0';
627 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
628 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
629 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
632 static void LoadSubstList(void)
634 FontSubst *psub, **ppsub;
635 HKEY hkey;
636 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
637 LPSTR value;
638 LPVOID data;
640 if(substlist) {
641 for(psub = substlist; psub;) {
642 FontSubst *ptmp;
643 HeapFree(GetProcessHeap(), 0, psub->to.name);
644 HeapFree(GetProcessHeap(), 0, psub->from.name);
645 ptmp = psub;
646 psub = psub->next;
647 HeapFree(GetProcessHeap(), 0, ptmp);
649 substlist = NULL;
652 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
653 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
654 &hkey) == ERROR_SUCCESS) {
656 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
657 &valuelen, &datalen, NULL, NULL);
659 valuelen++; /* returned value doesn't include room for '\0' */
660 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
661 data = HeapAlloc(GetProcessHeap(), 0, datalen);
663 dlen = datalen;
664 vlen = valuelen;
665 ppsub = &substlist;
666 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
667 &dlen) == ERROR_SUCCESS) {
668 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
670 *ppsub = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppsub));
671 (*ppsub)->next = NULL;
672 split_subst_info(&((*ppsub)->from), value);
673 split_subst_info(&((*ppsub)->to), data);
675 /* Win 2000 doesn't allow mapping between different charsets
676 or mapping of DEFAULT_CHARSET */
677 if(((*ppsub)->to.charset != (*ppsub)->from.charset) ||
678 (*ppsub)->to.charset == DEFAULT_CHARSET) {
679 HeapFree(GetProcessHeap(), 0, (*ppsub)->to.name);
680 HeapFree(GetProcessHeap(), 0, (*ppsub)->from.name);
681 HeapFree(GetProcessHeap(), 0, *ppsub);
682 *ppsub = NULL;
683 } else {
684 ppsub = &((*ppsub)->next);
686 /* reset dlen and vlen */
687 dlen = datalen;
688 vlen = valuelen;
690 HeapFree(GetProcessHeap(), 0, data);
691 HeapFree(GetProcessHeap(), 0, value);
692 RegCloseKey(hkey);
696 /***********************************************************
697 * The replacement list is a way to map an entire font
698 * family onto another family. For example adding
700 * [HKLM\Software\Wine\Wine\FontReplacements]
701 * "Wingdings"="Winedings"
703 * would enumerate the Winedings font both as Winedings and
704 * Wingdings. However if a real Wingdings font is present the
705 * replacement does not take place.
708 static void LoadReplaceList(void)
710 HKEY hkey;
711 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
712 LPSTR value;
713 LPVOID data;
714 Family *family;
715 Face *face;
716 WCHAR old_nameW[200];
718 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
719 "Software\\Wine\\Wine\\FontReplacements",
720 &hkey) == ERROR_SUCCESS) {
722 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
723 &valuelen, &datalen, NULL, NULL);
725 valuelen++; /* returned value doesn't include room for '\0' */
726 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
727 data = HeapAlloc(GetProcessHeap(), 0, datalen);
729 dlen = datalen;
730 vlen = valuelen;
731 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
732 &dlen) == ERROR_SUCCESS) {
733 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
734 /* "NewName"="Oldname" */
735 if(!MultiByteToWideChar(CP_ACP, 0, data, -1, old_nameW, sizeof(old_nameW)))
736 break;
738 /* Find the old family and hence all of the font files
739 in that family */
740 for(family = FontList; family; family = family->next) {
741 if(!strcmpiW(family->FamilyName, old_nameW)) {
742 for(face = family->FirstFace; face; face = face->next) {
743 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
744 debugstr_w(face->StyleName), value);
745 /* Now add a new entry with the new family name */
746 AddFontFileToList(face->file, value, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
748 break;
751 /* reset dlen and vlen */
752 dlen = datalen;
753 vlen = valuelen;
755 HeapFree(GetProcessHeap(), 0, data);
756 HeapFree(GetProcessHeap(), 0, value);
757 RegCloseKey(hkey);
762 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
764 DIR *dir;
765 struct dirent *dent;
766 char path[MAX_PATH];
768 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
770 dir = opendir(dirname);
771 if(!dir) {
772 ERR("Can't open directory %s\n", debugstr_a(dirname));
773 return FALSE;
775 while((dent = readdir(dir)) != NULL) {
776 struct stat statbuf;
778 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
779 continue;
781 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
783 sprintf(path, "%s/%s", dirname, dent->d_name);
785 if(stat(path, &statbuf) == -1)
787 WARN("Can't stat %s\n", debugstr_a(path));
788 continue;
790 if(S_ISDIR(statbuf.st_mode))
791 ReadFontDir(path, external_fonts);
792 else
793 AddFontFileToList(path, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
795 closedir(dir);
796 return TRUE;
799 static void load_fontconfig_fonts(void)
801 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
802 void *fc_handle = NULL;
803 FcConfig *config;
804 FcPattern *pat;
805 FcObjectSet *os;
806 FcFontSet *fontset;
807 FcValue v;
808 int i, len;
809 const char *ext;
811 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
812 if(!fc_handle) {
813 TRACE("Wine cannot find the fontconfig library (%s).\n",
814 SONAME_LIBFONTCONFIG);
815 return;
817 #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;}
818 LOAD_FUNCPTR(FcConfigGetCurrent);
819 LOAD_FUNCPTR(FcFontList);
820 LOAD_FUNCPTR(FcFontSetDestroy);
821 LOAD_FUNCPTR(FcInit);
822 LOAD_FUNCPTR(FcObjectSetAdd);
823 LOAD_FUNCPTR(FcObjectSetCreate);
824 LOAD_FUNCPTR(FcObjectSetDestroy);
825 LOAD_FUNCPTR(FcPatternCreate);
826 LOAD_FUNCPTR(FcPatternDestroy);
827 LOAD_FUNCPTR(FcPatternGet);
828 #undef LOAD_FUNCPTR
830 if(!pFcInit()) return;
832 config = pFcConfigGetCurrent();
833 pat = pFcPatternCreate();
834 os = pFcObjectSetCreate();
835 pFcObjectSetAdd(os, FC_FILE);
836 fontset = pFcFontList(config, pat, os);
837 if(!fontset) return;
838 for(i = 0; i < fontset->nfont; i++) {
839 if(pFcPatternGet(fontset->fonts[i], FC_FILE, 0, &v) != FcResultMatch)
840 continue;
841 if(v.type != FcTypeString) continue;
842 TRACE("fontconfig: %s\n", v.u.s);
844 /* We're just interested in OT/TT fonts for now, so this hack just
845 picks up the standard extensions to save time loading every other
846 font */
847 len = strlen(v.u.s);
848 if(len < 4) continue;
849 ext = v.u.s + len - 3;
850 if(!strcasecmp(ext, "ttf") || !strcasecmp(ext, "ttc") || !strcasecmp(ext, "otf"))
851 AddFontFileToList(v.u.s, NULL, ADDFONT_EXTERNAL_FONT);
853 pFcFontSetDestroy(fontset);
854 pFcObjectSetDestroy(os);
855 pFcPatternDestroy(pat);
856 sym_not_found:
857 #endif
858 return;
862 void load_system_fonts(void)
864 HKEY hkey;
865 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
866 const WCHAR **value;
867 DWORD dlen, type;
868 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
869 char *unixname;
871 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
872 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
873 strcatW(windowsdir, fontsW);
874 for(value = SystemFontValues; *value; value++) {
875 dlen = sizeof(data);
876 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
877 type == REG_SZ) {
878 sprintfW(pathW, fmtW, windowsdir, data);
879 if((unixname = wine_get_unix_file_name(pathW))) {
880 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
881 HeapFree(GetProcessHeap(), 0, unixname);
885 RegCloseKey(hkey);
889 /*************************************************************
891 * This adds registry entries for any externally loaded fonts
892 * (fonts from fontconfig or FontDirs). It also deletes entries
893 * of no longer existing fonts.
896 void update_reg_entries(void)
898 HKEY winkey = 0, externalkey = 0;
899 LPWSTR valueW;
900 LPVOID data;
901 DWORD dlen, vlen, datalen, valuelen, i, type, len, len_fam;
902 Family *family;
903 Face *face;
904 WCHAR *file;
905 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
906 static const WCHAR spaceW[] = {' ', '\0'};
907 char *path;
909 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
910 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winkey, NULL) != ERROR_SUCCESS) {
911 ERR("Can't create Windows font reg key\n");
912 goto end;
914 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, external_fonts_reg_key,
915 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
916 ERR("Can't create external font reg key\n");
917 goto end;
920 /* Delete all external fonts added last time */
922 RegQueryInfoKeyW(externalkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
923 &valuelen, &datalen, NULL, NULL);
924 valuelen++; /* returned value doesn't include room for '\0' */
925 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
926 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
928 dlen = datalen * sizeof(WCHAR);
929 vlen = valuelen;
930 i = 0;
931 while(RegEnumValueW(externalkey, i++, valueW, &vlen, NULL, &type, data,
932 &dlen) == ERROR_SUCCESS) {
934 RegDeleteValueW(winkey, valueW);
935 /* reset dlen and vlen */
936 dlen = datalen;
937 vlen = valuelen;
939 HeapFree(GetProcessHeap(), 0, data);
940 HeapFree(GetProcessHeap(), 0, valueW);
942 /* Delete the old external fonts key */
943 RegCloseKey(externalkey);
944 externalkey = 0;
945 RegDeleteKeyW(HKEY_LOCAL_MACHINE, external_fonts_reg_key);
947 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, external_fonts_reg_key,
948 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
949 ERR("Can't create external font reg key\n");
950 goto end;
953 /* enumerate the fonts and add external ones to the two keys */
955 for(family = FontList; family; family = family->next) {
956 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
957 for(face = family->FirstFace; face; face = face->next) {
958 if(!face->external) continue;
959 len = len_fam;
960 if(strcmpiW(face->StyleName, RegularW))
961 len = len_fam + strlenW(face->StyleName) + 1;
962 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
963 strcpyW(valueW, family->FamilyName);
964 if(len != len_fam) {
965 strcatW(valueW, spaceW);
966 strcatW(valueW, face->StyleName);
968 strcatW(valueW, TrueType);
969 if((path = strrchr(face->file, '/')) == NULL)
970 path = face->file;
971 else
972 path++;
973 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
975 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
976 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
977 RegSetValueExW(winkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
978 RegSetValueExW(externalkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
980 HeapFree(GetProcessHeap(), 0, file);
981 HeapFree(GetProcessHeap(), 0, valueW);
984 end:
985 if(externalkey)
986 RegCloseKey(externalkey);
987 if(winkey)
988 RegCloseKey(winkey);
989 return;
993 /*************************************************************
994 * WineEngAddFontResourceEx
997 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
999 if (ft_handle) /* do it only if we have freetype up and running */
1001 char *unixname;
1003 if(flags)
1004 FIXME("Ignoring flags %lx\n", flags);
1006 if((unixname = wine_get_unix_file_name(file)))
1008 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1009 HeapFree(GetProcessHeap(), 0, unixname);
1012 return 1;
1015 /*************************************************************
1016 * WineEngRemoveFontResourceEx
1019 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1021 FIXME(":stub\n");
1022 return TRUE;
1025 /*************************************************************
1026 * WineEngInit
1028 * Initialize FreeType library and create a list of available faces
1030 BOOL WineEngInit(void)
1032 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
1033 HKEY hkey;
1034 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1035 LPVOID data;
1036 WCHAR windowsdir[MAX_PATH];
1037 char *unixname;
1038 HANDLE font_mutex;
1040 TRACE("\n");
1042 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
1043 if(!ft_handle) {
1044 WINE_MESSAGE(
1045 "Wine cannot find the FreeType font library. To enable Wine to\n"
1046 "use TrueType fonts please install a version of FreeType greater than\n"
1047 "or equal to 2.0.5.\n"
1048 "http://www.freetype.org\n");
1049 return FALSE;
1052 #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;}
1054 LOAD_FUNCPTR(FT_Vector_Unit)
1055 LOAD_FUNCPTR(FT_Done_Face)
1056 LOAD_FUNCPTR(FT_Get_Char_Index)
1057 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
1058 LOAD_FUNCPTR(FT_Init_FreeType)
1059 LOAD_FUNCPTR(FT_Load_Glyph)
1060 LOAD_FUNCPTR(FT_Matrix_Multiply)
1061 LOAD_FUNCPTR(FT_MulFix)
1062 LOAD_FUNCPTR(FT_New_Face)
1063 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
1064 LOAD_FUNCPTR(FT_Outline_Transform)
1065 LOAD_FUNCPTR(FT_Outline_Translate)
1066 LOAD_FUNCPTR(FT_Select_Charmap)
1067 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
1068 LOAD_FUNCPTR(FT_Vector_Transform)
1070 #undef LOAD_FUNCPTR
1071 /* Don't warn if this one is missing */
1072 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
1073 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
1074 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
1075 #ifdef HAVE_FREETYPE_FTWINFNT_H
1076 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
1077 #endif
1078 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
1079 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
1080 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
1081 <= 2.0.3 has FT_Sqrt64 */
1082 goto sym_not_found;
1085 if(pFT_Init_FreeType(&library) != 0) {
1086 ERR("Can't init FreeType library\n");
1087 wine_dlclose(ft_handle, NULL, 0);
1088 ft_handle = NULL;
1089 return FALSE;
1091 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
1092 if (pFT_Library_Version)
1094 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
1096 if (FT_Version.major<=0)
1098 FT_Version.major=2;
1099 FT_Version.minor=0;
1100 FT_Version.patch=5;
1102 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
1103 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
1104 ((FT_Version.minor << 8) & 0x00ff00) |
1105 ((FT_Version.patch ) & 0x0000ff);
1107 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
1108 ERR("Failed to create font mutex\n");
1109 return FALSE;
1111 WaitForSingleObject(font_mutex, INFINITE);
1113 /* load the system fonts */
1114 load_system_fonts();
1116 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
1117 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1118 strcatW(windowsdir, fontsW);
1119 if((unixname = wine_get_unix_file_name(windowsdir)))
1121 ReadFontDir(unixname, FALSE);
1122 HeapFree(GetProcessHeap(), 0, unixname);
1125 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
1126 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
1127 full path as the entry. Also look for any .fon fonts, since ReadFontDir
1128 will skip these. */
1129 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
1130 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1131 &hkey) == ERROR_SUCCESS) {
1132 LPWSTR valueW;
1133 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1134 &valuelen, &datalen, NULL, NULL);
1136 valuelen++; /* returned value doesn't include room for '\0' */
1137 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1138 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1139 if (valueW && data)
1141 dlen = datalen * sizeof(WCHAR);
1142 vlen = valuelen;
1143 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
1144 &dlen) == ERROR_SUCCESS) {
1145 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
1147 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
1149 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1150 HeapFree(GetProcessHeap(), 0, unixname);
1153 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
1155 WCHAR pathW[MAX_PATH];
1156 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1157 sprintfW(pathW, fmtW, windowsdir, data);
1158 if((unixname = wine_get_unix_file_name(pathW)))
1160 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1161 HeapFree(GetProcessHeap(), 0, unixname);
1164 /* reset dlen and vlen */
1165 dlen = datalen;
1166 vlen = valuelen;
1169 if (data) HeapFree(GetProcessHeap(), 0, data);
1170 if (valueW) HeapFree(GetProcessHeap(), 0, valueW);
1171 RegCloseKey(hkey);
1174 load_fontconfig_fonts();
1176 /* then look in any directories that we've specified in the config file */
1177 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1178 "Software\\Wine\\Wine\\Config\\FontDirs",
1179 &hkey) == ERROR_SUCCESS) {
1180 LPSTR value;
1181 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1182 &valuelen, &datalen, NULL, NULL);
1184 valuelen++; /* returned value doesn't include room for '\0' */
1185 value = HeapAlloc(GetProcessHeap(), 0, valuelen);
1186 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1188 dlen = datalen;
1189 vlen = valuelen;
1190 i = 0;
1191 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1192 &dlen) == ERROR_SUCCESS) {
1193 TRACE("Got %s=%s\n", value, (LPSTR)data);
1194 ReadFontDir((LPSTR)data, TRUE);
1195 /* reset dlen and vlen */
1196 dlen = datalen;
1197 vlen = valuelen;
1199 HeapFree(GetProcessHeap(), 0, data);
1200 HeapFree(GetProcessHeap(), 0, value);
1201 RegCloseKey(hkey);
1204 DumpFontList();
1205 LoadSubstList();
1206 DumpSubstList();
1207 LoadReplaceList();
1208 update_reg_entries();
1210 ReleaseMutex(font_mutex);
1211 return TRUE;
1212 sym_not_found:
1213 WINE_MESSAGE(
1214 "Wine cannot find certain functions that it needs inside the FreeType\n"
1215 "font library. To enable Wine to use TrueType fonts please upgrade\n"
1216 "FreeType to at least version 2.0.5.\n"
1217 "http://www.freetype.org\n");
1218 wine_dlclose(ft_handle, NULL, 0);
1219 ft_handle = NULL;
1220 return FALSE;
1224 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
1226 TT_OS2 *pOS2;
1227 TT_HoriHeader *pHori;
1229 LONG ppem;
1231 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1232 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1234 if(height == 0) height = 16;
1236 /* Calc. height of EM square:
1238 * For +ve lfHeight we have
1239 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
1240 * Re-arranging gives:
1241 * ppem = units_per_em * lfheight / (winAscent + winDescent)
1243 * For -ve lfHeight we have
1244 * |lfHeight| = ppem
1245 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
1246 * with il = winAscent + winDescent - units_per_em]
1250 if(height > 0) {
1251 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
1252 ppem = ft_face->units_per_EM * height /
1253 (pHori->Ascender - pHori->Descender);
1254 else
1255 ppem = ft_face->units_per_EM * height /
1256 (pOS2->usWinAscent + pOS2->usWinDescent);
1258 else
1259 ppem = -height;
1261 return ppem;
1264 static LONG load_VDMX(GdiFont, LONG);
1266 static FT_Face OpenFontFile(GdiFont font, char *file, FT_Long face_index, LONG width, LONG height)
1268 FT_Error err;
1269 FT_Face ft_face;
1270 LONG ppem;
1272 err = pFT_New_Face(library, file, face_index, &ft_face);
1273 if(err) {
1274 ERR("FT_New_Face rets %d\n", err);
1275 return 0;
1278 /* set it here, as load_VDMX needs it */
1279 font->ft_face = ft_face;
1281 if(FT_IS_SCALABLE(ft_face)) {
1282 /* load the VDMX table if we have one */
1283 ppem = load_VDMX(font, height);
1284 if(ppem == 0)
1285 ppem = calc_ppem_for_height(ft_face, height);
1287 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, ppem)) != 0)
1288 WARN("FT_Set_Pixel_Sizes %d, %ld rets %x\n", 0, ppem, err);
1289 } else {
1290 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
1291 WARN("FT_Set_Pixel_Sizes %ld, %ld rets %x\n", width, height, err);
1293 return ft_face;
1297 static int get_nearest_charset(Face *face)
1299 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
1300 a single face with the requested charset. The idea is to check if
1301 the selected font supports the current ANSI codepage, if it does
1302 return the corresponding charset, else return the first charset */
1304 CHARSETINFO csi;
1305 int acp = GetACP(), i;
1306 DWORD fs0;
1308 if(TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE))
1309 if(csi.fs.fsCsb[0] & face->fs.fsCsb[0])
1310 return csi.ciCharset;
1312 for(i = 0; i < 32; i++) {
1313 fs0 = 1L << i;
1314 if(face->fs.fsCsb[0] & fs0) {
1315 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG))
1316 return csi.ciCharset;
1317 else
1318 FIXME("TCI failing on %lx\n", fs0);
1322 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08lx file = %s\n",
1323 face->fs.fsCsb[0], face->file);
1324 return DEFAULT_CHARSET;
1327 static GdiFont alloc_font(void)
1329 GdiFont ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
1330 ret->gmsize = INIT_GM_SIZE;
1331 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1332 ret->gmsize * sizeof(*ret->gm));
1333 ret->potm = NULL;
1334 ret->xform.eM11 = ret->xform.eM22 = 1.0;
1335 return ret;
1338 static void free_font(GdiFont font)
1340 if (font->ft_face) pFT_Done_Face(font->ft_face);
1341 if (font->potm) HeapFree(GetProcessHeap(), 0, font->potm);
1342 if (font->name) HeapFree(GetProcessHeap(), 0, font->name);
1343 HeapFree(GetProcessHeap(), 0, font->gm);
1344 HeapFree(GetProcessHeap(), 0, font);
1348 /*************************************************************
1349 * load_VDMX
1351 * load the vdmx entry for the specified height
1354 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
1355 ( ( (FT_ULong)_x4 << 24 ) | \
1356 ( (FT_ULong)_x3 << 16 ) | \
1357 ( (FT_ULong)_x2 << 8 ) | \
1358 (FT_ULong)_x1 )
1360 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
1362 typedef struct {
1363 BYTE bCharSet;
1364 BYTE xRatio;
1365 BYTE yStartRatio;
1366 BYTE yEndRatio;
1367 } Ratios;
1370 static LONG load_VDMX(GdiFont font, LONG height)
1372 BYTE hdr[6], tmp[2], group[4];
1373 BYTE devXRatio, devYRatio;
1374 USHORT numRecs, numRatios;
1375 DWORD offset = -1;
1376 LONG ppem = 0;
1377 int i, result;
1379 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
1381 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
1382 return ppem;
1384 /* FIXME: need the real device aspect ratio */
1385 devXRatio = 1;
1386 devYRatio = 1;
1388 numRecs = GET_BE_WORD(&hdr[2]);
1389 numRatios = GET_BE_WORD(&hdr[4]);
1391 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
1392 for(i = 0; i < numRatios; i++) {
1393 Ratios ratio;
1395 offset = (3 * 2) + (i * sizeof(Ratios));
1396 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
1397 offset = -1;
1399 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
1401 if(ratio.bCharSet != 1)
1402 continue;
1404 if((ratio.xRatio == 0 &&
1405 ratio.yStartRatio == 0 &&
1406 ratio.yEndRatio == 0) ||
1407 (devXRatio == ratio.xRatio &&
1408 devYRatio >= ratio.yStartRatio &&
1409 devYRatio <= ratio.yEndRatio))
1411 offset = (3 * 2) + (numRatios * 4) + (i * 2);
1412 WineEngGetFontData(font, MS_VDMX_TAG, offset, tmp, 2);
1413 offset = GET_BE_WORD(tmp);
1414 break;
1418 if(offset < 0) {
1419 FIXME("No suitable ratio found\n");
1420 return ppem;
1423 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, group, 4) != GDI_ERROR) {
1424 USHORT recs;
1425 BYTE startsz, endsz;
1426 BYTE *vTable;
1428 recs = GET_BE_WORD(group);
1429 startsz = group[2];
1430 endsz = group[3];
1432 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
1434 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
1435 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
1436 if(result == GDI_ERROR) {
1437 FIXME("Failed to retrieve vTable\n");
1438 goto end;
1441 if(height > 0) {
1442 for(i = 0; i < recs; i++) {
1443 SHORT yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1444 SHORT yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1445 ppem = GET_BE_WORD(&vTable[i * 6]);
1447 if(yMax + -yMin == height) {
1448 font->yMax = yMax;
1449 font->yMin = yMin;
1450 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1451 break;
1453 if(yMax + -yMin > height) {
1454 if(--i < 0) {
1455 ppem = 0;
1456 goto end; /* failed */
1458 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1459 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1460 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1461 break;
1464 if(!font->yMax) {
1465 ppem = 0;
1466 TRACE("ppem not found for height %ld\n", height);
1468 } else {
1469 ppem = -height;
1470 if(ppem < startsz || ppem > endsz)
1471 goto end;
1473 for(i = 0; i < recs; i++) {
1474 USHORT yPelHeight;
1475 yPelHeight = GET_BE_WORD(&vTable[i * 6]);
1477 if(yPelHeight > ppem)
1478 break; /* failed */
1480 if(yPelHeight == ppem) {
1481 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1482 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1483 TRACE("ppem %ld found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
1484 break;
1488 end:
1489 HeapFree(GetProcessHeap(), 0, vTable);
1492 return ppem;
1496 /*************************************************************
1497 * WineEngCreateFontInstance
1500 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
1502 GdiFont ret;
1503 Face *face, *best;
1504 Family *family = NULL;
1505 INT height, width = 0;
1506 signed int diff = 0, newdiff;
1507 BOOL bd, it, can_use_bitmap;
1508 LOGFONTW lf;
1509 CHARSETINFO csi;
1510 struct list *elem_ptr;
1512 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
1513 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
1515 TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
1516 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
1517 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
1518 lf.lfEscapement);
1520 /* check the cache first */
1521 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
1522 ret = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
1523 if(ret->hfont == hfont && !memcmp(&ret->xform, &dc->xformWorld2Vport, offsetof(XFORM, eDx)) &&
1524 (can_use_bitmap || FT_IS_SCALABLE(ret->ft_face))) {
1526 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
1527 return ret;
1531 if(!FontList || !have_installed_roman_font) /* No fonts installed */
1533 TRACE("No fonts installed\n");
1534 return NULL;
1537 ret = alloc_font();
1538 memcpy(&ret->xform, &dc->xformWorld2Vport, sizeof(XFORM));
1540 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
1541 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
1542 original value lfCharSet. Note this is a special case for
1543 Symbol and doesn't happen at least for "Wingdings*" */
1545 if(!strcmpiW(lf.lfFaceName, SymbolW))
1546 lf.lfCharSet = SYMBOL_CHARSET;
1548 if(!TranslateCharsetInfo((DWORD*)(INT)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
1549 switch(lf.lfCharSet) {
1550 case DEFAULT_CHARSET:
1551 csi.fs.fsCsb[0] = 0;
1552 break;
1553 default:
1554 FIXME("Untranslated charset %d\n", lf.lfCharSet);
1555 csi.fs.fsCsb[0] = 0;
1556 break;
1560 if(lf.lfFaceName[0] != '\0') {
1561 FontSubst *psub;
1562 for(psub = substlist; psub; psub = psub->next)
1563 if(!strcmpiW(lf.lfFaceName, psub->from.name) &&
1564 (psub->from.charset == -1 ||
1565 psub->from.charset == lf.lfCharSet))
1566 break;
1567 if(psub) {
1568 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
1569 debugstr_w(psub->to.name));
1570 strcpyW(lf.lfFaceName, psub->to.name);
1573 /* We want a match on name and charset or just name if
1574 charset was DEFAULT_CHARSET. If the latter then
1575 we fixup the returned charset later in get_nearest_charset
1576 where we'll either use the charset of the current ansi codepage
1577 or if that's unavailable the first charset that the font supports.
1579 for(family = FontList; family; family = family->next) {
1580 if(!strcmpiW(family->FamilyName, lf.lfFaceName))
1581 if((csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0]) || !csi.fs.fsCsb[0])
1582 if(family->FirstFace->scalable || can_use_bitmap)
1583 break;
1587 if(!family) {
1588 /* If requested charset was DEFAULT_CHARSET then try using charset
1589 corresponding to the current ansi codepage */
1590 if(!csi.fs.fsCsb[0]) {
1591 INT acp = GetACP();
1592 if(!TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE)) {
1593 FIXME("TCI failed on codepage %d\n", acp);
1594 csi.fs.fsCsb[0] = 0;
1595 } else
1596 lf.lfCharSet = csi.ciCharset;
1599 /* Face families are in the top 4 bits of lfPitchAndFamily,
1600 so mask with 0xF0 before testing */
1602 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
1603 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
1604 strcpyW(lf.lfFaceName, defFixed);
1605 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
1606 strcpyW(lf.lfFaceName, defSerif);
1607 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
1608 strcpyW(lf.lfFaceName, defSans);
1609 else
1610 strcpyW(lf.lfFaceName, defSans);
1611 for(family = FontList; family; family = family->next) {
1612 if(!strcmpiW(family->FamilyName, lf.lfFaceName) &&
1613 (csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0]))
1614 if(family->FirstFace->scalable || can_use_bitmap)
1615 break;
1619 if(!family) {
1620 for(family = FontList; family; family = family->next) {
1621 if(csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0])
1622 if(family->FirstFace->scalable || can_use_bitmap)
1623 break;
1627 if(!family) {
1628 family = FontList;
1629 csi.fs.fsCsb[0] = 0;
1630 FIXME("just using first face for now\n");
1633 it = lf.lfItalic ? 1 : 0;
1634 bd = lf.lfWeight > 550 ? 1 : 0;
1636 height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
1637 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
1639 best = NULL;
1640 for(face = family->FirstFace; face; face = face->next) {
1641 if(!(face->Italic ^ it) && !(face->Bold ^ bd)) {
1642 if(face->scalable)
1643 break;
1644 if(height > 0)
1645 newdiff = height - (signed int)(face->size.y_ppem >> 6);
1646 else
1647 newdiff = -height - ((signed int)(face->size.y_ppem >> 6) - face->size.internal_leading);
1648 if(!best || (diff > 0 && newdiff < diff && newdiff >= 0) ||
1649 (diff < 0 && newdiff > diff)) {
1650 TRACE("%ld is better for %d diff was %d\n", face->size.y_ppem >> 6, height, diff);
1651 diff = newdiff;
1652 best = face;
1653 if(diff == 0)
1654 break;
1658 if(!face && best)
1659 face = best;
1660 else if(!face) {
1661 face = family->FirstFace;
1662 if(it && !face->Italic) ret->fake_italic = TRUE;
1663 if(bd && !face->Bold) ret->fake_bold = TRUE;
1666 memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
1668 if(csi.fs.fsCsb[0])
1669 ret->charset = lf.lfCharSet;
1670 else
1671 ret->charset = get_nearest_charset(face);
1673 TRACE("Chosen: %s %s\n", debugstr_w(family->FamilyName),
1674 debugstr_w(face->StyleName));
1676 if(!face->scalable) {
1677 width = face->size.x_ppem >> 6;
1678 height = face->size.y_ppem >> 6;
1680 ret->ft_face = OpenFontFile(ret, face->file, face->face_index, width, height);
1682 if (!ret->ft_face)
1684 free_font( ret );
1685 return 0;
1688 if (ret->charset == SYMBOL_CHARSET &&
1689 !pFT_Select_Charmap(ret->ft_face, ft_encoding_symbol)) {
1690 /* No ops */
1692 else if (!pFT_Select_Charmap(ret->ft_face, ft_encoding_unicode)) {
1693 /* No ops */
1695 else {
1696 pFT_Select_Charmap(ret->ft_face, ft_encoding_apple_roman);
1699 ret->orientation = lf.lfOrientation;
1700 ret->name = strdupW(family->FamilyName);
1701 ret->underline = lf.lfUnderline ? 0xff : 0;
1702 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
1704 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
1705 ret->hfont = hfont;
1706 ret->aveWidth= lf.lfWidth;
1707 list_add_head(&gdi_font_list, &ret->entry);
1708 return ret;
1711 static void dump_gdi_font_list(void)
1713 GdiFont gdiFont;
1714 LOGFONTW lf;
1715 struct list *elem_ptr;
1717 TRACE("---------- gdiFont Cache ----------\n");
1718 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
1719 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
1720 GetObjectW( gdiFont->hfont, sizeof(lf), &lf );
1721 TRACE("gdiFont=%p hfont=%p (%s)\n",
1722 gdiFont, gdiFont->hfont, debugstr_w(lf.lfFaceName));
1726 /*************************************************************
1727 * WineEngDestroyFontInstance
1729 * free the gdiFont associated with this handle
1732 BOOL WineEngDestroyFontInstance(HFONT handle)
1734 GdiFont gdiFont;
1735 BOOL ret = FALSE;
1736 struct list *elem_ptr;
1738 TRACE("destroying hfont=%p\n", handle);
1739 if(TRACE_ON(font))
1740 dump_gdi_font_list();
1742 elem_ptr = list_head(&gdi_font_list);
1743 while(elem_ptr) {
1744 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
1745 elem_ptr = list_next(&gdi_font_list, elem_ptr);
1746 if(gdiFont->hfont == handle) {
1747 list_remove(&gdiFont->entry);
1748 free_font(gdiFont);
1749 ret = TRUE;
1752 return ret;
1755 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
1756 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
1758 OUTLINETEXTMETRICW *potm = NULL;
1759 UINT size;
1760 TEXTMETRICW tm, *ptm;
1761 GdiFont font = alloc_font();
1762 LONG width, height;
1764 if(face->scalable) {
1765 height = 100;
1766 width = 0;
1767 } else {
1768 height = face->size.y_ppem >> 6;
1769 width = face->size.x_ppem >> 6;
1772 if (!(font->ft_face = OpenFontFile(font, face->file, face->face_index, width, height)))
1774 free_font(font);
1775 return;
1778 font->name = strdupW(face->family->FamilyName);
1780 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
1782 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
1783 if(size) {
1784 potm = HeapAlloc(GetProcessHeap(), 0, size);
1785 WineEngGetOutlineTextMetrics(font, size, potm);
1786 ptm = (TEXTMETRICW*)&potm->otmTextMetrics;
1787 } else {
1788 WineEngGetTextMetrics(font, &tm);
1789 ptm = &tm;
1792 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = ptm->tmHeight;
1793 pntm->ntmTm.tmAscent = ptm->tmAscent;
1794 pntm->ntmTm.tmDescent = ptm->tmDescent;
1795 pntm->ntmTm.tmInternalLeading = ptm->tmInternalLeading;
1796 pntm->ntmTm.tmExternalLeading = ptm->tmExternalLeading;
1797 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = ptm->tmAveCharWidth;
1798 pntm->ntmTm.tmMaxCharWidth = ptm->tmMaxCharWidth;
1799 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = ptm->tmWeight;
1800 pntm->ntmTm.tmOverhang = ptm->tmOverhang;
1801 pntm->ntmTm.tmDigitizedAspectX = ptm->tmDigitizedAspectX;
1802 pntm->ntmTm.tmDigitizedAspectY = ptm->tmDigitizedAspectY;
1803 pntm->ntmTm.tmFirstChar = ptm->tmFirstChar;
1804 pntm->ntmTm.tmLastChar = ptm->tmLastChar;
1805 pntm->ntmTm.tmDefaultChar = ptm->tmDefaultChar;
1806 pntm->ntmTm.tmBreakChar = ptm->tmBreakChar;
1807 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = ptm->tmItalic;
1808 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = ptm->tmUnderlined;
1809 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = ptm->tmStruckOut;
1810 pntm->ntmTm.tmPitchAndFamily = ptm->tmPitchAndFamily;
1811 pelf->elfLogFont.lfPitchAndFamily = (ptm->tmPitchAndFamily & 0xf1) + 1;
1812 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = ptm->tmCharSet;
1813 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
1814 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
1815 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
1817 *ptype = ptm->tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
1818 if(!(ptm->tmPitchAndFamily & TMPF_VECTOR))
1819 *ptype |= RASTER_FONTTYPE;
1821 if(potm) {
1822 pntm->ntmTm.ntmFlags = ptm->tmItalic ? NTM_ITALIC : 0;
1823 if(ptm->tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
1824 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
1826 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
1827 pntm->ntmTm.ntmCellHeight = 0;
1828 pntm->ntmTm.ntmAvgWidth = 0;
1830 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
1832 strncpyW(pelf->elfLogFont.lfFaceName,
1833 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
1834 LF_FACESIZE);
1835 strncpyW(pelf->elfFullName,
1836 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
1837 LF_FULLFACESIZE);
1838 strncpyW(pelf->elfStyle,
1839 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
1840 LF_FACESIZE);
1842 } else {
1843 strncpyW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
1844 strncpyW(pelf->elfFullName, face->family->FamilyName, LF_FACESIZE);
1845 pelf->elfStyle[0] = '\0';
1848 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
1850 HeapFree(GetProcessHeap(), 0, potm);
1851 free_font(font);
1852 return;
1855 /*************************************************************
1856 * WineEngEnumFonts
1859 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
1861 Family *family;
1862 Face *face;
1863 ENUMLOGFONTEXW elf;
1864 NEWTEXTMETRICEXW ntm;
1865 DWORD type, ret = 1;
1866 FONTSIGNATURE fs;
1867 CHARSETINFO csi;
1868 LOGFONTW lf;
1869 int i;
1871 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
1873 if(plf->lfFaceName[0]) {
1874 FontSubst *psub;
1875 for(psub = substlist; psub; psub = psub->next)
1876 if(!strcmpiW(plf->lfFaceName, psub->from.name) &&
1877 (psub->from.charset == -1 ||
1878 psub->from.charset == plf->lfCharSet))
1879 break;
1880 if(psub) {
1881 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
1882 debugstr_w(psub->to.name));
1883 memcpy(&lf, plf, sizeof(lf));
1884 strcpyW(lf.lfFaceName, psub->to.name);
1885 plf = &lf;
1887 for(family = FontList; family; family = family->next) {
1888 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
1889 for(face = family->FirstFace; face; face = face->next) {
1890 GetEnumStructs(face, &elf, &ntm, &type);
1891 for(i = 0; i < 32; i++) {
1892 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
1893 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
1894 strcpyW(elf.elfScript, OEM_DOSW);
1895 i = 32; /* break out of loop */
1896 } else if(!(face->fs.fsCsb[0] & (1L << i)))
1897 continue;
1898 else {
1899 fs.fsCsb[0] = 1L << i;
1900 fs.fsCsb[1] = 0;
1901 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
1902 TCI_SRCFONTSIG))
1903 csi.ciCharset = DEFAULT_CHARSET;
1904 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
1905 if(csi.ciCharset != DEFAULT_CHARSET) {
1906 elf.elfLogFont.lfCharSet =
1907 ntm.ntmTm.tmCharSet = csi.ciCharset;
1908 if(ElfScriptsW[i])
1909 strcpyW(elf.elfScript, ElfScriptsW[i]);
1910 else
1911 FIXME("Unknown elfscript for bit %d\n", i);
1914 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
1915 debugstr_w(elf.elfLogFont.lfFaceName),
1916 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
1917 csi.ciCharset, type, debugstr_w(elf.elfScript),
1918 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
1919 ntm.ntmTm.ntmFlags);
1920 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
1921 if(!ret) goto end;
1926 } else {
1927 for(family = FontList; family; family = family->next) {
1928 GetEnumStructs(family->FirstFace, &elf, &ntm, &type);
1929 for(i = 0; i < 32; i++) {
1930 if(!family->FirstFace->scalable && family->FirstFace->fs.fsCsb[0] == 0) { /* OEM bitmap */
1931 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
1932 strcpyW(elf.elfScript, OEM_DOSW);
1933 i = 32; /* break out of loop */
1934 } else if(!(family->FirstFace->fs.fsCsb[0] & (1L << i)))
1935 continue;
1936 else {
1937 fs.fsCsb[0] = 1L << i;
1938 fs.fsCsb[1] = 0;
1939 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
1940 TCI_SRCFONTSIG))
1941 csi.ciCharset = DEFAULT_CHARSET;
1942 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
1943 if(csi.ciCharset != DEFAULT_CHARSET) {
1944 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
1945 csi.ciCharset;
1946 if(ElfScriptsW[i])
1947 strcpyW(elf.elfScript, ElfScriptsW[i]);
1948 else
1949 FIXME("Unknown elfscript for bit %d\n", i);
1952 TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
1953 debugstr_w(elf.elfLogFont.lfFaceName),
1954 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
1955 csi.ciCharset, type, debugstr_w(elf.elfScript),
1956 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
1957 ntm.ntmTm.ntmFlags);
1958 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
1959 if(!ret) goto end;
1963 end:
1964 return ret;
1967 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
1969 pt->x.value = vec->x >> 6;
1970 pt->x.fract = (vec->x & 0x3f) << 10;
1971 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
1972 pt->y.value = vec->y >> 6;
1973 pt->y.fract = (vec->y & 0x3f) << 10;
1974 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
1975 return;
1978 static FT_UInt get_glyph_index(GdiFont font, UINT glyph)
1980 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
1981 glyph = glyph + 0xf000;
1982 return pFT_Get_Char_Index(font->ft_face, glyph);
1985 /*************************************************************
1986 * WineEngGetGlyphIndices
1988 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
1990 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
1991 LPWORD pgi, DWORD flags)
1993 INT i;
1995 for(i = 0; i < count; i++)
1996 pgi[i] = get_glyph_index(font, lpstr[i]);
1998 return count;
2001 /*************************************************************
2002 * WineEngGetGlyphOutline
2004 * Behaves in exactly the same way as the win32 api GetGlyphOutline
2005 * except that the first parameter is the HWINEENGFONT of the font in
2006 * question rather than an HDC.
2009 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
2010 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
2011 const MAT2* lpmat)
2013 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
2014 FT_Face ft_face = font->ft_face;
2015 FT_UInt glyph_index;
2016 DWORD width, height, pitch, needed = 0;
2017 FT_Bitmap ft_bitmap;
2018 FT_Error err;
2019 INT left, right, top = 0, bottom = 0;
2020 FT_Angle angle = 0;
2021 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
2022 float widthRatio = 1.0;
2023 FT_Matrix transMat = identityMat;
2024 BOOL needsTransform = FALSE;
2027 TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font, glyph, format, lpgm,
2028 buflen, buf, lpmat);
2030 if(format & GGO_GLYPH_INDEX) {
2031 glyph_index = glyph;
2032 format &= ~GGO_GLYPH_INDEX;
2033 } else
2034 glyph_index = get_glyph_index(font, glyph);
2036 if(glyph_index >= font->gmsize) {
2037 font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
2038 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
2039 font->gmsize * sizeof(*font->gm));
2040 } else {
2041 if(format == GGO_METRICS && font->gm[glyph_index].init) {
2042 memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
2043 return 1; /* FIXME */
2047 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP) || font->aveWidth || lpmat)
2048 load_flags |= FT_LOAD_NO_BITMAP;
2050 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
2052 if(err) {
2053 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
2054 return GDI_ERROR;
2057 /* Scaling factor */
2058 if (font->aveWidth && font->potm) {
2059 widthRatio = (float)font->aveWidth * font->xform.eM11 / (float) font->potm->otmTextMetrics.tmAveCharWidth;
2062 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
2063 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
2065 font->gm[glyph_index].adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
2066 font->gm[glyph_index].lsb = left >> 6;
2067 font->gm[glyph_index].bbx = (right - left) >> 6;
2069 /* Scaling transform */
2070 if(font->aveWidth) {
2071 FT_Matrix scaleMat;
2072 scaleMat.xx = FT_FixedFromFloat(widthRatio);
2073 scaleMat.xy = 0;
2074 scaleMat.yx = 0;
2075 scaleMat.yy = (1 << 16);
2077 pFT_Matrix_Multiply(&scaleMat, &transMat);
2078 needsTransform = TRUE;
2081 /* Rotation transform */
2082 if(font->orientation) {
2083 FT_Matrix rotationMat;
2084 FT_Vector vecAngle;
2085 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
2086 pFT_Vector_Unit(&vecAngle, angle);
2087 rotationMat.xx = vecAngle.x;
2088 rotationMat.xy = -vecAngle.y;
2089 rotationMat.yx = -rotationMat.xy;
2090 rotationMat.yy = rotationMat.xx;
2092 pFT_Matrix_Multiply(&rotationMat, &transMat);
2093 needsTransform = TRUE;
2096 /* Extra transformation specified by caller */
2097 if (lpmat) {
2098 FT_Matrix extraMat;
2099 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
2100 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
2101 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
2102 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
2103 pFT_Matrix_Multiply(&extraMat, &transMat);
2104 needsTransform = TRUE;
2107 if(!needsTransform) {
2108 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
2109 bottom = (ft_face->glyph->metrics.horiBearingY -
2110 ft_face->glyph->metrics.height) & -64;
2111 lpgm->gmCellIncX = font->gm[glyph_index].adv;
2112 lpgm->gmCellIncY = 0;
2113 } else {
2114 INT xc, yc;
2115 FT_Vector vec;
2116 for(xc = 0; xc < 2; xc++) {
2117 for(yc = 0; yc < 2; yc++) {
2118 vec.x = (ft_face->glyph->metrics.horiBearingX +
2119 xc * ft_face->glyph->metrics.width);
2120 vec.y = ft_face->glyph->metrics.horiBearingY -
2121 yc * ft_face->glyph->metrics.height;
2122 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
2123 pFT_Vector_Transform(&vec, &transMat);
2124 if(xc == 0 && yc == 0) {
2125 left = right = vec.x;
2126 top = bottom = vec.y;
2127 } else {
2128 if(vec.x < left) left = vec.x;
2129 else if(vec.x > right) right = vec.x;
2130 if(vec.y < bottom) bottom = vec.y;
2131 else if(vec.y > top) top = vec.y;
2135 left = left & -64;
2136 right = (right + 63) & -64;
2137 bottom = bottom & -64;
2138 top = (top + 63) & -64;
2140 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
2141 vec.x = ft_face->glyph->metrics.horiAdvance;
2142 vec.y = 0;
2143 pFT_Vector_Transform(&vec, &transMat);
2144 lpgm->gmCellIncX = (vec.x+63) >> 6;
2145 lpgm->gmCellIncY = -((vec.y+63) >> 6);
2147 lpgm->gmBlackBoxX = (right - left) >> 6;
2148 lpgm->gmBlackBoxY = (top - bottom) >> 6;
2149 lpgm->gmptGlyphOrigin.x = left >> 6;
2150 lpgm->gmptGlyphOrigin.y = top >> 6;
2152 memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
2153 font->gm[glyph_index].init = TRUE;
2155 if(format == GGO_METRICS)
2156 return 1; /* FIXME */
2158 if (buf && !buflen){
2159 return GDI_ERROR;
2162 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP) {
2163 TRACE("loaded a bitmap\n");
2164 return GDI_ERROR;
2167 switch(format) {
2168 case GGO_BITMAP:
2169 width = lpgm->gmBlackBoxX;
2170 height = lpgm->gmBlackBoxY;
2171 pitch = ((width + 31) >> 5) << 2;
2172 needed = pitch * height;
2174 if(!buf || !buflen) break;
2176 switch(ft_face->glyph->format) {
2177 case ft_glyph_format_bitmap:
2179 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
2180 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
2181 INT h = ft_face->glyph->bitmap.rows;
2182 while(h--) {
2183 memcpy(dst, src, w);
2184 src += ft_face->glyph->bitmap.pitch;
2185 dst += pitch;
2187 break;
2190 case ft_glyph_format_outline:
2191 ft_bitmap.width = width;
2192 ft_bitmap.rows = height;
2193 ft_bitmap.pitch = pitch;
2194 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
2195 ft_bitmap.buffer = buf;
2197 if(needsTransform) {
2198 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
2201 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
2203 /* Note: FreeType will only set 'black' bits for us. */
2204 memset(buf, 0, needed);
2205 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
2206 break;
2208 default:
2209 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
2210 return GDI_ERROR;
2212 break;
2214 case GGO_GRAY2_BITMAP:
2215 case GGO_GRAY4_BITMAP:
2216 case GGO_GRAY8_BITMAP:
2217 case WINE_GGO_GRAY16_BITMAP:
2219 int mult, row, col;
2220 BYTE *start, *ptr;
2222 width = lpgm->gmBlackBoxX;
2223 height = lpgm->gmBlackBoxY;
2224 pitch = (width + 3) / 4 * 4;
2225 needed = pitch * height;
2227 if(!buf || !buflen) break;
2228 ft_bitmap.width = width;
2229 ft_bitmap.rows = height;
2230 ft_bitmap.pitch = pitch;
2231 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
2232 ft_bitmap.buffer = buf;
2234 if(needsTransform) {
2235 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
2238 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
2240 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
2242 if(format == GGO_GRAY2_BITMAP)
2243 mult = 5;
2244 else if(format == GGO_GRAY4_BITMAP)
2245 mult = 17;
2246 else if(format == GGO_GRAY8_BITMAP)
2247 mult = 65;
2248 else if(format == WINE_GGO_GRAY16_BITMAP)
2249 break;
2250 else {
2251 assert(0);
2252 break;
2255 start = buf;
2256 for(row = 0; row < height; row++) {
2257 ptr = start;
2258 for(col = 0; col < width; col++, ptr++) {
2259 *ptr = (*(unsigned int*)ptr * mult + 128) / 256;
2261 start += pitch;
2263 break;
2266 case GGO_NATIVE:
2268 int contour, point = 0, first_pt;
2269 FT_Outline *outline = &ft_face->glyph->outline;
2270 TTPOLYGONHEADER *pph;
2271 TTPOLYCURVE *ppc;
2272 DWORD pph_start, cpfx, type;
2274 if(buflen == 0) buf = NULL;
2276 if (needsTransform && buf) {
2277 pFT_Outline_Transform(outline, &transMat);
2280 for(contour = 0; contour < outline->n_contours; contour++) {
2281 pph_start = needed;
2282 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
2283 first_pt = point;
2284 if(buf) {
2285 pph->dwType = TT_POLYGON_TYPE;
2286 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2288 needed += sizeof(*pph);
2289 point++;
2290 while(point <= outline->contours[contour]) {
2291 ppc = (TTPOLYCURVE *)((char *)buf + needed);
2292 type = (outline->tags[point] & FT_Curve_Tag_On) ?
2293 TT_PRIM_LINE : TT_PRIM_QSPLINE;
2294 cpfx = 0;
2295 do {
2296 if(buf)
2297 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2298 cpfx++;
2299 point++;
2300 } while(point <= outline->contours[contour] &&
2301 (outline->tags[point] & FT_Curve_Tag_On) ==
2302 (outline->tags[point-1] & FT_Curve_Tag_On));
2303 /* At the end of a contour Windows adds the start point, but
2304 only for Beziers */
2305 if(point > outline->contours[contour] &&
2306 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
2307 if(buf)
2308 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
2309 cpfx++;
2310 } else if(point <= outline->contours[contour] &&
2311 outline->tags[point] & FT_Curve_Tag_On) {
2312 /* add closing pt for bezier */
2313 if(buf)
2314 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2315 cpfx++;
2316 point++;
2318 if(buf) {
2319 ppc->wType = type;
2320 ppc->cpfx = cpfx;
2322 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2324 if(buf)
2325 pph->cb = needed - pph_start;
2327 break;
2329 case GGO_BEZIER:
2331 /* Convert the quadratic Beziers to cubic Beziers.
2332 The parametric eqn for a cubic Bezier is, from PLRM:
2333 r(t) = at^3 + bt^2 + ct + r0
2334 with the control points:
2335 r1 = r0 + c/3
2336 r2 = r1 + (c + b)/3
2337 r3 = r0 + c + b + a
2339 A quadratic Beizer has the form:
2340 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
2342 So equating powers of t leads to:
2343 r1 = 2/3 p1 + 1/3 p0
2344 r2 = 2/3 p1 + 1/3 p2
2345 and of course r0 = p0, r3 = p2
2348 int contour, point = 0, first_pt;
2349 FT_Outline *outline = &ft_face->glyph->outline;
2350 TTPOLYGONHEADER *pph;
2351 TTPOLYCURVE *ppc;
2352 DWORD pph_start, cpfx, type;
2353 FT_Vector cubic_control[4];
2354 if(buflen == 0) buf = NULL;
2356 if (needsTransform && buf) {
2357 pFT_Outline_Transform(outline, &transMat);
2360 for(contour = 0; contour < outline->n_contours; contour++) {
2361 pph_start = needed;
2362 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
2363 first_pt = point;
2364 if(buf) {
2365 pph->dwType = TT_POLYGON_TYPE;
2366 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2368 needed += sizeof(*pph);
2369 point++;
2370 while(point <= outline->contours[contour]) {
2371 ppc = (TTPOLYCURVE *)((char *)buf + needed);
2372 type = (outline->tags[point] & FT_Curve_Tag_On) ?
2373 TT_PRIM_LINE : TT_PRIM_CSPLINE;
2374 cpfx = 0;
2375 do {
2376 if(type == TT_PRIM_LINE) {
2377 if(buf)
2378 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2379 cpfx++;
2380 point++;
2381 } else {
2382 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
2383 so cpfx = 3n */
2385 /* FIXME: Possible optimization in endpoint calculation
2386 if there are two consecutive curves */
2387 cubic_control[0] = outline->points[point-1];
2388 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
2389 cubic_control[0].x += outline->points[point].x + 1;
2390 cubic_control[0].y += outline->points[point].y + 1;
2391 cubic_control[0].x >>= 1;
2392 cubic_control[0].y >>= 1;
2394 if(point+1 > outline->contours[contour])
2395 cubic_control[3] = outline->points[first_pt];
2396 else {
2397 cubic_control[3] = outline->points[point+1];
2398 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
2399 cubic_control[3].x += outline->points[point].x + 1;
2400 cubic_control[3].y += outline->points[point].y + 1;
2401 cubic_control[3].x >>= 1;
2402 cubic_control[3].y >>= 1;
2405 /* r1 = 1/3 p0 + 2/3 p1
2406 r2 = 1/3 p2 + 2/3 p1 */
2407 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
2408 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
2409 cubic_control[2] = cubic_control[1];
2410 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
2411 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
2412 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
2413 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
2414 if(buf) {
2415 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
2416 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
2417 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
2419 cpfx += 3;
2420 point++;
2422 } while(point <= outline->contours[contour] &&
2423 (outline->tags[point] & FT_Curve_Tag_On) ==
2424 (outline->tags[point-1] & FT_Curve_Tag_On));
2425 /* At the end of a contour Windows adds the start point,
2426 but only for Beziers and we've already done that.
2428 if(point <= outline->contours[contour] &&
2429 outline->tags[point] & FT_Curve_Tag_On) {
2430 /* This is the closing pt of a bezier, but we've already
2431 added it, so just inc point and carry on */
2432 point++;
2434 if(buf) {
2435 ppc->wType = type;
2436 ppc->cpfx = cpfx;
2438 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2440 if(buf)
2441 pph->cb = needed - pph_start;
2443 break;
2446 default:
2447 FIXME("Unsupported format %d\n", format);
2448 return GDI_ERROR;
2450 return needed;
2453 static BOOL get_bitmap_text_metrics(GdiFont font)
2455 FT_Face ft_face = font->ft_face;
2456 #ifdef HAVE_FREETYPE_FTWINFNT_H
2457 FT_WinFNT_HeaderRec winfnt_header;
2458 #endif
2459 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
2460 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
2461 font->potm->otmSize = size;
2463 #define TM font->potm->otmTextMetrics
2464 #ifdef HAVE_FREETYPE_FTWINFNT_H
2465 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
2467 TM.tmHeight = winfnt_header.pixel_height;
2468 TM.tmAscent = winfnt_header.ascent;
2469 TM.tmDescent = TM.tmHeight - TM.tmAscent;
2470 TM.tmInternalLeading = winfnt_header.internal_leading;
2471 TM.tmExternalLeading = winfnt_header.external_leading;
2472 TM.tmAveCharWidth = winfnt_header.avg_width;
2473 TM.tmMaxCharWidth = winfnt_header.max_width;
2474 TM.tmWeight = winfnt_header.weight;
2475 TM.tmOverhang = 0;
2476 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
2477 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
2478 TM.tmFirstChar = winfnt_header.first_char;
2479 TM.tmLastChar = winfnt_header.last_char;
2480 TM.tmDefaultChar = winfnt_header.default_char;
2481 TM.tmBreakChar = winfnt_header.break_char;
2482 TM.tmItalic = winfnt_header.italic;
2483 TM.tmUnderlined = font->underline;
2484 TM.tmStruckOut = font->strikeout;
2485 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
2486 TM.tmCharSet = winfnt_header.charset;
2488 else
2489 #endif
2491 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
2492 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
2493 TM.tmHeight = TM.tmAscent + TM.tmDescent;
2494 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
2495 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
2496 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
2497 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
2498 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
2499 TM.tmOverhang = 0;
2500 TM.tmDigitizedAspectX = 96; /* FIXME */
2501 TM.tmDigitizedAspectY = 96; /* FIXME */
2502 TM.tmFirstChar = 1;
2503 TM.tmLastChar = 255;
2504 TM.tmDefaultChar = 32;
2505 TM.tmBreakChar = 32;
2506 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
2507 TM.tmUnderlined = font->underline;
2508 TM.tmStruckOut = font->strikeout;
2509 /* NB inverted meaning of TMPF_FIXED_PITCH */
2510 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
2511 TM.tmCharSet = font->charset;
2513 #undef TM
2515 return TRUE;
2518 /*************************************************************
2519 * WineEngGetTextMetrics
2522 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
2524 if(!font->potm) {
2525 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
2526 if(!get_bitmap_text_metrics(font))
2527 return FALSE;
2529 if(!font->potm) return FALSE;
2530 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
2532 if (font->aveWidth) {
2533 ptm->tmAveCharWidth = font->aveWidth * font->xform.eM11;
2535 return TRUE;
2539 /*************************************************************
2540 * WineEngGetOutlineTextMetrics
2543 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
2544 OUTLINETEXTMETRICW *potm)
2546 FT_Face ft_face = font->ft_face;
2547 UINT needed, lenfam, lensty, ret;
2548 TT_OS2 *pOS2;
2549 TT_HoriHeader *pHori;
2550 TT_Postscript *pPost;
2551 FT_Fixed x_scale, y_scale;
2552 WCHAR *family_nameW, *style_nameW;
2553 static const WCHAR spaceW[] = {' ', '\0'};
2554 char *cp;
2555 INT ascent, descent;
2557 TRACE("font=%p\n", font);
2559 if(!FT_IS_SCALABLE(ft_face))
2560 return 0;
2562 if(font->potm) {
2563 if(cbSize >= font->potm->otmSize)
2564 memcpy(potm, font->potm, font->potm->otmSize);
2565 return font->potm->otmSize;
2569 needed = sizeof(*potm);
2571 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
2572 family_nameW = strdupW(font->name);
2574 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
2575 * sizeof(WCHAR);
2576 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
2577 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
2578 style_nameW, lensty);
2580 /* These names should be read from the TT name table */
2582 /* length of otmpFamilyName */
2583 needed += lenfam;
2585 /* length of otmpFaceName */
2586 if(!strcasecmp(ft_face->style_name, "regular")) {
2587 needed += lenfam; /* just the family name */
2588 } else {
2589 needed += lenfam + lensty; /* family + " " + style */
2592 /* length of otmpStyleName */
2593 needed += lensty;
2595 /* length of otmpFullName */
2596 needed += lenfam + lensty;
2599 x_scale = ft_face->size->metrics.x_scale;
2600 y_scale = ft_face->size->metrics.y_scale;
2602 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2603 if(!pOS2) {
2604 FIXME("Can't find OS/2 table - not TT font?\n");
2605 ret = 0;
2606 goto end;
2609 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2610 if(!pHori) {
2611 FIXME("Can't find HHEA table - not TT font?\n");
2612 ret = 0;
2613 goto end;
2616 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
2618 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",
2619 pOS2->usWinAscent, pOS2->usWinDescent,
2620 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
2621 ft_face->ascender, ft_face->descender, ft_face->height,
2622 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
2623 ft_face->bbox.yMax, ft_face->bbox.yMin);
2625 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
2626 font->potm->otmSize = needed;
2628 #define TM font->potm->otmTextMetrics
2630 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
2631 ascent = pHori->Ascender;
2632 descent = -pHori->Descender;
2633 } else {
2634 ascent = pOS2->usWinAscent;
2635 descent = pOS2->usWinDescent;
2638 if(font->yMax) {
2639 TM.tmAscent = font->yMax;
2640 TM.tmDescent = -font->yMin;
2641 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
2642 } else {
2643 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
2644 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
2645 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
2646 - ft_face->units_per_EM, y_scale) + 32) >> 6;
2649 TM.tmHeight = TM.tmAscent + TM.tmDescent;
2651 /* MSDN says:
2652 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
2654 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
2655 ((ascent + descent) -
2656 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
2658 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
2659 if (TM.tmAveCharWidth == 0) {
2660 TM.tmAveCharWidth = 1;
2662 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
2663 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
2664 TM.tmOverhang = 0;
2665 TM.tmDigitizedAspectX = 300;
2666 TM.tmDigitizedAspectY = 300;
2667 TM.tmFirstChar = pOS2->usFirstCharIndex;
2668 TM.tmLastChar = pOS2->usLastCharIndex;
2669 TM.tmDefaultChar = pOS2->usDefaultChar;
2670 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
2671 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
2672 TM.tmUnderlined = font->underline;
2673 TM.tmStruckOut = font->strikeout;
2675 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
2676 if(!FT_IS_FIXED_WIDTH(ft_face))
2677 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
2678 else
2679 TM.tmPitchAndFamily = 0;
2681 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
2682 case PAN_FAMILY_SCRIPT:
2683 TM.tmPitchAndFamily |= FF_SCRIPT;
2684 break;
2685 case PAN_FAMILY_DECORATIVE:
2686 case PAN_FAMILY_PICTORIAL:
2687 TM.tmPitchAndFamily |= FF_DECORATIVE;
2688 break;
2689 case PAN_FAMILY_TEXT_DISPLAY:
2690 if(TM.tmPitchAndFamily == 0) /* fixed */
2691 TM.tmPitchAndFamily = FF_MODERN;
2692 else {
2693 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
2694 case PAN_SERIF_NORMAL_SANS:
2695 case PAN_SERIF_OBTUSE_SANS:
2696 case PAN_SERIF_PERP_SANS:
2697 TM.tmPitchAndFamily |= FF_SWISS;
2698 break;
2699 default:
2700 TM.tmPitchAndFamily |= FF_ROMAN;
2703 break;
2704 default:
2705 TM.tmPitchAndFamily |= FF_DONTCARE;
2708 if(FT_IS_SCALABLE(ft_face))
2709 TM.tmPitchAndFamily |= TMPF_VECTOR;
2710 if(FT_IS_SFNT(ft_face))
2711 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
2713 TM.tmCharSet = font->charset;
2714 #undef TM
2716 font->potm->otmFiller = 0;
2717 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
2718 font->potm->otmfsSelection = pOS2->fsSelection;
2719 font->potm->otmfsType = pOS2->fsType;
2720 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
2721 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
2722 font->potm->otmItalicAngle = 0; /* POST table */
2723 font->potm->otmEMSquare = ft_face->units_per_EM;
2724 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
2725 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
2726 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
2727 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
2728 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
2729 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
2730 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
2731 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
2732 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
2733 font->potm->otmMacAscent = 0; /* where do these come from ? */
2734 font->potm->otmMacDescent = 0;
2735 font->potm->otmMacLineGap = 0;
2736 font->potm->otmusMinimumPPEM = 0; /* TT Header */
2737 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
2738 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
2739 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
2740 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
2741 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
2742 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
2743 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
2744 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
2745 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
2746 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
2747 if(!pPost) {
2748 font->potm->otmsUnderscoreSize = 0;
2749 font->potm->otmsUnderscorePosition = 0;
2750 } else {
2751 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
2752 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
2755 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
2756 cp = (char*)font->potm + sizeof(*font->potm);
2757 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
2758 strcpyW((WCHAR*)cp, family_nameW);
2759 cp += lenfam;
2760 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
2761 strcpyW((WCHAR*)cp, style_nameW);
2762 cp += lensty;
2763 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
2764 strcpyW((WCHAR*)cp, family_nameW);
2765 if(strcasecmp(ft_face->style_name, "regular")) {
2766 strcatW((WCHAR*)cp, spaceW);
2767 strcatW((WCHAR*)cp, style_nameW);
2768 cp += lenfam + lensty;
2769 } else
2770 cp += lenfam;
2771 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
2772 strcpyW((WCHAR*)cp, family_nameW);
2773 strcatW((WCHAR*)cp, spaceW);
2774 strcatW((WCHAR*)cp, style_nameW);
2775 ret = needed;
2777 if(potm && needed <= cbSize)
2778 memcpy(potm, font->potm, font->potm->otmSize);
2780 end:
2781 HeapFree(GetProcessHeap(), 0, style_nameW);
2782 HeapFree(GetProcessHeap(), 0, family_nameW);
2784 return ret;
2788 /*************************************************************
2789 * WineEngGetCharWidth
2792 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
2793 LPINT buffer)
2795 UINT c;
2796 GLYPHMETRICS gm;
2797 FT_UInt glyph_index;
2799 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
2801 for(c = firstChar; c <= lastChar; c++) {
2802 glyph_index = get_glyph_index(font, c);
2803 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
2804 &gm, 0, NULL, NULL);
2805 buffer[c - firstChar] = font->gm[glyph_index].adv;
2807 return TRUE;
2810 /*************************************************************
2811 * WineEngGetCharABCWidths
2814 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
2815 LPABC buffer)
2817 UINT c;
2818 GLYPHMETRICS gm;
2819 FT_UInt glyph_index;
2821 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
2823 for(c = firstChar; c <= lastChar; c++) {
2824 glyph_index = get_glyph_index(font, c);
2825 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
2826 &gm, 0, NULL, NULL);
2827 buffer[c - firstChar].abcA = font->gm[glyph_index].lsb;
2828 buffer[c - firstChar].abcB = font->gm[glyph_index].bbx;
2829 buffer[c - firstChar].abcC = font->gm[glyph_index].adv - font->gm[glyph_index].lsb -
2830 font->gm[glyph_index].bbx;
2832 return TRUE;
2835 /*************************************************************
2836 * WineEngGetTextExtentPoint
2839 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
2840 LPSIZE size)
2842 INT idx;
2843 GLYPHMETRICS gm;
2844 TEXTMETRICW tm;
2845 FT_UInt glyph_index;
2847 TRACE("%p, %s, %d, %p\n", font, debugstr_wn(wstr, count), count,
2848 size);
2850 size->cx = 0;
2851 WineEngGetTextMetrics(font, &tm);
2852 size->cy = tm.tmHeight;
2854 for(idx = 0; idx < count; idx++) {
2855 glyph_index = get_glyph_index(font, wstr[idx]);
2856 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
2857 &gm, 0, NULL, NULL);
2858 size->cx += font->gm[glyph_index].adv;
2860 TRACE("return %ld,%ld\n", size->cx, size->cy);
2861 return TRUE;
2864 /*************************************************************
2865 * WineEngGetTextExtentPointI
2868 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
2869 LPSIZE size)
2871 INT idx;
2872 GLYPHMETRICS gm;
2873 TEXTMETRICW tm;
2875 TRACE("%p, %p, %d, %p\n", font, indices, count, size);
2877 size->cx = 0;
2878 WineEngGetTextMetrics(font, &tm);
2879 size->cy = tm.tmHeight;
2881 for(idx = 0; idx < count; idx++) {
2882 WineEngGetGlyphOutline(font, indices[idx],
2883 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
2884 NULL);
2885 size->cx += font->gm[indices[idx]].adv;
2887 TRACE("return %ld,%ld\n", size->cx, size->cy);
2888 return TRUE;
2891 /*************************************************************
2892 * WineEngGetFontData
2895 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
2896 DWORD cbData)
2898 FT_Face ft_face = font->ft_face;
2899 DWORD len;
2900 FT_Error err;
2902 TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
2903 font, table, offset, buf, cbData);
2905 if(!FT_IS_SFNT(ft_face))
2906 return GDI_ERROR;
2908 if(!buf || !cbData)
2909 len = 0;
2910 else
2911 len = cbData;
2913 if(table) { /* MS tags differ in endidness from FT ones */
2914 table = table >> 24 | table << 24 |
2915 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
2918 /* If the FT_Load_Sfnt_Table function is there we'll use it */
2919 if(pFT_Load_Sfnt_Table)
2920 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
2921 else { /* Do it the hard way */
2922 TT_Face tt_face = (TT_Face) ft_face;
2923 SFNT_Interface *sfnt;
2924 if (FT_Version.major==2 && FT_Version.minor==0)
2926 /* 2.0.x */
2927 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
2929 else
2931 /* A field was added in the middle of the structure in 2.1.x */
2932 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
2934 err = sfnt->load_any(tt_face, table, offset, buf, &len);
2936 if(err) {
2937 TRACE("Can't find table %08lx.\n", table);
2938 return GDI_ERROR;
2940 return len;
2943 /*************************************************************
2944 * WineEngGetTextFace
2947 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
2949 if(str) {
2950 lstrcpynW(str, font->name, count);
2951 return strlenW(font->name);
2952 } else
2953 return strlenW(font->name) + 1;
2956 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
2958 if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
2959 return font->charset;
2962 #else /* HAVE_FREETYPE */
2964 BOOL WineEngInit(void)
2966 return FALSE;
2968 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
2970 return NULL;
2972 BOOL WineEngDestroyFontInstance(HFONT hfont)
2974 return FALSE;
2977 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
2979 return 1;
2982 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
2983 LPWORD pgi, DWORD flags)
2985 return GDI_ERROR;
2988 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
2989 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
2990 const MAT2* lpmat)
2992 ERR("called but we don't have FreeType\n");
2993 return GDI_ERROR;
2996 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
2998 ERR("called but we don't have FreeType\n");
2999 return FALSE;
3002 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
3003 OUTLINETEXTMETRICW *potm)
3005 ERR("called but we don't have FreeType\n");
3006 return 0;
3009 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
3010 LPINT buffer)
3012 ERR("called but we don't have FreeType\n");
3013 return FALSE;
3016 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
3017 LPABC buffer)
3019 ERR("called but we don't have FreeType\n");
3020 return FALSE;
3023 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
3024 LPSIZE size)
3026 ERR("called but we don't have FreeType\n");
3027 return FALSE;
3030 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
3031 LPSIZE size)
3033 ERR("called but we don't have FreeType\n");
3034 return FALSE;
3037 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
3038 DWORD cbData)
3040 ERR("called but we don't have FreeType\n");
3041 return GDI_ERROR;
3044 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
3046 ERR("called but we don't have FreeType\n");
3047 return 0;
3050 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3052 FIXME(":stub\n");
3053 return 1;
3056 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3058 FIXME(":stub\n");
3059 return TRUE;
3062 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
3064 FIXME(":stub\n");
3065 return DEFAULT_CHARSET;
3068 #endif /* HAVE_FREETYPE */