2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
6 * This file contains the WineEng* functions.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "wine/port.h"
40 #include "gdi_private.h"
41 #include "wine/unicode.h"
42 #include "wine/debug.h"
43 #include "wine/list.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(font);
49 #ifdef HAVE_FT2BUILD_H
52 #ifdef HAVE_FREETYPE_FREETYPE_H
53 #include <freetype/freetype.h>
55 #ifdef HAVE_FREETYPE_FTGLYPH_H
56 #include <freetype/ftglyph.h>
58 #ifdef HAVE_FREETYPE_TTTABLES_H
59 #include <freetype/tttables.h>
61 #ifdef HAVE_FREETYPE_FTSNAMES_H
62 #include <freetype/ftsnames.h>
64 # ifdef HAVE_FREETYPE_FTNAMES_H
65 # include <freetype/ftnames.h>
68 #ifdef HAVE_FREETYPE_TTNAMEID_H
69 #include <freetype/ttnameid.h>
71 #ifdef HAVE_FREETYPE_FTOUTLN_H
72 #include <freetype/ftoutln.h>
74 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
75 #include <freetype/internal/sfnt.h>
77 #ifdef HAVE_FREETYPE_FTTRIGON_H
78 #include <freetype/fttrigon.h>
80 #ifdef HAVE_FREETYPE_FTWINFNT_H
81 #include <freetype/ftwinfnt.h>
84 #ifndef SONAME_LIBFREETYPE
85 #define SONAME_LIBFREETYPE "libfreetype.so"
88 static FT_Library library = 0;
95 static FT_Version_t FT_Version;
96 static DWORD FT_SimpleVersion;
98 static void *ft_handle = NULL;
100 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
101 MAKE_FUNCPTR(FT_Vector_Unit);
102 MAKE_FUNCPTR(FT_Done_Face);
103 MAKE_FUNCPTR(FT_Get_Char_Index);
104 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
105 MAKE_FUNCPTR(FT_Init_FreeType);
106 MAKE_FUNCPTR(FT_Load_Glyph);
107 MAKE_FUNCPTR(FT_Matrix_Multiply);
108 MAKE_FUNCPTR(FT_MulFix);
109 MAKE_FUNCPTR(FT_New_Face);
110 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
111 MAKE_FUNCPTR(FT_Outline_Transform);
112 MAKE_FUNCPTR(FT_Outline_Translate);
113 MAKE_FUNCPTR(FT_Select_Charmap);
114 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
115 MAKE_FUNCPTR(FT_Vector_Transform);
116 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
117 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
118 static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*);
119 #ifdef HAVE_FREETYPE_FTWINFNT_H
120 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
123 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
124 #include <fontconfig/fontconfig.h>
125 MAKE_FUNCPTR(FcConfigGetCurrent);
126 MAKE_FUNCPTR(FcFontList);
127 MAKE_FUNCPTR(FcFontSetDestroy);
128 MAKE_FUNCPTR(FcInit);
129 MAKE_FUNCPTR(FcObjectSetAdd);
130 MAKE_FUNCPTR(FcObjectSetCreate);
131 MAKE_FUNCPTR(FcObjectSetDestroy);
132 MAKE_FUNCPTR(FcPatternCreate);
133 MAKE_FUNCPTR(FcPatternDestroy);
134 MAKE_FUNCPTR(FcPatternGet);
135 #ifndef SONAME_LIBFONTCONFIG
136 #define SONAME_LIBFONTCONFIG "libfontconfig.so"
142 #ifndef ft_encoding_none
143 #define FT_ENCODING_NONE ft_encoding_none
145 #ifndef ft_encoding_ms_symbol
146 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
148 #ifndef ft_encoding_unicode
149 #define FT_ENCODING_UNICODE ft_encoding_unicode
151 #ifndef ft_encoding_apple_roman
152 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
155 #define GET_BE_WORD(ptr) MAKEWORD( ((BYTE *)(ptr))[1], ((BYTE *)(ptr))[0] )
157 /* This is bascially a copy of FT_Bitmap_Size with an extra element added */
164 FT_Short internal_leading;
167 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
168 So to let this compile on older versions of FreeType we'll define the
169 new structure here. */
171 FT_Short height, width;
172 FT_Pos size, x_ppem, y_ppem;
175 typedef struct tagFace {
183 FT_Fixed font_version;
185 Bitmap_Size size; /* set if face is a bitmap */
186 BOOL external; /* TRUE if we should manually add this font to the registry */
187 struct tagFamily *family;
190 typedef struct tagFamily {
198 INT adv; /* These three hold to widths of the unrotated chars */
215 typedef struct tagHFONTLIST {
233 struct list hfontlist;
238 OUTLINETEXTMETRICW *potm;
242 #define INIT_GM_SIZE 128
244 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
245 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
246 #define UNUSED_CACHE_SIZE 10
248 static struct list font_list = LIST_INIT(font_list);
250 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ',
251 'R','o','m','a','n','\0'};
252 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
253 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
255 static const WCHAR defSystem[] = {'A','r','i','a','l','\0'};
256 static const WCHAR SystemW[] = {'S','y','s','t','e','m','\0'};
257 static const WCHAR MSSansSerifW[] = {'M','S',' ','S','a','n','s',' ',
258 'S','e','r','i','f','\0'};
259 static const WCHAR HelvW[] = {'H','e','l','v','\0'};
260 static const WCHAR RegularW[] = {'R','e','g','u','l','a','r','\0'};
262 static const WCHAR fontsW[] = {'\\','F','o','n','t','s','\0'};
263 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
264 'W','i','n','d','o','w','s','\\',
265 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
266 'F','o','n','t','s','\0'};
268 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
269 'W','i','n','d','o','w','s',' ','N','T','\\',
270 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
271 'F','o','n','t','s','\0'};
273 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
274 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
275 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
276 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
278 static const WCHAR *SystemFontValues[4] = {
285 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\','W','i','n','e','\\',
286 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
288 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
289 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
290 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
291 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
292 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
293 'E','u','r','o','p','e','a','n','\0'};
294 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
295 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
296 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
297 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
298 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
299 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
300 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
301 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
302 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
303 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
304 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
305 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
307 static const WCHAR *ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
317 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
325 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
334 typedef struct tagFontSubst {
337 struct tagFontSubst *next;
340 static FontSubst *substlist = NULL;
341 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
343 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
346 /****************************************
347 * Notes on .fon files
349 * The fonts System, FixedSys and Terminal are special. There are typically multiple
350 * versions installed for different resolutions and codepages. Windows stores which one to use
351 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
353 * FIXEDFON.FON FixedSys
355 * OEMFONT.FON Terminal
356 * LogPixels Current dpi set by the display control panel applet
357 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
358 * also has a LogPixels value that appears to mirror this)
360 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
361 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
362 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
363 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
364 * so that makes sense.
366 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
367 * to be mapped into the registry on Windows 2000 at least).
370 * ega80woa.fon=ega80850.fon
371 * ega40woa.fon=ega40850.fon
372 * cga80woa.fon=cga80850.fon
373 * cga40woa.fon=cga40850.fon
377 static inline BOOL is_win9x(void)
379 return GetVersion() & 0x80000000;
382 This function builds an FT_Fixed from a float. It puts the integer part
383 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
384 It fails if the integer part of the float number is greater than SHORT_MAX.
386 static inline FT_Fixed FT_FixedFromFloat(float f)
389 unsigned short fract = (f - value) * 0xFFFF;
390 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
394 This function builds an FT_Fixed from a FIXED. It simply put f.value
395 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
397 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
399 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
402 #define ADDFONT_EXTERNAL_FONT 0x01
403 #define ADDFONT_FORCE_BITMAP 0x02
404 static BOOL AddFontFileToList(const char *file, char *fake_family, DWORD flags)
408 TT_Header *pHeader = NULL;
409 WCHAR *FamilyW, *StyleW;
413 struct list *family_elem_ptr, *face_elem_ptr;
415 FT_Long face_index = 0, num_faces;
416 #ifdef HAVE_FREETYPE_FTWINFNT_H
417 FT_WinFNT_HeaderRec winfnt_header;
422 char *family_name = fake_family;
424 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
425 if((err = pFT_New_Face(library, file, face_index, &ft_face)) != 0) {
426 WARN("Unable to load font file %s err = %x\n", debugstr_a(file), err);
430 if(!FT_IS_SFNT(ft_face) && (FT_IS_SCALABLE(ft_face) || !(flags & ADDFONT_FORCE_BITMAP))) { /* for now we'll accept TT/OT or bitmap fonts*/
431 pFT_Done_Face(ft_face);
435 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
436 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
437 pFT_Done_Face(ft_face);
441 if(FT_IS_SFNT(ft_face) && (!pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2) ||
442 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
443 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))) {
444 TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
445 "Skipping this font.\n", debugstr_a(file));
446 pFT_Done_Face(ft_face);
450 if(!ft_face->family_name || !ft_face->style_name) {
451 TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file));
452 pFT_Done_Face(ft_face);
457 family_name = ft_face->family_name;
461 My_FT_Bitmap_Size *size = NULL;
463 if(!FT_IS_SCALABLE(ft_face))
464 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
466 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
467 FamilyW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
468 MultiByteToWideChar(CP_ACP, 0, family_name, -1, FamilyW, len);
471 LIST_FOR_EACH(family_elem_ptr, &font_list) {
472 family = LIST_ENTRY(family_elem_ptr, Family, entry);
473 if(!strcmpW(family->FamilyName, FamilyW))
478 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
479 family->FamilyName = FamilyW;
480 list_init(&family->faces);
481 list_add_tail(&font_list, &family->entry);
483 HeapFree(GetProcessHeap(), 0, FamilyW);
486 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
487 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
488 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
490 face_elem_ptr = list_head(&family->faces);
491 while(face_elem_ptr) {
492 face = LIST_ENTRY(face_elem_ptr, Face, entry);
493 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
494 if(!strcmpW(face->StyleName, StyleW) &&
495 (FT_IS_SCALABLE(ft_face) || (size->y_ppem == face->size.y_ppem))) {
496 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
497 debugstr_w(family->FamilyName), debugstr_w(StyleW),
498 face->font_version, pHeader ? pHeader->Font_Revision : 0);
501 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
502 HeapFree(GetProcessHeap(), 0, StyleW);
503 pFT_Done_Face(ft_face);
506 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
507 TRACE("Original font is newer so skipping this one\n");
508 HeapFree(GetProcessHeap(), 0, StyleW);
509 pFT_Done_Face(ft_face);
512 TRACE("Replacing original with this one\n");
513 list_remove(&face->entry);
514 HeapFree(GetProcessHeap(), 0, face->file);
515 HeapFree(GetProcessHeap(), 0, face->StyleName);
516 HeapFree(GetProcessHeap(), 0, face);
521 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
522 list_add_tail(&family->faces, &face->entry);
523 face->StyleName = StyleW;
524 face->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
525 strcpy(face->file, file);
526 face->face_index = face_index;
527 face->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
528 face->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
529 face->font_version = pHeader ? pHeader->Font_Revision : 0;
530 face->family = family;
531 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
533 if(FT_IS_SCALABLE(ft_face)) {
534 memset(&face->size, 0, sizeof(face->size));
535 face->scalable = TRUE;
537 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
538 size->height, size->width, size->size >> 6,
539 size->x_ppem >> 6, size->y_ppem >> 6);
540 face->size.height = size->height;
541 face->size.width = size->width;
542 face->size.size = size->size;
543 face->size.x_ppem = size->x_ppem;
544 face->size.y_ppem = size->y_ppem;
545 face->size.internal_leading = 0;
546 face->scalable = FALSE;
549 memset(&face->fs, 0, sizeof(face->fs));
551 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
553 face->fs.fsCsb[0] = pOS2->ulCodePageRange1;
554 face->fs.fsCsb[1] = pOS2->ulCodePageRange2;
555 face->fs.fsUsb[0] = pOS2->ulUnicodeRange1;
556 face->fs.fsUsb[1] = pOS2->ulUnicodeRange2;
557 face->fs.fsUsb[2] = pOS2->ulUnicodeRange3;
558 face->fs.fsUsb[3] = pOS2->ulUnicodeRange4;
559 if(pOS2->version == 0) {
562 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
563 face->fs.fsCsb[0] |= 1;
565 face->fs.fsCsb[0] |= 1L << 31;
568 #ifdef HAVE_FREETYPE_FTWINFNT_H
569 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
571 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
572 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
573 if(TranslateCharsetInfo((DWORD*)(UINT)winfnt_header.charset, &csi, TCI_SRCCHARSET))
574 memcpy(&face->fs, &csi.fs, sizeof(csi.fs));
575 face->size.internal_leading = winfnt_header.internal_leading;
578 TRACE("fsCsb = %08lx %08lx/%08lx %08lx %08lx %08lx\n",
579 face->fs.fsCsb[0], face->fs.fsCsb[1],
580 face->fs.fsUsb[0], face->fs.fsUsb[1],
581 face->fs.fsUsb[2], face->fs.fsUsb[3]);
584 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
585 for(i = 0; i < ft_face->num_charmaps; i++) {
586 switch(ft_face->charmaps[i]->encoding) {
587 case FT_ENCODING_UNICODE:
588 case FT_ENCODING_APPLE_ROMAN:
589 face->fs.fsCsb[0] |= 1;
591 case FT_ENCODING_MS_SYMBOL:
592 face->fs.fsCsb[0] |= 1L << 31;
600 if(face->fs.fsCsb[0] & ~(1L << 31))
601 have_installed_roman_font = TRUE;
602 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
604 num_faces = ft_face->num_faces;
605 pFT_Done_Face(ft_face);
606 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
608 } while(num_faces > ++face_index);
612 static void DumpFontList(void)
616 struct list *family_elem_ptr, *face_elem_ptr;
618 LIST_FOR_EACH(family_elem_ptr, &font_list) {
619 family = LIST_ENTRY(family_elem_ptr, Family, entry);
620 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
621 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
622 face = LIST_ENTRY(face_elem_ptr, Face, entry);
623 TRACE("\t%s", debugstr_w(face->StyleName));
625 TRACE(" %ld", face->size.y_ppem >> 6);
632 static void DumpSubstList(void)
636 for(psub = substlist; psub; psub = psub->next)
637 if(psub->from.charset != -1 || psub->to.charset != -1)
638 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
639 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
641 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
642 debugstr_w(psub->to.name));
646 static LPWSTR strdupW(LPWSTR p)
649 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
650 ret = HeapAlloc(GetProcessHeap(), 0, len);
655 static void split_subst_info(NameCs *nc, LPSTR str)
657 CHAR *p = strrchr(str, ',');
662 nc->charset = strtol(p+1, NULL, 10);
665 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
666 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
667 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
670 static void LoadSubstList(void)
672 FontSubst *psub, **ppsub;
674 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
679 for(psub = substlist; psub;) {
681 HeapFree(GetProcessHeap(), 0, psub->to.name);
682 HeapFree(GetProcessHeap(), 0, psub->from.name);
685 HeapFree(GetProcessHeap(), 0, ptmp);
690 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
691 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
692 &hkey) == ERROR_SUCCESS) {
694 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
695 &valuelen, &datalen, NULL, NULL);
697 valuelen++; /* returned value doesn't include room for '\0' */
698 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
699 data = HeapAlloc(GetProcessHeap(), 0, datalen);
704 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
705 &dlen) == ERROR_SUCCESS) {
706 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
708 *ppsub = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppsub));
709 (*ppsub)->next = NULL;
710 split_subst_info(&((*ppsub)->from), value);
711 split_subst_info(&((*ppsub)->to), data);
713 /* Win 2000 doesn't allow mapping between different charsets
714 or mapping of DEFAULT_CHARSET */
715 if(((*ppsub)->to.charset != (*ppsub)->from.charset) ||
716 (*ppsub)->to.charset == DEFAULT_CHARSET) {
717 HeapFree(GetProcessHeap(), 0, (*ppsub)->to.name);
718 HeapFree(GetProcessHeap(), 0, (*ppsub)->from.name);
719 HeapFree(GetProcessHeap(), 0, *ppsub);
722 ppsub = &((*ppsub)->next);
724 /* reset dlen and vlen */
728 HeapFree(GetProcessHeap(), 0, data);
729 HeapFree(GetProcessHeap(), 0, value);
734 /***********************************************************
735 * The replacement list is a way to map an entire font
736 * family onto another family. For example adding
738 * [HKLM\Software\Wine\Wine\FontReplacements]
739 * "Wingdings"="Winedings"
741 * would enumerate the Winedings font both as Winedings and
742 * Wingdings. However if a real Wingdings font is present the
743 * replacement does not take place.
746 static void LoadReplaceList(void)
749 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
754 struct list *family_elem_ptr, *face_elem_ptr;
755 WCHAR old_nameW[200];
757 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
758 "Software\\Wine\\Wine\\FontReplacements",
759 &hkey) == ERROR_SUCCESS) {
761 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
762 &valuelen, &datalen, NULL, NULL);
764 valuelen++; /* returned value doesn't include room for '\0' */
765 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
766 data = HeapAlloc(GetProcessHeap(), 0, datalen);
770 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
771 &dlen) == ERROR_SUCCESS) {
772 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
773 /* "NewName"="Oldname" */
774 if(!MultiByteToWideChar(CP_ACP, 0, data, -1, old_nameW, sizeof(old_nameW)))
777 /* Find the old family and hence all of the font files
779 LIST_FOR_EACH(family_elem_ptr, &font_list) {
780 family = LIST_ENTRY(family_elem_ptr, Family, entry);
781 if(!strcmpiW(family->FamilyName, old_nameW)) {
782 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
783 face = LIST_ENTRY(face_elem_ptr, Face, entry);
784 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
785 debugstr_w(face->StyleName), value);
786 /* Now add a new entry with the new family name */
787 AddFontFileToList(face->file, value, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
792 /* reset dlen and vlen */
796 HeapFree(GetProcessHeap(), 0, data);
797 HeapFree(GetProcessHeap(), 0, value);
803 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
809 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
811 dir = opendir(dirname);
813 ERR("Can't open directory %s\n", debugstr_a(dirname));
816 while((dent = readdir(dir)) != NULL) {
819 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
822 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
824 sprintf(path, "%s/%s", dirname, dent->d_name);
826 if(stat(path, &statbuf) == -1)
828 WARN("Can't stat %s\n", debugstr_a(path));
831 if(S_ISDIR(statbuf.st_mode))
832 ReadFontDir(path, external_fonts);
834 AddFontFileToList(path, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
840 static void load_fontconfig_fonts(void)
842 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
843 void *fc_handle = NULL;
852 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
854 TRACE("Wine cannot find the fontconfig library (%s).\n",
855 SONAME_LIBFONTCONFIG);
858 #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;}
859 LOAD_FUNCPTR(FcConfigGetCurrent);
860 LOAD_FUNCPTR(FcFontList);
861 LOAD_FUNCPTR(FcFontSetDestroy);
862 LOAD_FUNCPTR(FcInit);
863 LOAD_FUNCPTR(FcObjectSetAdd);
864 LOAD_FUNCPTR(FcObjectSetCreate);
865 LOAD_FUNCPTR(FcObjectSetDestroy);
866 LOAD_FUNCPTR(FcPatternCreate);
867 LOAD_FUNCPTR(FcPatternDestroy);
868 LOAD_FUNCPTR(FcPatternGet);
871 if(!pFcInit()) return;
873 config = pFcConfigGetCurrent();
874 pat = pFcPatternCreate();
875 os = pFcObjectSetCreate();
876 pFcObjectSetAdd(os, FC_FILE);
877 fontset = pFcFontList(config, pat, os);
879 for(i = 0; i < fontset->nfont; i++) {
880 if(pFcPatternGet(fontset->fonts[i], FC_FILE, 0, &v) != FcResultMatch)
882 if(v.type != FcTypeString) continue;
883 TRACE("fontconfig: %s\n", v.u.s);
885 /* We're just interested in OT/TT fonts for now, so this hack just
886 picks up the standard extensions to save time loading every other
889 if(len < 4) continue;
890 ext = v.u.s + len - 3;
891 if(!strcasecmp(ext, "ttf") || !strcasecmp(ext, "ttc") || !strcasecmp(ext, "otf"))
892 AddFontFileToList(v.u.s, NULL, ADDFONT_EXTERNAL_FONT);
894 pFcFontSetDestroy(fontset);
895 pFcObjectSetDestroy(os);
896 pFcPatternDestroy(pat);
903 void load_system_fonts(void)
906 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
909 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
912 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
913 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
914 strcatW(windowsdir, fontsW);
915 for(value = SystemFontValues; *value; value++) {
917 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
919 sprintfW(pathW, fmtW, windowsdir, data);
920 if((unixname = wine_get_unix_file_name(pathW))) {
921 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
922 HeapFree(GetProcessHeap(), 0, unixname);
930 /*************************************************************
932 * This adds registry entries for any externally loaded fonts
933 * (fonts from fontconfig or FontDirs). It also deletes entries
934 * of no longer existing fonts.
937 void update_reg_entries(void)
939 HKEY winkey = 0, externalkey = 0;
942 DWORD dlen, vlen, datalen, valuelen, i, type, len, len_fam;
945 struct list *family_elem_ptr, *face_elem_ptr;
947 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
948 static const WCHAR spaceW[] = {' ', '\0'};
951 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
952 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winkey, NULL) != ERROR_SUCCESS) {
953 ERR("Can't create Windows font reg key\n");
956 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, external_fonts_reg_key,
957 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
958 ERR("Can't create external font reg key\n");
962 /* Delete all external fonts added last time */
964 RegQueryInfoKeyW(externalkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
965 &valuelen, &datalen, NULL, NULL);
966 valuelen++; /* returned value doesn't include room for '\0' */
967 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
968 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
970 dlen = datalen * sizeof(WCHAR);
973 while(RegEnumValueW(externalkey, i++, valueW, &vlen, NULL, &type, data,
974 &dlen) == ERROR_SUCCESS) {
976 RegDeleteValueW(winkey, valueW);
977 /* reset dlen and vlen */
981 HeapFree(GetProcessHeap(), 0, data);
982 HeapFree(GetProcessHeap(), 0, valueW);
984 /* Delete the old external fonts key */
985 RegCloseKey(externalkey);
987 RegDeleteKeyW(HKEY_LOCAL_MACHINE, external_fonts_reg_key);
989 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, external_fonts_reg_key,
990 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
991 ERR("Can't create external font reg key\n");
995 /* enumerate the fonts and add external ones to the two keys */
997 LIST_FOR_EACH(family_elem_ptr, &font_list) {
998 family = LIST_ENTRY(family_elem_ptr, Family, entry);
999 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
1000 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1001 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1002 if(!face->external) continue;
1004 if(strcmpiW(face->StyleName, RegularW))
1005 len = len_fam + strlenW(face->StyleName) + 1;
1006 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1007 strcpyW(valueW, family->FamilyName);
1008 if(len != len_fam) {
1009 strcatW(valueW, spaceW);
1010 strcatW(valueW, face->StyleName);
1012 strcatW(valueW, TrueType);
1013 if((path = strrchr(face->file, '/')) == NULL)
1017 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1019 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1020 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1021 RegSetValueExW(winkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1022 RegSetValueExW(externalkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1024 HeapFree(GetProcessHeap(), 0, file);
1025 HeapFree(GetProcessHeap(), 0, valueW);
1030 RegCloseKey(externalkey);
1032 RegCloseKey(winkey);
1037 /*************************************************************
1038 * WineEngAddFontResourceEx
1041 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1043 if (ft_handle) /* do it only if we have freetype up and running */
1048 FIXME("Ignoring flags %lx\n", flags);
1050 if((unixname = wine_get_unix_file_name(file)))
1052 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1053 HeapFree(GetProcessHeap(), 0, unixname);
1059 /*************************************************************
1060 * WineEngRemoveFontResourceEx
1063 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1069 /*************************************************************
1072 * Initialize FreeType library and create a list of available faces
1074 BOOL WineEngInit(void)
1076 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
1078 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1080 WCHAR windowsdir[MAX_PATH];
1086 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
1089 "Wine cannot find the FreeType font library. To enable Wine to\n"
1090 "use TrueType fonts please install a version of FreeType greater than\n"
1091 "or equal to 2.0.5.\n"
1092 "http://www.freetype.org\n");
1096 #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;}
1098 LOAD_FUNCPTR(FT_Vector_Unit)
1099 LOAD_FUNCPTR(FT_Done_Face)
1100 LOAD_FUNCPTR(FT_Get_Char_Index)
1101 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
1102 LOAD_FUNCPTR(FT_Init_FreeType)
1103 LOAD_FUNCPTR(FT_Load_Glyph)
1104 LOAD_FUNCPTR(FT_Matrix_Multiply)
1105 LOAD_FUNCPTR(FT_MulFix)
1106 LOAD_FUNCPTR(FT_New_Face)
1107 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
1108 LOAD_FUNCPTR(FT_Outline_Transform)
1109 LOAD_FUNCPTR(FT_Outline_Translate)
1110 LOAD_FUNCPTR(FT_Select_Charmap)
1111 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
1112 LOAD_FUNCPTR(FT_Vector_Transform)
1115 /* Don't warn if this one is missing */
1116 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
1117 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
1118 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
1119 #ifdef HAVE_FREETYPE_FTWINFNT_H
1120 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
1122 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
1123 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
1124 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
1125 <= 2.0.3 has FT_Sqrt64 */
1129 if(pFT_Init_FreeType(&library) != 0) {
1130 ERR("Can't init FreeType library\n");
1131 wine_dlclose(ft_handle, NULL, 0);
1135 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
1136 if (pFT_Library_Version)
1138 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
1140 if (FT_Version.major<=0)
1146 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
1147 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
1148 ((FT_Version.minor << 8) & 0x00ff00) |
1149 ((FT_Version.patch ) & 0x0000ff);
1151 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
1152 ERR("Failed to create font mutex\n");
1155 WaitForSingleObject(font_mutex, INFINITE);
1157 /* load the system fonts */
1158 load_system_fonts();
1160 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
1161 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1162 strcatW(windowsdir, fontsW);
1163 if((unixname = wine_get_unix_file_name(windowsdir)))
1165 ReadFontDir(unixname, FALSE);
1166 HeapFree(GetProcessHeap(), 0, unixname);
1169 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
1170 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
1171 full path as the entry. Also look for any .fon fonts, since ReadFontDir
1173 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
1174 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1175 &hkey) == ERROR_SUCCESS) {
1177 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1178 &valuelen, &datalen, NULL, NULL);
1180 valuelen++; /* returned value doesn't include room for '\0' */
1181 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1182 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1185 dlen = datalen * sizeof(WCHAR);
1187 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
1188 &dlen) == ERROR_SUCCESS) {
1189 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
1191 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
1193 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1194 HeapFree(GetProcessHeap(), 0, unixname);
1197 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
1199 WCHAR pathW[MAX_PATH];
1200 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1201 sprintfW(pathW, fmtW, windowsdir, data);
1202 if((unixname = wine_get_unix_file_name(pathW)))
1204 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1205 HeapFree(GetProcessHeap(), 0, unixname);
1208 /* reset dlen and vlen */
1213 HeapFree(GetProcessHeap(), 0, data);
1214 HeapFree(GetProcessHeap(), 0, valueW);
1218 load_fontconfig_fonts();
1220 /* then look in any directories that we've specified in the config file */
1221 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1222 "Software\\Wine\\Wine\\Config\\FontDirs",
1223 &hkey) == ERROR_SUCCESS) {
1225 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1226 &valuelen, &datalen, NULL, NULL);
1228 valuelen++; /* returned value doesn't include room for '\0' */
1229 value = HeapAlloc(GetProcessHeap(), 0, valuelen);
1230 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1235 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1236 &dlen) == ERROR_SUCCESS) {
1237 TRACE("Got %s=%s\n", value, (LPSTR)data);
1238 ReadFontDir((LPSTR)data, TRUE);
1239 /* reset dlen and vlen */
1243 HeapFree(GetProcessHeap(), 0, data);
1244 HeapFree(GetProcessHeap(), 0, value);
1252 update_reg_entries();
1254 ReleaseMutex(font_mutex);
1258 "Wine cannot find certain functions that it needs inside the FreeType\n"
1259 "font library. To enable Wine to use TrueType fonts please upgrade\n"
1260 "FreeType to at least version 2.0.5.\n"
1261 "http://www.freetype.org\n");
1262 wine_dlclose(ft_handle, NULL, 0);
1268 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
1271 TT_HoriHeader *pHori;
1275 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1276 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1278 if(height == 0) height = 16;
1280 /* Calc. height of EM square:
1282 * For +ve lfHeight we have
1283 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
1284 * Re-arranging gives:
1285 * ppem = units_per_em * lfheight / (winAscent + winDescent)
1287 * For -ve lfHeight we have
1289 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
1290 * with il = winAscent + winDescent - units_per_em]
1295 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
1296 ppem = ft_face->units_per_EM * height /
1297 (pHori->Ascender - pHori->Descender);
1299 ppem = ft_face->units_per_EM * height /
1300 (pOS2->usWinAscent + pOS2->usWinDescent);
1308 static LONG load_VDMX(GdiFont, LONG);
1310 static FT_Face OpenFontFile(GdiFont font, char *file, FT_Long face_index, LONG width, LONG height)
1316 err = pFT_New_Face(library, file, face_index, &ft_face);
1318 ERR("FT_New_Face rets %d\n", err);
1322 /* set it here, as load_VDMX needs it */
1323 font->ft_face = ft_face;
1325 if(FT_IS_SCALABLE(ft_face)) {
1326 /* load the VDMX table if we have one */
1327 ppem = load_VDMX(font, height);
1329 ppem = calc_ppem_for_height(ft_face, height);
1331 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, ppem)) != 0)
1332 WARN("FT_Set_Pixel_Sizes %d, %ld rets %x\n", 0, ppem, err);
1334 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
1335 WARN("FT_Set_Pixel_Sizes %ld, %ld rets %x\n", width, height, err);
1341 static int get_nearest_charset(Face *face, int *cp)
1343 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
1344 a single face with the requested charset. The idea is to check if
1345 the selected font supports the current ANSI codepage, if it does
1346 return the corresponding charset, else return the first charset */
1349 int acp = GetACP(), i;
1353 if(TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE))
1354 if(csi.fs.fsCsb[0] & face->fs.fsCsb[0])
1355 return csi.ciCharset;
1357 for(i = 0; i < 32; i++) {
1359 if(face->fs.fsCsb[0] & fs0) {
1360 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
1362 return csi.ciCharset;
1365 FIXME("TCI failing on %lx\n", fs0);
1369 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08lx file = %s\n",
1370 face->fs.fsCsb[0], face->file);
1372 return DEFAULT_CHARSET;
1375 static GdiFont alloc_font(void)
1377 GdiFont ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
1378 ret->gmsize = INIT_GM_SIZE;
1379 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1380 ret->gmsize * sizeof(*ret->gm));
1382 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
1383 list_init(&ret->hfontlist);
1387 static void free_font(GdiFont font)
1389 if (font->ft_face) pFT_Done_Face(font->ft_face);
1390 HeapFree(GetProcessHeap(), 0, font->potm);
1391 HeapFree(GetProcessHeap(), 0, font->name);
1392 HeapFree(GetProcessHeap(), 0, font->gm);
1393 HeapFree(GetProcessHeap(), 0, font);
1397 /*************************************************************
1400 * load the vdmx entry for the specified height
1403 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
1404 ( ( (FT_ULong)_x4 << 24 ) | \
1405 ( (FT_ULong)_x3 << 16 ) | \
1406 ( (FT_ULong)_x2 << 8 ) | \
1409 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
1419 static LONG load_VDMX(GdiFont font, LONG height)
1421 BYTE hdr[6], tmp[2], group[4];
1422 BYTE devXRatio, devYRatio;
1423 USHORT numRecs, numRatios;
1424 DWORD result, offset = -1;
1428 /* For documentation on VDMX records, see
1429 * http://www.microsoft.com/OpenType/OTSpec/vdmx.htm
1432 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
1434 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
1437 /* FIXME: need the real device aspect ratio */
1441 numRecs = GET_BE_WORD(&hdr[2]);
1442 numRatios = GET_BE_WORD(&hdr[4]);
1444 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
1445 for(i = 0; i < numRatios; i++) {
1448 offset = (3 * 2) + (i * sizeof(Ratios));
1449 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
1452 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
1454 if((ratio.xRatio == 0 &&
1455 ratio.yStartRatio == 0 &&
1456 ratio.yEndRatio == 0) ||
1457 (devXRatio == ratio.xRatio &&
1458 devYRatio >= ratio.yStartRatio &&
1459 devYRatio <= ratio.yEndRatio))
1461 offset = (3 * 2) + (numRatios * 4) + (i * 2);
1462 WineEngGetFontData(font, MS_VDMX_TAG, offset, tmp, 2);
1463 offset = GET_BE_WORD(tmp);
1469 FIXME("No suitable ratio found\n");
1473 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, group, 4) != GDI_ERROR) {
1475 BYTE startsz, endsz;
1478 recs = GET_BE_WORD(group);
1482 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
1484 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
1485 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
1486 if(result == GDI_ERROR) {
1487 FIXME("Failed to retrieve vTable\n");
1492 for(i = 0; i < recs; i++) {
1493 SHORT yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1494 SHORT yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1495 ppem = GET_BE_WORD(&vTable[i * 6]);
1497 if(yMax + -yMin == height) {
1500 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1503 if(yMax + -yMin > height) {
1506 goto end; /* failed */
1508 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1509 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1510 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1516 TRACE("ppem not found for height %ld\n", height);
1520 if(ppem < startsz || ppem > endsz)
1523 for(i = 0; i < recs; i++) {
1525 yPelHeight = GET_BE_WORD(&vTable[i * 6]);
1527 if(yPelHeight > ppem)
1530 if(yPelHeight == ppem) {
1531 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1532 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1533 TRACE("ppem %ld found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
1539 HeapFree(GetProcessHeap(), 0, vTable);
1545 static BOOL fontcmp(GdiFont font, FONT_DESC *fd)
1547 if(font->font_desc.hash != fd->hash) return TRUE;
1548 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
1549 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
1550 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
1553 static void calc_hash(FONT_DESC *pfd)
1555 DWORD hash = 0, *ptr, two_chars;
1559 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
1561 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
1563 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
1565 pwc = (WCHAR *)&two_chars;
1567 *pwc = toupperW(*pwc);
1569 *pwc = toupperW(*pwc);
1577 static GdiFont find_in_cache(HFONT hfont, LOGFONTW *plf, XFORM *pxf, BOOL can_use_bitmap)
1582 struct list *font_elem_ptr, *hfontlist_elem_ptr;
1584 memcpy(&fd.lf, plf, sizeof(LOGFONTW));
1585 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
1588 /* try the in-use list */
1589 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
1590 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
1591 if(!fontcmp(ret, &fd)) {
1592 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
1593 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
1594 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
1595 if(hflist->hfont == hfont)
1598 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
1599 hflist->hfont = hfont;
1600 list_add_head(&ret->hfontlist, &hflist->entry);
1605 /* then the unused list */
1606 font_elem_ptr = list_head(&unused_gdi_font_list);
1607 while(font_elem_ptr) {
1608 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
1609 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
1610 if(!fontcmp(ret, &fd)) {
1611 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
1612 assert(list_empty(&ret->hfontlist));
1613 TRACE("Found %p in unused list\n", ret);
1614 list_remove(&ret->entry);
1615 list_add_head(&gdi_font_list, &ret->entry);
1616 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
1617 hflist->hfont = hfont;
1618 list_add_head(&ret->hfontlist, &hflist->entry);
1625 /*************************************************************
1626 * WineEngCreateFontInstance
1629 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
1634 struct list *family_elem_ptr, *face_elem_ptr;
1635 INT height, width = 0;
1636 signed int diff = 0, newdiff;
1637 BOOL bd, it, can_use_bitmap;
1642 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
1643 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
1645 TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
1646 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
1647 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
1650 /* check the cache first */
1651 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
1652 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
1656 TRACE("not in cache\n");
1657 if(list_empty(&font_list) || !have_installed_roman_font) /* No fonts installed */
1659 TRACE("No fonts installed\n");
1665 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
1666 memcpy(&ret->font_desc.lf, &lf, sizeof(LOGFONTW));
1667 calc_hash(&ret->font_desc);
1668 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
1669 hflist->hfont = hfont;
1670 list_add_head(&ret->hfontlist, &hflist->entry);
1673 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
1674 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
1675 original value lfCharSet. Note this is a special case for
1676 Symbol and doesn't happen at least for "Wingdings*" */
1678 if(!strcmpiW(lf.lfFaceName, SymbolW))
1679 lf.lfCharSet = SYMBOL_CHARSET;
1681 if(!TranslateCharsetInfo((DWORD*)(INT)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
1682 switch(lf.lfCharSet) {
1683 case DEFAULT_CHARSET:
1684 csi.fs.fsCsb[0] = 0;
1687 FIXME("Untranslated charset %d\n", lf.lfCharSet);
1688 csi.fs.fsCsb[0] = 0;
1694 if(lf.lfFaceName[0] != '\0') {
1696 for(psub = substlist; psub; psub = psub->next)
1697 if(!strcmpiW(lf.lfFaceName, psub->from.name) &&
1698 (psub->from.charset == -1 ||
1699 psub->from.charset == lf.lfCharSet))
1702 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
1703 debugstr_w(psub->to.name));
1704 strcpyW(lf.lfFaceName, psub->to.name);
1707 /* We want a match on name and charset or just name if
1708 charset was DEFAULT_CHARSET. If the latter then
1709 we fixup the returned charset later in get_nearest_charset
1710 where we'll either use the charset of the current ansi codepage
1711 or if that's unavailable the first charset that the font supports.
1713 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1714 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1715 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
1716 face_elem_ptr = list_head(&family->faces);
1717 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1718 if((csi.fs.fsCsb[0] & face->fs.fsCsb[0]) || !csi.fs.fsCsb[0])
1719 if(face->scalable || can_use_bitmap)
1727 /* If requested charset was DEFAULT_CHARSET then try using charset
1728 corresponding to the current ansi codepage */
1729 if(!csi.fs.fsCsb[0]) {
1731 if(!TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE)) {
1732 FIXME("TCI failed on codepage %d\n", acp);
1733 csi.fs.fsCsb[0] = 0;
1735 lf.lfCharSet = csi.ciCharset;
1738 /* Face families are in the top 4 bits of lfPitchAndFamily,
1739 so mask with 0xF0 before testing */
1741 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
1742 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
1743 strcpyW(lf.lfFaceName, defFixed);
1744 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
1745 strcpyW(lf.lfFaceName, defSerif);
1746 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
1747 strcpyW(lf.lfFaceName, defSans);
1749 strcpyW(lf.lfFaceName, defSans);
1750 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1751 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1752 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
1753 face_elem_ptr = list_head(&family->faces);
1754 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1755 if(csi.fs.fsCsb[0] & face->fs.fsCsb[0])
1756 if(face->scalable || can_use_bitmap)
1764 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1765 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1766 face_elem_ptr = list_head(&family->faces);
1767 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1768 if(csi.fs.fsCsb[0] & face->fs.fsCsb[0])
1769 if(face->scalable || can_use_bitmap)
1776 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1777 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1778 face_elem_ptr = list_head(&family->faces);
1779 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1780 if(face->scalable || can_use_bitmap) {
1781 csi.fs.fsCsb[0] = 0;
1782 FIXME("just using first face for now\n");
1788 FIXME("can't find a single appropriate font - bailing\n");
1794 it = lf.lfItalic ? 1 : 0;
1795 bd = lf.lfWeight > 550 ? 1 : 0;
1797 height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
1798 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
1801 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1802 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1803 if(!(face->Italic ^ it) && !(face->Bold ^ bd)) {
1807 newdiff = height - (signed int)(face->size.y_ppem >> 6);
1809 newdiff = -height - ((signed int)(face->size.y_ppem >> 6) - face->size.internal_leading);
1810 if(!best || (diff > 0 && newdiff < diff && newdiff >= 0) ||
1811 (diff < 0 && newdiff > diff)) {
1812 TRACE("%ld is better for %d diff was %d\n", face->size.y_ppem >> 6, height, diff);
1825 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1826 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1830 newdiff = height - (signed int)(face->size.y_ppem >> 6);
1832 newdiff = -height - ((signed int)(face->size.y_ppem >> 6) - face->size.internal_leading);
1833 if(!best || (diff > 0 && newdiff < diff && newdiff >= 0) ||
1834 (diff < 0 && newdiff > diff)) {
1835 TRACE("%ld is better for %d diff was %d\n", face->size.y_ppem >> 6, height, diff);
1845 if(it && !face->Italic) ret->fake_italic = TRUE;
1846 if(bd && !face->Bold) ret->fake_bold = TRUE;
1849 memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
1851 if(csi.fs.fsCsb[0]) {
1852 ret->charset = lf.lfCharSet;
1853 ret->codepage = csi.ciACP;
1856 ret->charset = get_nearest_charset(face, &ret->codepage);
1858 TRACE("Chosen: %s %s\n", debugstr_w(family->FamilyName),
1859 debugstr_w(face->StyleName));
1861 if(!face->scalable) {
1862 width = face->size.x_ppem >> 6;
1863 height = face->size.y_ppem >> 6;
1865 ret->ft_face = OpenFontFile(ret, face->file, face->face_index, width, height);
1873 if (ret->charset == SYMBOL_CHARSET &&
1874 !pFT_Select_Charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
1877 else if (!pFT_Select_Charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
1881 pFT_Select_Charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
1884 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
1885 ret->name = strdupW(family->FamilyName);
1886 ret->underline = lf.lfUnderline ? 0xff : 0;
1887 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
1889 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
1891 ret->aveWidth = FT_IS_SCALABLE(ret->ft_face) ? lf.lfWidth : 0;
1892 list_add_head(&gdi_font_list, &ret->entry);
1896 static void dump_gdi_font_list(void)
1899 struct list *elem_ptr;
1901 TRACE("---------- gdiFont Cache ----------\n");
1902 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
1903 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
1904 TRACE("gdiFont=%p %s %ld\n",
1905 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
1908 TRACE("---------- Unused gdiFont Cache ----------\n");
1909 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
1910 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
1911 TRACE("gdiFont=%p %s %ld\n",
1912 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
1916 /*************************************************************
1917 * WineEngDestroyFontInstance
1919 * free the gdiFont associated with this handle
1922 BOOL WineEngDestroyFontInstance(HFONT handle)
1927 struct list *font_elem_ptr, *hfontlist_elem_ptr;
1930 TRACE("destroying hfont=%p\n", handle);
1932 dump_gdi_font_list();
1934 font_elem_ptr = list_head(&gdi_font_list);
1935 while(font_elem_ptr) {
1936 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
1937 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
1939 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
1940 while(hfontlist_elem_ptr) {
1941 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
1942 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
1943 if(hflist->hfont == handle) {
1944 list_remove(&hflist->entry);
1945 HeapFree(GetProcessHeap(), 0, hflist);
1949 if(list_empty(&gdiFont->hfontlist)) {
1950 TRACE("Moving to Unused list\n");
1951 list_remove(&gdiFont->entry);
1952 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
1957 font_elem_ptr = list_head(&unused_gdi_font_list);
1958 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
1959 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
1960 while(font_elem_ptr) {
1961 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
1962 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
1963 TRACE("freeing %p\n", gdiFont);
1964 list_remove(&gdiFont->entry);
1970 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
1971 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
1973 OUTLINETEXTMETRICW *potm = NULL;
1975 TEXTMETRICW tm, *ptm;
1976 GdiFont font = alloc_font();
1979 if(face->scalable) {
1983 height = face->size.y_ppem >> 6;
1984 width = face->size.x_ppem >> 6;
1987 if (!(font->ft_face = OpenFontFile(font, face->file, face->face_index, width, height)))
1993 font->name = strdupW(face->family->FamilyName);
1995 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
1997 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
1999 potm = HeapAlloc(GetProcessHeap(), 0, size);
2000 WineEngGetOutlineTextMetrics(font, size, potm);
2001 ptm = (TEXTMETRICW*)&potm->otmTextMetrics;
2003 WineEngGetTextMetrics(font, &tm);
2007 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = ptm->tmHeight;
2008 pntm->ntmTm.tmAscent = ptm->tmAscent;
2009 pntm->ntmTm.tmDescent = ptm->tmDescent;
2010 pntm->ntmTm.tmInternalLeading = ptm->tmInternalLeading;
2011 pntm->ntmTm.tmExternalLeading = ptm->tmExternalLeading;
2012 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = ptm->tmAveCharWidth;
2013 pntm->ntmTm.tmMaxCharWidth = ptm->tmMaxCharWidth;
2014 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = ptm->tmWeight;
2015 pntm->ntmTm.tmOverhang = ptm->tmOverhang;
2016 pntm->ntmTm.tmDigitizedAspectX = ptm->tmDigitizedAspectX;
2017 pntm->ntmTm.tmDigitizedAspectY = ptm->tmDigitizedAspectY;
2018 pntm->ntmTm.tmFirstChar = ptm->tmFirstChar;
2019 pntm->ntmTm.tmLastChar = ptm->tmLastChar;
2020 pntm->ntmTm.tmDefaultChar = ptm->tmDefaultChar;
2021 pntm->ntmTm.tmBreakChar = ptm->tmBreakChar;
2022 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = ptm->tmItalic;
2023 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = ptm->tmUnderlined;
2024 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = ptm->tmStruckOut;
2025 pntm->ntmTm.tmPitchAndFamily = ptm->tmPitchAndFamily;
2026 pelf->elfLogFont.lfPitchAndFamily = (ptm->tmPitchAndFamily & 0xf1) + 1;
2027 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = ptm->tmCharSet;
2028 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
2029 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
2030 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
2032 *ptype = ptm->tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
2033 if(!(ptm->tmPitchAndFamily & TMPF_VECTOR))
2034 *ptype |= RASTER_FONTTYPE;
2036 pntm->ntmTm.ntmFlags = ptm->tmItalic ? NTM_ITALIC : 0;
2037 if(ptm->tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
2038 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
2040 pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
2041 pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
2042 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
2045 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
2047 strncpyW(pelf->elfLogFont.lfFaceName,
2048 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
2050 strncpyW(pelf->elfFullName,
2051 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
2053 strncpyW(pelf->elfStyle,
2054 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
2057 HeapFree(GetProcessHeap(), 0, potm);
2059 pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
2061 strncpyW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
2062 strncpyW(pelf->elfFullName, face->family->FamilyName, LF_FACESIZE);
2063 pelf->elfStyle[0] = '\0';
2066 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
2071 /*************************************************************
2075 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
2079 struct list *family_elem_ptr, *face_elem_ptr;
2081 NEWTEXTMETRICEXW ntm;
2082 DWORD type, ret = 1;
2088 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
2090 if(plf->lfFaceName[0]) {
2092 for(psub = substlist; psub; psub = psub->next)
2093 if(!strcmpiW(plf->lfFaceName, psub->from.name) &&
2094 (psub->from.charset == -1 ||
2095 psub->from.charset == plf->lfCharSet))
2098 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
2099 debugstr_w(psub->to.name));
2100 memcpy(&lf, plf, sizeof(lf));
2101 strcpyW(lf.lfFaceName, psub->to.name);
2105 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2106 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2107 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
2108 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2109 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2110 GetEnumStructs(face, &elf, &ntm, &type);
2111 for(i = 0; i < 32; i++) {
2112 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
2113 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2114 strcpyW(elf.elfScript, OEM_DOSW);
2115 i = 32; /* break out of loop */
2116 } else if(!(face->fs.fsCsb[0] & (1L << i)))
2119 fs.fsCsb[0] = 1L << i;
2121 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
2123 csi.ciCharset = DEFAULT_CHARSET;
2124 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
2125 if(csi.ciCharset != DEFAULT_CHARSET) {
2126 elf.elfLogFont.lfCharSet =
2127 ntm.ntmTm.tmCharSet = csi.ciCharset;
2129 strcpyW(elf.elfScript, ElfScriptsW[i]);
2131 FIXME("Unknown elfscript for bit %d\n", i);
2134 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2135 debugstr_w(elf.elfLogFont.lfFaceName),
2136 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2137 csi.ciCharset, type, debugstr_w(elf.elfScript),
2138 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
2139 ntm.ntmTm.ntmFlags);
2140 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
2147 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2148 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2149 face_elem_ptr = list_head(&family->faces);
2150 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2151 GetEnumStructs(face, &elf, &ntm, &type);
2152 for(i = 0; i < 32; i++) {
2153 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
2154 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2155 strcpyW(elf.elfScript, OEM_DOSW);
2156 i = 32; /* break out of loop */
2157 } else if(!(face->fs.fsCsb[0] & (1L << i)))
2160 fs.fsCsb[0] = 1L << i;
2162 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
2164 csi.ciCharset = DEFAULT_CHARSET;
2165 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
2166 if(csi.ciCharset != DEFAULT_CHARSET) {
2167 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
2170 strcpyW(elf.elfScript, ElfScriptsW[i]);
2172 FIXME("Unknown elfscript for bit %d\n", i);
2175 TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2176 debugstr_w(elf.elfLogFont.lfFaceName),
2177 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2178 csi.ciCharset, type, debugstr_w(elf.elfScript),
2179 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
2180 ntm.ntmTm.ntmFlags);
2181 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
2190 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
2192 pt->x.value = vec->x >> 6;
2193 pt->x.fract = (vec->x & 0x3f) << 10;
2194 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
2195 pt->y.value = vec->y >> 6;
2196 pt->y.fract = (vec->y & 0x3f) << 10;
2197 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
2201 static FT_UInt get_glyph_index(GdiFont font, UINT glyph)
2203 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
2204 WCHAR wc = (WCHAR)glyph;
2206 WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), 0, 0);
2207 return pFT_Get_Char_Index(font->ft_face, buf);
2210 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
2211 glyph = glyph + 0xf000;
2212 return pFT_Get_Char_Index(font->ft_face, glyph);
2215 /*************************************************************
2216 * WineEngGetGlyphIndices
2218 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
2220 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
2221 LPWORD pgi, DWORD flags)
2225 for(i = 0; i < count; i++)
2226 pgi[i] = get_glyph_index(font, lpstr[i]);
2231 /*************************************************************
2232 * WineEngGetGlyphOutline
2234 * Behaves in exactly the same way as the win32 api GetGlyphOutline
2235 * except that the first parameter is the HWINEENGFONT of the font in
2236 * question rather than an HDC.
2239 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
2240 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
2243 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
2244 FT_Face ft_face = font->ft_face;
2245 FT_UInt glyph_index;
2246 DWORD width, height, pitch, needed = 0;
2247 FT_Bitmap ft_bitmap;
2249 INT left, right, top = 0, bottom = 0;
2251 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
2252 float widthRatio = 1.0;
2253 FT_Matrix transMat = identityMat;
2254 BOOL needsTransform = FALSE;
2257 TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font, glyph, format, lpgm,
2258 buflen, buf, lpmat);
2260 if(format & GGO_GLYPH_INDEX) {
2261 glyph_index = glyph;
2262 format &= ~GGO_GLYPH_INDEX;
2264 glyph_index = get_glyph_index(font, glyph);
2266 if(glyph_index >= font->gmsize) {
2267 font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
2268 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
2269 font->gmsize * sizeof(*font->gm));
2271 if(format == GGO_METRICS && font->gm[glyph_index].init) {
2272 memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
2273 return 1; /* FIXME */
2277 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP) || font->aveWidth || lpmat)
2278 load_flags |= FT_LOAD_NO_BITMAP;
2280 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
2283 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
2287 /* Scaling factor */
2288 if (font->aveWidth && font->potm) {
2289 widthRatio = (float)font->aveWidth * font->font_desc.matrix.eM11 / (float) font->potm->otmTextMetrics.tmAveCharWidth;
2292 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
2293 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
2295 font->gm[glyph_index].adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
2296 font->gm[glyph_index].lsb = left >> 6;
2297 font->gm[glyph_index].bbx = (right - left) >> 6;
2299 /* Scaling transform */
2300 if(font->aveWidth) {
2302 scaleMat.xx = FT_FixedFromFloat(widthRatio);
2305 scaleMat.yy = (1 << 16);
2307 pFT_Matrix_Multiply(&scaleMat, &transMat);
2308 needsTransform = TRUE;
2311 /* Rotation transform */
2312 if(font->orientation) {
2313 FT_Matrix rotationMat;
2315 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
2316 pFT_Vector_Unit(&vecAngle, angle);
2317 rotationMat.xx = vecAngle.x;
2318 rotationMat.xy = -vecAngle.y;
2319 rotationMat.yx = -rotationMat.xy;
2320 rotationMat.yy = rotationMat.xx;
2322 pFT_Matrix_Multiply(&rotationMat, &transMat);
2323 needsTransform = TRUE;
2326 /* Extra transformation specified by caller */
2329 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
2330 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
2331 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
2332 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
2333 pFT_Matrix_Multiply(&extraMat, &transMat);
2334 needsTransform = TRUE;
2337 if(!needsTransform) {
2338 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
2339 bottom = (ft_face->glyph->metrics.horiBearingY -
2340 ft_face->glyph->metrics.height) & -64;
2341 lpgm->gmCellIncX = font->gm[glyph_index].adv;
2342 lpgm->gmCellIncY = 0;
2346 for(xc = 0; xc < 2; xc++) {
2347 for(yc = 0; yc < 2; yc++) {
2348 vec.x = (ft_face->glyph->metrics.horiBearingX +
2349 xc * ft_face->glyph->metrics.width);
2350 vec.y = ft_face->glyph->metrics.horiBearingY -
2351 yc * ft_face->glyph->metrics.height;
2352 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
2353 pFT_Vector_Transform(&vec, &transMat);
2354 if(xc == 0 && yc == 0) {
2355 left = right = vec.x;
2356 top = bottom = vec.y;
2358 if(vec.x < left) left = vec.x;
2359 else if(vec.x > right) right = vec.x;
2360 if(vec.y < bottom) bottom = vec.y;
2361 else if(vec.y > top) top = vec.y;
2366 right = (right + 63) & -64;
2367 bottom = bottom & -64;
2368 top = (top + 63) & -64;
2370 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
2371 vec.x = ft_face->glyph->metrics.horiAdvance;
2373 pFT_Vector_Transform(&vec, &transMat);
2374 lpgm->gmCellIncX = (vec.x+63) >> 6;
2375 lpgm->gmCellIncY = -((vec.y+63) >> 6);
2377 lpgm->gmBlackBoxX = (right - left) >> 6;
2378 lpgm->gmBlackBoxY = (top - bottom) >> 6;
2379 lpgm->gmptGlyphOrigin.x = left >> 6;
2380 lpgm->gmptGlyphOrigin.y = top >> 6;
2382 memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
2383 font->gm[glyph_index].init = TRUE;
2385 if(format == GGO_METRICS)
2386 return 1; /* FIXME */
2388 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP) {
2389 TRACE("loaded a bitmap\n");
2395 width = lpgm->gmBlackBoxX;
2396 height = lpgm->gmBlackBoxY;
2397 pitch = ((width + 31) >> 5) << 2;
2398 needed = pitch * height;
2400 if(!buf || !buflen) break;
2402 switch(ft_face->glyph->format) {
2403 case ft_glyph_format_bitmap:
2405 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
2406 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
2407 INT h = ft_face->glyph->bitmap.rows;
2409 memcpy(dst, src, w);
2410 src += ft_face->glyph->bitmap.pitch;
2416 case ft_glyph_format_outline:
2417 ft_bitmap.width = width;
2418 ft_bitmap.rows = height;
2419 ft_bitmap.pitch = pitch;
2420 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
2421 ft_bitmap.buffer = buf;
2423 if(needsTransform) {
2424 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
2427 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
2429 /* Note: FreeType will only set 'black' bits for us. */
2430 memset(buf, 0, needed);
2431 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
2435 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
2440 case GGO_GRAY2_BITMAP:
2441 case GGO_GRAY4_BITMAP:
2442 case GGO_GRAY8_BITMAP:
2443 case WINE_GGO_GRAY16_BITMAP:
2445 unsigned int mult, row, col;
2448 width = lpgm->gmBlackBoxX;
2449 height = lpgm->gmBlackBoxY;
2450 pitch = (width + 3) / 4 * 4;
2451 needed = pitch * height;
2453 if(!buf || !buflen) break;
2454 ft_bitmap.width = width;
2455 ft_bitmap.rows = height;
2456 ft_bitmap.pitch = pitch;
2457 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
2458 ft_bitmap.buffer = buf;
2460 if(needsTransform) {
2461 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
2464 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
2466 memset(ft_bitmap.buffer, 0, buflen);
2468 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
2470 if(format == GGO_GRAY2_BITMAP)
2472 else if(format == GGO_GRAY4_BITMAP)
2474 else if(format == GGO_GRAY8_BITMAP)
2476 else if(format == WINE_GGO_GRAY16_BITMAP)
2484 for(row = 0; row < height; row++) {
2486 for(col = 0; col < width; col++, ptr++) {
2487 *ptr = (((int)*ptr) * mult + 128) / 256;
2496 int contour, point = 0, first_pt;
2497 FT_Outline *outline = &ft_face->glyph->outline;
2498 TTPOLYGONHEADER *pph;
2500 DWORD pph_start, cpfx, type;
2502 if(buflen == 0) buf = NULL;
2504 if (needsTransform && buf) {
2505 pFT_Outline_Transform(outline, &transMat);
2508 for(contour = 0; contour < outline->n_contours; contour++) {
2510 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
2513 pph->dwType = TT_POLYGON_TYPE;
2514 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2516 needed += sizeof(*pph);
2518 while(point <= outline->contours[contour]) {
2519 ppc = (TTPOLYCURVE *)((char *)buf + needed);
2520 type = (outline->tags[point] & FT_Curve_Tag_On) ?
2521 TT_PRIM_LINE : TT_PRIM_QSPLINE;
2525 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2528 } while(point <= outline->contours[contour] &&
2529 (outline->tags[point] & FT_Curve_Tag_On) ==
2530 (outline->tags[point-1] & FT_Curve_Tag_On));
2531 /* At the end of a contour Windows adds the start point, but
2533 if(point > outline->contours[contour] &&
2534 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
2536 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
2538 } else if(point <= outline->contours[contour] &&
2539 outline->tags[point] & FT_Curve_Tag_On) {
2540 /* add closing pt for bezier */
2542 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2550 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2553 pph->cb = needed - pph_start;
2559 /* Convert the quadratic Beziers to cubic Beziers.
2560 The parametric eqn for a cubic Bezier is, from PLRM:
2561 r(t) = at^3 + bt^2 + ct + r0
2562 with the control points:
2567 A quadratic Beizer has the form:
2568 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
2570 So equating powers of t leads to:
2571 r1 = 2/3 p1 + 1/3 p0
2572 r2 = 2/3 p1 + 1/3 p2
2573 and of course r0 = p0, r3 = p2
2576 int contour, point = 0, first_pt;
2577 FT_Outline *outline = &ft_face->glyph->outline;
2578 TTPOLYGONHEADER *pph;
2580 DWORD pph_start, cpfx, type;
2581 FT_Vector cubic_control[4];
2582 if(buflen == 0) buf = NULL;
2584 if (needsTransform && buf) {
2585 pFT_Outline_Transform(outline, &transMat);
2588 for(contour = 0; contour < outline->n_contours; contour++) {
2590 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
2593 pph->dwType = TT_POLYGON_TYPE;
2594 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2596 needed += sizeof(*pph);
2598 while(point <= outline->contours[contour]) {
2599 ppc = (TTPOLYCURVE *)((char *)buf + needed);
2600 type = (outline->tags[point] & FT_Curve_Tag_On) ?
2601 TT_PRIM_LINE : TT_PRIM_CSPLINE;
2604 if(type == TT_PRIM_LINE) {
2606 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2610 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
2613 /* FIXME: Possible optimization in endpoint calculation
2614 if there are two consecutive curves */
2615 cubic_control[0] = outline->points[point-1];
2616 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
2617 cubic_control[0].x += outline->points[point].x + 1;
2618 cubic_control[0].y += outline->points[point].y + 1;
2619 cubic_control[0].x >>= 1;
2620 cubic_control[0].y >>= 1;
2622 if(point+1 > outline->contours[contour])
2623 cubic_control[3] = outline->points[first_pt];
2625 cubic_control[3] = outline->points[point+1];
2626 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
2627 cubic_control[3].x += outline->points[point].x + 1;
2628 cubic_control[3].y += outline->points[point].y + 1;
2629 cubic_control[3].x >>= 1;
2630 cubic_control[3].y >>= 1;
2633 /* r1 = 1/3 p0 + 2/3 p1
2634 r2 = 1/3 p2 + 2/3 p1 */
2635 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
2636 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
2637 cubic_control[2] = cubic_control[1];
2638 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
2639 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
2640 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
2641 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
2643 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
2644 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
2645 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
2650 } while(point <= outline->contours[contour] &&
2651 (outline->tags[point] & FT_Curve_Tag_On) ==
2652 (outline->tags[point-1] & FT_Curve_Tag_On));
2653 /* At the end of a contour Windows adds the start point,
2654 but only for Beziers and we've already done that.
2656 if(point <= outline->contours[contour] &&
2657 outline->tags[point] & FT_Curve_Tag_On) {
2658 /* This is the closing pt of a bezier, but we've already
2659 added it, so just inc point and carry on */
2666 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2669 pph->cb = needed - pph_start;
2675 FIXME("Unsupported format %d\n", format);
2681 static BOOL get_bitmap_text_metrics(GdiFont font)
2683 FT_Face ft_face = font->ft_face;
2684 #ifdef HAVE_FREETYPE_FTWINFNT_H
2685 FT_WinFNT_HeaderRec winfnt_header;
2687 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
2688 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
2689 font->potm->otmSize = size;
2691 #define TM font->potm->otmTextMetrics
2692 #ifdef HAVE_FREETYPE_FTWINFNT_H
2693 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
2695 TM.tmHeight = winfnt_header.pixel_height;
2696 TM.tmAscent = winfnt_header.ascent;
2697 TM.tmDescent = TM.tmHeight - TM.tmAscent;
2698 TM.tmInternalLeading = winfnt_header.internal_leading;
2699 TM.tmExternalLeading = winfnt_header.external_leading;
2700 TM.tmAveCharWidth = winfnt_header.avg_width;
2701 TM.tmMaxCharWidth = winfnt_header.max_width;
2702 TM.tmWeight = winfnt_header.weight;
2704 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
2705 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
2706 TM.tmFirstChar = winfnt_header.first_char;
2707 TM.tmLastChar = winfnt_header.last_char;
2708 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
2709 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
2710 TM.tmItalic = winfnt_header.italic;
2711 TM.tmUnderlined = font->underline;
2712 TM.tmStruckOut = font->strikeout;
2713 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
2714 TM.tmCharSet = winfnt_header.charset;
2719 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
2720 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
2721 TM.tmHeight = TM.tmAscent + TM.tmDescent;
2722 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
2723 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
2724 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
2725 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
2726 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
2728 TM.tmDigitizedAspectX = 96; /* FIXME */
2729 TM.tmDigitizedAspectY = 96; /* FIXME */
2731 TM.tmLastChar = 255;
2732 TM.tmDefaultChar = 32;
2733 TM.tmBreakChar = 32;
2734 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
2735 TM.tmUnderlined = font->underline;
2736 TM.tmStruckOut = font->strikeout;
2737 /* NB inverted meaning of TMPF_FIXED_PITCH */
2738 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
2739 TM.tmCharSet = font->charset;
2746 /*************************************************************
2747 * WineEngGetTextMetrics
2750 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
2753 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
2754 if(!get_bitmap_text_metrics(font))
2757 if(!font->potm) return FALSE;
2758 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
2760 if (font->aveWidth) {
2761 ptm->tmAveCharWidth = font->aveWidth * font->font_desc.matrix.eM11;
2767 /*************************************************************
2768 * WineEngGetOutlineTextMetrics
2771 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
2772 OUTLINETEXTMETRICW *potm)
2774 FT_Face ft_face = font->ft_face;
2775 UINT needed, lenfam, lensty, ret;
2777 TT_HoriHeader *pHori;
2778 TT_Postscript *pPost;
2779 FT_Fixed x_scale, y_scale;
2780 WCHAR *family_nameW, *style_nameW;
2781 static const WCHAR spaceW[] = {' ', '\0'};
2783 INT ascent, descent;
2785 TRACE("font=%p\n", font);
2787 if(!FT_IS_SCALABLE(ft_face))
2791 if(cbSize >= font->potm->otmSize)
2792 memcpy(potm, font->potm, font->potm->otmSize);
2793 return font->potm->otmSize;
2797 needed = sizeof(*potm);
2799 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
2800 family_nameW = strdupW(font->name);
2802 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
2804 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
2805 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
2806 style_nameW, lensty);
2808 /* These names should be read from the TT name table */
2810 /* length of otmpFamilyName */
2813 /* length of otmpFaceName */
2814 if(!strcasecmp(ft_face->style_name, "regular")) {
2815 needed += lenfam; /* just the family name */
2817 needed += lenfam + lensty; /* family + " " + style */
2820 /* length of otmpStyleName */
2823 /* length of otmpFullName */
2824 needed += lenfam + lensty;
2827 x_scale = ft_face->size->metrics.x_scale;
2828 y_scale = ft_face->size->metrics.y_scale;
2830 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2832 FIXME("Can't find OS/2 table - not TT font?\n");
2837 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2839 FIXME("Can't find HHEA table - not TT font?\n");
2844 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
2846 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",
2847 pOS2->usWinAscent, pOS2->usWinDescent,
2848 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
2849 ft_face->ascender, ft_face->descender, ft_face->height,
2850 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
2851 ft_face->bbox.yMax, ft_face->bbox.yMin);
2853 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
2854 font->potm->otmSize = needed;
2856 #define TM font->potm->otmTextMetrics
2858 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
2859 ascent = pHori->Ascender;
2860 descent = -pHori->Descender;
2862 ascent = pOS2->usWinAscent;
2863 descent = pOS2->usWinDescent;
2867 TM.tmAscent = font->yMax;
2868 TM.tmDescent = -font->yMin;
2869 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
2871 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
2872 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
2873 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
2874 - ft_face->units_per_EM, y_scale) + 32) >> 6;
2877 TM.tmHeight = TM.tmAscent + TM.tmDescent;
2880 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
2882 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
2883 ((ascent + descent) -
2884 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
2886 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
2887 if (TM.tmAveCharWidth == 0) {
2888 TM.tmAveCharWidth = 1;
2890 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
2891 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
2893 TM.tmDigitizedAspectX = 300;
2894 TM.tmDigitizedAspectY = 300;
2895 TM.tmFirstChar = pOS2->usFirstCharIndex;
2896 TM.tmLastChar = pOS2->usLastCharIndex;
2897 TM.tmDefaultChar = pOS2->usDefaultChar;
2898 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
2899 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
2900 TM.tmUnderlined = font->underline;
2901 TM.tmStruckOut = font->strikeout;
2903 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
2904 if(!FT_IS_FIXED_WIDTH(ft_face) &&
2905 (pOS2->version == 0xFFFFU ||
2906 pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
2907 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
2909 TM.tmPitchAndFamily = 0;
2911 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
2912 case PAN_FAMILY_SCRIPT:
2913 TM.tmPitchAndFamily |= FF_SCRIPT;
2915 case PAN_FAMILY_DECORATIVE:
2916 case PAN_FAMILY_PICTORIAL:
2917 TM.tmPitchAndFamily |= FF_DECORATIVE;
2919 case PAN_FAMILY_TEXT_DISPLAY:
2920 if(TM.tmPitchAndFamily == 0) /* fixed */
2921 TM.tmPitchAndFamily = FF_MODERN;
2923 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
2924 case PAN_SERIF_NORMAL_SANS:
2925 case PAN_SERIF_OBTUSE_SANS:
2926 case PAN_SERIF_PERP_SANS:
2927 TM.tmPitchAndFamily |= FF_SWISS;
2930 TM.tmPitchAndFamily |= FF_ROMAN;
2935 TM.tmPitchAndFamily |= FF_DONTCARE;
2938 if(FT_IS_SCALABLE(ft_face))
2939 TM.tmPitchAndFamily |= TMPF_VECTOR;
2940 if(FT_IS_SFNT(ft_face))
2941 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
2943 TM.tmCharSet = font->charset;
2946 font->potm->otmFiller = 0;
2947 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
2948 font->potm->otmfsSelection = pOS2->fsSelection;
2949 font->potm->otmfsType = pOS2->fsType;
2950 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
2951 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
2952 font->potm->otmItalicAngle = 0; /* POST table */
2953 font->potm->otmEMSquare = ft_face->units_per_EM;
2954 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
2955 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
2956 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
2957 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
2958 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
2959 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
2960 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
2961 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
2962 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
2963 font->potm->otmMacAscent = 0; /* where do these come from ? */
2964 font->potm->otmMacDescent = 0;
2965 font->potm->otmMacLineGap = 0;
2966 font->potm->otmusMinimumPPEM = 0; /* TT Header */
2967 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
2968 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
2969 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
2970 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
2971 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
2972 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
2973 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
2974 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
2975 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
2976 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
2978 font->potm->otmsUnderscoreSize = 0;
2979 font->potm->otmsUnderscorePosition = 0;
2981 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
2982 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
2985 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
2986 cp = (char*)font->potm + sizeof(*font->potm);
2987 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
2988 strcpyW((WCHAR*)cp, family_nameW);
2990 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
2991 strcpyW((WCHAR*)cp, style_nameW);
2993 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
2994 strcpyW((WCHAR*)cp, family_nameW);
2995 if(strcasecmp(ft_face->style_name, "regular")) {
2996 strcatW((WCHAR*)cp, spaceW);
2997 strcatW((WCHAR*)cp, style_nameW);
2998 cp += lenfam + lensty;
3001 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
3002 strcpyW((WCHAR*)cp, family_nameW);
3003 strcatW((WCHAR*)cp, spaceW);
3004 strcatW((WCHAR*)cp, style_nameW);
3007 if(potm && needed <= cbSize)
3008 memcpy(potm, font->potm, font->potm->otmSize);
3011 HeapFree(GetProcessHeap(), 0, style_nameW);
3012 HeapFree(GetProcessHeap(), 0, family_nameW);
3018 /*************************************************************
3019 * WineEngGetCharWidth
3022 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
3027 FT_UInt glyph_index;
3029 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
3031 for(c = firstChar; c <= lastChar; c++) {
3032 glyph_index = get_glyph_index(font, c);
3033 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3034 &gm, 0, NULL, NULL);
3035 buffer[c - firstChar] = font->gm[glyph_index].adv;
3040 /*************************************************************
3041 * WineEngGetCharABCWidths
3044 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
3049 FT_UInt glyph_index;
3051 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
3053 if(!FT_IS_SCALABLE(font->ft_face))
3056 for(c = firstChar; c <= lastChar; c++) {
3057 glyph_index = get_glyph_index(font, c);
3058 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3059 &gm, 0, NULL, NULL);
3060 buffer[c - firstChar].abcA = font->gm[glyph_index].lsb;
3061 buffer[c - firstChar].abcB = font->gm[glyph_index].bbx;
3062 buffer[c - firstChar].abcC = font->gm[glyph_index].adv - font->gm[glyph_index].lsb -
3063 font->gm[glyph_index].bbx;
3068 /*************************************************************
3069 * WineEngGetTextExtentPoint
3072 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
3078 FT_UInt glyph_index;
3080 TRACE("%p, %s, %d, %p\n", font, debugstr_wn(wstr, count), count,
3084 WineEngGetTextMetrics(font, &tm);
3085 size->cy = tm.tmHeight;
3087 for(idx = 0; idx < count; idx++) {
3088 glyph_index = get_glyph_index(font, wstr[idx]);
3089 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3090 &gm, 0, NULL, NULL);
3091 size->cx += font->gm[glyph_index].adv;
3093 TRACE("return %ld,%ld\n", size->cx, size->cy);
3097 /*************************************************************
3098 * WineEngGetTextExtentPointI
3101 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
3108 TRACE("%p, %p, %d, %p\n", font, indices, count, size);
3111 WineEngGetTextMetrics(font, &tm);
3112 size->cy = tm.tmHeight;
3114 for(idx = 0; idx < count; idx++) {
3115 WineEngGetGlyphOutline(font, indices[idx],
3116 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
3118 size->cx += font->gm[indices[idx]].adv;
3120 TRACE("return %ld,%ld\n", size->cx, size->cy);
3124 /*************************************************************
3125 * WineEngGetFontData
3128 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
3131 FT_Face ft_face = font->ft_face;
3135 TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
3136 font, table, offset, buf, cbData);
3138 if(!FT_IS_SFNT(ft_face))
3146 if(table) { /* MS tags differ in endidness from FT ones */
3147 table = table >> 24 | table << 24 |
3148 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
3151 /* If the FT_Load_Sfnt_Table function is there we'll use it */
3152 if(pFT_Load_Sfnt_Table)
3153 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
3154 else { /* Do it the hard way */
3155 TT_Face tt_face = (TT_Face) ft_face;
3156 SFNT_Interface *sfnt;
3157 if (FT_Version.major==2 && FT_Version.minor==0)
3160 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
3164 /* A field was added in the middle of the structure in 2.1.x */
3165 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
3167 err = sfnt->load_any(tt_face, table, offset, buf, &len);
3170 TRACE("Can't find table %08lx.\n", table);
3176 /*************************************************************
3177 * WineEngGetTextFace
3180 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
3183 lstrcpynW(str, font->name, count);
3184 return strlenW(font->name);
3186 return strlenW(font->name) + 1;
3189 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
3191 if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
3192 return font->charset;
3195 #else /* HAVE_FREETYPE */
3197 BOOL WineEngInit(void)
3201 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
3205 BOOL WineEngDestroyFontInstance(HFONT hfont)
3210 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3215 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
3216 LPWORD pgi, DWORD flags)
3221 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
3222 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
3225 ERR("called but we don't have FreeType\n");
3229 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
3231 ERR("called but we don't have FreeType\n");
3235 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
3236 OUTLINETEXTMETRICW *potm)
3238 ERR("called but we don't have FreeType\n");
3242 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
3245 ERR("called but we don't have FreeType\n");
3249 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
3252 ERR("called but we don't have FreeType\n");
3256 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
3259 ERR("called but we don't have FreeType\n");
3263 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
3266 ERR("called but we don't have FreeType\n");
3270 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
3273 ERR("called but we don't have FreeType\n");
3277 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
3279 ERR("called but we don't have FreeType\n");
3283 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3289 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3295 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
3298 return DEFAULT_CHARSET;
3301 #endif /* HAVE_FREETYPE */