Moved a bunch of definitions from gdi.h into a new gdi_private.h to
[wine/multimedia.git] / dlls / gdi / freetype.c
blobe03e4ba0920ac8b1d80a5dd39eea345bdb0fd598
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"
44 WINE_DEFAULT_DEBUG_CHANNEL(font);
46 #ifdef HAVE_FREETYPE
48 #ifdef HAVE_FT2BUILD_H
49 #include <ft2build.h>
50 #endif
51 #ifdef HAVE_FREETYPE_FREETYPE_H
52 #include <freetype/freetype.h>
53 #endif
54 #ifdef HAVE_FREETYPE_FTGLYPH_H
55 #include <freetype/ftglyph.h>
56 #endif
57 #ifdef HAVE_FREETYPE_TTTABLES_H
58 #include <freetype/tttables.h>
59 #endif
60 #ifdef HAVE_FREETYPE_FTSNAMES_H
61 #include <freetype/ftsnames.h>
62 #else
63 # ifdef HAVE_FREETYPE_FTNAMES_H
64 # include <freetype/ftnames.h>
65 # endif
66 #endif
67 #ifdef HAVE_FREETYPE_TTNAMEID_H
68 #include <freetype/ttnameid.h>
69 #endif
70 #ifdef HAVE_FREETYPE_FTOUTLN_H
71 #include <freetype/ftoutln.h>
72 #endif
73 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
74 #include <freetype/internal/sfnt.h>
75 #endif
76 #ifdef HAVE_FREETYPE_FTTRIGON_H
77 #include <freetype/fttrigon.h>
78 #endif
80 #ifndef SONAME_LIBFREETYPE
81 #define SONAME_LIBFREETYPE "libfreetype.so"
82 #endif
84 static FT_Library library = 0;
85 typedef struct
87 FT_Int major;
88 FT_Int minor;
89 FT_Int patch;
90 } FT_Version_t;
91 static FT_Version_t FT_Version;
93 static void *ft_handle = NULL;
95 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
96 MAKE_FUNCPTR(FT_Vector_Unit);
97 MAKE_FUNCPTR(FT_Done_Face);
98 MAKE_FUNCPTR(FT_Get_Char_Index);
99 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
100 MAKE_FUNCPTR(FT_Init_FreeType);
101 MAKE_FUNCPTR(FT_Load_Glyph);
102 MAKE_FUNCPTR(FT_Matrix_Multiply);
103 MAKE_FUNCPTR(FT_MulFix);
104 MAKE_FUNCPTR(FT_New_Face);
105 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
106 MAKE_FUNCPTR(FT_Outline_Transform);
107 MAKE_FUNCPTR(FT_Outline_Translate);
108 MAKE_FUNCPTR(FT_Select_Charmap);
109 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
110 MAKE_FUNCPTR(FT_Vector_Transform);
111 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
112 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
113 static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*);
115 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
116 #include <fontconfig/fontconfig.h>
117 MAKE_FUNCPTR(FcConfigGetCurrent);
118 MAKE_FUNCPTR(FcFontList);
119 MAKE_FUNCPTR(FcFontSetDestroy);
120 MAKE_FUNCPTR(FcInit);
121 MAKE_FUNCPTR(FcObjectSetAdd);
122 MAKE_FUNCPTR(FcObjectSetCreate);
123 MAKE_FUNCPTR(FcObjectSetDestroy);
124 MAKE_FUNCPTR(FcPatternCreate);
125 MAKE_FUNCPTR(FcPatternDestroy);
126 MAKE_FUNCPTR(FcPatternGet);
127 #ifndef SONAME_LIBFONTCONFIG
128 #define SONAME_LIBFONTCONFIG "libfontconfig.so"
129 #endif
130 #endif
132 #undef MAKE_FUNCPTR
135 #define GET_BE_WORD(ptr) MAKEWORD( ((BYTE *)(ptr))[1], ((BYTE *)(ptr))[0] )
137 typedef struct tagFace {
138 WCHAR *StyleName;
139 char *file;
140 FT_Long face_index;
141 BOOL Italic;
142 BOOL Bold;
143 FONTSIGNATURE fs;
144 FT_Fixed font_version;
145 struct tagFace *next;
146 struct tagFamily *family;
147 } Face;
149 typedef struct tagFamily {
150 WCHAR *FamilyName;
151 Face *FirstFace;
152 struct tagFamily *next;
153 } Family;
155 typedef struct {
156 GLYPHMETRICS gm;
157 INT adv; /* These three hold to widths of the unrotated chars */
158 INT lsb;
159 INT bbx;
160 BOOL init;
161 } GM;
163 struct tagGdiFont {
164 FT_Face ft_face;
165 XFORM xform;
166 LPWSTR name;
167 int charset;
168 BOOL fake_italic;
169 BOOL fake_bold;
170 INT orientation;
171 GM *gm;
172 DWORD gmsize;
173 HFONT hfont;
174 LONG aveWidth;
175 SHORT yMax;
176 SHORT yMin;
177 OUTLINETEXTMETRICW *potm;
178 FONTSIGNATURE fs;
179 struct tagGdiFont *next;
182 #define INIT_GM_SIZE 128
184 static GdiFont GdiFontList = NULL;
186 static Family *FontList = NULL;
188 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ',
189 'R','o','m','a','n','\0'};
190 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
191 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
193 static const WCHAR defSystem[] = {'A','r','i','a','l','\0'};
194 static const WCHAR SystemW[] = {'S','y','s','t','e','m','\0'};
195 static const WCHAR MSSansSerifW[] = {'M','S',' ','S','a','n','s',' ',
196 'S','e','r','i','f','\0'};
197 static const WCHAR HelvW[] = {'H','e','l','v','\0'};
199 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
200 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
201 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
202 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
203 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
204 'E','u','r','o','p','e','a','n','\0'};
205 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
206 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
207 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
208 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
209 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
210 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
211 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
212 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
213 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
214 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
215 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
217 static const WCHAR *ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
218 WesternW, /*00*/
219 Central_EuropeanW,
220 CyrillicW,
221 GreekW,
222 TurkishW,
223 HebrewW,
224 ArabicW,
225 BalticW,
226 VietnameseW, /*08*/
227 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
228 ThaiW,
229 JapaneseW,
230 CHINESE_GB2312W,
231 HangulW,
232 CHINESE_BIG5W,
233 Hangul_Johab_W,
234 NULL, NULL, /*23*/
235 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
236 SymbolW /*31*/
239 typedef struct {
240 WCHAR *name;
241 INT charset;
242 } NameCs;
244 typedef struct tagFontSubst {
245 NameCs from;
246 NameCs to;
247 struct tagFontSubst *next;
248 } FontSubst;
250 static FontSubst *substlist = NULL;
251 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
254 This function builds an FT_Fixed from a float. It puts the integer part
255 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
256 It fails if the integer part of the float number is greater than SHORT_MAX.
258 static inline FT_Fixed FT_FixedFromFloat(float f)
260 short value = f;
261 unsigned short fract = (f - value) * 0xFFFF;
262 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
266 This function builds an FT_Fixed from a FIXED. It simply put f.value
267 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
269 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
271 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
274 static BOOL AddFontFileToList(const char *file, char *fake_family)
276 FT_Face ft_face;
277 TT_OS2 *pOS2;
278 TT_Header *pHeader;
279 WCHAR *FamilyW, *StyleW;
280 DWORD len;
281 Family *family = FontList;
282 Family **insert = &FontList;
283 Face **insertface, *next;
284 FT_Error err;
285 FT_Long face_index = 0, num_faces;
286 int i;
288 do {
289 char *family_name = fake_family;
291 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
292 if((err = pFT_New_Face(library, file, face_index, &ft_face)) != 0) {
293 WARN("Unable to load font file %s err = %x\n", debugstr_a(file), err);
294 return FALSE;
297 if(!FT_IS_SFNT(ft_face)) { /* for now we'll skip everything but TT/OT */
298 pFT_Done_Face(ft_face);
299 return FALSE;
301 if(!pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2) ||
302 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
303 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head))) {
304 TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
305 "Skipping this font.\n", debugstr_a(file));
306 pFT_Done_Face(ft_face);
307 return FALSE;
310 if(!ft_face->family_name || !ft_face->style_name) {
311 TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file));
312 pFT_Done_Face(ft_face);
313 return FALSE;
316 if(!family_name)
317 family_name = ft_face->family_name;
319 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
320 FamilyW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
321 MultiByteToWideChar(CP_ACP, 0, family_name, -1, FamilyW, len);
323 while(family) {
324 if(!strcmpW(family->FamilyName, FamilyW))
325 break;
326 insert = &family->next;
327 family = family->next;
329 if(!family) {
330 family = *insert = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
331 family->FamilyName = FamilyW;
332 family->FirstFace = NULL;
333 family->next = NULL;
334 } else {
335 HeapFree(GetProcessHeap(), 0, FamilyW);
338 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
339 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
340 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
342 next = NULL;
343 for(insertface = &family->FirstFace; *insertface;
344 insertface = &(*insertface)->next) {
345 if(!strcmpW((*insertface)->StyleName, StyleW)) {
346 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
347 debugstr_w(family->FamilyName), debugstr_w(StyleW),
348 (*insertface)->font_version, pHeader->Font_Revision);
350 if(fake_family) {
351 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
352 HeapFree(GetProcessHeap(), 0, StyleW);
353 pFT_Done_Face(ft_face);
354 return FALSE;
356 if(pHeader->Font_Revision <= (*insertface)->font_version) {
357 TRACE("Original font is newer so skipping this one\n");
358 HeapFree(GetProcessHeap(), 0, StyleW);
359 pFT_Done_Face(ft_face);
360 return FALSE;
361 } else {
362 TRACE("Replacing original with this one\n");
363 next = (*insertface)->next;
364 HeapFree(GetProcessHeap(), 0, (*insertface)->file);
365 HeapFree(GetProcessHeap(), 0, (*insertface)->StyleName);
366 HeapFree(GetProcessHeap(), 0, *insertface);
367 break;
371 *insertface = HeapAlloc(GetProcessHeap(), 0, sizeof(**insertface));
372 (*insertface)->StyleName = StyleW;
373 (*insertface)->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
374 strcpy((*insertface)->file, file);
375 (*insertface)->face_index = face_index;
376 (*insertface)->next = next;
377 (*insertface)->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
378 (*insertface)->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
379 (*insertface)->font_version = pHeader->Font_Revision;
380 (*insertface)->family = family;
382 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
383 if(pOS2) {
384 (*insertface)->fs.fsCsb[0] = pOS2->ulCodePageRange1;
385 (*insertface)->fs.fsCsb[1] = pOS2->ulCodePageRange2;
386 (*insertface)->fs.fsUsb[0] = pOS2->ulUnicodeRange1;
387 (*insertface)->fs.fsUsb[1] = pOS2->ulUnicodeRange2;
388 (*insertface)->fs.fsUsb[2] = pOS2->ulUnicodeRange3;
389 (*insertface)->fs.fsUsb[3] = pOS2->ulUnicodeRange4;
390 } else {
391 (*insertface)->fs.fsCsb[0] = (*insertface)->fs.fsCsb[1] = 0;
392 (*insertface)->fs.fsUsb[0] = 0;
393 (*insertface)->fs.fsUsb[1] = 0;
394 (*insertface)->fs.fsUsb[2] = 0;
395 (*insertface)->fs.fsUsb[3] = 0;
397 TRACE("fsCsb = %08lx %08lx/%08lx %08lx %08lx %08lx\n",
398 (*insertface)->fs.fsCsb[0], (*insertface)->fs.fsCsb[1],
399 (*insertface)->fs.fsUsb[0], (*insertface)->fs.fsUsb[1],
400 (*insertface)->fs.fsUsb[2], (*insertface)->fs.fsUsb[3]);
402 if(pOS2->version == 0) {
403 FT_UInt dummy;
405 /* If the function is not there, we assume the font is ok */
406 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
407 (*insertface)->fs.fsCsb[0] |= 1;
408 else
409 (*insertface)->fs.fsCsb[0] |= 1L << 31;
412 if((*insertface)->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
413 for(i = 0; i < ft_face->num_charmaps; i++) {
414 switch(ft_face->charmaps[i]->encoding) {
415 case ft_encoding_unicode:
416 case ft_encoding_apple_roman:
417 (*insertface)->fs.fsCsb[0] |= 1;
418 break;
419 case ft_encoding_symbol:
420 (*insertface)->fs.fsCsb[0] |= 1L << 31;
421 break;
422 default:
423 break;
428 if((*insertface)->fs.fsCsb[0] & ~(1L << 31))
429 have_installed_roman_font = TRUE;
431 num_faces = ft_face->num_faces;
432 pFT_Done_Face(ft_face);
433 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
434 debugstr_w(StyleW));
435 } while(num_faces > ++face_index);
436 return TRUE;
439 static void DumpFontList(void)
441 Family *family;
442 Face *face;
444 for(family = FontList; family; family = family->next) {
445 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
446 for(face = family->FirstFace; face; face = face->next) {
447 TRACE("\t%s\n", debugstr_w(face->StyleName));
450 return;
453 static void DumpSubstList(void)
455 FontSubst *psub;
457 for(psub = substlist; psub; psub = psub->next)
458 if(psub->from.charset != -1 || psub->to.charset != -1)
459 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
460 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
461 else
462 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
463 debugstr_w(psub->to.name));
464 return;
467 static LPWSTR strdupW(LPWSTR p)
469 LPWSTR ret;
470 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
471 ret = HeapAlloc(GetProcessHeap(), 0, len);
472 memcpy(ret, p, len);
473 return ret;
476 static void split_subst_info(NameCs *nc, LPSTR str)
478 CHAR *p = strrchr(str, ',');
479 DWORD len;
481 nc->charset = -1;
482 if(p && *(p+1)) {
483 nc->charset = strtol(p+1, NULL, 10);
484 *p = '\0';
486 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
487 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
488 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
491 static void LoadSubstList(void)
493 FontSubst *psub, **ppsub;
494 HKEY hkey;
495 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
496 LPSTR value;
497 LPVOID data;
499 if(substlist) {
500 for(psub = substlist; psub;) {
501 FontSubst *ptmp;
502 HeapFree(GetProcessHeap(), 0, psub->to.name);
503 HeapFree(GetProcessHeap(), 0, psub->from.name);
504 ptmp = psub;
505 psub = psub->next;
506 HeapFree(GetProcessHeap(), 0, ptmp);
508 substlist = NULL;
511 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
512 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
513 &hkey) == ERROR_SUCCESS) {
515 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
516 &valuelen, &datalen, NULL, NULL);
518 valuelen++; /* returned value doesn't include room for '\0' */
519 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
520 data = HeapAlloc(GetProcessHeap(), 0, datalen);
522 dlen = datalen;
523 vlen = valuelen;
524 ppsub = &substlist;
525 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
526 &dlen) == ERROR_SUCCESS) {
527 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
529 *ppsub = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppsub));
530 (*ppsub)->next = NULL;
531 split_subst_info(&((*ppsub)->from), value);
532 split_subst_info(&((*ppsub)->to), data);
534 /* Win 2000 doesn't allow mapping between different charsets
535 or mapping of DEFAULT_CHARSET */
536 if(((*ppsub)->to.charset != (*ppsub)->from.charset) ||
537 (*ppsub)->to.charset == DEFAULT_CHARSET) {
538 HeapFree(GetProcessHeap(), 0, (*ppsub)->to.name);
539 HeapFree(GetProcessHeap(), 0, (*ppsub)->from.name);
540 HeapFree(GetProcessHeap(), 0, *ppsub);
541 *ppsub = NULL;
542 } else {
543 ppsub = &((*ppsub)->next);
545 /* reset dlen and vlen */
546 dlen = datalen;
547 vlen = valuelen;
549 HeapFree(GetProcessHeap(), 0, data);
550 HeapFree(GetProcessHeap(), 0, value);
551 RegCloseKey(hkey);
555 /***********************************************************
556 * The replacement list is a way to map an entire font
557 * family onto another family. For example adding
559 * [HKLM\Software\Wine\Wine\FontReplacements]
560 * "Wingdings"="Winedings"
562 * would enumerate the Winedings font both as Winedings and
563 * Wingdings. However if a real Wingdings font is present the
564 * replacement does not take place.
567 static void LoadReplaceList(void)
569 HKEY hkey;
570 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
571 LPSTR value;
572 LPVOID data;
573 Family *family;
574 Face *face;
575 WCHAR old_nameW[200];
577 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
578 "Software\\Wine\\Wine\\FontReplacements",
579 &hkey) == ERROR_SUCCESS) {
581 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
582 &valuelen, &datalen, NULL, NULL);
584 valuelen++; /* returned value doesn't include room for '\0' */
585 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
586 data = HeapAlloc(GetProcessHeap(), 0, datalen);
588 dlen = datalen;
589 vlen = valuelen;
590 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
591 &dlen) == ERROR_SUCCESS) {
592 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
593 /* "NewName"="Oldname" */
594 if(!MultiByteToWideChar(CP_ACP, 0, data, -1, old_nameW, sizeof(old_nameW)))
595 break;
597 /* Find the old family and hence all of the font files
598 in that family */
599 for(family = FontList; family; family = family->next) {
600 if(!strcmpiW(family->FamilyName, old_nameW)) {
601 for(face = family->FirstFace; face; face = face->next) {
602 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
603 debugstr_w(face->StyleName), value);
604 /* Now add a new entry with the new family name */
605 AddFontFileToList(face->file, value);
607 break;
610 /* reset dlen and vlen */
611 dlen = datalen;
612 vlen = valuelen;
614 HeapFree(GetProcessHeap(), 0, data);
615 HeapFree(GetProcessHeap(), 0, value);
616 RegCloseKey(hkey);
621 static BOOL ReadFontDir(const char *dirname)
623 DIR *dir;
624 struct dirent *dent;
625 char path[MAX_PATH];
627 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
629 dir = opendir(dirname);
630 if(!dir) {
631 ERR("Can't open directory %s\n", debugstr_a(dirname));
632 return FALSE;
634 while((dent = readdir(dir)) != NULL) {
635 struct stat statbuf;
637 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
638 continue;
640 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
642 sprintf(path, "%s/%s", dirname, dent->d_name);
644 if(stat(path, &statbuf) == -1)
646 WARN("Can't stat %s\n", debugstr_a(path));
647 continue;
649 if(S_ISDIR(statbuf.st_mode))
650 ReadFontDir(path);
651 else
652 AddFontFileToList(path, NULL);
654 closedir(dir);
655 return TRUE;
658 static void load_fontconfig_fonts(void)
660 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
661 void *fc_handle = NULL;
662 FcConfig *config;
663 FcPattern *pat;
664 FcObjectSet *os;
665 FcFontSet *fontset;
666 FcValue v;
667 int i, len;
668 const char *ext;
670 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
671 if(!fc_handle) {
672 TRACE("Wine cannot find the fontconfig library (%s).\n",
673 SONAME_LIBFONTCONFIG);
674 return;
676 #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;}
677 LOAD_FUNCPTR(FcConfigGetCurrent);
678 LOAD_FUNCPTR(FcFontList);
679 LOAD_FUNCPTR(FcFontSetDestroy);
680 LOAD_FUNCPTR(FcInit);
681 LOAD_FUNCPTR(FcObjectSetAdd);
682 LOAD_FUNCPTR(FcObjectSetCreate);
683 LOAD_FUNCPTR(FcObjectSetDestroy);
684 LOAD_FUNCPTR(FcPatternCreate);
685 LOAD_FUNCPTR(FcPatternDestroy);
686 LOAD_FUNCPTR(FcPatternGet);
687 #undef LOAD_FUNCPTR
689 if(!pFcInit()) return;
691 config = pFcConfigGetCurrent();
692 pat = pFcPatternCreate();
693 os = pFcObjectSetCreate();
694 pFcObjectSetAdd(os, FC_FILE);
695 fontset = pFcFontList(config, pat, os);
696 if(!fontset) return;
697 for(i = 0; i < fontset->nfont; i++) {
698 if(pFcPatternGet(fontset->fonts[i], FC_FILE, 0, &v) != FcResultMatch)
699 continue;
700 if(v.type != FcTypeString) continue;
701 TRACE("fontconfig: %s\n", v.u.s);
703 /* We're just interested in OT/TT fonts for now, so this hack just
704 picks up the standard extensions to save time loading every other
705 font */
706 len = strlen(v.u.s);
707 if(len < 4) continue;
708 ext = v.u.s + len - 3;
709 if(!strcasecmp(ext, "ttf") || !strcasecmp(ext, "ttc") || !strcasecmp(ext, "otf"))
710 AddFontFileToList(v.u.s, NULL);
712 pFcFontSetDestroy(fontset);
713 pFcObjectSetDestroy(os);
714 pFcPatternDestroy(pat);
715 sym_not_found:
716 #endif
717 return;
719 /*************************************************************
720 * WineEngAddFontResourceEx
723 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
725 if (ft_handle) /* do it only if we have freetype up and running */
727 char unixname[MAX_PATH];
729 if(flags)
730 FIXME("Ignoring flags %lx\n", flags);
732 if(wine_get_unix_file_name(file, unixname, sizeof(unixname)))
733 AddFontFileToList(unixname, NULL);
735 return 1;
738 /*************************************************************
739 * WineEngRemoveFontResourceEx
742 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
744 FIXME(":stub\n");
745 return TRUE;
748 /*************************************************************
749 * WineEngInit
751 * Initialize FreeType library and create a list of available faces
753 BOOL WineEngInit(void)
755 static const WCHAR fontsW[] = {'\\','F','o','n','t','s','\0'};
756 HKEY hkey;
757 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
758 LPVOID data;
759 WCHAR windowsdir[MAX_PATH];
760 char unixname[MAX_PATH];
762 TRACE("\n");
764 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
765 if(!ft_handle) {
766 WINE_MESSAGE(
767 "Wine cannot find the FreeType font library. To enable Wine to\n"
768 "use TrueType fonts please install a version of FreeType greater than\n"
769 "or equal to 2.0.5.\n"
770 "http://www.freetype.org\n");
771 return FALSE;
774 #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;}
776 LOAD_FUNCPTR(FT_Vector_Unit)
777 LOAD_FUNCPTR(FT_Done_Face)
778 LOAD_FUNCPTR(FT_Get_Char_Index)
779 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
780 LOAD_FUNCPTR(FT_Init_FreeType)
781 LOAD_FUNCPTR(FT_Load_Glyph)
782 LOAD_FUNCPTR(FT_Matrix_Multiply)
783 LOAD_FUNCPTR(FT_MulFix)
784 LOAD_FUNCPTR(FT_New_Face)
785 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
786 LOAD_FUNCPTR(FT_Outline_Transform)
787 LOAD_FUNCPTR(FT_Outline_Translate)
788 LOAD_FUNCPTR(FT_Select_Charmap)
789 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
790 LOAD_FUNCPTR(FT_Vector_Transform)
792 #undef LOAD_FUNCPTR
793 /* Don't warn if this one is missing */
794 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
795 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
796 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
798 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
799 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
800 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
801 <= 2.0.3 has FT_Sqrt64 */
802 goto sym_not_found;
805 if(pFT_Init_FreeType(&library) != 0) {
806 ERR("Can't init FreeType library\n");
807 wine_dlclose(ft_handle, NULL, 0);
808 ft_handle = NULL;
809 return FALSE;
811 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
812 if (pFT_Library_Version)
814 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
816 if (FT_Version.major<=0)
818 FT_Version.major=2;
819 FT_Version.minor=0;
820 FT_Version.patch=5;
822 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
824 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
825 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
826 strcatW(windowsdir, fontsW);
827 if(wine_get_unix_file_name(windowsdir, unixname, sizeof(unixname)))
828 ReadFontDir(unixname);
830 /* now look under HKLM\Software\Microsoft\Windows\CurrentVersion\Fonts
831 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
832 full path as the entry */
833 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
834 "Software\\Microsoft\\Windows\\CurrentVersion\\Fonts",
835 &hkey) == ERROR_SUCCESS) {
836 LPWSTR valueW;
837 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
838 &valuelen, &datalen, NULL, NULL);
840 valuelen++; /* returned value doesn't include room for '\0' */
841 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
842 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
844 dlen = datalen * sizeof(WCHAR);
845 vlen = valuelen;
846 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
847 &dlen) == ERROR_SUCCESS) {
848 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
849 if(wine_get_unix_file_name((LPWSTR)data, unixname, sizeof(unixname)))
850 AddFontFileToList(unixname, NULL);
852 /* reset dlen and vlen */
853 dlen = datalen;
854 vlen = valuelen;
856 HeapFree(GetProcessHeap(), 0, data);
857 HeapFree(GetProcessHeap(), 0, valueW);
858 RegCloseKey(hkey);
861 load_fontconfig_fonts();
863 /* then look in any directories that we've specified in the config file */
864 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
865 "Software\\Wine\\Wine\\Config\\FontDirs",
866 &hkey) == ERROR_SUCCESS) {
867 LPSTR value;
868 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
869 &valuelen, &datalen, NULL, NULL);
871 valuelen++; /* returned value doesn't include room for '\0' */
872 value = HeapAlloc(GetProcessHeap(), 0, valuelen);
873 data = HeapAlloc(GetProcessHeap(), 0, datalen);
875 dlen = datalen;
876 vlen = valuelen;
877 i = 0;
878 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
879 &dlen) == ERROR_SUCCESS) {
880 TRACE("Got %s=%s\n", value, (LPSTR)data);
881 ReadFontDir((LPSTR)data);
882 /* reset dlen and vlen */
883 dlen = datalen;
884 vlen = valuelen;
886 HeapFree(GetProcessHeap(), 0, data);
887 HeapFree(GetProcessHeap(), 0, value);
888 RegCloseKey(hkey);
891 DumpFontList();
892 LoadSubstList();
893 DumpSubstList();
894 LoadReplaceList();
895 return TRUE;
896 sym_not_found:
897 WINE_MESSAGE(
898 "Wine cannot find certain functions that it needs inside the FreeType\n"
899 "font library. To enable Wine to use TrueType fonts please upgrade\n"
900 "FreeType to at least version 2.0.5.\n"
901 "http://www.freetype.org\n");
902 wine_dlclose(ft_handle, NULL, 0);
903 ft_handle = NULL;
904 return FALSE;
908 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
910 TT_OS2 *pOS2;
911 TT_HoriHeader *pHori;
913 LONG ppem;
915 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
916 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
918 if(height == 0) height = 16;
920 /* Calc. height of EM square:
922 * For +ve lfHeight we have
923 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
924 * Re-arranging gives:
925 * ppem = units_per_em * lfheight / (winAscent + winDescent)
927 * For -ve lfHeight we have
928 * |lfHeight| = ppem
929 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
930 * with il = winAscent + winDescent - units_per_em]
934 if(height > 0) {
935 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
936 ppem = ft_face->units_per_EM * height /
937 (pHori->Ascender - pHori->Descender);
938 else
939 ppem = ft_face->units_per_EM * height /
940 (pOS2->usWinAscent + pOS2->usWinDescent);
942 else
943 ppem = -height;
945 return ppem;
948 static LONG load_VDMX(GdiFont, LONG);
950 static FT_Face OpenFontFile(GdiFont font, char *file, FT_Long face_index, LONG height)
952 FT_Error err;
953 FT_Face ft_face;
954 LONG ppem;
956 err = pFT_New_Face(library, file, face_index, &ft_face);
957 if(err) {
958 ERR("FT_New_Face rets %d\n", err);
959 return 0;
962 /* set it here, as load_VDMX needs it */
963 font->ft_face = ft_face;
965 /* load the VDMX table if we have one */
966 ppem = load_VDMX(font, height);
967 if(ppem == 0)
968 ppem = calc_ppem_for_height(ft_face, height);
970 pFT_Set_Pixel_Sizes(ft_face, 0, ppem);
972 return ft_face;
976 static int get_nearest_charset(Face *face)
978 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
979 a single face with the requested charset. The idea is to check if
980 the selected font supports the current ANSI codepage, if it does
981 return the corresponding charset, else return the first charset */
983 CHARSETINFO csi;
984 int acp = GetACP(), i;
985 DWORD fs0;
987 if(TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE))
988 if(csi.fs.fsCsb[0] & face->fs.fsCsb[0])
989 return csi.ciCharset;
991 for(i = 0; i < 32; i++) {
992 fs0 = 1L << i;
993 if(face->fs.fsCsb[0] & fs0) {
994 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG))
995 return csi.ciCharset;
996 else
997 FIXME("TCI failing on %lx\n", fs0);
1001 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08lx file = %s\n",
1002 face->fs.fsCsb[0], face->file);
1003 return DEFAULT_CHARSET;
1006 static GdiFont alloc_font(void)
1008 GdiFont ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
1009 ret->gmsize = INIT_GM_SIZE;
1010 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1011 ret->gmsize * sizeof(*ret->gm));
1012 ret->next = NULL;
1013 ret->potm = NULL;
1014 ret->xform.eM11 = ret->xform.eM22 = 1.0;
1015 return ret;
1018 static void free_font(GdiFont font)
1020 if (font->ft_face) pFT_Done_Face(font->ft_face);
1021 if (font->potm) HeapFree(GetProcessHeap(), 0, font->potm);
1022 if (font->name) HeapFree(GetProcessHeap(), 0, font->name);
1023 HeapFree(GetProcessHeap(), 0, font->gm);
1024 HeapFree(GetProcessHeap(), 0, font);
1028 /*************************************************************
1029 * load_VDMX
1031 * load the vdmx entry for the specified height
1034 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
1035 ( ( (FT_ULong)_x4 << 24 ) | \
1036 ( (FT_ULong)_x3 << 16 ) | \
1037 ( (FT_ULong)_x2 << 8 ) | \
1038 (FT_ULong)_x1 )
1040 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
1042 typedef struct {
1043 BYTE bCharSet;
1044 BYTE xRatio;
1045 BYTE yStartRatio;
1046 BYTE yEndRatio;
1047 } Ratios;
1050 static LONG load_VDMX(GdiFont font, LONG height)
1052 BYTE hdr[6], tmp[2], group[4];
1053 BYTE devXRatio, devYRatio;
1054 USHORT numRecs, numRatios;
1055 DWORD offset = -1;
1056 LONG ppem = 0;
1057 int i, result;
1059 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
1061 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
1062 return ppem;
1064 /* FIXME: need the real device aspect ratio */
1065 devXRatio = 1;
1066 devYRatio = 1;
1068 numRecs = GET_BE_WORD(&hdr[2]);
1069 numRatios = GET_BE_WORD(&hdr[4]);
1071 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
1072 for(i = 0; i < numRatios; i++) {
1073 Ratios ratio;
1075 offset = (3 * 2) + (i * sizeof(Ratios));
1076 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
1077 offset = -1;
1079 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
1081 if(ratio.bCharSet != 1)
1082 continue;
1084 if((ratio.xRatio == 0 &&
1085 ratio.yStartRatio == 0 &&
1086 ratio.yEndRatio == 0) ||
1087 (devXRatio == ratio.xRatio &&
1088 devYRatio >= ratio.yStartRatio &&
1089 devYRatio <= ratio.yEndRatio))
1091 offset = (3 * 2) + (numRatios * 4) + (i * 2);
1092 WineEngGetFontData(font, MS_VDMX_TAG, offset, tmp, 2);
1093 offset = GET_BE_WORD(tmp);
1094 break;
1098 if(offset < 0) {
1099 FIXME("No suitable ratio found\n");
1100 return ppem;
1103 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, group, 4) != GDI_ERROR) {
1104 USHORT recs;
1105 BYTE startsz, endsz;
1106 BYTE *vTable;
1108 recs = GET_BE_WORD(group);
1109 startsz = group[2];
1110 endsz = group[3];
1112 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
1114 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
1115 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
1116 if(result == GDI_ERROR) {
1117 FIXME("Failed to retrieve vTable\n");
1118 goto end;
1121 if(height > 0) {
1122 for(i = 0; i < recs; i++) {
1123 SHORT yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1124 SHORT yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1125 ppem = GET_BE_WORD(&vTable[i * 6]);
1127 if(yMax + -yMin == height) {
1128 font->yMax = yMax;
1129 font->yMin = yMin;
1130 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1131 break;
1133 if(yMax + -yMin > height) {
1134 if(--i < 0) {
1135 ppem = 0;
1136 goto end; /* failed */
1138 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1139 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1140 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1141 break;
1144 if(!font->yMax) {
1145 ppem = 0;
1146 TRACE("ppem not found for height %ld\n", height);
1148 } else {
1149 ppem = -height;
1150 if(ppem < startsz || ppem > endsz)
1151 goto end;
1153 for(i = 0; i < recs; i++) {
1154 USHORT yPelHeight;
1155 yPelHeight = GET_BE_WORD(&vTable[i * 6]);
1157 if(yPelHeight > ppem)
1158 break; /* failed */
1160 if(yPelHeight == ppem) {
1161 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1162 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1163 TRACE("ppem %ld found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
1164 break;
1168 end:
1169 HeapFree(GetProcessHeap(), 0, vTable);
1172 return ppem;
1176 /*************************************************************
1177 * WineEngCreateFontInstance
1180 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
1182 GdiFont ret;
1183 Face *face;
1184 Family *family = NULL;
1185 BOOL bd, it;
1186 LOGFONTW lf;
1187 CHARSETINFO csi;
1189 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
1191 TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
1192 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
1193 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
1194 lf.lfEscapement);
1196 /* check the cache first */
1197 for(ret = GdiFontList; ret; ret = ret->next) {
1198 if(ret->hfont == hfont && !memcmp(&ret->xform, &dc->xformWorld2Vport, offsetof(XFORM, eDx))) {
1199 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
1200 return ret;
1204 if(!FontList || !have_installed_roman_font) /* No fonts installed */
1206 TRACE("No fonts installed\n");
1207 return NULL;
1210 ret = alloc_font();
1211 memcpy(&ret->xform, &dc->xformWorld2Vport, sizeof(XFORM));
1213 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
1214 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
1215 original value lfCharSet. Note this is a special case for
1216 Symbol and doesn't happen at least for "Wingdings*" */
1218 if(!strcmpiW(lf.lfFaceName, SymbolW))
1219 lf.lfCharSet = SYMBOL_CHARSET;
1221 if(!TranslateCharsetInfo((DWORD*)(INT)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
1222 switch(lf.lfCharSet) {
1223 case DEFAULT_CHARSET:
1224 csi.fs.fsCsb[0] = 0;
1225 break;
1226 default:
1227 FIXME("Untranslated charset %d\n", lf.lfCharSet);
1228 csi.fs.fsCsb[0] = 0;
1229 break;
1233 if(lf.lfFaceName[0] != '\0') {
1234 FontSubst *psub;
1235 for(psub = substlist; psub; psub = psub->next)
1236 if(!strcmpiW(lf.lfFaceName, psub->from.name) &&
1237 (psub->from.charset == -1 ||
1238 psub->from.charset == lf.lfCharSet))
1239 break;
1240 if(psub) {
1241 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
1242 debugstr_w(psub->to.name));
1243 strcpyW(lf.lfFaceName, psub->to.name);
1246 /* We want a match on name and charset or just name if
1247 charset was DEFAULT_CHARSET. If the latter then
1248 we fixup the returned charset later in get_nearest_charset
1249 where we'll either use the charset of the current ansi codepage
1250 or if that's unavailable the first charset that the font supports.
1252 for(family = FontList; family; family = family->next) {
1253 if(!strcmpiW(family->FamilyName, lf.lfFaceName))
1254 if((csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0]) || !csi.fs.fsCsb[0])
1255 break;
1258 if(!family) { /* do other aliases here */
1259 if(!strcmpiW(lf.lfFaceName, SystemW))
1260 strcpyW(lf.lfFaceName, defSystem);
1261 else if(!strcmpiW(lf.lfFaceName, MSSansSerifW))
1262 strcpyW(lf.lfFaceName, defSans);
1263 else if(!strcmpiW(lf.lfFaceName, HelvW))
1264 strcpyW(lf.lfFaceName, defSans);
1265 else
1266 goto not_found;
1268 for(family = FontList; family; family = family->next) {
1269 if(!strcmpiW(family->FamilyName, lf.lfFaceName))
1270 if((csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0]) || !csi.fs.fsCsb[0])
1271 break;
1276 not_found:
1277 if(!family) {
1278 /* If requested charset was DEFAULT_CHARSET then try using charset
1279 corresponding to the current ansi codepage */
1280 if(!csi.fs.fsCsb[0]) {
1281 INT acp = GetACP();
1282 if(!TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE)) {
1283 FIXME("TCI failed on codepage %d\n", acp);
1284 csi.fs.fsCsb[0] = 0;
1285 } else
1286 lf.lfCharSet = csi.ciCharset;
1289 /* Face families are in the top 4 bits of lfPitchAndFamily,
1290 so mask with 0xF0 before testing */
1292 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
1293 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
1294 strcpyW(lf.lfFaceName, defFixed);
1295 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
1296 strcpyW(lf.lfFaceName, defSerif);
1297 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
1298 strcpyW(lf.lfFaceName, defSans);
1299 else
1300 strcpyW(lf.lfFaceName, defSans);
1301 for(family = FontList; family; family = family->next) {
1302 if(!strcmpiW(family->FamilyName, lf.lfFaceName) &&
1303 (csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0]))
1304 break;
1308 if(!family) {
1309 for(family = FontList; family; family = family->next) {
1310 if(csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0])
1311 break;
1315 if(!family) {
1316 family = FontList;
1317 csi.fs.fsCsb[0] = 0;
1318 FIXME("just using first face for now\n");
1321 it = lf.lfItalic ? 1 : 0;
1322 bd = lf.lfWeight > 550 ? 1 : 0;
1324 for(face = family->FirstFace; face; face = face->next) {
1325 if(!(face->Italic ^ it) && !(face->Bold ^ bd))
1326 break;
1328 if(!face) {
1329 face = family->FirstFace;
1330 if(it && !face->Italic) ret->fake_italic = TRUE;
1331 if(bd && !face->Bold) ret->fake_bold = TRUE;
1334 memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
1336 if(csi.fs.fsCsb[0])
1337 ret->charset = lf.lfCharSet;
1338 else
1339 ret->charset = get_nearest_charset(face);
1341 TRACE("Chosen: %s %s\n", debugstr_w(family->FamilyName),
1342 debugstr_w(face->StyleName));
1344 ret->ft_face = OpenFontFile(ret, face->file, face->face_index,
1345 lf.lfHeight < 0 ?
1346 -abs(INTERNAL_YWSTODS(dc,lf.lfHeight)) :
1347 abs(INTERNAL_YWSTODS(dc, lf.lfHeight)));
1348 if (!ret->ft_face)
1350 free_font( ret );
1351 return 0;
1354 if (ret->charset == SYMBOL_CHARSET &&
1355 !pFT_Select_Charmap(ret->ft_face, ft_encoding_symbol)) {
1356 /* No ops */
1358 else if (!pFT_Select_Charmap(ret->ft_face, ft_encoding_unicode)) {
1359 /* No ops */
1361 else {
1362 pFT_Select_Charmap(ret->ft_face, ft_encoding_apple_roman);
1365 ret->orientation = lf.lfOrientation;
1366 ret->name = strdupW(family->FamilyName);
1368 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
1369 ret->hfont = hfont;
1370 ret->aveWidth= lf.lfWidth;
1371 ret->next = GdiFontList;
1372 GdiFontList = ret;
1374 return ret;
1377 static void DumpGdiFontList(void)
1379 GdiFont gdiFont;
1381 TRACE("---------- gdiFont Cache ----------\n");
1382 for(gdiFont = GdiFontList; gdiFont; gdiFont = gdiFont->next) {
1383 LOGFONTW lf;
1384 GetObjectW( gdiFont->hfont, sizeof(lf), &lf );
1385 TRACE("gdiFont=%p hfont=%p (%s)\n",
1386 gdiFont, gdiFont->hfont, debugstr_w(lf.lfFaceName));
1390 /*************************************************************
1391 * WineEngDestroyFontInstance
1393 * free the gdiFont associated with this handle
1396 BOOL WineEngDestroyFontInstance(HFONT handle)
1398 GdiFont gdiFont;
1399 GdiFont gdiPrev = NULL;
1400 BOOL ret = FALSE;
1402 TRACE("destroying hfont=%p\n", handle);
1403 if(TRACE_ON(font))
1404 DumpGdiFontList();
1406 gdiFont = GdiFontList;
1407 while(gdiFont) {
1408 if(gdiFont->hfont == handle) {
1409 if(gdiPrev) {
1410 gdiPrev->next = gdiFont->next;
1411 free_font(gdiFont);
1412 gdiFont = gdiPrev->next;
1413 } else {
1414 GdiFontList = gdiFont->next;
1415 free_font(gdiFont);
1416 gdiFont = GdiFontList;
1418 ret = TRUE;
1419 } else {
1420 gdiPrev = gdiFont;
1421 gdiFont = gdiFont->next;
1424 return ret;
1427 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
1428 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
1430 OUTLINETEXTMETRICW *potm;
1431 UINT size;
1432 GdiFont font = alloc_font();
1434 if (!(font->ft_face = OpenFontFile(font, face->file, face->face_index, 100)))
1436 free_font(font);
1437 return;
1440 font->name = strdupW(face->family->FamilyName);
1442 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
1444 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
1445 potm = HeapAlloc(GetProcessHeap(), 0, size);
1446 WineEngGetOutlineTextMetrics(font, size, potm);
1448 #define TM potm->otmTextMetrics
1450 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = TM.tmHeight;
1451 pntm->ntmTm.tmAscent = TM.tmAscent;
1452 pntm->ntmTm.tmDescent = TM.tmDescent;
1453 pntm->ntmTm.tmInternalLeading = TM.tmInternalLeading;
1454 pntm->ntmTm.tmExternalLeading = TM.tmExternalLeading;
1455 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = TM.tmAveCharWidth;
1456 pntm->ntmTm.tmMaxCharWidth = TM.tmMaxCharWidth;
1457 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = TM.tmWeight;
1458 pntm->ntmTm.tmOverhang = TM.tmOverhang;
1459 pntm->ntmTm.tmDigitizedAspectX = TM.tmDigitizedAspectX;
1460 pntm->ntmTm.tmDigitizedAspectY = TM.tmDigitizedAspectY;
1461 pntm->ntmTm.tmFirstChar = TM.tmFirstChar;
1462 pntm->ntmTm.tmLastChar = TM.tmLastChar;
1463 pntm->ntmTm.tmDefaultChar = TM.tmDefaultChar;
1464 pntm->ntmTm.tmBreakChar = TM.tmBreakChar;
1465 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = TM.tmItalic;
1466 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = TM.tmUnderlined;
1467 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = TM.tmStruckOut;
1468 pntm->ntmTm.tmPitchAndFamily = TM.tmPitchAndFamily;
1469 pelf->elfLogFont.lfPitchAndFamily = (TM.tmPitchAndFamily & 0xf1) + 1;
1470 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = TM.tmCharSet;
1471 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
1472 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
1473 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
1475 pntm->ntmTm.ntmFlags = TM.tmItalic ? NTM_ITALIC : 0;
1476 if(TM.tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
1477 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
1479 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
1480 pntm->ntmTm.ntmCellHeight = 0;
1481 pntm->ntmTm.ntmAvgWidth = 0;
1483 *ptype = TM.tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
1484 if(!(TM.tmPitchAndFamily & TMPF_VECTOR))
1485 *ptype |= RASTER_FONTTYPE;
1487 #undef TM
1488 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
1490 strncpyW(pelf->elfLogFont.lfFaceName,
1491 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
1492 LF_FACESIZE);
1493 strncpyW(pelf->elfFullName,
1494 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
1495 LF_FULLFACESIZE);
1496 strncpyW(pelf->elfStyle,
1497 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
1498 LF_FACESIZE);
1499 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
1501 HeapFree(GetProcessHeap(), 0, potm);
1502 free_font(font);
1503 return;
1506 /*************************************************************
1507 * WineEngEnumFonts
1510 DWORD WineEngEnumFonts(LPLOGFONTW plf, DEVICEFONTENUMPROC proc,
1511 LPARAM lparam)
1513 Family *family;
1514 Face *face;
1515 ENUMLOGFONTEXW elf;
1516 NEWTEXTMETRICEXW ntm;
1517 DWORD type, ret = 1;
1518 FONTSIGNATURE fs;
1519 CHARSETINFO csi;
1520 LOGFONTW lf;
1521 int i;
1523 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
1525 if(plf->lfFaceName[0]) {
1526 FontSubst *psub;
1527 for(psub = substlist; psub; psub = psub->next)
1528 if(!strcmpiW(plf->lfFaceName, psub->from.name) &&
1529 (psub->from.charset == -1 ||
1530 psub->from.charset == plf->lfCharSet))
1531 break;
1532 if(psub) {
1533 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
1534 debugstr_w(psub->to.name));
1535 memcpy(&lf, plf, sizeof(lf));
1536 strcpyW(lf.lfFaceName, psub->to.name);
1537 plf = &lf;
1539 for(family = FontList; family; family = family->next) {
1540 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
1541 for(face = family->FirstFace; face; face = face->next) {
1542 GetEnumStructs(face, &elf, &ntm, &type);
1543 for(i = 0; i < 32; i++) {
1544 if(face->fs.fsCsb[0] & (1L << i)) {
1545 fs.fsCsb[0] = 1L << i;
1546 fs.fsCsb[1] = 0;
1547 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
1548 TCI_SRCFONTSIG))
1549 csi.ciCharset = DEFAULT_CHARSET;
1550 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
1551 if(csi.ciCharset != DEFAULT_CHARSET) {
1552 elf.elfLogFont.lfCharSet =
1553 ntm.ntmTm.tmCharSet = csi.ciCharset;
1554 if(ElfScriptsW[i])
1555 strcpyW(elf.elfScript, ElfScriptsW[i]);
1556 else
1557 FIXME("Unknown elfscript for bit %d\n", i);
1558 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
1559 debugstr_w(elf.elfLogFont.lfFaceName),
1560 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
1561 csi.ciCharset, type, debugstr_w(elf.elfScript),
1562 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
1563 ntm.ntmTm.ntmFlags);
1564 ret = proc(&elf, &ntm, type, lparam);
1565 if(!ret) goto end;
1572 } else {
1573 for(family = FontList; family; family = family->next) {
1574 GetEnumStructs(family->FirstFace, &elf, &ntm, &type);
1575 for(i = 0; i < 32; i++) {
1576 if(family->FirstFace->fs.fsCsb[0] & (1L << i)) {
1577 fs.fsCsb[0] = 1L << i;
1578 fs.fsCsb[1] = 0;
1579 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
1580 TCI_SRCFONTSIG))
1581 csi.ciCharset = DEFAULT_CHARSET;
1582 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
1583 if(csi.ciCharset != DEFAULT_CHARSET) {
1584 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
1585 csi.ciCharset;
1586 if(ElfScriptsW[i])
1587 strcpyW(elf.elfScript, ElfScriptsW[i]);
1588 else
1589 FIXME("Unknown elfscript for bit %d\n", i);
1590 TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
1591 debugstr_w(elf.elfLogFont.lfFaceName),
1592 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
1593 csi.ciCharset, type, debugstr_w(elf.elfScript),
1594 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
1595 ntm.ntmTm.ntmFlags);
1596 ret = proc(&elf, &ntm, type, lparam);
1597 if(!ret) goto end;
1603 end:
1604 return ret;
1607 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
1609 pt->x.value = vec->x >> 6;
1610 pt->x.fract = (vec->x & 0x3f) << 10;
1611 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
1612 pt->y.value = vec->y >> 6;
1613 pt->y.fract = (vec->y & 0x3f) << 10;
1614 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
1615 return;
1618 static FT_UInt get_glyph_index(GdiFont font, UINT glyph)
1620 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
1621 glyph = glyph + 0xf000;
1622 return pFT_Get_Char_Index(font->ft_face, glyph);
1625 /*************************************************************
1626 * WineEngGetGlyphIndices
1628 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
1630 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
1631 LPWORD pgi, DWORD flags)
1633 INT i;
1635 for(i = 0; i < count; i++)
1636 pgi[i] = get_glyph_index(font, lpstr[i]);
1638 return count;
1641 /*************************************************************
1642 * WineEngGetGlyphOutline
1644 * Behaves in exactly the same way as the win32 api GetGlyphOutline
1645 * except that the first parameter is the HWINEENGFONT of the font in
1646 * question rather than an HDC.
1649 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
1650 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
1651 const MAT2* lpmat)
1653 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
1654 FT_Face ft_face = font->ft_face;
1655 FT_UInt glyph_index;
1656 DWORD width, height, pitch, needed = 0;
1657 FT_Bitmap ft_bitmap;
1658 FT_Error err;
1659 INT left, right, top = 0, bottom = 0;
1660 FT_Angle angle = 0;
1661 FT_Int load_flags = FT_LOAD_DEFAULT;
1662 float widthRatio = 1.0;
1663 FT_Matrix transMat = identityMat;
1664 BOOL needsTransform = FALSE;
1667 TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font, glyph, format, lpgm,
1668 buflen, buf, lpmat);
1670 if(format & GGO_GLYPH_INDEX) {
1671 glyph_index = glyph;
1672 format &= ~GGO_GLYPH_INDEX;
1673 } else
1674 glyph_index = get_glyph_index(font, glyph);
1676 if(glyph_index >= font->gmsize) {
1677 font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
1678 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
1679 font->gmsize * sizeof(*font->gm));
1680 } else {
1681 if(format == GGO_METRICS && font->gm[glyph_index].init) {
1682 memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
1683 return 1; /* FIXME */
1687 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP) || font->aveWidth || lpmat)
1688 load_flags |= FT_LOAD_NO_BITMAP;
1690 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
1692 if(err) {
1693 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
1694 return GDI_ERROR;
1697 /* Scaling factor */
1698 if (font->aveWidth && font->potm) {
1699 widthRatio = (float)font->aveWidth * font->xform.eM11 / (float) font->potm->otmTextMetrics.tmAveCharWidth;
1702 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
1703 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
1705 font->gm[glyph_index].adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
1706 font->gm[glyph_index].lsb = left >> 6;
1707 font->gm[glyph_index].bbx = (right - left) >> 6;
1709 /* Scaling transform */
1710 if(font->aveWidth) {
1711 FT_Matrix scaleMat;
1712 scaleMat.xx = FT_FixedFromFloat(widthRatio);
1713 scaleMat.xy = 0;
1714 scaleMat.yx = 0;
1715 scaleMat.yy = (1 << 16);
1717 pFT_Matrix_Multiply(&scaleMat, &transMat);
1718 needsTransform = TRUE;
1721 /* Rotation transform */
1722 if(font->orientation) {
1723 FT_Matrix rotationMat;
1724 FT_Vector vecAngle;
1725 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
1726 pFT_Vector_Unit(&vecAngle, angle);
1727 rotationMat.xx = vecAngle.x;
1728 rotationMat.xy = -vecAngle.y;
1729 rotationMat.yx = -rotationMat.xy;
1730 rotationMat.yy = rotationMat.xx;
1732 pFT_Matrix_Multiply(&rotationMat, &transMat);
1733 needsTransform = TRUE;
1736 /* Extra transformation specified by caller */
1737 if (lpmat) {
1738 FT_Matrix extraMat;
1739 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
1740 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
1741 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
1742 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
1743 pFT_Matrix_Multiply(&extraMat, &transMat);
1744 needsTransform = TRUE;
1747 if(!needsTransform) {
1748 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
1749 bottom = (ft_face->glyph->metrics.horiBearingY -
1750 ft_face->glyph->metrics.height) & -64;
1751 lpgm->gmCellIncX = font->gm[glyph_index].adv;
1752 lpgm->gmCellIncY = 0;
1753 } else {
1754 INT xc, yc;
1755 FT_Vector vec;
1756 for(xc = 0; xc < 2; xc++) {
1757 for(yc = 0; yc < 2; yc++) {
1758 vec.x = (ft_face->glyph->metrics.horiBearingX +
1759 xc * ft_face->glyph->metrics.width);
1760 vec.y = ft_face->glyph->metrics.horiBearingY -
1761 yc * ft_face->glyph->metrics.height;
1762 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
1763 pFT_Vector_Transform(&vec, &transMat);
1764 if(xc == 0 && yc == 0) {
1765 left = right = vec.x;
1766 top = bottom = vec.y;
1767 } else {
1768 if(vec.x < left) left = vec.x;
1769 else if(vec.x > right) right = vec.x;
1770 if(vec.y < bottom) bottom = vec.y;
1771 else if(vec.y > top) top = vec.y;
1775 left = left & -64;
1776 right = (right + 63) & -64;
1777 bottom = bottom & -64;
1778 top = (top + 63) & -64;
1780 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
1781 vec.x = ft_face->glyph->metrics.horiAdvance;
1782 vec.y = 0;
1783 pFT_Vector_Transform(&vec, &transMat);
1784 lpgm->gmCellIncX = (vec.x+63) >> 6;
1785 lpgm->gmCellIncY = -((vec.y+63) >> 6);
1787 lpgm->gmBlackBoxX = (right - left) >> 6;
1788 lpgm->gmBlackBoxY = (top - bottom) >> 6;
1789 lpgm->gmptGlyphOrigin.x = left >> 6;
1790 lpgm->gmptGlyphOrigin.y = top >> 6;
1792 memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
1793 font->gm[glyph_index].init = TRUE;
1795 if(format == GGO_METRICS)
1796 return 1; /* FIXME */
1798 if (buf && !buflen){
1799 return GDI_ERROR;
1802 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP) {
1803 FIXME("loaded a bitmap\n");
1804 return GDI_ERROR;
1807 switch(format) {
1808 case GGO_BITMAP:
1809 width = lpgm->gmBlackBoxX;
1810 height = lpgm->gmBlackBoxY;
1811 pitch = ((width + 31) >> 5) << 2;
1812 needed = pitch * height;
1814 if(!buf || !buflen) break;
1816 switch(ft_face->glyph->format) {
1817 case ft_glyph_format_bitmap:
1819 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
1820 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
1821 INT h = ft_face->glyph->bitmap.rows;
1822 while(h--) {
1823 memcpy(dst, src, w);
1824 src += ft_face->glyph->bitmap.pitch;
1825 dst += pitch;
1827 break;
1830 case ft_glyph_format_outline:
1831 ft_bitmap.width = width;
1832 ft_bitmap.rows = height;
1833 ft_bitmap.pitch = pitch;
1834 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
1835 ft_bitmap.buffer = buf;
1837 if(needsTransform) {
1838 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
1841 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
1843 /* Note: FreeType will only set 'black' bits for us. */
1844 memset(buf, 0, needed);
1845 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
1846 break;
1848 default:
1849 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
1850 return GDI_ERROR;
1852 break;
1854 case GGO_GRAY2_BITMAP:
1855 case GGO_GRAY4_BITMAP:
1856 case GGO_GRAY8_BITMAP:
1857 case WINE_GGO_GRAY16_BITMAP:
1859 int mult, row, col;
1860 BYTE *start, *ptr;
1862 width = lpgm->gmBlackBoxX;
1863 height = lpgm->gmBlackBoxY;
1864 pitch = (width + 3) / 4 * 4;
1865 needed = pitch * height;
1867 if(!buf || !buflen) break;
1868 ft_bitmap.width = width;
1869 ft_bitmap.rows = height;
1870 ft_bitmap.pitch = pitch;
1871 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
1872 ft_bitmap.buffer = buf;
1874 if(needsTransform) {
1875 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
1878 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
1880 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
1882 if(format == GGO_GRAY2_BITMAP)
1883 mult = 5;
1884 else if(format == GGO_GRAY4_BITMAP)
1885 mult = 17;
1886 else if(format == GGO_GRAY8_BITMAP)
1887 mult = 65;
1888 else if(format == WINE_GGO_GRAY16_BITMAP)
1889 break;
1890 else {
1891 assert(0);
1892 break;
1895 start = buf;
1896 for(row = 0; row < height; row++) {
1897 ptr = start;
1898 for(col = 0; col < width; col++, ptr++) {
1899 *ptr = (*(unsigned int*)ptr * mult + 128) / 256;
1901 start += pitch;
1903 break;
1906 case GGO_NATIVE:
1908 int contour, point = 0, first_pt;
1909 FT_Outline *outline = &ft_face->glyph->outline;
1910 TTPOLYGONHEADER *pph;
1911 TTPOLYCURVE *ppc;
1912 DWORD pph_start, cpfx, type;
1914 if(buflen == 0) buf = NULL;
1916 if (needsTransform && buf) {
1917 pFT_Outline_Transform(outline, &transMat);
1920 for(contour = 0; contour < outline->n_contours; contour++) {
1921 pph_start = needed;
1922 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
1923 first_pt = point;
1924 if(buf) {
1925 pph->dwType = TT_POLYGON_TYPE;
1926 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
1928 needed += sizeof(*pph);
1929 point++;
1930 while(point <= outline->contours[contour]) {
1931 ppc = (TTPOLYCURVE *)((char *)buf + needed);
1932 type = (outline->tags[point] & FT_Curve_Tag_On) ?
1933 TT_PRIM_LINE : TT_PRIM_QSPLINE;
1934 cpfx = 0;
1935 do {
1936 if(buf)
1937 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
1938 cpfx++;
1939 point++;
1940 } while(point <= outline->contours[contour] &&
1941 (outline->tags[point] & FT_Curve_Tag_On) ==
1942 (outline->tags[point-1] & FT_Curve_Tag_On));
1943 /* At the end of a contour Windows adds the start point, but
1944 only for Beziers */
1945 if(point > outline->contours[contour] &&
1946 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
1947 if(buf)
1948 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
1949 cpfx++;
1950 } else if(point <= outline->contours[contour] &&
1951 outline->tags[point] & FT_Curve_Tag_On) {
1952 /* add closing pt for bezier */
1953 if(buf)
1954 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
1955 cpfx++;
1956 point++;
1958 if(buf) {
1959 ppc->wType = type;
1960 ppc->cpfx = cpfx;
1962 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
1964 if(buf)
1965 pph->cb = needed - pph_start;
1967 break;
1969 case GGO_BEZIER:
1971 /* Convert the quadratic Beziers to cubic Beziers.
1972 The parametric eqn for a cubic Bezier is, from PLRM:
1973 r(t) = at^3 + bt^2 + ct + r0
1974 with the control points:
1975 r1 = r0 + c/3
1976 r2 = r1 + (c + b)/3
1977 r3 = r0 + c + b + a
1979 A quadratic Beizer has the form:
1980 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
1982 So equating powers of t leads to:
1983 r1 = 2/3 p1 + 1/3 p0
1984 r2 = 2/3 p1 + 1/3 p2
1985 and of course r0 = p0, r3 = p2
1988 int contour, point = 0, first_pt;
1989 FT_Outline *outline = &ft_face->glyph->outline;
1990 TTPOLYGONHEADER *pph;
1991 TTPOLYCURVE *ppc;
1992 DWORD pph_start, cpfx, type;
1993 FT_Vector cubic_control[4];
1994 if(buflen == 0) buf = NULL;
1996 if (needsTransform && buf) {
1997 pFT_Outline_Transform(outline, &transMat);
2000 for(contour = 0; contour < outline->n_contours; contour++) {
2001 pph_start = needed;
2002 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
2003 first_pt = point;
2004 if(buf) {
2005 pph->dwType = TT_POLYGON_TYPE;
2006 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2008 needed += sizeof(*pph);
2009 point++;
2010 while(point <= outline->contours[contour]) {
2011 ppc = (TTPOLYCURVE *)((char *)buf + needed);
2012 type = (outline->tags[point] & FT_Curve_Tag_On) ?
2013 TT_PRIM_LINE : TT_PRIM_CSPLINE;
2014 cpfx = 0;
2015 do {
2016 if(type == TT_PRIM_LINE) {
2017 if(buf)
2018 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2019 cpfx++;
2020 point++;
2021 } else {
2022 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
2023 so cpfx = 3n */
2025 /* FIXME: Possible optimization in endpoint calculation
2026 if there are two consecutive curves */
2027 cubic_control[0] = outline->points[point-1];
2028 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
2029 cubic_control[0].x += outline->points[point].x + 1;
2030 cubic_control[0].y += outline->points[point].y + 1;
2031 cubic_control[0].x >>= 1;
2032 cubic_control[0].y >>= 1;
2034 if(point+1 > outline->contours[contour])
2035 cubic_control[3] = outline->points[first_pt];
2036 else {
2037 cubic_control[3] = outline->points[point+1];
2038 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
2039 cubic_control[3].x += outline->points[point].x + 1;
2040 cubic_control[3].y += outline->points[point].y + 1;
2041 cubic_control[3].x >>= 1;
2042 cubic_control[3].y >>= 1;
2045 /* r1 = 1/3 p0 + 2/3 p1
2046 r2 = 1/3 p2 + 2/3 p1 */
2047 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
2048 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
2049 cubic_control[2] = cubic_control[1];
2050 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
2051 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
2052 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
2053 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
2054 if(buf) {
2055 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
2056 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
2057 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
2059 cpfx += 3;
2060 point++;
2062 } while(point <= outline->contours[contour] &&
2063 (outline->tags[point] & FT_Curve_Tag_On) ==
2064 (outline->tags[point-1] & FT_Curve_Tag_On));
2065 /* At the end of a contour Windows adds the start point,
2066 but only for Beziers and we've already done that.
2068 if(point <= outline->contours[contour] &&
2069 outline->tags[point] & FT_Curve_Tag_On) {
2070 /* This is the closing pt of a bezier, but we've already
2071 added it, so just inc point and carry on */
2072 point++;
2074 if(buf) {
2075 ppc->wType = type;
2076 ppc->cpfx = cpfx;
2078 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2080 if(buf)
2081 pph->cb = needed - pph_start;
2083 break;
2086 default:
2087 FIXME("Unsupported format %d\n", format);
2088 return GDI_ERROR;
2090 return needed;
2093 /*************************************************************
2094 * WineEngGetTextMetrics
2097 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
2099 if(!font->potm) {
2100 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
2101 return FALSE;
2103 if(!font->potm) return FALSE;
2104 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
2106 if (font->aveWidth) {
2107 ptm->tmAveCharWidth = font->aveWidth * font->xform.eM11;
2109 return TRUE;
2113 /*************************************************************
2114 * WineEngGetOutlineTextMetrics
2117 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
2118 OUTLINETEXTMETRICW *potm)
2120 FT_Face ft_face = font->ft_face;
2121 UINT needed, lenfam, lensty, ret;
2122 TT_OS2 *pOS2;
2123 TT_HoriHeader *pHori;
2124 TT_Postscript *pPost;
2125 FT_Fixed x_scale, y_scale;
2126 WCHAR *family_nameW, *style_nameW;
2127 WCHAR spaceW[] = {' ', '\0'};
2128 char *cp;
2129 INT ascent, descent;
2131 TRACE("font=%p\n", font);
2133 if(font->potm) {
2134 if(cbSize >= font->potm->otmSize)
2135 memcpy(potm, font->potm, font->potm->otmSize);
2136 return font->potm->otmSize;
2139 needed = sizeof(*potm);
2141 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
2142 family_nameW = strdupW(font->name);
2144 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
2145 * sizeof(WCHAR);
2146 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
2147 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
2148 style_nameW, lensty);
2150 /* These names should be read from the TT name table */
2152 /* length of otmpFamilyName */
2153 needed += lenfam;
2155 /* length of otmpFaceName */
2156 if(!strcasecmp(ft_face->style_name, "regular")) {
2157 needed += lenfam; /* just the family name */
2158 } else {
2159 needed += lenfam + lensty; /* family + " " + style */
2162 /* length of otmpStyleName */
2163 needed += lensty;
2165 /* length of otmpFullName */
2166 needed += lenfam + lensty;
2169 x_scale = ft_face->size->metrics.x_scale;
2170 y_scale = ft_face->size->metrics.y_scale;
2172 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2173 if(!pOS2) {
2174 FIXME("Can't find OS/2 table - not TT font?\n");
2175 ret = 0;
2176 goto end;
2179 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2180 if(!pHori) {
2181 FIXME("Can't find HHEA table - not TT font?\n");
2182 ret = 0;
2183 goto end;
2186 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
2188 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",
2189 pOS2->usWinAscent, pOS2->usWinDescent,
2190 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
2191 ft_face->ascender, ft_face->descender, ft_face->height,
2192 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
2193 ft_face->bbox.yMax, ft_face->bbox.yMin);
2195 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
2196 font->potm->otmSize = needed;
2198 #define TM font->potm->otmTextMetrics
2200 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
2201 ascent = pHori->Ascender;
2202 descent = -pHori->Descender;
2203 } else {
2204 ascent = pOS2->usWinAscent;
2205 descent = pOS2->usWinDescent;
2208 if(font->yMax) {
2209 TM.tmAscent = font->yMax;
2210 TM.tmDescent = -font->yMin;
2211 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
2212 } else {
2213 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
2214 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
2215 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
2216 - ft_face->units_per_EM, y_scale) + 32) >> 6;
2219 TM.tmHeight = TM.tmAscent + TM.tmDescent;
2221 /* MSDN says:
2222 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
2224 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
2225 ((ascent + descent) -
2226 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
2228 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
2229 if (TM.tmAveCharWidth == 0) {
2230 TM.tmAveCharWidth = 1;
2232 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
2233 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
2234 TM.tmOverhang = 0;
2235 TM.tmDigitizedAspectX = 300;
2236 TM.tmDigitizedAspectY = 300;
2237 TM.tmFirstChar = pOS2->usFirstCharIndex;
2238 TM.tmLastChar = pOS2->usLastCharIndex;
2239 TM.tmDefaultChar = pOS2->usDefaultChar;
2240 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
2241 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
2242 TM.tmUnderlined = 0; /* entry in OS2 table */
2243 TM.tmStruckOut = 0; /* entry in OS2 table */
2245 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
2246 if(!FT_IS_FIXED_WIDTH(ft_face))
2247 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
2248 else
2249 TM.tmPitchAndFamily = 0;
2251 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
2252 case PAN_FAMILY_SCRIPT:
2253 TM.tmPitchAndFamily |= FF_SCRIPT;
2254 break;
2255 case PAN_FAMILY_DECORATIVE:
2256 case PAN_FAMILY_PICTORIAL:
2257 TM.tmPitchAndFamily |= FF_DECORATIVE;
2258 break;
2259 case PAN_FAMILY_TEXT_DISPLAY:
2260 if(TM.tmPitchAndFamily == 0) /* fixed */
2261 TM.tmPitchAndFamily = FF_MODERN;
2262 else {
2263 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
2264 case PAN_SERIF_NORMAL_SANS:
2265 case PAN_SERIF_OBTUSE_SANS:
2266 case PAN_SERIF_PERP_SANS:
2267 TM.tmPitchAndFamily |= FF_SWISS;
2268 break;
2269 default:
2270 TM.tmPitchAndFamily |= FF_ROMAN;
2273 break;
2274 default:
2275 TM.tmPitchAndFamily |= FF_DONTCARE;
2278 if(FT_IS_SCALABLE(ft_face))
2279 TM.tmPitchAndFamily |= TMPF_VECTOR;
2280 if(FT_IS_SFNT(ft_face))
2281 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
2283 TM.tmCharSet = font->charset;
2284 #undef TM
2286 font->potm->otmFiller = 0;
2287 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
2288 font->potm->otmfsSelection = pOS2->fsSelection;
2289 font->potm->otmfsType = pOS2->fsType;
2290 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
2291 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
2292 font->potm->otmItalicAngle = 0; /* POST table */
2293 font->potm->otmEMSquare = ft_face->units_per_EM;
2294 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
2295 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
2296 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
2297 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
2298 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
2299 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
2300 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
2301 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
2302 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
2303 font->potm->otmMacAscent = 0; /* where do these come from ? */
2304 font->potm->otmMacDescent = 0;
2305 font->potm->otmMacLineGap = 0;
2306 font->potm->otmusMinimumPPEM = 0; /* TT Header */
2307 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
2308 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
2309 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
2310 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
2311 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
2312 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
2313 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
2314 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
2315 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
2316 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
2317 if(!pPost) {
2318 font->potm->otmsUnderscoreSize = 0;
2319 font->potm->otmsUnderscorePosition = 0;
2320 } else {
2321 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
2322 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
2325 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
2326 cp = (char*)font->potm + sizeof(*font->potm);
2327 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
2328 strcpyW((WCHAR*)cp, family_nameW);
2329 cp += lenfam;
2330 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
2331 strcpyW((WCHAR*)cp, style_nameW);
2332 cp += lensty;
2333 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
2334 strcpyW((WCHAR*)cp, family_nameW);
2335 if(strcasecmp(ft_face->style_name, "regular")) {
2336 strcatW((WCHAR*)cp, spaceW);
2337 strcatW((WCHAR*)cp, style_nameW);
2338 cp += lenfam + lensty;
2339 } else
2340 cp += lenfam;
2341 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
2342 strcpyW((WCHAR*)cp, family_nameW);
2343 strcatW((WCHAR*)cp, spaceW);
2344 strcatW((WCHAR*)cp, style_nameW);
2345 ret = needed;
2347 if(potm && needed <= cbSize)
2348 memcpy(potm, font->potm, font->potm->otmSize);
2350 end:
2351 HeapFree(GetProcessHeap(), 0, style_nameW);
2352 HeapFree(GetProcessHeap(), 0, family_nameW);
2354 return ret;
2358 /*************************************************************
2359 * WineEngGetCharWidth
2362 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
2363 LPINT buffer)
2365 UINT c;
2366 GLYPHMETRICS gm;
2367 FT_UInt glyph_index;
2369 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
2371 for(c = firstChar; c <= lastChar; c++) {
2372 glyph_index = get_glyph_index(font, c);
2373 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
2374 &gm, 0, NULL, NULL);
2375 buffer[c - firstChar] = font->gm[glyph_index].adv;
2377 return TRUE;
2380 /*************************************************************
2381 * WineEngGetTextExtentPoint
2384 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
2385 LPSIZE size)
2387 INT idx;
2388 GLYPHMETRICS gm;
2389 TEXTMETRICW tm;
2390 FT_UInt glyph_index;
2392 TRACE("%p, %s, %d, %p\n", font, debugstr_wn(wstr, count), count,
2393 size);
2395 size->cx = 0;
2396 WineEngGetTextMetrics(font, &tm);
2397 size->cy = tm.tmHeight;
2399 for(idx = 0; idx < count; idx++) {
2400 glyph_index = get_glyph_index(font, wstr[idx]);
2401 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
2402 &gm, 0, NULL, NULL);
2403 size->cx += font->gm[glyph_index].adv;
2405 TRACE("return %ld,%ld\n", size->cx, size->cy);
2406 return TRUE;
2409 /*************************************************************
2410 * WineEngGetTextExtentPointI
2413 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
2414 LPSIZE size)
2416 INT idx;
2417 GLYPHMETRICS gm;
2418 TEXTMETRICW tm;
2420 TRACE("%p, %p, %d, %p\n", font, indices, count, size);
2422 size->cx = 0;
2423 WineEngGetTextMetrics(font, &tm);
2424 size->cy = tm.tmHeight;
2426 for(idx = 0; idx < count; idx++) {
2427 WineEngGetGlyphOutline(font, indices[idx],
2428 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
2429 NULL);
2430 size->cx += font->gm[indices[idx]].adv;
2432 TRACE("return %ld,%ld\n", size->cx, size->cy);
2433 return TRUE;
2436 /*************************************************************
2437 * WineEngGetFontData
2440 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
2441 DWORD cbData)
2443 FT_Face ft_face = font->ft_face;
2444 DWORD len;
2445 FT_Error err;
2447 TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
2448 font, table, offset, buf, cbData);
2450 if(!FT_IS_SFNT(ft_face))
2451 return GDI_ERROR;
2453 if(!buf || !cbData)
2454 len = 0;
2455 else
2456 len = cbData;
2458 if(table) { /* MS tags differ in endidness from FT ones */
2459 table = table >> 24 | table << 24 |
2460 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
2463 /* If the FT_Load_Sfnt_Table function is there we'll use it */
2464 if(pFT_Load_Sfnt_Table)
2465 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
2466 else { /* Do it the hard way */
2467 TT_Face tt_face = (TT_Face) ft_face;
2468 SFNT_Interface *sfnt;
2469 if (FT_Version.major==2 && FT_Version.minor==0)
2471 /* 2.0.x */
2472 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
2474 else
2476 /* A field was added in the middle of the structure in 2.1.x */
2477 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
2479 err = sfnt->load_any(tt_face, table, offset, buf, &len);
2481 if(err) {
2482 TRACE("Can't find table %08lx.\n", table);
2483 return GDI_ERROR;
2485 return len;
2488 /*************************************************************
2489 * WineEngGetTextFace
2492 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
2494 if(str) {
2495 lstrcpynW(str, font->name, count);
2496 return strlenW(font->name);
2497 } else
2498 return strlenW(font->name) + 1;
2501 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
2503 if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
2504 return font->charset;
2507 #else /* HAVE_FREETYPE */
2509 BOOL WineEngInit(void)
2511 return FALSE;
2513 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
2515 return NULL;
2517 BOOL WineEngDestroyFontInstance(HFONT hfont)
2519 return FALSE;
2522 DWORD WineEngEnumFonts(LPLOGFONTW plf, DEVICEFONTENUMPROC proc, LPARAM lparam)
2524 return 1;
2527 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
2528 LPWORD pgi, DWORD flags)
2530 return GDI_ERROR;
2533 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
2534 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
2535 const MAT2* lpmat)
2537 ERR("called but we don't have FreeType\n");
2538 return GDI_ERROR;
2541 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
2543 ERR("called but we don't have FreeType\n");
2544 return FALSE;
2547 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
2548 OUTLINETEXTMETRICW *potm)
2550 ERR("called but we don't have FreeType\n");
2551 return 0;
2554 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
2555 LPINT buffer)
2557 ERR("called but we don't have FreeType\n");
2558 return FALSE;
2561 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
2562 LPSIZE size)
2564 ERR("called but we don't have FreeType\n");
2565 return FALSE;
2568 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
2569 LPSIZE size)
2571 ERR("called but we don't have FreeType\n");
2572 return FALSE;
2575 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
2576 DWORD cbData)
2578 ERR("called but we don't have FreeType\n");
2579 return GDI_ERROR;
2582 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
2584 ERR("called but we don't have FreeType\n");
2585 return 0;
2588 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2590 FIXME(":stub\n");
2591 return 1;
2594 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2596 FIXME(":stub\n");
2597 return TRUE;
2600 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
2602 FIXME(":stub\n");
2603 return DEFAULT_CHARSET;
2606 #endif /* HAVE_FREETYPE */