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
39 #include "wine/unicode.h"
40 #include "wine/port.h"
41 #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*);
114 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
115 #include <fontconfig/fontconfig.h>
116 MAKE_FUNCPTR(FcConfigGetCurrent);
117 MAKE_FUNCPTR(FcFontList);
118 MAKE_FUNCPTR(FcFontSetDestroy);
119 MAKE_FUNCPTR(FcInit);
120 MAKE_FUNCPTR(FcObjectSetAdd);
121 MAKE_FUNCPTR(FcObjectSetCreate);
122 MAKE_FUNCPTR(FcObjectSetDestroy);
123 MAKE_FUNCPTR(FcPatternCreate);
124 MAKE_FUNCPTR(FcPatternDestroy);
125 MAKE_FUNCPTR(FcPatternGet);
126 #ifndef SONAME_LIBFONTCONFIG
127 #define SONAME_LIBFONTCONFIG "libfontconfig.so"
134 #define GET_BE_WORD(ptr) MAKEWORD( ((BYTE *)(ptr))[1], ((BYTE *)(ptr))[0] )
136 typedef struct tagFace {
143 FT_Fixed font_version;
144 struct tagFace *next;
145 struct tagFamily *family;
148 typedef struct tagFamily {
151 struct tagFamily *next;
156 INT adv; /* These three hold to widths of the unrotated chars */
176 OUTLINETEXTMETRICW *potm;
178 struct tagGdiFont *next;
181 #define INIT_GM_SIZE 128
183 static GdiFont GdiFontList = NULL;
185 static Family *FontList = NULL;
187 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ',
188 'R','o','m','a','n','\0'};
189 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
190 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
192 static const WCHAR defSystem[] = {'A','r','i','a','l','\0'};
193 static const WCHAR SystemW[] = {'S','y','s','t','e','m','\0'};
194 static const WCHAR MSSansSerifW[] = {'M','S',' ','S','a','n','s',' ',
195 'S','e','r','i','f','\0'};
196 static const WCHAR HelvW[] = {'H','e','l','v','\0'};
198 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
199 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
200 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
201 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
202 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
203 'E','u','r','o','p','e','a','n','\0'};
204 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
205 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
206 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
207 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
208 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
209 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
210 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
211 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
212 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
213 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
214 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
216 static const WCHAR *ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
226 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
234 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
243 typedef struct tagFontSubst {
246 struct tagFontSubst *next;
249 static FontSubst *substlist = NULL;
250 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
253 This function builds an FT_Fixed from a float. It puts the integer part
254 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
255 It fails if the integer part of the float number is greater than SHORT_MAX.
257 static inline FT_Fixed FT_FixedFromFloat(float f)
260 unsigned short fract = (f - value) * 0xFFFF;
261 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
265 This function builds an FT_Fixed from a FIXED. It simply put f.value
266 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
268 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
270 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
273 static BOOL AddFontFileToList(const char *file, char *fake_family)
278 WCHAR *FamilyW, *StyleW;
280 Family *family = FontList;
281 Family **insert = &FontList;
282 Face **insertface, *next;
284 FT_Long face_index = 0, num_faces;
288 char *family_name = fake_family;
290 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
291 if((err = pFT_New_Face(library, file, face_index, &ft_face)) != 0) {
292 WARN("Unable to load font file %s err = %x\n", debugstr_a(file), err);
296 if(!FT_IS_SFNT(ft_face)) { /* for now we'll skip everything but TT/OT */
297 pFT_Done_Face(ft_face);
300 if(!pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2) ||
301 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
302 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head))) {
303 TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
304 "Skipping this font.\n", debugstr_a(file));
305 pFT_Done_Face(ft_face);
309 if(!ft_face->family_name || !ft_face->style_name) {
310 TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file));
311 pFT_Done_Face(ft_face);
316 family_name = ft_face->family_name;
318 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
319 FamilyW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
320 MultiByteToWideChar(CP_ACP, 0, family_name, -1, FamilyW, len);
323 if(!strcmpW(family->FamilyName, FamilyW))
325 insert = &family->next;
326 family = family->next;
329 family = *insert = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
330 family->FamilyName = FamilyW;
331 family->FirstFace = NULL;
334 HeapFree(GetProcessHeap(), 0, FamilyW);
337 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
338 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
339 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
342 for(insertface = &family->FirstFace; *insertface;
343 insertface = &(*insertface)->next) {
344 if(!strcmpW((*insertface)->StyleName, StyleW)) {
345 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
346 debugstr_w(family->FamilyName), debugstr_w(StyleW),
347 (*insertface)->font_version, pHeader->Font_Revision);
350 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
351 HeapFree(GetProcessHeap(), 0, StyleW);
352 pFT_Done_Face(ft_face);
355 if(pHeader->Font_Revision <= (*insertface)->font_version) {
356 TRACE("Original font is newer so skipping this one\n");
357 HeapFree(GetProcessHeap(), 0, StyleW);
358 pFT_Done_Face(ft_face);
361 TRACE("Replacing original with this one\n");
362 next = (*insertface)->next;
363 HeapFree(GetProcessHeap(), 0, (*insertface)->file);
364 HeapFree(GetProcessHeap(), 0, (*insertface)->StyleName);
365 HeapFree(GetProcessHeap(), 0, *insertface);
370 *insertface = HeapAlloc(GetProcessHeap(), 0, sizeof(**insertface));
371 (*insertface)->StyleName = StyleW;
372 (*insertface)->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
373 strcpy((*insertface)->file, file);
374 (*insertface)->face_index = face_index;
375 (*insertface)->next = next;
376 (*insertface)->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
377 (*insertface)->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
378 (*insertface)->font_version = pHeader->Font_Revision;
379 (*insertface)->family = family;
381 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
383 (*insertface)->fs.fsCsb[0] = pOS2->ulCodePageRange1;
384 (*insertface)->fs.fsCsb[1] = pOS2->ulCodePageRange2;
385 (*insertface)->fs.fsUsb[0] = pOS2->ulUnicodeRange1;
386 (*insertface)->fs.fsUsb[1] = pOS2->ulUnicodeRange2;
387 (*insertface)->fs.fsUsb[2] = pOS2->ulUnicodeRange3;
388 (*insertface)->fs.fsUsb[3] = pOS2->ulUnicodeRange4;
390 (*insertface)->fs.fsCsb[0] = (*insertface)->fs.fsCsb[1] = 0;
391 (*insertface)->fs.fsUsb[0] = 0;
392 (*insertface)->fs.fsUsb[1] = 0;
393 (*insertface)->fs.fsUsb[2] = 0;
394 (*insertface)->fs.fsUsb[3] = 0;
396 TRACE("fsCsb = %08lx %08lx/%08lx %08lx %08lx %08lx\n",
397 (*insertface)->fs.fsCsb[0], (*insertface)->fs.fsCsb[1],
398 (*insertface)->fs.fsUsb[0], (*insertface)->fs.fsUsb[1],
399 (*insertface)->fs.fsUsb[2], (*insertface)->fs.fsUsb[3]);
401 if((*insertface)->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
402 for(i = 0; i < ft_face->num_charmaps; i++) {
403 switch(ft_face->charmaps[i]->encoding) {
404 case ft_encoding_unicode:
405 case ft_encoding_apple_roman:
406 (*insertface)->fs.fsCsb[0] |= 1;
408 case ft_encoding_symbol:
409 (*insertface)->fs.fsCsb[0] |= 1L << 31;
417 if((*insertface)->fs.fsCsb[0] & ~(1L << 31))
418 have_installed_roman_font = TRUE;
420 num_faces = ft_face->num_faces;
421 pFT_Done_Face(ft_face);
422 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
424 } while(num_faces > ++face_index);
428 static void DumpFontList(void)
433 for(family = FontList; family; family = family->next) {
434 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
435 for(face = family->FirstFace; face; face = face->next) {
436 TRACE("\t%s\n", debugstr_w(face->StyleName));
442 static void DumpSubstList(void)
446 for(psub = substlist; psub; psub = psub->next)
447 if(psub->from.charset != -1 || psub->to.charset != -1)
448 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
449 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
451 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
452 debugstr_w(psub->to.name));
456 static LPWSTR strdupW(LPWSTR p)
459 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
460 ret = HeapAlloc(GetProcessHeap(), 0, len);
465 static void split_subst_info(NameCs *nc, LPSTR str)
467 CHAR *p = strrchr(str, ',');
472 nc->charset = strtol(p+1, NULL, 10);
475 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
476 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
477 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
480 static void LoadSubstList(void)
482 FontSubst *psub, **ppsub;
484 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
489 for(psub = substlist; psub;) {
491 HeapFree(GetProcessHeap(), 0, psub->to.name);
492 HeapFree(GetProcessHeap(), 0, psub->from.name);
495 HeapFree(GetProcessHeap(), 0, ptmp);
500 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
501 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
502 &hkey) == ERROR_SUCCESS) {
504 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
505 &valuelen, &datalen, NULL, NULL);
507 valuelen++; /* returned value doesn't include room for '\0' */
508 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
509 data = HeapAlloc(GetProcessHeap(), 0, datalen);
514 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
515 &dlen) == ERROR_SUCCESS) {
516 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
518 *ppsub = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppsub));
519 (*ppsub)->next = NULL;
520 split_subst_info(&((*ppsub)->from), value);
521 split_subst_info(&((*ppsub)->to), data);
523 /* Win 2000 doesn't allow mapping between different charsets
524 or mapping of DEFAULT_CHARSET */
525 if(((*ppsub)->to.charset != (*ppsub)->from.charset) ||
526 (*ppsub)->to.charset == DEFAULT_CHARSET) {
527 HeapFree(GetProcessHeap(), 0, (*ppsub)->to.name);
528 HeapFree(GetProcessHeap(), 0, (*ppsub)->from.name);
529 HeapFree(GetProcessHeap(), 0, *ppsub);
532 ppsub = &((*ppsub)->next);
534 /* reset dlen and vlen */
538 HeapFree(GetProcessHeap(), 0, data);
539 HeapFree(GetProcessHeap(), 0, value);
544 /***********************************************************
545 * The replacement list is a way to map an entire font
546 * family onto another family. For example adding
548 * [HKLM\Software\Wine\Wine\FontReplacements]
549 * "Wingdings"="Winedings"
551 * would enumerate the Winedings font both as Winedings and
552 * Wingdings. However if a real Wingdings font is present the
553 * replacement does not take place.
556 static void LoadReplaceList(void)
559 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
564 WCHAR old_nameW[200];
566 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
567 "Software\\Wine\\Wine\\FontReplacements",
568 &hkey) == ERROR_SUCCESS) {
570 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
571 &valuelen, &datalen, NULL, NULL);
573 valuelen++; /* returned value doesn't include room for '\0' */
574 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
575 data = HeapAlloc(GetProcessHeap(), 0, datalen);
579 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
580 &dlen) == ERROR_SUCCESS) {
581 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
582 /* "NewName"="Oldname" */
583 if(!MultiByteToWideChar(CP_ACP, 0, data, -1, old_nameW, sizeof(old_nameW)))
586 /* Find the old family and hence all of the font files
588 for(family = FontList; family; family = family->next) {
589 if(!strcmpiW(family->FamilyName, old_nameW)) {
590 for(face = family->FirstFace; face; face = face->next) {
591 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
592 debugstr_w(face->StyleName), value);
593 /* Now add a new entry with the new family name */
594 AddFontFileToList(face->file, value);
599 /* reset dlen and vlen */
603 HeapFree(GetProcessHeap(), 0, data);
604 HeapFree(GetProcessHeap(), 0, value);
610 static BOOL ReadFontDir(char *dirname)
616 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
618 dir = opendir(dirname);
620 ERR("Can't open directory %s\n", debugstr_a(dirname));
623 while((dent = readdir(dir)) != NULL) {
626 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
629 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
631 sprintf(path, "%s/%s", dirname, dent->d_name);
633 if(stat(path, &statbuf) == -1)
635 WARN("Can't stat %s\n", debugstr_a(path));
638 if(S_ISDIR(statbuf.st_mode))
641 AddFontFileToList(path, NULL);
647 static void load_fontconfig_fonts(void)
649 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
650 void *fc_handle = NULL;
659 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
661 TRACE("Wine cannot find the fontconfig library (%s).\n",
662 SONAME_LIBFONTCONFIG);
665 #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;}
666 LOAD_FUNCPTR(FcConfigGetCurrent);
667 LOAD_FUNCPTR(FcFontList);
668 LOAD_FUNCPTR(FcFontSetDestroy);
669 LOAD_FUNCPTR(FcInit);
670 LOAD_FUNCPTR(FcObjectSetAdd);
671 LOAD_FUNCPTR(FcObjectSetCreate);
672 LOAD_FUNCPTR(FcObjectSetDestroy);
673 LOAD_FUNCPTR(FcPatternCreate);
674 LOAD_FUNCPTR(FcPatternDestroy);
675 LOAD_FUNCPTR(FcPatternGet);
678 if(!pFcInit()) return;
680 config = pFcConfigGetCurrent();
681 pat = pFcPatternCreate();
682 os = pFcObjectSetCreate();
683 pFcObjectSetAdd(os, FC_FILE);
684 fontset = pFcFontList(config, pat, os);
686 for(i = 0; i < fontset->nfont; i++) {
687 if(pFcPatternGet(fontset->fonts[i], FC_FILE, 0, &v) != FcResultMatch)
689 if(v.type != FcTypeString) continue;
690 TRACE("fontconfig: %s\n", v.u.s);
692 /* We're just interested in OT/TT fonts for now, so this hack just
693 picks up the standard extensions to save time loading every other
696 if(len < 4) continue;
697 ext = v.u.s + len - 3;
698 if(!strcasecmp(ext, "ttf") || !strcasecmp(ext, "ttc") || !strcasecmp(ext, "otf"))
699 AddFontFileToList(v.u.s, NULL);
701 pFcFontSetDestroy(fontset);
702 pFcObjectSetDestroy(os);
703 pFcPatternDestroy(pat);
708 /*************************************************************
709 * WineEngAddFontResourceEx
712 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
714 if (ft_handle) /* do it only if we have freetype up and running */
716 DWORD len = WideCharToMultiByte(CP_ACP, 0, file, -1, NULL, 0, NULL, NULL);
717 LPSTR fileA = HeapAlloc(GetProcessHeap(), 0, len);
718 char unixname[MAX_PATH];
719 WideCharToMultiByte(CP_ACP, 0, file, -1, fileA, len, NULL, NULL);
722 FIXME("Ignoring flags %lx\n", flags);
724 if(wine_get_unix_file_name(fileA, unixname, sizeof(unixname)))
725 AddFontFileToList(unixname, NULL);
726 HeapFree(GetProcessHeap(), 0, fileA);
731 /*************************************************************
732 * WineEngRemoveFontResourceEx
735 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
741 /*************************************************************
744 * Initialize FreeType library and create a list of available faces
746 BOOL WineEngInit(void)
749 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
752 char windowsdir[MAX_PATH];
753 char unixname[MAX_PATH];
757 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
760 "Wine cannot find the FreeType font library. To enable Wine to\n"
761 "use TrueType fonts please install a version of FreeType greater than\n"
762 "or equal to 2.0.5.\n"
763 "http://www.freetype.org\n");
767 #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;}
769 LOAD_FUNCPTR(FT_Vector_Unit)
770 LOAD_FUNCPTR(FT_Done_Face)
771 LOAD_FUNCPTR(FT_Get_Char_Index)
772 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
773 LOAD_FUNCPTR(FT_Init_FreeType)
774 LOAD_FUNCPTR(FT_Load_Glyph)
775 LOAD_FUNCPTR(FT_Matrix_Multiply)
776 LOAD_FUNCPTR(FT_MulFix)
777 LOAD_FUNCPTR(FT_New_Face)
778 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
779 LOAD_FUNCPTR(FT_Outline_Transform)
780 LOAD_FUNCPTR(FT_Outline_Translate)
781 LOAD_FUNCPTR(FT_Select_Charmap)
782 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
783 LOAD_FUNCPTR(FT_Vector_Transform)
786 /* Don't warn if this one is missing */
787 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
788 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
790 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
791 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
792 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
793 <= 2.0.3 has FT_Sqrt64 */
797 if(pFT_Init_FreeType(&library) != 0) {
798 ERR("Can't init FreeType library\n");
799 wine_dlclose(ft_handle, NULL, 0);
803 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
804 if (pFT_Library_Version)
806 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
808 if (FT_Version.major<=0)
814 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
816 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
817 GetWindowsDirectoryA(windowsdir, sizeof(windowsdir));
818 strcat(windowsdir, "\\Fonts");
819 if(wine_get_unix_file_name(windowsdir, unixname, sizeof(unixname)))
820 ReadFontDir(unixname);
822 /* now look under HKLM\Software\Microsoft\Windows\CurrentVersion\Fonts
823 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
824 full path as the entry */
825 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
826 "Software\\Microsoft\\Windows\\CurrentVersion\\Fonts",
827 &hkey) == ERROR_SUCCESS) {
828 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
829 &valuelen, &datalen, NULL, NULL);
831 valuelen++; /* returned value doesn't include room for '\0' */
832 value = HeapAlloc(GetProcessHeap(), 0, valuelen);
833 data = HeapAlloc(GetProcessHeap(), 0, datalen);
837 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
838 &dlen) == ERROR_SUCCESS) {
839 if(((LPSTR)data)[0] && ((LPSTR)data)[1] == ':')
840 if(wine_get_unix_file_name((LPSTR)data, unixname, sizeof(unixname)))
841 AddFontFileToList(unixname, NULL);
843 /* reset dlen and vlen */
847 HeapFree(GetProcessHeap(), 0, data);
848 HeapFree(GetProcessHeap(), 0, value);
852 load_fontconfig_fonts();
854 /* then look in any directories that we've specified in the config file */
855 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
856 "Software\\Wine\\Wine\\Config\\FontDirs",
857 &hkey) == ERROR_SUCCESS) {
859 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
860 &valuelen, &datalen, NULL, NULL);
862 valuelen++; /* returned value doesn't include room for '\0' */
863 value = HeapAlloc(GetProcessHeap(), 0, valuelen);
864 data = HeapAlloc(GetProcessHeap(), 0, datalen);
869 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
870 &dlen) == ERROR_SUCCESS) {
871 TRACE("Got %s=%s\n", value, (LPSTR)data);
872 ReadFontDir((LPSTR)data);
873 /* reset dlen and vlen */
877 HeapFree(GetProcessHeap(), 0, data);
878 HeapFree(GetProcessHeap(), 0, value);
889 "Wine cannot find certain functions that it needs inside the FreeType\n"
890 "font library. To enable Wine to use TrueType fonts please upgrade\n"
891 "FreeType to at least version 2.0.5.\n"
892 "http://www.freetype.org\n");
893 wine_dlclose(ft_handle, NULL, 0);
899 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
904 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
906 if(height == 0) height = 16;
908 /* Calc. height of EM square:
910 * For +ve lfHeight we have
911 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
912 * Re-arranging gives:
913 * ppem = units_per_em * lfheight / (winAscent + winDescent)
915 * For -ve lfHeight we have
917 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
918 * with il = winAscent + winDescent - units_per_em]
923 ppem = ft_face->units_per_EM * height /
924 (pOS2->usWinAscent + pOS2->usWinDescent);
931 static LONG load_VDMX(GdiFont, LONG);
933 static FT_Face OpenFontFile(GdiFont font, char *file, FT_Long face_index, LONG height)
939 err = pFT_New_Face(library, file, face_index, &ft_face);
941 ERR("FT_New_Face rets %d\n", err);
945 /* set it here, as load_VDMX needs it */
946 font->ft_face = ft_face;
948 /* load the VDMX table if we have one */
949 ppem = load_VDMX(font, height);
951 ppem = calc_ppem_for_height(ft_face, height);
953 pFT_Set_Pixel_Sizes(ft_face, 0, ppem);
959 static int get_nearest_charset(Face *face)
961 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
962 a single face with the requested charset. The idea is to check if
963 the selected font supports the current ANSI codepage, if it does
964 return the corresponding charset, else return the first charset */
967 int acp = GetACP(), i;
970 if(TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE))
971 if(csi.fs.fsCsb[0] & face->fs.fsCsb[0])
972 return csi.ciCharset;
974 for(i = 0; i < 32; i++) {
976 if(face->fs.fsCsb[0] & fs0) {
977 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG))
978 return csi.ciCharset;
980 FIXME("TCI failing on %lx\n", fs0);
984 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08lx file = %s\n",
985 face->fs.fsCsb[0], face->file);
986 return DEFAULT_CHARSET;
989 static GdiFont alloc_font(void)
991 GdiFont ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
992 ret->gmsize = INIT_GM_SIZE;
993 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
994 ret->gmsize * sizeof(*ret->gm));
997 ret->xform.eM11 = ret->xform.eM22 = 1.0;
1001 static void free_font(GdiFont font)
1003 if (font->ft_face) pFT_Done_Face(font->ft_face);
1004 if (font->potm) HeapFree(GetProcessHeap(), 0, font->potm);
1005 if (font->name) HeapFree(GetProcessHeap(), 0, font->name);
1006 HeapFree(GetProcessHeap(), 0, font->gm);
1007 HeapFree(GetProcessHeap(), 0, font);
1011 /*************************************************************
1014 * load the vdmx entry for the specified height
1017 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
1018 ( ( (FT_ULong)_x4 << 24 ) | \
1019 ( (FT_ULong)_x3 << 16 ) | \
1020 ( (FT_ULong)_x2 << 8 ) | \
1023 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
1033 static LONG load_VDMX(GdiFont font, LONG height)
1035 BYTE hdr[6], tmp[2], group[4];
1036 BYTE devXRatio, devYRatio;
1037 USHORT numRecs, numRatios;
1042 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
1044 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
1047 /* FIXME: need the real device aspect ratio */
1051 numRecs = GET_BE_WORD(&hdr[2]);
1052 numRatios = GET_BE_WORD(&hdr[4]);
1054 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
1055 for(i = 0; i < numRatios; i++) {
1058 offset = (3 * 2) + (i * sizeof(Ratios));
1059 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
1062 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
1064 if(ratio.bCharSet != 1)
1067 if((ratio.xRatio == 0 &&
1068 ratio.yStartRatio == 0 &&
1069 ratio.yEndRatio == 0) ||
1070 (devXRatio == ratio.xRatio &&
1071 devYRatio >= ratio.yStartRatio &&
1072 devYRatio <= ratio.yEndRatio))
1074 offset = (3 * 2) + (numRatios * 4) + (i * 2);
1075 WineEngGetFontData(font, MS_VDMX_TAG, offset, tmp, 2);
1076 offset = GET_BE_WORD(tmp);
1082 FIXME("No suitable ratio found\n");
1086 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, group, 4) != GDI_ERROR) {
1088 BYTE startsz, endsz;
1091 recs = GET_BE_WORD(group);
1095 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
1097 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
1098 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
1099 if(result == GDI_ERROR) {
1100 FIXME("Failed to retrieve vTable\n");
1105 for(i = 0; i < recs; i++) {
1106 SHORT yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1107 SHORT yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1108 ppem = GET_BE_WORD(&vTable[i * 6]);
1110 if(yMax + -yMin == height) {
1113 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1116 if(yMax + -yMin > height) {
1119 goto end; /* failed */
1121 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1122 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1123 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1129 TRACE("ppem not found for height %ld\n", height);
1133 if(ppem < startsz || ppem > endsz)
1136 for(i = 0; i < recs; i++) {
1138 yPelHeight = GET_BE_WORD(&vTable[i * 6]);
1140 if(yPelHeight > ppem)
1143 if(yPelHeight == ppem) {
1144 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1145 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1146 TRACE("ppem %ld found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
1152 HeapFree(GetProcessHeap(), 0, vTable);
1159 /*************************************************************
1160 * WineEngCreateFontInstance
1163 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
1167 Family *family = NULL;
1172 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
1174 TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
1175 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
1176 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
1179 /* check the cache first */
1180 for(ret = GdiFontList; ret; ret = ret->next) {
1181 if(ret->hfont == hfont && !memcmp(&ret->xform, &dc->xformWorld2Vport, offsetof(XFORM, eDx))) {
1182 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
1187 if(!FontList || !have_installed_roman_font) /* No fonts installed */
1189 TRACE("No fonts installed\n");
1194 memcpy(&ret->xform, &dc->xformWorld2Vport, sizeof(XFORM));
1196 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
1197 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
1198 original value lfCharSet. Note this is a special case for
1199 Symbol and doesn't happen at least for "Wingdings*" */
1201 if(!strcmpiW(lf.lfFaceName, SymbolW))
1202 lf.lfCharSet = SYMBOL_CHARSET;
1204 if(!TranslateCharsetInfo((DWORD*)(INT)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
1205 switch(lf.lfCharSet) {
1206 case DEFAULT_CHARSET:
1207 csi.fs.fsCsb[0] = 0;
1210 FIXME("Untranslated charset %d\n", lf.lfCharSet);
1211 csi.fs.fsCsb[0] = 0;
1216 if(lf.lfFaceName[0] != '\0') {
1218 for(psub = substlist; psub; psub = psub->next)
1219 if(!strcmpiW(lf.lfFaceName, psub->from.name) &&
1220 (psub->from.charset == -1 ||
1221 psub->from.charset == lf.lfCharSet))
1224 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
1225 debugstr_w(psub->to.name));
1226 strcpyW(lf.lfFaceName, psub->to.name);
1229 /* We want a match on name and charset or just name if
1230 charset was DEFAULT_CHARSET. If the latter then
1231 we fixup the returned charset later in get_nearest_charset
1232 where we'll either use the charset of the current ansi codepage
1233 or if that's unavailable the first charset that the font supports.
1235 for(family = FontList; family; family = family->next) {
1236 if(!strcmpiW(family->FamilyName, lf.lfFaceName))
1237 if((csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0]) || !csi.fs.fsCsb[0])
1241 if(!family) { /* do other aliases here */
1242 if(!strcmpiW(lf.lfFaceName, SystemW))
1243 strcpyW(lf.lfFaceName, defSystem);
1244 else if(!strcmpiW(lf.lfFaceName, MSSansSerifW))
1245 strcpyW(lf.lfFaceName, defSans);
1246 else if(!strcmpiW(lf.lfFaceName, HelvW))
1247 strcpyW(lf.lfFaceName, defSans);
1251 for(family = FontList; family; family = family->next) {
1252 if(!strcmpiW(family->FamilyName, lf.lfFaceName))
1253 if((csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0]) || !csi.fs.fsCsb[0])
1261 /* If requested charset was DEFAULT_CHARSET then try using charset
1262 corresponding to the current ansi codepage */
1263 if(!csi.fs.fsCsb[0]) {
1265 if(!TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE)) {
1266 FIXME("TCI failed on codepage %d\n", acp);
1267 csi.fs.fsCsb[0] = 0;
1269 lf.lfCharSet = csi.ciCharset;
1272 /* Face families are in the top 4 bits of lfPitchAndFamily,
1273 so mask with 0xF0 before testing */
1275 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
1276 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
1277 strcpyW(lf.lfFaceName, defFixed);
1278 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
1279 strcpyW(lf.lfFaceName, defSerif);
1280 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
1281 strcpyW(lf.lfFaceName, defSans);
1283 strcpyW(lf.lfFaceName, defSans);
1284 for(family = FontList; family; family = family->next) {
1285 if(!strcmpiW(family->FamilyName, lf.lfFaceName) &&
1286 (csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0]))
1292 for(family = FontList; family; family = family->next) {
1293 if(csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0])
1300 csi.fs.fsCsb[0] = 0;
1301 FIXME("just using first face for now\n");
1304 it = lf.lfItalic ? 1 : 0;
1305 bd = lf.lfWeight > 550 ? 1 : 0;
1307 for(face = family->FirstFace; face; face = face->next) {
1308 if(!(face->Italic ^ it) && !(face->Bold ^ bd))
1312 face = family->FirstFace;
1313 if(it && !face->Italic) ret->fake_italic = TRUE;
1314 if(bd && !face->Bold) ret->fake_bold = TRUE;
1317 memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
1320 ret->charset = lf.lfCharSet;
1322 ret->charset = get_nearest_charset(face);
1324 TRACE("Chosen: %s %s\n", debugstr_w(family->FamilyName),
1325 debugstr_w(face->StyleName));
1327 ret->ft_face = OpenFontFile(ret, face->file, face->face_index,
1329 -abs(INTERNAL_YWSTODS(dc,lf.lfHeight)) :
1330 abs(INTERNAL_YWSTODS(dc, lf.lfHeight)));
1337 if (ret->charset == SYMBOL_CHARSET &&
1338 !pFT_Select_Charmap(ret->ft_face, ft_encoding_symbol)) {
1341 else if (!pFT_Select_Charmap(ret->ft_face, ft_encoding_unicode)) {
1345 pFT_Select_Charmap(ret->ft_face, ft_encoding_apple_roman);
1348 ret->orientation = lf.lfOrientation;
1349 ret->name = strdupW(family->FamilyName);
1351 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
1353 ret->aveWidth= lf.lfWidth;
1354 ret->next = GdiFontList;
1360 static void DumpGdiFontList(void)
1364 TRACE("---------- gdiFont Cache ----------\n");
1365 for(gdiFont = GdiFontList; gdiFont; gdiFont = gdiFont->next) {
1367 GetObjectW( gdiFont->hfont, sizeof(lf), &lf );
1368 TRACE("gdiFont=%p hfont=%p (%s)\n",
1369 gdiFont, gdiFont->hfont, debugstr_w(lf.lfFaceName));
1373 /*************************************************************
1374 * WineEngDestroyFontInstance
1376 * free the gdiFont associated with this handle
1379 BOOL WineEngDestroyFontInstance(HFONT handle)
1382 GdiFont gdiPrev = NULL;
1385 TRACE("destroying hfont=%p\n", handle);
1389 gdiFont = GdiFontList;
1391 if(gdiFont->hfont == handle) {
1393 gdiPrev->next = gdiFont->next;
1395 gdiFont = gdiPrev->next;
1397 GdiFontList = gdiFont->next;
1399 gdiFont = GdiFontList;
1404 gdiFont = gdiFont->next;
1410 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
1411 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
1413 OUTLINETEXTMETRICW *potm;
1415 GdiFont font = alloc_font();
1417 if (!(font->ft_face = OpenFontFile(font, face->file, face->face_index, 100)))
1423 font->name = strdupW(face->family->FamilyName);
1425 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
1427 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
1428 potm = HeapAlloc(GetProcessHeap(), 0, size);
1429 WineEngGetOutlineTextMetrics(font, size, potm);
1431 #define TM potm->otmTextMetrics
1433 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = TM.tmHeight;
1434 pntm->ntmTm.tmAscent = TM.tmAscent;
1435 pntm->ntmTm.tmDescent = TM.tmDescent;
1436 pntm->ntmTm.tmInternalLeading = TM.tmInternalLeading;
1437 pntm->ntmTm.tmExternalLeading = TM.tmExternalLeading;
1438 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = TM.tmAveCharWidth;
1439 pntm->ntmTm.tmMaxCharWidth = TM.tmMaxCharWidth;
1440 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = TM.tmWeight;
1441 pntm->ntmTm.tmOverhang = TM.tmOverhang;
1442 pntm->ntmTm.tmDigitizedAspectX = TM.tmDigitizedAspectX;
1443 pntm->ntmTm.tmDigitizedAspectY = TM.tmDigitizedAspectY;
1444 pntm->ntmTm.tmFirstChar = TM.tmFirstChar;
1445 pntm->ntmTm.tmLastChar = TM.tmLastChar;
1446 pntm->ntmTm.tmDefaultChar = TM.tmDefaultChar;
1447 pntm->ntmTm.tmBreakChar = TM.tmBreakChar;
1448 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = TM.tmItalic;
1449 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = TM.tmUnderlined;
1450 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = TM.tmStruckOut;
1451 pntm->ntmTm.tmPitchAndFamily = TM.tmPitchAndFamily;
1452 pelf->elfLogFont.lfPitchAndFamily = (TM.tmPitchAndFamily & 0xf1) + 1;
1453 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = TM.tmCharSet;
1454 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
1455 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
1456 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
1458 pntm->ntmTm.ntmFlags = TM.tmItalic ? NTM_ITALIC : 0;
1459 if(TM.tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
1460 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
1462 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
1463 pntm->ntmTm.ntmCellHeight = 0;
1464 pntm->ntmTm.ntmAvgWidth = 0;
1466 *ptype = TM.tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
1467 if(!(TM.tmPitchAndFamily & TMPF_VECTOR))
1468 *ptype |= RASTER_FONTTYPE;
1471 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
1473 strncpyW(pelf->elfLogFont.lfFaceName,
1474 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
1476 strncpyW(pelf->elfFullName,
1477 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
1479 strncpyW(pelf->elfStyle,
1480 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
1482 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
1484 HeapFree(GetProcessHeap(), 0, potm);
1489 /*************************************************************
1493 DWORD WineEngEnumFonts(LPLOGFONTW plf, DEVICEFONTENUMPROC proc,
1499 NEWTEXTMETRICEXW ntm;
1500 DWORD type, ret = 1;
1506 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
1508 if(plf->lfFaceName[0]) {
1510 for(psub = substlist; psub; psub = psub->next)
1511 if(!strcmpiW(plf->lfFaceName, psub->from.name) &&
1512 (psub->from.charset == -1 ||
1513 psub->from.charset == plf->lfCharSet))
1516 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
1517 debugstr_w(psub->to.name));
1518 memcpy(&lf, plf, sizeof(lf));
1519 strcpyW(lf.lfFaceName, psub->to.name);
1522 for(family = FontList; family; family = family->next) {
1523 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
1524 for(face = family->FirstFace; face; face = face->next) {
1525 GetEnumStructs(face, &elf, &ntm, &type);
1526 for(i = 0; i < 32; i++) {
1527 if(face->fs.fsCsb[0] & (1L << i)) {
1528 fs.fsCsb[0] = 1L << i;
1530 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
1532 csi.ciCharset = DEFAULT_CHARSET;
1533 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
1534 if(csi.ciCharset != DEFAULT_CHARSET) {
1535 elf.elfLogFont.lfCharSet =
1536 ntm.ntmTm.tmCharSet = csi.ciCharset;
1538 strcpyW(elf.elfScript, ElfScriptsW[i]);
1540 FIXME("Unknown elfscript for bit %d\n", i);
1541 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
1542 debugstr_w(elf.elfLogFont.lfFaceName),
1543 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
1544 csi.ciCharset, type, debugstr_w(elf.elfScript),
1545 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
1546 ntm.ntmTm.ntmFlags);
1547 ret = proc(&elf, &ntm, type, lparam);
1556 for(family = FontList; family; family = family->next) {
1557 GetEnumStructs(family->FirstFace, &elf, &ntm, &type);
1558 for(i = 0; i < 32; i++) {
1559 if(family->FirstFace->fs.fsCsb[0] & (1L << i)) {
1560 fs.fsCsb[0] = 1L << i;
1562 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
1564 csi.ciCharset = DEFAULT_CHARSET;
1565 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
1566 if(csi.ciCharset != DEFAULT_CHARSET) {
1567 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
1570 strcpyW(elf.elfScript, ElfScriptsW[i]);
1572 FIXME("Unknown elfscript for bit %d\n", i);
1573 TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
1574 debugstr_w(elf.elfLogFont.lfFaceName),
1575 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
1576 csi.ciCharset, type, debugstr_w(elf.elfScript),
1577 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
1578 ntm.ntmTm.ntmFlags);
1579 ret = proc(&elf, &ntm, type, lparam);
1590 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
1592 pt->x.value = vec->x >> 6;
1593 pt->x.fract = (vec->x & 0x3f) << 10;
1594 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
1595 pt->y.value = vec->y >> 6;
1596 pt->y.fract = (vec->y & 0x3f) << 10;
1597 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
1601 static FT_UInt get_glyph_index(GdiFont font, UINT glyph)
1603 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
1604 glyph = glyph + 0xf000;
1605 return pFT_Get_Char_Index(font->ft_face, glyph);
1608 /*************************************************************
1609 * WineEngGetGlyphIndices
1611 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
1613 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
1614 LPWORD pgi, DWORD flags)
1618 for(i = 0; i < count; i++)
1619 pgi[i] = get_glyph_index(font, lpstr[i]);
1624 /*************************************************************
1625 * WineEngGetGlyphOutline
1627 * Behaves in exactly the same way as the win32 api GetGlyphOutline
1628 * except that the first parameter is the HWINEENGFONT of the font in
1629 * question rather than an HDC.
1632 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
1633 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
1636 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
1637 FT_Face ft_face = font->ft_face;
1638 FT_UInt glyph_index;
1639 DWORD width, height, pitch, needed = 0;
1640 FT_Bitmap ft_bitmap;
1642 INT left, right, top = 0, bottom = 0;
1644 FT_Int load_flags = FT_LOAD_DEFAULT;
1645 float widthRatio = 1.0;
1646 FT_Matrix transMat = identityMat;
1647 BOOL needsTransform = FALSE;
1650 TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font, glyph, format, lpgm,
1651 buflen, buf, lpmat);
1653 if(format & GGO_GLYPH_INDEX) {
1654 glyph_index = glyph;
1655 format &= ~GGO_GLYPH_INDEX;
1657 glyph_index = get_glyph_index(font, glyph);
1659 if(glyph_index >= font->gmsize) {
1660 font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
1661 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
1662 font->gmsize * sizeof(*font->gm));
1664 if(format == GGO_METRICS && font->gm[glyph_index].init) {
1665 memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
1666 return 1; /* FIXME */
1670 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP) || font->aveWidth || lpmat)
1671 load_flags |= FT_LOAD_NO_BITMAP;
1673 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
1676 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
1680 /* Scaling factor */
1681 if (font->aveWidth && font->potm) {
1682 widthRatio = (float)font->aveWidth * font->xform.eM11 / (float) font->potm->otmTextMetrics.tmAveCharWidth;
1685 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
1686 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
1688 font->gm[glyph_index].adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
1689 font->gm[glyph_index].lsb = left >> 6;
1690 font->gm[glyph_index].bbx = (right - left) >> 6;
1692 /* Scaling transform */
1693 if(font->aveWidth) {
1695 scaleMat.xx = FT_FixedFromFloat(widthRatio);
1698 scaleMat.yy = (1 << 16);
1700 pFT_Matrix_Multiply(&scaleMat, &transMat);
1701 needsTransform = TRUE;
1704 /* Rotation transform */
1705 if(font->orientation) {
1706 FT_Matrix rotationMat;
1708 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
1709 pFT_Vector_Unit(&vecAngle, angle);
1710 rotationMat.xx = vecAngle.x;
1711 rotationMat.xy = -vecAngle.y;
1712 rotationMat.yx = -rotationMat.xy;
1713 rotationMat.yy = rotationMat.xx;
1715 pFT_Matrix_Multiply(&rotationMat, &transMat);
1716 needsTransform = TRUE;
1719 /* Extra transformation specified by caller */
1722 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
1723 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
1724 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
1725 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
1726 pFT_Matrix_Multiply(&extraMat, &transMat);
1727 needsTransform = TRUE;
1730 if(!needsTransform) {
1731 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
1732 bottom = (ft_face->glyph->metrics.horiBearingY -
1733 ft_face->glyph->metrics.height) & -64;
1734 lpgm->gmCellIncX = font->gm[glyph_index].adv;
1735 lpgm->gmCellIncY = 0;
1739 for(xc = 0; xc < 2; xc++) {
1740 for(yc = 0; yc < 2; yc++) {
1741 vec.x = (ft_face->glyph->metrics.horiBearingX +
1742 xc * ft_face->glyph->metrics.width);
1743 vec.y = ft_face->glyph->metrics.horiBearingY -
1744 yc * ft_face->glyph->metrics.height;
1745 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
1746 pFT_Vector_Transform(&vec, &transMat);
1747 if(xc == 0 && yc == 0) {
1748 left = right = vec.x;
1749 top = bottom = vec.y;
1751 if(vec.x < left) left = vec.x;
1752 else if(vec.x > right) right = vec.x;
1753 if(vec.y < bottom) bottom = vec.y;
1754 else if(vec.y > top) top = vec.y;
1759 right = (right + 63) & -64;
1760 bottom = bottom & -64;
1761 top = (top + 63) & -64;
1763 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
1764 vec.x = ft_face->glyph->metrics.horiAdvance;
1766 pFT_Vector_Transform(&vec, &transMat);
1767 lpgm->gmCellIncX = (vec.x+63) >> 6;
1768 lpgm->gmCellIncY = -((vec.y+63) >> 6);
1770 lpgm->gmBlackBoxX = (right - left) >> 6;
1771 lpgm->gmBlackBoxY = (top - bottom) >> 6;
1772 lpgm->gmptGlyphOrigin.x = left >> 6;
1773 lpgm->gmptGlyphOrigin.y = top >> 6;
1775 memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
1776 font->gm[glyph_index].init = TRUE;
1778 if(format == GGO_METRICS)
1779 return 1; /* FIXME */
1781 if (buf && !buflen){
1785 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP) {
1786 FIXME("loaded a bitmap\n");
1792 width = lpgm->gmBlackBoxX;
1793 height = lpgm->gmBlackBoxY;
1794 pitch = ((width + 31) >> 5) << 2;
1795 needed = pitch * height;
1797 if(!buf || !buflen) break;
1799 switch(ft_face->glyph->format) {
1800 case ft_glyph_format_bitmap:
1802 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
1803 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
1804 INT h = ft_face->glyph->bitmap.rows;
1806 memcpy(dst, src, w);
1807 src += ft_face->glyph->bitmap.pitch;
1813 case ft_glyph_format_outline:
1814 ft_bitmap.width = width;
1815 ft_bitmap.rows = height;
1816 ft_bitmap.pitch = pitch;
1817 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
1818 ft_bitmap.buffer = buf;
1820 if(needsTransform) {
1821 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
1824 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
1826 /* Note: FreeType will only set 'black' bits for us. */
1827 memset(buf, 0, needed);
1828 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
1832 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
1837 case GGO_GRAY2_BITMAP:
1838 case GGO_GRAY4_BITMAP:
1839 case GGO_GRAY8_BITMAP:
1840 case WINE_GGO_GRAY16_BITMAP:
1845 width = lpgm->gmBlackBoxX;
1846 height = lpgm->gmBlackBoxY;
1847 pitch = (width + 3) / 4 * 4;
1848 needed = pitch * height;
1850 if(!buf || !buflen) break;
1851 ft_bitmap.width = width;
1852 ft_bitmap.rows = height;
1853 ft_bitmap.pitch = pitch;
1854 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
1855 ft_bitmap.buffer = buf;
1857 if(needsTransform) {
1858 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
1861 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
1863 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
1865 if(format == GGO_GRAY2_BITMAP)
1867 else if(format == GGO_GRAY4_BITMAP)
1869 else if(format == GGO_GRAY8_BITMAP)
1871 else if(format == WINE_GGO_GRAY16_BITMAP)
1879 for(row = 0; row < height; row++) {
1881 for(col = 0; col < width; col++, ptr++) {
1882 *ptr = (*(unsigned int*)ptr * mult + 128) / 256;
1891 int contour, point = 0, first_pt;
1892 FT_Outline *outline = &ft_face->glyph->outline;
1893 TTPOLYGONHEADER *pph;
1895 DWORD pph_start, cpfx, type;
1897 if(buflen == 0) buf = NULL;
1899 if (needsTransform && buf) {
1900 pFT_Outline_Transform(outline, &transMat);
1903 for(contour = 0; contour < outline->n_contours; contour++) {
1905 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
1908 pph->dwType = TT_POLYGON_TYPE;
1909 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
1911 needed += sizeof(*pph);
1913 while(point <= outline->contours[contour]) {
1914 ppc = (TTPOLYCURVE *)((char *)buf + needed);
1915 type = (outline->tags[point] & FT_Curve_Tag_On) ?
1916 TT_PRIM_LINE : TT_PRIM_QSPLINE;
1920 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
1923 } while(point <= outline->contours[contour] &&
1924 (outline->tags[point] & FT_Curve_Tag_On) ==
1925 (outline->tags[point-1] & FT_Curve_Tag_On));
1926 /* At the end of a contour Windows adds the start point, but
1928 if(point > outline->contours[contour] &&
1929 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
1931 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
1933 } else if(point <= outline->contours[contour] &&
1934 outline->tags[point] & FT_Curve_Tag_On) {
1935 /* add closing pt for bezier */
1937 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
1945 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
1948 pph->cb = needed - pph_start;
1954 /* Convert the quadratic Beziers to cubic Beziers.
1955 The parametric eqn for a cubic Bezier is, from PLRM:
1956 r(t) = at^3 + bt^2 + ct + r0
1957 with the control points:
1962 A quadratic Beizer has the form:
1963 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
1965 So equating powers of t leads to:
1966 r1 = 2/3 p1 + 1/3 p0
1967 r2 = 2/3 p1 + 1/3 p2
1968 and of course r0 = p0, r3 = p2
1971 int contour, point = 0, first_pt;
1972 FT_Outline *outline = &ft_face->glyph->outline;
1973 TTPOLYGONHEADER *pph;
1975 DWORD pph_start, cpfx, type;
1976 FT_Vector cubic_control[4];
1977 if(buflen == 0) buf = NULL;
1979 if (needsTransform && buf) {
1980 pFT_Outline_Transform(outline, &transMat);
1983 for(contour = 0; contour < outline->n_contours; contour++) {
1985 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
1988 pph->dwType = TT_POLYGON_TYPE;
1989 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
1991 needed += sizeof(*pph);
1993 while(point <= outline->contours[contour]) {
1994 ppc = (TTPOLYCURVE *)((char *)buf + needed);
1995 type = (outline->tags[point] & FT_Curve_Tag_On) ?
1996 TT_PRIM_LINE : TT_PRIM_CSPLINE;
1999 if(type == TT_PRIM_LINE) {
2001 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2005 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
2008 /* FIXME: Possible optimization in endpoint calculation
2009 if there are two consecutive curves */
2010 cubic_control[0] = outline->points[point-1];
2011 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
2012 cubic_control[0].x += outline->points[point].x + 1;
2013 cubic_control[0].y += outline->points[point].y + 1;
2014 cubic_control[0].x >>= 1;
2015 cubic_control[0].y >>= 1;
2017 if(point+1 > outline->contours[contour])
2018 cubic_control[3] = outline->points[first_pt];
2020 cubic_control[3] = outline->points[point+1];
2021 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
2022 cubic_control[3].x += outline->points[point].x + 1;
2023 cubic_control[3].y += outline->points[point].y + 1;
2024 cubic_control[3].x >>= 1;
2025 cubic_control[3].y >>= 1;
2028 /* r1 = 1/3 p0 + 2/3 p1
2029 r2 = 1/3 p2 + 2/3 p1 */
2030 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
2031 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
2032 cubic_control[2] = cubic_control[1];
2033 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
2034 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
2035 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
2036 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
2038 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
2039 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
2040 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
2045 } while(point <= outline->contours[contour] &&
2046 (outline->tags[point] & FT_Curve_Tag_On) ==
2047 (outline->tags[point-1] & FT_Curve_Tag_On));
2048 /* At the end of a contour Windows adds the start point,
2049 but only for Beziers and we've already done that.
2051 if(point <= outline->contours[contour] &&
2052 outline->tags[point] & FT_Curve_Tag_On) {
2053 /* This is the closing pt of a bezier, but we've already
2054 added it, so just inc point and carry on */
2061 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2064 pph->cb = needed - pph_start;
2070 FIXME("Unsupported format %d\n", format);
2076 /*************************************************************
2077 * WineEngGetTextMetrics
2080 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
2083 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
2086 if(!font->potm) return FALSE;
2087 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
2089 if (font->aveWidth) {
2090 ptm->tmAveCharWidth = font->aveWidth * font->xform.eM11;
2096 /*************************************************************
2097 * WineEngGetOutlineTextMetrics
2100 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
2101 OUTLINETEXTMETRICW *potm)
2103 FT_Face ft_face = font->ft_face;
2104 UINT needed, lenfam, lensty, ret;
2106 TT_HoriHeader *pHori;
2107 TT_Postscript *pPost;
2108 FT_Fixed x_scale, y_scale;
2109 WCHAR *family_nameW, *style_nameW;
2110 WCHAR spaceW[] = {' ', '\0'};
2113 TRACE("font=%p\n", font);
2116 if(cbSize >= font->potm->otmSize)
2117 memcpy(potm, font->potm, font->potm->otmSize);
2118 return font->potm->otmSize;
2121 needed = sizeof(*potm);
2123 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
2124 family_nameW = strdupW(font->name);
2126 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
2128 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
2129 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
2130 style_nameW, lensty);
2132 /* These names should be read from the TT name table */
2134 /* length of otmpFamilyName */
2137 /* length of otmpFaceName */
2138 if(!strcasecmp(ft_face->style_name, "regular")) {
2139 needed += lenfam; /* just the family name */
2141 needed += lenfam + lensty; /* family + " " + style */
2144 /* length of otmpStyleName */
2147 /* length of otmpFullName */
2148 needed += lenfam + lensty;
2151 x_scale = ft_face->size->metrics.x_scale;
2152 y_scale = ft_face->size->metrics.y_scale;
2154 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2156 FIXME("Can't find OS/2 table - not TT font?\n");
2161 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2163 FIXME("Can't find HHEA table - not TT font?\n");
2168 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
2170 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",
2171 pOS2->usWinAscent, pOS2->usWinDescent,
2172 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
2173 ft_face->ascender, ft_face->descender, ft_face->height,
2174 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
2175 ft_face->bbox.yMax, ft_face->bbox.yMin);
2177 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
2178 font->potm->otmSize = needed;
2180 #define TM font->potm->otmTextMetrics
2183 TM.tmAscent = font->yMax;
2184 TM.tmDescent = -font->yMin;
2185 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
2187 TM.tmAscent = (pFT_MulFix(pOS2->usWinAscent, y_scale) + 32) >> 6;
2188 TM.tmDescent = (pFT_MulFix(pOS2->usWinDescent, y_scale) + 32) >> 6;
2189 TM.tmInternalLeading = (pFT_MulFix(pOS2->usWinAscent + pOS2->usWinDescent
2190 - ft_face->units_per_EM, y_scale) + 32) >> 6;
2193 TM.tmHeight = TM.tmAscent + TM.tmDescent;
2196 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
2198 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
2199 ((pOS2->usWinAscent + pOS2->usWinDescent) -
2200 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
2202 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
2203 if (TM.tmAveCharWidth == 0) {
2204 TM.tmAveCharWidth = 1;
2206 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
2207 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
2209 TM.tmDigitizedAspectX = 300;
2210 TM.tmDigitizedAspectY = 300;
2211 TM.tmFirstChar = pOS2->usFirstCharIndex;
2212 TM.tmLastChar = pOS2->usLastCharIndex;
2213 TM.tmDefaultChar = pOS2->usDefaultChar;
2214 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
2215 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
2216 TM.tmUnderlined = 0; /* entry in OS2 table */
2217 TM.tmStruckOut = 0; /* entry in OS2 table */
2219 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
2220 if(!FT_IS_FIXED_WIDTH(ft_face))
2221 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
2223 TM.tmPitchAndFamily = 0;
2225 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
2226 case PAN_FAMILY_SCRIPT:
2227 TM.tmPitchAndFamily |= FF_SCRIPT;
2229 case PAN_FAMILY_DECORATIVE:
2230 case PAN_FAMILY_PICTORIAL:
2231 TM.tmPitchAndFamily |= FF_DECORATIVE;
2233 case PAN_FAMILY_TEXT_DISPLAY:
2234 if(TM.tmPitchAndFamily == 0) /* fixed */
2235 TM.tmPitchAndFamily = FF_MODERN;
2237 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
2238 case PAN_SERIF_NORMAL_SANS:
2239 case PAN_SERIF_OBTUSE_SANS:
2240 case PAN_SERIF_PERP_SANS:
2241 TM.tmPitchAndFamily |= FF_SWISS;
2244 TM.tmPitchAndFamily |= FF_ROMAN;
2249 TM.tmPitchAndFamily |= FF_DONTCARE;
2252 if(FT_IS_SCALABLE(ft_face))
2253 TM.tmPitchAndFamily |= TMPF_VECTOR;
2254 if(FT_IS_SFNT(ft_face))
2255 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
2257 TM.tmCharSet = font->charset;
2260 font->potm->otmFiller = 0;
2261 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
2262 font->potm->otmfsSelection = pOS2->fsSelection;
2263 font->potm->otmfsType = pOS2->fsType;
2264 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
2265 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
2266 font->potm->otmItalicAngle = 0; /* POST table */
2267 font->potm->otmEMSquare = ft_face->units_per_EM;
2268 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
2269 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
2270 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
2271 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
2272 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
2273 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
2274 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
2275 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
2276 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
2277 font->potm->otmMacAscent = 0; /* where do these come from ? */
2278 font->potm->otmMacDescent = 0;
2279 font->potm->otmMacLineGap = 0;
2280 font->potm->otmusMinimumPPEM = 0; /* TT Header */
2281 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
2282 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
2283 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
2284 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
2285 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
2286 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
2287 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
2288 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
2289 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
2290 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
2292 font->potm->otmsUnderscoreSize = 0;
2293 font->potm->otmsUnderscorePosition = 0;
2295 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
2296 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
2299 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
2300 cp = (char*)font->potm + sizeof(*font->potm);
2301 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
2302 strcpyW((WCHAR*)cp, family_nameW);
2304 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
2305 strcpyW((WCHAR*)cp, style_nameW);
2307 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
2308 strcpyW((WCHAR*)cp, family_nameW);
2309 if(strcasecmp(ft_face->style_name, "regular")) {
2310 strcatW((WCHAR*)cp, spaceW);
2311 strcatW((WCHAR*)cp, style_nameW);
2312 cp += lenfam + lensty;
2315 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
2316 strcpyW((WCHAR*)cp, family_nameW);
2317 strcatW((WCHAR*)cp, spaceW);
2318 strcatW((WCHAR*)cp, style_nameW);
2321 if(potm && needed <= cbSize)
2322 memcpy(potm, font->potm, font->potm->otmSize);
2325 HeapFree(GetProcessHeap(), 0, style_nameW);
2326 HeapFree(GetProcessHeap(), 0, family_nameW);
2332 /*************************************************************
2333 * WineEngGetCharWidth
2336 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
2341 FT_UInt glyph_index;
2343 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
2345 for(c = firstChar; c <= lastChar; c++) {
2346 glyph_index = get_glyph_index(font, c);
2347 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
2348 &gm, 0, NULL, NULL);
2349 buffer[c - firstChar] = font->gm[glyph_index].adv;
2354 /*************************************************************
2355 * WineEngGetTextExtentPoint
2358 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
2364 FT_UInt glyph_index;
2366 TRACE("%p, %s, %d, %p\n", font, debugstr_wn(wstr, count), count,
2370 WineEngGetTextMetrics(font, &tm);
2371 size->cy = tm.tmHeight;
2373 for(idx = 0; idx < count; idx++) {
2374 glyph_index = get_glyph_index(font, wstr[idx]);
2375 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
2376 &gm, 0, NULL, NULL);
2377 size->cx += font->gm[glyph_index].adv;
2379 TRACE("return %ld,%ld\n", size->cx, size->cy);
2383 /*************************************************************
2384 * WineEngGetTextExtentPointI
2387 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
2394 TRACE("%p, %p, %d, %p\n", font, indices, count, size);
2397 WineEngGetTextMetrics(font, &tm);
2398 size->cy = tm.tmHeight;
2400 for(idx = 0; idx < count; idx++) {
2401 WineEngGetGlyphOutline(font, indices[idx],
2402 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
2404 size->cx += font->gm[indices[idx]].adv;
2406 TRACE("return %ld,%ld\n", size->cx, size->cy);
2410 /*************************************************************
2411 * WineEngGetFontData
2414 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
2417 FT_Face ft_face = font->ft_face;
2421 TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
2422 font, table, offset, buf, cbData);
2424 if(!FT_IS_SFNT(ft_face))
2432 if(table) { /* MS tags differ in endidness from FT ones */
2433 table = table >> 24 | table << 24 |
2434 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
2437 /* If the FT_Load_Sfnt_Table function is there we'll use it */
2438 if(pFT_Load_Sfnt_Table)
2439 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
2440 else { /* Do it the hard way */
2441 TT_Face tt_face = (TT_Face) ft_face;
2442 SFNT_Interface *sfnt;
2443 if (FT_Version.major==2 && FT_Version.minor==0)
2446 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
2450 /* A field was added in the middle of the structure in 2.1.x */
2451 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
2453 err = sfnt->load_any(tt_face, table, offset, buf, &len);
2456 TRACE("Can't find table %08lx.\n", table);
2462 /*************************************************************
2463 * WineEngGetTextFace
2466 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
2469 lstrcpynW(str, font->name, count);
2470 return strlenW(font->name);
2472 return strlenW(font->name) + 1;
2475 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
2477 if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
2478 return font->charset;
2481 #else /* HAVE_FREETYPE */
2483 BOOL WineEngInit(void)
2487 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
2491 BOOL WineEngDestroyFontInstance(HFONT hfont)
2496 DWORD WineEngEnumFonts(LPLOGFONTW plf, DEVICEFONTENUMPROC proc, LPARAM lparam)
2501 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
2502 LPWORD pgi, DWORD flags)
2507 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
2508 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
2511 ERR("called but we don't have FreeType\n");
2515 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
2517 ERR("called but we don't have FreeType\n");
2521 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
2522 OUTLINETEXTMETRICW *potm)
2524 ERR("called but we don't have FreeType\n");
2528 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
2531 ERR("called but we don't have FreeType\n");
2535 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
2538 ERR("called but we don't have FreeType\n");
2542 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
2545 ERR("called but we don't have FreeType\n");
2549 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
2552 ERR("called but we don't have FreeType\n");
2556 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
2558 ERR("called but we don't have FreeType\n");
2562 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2568 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2574 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
2577 return DEFAULT_CHARSET;
2580 #endif /* HAVE_FREETYPE */