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_FREETYPE_FREETYPE_H
49 #include <freetype/freetype.h>
51 #ifdef HAVE_FREETYPE_FTGLYPH_H
52 #include <freetype/ftglyph.h>
54 #ifdef HAVE_FREETYPE_TTTABLES_H
55 #include <freetype/tttables.h>
57 #ifdef HAVE_FREETYPE_FTSNAMES_H
58 #include <freetype/ftsnames.h>
60 # ifdef HAVE_FREETYPE_FTNAMES_H
61 # include <freetype/ftnames.h>
64 #ifdef HAVE_FREETYPE_TTNAMEID_H
65 #include <freetype/ttnameid.h>
67 #ifdef HAVE_FREETYPE_FTOUTLN_H
68 #include <freetype/ftoutln.h>
70 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
71 #include <freetype/internal/sfnt.h>
73 #ifdef HAVE_FREETYPE_FTTRIGON_H
74 #include <freetype/fttrigon.h>
77 #ifndef SONAME_LIBFREETYPE
78 #define SONAME_LIBFREETYPE "libfreetype.so"
81 static FT_Library library = 0;
88 static FT_Version_t FT_Version;
90 static void *ft_handle = NULL;
92 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
94 MAKE_FUNCPTR(FT_Done_Face);
95 MAKE_FUNCPTR(FT_Get_Char_Index);
96 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
97 MAKE_FUNCPTR(FT_Init_FreeType);
98 MAKE_FUNCPTR(FT_Load_Glyph);
99 MAKE_FUNCPTR(FT_MulFix);
100 MAKE_FUNCPTR(FT_New_Face);
101 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
102 MAKE_FUNCPTR(FT_Outline_Transform);
103 MAKE_FUNCPTR(FT_Outline_Translate);
104 MAKE_FUNCPTR(FT_Select_Charmap);
105 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
106 MAKE_FUNCPTR(FT_Sin);
107 MAKE_FUNCPTR(FT_Vector_Rotate);
109 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
110 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
112 #define GET_BE_WORD(ptr) MAKEWORD( ((BYTE *)(ptr))[1], ((BYTE *)(ptr))[0] )
114 typedef struct tagFace {
121 FT_Fixed font_version;
122 struct tagFace *next;
123 struct tagFamily *family;
126 typedef struct tagFamily {
129 struct tagFamily *next;
134 INT adv; /* These three hold to widths of the unrotated chars */
153 OUTLINETEXTMETRICW *potm;
155 struct tagGdiFont *next;
158 #define INIT_GM_SIZE 128
160 static GdiFont GdiFontList = NULL;
162 static Family *FontList = NULL;
164 static WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ',
165 'R','o','m','a','n','\0'};
166 static WCHAR defSans[] = {'A','r','i','a','l','\0'};
167 static WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
169 static WCHAR defSystem[] = {'A','r','i','a','l','\0'};
170 static WCHAR SystemW[] = {'S','y','s','t','e','m','\0'};
171 static WCHAR MSSansSerifW[] = {'M','S',' ','S','a','n','s',' ',
172 'S','e','r','i','f','\0'};
173 static WCHAR HelvW[] = {'H','e','l','v','\0'};
175 static WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
176 static WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
177 static WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
178 static WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
179 static WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
180 'E','u','r','o','p','e','a','n','\0'};
181 static WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
182 static WCHAR GreekW[] = {'G','r','e','e','k','\0'};
183 static WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
184 static WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
185 static WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
186 static WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
187 static WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
188 static WCHAR ThaiW[] = {'T','h','a','i','\0'};
189 static WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
190 static WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
191 static WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
193 static WCHAR *ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
203 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
211 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
220 typedef struct tagFontSubst {
223 struct tagFontSubst *next;
226 static FontSubst *substlist = NULL;
227 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
229 static BOOL AddFontFileToList(char *file, char *fake_family)
234 WCHAR *FamilyW, *StyleW;
236 Family *family = FontList;
237 Family **insert = &FontList;
238 Face **insertface, *next;
240 FT_Long face_index = 0, num_faces;
244 char *family_name = fake_family;
246 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
247 if((err = pFT_New_Face(library, file, face_index, &ft_face)) != 0) {
248 WARN("Unable to load font file %s err = %x\n", debugstr_a(file), err);
252 if(!FT_IS_SFNT(ft_face)) { /* for now we'll skip everything but TT/OT */
253 pFT_Done_Face(ft_face);
256 if(!pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2) ||
257 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
258 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head))) {
259 TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
260 "Skipping this font.\n", debugstr_a(file));
261 pFT_Done_Face(ft_face);
265 if(!ft_face->family_name || !ft_face->style_name) {
266 TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file));
267 pFT_Done_Face(ft_face);
272 family_name = ft_face->family_name;
274 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
275 FamilyW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
276 MultiByteToWideChar(CP_ACP, 0, family_name, -1, FamilyW, len);
279 if(!strcmpW(family->FamilyName, FamilyW))
281 insert = &family->next;
282 family = family->next;
285 family = *insert = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
286 family->FamilyName = FamilyW;
287 family->FirstFace = NULL;
290 HeapFree(GetProcessHeap(), 0, FamilyW);
293 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
294 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
295 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
298 for(insertface = &family->FirstFace; *insertface;
299 insertface = &(*insertface)->next) {
300 if(!strcmpW((*insertface)->StyleName, StyleW)) {
301 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
302 debugstr_w(family->FamilyName), debugstr_w(StyleW),
303 (*insertface)->font_version, pHeader->Font_Revision);
306 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
307 HeapFree(GetProcessHeap(), 0, StyleW);
308 pFT_Done_Face(ft_face);
311 if(pHeader->Font_Revision <= (*insertface)->font_version) {
312 TRACE("Original font is newer so skipping this one\n");
313 HeapFree(GetProcessHeap(), 0, StyleW);
314 pFT_Done_Face(ft_face);
317 TRACE("Replacing original with this one\n");
318 next = (*insertface)->next;
319 HeapFree(GetProcessHeap(), 0, (*insertface)->file);
320 HeapFree(GetProcessHeap(), 0, (*insertface)->StyleName);
321 HeapFree(GetProcessHeap(), 0, *insertface);
326 *insertface = HeapAlloc(GetProcessHeap(), 0, sizeof(**insertface));
327 (*insertface)->StyleName = StyleW;
328 (*insertface)->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
329 strcpy((*insertface)->file, file);
330 (*insertface)->face_index = face_index;
331 (*insertface)->next = next;
332 (*insertface)->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
333 (*insertface)->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
334 (*insertface)->font_version = pHeader->Font_Revision;
335 (*insertface)->family = family;
337 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
339 (*insertface)->fs.fsCsb[0] = pOS2->ulCodePageRange1;
340 (*insertface)->fs.fsCsb[1] = pOS2->ulCodePageRange2;
341 (*insertface)->fs.fsUsb[0] = pOS2->ulUnicodeRange1;
342 (*insertface)->fs.fsUsb[1] = pOS2->ulUnicodeRange2;
343 (*insertface)->fs.fsUsb[2] = pOS2->ulUnicodeRange3;
344 (*insertface)->fs.fsUsb[3] = pOS2->ulUnicodeRange4;
346 (*insertface)->fs.fsCsb[0] = (*insertface)->fs.fsCsb[1] = 0;
347 (*insertface)->fs.fsUsb[0] = 0;
348 (*insertface)->fs.fsUsb[1] = 0;
349 (*insertface)->fs.fsUsb[2] = 0;
350 (*insertface)->fs.fsUsb[3] = 0;
352 TRACE("fsCsb = %08lx %08lx/%08lx %08lx %08lx %08lx\n",
353 (*insertface)->fs.fsCsb[0], (*insertface)->fs.fsCsb[1],
354 (*insertface)->fs.fsUsb[0], (*insertface)->fs.fsUsb[1],
355 (*insertface)->fs.fsUsb[2], (*insertface)->fs.fsUsb[3]);
357 if((*insertface)->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
358 for(i = 0; i < ft_face->num_charmaps &&
359 !(*insertface)->fs.fsCsb[0]; i++) {
360 switch(ft_face->charmaps[i]->encoding) {
361 case ft_encoding_unicode:
362 (*insertface)->fs.fsCsb[0] = 1;
364 case ft_encoding_symbol:
365 (*insertface)->fs.fsCsb[0] = 1L << 31;
373 if((*insertface)->fs.fsCsb[0] & ~(1L << 31))
374 have_installed_roman_font = TRUE;
376 num_faces = ft_face->num_faces;
377 pFT_Done_Face(ft_face);
378 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
380 } while(num_faces > ++face_index);
384 static void DumpFontList(void)
389 for(family = FontList; family; family = family->next) {
390 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
391 for(face = family->FirstFace; face; face = face->next) {
392 TRACE("\t%s\n", debugstr_w(face->StyleName));
398 static void DumpSubstList(void)
402 for(psub = substlist; psub; psub = psub->next)
403 if(psub->from.charset != -1 || psub->to.charset != -1)
404 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
405 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
407 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
408 debugstr_w(psub->to.name));
412 static LPWSTR strdupW(LPWSTR p)
415 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
416 ret = HeapAlloc(GetProcessHeap(), 0, len);
421 static void split_subst_info(NameCs *nc, LPSTR str)
423 CHAR *p = strrchr(str, ',');
428 nc->charset = strtol(p+1, NULL, 10);
431 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
432 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
433 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
436 static void LoadSubstList(void)
438 FontSubst *psub, **ppsub;
440 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
445 for(psub = substlist; psub;) {
447 HeapFree(GetProcessHeap(), 0, psub->to.name);
448 HeapFree(GetProcessHeap(), 0, psub->from.name);
451 HeapFree(GetProcessHeap(), 0, ptmp);
456 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
457 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
458 &hkey) == ERROR_SUCCESS) {
460 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
461 &valuelen, &datalen, NULL, NULL);
463 valuelen++; /* returned value doesn't include room for '\0' */
464 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
465 data = HeapAlloc(GetProcessHeap(), 0, datalen);
470 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
471 &dlen) == ERROR_SUCCESS) {
472 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
474 *ppsub = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppsub));
475 (*ppsub)->next = NULL;
476 split_subst_info(&((*ppsub)->from), value);
477 split_subst_info(&((*ppsub)->to), data);
479 /* Win 2000 doesn't allow mapping between different charsets
480 or mapping of DEFAULT_CHARSET */
481 if(((*ppsub)->to.charset != (*ppsub)->from.charset) ||
482 (*ppsub)->to.charset == DEFAULT_CHARSET) {
483 HeapFree(GetProcessHeap(), 0, (*ppsub)->to.name);
484 HeapFree(GetProcessHeap(), 0, (*ppsub)->from.name);
485 HeapFree(GetProcessHeap(), 0, *ppsub);
488 ppsub = &((*ppsub)->next);
490 /* reset dlen and vlen */
494 HeapFree(GetProcessHeap(), 0, data);
495 HeapFree(GetProcessHeap(), 0, value);
500 /***********************************************************
501 * The replacement list is a way to map an entire font
502 * family onto another family. For example adding
504 * [HKLM\Software\Wine\Wine\FontReplacements]
505 * "Wingdings"="Winedings"
507 * would enumerate the Winedings font both as Winedings and
508 * Wingdings. However if a real Wingdings font is present the
509 * replacement does not take place.
512 static void LoadReplaceList(void)
515 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
520 WCHAR old_nameW[200];
522 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
523 "Software\\Wine\\Wine\\FontReplacements",
524 &hkey) == ERROR_SUCCESS) {
526 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
527 &valuelen, &datalen, NULL, NULL);
529 valuelen++; /* returned value doesn't include room for '\0' */
530 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
531 data = HeapAlloc(GetProcessHeap(), 0, datalen);
535 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
536 &dlen) == ERROR_SUCCESS) {
537 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
538 /* "NewName"="Oldname" */
539 if(!MultiByteToWideChar(CP_ACP, 0, data, -1, old_nameW, sizeof(old_nameW)))
542 /* Find the old family and hence all of the font files
544 for(family = FontList; family; family = family->next) {
545 if(!strcmpiW(family->FamilyName, old_nameW)) {
546 for(face = family->FirstFace; face; face = face->next) {
547 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
548 debugstr_w(face->StyleName), value);
549 /* Now add a new entry with the new family name */
550 AddFontFileToList(face->file, value);
555 /* reset dlen and vlen */
559 HeapFree(GetProcessHeap(), 0, data);
560 HeapFree(GetProcessHeap(), 0, value);
566 static BOOL ReadFontDir(char *dirname)
572 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
574 dir = opendir(dirname);
576 ERR("Can't open directory %s\n", debugstr_a(dirname));
579 while((dent = readdir(dir)) != NULL) {
582 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
585 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
587 sprintf(path, "%s/%s", dirname, dent->d_name);
589 if(stat(path, &statbuf) == -1)
591 WARN("Can't stat %s\n", debugstr_a(path));
594 if(S_ISDIR(statbuf.st_mode))
597 AddFontFileToList(path, NULL);
603 /*************************************************************
604 * WineEngAddFontResourceEx
607 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
609 if (ft_handle) /* do it only if we have freetype up and running */
611 DWORD len = WideCharToMultiByte(CP_ACP, 0, file, -1, NULL, 0, NULL, NULL);
612 LPSTR fileA = HeapAlloc(GetProcessHeap(), 0, len);
613 char unixname[MAX_PATH];
614 WideCharToMultiByte(CP_ACP, 0, file, -1, fileA, len, NULL, NULL);
617 FIXME("Ignoring flags %lx\n", flags);
619 if(wine_get_unix_file_name(fileA, unixname, sizeof(unixname)))
620 AddFontFileToList(unixname, NULL);
621 HeapFree(GetProcessHeap(), 0, fileA);
626 /*************************************************************
627 * WineEngRemoveFontResourceEx
630 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
636 /*************************************************************
639 * Initialize FreeType library and create a list of available faces
641 BOOL WineEngInit(void)
644 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
647 char windowsdir[MAX_PATH];
648 char unixname[MAX_PATH];
652 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
655 "Wine cannot find the FreeType font library. To enable Wine to\n"
656 "use TrueType fonts please install a version of FreeType greater than\n"
657 "or equal to 2.0.5.\n"
658 "http://www.freetype.org\n");
662 #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;}
665 LOAD_FUNCPTR(FT_Done_Face)
666 LOAD_FUNCPTR(FT_Get_Char_Index)
667 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
668 LOAD_FUNCPTR(FT_Init_FreeType)
669 LOAD_FUNCPTR(FT_Load_Glyph)
670 LOAD_FUNCPTR(FT_MulFix)
671 LOAD_FUNCPTR(FT_New_Face)
672 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
673 LOAD_FUNCPTR(FT_Outline_Transform)
674 LOAD_FUNCPTR(FT_Outline_Translate)
675 LOAD_FUNCPTR(FT_Select_Charmap)
676 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
678 LOAD_FUNCPTR(FT_Vector_Rotate)
681 /* Don't warn if this one is missing */
682 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
683 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
685 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
686 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
687 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
688 <= 2.0.3 has FT_Sqrt64 */
692 if(pFT_Init_FreeType(&library) != 0) {
693 ERR("Can't init FreeType library\n");
694 wine_dlclose(ft_handle, NULL, 0);
698 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
699 if (pFT_Library_Version)
701 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
703 if (FT_Version.major<=0)
709 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
711 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
712 GetWindowsDirectoryA(windowsdir, sizeof(windowsdir));
713 strcat(windowsdir, "\\Fonts");
714 if(wine_get_unix_file_name(windowsdir, unixname, sizeof(unixname)))
715 ReadFontDir(unixname);
717 /* now look under HKLM\Software\Microsoft\Windows\CurrentVersion\Fonts
718 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
719 full path as the entry */
720 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
721 "Software\\Microsoft\\Windows\\CurrentVersion\\Fonts",
722 &hkey) == ERROR_SUCCESS) {
723 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
724 &valuelen, &datalen, NULL, NULL);
726 valuelen++; /* returned value doesn't include room for '\0' */
727 value = HeapAlloc(GetProcessHeap(), 0, valuelen);
728 data = HeapAlloc(GetProcessHeap(), 0, datalen);
732 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
733 &dlen) == ERROR_SUCCESS) {
734 if(((LPSTR)data)[0] && ((LPSTR)data)[1] == ':')
735 if(wine_get_unix_file_name((LPSTR)data, unixname, sizeof(unixname)))
736 AddFontFileToList(unixname, NULL);
738 /* reset dlen and vlen */
742 HeapFree(GetProcessHeap(), 0, data);
743 HeapFree(GetProcessHeap(), 0, value);
748 /* then look in any directories that we've specified in the config file */
749 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
750 "Software\\Wine\\Wine\\Config\\FontDirs",
751 &hkey) == ERROR_SUCCESS) {
753 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
754 &valuelen, &datalen, NULL, NULL);
756 valuelen++; /* returned value doesn't include room for '\0' */
757 value = HeapAlloc(GetProcessHeap(), 0, valuelen);
758 data = HeapAlloc(GetProcessHeap(), 0, datalen);
763 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
764 &dlen) == ERROR_SUCCESS) {
765 TRACE("Got %s=%s\n", value, (LPSTR)data);
766 ReadFontDir((LPSTR)data);
767 /* reset dlen and vlen */
771 HeapFree(GetProcessHeap(), 0, data);
772 HeapFree(GetProcessHeap(), 0, value);
783 "Wine cannot find certain functions that it needs inside the FreeType\n"
784 "font library. To enable Wine to use TrueType fonts please upgrade\n"
785 "FreeType to at least version 2.0.5.\n"
786 "http://www.freetype.org\n");
787 wine_dlclose(ft_handle, NULL, 0);
793 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
798 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
800 if(height == 0) height = 16;
802 /* Calc. height of EM square:
804 * For +ve lfHeight we have
805 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
806 * Re-arranging gives:
807 * ppem = units_per_em * lfheight / (winAscent + winDescent)
809 * For -ve lfHeight we have
811 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
812 * with il = winAscent + winDescent - units_per_em]
817 ppem = ft_face->units_per_EM * height /
818 (pOS2->usWinAscent + pOS2->usWinDescent);
825 static LONG load_VDMX(GdiFont, LONG);
827 static FT_Face OpenFontFile(GdiFont font, char *file, FT_Long face_index, LONG height)
833 err = pFT_New_Face(library, file, face_index, &ft_face);
835 ERR("FT_New_Face rets %d\n", err);
839 /* set it here, as load_VDMX needs it */
840 font->ft_face = ft_face;
842 /* load the VDMX table if we have one */
843 ppem = load_VDMX(font, height);
845 ppem = calc_ppem_for_height(ft_face, height);
847 pFT_Set_Pixel_Sizes(ft_face, 0, ppem);
853 static int get_nearest_charset(Face *face)
855 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
856 a single face with the requested charset. The idea is to check if
857 the selected font supports the current ANSI codepage, if it does
858 return the corresponding charset, else return the first charset */
861 int acp = GetACP(), i;
864 if(TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE))
865 if(csi.fs.fsCsb[0] & face->fs.fsCsb[0])
866 return csi.ciCharset;
868 for(i = 0; i < 32; i++) {
870 if(face->fs.fsCsb[0] & fs0) {
871 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG))
872 return csi.ciCharset;
874 FIXME("TCI failing on %lx\n", fs0);
878 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08lx file = %s\n",
879 face->fs.fsCsb[0], face->file);
880 return DEFAULT_CHARSET;
883 static GdiFont alloc_font(void)
885 GdiFont ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
886 ret->gmsize = INIT_GM_SIZE;
887 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
888 ret->gmsize * sizeof(*ret->gm));
891 ret->xform.eM11 = ret->xform.eM22 = 1.0;
895 static void free_font(GdiFont font)
897 if (font->ft_face) pFT_Done_Face(font->ft_face);
898 if (font->potm) HeapFree(GetProcessHeap(), 0, font->potm);
899 if (font->name) HeapFree(GetProcessHeap(), 0, font->name);
900 HeapFree(GetProcessHeap(), 0, font->gm);
901 HeapFree(GetProcessHeap(), 0, font);
905 /*************************************************************
908 * load the vdmx entry for the specified height
911 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
912 ( ( (FT_ULong)_x4 << 24 ) | \
913 ( (FT_ULong)_x3 << 16 ) | \
914 ( (FT_ULong)_x2 << 8 ) | \
917 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
927 static LONG load_VDMX(GdiFont font, LONG height)
929 BYTE hdr[6], tmp[2], group[4];
930 BYTE devXRatio, devYRatio;
931 USHORT numRecs, numRatios;
936 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
938 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
941 /* FIXME: need the real device aspect ratio */
945 numRecs = GET_BE_WORD(&hdr[2]);
946 numRatios = GET_BE_WORD(&hdr[4]);
948 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
949 for(i = 0; i < numRatios; i++) {
952 offset = (3 * 2) + (i * sizeof(Ratios));
953 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
956 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
958 if(ratio.bCharSet != 1)
961 if((ratio.xRatio == 0 &&
962 ratio.yStartRatio == 0 &&
963 ratio.yEndRatio == 0) ||
964 (devXRatio == ratio.xRatio &&
965 devYRatio >= ratio.yStartRatio &&
966 devYRatio <= ratio.yEndRatio))
968 offset = (3 * 2) + (numRatios * 4) + (i * 2);
969 WineEngGetFontData(font, MS_VDMX_TAG, offset, tmp, 2);
970 offset = GET_BE_WORD(tmp);
976 FIXME("No suitable ratio found\n");
980 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, group, 4) != GDI_ERROR) {
985 recs = GET_BE_WORD(group);
989 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
991 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
992 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
993 if(result == GDI_ERROR) {
994 FIXME("Failed to retrieve vTable\n");
999 for(i = 0; i < recs; i++) {
1000 SHORT yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1001 SHORT yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1002 ppem = GET_BE_WORD(&vTable[i * 6]);
1004 if(yMax + -yMin == height) {
1007 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1010 if(yMax + -yMin > height) {
1013 goto end; /* failed */
1015 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1016 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1017 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1023 TRACE("ppem not found for height %ld\n", height);
1027 if(ppem < startsz || ppem > endsz)
1030 for(i = 0; i < recs; i++) {
1032 yPelHeight = GET_BE_WORD(&vTable[i * 6]);
1034 if(yPelHeight > ppem)
1037 if(yPelHeight == ppem) {
1038 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1039 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1040 TRACE("ppem %ld found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
1046 HeapFree(GetProcessHeap(), 0, vTable);
1053 /*************************************************************
1054 * WineEngCreateFontInstance
1057 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
1061 Family *family = NULL;
1066 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
1068 TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
1069 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
1070 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
1073 /* check the cache first */
1074 for(ret = GdiFontList; ret; ret = ret->next) {
1075 if(ret->hfont == hfont && !memcmp(&ret->xform, &dc->xformWorld2Vport, offsetof(XFORM, eDx))) {
1076 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
1081 if(!FontList || !have_installed_roman_font) /* No fonts installed */
1083 TRACE("No fonts installed\n");
1088 memcpy(&ret->xform, &dc->xformWorld2Vport, sizeof(XFORM));
1090 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
1091 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
1092 original value lfCharSet. Note this is a special case for
1093 Symbol and doesn't happen at least for "Wingdings*" */
1095 if(!strcmpiW(lf.lfFaceName, SymbolW))
1096 lf.lfCharSet = SYMBOL_CHARSET;
1098 if(!TranslateCharsetInfo((DWORD*)(INT)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
1099 switch(lf.lfCharSet) {
1100 case DEFAULT_CHARSET:
1101 csi.fs.fsCsb[0] = 0;
1104 FIXME("Untranslated charset %d\n", lf.lfCharSet);
1105 csi.fs.fsCsb[0] = 0;
1110 if(lf.lfFaceName[0] != '\0') {
1112 for(psub = substlist; psub; psub = psub->next)
1113 if(!strcmpiW(lf.lfFaceName, psub->from.name) &&
1114 (psub->from.charset == -1 ||
1115 psub->from.charset == lf.lfCharSet))
1118 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
1119 debugstr_w(psub->to.name));
1120 strcpyW(lf.lfFaceName, psub->to.name);
1123 /* We want a match on name and charset or just name if
1124 charset was DEFAULT_CHARSET. If the latter then
1125 we fixup the returned charset later in get_nearest_charset
1126 where we'll either use the charset of the current ansi codepage
1127 or if that's unavailable the first charset that the font supports.
1129 for(family = FontList; family; family = family->next) {
1130 if(!strcmpiW(family->FamilyName, lf.lfFaceName))
1131 if((csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0]) || !csi.fs.fsCsb[0])
1135 if(!family) { /* do other aliases here */
1136 if(!strcmpiW(lf.lfFaceName, SystemW))
1137 strcpyW(lf.lfFaceName, defSystem);
1138 else if(!strcmpiW(lf.lfFaceName, MSSansSerifW))
1139 strcpyW(lf.lfFaceName, defSans);
1140 else if(!strcmpiW(lf.lfFaceName, HelvW))
1141 strcpyW(lf.lfFaceName, defSans);
1145 for(family = FontList; family; family = family->next) {
1146 if(!strcmpiW(family->FamilyName, lf.lfFaceName))
1147 if((csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0]) || !csi.fs.fsCsb[0])
1155 /* If requested charset was DEFAULT_CHARSET then try using charset
1156 corresponding to the current ansi codepage */
1157 if(!csi.fs.fsCsb[0]) {
1159 if(!TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE)) {
1160 FIXME("TCI failed on codepage %d\n", acp);
1161 csi.fs.fsCsb[0] = 0;
1163 lf.lfCharSet = csi.ciCharset;
1165 if(lf.lfPitchAndFamily & FIXED_PITCH ||
1166 lf.lfPitchAndFamily & FF_MODERN)
1167 strcpyW(lf.lfFaceName, defFixed);
1168 else if(lf.lfPitchAndFamily & FF_ROMAN)
1169 strcpyW(lf.lfFaceName, defSerif);
1170 else if(lf.lfPitchAndFamily & FF_SWISS)
1171 strcpyW(lf.lfFaceName, defSans);
1173 strcpyW(lf.lfFaceName, defSans);
1174 for(family = FontList; family; family = family->next) {
1175 if(!strcmpiW(family->FamilyName, lf.lfFaceName) &&
1176 (csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0]))
1182 for(family = FontList; family; family = family->next) {
1183 if(csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0])
1190 csi.fs.fsCsb[0] = 0;
1191 FIXME("just using first face for now\n");
1194 it = lf.lfItalic ? 1 : 0;
1195 bd = lf.lfWeight > 550 ? 1 : 0;
1197 for(face = family->FirstFace; face; face = face->next) {
1198 if(!(face->Italic ^ it) && !(face->Bold ^ bd))
1202 face = family->FirstFace;
1203 if(it && !face->Italic) ret->fake_italic = TRUE;
1204 if(bd && !face->Bold) ret->fake_bold = TRUE;
1207 memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
1210 ret->charset = lf.lfCharSet;
1212 ret->charset = get_nearest_charset(face);
1214 TRACE("Chosen: %s %s\n", debugstr_w(family->FamilyName),
1215 debugstr_w(face->StyleName));
1217 ret->ft_face = OpenFontFile(ret, face->file, face->face_index,
1219 -abs(INTERNAL_YWSTODS(dc,lf.lfHeight)) :
1220 abs(INTERNAL_YWSTODS(dc, lf.lfHeight)));
1227 if(ret->charset == SYMBOL_CHARSET)
1228 pFT_Select_Charmap(ret->ft_face, ft_encoding_symbol);
1229 ret->orientation = lf.lfOrientation;
1230 ret->name = strdupW(family->FamilyName);
1232 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
1234 ret->next = GdiFontList;
1240 static void DumpGdiFontList(void)
1244 TRACE("---------- gdiFont Cache ----------\n");
1245 for(gdiFont = GdiFontList; gdiFont; gdiFont = gdiFont->next) {
1247 GetObjectW( gdiFont->hfont, sizeof(lf), &lf );
1248 TRACE("gdiFont=%p hfont=%p (%s)\n",
1249 gdiFont, gdiFont->hfont, debugstr_w(lf.lfFaceName));
1253 /*************************************************************
1254 * WineEngDestroyFontInstance
1256 * free the gdiFont associated with this handle
1259 BOOL WineEngDestroyFontInstance(HFONT handle)
1262 GdiFont gdiPrev = NULL;
1265 TRACE("destroying hfont=%p\n", handle);
1269 gdiFont = GdiFontList;
1271 if(gdiFont->hfont == handle) {
1273 gdiPrev->next = gdiFont->next;
1275 gdiFont = gdiPrev->next;
1277 GdiFontList = gdiFont->next;
1279 gdiFont = GdiFontList;
1284 gdiFont = gdiFont->next;
1290 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
1291 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
1293 OUTLINETEXTMETRICW *potm;
1295 GdiFont font = alloc_font();
1297 if (!(font->ft_face = OpenFontFile(font, face->file, face->face_index, 100)))
1303 font->name = strdupW(face->family->FamilyName);
1305 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
1307 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
1308 potm = HeapAlloc(GetProcessHeap(), 0, size);
1309 WineEngGetOutlineTextMetrics(font, size, potm);
1311 #define TM potm->otmTextMetrics
1313 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = TM.tmHeight;
1314 pntm->ntmTm.tmAscent = TM.tmAscent;
1315 pntm->ntmTm.tmDescent = TM.tmDescent;
1316 pntm->ntmTm.tmInternalLeading = TM.tmInternalLeading;
1317 pntm->ntmTm.tmExternalLeading = TM.tmExternalLeading;
1318 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = TM.tmAveCharWidth;
1319 pntm->ntmTm.tmMaxCharWidth = TM.tmMaxCharWidth;
1320 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = TM.tmWeight;
1321 pntm->ntmTm.tmOverhang = TM.tmOverhang;
1322 pntm->ntmTm.tmDigitizedAspectX = TM.tmDigitizedAspectX;
1323 pntm->ntmTm.tmDigitizedAspectY = TM.tmDigitizedAspectY;
1324 pntm->ntmTm.tmFirstChar = TM.tmFirstChar;
1325 pntm->ntmTm.tmLastChar = TM.tmLastChar;
1326 pntm->ntmTm.tmDefaultChar = TM.tmDefaultChar;
1327 pntm->ntmTm.tmBreakChar = TM.tmBreakChar;
1328 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = TM.tmItalic;
1329 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = TM.tmUnderlined;
1330 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = TM.tmStruckOut;
1331 pntm->ntmTm.tmPitchAndFamily = TM.tmPitchAndFamily;
1332 pelf->elfLogFont.lfPitchAndFamily = (TM.tmPitchAndFamily & 0xf1) + 1;
1333 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = TM.tmCharSet;
1334 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
1335 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
1336 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
1338 pntm->ntmTm.ntmFlags = TM.tmItalic ? NTM_ITALIC : 0;
1339 if(TM.tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
1340 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
1342 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
1343 pntm->ntmTm.ntmCellHeight = 0;
1344 pntm->ntmTm.ntmAvgWidth = 0;
1346 *ptype = TM.tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
1347 if(!(TM.tmPitchAndFamily & TMPF_VECTOR))
1348 *ptype |= RASTER_FONTTYPE;
1351 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
1353 strncpyW(pelf->elfLogFont.lfFaceName,
1354 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
1356 strncpyW(pelf->elfFullName,
1357 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
1359 strncpyW(pelf->elfStyle,
1360 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
1362 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
1364 HeapFree(GetProcessHeap(), 0, potm);
1369 /*************************************************************
1373 DWORD WineEngEnumFonts(LPLOGFONTW plf, DEVICEFONTENUMPROC proc,
1379 NEWTEXTMETRICEXW ntm;
1380 DWORD type, ret = 1;
1386 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
1388 if(plf->lfFaceName[0]) {
1390 for(psub = substlist; psub; psub = psub->next)
1391 if(!strcmpiW(plf->lfFaceName, psub->from.name) &&
1392 (psub->from.charset == -1 ||
1393 psub->from.charset == plf->lfCharSet))
1396 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
1397 debugstr_w(psub->to.name));
1398 memcpy(&lf, plf, sizeof(lf));
1399 strcpyW(lf.lfFaceName, psub->to.name);
1402 for(family = FontList; family; family = family->next) {
1403 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
1404 for(face = family->FirstFace; face; face = face->next) {
1405 GetEnumStructs(face, &elf, &ntm, &type);
1406 for(i = 0; i < 32; i++) {
1407 if(face->fs.fsCsb[0] & (1L << i)) {
1408 fs.fsCsb[0] = 1L << i;
1410 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
1412 csi.ciCharset = DEFAULT_CHARSET;
1413 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
1414 if(csi.ciCharset != DEFAULT_CHARSET) {
1415 elf.elfLogFont.lfCharSet =
1416 ntm.ntmTm.tmCharSet = csi.ciCharset;
1418 strcpyW(elf.elfScript, ElfScriptsW[i]);
1420 FIXME("Unknown elfscript for bit %d\n", i);
1421 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
1422 debugstr_w(elf.elfLogFont.lfFaceName),
1423 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
1424 csi.ciCharset, type, debugstr_w(elf.elfScript),
1425 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
1426 ntm.ntmTm.ntmFlags);
1427 ret = proc(&elf, &ntm, type, lparam);
1436 for(family = FontList; family; family = family->next) {
1437 GetEnumStructs(family->FirstFace, &elf, &ntm, &type);
1438 for(i = 0; i < 32; i++) {
1439 if(family->FirstFace->fs.fsCsb[0] & (1L << i)) {
1440 fs.fsCsb[0] = 1L << i;
1442 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
1444 csi.ciCharset = DEFAULT_CHARSET;
1445 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
1446 if(csi.ciCharset != DEFAULT_CHARSET) {
1447 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
1450 strcpyW(elf.elfScript, ElfScriptsW[i]);
1452 FIXME("Unknown elfscript for bit %d\n", i);
1453 TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
1454 debugstr_w(elf.elfLogFont.lfFaceName),
1455 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
1456 csi.ciCharset, type, debugstr_w(elf.elfScript),
1457 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
1458 ntm.ntmTm.ntmFlags);
1459 ret = proc(&elf, &ntm, type, lparam);
1470 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
1472 pt->x.value = vec->x >> 6;
1473 pt->x.fract = (vec->x & 0x3f) << 10;
1474 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
1475 pt->y.value = vec->y >> 6;
1476 pt->y.fract = (vec->y & 0x3f) << 10;
1477 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
1481 static FT_UInt get_glyph_index(GdiFont font, UINT glyph)
1483 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
1484 glyph = glyph + 0xf000;
1485 return pFT_Get_Char_Index(font->ft_face, glyph);
1488 /*************************************************************
1489 * WineEngGetGlyphIndices
1491 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
1493 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
1494 LPWORD pgi, DWORD flags)
1498 for(i = 0; i < count; i++)
1499 pgi[i] = get_glyph_index(font, lpstr[i]);
1504 /*************************************************************
1505 * WineEngGetGlyphOutline
1507 * Behaves in exactly the same way as the win32 api GetGlyphOutline
1508 * except that the first parameter is the HWINEENGFONT of the font in
1509 * question rather than an HDC.
1512 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
1513 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
1516 FT_Face ft_face = font->ft_face;
1517 FT_UInt glyph_index;
1518 DWORD width, height, pitch, needed = 0;
1519 FT_Bitmap ft_bitmap;
1521 INT left, right, top = 0, bottom = 0;
1523 FT_Int load_flags = FT_LOAD_DEFAULT;
1525 TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font, glyph, format, lpgm,
1526 buflen, buf, lpmat);
1528 if(format & GGO_GLYPH_INDEX) {
1529 glyph_index = glyph;
1530 format &= ~GGO_GLYPH_INDEX;
1532 glyph_index = get_glyph_index(font, glyph);
1534 if(glyph_index >= font->gmsize) {
1535 font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
1536 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
1537 font->gmsize * sizeof(*font->gm));
1539 if(format == GGO_METRICS && font->gm[glyph_index].init) {
1540 memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
1541 return 1; /* FIXME */
1545 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP))
1546 load_flags |= FT_LOAD_NO_BITMAP;
1548 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
1551 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
1555 left = ft_face->glyph->metrics.horiBearingX & -64;
1556 right = ((ft_face->glyph->metrics.horiBearingX +
1557 ft_face->glyph->metrics.width) + 63) & -64;
1559 font->gm[glyph_index].adv = (ft_face->glyph->metrics.horiAdvance + 63) >> 6;
1560 font->gm[glyph_index].lsb = left >> 6;
1561 font->gm[glyph_index].bbx = (right - left) >> 6;
1563 if(font->orientation == 0) {
1564 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
1565 bottom = (ft_face->glyph->metrics.horiBearingY -
1566 ft_face->glyph->metrics.height) & -64;
1567 lpgm->gmCellIncX = font->gm[glyph_index].adv;
1568 lpgm->gmCellIncY = 0;
1572 angle = font->orientation / 10 << 16;
1573 angle |= ((font->orientation % 10) * (1 << 16)) / 10;
1574 TRACE("angle %ld\n", angle >> 16);
1575 for(xc = 0; xc < 2; xc++) {
1576 for(yc = 0; yc < 2; yc++) {
1577 vec.x = ft_face->glyph->metrics.horiBearingX +
1578 xc * ft_face->glyph->metrics.width;
1579 vec.y = ft_face->glyph->metrics.horiBearingY -
1580 yc * ft_face->glyph->metrics.height;
1581 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
1582 pFT_Vector_Rotate(&vec, angle);
1583 if(xc == 0 && yc == 0) {
1584 left = right = vec.x;
1585 top = bottom = vec.y;
1587 if(vec.x < left) left = vec.x;
1588 else if(vec.x > right) right = vec.x;
1589 if(vec.y < bottom) bottom = vec.y;
1590 else if(vec.y > top) top = vec.y;
1595 right = (right + 63) & -64;
1596 bottom = bottom & -64;
1597 top = (top + 63) & -64;
1599 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
1600 vec.x = ft_face->glyph->metrics.horiAdvance;
1602 pFT_Vector_Rotate(&vec, angle);
1603 lpgm->gmCellIncX = (vec.x+63) >> 6;
1604 lpgm->gmCellIncY = -(vec.y+63) >> 6;
1606 lpgm->gmBlackBoxX = (right - left) >> 6;
1607 lpgm->gmBlackBoxY = (top - bottom) >> 6;
1608 lpgm->gmptGlyphOrigin.x = left >> 6;
1609 lpgm->gmptGlyphOrigin.y = top >> 6;
1611 memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
1612 font->gm[glyph_index].init = TRUE;
1614 if(format == GGO_METRICS)
1615 return 1; /* FIXME */
1617 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP) {
1618 FIXME("loaded a bitmap\n");
1624 width = lpgm->gmBlackBoxX;
1625 height = lpgm->gmBlackBoxY;
1626 pitch = (width + 31) / 32 * 4;
1627 needed = pitch * height;
1629 if(!buf || !buflen) break;
1631 switch(ft_face->glyph->format) {
1632 case ft_glyph_format_bitmap:
1634 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
1635 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
1636 INT h = ft_face->glyph->bitmap.rows;
1638 memcpy(dst, src, w);
1639 src += ft_face->glyph->bitmap.pitch;
1645 case ft_glyph_format_outline:
1646 ft_bitmap.width = width;
1647 ft_bitmap.rows = height;
1648 ft_bitmap.pitch = pitch;
1649 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
1650 ft_bitmap.buffer = buf;
1652 if(font->orientation) {
1654 matrix.xx = matrix.yy = pFT_Cos(angle);
1655 matrix.xy = -pFT_Sin(angle);
1656 matrix.yx = -matrix.xy;
1658 pFT_Outline_Transform(&ft_face->glyph->outline, &matrix);
1661 if (lpmat) pFT_Outline_Transform(&ft_face->glyph->outline, (FT_Matrix *)lpmat);
1662 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
1664 /* Note: FreeType will only set 'black' bits for us. */
1665 memset(buf, 0, needed);
1666 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
1670 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
1675 case GGO_GRAY2_BITMAP:
1676 case GGO_GRAY4_BITMAP:
1677 case GGO_GRAY8_BITMAP:
1678 case WINE_GGO_GRAY16_BITMAP:
1683 width = lpgm->gmBlackBoxX;
1684 height = lpgm->gmBlackBoxY;
1685 pitch = (width + 3) / 4 * 4;
1686 needed = pitch * height;
1688 if(!buf || !buflen) break;
1689 ft_bitmap.width = width;
1690 ft_bitmap.rows = height;
1691 ft_bitmap.pitch = pitch;
1692 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
1693 ft_bitmap.buffer = buf;
1695 if(font->orientation) {
1697 matrix.xx = matrix.yy = pFT_Cos(angle);
1698 matrix.xy = -pFT_Sin(angle);
1699 matrix.yx = -matrix.xy;
1700 pFT_Outline_Transform(&ft_face->glyph->outline, &matrix);
1703 if (lpmat) pFT_Outline_Transform(&ft_face->glyph->outline, (FT_Matrix *)lpmat);
1704 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
1706 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
1708 if(format == GGO_GRAY2_BITMAP)
1710 else if(format == GGO_GRAY4_BITMAP)
1712 else if(format == GGO_GRAY8_BITMAP)
1714 else if(format == WINE_GGO_GRAY16_BITMAP)
1722 for(row = 0; row < height; row++) {
1724 for(col = 0; col < width; col++, ptr++) {
1725 *ptr = (*(unsigned int*)ptr * mult + 128) / 256;
1734 int contour, point = 0, first_pt;
1735 FT_Outline *outline = &ft_face->glyph->outline;
1736 TTPOLYGONHEADER *pph;
1738 DWORD pph_start, cpfx, type;
1740 if(buflen == 0) buf = NULL;
1742 if (lpmat) pFT_Outline_Transform(outline, (FT_Matrix *)lpmat);
1744 for(contour = 0; contour < outline->n_contours; contour++) {
1746 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
1749 pph->dwType = TT_POLYGON_TYPE;
1750 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
1752 needed += sizeof(*pph);
1754 while(point <= outline->contours[contour]) {
1755 ppc = (TTPOLYCURVE *)((char *)buf + needed);
1756 type = (outline->tags[point] & FT_Curve_Tag_On) ?
1757 TT_PRIM_LINE : TT_PRIM_QSPLINE;
1761 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
1764 } while(point <= outline->contours[contour] &&
1765 (outline->tags[point] & FT_Curve_Tag_On) ==
1766 (outline->tags[point-1] & FT_Curve_Tag_On));
1767 /* At the end of a contour Windows adds the start point, but
1769 if(point > outline->contours[contour] &&
1770 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
1772 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
1774 } else if(point <= outline->contours[contour] &&
1775 outline->tags[point] & FT_Curve_Tag_On) {
1776 /* add closing pt for bezier */
1778 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
1786 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
1789 pph->cb = needed - pph_start;
1795 /* Convert the quadratic Beziers to cubic Beziers.
1796 The parametric eqn for a cubic Bezier is, from PLRM:
1797 r(t) = at^3 + bt^2 + ct + r0
1798 with the control points:
1803 A quadratic Beizer has the form:
1804 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
1806 So equating powers of t leads to:
1807 r1 = 2/3 p1 + 1/3 p0
1808 r2 = 2/3 p1 + 1/3 p2
1809 and of course r0 = p0, r3 = p2
1812 int contour, point = 0, first_pt;
1813 FT_Outline *outline = &ft_face->glyph->outline;
1814 TTPOLYGONHEADER *pph;
1816 DWORD pph_start, cpfx, type;
1817 FT_Vector cubic_control[4];
1818 if(buflen == 0) buf = NULL;
1820 if (lpmat) pFT_Outline_Transform(outline, (FT_Matrix *)lpmat);
1822 for(contour = 0; contour < outline->n_contours; contour++) {
1824 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
1827 pph->dwType = TT_POLYGON_TYPE;
1828 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
1830 needed += sizeof(*pph);
1832 while(point <= outline->contours[contour]) {
1833 ppc = (TTPOLYCURVE *)((char *)buf + needed);
1834 type = (outline->tags[point] & FT_Curve_Tag_On) ?
1835 TT_PRIM_LINE : TT_PRIM_CSPLINE;
1838 if(type == TT_PRIM_LINE) {
1840 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
1844 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
1847 /* FIXME: Possible optimization in endpoint calculation
1848 if there are two consecutive curves */
1849 cubic_control[0] = outline->points[point-1];
1850 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
1851 cubic_control[0].x += outline->points[point].x + 1;
1852 cubic_control[0].y += outline->points[point].y + 1;
1853 cubic_control[0].x >>= 1;
1854 cubic_control[0].y >>= 1;
1856 if(point+1 > outline->contours[contour])
1857 cubic_control[3] = outline->points[first_pt];
1859 cubic_control[3] = outline->points[point+1];
1860 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
1861 cubic_control[3].x += outline->points[point].x + 1;
1862 cubic_control[3].y += outline->points[point].y + 1;
1863 cubic_control[3].x >>= 1;
1864 cubic_control[3].y >>= 1;
1867 /* r1 = 1/3 p0 + 2/3 p1
1868 r2 = 1/3 p2 + 2/3 p1 */
1869 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
1870 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
1871 cubic_control[2] = cubic_control[1];
1872 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
1873 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
1874 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
1875 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
1877 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
1878 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
1879 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
1884 } while(point <= outline->contours[contour] &&
1885 (outline->tags[point] & FT_Curve_Tag_On) ==
1886 (outline->tags[point-1] & FT_Curve_Tag_On));
1887 /* At the end of a contour Windows adds the start point,
1888 but only for Beziers and we've already done that.
1890 if(point <= outline->contours[contour] &&
1891 outline->tags[point] & FT_Curve_Tag_On) {
1892 /* This is the closing pt of a bezier, but we've already
1893 added it, so just inc point and carry on */
1900 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
1903 pph->cb = needed - pph_start;
1909 FIXME("Unsupported format %d\n", format);
1915 /*************************************************************
1916 * WineEngGetTextMetrics
1919 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
1922 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
1925 if(!font->potm) return FALSE;
1926 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
1931 /*************************************************************
1932 * WineEngGetOutlineTextMetrics
1935 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
1936 OUTLINETEXTMETRICW *potm)
1938 FT_Face ft_face = font->ft_face;
1939 UINT needed, lenfam, lensty, ret;
1941 TT_HoriHeader *pHori;
1942 TT_Postscript *pPost;
1943 FT_Fixed x_scale, y_scale;
1944 WCHAR *family_nameW, *style_nameW;
1945 WCHAR spaceW[] = {' ', '\0'};
1948 TRACE("font=%p\n", font);
1951 if(cbSize >= font->potm->otmSize)
1952 memcpy(potm, font->potm, font->potm->otmSize);
1953 return font->potm->otmSize;
1956 needed = sizeof(*potm);
1958 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
1959 family_nameW = strdupW(font->name);
1961 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
1963 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
1964 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
1965 style_nameW, lensty);
1967 /* These names should be read from the TT name table */
1969 /* length of otmpFamilyName */
1972 /* length of otmpFaceName */
1973 if(!strcasecmp(ft_face->style_name, "regular")) {
1974 needed += lenfam; /* just the family name */
1976 needed += lenfam + lensty; /* family + " " + style */
1979 /* length of otmpStyleName */
1982 /* length of otmpFullName */
1983 needed += lenfam + lensty;
1986 x_scale = ft_face->size->metrics.x_scale;
1987 y_scale = ft_face->size->metrics.y_scale;
1989 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1991 FIXME("Can't find OS/2 table - not TT font?\n");
1996 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1998 FIXME("Can't find HHEA table - not TT font?\n");
2003 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
2005 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",
2006 pOS2->usWinAscent, pOS2->usWinDescent,
2007 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
2008 ft_face->ascender, ft_face->descender, ft_face->height,
2009 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
2010 ft_face->bbox.yMax, ft_face->bbox.yMin);
2012 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
2013 font->potm->otmSize = needed;
2015 #define TM font->potm->otmTextMetrics
2018 TM.tmAscent = font->yMax;
2019 TM.tmDescent = -font->yMin;
2020 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
2022 TM.tmAscent = (pFT_MulFix(pOS2->usWinAscent, y_scale) + 32) >> 6;
2023 TM.tmDescent = (pFT_MulFix(pOS2->usWinDescent, y_scale) + 32) >> 6;
2024 TM.tmInternalLeading = (pFT_MulFix(pOS2->usWinAscent + pOS2->usWinDescent
2025 - ft_face->units_per_EM, y_scale) + 32) >> 6;
2028 TM.tmHeight = TM.tmAscent + TM.tmDescent;
2031 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
2033 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
2034 ((pOS2->usWinAscent + pOS2->usWinDescent) -
2035 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
2037 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
2038 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
2039 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
2041 TM.tmDigitizedAspectX = 300;
2042 TM.tmDigitizedAspectY = 300;
2043 TM.tmFirstChar = pOS2->usFirstCharIndex;
2044 TM.tmLastChar = pOS2->usLastCharIndex;
2045 TM.tmDefaultChar = pOS2->usDefaultChar;
2046 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
2047 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
2048 TM.tmUnderlined = 0; /* entry in OS2 table */
2049 TM.tmStruckOut = 0; /* entry in OS2 table */
2051 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
2052 if(!FT_IS_FIXED_WIDTH(ft_face))
2053 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
2055 TM.tmPitchAndFamily = 0;
2057 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
2058 case PAN_FAMILY_SCRIPT:
2059 TM.tmPitchAndFamily |= FF_SCRIPT;
2061 case PAN_FAMILY_DECORATIVE:
2062 case PAN_FAMILY_PICTORIAL:
2063 TM.tmPitchAndFamily |= FF_DECORATIVE;
2065 case PAN_FAMILY_TEXT_DISPLAY:
2066 if(TM.tmPitchAndFamily == 0) /* fixed */
2067 TM.tmPitchAndFamily = FF_MODERN;
2069 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
2070 case PAN_SERIF_NORMAL_SANS:
2071 case PAN_SERIF_OBTUSE_SANS:
2072 case PAN_SERIF_PERP_SANS:
2073 TM.tmPitchAndFamily |= FF_SWISS;
2076 TM.tmPitchAndFamily |= FF_ROMAN;
2081 TM.tmPitchAndFamily |= FF_DONTCARE;
2084 if(FT_IS_SCALABLE(ft_face))
2085 TM.tmPitchAndFamily |= TMPF_VECTOR;
2086 if(FT_IS_SFNT(ft_face))
2087 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
2089 TM.tmCharSet = font->charset;
2092 font->potm->otmFiller = 0;
2093 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
2094 font->potm->otmfsSelection = pOS2->fsSelection;
2095 font->potm->otmfsType = pOS2->fsType;
2096 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
2097 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
2098 font->potm->otmItalicAngle = 0; /* POST table */
2099 font->potm->otmEMSquare = ft_face->units_per_EM;
2100 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
2101 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
2102 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
2103 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
2104 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
2105 font->potm->otmrcFontBox.left = ft_face->bbox.xMin;
2106 font->potm->otmrcFontBox.right = ft_face->bbox.xMax;
2107 font->potm->otmrcFontBox.top = ft_face->bbox.yMin;
2108 font->potm->otmrcFontBox.bottom = ft_face->bbox.yMax;
2109 font->potm->otmMacAscent = 0; /* where do these come from ? */
2110 font->potm->otmMacDescent = 0;
2111 font->potm->otmMacLineGap = 0;
2112 font->potm->otmusMinimumPPEM = 0; /* TT Header */
2113 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
2114 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
2115 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
2116 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
2117 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
2118 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
2119 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
2120 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
2121 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
2122 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
2124 font->potm->otmsUnderscoreSize = 0;
2125 font->potm->otmsUnderscorePosition = 0;
2127 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
2128 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
2131 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
2132 cp = (char*)font->potm + sizeof(*font->potm);
2133 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
2134 strcpyW((WCHAR*)cp, family_nameW);
2136 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
2137 strcpyW((WCHAR*)cp, style_nameW);
2139 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
2140 strcpyW((WCHAR*)cp, family_nameW);
2141 if(strcasecmp(ft_face->style_name, "regular")) {
2142 strcatW((WCHAR*)cp, spaceW);
2143 strcatW((WCHAR*)cp, style_nameW);
2144 cp += lenfam + lensty;
2147 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
2148 strcpyW((WCHAR*)cp, family_nameW);
2149 strcatW((WCHAR*)cp, spaceW);
2150 strcatW((WCHAR*)cp, style_nameW);
2153 if(needed <= cbSize)
2154 memcpy(potm, font->potm, font->potm->otmSize);
2157 HeapFree(GetProcessHeap(), 0, style_nameW);
2158 HeapFree(GetProcessHeap(), 0, family_nameW);
2164 /*************************************************************
2165 * WineEngGetCharWidth
2168 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
2173 FT_UInt glyph_index;
2175 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
2177 for(c = firstChar; c <= lastChar; c++) {
2178 glyph_index = get_glyph_index(font, c);
2179 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
2180 &gm, 0, NULL, NULL);
2181 buffer[c - firstChar] = font->gm[glyph_index].adv;
2186 /*************************************************************
2187 * WineEngGetTextExtentPoint
2190 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
2196 FT_UInt glyph_index;
2198 TRACE("%p, %s, %d, %p\n", font, debugstr_wn(wstr, count), count,
2202 WineEngGetTextMetrics(font, &tm);
2203 size->cy = tm.tmHeight;
2205 for(idx = 0; idx < count; idx++) {
2206 glyph_index = get_glyph_index(font, wstr[idx]);
2207 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
2208 &gm, 0, NULL, NULL);
2209 size->cx += font->gm[glyph_index].adv;
2211 TRACE("return %ld,%ld\n", size->cx, size->cy);
2215 /*************************************************************
2216 * WineEngGetTextExtentPointI
2219 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
2226 TRACE("%p, %p, %d, %p\n", font, indices, count, size);
2229 WineEngGetTextMetrics(font, &tm);
2230 size->cy = tm.tmHeight;
2232 for(idx = 0; idx < count; idx++) {
2233 WineEngGetGlyphOutline(font, indices[idx],
2234 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
2236 size->cx += font->gm[indices[idx]].adv;
2238 TRACE("return %ld,%ld\n", size->cx, size->cy);
2242 /*************************************************************
2243 * WineEngGetFontData
2246 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
2249 FT_Face ft_face = font->ft_face;
2253 TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
2254 font, table, offset, buf, cbData);
2256 if(!FT_IS_SFNT(ft_face))
2264 if(table) { /* MS tags differ in endidness from FT ones */
2265 table = table >> 24 | table << 24 |
2266 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
2269 /* If the FT_Load_Sfnt_Table function is there we'll use it */
2270 if(pFT_Load_Sfnt_Table)
2271 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
2272 else { /* Do it the hard way */
2273 TT_Face tt_face = (TT_Face) ft_face;
2274 SFNT_Interface *sfnt;
2275 if (FT_Version.major==2 && FT_Version.minor==0)
2278 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
2282 /* A field was added in the middle of the structure in 2.1.x */
2283 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
2285 err = sfnt->load_any(tt_face, table, offset, buf, &len);
2288 TRACE("Can't find table %08lx.\n", table);
2294 /*************************************************************
2295 * WineEngGetTextFace
2298 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
2301 lstrcpynW(str, font->name, count);
2302 return strlenW(font->name);
2304 return strlenW(font->name) + 1;
2307 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
2309 if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
2310 return font->charset;
2313 #else /* HAVE_FREETYPE */
2315 BOOL WineEngInit(void)
2319 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
2323 BOOL WineEngDestroyFontInstance(HFONT hfont)
2328 DWORD WineEngEnumFonts(LPLOGFONTW plf, DEVICEFONTENUMPROC proc, LPARAM lparam)
2333 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
2334 LPWORD pgi, DWORD flags)
2339 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
2340 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
2343 ERR("called but we don't have FreeType\n");
2347 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
2349 ERR("called but we don't have FreeType\n");
2353 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
2354 OUTLINETEXTMETRICW *potm)
2356 ERR("called but we don't have FreeType\n");
2360 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
2363 ERR("called but we don't have FreeType\n");
2367 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
2370 ERR("called but we don't have FreeType\n");
2374 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
2377 ERR("called but we don't have FreeType\n");
2381 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
2384 ERR("called but we don't have FreeType\n");
2388 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
2390 ERR("called but we don't have FreeType\n");
2394 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2400 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2406 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
2409 return DEFAULT_CHARSET;
2412 #endif /* HAVE_FREETYPE */