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 {
220 struct list hfontlist;
225 OUTLINETEXTMETRICW *potm;
229 #define INIT_GM_SIZE 128
231 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
232 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
233 #define UNUSED_CACHE_SIZE 10
235 static struct list font_list = LIST_INIT(font_list);
237 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ',
238 'R','o','m','a','n','\0'};
239 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
240 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
242 static const WCHAR defSystem[] = {'A','r','i','a','l','\0'};
243 static const WCHAR SystemW[] = {'S','y','s','t','e','m','\0'};
244 static const WCHAR MSSansSerifW[] = {'M','S',' ','S','a','n','s',' ',
245 'S','e','r','i','f','\0'};
246 static const WCHAR HelvW[] = {'H','e','l','v','\0'};
247 static const WCHAR RegularW[] = {'R','e','g','u','l','a','r','\0'};
249 static const WCHAR fontsW[] = {'\\','F','o','n','t','s','\0'};
250 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
251 'W','i','n','d','o','w','s','\\',
252 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
253 'F','o','n','t','s','\0'};
255 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
256 'W','i','n','d','o','w','s',' ','N','T','\\',
257 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
258 'F','o','n','t','s','\0'};
260 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
261 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
262 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
263 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
265 static const WCHAR *SystemFontValues[4] = {
272 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\','W','i','n','e','\\',
273 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
275 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
276 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
277 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
278 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
279 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
280 'E','u','r','o','p','e','a','n','\0'};
281 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
282 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
283 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
284 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
285 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
286 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
287 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
288 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
289 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
290 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
291 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
292 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
294 static const WCHAR *ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
304 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
312 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
321 typedef struct tagFontSubst {
324 struct tagFontSubst *next;
327 static FontSubst *substlist = NULL;
328 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
330 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
333 /****************************************
334 * Notes on .fon files
336 * The fonts System, FixedSys and Terminal are special. There are typically multiple
337 * versions installed for different resolutions and codepages. Windows stores which one to use
338 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
340 * FIXEDFON.FON FixedSys
342 * OEMFONT.FON Termial
343 * LogPixels Current dpi set by the display control panel applet
344 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
345 * also has a LogPixels value that appears to mirror this)
347 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
348 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
349 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
350 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
351 * so that makes sense.
353 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
354 * to be mapped into the registry on Windows 2000 at least).
357 * ega80woa.fon=ega80850.fon
358 * ega40woa.fon=ega40850.fon
359 * cga80woa.fon=cga80850.fon
360 * cga40woa.fon=cga40850.fon
364 static inline BOOL is_win9x(void)
366 return GetVersion() & 0x80000000;
369 This function builds an FT_Fixed from a float. It puts the integer part
370 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
371 It fails if the integer part of the float number is greater than SHORT_MAX.
373 static inline FT_Fixed FT_FixedFromFloat(float f)
376 unsigned short fract = (f - value) * 0xFFFF;
377 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
381 This function builds an FT_Fixed from a FIXED. It simply put f.value
382 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
384 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
386 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
389 #define ADDFONT_EXTERNAL_FONT 0x01
390 #define ADDFONT_FORCE_BITMAP 0x02
391 static BOOL AddFontFileToList(const char *file, char *fake_family, DWORD flags)
395 TT_Header *pHeader = NULL;
396 WCHAR *FamilyW, *StyleW;
400 struct list *family_elem_ptr, *face_elem_ptr;
402 FT_Long face_index = 0, num_faces;
403 #ifdef HAVE_FREETYPE_FTWINFNT_H
404 FT_WinFNT_HeaderRec winfnt_header;
409 char *family_name = fake_family;
411 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
412 if((err = pFT_New_Face(library, file, face_index, &ft_face)) != 0) {
413 WARN("Unable to load font file %s err = %x\n", debugstr_a(file), err);
417 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*/
418 pFT_Done_Face(ft_face);
422 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
423 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
424 pFT_Done_Face(ft_face);
428 if(FT_IS_SFNT(ft_face) && (!pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2) ||
429 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
430 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))) {
431 TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
432 "Skipping this font.\n", debugstr_a(file));
433 pFT_Done_Face(ft_face);
437 if(!ft_face->family_name || !ft_face->style_name) {
438 TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file));
439 pFT_Done_Face(ft_face);
444 family_name = ft_face->family_name;
448 My_FT_Bitmap_Size *size = NULL;
450 if(!FT_IS_SCALABLE(ft_face))
451 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
453 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
454 FamilyW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
455 MultiByteToWideChar(CP_ACP, 0, family_name, -1, FamilyW, len);
458 LIST_FOR_EACH(family_elem_ptr, &font_list) {
459 family = LIST_ENTRY(family_elem_ptr, Family, entry);
460 if(!strcmpW(family->FamilyName, FamilyW))
465 family = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
466 family->FamilyName = FamilyW;
467 list_init(&family->faces);
468 list_add_tail(&font_list, &family->entry);
470 HeapFree(GetProcessHeap(), 0, FamilyW);
473 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
474 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
475 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
477 face_elem_ptr = list_head(&family->faces);
478 while(face_elem_ptr) {
479 face = LIST_ENTRY(face_elem_ptr, Face, entry);
480 face_elem_ptr = list_next(&family->faces, face_elem_ptr);
481 if(!strcmpW(face->StyleName, StyleW) &&
482 (FT_IS_SCALABLE(ft_face) || (size->y_ppem == face->size.y_ppem))) {
483 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
484 debugstr_w(family->FamilyName), debugstr_w(StyleW),
485 face->font_version, pHeader ? pHeader->Font_Revision : 0);
488 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
489 HeapFree(GetProcessHeap(), 0, StyleW);
490 pFT_Done_Face(ft_face);
493 if(!pHeader || pHeader->Font_Revision <= face->font_version) {
494 TRACE("Original font is newer so skipping this one\n");
495 HeapFree(GetProcessHeap(), 0, StyleW);
496 pFT_Done_Face(ft_face);
499 TRACE("Replacing original with this one\n");
500 list_remove(&face->entry);
501 HeapFree(GetProcessHeap(), 0, face->file);
502 HeapFree(GetProcessHeap(), 0, face->StyleName);
503 HeapFree(GetProcessHeap(), 0, face);
508 face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face));
509 list_add_tail(&family->faces, &face->entry);
510 face->StyleName = StyleW;
511 face->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
512 strcpy(face->file, file);
513 face->face_index = face_index;
514 face->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
515 face->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
516 face->font_version = pHeader ? pHeader->Font_Revision : 0;
517 face->family = family;
518 face->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
520 if(FT_IS_SCALABLE(ft_face)) {
521 memset(&face->size, 0, sizeof(face->size));
522 face->scalable = TRUE;
524 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
525 size->height, size->width, size->size >> 6,
526 size->x_ppem >> 6, size->y_ppem >> 6);
527 face->size.height = size->height;
528 face->size.width = size->width;
529 face->size.size = size->size;
530 face->size.x_ppem = size->x_ppem;
531 face->size.y_ppem = size->y_ppem;
532 face->size.internal_leading = 0;
533 face->scalable = FALSE;
536 memset(&face->fs, 0, sizeof(face->fs));
538 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
540 face->fs.fsCsb[0] = pOS2->ulCodePageRange1;
541 face->fs.fsCsb[1] = pOS2->ulCodePageRange2;
542 face->fs.fsUsb[0] = pOS2->ulUnicodeRange1;
543 face->fs.fsUsb[1] = pOS2->ulUnicodeRange2;
544 face->fs.fsUsb[2] = pOS2->ulUnicodeRange3;
545 face->fs.fsUsb[3] = pOS2->ulUnicodeRange4;
546 if(pOS2->version == 0) {
549 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
550 face->fs.fsCsb[0] |= 1;
552 face->fs.fsCsb[0] |= 1L << 31;
555 #ifdef HAVE_FREETYPE_FTWINFNT_H
556 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
558 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
559 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
560 if(TranslateCharsetInfo((DWORD*)(UINT)winfnt_header.charset, &csi, TCI_SRCCHARSET))
561 memcpy(&face->fs, &csi.fs, sizeof(csi.fs));
562 face->size.internal_leading = winfnt_header.internal_leading;
565 TRACE("fsCsb = %08lx %08lx/%08lx %08lx %08lx %08lx\n",
566 face->fs.fsCsb[0], face->fs.fsCsb[1],
567 face->fs.fsUsb[0], face->fs.fsUsb[1],
568 face->fs.fsUsb[2], face->fs.fsUsb[3]);
571 if(face->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
572 for(i = 0; i < ft_face->num_charmaps; i++) {
573 switch(ft_face->charmaps[i]->encoding) {
574 case ft_encoding_unicode:
575 case ft_encoding_apple_roman:
576 face->fs.fsCsb[0] |= 1;
578 case ft_encoding_symbol:
579 face->fs.fsCsb[0] |= 1L << 31;
587 if(face->fs.fsCsb[0] & ~(1L << 31))
588 have_installed_roman_font = TRUE;
589 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
591 num_faces = ft_face->num_faces;
592 pFT_Done_Face(ft_face);
593 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
595 } while(num_faces > ++face_index);
599 static void DumpFontList(void)
603 struct list *family_elem_ptr, *face_elem_ptr;
605 LIST_FOR_EACH(family_elem_ptr, &font_list) {
606 family = LIST_ENTRY(family_elem_ptr, Family, entry);
607 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
608 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
609 face = LIST_ENTRY(face_elem_ptr, Face, entry);
610 TRACE("\t%s", debugstr_w(face->StyleName));
612 TRACE(" %ld", face->size.y_ppem >> 6);
619 static void DumpSubstList(void)
623 for(psub = substlist; psub; psub = psub->next)
624 if(psub->from.charset != -1 || psub->to.charset != -1)
625 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
626 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
628 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
629 debugstr_w(psub->to.name));
633 static LPWSTR strdupW(LPWSTR p)
636 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
637 ret = HeapAlloc(GetProcessHeap(), 0, len);
642 static void split_subst_info(NameCs *nc, LPSTR str)
644 CHAR *p = strrchr(str, ',');
649 nc->charset = strtol(p+1, NULL, 10);
652 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
653 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
654 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
657 static void LoadSubstList(void)
659 FontSubst *psub, **ppsub;
661 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
666 for(psub = substlist; psub;) {
668 HeapFree(GetProcessHeap(), 0, psub->to.name);
669 HeapFree(GetProcessHeap(), 0, psub->from.name);
672 HeapFree(GetProcessHeap(), 0, ptmp);
677 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
678 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
679 &hkey) == ERROR_SUCCESS) {
681 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
682 &valuelen, &datalen, NULL, NULL);
684 valuelen++; /* returned value doesn't include room for '\0' */
685 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
686 data = HeapAlloc(GetProcessHeap(), 0, datalen);
691 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
692 &dlen) == ERROR_SUCCESS) {
693 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
695 *ppsub = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppsub));
696 (*ppsub)->next = NULL;
697 split_subst_info(&((*ppsub)->from), value);
698 split_subst_info(&((*ppsub)->to), data);
700 /* Win 2000 doesn't allow mapping between different charsets
701 or mapping of DEFAULT_CHARSET */
702 if(((*ppsub)->to.charset != (*ppsub)->from.charset) ||
703 (*ppsub)->to.charset == DEFAULT_CHARSET) {
704 HeapFree(GetProcessHeap(), 0, (*ppsub)->to.name);
705 HeapFree(GetProcessHeap(), 0, (*ppsub)->from.name);
706 HeapFree(GetProcessHeap(), 0, *ppsub);
709 ppsub = &((*ppsub)->next);
711 /* reset dlen and vlen */
715 HeapFree(GetProcessHeap(), 0, data);
716 HeapFree(GetProcessHeap(), 0, value);
721 /***********************************************************
722 * The replacement list is a way to map an entire font
723 * family onto another family. For example adding
725 * [HKLM\Software\Wine\Wine\FontReplacements]
726 * "Wingdings"="Winedings"
728 * would enumerate the Winedings font both as Winedings and
729 * Wingdings. However if a real Wingdings font is present the
730 * replacement does not take place.
733 static void LoadReplaceList(void)
736 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
741 struct list *family_elem_ptr, *face_elem_ptr;
742 WCHAR old_nameW[200];
744 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
745 "Software\\Wine\\Wine\\FontReplacements",
746 &hkey) == ERROR_SUCCESS) {
748 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
749 &valuelen, &datalen, NULL, NULL);
751 valuelen++; /* returned value doesn't include room for '\0' */
752 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
753 data = HeapAlloc(GetProcessHeap(), 0, datalen);
757 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
758 &dlen) == ERROR_SUCCESS) {
759 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
760 /* "NewName"="Oldname" */
761 if(!MultiByteToWideChar(CP_ACP, 0, data, -1, old_nameW, sizeof(old_nameW)))
764 /* Find the old family and hence all of the font files
766 LIST_FOR_EACH(family_elem_ptr, &font_list) {
767 family = LIST_ENTRY(family_elem_ptr, Family, entry);
768 if(!strcmpiW(family->FamilyName, old_nameW)) {
769 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
770 face = LIST_ENTRY(face_elem_ptr, Face, entry);
771 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
772 debugstr_w(face->StyleName), value);
773 /* Now add a new entry with the new family name */
774 AddFontFileToList(face->file, value, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
779 /* reset dlen and vlen */
783 HeapFree(GetProcessHeap(), 0, data);
784 HeapFree(GetProcessHeap(), 0, value);
790 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
796 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
798 dir = opendir(dirname);
800 ERR("Can't open directory %s\n", debugstr_a(dirname));
803 while((dent = readdir(dir)) != NULL) {
806 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
809 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
811 sprintf(path, "%s/%s", dirname, dent->d_name);
813 if(stat(path, &statbuf) == -1)
815 WARN("Can't stat %s\n", debugstr_a(path));
818 if(S_ISDIR(statbuf.st_mode))
819 ReadFontDir(path, external_fonts);
821 AddFontFileToList(path, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
827 static void load_fontconfig_fonts(void)
829 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
830 void *fc_handle = NULL;
839 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
841 TRACE("Wine cannot find the fontconfig library (%s).\n",
842 SONAME_LIBFONTCONFIG);
845 #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;}
846 LOAD_FUNCPTR(FcConfigGetCurrent);
847 LOAD_FUNCPTR(FcFontList);
848 LOAD_FUNCPTR(FcFontSetDestroy);
849 LOAD_FUNCPTR(FcInit);
850 LOAD_FUNCPTR(FcObjectSetAdd);
851 LOAD_FUNCPTR(FcObjectSetCreate);
852 LOAD_FUNCPTR(FcObjectSetDestroy);
853 LOAD_FUNCPTR(FcPatternCreate);
854 LOAD_FUNCPTR(FcPatternDestroy);
855 LOAD_FUNCPTR(FcPatternGet);
858 if(!pFcInit()) return;
860 config = pFcConfigGetCurrent();
861 pat = pFcPatternCreate();
862 os = pFcObjectSetCreate();
863 pFcObjectSetAdd(os, FC_FILE);
864 fontset = pFcFontList(config, pat, os);
866 for(i = 0; i < fontset->nfont; i++) {
867 if(pFcPatternGet(fontset->fonts[i], FC_FILE, 0, &v) != FcResultMatch)
869 if(v.type != FcTypeString) continue;
870 TRACE("fontconfig: %s\n", v.u.s);
872 /* We're just interested in OT/TT fonts for now, so this hack just
873 picks up the standard extensions to save time loading every other
876 if(len < 4) continue;
877 ext = v.u.s + len - 3;
878 if(!strcasecmp(ext, "ttf") || !strcasecmp(ext, "ttc") || !strcasecmp(ext, "otf"))
879 AddFontFileToList(v.u.s, NULL, ADDFONT_EXTERNAL_FONT);
881 pFcFontSetDestroy(fontset);
882 pFcObjectSetDestroy(os);
883 pFcPatternDestroy(pat);
890 void load_system_fonts(void)
893 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
896 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
899 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
900 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
901 strcatW(windowsdir, fontsW);
902 for(value = SystemFontValues; *value; value++) {
904 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
906 sprintfW(pathW, fmtW, windowsdir, data);
907 if((unixname = wine_get_unix_file_name(pathW))) {
908 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
909 HeapFree(GetProcessHeap(), 0, unixname);
917 /*************************************************************
919 * This adds registry entries for any externally loaded fonts
920 * (fonts from fontconfig or FontDirs). It also deletes entries
921 * of no longer existing fonts.
924 void update_reg_entries(void)
926 HKEY winkey = 0, externalkey = 0;
929 DWORD dlen, vlen, datalen, valuelen, i, type, len, len_fam;
932 struct list *family_elem_ptr, *face_elem_ptr;
934 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
935 static const WCHAR spaceW[] = {' ', '\0'};
938 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
939 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winkey, NULL) != ERROR_SUCCESS) {
940 ERR("Can't create Windows font reg key\n");
943 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, external_fonts_reg_key,
944 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
945 ERR("Can't create external font reg key\n");
949 /* Delete all external fonts added last time */
951 RegQueryInfoKeyW(externalkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
952 &valuelen, &datalen, NULL, NULL);
953 valuelen++; /* returned value doesn't include room for '\0' */
954 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
955 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
957 dlen = datalen * sizeof(WCHAR);
960 while(RegEnumValueW(externalkey, i++, valueW, &vlen, NULL, &type, data,
961 &dlen) == ERROR_SUCCESS) {
963 RegDeleteValueW(winkey, valueW);
964 /* reset dlen and vlen */
968 HeapFree(GetProcessHeap(), 0, data);
969 HeapFree(GetProcessHeap(), 0, valueW);
971 /* Delete the old external fonts key */
972 RegCloseKey(externalkey);
974 RegDeleteKeyW(HKEY_LOCAL_MACHINE, external_fonts_reg_key);
976 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, external_fonts_reg_key,
977 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
978 ERR("Can't create external font reg key\n");
982 /* enumerate the fonts and add external ones to the two keys */
984 LIST_FOR_EACH(family_elem_ptr, &font_list) {
985 family = LIST_ENTRY(family_elem_ptr, Family, entry);
986 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
987 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
988 face = LIST_ENTRY(face_elem_ptr, Face, entry);
989 if(!face->external) continue;
991 if(strcmpiW(face->StyleName, RegularW))
992 len = len_fam + strlenW(face->StyleName) + 1;
993 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
994 strcpyW(valueW, family->FamilyName);
996 strcatW(valueW, spaceW);
997 strcatW(valueW, face->StyleName);
999 strcatW(valueW, TrueType);
1000 if((path = strrchr(face->file, '/')) == NULL)
1004 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
1006 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1007 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
1008 RegSetValueExW(winkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1009 RegSetValueExW(externalkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
1011 HeapFree(GetProcessHeap(), 0, file);
1012 HeapFree(GetProcessHeap(), 0, valueW);
1017 RegCloseKey(externalkey);
1019 RegCloseKey(winkey);
1024 /*************************************************************
1025 * WineEngAddFontResourceEx
1028 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1030 if (ft_handle) /* do it only if we have freetype up and running */
1035 FIXME("Ignoring flags %lx\n", flags);
1037 if((unixname = wine_get_unix_file_name(file)))
1039 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1040 HeapFree(GetProcessHeap(), 0, unixname);
1046 /*************************************************************
1047 * WineEngRemoveFontResourceEx
1050 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1056 /*************************************************************
1059 * Initialize FreeType library and create a list of available faces
1061 BOOL WineEngInit(void)
1063 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
1065 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1067 WCHAR windowsdir[MAX_PATH];
1073 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
1076 "Wine cannot find the FreeType font library. To enable Wine to\n"
1077 "use TrueType fonts please install a version of FreeType greater than\n"
1078 "or equal to 2.0.5.\n"
1079 "http://www.freetype.org\n");
1083 #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;}
1085 LOAD_FUNCPTR(FT_Vector_Unit)
1086 LOAD_FUNCPTR(FT_Done_Face)
1087 LOAD_FUNCPTR(FT_Get_Char_Index)
1088 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
1089 LOAD_FUNCPTR(FT_Init_FreeType)
1090 LOAD_FUNCPTR(FT_Load_Glyph)
1091 LOAD_FUNCPTR(FT_Matrix_Multiply)
1092 LOAD_FUNCPTR(FT_MulFix)
1093 LOAD_FUNCPTR(FT_New_Face)
1094 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
1095 LOAD_FUNCPTR(FT_Outline_Transform)
1096 LOAD_FUNCPTR(FT_Outline_Translate)
1097 LOAD_FUNCPTR(FT_Select_Charmap)
1098 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
1099 LOAD_FUNCPTR(FT_Vector_Transform)
1102 /* Don't warn if this one is missing */
1103 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
1104 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
1105 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
1106 #ifdef HAVE_FREETYPE_FTWINFNT_H
1107 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
1109 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
1110 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
1111 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
1112 <= 2.0.3 has FT_Sqrt64 */
1116 if(pFT_Init_FreeType(&library) != 0) {
1117 ERR("Can't init FreeType library\n");
1118 wine_dlclose(ft_handle, NULL, 0);
1122 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
1123 if (pFT_Library_Version)
1125 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
1127 if (FT_Version.major<=0)
1133 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
1134 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
1135 ((FT_Version.minor << 8) & 0x00ff00) |
1136 ((FT_Version.patch ) & 0x0000ff);
1138 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
1139 ERR("Failed to create font mutex\n");
1142 WaitForSingleObject(font_mutex, INFINITE);
1144 /* load the system fonts */
1145 load_system_fonts();
1147 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
1148 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1149 strcatW(windowsdir, fontsW);
1150 if((unixname = wine_get_unix_file_name(windowsdir)))
1152 ReadFontDir(unixname, FALSE);
1153 HeapFree(GetProcessHeap(), 0, unixname);
1156 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
1157 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
1158 full path as the entry. Also look for any .fon fonts, since ReadFontDir
1160 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
1161 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1162 &hkey) == ERROR_SUCCESS) {
1164 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1165 &valuelen, &datalen, NULL, NULL);
1167 valuelen++; /* returned value doesn't include room for '\0' */
1168 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1169 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1172 dlen = datalen * sizeof(WCHAR);
1174 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
1175 &dlen) == ERROR_SUCCESS) {
1176 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
1178 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
1180 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1181 HeapFree(GetProcessHeap(), 0, unixname);
1184 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
1186 WCHAR pathW[MAX_PATH];
1187 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1188 sprintfW(pathW, fmtW, windowsdir, data);
1189 if((unixname = wine_get_unix_file_name(pathW)))
1191 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1192 HeapFree(GetProcessHeap(), 0, unixname);
1195 /* reset dlen and vlen */
1200 if (data) HeapFree(GetProcessHeap(), 0, data);
1201 if (valueW) HeapFree(GetProcessHeap(), 0, valueW);
1205 load_fontconfig_fonts();
1207 /* then look in any directories that we've specified in the config file */
1208 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1209 "Software\\Wine\\Wine\\Config\\FontDirs",
1210 &hkey) == ERROR_SUCCESS) {
1212 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1213 &valuelen, &datalen, NULL, NULL);
1215 valuelen++; /* returned value doesn't include room for '\0' */
1216 value = HeapAlloc(GetProcessHeap(), 0, valuelen);
1217 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1222 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1223 &dlen) == ERROR_SUCCESS) {
1224 TRACE("Got %s=%s\n", value, (LPSTR)data);
1225 ReadFontDir((LPSTR)data, TRUE);
1226 /* reset dlen and vlen */
1230 HeapFree(GetProcessHeap(), 0, data);
1231 HeapFree(GetProcessHeap(), 0, value);
1239 update_reg_entries();
1241 ReleaseMutex(font_mutex);
1245 "Wine cannot find certain functions that it needs inside the FreeType\n"
1246 "font library. To enable Wine to use TrueType fonts please upgrade\n"
1247 "FreeType to at least version 2.0.5.\n"
1248 "http://www.freetype.org\n");
1249 wine_dlclose(ft_handle, NULL, 0);
1255 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
1258 TT_HoriHeader *pHori;
1262 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1263 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1265 if(height == 0) height = 16;
1267 /* Calc. height of EM square:
1269 * For +ve lfHeight we have
1270 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
1271 * Re-arranging gives:
1272 * ppem = units_per_em * lfheight / (winAscent + winDescent)
1274 * For -ve lfHeight we have
1276 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
1277 * with il = winAscent + winDescent - units_per_em]
1282 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
1283 ppem = ft_face->units_per_EM * height /
1284 (pHori->Ascender - pHori->Descender);
1286 ppem = ft_face->units_per_EM * height /
1287 (pOS2->usWinAscent + pOS2->usWinDescent);
1295 static LONG load_VDMX(GdiFont, LONG);
1297 static FT_Face OpenFontFile(GdiFont font, char *file, FT_Long face_index, LONG width, LONG height)
1303 err = pFT_New_Face(library, file, face_index, &ft_face);
1305 ERR("FT_New_Face rets %d\n", err);
1309 /* set it here, as load_VDMX needs it */
1310 font->ft_face = ft_face;
1312 if(FT_IS_SCALABLE(ft_face)) {
1313 /* load the VDMX table if we have one */
1314 ppem = load_VDMX(font, height);
1316 ppem = calc_ppem_for_height(ft_face, height);
1318 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, ppem)) != 0)
1319 WARN("FT_Set_Pixel_Sizes %d, %ld rets %x\n", 0, ppem, err);
1321 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
1322 WARN("FT_Set_Pixel_Sizes %ld, %ld rets %x\n", width, height, err);
1328 static int get_nearest_charset(Face *face)
1330 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
1331 a single face with the requested charset. The idea is to check if
1332 the selected font supports the current ANSI codepage, if it does
1333 return the corresponding charset, else return the first charset */
1336 int acp = GetACP(), i;
1339 if(TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE))
1340 if(csi.fs.fsCsb[0] & face->fs.fsCsb[0])
1341 return csi.ciCharset;
1343 for(i = 0; i < 32; i++) {
1345 if(face->fs.fsCsb[0] & fs0) {
1346 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG))
1347 return csi.ciCharset;
1349 FIXME("TCI failing on %lx\n", fs0);
1353 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08lx file = %s\n",
1354 face->fs.fsCsb[0], face->file);
1355 return DEFAULT_CHARSET;
1358 static GdiFont alloc_font(void)
1360 GdiFont ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
1361 ret->gmsize = INIT_GM_SIZE;
1362 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1363 ret->gmsize * sizeof(*ret->gm));
1365 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
1366 list_init(&ret->hfontlist);
1370 static void free_font(GdiFont font)
1372 if (font->ft_face) pFT_Done_Face(font->ft_face);
1373 if (font->potm) HeapFree(GetProcessHeap(), 0, font->potm);
1374 if (font->name) HeapFree(GetProcessHeap(), 0, font->name);
1375 HeapFree(GetProcessHeap(), 0, font->gm);
1376 HeapFree(GetProcessHeap(), 0, font);
1380 /*************************************************************
1383 * load the vdmx entry for the specified height
1386 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
1387 ( ( (FT_ULong)_x4 << 24 ) | \
1388 ( (FT_ULong)_x3 << 16 ) | \
1389 ( (FT_ULong)_x2 << 8 ) | \
1392 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
1402 static LONG load_VDMX(GdiFont font, LONG height)
1404 BYTE hdr[6], tmp[2], group[4];
1405 BYTE devXRatio, devYRatio;
1406 USHORT numRecs, numRatios;
1411 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
1413 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
1416 /* FIXME: need the real device aspect ratio */
1420 numRecs = GET_BE_WORD(&hdr[2]);
1421 numRatios = GET_BE_WORD(&hdr[4]);
1423 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
1424 for(i = 0; i < numRatios; i++) {
1427 offset = (3 * 2) + (i * sizeof(Ratios));
1428 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
1431 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
1433 if(ratio.bCharSet != 1)
1436 if((ratio.xRatio == 0 &&
1437 ratio.yStartRatio == 0 &&
1438 ratio.yEndRatio == 0) ||
1439 (devXRatio == ratio.xRatio &&
1440 devYRatio >= ratio.yStartRatio &&
1441 devYRatio <= ratio.yEndRatio))
1443 offset = (3 * 2) + (numRatios * 4) + (i * 2);
1444 WineEngGetFontData(font, MS_VDMX_TAG, offset, tmp, 2);
1445 offset = GET_BE_WORD(tmp);
1451 FIXME("No suitable ratio found\n");
1455 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, group, 4) != GDI_ERROR) {
1457 BYTE startsz, endsz;
1460 recs = GET_BE_WORD(group);
1464 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
1466 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
1467 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
1468 if(result == GDI_ERROR) {
1469 FIXME("Failed to retrieve vTable\n");
1474 for(i = 0; i < recs; i++) {
1475 SHORT yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1476 SHORT yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1477 ppem = GET_BE_WORD(&vTable[i * 6]);
1479 if(yMax + -yMin == height) {
1482 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1485 if(yMax + -yMin > height) {
1488 goto end; /* failed */
1490 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1491 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1492 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1498 TRACE("ppem not found for height %ld\n", height);
1502 if(ppem < startsz || ppem > endsz)
1505 for(i = 0; i < recs; i++) {
1507 yPelHeight = GET_BE_WORD(&vTable[i * 6]);
1509 if(yPelHeight > ppem)
1512 if(yPelHeight == ppem) {
1513 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1514 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1515 TRACE("ppem %ld found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
1521 HeapFree(GetProcessHeap(), 0, vTable);
1527 static BOOL fontcmp(GdiFont font, FONT_DESC *fd)
1529 if(font->font_desc.hash != fd->hash) return TRUE;
1530 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
1531 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
1532 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
1535 static void calc_hash(FONT_DESC *pfd)
1537 DWORD hash = 0, *ptr, two_chars;
1541 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
1543 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
1545 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
1547 pwc = (WCHAR *)&two_chars;
1549 *pwc = toupperW(*pwc);
1551 *pwc = toupperW(*pwc);
1559 static GdiFont find_in_cache(HFONT hfont, LOGFONTW *plf, XFORM *pxf, BOOL can_use_bitmap)
1564 struct list *font_elem_ptr, *hfontlist_elem_ptr;
1566 memcpy(&fd.lf, plf, sizeof(LOGFONTW));
1567 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
1570 /* try the in-use list */
1571 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
1572 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
1573 if(!fontcmp(ret, &fd)) {
1574 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
1575 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
1576 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
1577 if(hflist->hfont == hfont)
1580 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
1581 hflist->hfont = hfont;
1582 list_add_head(&ret->hfontlist, &hflist->entry);
1587 /* then the unused list */
1588 font_elem_ptr = list_head(&unused_gdi_font_list);
1589 while(font_elem_ptr) {
1590 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
1591 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
1592 if(!fontcmp(ret, &fd)) {
1593 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
1594 assert(list_empty(&ret->hfontlist));
1595 TRACE("Found %p in unused list\n", ret);
1596 list_remove(&ret->entry);
1597 list_add_head(&gdi_font_list, &ret->entry);
1598 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
1599 hflist->hfont = hfont;
1600 list_add_head(&ret->hfontlist, &hflist->entry);
1607 /*************************************************************
1608 * WineEngCreateFontInstance
1611 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
1616 struct list *family_elem_ptr, *face_elem_ptr;
1617 INT height, width = 0;
1618 signed int diff = 0, newdiff;
1619 BOOL bd, it, can_use_bitmap;
1624 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
1625 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
1627 TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
1628 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
1629 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
1632 /* check the cache first */
1633 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
1634 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
1638 TRACE("not in cache\n");
1639 if(list_empty(&font_list) || !have_installed_roman_font) /* No fonts installed */
1641 TRACE("No fonts installed\n");
1647 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
1648 memcpy(&ret->font_desc.lf, &lf, sizeof(LOGFONTW));
1649 calc_hash(&ret->font_desc);
1650 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
1651 hflist->hfont = hfont;
1652 list_add_head(&ret->hfontlist, &hflist->entry);
1655 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
1656 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
1657 original value lfCharSet. Note this is a special case for
1658 Symbol and doesn't happen at least for "Wingdings*" */
1660 if(!strcmpiW(lf.lfFaceName, SymbolW))
1661 lf.lfCharSet = SYMBOL_CHARSET;
1663 if(!TranslateCharsetInfo((DWORD*)(INT)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
1664 switch(lf.lfCharSet) {
1665 case DEFAULT_CHARSET:
1666 csi.fs.fsCsb[0] = 0;
1669 FIXME("Untranslated charset %d\n", lf.lfCharSet);
1670 csi.fs.fsCsb[0] = 0;
1676 if(lf.lfFaceName[0] != '\0') {
1678 for(psub = substlist; psub; psub = psub->next)
1679 if(!strcmpiW(lf.lfFaceName, psub->from.name) &&
1680 (psub->from.charset == -1 ||
1681 psub->from.charset == lf.lfCharSet))
1684 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
1685 debugstr_w(psub->to.name));
1686 strcpyW(lf.lfFaceName, psub->to.name);
1689 /* We want a match on name and charset or just name if
1690 charset was DEFAULT_CHARSET. If the latter then
1691 we fixup the returned charset later in get_nearest_charset
1692 where we'll either use the charset of the current ansi codepage
1693 or if that's unavailable the first charset that the font supports.
1695 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1696 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1697 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
1698 face_elem_ptr = list_head(&family->faces);
1699 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1700 if((csi.fs.fsCsb[0] & face->fs.fsCsb[0]) || !csi.fs.fsCsb[0])
1701 if(face->scalable || can_use_bitmap)
1709 /* If requested charset was DEFAULT_CHARSET then try using charset
1710 corresponding to the current ansi codepage */
1711 if(!csi.fs.fsCsb[0]) {
1713 if(!TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE)) {
1714 FIXME("TCI failed on codepage %d\n", acp);
1715 csi.fs.fsCsb[0] = 0;
1717 lf.lfCharSet = csi.ciCharset;
1720 /* Face families are in the top 4 bits of lfPitchAndFamily,
1721 so mask with 0xF0 before testing */
1723 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
1724 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
1725 strcpyW(lf.lfFaceName, defFixed);
1726 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
1727 strcpyW(lf.lfFaceName, defSerif);
1728 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
1729 strcpyW(lf.lfFaceName, defSans);
1731 strcpyW(lf.lfFaceName, defSans);
1732 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1733 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1734 if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
1735 face_elem_ptr = list_head(&family->faces);
1736 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1737 if(csi.fs.fsCsb[0] & face->fs.fsCsb[0])
1738 if(face->scalable || can_use_bitmap)
1746 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1747 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1748 face_elem_ptr = list_head(&family->faces);
1749 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1750 if(csi.fs.fsCsb[0] & face->fs.fsCsb[0])
1751 if(face->scalable || can_use_bitmap)
1758 LIST_FOR_EACH(family_elem_ptr, &font_list) {
1759 family = LIST_ENTRY(family_elem_ptr, Family, entry);
1760 face_elem_ptr = list_head(&family->faces);
1761 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1762 if(face->scalable || can_use_bitmap) {
1763 csi.fs.fsCsb[0] = 0;
1764 FIXME("just using first face for now\n");
1770 FIXME("can't find a single appropriate font - bailing\n");
1776 it = lf.lfItalic ? 1 : 0;
1777 bd = lf.lfWeight > 550 ? 1 : 0;
1779 height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
1780 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
1783 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1784 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1785 if(!(face->Italic ^ it) && !(face->Bold ^ bd)) {
1789 newdiff = height - (signed int)(face->size.y_ppem >> 6);
1791 newdiff = -height - ((signed int)(face->size.y_ppem >> 6) - face->size.internal_leading);
1792 if(!best || (diff > 0 && newdiff < diff && newdiff >= 0) ||
1793 (diff < 0 && newdiff > diff)) {
1794 TRACE("%ld is better for %d diff was %d\n", face->size.y_ppem >> 6, height, diff);
1807 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1808 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1812 newdiff = height - (signed int)(face->size.y_ppem >> 6);
1814 newdiff = -height - ((signed int)(face->size.y_ppem >> 6) - face->size.internal_leading);
1815 if(!best || (diff > 0 && newdiff < diff && newdiff >= 0) ||
1816 (diff < 0 && newdiff > diff)) {
1817 TRACE("%ld is better for %d diff was %d\n", face->size.y_ppem >> 6, height, diff);
1827 if(it && !face->Italic) ret->fake_italic = TRUE;
1828 if(bd && !face->Bold) ret->fake_bold = TRUE;
1831 memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
1834 ret->charset = lf.lfCharSet;
1836 ret->charset = get_nearest_charset(face);
1838 TRACE("Chosen: %s %s\n", debugstr_w(family->FamilyName),
1839 debugstr_w(face->StyleName));
1841 if(!face->scalable) {
1842 width = face->size.x_ppem >> 6;
1843 height = face->size.y_ppem >> 6;
1845 ret->ft_face = OpenFontFile(ret, face->file, face->face_index, width, height);
1853 if (ret->charset == SYMBOL_CHARSET &&
1854 !pFT_Select_Charmap(ret->ft_face, ft_encoding_symbol)) {
1857 else if (!pFT_Select_Charmap(ret->ft_face, ft_encoding_unicode)) {
1861 pFT_Select_Charmap(ret->ft_face, ft_encoding_apple_roman);
1864 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
1865 ret->name = strdupW(family->FamilyName);
1866 ret->underline = lf.lfUnderline ? 0xff : 0;
1867 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
1869 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
1871 ret->aveWidth = FT_IS_SCALABLE(ret->ft_face) ? lf.lfWidth : 0;
1872 list_add_head(&gdi_font_list, &ret->entry);
1876 static void dump_gdi_font_list(void)
1879 struct list *elem_ptr;
1881 TRACE("---------- gdiFont Cache ----------\n");
1882 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
1883 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
1884 TRACE("gdiFont=%p %s %ld\n",
1885 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
1888 TRACE("---------- Unused gdiFont Cache ----------\n");
1889 LIST_FOR_EACH(elem_ptr, &unused_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);
1896 /*************************************************************
1897 * WineEngDestroyFontInstance
1899 * free the gdiFont associated with this handle
1902 BOOL WineEngDestroyFontInstance(HFONT handle)
1907 struct list *font_elem_ptr, *hfontlist_elem_ptr;
1910 TRACE("destroying hfont=%p\n", handle);
1912 dump_gdi_font_list();
1914 font_elem_ptr = list_head(&gdi_font_list);
1915 while(font_elem_ptr) {
1916 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
1917 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
1919 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
1920 while(hfontlist_elem_ptr) {
1921 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
1922 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
1923 if(hflist->hfont == handle) {
1924 list_remove(&hflist->entry);
1925 HeapFree(GetProcessHeap(), 0, hflist);
1929 if(list_empty(&gdiFont->hfontlist)) {
1930 TRACE("Moving to Unused list\n");
1931 list_remove(&gdiFont->entry);
1932 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
1937 font_elem_ptr = list_head(&unused_gdi_font_list);
1938 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
1939 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
1940 while(font_elem_ptr) {
1941 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
1942 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
1943 TRACE("freeing %p\n", gdiFont);
1944 list_remove(&gdiFont->entry);
1950 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
1951 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
1953 OUTLINETEXTMETRICW *potm = NULL;
1955 TEXTMETRICW tm, *ptm;
1956 GdiFont font = alloc_font();
1959 if(face->scalable) {
1963 height = face->size.y_ppem >> 6;
1964 width = face->size.x_ppem >> 6;
1967 if (!(font->ft_face = OpenFontFile(font, face->file, face->face_index, width, height)))
1973 font->name = strdupW(face->family->FamilyName);
1975 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
1977 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
1979 potm = HeapAlloc(GetProcessHeap(), 0, size);
1980 WineEngGetOutlineTextMetrics(font, size, potm);
1981 ptm = (TEXTMETRICW*)&potm->otmTextMetrics;
1983 WineEngGetTextMetrics(font, &tm);
1987 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = ptm->tmHeight;
1988 pntm->ntmTm.tmAscent = ptm->tmAscent;
1989 pntm->ntmTm.tmDescent = ptm->tmDescent;
1990 pntm->ntmTm.tmInternalLeading = ptm->tmInternalLeading;
1991 pntm->ntmTm.tmExternalLeading = ptm->tmExternalLeading;
1992 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = ptm->tmAveCharWidth;
1993 pntm->ntmTm.tmMaxCharWidth = ptm->tmMaxCharWidth;
1994 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = ptm->tmWeight;
1995 pntm->ntmTm.tmOverhang = ptm->tmOverhang;
1996 pntm->ntmTm.tmDigitizedAspectX = ptm->tmDigitizedAspectX;
1997 pntm->ntmTm.tmDigitizedAspectY = ptm->tmDigitizedAspectY;
1998 pntm->ntmTm.tmFirstChar = ptm->tmFirstChar;
1999 pntm->ntmTm.tmLastChar = ptm->tmLastChar;
2000 pntm->ntmTm.tmDefaultChar = ptm->tmDefaultChar;
2001 pntm->ntmTm.tmBreakChar = ptm->tmBreakChar;
2002 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = ptm->tmItalic;
2003 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = ptm->tmUnderlined;
2004 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = ptm->tmStruckOut;
2005 pntm->ntmTm.tmPitchAndFamily = ptm->tmPitchAndFamily;
2006 pelf->elfLogFont.lfPitchAndFamily = (ptm->tmPitchAndFamily & 0xf1) + 1;
2007 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = ptm->tmCharSet;
2008 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
2009 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
2010 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
2012 *ptype = ptm->tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
2013 if(!(ptm->tmPitchAndFamily & TMPF_VECTOR))
2014 *ptype |= RASTER_FONTTYPE;
2017 pntm->ntmTm.ntmFlags = ptm->tmItalic ? NTM_ITALIC : 0;
2018 if(ptm->tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
2019 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
2021 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
2022 pntm->ntmTm.ntmCellHeight = 0;
2023 pntm->ntmTm.ntmAvgWidth = 0;
2025 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
2027 strncpyW(pelf->elfLogFont.lfFaceName,
2028 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
2030 strncpyW(pelf->elfFullName,
2031 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
2033 strncpyW(pelf->elfStyle,
2034 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
2038 strncpyW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
2039 strncpyW(pelf->elfFullName, face->family->FamilyName, LF_FACESIZE);
2040 pelf->elfStyle[0] = '\0';
2043 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
2045 HeapFree(GetProcessHeap(), 0, potm);
2050 /*************************************************************
2054 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
2058 struct list *family_elem_ptr, *face_elem_ptr;
2060 NEWTEXTMETRICEXW ntm;
2061 DWORD type, ret = 1;
2067 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
2069 if(plf->lfFaceName[0]) {
2071 for(psub = substlist; psub; psub = psub->next)
2072 if(!strcmpiW(plf->lfFaceName, psub->from.name) &&
2073 (psub->from.charset == -1 ||
2074 psub->from.charset == plf->lfCharSet))
2077 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
2078 debugstr_w(psub->to.name));
2079 memcpy(&lf, plf, sizeof(lf));
2080 strcpyW(lf.lfFaceName, psub->to.name);
2084 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2085 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2086 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
2087 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2088 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2089 GetEnumStructs(face, &elf, &ntm, &type);
2090 for(i = 0; i < 32; i++) {
2091 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
2092 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2093 strcpyW(elf.elfScript, OEM_DOSW);
2094 i = 32; /* break out of loop */
2095 } else if(!(face->fs.fsCsb[0] & (1L << i)))
2098 fs.fsCsb[0] = 1L << i;
2100 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
2102 csi.ciCharset = DEFAULT_CHARSET;
2103 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
2104 if(csi.ciCharset != DEFAULT_CHARSET) {
2105 elf.elfLogFont.lfCharSet =
2106 ntm.ntmTm.tmCharSet = csi.ciCharset;
2108 strcpyW(elf.elfScript, ElfScriptsW[i]);
2110 FIXME("Unknown elfscript for bit %d\n", i);
2113 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2114 debugstr_w(elf.elfLogFont.lfFaceName),
2115 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2116 csi.ciCharset, type, debugstr_w(elf.elfScript),
2117 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
2118 ntm.ntmTm.ntmFlags);
2119 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
2126 LIST_FOR_EACH(family_elem_ptr, &font_list) {
2127 family = LIST_ENTRY(family_elem_ptr, Family, entry);
2128 face_elem_ptr = list_head(&family->faces);
2129 face = LIST_ENTRY(face_elem_ptr, Face, entry);
2130 GetEnumStructs(face, &elf, &ntm, &type);
2131 for(i = 0; i < 32; i++) {
2132 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
2133 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2134 strcpyW(elf.elfScript, OEM_DOSW);
2135 i = 32; /* break out of loop */
2136 } else if(!(face->fs.fsCsb[0] & (1L << i)))
2139 fs.fsCsb[0] = 1L << i;
2141 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
2143 csi.ciCharset = DEFAULT_CHARSET;
2144 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
2145 if(csi.ciCharset != DEFAULT_CHARSET) {
2146 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
2149 strcpyW(elf.elfScript, ElfScriptsW[i]);
2151 FIXME("Unknown elfscript for bit %d\n", i);
2154 TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2155 debugstr_w(elf.elfLogFont.lfFaceName),
2156 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2157 csi.ciCharset, type, debugstr_w(elf.elfScript),
2158 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
2159 ntm.ntmTm.ntmFlags);
2160 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
2169 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
2171 pt->x.value = vec->x >> 6;
2172 pt->x.fract = (vec->x & 0x3f) << 10;
2173 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
2174 pt->y.value = vec->y >> 6;
2175 pt->y.fract = (vec->y & 0x3f) << 10;
2176 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
2180 static FT_UInt get_glyph_index(GdiFont font, UINT glyph)
2182 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
2183 glyph = glyph + 0xf000;
2184 return pFT_Get_Char_Index(font->ft_face, glyph);
2187 /*************************************************************
2188 * WineEngGetGlyphIndices
2190 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
2192 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
2193 LPWORD pgi, DWORD flags)
2197 for(i = 0; i < count; i++)
2198 pgi[i] = get_glyph_index(font, lpstr[i]);
2203 /*************************************************************
2204 * WineEngGetGlyphOutline
2206 * Behaves in exactly the same way as the win32 api GetGlyphOutline
2207 * except that the first parameter is the HWINEENGFONT of the font in
2208 * question rather than an HDC.
2211 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
2212 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
2215 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
2216 FT_Face ft_face = font->ft_face;
2217 FT_UInt glyph_index;
2218 DWORD width, height, pitch, needed = 0;
2219 FT_Bitmap ft_bitmap;
2221 INT left, right, top = 0, bottom = 0;
2223 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
2224 float widthRatio = 1.0;
2225 FT_Matrix transMat = identityMat;
2226 BOOL needsTransform = FALSE;
2229 TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font, glyph, format, lpgm,
2230 buflen, buf, lpmat);
2232 if(format & GGO_GLYPH_INDEX) {
2233 glyph_index = glyph;
2234 format &= ~GGO_GLYPH_INDEX;
2236 glyph_index = get_glyph_index(font, glyph);
2238 if(glyph_index >= font->gmsize) {
2239 font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
2240 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
2241 font->gmsize * sizeof(*font->gm));
2243 if(format == GGO_METRICS && font->gm[glyph_index].init) {
2244 memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
2245 return 1; /* FIXME */
2249 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP) || font->aveWidth || lpmat)
2250 load_flags |= FT_LOAD_NO_BITMAP;
2252 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
2255 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
2259 /* Scaling factor */
2260 if (font->aveWidth && font->potm) {
2261 widthRatio = (float)font->aveWidth * font->font_desc.matrix.eM11 / (float) font->potm->otmTextMetrics.tmAveCharWidth;
2264 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
2265 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
2267 font->gm[glyph_index].adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
2268 font->gm[glyph_index].lsb = left >> 6;
2269 font->gm[glyph_index].bbx = (right - left) >> 6;
2271 /* Scaling transform */
2272 if(font->aveWidth) {
2274 scaleMat.xx = FT_FixedFromFloat(widthRatio);
2277 scaleMat.yy = (1 << 16);
2279 pFT_Matrix_Multiply(&scaleMat, &transMat);
2280 needsTransform = TRUE;
2283 /* Rotation transform */
2284 if(font->orientation) {
2285 FT_Matrix rotationMat;
2287 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
2288 pFT_Vector_Unit(&vecAngle, angle);
2289 rotationMat.xx = vecAngle.x;
2290 rotationMat.xy = -vecAngle.y;
2291 rotationMat.yx = -rotationMat.xy;
2292 rotationMat.yy = rotationMat.xx;
2294 pFT_Matrix_Multiply(&rotationMat, &transMat);
2295 needsTransform = TRUE;
2298 /* Extra transformation specified by caller */
2301 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
2302 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
2303 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
2304 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
2305 pFT_Matrix_Multiply(&extraMat, &transMat);
2306 needsTransform = TRUE;
2309 if(!needsTransform) {
2310 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
2311 bottom = (ft_face->glyph->metrics.horiBearingY -
2312 ft_face->glyph->metrics.height) & -64;
2313 lpgm->gmCellIncX = font->gm[glyph_index].adv;
2314 lpgm->gmCellIncY = 0;
2318 for(xc = 0; xc < 2; xc++) {
2319 for(yc = 0; yc < 2; yc++) {
2320 vec.x = (ft_face->glyph->metrics.horiBearingX +
2321 xc * ft_face->glyph->metrics.width);
2322 vec.y = ft_face->glyph->metrics.horiBearingY -
2323 yc * ft_face->glyph->metrics.height;
2324 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
2325 pFT_Vector_Transform(&vec, &transMat);
2326 if(xc == 0 && yc == 0) {
2327 left = right = vec.x;
2328 top = bottom = vec.y;
2330 if(vec.x < left) left = vec.x;
2331 else if(vec.x > right) right = vec.x;
2332 if(vec.y < bottom) bottom = vec.y;
2333 else if(vec.y > top) top = vec.y;
2338 right = (right + 63) & -64;
2339 bottom = bottom & -64;
2340 top = (top + 63) & -64;
2342 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
2343 vec.x = ft_face->glyph->metrics.horiAdvance;
2345 pFT_Vector_Transform(&vec, &transMat);
2346 lpgm->gmCellIncX = (vec.x+63) >> 6;
2347 lpgm->gmCellIncY = -((vec.y+63) >> 6);
2349 lpgm->gmBlackBoxX = (right - left) >> 6;
2350 lpgm->gmBlackBoxY = (top - bottom) >> 6;
2351 lpgm->gmptGlyphOrigin.x = left >> 6;
2352 lpgm->gmptGlyphOrigin.y = top >> 6;
2354 memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
2355 font->gm[glyph_index].init = TRUE;
2357 if(format == GGO_METRICS)
2358 return 1; /* FIXME */
2360 if (buf && !buflen){
2364 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP) {
2365 TRACE("loaded a bitmap\n");
2371 width = lpgm->gmBlackBoxX;
2372 height = lpgm->gmBlackBoxY;
2373 pitch = ((width + 31) >> 5) << 2;
2374 needed = pitch * height;
2376 if(!buf || !buflen) break;
2378 switch(ft_face->glyph->format) {
2379 case ft_glyph_format_bitmap:
2381 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
2382 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
2383 INT h = ft_face->glyph->bitmap.rows;
2385 memcpy(dst, src, w);
2386 src += ft_face->glyph->bitmap.pitch;
2392 case ft_glyph_format_outline:
2393 ft_bitmap.width = width;
2394 ft_bitmap.rows = height;
2395 ft_bitmap.pitch = pitch;
2396 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
2397 ft_bitmap.buffer = buf;
2399 if(needsTransform) {
2400 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
2403 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
2405 /* Note: FreeType will only set 'black' bits for us. */
2406 memset(buf, 0, needed);
2407 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
2411 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
2416 case GGO_GRAY2_BITMAP:
2417 case GGO_GRAY4_BITMAP:
2418 case GGO_GRAY8_BITMAP:
2419 case WINE_GGO_GRAY16_BITMAP:
2424 width = lpgm->gmBlackBoxX;
2425 height = lpgm->gmBlackBoxY;
2426 pitch = (width + 3) / 4 * 4;
2427 needed = pitch * height;
2429 if(!buf || !buflen) break;
2430 ft_bitmap.width = width;
2431 ft_bitmap.rows = height;
2432 ft_bitmap.pitch = pitch;
2433 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
2434 ft_bitmap.buffer = buf;
2436 if(needsTransform) {
2437 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
2440 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
2442 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
2444 if(format == GGO_GRAY2_BITMAP)
2446 else if(format == GGO_GRAY4_BITMAP)
2448 else if(format == GGO_GRAY8_BITMAP)
2450 else if(format == WINE_GGO_GRAY16_BITMAP)
2458 for(row = 0; row < height; row++) {
2460 for(col = 0; col < width; col++, ptr++) {
2461 *ptr = (*(unsigned int*)ptr * mult + 128) / 256;
2470 int contour, point = 0, first_pt;
2471 FT_Outline *outline = &ft_face->glyph->outline;
2472 TTPOLYGONHEADER *pph;
2474 DWORD pph_start, cpfx, type;
2476 if(buflen == 0) buf = NULL;
2478 if (needsTransform && buf) {
2479 pFT_Outline_Transform(outline, &transMat);
2482 for(contour = 0; contour < outline->n_contours; contour++) {
2484 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
2487 pph->dwType = TT_POLYGON_TYPE;
2488 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2490 needed += sizeof(*pph);
2492 while(point <= outline->contours[contour]) {
2493 ppc = (TTPOLYCURVE *)((char *)buf + needed);
2494 type = (outline->tags[point] & FT_Curve_Tag_On) ?
2495 TT_PRIM_LINE : TT_PRIM_QSPLINE;
2499 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2502 } while(point <= outline->contours[contour] &&
2503 (outline->tags[point] & FT_Curve_Tag_On) ==
2504 (outline->tags[point-1] & FT_Curve_Tag_On));
2505 /* At the end of a contour Windows adds the start point, but
2507 if(point > outline->contours[contour] &&
2508 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
2510 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
2512 } else if(point <= outline->contours[contour] &&
2513 outline->tags[point] & FT_Curve_Tag_On) {
2514 /* add closing pt for bezier */
2516 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2524 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2527 pph->cb = needed - pph_start;
2533 /* Convert the quadratic Beziers to cubic Beziers.
2534 The parametric eqn for a cubic Bezier is, from PLRM:
2535 r(t) = at^3 + bt^2 + ct + r0
2536 with the control points:
2541 A quadratic Beizer has the form:
2542 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
2544 So equating powers of t leads to:
2545 r1 = 2/3 p1 + 1/3 p0
2546 r2 = 2/3 p1 + 1/3 p2
2547 and of course r0 = p0, r3 = p2
2550 int contour, point = 0, first_pt;
2551 FT_Outline *outline = &ft_face->glyph->outline;
2552 TTPOLYGONHEADER *pph;
2554 DWORD pph_start, cpfx, type;
2555 FT_Vector cubic_control[4];
2556 if(buflen == 0) buf = NULL;
2558 if (needsTransform && buf) {
2559 pFT_Outline_Transform(outline, &transMat);
2562 for(contour = 0; contour < outline->n_contours; contour++) {
2564 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
2567 pph->dwType = TT_POLYGON_TYPE;
2568 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2570 needed += sizeof(*pph);
2572 while(point <= outline->contours[contour]) {
2573 ppc = (TTPOLYCURVE *)((char *)buf + needed);
2574 type = (outline->tags[point] & FT_Curve_Tag_On) ?
2575 TT_PRIM_LINE : TT_PRIM_CSPLINE;
2578 if(type == TT_PRIM_LINE) {
2580 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2584 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
2587 /* FIXME: Possible optimization in endpoint calculation
2588 if there are two consecutive curves */
2589 cubic_control[0] = outline->points[point-1];
2590 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
2591 cubic_control[0].x += outline->points[point].x + 1;
2592 cubic_control[0].y += outline->points[point].y + 1;
2593 cubic_control[0].x >>= 1;
2594 cubic_control[0].y >>= 1;
2596 if(point+1 > outline->contours[contour])
2597 cubic_control[3] = outline->points[first_pt];
2599 cubic_control[3] = outline->points[point+1];
2600 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
2601 cubic_control[3].x += outline->points[point].x + 1;
2602 cubic_control[3].y += outline->points[point].y + 1;
2603 cubic_control[3].x >>= 1;
2604 cubic_control[3].y >>= 1;
2607 /* r1 = 1/3 p0 + 2/3 p1
2608 r2 = 1/3 p2 + 2/3 p1 */
2609 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
2610 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
2611 cubic_control[2] = cubic_control[1];
2612 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
2613 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
2614 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
2615 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
2617 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
2618 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
2619 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
2624 } while(point <= outline->contours[contour] &&
2625 (outline->tags[point] & FT_Curve_Tag_On) ==
2626 (outline->tags[point-1] & FT_Curve_Tag_On));
2627 /* At the end of a contour Windows adds the start point,
2628 but only for Beziers and we've already done that.
2630 if(point <= outline->contours[contour] &&
2631 outline->tags[point] & FT_Curve_Tag_On) {
2632 /* This is the closing pt of a bezier, but we've already
2633 added it, so just inc point and carry on */
2640 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2643 pph->cb = needed - pph_start;
2649 FIXME("Unsupported format %d\n", format);
2655 static BOOL get_bitmap_text_metrics(GdiFont font)
2657 FT_Face ft_face = font->ft_face;
2658 #ifdef HAVE_FREETYPE_FTWINFNT_H
2659 FT_WinFNT_HeaderRec winfnt_header;
2661 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
2662 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
2663 font->potm->otmSize = size;
2665 #define TM font->potm->otmTextMetrics
2666 #ifdef HAVE_FREETYPE_FTWINFNT_H
2667 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
2669 TM.tmHeight = winfnt_header.pixel_height;
2670 TM.tmAscent = winfnt_header.ascent;
2671 TM.tmDescent = TM.tmHeight - TM.tmAscent;
2672 TM.tmInternalLeading = winfnt_header.internal_leading;
2673 TM.tmExternalLeading = winfnt_header.external_leading;
2674 TM.tmAveCharWidth = winfnt_header.avg_width;
2675 TM.tmMaxCharWidth = winfnt_header.max_width;
2676 TM.tmWeight = winfnt_header.weight;
2678 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
2679 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
2680 TM.tmFirstChar = winfnt_header.first_char;
2681 TM.tmLastChar = winfnt_header.last_char;
2682 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
2683 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
2684 TM.tmItalic = winfnt_header.italic;
2685 TM.tmUnderlined = font->underline;
2686 TM.tmStruckOut = font->strikeout;
2687 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
2688 TM.tmCharSet = winfnt_header.charset;
2693 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
2694 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
2695 TM.tmHeight = TM.tmAscent + TM.tmDescent;
2696 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
2697 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
2698 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
2699 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
2700 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
2702 TM.tmDigitizedAspectX = 96; /* FIXME */
2703 TM.tmDigitizedAspectY = 96; /* FIXME */
2705 TM.tmLastChar = 255;
2706 TM.tmDefaultChar = 32;
2707 TM.tmBreakChar = 32;
2708 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
2709 TM.tmUnderlined = font->underline;
2710 TM.tmStruckOut = font->strikeout;
2711 /* NB inverted meaning of TMPF_FIXED_PITCH */
2712 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
2713 TM.tmCharSet = font->charset;
2720 /*************************************************************
2721 * WineEngGetTextMetrics
2724 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
2727 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
2728 if(!get_bitmap_text_metrics(font))
2731 if(!font->potm) return FALSE;
2732 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
2734 if (font->aveWidth) {
2735 ptm->tmAveCharWidth = font->aveWidth * font->font_desc.matrix.eM11;
2741 /*************************************************************
2742 * WineEngGetOutlineTextMetrics
2745 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
2746 OUTLINETEXTMETRICW *potm)
2748 FT_Face ft_face = font->ft_face;
2749 UINT needed, lenfam, lensty, ret;
2751 TT_HoriHeader *pHori;
2752 TT_Postscript *pPost;
2753 FT_Fixed x_scale, y_scale;
2754 WCHAR *family_nameW, *style_nameW;
2755 static const WCHAR spaceW[] = {' ', '\0'};
2757 INT ascent, descent;
2759 TRACE("font=%p\n", font);
2761 if(!FT_IS_SCALABLE(ft_face))
2765 if(cbSize >= font->potm->otmSize)
2766 memcpy(potm, font->potm, font->potm->otmSize);
2767 return font->potm->otmSize;
2771 needed = sizeof(*potm);
2773 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
2774 family_nameW = strdupW(font->name);
2776 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
2778 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
2779 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
2780 style_nameW, lensty);
2782 /* These names should be read from the TT name table */
2784 /* length of otmpFamilyName */
2787 /* length of otmpFaceName */
2788 if(!strcasecmp(ft_face->style_name, "regular")) {
2789 needed += lenfam; /* just the family name */
2791 needed += lenfam + lensty; /* family + " " + style */
2794 /* length of otmpStyleName */
2797 /* length of otmpFullName */
2798 needed += lenfam + lensty;
2801 x_scale = ft_face->size->metrics.x_scale;
2802 y_scale = ft_face->size->metrics.y_scale;
2804 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2806 FIXME("Can't find OS/2 table - not TT font?\n");
2811 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2813 FIXME("Can't find HHEA table - not TT font?\n");
2818 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
2820 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",
2821 pOS2->usWinAscent, pOS2->usWinDescent,
2822 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
2823 ft_face->ascender, ft_face->descender, ft_face->height,
2824 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
2825 ft_face->bbox.yMax, ft_face->bbox.yMin);
2827 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
2828 font->potm->otmSize = needed;
2830 #define TM font->potm->otmTextMetrics
2832 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
2833 ascent = pHori->Ascender;
2834 descent = -pHori->Descender;
2836 ascent = pOS2->usWinAscent;
2837 descent = pOS2->usWinDescent;
2841 TM.tmAscent = font->yMax;
2842 TM.tmDescent = -font->yMin;
2843 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
2845 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
2846 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
2847 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
2848 - ft_face->units_per_EM, y_scale) + 32) >> 6;
2851 TM.tmHeight = TM.tmAscent + TM.tmDescent;
2854 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
2856 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
2857 ((ascent + descent) -
2858 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
2860 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
2861 if (TM.tmAveCharWidth == 0) {
2862 TM.tmAveCharWidth = 1;
2864 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
2865 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
2867 TM.tmDigitizedAspectX = 300;
2868 TM.tmDigitizedAspectY = 300;
2869 TM.tmFirstChar = pOS2->usFirstCharIndex;
2870 TM.tmLastChar = pOS2->usLastCharIndex;
2871 TM.tmDefaultChar = pOS2->usDefaultChar;
2872 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
2873 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
2874 TM.tmUnderlined = font->underline;
2875 TM.tmStruckOut = font->strikeout;
2877 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
2878 if(!FT_IS_FIXED_WIDTH(ft_face))
2879 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
2881 TM.tmPitchAndFamily = 0;
2883 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
2884 case PAN_FAMILY_SCRIPT:
2885 TM.tmPitchAndFamily |= FF_SCRIPT;
2887 case PAN_FAMILY_DECORATIVE:
2888 case PAN_FAMILY_PICTORIAL:
2889 TM.tmPitchAndFamily |= FF_DECORATIVE;
2891 case PAN_FAMILY_TEXT_DISPLAY:
2892 if(TM.tmPitchAndFamily == 0) /* fixed */
2893 TM.tmPitchAndFamily = FF_MODERN;
2895 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
2896 case PAN_SERIF_NORMAL_SANS:
2897 case PAN_SERIF_OBTUSE_SANS:
2898 case PAN_SERIF_PERP_SANS:
2899 TM.tmPitchAndFamily |= FF_SWISS;
2902 TM.tmPitchAndFamily |= FF_ROMAN;
2907 TM.tmPitchAndFamily |= FF_DONTCARE;
2910 if(FT_IS_SCALABLE(ft_face))
2911 TM.tmPitchAndFamily |= TMPF_VECTOR;
2912 if(FT_IS_SFNT(ft_face))
2913 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
2915 TM.tmCharSet = font->charset;
2918 font->potm->otmFiller = 0;
2919 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
2920 font->potm->otmfsSelection = pOS2->fsSelection;
2921 font->potm->otmfsType = pOS2->fsType;
2922 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
2923 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
2924 font->potm->otmItalicAngle = 0; /* POST table */
2925 font->potm->otmEMSquare = ft_face->units_per_EM;
2926 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
2927 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
2928 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
2929 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
2930 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
2931 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
2932 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
2933 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
2934 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
2935 font->potm->otmMacAscent = 0; /* where do these come from ? */
2936 font->potm->otmMacDescent = 0;
2937 font->potm->otmMacLineGap = 0;
2938 font->potm->otmusMinimumPPEM = 0; /* TT Header */
2939 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
2940 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
2941 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
2942 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
2943 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
2944 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
2945 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
2946 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
2947 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
2948 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
2950 font->potm->otmsUnderscoreSize = 0;
2951 font->potm->otmsUnderscorePosition = 0;
2953 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
2954 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
2957 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
2958 cp = (char*)font->potm + sizeof(*font->potm);
2959 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
2960 strcpyW((WCHAR*)cp, family_nameW);
2962 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
2963 strcpyW((WCHAR*)cp, style_nameW);
2965 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
2966 strcpyW((WCHAR*)cp, family_nameW);
2967 if(strcasecmp(ft_face->style_name, "regular")) {
2968 strcatW((WCHAR*)cp, spaceW);
2969 strcatW((WCHAR*)cp, style_nameW);
2970 cp += lenfam + lensty;
2973 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
2974 strcpyW((WCHAR*)cp, family_nameW);
2975 strcatW((WCHAR*)cp, spaceW);
2976 strcatW((WCHAR*)cp, style_nameW);
2979 if(potm && needed <= cbSize)
2980 memcpy(potm, font->potm, font->potm->otmSize);
2983 HeapFree(GetProcessHeap(), 0, style_nameW);
2984 HeapFree(GetProcessHeap(), 0, family_nameW);
2990 /*************************************************************
2991 * WineEngGetCharWidth
2994 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
2999 FT_UInt glyph_index;
3001 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
3003 for(c = firstChar; c <= lastChar; c++) {
3004 glyph_index = get_glyph_index(font, c);
3005 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3006 &gm, 0, NULL, NULL);
3007 buffer[c - firstChar] = font->gm[glyph_index].adv;
3012 /*************************************************************
3013 * WineEngGetCharABCWidths
3016 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
3021 FT_UInt glyph_index;
3023 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
3025 if(!FT_IS_SCALABLE(font->ft_face))
3028 for(c = firstChar; c <= lastChar; c++) {
3029 glyph_index = get_glyph_index(font, c);
3030 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3031 &gm, 0, NULL, NULL);
3032 buffer[c - firstChar].abcA = font->gm[glyph_index].lsb;
3033 buffer[c - firstChar].abcB = font->gm[glyph_index].bbx;
3034 buffer[c - firstChar].abcC = font->gm[glyph_index].adv - font->gm[glyph_index].lsb -
3035 font->gm[glyph_index].bbx;
3040 /*************************************************************
3041 * WineEngGetTextExtentPoint
3044 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
3050 FT_UInt glyph_index;
3052 TRACE("%p, %s, %d, %p\n", font, debugstr_wn(wstr, count), count,
3056 WineEngGetTextMetrics(font, &tm);
3057 size->cy = tm.tmHeight;
3059 for(idx = 0; idx < count; idx++) {
3060 glyph_index = get_glyph_index(font, wstr[idx]);
3061 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3062 &gm, 0, NULL, NULL);
3063 size->cx += font->gm[glyph_index].adv;
3065 TRACE("return %ld,%ld\n", size->cx, size->cy);
3069 /*************************************************************
3070 * WineEngGetTextExtentPointI
3073 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
3080 TRACE("%p, %p, %d, %p\n", font, indices, count, size);
3083 WineEngGetTextMetrics(font, &tm);
3084 size->cy = tm.tmHeight;
3086 for(idx = 0; idx < count; idx++) {
3087 WineEngGetGlyphOutline(font, indices[idx],
3088 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
3090 size->cx += font->gm[indices[idx]].adv;
3092 TRACE("return %ld,%ld\n", size->cx, size->cy);
3096 /*************************************************************
3097 * WineEngGetFontData
3100 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
3103 FT_Face ft_face = font->ft_face;
3107 TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
3108 font, table, offset, buf, cbData);
3110 if(!FT_IS_SFNT(ft_face))
3118 if(table) { /* MS tags differ in endidness from FT ones */
3119 table = table >> 24 | table << 24 |
3120 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
3123 /* If the FT_Load_Sfnt_Table function is there we'll use it */
3124 if(pFT_Load_Sfnt_Table)
3125 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
3126 else { /* Do it the hard way */
3127 TT_Face tt_face = (TT_Face) ft_face;
3128 SFNT_Interface *sfnt;
3129 if (FT_Version.major==2 && FT_Version.minor==0)
3132 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
3136 /* A field was added in the middle of the structure in 2.1.x */
3137 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
3139 err = sfnt->load_any(tt_face, table, offset, buf, &len);
3142 TRACE("Can't find table %08lx.\n", table);
3148 /*************************************************************
3149 * WineEngGetTextFace
3152 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
3155 lstrcpynW(str, font->name, count);
3156 return strlenW(font->name);
3158 return strlenW(font->name) + 1;
3161 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
3163 if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
3164 return font->charset;
3167 #else /* HAVE_FREETYPE */
3169 BOOL WineEngInit(void)
3173 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
3177 BOOL WineEngDestroyFontInstance(HFONT hfont)
3182 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3187 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
3188 LPWORD pgi, DWORD flags)
3193 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
3194 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
3197 ERR("called but we don't have FreeType\n");
3201 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
3203 ERR("called but we don't have FreeType\n");
3207 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
3208 OUTLINETEXTMETRICW *potm)
3210 ERR("called but we don't have FreeType\n");
3214 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
3217 ERR("called but we don't have FreeType\n");
3221 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
3224 ERR("called but we don't have FreeType\n");
3228 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
3231 ERR("called but we don't have FreeType\n");
3235 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
3238 ERR("called but we don't have FreeType\n");
3242 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
3245 ERR("called but we don't have FreeType\n");
3249 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
3251 ERR("called but we don't have FreeType\n");
3255 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3261 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3267 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
3270 return DEFAULT_CHARSET;
3273 #endif /* HAVE_FREETYPE */