Make the standard create_file request handle serial ports too, and
[wine.git] / dlls / gdi / freetype.c
blobbe2bf1759138ac47e348847cf44c69ed209416c5
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 BOOL external; /* TRUE if we should manually add this font to the registry */
146 struct tagFace *next;
147 struct tagFamily *family;
148 } Face;
150 typedef struct tagFamily {
151 WCHAR *FamilyName;
152 Face *FirstFace;
153 struct tagFamily *next;
154 } Family;
156 typedef struct {
157 GLYPHMETRICS gm;
158 INT adv; /* These three hold to widths of the unrotated chars */
159 INT lsb;
160 INT bbx;
161 BOOL init;
162 } GM;
164 struct tagGdiFont {
165 FT_Face ft_face;
166 XFORM xform;
167 LPWSTR name;
168 int charset;
169 BOOL fake_italic;
170 BOOL fake_bold;
171 INT orientation;
172 GM *gm;
173 DWORD gmsize;
174 HFONT hfont;
175 LONG aveWidth;
176 SHORT yMax;
177 SHORT yMin;
178 OUTLINETEXTMETRICW *potm;
179 FONTSIGNATURE fs;
180 struct tagGdiFont *next;
183 #define INIT_GM_SIZE 128
185 static GdiFont GdiFontList = NULL;
187 static Family *FontList = NULL;
189 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ',
190 'R','o','m','a','n','\0'};
191 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
192 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
194 static const WCHAR defSystem[] = {'A','r','i','a','l','\0'};
195 static const WCHAR SystemW[] = {'S','y','s','t','e','m','\0'};
196 static const WCHAR MSSansSerifW[] = {'M','S',' ','S','a','n','s',' ',
197 'S','e','r','i','f','\0'};
198 static const WCHAR HelvW[] = {'H','e','l','v','\0'};
199 static const WCHAR RegularW[] = {'R','e','g','u','l','a','r','\0'};
201 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
202 'W','i','n','d','o','w','s','\\',
203 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
204 'F','o','n','t','s','\0'};
206 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
207 'W','i','n','d','o','w','s',' ','N','T','\\',
208 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
209 'F','o','n','t','s','\0'};
211 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\','W','i','n','e','\\',
212 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
214 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
215 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
216 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
217 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
218 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
219 'E','u','r','o','p','e','a','n','\0'};
220 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
221 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
222 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
223 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
224 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
225 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
226 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
227 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
228 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
229 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
230 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
232 static const WCHAR *ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
233 WesternW, /*00*/
234 Central_EuropeanW,
235 CyrillicW,
236 GreekW,
237 TurkishW,
238 HebrewW,
239 ArabicW,
240 BalticW,
241 VietnameseW, /*08*/
242 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
243 ThaiW,
244 JapaneseW,
245 CHINESE_GB2312W,
246 HangulW,
247 CHINESE_BIG5W,
248 Hangul_Johab_W,
249 NULL, NULL, /*23*/
250 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
251 SymbolW /*31*/
254 typedef struct {
255 WCHAR *name;
256 INT charset;
257 } NameCs;
259 typedef struct tagFontSubst {
260 NameCs from;
261 NameCs to;
262 struct tagFontSubst *next;
263 } FontSubst;
265 static FontSubst *substlist = NULL;
266 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
268 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
270 static inline BOOL is_win9x(void)
272 return GetVersion() & 0x80000000;
275 This function builds an FT_Fixed from a float. It puts the integer part
276 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
277 It fails if the integer part of the float number is greater than SHORT_MAX.
279 static inline FT_Fixed FT_FixedFromFloat(float f)
281 short value = f;
282 unsigned short fract = (f - value) * 0xFFFF;
283 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
287 This function builds an FT_Fixed from a FIXED. It simply put f.value
288 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
290 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
292 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
295 static BOOL AddFontFileToList(const char *file, char *fake_family, BOOL external_font)
297 FT_Face ft_face;
298 TT_OS2 *pOS2;
299 TT_Header *pHeader;
300 WCHAR *FamilyW, *StyleW;
301 DWORD len;
302 Family *family = FontList;
303 Family **insert = &FontList;
304 Face **insertface, *next;
305 FT_Error err;
306 FT_Long face_index = 0, num_faces;
307 int i;
309 do {
310 char *family_name = fake_family;
312 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
313 if((err = pFT_New_Face(library, file, face_index, &ft_face)) != 0) {
314 WARN("Unable to load font file %s err = %x\n", debugstr_a(file), err);
315 return FALSE;
318 if(!FT_IS_SFNT(ft_face)) { /* for now we'll skip everything but TT/OT */
319 pFT_Done_Face(ft_face);
320 return FALSE;
322 if(!pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2) ||
323 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
324 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head))) {
325 TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
326 "Skipping this font.\n", debugstr_a(file));
327 pFT_Done_Face(ft_face);
328 return FALSE;
331 if(!ft_face->family_name || !ft_face->style_name) {
332 TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file));
333 pFT_Done_Face(ft_face);
334 return FALSE;
337 if(!family_name)
338 family_name = ft_face->family_name;
340 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
341 FamilyW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
342 MultiByteToWideChar(CP_ACP, 0, family_name, -1, FamilyW, len);
344 while(family) {
345 if(!strcmpW(family->FamilyName, FamilyW))
346 break;
347 insert = &family->next;
348 family = family->next;
350 if(!family) {
351 family = *insert = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
352 family->FamilyName = FamilyW;
353 family->FirstFace = NULL;
354 family->next = NULL;
355 } else {
356 HeapFree(GetProcessHeap(), 0, FamilyW);
359 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
360 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
361 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
363 next = NULL;
364 for(insertface = &family->FirstFace; *insertface;
365 insertface = &(*insertface)->next) {
366 if(!strcmpW((*insertface)->StyleName, StyleW)) {
367 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
368 debugstr_w(family->FamilyName), debugstr_w(StyleW),
369 (*insertface)->font_version, pHeader->Font_Revision);
371 if(fake_family) {
372 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
373 HeapFree(GetProcessHeap(), 0, StyleW);
374 pFT_Done_Face(ft_face);
375 return FALSE;
377 if(pHeader->Font_Revision <= (*insertface)->font_version) {
378 TRACE("Original font is newer so skipping this one\n");
379 HeapFree(GetProcessHeap(), 0, StyleW);
380 pFT_Done_Face(ft_face);
381 return FALSE;
382 } else {
383 TRACE("Replacing original with this one\n");
384 next = (*insertface)->next;
385 HeapFree(GetProcessHeap(), 0, (*insertface)->file);
386 HeapFree(GetProcessHeap(), 0, (*insertface)->StyleName);
387 HeapFree(GetProcessHeap(), 0, *insertface);
388 break;
392 *insertface = HeapAlloc(GetProcessHeap(), 0, sizeof(**insertface));
393 (*insertface)->StyleName = StyleW;
394 (*insertface)->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
395 strcpy((*insertface)->file, file);
396 (*insertface)->face_index = face_index;
397 (*insertface)->next = next;
398 (*insertface)->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
399 (*insertface)->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
400 (*insertface)->font_version = pHeader->Font_Revision;
401 (*insertface)->family = family;
402 (*insertface)->external = external_font;
404 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
405 if(pOS2) {
406 (*insertface)->fs.fsCsb[0] = pOS2->ulCodePageRange1;
407 (*insertface)->fs.fsCsb[1] = pOS2->ulCodePageRange2;
408 (*insertface)->fs.fsUsb[0] = pOS2->ulUnicodeRange1;
409 (*insertface)->fs.fsUsb[1] = pOS2->ulUnicodeRange2;
410 (*insertface)->fs.fsUsb[2] = pOS2->ulUnicodeRange3;
411 (*insertface)->fs.fsUsb[3] = pOS2->ulUnicodeRange4;
412 } else {
413 (*insertface)->fs.fsCsb[0] = (*insertface)->fs.fsCsb[1] = 0;
414 (*insertface)->fs.fsUsb[0] = 0;
415 (*insertface)->fs.fsUsb[1] = 0;
416 (*insertface)->fs.fsUsb[2] = 0;
417 (*insertface)->fs.fsUsb[3] = 0;
419 TRACE("fsCsb = %08lx %08lx/%08lx %08lx %08lx %08lx\n",
420 (*insertface)->fs.fsCsb[0], (*insertface)->fs.fsCsb[1],
421 (*insertface)->fs.fsUsb[0], (*insertface)->fs.fsUsb[1],
422 (*insertface)->fs.fsUsb[2], (*insertface)->fs.fsUsb[3]);
424 if(pOS2->version == 0) {
425 FT_UInt dummy;
427 /* If the function is not there, we assume the font is ok */
428 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
429 (*insertface)->fs.fsCsb[0] |= 1;
430 else
431 (*insertface)->fs.fsCsb[0] |= 1L << 31;
434 if((*insertface)->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
435 for(i = 0; i < ft_face->num_charmaps; i++) {
436 switch(ft_face->charmaps[i]->encoding) {
437 case ft_encoding_unicode:
438 case ft_encoding_apple_roman:
439 (*insertface)->fs.fsCsb[0] |= 1;
440 break;
441 case ft_encoding_symbol:
442 (*insertface)->fs.fsCsb[0] |= 1L << 31;
443 break;
444 default:
445 break;
450 if((*insertface)->fs.fsCsb[0] & ~(1L << 31))
451 have_installed_roman_font = TRUE;
453 num_faces = ft_face->num_faces;
454 pFT_Done_Face(ft_face);
455 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
456 debugstr_w(StyleW));
457 } while(num_faces > ++face_index);
458 return TRUE;
461 static void DumpFontList(void)
463 Family *family;
464 Face *face;
466 for(family = FontList; family; family = family->next) {
467 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
468 for(face = family->FirstFace; face; face = face->next) {
469 TRACE("\t%s\n", debugstr_w(face->StyleName));
472 return;
475 static void DumpSubstList(void)
477 FontSubst *psub;
479 for(psub = substlist; psub; psub = psub->next)
480 if(psub->from.charset != -1 || psub->to.charset != -1)
481 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
482 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
483 else
484 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
485 debugstr_w(psub->to.name));
486 return;
489 static LPWSTR strdupW(LPWSTR p)
491 LPWSTR ret;
492 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
493 ret = HeapAlloc(GetProcessHeap(), 0, len);
494 memcpy(ret, p, len);
495 return ret;
498 static void split_subst_info(NameCs *nc, LPSTR str)
500 CHAR *p = strrchr(str, ',');
501 DWORD len;
503 nc->charset = -1;
504 if(p && *(p+1)) {
505 nc->charset = strtol(p+1, NULL, 10);
506 *p = '\0';
508 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
509 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
510 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
513 static void LoadSubstList(void)
515 FontSubst *psub, **ppsub;
516 HKEY hkey;
517 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
518 LPSTR value;
519 LPVOID data;
521 if(substlist) {
522 for(psub = substlist; psub;) {
523 FontSubst *ptmp;
524 HeapFree(GetProcessHeap(), 0, psub->to.name);
525 HeapFree(GetProcessHeap(), 0, psub->from.name);
526 ptmp = psub;
527 psub = psub->next;
528 HeapFree(GetProcessHeap(), 0, ptmp);
530 substlist = NULL;
533 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
534 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
535 &hkey) == ERROR_SUCCESS) {
537 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
538 &valuelen, &datalen, NULL, NULL);
540 valuelen++; /* returned value doesn't include room for '\0' */
541 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
542 data = HeapAlloc(GetProcessHeap(), 0, datalen);
544 dlen = datalen;
545 vlen = valuelen;
546 ppsub = &substlist;
547 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
548 &dlen) == ERROR_SUCCESS) {
549 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
551 *ppsub = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppsub));
552 (*ppsub)->next = NULL;
553 split_subst_info(&((*ppsub)->from), value);
554 split_subst_info(&((*ppsub)->to), data);
556 /* Win 2000 doesn't allow mapping between different charsets
557 or mapping of DEFAULT_CHARSET */
558 if(((*ppsub)->to.charset != (*ppsub)->from.charset) ||
559 (*ppsub)->to.charset == DEFAULT_CHARSET) {
560 HeapFree(GetProcessHeap(), 0, (*ppsub)->to.name);
561 HeapFree(GetProcessHeap(), 0, (*ppsub)->from.name);
562 HeapFree(GetProcessHeap(), 0, *ppsub);
563 *ppsub = NULL;
564 } else {
565 ppsub = &((*ppsub)->next);
567 /* reset dlen and vlen */
568 dlen = datalen;
569 vlen = valuelen;
571 HeapFree(GetProcessHeap(), 0, data);
572 HeapFree(GetProcessHeap(), 0, value);
573 RegCloseKey(hkey);
577 /***********************************************************
578 * The replacement list is a way to map an entire font
579 * family onto another family. For example adding
581 * [HKLM\Software\Wine\Wine\FontReplacements]
582 * "Wingdings"="Winedings"
584 * would enumerate the Winedings font both as Winedings and
585 * Wingdings. However if a real Wingdings font is present the
586 * replacement does not take place.
589 static void LoadReplaceList(void)
591 HKEY hkey;
592 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
593 LPSTR value;
594 LPVOID data;
595 Family *family;
596 Face *face;
597 WCHAR old_nameW[200];
599 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
600 "Software\\Wine\\Wine\\FontReplacements",
601 &hkey) == ERROR_SUCCESS) {
603 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
604 &valuelen, &datalen, NULL, NULL);
606 valuelen++; /* returned value doesn't include room for '\0' */
607 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
608 data = HeapAlloc(GetProcessHeap(), 0, datalen);
610 dlen = datalen;
611 vlen = valuelen;
612 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
613 &dlen) == ERROR_SUCCESS) {
614 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
615 /* "NewName"="Oldname" */
616 if(!MultiByteToWideChar(CP_ACP, 0, data, -1, old_nameW, sizeof(old_nameW)))
617 break;
619 /* Find the old family and hence all of the font files
620 in that family */
621 for(family = FontList; family; family = family->next) {
622 if(!strcmpiW(family->FamilyName, old_nameW)) {
623 for(face = family->FirstFace; face; face = face->next) {
624 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
625 debugstr_w(face->StyleName), value);
626 /* Now add a new entry with the new family name */
627 AddFontFileToList(face->file, value, face->external);
629 break;
632 /* reset dlen and vlen */
633 dlen = datalen;
634 vlen = valuelen;
636 HeapFree(GetProcessHeap(), 0, data);
637 HeapFree(GetProcessHeap(), 0, value);
638 RegCloseKey(hkey);
643 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
645 DIR *dir;
646 struct dirent *dent;
647 char path[MAX_PATH];
649 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
651 dir = opendir(dirname);
652 if(!dir) {
653 ERR("Can't open directory %s\n", debugstr_a(dirname));
654 return FALSE;
656 while((dent = readdir(dir)) != NULL) {
657 struct stat statbuf;
659 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
660 continue;
662 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
664 sprintf(path, "%s/%s", dirname, dent->d_name);
666 if(stat(path, &statbuf) == -1)
668 WARN("Can't stat %s\n", debugstr_a(path));
669 continue;
671 if(S_ISDIR(statbuf.st_mode))
672 ReadFontDir(path, external_fonts);
673 else
674 AddFontFileToList(path, NULL, external_fonts);
676 closedir(dir);
677 return TRUE;
680 static void load_fontconfig_fonts(void)
682 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
683 void *fc_handle = NULL;
684 FcConfig *config;
685 FcPattern *pat;
686 FcObjectSet *os;
687 FcFontSet *fontset;
688 FcValue v;
689 int i, len;
690 const char *ext;
692 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
693 if(!fc_handle) {
694 TRACE("Wine cannot find the fontconfig library (%s).\n",
695 SONAME_LIBFONTCONFIG);
696 return;
698 #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;}
699 LOAD_FUNCPTR(FcConfigGetCurrent);
700 LOAD_FUNCPTR(FcFontList);
701 LOAD_FUNCPTR(FcFontSetDestroy);
702 LOAD_FUNCPTR(FcInit);
703 LOAD_FUNCPTR(FcObjectSetAdd);
704 LOAD_FUNCPTR(FcObjectSetCreate);
705 LOAD_FUNCPTR(FcObjectSetDestroy);
706 LOAD_FUNCPTR(FcPatternCreate);
707 LOAD_FUNCPTR(FcPatternDestroy);
708 LOAD_FUNCPTR(FcPatternGet);
709 #undef LOAD_FUNCPTR
711 if(!pFcInit()) return;
713 config = pFcConfigGetCurrent();
714 pat = pFcPatternCreate();
715 os = pFcObjectSetCreate();
716 pFcObjectSetAdd(os, FC_FILE);
717 fontset = pFcFontList(config, pat, os);
718 if(!fontset) return;
719 for(i = 0; i < fontset->nfont; i++) {
720 if(pFcPatternGet(fontset->fonts[i], FC_FILE, 0, &v) != FcResultMatch)
721 continue;
722 if(v.type != FcTypeString) continue;
723 TRACE("fontconfig: %s\n", v.u.s);
725 /* We're just interested in OT/TT fonts for now, so this hack just
726 picks up the standard extensions to save time loading every other
727 font */
728 len = strlen(v.u.s);
729 if(len < 4) continue;
730 ext = v.u.s + len - 3;
731 if(!strcasecmp(ext, "ttf") || !strcasecmp(ext, "ttc") || !strcasecmp(ext, "otf"))
732 AddFontFileToList(v.u.s, NULL, TRUE);
734 pFcFontSetDestroy(fontset);
735 pFcObjectSetDestroy(os);
736 pFcPatternDestroy(pat);
737 sym_not_found:
738 #endif
739 return;
742 /*************************************************************
744 * This adds registry entries for any externally loaded fonts
745 * (fonts from fontconfig or FontDirs). It also deletes entries
746 * of no longer existing fonts.
749 void update_reg_entries(void)
751 HKEY winkey = 0, externalkey = 0;
752 LPWSTR valueW;
753 LPVOID data;
754 DWORD dlen, vlen, datalen, valuelen, i, type, len, len_fam;
755 Family *family;
756 Face *face;
757 WCHAR *file;
758 const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
759 const WCHAR spaceW[] = {' ', '\0'};
760 char *path;
762 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
763 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winkey, NULL) != ERROR_SUCCESS) {
764 ERR("Can't create Windows font reg key\n");
765 goto end;
767 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, external_fonts_reg_key,
768 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
769 ERR("Can't create external font reg key\n");
770 goto end;
773 /* Delete all external fonts added last time */
775 RegQueryInfoKeyW(externalkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
776 &valuelen, &datalen, NULL, NULL);
777 valuelen++; /* returned value doesn't include room for '\0' */
778 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
779 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
781 dlen = datalen * sizeof(WCHAR);
782 vlen = valuelen;
783 i = 0;
784 while(RegEnumValueW(externalkey, i++, valueW, &vlen, NULL, &type, data,
785 &dlen) == ERROR_SUCCESS) {
787 RegDeleteValueW(winkey, valueW);
788 /* reset dlen and vlen */
789 dlen = datalen;
790 vlen = valuelen;
792 HeapFree(GetProcessHeap(), 0, data);
793 HeapFree(GetProcessHeap(), 0, valueW);
795 /* Delete the old external fonts key */
796 RegCloseKey(externalkey);
797 externalkey = 0;
798 RegDeleteKeyW(HKEY_LOCAL_MACHINE, external_fonts_reg_key);
800 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, external_fonts_reg_key,
801 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
802 ERR("Can't create external font reg key\n");
803 goto end;
806 /* enumerate the fonts and add external ones to the two keys */
808 for(family = FontList; family; family = family->next) {
809 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
810 for(face = family->FirstFace; face; face = face->next) {
811 if(!face->external) continue;
812 len = len_fam;
813 if(strcmpiW(face->StyleName, RegularW))
814 len = len_fam + strlenW(face->StyleName) + 1;
815 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
816 strcpyW(valueW, family->FamilyName);
817 if(len != len_fam) {
818 strcatW(valueW, spaceW);
819 strcatW(valueW, face->StyleName);
821 strcatW(valueW, TrueType);
822 if((path = strrchr(face->file, '/')) == NULL)
823 path = face->file;
824 else
825 path++;
826 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
828 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
829 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
830 RegSetValueExW(winkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
831 RegSetValueExW(externalkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
833 HeapFree(GetProcessHeap(), 0, file);
834 HeapFree(GetProcessHeap(), 0, valueW);
837 end:
838 if(externalkey)
839 RegCloseKey(externalkey);
840 if(winkey)
841 RegCloseKey(winkey);
842 return;
846 /*************************************************************
847 * WineEngAddFontResourceEx
850 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
852 if (ft_handle) /* do it only if we have freetype up and running */
854 char unixname[MAX_PATH];
856 if(flags)
857 FIXME("Ignoring flags %lx\n", flags);
859 if(wine_get_unix_file_name(file, unixname, sizeof(unixname)))
860 AddFontFileToList(unixname, NULL, FALSE);
862 return 1;
865 /*************************************************************
866 * WineEngRemoveFontResourceEx
869 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
871 FIXME(":stub\n");
872 return TRUE;
875 /*************************************************************
876 * WineEngInit
878 * Initialize FreeType library and create a list of available faces
880 BOOL WineEngInit(void)
882 static const WCHAR fontsW[] = {'\\','F','o','n','t','s','\0'};
883 HKEY hkey;
884 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
885 LPVOID data;
886 WCHAR windowsdir[MAX_PATH];
887 char unixname[MAX_PATH];
888 HANDLE font_mutex;
890 TRACE("\n");
892 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
893 if(!ft_handle) {
894 WINE_MESSAGE(
895 "Wine cannot find the FreeType font library. To enable Wine to\n"
896 "use TrueType fonts please install a version of FreeType greater than\n"
897 "or equal to 2.0.5.\n"
898 "http://www.freetype.org\n");
899 return FALSE;
902 #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;}
904 LOAD_FUNCPTR(FT_Vector_Unit)
905 LOAD_FUNCPTR(FT_Done_Face)
906 LOAD_FUNCPTR(FT_Get_Char_Index)
907 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
908 LOAD_FUNCPTR(FT_Init_FreeType)
909 LOAD_FUNCPTR(FT_Load_Glyph)
910 LOAD_FUNCPTR(FT_Matrix_Multiply)
911 LOAD_FUNCPTR(FT_MulFix)
912 LOAD_FUNCPTR(FT_New_Face)
913 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
914 LOAD_FUNCPTR(FT_Outline_Transform)
915 LOAD_FUNCPTR(FT_Outline_Translate)
916 LOAD_FUNCPTR(FT_Select_Charmap)
917 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
918 LOAD_FUNCPTR(FT_Vector_Transform)
920 #undef LOAD_FUNCPTR
921 /* Don't warn if this one is missing */
922 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
923 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
924 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
926 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
927 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
928 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
929 <= 2.0.3 has FT_Sqrt64 */
930 goto sym_not_found;
933 if(pFT_Init_FreeType(&library) != 0) {
934 ERR("Can't init FreeType library\n");
935 wine_dlclose(ft_handle, NULL, 0);
936 ft_handle = NULL;
937 return FALSE;
939 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
940 if (pFT_Library_Version)
942 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
944 if (FT_Version.major<=0)
946 FT_Version.major=2;
947 FT_Version.minor=0;
948 FT_Version.patch=5;
950 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
952 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
953 ERR("Failed to create font mutex\n");
954 return FALSE;
956 WaitForSingleObject(font_mutex, INFINITE);
958 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
959 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
960 strcatW(windowsdir, fontsW);
961 if(wine_get_unix_file_name(windowsdir, unixname, sizeof(unixname)))
962 ReadFontDir(unixname, FALSE);
964 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
965 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
966 full path as the entry */
967 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
968 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
969 &hkey) == ERROR_SUCCESS) {
970 LPWSTR valueW;
971 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
972 &valuelen, &datalen, NULL, NULL);
974 valuelen++; /* returned value doesn't include room for '\0' */
975 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
976 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
977 if (valueW && data)
979 dlen = datalen * sizeof(WCHAR);
980 vlen = valuelen;
981 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
982 &dlen) == ERROR_SUCCESS) {
983 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
984 if(wine_get_unix_file_name((LPWSTR)data, unixname, sizeof(unixname)))
985 AddFontFileToList(unixname, NULL, FALSE);
986 /* reset dlen and vlen */
987 dlen = datalen;
988 vlen = valuelen;
991 if (data) HeapFree(GetProcessHeap(), 0, data);
992 if (valueW) HeapFree(GetProcessHeap(), 0, valueW);
993 RegCloseKey(hkey);
996 load_fontconfig_fonts();
998 /* then look in any directories that we've specified in the config file */
999 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1000 "Software\\Wine\\Wine\\Config\\FontDirs",
1001 &hkey) == ERROR_SUCCESS) {
1002 LPSTR value;
1003 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1004 &valuelen, &datalen, NULL, NULL);
1006 valuelen++; /* returned value doesn't include room for '\0' */
1007 value = HeapAlloc(GetProcessHeap(), 0, valuelen);
1008 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1010 dlen = datalen;
1011 vlen = valuelen;
1012 i = 0;
1013 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1014 &dlen) == ERROR_SUCCESS) {
1015 TRACE("Got %s=%s\n", value, (LPSTR)data);
1016 ReadFontDir((LPSTR)data, TRUE);
1017 /* reset dlen and vlen */
1018 dlen = datalen;
1019 vlen = valuelen;
1021 HeapFree(GetProcessHeap(), 0, data);
1022 HeapFree(GetProcessHeap(), 0, value);
1023 RegCloseKey(hkey);
1026 DumpFontList();
1027 LoadSubstList();
1028 DumpSubstList();
1029 LoadReplaceList();
1030 update_reg_entries();
1032 ReleaseMutex(font_mutex);
1033 return TRUE;
1034 sym_not_found:
1035 WINE_MESSAGE(
1036 "Wine cannot find certain functions that it needs inside the FreeType\n"
1037 "font library. To enable Wine to use TrueType fonts please upgrade\n"
1038 "FreeType to at least version 2.0.5.\n"
1039 "http://www.freetype.org\n");
1040 wine_dlclose(ft_handle, NULL, 0);
1041 ft_handle = NULL;
1042 return FALSE;
1046 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
1048 TT_OS2 *pOS2;
1049 TT_HoriHeader *pHori;
1051 LONG ppem;
1053 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1054 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1056 if(height == 0) height = 16;
1058 /* Calc. height of EM square:
1060 * For +ve lfHeight we have
1061 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
1062 * Re-arranging gives:
1063 * ppem = units_per_em * lfheight / (winAscent + winDescent)
1065 * For -ve lfHeight we have
1066 * |lfHeight| = ppem
1067 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
1068 * with il = winAscent + winDescent - units_per_em]
1072 if(height > 0) {
1073 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
1074 ppem = ft_face->units_per_EM * height /
1075 (pHori->Ascender - pHori->Descender);
1076 else
1077 ppem = ft_face->units_per_EM * height /
1078 (pOS2->usWinAscent + pOS2->usWinDescent);
1080 else
1081 ppem = -height;
1083 return ppem;
1086 static LONG load_VDMX(GdiFont, LONG);
1088 static FT_Face OpenFontFile(GdiFont font, char *file, FT_Long face_index, LONG height)
1090 FT_Error err;
1091 FT_Face ft_face;
1092 LONG ppem;
1094 err = pFT_New_Face(library, file, face_index, &ft_face);
1095 if(err) {
1096 ERR("FT_New_Face rets %d\n", err);
1097 return 0;
1100 /* set it here, as load_VDMX needs it */
1101 font->ft_face = ft_face;
1103 /* load the VDMX table if we have one */
1104 ppem = load_VDMX(font, height);
1105 if(ppem == 0)
1106 ppem = calc_ppem_for_height(ft_face, height);
1108 pFT_Set_Pixel_Sizes(ft_face, 0, ppem);
1110 return ft_face;
1114 static int get_nearest_charset(Face *face)
1116 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
1117 a single face with the requested charset. The idea is to check if
1118 the selected font supports the current ANSI codepage, if it does
1119 return the corresponding charset, else return the first charset */
1121 CHARSETINFO csi;
1122 int acp = GetACP(), i;
1123 DWORD fs0;
1125 if(TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE))
1126 if(csi.fs.fsCsb[0] & face->fs.fsCsb[0])
1127 return csi.ciCharset;
1129 for(i = 0; i < 32; i++) {
1130 fs0 = 1L << i;
1131 if(face->fs.fsCsb[0] & fs0) {
1132 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG))
1133 return csi.ciCharset;
1134 else
1135 FIXME("TCI failing on %lx\n", fs0);
1139 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08lx file = %s\n",
1140 face->fs.fsCsb[0], face->file);
1141 return DEFAULT_CHARSET;
1144 static GdiFont alloc_font(void)
1146 GdiFont ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
1147 ret->gmsize = INIT_GM_SIZE;
1148 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1149 ret->gmsize * sizeof(*ret->gm));
1150 ret->next = NULL;
1151 ret->potm = NULL;
1152 ret->xform.eM11 = ret->xform.eM22 = 1.0;
1153 return ret;
1156 static void free_font(GdiFont font)
1158 if (font->ft_face) pFT_Done_Face(font->ft_face);
1159 if (font->potm) HeapFree(GetProcessHeap(), 0, font->potm);
1160 if (font->name) HeapFree(GetProcessHeap(), 0, font->name);
1161 HeapFree(GetProcessHeap(), 0, font->gm);
1162 HeapFree(GetProcessHeap(), 0, font);
1166 /*************************************************************
1167 * load_VDMX
1169 * load the vdmx entry for the specified height
1172 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
1173 ( ( (FT_ULong)_x4 << 24 ) | \
1174 ( (FT_ULong)_x3 << 16 ) | \
1175 ( (FT_ULong)_x2 << 8 ) | \
1176 (FT_ULong)_x1 )
1178 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
1180 typedef struct {
1181 BYTE bCharSet;
1182 BYTE xRatio;
1183 BYTE yStartRatio;
1184 BYTE yEndRatio;
1185 } Ratios;
1188 static LONG load_VDMX(GdiFont font, LONG height)
1190 BYTE hdr[6], tmp[2], group[4];
1191 BYTE devXRatio, devYRatio;
1192 USHORT numRecs, numRatios;
1193 DWORD offset = -1;
1194 LONG ppem = 0;
1195 int i, result;
1197 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
1199 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
1200 return ppem;
1202 /* FIXME: need the real device aspect ratio */
1203 devXRatio = 1;
1204 devYRatio = 1;
1206 numRecs = GET_BE_WORD(&hdr[2]);
1207 numRatios = GET_BE_WORD(&hdr[4]);
1209 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
1210 for(i = 0; i < numRatios; i++) {
1211 Ratios ratio;
1213 offset = (3 * 2) + (i * sizeof(Ratios));
1214 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
1215 offset = -1;
1217 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
1219 if(ratio.bCharSet != 1)
1220 continue;
1222 if((ratio.xRatio == 0 &&
1223 ratio.yStartRatio == 0 &&
1224 ratio.yEndRatio == 0) ||
1225 (devXRatio == ratio.xRatio &&
1226 devYRatio >= ratio.yStartRatio &&
1227 devYRatio <= ratio.yEndRatio))
1229 offset = (3 * 2) + (numRatios * 4) + (i * 2);
1230 WineEngGetFontData(font, MS_VDMX_TAG, offset, tmp, 2);
1231 offset = GET_BE_WORD(tmp);
1232 break;
1236 if(offset < 0) {
1237 FIXME("No suitable ratio found\n");
1238 return ppem;
1241 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, group, 4) != GDI_ERROR) {
1242 USHORT recs;
1243 BYTE startsz, endsz;
1244 BYTE *vTable;
1246 recs = GET_BE_WORD(group);
1247 startsz = group[2];
1248 endsz = group[3];
1250 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
1252 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
1253 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
1254 if(result == GDI_ERROR) {
1255 FIXME("Failed to retrieve vTable\n");
1256 goto end;
1259 if(height > 0) {
1260 for(i = 0; i < recs; i++) {
1261 SHORT yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1262 SHORT yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1263 ppem = GET_BE_WORD(&vTable[i * 6]);
1265 if(yMax + -yMin == height) {
1266 font->yMax = yMax;
1267 font->yMin = yMin;
1268 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1269 break;
1271 if(yMax + -yMin > height) {
1272 if(--i < 0) {
1273 ppem = 0;
1274 goto end; /* failed */
1276 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1277 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1278 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1279 break;
1282 if(!font->yMax) {
1283 ppem = 0;
1284 TRACE("ppem not found for height %ld\n", height);
1286 } else {
1287 ppem = -height;
1288 if(ppem < startsz || ppem > endsz)
1289 goto end;
1291 for(i = 0; i < recs; i++) {
1292 USHORT yPelHeight;
1293 yPelHeight = GET_BE_WORD(&vTable[i * 6]);
1295 if(yPelHeight > ppem)
1296 break; /* failed */
1298 if(yPelHeight == ppem) {
1299 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1300 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1301 TRACE("ppem %ld found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
1302 break;
1306 end:
1307 HeapFree(GetProcessHeap(), 0, vTable);
1310 return ppem;
1314 /*************************************************************
1315 * WineEngCreateFontInstance
1318 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
1320 GdiFont ret;
1321 Face *face;
1322 Family *family = NULL;
1323 INT height;
1324 BOOL bd, it;
1325 LOGFONTW lf;
1326 CHARSETINFO csi;
1328 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
1330 TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
1331 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
1332 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
1333 lf.lfEscapement);
1335 /* check the cache first */
1336 for(ret = GdiFontList; ret; ret = ret->next) {
1337 if(ret->hfont == hfont && !memcmp(&ret->xform, &dc->xformWorld2Vport, offsetof(XFORM, eDx))) {
1338 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
1339 return ret;
1343 if(!FontList || !have_installed_roman_font) /* No fonts installed */
1345 TRACE("No fonts installed\n");
1346 return NULL;
1349 ret = alloc_font();
1350 memcpy(&ret->xform, &dc->xformWorld2Vport, sizeof(XFORM));
1352 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
1353 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
1354 original value lfCharSet. Note this is a special case for
1355 Symbol and doesn't happen at least for "Wingdings*" */
1357 if(!strcmpiW(lf.lfFaceName, SymbolW))
1358 lf.lfCharSet = SYMBOL_CHARSET;
1360 if(!TranslateCharsetInfo((DWORD*)(INT)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
1361 switch(lf.lfCharSet) {
1362 case DEFAULT_CHARSET:
1363 csi.fs.fsCsb[0] = 0;
1364 break;
1365 default:
1366 FIXME("Untranslated charset %d\n", lf.lfCharSet);
1367 csi.fs.fsCsb[0] = 0;
1368 break;
1372 if(lf.lfFaceName[0] != '\0') {
1373 FontSubst *psub;
1374 for(psub = substlist; psub; psub = psub->next)
1375 if(!strcmpiW(lf.lfFaceName, psub->from.name) &&
1376 (psub->from.charset == -1 ||
1377 psub->from.charset == lf.lfCharSet))
1378 break;
1379 if(psub) {
1380 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
1381 debugstr_w(psub->to.name));
1382 strcpyW(lf.lfFaceName, psub->to.name);
1385 /* We want a match on name and charset or just name if
1386 charset was DEFAULT_CHARSET. If the latter then
1387 we fixup the returned charset later in get_nearest_charset
1388 where we'll either use the charset of the current ansi codepage
1389 or if that's unavailable the first charset that the font supports.
1391 for(family = FontList; family; family = family->next) {
1392 if(!strcmpiW(family->FamilyName, lf.lfFaceName))
1393 if((csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0]) || !csi.fs.fsCsb[0])
1394 break;
1397 if(!family) { /* do other aliases here */
1398 if(!strcmpiW(lf.lfFaceName, SystemW))
1399 strcpyW(lf.lfFaceName, defSystem);
1400 else if(!strcmpiW(lf.lfFaceName, MSSansSerifW))
1401 strcpyW(lf.lfFaceName, defSans);
1402 else if(!strcmpiW(lf.lfFaceName, HelvW))
1403 strcpyW(lf.lfFaceName, defSans);
1404 else
1405 goto not_found;
1407 for(family = FontList; family; family = family->next) {
1408 if(!strcmpiW(family->FamilyName, lf.lfFaceName))
1409 if((csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0]) || !csi.fs.fsCsb[0])
1410 break;
1415 not_found:
1416 if(!family) {
1417 /* If requested charset was DEFAULT_CHARSET then try using charset
1418 corresponding to the current ansi codepage */
1419 if(!csi.fs.fsCsb[0]) {
1420 INT acp = GetACP();
1421 if(!TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE)) {
1422 FIXME("TCI failed on codepage %d\n", acp);
1423 csi.fs.fsCsb[0] = 0;
1424 } else
1425 lf.lfCharSet = csi.ciCharset;
1428 /* Face families are in the top 4 bits of lfPitchAndFamily,
1429 so mask with 0xF0 before testing */
1431 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
1432 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
1433 strcpyW(lf.lfFaceName, defFixed);
1434 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
1435 strcpyW(lf.lfFaceName, defSerif);
1436 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
1437 strcpyW(lf.lfFaceName, defSans);
1438 else
1439 strcpyW(lf.lfFaceName, defSans);
1440 for(family = FontList; family; family = family->next) {
1441 if(!strcmpiW(family->FamilyName, lf.lfFaceName) &&
1442 (csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0]))
1443 break;
1447 if(!family) {
1448 for(family = FontList; family; family = family->next) {
1449 if(csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0])
1450 break;
1454 if(!family) {
1455 family = FontList;
1456 csi.fs.fsCsb[0] = 0;
1457 FIXME("just using first face for now\n");
1460 it = lf.lfItalic ? 1 : 0;
1461 bd = lf.lfWeight > 550 ? 1 : 0;
1463 for(face = family->FirstFace; face; face = face->next) {
1464 if(!(face->Italic ^ it) && !(face->Bold ^ bd))
1465 break;
1467 if(!face) {
1468 face = family->FirstFace;
1469 if(it && !face->Italic) ret->fake_italic = TRUE;
1470 if(bd && !face->Bold) ret->fake_bold = TRUE;
1473 memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
1475 if(csi.fs.fsCsb[0])
1476 ret->charset = lf.lfCharSet;
1477 else
1478 ret->charset = get_nearest_charset(face);
1480 TRACE("Chosen: %s %s\n", debugstr_w(family->FamilyName),
1481 debugstr_w(face->StyleName));
1483 height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
1484 ret->ft_face = OpenFontFile(ret, face->file, face->face_index,
1485 lf.lfHeight < 0 ? -abs(height) : abs(height));
1486 if (!ret->ft_face)
1488 free_font( ret );
1489 return 0;
1492 if (ret->charset == SYMBOL_CHARSET &&
1493 !pFT_Select_Charmap(ret->ft_face, ft_encoding_symbol)) {
1494 /* No ops */
1496 else if (!pFT_Select_Charmap(ret->ft_face, ft_encoding_unicode)) {
1497 /* No ops */
1499 else {
1500 pFT_Select_Charmap(ret->ft_face, ft_encoding_apple_roman);
1503 ret->orientation = lf.lfOrientation;
1504 ret->name = strdupW(family->FamilyName);
1506 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
1507 ret->hfont = hfont;
1508 ret->aveWidth= lf.lfWidth;
1509 ret->next = GdiFontList;
1510 GdiFontList = ret;
1512 return ret;
1515 static void DumpGdiFontList(void)
1517 GdiFont gdiFont;
1519 TRACE("---------- gdiFont Cache ----------\n");
1520 for(gdiFont = GdiFontList; gdiFont; gdiFont = gdiFont->next) {
1521 LOGFONTW lf;
1522 GetObjectW( gdiFont->hfont, sizeof(lf), &lf );
1523 TRACE("gdiFont=%p hfont=%p (%s)\n",
1524 gdiFont, gdiFont->hfont, debugstr_w(lf.lfFaceName));
1528 /*************************************************************
1529 * WineEngDestroyFontInstance
1531 * free the gdiFont associated with this handle
1534 BOOL WineEngDestroyFontInstance(HFONT handle)
1536 GdiFont gdiFont;
1537 GdiFont gdiPrev = NULL;
1538 BOOL ret = FALSE;
1540 TRACE("destroying hfont=%p\n", handle);
1541 if(TRACE_ON(font))
1542 DumpGdiFontList();
1544 gdiFont = GdiFontList;
1545 while(gdiFont) {
1546 if(gdiFont->hfont == handle) {
1547 if(gdiPrev) {
1548 gdiPrev->next = gdiFont->next;
1549 free_font(gdiFont);
1550 gdiFont = gdiPrev->next;
1551 } else {
1552 GdiFontList = gdiFont->next;
1553 free_font(gdiFont);
1554 gdiFont = GdiFontList;
1556 ret = TRUE;
1557 } else {
1558 gdiPrev = gdiFont;
1559 gdiFont = gdiFont->next;
1562 return ret;
1565 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
1566 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
1568 OUTLINETEXTMETRICW *potm;
1569 UINT size;
1570 GdiFont font = alloc_font();
1572 if (!(font->ft_face = OpenFontFile(font, face->file, face->face_index, 100)))
1574 free_font(font);
1575 return;
1578 font->name = strdupW(face->family->FamilyName);
1580 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
1582 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
1583 potm = HeapAlloc(GetProcessHeap(), 0, size);
1584 WineEngGetOutlineTextMetrics(font, size, potm);
1586 #define TM potm->otmTextMetrics
1588 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = TM.tmHeight;
1589 pntm->ntmTm.tmAscent = TM.tmAscent;
1590 pntm->ntmTm.tmDescent = TM.tmDescent;
1591 pntm->ntmTm.tmInternalLeading = TM.tmInternalLeading;
1592 pntm->ntmTm.tmExternalLeading = TM.tmExternalLeading;
1593 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = TM.tmAveCharWidth;
1594 pntm->ntmTm.tmMaxCharWidth = TM.tmMaxCharWidth;
1595 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = TM.tmWeight;
1596 pntm->ntmTm.tmOverhang = TM.tmOverhang;
1597 pntm->ntmTm.tmDigitizedAspectX = TM.tmDigitizedAspectX;
1598 pntm->ntmTm.tmDigitizedAspectY = TM.tmDigitizedAspectY;
1599 pntm->ntmTm.tmFirstChar = TM.tmFirstChar;
1600 pntm->ntmTm.tmLastChar = TM.tmLastChar;
1601 pntm->ntmTm.tmDefaultChar = TM.tmDefaultChar;
1602 pntm->ntmTm.tmBreakChar = TM.tmBreakChar;
1603 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = TM.tmItalic;
1604 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = TM.tmUnderlined;
1605 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = TM.tmStruckOut;
1606 pntm->ntmTm.tmPitchAndFamily = TM.tmPitchAndFamily;
1607 pelf->elfLogFont.lfPitchAndFamily = (TM.tmPitchAndFamily & 0xf1) + 1;
1608 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = TM.tmCharSet;
1609 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
1610 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
1611 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
1613 pntm->ntmTm.ntmFlags = TM.tmItalic ? NTM_ITALIC : 0;
1614 if(TM.tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
1615 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
1617 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
1618 pntm->ntmTm.ntmCellHeight = 0;
1619 pntm->ntmTm.ntmAvgWidth = 0;
1621 *ptype = TM.tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
1622 if(!(TM.tmPitchAndFamily & TMPF_VECTOR))
1623 *ptype |= RASTER_FONTTYPE;
1625 #undef TM
1626 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
1628 strncpyW(pelf->elfLogFont.lfFaceName,
1629 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
1630 LF_FACESIZE);
1631 strncpyW(pelf->elfFullName,
1632 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
1633 LF_FULLFACESIZE);
1634 strncpyW(pelf->elfStyle,
1635 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
1636 LF_FACESIZE);
1637 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
1639 HeapFree(GetProcessHeap(), 0, potm);
1640 free_font(font);
1641 return;
1644 /*************************************************************
1645 * WineEngEnumFonts
1648 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
1650 Family *family;
1651 Face *face;
1652 ENUMLOGFONTEXW elf;
1653 NEWTEXTMETRICEXW ntm;
1654 DWORD type, ret = 1;
1655 FONTSIGNATURE fs;
1656 CHARSETINFO csi;
1657 LOGFONTW lf;
1658 int i;
1660 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
1662 if(plf->lfFaceName[0]) {
1663 FontSubst *psub;
1664 for(psub = substlist; psub; psub = psub->next)
1665 if(!strcmpiW(plf->lfFaceName, psub->from.name) &&
1666 (psub->from.charset == -1 ||
1667 psub->from.charset == plf->lfCharSet))
1668 break;
1669 if(psub) {
1670 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
1671 debugstr_w(psub->to.name));
1672 memcpy(&lf, plf, sizeof(lf));
1673 strcpyW(lf.lfFaceName, psub->to.name);
1674 plf = &lf;
1676 for(family = FontList; family; family = family->next) {
1677 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
1678 for(face = family->FirstFace; face; face = face->next) {
1679 GetEnumStructs(face, &elf, &ntm, &type);
1680 for(i = 0; i < 32; i++) {
1681 if(face->fs.fsCsb[0] & (1L << i)) {
1682 fs.fsCsb[0] = 1L << i;
1683 fs.fsCsb[1] = 0;
1684 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
1685 TCI_SRCFONTSIG))
1686 csi.ciCharset = DEFAULT_CHARSET;
1687 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
1688 if(csi.ciCharset != DEFAULT_CHARSET) {
1689 elf.elfLogFont.lfCharSet =
1690 ntm.ntmTm.tmCharSet = csi.ciCharset;
1691 if(ElfScriptsW[i])
1692 strcpyW(elf.elfScript, ElfScriptsW[i]);
1693 else
1694 FIXME("Unknown elfscript for bit %d\n", i);
1695 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
1696 debugstr_w(elf.elfLogFont.lfFaceName),
1697 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
1698 csi.ciCharset, type, debugstr_w(elf.elfScript),
1699 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
1700 ntm.ntmTm.ntmFlags);
1701 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
1702 if(!ret) goto end;
1709 } else {
1710 for(family = FontList; family; family = family->next) {
1711 GetEnumStructs(family->FirstFace, &elf, &ntm, &type);
1712 for(i = 0; i < 32; i++) {
1713 if(family->FirstFace->fs.fsCsb[0] & (1L << i)) {
1714 fs.fsCsb[0] = 1L << i;
1715 fs.fsCsb[1] = 0;
1716 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
1717 TCI_SRCFONTSIG))
1718 csi.ciCharset = DEFAULT_CHARSET;
1719 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
1720 if(csi.ciCharset != DEFAULT_CHARSET) {
1721 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
1722 csi.ciCharset;
1723 if(ElfScriptsW[i])
1724 strcpyW(elf.elfScript, ElfScriptsW[i]);
1725 else
1726 FIXME("Unknown elfscript for bit %d\n", i);
1727 TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
1728 debugstr_w(elf.elfLogFont.lfFaceName),
1729 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
1730 csi.ciCharset, type, debugstr_w(elf.elfScript),
1731 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
1732 ntm.ntmTm.ntmFlags);
1733 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
1734 if(!ret) goto end;
1740 end:
1741 return ret;
1744 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
1746 pt->x.value = vec->x >> 6;
1747 pt->x.fract = (vec->x & 0x3f) << 10;
1748 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
1749 pt->y.value = vec->y >> 6;
1750 pt->y.fract = (vec->y & 0x3f) << 10;
1751 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
1752 return;
1755 static FT_UInt get_glyph_index(GdiFont font, UINT glyph)
1757 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
1758 glyph = glyph + 0xf000;
1759 return pFT_Get_Char_Index(font->ft_face, glyph);
1762 /*************************************************************
1763 * WineEngGetGlyphIndices
1765 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
1767 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
1768 LPWORD pgi, DWORD flags)
1770 INT i;
1772 for(i = 0; i < count; i++)
1773 pgi[i] = get_glyph_index(font, lpstr[i]);
1775 return count;
1778 /*************************************************************
1779 * WineEngGetGlyphOutline
1781 * Behaves in exactly the same way as the win32 api GetGlyphOutline
1782 * except that the first parameter is the HWINEENGFONT of the font in
1783 * question rather than an HDC.
1786 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
1787 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
1788 const MAT2* lpmat)
1790 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
1791 FT_Face ft_face = font->ft_face;
1792 FT_UInt glyph_index;
1793 DWORD width, height, pitch, needed = 0;
1794 FT_Bitmap ft_bitmap;
1795 FT_Error err;
1796 INT left, right, top = 0, bottom = 0;
1797 FT_Angle angle = 0;
1798 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
1799 float widthRatio = 1.0;
1800 FT_Matrix transMat = identityMat;
1801 BOOL needsTransform = FALSE;
1804 TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font, glyph, format, lpgm,
1805 buflen, buf, lpmat);
1807 if(format & GGO_GLYPH_INDEX) {
1808 glyph_index = glyph;
1809 format &= ~GGO_GLYPH_INDEX;
1810 } else
1811 glyph_index = get_glyph_index(font, glyph);
1813 if(glyph_index >= font->gmsize) {
1814 font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
1815 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
1816 font->gmsize * sizeof(*font->gm));
1817 } else {
1818 if(format == GGO_METRICS && font->gm[glyph_index].init) {
1819 memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
1820 return 1; /* FIXME */
1824 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP) || font->aveWidth || lpmat)
1825 load_flags |= FT_LOAD_NO_BITMAP;
1827 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
1829 if(err) {
1830 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
1831 return GDI_ERROR;
1834 /* Scaling factor */
1835 if (font->aveWidth && font->potm) {
1836 widthRatio = (float)font->aveWidth * font->xform.eM11 / (float) font->potm->otmTextMetrics.tmAveCharWidth;
1839 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
1840 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
1842 font->gm[glyph_index].adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
1843 font->gm[glyph_index].lsb = left >> 6;
1844 font->gm[glyph_index].bbx = (right - left) >> 6;
1846 /* Scaling transform */
1847 if(font->aveWidth) {
1848 FT_Matrix scaleMat;
1849 scaleMat.xx = FT_FixedFromFloat(widthRatio);
1850 scaleMat.xy = 0;
1851 scaleMat.yx = 0;
1852 scaleMat.yy = (1 << 16);
1854 pFT_Matrix_Multiply(&scaleMat, &transMat);
1855 needsTransform = TRUE;
1858 /* Rotation transform */
1859 if(font->orientation) {
1860 FT_Matrix rotationMat;
1861 FT_Vector vecAngle;
1862 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
1863 pFT_Vector_Unit(&vecAngle, angle);
1864 rotationMat.xx = vecAngle.x;
1865 rotationMat.xy = -vecAngle.y;
1866 rotationMat.yx = -rotationMat.xy;
1867 rotationMat.yy = rotationMat.xx;
1869 pFT_Matrix_Multiply(&rotationMat, &transMat);
1870 needsTransform = TRUE;
1873 /* Extra transformation specified by caller */
1874 if (lpmat) {
1875 FT_Matrix extraMat;
1876 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
1877 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
1878 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
1879 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
1880 pFT_Matrix_Multiply(&extraMat, &transMat);
1881 needsTransform = TRUE;
1884 if(!needsTransform) {
1885 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
1886 bottom = (ft_face->glyph->metrics.horiBearingY -
1887 ft_face->glyph->metrics.height) & -64;
1888 lpgm->gmCellIncX = font->gm[glyph_index].adv;
1889 lpgm->gmCellIncY = 0;
1890 } else {
1891 INT xc, yc;
1892 FT_Vector vec;
1893 for(xc = 0; xc < 2; xc++) {
1894 for(yc = 0; yc < 2; yc++) {
1895 vec.x = (ft_face->glyph->metrics.horiBearingX +
1896 xc * ft_face->glyph->metrics.width);
1897 vec.y = ft_face->glyph->metrics.horiBearingY -
1898 yc * ft_face->glyph->metrics.height;
1899 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
1900 pFT_Vector_Transform(&vec, &transMat);
1901 if(xc == 0 && yc == 0) {
1902 left = right = vec.x;
1903 top = bottom = vec.y;
1904 } else {
1905 if(vec.x < left) left = vec.x;
1906 else if(vec.x > right) right = vec.x;
1907 if(vec.y < bottom) bottom = vec.y;
1908 else if(vec.y > top) top = vec.y;
1912 left = left & -64;
1913 right = (right + 63) & -64;
1914 bottom = bottom & -64;
1915 top = (top + 63) & -64;
1917 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
1918 vec.x = ft_face->glyph->metrics.horiAdvance;
1919 vec.y = 0;
1920 pFT_Vector_Transform(&vec, &transMat);
1921 lpgm->gmCellIncX = (vec.x+63) >> 6;
1922 lpgm->gmCellIncY = -((vec.y+63) >> 6);
1924 lpgm->gmBlackBoxX = (right - left) >> 6;
1925 lpgm->gmBlackBoxY = (top - bottom) >> 6;
1926 lpgm->gmptGlyphOrigin.x = left >> 6;
1927 lpgm->gmptGlyphOrigin.y = top >> 6;
1929 memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
1930 font->gm[glyph_index].init = TRUE;
1932 if(format == GGO_METRICS)
1933 return 1; /* FIXME */
1935 if (buf && !buflen){
1936 return GDI_ERROR;
1939 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP) {
1940 FIXME("loaded a bitmap\n");
1941 return GDI_ERROR;
1944 switch(format) {
1945 case GGO_BITMAP:
1946 width = lpgm->gmBlackBoxX;
1947 height = lpgm->gmBlackBoxY;
1948 pitch = ((width + 31) >> 5) << 2;
1949 needed = pitch * height;
1951 if(!buf || !buflen) break;
1953 switch(ft_face->glyph->format) {
1954 case ft_glyph_format_bitmap:
1956 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
1957 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
1958 INT h = ft_face->glyph->bitmap.rows;
1959 while(h--) {
1960 memcpy(dst, src, w);
1961 src += ft_face->glyph->bitmap.pitch;
1962 dst += pitch;
1964 break;
1967 case ft_glyph_format_outline:
1968 ft_bitmap.width = width;
1969 ft_bitmap.rows = height;
1970 ft_bitmap.pitch = pitch;
1971 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
1972 ft_bitmap.buffer = buf;
1974 if(needsTransform) {
1975 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
1978 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
1980 /* Note: FreeType will only set 'black' bits for us. */
1981 memset(buf, 0, needed);
1982 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
1983 break;
1985 default:
1986 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
1987 return GDI_ERROR;
1989 break;
1991 case GGO_GRAY2_BITMAP:
1992 case GGO_GRAY4_BITMAP:
1993 case GGO_GRAY8_BITMAP:
1994 case WINE_GGO_GRAY16_BITMAP:
1996 int mult, row, col;
1997 BYTE *start, *ptr;
1999 width = lpgm->gmBlackBoxX;
2000 height = lpgm->gmBlackBoxY;
2001 pitch = (width + 3) / 4 * 4;
2002 needed = pitch * height;
2004 if(!buf || !buflen) break;
2005 ft_bitmap.width = width;
2006 ft_bitmap.rows = height;
2007 ft_bitmap.pitch = pitch;
2008 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
2009 ft_bitmap.buffer = buf;
2011 if(needsTransform) {
2012 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
2015 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
2017 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
2019 if(format == GGO_GRAY2_BITMAP)
2020 mult = 5;
2021 else if(format == GGO_GRAY4_BITMAP)
2022 mult = 17;
2023 else if(format == GGO_GRAY8_BITMAP)
2024 mult = 65;
2025 else if(format == WINE_GGO_GRAY16_BITMAP)
2026 break;
2027 else {
2028 assert(0);
2029 break;
2032 start = buf;
2033 for(row = 0; row < height; row++) {
2034 ptr = start;
2035 for(col = 0; col < width; col++, ptr++) {
2036 *ptr = (*(unsigned int*)ptr * mult + 128) / 256;
2038 start += pitch;
2040 break;
2043 case GGO_NATIVE:
2045 int contour, point = 0, first_pt;
2046 FT_Outline *outline = &ft_face->glyph->outline;
2047 TTPOLYGONHEADER *pph;
2048 TTPOLYCURVE *ppc;
2049 DWORD pph_start, cpfx, type;
2051 if(buflen == 0) buf = NULL;
2053 if (needsTransform && buf) {
2054 pFT_Outline_Transform(outline, &transMat);
2057 for(contour = 0; contour < outline->n_contours; contour++) {
2058 pph_start = needed;
2059 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
2060 first_pt = point;
2061 if(buf) {
2062 pph->dwType = TT_POLYGON_TYPE;
2063 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2065 needed += sizeof(*pph);
2066 point++;
2067 while(point <= outline->contours[contour]) {
2068 ppc = (TTPOLYCURVE *)((char *)buf + needed);
2069 type = (outline->tags[point] & FT_Curve_Tag_On) ?
2070 TT_PRIM_LINE : TT_PRIM_QSPLINE;
2071 cpfx = 0;
2072 do {
2073 if(buf)
2074 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2075 cpfx++;
2076 point++;
2077 } while(point <= outline->contours[contour] &&
2078 (outline->tags[point] & FT_Curve_Tag_On) ==
2079 (outline->tags[point-1] & FT_Curve_Tag_On));
2080 /* At the end of a contour Windows adds the start point, but
2081 only for Beziers */
2082 if(point > outline->contours[contour] &&
2083 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
2084 if(buf)
2085 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
2086 cpfx++;
2087 } else if(point <= outline->contours[contour] &&
2088 outline->tags[point] & FT_Curve_Tag_On) {
2089 /* add closing pt for bezier */
2090 if(buf)
2091 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2092 cpfx++;
2093 point++;
2095 if(buf) {
2096 ppc->wType = type;
2097 ppc->cpfx = cpfx;
2099 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2101 if(buf)
2102 pph->cb = needed - pph_start;
2104 break;
2106 case GGO_BEZIER:
2108 /* Convert the quadratic Beziers to cubic Beziers.
2109 The parametric eqn for a cubic Bezier is, from PLRM:
2110 r(t) = at^3 + bt^2 + ct + r0
2111 with the control points:
2112 r1 = r0 + c/3
2113 r2 = r1 + (c + b)/3
2114 r3 = r0 + c + b + a
2116 A quadratic Beizer has the form:
2117 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
2119 So equating powers of t leads to:
2120 r1 = 2/3 p1 + 1/3 p0
2121 r2 = 2/3 p1 + 1/3 p2
2122 and of course r0 = p0, r3 = p2
2125 int contour, point = 0, first_pt;
2126 FT_Outline *outline = &ft_face->glyph->outline;
2127 TTPOLYGONHEADER *pph;
2128 TTPOLYCURVE *ppc;
2129 DWORD pph_start, cpfx, type;
2130 FT_Vector cubic_control[4];
2131 if(buflen == 0) buf = NULL;
2133 if (needsTransform && buf) {
2134 pFT_Outline_Transform(outline, &transMat);
2137 for(contour = 0; contour < outline->n_contours; contour++) {
2138 pph_start = needed;
2139 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
2140 first_pt = point;
2141 if(buf) {
2142 pph->dwType = TT_POLYGON_TYPE;
2143 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2145 needed += sizeof(*pph);
2146 point++;
2147 while(point <= outline->contours[contour]) {
2148 ppc = (TTPOLYCURVE *)((char *)buf + needed);
2149 type = (outline->tags[point] & FT_Curve_Tag_On) ?
2150 TT_PRIM_LINE : TT_PRIM_CSPLINE;
2151 cpfx = 0;
2152 do {
2153 if(type == TT_PRIM_LINE) {
2154 if(buf)
2155 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2156 cpfx++;
2157 point++;
2158 } else {
2159 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
2160 so cpfx = 3n */
2162 /* FIXME: Possible optimization in endpoint calculation
2163 if there are two consecutive curves */
2164 cubic_control[0] = outline->points[point-1];
2165 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
2166 cubic_control[0].x += outline->points[point].x + 1;
2167 cubic_control[0].y += outline->points[point].y + 1;
2168 cubic_control[0].x >>= 1;
2169 cubic_control[0].y >>= 1;
2171 if(point+1 > outline->contours[contour])
2172 cubic_control[3] = outline->points[first_pt];
2173 else {
2174 cubic_control[3] = outline->points[point+1];
2175 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
2176 cubic_control[3].x += outline->points[point].x + 1;
2177 cubic_control[3].y += outline->points[point].y + 1;
2178 cubic_control[3].x >>= 1;
2179 cubic_control[3].y >>= 1;
2182 /* r1 = 1/3 p0 + 2/3 p1
2183 r2 = 1/3 p2 + 2/3 p1 */
2184 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
2185 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
2186 cubic_control[2] = cubic_control[1];
2187 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
2188 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
2189 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
2190 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
2191 if(buf) {
2192 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
2193 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
2194 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
2196 cpfx += 3;
2197 point++;
2199 } while(point <= outline->contours[contour] &&
2200 (outline->tags[point] & FT_Curve_Tag_On) ==
2201 (outline->tags[point-1] & FT_Curve_Tag_On));
2202 /* At the end of a contour Windows adds the start point,
2203 but only for Beziers and we've already done that.
2205 if(point <= outline->contours[contour] &&
2206 outline->tags[point] & FT_Curve_Tag_On) {
2207 /* This is the closing pt of a bezier, but we've already
2208 added it, so just inc point and carry on */
2209 point++;
2211 if(buf) {
2212 ppc->wType = type;
2213 ppc->cpfx = cpfx;
2215 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2217 if(buf)
2218 pph->cb = needed - pph_start;
2220 break;
2223 default:
2224 FIXME("Unsupported format %d\n", format);
2225 return GDI_ERROR;
2227 return needed;
2230 /*************************************************************
2231 * WineEngGetTextMetrics
2234 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
2236 if(!font->potm) {
2237 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
2238 return FALSE;
2240 if(!font->potm) return FALSE;
2241 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
2243 if (font->aveWidth) {
2244 ptm->tmAveCharWidth = font->aveWidth * font->xform.eM11;
2246 return TRUE;
2250 /*************************************************************
2251 * WineEngGetOutlineTextMetrics
2254 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
2255 OUTLINETEXTMETRICW *potm)
2257 FT_Face ft_face = font->ft_face;
2258 UINT needed, lenfam, lensty, ret;
2259 TT_OS2 *pOS2;
2260 TT_HoriHeader *pHori;
2261 TT_Postscript *pPost;
2262 FT_Fixed x_scale, y_scale;
2263 WCHAR *family_nameW, *style_nameW;
2264 WCHAR spaceW[] = {' ', '\0'};
2265 char *cp;
2266 INT ascent, descent;
2268 TRACE("font=%p\n", font);
2270 if(font->potm) {
2271 if(cbSize >= font->potm->otmSize)
2272 memcpy(potm, font->potm, font->potm->otmSize);
2273 return font->potm->otmSize;
2276 needed = sizeof(*potm);
2278 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
2279 family_nameW = strdupW(font->name);
2281 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
2282 * sizeof(WCHAR);
2283 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
2284 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
2285 style_nameW, lensty);
2287 /* These names should be read from the TT name table */
2289 /* length of otmpFamilyName */
2290 needed += lenfam;
2292 /* length of otmpFaceName */
2293 if(!strcasecmp(ft_face->style_name, "regular")) {
2294 needed += lenfam; /* just the family name */
2295 } else {
2296 needed += lenfam + lensty; /* family + " " + style */
2299 /* length of otmpStyleName */
2300 needed += lensty;
2302 /* length of otmpFullName */
2303 needed += lenfam + lensty;
2306 x_scale = ft_face->size->metrics.x_scale;
2307 y_scale = ft_face->size->metrics.y_scale;
2309 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2310 if(!pOS2) {
2311 FIXME("Can't find OS/2 table - not TT font?\n");
2312 ret = 0;
2313 goto end;
2316 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2317 if(!pHori) {
2318 FIXME("Can't find HHEA table - not TT font?\n");
2319 ret = 0;
2320 goto end;
2323 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
2325 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",
2326 pOS2->usWinAscent, pOS2->usWinDescent,
2327 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
2328 ft_face->ascender, ft_face->descender, ft_face->height,
2329 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
2330 ft_face->bbox.yMax, ft_face->bbox.yMin);
2332 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
2333 font->potm->otmSize = needed;
2335 #define TM font->potm->otmTextMetrics
2337 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
2338 ascent = pHori->Ascender;
2339 descent = -pHori->Descender;
2340 } else {
2341 ascent = pOS2->usWinAscent;
2342 descent = pOS2->usWinDescent;
2345 if(font->yMax) {
2346 TM.tmAscent = font->yMax;
2347 TM.tmDescent = -font->yMin;
2348 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
2349 } else {
2350 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
2351 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
2352 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
2353 - ft_face->units_per_EM, y_scale) + 32) >> 6;
2356 TM.tmHeight = TM.tmAscent + TM.tmDescent;
2358 /* MSDN says:
2359 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
2361 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
2362 ((ascent + descent) -
2363 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
2365 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
2366 if (TM.tmAveCharWidth == 0) {
2367 TM.tmAveCharWidth = 1;
2369 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
2370 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
2371 TM.tmOverhang = 0;
2372 TM.tmDigitizedAspectX = 300;
2373 TM.tmDigitizedAspectY = 300;
2374 TM.tmFirstChar = pOS2->usFirstCharIndex;
2375 TM.tmLastChar = pOS2->usLastCharIndex;
2376 TM.tmDefaultChar = pOS2->usDefaultChar;
2377 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
2378 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
2379 TM.tmUnderlined = 0; /* entry in OS2 table */
2380 TM.tmStruckOut = 0; /* entry in OS2 table */
2382 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
2383 if(!FT_IS_FIXED_WIDTH(ft_face))
2384 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
2385 else
2386 TM.tmPitchAndFamily = 0;
2388 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
2389 case PAN_FAMILY_SCRIPT:
2390 TM.tmPitchAndFamily |= FF_SCRIPT;
2391 break;
2392 case PAN_FAMILY_DECORATIVE:
2393 case PAN_FAMILY_PICTORIAL:
2394 TM.tmPitchAndFamily |= FF_DECORATIVE;
2395 break;
2396 case PAN_FAMILY_TEXT_DISPLAY:
2397 if(TM.tmPitchAndFamily == 0) /* fixed */
2398 TM.tmPitchAndFamily = FF_MODERN;
2399 else {
2400 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
2401 case PAN_SERIF_NORMAL_SANS:
2402 case PAN_SERIF_OBTUSE_SANS:
2403 case PAN_SERIF_PERP_SANS:
2404 TM.tmPitchAndFamily |= FF_SWISS;
2405 break;
2406 default:
2407 TM.tmPitchAndFamily |= FF_ROMAN;
2410 break;
2411 default:
2412 TM.tmPitchAndFamily |= FF_DONTCARE;
2415 if(FT_IS_SCALABLE(ft_face))
2416 TM.tmPitchAndFamily |= TMPF_VECTOR;
2417 if(FT_IS_SFNT(ft_face))
2418 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
2420 TM.tmCharSet = font->charset;
2421 #undef TM
2423 font->potm->otmFiller = 0;
2424 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
2425 font->potm->otmfsSelection = pOS2->fsSelection;
2426 font->potm->otmfsType = pOS2->fsType;
2427 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
2428 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
2429 font->potm->otmItalicAngle = 0; /* POST table */
2430 font->potm->otmEMSquare = ft_face->units_per_EM;
2431 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
2432 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
2433 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
2434 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
2435 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
2436 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
2437 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
2438 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
2439 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
2440 font->potm->otmMacAscent = 0; /* where do these come from ? */
2441 font->potm->otmMacDescent = 0;
2442 font->potm->otmMacLineGap = 0;
2443 font->potm->otmusMinimumPPEM = 0; /* TT Header */
2444 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
2445 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
2446 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
2447 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
2448 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
2449 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
2450 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
2451 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
2452 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
2453 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
2454 if(!pPost) {
2455 font->potm->otmsUnderscoreSize = 0;
2456 font->potm->otmsUnderscorePosition = 0;
2457 } else {
2458 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
2459 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
2462 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
2463 cp = (char*)font->potm + sizeof(*font->potm);
2464 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
2465 strcpyW((WCHAR*)cp, family_nameW);
2466 cp += lenfam;
2467 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
2468 strcpyW((WCHAR*)cp, style_nameW);
2469 cp += lensty;
2470 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
2471 strcpyW((WCHAR*)cp, family_nameW);
2472 if(strcasecmp(ft_face->style_name, "regular")) {
2473 strcatW((WCHAR*)cp, spaceW);
2474 strcatW((WCHAR*)cp, style_nameW);
2475 cp += lenfam + lensty;
2476 } else
2477 cp += lenfam;
2478 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
2479 strcpyW((WCHAR*)cp, family_nameW);
2480 strcatW((WCHAR*)cp, spaceW);
2481 strcatW((WCHAR*)cp, style_nameW);
2482 ret = needed;
2484 if(potm && needed <= cbSize)
2485 memcpy(potm, font->potm, font->potm->otmSize);
2487 end:
2488 HeapFree(GetProcessHeap(), 0, style_nameW);
2489 HeapFree(GetProcessHeap(), 0, family_nameW);
2491 return ret;
2495 /*************************************************************
2496 * WineEngGetCharWidth
2499 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
2500 LPINT buffer)
2502 UINT c;
2503 GLYPHMETRICS gm;
2504 FT_UInt glyph_index;
2506 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
2508 for(c = firstChar; c <= lastChar; c++) {
2509 glyph_index = get_glyph_index(font, c);
2510 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
2511 &gm, 0, NULL, NULL);
2512 buffer[c - firstChar] = font->gm[glyph_index].adv;
2514 return TRUE;
2517 /*************************************************************
2518 * WineEngGetCharABCWidths
2521 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
2522 LPABC buffer)
2524 UINT c;
2525 GLYPHMETRICS gm;
2526 FT_UInt glyph_index;
2528 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
2530 for(c = firstChar; c <= lastChar; c++) {
2531 glyph_index = get_glyph_index(font, c);
2532 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
2533 &gm, 0, NULL, NULL);
2534 buffer[c - firstChar].abcA = font->gm[glyph_index].lsb;
2535 buffer[c - firstChar].abcB = font->gm[glyph_index].bbx;
2536 buffer[c - firstChar].abcC = font->gm[glyph_index].adv - font->gm[glyph_index].lsb -
2537 font->gm[glyph_index].bbx;
2539 return TRUE;
2542 /*************************************************************
2543 * WineEngGetTextExtentPoint
2546 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
2547 LPSIZE size)
2549 INT idx;
2550 GLYPHMETRICS gm;
2551 TEXTMETRICW tm;
2552 FT_UInt glyph_index;
2554 TRACE("%p, %s, %d, %p\n", font, debugstr_wn(wstr, count), count,
2555 size);
2557 size->cx = 0;
2558 WineEngGetTextMetrics(font, &tm);
2559 size->cy = tm.tmHeight;
2561 for(idx = 0; idx < count; idx++) {
2562 glyph_index = get_glyph_index(font, wstr[idx]);
2563 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
2564 &gm, 0, NULL, NULL);
2565 size->cx += font->gm[glyph_index].adv;
2567 TRACE("return %ld,%ld\n", size->cx, size->cy);
2568 return TRUE;
2571 /*************************************************************
2572 * WineEngGetTextExtentPointI
2575 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
2576 LPSIZE size)
2578 INT idx;
2579 GLYPHMETRICS gm;
2580 TEXTMETRICW tm;
2582 TRACE("%p, %p, %d, %p\n", font, indices, count, size);
2584 size->cx = 0;
2585 WineEngGetTextMetrics(font, &tm);
2586 size->cy = tm.tmHeight;
2588 for(idx = 0; idx < count; idx++) {
2589 WineEngGetGlyphOutline(font, indices[idx],
2590 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
2591 NULL);
2592 size->cx += font->gm[indices[idx]].adv;
2594 TRACE("return %ld,%ld\n", size->cx, size->cy);
2595 return TRUE;
2598 /*************************************************************
2599 * WineEngGetFontData
2602 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
2603 DWORD cbData)
2605 FT_Face ft_face = font->ft_face;
2606 DWORD len;
2607 FT_Error err;
2609 TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
2610 font, table, offset, buf, cbData);
2612 if(!FT_IS_SFNT(ft_face))
2613 return GDI_ERROR;
2615 if(!buf || !cbData)
2616 len = 0;
2617 else
2618 len = cbData;
2620 if(table) { /* MS tags differ in endidness from FT ones */
2621 table = table >> 24 | table << 24 |
2622 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
2625 /* If the FT_Load_Sfnt_Table function is there we'll use it */
2626 if(pFT_Load_Sfnt_Table)
2627 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
2628 else { /* Do it the hard way */
2629 TT_Face tt_face = (TT_Face) ft_face;
2630 SFNT_Interface *sfnt;
2631 if (FT_Version.major==2 && FT_Version.minor==0)
2633 /* 2.0.x */
2634 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
2636 else
2638 /* A field was added in the middle of the structure in 2.1.x */
2639 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
2641 err = sfnt->load_any(tt_face, table, offset, buf, &len);
2643 if(err) {
2644 TRACE("Can't find table %08lx.\n", table);
2645 return GDI_ERROR;
2647 return len;
2650 /*************************************************************
2651 * WineEngGetTextFace
2654 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
2656 if(str) {
2657 lstrcpynW(str, font->name, count);
2658 return strlenW(font->name);
2659 } else
2660 return strlenW(font->name) + 1;
2663 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
2665 if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
2666 return font->charset;
2669 #else /* HAVE_FREETYPE */
2671 BOOL WineEngInit(void)
2673 return FALSE;
2675 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
2677 return NULL;
2679 BOOL WineEngDestroyFontInstance(HFONT hfont)
2681 return FALSE;
2684 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
2686 return 1;
2689 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
2690 LPWORD pgi, DWORD flags)
2692 return GDI_ERROR;
2695 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
2696 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
2697 const MAT2* lpmat)
2699 ERR("called but we don't have FreeType\n");
2700 return GDI_ERROR;
2703 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
2705 ERR("called but we don't have FreeType\n");
2706 return FALSE;
2709 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
2710 OUTLINETEXTMETRICW *potm)
2712 ERR("called but we don't have FreeType\n");
2713 return 0;
2716 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
2717 LPINT buffer)
2719 ERR("called but we don't have FreeType\n");
2720 return FALSE;
2723 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
2724 LPABC buffer)
2726 ERR("called but we don't have FreeType\n");
2727 return FALSE;
2730 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
2731 LPSIZE size)
2733 ERR("called but we don't have FreeType\n");
2734 return FALSE;
2737 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
2738 LPSIZE size)
2740 ERR("called but we don't have FreeType\n");
2741 return FALSE;
2744 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
2745 DWORD cbData)
2747 ERR("called but we don't have FreeType\n");
2748 return GDI_ERROR;
2751 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
2753 ERR("called but we don't have FreeType\n");
2754 return 0;
2757 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2759 FIXME(":stub\n");
2760 return 1;
2763 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2765 FIXME(":stub\n");
2766 return TRUE;
2769 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
2771 FIXME(":stub\n");
2772 return DEFAULT_CHARSET;
2775 #endif /* HAVE_FREETYPE */