Specify fourcc codes for encodings directly, instead of using changing
[wine.git] / dlls / gdi / freetype.c
blob6f6256f3e184d07e21bee27957c5da62e66c4ebb
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
24 #include "config.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 "wine/unicode.h"
40 #include "wine/port.h"
41 #include "wine/debug.h"
42 #include "gdi.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(font);
46 #ifdef HAVE_FREETYPE
48 #ifdef HAVE_FREETYPE_FREETYPE_H
49 #include <freetype/freetype.h>
50 #endif
51 #ifdef HAVE_FREETYPE_FTGLYPH_H
52 #include <freetype/ftglyph.h>
53 #endif
54 #ifdef HAVE_FREETYPE_TTTABLES_H
55 #include <freetype/tttables.h>
56 #endif
57 #ifdef HAVE_FREETYPE_FTSNAMES_H
58 #include <freetype/ftsnames.h>
59 #else
60 # ifdef HAVE_FREETYPE_FTNAMES_H
61 # include <freetype/ftnames.h>
62 # endif
63 #endif
64 #ifdef HAVE_FREETYPE_TTNAMEID_H
65 #include <freetype/ttnameid.h>
66 #endif
67 #ifdef HAVE_FREETYPE_FTOUTLN_H
68 #include <freetype/ftoutln.h>
69 #endif
70 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
71 #include <freetype/internal/sfnt.h>
72 #endif
73 #ifdef HAVE_FREETYPE_FTTRIGON_H
74 #include <freetype/fttrigon.h>
75 #endif
77 #ifndef SONAME_LIBFREETYPE
78 #define SONAME_LIBFREETYPE "libfreetype.so"
79 #endif
81 static FT_Library library = 0;
82 typedef struct
84 FT_Int major;
85 FT_Int minor;
86 FT_Int patch;
87 } FT_Version_t;
88 static FT_Version_t FT_Version;
90 static void *ft_handle = NULL;
92 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
93 MAKE_FUNCPTR(FT_Vector_Unit);
94 MAKE_FUNCPTR(FT_Done_Face);
95 MAKE_FUNCPTR(FT_Get_Char_Index);
96 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
97 MAKE_FUNCPTR(FT_Init_FreeType);
98 MAKE_FUNCPTR(FT_Load_Glyph);
99 MAKE_FUNCPTR(FT_Matrix_Multiply);
100 MAKE_FUNCPTR(FT_MulFix);
101 MAKE_FUNCPTR(FT_New_Face);
102 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
103 MAKE_FUNCPTR(FT_Outline_Transform);
104 MAKE_FUNCPTR(FT_Outline_Translate);
105 MAKE_FUNCPTR(FT_Select_Charmap);
106 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
107 MAKE_FUNCPTR(FT_Vector_Transform);
108 #undef MAKE_FUNCPTR
109 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
110 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
112 #define GET_BE_WORD(ptr) MAKEWORD( ((BYTE *)(ptr))[1], ((BYTE *)(ptr))[0] )
114 typedef struct tagFace {
115 WCHAR *StyleName;
116 char *file;
117 FT_Long face_index;
118 BOOL Italic;
119 BOOL Bold;
120 FONTSIGNATURE fs;
121 FT_Fixed font_version;
122 struct tagFace *next;
123 struct tagFamily *family;
124 } Face;
126 typedef struct tagFamily {
127 WCHAR *FamilyName;
128 Face *FirstFace;
129 struct tagFamily *next;
130 } Family;
132 typedef struct {
133 GLYPHMETRICS gm;
134 INT adv; /* These three hold to widths of the unrotated chars */
135 INT lsb;
136 INT bbx;
137 BOOL init;
138 } GM;
140 struct tagGdiFont {
141 FT_Face ft_face;
142 XFORM xform;
143 LPWSTR name;
144 int charset;
145 BOOL fake_italic;
146 BOOL fake_bold;
147 INT orientation;
148 GM *gm;
149 DWORD gmsize;
150 HFONT hfont;
151 LONG aveWidth;
152 SHORT yMax;
153 SHORT yMin;
154 OUTLINETEXTMETRICW *potm;
155 FONTSIGNATURE fs;
156 struct tagGdiFont *next;
159 #define INIT_GM_SIZE 128
161 static GdiFont GdiFontList = NULL;
163 static Family *FontList = NULL;
165 static WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ',
166 'R','o','m','a','n','\0'};
167 static WCHAR defSans[] = {'A','r','i','a','l','\0'};
168 static WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
170 static WCHAR defSystem[] = {'A','r','i','a','l','\0'};
171 static WCHAR SystemW[] = {'S','y','s','t','e','m','\0'};
172 static WCHAR MSSansSerifW[] = {'M','S',' ','S','a','n','s',' ',
173 'S','e','r','i','f','\0'};
174 static WCHAR HelvW[] = {'H','e','l','v','\0'};
176 static WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
177 static WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
178 static WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
179 static WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
180 static WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
181 'E','u','r','o','p','e','a','n','\0'};
182 static WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
183 static WCHAR GreekW[] = {'G','r','e','e','k','\0'};
184 static WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
185 static WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
186 static WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
187 static WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
188 static WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
189 static WCHAR ThaiW[] = {'T','h','a','i','\0'};
190 static WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
191 static WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
192 static WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
194 static WCHAR *ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
195 WesternW, /*00*/
196 Central_EuropeanW,
197 CyrillicW,
198 GreekW,
199 TurkishW,
200 HebrewW,
201 ArabicW,
202 BalticW,
203 VietnameseW, /*08*/
204 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
205 ThaiW,
206 JapaneseW,
207 CHINESE_GB2312W,
208 HangulW,
209 CHINESE_BIG5W,
210 Hangul_Johab_W,
211 NULL, NULL, /*23*/
212 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
213 SymbolW /*31*/
216 typedef struct {
217 WCHAR *name;
218 INT charset;
219 } NameCs;
221 typedef struct tagFontSubst {
222 NameCs from;
223 NameCs to;
224 struct tagFontSubst *next;
225 } FontSubst;
227 static FontSubst *substlist = NULL;
228 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
231 This function builds an FT_Fixed from a float. It puts the integer part
232 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
233 It fails if the integer part of the float number is greater than SHORT_MAX.
235 static inline FT_Fixed FT_FixedFromFloat(float f)
237 short value = f;
238 unsigned short fract = (f - value) * 0xFFFF;
239 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
243 This function builds an FT_Fixed from a FIXED. It simply put f.value
244 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
246 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
248 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
251 static BOOL AddFontFileToList(char *file, char *fake_family)
253 FT_Face ft_face;
254 TT_OS2 *pOS2;
255 TT_Header *pHeader;
256 WCHAR *FamilyW, *StyleW;
257 DWORD len;
258 Family *family = FontList;
259 Family **insert = &FontList;
260 Face **insertface, *next;
261 FT_Error err;
262 FT_Long face_index = 0, num_faces;
263 int i;
265 do {
266 char *family_name = fake_family;
268 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
269 if((err = pFT_New_Face(library, file, face_index, &ft_face)) != 0) {
270 WARN("Unable to load font file %s err = %x\n", debugstr_a(file), err);
271 return FALSE;
274 if(!FT_IS_SFNT(ft_face)) { /* for now we'll skip everything but TT/OT */
275 pFT_Done_Face(ft_face);
276 return FALSE;
278 if(!pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2) ||
279 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
280 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head))) {
281 TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
282 "Skipping this font.\n", debugstr_a(file));
283 pFT_Done_Face(ft_face);
284 return FALSE;
287 if(!ft_face->family_name || !ft_face->style_name) {
288 TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file));
289 pFT_Done_Face(ft_face);
290 return FALSE;
293 if(!family_name)
294 family_name = ft_face->family_name;
296 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
297 FamilyW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
298 MultiByteToWideChar(CP_ACP, 0, family_name, -1, FamilyW, len);
300 while(family) {
301 if(!strcmpW(family->FamilyName, FamilyW))
302 break;
303 insert = &family->next;
304 family = family->next;
306 if(!family) {
307 family = *insert = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
308 family->FamilyName = FamilyW;
309 family->FirstFace = NULL;
310 family->next = NULL;
311 } else {
312 HeapFree(GetProcessHeap(), 0, FamilyW);
315 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
316 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
317 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
319 next = NULL;
320 for(insertface = &family->FirstFace; *insertface;
321 insertface = &(*insertface)->next) {
322 if(!strcmpW((*insertface)->StyleName, StyleW)) {
323 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
324 debugstr_w(family->FamilyName), debugstr_w(StyleW),
325 (*insertface)->font_version, pHeader->Font_Revision);
327 if(fake_family) {
328 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
329 HeapFree(GetProcessHeap(), 0, StyleW);
330 pFT_Done_Face(ft_face);
331 return FALSE;
333 if(pHeader->Font_Revision <= (*insertface)->font_version) {
334 TRACE("Original font is newer so skipping this one\n");
335 HeapFree(GetProcessHeap(), 0, StyleW);
336 pFT_Done_Face(ft_face);
337 return FALSE;
338 } else {
339 TRACE("Replacing original with this one\n");
340 next = (*insertface)->next;
341 HeapFree(GetProcessHeap(), 0, (*insertface)->file);
342 HeapFree(GetProcessHeap(), 0, (*insertface)->StyleName);
343 HeapFree(GetProcessHeap(), 0, *insertface);
344 break;
348 *insertface = HeapAlloc(GetProcessHeap(), 0, sizeof(**insertface));
349 (*insertface)->StyleName = StyleW;
350 (*insertface)->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
351 strcpy((*insertface)->file, file);
352 (*insertface)->face_index = face_index;
353 (*insertface)->next = next;
354 (*insertface)->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
355 (*insertface)->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
356 (*insertface)->font_version = pHeader->Font_Revision;
357 (*insertface)->family = family;
359 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
360 if(pOS2) {
361 (*insertface)->fs.fsCsb[0] = pOS2->ulCodePageRange1;
362 (*insertface)->fs.fsCsb[1] = pOS2->ulCodePageRange2;
363 (*insertface)->fs.fsUsb[0] = pOS2->ulUnicodeRange1;
364 (*insertface)->fs.fsUsb[1] = pOS2->ulUnicodeRange2;
365 (*insertface)->fs.fsUsb[2] = pOS2->ulUnicodeRange3;
366 (*insertface)->fs.fsUsb[3] = pOS2->ulUnicodeRange4;
367 } else {
368 (*insertface)->fs.fsCsb[0] = (*insertface)->fs.fsCsb[1] = 0;
369 (*insertface)->fs.fsUsb[0] = 0;
370 (*insertface)->fs.fsUsb[1] = 0;
371 (*insertface)->fs.fsUsb[2] = 0;
372 (*insertface)->fs.fsUsb[3] = 0;
374 TRACE("fsCsb = %08lx %08lx/%08lx %08lx %08lx %08lx\n",
375 (*insertface)->fs.fsCsb[0], (*insertface)->fs.fsCsb[1],
376 (*insertface)->fs.fsUsb[0], (*insertface)->fs.fsUsb[1],
377 (*insertface)->fs.fsUsb[2], (*insertface)->fs.fsUsb[3]);
379 if((*insertface)->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
380 for(i = 0; i < ft_face->num_charmaps; i++) {
381 switch(ft_face->charmaps[i]->encoding) {
382 case ft_encoding_unicode:
383 case ft_encoding_apple_roman:
384 (*insertface)->fs.fsCsb[0] |= 1;
385 break;
386 case ft_encoding_symbol:
387 (*insertface)->fs.fsCsb[0] |= 1L << 31;
388 break;
389 default:
390 break;
395 if((*insertface)->fs.fsCsb[0] & ~(1L << 31))
396 have_installed_roman_font = TRUE;
398 num_faces = ft_face->num_faces;
399 pFT_Done_Face(ft_face);
400 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
401 debugstr_w(StyleW));
402 } while(num_faces > ++face_index);
403 return TRUE;
406 static void DumpFontList(void)
408 Family *family;
409 Face *face;
411 for(family = FontList; family; family = family->next) {
412 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
413 for(face = family->FirstFace; face; face = face->next) {
414 TRACE("\t%s\n", debugstr_w(face->StyleName));
417 return;
420 static void DumpSubstList(void)
422 FontSubst *psub;
424 for(psub = substlist; psub; psub = psub->next)
425 if(psub->from.charset != -1 || psub->to.charset != -1)
426 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
427 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
428 else
429 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
430 debugstr_w(psub->to.name));
431 return;
434 static LPWSTR strdupW(LPWSTR p)
436 LPWSTR ret;
437 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
438 ret = HeapAlloc(GetProcessHeap(), 0, len);
439 memcpy(ret, p, len);
440 return ret;
443 static void split_subst_info(NameCs *nc, LPSTR str)
445 CHAR *p = strrchr(str, ',');
446 DWORD len;
448 nc->charset = -1;
449 if(p && *(p+1)) {
450 nc->charset = strtol(p+1, NULL, 10);
451 *p = '\0';
453 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
454 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
455 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
458 static void LoadSubstList(void)
460 FontSubst *psub, **ppsub;
461 HKEY hkey;
462 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
463 LPSTR value;
464 LPVOID data;
466 if(substlist) {
467 for(psub = substlist; psub;) {
468 FontSubst *ptmp;
469 HeapFree(GetProcessHeap(), 0, psub->to.name);
470 HeapFree(GetProcessHeap(), 0, psub->from.name);
471 ptmp = psub;
472 psub = psub->next;
473 HeapFree(GetProcessHeap(), 0, ptmp);
475 substlist = NULL;
478 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
479 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
480 &hkey) == ERROR_SUCCESS) {
482 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
483 &valuelen, &datalen, NULL, NULL);
485 valuelen++; /* returned value doesn't include room for '\0' */
486 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
487 data = HeapAlloc(GetProcessHeap(), 0, datalen);
489 dlen = datalen;
490 vlen = valuelen;
491 ppsub = &substlist;
492 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
493 &dlen) == ERROR_SUCCESS) {
494 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
496 *ppsub = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppsub));
497 (*ppsub)->next = NULL;
498 split_subst_info(&((*ppsub)->from), value);
499 split_subst_info(&((*ppsub)->to), data);
501 /* Win 2000 doesn't allow mapping between different charsets
502 or mapping of DEFAULT_CHARSET */
503 if(((*ppsub)->to.charset != (*ppsub)->from.charset) ||
504 (*ppsub)->to.charset == DEFAULT_CHARSET) {
505 HeapFree(GetProcessHeap(), 0, (*ppsub)->to.name);
506 HeapFree(GetProcessHeap(), 0, (*ppsub)->from.name);
507 HeapFree(GetProcessHeap(), 0, *ppsub);
508 *ppsub = NULL;
509 } else {
510 ppsub = &((*ppsub)->next);
512 /* reset dlen and vlen */
513 dlen = datalen;
514 vlen = valuelen;
516 HeapFree(GetProcessHeap(), 0, data);
517 HeapFree(GetProcessHeap(), 0, value);
518 RegCloseKey(hkey);
522 /***********************************************************
523 * The replacement list is a way to map an entire font
524 * family onto another family. For example adding
526 * [HKLM\Software\Wine\Wine\FontReplacements]
527 * "Wingdings"="Winedings"
529 * would enumerate the Winedings font both as Winedings and
530 * Wingdings. However if a real Wingdings font is present the
531 * replacement does not take place.
534 static void LoadReplaceList(void)
536 HKEY hkey;
537 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
538 LPSTR value;
539 LPVOID data;
540 Family *family;
541 Face *face;
542 WCHAR old_nameW[200];
544 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
545 "Software\\Wine\\Wine\\FontReplacements",
546 &hkey) == ERROR_SUCCESS) {
548 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
549 &valuelen, &datalen, NULL, NULL);
551 valuelen++; /* returned value doesn't include room for '\0' */
552 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
553 data = HeapAlloc(GetProcessHeap(), 0, datalen);
555 dlen = datalen;
556 vlen = valuelen;
557 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
558 &dlen) == ERROR_SUCCESS) {
559 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
560 /* "NewName"="Oldname" */
561 if(!MultiByteToWideChar(CP_ACP, 0, data, -1, old_nameW, sizeof(old_nameW)))
562 break;
564 /* Find the old family and hence all of the font files
565 in that family */
566 for(family = FontList; family; family = family->next) {
567 if(!strcmpiW(family->FamilyName, old_nameW)) {
568 for(face = family->FirstFace; face; face = face->next) {
569 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
570 debugstr_w(face->StyleName), value);
571 /* Now add a new entry with the new family name */
572 AddFontFileToList(face->file, value);
574 break;
577 /* reset dlen and vlen */
578 dlen = datalen;
579 vlen = valuelen;
581 HeapFree(GetProcessHeap(), 0, data);
582 HeapFree(GetProcessHeap(), 0, value);
583 RegCloseKey(hkey);
588 static BOOL ReadFontDir(char *dirname)
590 DIR *dir;
591 struct dirent *dent;
592 char path[MAX_PATH];
594 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
596 dir = opendir(dirname);
597 if(!dir) {
598 ERR("Can't open directory %s\n", debugstr_a(dirname));
599 return FALSE;
601 while((dent = readdir(dir)) != NULL) {
602 struct stat statbuf;
604 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
605 continue;
607 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
609 sprintf(path, "%s/%s", dirname, dent->d_name);
611 if(stat(path, &statbuf) == -1)
613 WARN("Can't stat %s\n", debugstr_a(path));
614 continue;
616 if(S_ISDIR(statbuf.st_mode))
617 ReadFontDir(path);
618 else
619 AddFontFileToList(path, NULL);
621 closedir(dir);
622 return TRUE;
625 /*************************************************************
626 * WineEngAddFontResourceEx
629 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
631 if (ft_handle) /* do it only if we have freetype up and running */
633 DWORD len = WideCharToMultiByte(CP_ACP, 0, file, -1, NULL, 0, NULL, NULL);
634 LPSTR fileA = HeapAlloc(GetProcessHeap(), 0, len);
635 char unixname[MAX_PATH];
636 WideCharToMultiByte(CP_ACP, 0, file, -1, fileA, len, NULL, NULL);
638 if(flags)
639 FIXME("Ignoring flags %lx\n", flags);
641 if(wine_get_unix_file_name(fileA, unixname, sizeof(unixname)))
642 AddFontFileToList(unixname, NULL);
643 HeapFree(GetProcessHeap(), 0, fileA);
645 return 1;
648 /*************************************************************
649 * WineEngRemoveFontResourceEx
652 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
654 FIXME(":stub\n");
655 return TRUE;
658 /*************************************************************
659 * WineEngInit
661 * Initialize FreeType library and create a list of available faces
663 BOOL WineEngInit(void)
665 HKEY hkey;
666 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
667 LPSTR value;
668 LPVOID data;
669 char windowsdir[MAX_PATH];
670 char unixname[MAX_PATH];
672 TRACE("\n");
674 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
675 if(!ft_handle) {
676 WINE_MESSAGE(
677 "Wine cannot find the FreeType font library. To enable Wine to\n"
678 "use TrueType fonts please install a version of FreeType greater than\n"
679 "or equal to 2.0.5.\n"
680 "http://www.freetype.org\n");
681 return FALSE;
684 #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;}
686 LOAD_FUNCPTR(FT_Vector_Unit)
687 LOAD_FUNCPTR(FT_Done_Face)
688 LOAD_FUNCPTR(FT_Get_Char_Index)
689 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
690 LOAD_FUNCPTR(FT_Init_FreeType)
691 LOAD_FUNCPTR(FT_Load_Glyph)
692 LOAD_FUNCPTR(FT_Matrix_Multiply)
693 LOAD_FUNCPTR(FT_MulFix)
694 LOAD_FUNCPTR(FT_New_Face)
695 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
696 LOAD_FUNCPTR(FT_Outline_Transform)
697 LOAD_FUNCPTR(FT_Outline_Translate)
698 LOAD_FUNCPTR(FT_Select_Charmap)
699 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
700 LOAD_FUNCPTR(FT_Vector_Transform)
702 #undef LOAD_FUNCPTR
703 /* Don't warn if this one is missing */
704 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
705 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
707 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
708 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
709 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
710 <= 2.0.3 has FT_Sqrt64 */
711 goto sym_not_found;
714 if(pFT_Init_FreeType(&library) != 0) {
715 ERR("Can't init FreeType library\n");
716 wine_dlclose(ft_handle, NULL, 0);
717 ft_handle = NULL;
718 return FALSE;
720 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
721 if (pFT_Library_Version)
723 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
725 if (FT_Version.major<=0)
727 FT_Version.major=2;
728 FT_Version.minor=0;
729 FT_Version.patch=5;
731 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
733 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
734 GetWindowsDirectoryA(windowsdir, sizeof(windowsdir));
735 strcat(windowsdir, "\\Fonts");
736 if(wine_get_unix_file_name(windowsdir, unixname, sizeof(unixname)))
737 ReadFontDir(unixname);
739 /* now look under HKLM\Software\Microsoft\Windows\CurrentVersion\Fonts
740 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
741 full path as the entry */
742 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
743 "Software\\Microsoft\\Windows\\CurrentVersion\\Fonts",
744 &hkey) == ERROR_SUCCESS) {
745 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
746 &valuelen, &datalen, NULL, NULL);
748 valuelen++; /* returned value doesn't include room for '\0' */
749 value = HeapAlloc(GetProcessHeap(), 0, valuelen);
750 data = HeapAlloc(GetProcessHeap(), 0, datalen);
752 dlen = datalen;
753 vlen = valuelen;
754 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
755 &dlen) == ERROR_SUCCESS) {
756 if(((LPSTR)data)[0] && ((LPSTR)data)[1] == ':')
757 if(wine_get_unix_file_name((LPSTR)data, unixname, sizeof(unixname)))
758 AddFontFileToList(unixname, NULL);
760 /* reset dlen and vlen */
761 dlen = datalen;
762 vlen = valuelen;
764 HeapFree(GetProcessHeap(), 0, data);
765 HeapFree(GetProcessHeap(), 0, value);
766 RegCloseKey(hkey);
770 /* then look in any directories that we've specified in the config file */
771 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
772 "Software\\Wine\\Wine\\Config\\FontDirs",
773 &hkey) == ERROR_SUCCESS) {
775 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
776 &valuelen, &datalen, NULL, NULL);
778 valuelen++; /* returned value doesn't include room for '\0' */
779 value = HeapAlloc(GetProcessHeap(), 0, valuelen);
780 data = HeapAlloc(GetProcessHeap(), 0, datalen);
782 dlen = datalen;
783 vlen = valuelen;
784 i = 0;
785 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
786 &dlen) == ERROR_SUCCESS) {
787 TRACE("Got %s=%s\n", value, (LPSTR)data);
788 ReadFontDir((LPSTR)data);
789 /* reset dlen and vlen */
790 dlen = datalen;
791 vlen = valuelen;
793 HeapFree(GetProcessHeap(), 0, data);
794 HeapFree(GetProcessHeap(), 0, value);
795 RegCloseKey(hkey);
798 DumpFontList();
799 LoadSubstList();
800 DumpSubstList();
801 LoadReplaceList();
802 return TRUE;
803 sym_not_found:
804 WINE_MESSAGE(
805 "Wine cannot find certain functions that it needs inside the FreeType\n"
806 "font library. To enable Wine to use TrueType fonts please upgrade\n"
807 "FreeType to at least version 2.0.5.\n"
808 "http://www.freetype.org\n");
809 wine_dlclose(ft_handle, NULL, 0);
810 ft_handle = NULL;
811 return FALSE;
815 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
817 TT_OS2 *pOS2;
818 LONG ppem;
820 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
822 if(height == 0) height = 16;
824 /* Calc. height of EM square:
826 * For +ve lfHeight we have
827 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
828 * Re-arranging gives:
829 * ppem = units_per_em * lfheight / (winAscent + winDescent)
831 * For -ve lfHeight we have
832 * |lfHeight| = ppem
833 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
834 * with il = winAscent + winDescent - units_per_em]
838 if(height > 0)
839 ppem = ft_face->units_per_EM * height /
840 (pOS2->usWinAscent + pOS2->usWinDescent);
841 else
842 ppem = -height;
844 return ppem;
847 static LONG load_VDMX(GdiFont, LONG);
849 static FT_Face OpenFontFile(GdiFont font, char *file, FT_Long face_index, LONG height)
851 FT_Error err;
852 FT_Face ft_face;
853 LONG ppem;
855 err = pFT_New_Face(library, file, face_index, &ft_face);
856 if(err) {
857 ERR("FT_New_Face rets %d\n", err);
858 return 0;
861 /* set it here, as load_VDMX needs it */
862 font->ft_face = ft_face;
864 /* load the VDMX table if we have one */
865 ppem = load_VDMX(font, height);
866 if(ppem == 0)
867 ppem = calc_ppem_for_height(ft_face, height);
869 pFT_Set_Pixel_Sizes(ft_face, 0, ppem);
871 return ft_face;
875 static int get_nearest_charset(Face *face)
877 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
878 a single face with the requested charset. The idea is to check if
879 the selected font supports the current ANSI codepage, if it does
880 return the corresponding charset, else return the first charset */
882 CHARSETINFO csi;
883 int acp = GetACP(), i;
884 DWORD fs0;
886 if(TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE))
887 if(csi.fs.fsCsb[0] & face->fs.fsCsb[0])
888 return csi.ciCharset;
890 for(i = 0; i < 32; i++) {
891 fs0 = 1L << i;
892 if(face->fs.fsCsb[0] & fs0) {
893 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG))
894 return csi.ciCharset;
895 else
896 FIXME("TCI failing on %lx\n", fs0);
900 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08lx file = %s\n",
901 face->fs.fsCsb[0], face->file);
902 return DEFAULT_CHARSET;
905 static GdiFont alloc_font(void)
907 GdiFont ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
908 ret->gmsize = INIT_GM_SIZE;
909 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
910 ret->gmsize * sizeof(*ret->gm));
911 ret->next = NULL;
912 ret->potm = NULL;
913 ret->xform.eM11 = ret->xform.eM22 = 1.0;
914 return ret;
917 static void free_font(GdiFont font)
919 if (font->ft_face) pFT_Done_Face(font->ft_face);
920 if (font->potm) HeapFree(GetProcessHeap(), 0, font->potm);
921 if (font->name) HeapFree(GetProcessHeap(), 0, font->name);
922 HeapFree(GetProcessHeap(), 0, font->gm);
923 HeapFree(GetProcessHeap(), 0, font);
927 /*************************************************************
928 * load_VDMX
930 * load the vdmx entry for the specified height
933 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
934 ( ( (FT_ULong)_x4 << 24 ) | \
935 ( (FT_ULong)_x3 << 16 ) | \
936 ( (FT_ULong)_x2 << 8 ) | \
937 (FT_ULong)_x1 )
939 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
941 typedef struct {
942 BYTE bCharSet;
943 BYTE xRatio;
944 BYTE yStartRatio;
945 BYTE yEndRatio;
946 } Ratios;
949 static LONG load_VDMX(GdiFont font, LONG height)
951 BYTE hdr[6], tmp[2], group[4];
952 BYTE devXRatio, devYRatio;
953 USHORT numRecs, numRatios;
954 DWORD offset = -1;
955 LONG ppem = 0;
956 int i, result;
958 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
960 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
961 return ppem;
963 /* FIXME: need the real device aspect ratio */
964 devXRatio = 1;
965 devYRatio = 1;
967 numRecs = GET_BE_WORD(&hdr[2]);
968 numRatios = GET_BE_WORD(&hdr[4]);
970 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
971 for(i = 0; i < numRatios; i++) {
972 Ratios ratio;
974 offset = (3 * 2) + (i * sizeof(Ratios));
975 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
976 offset = -1;
978 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
980 if(ratio.bCharSet != 1)
981 continue;
983 if((ratio.xRatio == 0 &&
984 ratio.yStartRatio == 0 &&
985 ratio.yEndRatio == 0) ||
986 (devXRatio == ratio.xRatio &&
987 devYRatio >= ratio.yStartRatio &&
988 devYRatio <= ratio.yEndRatio))
990 offset = (3 * 2) + (numRatios * 4) + (i * 2);
991 WineEngGetFontData(font, MS_VDMX_TAG, offset, tmp, 2);
992 offset = GET_BE_WORD(tmp);
993 break;
997 if(offset < 0) {
998 FIXME("No suitable ratio found\n");
999 return ppem;
1002 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, group, 4) != GDI_ERROR) {
1003 USHORT recs;
1004 BYTE startsz, endsz;
1005 BYTE *vTable;
1007 recs = GET_BE_WORD(group);
1008 startsz = group[2];
1009 endsz = group[3];
1011 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
1013 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
1014 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
1015 if(result == GDI_ERROR) {
1016 FIXME("Failed to retrieve vTable\n");
1017 goto end;
1020 if(height > 0) {
1021 for(i = 0; i < recs; i++) {
1022 SHORT yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1023 SHORT yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1024 ppem = GET_BE_WORD(&vTable[i * 6]);
1026 if(yMax + -yMin == height) {
1027 font->yMax = yMax;
1028 font->yMin = yMin;
1029 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1030 break;
1032 if(yMax + -yMin > height) {
1033 if(--i < 0) {
1034 ppem = 0;
1035 goto end; /* failed */
1037 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1038 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1039 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1040 break;
1043 if(!font->yMax) {
1044 ppem = 0;
1045 TRACE("ppem not found for height %ld\n", height);
1047 } else {
1048 ppem = -height;
1049 if(ppem < startsz || ppem > endsz)
1050 goto end;
1052 for(i = 0; i < recs; i++) {
1053 USHORT yPelHeight;
1054 yPelHeight = GET_BE_WORD(&vTable[i * 6]);
1056 if(yPelHeight > ppem)
1057 break; /* failed */
1059 if(yPelHeight == ppem) {
1060 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1061 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1062 TRACE("ppem %ld found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
1063 break;
1067 end:
1068 HeapFree(GetProcessHeap(), 0, vTable);
1071 return ppem;
1075 /*************************************************************
1076 * WineEngCreateFontInstance
1079 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
1081 GdiFont ret;
1082 Face *face;
1083 Family *family = NULL;
1084 BOOL bd, it;
1085 LOGFONTW lf;
1086 CHARSETINFO csi;
1088 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
1090 TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
1091 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
1092 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
1093 lf.lfEscapement);
1095 /* check the cache first */
1096 for(ret = GdiFontList; ret; ret = ret->next) {
1097 if(ret->hfont == hfont && !memcmp(&ret->xform, &dc->xformWorld2Vport, offsetof(XFORM, eDx))) {
1098 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
1099 return ret;
1103 if(!FontList || !have_installed_roman_font) /* No fonts installed */
1105 TRACE("No fonts installed\n");
1106 return NULL;
1109 ret = alloc_font();
1110 memcpy(&ret->xform, &dc->xformWorld2Vport, sizeof(XFORM));
1112 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
1113 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
1114 original value lfCharSet. Note this is a special case for
1115 Symbol and doesn't happen at least for "Wingdings*" */
1117 if(!strcmpiW(lf.lfFaceName, SymbolW))
1118 lf.lfCharSet = SYMBOL_CHARSET;
1120 if(!TranslateCharsetInfo((DWORD*)(INT)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
1121 switch(lf.lfCharSet) {
1122 case DEFAULT_CHARSET:
1123 csi.fs.fsCsb[0] = 0;
1124 break;
1125 default:
1126 FIXME("Untranslated charset %d\n", lf.lfCharSet);
1127 csi.fs.fsCsb[0] = 0;
1128 break;
1132 if(lf.lfFaceName[0] != '\0') {
1133 FontSubst *psub;
1134 for(psub = substlist; psub; psub = psub->next)
1135 if(!strcmpiW(lf.lfFaceName, psub->from.name) &&
1136 (psub->from.charset == -1 ||
1137 psub->from.charset == lf.lfCharSet))
1138 break;
1139 if(psub) {
1140 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
1141 debugstr_w(psub->to.name));
1142 strcpyW(lf.lfFaceName, psub->to.name);
1145 /* We want a match on name and charset or just name if
1146 charset was DEFAULT_CHARSET. If the latter then
1147 we fixup the returned charset later in get_nearest_charset
1148 where we'll either use the charset of the current ansi codepage
1149 or if that's unavailable the first charset that the font supports.
1151 for(family = FontList; family; family = family->next) {
1152 if(!strcmpiW(family->FamilyName, lf.lfFaceName))
1153 if((csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0]) || !csi.fs.fsCsb[0])
1154 break;
1157 if(!family) { /* do other aliases here */
1158 if(!strcmpiW(lf.lfFaceName, SystemW))
1159 strcpyW(lf.lfFaceName, defSystem);
1160 else if(!strcmpiW(lf.lfFaceName, MSSansSerifW))
1161 strcpyW(lf.lfFaceName, defSans);
1162 else if(!strcmpiW(lf.lfFaceName, HelvW))
1163 strcpyW(lf.lfFaceName, defSans);
1164 else
1165 goto not_found;
1167 for(family = FontList; family; family = family->next) {
1168 if(!strcmpiW(family->FamilyName, lf.lfFaceName))
1169 if((csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0]) || !csi.fs.fsCsb[0])
1170 break;
1175 not_found:
1176 if(!family) {
1177 /* If requested charset was DEFAULT_CHARSET then try using charset
1178 corresponding to the current ansi codepage */
1179 if(!csi.fs.fsCsb[0]) {
1180 INT acp = GetACP();
1181 if(!TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE)) {
1182 FIXME("TCI failed on codepage %d\n", acp);
1183 csi.fs.fsCsb[0] = 0;
1184 } else
1185 lf.lfCharSet = csi.ciCharset;
1188 /* Face families are in the top 4 bits of lfPitchAndFamily,
1189 so mask with 0xF0 before testing */
1191 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
1192 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
1193 strcpyW(lf.lfFaceName, defFixed);
1194 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
1195 strcpyW(lf.lfFaceName, defSerif);
1196 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
1197 strcpyW(lf.lfFaceName, defSans);
1198 else
1199 strcpyW(lf.lfFaceName, defSans);
1200 for(family = FontList; family; family = family->next) {
1201 if(!strcmpiW(family->FamilyName, lf.lfFaceName) &&
1202 (csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0]))
1203 break;
1207 if(!family) {
1208 for(family = FontList; family; family = family->next) {
1209 if(csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0])
1210 break;
1214 if(!family) {
1215 family = FontList;
1216 csi.fs.fsCsb[0] = 0;
1217 FIXME("just using first face for now\n");
1220 it = lf.lfItalic ? 1 : 0;
1221 bd = lf.lfWeight > 550 ? 1 : 0;
1223 for(face = family->FirstFace; face; face = face->next) {
1224 if(!(face->Italic ^ it) && !(face->Bold ^ bd))
1225 break;
1227 if(!face) {
1228 face = family->FirstFace;
1229 if(it && !face->Italic) ret->fake_italic = TRUE;
1230 if(bd && !face->Bold) ret->fake_bold = TRUE;
1233 memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
1235 if(csi.fs.fsCsb[0])
1236 ret->charset = lf.lfCharSet;
1237 else
1238 ret->charset = get_nearest_charset(face);
1240 TRACE("Chosen: %s %s\n", debugstr_w(family->FamilyName),
1241 debugstr_w(face->StyleName));
1243 ret->ft_face = OpenFontFile(ret, face->file, face->face_index,
1244 lf.lfHeight < 0 ?
1245 -abs(INTERNAL_YWSTODS(dc,lf.lfHeight)) :
1246 abs(INTERNAL_YWSTODS(dc, lf.lfHeight)));
1247 if (!ret->ft_face)
1249 free_font( ret );
1250 return 0;
1253 if (ret->charset == SYMBOL_CHARSET &&
1254 !pFT_Select_Charmap(ret->ft_face, MS_MAKE_TAG('s','y','m','b'))) {
1255 /* No ops */
1257 else if (!pFT_Select_Charmap(ret->ft_face, MS_MAKE_TAG('u','n','i','c'))) {
1258 /* No ops */
1260 else {
1261 pFT_Select_Charmap(ret->ft_face, MS_MAKE_TAG('a','r','m','n'));
1264 ret->orientation = lf.lfOrientation;
1265 ret->name = strdupW(family->FamilyName);
1267 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
1268 ret->hfont = hfont;
1269 ret->aveWidth= lf.lfWidth;
1270 ret->next = GdiFontList;
1271 GdiFontList = ret;
1273 return ret;
1276 static void DumpGdiFontList(void)
1278 GdiFont gdiFont;
1280 TRACE("---------- gdiFont Cache ----------\n");
1281 for(gdiFont = GdiFontList; gdiFont; gdiFont = gdiFont->next) {
1282 LOGFONTW lf;
1283 GetObjectW( gdiFont->hfont, sizeof(lf), &lf );
1284 TRACE("gdiFont=%p hfont=%p (%s)\n",
1285 gdiFont, gdiFont->hfont, debugstr_w(lf.lfFaceName));
1289 /*************************************************************
1290 * WineEngDestroyFontInstance
1292 * free the gdiFont associated with this handle
1295 BOOL WineEngDestroyFontInstance(HFONT handle)
1297 GdiFont gdiFont;
1298 GdiFont gdiPrev = NULL;
1299 BOOL ret = FALSE;
1301 TRACE("destroying hfont=%p\n", handle);
1302 if(TRACE_ON(font))
1303 DumpGdiFontList();
1305 gdiFont = GdiFontList;
1306 while(gdiFont) {
1307 if(gdiFont->hfont == handle) {
1308 if(gdiPrev) {
1309 gdiPrev->next = gdiFont->next;
1310 free_font(gdiFont);
1311 gdiFont = gdiPrev->next;
1312 } else {
1313 GdiFontList = gdiFont->next;
1314 free_font(gdiFont);
1315 gdiFont = GdiFontList;
1317 ret = TRUE;
1318 } else {
1319 gdiPrev = gdiFont;
1320 gdiFont = gdiFont->next;
1323 return ret;
1326 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
1327 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
1329 OUTLINETEXTMETRICW *potm;
1330 UINT size;
1331 GdiFont font = alloc_font();
1333 if (!(font->ft_face = OpenFontFile(font, face->file, face->face_index, 100)))
1335 free_font(font);
1336 return;
1339 font->name = strdupW(face->family->FamilyName);
1341 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
1343 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
1344 potm = HeapAlloc(GetProcessHeap(), 0, size);
1345 WineEngGetOutlineTextMetrics(font, size, potm);
1347 #define TM potm->otmTextMetrics
1349 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = TM.tmHeight;
1350 pntm->ntmTm.tmAscent = TM.tmAscent;
1351 pntm->ntmTm.tmDescent = TM.tmDescent;
1352 pntm->ntmTm.tmInternalLeading = TM.tmInternalLeading;
1353 pntm->ntmTm.tmExternalLeading = TM.tmExternalLeading;
1354 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = TM.tmAveCharWidth;
1355 pntm->ntmTm.tmMaxCharWidth = TM.tmMaxCharWidth;
1356 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = TM.tmWeight;
1357 pntm->ntmTm.tmOverhang = TM.tmOverhang;
1358 pntm->ntmTm.tmDigitizedAspectX = TM.tmDigitizedAspectX;
1359 pntm->ntmTm.tmDigitizedAspectY = TM.tmDigitizedAspectY;
1360 pntm->ntmTm.tmFirstChar = TM.tmFirstChar;
1361 pntm->ntmTm.tmLastChar = TM.tmLastChar;
1362 pntm->ntmTm.tmDefaultChar = TM.tmDefaultChar;
1363 pntm->ntmTm.tmBreakChar = TM.tmBreakChar;
1364 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = TM.tmItalic;
1365 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = TM.tmUnderlined;
1366 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = TM.tmStruckOut;
1367 pntm->ntmTm.tmPitchAndFamily = TM.tmPitchAndFamily;
1368 pelf->elfLogFont.lfPitchAndFamily = (TM.tmPitchAndFamily & 0xf1) + 1;
1369 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = TM.tmCharSet;
1370 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
1371 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
1372 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
1374 pntm->ntmTm.ntmFlags = TM.tmItalic ? NTM_ITALIC : 0;
1375 if(TM.tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
1376 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
1378 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
1379 pntm->ntmTm.ntmCellHeight = 0;
1380 pntm->ntmTm.ntmAvgWidth = 0;
1382 *ptype = TM.tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
1383 if(!(TM.tmPitchAndFamily & TMPF_VECTOR))
1384 *ptype |= RASTER_FONTTYPE;
1386 #undef TM
1387 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
1389 strncpyW(pelf->elfLogFont.lfFaceName,
1390 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
1391 LF_FACESIZE);
1392 strncpyW(pelf->elfFullName,
1393 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
1394 LF_FULLFACESIZE);
1395 strncpyW(pelf->elfStyle,
1396 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
1397 LF_FACESIZE);
1398 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
1400 HeapFree(GetProcessHeap(), 0, potm);
1401 free_font(font);
1402 return;
1405 /*************************************************************
1406 * WineEngEnumFonts
1409 DWORD WineEngEnumFonts(LPLOGFONTW plf, DEVICEFONTENUMPROC proc,
1410 LPARAM lparam)
1412 Family *family;
1413 Face *face;
1414 ENUMLOGFONTEXW elf;
1415 NEWTEXTMETRICEXW ntm;
1416 DWORD type, ret = 1;
1417 FONTSIGNATURE fs;
1418 CHARSETINFO csi;
1419 LOGFONTW lf;
1420 int i;
1422 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
1424 if(plf->lfFaceName[0]) {
1425 FontSubst *psub;
1426 for(psub = substlist; psub; psub = psub->next)
1427 if(!strcmpiW(plf->lfFaceName, psub->from.name) &&
1428 (psub->from.charset == -1 ||
1429 psub->from.charset == plf->lfCharSet))
1430 break;
1431 if(psub) {
1432 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
1433 debugstr_w(psub->to.name));
1434 memcpy(&lf, plf, sizeof(lf));
1435 strcpyW(lf.lfFaceName, psub->to.name);
1436 plf = &lf;
1438 for(family = FontList; family; family = family->next) {
1439 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
1440 for(face = family->FirstFace; face; face = face->next) {
1441 GetEnumStructs(face, &elf, &ntm, &type);
1442 for(i = 0; i < 32; i++) {
1443 if(face->fs.fsCsb[0] & (1L << i)) {
1444 fs.fsCsb[0] = 1L << i;
1445 fs.fsCsb[1] = 0;
1446 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
1447 TCI_SRCFONTSIG))
1448 csi.ciCharset = DEFAULT_CHARSET;
1449 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
1450 if(csi.ciCharset != DEFAULT_CHARSET) {
1451 elf.elfLogFont.lfCharSet =
1452 ntm.ntmTm.tmCharSet = csi.ciCharset;
1453 if(ElfScriptsW[i])
1454 strcpyW(elf.elfScript, ElfScriptsW[i]);
1455 else
1456 FIXME("Unknown elfscript for bit %d\n", i);
1457 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
1458 debugstr_w(elf.elfLogFont.lfFaceName),
1459 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
1460 csi.ciCharset, type, debugstr_w(elf.elfScript),
1461 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
1462 ntm.ntmTm.ntmFlags);
1463 ret = proc(&elf, &ntm, type, lparam);
1464 if(!ret) goto end;
1471 } else {
1472 for(family = FontList; family; family = family->next) {
1473 GetEnumStructs(family->FirstFace, &elf, &ntm, &type);
1474 for(i = 0; i < 32; i++) {
1475 if(family->FirstFace->fs.fsCsb[0] & (1L << i)) {
1476 fs.fsCsb[0] = 1L << i;
1477 fs.fsCsb[1] = 0;
1478 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
1479 TCI_SRCFONTSIG))
1480 csi.ciCharset = DEFAULT_CHARSET;
1481 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
1482 if(csi.ciCharset != DEFAULT_CHARSET) {
1483 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
1484 csi.ciCharset;
1485 if(ElfScriptsW[i])
1486 strcpyW(elf.elfScript, ElfScriptsW[i]);
1487 else
1488 FIXME("Unknown elfscript for bit %d\n", i);
1489 TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
1490 debugstr_w(elf.elfLogFont.lfFaceName),
1491 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
1492 csi.ciCharset, type, debugstr_w(elf.elfScript),
1493 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
1494 ntm.ntmTm.ntmFlags);
1495 ret = proc(&elf, &ntm, type, lparam);
1496 if(!ret) goto end;
1502 end:
1503 return ret;
1506 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
1508 pt->x.value = vec->x >> 6;
1509 pt->x.fract = (vec->x & 0x3f) << 10;
1510 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
1511 pt->y.value = vec->y >> 6;
1512 pt->y.fract = (vec->y & 0x3f) << 10;
1513 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
1514 return;
1517 static FT_UInt get_glyph_index(GdiFont font, UINT glyph)
1519 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
1520 glyph = glyph + 0xf000;
1521 return pFT_Get_Char_Index(font->ft_face, glyph);
1524 /*************************************************************
1525 * WineEngGetGlyphIndices
1527 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
1529 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
1530 LPWORD pgi, DWORD flags)
1532 INT i;
1534 for(i = 0; i < count; i++)
1535 pgi[i] = get_glyph_index(font, lpstr[i]);
1537 return count;
1540 /*************************************************************
1541 * WineEngGetGlyphOutline
1543 * Behaves in exactly the same way as the win32 api GetGlyphOutline
1544 * except that the first parameter is the HWINEENGFONT of the font in
1545 * question rather than an HDC.
1548 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
1549 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
1550 const MAT2* lpmat)
1552 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
1553 FT_Face ft_face = font->ft_face;
1554 FT_UInt glyph_index;
1555 DWORD width, height, pitch, needed = 0;
1556 FT_Bitmap ft_bitmap;
1557 FT_Error err;
1558 INT left, right, top = 0, bottom = 0;
1559 FT_Angle angle = 0;
1560 FT_Int load_flags = FT_LOAD_DEFAULT;
1561 float widthRatio = 1.0;
1562 FT_Matrix transMat = identityMat;
1563 BOOL needsTransform = FALSE;
1566 TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font, glyph, format, lpgm,
1567 buflen, buf, lpmat);
1569 if(format & GGO_GLYPH_INDEX) {
1570 glyph_index = glyph;
1571 format &= ~GGO_GLYPH_INDEX;
1572 } else
1573 glyph_index = get_glyph_index(font, glyph);
1575 if(glyph_index >= font->gmsize) {
1576 font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
1577 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
1578 font->gmsize * sizeof(*font->gm));
1579 } else {
1580 if(format == GGO_METRICS && font->gm[glyph_index].init) {
1581 memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
1582 return 1; /* FIXME */
1586 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP) || font->aveWidth || lpmat)
1587 load_flags |= FT_LOAD_NO_BITMAP;
1589 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
1591 if(err) {
1592 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
1593 return GDI_ERROR;
1596 /* Scaling factor */
1597 if (font->aveWidth && font->potm) {
1598 widthRatio = (float)font->aveWidth * font->xform.eM11 / (float) font->potm->otmTextMetrics.tmAveCharWidth;
1601 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
1602 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
1604 font->gm[glyph_index].adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
1605 font->gm[glyph_index].lsb = left >> 6;
1606 font->gm[glyph_index].bbx = (right - left) >> 6;
1608 /* Scaling transform */
1609 if(font->aveWidth) {
1610 FT_Matrix scaleMat;
1611 scaleMat.xx = FT_FixedFromFloat(widthRatio);
1612 scaleMat.xy = 0;
1613 scaleMat.yx = 0;
1614 scaleMat.yy = (1 << 16);
1616 pFT_Matrix_Multiply(&scaleMat, &transMat);
1617 needsTransform = TRUE;
1620 /* Rotation transform */
1621 if(font->orientation) {
1622 FT_Matrix rotationMat;
1623 FT_Vector vecAngle;
1624 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
1625 pFT_Vector_Unit(&vecAngle, angle);
1626 rotationMat.xx = vecAngle.x;
1627 rotationMat.xy = -vecAngle.y;
1628 rotationMat.yx = -rotationMat.xy;
1629 rotationMat.yy = rotationMat.xx;
1631 pFT_Matrix_Multiply(&rotationMat, &transMat);
1632 needsTransform = TRUE;
1635 /* Extra transformation specified by caller */
1636 if (lpmat) {
1637 FT_Matrix extraMat;
1638 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
1639 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
1640 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
1641 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
1642 pFT_Matrix_Multiply(&extraMat, &transMat);
1643 needsTransform = TRUE;
1646 if(!needsTransform) {
1647 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
1648 bottom = (ft_face->glyph->metrics.horiBearingY -
1649 ft_face->glyph->metrics.height) & -64;
1650 lpgm->gmCellIncX = font->gm[glyph_index].adv;
1651 lpgm->gmCellIncY = 0;
1652 } else {
1653 INT xc, yc;
1654 FT_Vector vec;
1655 for(xc = 0; xc < 2; xc++) {
1656 for(yc = 0; yc < 2; yc++) {
1657 vec.x = (ft_face->glyph->metrics.horiBearingX +
1658 xc * ft_face->glyph->metrics.width);
1659 vec.y = ft_face->glyph->metrics.horiBearingY -
1660 yc * ft_face->glyph->metrics.height;
1661 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
1662 pFT_Vector_Transform(&vec, &transMat);
1663 if(xc == 0 && yc == 0) {
1664 left = right = vec.x;
1665 top = bottom = vec.y;
1666 } else {
1667 if(vec.x < left) left = vec.x;
1668 else if(vec.x > right) right = vec.x;
1669 if(vec.y < bottom) bottom = vec.y;
1670 else if(vec.y > top) top = vec.y;
1674 left = left & -64;
1675 right = (right + 63) & -64;
1676 bottom = bottom & -64;
1677 top = (top + 63) & -64;
1679 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
1680 vec.x = ft_face->glyph->metrics.horiAdvance;
1681 vec.y = 0;
1682 pFT_Vector_Transform(&vec, &transMat);
1683 lpgm->gmCellIncX = (vec.x+63) >> 6;
1684 lpgm->gmCellIncY = -((vec.y+63) >> 6);
1686 lpgm->gmBlackBoxX = (right - left) >> 6;
1687 lpgm->gmBlackBoxY = (top - bottom) >> 6;
1688 lpgm->gmptGlyphOrigin.x = left >> 6;
1689 lpgm->gmptGlyphOrigin.y = top >> 6;
1691 memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
1692 font->gm[glyph_index].init = TRUE;
1694 if(format == GGO_METRICS)
1695 return 1; /* FIXME */
1697 if (buf && !buflen){
1698 return GDI_ERROR;
1701 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP) {
1702 FIXME("loaded a bitmap\n");
1703 return GDI_ERROR;
1706 switch(format) {
1707 case GGO_BITMAP:
1708 width = lpgm->gmBlackBoxX;
1709 height = lpgm->gmBlackBoxY;
1710 pitch = ((width + 31) >> 5) << 2;
1711 needed = pitch * height;
1713 if(!buf || !buflen) break;
1715 switch(ft_face->glyph->format) {
1716 case ft_glyph_format_bitmap:
1718 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
1719 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
1720 INT h = ft_face->glyph->bitmap.rows;
1721 while(h--) {
1722 memcpy(dst, src, w);
1723 src += ft_face->glyph->bitmap.pitch;
1724 dst += pitch;
1726 break;
1729 case ft_glyph_format_outline:
1730 ft_bitmap.width = width;
1731 ft_bitmap.rows = height;
1732 ft_bitmap.pitch = pitch;
1733 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
1734 ft_bitmap.buffer = buf;
1736 if(needsTransform) {
1737 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
1740 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
1742 /* Note: FreeType will only set 'black' bits for us. */
1743 memset(buf, 0, needed);
1744 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
1745 break;
1747 default:
1748 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
1749 return GDI_ERROR;
1751 break;
1753 case GGO_GRAY2_BITMAP:
1754 case GGO_GRAY4_BITMAP:
1755 case GGO_GRAY8_BITMAP:
1756 case WINE_GGO_GRAY16_BITMAP:
1758 int mult, row, col;
1759 BYTE *start, *ptr;
1761 width = lpgm->gmBlackBoxX;
1762 height = lpgm->gmBlackBoxY;
1763 pitch = (width + 3) / 4 * 4;
1764 needed = pitch * height;
1766 if(!buf || !buflen) break;
1767 ft_bitmap.width = width;
1768 ft_bitmap.rows = height;
1769 ft_bitmap.pitch = pitch;
1770 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
1771 ft_bitmap.buffer = buf;
1773 if(needsTransform) {
1774 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
1777 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
1779 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
1781 if(format == GGO_GRAY2_BITMAP)
1782 mult = 5;
1783 else if(format == GGO_GRAY4_BITMAP)
1784 mult = 17;
1785 else if(format == GGO_GRAY8_BITMAP)
1786 mult = 65;
1787 else if(format == WINE_GGO_GRAY16_BITMAP)
1788 break;
1789 else {
1790 assert(0);
1791 break;
1794 start = buf;
1795 for(row = 0; row < height; row++) {
1796 ptr = start;
1797 for(col = 0; col < width; col++, ptr++) {
1798 *ptr = (*(unsigned int*)ptr * mult + 128) / 256;
1800 start += pitch;
1802 break;
1805 case GGO_NATIVE:
1807 int contour, point = 0, first_pt;
1808 FT_Outline *outline = &ft_face->glyph->outline;
1809 TTPOLYGONHEADER *pph;
1810 TTPOLYCURVE *ppc;
1811 DWORD pph_start, cpfx, type;
1813 if(buflen == 0) buf = NULL;
1815 if (needsTransform && buf) {
1816 pFT_Outline_Transform(outline, &transMat);
1819 for(contour = 0; contour < outline->n_contours; contour++) {
1820 pph_start = needed;
1821 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
1822 first_pt = point;
1823 if(buf) {
1824 pph->dwType = TT_POLYGON_TYPE;
1825 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
1827 needed += sizeof(*pph);
1828 point++;
1829 while(point <= outline->contours[contour]) {
1830 ppc = (TTPOLYCURVE *)((char *)buf + needed);
1831 type = (outline->tags[point] & FT_Curve_Tag_On) ?
1832 TT_PRIM_LINE : TT_PRIM_QSPLINE;
1833 cpfx = 0;
1834 do {
1835 if(buf)
1836 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
1837 cpfx++;
1838 point++;
1839 } while(point <= outline->contours[contour] &&
1840 (outline->tags[point] & FT_Curve_Tag_On) ==
1841 (outline->tags[point-1] & FT_Curve_Tag_On));
1842 /* At the end of a contour Windows adds the start point, but
1843 only for Beziers */
1844 if(point > outline->contours[contour] &&
1845 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
1846 if(buf)
1847 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
1848 cpfx++;
1849 } else if(point <= outline->contours[contour] &&
1850 outline->tags[point] & FT_Curve_Tag_On) {
1851 /* add closing pt for bezier */
1852 if(buf)
1853 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
1854 cpfx++;
1855 point++;
1857 if(buf) {
1858 ppc->wType = type;
1859 ppc->cpfx = cpfx;
1861 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
1863 if(buf)
1864 pph->cb = needed - pph_start;
1866 break;
1868 case GGO_BEZIER:
1870 /* Convert the quadratic Beziers to cubic Beziers.
1871 The parametric eqn for a cubic Bezier is, from PLRM:
1872 r(t) = at^3 + bt^2 + ct + r0
1873 with the control points:
1874 r1 = r0 + c/3
1875 r2 = r1 + (c + b)/3
1876 r3 = r0 + c + b + a
1878 A quadratic Beizer has the form:
1879 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
1881 So equating powers of t leads to:
1882 r1 = 2/3 p1 + 1/3 p0
1883 r2 = 2/3 p1 + 1/3 p2
1884 and of course r0 = p0, r3 = p2
1887 int contour, point = 0, first_pt;
1888 FT_Outline *outline = &ft_face->glyph->outline;
1889 TTPOLYGONHEADER *pph;
1890 TTPOLYCURVE *ppc;
1891 DWORD pph_start, cpfx, type;
1892 FT_Vector cubic_control[4];
1893 if(buflen == 0) buf = NULL;
1895 if (needsTransform && buf) {
1896 pFT_Outline_Transform(outline, &transMat);
1899 for(contour = 0; contour < outline->n_contours; contour++) {
1900 pph_start = needed;
1901 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
1902 first_pt = point;
1903 if(buf) {
1904 pph->dwType = TT_POLYGON_TYPE;
1905 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
1907 needed += sizeof(*pph);
1908 point++;
1909 while(point <= outline->contours[contour]) {
1910 ppc = (TTPOLYCURVE *)((char *)buf + needed);
1911 type = (outline->tags[point] & FT_Curve_Tag_On) ?
1912 TT_PRIM_LINE : TT_PRIM_CSPLINE;
1913 cpfx = 0;
1914 do {
1915 if(type == TT_PRIM_LINE) {
1916 if(buf)
1917 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
1918 cpfx++;
1919 point++;
1920 } else {
1921 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
1922 so cpfx = 3n */
1924 /* FIXME: Possible optimization in endpoint calculation
1925 if there are two consecutive curves */
1926 cubic_control[0] = outline->points[point-1];
1927 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
1928 cubic_control[0].x += outline->points[point].x + 1;
1929 cubic_control[0].y += outline->points[point].y + 1;
1930 cubic_control[0].x >>= 1;
1931 cubic_control[0].y >>= 1;
1933 if(point+1 > outline->contours[contour])
1934 cubic_control[3] = outline->points[first_pt];
1935 else {
1936 cubic_control[3] = outline->points[point+1];
1937 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
1938 cubic_control[3].x += outline->points[point].x + 1;
1939 cubic_control[3].y += outline->points[point].y + 1;
1940 cubic_control[3].x >>= 1;
1941 cubic_control[3].y >>= 1;
1944 /* r1 = 1/3 p0 + 2/3 p1
1945 r2 = 1/3 p2 + 2/3 p1 */
1946 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
1947 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
1948 cubic_control[2] = cubic_control[1];
1949 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
1950 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
1951 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
1952 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
1953 if(buf) {
1954 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
1955 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
1956 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
1958 cpfx += 3;
1959 point++;
1961 } while(point <= outline->contours[contour] &&
1962 (outline->tags[point] & FT_Curve_Tag_On) ==
1963 (outline->tags[point-1] & FT_Curve_Tag_On));
1964 /* At the end of a contour Windows adds the start point,
1965 but only for Beziers and we've already done that.
1967 if(point <= outline->contours[contour] &&
1968 outline->tags[point] & FT_Curve_Tag_On) {
1969 /* This is the closing pt of a bezier, but we've already
1970 added it, so just inc point and carry on */
1971 point++;
1973 if(buf) {
1974 ppc->wType = type;
1975 ppc->cpfx = cpfx;
1977 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
1979 if(buf)
1980 pph->cb = needed - pph_start;
1982 break;
1985 default:
1986 FIXME("Unsupported format %d\n", format);
1987 return GDI_ERROR;
1989 return needed;
1992 /*************************************************************
1993 * WineEngGetTextMetrics
1996 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
1998 if(!font->potm) {
1999 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
2000 return FALSE;
2002 if(!font->potm) return FALSE;
2003 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
2005 if (font->aveWidth) {
2006 ptm->tmAveCharWidth = font->aveWidth * font->xform.eM11;
2008 return TRUE;
2012 /*************************************************************
2013 * WineEngGetOutlineTextMetrics
2016 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
2017 OUTLINETEXTMETRICW *potm)
2019 FT_Face ft_face = font->ft_face;
2020 UINT needed, lenfam, lensty, ret;
2021 TT_OS2 *pOS2;
2022 TT_HoriHeader *pHori;
2023 TT_Postscript *pPost;
2024 FT_Fixed x_scale, y_scale;
2025 WCHAR *family_nameW, *style_nameW;
2026 WCHAR spaceW[] = {' ', '\0'};
2027 char *cp;
2029 TRACE("font=%p\n", font);
2031 if(font->potm) {
2032 if(cbSize >= font->potm->otmSize)
2033 memcpy(potm, font->potm, font->potm->otmSize);
2034 return font->potm->otmSize;
2037 needed = sizeof(*potm);
2039 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
2040 family_nameW = strdupW(font->name);
2042 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
2043 * sizeof(WCHAR);
2044 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
2045 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
2046 style_nameW, lensty);
2048 /* These names should be read from the TT name table */
2050 /* length of otmpFamilyName */
2051 needed += lenfam;
2053 /* length of otmpFaceName */
2054 if(!strcasecmp(ft_face->style_name, "regular")) {
2055 needed += lenfam; /* just the family name */
2056 } else {
2057 needed += lenfam + lensty; /* family + " " + style */
2060 /* length of otmpStyleName */
2061 needed += lensty;
2063 /* length of otmpFullName */
2064 needed += lenfam + lensty;
2067 x_scale = ft_face->size->metrics.x_scale;
2068 y_scale = ft_face->size->metrics.y_scale;
2070 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2071 if(!pOS2) {
2072 FIXME("Can't find OS/2 table - not TT font?\n");
2073 ret = 0;
2074 goto end;
2077 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2078 if(!pHori) {
2079 FIXME("Can't find HHEA table - not TT font?\n");
2080 ret = 0;
2081 goto end;
2084 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
2086 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",
2087 pOS2->usWinAscent, pOS2->usWinDescent,
2088 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
2089 ft_face->ascender, ft_face->descender, ft_face->height,
2090 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
2091 ft_face->bbox.yMax, ft_face->bbox.yMin);
2093 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
2094 font->potm->otmSize = needed;
2096 #define TM font->potm->otmTextMetrics
2098 if(font->yMax) {
2099 TM.tmAscent = font->yMax;
2100 TM.tmDescent = -font->yMin;
2101 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
2102 } else {
2103 TM.tmAscent = (pFT_MulFix(pOS2->usWinAscent, y_scale) + 32) >> 6;
2104 TM.tmDescent = (pFT_MulFix(pOS2->usWinDescent, y_scale) + 32) >> 6;
2105 TM.tmInternalLeading = (pFT_MulFix(pOS2->usWinAscent + pOS2->usWinDescent
2106 - ft_face->units_per_EM, y_scale) + 32) >> 6;
2109 TM.tmHeight = TM.tmAscent + TM.tmDescent;
2111 /* MSDN says:
2112 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
2114 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
2115 ((pOS2->usWinAscent + pOS2->usWinDescent) -
2116 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
2118 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
2119 if (TM.tmAveCharWidth == 0) {
2120 TM.tmAveCharWidth = 1;
2122 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
2123 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
2124 TM.tmOverhang = 0;
2125 TM.tmDigitizedAspectX = 300;
2126 TM.tmDigitizedAspectY = 300;
2127 TM.tmFirstChar = pOS2->usFirstCharIndex;
2128 TM.tmLastChar = pOS2->usLastCharIndex;
2129 TM.tmDefaultChar = pOS2->usDefaultChar;
2130 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
2131 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
2132 TM.tmUnderlined = 0; /* entry in OS2 table */
2133 TM.tmStruckOut = 0; /* entry in OS2 table */
2135 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
2136 if(!FT_IS_FIXED_WIDTH(ft_face))
2137 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
2138 else
2139 TM.tmPitchAndFamily = 0;
2141 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
2142 case PAN_FAMILY_SCRIPT:
2143 TM.tmPitchAndFamily |= FF_SCRIPT;
2144 break;
2145 case PAN_FAMILY_DECORATIVE:
2146 case PAN_FAMILY_PICTORIAL:
2147 TM.tmPitchAndFamily |= FF_DECORATIVE;
2148 break;
2149 case PAN_FAMILY_TEXT_DISPLAY:
2150 if(TM.tmPitchAndFamily == 0) /* fixed */
2151 TM.tmPitchAndFamily = FF_MODERN;
2152 else {
2153 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
2154 case PAN_SERIF_NORMAL_SANS:
2155 case PAN_SERIF_OBTUSE_SANS:
2156 case PAN_SERIF_PERP_SANS:
2157 TM.tmPitchAndFamily |= FF_SWISS;
2158 break;
2159 default:
2160 TM.tmPitchAndFamily |= FF_ROMAN;
2163 break;
2164 default:
2165 TM.tmPitchAndFamily |= FF_DONTCARE;
2168 if(FT_IS_SCALABLE(ft_face))
2169 TM.tmPitchAndFamily |= TMPF_VECTOR;
2170 if(FT_IS_SFNT(ft_face))
2171 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
2173 TM.tmCharSet = font->charset;
2174 #undef TM
2176 font->potm->otmFiller = 0;
2177 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
2178 font->potm->otmfsSelection = pOS2->fsSelection;
2179 font->potm->otmfsType = pOS2->fsType;
2180 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
2181 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
2182 font->potm->otmItalicAngle = 0; /* POST table */
2183 font->potm->otmEMSquare = ft_face->units_per_EM;
2184 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
2185 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
2186 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
2187 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
2188 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
2189 font->potm->otmrcFontBox.left = ft_face->bbox.xMin;
2190 font->potm->otmrcFontBox.right = ft_face->bbox.xMax;
2191 font->potm->otmrcFontBox.top = ft_face->bbox.yMin;
2192 font->potm->otmrcFontBox.bottom = ft_face->bbox.yMax;
2193 font->potm->otmMacAscent = 0; /* where do these come from ? */
2194 font->potm->otmMacDescent = 0;
2195 font->potm->otmMacLineGap = 0;
2196 font->potm->otmusMinimumPPEM = 0; /* TT Header */
2197 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
2198 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
2199 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
2200 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
2201 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
2202 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
2203 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
2204 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
2205 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
2206 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
2207 if(!pPost) {
2208 font->potm->otmsUnderscoreSize = 0;
2209 font->potm->otmsUnderscorePosition = 0;
2210 } else {
2211 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
2212 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
2215 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
2216 cp = (char*)font->potm + sizeof(*font->potm);
2217 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
2218 strcpyW((WCHAR*)cp, family_nameW);
2219 cp += lenfam;
2220 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
2221 strcpyW((WCHAR*)cp, style_nameW);
2222 cp += lensty;
2223 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
2224 strcpyW((WCHAR*)cp, family_nameW);
2225 if(strcasecmp(ft_face->style_name, "regular")) {
2226 strcatW((WCHAR*)cp, spaceW);
2227 strcatW((WCHAR*)cp, style_nameW);
2228 cp += lenfam + lensty;
2229 } else
2230 cp += lenfam;
2231 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
2232 strcpyW((WCHAR*)cp, family_nameW);
2233 strcatW((WCHAR*)cp, spaceW);
2234 strcatW((WCHAR*)cp, style_nameW);
2235 ret = needed;
2237 if(potm && needed <= cbSize)
2238 memcpy(potm, font->potm, font->potm->otmSize);
2240 end:
2241 HeapFree(GetProcessHeap(), 0, style_nameW);
2242 HeapFree(GetProcessHeap(), 0, family_nameW);
2244 return ret;
2248 /*************************************************************
2249 * WineEngGetCharWidth
2252 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
2253 LPINT buffer)
2255 UINT c;
2256 GLYPHMETRICS gm;
2257 FT_UInt glyph_index;
2259 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
2261 for(c = firstChar; c <= lastChar; c++) {
2262 glyph_index = get_glyph_index(font, c);
2263 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
2264 &gm, 0, NULL, NULL);
2265 buffer[c - firstChar] = font->gm[glyph_index].adv;
2267 return TRUE;
2270 /*************************************************************
2271 * WineEngGetTextExtentPoint
2274 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
2275 LPSIZE size)
2277 INT idx;
2278 GLYPHMETRICS gm;
2279 TEXTMETRICW tm;
2280 FT_UInt glyph_index;
2282 TRACE("%p, %s, %d, %p\n", font, debugstr_wn(wstr, count), count,
2283 size);
2285 size->cx = 0;
2286 WineEngGetTextMetrics(font, &tm);
2287 size->cy = tm.tmHeight;
2289 for(idx = 0; idx < count; idx++) {
2290 glyph_index = get_glyph_index(font, wstr[idx]);
2291 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
2292 &gm, 0, NULL, NULL);
2293 size->cx += font->gm[glyph_index].adv;
2295 TRACE("return %ld,%ld\n", size->cx, size->cy);
2296 return TRUE;
2299 /*************************************************************
2300 * WineEngGetTextExtentPointI
2303 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
2304 LPSIZE size)
2306 INT idx;
2307 GLYPHMETRICS gm;
2308 TEXTMETRICW tm;
2310 TRACE("%p, %p, %d, %p\n", font, indices, count, size);
2312 size->cx = 0;
2313 WineEngGetTextMetrics(font, &tm);
2314 size->cy = tm.tmHeight;
2316 for(idx = 0; idx < count; idx++) {
2317 WineEngGetGlyphOutline(font, indices[idx],
2318 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
2319 NULL);
2320 size->cx += font->gm[indices[idx]].adv;
2322 TRACE("return %ld,%ld\n", size->cx, size->cy);
2323 return TRUE;
2326 /*************************************************************
2327 * WineEngGetFontData
2330 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
2331 DWORD cbData)
2333 FT_Face ft_face = font->ft_face;
2334 DWORD len;
2335 FT_Error err;
2337 TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
2338 font, table, offset, buf, cbData);
2340 if(!FT_IS_SFNT(ft_face))
2341 return GDI_ERROR;
2343 if(!buf || !cbData)
2344 len = 0;
2345 else
2346 len = cbData;
2348 if(table) { /* MS tags differ in endidness from FT ones */
2349 table = table >> 24 | table << 24 |
2350 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
2353 /* If the FT_Load_Sfnt_Table function is there we'll use it */
2354 if(pFT_Load_Sfnt_Table)
2355 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
2356 else { /* Do it the hard way */
2357 TT_Face tt_face = (TT_Face) ft_face;
2358 SFNT_Interface *sfnt;
2359 if (FT_Version.major==2 && FT_Version.minor==0)
2361 /* 2.0.x */
2362 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
2364 else
2366 /* A field was added in the middle of the structure in 2.1.x */
2367 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
2369 err = sfnt->load_any(tt_face, table, offset, buf, &len);
2371 if(err) {
2372 TRACE("Can't find table %08lx.\n", table);
2373 return GDI_ERROR;
2375 return len;
2378 /*************************************************************
2379 * WineEngGetTextFace
2382 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
2384 if(str) {
2385 lstrcpynW(str, font->name, count);
2386 return strlenW(font->name);
2387 } else
2388 return strlenW(font->name) + 1;
2391 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
2393 if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
2394 return font->charset;
2397 #else /* HAVE_FREETYPE */
2399 BOOL WineEngInit(void)
2401 return FALSE;
2403 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
2405 return NULL;
2407 BOOL WineEngDestroyFontInstance(HFONT hfont)
2409 return FALSE;
2412 DWORD WineEngEnumFonts(LPLOGFONTW plf, DEVICEFONTENUMPROC proc, LPARAM lparam)
2414 return 1;
2417 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
2418 LPWORD pgi, DWORD flags)
2420 return GDI_ERROR;
2423 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
2424 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
2425 const MAT2* lpmat)
2427 ERR("called but we don't have FreeType\n");
2428 return GDI_ERROR;
2431 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
2433 ERR("called but we don't have FreeType\n");
2434 return FALSE;
2437 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
2438 OUTLINETEXTMETRICW *potm)
2440 ERR("called but we don't have FreeType\n");
2441 return 0;
2444 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
2445 LPINT buffer)
2447 ERR("called but we don't have FreeType\n");
2448 return FALSE;
2451 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
2452 LPSIZE size)
2454 ERR("called but we don't have FreeType\n");
2455 return FALSE;
2458 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
2459 LPSIZE size)
2461 ERR("called but we don't have FreeType\n");
2462 return FALSE;
2465 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
2466 DWORD cbData)
2468 ERR("called but we don't have FreeType\n");
2469 return GDI_ERROR;
2472 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
2474 ERR("called but we don't have FreeType\n");
2475 return 0;
2478 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2480 FIXME(":stub\n");
2481 return 1;
2484 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2486 FIXME(":stub\n");
2487 return TRUE;
2490 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
2492 FIXME(":stub\n");
2493 return DEFAULT_CHARSET;
2496 #endif /* HAVE_FREETYPE */