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"
143 #define GET_BE_WORD(ptr) MAKEWORD( ((BYTE *)(ptr))[1], ((BYTE *)(ptr))[0] )
145 /* This is bascially a copy of FT_Bitmap_Size with an extra element added */
152 FT_Short internal_leading;
155 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
156 So to let this compile on older versions of FreeType we'll define the
157 new structure here. */
159 FT_Short height, width;
160 FT_Pos size, x_ppem, y_ppem;
163 typedef struct tagFace {
171 FT_Fixed font_version;
173 Bitmap_Size size; /* set if face is a bitmap */
174 BOOL external; /* TRUE if we should manually add this font to the registry */
175 struct tagFamily *family;
178 typedef struct tagFamily {
186 INT adv; /* These three hold to widths of the unrotated chars */
203 typedef struct tagHFONTLIST {
221 struct list hfontlist;
226 OUTLINETEXTMETRICW *potm;
230 #define INIT_GM_SIZE 128
232 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
233 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
234 #define UNUSED_CACHE_SIZE 10
236 static struct list font_list = LIST_INIT(font_list);
238 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ',
239 'R','o','m','a','n','\0'};
240 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
241 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
243 static const WCHAR defSystem[] = {'A','r','i','a','l','\0'};
244 static const WCHAR SystemW[] = {'S','y','s','t','e','m','\0'};
245 static const WCHAR MSSansSerifW[] = {'M','S',' ','S','a','n','s',' ',
246 'S','e','r','i','f','\0'};
247 static const WCHAR HelvW[] = {'H','e','l','v','\0'};
248 static const WCHAR RegularW[] = {'R','e','g','u','l','a','r','\0'};
250 static const WCHAR fontsW[] = {'\\','F','o','n','t','s','\0'};
251 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
252 'W','i','n','d','o','w','s','\\',
253 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
254 'F','o','n','t','s','\0'};
256 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
257 'W','i','n','d','o','w','s',' ','N','T','\\',
258 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
259 'F','o','n','t','s','\0'};
261 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
262 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
263 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
264 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
266 static const WCHAR *SystemFontValues[4] = {
273 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\','W','i','n','e','\\',
274 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
276 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
277 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
278 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
279 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
280 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
281 'E','u','r','o','p','e','a','n','\0'};
282 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
283 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
284 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
285 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
286 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
287 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
288 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
289 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
290 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
291 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
292 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
293 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
295 static const WCHAR *ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
305 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
313 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
322 typedef struct tagFontSubst {
325 struct tagFontSubst *next;
328 static FontSubst *substlist = NULL;
329 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
331 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
334 /****************************************
335 * Notes on .fon files
337 * The fonts System, FixedSys and Terminal are special. There are typically multiple
338 * versions installed for different resolutions and codepages. Windows stores which one to use
339 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
341 * FIXEDFON.FON FixedSys
343 * OEMFONT.FON Termial
344 * LogPixels Current dpi set by the display control panel applet
345 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
346 * also has a LogPixels value that appears to mirror this)
348 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
349 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
350 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
351 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
352 * so that makes sense.
354 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
355 * to be mapped into the registry on Windows 2000 at least).
358 * ega80woa.fon=ega80850.fon
359 * ega40woa.fon=ega40850.fon
360 * cga80woa.fon=cga80850.fon
361 * cga40woa.fon=cga40850.fon
365 static inline BOOL is_win9x(void)
367 return GetVersion() & 0x80000000;
370 This function builds an FT_Fixed from a float. It puts the integer part
371 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
372 It fails if the integer part of the float number is greater than SHORT_MAX.
374 static inline FT_Fixed FT_FixedFromFloat(float f)
377 unsigned short fract = (f - value) * 0xFFFF;
378 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
382 This function builds an FT_Fixed from a FIXED. It simply put f.value
383 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
385 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
387 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
390 #define ADDFONT_EXTERNAL_FONT 0x01
391 #define ADDFONT_FORCE_BITMAP 0x02
392 static BOOL AddFontFileToList(const char *file, char *fake_family, DWORD flags)
396 TT_Header *pHeader = NULL;
397 WCHAR *FamilyW, *StyleW;
401 struct list *family_elem_ptr, *face_elem_ptr;
403 FT_Long face_index = 0, num_faces;
404 #ifdef HAVE_FREETYPE_FTWINFNT_H
405 FT_WinFNT_HeaderRec winfnt_header;
410 char *family_name = fake_family;
412 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
413 if((err = pFT_New_Face(library, file, face_index, &ft_face)) != 0) {
414 WARN("Unable to load font file %s err = %x\n", debugstr_a(file), err);
418 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*/
419 pFT_Done_Face(ft_face);
423 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
424 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
425 pFT_Done_Face(ft_face);
429 if(FT_IS_SFNT(ft_face) && (!pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2) ||
430 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
431 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))) {
432 TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
433 "Skipping this font.\n", debugstr_a(file));
434 pFT_Done_Face(ft_face);
438 if(!ft_face->family_name || !ft_face->style_name) {
439 TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file));
440 pFT_Done_Face(ft_face);
445 family_name = ft_face->family_name;
449 My_FT_Bitmap_Size *size = NULL;
451 if(!FT_IS_SCALABLE(ft_face))
452 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
454 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
455 FamilyW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
456 MultiByteToWideChar(CP_ACP, 0, family_name, -1, FamilyW, len);
459 LIST_FOR_EACH(family_elem_ptr, &font_list) {
460 family = LIST_ENTRY(family_elem_ptr, Family, entry);
461 if(!strcmpW(family->FamilyName, FamilyW))
466 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
467 family->FamilyName = FamilyW;
468 list_init(&family->faces);
469 list_add_tail(&font_list, &family->entry);
471 HeapFree(GetProcessHeap(), 0, FamilyW);
474 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
475 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
476 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
478 face_elem_ptr = list_head(&family->faces);
479 while(face_elem_ptr) {
480 face = LIST_ENTRY(face_elem_ptr, Face, entry);
481 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
482 if(!strcmpW(face->StyleName, StyleW) &&
483 (FT_IS_SCALABLE(ft_face) || (size->y_ppem == face->size.y_ppem))) {
484 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
485 debugstr_w(family->FamilyName), debugstr_w(StyleW),
486 face->font_version, pHeader ? pHeader->Font_Revision : 0);
489 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
490 HeapFree(GetProcessHeap(), 0, StyleW);
491 pFT_Done_Face(ft_face);
494 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
495 TRACE("Original font is newer so skipping this one\n");
496 HeapFree(GetProcessHeap(), 0, StyleW);
497 pFT_Done_Face(ft_face);
500 TRACE("Replacing original with this one\n");
501 list_remove(&face->entry);
502 HeapFree(GetProcessHeap(), 0, face->file);
503 HeapFree(GetProcessHeap(), 0, face->StyleName);
504 HeapFree(GetProcessHeap(), 0, face);
509 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
510 list_add_tail(&family->faces, &face->entry);
511 face->StyleName = StyleW;
512 face->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
513 strcpy(face->file, file);
514 face->face_index = face_index;
515 face->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
516 face->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
517 face->font_version = pHeader ? pHeader->Font_Revision : 0;
518 face->family = family;
519 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
521 if(FT_IS_SCALABLE(ft_face)) {
522 memset(&face->size, 0, sizeof(face->size));
523 face->scalable = TRUE;
525 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
526 size->height, size->width, size->size >> 6,
527 size->x_ppem >> 6, size->y_ppem >> 6);
528 face->size.height = size->height;
529 face->size.width = size->width;
530 face->size.size = size->size;
531 face->size.x_ppem = size->x_ppem;
532 face->size.y_ppem = size->y_ppem;
533 face->size.internal_leading = 0;
534 face->scalable = FALSE;
537 memset(&face->fs, 0, sizeof(face->fs));
539 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
541 face->fs.fsCsb[0] = pOS2->ulCodePageRange1;
542 face->fs.fsCsb[1] = pOS2->ulCodePageRange2;
543 face->fs.fsUsb[0] = pOS2->ulUnicodeRange1;
544 face->fs.fsUsb[1] = pOS2->ulUnicodeRange2;
545 face->fs.fsUsb[2] = pOS2->ulUnicodeRange3;
546 face->fs.fsUsb[3] = pOS2->ulUnicodeRange4;
547 if(pOS2->version == 0) {
550 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
551 face->fs.fsCsb[0] |= 1;
553 face->fs.fsCsb[0] |= 1L << 31;
556 #ifdef HAVE_FREETYPE_FTWINFNT_H
557 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
559 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
560 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
561 if(TranslateCharsetInfo((DWORD*)(UINT)winfnt_header.charset, &csi, TCI_SRCCHARSET))
562 memcpy(&face->fs, &csi.fs, sizeof(csi.fs));
563 face->size.internal_leading = winfnt_header.internal_leading;
566 TRACE("fsCsb = %08lx %08lx/%08lx %08lx %08lx %08lx\n",
567 face->fs.fsCsb[0], face->fs.fsCsb[1],
568 face->fs.fsUsb[0], face->fs.fsUsb[1],
569 face->fs.fsUsb[2], face->fs.fsUsb[3]);
572 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
573 for(i = 0; i < ft_face->num_charmaps; i++) {
574 switch(ft_face->charmaps[i]->encoding) {
575 case ft_encoding_unicode:
576 case ft_encoding_apple_roman:
577 face->fs.fsCsb[0] |= 1;
579 case ft_encoding_symbol:
580 face->fs.fsCsb[0] |= 1L << 31;
588 if(face->fs.fsCsb[0] & ~(1L << 31))
589 have_installed_roman_font = TRUE;
590 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
592 num_faces = ft_face->num_faces;
593 pFT_Done_Face(ft_face);
594 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
596 } while(num_faces > ++face_index);
600 static void DumpFontList(void)
604 struct list *family_elem_ptr, *face_elem_ptr;
606 LIST_FOR_EACH(family_elem_ptr, &font_list) {
607 family = LIST_ENTRY(family_elem_ptr, Family, entry);
608 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
609 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
610 face = LIST_ENTRY(face_elem_ptr, Face, entry);
611 TRACE("\t%s", debugstr_w(face->StyleName));
613 TRACE(" %ld", face->size.y_ppem >> 6);
620 static void DumpSubstList(void)
624 for(psub = substlist; psub; psub = psub->next)
625 if(psub->from.charset != -1 || psub->to.charset != -1)
626 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
627 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
629 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
630 debugstr_w(psub->to.name));
634 static LPWSTR strdupW(LPWSTR p)
637 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
638 ret = HeapAlloc(GetProcessHeap(), 0, len);
643 static void split_subst_info(NameCs *nc, LPSTR str)
645 CHAR *p = strrchr(str, ',');
650 nc->charset = strtol(p+1, NULL, 10);
653 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
654 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
655 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
658 static void LoadSubstList(void)
660 FontSubst *psub, **ppsub;
662 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
667 for(psub = substlist; psub;) {
669 HeapFree(GetProcessHeap(), 0, psub->to.name);
670 HeapFree(GetProcessHeap(), 0, psub->from.name);
673 HeapFree(GetProcessHeap(), 0, ptmp);
678 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
679 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
680 &hkey) == ERROR_SUCCESS) {
682 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
683 &valuelen, &datalen, NULL, NULL);
685 valuelen++; /* returned value doesn't include room for '\0' */
686 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
687 data = HeapAlloc(GetProcessHeap(), 0, datalen);
692 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
693 &dlen) == ERROR_SUCCESS) {
694 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
696 *ppsub = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppsub));
697 (*ppsub)->next = NULL;
698 split_subst_info(&((*ppsub)->from), value);
699 split_subst_info(&((*ppsub)->to), data);
701 /* Win 2000 doesn't allow mapping between different charsets
702 or mapping of DEFAULT_CHARSET */
703 if(((*ppsub)->to.charset != (*ppsub)->from.charset) ||
704 (*ppsub)->to.charset == DEFAULT_CHARSET) {
705 HeapFree(GetProcessHeap(), 0, (*ppsub)->to.name);
706 HeapFree(GetProcessHeap(), 0, (*ppsub)->from.name);
707 HeapFree(GetProcessHeap(), 0, *ppsub);
710 ppsub = &((*ppsub)->next);
712 /* reset dlen and vlen */
716 HeapFree(GetProcessHeap(), 0, data);
717 HeapFree(GetProcessHeap(), 0, value);
722 /***********************************************************
723 * The replacement list is a way to map an entire font
724 * family onto another family. For example adding
726 * [HKLM\Software\Wine\Wine\FontReplacements]
727 * "Wingdings"="Winedings"
729 * would enumerate the Winedings font both as Winedings and
730 * Wingdings. However if a real Wingdings font is present the
731 * replacement does not take place.
734 static void LoadReplaceList(void)
737 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
742 struct list *family_elem_ptr, *face_elem_ptr;
743 WCHAR old_nameW[200];
745 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
746 "Software\\Wine\\Wine\\FontReplacements",
747 &hkey) == ERROR_SUCCESS) {
749 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
750 &valuelen, &datalen, NULL, NULL);
752 valuelen++; /* returned value doesn't include room for '\0' */
753 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
754 data = HeapAlloc(GetProcessHeap(), 0, datalen);
758 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
759 &dlen) == ERROR_SUCCESS) {
760 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
761 /* "NewName"="Oldname" */
762 if(!MultiByteToWideChar(CP_ACP, 0, data, -1, old_nameW, sizeof(old_nameW)))
765 /* Find the old family and hence all of the font files
767 LIST_FOR_EACH(family_elem_ptr, &font_list) {
768 family = LIST_ENTRY(family_elem_ptr, Family, entry);
769 if(!strcmpiW(family->FamilyName, old_nameW)) {
770 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
771 face = LIST_ENTRY(face_elem_ptr, Face, entry);
772 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
773 debugstr_w(face->StyleName), value);
774 /* Now add a new entry with the new family name */
775 AddFontFileToList(face->file, value, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
780 /* reset dlen and vlen */
784 HeapFree(GetProcessHeap(), 0, data);
785 HeapFree(GetProcessHeap(), 0, value);
791 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
797 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
799 dir = opendir(dirname);
801 ERR("Can't open directory %s\n", debugstr_a(dirname));
804 while((dent = readdir(dir)) != NULL) {
807 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
810 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
812 sprintf(path, "%s/%s", dirname, dent->d_name);
814 if(stat(path, &statbuf) == -1)
816 WARN("Can't stat %s\n", debugstr_a(path));
819 if(S_ISDIR(statbuf.st_mode))
820 ReadFontDir(path, external_fonts);
822 AddFontFileToList(path, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
828 static void load_fontconfig_fonts(void)
830 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
831 void *fc_handle = NULL;
840 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
842 TRACE("Wine cannot find the fontconfig library (%s).\n",
843 SONAME_LIBFONTCONFIG);
846 #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;}
847 LOAD_FUNCPTR(FcConfigGetCurrent);
848 LOAD_FUNCPTR(FcFontList);
849 LOAD_FUNCPTR(FcFontSetDestroy);
850 LOAD_FUNCPTR(FcInit);
851 LOAD_FUNCPTR(FcObjectSetAdd);
852 LOAD_FUNCPTR(FcObjectSetCreate);
853 LOAD_FUNCPTR(FcObjectSetDestroy);
854 LOAD_FUNCPTR(FcPatternCreate);
855 LOAD_FUNCPTR(FcPatternDestroy);
856 LOAD_FUNCPTR(FcPatternGet);
859 if(!pFcInit()) return;
861 config = pFcConfigGetCurrent();
862 pat = pFcPatternCreate();
863 os = pFcObjectSetCreate();
864 pFcObjectSetAdd(os, FC_FILE);
865 fontset = pFcFontList(config, pat, os);
867 for(i = 0; i < fontset->nfont; i++) {
868 if(pFcPatternGet(fontset->fonts[i], FC_FILE, 0, &v) != FcResultMatch)
870 if(v.type != FcTypeString) continue;
871 TRACE("fontconfig: %s\n", v.u.s);
873 /* We're just interested in OT/TT fonts for now, so this hack just
874 picks up the standard extensions to save time loading every other
877 if(len < 4) continue;
878 ext = v.u.s + len - 3;
879 if(!strcasecmp(ext, "ttf") || !strcasecmp(ext, "ttc") || !strcasecmp(ext, "otf"))
880 AddFontFileToList(v.u.s, NULL, ADDFONT_EXTERNAL_FONT);
882 pFcFontSetDestroy(fontset);
883 pFcObjectSetDestroy(os);
884 pFcPatternDestroy(pat);
891 void load_system_fonts(void)
894 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
897 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
900 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
901 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
902 strcatW(windowsdir, fontsW);
903 for(value = SystemFontValues; *value; value++) {
905 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
907 sprintfW(pathW, fmtW, windowsdir, data);
908 if((unixname = wine_get_unix_file_name(pathW))) {
909 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
910 HeapFree(GetProcessHeap(), 0, unixname);
918 /*************************************************************
920 * This adds registry entries for any externally loaded fonts
921 * (fonts from fontconfig or FontDirs). It also deletes entries
922 * of no longer existing fonts.
925 void update_reg_entries(void)
927 HKEY winkey = 0, externalkey = 0;
930 DWORD dlen, vlen, datalen, valuelen, i, type, len, len_fam;
933 struct list *family_elem_ptr, *face_elem_ptr;
935 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
936 static const WCHAR spaceW[] = {' ', '\0'};
939 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
940 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winkey, NULL) != ERROR_SUCCESS) {
941 ERR("Can't create Windows font reg key\n");
944 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, external_fonts_reg_key,
945 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
946 ERR("Can't create external font reg key\n");
950 /* Delete all external fonts added last time */
952 RegQueryInfoKeyW(externalkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
953 &valuelen, &datalen, NULL, NULL);
954 valuelen++; /* returned value doesn't include room for '\0' */
955 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
956 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
958 dlen = datalen * sizeof(WCHAR);
961 while(RegEnumValueW(externalkey, i++, valueW, &vlen, NULL, &type, data,
962 &dlen) == ERROR_SUCCESS) {
964 RegDeleteValueW(winkey, valueW);
965 /* reset dlen and vlen */
969 HeapFree(GetProcessHeap(), 0, data);
970 HeapFree(GetProcessHeap(), 0, valueW);
972 /* Delete the old external fonts key */
973 RegCloseKey(externalkey);
975 RegDeleteKeyW(HKEY_LOCAL_MACHINE, external_fonts_reg_key);
977 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, external_fonts_reg_key,
978 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
979 ERR("Can't create external font reg key\n");
983 /* enumerate the fonts and add external ones to the two keys */
985 LIST_FOR_EACH(family_elem_ptr, &font_list) {
986 family = LIST_ENTRY(family_elem_ptr, Family, entry);
987 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
988 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
989 face = LIST_ENTRY(face_elem_ptr, Face, entry);
990 if(!face->external) continue;
992 if(strcmpiW(face->StyleName, RegularW))
993 len = len_fam + strlenW(face->StyleName) + 1;
994 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
995 strcpyW(valueW, family->FamilyName);
997 strcatW(valueW, spaceW);
998 strcatW(valueW, face->StyleName);
1000 strcatW(valueW, TrueType);
1001 if((path = strrchr(face->file, '/')) == NULL)
1005 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1007 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1008 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1009 RegSetValueExW(winkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1010 RegSetValueExW(externalkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1012 HeapFree(GetProcessHeap(), 0, file);
1013 HeapFree(GetProcessHeap(), 0, valueW);
1018 RegCloseKey(externalkey);
1020 RegCloseKey(winkey);
1025 /*************************************************************
1026 * WineEngAddFontResourceEx
1029 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1031 if (ft_handle) /* do it only if we have freetype up and running */
1036 FIXME("Ignoring flags %lx\n", flags);
1038 if((unixname = wine_get_unix_file_name(file)))
1040 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1041 HeapFree(GetProcessHeap(), 0, unixname);
1047 /*************************************************************
1048 * WineEngRemoveFontResourceEx
1051 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1057 /*************************************************************
1060 * Initialize FreeType library and create a list of available faces
1062 BOOL WineEngInit(void)
1064 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
1066 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1068 WCHAR windowsdir[MAX_PATH];
1074 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
1077 "Wine cannot find the FreeType font library. To enable Wine to\n"
1078 "use TrueType fonts please install a version of FreeType greater than\n"
1079 "or equal to 2.0.5.\n"
1080 "http://www.freetype.org\n");
1084 #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;}
1086 LOAD_FUNCPTR(FT_Vector_Unit)
1087 LOAD_FUNCPTR(FT_Done_Face)
1088 LOAD_FUNCPTR(FT_Get_Char_Index)
1089 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
1090 LOAD_FUNCPTR(FT_Init_FreeType)
1091 LOAD_FUNCPTR(FT_Load_Glyph)
1092 LOAD_FUNCPTR(FT_Matrix_Multiply)
1093 LOAD_FUNCPTR(FT_MulFix)
1094 LOAD_FUNCPTR(FT_New_Face)
1095 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
1096 LOAD_FUNCPTR(FT_Outline_Transform)
1097 LOAD_FUNCPTR(FT_Outline_Translate)
1098 LOAD_FUNCPTR(FT_Select_Charmap)
1099 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
1100 LOAD_FUNCPTR(FT_Vector_Transform)
1103 /* Don't warn if this one is missing */
1104 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
1105 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
1106 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
1107 #ifdef HAVE_FREETYPE_FTWINFNT_H
1108 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
1110 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
1111 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
1112 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
1113 <= 2.0.3 has FT_Sqrt64 */
1117 if(pFT_Init_FreeType(&library) != 0) {
1118 ERR("Can't init FreeType library\n");
1119 wine_dlclose(ft_handle, NULL, 0);
1123 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
1124 if (pFT_Library_Version)
1126 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
1128 if (FT_Version.major<=0)
1134 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
1135 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
1136 ((FT_Version.minor << 8) & 0x00ff00) |
1137 ((FT_Version.patch ) & 0x0000ff);
1139 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
1140 ERR("Failed to create font mutex\n");
1143 WaitForSingleObject(font_mutex, INFINITE);
1145 /* load the system fonts */
1146 load_system_fonts();
1148 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
1149 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1150 strcatW(windowsdir, fontsW);
1151 if((unixname = wine_get_unix_file_name(windowsdir)))
1153 ReadFontDir(unixname, FALSE);
1154 HeapFree(GetProcessHeap(), 0, unixname);
1157 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
1158 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
1159 full path as the entry. Also look for any .fon fonts, since ReadFontDir
1161 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
1162 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1163 &hkey) == ERROR_SUCCESS) {
1165 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1166 &valuelen, &datalen, NULL, NULL);
1168 valuelen++; /* returned value doesn't include room for '\0' */
1169 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1170 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1173 dlen = datalen * sizeof(WCHAR);
1175 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
1176 &dlen) == ERROR_SUCCESS) {
1177 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
1179 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
1181 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1182 HeapFree(GetProcessHeap(), 0, unixname);
1185 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
1187 WCHAR pathW[MAX_PATH];
1188 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1189 sprintfW(pathW, fmtW, windowsdir, data);
1190 if((unixname = wine_get_unix_file_name(pathW)))
1192 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1193 HeapFree(GetProcessHeap(), 0, unixname);
1196 /* reset dlen and vlen */
1201 if (data) HeapFree(GetProcessHeap(), 0, data);
1202 if (valueW) HeapFree(GetProcessHeap(), 0, valueW);
1206 load_fontconfig_fonts();
1208 /* then look in any directories that we've specified in the config file */
1209 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1210 "Software\\Wine\\Wine\\Config\\FontDirs",
1211 &hkey) == ERROR_SUCCESS) {
1213 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1214 &valuelen, &datalen, NULL, NULL);
1216 valuelen++; /* returned value doesn't include room for '\0' */
1217 value = HeapAlloc(GetProcessHeap(), 0, valuelen);
1218 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1223 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1224 &dlen) == ERROR_SUCCESS) {
1225 TRACE("Got %s=%s\n", value, (LPSTR)data);
1226 ReadFontDir((LPSTR)data, TRUE);
1227 /* reset dlen and vlen */
1231 HeapFree(GetProcessHeap(), 0, data);
1232 HeapFree(GetProcessHeap(), 0, value);
1240 update_reg_entries();
1242 ReleaseMutex(font_mutex);
1246 "Wine cannot find certain functions that it needs inside the FreeType\n"
1247 "font library. To enable Wine to use TrueType fonts please upgrade\n"
1248 "FreeType to at least version 2.0.5.\n"
1249 "http://www.freetype.org\n");
1250 wine_dlclose(ft_handle, NULL, 0);
1256 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
1259 TT_HoriHeader *pHori;
1263 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1264 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1266 if(height == 0) height = 16;
1268 /* Calc. height of EM square:
1270 * For +ve lfHeight we have
1271 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
1272 * Re-arranging gives:
1273 * ppem = units_per_em * lfheight / (winAscent + winDescent)
1275 * For -ve lfHeight we have
1277 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
1278 * with il = winAscent + winDescent - units_per_em]
1283 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
1284 ppem = ft_face->units_per_EM * height /
1285 (pHori->Ascender - pHori->Descender);
1287 ppem = ft_face->units_per_EM * height /
1288 (pOS2->usWinAscent + pOS2->usWinDescent);
1296 static LONG load_VDMX(GdiFont, LONG);
1298 static FT_Face OpenFontFile(GdiFont font, char *file, FT_Long face_index, LONG width, LONG height)
1304 err = pFT_New_Face(library, file, face_index, &ft_face);
1306 ERR("FT_New_Face rets %d\n", err);
1310 /* set it here, as load_VDMX needs it */
1311 font->ft_face = ft_face;
1313 if(FT_IS_SCALABLE(ft_face)) {
1314 /* load the VDMX table if we have one */
1315 ppem = load_VDMX(font, height);
1317 ppem = calc_ppem_for_height(ft_face, height);
1319 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, ppem)) != 0)
1320 WARN("FT_Set_Pixel_Sizes %d, %ld rets %x\n", 0, ppem, err);
1322 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
1323 WARN("FT_Set_Pixel_Sizes %ld, %ld rets %x\n", width, height, err);
1329 static int get_nearest_charset(Face *face, int *cp)
1331 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
1332 a single face with the requested charset. The idea is to check if
1333 the selected font supports the current ANSI codepage, if it does
1334 return the corresponding charset, else return the first charset */
1337 int acp = GetACP(), i;
1341 if(TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE))
1342 if(csi.fs.fsCsb[0] & face->fs.fsCsb[0])
1343 return csi.ciCharset;
1345 for(i = 0; i < 32; i++) {
1347 if(face->fs.fsCsb[0] & fs0) {
1348 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) {
1350 return csi.ciCharset;
1353 FIXME("TCI failing on %lx\n", fs0);
1357 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08lx file = %s\n",
1358 face->fs.fsCsb[0], face->file);
1360 return DEFAULT_CHARSET;
1363 static GdiFont alloc_font(void)
1365 GdiFont ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
1366 ret->gmsize = INIT_GM_SIZE;
1367 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1368 ret->gmsize * sizeof(*ret->gm));
1370 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
1371 list_init(&ret->hfontlist);
1375 static void free_font(GdiFont font)
1377 if (font->ft_face) pFT_Done_Face(font->ft_face);
1378 if (font->potm) HeapFree(GetProcessHeap(), 0, font->potm);
1379 if (font->name) HeapFree(GetProcessHeap(), 0, font->name);
1380 HeapFree(GetProcessHeap(), 0, font->gm);
1381 HeapFree(GetProcessHeap(), 0, font);
1385 /*************************************************************
1388 * load the vdmx entry for the specified height
1391 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
1392 ( ( (FT_ULong)_x4 << 24 ) | \
1393 ( (FT_ULong)_x3 << 16 ) | \
1394 ( (FT_ULong)_x2 << 8 ) | \
1397 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
1407 static LONG load_VDMX(GdiFont font, LONG height)
1409 BYTE hdr[6], tmp[2], group[4];
1410 BYTE devXRatio, devYRatio;
1411 USHORT numRecs, numRatios;
1416 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
1418 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
1421 /* FIXME: need the real device aspect ratio */
1425 numRecs = GET_BE_WORD(&hdr[2]);
1426 numRatios = GET_BE_WORD(&hdr[4]);
1428 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
1429 for(i = 0; i < numRatios; i++) {
1432 offset = (3 * 2) + (i * sizeof(Ratios));
1433 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
1436 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
1438 if(ratio.bCharSet != 1)
1441 if((ratio.xRatio == 0 &&
1442 ratio.yStartRatio == 0 &&
1443 ratio.yEndRatio == 0) ||
1444 (devXRatio == ratio.xRatio &&
1445 devYRatio >= ratio.yStartRatio &&
1446 devYRatio <= ratio.yEndRatio))
1448 offset = (3 * 2) + (numRatios * 4) + (i * 2);
1449 WineEngGetFontData(font, MS_VDMX_TAG, offset, tmp, 2);
1450 offset = GET_BE_WORD(tmp);
1456 FIXME("No suitable ratio found\n");
1460 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, group, 4) != GDI_ERROR) {
1462 BYTE startsz, endsz;
1465 recs = GET_BE_WORD(group);
1469 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
1471 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
1472 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
1473 if(result == GDI_ERROR) {
1474 FIXME("Failed to retrieve vTable\n");
1479 for(i = 0; i < recs; i++) {
1480 SHORT yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1481 SHORT yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1482 ppem = GET_BE_WORD(&vTable[i * 6]);
1484 if(yMax + -yMin == height) {
1487 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1490 if(yMax + -yMin > height) {
1493 goto end; /* failed */
1495 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1496 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1497 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1503 TRACE("ppem not found for height %ld\n", height);
1507 if(ppem < startsz || ppem > endsz)
1510 for(i = 0; i < recs; i++) {
1512 yPelHeight = GET_BE_WORD(&vTable[i * 6]);
1514 if(yPelHeight > ppem)
1517 if(yPelHeight == ppem) {
1518 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1519 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1520 TRACE("ppem %ld found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
1526 HeapFree(GetProcessHeap(), 0, vTable);
1532 static BOOL fontcmp(GdiFont font, FONT_DESC *fd)
1534 if(font->font_desc.hash != fd->hash) return TRUE;
1535 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
1536 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
1537 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
1540 static void calc_hash(FONT_DESC *pfd)
1542 DWORD hash = 0, *ptr, two_chars;
1546 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
1548 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
1550 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
1552 pwc = (WCHAR *)&two_chars;
1554 *pwc = toupperW(*pwc);
1556 *pwc = toupperW(*pwc);
1564 static GdiFont find_in_cache(HFONT hfont, LOGFONTW *plf, XFORM *pxf, BOOL can_use_bitmap)
1569 struct list *font_elem_ptr, *hfontlist_elem_ptr;
1571 memcpy(&fd.lf, plf, sizeof(LOGFONTW));
1572 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
1575 /* try the in-use list */
1576 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
1577 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
1578 if(!fontcmp(ret, &fd)) {
1579 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
1580 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
1581 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
1582 if(hflist->hfont == hfont)
1585 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
1586 hflist->hfont = hfont;
1587 list_add_head(&ret->hfontlist, &hflist->entry);
1592 /* then the unused list */
1593 font_elem_ptr = list_head(&unused_gdi_font_list);
1594 while(font_elem_ptr) {
1595 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
1596 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
1597 if(!fontcmp(ret, &fd)) {
1598 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
1599 assert(list_empty(&ret->hfontlist));
1600 TRACE("Found %p in unused list\n", ret);
1601 list_remove(&ret->entry);
1602 list_add_head(&gdi_font_list, &ret->entry);
1603 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
1604 hflist->hfont = hfont;
1605 list_add_head(&ret->hfontlist, &hflist->entry);
1612 /*************************************************************
1613 * WineEngCreateFontInstance
1616 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
1621 struct list *family_elem_ptr, *face_elem_ptr;
1622 INT height, width = 0;
1623 signed int diff = 0, newdiff;
1624 BOOL bd, it, can_use_bitmap;
1629 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
1630 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
1632 TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
1633 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
1634 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
1637 /* check the cache first */
1638 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
1639 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
1643 TRACE("not in cache\n");
1644 if(list_empty(&font_list) || !have_installed_roman_font) /* No fonts installed */
1646 TRACE("No fonts installed\n");
1652 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
1653 memcpy(&ret->font_desc.lf, &lf, sizeof(LOGFONTW));
1654 calc_hash(&ret->font_desc);
1655 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
1656 hflist->hfont = hfont;
1657 list_add_head(&ret->hfontlist, &hflist->entry);
1660 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
1661 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
1662 original value lfCharSet. Note this is a special case for
1663 Symbol and doesn't happen at least for "Wingdings*" */
1665 if(!strcmpiW(lf.lfFaceName, SymbolW))
1666 lf.lfCharSet = SYMBOL_CHARSET;
1668 if(!TranslateCharsetInfo((DWORD*)(INT)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
1669 switch(lf.lfCharSet) {
1670 case DEFAULT_CHARSET:
1671 csi.fs.fsCsb[0] = 0;
1674 FIXME("Untranslated charset %d\n", lf.lfCharSet);
1675 csi.fs.fsCsb[0] = 0;
1681 if(lf.lfFaceName[0] != '\0') {
1683 for(psub = substlist; psub; psub = psub->next)
1684 if(!strcmpiW(lf.lfFaceName, psub->from.name) &&
1685 (psub->from.charset == -1 ||
1686 psub->from.charset == lf.lfCharSet))
1689 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
1690 debugstr_w(psub->to.name));
1691 strcpyW(lf.lfFaceName, psub->to.name);
1694 /* We want a match on name and charset or just name if
1695 charset was DEFAULT_CHARSET. If the latter then
1696 we fixup the returned charset later in get_nearest_charset
1697 where we'll either use the charset of the current ansi codepage
1698 or if that's unavailable the first charset that the font supports.
1700 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1701 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1702 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
1703 face_elem_ptr = list_head(&family->faces);
1704 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1705 if((csi.fs.fsCsb[0] & face->fs.fsCsb[0]) || !csi.fs.fsCsb[0])
1706 if(face->scalable || can_use_bitmap)
1714 /* If requested charset was DEFAULT_CHARSET then try using charset
1715 corresponding to the current ansi codepage */
1716 if(!csi.fs.fsCsb[0]) {
1718 if(!TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE)) {
1719 FIXME("TCI failed on codepage %d\n", acp);
1720 csi.fs.fsCsb[0] = 0;
1722 lf.lfCharSet = csi.ciCharset;
1725 /* Face families are in the top 4 bits of lfPitchAndFamily,
1726 so mask with 0xF0 before testing */
1728 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
1729 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
1730 strcpyW(lf.lfFaceName, defFixed);
1731 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
1732 strcpyW(lf.lfFaceName, defSerif);
1733 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
1734 strcpyW(lf.lfFaceName, defSans);
1736 strcpyW(lf.lfFaceName, defSans);
1737 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1738 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1739 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
1740 face_elem_ptr = list_head(&family->faces);
1741 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1742 if(csi.fs.fsCsb[0] & face->fs.fsCsb[0])
1743 if(face->scalable || can_use_bitmap)
1751 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1752 family = LIST_ENTRY(family_elem_ptr, Family, entry);
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)
1763 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1764 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1765 face_elem_ptr = list_head(&family->faces);
1766 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1767 if(face->scalable || can_use_bitmap) {
1768 csi.fs.fsCsb[0] = 0;
1769 FIXME("just using first face for now\n");
1775 FIXME("can't find a single appropriate font - bailing\n");
1781 it = lf.lfItalic ? 1 : 0;
1782 bd = lf.lfWeight > 550 ? 1 : 0;
1784 height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
1785 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
1788 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1789 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1790 if(!(face->Italic ^ it) && !(face->Bold ^ bd)) {
1794 newdiff = height - (signed int)(face->size.y_ppem >> 6);
1796 newdiff = -height - ((signed int)(face->size.y_ppem >> 6) - face->size.internal_leading);
1797 if(!best || (diff > 0 && newdiff < diff && newdiff >= 0) ||
1798 (diff < 0 && newdiff > diff)) {
1799 TRACE("%ld is better for %d diff was %d\n", face->size.y_ppem >> 6, height, diff);
1812 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1813 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1817 newdiff = height - (signed int)(face->size.y_ppem >> 6);
1819 newdiff = -height - ((signed int)(face->size.y_ppem >> 6) - face->size.internal_leading);
1820 if(!best || (diff > 0 && newdiff < diff && newdiff >= 0) ||
1821 (diff < 0 && newdiff > diff)) {
1822 TRACE("%ld is better for %d diff was %d\n", face->size.y_ppem >> 6, height, diff);
1832 if(it && !face->Italic) ret->fake_italic = TRUE;
1833 if(bd && !face->Bold) ret->fake_bold = TRUE;
1836 memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
1838 if(csi.fs.fsCsb[0]) {
1839 ret->charset = lf.lfCharSet;
1840 ret->codepage = csi.ciACP;
1843 ret->charset = get_nearest_charset(face, &ret->codepage);
1845 TRACE("Chosen: %s %s\n", debugstr_w(family->FamilyName),
1846 debugstr_w(face->StyleName));
1848 if(!face->scalable) {
1849 width = face->size.x_ppem >> 6;
1850 height = face->size.y_ppem >> 6;
1852 ret->ft_face = OpenFontFile(ret, face->file, face->face_index, width, height);
1860 if (ret->charset == SYMBOL_CHARSET &&
1861 !pFT_Select_Charmap(ret->ft_face, ft_encoding_symbol)) {
1864 else if (!pFT_Select_Charmap(ret->ft_face, ft_encoding_unicode)) {
1868 pFT_Select_Charmap(ret->ft_face, ft_encoding_apple_roman);
1871 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
1872 ret->name = strdupW(family->FamilyName);
1873 ret->underline = lf.lfUnderline ? 0xff : 0;
1874 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
1876 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
1878 ret->aveWidth = FT_IS_SCALABLE(ret->ft_face) ? lf.lfWidth : 0;
1879 list_add_head(&gdi_font_list, &ret->entry);
1883 static void dump_gdi_font_list(void)
1886 struct list *elem_ptr;
1888 TRACE("---------- gdiFont Cache ----------\n");
1889 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
1890 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
1891 TRACE("gdiFont=%p %s %ld\n",
1892 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
1895 TRACE("---------- Unused gdiFont Cache ----------\n");
1896 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
1897 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
1898 TRACE("gdiFont=%p %s %ld\n",
1899 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
1903 /*************************************************************
1904 * WineEngDestroyFontInstance
1906 * free the gdiFont associated with this handle
1909 BOOL WineEngDestroyFontInstance(HFONT handle)
1914 struct list *font_elem_ptr, *hfontlist_elem_ptr;
1917 TRACE("destroying hfont=%p\n", handle);
1919 dump_gdi_font_list();
1921 font_elem_ptr = list_head(&gdi_font_list);
1922 while(font_elem_ptr) {
1923 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
1924 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
1926 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
1927 while(hfontlist_elem_ptr) {
1928 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
1929 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
1930 if(hflist->hfont == handle) {
1931 list_remove(&hflist->entry);
1932 HeapFree(GetProcessHeap(), 0, hflist);
1936 if(list_empty(&gdiFont->hfontlist)) {
1937 TRACE("Moving to Unused list\n");
1938 list_remove(&gdiFont->entry);
1939 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
1944 font_elem_ptr = list_head(&unused_gdi_font_list);
1945 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
1946 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
1947 while(font_elem_ptr) {
1948 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
1949 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
1950 TRACE("freeing %p\n", gdiFont);
1951 list_remove(&gdiFont->entry);
1957 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
1958 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
1960 OUTLINETEXTMETRICW *potm = NULL;
1962 TEXTMETRICW tm, *ptm;
1963 GdiFont font = alloc_font();
1966 if(face->scalable) {
1970 height = face->size.y_ppem >> 6;
1971 width = face->size.x_ppem >> 6;
1974 if (!(font->ft_face = OpenFontFile(font, face->file, face->face_index, width, height)))
1980 font->name = strdupW(face->family->FamilyName);
1982 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
1984 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
1986 potm = HeapAlloc(GetProcessHeap(), 0, size);
1987 WineEngGetOutlineTextMetrics(font, size, potm);
1988 ptm = (TEXTMETRICW*)&potm->otmTextMetrics;
1990 WineEngGetTextMetrics(font, &tm);
1994 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = ptm->tmHeight;
1995 pntm->ntmTm.tmAscent = ptm->tmAscent;
1996 pntm->ntmTm.tmDescent = ptm->tmDescent;
1997 pntm->ntmTm.tmInternalLeading = ptm->tmInternalLeading;
1998 pntm->ntmTm.tmExternalLeading = ptm->tmExternalLeading;
1999 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = ptm->tmAveCharWidth;
2000 pntm->ntmTm.tmMaxCharWidth = ptm->tmMaxCharWidth;
2001 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = ptm->tmWeight;
2002 pntm->ntmTm.tmOverhang = ptm->tmOverhang;
2003 pntm->ntmTm.tmDigitizedAspectX = ptm->tmDigitizedAspectX;
2004 pntm->ntmTm.tmDigitizedAspectY = ptm->tmDigitizedAspectY;
2005 pntm->ntmTm.tmFirstChar = ptm->tmFirstChar;
2006 pntm->ntmTm.tmLastChar = ptm->tmLastChar;
2007 pntm->ntmTm.tmDefaultChar = ptm->tmDefaultChar;
2008 pntm->ntmTm.tmBreakChar = ptm->tmBreakChar;
2009 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = ptm->tmItalic;
2010 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = ptm->tmUnderlined;
2011 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = ptm->tmStruckOut;
2012 pntm->ntmTm.tmPitchAndFamily = ptm->tmPitchAndFamily;
2013 pelf->elfLogFont.lfPitchAndFamily = (ptm->tmPitchAndFamily & 0xf1) + 1;
2014 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = ptm->tmCharSet;
2015 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
2016 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
2017 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
2019 *ptype = ptm->tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
2020 if(!(ptm->tmPitchAndFamily & TMPF_VECTOR))
2021 *ptype |= RASTER_FONTTYPE;
2024 pntm->ntmTm.ntmFlags = ptm->tmItalic ? NTM_ITALIC : 0;
2025 if(ptm->tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
2026 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
2028 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
2029 pntm->ntmTm.ntmCellHeight = 0;
2030 pntm->ntmTm.ntmAvgWidth = 0;
2032 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
2034 strncpyW(pelf->elfLogFont.lfFaceName,
2035 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
2037 strncpyW(pelf->elfFullName,
2038 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
2040 strncpyW(pelf->elfStyle,
2041 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
2045 strncpyW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
2046 strncpyW(pelf->elfFullName, face->family->FamilyName, LF_FACESIZE);
2047 pelf->elfStyle[0] = '\0';
2050 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
2052 HeapFree(GetProcessHeap(), 0, potm);
2057 /*************************************************************
2061 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
2065 struct list *family_elem_ptr, *face_elem_ptr;
2067 NEWTEXTMETRICEXW ntm;
2068 DWORD type, ret = 1;
2074 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
2076 if(plf->lfFaceName[0]) {
2078 for(psub = substlist; psub; psub = psub->next)
2079 if(!strcmpiW(plf->lfFaceName, psub->from.name) &&
2080 (psub->from.charset == -1 ||
2081 psub->from.charset == plf->lfCharSet))
2084 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
2085 debugstr_w(psub->to.name));
2086 memcpy(&lf, plf, sizeof(lf));
2087 strcpyW(lf.lfFaceName, psub->to.name);
2091 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2092 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2093 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
2094 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2095 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2096 GetEnumStructs(face, &elf, &ntm, &type);
2097 for(i = 0; i < 32; i++) {
2098 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
2099 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2100 strcpyW(elf.elfScript, OEM_DOSW);
2101 i = 32; /* break out of loop */
2102 } else if(!(face->fs.fsCsb[0] & (1L << i)))
2105 fs.fsCsb[0] = 1L << i;
2107 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
2109 csi.ciCharset = DEFAULT_CHARSET;
2110 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
2111 if(csi.ciCharset != DEFAULT_CHARSET) {
2112 elf.elfLogFont.lfCharSet =
2113 ntm.ntmTm.tmCharSet = csi.ciCharset;
2115 strcpyW(elf.elfScript, ElfScriptsW[i]);
2117 FIXME("Unknown elfscript for bit %d\n", i);
2120 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2121 debugstr_w(elf.elfLogFont.lfFaceName),
2122 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2123 csi.ciCharset, type, debugstr_w(elf.elfScript),
2124 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
2125 ntm.ntmTm.ntmFlags);
2126 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
2133 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2134 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2135 face_elem_ptr = list_head(&family->faces);
2136 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2137 GetEnumStructs(face, &elf, &ntm, &type);
2138 for(i = 0; i < 32; i++) {
2139 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
2140 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2141 strcpyW(elf.elfScript, OEM_DOSW);
2142 i = 32; /* break out of loop */
2143 } else if(!(face->fs.fsCsb[0] & (1L << i)))
2146 fs.fsCsb[0] = 1L << i;
2148 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
2150 csi.ciCharset = DEFAULT_CHARSET;
2151 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
2152 if(csi.ciCharset != DEFAULT_CHARSET) {
2153 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
2156 strcpyW(elf.elfScript, ElfScriptsW[i]);
2158 FIXME("Unknown elfscript for bit %d\n", i);
2161 TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2162 debugstr_w(elf.elfLogFont.lfFaceName),
2163 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2164 csi.ciCharset, type, debugstr_w(elf.elfScript),
2165 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
2166 ntm.ntmTm.ntmFlags);
2167 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
2176 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
2178 pt->x.value = vec->x >> 6;
2179 pt->x.fract = (vec->x & 0x3f) << 10;
2180 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
2181 pt->y.value = vec->y >> 6;
2182 pt->y.fract = (vec->y & 0x3f) << 10;
2183 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
2187 static FT_UInt get_glyph_index(GdiFont font, UINT glyph)
2189 if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
2190 WCHAR wc = (WCHAR)glyph;
2192 WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), 0, 0);
2193 return pFT_Get_Char_Index(font->ft_face, buf);
2196 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
2197 glyph = glyph + 0xf000;
2198 return pFT_Get_Char_Index(font->ft_face, glyph);
2201 /*************************************************************
2202 * WineEngGetGlyphIndices
2204 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
2206 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
2207 LPWORD pgi, DWORD flags)
2211 for(i = 0; i < count; i++)
2212 pgi[i] = get_glyph_index(font, lpstr[i]);
2217 /*************************************************************
2218 * WineEngGetGlyphOutline
2220 * Behaves in exactly the same way as the win32 api GetGlyphOutline
2221 * except that the first parameter is the HWINEENGFONT of the font in
2222 * question rather than an HDC.
2225 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
2226 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
2229 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
2230 FT_Face ft_face = font->ft_face;
2231 FT_UInt glyph_index;
2232 DWORD width, height, pitch, needed = 0;
2233 FT_Bitmap ft_bitmap;
2235 INT left, right, top = 0, bottom = 0;
2237 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
2238 float widthRatio = 1.0;
2239 FT_Matrix transMat = identityMat;
2240 BOOL needsTransform = FALSE;
2243 TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font, glyph, format, lpgm,
2244 buflen, buf, lpmat);
2246 if(format & GGO_GLYPH_INDEX) {
2247 glyph_index = glyph;
2248 format &= ~GGO_GLYPH_INDEX;
2250 glyph_index = get_glyph_index(font, glyph);
2252 if(glyph_index >= font->gmsize) {
2253 font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
2254 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
2255 font->gmsize * sizeof(*font->gm));
2257 if(format == GGO_METRICS && font->gm[glyph_index].init) {
2258 memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
2259 return 1; /* FIXME */
2263 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP) || font->aveWidth || lpmat)
2264 load_flags |= FT_LOAD_NO_BITMAP;
2266 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
2269 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
2273 /* Scaling factor */
2274 if (font->aveWidth && font->potm) {
2275 widthRatio = (float)font->aveWidth * font->font_desc.matrix.eM11 / (float) font->potm->otmTextMetrics.tmAveCharWidth;
2278 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
2279 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
2281 font->gm[glyph_index].adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
2282 font->gm[glyph_index].lsb = left >> 6;
2283 font->gm[glyph_index].bbx = (right - left) >> 6;
2285 /* Scaling transform */
2286 if(font->aveWidth) {
2288 scaleMat.xx = FT_FixedFromFloat(widthRatio);
2291 scaleMat.yy = (1 << 16);
2293 pFT_Matrix_Multiply(&scaleMat, &transMat);
2294 needsTransform = TRUE;
2297 /* Rotation transform */
2298 if(font->orientation) {
2299 FT_Matrix rotationMat;
2301 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
2302 pFT_Vector_Unit(&vecAngle, angle);
2303 rotationMat.xx = vecAngle.x;
2304 rotationMat.xy = -vecAngle.y;
2305 rotationMat.yx = -rotationMat.xy;
2306 rotationMat.yy = rotationMat.xx;
2308 pFT_Matrix_Multiply(&rotationMat, &transMat);
2309 needsTransform = TRUE;
2312 /* Extra transformation specified by caller */
2315 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
2316 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
2317 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
2318 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
2319 pFT_Matrix_Multiply(&extraMat, &transMat);
2320 needsTransform = TRUE;
2323 if(!needsTransform) {
2324 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
2325 bottom = (ft_face->glyph->metrics.horiBearingY -
2326 ft_face->glyph->metrics.height) & -64;
2327 lpgm->gmCellIncX = font->gm[glyph_index].adv;
2328 lpgm->gmCellIncY = 0;
2332 for(xc = 0; xc < 2; xc++) {
2333 for(yc = 0; yc < 2; yc++) {
2334 vec.x = (ft_face->glyph->metrics.horiBearingX +
2335 xc * ft_face->glyph->metrics.width);
2336 vec.y = ft_face->glyph->metrics.horiBearingY -
2337 yc * ft_face->glyph->metrics.height;
2338 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
2339 pFT_Vector_Transform(&vec, &transMat);
2340 if(xc == 0 && yc == 0) {
2341 left = right = vec.x;
2342 top = bottom = vec.y;
2344 if(vec.x < left) left = vec.x;
2345 else if(vec.x > right) right = vec.x;
2346 if(vec.y < bottom) bottom = vec.y;
2347 else if(vec.y > top) top = vec.y;
2352 right = (right + 63) & -64;
2353 bottom = bottom & -64;
2354 top = (top + 63) & -64;
2356 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
2357 vec.x = ft_face->glyph->metrics.horiAdvance;
2359 pFT_Vector_Transform(&vec, &transMat);
2360 lpgm->gmCellIncX = (vec.x+63) >> 6;
2361 lpgm->gmCellIncY = -((vec.y+63) >> 6);
2363 lpgm->gmBlackBoxX = (right - left) >> 6;
2364 lpgm->gmBlackBoxY = (top - bottom) >> 6;
2365 lpgm->gmptGlyphOrigin.x = left >> 6;
2366 lpgm->gmptGlyphOrigin.y = top >> 6;
2368 memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
2369 font->gm[glyph_index].init = TRUE;
2371 if(format == GGO_METRICS)
2372 return 1; /* FIXME */
2374 if (buf && !buflen){
2378 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP) {
2379 TRACE("loaded a bitmap\n");
2385 width = lpgm->gmBlackBoxX;
2386 height = lpgm->gmBlackBoxY;
2387 pitch = ((width + 31) >> 5) << 2;
2388 needed = pitch * height;
2390 if(!buf || !buflen) break;
2392 switch(ft_face->glyph->format) {
2393 case ft_glyph_format_bitmap:
2395 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
2396 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
2397 INT h = ft_face->glyph->bitmap.rows;
2399 memcpy(dst, src, w);
2400 src += ft_face->glyph->bitmap.pitch;
2406 case ft_glyph_format_outline:
2407 ft_bitmap.width = width;
2408 ft_bitmap.rows = height;
2409 ft_bitmap.pitch = pitch;
2410 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
2411 ft_bitmap.buffer = buf;
2413 if(needsTransform) {
2414 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
2417 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
2419 /* Note: FreeType will only set 'black' bits for us. */
2420 memset(buf, 0, needed);
2421 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
2425 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
2430 case GGO_GRAY2_BITMAP:
2431 case GGO_GRAY4_BITMAP:
2432 case GGO_GRAY8_BITMAP:
2433 case WINE_GGO_GRAY16_BITMAP:
2438 width = lpgm->gmBlackBoxX;
2439 height = lpgm->gmBlackBoxY;
2440 pitch = (width + 3) / 4 * 4;
2441 needed = pitch * height;
2443 if(!buf || !buflen) break;
2444 ft_bitmap.width = width;
2445 ft_bitmap.rows = height;
2446 ft_bitmap.pitch = pitch;
2447 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
2448 ft_bitmap.buffer = buf;
2450 if(needsTransform) {
2451 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
2454 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
2456 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
2458 if(format == GGO_GRAY2_BITMAP)
2460 else if(format == GGO_GRAY4_BITMAP)
2462 else if(format == GGO_GRAY8_BITMAP)
2464 else if(format == WINE_GGO_GRAY16_BITMAP)
2472 for(row = 0; row < height; row++) {
2474 for(col = 0; col < width; col++, ptr++) {
2475 *ptr = (*(unsigned int*)ptr * mult + 128) / 256;
2484 int contour, point = 0, first_pt;
2485 FT_Outline *outline = &ft_face->glyph->outline;
2486 TTPOLYGONHEADER *pph;
2488 DWORD pph_start, cpfx, type;
2490 if(buflen == 0) buf = NULL;
2492 if (needsTransform && buf) {
2493 pFT_Outline_Transform(outline, &transMat);
2496 for(contour = 0; contour < outline->n_contours; contour++) {
2498 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
2501 pph->dwType = TT_POLYGON_TYPE;
2502 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2504 needed += sizeof(*pph);
2506 while(point <= outline->contours[contour]) {
2507 ppc = (TTPOLYCURVE *)((char *)buf + needed);
2508 type = (outline->tags[point] & FT_Curve_Tag_On) ?
2509 TT_PRIM_LINE : TT_PRIM_QSPLINE;
2513 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2516 } while(point <= outline->contours[contour] &&
2517 (outline->tags[point] & FT_Curve_Tag_On) ==
2518 (outline->tags[point-1] & FT_Curve_Tag_On));
2519 /* At the end of a contour Windows adds the start point, but
2521 if(point > outline->contours[contour] &&
2522 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
2524 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
2526 } else if(point <= outline->contours[contour] &&
2527 outline->tags[point] & FT_Curve_Tag_On) {
2528 /* add closing pt for bezier */
2530 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2538 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2541 pph->cb = needed - pph_start;
2547 /* Convert the quadratic Beziers to cubic Beziers.
2548 The parametric eqn for a cubic Bezier is, from PLRM:
2549 r(t) = at^3 + bt^2 + ct + r0
2550 with the control points:
2555 A quadratic Beizer has the form:
2556 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
2558 So equating powers of t leads to:
2559 r1 = 2/3 p1 + 1/3 p0
2560 r2 = 2/3 p1 + 1/3 p2
2561 and of course r0 = p0, r3 = p2
2564 int contour, point = 0, first_pt;
2565 FT_Outline *outline = &ft_face->glyph->outline;
2566 TTPOLYGONHEADER *pph;
2568 DWORD pph_start, cpfx, type;
2569 FT_Vector cubic_control[4];
2570 if(buflen == 0) buf = NULL;
2572 if (needsTransform && buf) {
2573 pFT_Outline_Transform(outline, &transMat);
2576 for(contour = 0; contour < outline->n_contours; contour++) {
2578 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
2581 pph->dwType = TT_POLYGON_TYPE;
2582 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2584 needed += sizeof(*pph);
2586 while(point <= outline->contours[contour]) {
2587 ppc = (TTPOLYCURVE *)((char *)buf + needed);
2588 type = (outline->tags[point] & FT_Curve_Tag_On) ?
2589 TT_PRIM_LINE : TT_PRIM_CSPLINE;
2592 if(type == TT_PRIM_LINE) {
2594 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2598 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
2601 /* FIXME: Possible optimization in endpoint calculation
2602 if there are two consecutive curves */
2603 cubic_control[0] = outline->points[point-1];
2604 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
2605 cubic_control[0].x += outline->points[point].x + 1;
2606 cubic_control[0].y += outline->points[point].y + 1;
2607 cubic_control[0].x >>= 1;
2608 cubic_control[0].y >>= 1;
2610 if(point+1 > outline->contours[contour])
2611 cubic_control[3] = outline->points[first_pt];
2613 cubic_control[3] = outline->points[point+1];
2614 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
2615 cubic_control[3].x += outline->points[point].x + 1;
2616 cubic_control[3].y += outline->points[point].y + 1;
2617 cubic_control[3].x >>= 1;
2618 cubic_control[3].y >>= 1;
2621 /* r1 = 1/3 p0 + 2/3 p1
2622 r2 = 1/3 p2 + 2/3 p1 */
2623 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
2624 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
2625 cubic_control[2] = cubic_control[1];
2626 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
2627 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
2628 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
2629 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
2631 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
2632 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
2633 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
2638 } while(point <= outline->contours[contour] &&
2639 (outline->tags[point] & FT_Curve_Tag_On) ==
2640 (outline->tags[point-1] & FT_Curve_Tag_On));
2641 /* At the end of a contour Windows adds the start point,
2642 but only for Beziers and we've already done that.
2644 if(point <= outline->contours[contour] &&
2645 outline->tags[point] & FT_Curve_Tag_On) {
2646 /* This is the closing pt of a bezier, but we've already
2647 added it, so just inc point and carry on */
2654 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2657 pph->cb = needed - pph_start;
2663 FIXME("Unsupported format %d\n", format);
2669 static BOOL get_bitmap_text_metrics(GdiFont font)
2671 FT_Face ft_face = font->ft_face;
2672 #ifdef HAVE_FREETYPE_FTWINFNT_H
2673 FT_WinFNT_HeaderRec winfnt_header;
2675 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
2676 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
2677 font->potm->otmSize = size;
2679 #define TM font->potm->otmTextMetrics
2680 #ifdef HAVE_FREETYPE_FTWINFNT_H
2681 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
2683 TM.tmHeight = winfnt_header.pixel_height;
2684 TM.tmAscent = winfnt_header.ascent;
2685 TM.tmDescent = TM.tmHeight - TM.tmAscent;
2686 TM.tmInternalLeading = winfnt_header.internal_leading;
2687 TM.tmExternalLeading = winfnt_header.external_leading;
2688 TM.tmAveCharWidth = winfnt_header.avg_width;
2689 TM.tmMaxCharWidth = winfnt_header.max_width;
2690 TM.tmWeight = winfnt_header.weight;
2692 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
2693 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
2694 TM.tmFirstChar = winfnt_header.first_char;
2695 TM.tmLastChar = winfnt_header.last_char;
2696 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
2697 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
2698 TM.tmItalic = winfnt_header.italic;
2699 TM.tmUnderlined = font->underline;
2700 TM.tmStruckOut = font->strikeout;
2701 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
2702 TM.tmCharSet = winfnt_header.charset;
2707 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
2708 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
2709 TM.tmHeight = TM.tmAscent + TM.tmDescent;
2710 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
2711 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
2712 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
2713 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
2714 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
2716 TM.tmDigitizedAspectX = 96; /* FIXME */
2717 TM.tmDigitizedAspectY = 96; /* FIXME */
2719 TM.tmLastChar = 255;
2720 TM.tmDefaultChar = 32;
2721 TM.tmBreakChar = 32;
2722 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
2723 TM.tmUnderlined = font->underline;
2724 TM.tmStruckOut = font->strikeout;
2725 /* NB inverted meaning of TMPF_FIXED_PITCH */
2726 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
2727 TM.tmCharSet = font->charset;
2734 /*************************************************************
2735 * WineEngGetTextMetrics
2738 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
2741 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
2742 if(!get_bitmap_text_metrics(font))
2745 if(!font->potm) return FALSE;
2746 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
2748 if (font->aveWidth) {
2749 ptm->tmAveCharWidth = font->aveWidth * font->font_desc.matrix.eM11;
2755 /*************************************************************
2756 * WineEngGetOutlineTextMetrics
2759 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
2760 OUTLINETEXTMETRICW *potm)
2762 FT_Face ft_face = font->ft_face;
2763 UINT needed, lenfam, lensty, ret;
2765 TT_HoriHeader *pHori;
2766 TT_Postscript *pPost;
2767 FT_Fixed x_scale, y_scale;
2768 WCHAR *family_nameW, *style_nameW;
2769 static const WCHAR spaceW[] = {' ', '\0'};
2771 INT ascent, descent;
2773 TRACE("font=%p\n", font);
2775 if(!FT_IS_SCALABLE(ft_face))
2779 if(cbSize >= font->potm->otmSize)
2780 memcpy(potm, font->potm, font->potm->otmSize);
2781 return font->potm->otmSize;
2785 needed = sizeof(*potm);
2787 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
2788 family_nameW = strdupW(font->name);
2790 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
2792 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
2793 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
2794 style_nameW, lensty);
2796 /* These names should be read from the TT name table */
2798 /* length of otmpFamilyName */
2801 /* length of otmpFaceName */
2802 if(!strcasecmp(ft_face->style_name, "regular")) {
2803 needed += lenfam; /* just the family name */
2805 needed += lenfam + lensty; /* family + " " + style */
2808 /* length of otmpStyleName */
2811 /* length of otmpFullName */
2812 needed += lenfam + lensty;
2815 x_scale = ft_face->size->metrics.x_scale;
2816 y_scale = ft_face->size->metrics.y_scale;
2818 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2820 FIXME("Can't find OS/2 table - not TT font?\n");
2825 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2827 FIXME("Can't find HHEA table - not TT font?\n");
2832 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
2834 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",
2835 pOS2->usWinAscent, pOS2->usWinDescent,
2836 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
2837 ft_face->ascender, ft_face->descender, ft_face->height,
2838 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
2839 ft_face->bbox.yMax, ft_face->bbox.yMin);
2841 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
2842 font->potm->otmSize = needed;
2844 #define TM font->potm->otmTextMetrics
2846 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
2847 ascent = pHori->Ascender;
2848 descent = -pHori->Descender;
2850 ascent = pOS2->usWinAscent;
2851 descent = pOS2->usWinDescent;
2855 TM.tmAscent = font->yMax;
2856 TM.tmDescent = -font->yMin;
2857 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
2859 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
2860 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
2861 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
2862 - ft_face->units_per_EM, y_scale) + 32) >> 6;
2865 TM.tmHeight = TM.tmAscent + TM.tmDescent;
2868 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
2870 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
2871 ((ascent + descent) -
2872 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
2874 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
2875 if (TM.tmAveCharWidth == 0) {
2876 TM.tmAveCharWidth = 1;
2878 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
2879 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
2881 TM.tmDigitizedAspectX = 300;
2882 TM.tmDigitizedAspectY = 300;
2883 TM.tmFirstChar = pOS2->usFirstCharIndex;
2884 TM.tmLastChar = pOS2->usLastCharIndex;
2885 TM.tmDefaultChar = pOS2->usDefaultChar;
2886 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
2887 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
2888 TM.tmUnderlined = font->underline;
2889 TM.tmStruckOut = font->strikeout;
2891 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
2892 if(!FT_IS_FIXED_WIDTH(ft_face))
2893 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
2895 TM.tmPitchAndFamily = 0;
2897 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
2898 case PAN_FAMILY_SCRIPT:
2899 TM.tmPitchAndFamily |= FF_SCRIPT;
2901 case PAN_FAMILY_DECORATIVE:
2902 case PAN_FAMILY_PICTORIAL:
2903 TM.tmPitchAndFamily |= FF_DECORATIVE;
2905 case PAN_FAMILY_TEXT_DISPLAY:
2906 if(TM.tmPitchAndFamily == 0) /* fixed */
2907 TM.tmPitchAndFamily = FF_MODERN;
2909 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
2910 case PAN_SERIF_NORMAL_SANS:
2911 case PAN_SERIF_OBTUSE_SANS:
2912 case PAN_SERIF_PERP_SANS:
2913 TM.tmPitchAndFamily |= FF_SWISS;
2916 TM.tmPitchAndFamily |= FF_ROMAN;
2921 TM.tmPitchAndFamily |= FF_DONTCARE;
2924 if(FT_IS_SCALABLE(ft_face))
2925 TM.tmPitchAndFamily |= TMPF_VECTOR;
2926 if(FT_IS_SFNT(ft_face))
2927 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
2929 TM.tmCharSet = font->charset;
2932 font->potm->otmFiller = 0;
2933 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
2934 font->potm->otmfsSelection = pOS2->fsSelection;
2935 font->potm->otmfsType = pOS2->fsType;
2936 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
2937 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
2938 font->potm->otmItalicAngle = 0; /* POST table */
2939 font->potm->otmEMSquare = ft_face->units_per_EM;
2940 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
2941 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
2942 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
2943 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
2944 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
2945 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
2946 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
2947 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
2948 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
2949 font->potm->otmMacAscent = 0; /* where do these come from ? */
2950 font->potm->otmMacDescent = 0;
2951 font->potm->otmMacLineGap = 0;
2952 font->potm->otmusMinimumPPEM = 0; /* TT Header */
2953 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
2954 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
2955 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
2956 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
2957 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
2958 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
2959 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
2960 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
2961 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
2962 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
2964 font->potm->otmsUnderscoreSize = 0;
2965 font->potm->otmsUnderscorePosition = 0;
2967 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
2968 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
2971 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
2972 cp = (char*)font->potm + sizeof(*font->potm);
2973 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
2974 strcpyW((WCHAR*)cp, family_nameW);
2976 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
2977 strcpyW((WCHAR*)cp, style_nameW);
2979 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
2980 strcpyW((WCHAR*)cp, family_nameW);
2981 if(strcasecmp(ft_face->style_name, "regular")) {
2982 strcatW((WCHAR*)cp, spaceW);
2983 strcatW((WCHAR*)cp, style_nameW);
2984 cp += lenfam + lensty;
2987 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
2988 strcpyW((WCHAR*)cp, family_nameW);
2989 strcatW((WCHAR*)cp, spaceW);
2990 strcatW((WCHAR*)cp, style_nameW);
2993 if(potm && needed <= cbSize)
2994 memcpy(potm, font->potm, font->potm->otmSize);
2997 HeapFree(GetProcessHeap(), 0, style_nameW);
2998 HeapFree(GetProcessHeap(), 0, family_nameW);
3004 /*************************************************************
3005 * WineEngGetCharWidth
3008 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
3013 FT_UInt glyph_index;
3015 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
3017 for(c = firstChar; c <= lastChar; c++) {
3018 glyph_index = get_glyph_index(font, c);
3019 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3020 &gm, 0, NULL, NULL);
3021 buffer[c - firstChar] = font->gm[glyph_index].adv;
3026 /*************************************************************
3027 * WineEngGetCharABCWidths
3030 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
3035 FT_UInt glyph_index;
3037 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
3039 if(!FT_IS_SCALABLE(font->ft_face))
3042 for(c = firstChar; c <= lastChar; c++) {
3043 glyph_index = get_glyph_index(font, c);
3044 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3045 &gm, 0, NULL, NULL);
3046 buffer[c - firstChar].abcA = font->gm[glyph_index].lsb;
3047 buffer[c - firstChar].abcB = font->gm[glyph_index].bbx;
3048 buffer[c - firstChar].abcC = font->gm[glyph_index].adv - font->gm[glyph_index].lsb -
3049 font->gm[glyph_index].bbx;
3054 /*************************************************************
3055 * WineEngGetTextExtentPoint
3058 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
3064 FT_UInt glyph_index;
3066 TRACE("%p, %s, %d, %p\n", font, debugstr_wn(wstr, count), count,
3070 WineEngGetTextMetrics(font, &tm);
3071 size->cy = tm.tmHeight;
3073 for(idx = 0; idx < count; idx++) {
3074 glyph_index = get_glyph_index(font, wstr[idx]);
3075 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3076 &gm, 0, NULL, NULL);
3077 size->cx += font->gm[glyph_index].adv;
3079 TRACE("return %ld,%ld\n", size->cx, size->cy);
3083 /*************************************************************
3084 * WineEngGetTextExtentPointI
3087 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
3094 TRACE("%p, %p, %d, %p\n", font, indices, count, size);
3097 WineEngGetTextMetrics(font, &tm);
3098 size->cy = tm.tmHeight;
3100 for(idx = 0; idx < count; idx++) {
3101 WineEngGetGlyphOutline(font, indices[idx],
3102 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
3104 size->cx += font->gm[indices[idx]].adv;
3106 TRACE("return %ld,%ld\n", size->cx, size->cy);
3110 /*************************************************************
3111 * WineEngGetFontData
3114 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
3117 FT_Face ft_face = font->ft_face;
3121 TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
3122 font, table, offset, buf, cbData);
3124 if(!FT_IS_SFNT(ft_face))
3132 if(table) { /* MS tags differ in endidness from FT ones */
3133 table = table >> 24 | table << 24 |
3134 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
3137 /* If the FT_Load_Sfnt_Table function is there we'll use it */
3138 if(pFT_Load_Sfnt_Table)
3139 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
3140 else { /* Do it the hard way */
3141 TT_Face tt_face = (TT_Face) ft_face;
3142 SFNT_Interface *sfnt;
3143 if (FT_Version.major==2 && FT_Version.minor==0)
3146 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
3150 /* A field was added in the middle of the structure in 2.1.x */
3151 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
3153 err = sfnt->load_any(tt_face, table, offset, buf, &len);
3156 TRACE("Can't find table %08lx.\n", table);
3162 /*************************************************************
3163 * WineEngGetTextFace
3166 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
3169 lstrcpynW(str, font->name, count);
3170 return strlenW(font->name);
3172 return strlenW(font->name) + 1;
3175 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
3177 if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
3178 return font->charset;
3181 #else /* HAVE_FREETYPE */
3183 BOOL WineEngInit(void)
3187 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
3191 BOOL WineEngDestroyFontInstance(HFONT hfont)
3196 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3201 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
3202 LPWORD pgi, DWORD flags)
3207 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
3208 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
3211 ERR("called but we don't have FreeType\n");
3215 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
3217 ERR("called but we don't have FreeType\n");
3221 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
3222 OUTLINETEXTMETRICW *potm)
3224 ERR("called but we don't have FreeType\n");
3228 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
3231 ERR("called but we don't have FreeType\n");
3235 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
3238 ERR("called but we don't have FreeType\n");
3242 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
3245 ERR("called but we don't have FreeType\n");
3249 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
3252 ERR("called but we don't have FreeType\n");
3256 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
3259 ERR("called but we don't have FreeType\n");
3263 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
3265 ERR("called but we don't have FreeType\n");
3269 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3275 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3281 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
3284 return DEFAULT_CHARSET;
3287 #endif /* HAVE_FREETYPE */