2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
6 * This file contains the WineEng* functions.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "wine/port.h"
40 #include "gdi_private.h"
41 #include "wine/unicode.h"
42 #include "wine/debug.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(font);
48 #ifdef HAVE_FT2BUILD_H
51 #ifdef HAVE_FREETYPE_FREETYPE_H
52 #include <freetype/freetype.h>
54 #ifdef HAVE_FREETYPE_FTGLYPH_H
55 #include <freetype/ftglyph.h>
57 #ifdef HAVE_FREETYPE_TTTABLES_H
58 #include <freetype/tttables.h>
60 #ifdef HAVE_FREETYPE_FTSNAMES_H
61 #include <freetype/ftsnames.h>
63 # ifdef HAVE_FREETYPE_FTNAMES_H
64 # include <freetype/ftnames.h>
67 #ifdef HAVE_FREETYPE_TTNAMEID_H
68 #include <freetype/ttnameid.h>
70 #ifdef HAVE_FREETYPE_FTOUTLN_H
71 #include <freetype/ftoutln.h>
73 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
74 #include <freetype/internal/sfnt.h>
76 #ifdef HAVE_FREETYPE_FTTRIGON_H
77 #include <freetype/fttrigon.h>
80 #ifndef SONAME_LIBFREETYPE
81 #define SONAME_LIBFREETYPE "libfreetype.so"
84 static FT_Library library = 0;
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"
135 #define GET_BE_WORD(ptr) MAKEWORD( ((BYTE *)(ptr))[1], ((BYTE *)(ptr))[0] )
137 typedef struct tagFace {
144 FT_Fixed font_version;
145 struct tagFace *next;
146 struct tagFamily *family;
149 typedef struct tagFamily {
152 struct tagFamily *next;
157 INT adv; /* These three hold to widths of the unrotated chars */
177 OUTLINETEXTMETRICW *potm;
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 */
227 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
235 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
244 typedef struct tagFontSubst {
247 struct tagFontSubst *next;
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)
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)
279 WCHAR *FamilyW, *StyleW;
281 Family *family = FontList;
282 Family **insert = &FontList;
283 Face **insertface, *next;
285 FT_Long face_index = 0, num_faces;
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);
297 if(!FT_IS_SFNT(ft_face)) { /* for now we'll skip everything but TT/OT */
298 pFT_Done_Face(ft_face);
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);
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);
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);
324 if(!strcmpW(family->FamilyName, FamilyW))
326 insert = &family->next;
327 family = family->next;
330 family = *insert = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
331 family->FamilyName = FamilyW;
332 family->FirstFace = NULL;
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);
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);
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);
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);
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);
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);
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;
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) {
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;
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;
419 case ft_encoding_symbol:
420 (*insertface)->fs.fsCsb[0] |= 1L << 31;
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),
435 } while(num_faces > ++face_index);
439 static void DumpFontList(void)
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));
453 static void DumpSubstList(void)
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);
462 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
463 debugstr_w(psub->to.name));
467 static LPWSTR strdupW(LPWSTR p)
470 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
471 ret = HeapAlloc(GetProcessHeap(), 0, len);
476 static void split_subst_info(NameCs *nc, LPSTR str)
478 CHAR *p = strrchr(str, ',');
483 nc->charset = strtol(p+1, NULL, 10);
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;
495 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
500 for(psub = substlist; psub;) {
502 HeapFree(GetProcessHeap(), 0, psub->to.name);
503 HeapFree(GetProcessHeap(), 0, psub->from.name);
506 HeapFree(GetProcessHeap(), 0, ptmp);
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);
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);
543 ppsub = &((*ppsub)->next);
545 /* reset dlen and vlen */
549 HeapFree(GetProcessHeap(), 0, data);
550 HeapFree(GetProcessHeap(), 0, value);
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)
570 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
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);
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)))
597 /* Find the old family and hence all of the font files
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);
610 /* reset dlen and vlen */
614 HeapFree(GetProcessHeap(), 0, data);
615 HeapFree(GetProcessHeap(), 0, value);
621 static BOOL ReadFontDir(const char *dirname)
627 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
629 dir = opendir(dirname);
631 ERR("Can't open directory %s\n", debugstr_a(dirname));
634 while((dent = readdir(dir)) != NULL) {
637 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
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));
649 if(S_ISDIR(statbuf.st_mode))
652 AddFontFileToList(path, NULL);
658 static void load_fontconfig_fonts(void)
660 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
661 void *fc_handle = NULL;
670 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
672 TRACE("Wine cannot find the fontconfig library (%s).\n",
673 SONAME_LIBFONTCONFIG);
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);
689 if(!pFcInit()) return;
691 config = pFcConfigGetCurrent();
692 pat = pFcPatternCreate();
693 os = pFcObjectSetCreate();
694 pFcObjectSetAdd(os, FC_FILE);
695 fontset = pFcFontList(config, pat, os);
697 for(i = 0; i < fontset->nfont; i++) {
698 if(pFcPatternGet(fontset->fonts[i], FC_FILE, 0, &v) != FcResultMatch)
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
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);
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];
730 FIXME("Ignoring flags %lx\n", flags);
732 if(wine_get_unix_file_name(file, unixname, sizeof(unixname)))
733 AddFontFileToList(unixname, NULL);
738 /*************************************************************
739 * WineEngRemoveFontResourceEx
742 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
748 /*************************************************************
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'};
757 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
759 WCHAR windowsdir[MAX_PATH];
760 char unixname[MAX_PATH];
764 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
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");
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)
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 */
805 if(pFT_Init_FreeType(&library) != 0) {
806 ERR("Can't init FreeType library\n");
807 wine_dlclose(ft_handle, NULL, 0);
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)
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) {
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);
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 */
856 HeapFree(GetProcessHeap(), 0, data);
857 HeapFree(GetProcessHeap(), 0, valueW);
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) {
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);
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 */
886 HeapFree(GetProcessHeap(), 0, data);
887 HeapFree(GetProcessHeap(), 0, value);
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);
908 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
911 TT_HoriHeader *pHori;
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
929 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
930 * with il = winAscent + winDescent - units_per_em]
935 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
936 ppem = ft_face->units_per_EM * height /
937 (pHori->Ascender - pHori->Descender);
939 ppem = ft_face->units_per_EM * height /
940 (pOS2->usWinAscent + pOS2->usWinDescent);
948 static LONG load_VDMX(GdiFont, LONG);
950 static FT_Face OpenFontFile(GdiFont font, char *file, FT_Long face_index, LONG height)
956 err = pFT_New_Face(library, file, face_index, &ft_face);
958 ERR("FT_New_Face rets %d\n", err);
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);
968 ppem = calc_ppem_for_height(ft_face, height);
970 pFT_Set_Pixel_Sizes(ft_face, 0, ppem);
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 */
984 int acp = GetACP(), i;
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++) {
993 if(face->fs.fsCsb[0] & fs0) {
994 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG))
995 return csi.ciCharset;
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));
1014 ret->xform.eM11 = ret->xform.eM22 = 1.0;
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 /*************************************************************
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 ) | \
1040 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
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;
1059 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
1061 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
1064 /* FIXME: need the real device aspect ratio */
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++) {
1075 offset = (3 * 2) + (i * sizeof(Ratios));
1076 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
1079 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
1081 if(ratio.bCharSet != 1)
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);
1099 FIXME("No suitable ratio found\n");
1103 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, group, 4) != GDI_ERROR) {
1105 BYTE startsz, endsz;
1108 recs = GET_BE_WORD(group);
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");
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) {
1130 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1133 if(yMax + -yMin > height) {
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);
1146 TRACE("ppem not found for height %ld\n", height);
1150 if(ppem < startsz || ppem > endsz)
1153 for(i = 0; i < recs; i++) {
1155 yPelHeight = GET_BE_WORD(&vTable[i * 6]);
1157 if(yPelHeight > ppem)
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);
1169 HeapFree(GetProcessHeap(), 0, vTable);
1176 /*************************************************************
1177 * WineEngCreateFontInstance
1180 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
1184 Family *family = NULL;
1190 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
1192 TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
1193 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
1194 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
1197 /* check the cache first */
1198 for(ret = GdiFontList; ret; ret = ret->next) {
1199 if(ret->hfont == hfont && !memcmp(&ret->xform, &dc->xformWorld2Vport, offsetof(XFORM, eDx))) {
1200 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
1205 if(!FontList || !have_installed_roman_font) /* No fonts installed */
1207 TRACE("No fonts installed\n");
1212 memcpy(&ret->xform, &dc->xformWorld2Vport, sizeof(XFORM));
1214 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
1215 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
1216 original value lfCharSet. Note this is a special case for
1217 Symbol and doesn't happen at least for "Wingdings*" */
1219 if(!strcmpiW(lf.lfFaceName, SymbolW))
1220 lf.lfCharSet = SYMBOL_CHARSET;
1222 if(!TranslateCharsetInfo((DWORD*)(INT)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
1223 switch(lf.lfCharSet) {
1224 case DEFAULT_CHARSET:
1225 csi.fs.fsCsb[0] = 0;
1228 FIXME("Untranslated charset %d\n", lf.lfCharSet);
1229 csi.fs.fsCsb[0] = 0;
1234 if(lf.lfFaceName[0] != '\0') {
1236 for(psub = substlist; psub; psub = psub->next)
1237 if(!strcmpiW(lf.lfFaceName, psub->from.name) &&
1238 (psub->from.charset == -1 ||
1239 psub->from.charset == lf.lfCharSet))
1242 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
1243 debugstr_w(psub->to.name));
1244 strcpyW(lf.lfFaceName, psub->to.name);
1247 /* We want a match on name and charset or just name if
1248 charset was DEFAULT_CHARSET. If the latter then
1249 we fixup the returned charset later in get_nearest_charset
1250 where we'll either use the charset of the current ansi codepage
1251 or if that's unavailable the first charset that the font supports.
1253 for(family = FontList; family; family = family->next) {
1254 if(!strcmpiW(family->FamilyName, lf.lfFaceName))
1255 if((csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0]) || !csi.fs.fsCsb[0])
1259 if(!family) { /* do other aliases here */
1260 if(!strcmpiW(lf.lfFaceName, SystemW))
1261 strcpyW(lf.lfFaceName, defSystem);
1262 else if(!strcmpiW(lf.lfFaceName, MSSansSerifW))
1263 strcpyW(lf.lfFaceName, defSans);
1264 else if(!strcmpiW(lf.lfFaceName, HelvW))
1265 strcpyW(lf.lfFaceName, defSans);
1269 for(family = FontList; family; family = family->next) {
1270 if(!strcmpiW(family->FamilyName, lf.lfFaceName))
1271 if((csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0]) || !csi.fs.fsCsb[0])
1279 /* If requested charset was DEFAULT_CHARSET then try using charset
1280 corresponding to the current ansi codepage */
1281 if(!csi.fs.fsCsb[0]) {
1283 if(!TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE)) {
1284 FIXME("TCI failed on codepage %d\n", acp);
1285 csi.fs.fsCsb[0] = 0;
1287 lf.lfCharSet = csi.ciCharset;
1290 /* Face families are in the top 4 bits of lfPitchAndFamily,
1291 so mask with 0xF0 before testing */
1293 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
1294 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
1295 strcpyW(lf.lfFaceName, defFixed);
1296 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
1297 strcpyW(lf.lfFaceName, defSerif);
1298 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
1299 strcpyW(lf.lfFaceName, defSans);
1301 strcpyW(lf.lfFaceName, defSans);
1302 for(family = FontList; family; family = family->next) {
1303 if(!strcmpiW(family->FamilyName, lf.lfFaceName) &&
1304 (csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0]))
1310 for(family = FontList; family; family = family->next) {
1311 if(csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0])
1318 csi.fs.fsCsb[0] = 0;
1319 FIXME("just using first face for now\n");
1322 it = lf.lfItalic ? 1 : 0;
1323 bd = lf.lfWeight > 550 ? 1 : 0;
1325 for(face = family->FirstFace; face; face = face->next) {
1326 if(!(face->Italic ^ it) && !(face->Bold ^ bd))
1330 face = family->FirstFace;
1331 if(it && !face->Italic) ret->fake_italic = TRUE;
1332 if(bd && !face->Bold) ret->fake_bold = TRUE;
1335 memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
1338 ret->charset = lf.lfCharSet;
1340 ret->charset = get_nearest_charset(face);
1342 TRACE("Chosen: %s %s\n", debugstr_w(family->FamilyName),
1343 debugstr_w(face->StyleName));
1345 height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
1346 ret->ft_face = OpenFontFile(ret, face->file, face->face_index,
1347 lf.lfHeight < 0 ? -abs(height) : abs(height));
1354 if (ret->charset == SYMBOL_CHARSET &&
1355 !pFT_Select_Charmap(ret->ft_face, ft_encoding_symbol)) {
1358 else if (!pFT_Select_Charmap(ret->ft_face, ft_encoding_unicode)) {
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);
1370 ret->aveWidth= lf.lfWidth;
1371 ret->next = GdiFontList;
1377 static void DumpGdiFontList(void)
1381 TRACE("---------- gdiFont Cache ----------\n");
1382 for(gdiFont = GdiFontList; gdiFont; gdiFont = gdiFont->next) {
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)
1399 GdiFont gdiPrev = NULL;
1402 TRACE("destroying hfont=%p\n", handle);
1406 gdiFont = GdiFontList;
1408 if(gdiFont->hfont == handle) {
1410 gdiPrev->next = gdiFont->next;
1412 gdiFont = gdiPrev->next;
1414 GdiFontList = gdiFont->next;
1416 gdiFont = GdiFontList;
1421 gdiFont = gdiFont->next;
1427 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
1428 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
1430 OUTLINETEXTMETRICW *potm;
1432 GdiFont font = alloc_font();
1434 if (!(font->ft_face = OpenFontFile(font, face->file, face->face_index, 100)))
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;
1488 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
1490 strncpyW(pelf->elfLogFont.lfFaceName,
1491 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
1493 strncpyW(pelf->elfFullName,
1494 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
1496 strncpyW(pelf->elfStyle,
1497 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
1499 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
1501 HeapFree(GetProcessHeap(), 0, potm);
1506 /*************************************************************
1510 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
1515 NEWTEXTMETRICEXW ntm;
1516 DWORD type, ret = 1;
1522 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
1524 if(plf->lfFaceName[0]) {
1526 for(psub = substlist; psub; psub = psub->next)
1527 if(!strcmpiW(plf->lfFaceName, psub->from.name) &&
1528 (psub->from.charset == -1 ||
1529 psub->from.charset == plf->lfCharSet))
1532 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
1533 debugstr_w(psub->to.name));
1534 memcpy(&lf, plf, sizeof(lf));
1535 strcpyW(lf.lfFaceName, psub->to.name);
1538 for(family = FontList; family; family = family->next) {
1539 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
1540 for(face = family->FirstFace; face; face = face->next) {
1541 GetEnumStructs(face, &elf, &ntm, &type);
1542 for(i = 0; i < 32; i++) {
1543 if(face->fs.fsCsb[0] & (1L << i)) {
1544 fs.fsCsb[0] = 1L << i;
1546 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
1548 csi.ciCharset = DEFAULT_CHARSET;
1549 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
1550 if(csi.ciCharset != DEFAULT_CHARSET) {
1551 elf.elfLogFont.lfCharSet =
1552 ntm.ntmTm.tmCharSet = csi.ciCharset;
1554 strcpyW(elf.elfScript, ElfScriptsW[i]);
1556 FIXME("Unknown elfscript for bit %d\n", i);
1557 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
1558 debugstr_w(elf.elfLogFont.lfFaceName),
1559 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
1560 csi.ciCharset, type, debugstr_w(elf.elfScript),
1561 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
1562 ntm.ntmTm.ntmFlags);
1563 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
1572 for(family = FontList; family; family = family->next) {
1573 GetEnumStructs(family->FirstFace, &elf, &ntm, &type);
1574 for(i = 0; i < 32; i++) {
1575 if(family->FirstFace->fs.fsCsb[0] & (1L << i)) {
1576 fs.fsCsb[0] = 1L << i;
1578 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
1580 csi.ciCharset = DEFAULT_CHARSET;
1581 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
1582 if(csi.ciCharset != DEFAULT_CHARSET) {
1583 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
1586 strcpyW(elf.elfScript, ElfScriptsW[i]);
1588 FIXME("Unknown elfscript for bit %d\n", i);
1589 TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
1590 debugstr_w(elf.elfLogFont.lfFaceName),
1591 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
1592 csi.ciCharset, type, debugstr_w(elf.elfScript),
1593 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
1594 ntm.ntmTm.ntmFlags);
1595 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
1606 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
1608 pt->x.value = vec->x >> 6;
1609 pt->x.fract = (vec->x & 0x3f) << 10;
1610 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
1611 pt->y.value = vec->y >> 6;
1612 pt->y.fract = (vec->y & 0x3f) << 10;
1613 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
1617 static FT_UInt get_glyph_index(GdiFont font, UINT glyph)
1619 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
1620 glyph = glyph + 0xf000;
1621 return pFT_Get_Char_Index(font->ft_face, glyph);
1624 /*************************************************************
1625 * WineEngGetGlyphIndices
1627 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
1629 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
1630 LPWORD pgi, DWORD flags)
1634 for(i = 0; i < count; i++)
1635 pgi[i] = get_glyph_index(font, lpstr[i]);
1640 /*************************************************************
1641 * WineEngGetGlyphOutline
1643 * Behaves in exactly the same way as the win32 api GetGlyphOutline
1644 * except that the first parameter is the HWINEENGFONT of the font in
1645 * question rather than an HDC.
1648 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
1649 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
1652 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
1653 FT_Face ft_face = font->ft_face;
1654 FT_UInt glyph_index;
1655 DWORD width, height, pitch, needed = 0;
1656 FT_Bitmap ft_bitmap;
1658 INT left, right, top = 0, bottom = 0;
1660 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
1661 float widthRatio = 1.0;
1662 FT_Matrix transMat = identityMat;
1663 BOOL needsTransform = FALSE;
1666 TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font, glyph, format, lpgm,
1667 buflen, buf, lpmat);
1669 if(format & GGO_GLYPH_INDEX) {
1670 glyph_index = glyph;
1671 format &= ~GGO_GLYPH_INDEX;
1673 glyph_index = get_glyph_index(font, glyph);
1675 if(glyph_index >= font->gmsize) {
1676 font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
1677 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
1678 font->gmsize * sizeof(*font->gm));
1680 if(format == GGO_METRICS && font->gm[glyph_index].init) {
1681 memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
1682 return 1; /* FIXME */
1686 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP) || font->aveWidth || lpmat)
1687 load_flags |= FT_LOAD_NO_BITMAP;
1689 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
1692 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
1696 /* Scaling factor */
1697 if (font->aveWidth && font->potm) {
1698 widthRatio = (float)font->aveWidth * font->xform.eM11 / (float) font->potm->otmTextMetrics.tmAveCharWidth;
1701 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
1702 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
1704 font->gm[glyph_index].adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
1705 font->gm[glyph_index].lsb = left >> 6;
1706 font->gm[glyph_index].bbx = (right - left) >> 6;
1708 /* Scaling transform */
1709 if(font->aveWidth) {
1711 scaleMat.xx = FT_FixedFromFloat(widthRatio);
1714 scaleMat.yy = (1 << 16);
1716 pFT_Matrix_Multiply(&scaleMat, &transMat);
1717 needsTransform = TRUE;
1720 /* Rotation transform */
1721 if(font->orientation) {
1722 FT_Matrix rotationMat;
1724 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
1725 pFT_Vector_Unit(&vecAngle, angle);
1726 rotationMat.xx = vecAngle.x;
1727 rotationMat.xy = -vecAngle.y;
1728 rotationMat.yx = -rotationMat.xy;
1729 rotationMat.yy = rotationMat.xx;
1731 pFT_Matrix_Multiply(&rotationMat, &transMat);
1732 needsTransform = TRUE;
1735 /* Extra transformation specified by caller */
1738 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
1739 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
1740 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
1741 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
1742 pFT_Matrix_Multiply(&extraMat, &transMat);
1743 needsTransform = TRUE;
1746 if(!needsTransform) {
1747 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
1748 bottom = (ft_face->glyph->metrics.horiBearingY -
1749 ft_face->glyph->metrics.height) & -64;
1750 lpgm->gmCellIncX = font->gm[glyph_index].adv;
1751 lpgm->gmCellIncY = 0;
1755 for(xc = 0; xc < 2; xc++) {
1756 for(yc = 0; yc < 2; yc++) {
1757 vec.x = (ft_face->glyph->metrics.horiBearingX +
1758 xc * ft_face->glyph->metrics.width);
1759 vec.y = ft_face->glyph->metrics.horiBearingY -
1760 yc * ft_face->glyph->metrics.height;
1761 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
1762 pFT_Vector_Transform(&vec, &transMat);
1763 if(xc == 0 && yc == 0) {
1764 left = right = vec.x;
1765 top = bottom = vec.y;
1767 if(vec.x < left) left = vec.x;
1768 else if(vec.x > right) right = vec.x;
1769 if(vec.y < bottom) bottom = vec.y;
1770 else if(vec.y > top) top = vec.y;
1775 right = (right + 63) & -64;
1776 bottom = bottom & -64;
1777 top = (top + 63) & -64;
1779 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
1780 vec.x = ft_face->glyph->metrics.horiAdvance;
1782 pFT_Vector_Transform(&vec, &transMat);
1783 lpgm->gmCellIncX = (vec.x+63) >> 6;
1784 lpgm->gmCellIncY = -((vec.y+63) >> 6);
1786 lpgm->gmBlackBoxX = (right - left) >> 6;
1787 lpgm->gmBlackBoxY = (top - bottom) >> 6;
1788 lpgm->gmptGlyphOrigin.x = left >> 6;
1789 lpgm->gmptGlyphOrigin.y = top >> 6;
1791 memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
1792 font->gm[glyph_index].init = TRUE;
1794 if(format == GGO_METRICS)
1795 return 1; /* FIXME */
1797 if (buf && !buflen){
1801 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP) {
1802 FIXME("loaded a bitmap\n");
1808 width = lpgm->gmBlackBoxX;
1809 height = lpgm->gmBlackBoxY;
1810 pitch = ((width + 31) >> 5) << 2;
1811 needed = pitch * height;
1813 if(!buf || !buflen) break;
1815 switch(ft_face->glyph->format) {
1816 case ft_glyph_format_bitmap:
1818 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
1819 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
1820 INT h = ft_face->glyph->bitmap.rows;
1822 memcpy(dst, src, w);
1823 src += ft_face->glyph->bitmap.pitch;
1829 case ft_glyph_format_outline:
1830 ft_bitmap.width = width;
1831 ft_bitmap.rows = height;
1832 ft_bitmap.pitch = pitch;
1833 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
1834 ft_bitmap.buffer = buf;
1836 if(needsTransform) {
1837 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
1840 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
1842 /* Note: FreeType will only set 'black' bits for us. */
1843 memset(buf, 0, needed);
1844 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
1848 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
1853 case GGO_GRAY2_BITMAP:
1854 case GGO_GRAY4_BITMAP:
1855 case GGO_GRAY8_BITMAP:
1856 case WINE_GGO_GRAY16_BITMAP:
1861 width = lpgm->gmBlackBoxX;
1862 height = lpgm->gmBlackBoxY;
1863 pitch = (width + 3) / 4 * 4;
1864 needed = pitch * height;
1866 if(!buf || !buflen) break;
1867 ft_bitmap.width = width;
1868 ft_bitmap.rows = height;
1869 ft_bitmap.pitch = pitch;
1870 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
1871 ft_bitmap.buffer = buf;
1873 if(needsTransform) {
1874 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
1877 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
1879 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
1881 if(format == GGO_GRAY2_BITMAP)
1883 else if(format == GGO_GRAY4_BITMAP)
1885 else if(format == GGO_GRAY8_BITMAP)
1887 else if(format == WINE_GGO_GRAY16_BITMAP)
1895 for(row = 0; row < height; row++) {
1897 for(col = 0; col < width; col++, ptr++) {
1898 *ptr = (*(unsigned int*)ptr * mult + 128) / 256;
1907 int contour, point = 0, first_pt;
1908 FT_Outline *outline = &ft_face->glyph->outline;
1909 TTPOLYGONHEADER *pph;
1911 DWORD pph_start, cpfx, type;
1913 if(buflen == 0) buf = NULL;
1915 if (needsTransform && buf) {
1916 pFT_Outline_Transform(outline, &transMat);
1919 for(contour = 0; contour < outline->n_contours; contour++) {
1921 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
1924 pph->dwType = TT_POLYGON_TYPE;
1925 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
1927 needed += sizeof(*pph);
1929 while(point <= outline->contours[contour]) {
1930 ppc = (TTPOLYCURVE *)((char *)buf + needed);
1931 type = (outline->tags[point] & FT_Curve_Tag_On) ?
1932 TT_PRIM_LINE : TT_PRIM_QSPLINE;
1936 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
1939 } while(point <= outline->contours[contour] &&
1940 (outline->tags[point] & FT_Curve_Tag_On) ==
1941 (outline->tags[point-1] & FT_Curve_Tag_On));
1942 /* At the end of a contour Windows adds the start point, but
1944 if(point > outline->contours[contour] &&
1945 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
1947 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
1949 } else if(point <= outline->contours[contour] &&
1950 outline->tags[point] & FT_Curve_Tag_On) {
1951 /* add closing pt for bezier */
1953 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
1961 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
1964 pph->cb = needed - pph_start;
1970 /* Convert the quadratic Beziers to cubic Beziers.
1971 The parametric eqn for a cubic Bezier is, from PLRM:
1972 r(t) = at^3 + bt^2 + ct + r0
1973 with the control points:
1978 A quadratic Beizer has the form:
1979 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
1981 So equating powers of t leads to:
1982 r1 = 2/3 p1 + 1/3 p0
1983 r2 = 2/3 p1 + 1/3 p2
1984 and of course r0 = p0, r3 = p2
1987 int contour, point = 0, first_pt;
1988 FT_Outline *outline = &ft_face->glyph->outline;
1989 TTPOLYGONHEADER *pph;
1991 DWORD pph_start, cpfx, type;
1992 FT_Vector cubic_control[4];
1993 if(buflen == 0) buf = NULL;
1995 if (needsTransform && buf) {
1996 pFT_Outline_Transform(outline, &transMat);
1999 for(contour = 0; contour < outline->n_contours; contour++) {
2001 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
2004 pph->dwType = TT_POLYGON_TYPE;
2005 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2007 needed += sizeof(*pph);
2009 while(point <= outline->contours[contour]) {
2010 ppc = (TTPOLYCURVE *)((char *)buf + needed);
2011 type = (outline->tags[point] & FT_Curve_Tag_On) ?
2012 TT_PRIM_LINE : TT_PRIM_CSPLINE;
2015 if(type == TT_PRIM_LINE) {
2017 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2021 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
2024 /* FIXME: Possible optimization in endpoint calculation
2025 if there are two consecutive curves */
2026 cubic_control[0] = outline->points[point-1];
2027 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
2028 cubic_control[0].x += outline->points[point].x + 1;
2029 cubic_control[0].y += outline->points[point].y + 1;
2030 cubic_control[0].x >>= 1;
2031 cubic_control[0].y >>= 1;
2033 if(point+1 > outline->contours[contour])
2034 cubic_control[3] = outline->points[first_pt];
2036 cubic_control[3] = outline->points[point+1];
2037 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
2038 cubic_control[3].x += outline->points[point].x + 1;
2039 cubic_control[3].y += outline->points[point].y + 1;
2040 cubic_control[3].x >>= 1;
2041 cubic_control[3].y >>= 1;
2044 /* r1 = 1/3 p0 + 2/3 p1
2045 r2 = 1/3 p2 + 2/3 p1 */
2046 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
2047 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
2048 cubic_control[2] = cubic_control[1];
2049 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
2050 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
2051 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
2052 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
2054 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
2055 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
2056 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
2061 } while(point <= outline->contours[contour] &&
2062 (outline->tags[point] & FT_Curve_Tag_On) ==
2063 (outline->tags[point-1] & FT_Curve_Tag_On));
2064 /* At the end of a contour Windows adds the start point,
2065 but only for Beziers and we've already done that.
2067 if(point <= outline->contours[contour] &&
2068 outline->tags[point] & FT_Curve_Tag_On) {
2069 /* This is the closing pt of a bezier, but we've already
2070 added it, so just inc point and carry on */
2077 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2080 pph->cb = needed - pph_start;
2086 FIXME("Unsupported format %d\n", format);
2092 /*************************************************************
2093 * WineEngGetTextMetrics
2096 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
2099 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
2102 if(!font->potm) return FALSE;
2103 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
2105 if (font->aveWidth) {
2106 ptm->tmAveCharWidth = font->aveWidth * font->xform.eM11;
2112 /*************************************************************
2113 * WineEngGetOutlineTextMetrics
2116 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
2117 OUTLINETEXTMETRICW *potm)
2119 FT_Face ft_face = font->ft_face;
2120 UINT needed, lenfam, lensty, ret;
2122 TT_HoriHeader *pHori;
2123 TT_Postscript *pPost;
2124 FT_Fixed x_scale, y_scale;
2125 WCHAR *family_nameW, *style_nameW;
2126 WCHAR spaceW[] = {' ', '\0'};
2128 INT ascent, descent;
2130 TRACE("font=%p\n", font);
2133 if(cbSize >= font->potm->otmSize)
2134 memcpy(potm, font->potm, font->potm->otmSize);
2135 return font->potm->otmSize;
2138 needed = sizeof(*potm);
2140 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
2141 family_nameW = strdupW(font->name);
2143 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
2145 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
2146 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
2147 style_nameW, lensty);
2149 /* These names should be read from the TT name table */
2151 /* length of otmpFamilyName */
2154 /* length of otmpFaceName */
2155 if(!strcasecmp(ft_face->style_name, "regular")) {
2156 needed += lenfam; /* just the family name */
2158 needed += lenfam + lensty; /* family + " " + style */
2161 /* length of otmpStyleName */
2164 /* length of otmpFullName */
2165 needed += lenfam + lensty;
2168 x_scale = ft_face->size->metrics.x_scale;
2169 y_scale = ft_face->size->metrics.y_scale;
2171 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2173 FIXME("Can't find OS/2 table - not TT font?\n");
2178 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2180 FIXME("Can't find HHEA table - not TT font?\n");
2185 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
2187 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",
2188 pOS2->usWinAscent, pOS2->usWinDescent,
2189 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
2190 ft_face->ascender, ft_face->descender, ft_face->height,
2191 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
2192 ft_face->bbox.yMax, ft_face->bbox.yMin);
2194 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
2195 font->potm->otmSize = needed;
2197 #define TM font->potm->otmTextMetrics
2199 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
2200 ascent = pHori->Ascender;
2201 descent = -pHori->Descender;
2203 ascent = pOS2->usWinAscent;
2204 descent = pOS2->usWinDescent;
2208 TM.tmAscent = font->yMax;
2209 TM.tmDescent = -font->yMin;
2210 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
2212 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
2213 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
2214 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
2215 - ft_face->units_per_EM, y_scale) + 32) >> 6;
2218 TM.tmHeight = TM.tmAscent + TM.tmDescent;
2221 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
2223 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
2224 ((ascent + descent) -
2225 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
2227 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
2228 if (TM.tmAveCharWidth == 0) {
2229 TM.tmAveCharWidth = 1;
2231 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
2232 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
2234 TM.tmDigitizedAspectX = 300;
2235 TM.tmDigitizedAspectY = 300;
2236 TM.tmFirstChar = pOS2->usFirstCharIndex;
2237 TM.tmLastChar = pOS2->usLastCharIndex;
2238 TM.tmDefaultChar = pOS2->usDefaultChar;
2239 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
2240 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
2241 TM.tmUnderlined = 0; /* entry in OS2 table */
2242 TM.tmStruckOut = 0; /* entry in OS2 table */
2244 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
2245 if(!FT_IS_FIXED_WIDTH(ft_face))
2246 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
2248 TM.tmPitchAndFamily = 0;
2250 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
2251 case PAN_FAMILY_SCRIPT:
2252 TM.tmPitchAndFamily |= FF_SCRIPT;
2254 case PAN_FAMILY_DECORATIVE:
2255 case PAN_FAMILY_PICTORIAL:
2256 TM.tmPitchAndFamily |= FF_DECORATIVE;
2258 case PAN_FAMILY_TEXT_DISPLAY:
2259 if(TM.tmPitchAndFamily == 0) /* fixed */
2260 TM.tmPitchAndFamily = FF_MODERN;
2262 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
2263 case PAN_SERIF_NORMAL_SANS:
2264 case PAN_SERIF_OBTUSE_SANS:
2265 case PAN_SERIF_PERP_SANS:
2266 TM.tmPitchAndFamily |= FF_SWISS;
2269 TM.tmPitchAndFamily |= FF_ROMAN;
2274 TM.tmPitchAndFamily |= FF_DONTCARE;
2277 if(FT_IS_SCALABLE(ft_face))
2278 TM.tmPitchAndFamily |= TMPF_VECTOR;
2279 if(FT_IS_SFNT(ft_face))
2280 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
2282 TM.tmCharSet = font->charset;
2285 font->potm->otmFiller = 0;
2286 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
2287 font->potm->otmfsSelection = pOS2->fsSelection;
2288 font->potm->otmfsType = pOS2->fsType;
2289 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
2290 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
2291 font->potm->otmItalicAngle = 0; /* POST table */
2292 font->potm->otmEMSquare = ft_face->units_per_EM;
2293 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
2294 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
2295 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
2296 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
2297 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
2298 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
2299 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
2300 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
2301 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
2302 font->potm->otmMacAscent = 0; /* where do these come from ? */
2303 font->potm->otmMacDescent = 0;
2304 font->potm->otmMacLineGap = 0;
2305 font->potm->otmusMinimumPPEM = 0; /* TT Header */
2306 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
2307 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
2308 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
2309 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
2310 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
2311 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
2312 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
2313 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
2314 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
2315 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
2317 font->potm->otmsUnderscoreSize = 0;
2318 font->potm->otmsUnderscorePosition = 0;
2320 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
2321 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
2324 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
2325 cp = (char*)font->potm + sizeof(*font->potm);
2326 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
2327 strcpyW((WCHAR*)cp, family_nameW);
2329 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
2330 strcpyW((WCHAR*)cp, style_nameW);
2332 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
2333 strcpyW((WCHAR*)cp, family_nameW);
2334 if(strcasecmp(ft_face->style_name, "regular")) {
2335 strcatW((WCHAR*)cp, spaceW);
2336 strcatW((WCHAR*)cp, style_nameW);
2337 cp += lenfam + lensty;
2340 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
2341 strcpyW((WCHAR*)cp, family_nameW);
2342 strcatW((WCHAR*)cp, spaceW);
2343 strcatW((WCHAR*)cp, style_nameW);
2346 if(potm && needed <= cbSize)
2347 memcpy(potm, font->potm, font->potm->otmSize);
2350 HeapFree(GetProcessHeap(), 0, style_nameW);
2351 HeapFree(GetProcessHeap(), 0, family_nameW);
2357 /*************************************************************
2358 * WineEngGetCharWidth
2361 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
2366 FT_UInt glyph_index;
2368 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
2370 for(c = firstChar; c <= lastChar; c++) {
2371 glyph_index = get_glyph_index(font, c);
2372 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
2373 &gm, 0, NULL, NULL);
2374 buffer[c - firstChar] = font->gm[glyph_index].adv;
2379 /*************************************************************
2380 * WineEngGetTextExtentPoint
2383 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
2389 FT_UInt glyph_index;
2391 TRACE("%p, %s, %d, %p\n", font, debugstr_wn(wstr, count), count,
2395 WineEngGetTextMetrics(font, &tm);
2396 size->cy = tm.tmHeight;
2398 for(idx = 0; idx < count; idx++) {
2399 glyph_index = get_glyph_index(font, wstr[idx]);
2400 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
2401 &gm, 0, NULL, NULL);
2402 size->cx += font->gm[glyph_index].adv;
2404 TRACE("return %ld,%ld\n", size->cx, size->cy);
2408 /*************************************************************
2409 * WineEngGetTextExtentPointI
2412 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
2419 TRACE("%p, %p, %d, %p\n", font, indices, count, size);
2422 WineEngGetTextMetrics(font, &tm);
2423 size->cy = tm.tmHeight;
2425 for(idx = 0; idx < count; idx++) {
2426 WineEngGetGlyphOutline(font, indices[idx],
2427 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
2429 size->cx += font->gm[indices[idx]].adv;
2431 TRACE("return %ld,%ld\n", size->cx, size->cy);
2435 /*************************************************************
2436 * WineEngGetFontData
2439 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
2442 FT_Face ft_face = font->ft_face;
2446 TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
2447 font, table, offset, buf, cbData);
2449 if(!FT_IS_SFNT(ft_face))
2457 if(table) { /* MS tags differ in endidness from FT ones */
2458 table = table >> 24 | table << 24 |
2459 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
2462 /* If the FT_Load_Sfnt_Table function is there we'll use it */
2463 if(pFT_Load_Sfnt_Table)
2464 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
2465 else { /* Do it the hard way */
2466 TT_Face tt_face = (TT_Face) ft_face;
2467 SFNT_Interface *sfnt;
2468 if (FT_Version.major==2 && FT_Version.minor==0)
2471 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
2475 /* A field was added in the middle of the structure in 2.1.x */
2476 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
2478 err = sfnt->load_any(tt_face, table, offset, buf, &len);
2481 TRACE("Can't find table %08lx.\n", table);
2487 /*************************************************************
2488 * WineEngGetTextFace
2491 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
2494 lstrcpynW(str, font->name, count);
2495 return strlenW(font->name);
2497 return strlenW(font->name) + 1;
2500 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
2502 if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
2503 return font->charset;
2506 #else /* HAVE_FREETYPE */
2508 BOOL WineEngInit(void)
2512 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
2516 BOOL WineEngDestroyFontInstance(HFONT hfont)
2521 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
2526 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
2527 LPWORD pgi, DWORD flags)
2532 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
2533 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
2536 ERR("called but we don't have FreeType\n");
2540 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
2542 ERR("called but we don't have FreeType\n");
2546 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
2547 OUTLINETEXTMETRICW *potm)
2549 ERR("called but we don't have FreeType\n");
2553 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
2556 ERR("called but we don't have FreeType\n");
2560 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
2563 ERR("called but we don't have FreeType\n");
2567 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
2570 ERR("called but we don't have FreeType\n");
2574 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
2577 ERR("called but we don't have FreeType\n");
2581 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
2583 ERR("called but we don't have FreeType\n");
2587 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2593 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2599 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
2602 return DEFAULT_CHARSET;
2605 #endif /* HAVE_FREETYPE */