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 {
170 FT_Fixed font_version;
172 Bitmap_Size size; /* set if face is a bitmap */
173 BOOL external; /* TRUE if we should manually add this font to the registry */
174 struct tagFace *next;
175 struct tagFamily *family;
178 typedef struct tagFamily {
181 struct tagFamily *next;
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 Family *FontList = NULL;
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;
399 Face **insertface, *next;
401 FT_Long face_index = 0, num_faces;
402 #ifdef HAVE_FREETYPE_FTWINFNT_H
403 FT_WinFNT_HeaderRec winfnt_header;
408 char *family_name = fake_family;
410 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
411 if((err = pFT_New_Face(library, file, face_index, &ft_face)) != 0) {
412 WARN("Unable to load font file %s err = %x\n", debugstr_a(file), err);
416 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*/
417 pFT_Done_Face(ft_face);
421 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
422 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
423 pFT_Done_Face(ft_face);
427 if(FT_IS_SFNT(ft_face) && (!pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2) ||
428 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
429 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))) {
430 TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
431 "Skipping this font.\n", debugstr_a(file));
432 pFT_Done_Face(ft_face);
436 if(!ft_face->family_name || !ft_face->style_name) {
437 TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file));
438 pFT_Done_Face(ft_face);
443 family_name = ft_face->family_name;
447 My_FT_Bitmap_Size *size = NULL;
449 if(!FT_IS_SCALABLE(ft_face))
450 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
452 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
453 FamilyW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
454 MultiByteToWideChar(CP_ACP, 0, family_name, -1, FamilyW, len);
458 if(!strcmpW((*pfamily)->FamilyName, FamilyW))
460 pfamily = &(*pfamily)->next;
463 *pfamily = HeapAlloc(GetProcessHeap(), 0, sizeof(**pfamily));
464 (*pfamily)->FamilyName = FamilyW;
465 (*pfamily)->FirstFace = NULL;
466 (*pfamily)->next = NULL;
468 HeapFree(GetProcessHeap(), 0, FamilyW);
471 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
472 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
473 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
476 for(insertface = &(*pfamily)->FirstFace; *insertface;
477 insertface = &(*insertface)->next) {
478 if(!strcmpW((*insertface)->StyleName, StyleW) && (FT_IS_SCALABLE(ft_face) || (size->y_ppem == (*insertface)->size.y_ppem))) {
479 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
480 debugstr_w((*pfamily)->FamilyName), debugstr_w(StyleW),
481 (*insertface)->font_version, pHeader ? pHeader->Font_Revision : 0);
484 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
485 HeapFree(GetProcessHeap(), 0, StyleW);
486 pFT_Done_Face(ft_face);
489 if(!pHeader || pHeader->Font_Revision <= (*insertface)->font_version) {
490 TRACE("Original font is newer so skipping this one\n");
491 HeapFree(GetProcessHeap(), 0, StyleW);
492 pFT_Done_Face(ft_face);
495 TRACE("Replacing original with this one\n");
496 next = (*insertface)->next;
497 HeapFree(GetProcessHeap(), 0, (*insertface)->file);
498 HeapFree(GetProcessHeap(), 0, (*insertface)->StyleName);
499 HeapFree(GetProcessHeap(), 0, *insertface);
504 *insertface = HeapAlloc(GetProcessHeap(), 0, sizeof(**insertface));
505 (*insertface)->StyleName = StyleW;
506 (*insertface)->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
507 strcpy((*insertface)->file, file);
508 (*insertface)->face_index = face_index;
509 (*insertface)->next = next;
510 (*insertface)->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
511 (*insertface)->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
512 (*insertface)->font_version = pHeader ? pHeader->Font_Revision : 0;
513 (*insertface)->family = *pfamily;
514 (*insertface)->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
516 if(FT_IS_SCALABLE(ft_face)) {
517 memset(&(*insertface)->size, 0, sizeof((*insertface)->size));
518 (*insertface)->scalable = TRUE;
520 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
521 size->height, size->width, size->size >> 6,
522 size->x_ppem >> 6, size->y_ppem >> 6);
523 (*insertface)->size.height = size->height;
524 (*insertface)->size.width = size->width;
525 (*insertface)->size.size = size->size;
526 (*insertface)->size.x_ppem = size->x_ppem;
527 (*insertface)->size.y_ppem = size->y_ppem;
528 (*insertface)->size.internal_leading = 0;
529 (*insertface)->scalable = FALSE;
532 memset(&(*insertface)->fs, 0, sizeof((*insertface)->fs));
534 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
536 (*insertface)->fs.fsCsb[0] = pOS2->ulCodePageRange1;
537 (*insertface)->fs.fsCsb[1] = pOS2->ulCodePageRange2;
538 (*insertface)->fs.fsUsb[0] = pOS2->ulUnicodeRange1;
539 (*insertface)->fs.fsUsb[1] = pOS2->ulUnicodeRange2;
540 (*insertface)->fs.fsUsb[2] = pOS2->ulUnicodeRange3;
541 (*insertface)->fs.fsUsb[3] = pOS2->ulUnicodeRange4;
542 if(pOS2->version == 0) {
545 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
546 (*insertface)->fs.fsCsb[0] |= 1;
548 (*insertface)->fs.fsCsb[0] |= 1L << 31;
551 #ifdef HAVE_FREETYPE_FTWINFNT_H
552 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
554 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
555 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
556 if(TranslateCharsetInfo((DWORD*)(UINT)winfnt_header.charset, &csi, TCI_SRCCHARSET))
557 memcpy(&(*insertface)->fs, &csi.fs, sizeof(csi.fs));
558 (*insertface)->size.internal_leading = winfnt_header.internal_leading;
561 TRACE("fsCsb = %08lx %08lx/%08lx %08lx %08lx %08lx\n",
562 (*insertface)->fs.fsCsb[0], (*insertface)->fs.fsCsb[1],
563 (*insertface)->fs.fsUsb[0], (*insertface)->fs.fsUsb[1],
564 (*insertface)->fs.fsUsb[2], (*insertface)->fs.fsUsb[3]);
567 if((*insertface)->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
568 for(i = 0; i < ft_face->num_charmaps; i++) {
569 switch(ft_face->charmaps[i]->encoding) {
570 case ft_encoding_unicode:
571 case ft_encoding_apple_roman:
572 (*insertface)->fs.fsCsb[0] |= 1;
574 case ft_encoding_symbol:
575 (*insertface)->fs.fsCsb[0] |= 1L << 31;
583 if((*insertface)->fs.fsCsb[0] & ~(1L << 31))
584 have_installed_roman_font = TRUE;
585 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
587 num_faces = ft_face->num_faces;
588 pFT_Done_Face(ft_face);
589 TRACE("Added font %s %s\n", debugstr_w((*pfamily)->FamilyName),
591 } while(num_faces > ++face_index);
595 static void DumpFontList(void)
600 for(family = FontList; family; family = family->next) {
601 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
602 for(face = family->FirstFace; face; face = face->next) {
603 TRACE("\t%s", debugstr_w(face->StyleName));
605 TRACE(" %ld", face->size.y_ppem >> 6);
612 static void DumpSubstList(void)
616 for(psub = substlist; psub; psub = psub->next)
617 if(psub->from.charset != -1 || psub->to.charset != -1)
618 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
619 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
621 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
622 debugstr_w(psub->to.name));
626 static LPWSTR strdupW(LPWSTR p)
629 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
630 ret = HeapAlloc(GetProcessHeap(), 0, len);
635 static void split_subst_info(NameCs *nc, LPSTR str)
637 CHAR *p = strrchr(str, ',');
642 nc->charset = strtol(p+1, NULL, 10);
645 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
646 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
647 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
650 static void LoadSubstList(void)
652 FontSubst *psub, **ppsub;
654 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
659 for(psub = substlist; psub;) {
661 HeapFree(GetProcessHeap(), 0, psub->to.name);
662 HeapFree(GetProcessHeap(), 0, psub->from.name);
665 HeapFree(GetProcessHeap(), 0, ptmp);
670 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
671 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
672 &hkey) == ERROR_SUCCESS) {
674 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
675 &valuelen, &datalen, NULL, NULL);
677 valuelen++; /* returned value doesn't include room for '\0' */
678 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
679 data = HeapAlloc(GetProcessHeap(), 0, datalen);
684 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
685 &dlen) == ERROR_SUCCESS) {
686 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
688 *ppsub = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppsub));
689 (*ppsub)->next = NULL;
690 split_subst_info(&((*ppsub)->from), value);
691 split_subst_info(&((*ppsub)->to), data);
693 /* Win 2000 doesn't allow mapping between different charsets
694 or mapping of DEFAULT_CHARSET */
695 if(((*ppsub)->to.charset != (*ppsub)->from.charset) ||
696 (*ppsub)->to.charset == DEFAULT_CHARSET) {
697 HeapFree(GetProcessHeap(), 0, (*ppsub)->to.name);
698 HeapFree(GetProcessHeap(), 0, (*ppsub)->from.name);
699 HeapFree(GetProcessHeap(), 0, *ppsub);
702 ppsub = &((*ppsub)->next);
704 /* reset dlen and vlen */
708 HeapFree(GetProcessHeap(), 0, data);
709 HeapFree(GetProcessHeap(), 0, value);
714 /***********************************************************
715 * The replacement list is a way to map an entire font
716 * family onto another family. For example adding
718 * [HKLM\Software\Wine\Wine\FontReplacements]
719 * "Wingdings"="Winedings"
721 * would enumerate the Winedings font both as Winedings and
722 * Wingdings. However if a real Wingdings font is present the
723 * replacement does not take place.
726 static void LoadReplaceList(void)
729 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
734 WCHAR old_nameW[200];
736 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
737 "Software\\Wine\\Wine\\FontReplacements",
738 &hkey) == ERROR_SUCCESS) {
740 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
741 &valuelen, &datalen, NULL, NULL);
743 valuelen++; /* returned value doesn't include room for '\0' */
744 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
745 data = HeapAlloc(GetProcessHeap(), 0, datalen);
749 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
750 &dlen) == ERROR_SUCCESS) {
751 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
752 /* "NewName"="Oldname" */
753 if(!MultiByteToWideChar(CP_ACP, 0, data, -1, old_nameW, sizeof(old_nameW)))
756 /* Find the old family and hence all of the font files
758 for(family = FontList; family; family = family->next) {
759 if(!strcmpiW(family->FamilyName, old_nameW)) {
760 for(face = family->FirstFace; face; face = face->next) {
761 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
762 debugstr_w(face->StyleName), value);
763 /* Now add a new entry with the new family name */
764 AddFontFileToList(face->file, value, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
769 /* reset dlen and vlen */
773 HeapFree(GetProcessHeap(), 0, data);
774 HeapFree(GetProcessHeap(), 0, value);
780 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
786 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
788 dir = opendir(dirname);
790 ERR("Can't open directory %s\n", debugstr_a(dirname));
793 while((dent = readdir(dir)) != NULL) {
796 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
799 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
801 sprintf(path, "%s/%s", dirname, dent->d_name);
803 if(stat(path, &statbuf) == -1)
805 WARN("Can't stat %s\n", debugstr_a(path));
808 if(S_ISDIR(statbuf.st_mode))
809 ReadFontDir(path, external_fonts);
811 AddFontFileToList(path, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
817 static void load_fontconfig_fonts(void)
819 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
820 void *fc_handle = NULL;
829 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
831 TRACE("Wine cannot find the fontconfig library (%s).\n",
832 SONAME_LIBFONTCONFIG);
835 #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;}
836 LOAD_FUNCPTR(FcConfigGetCurrent);
837 LOAD_FUNCPTR(FcFontList);
838 LOAD_FUNCPTR(FcFontSetDestroy);
839 LOAD_FUNCPTR(FcInit);
840 LOAD_FUNCPTR(FcObjectSetAdd);
841 LOAD_FUNCPTR(FcObjectSetCreate);
842 LOAD_FUNCPTR(FcObjectSetDestroy);
843 LOAD_FUNCPTR(FcPatternCreate);
844 LOAD_FUNCPTR(FcPatternDestroy);
845 LOAD_FUNCPTR(FcPatternGet);
848 if(!pFcInit()) return;
850 config = pFcConfigGetCurrent();
851 pat = pFcPatternCreate();
852 os = pFcObjectSetCreate();
853 pFcObjectSetAdd(os, FC_FILE);
854 fontset = pFcFontList(config, pat, os);
856 for(i = 0; i < fontset->nfont; i++) {
857 if(pFcPatternGet(fontset->fonts[i], FC_FILE, 0, &v) != FcResultMatch)
859 if(v.type != FcTypeString) continue;
860 TRACE("fontconfig: %s\n", v.u.s);
862 /* We're just interested in OT/TT fonts for now, so this hack just
863 picks up the standard extensions to save time loading every other
866 if(len < 4) continue;
867 ext = v.u.s + len - 3;
868 if(!strcasecmp(ext, "ttf") || !strcasecmp(ext, "ttc") || !strcasecmp(ext, "otf"))
869 AddFontFileToList(v.u.s, NULL, ADDFONT_EXTERNAL_FONT);
871 pFcFontSetDestroy(fontset);
872 pFcObjectSetDestroy(os);
873 pFcPatternDestroy(pat);
880 void load_system_fonts(void)
883 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
886 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
889 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
890 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
891 strcatW(windowsdir, fontsW);
892 for(value = SystemFontValues; *value; value++) {
894 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
896 sprintfW(pathW, fmtW, windowsdir, data);
897 if((unixname = wine_get_unix_file_name(pathW))) {
898 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
899 HeapFree(GetProcessHeap(), 0, unixname);
907 /*************************************************************
909 * This adds registry entries for any externally loaded fonts
910 * (fonts from fontconfig or FontDirs). It also deletes entries
911 * of no longer existing fonts.
914 void update_reg_entries(void)
916 HKEY winkey = 0, externalkey = 0;
919 DWORD dlen, vlen, datalen, valuelen, i, type, len, len_fam;
923 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
924 static const WCHAR spaceW[] = {' ', '\0'};
927 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
928 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winkey, NULL) != ERROR_SUCCESS) {
929 ERR("Can't create Windows font reg key\n");
932 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, external_fonts_reg_key,
933 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
934 ERR("Can't create external font reg key\n");
938 /* Delete all external fonts added last time */
940 RegQueryInfoKeyW(externalkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
941 &valuelen, &datalen, NULL, NULL);
942 valuelen++; /* returned value doesn't include room for '\0' */
943 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
944 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
946 dlen = datalen * sizeof(WCHAR);
949 while(RegEnumValueW(externalkey, i++, valueW, &vlen, NULL, &type, data,
950 &dlen) == ERROR_SUCCESS) {
952 RegDeleteValueW(winkey, valueW);
953 /* reset dlen and vlen */
957 HeapFree(GetProcessHeap(), 0, data);
958 HeapFree(GetProcessHeap(), 0, valueW);
960 /* Delete the old external fonts key */
961 RegCloseKey(externalkey);
963 RegDeleteKeyW(HKEY_LOCAL_MACHINE, external_fonts_reg_key);
965 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, external_fonts_reg_key,
966 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
967 ERR("Can't create external font reg key\n");
971 /* enumerate the fonts and add external ones to the two keys */
973 for(family = FontList; family; family = family->next) {
974 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
975 for(face = family->FirstFace; face; face = face->next) {
976 if(!face->external) continue;
978 if(strcmpiW(face->StyleName, RegularW))
979 len = len_fam + strlenW(face->StyleName) + 1;
980 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
981 strcpyW(valueW, family->FamilyName);
983 strcatW(valueW, spaceW);
984 strcatW(valueW, face->StyleName);
986 strcatW(valueW, TrueType);
987 if((path = strrchr(face->file, '/')) == NULL)
991 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
993 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
994 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
995 RegSetValueExW(winkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
996 RegSetValueExW(externalkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
998 HeapFree(GetProcessHeap(), 0, file);
999 HeapFree(GetProcessHeap(), 0, valueW);
1004 RegCloseKey(externalkey);
1006 RegCloseKey(winkey);
1011 /*************************************************************
1012 * WineEngAddFontResourceEx
1015 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1017 if (ft_handle) /* do it only if we have freetype up and running */
1022 FIXME("Ignoring flags %lx\n", flags);
1024 if((unixname = wine_get_unix_file_name(file)))
1026 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1027 HeapFree(GetProcessHeap(), 0, unixname);
1033 /*************************************************************
1034 * WineEngRemoveFontResourceEx
1037 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1043 /*************************************************************
1046 * Initialize FreeType library and create a list of available faces
1048 BOOL WineEngInit(void)
1050 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
1052 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1054 WCHAR windowsdir[MAX_PATH];
1060 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
1063 "Wine cannot find the FreeType font library. To enable Wine to\n"
1064 "use TrueType fonts please install a version of FreeType greater than\n"
1065 "or equal to 2.0.5.\n"
1066 "http://www.freetype.org\n");
1070 #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;}
1072 LOAD_FUNCPTR(FT_Vector_Unit)
1073 LOAD_FUNCPTR(FT_Done_Face)
1074 LOAD_FUNCPTR(FT_Get_Char_Index)
1075 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
1076 LOAD_FUNCPTR(FT_Init_FreeType)
1077 LOAD_FUNCPTR(FT_Load_Glyph)
1078 LOAD_FUNCPTR(FT_Matrix_Multiply)
1079 LOAD_FUNCPTR(FT_MulFix)
1080 LOAD_FUNCPTR(FT_New_Face)
1081 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
1082 LOAD_FUNCPTR(FT_Outline_Transform)
1083 LOAD_FUNCPTR(FT_Outline_Translate)
1084 LOAD_FUNCPTR(FT_Select_Charmap)
1085 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
1086 LOAD_FUNCPTR(FT_Vector_Transform)
1089 /* Don't warn if this one is missing */
1090 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
1091 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
1092 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
1093 #ifdef HAVE_FREETYPE_FTWINFNT_H
1094 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
1096 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
1097 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
1098 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
1099 <= 2.0.3 has FT_Sqrt64 */
1103 if(pFT_Init_FreeType(&library) != 0) {
1104 ERR("Can't init FreeType library\n");
1105 wine_dlclose(ft_handle, NULL, 0);
1109 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
1110 if (pFT_Library_Version)
1112 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
1114 if (FT_Version.major<=0)
1120 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
1121 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
1122 ((FT_Version.minor << 8) & 0x00ff00) |
1123 ((FT_Version.patch ) & 0x0000ff);
1125 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
1126 ERR("Failed to create font mutex\n");
1129 WaitForSingleObject(font_mutex, INFINITE);
1131 /* load the system fonts */
1132 load_system_fonts();
1134 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
1135 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1136 strcatW(windowsdir, fontsW);
1137 if((unixname = wine_get_unix_file_name(windowsdir)))
1139 ReadFontDir(unixname, FALSE);
1140 HeapFree(GetProcessHeap(), 0, unixname);
1143 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
1144 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
1145 full path as the entry. Also look for any .fon fonts, since ReadFontDir
1147 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
1148 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1149 &hkey) == ERROR_SUCCESS) {
1151 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1152 &valuelen, &datalen, NULL, NULL);
1154 valuelen++; /* returned value doesn't include room for '\0' */
1155 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1156 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1159 dlen = datalen * sizeof(WCHAR);
1161 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
1162 &dlen) == ERROR_SUCCESS) {
1163 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
1165 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
1167 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1168 HeapFree(GetProcessHeap(), 0, unixname);
1171 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
1173 WCHAR pathW[MAX_PATH];
1174 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1175 sprintfW(pathW, fmtW, windowsdir, data);
1176 if((unixname = wine_get_unix_file_name(pathW)))
1178 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1179 HeapFree(GetProcessHeap(), 0, unixname);
1182 /* reset dlen and vlen */
1187 if (data) HeapFree(GetProcessHeap(), 0, data);
1188 if (valueW) HeapFree(GetProcessHeap(), 0, valueW);
1192 load_fontconfig_fonts();
1194 /* then look in any directories that we've specified in the config file */
1195 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1196 "Software\\Wine\\Wine\\Config\\FontDirs",
1197 &hkey) == ERROR_SUCCESS) {
1199 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1200 &valuelen, &datalen, NULL, NULL);
1202 valuelen++; /* returned value doesn't include room for '\0' */
1203 value = HeapAlloc(GetProcessHeap(), 0, valuelen);
1204 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1209 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1210 &dlen) == ERROR_SUCCESS) {
1211 TRACE("Got %s=%s\n", value, (LPSTR)data);
1212 ReadFontDir((LPSTR)data, TRUE);
1213 /* reset dlen and vlen */
1217 HeapFree(GetProcessHeap(), 0, data);
1218 HeapFree(GetProcessHeap(), 0, value);
1226 update_reg_entries();
1228 ReleaseMutex(font_mutex);
1232 "Wine cannot find certain functions that it needs inside the FreeType\n"
1233 "font library. To enable Wine to use TrueType fonts please upgrade\n"
1234 "FreeType to at least version 2.0.5.\n"
1235 "http://www.freetype.org\n");
1236 wine_dlclose(ft_handle, NULL, 0);
1242 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
1245 TT_HoriHeader *pHori;
1249 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1250 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1252 if(height == 0) height = 16;
1254 /* Calc. height of EM square:
1256 * For +ve lfHeight we have
1257 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
1258 * Re-arranging gives:
1259 * ppem = units_per_em * lfheight / (winAscent + winDescent)
1261 * For -ve lfHeight we have
1263 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
1264 * with il = winAscent + winDescent - units_per_em]
1269 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
1270 ppem = ft_face->units_per_EM * height /
1271 (pHori->Ascender - pHori->Descender);
1273 ppem = ft_face->units_per_EM * height /
1274 (pOS2->usWinAscent + pOS2->usWinDescent);
1282 static LONG load_VDMX(GdiFont, LONG);
1284 static FT_Face OpenFontFile(GdiFont font, char *file, FT_Long face_index, LONG width, LONG height)
1290 err = pFT_New_Face(library, file, face_index, &ft_face);
1292 ERR("FT_New_Face rets %d\n", err);
1296 /* set it here, as load_VDMX needs it */
1297 font->ft_face = ft_face;
1299 if(FT_IS_SCALABLE(ft_face)) {
1300 /* load the VDMX table if we have one */
1301 ppem = load_VDMX(font, height);
1303 ppem = calc_ppem_for_height(ft_face, height);
1305 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, ppem)) != 0)
1306 WARN("FT_Set_Pixel_Sizes %d, %ld rets %x\n", 0, ppem, err);
1308 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
1309 WARN("FT_Set_Pixel_Sizes %ld, %ld rets %x\n", width, height, err);
1315 static int get_nearest_charset(Face *face)
1317 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
1318 a single face with the requested charset. The idea is to check if
1319 the selected font supports the current ANSI codepage, if it does
1320 return the corresponding charset, else return the first charset */
1323 int acp = GetACP(), i;
1326 if(TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE))
1327 if(csi.fs.fsCsb[0] & face->fs.fsCsb[0])
1328 return csi.ciCharset;
1330 for(i = 0; i < 32; i++) {
1332 if(face->fs.fsCsb[0] & fs0) {
1333 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG))
1334 return csi.ciCharset;
1336 FIXME("TCI failing on %lx\n", fs0);
1340 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08lx file = %s\n",
1341 face->fs.fsCsb[0], face->file);
1342 return DEFAULT_CHARSET;
1345 static GdiFont alloc_font(void)
1347 GdiFont ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
1348 ret->gmsize = INIT_GM_SIZE;
1349 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1350 ret->gmsize * sizeof(*ret->gm));
1352 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
1353 list_init(&ret->hfontlist);
1357 static void free_font(GdiFont font)
1359 if (font->ft_face) pFT_Done_Face(font->ft_face);
1360 if (font->potm) HeapFree(GetProcessHeap(), 0, font->potm);
1361 if (font->name) HeapFree(GetProcessHeap(), 0, font->name);
1362 HeapFree(GetProcessHeap(), 0, font->gm);
1363 HeapFree(GetProcessHeap(), 0, font);
1367 /*************************************************************
1370 * load the vdmx entry for the specified height
1373 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
1374 ( ( (FT_ULong)_x4 << 24 ) | \
1375 ( (FT_ULong)_x3 << 16 ) | \
1376 ( (FT_ULong)_x2 << 8 ) | \
1379 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
1389 static LONG load_VDMX(GdiFont font, LONG height)
1391 BYTE hdr[6], tmp[2], group[4];
1392 BYTE devXRatio, devYRatio;
1393 USHORT numRecs, numRatios;
1398 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
1400 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
1403 /* FIXME: need the real device aspect ratio */
1407 numRecs = GET_BE_WORD(&hdr[2]);
1408 numRatios = GET_BE_WORD(&hdr[4]);
1410 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
1411 for(i = 0; i < numRatios; i++) {
1414 offset = (3 * 2) + (i * sizeof(Ratios));
1415 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
1418 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
1420 if(ratio.bCharSet != 1)
1423 if((ratio.xRatio == 0 &&
1424 ratio.yStartRatio == 0 &&
1425 ratio.yEndRatio == 0) ||
1426 (devXRatio == ratio.xRatio &&
1427 devYRatio >= ratio.yStartRatio &&
1428 devYRatio <= ratio.yEndRatio))
1430 offset = (3 * 2) + (numRatios * 4) + (i * 2);
1431 WineEngGetFontData(font, MS_VDMX_TAG, offset, tmp, 2);
1432 offset = GET_BE_WORD(tmp);
1438 FIXME("No suitable ratio found\n");
1442 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, group, 4) != GDI_ERROR) {
1444 BYTE startsz, endsz;
1447 recs = GET_BE_WORD(group);
1451 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
1453 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
1454 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
1455 if(result == GDI_ERROR) {
1456 FIXME("Failed to retrieve vTable\n");
1461 for(i = 0; i < recs; i++) {
1462 SHORT yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1463 SHORT yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1464 ppem = GET_BE_WORD(&vTable[i * 6]);
1466 if(yMax + -yMin == height) {
1469 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1472 if(yMax + -yMin > height) {
1475 goto end; /* failed */
1477 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1478 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1479 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1485 TRACE("ppem not found for height %ld\n", height);
1489 if(ppem < startsz || ppem > endsz)
1492 for(i = 0; i < recs; i++) {
1494 yPelHeight = GET_BE_WORD(&vTable[i * 6]);
1496 if(yPelHeight > ppem)
1499 if(yPelHeight == ppem) {
1500 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1501 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1502 TRACE("ppem %ld found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
1508 HeapFree(GetProcessHeap(), 0, vTable);
1514 static BOOL fontcmp(GdiFont font, FONT_DESC *fd)
1516 if(font->font_desc.hash != fd->hash) return TRUE;
1517 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
1518 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
1519 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
1522 static void calc_hash(FONT_DESC *pfd)
1524 DWORD hash = 0, *ptr, two_chars;
1528 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
1530 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
1532 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
1534 pwc = (WCHAR *)&two_chars;
1536 *pwc = toupperW(*pwc);
1538 *pwc = toupperW(*pwc);
1546 static GdiFont find_in_cache(HFONT hfont, LOGFONTW *plf, XFORM *pxf, BOOL can_use_bitmap)
1551 struct list *font_elem_ptr, *hfontlist_elem_ptr;
1553 memcpy(&fd.lf, plf, sizeof(LOGFONTW));
1554 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
1557 /* try the in-use list */
1558 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
1559 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
1560 if(!fontcmp(ret, &fd)) {
1561 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
1562 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
1563 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
1564 if(hflist->hfont == hfont)
1567 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
1568 hflist->hfont = hfont;
1569 list_add_head(&ret->hfontlist, &hflist->entry);
1574 /* then the unused list */
1575 font_elem_ptr = list_head(&unused_gdi_font_list);
1576 while(font_elem_ptr) {
1577 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
1578 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
1579 if(!fontcmp(ret, &fd)) {
1580 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
1581 assert(list_empty(&ret->hfontlist));
1582 TRACE("Found %p in unused list\n", ret);
1583 list_remove(&ret->entry);
1584 list_add_head(&gdi_font_list, &ret->entry);
1585 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
1586 hflist->hfont = hfont;
1587 list_add_head(&ret->hfontlist, &hflist->entry);
1594 /*************************************************************
1595 * WineEngCreateFontInstance
1598 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
1602 Family *family = NULL;
1603 INT height, width = 0;
1604 signed int diff = 0, newdiff;
1605 BOOL bd, it, can_use_bitmap;
1610 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
1611 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
1613 TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
1614 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
1615 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
1618 /* check the cache first */
1619 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
1620 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
1624 TRACE("not in cache\n");
1625 if(!FontList || !have_installed_roman_font) /* No fonts installed */
1627 TRACE("No fonts installed\n");
1633 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
1634 memcpy(&ret->font_desc.lf, &lf, sizeof(LOGFONTW));
1635 calc_hash(&ret->font_desc);
1636 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
1637 hflist->hfont = hfont;
1638 list_add_head(&ret->hfontlist, &hflist->entry);
1641 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
1642 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
1643 original value lfCharSet. Note this is a special case for
1644 Symbol and doesn't happen at least for "Wingdings*" */
1646 if(!strcmpiW(lf.lfFaceName, SymbolW))
1647 lf.lfCharSet = SYMBOL_CHARSET;
1649 if(!TranslateCharsetInfo((DWORD*)(INT)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
1650 switch(lf.lfCharSet) {
1651 case DEFAULT_CHARSET:
1652 csi.fs.fsCsb[0] = 0;
1655 FIXME("Untranslated charset %d\n", lf.lfCharSet);
1656 csi.fs.fsCsb[0] = 0;
1661 if(lf.lfFaceName[0] != '\0') {
1663 for(psub = substlist; psub; psub = psub->next)
1664 if(!strcmpiW(lf.lfFaceName, psub->from.name) &&
1665 (psub->from.charset == -1 ||
1666 psub->from.charset == lf.lfCharSet))
1669 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
1670 debugstr_w(psub->to.name));
1671 strcpyW(lf.lfFaceName, psub->to.name);
1674 /* We want a match on name and charset or just name if
1675 charset was DEFAULT_CHARSET. If the latter then
1676 we fixup the returned charset later in get_nearest_charset
1677 where we'll either use the charset of the current ansi codepage
1678 or if that's unavailable the first charset that the font supports.
1680 for(family = FontList; family; family = family->next) {
1681 if(!strcmpiW(family->FamilyName, lf.lfFaceName))
1682 if((csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0]) || !csi.fs.fsCsb[0])
1683 if(family->FirstFace->scalable || can_use_bitmap)
1689 /* If requested charset was DEFAULT_CHARSET then try using charset
1690 corresponding to the current ansi codepage */
1691 if(!csi.fs.fsCsb[0]) {
1693 if(!TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE)) {
1694 FIXME("TCI failed on codepage %d\n", acp);
1695 csi.fs.fsCsb[0] = 0;
1697 lf.lfCharSet = csi.ciCharset;
1700 /* Face families are in the top 4 bits of lfPitchAndFamily,
1701 so mask with 0xF0 before testing */
1703 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
1704 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
1705 strcpyW(lf.lfFaceName, defFixed);
1706 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
1707 strcpyW(lf.lfFaceName, defSerif);
1708 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
1709 strcpyW(lf.lfFaceName, defSans);
1711 strcpyW(lf.lfFaceName, defSans);
1712 for(family = FontList; family; family = family->next) {
1713 if(!strcmpiW(family->FamilyName, lf.lfFaceName) &&
1714 (csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0]))
1715 if(family->FirstFace->scalable || can_use_bitmap)
1721 for(family = FontList; family; family = family->next) {
1722 if(csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0])
1723 if(family->FirstFace->scalable || can_use_bitmap)
1729 for(family = FontList; family; family = family->next) {
1730 if(family->FirstFace->scalable || can_use_bitmap) {
1731 csi.fs.fsCsb[0] = 0;
1733 FIXME("just using first face for now\n");
1737 FIXME("can't find a single appropriate font - bailing\n");
1743 it = lf.lfItalic ? 1 : 0;
1744 bd = lf.lfWeight > 550 ? 1 : 0;
1746 height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
1747 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
1750 for(face = family->FirstFace; face; face = face->next) {
1751 if(!(face->Italic ^ it) && !(face->Bold ^ bd)) {
1755 newdiff = height - (signed int)(face->size.y_ppem >> 6);
1757 newdiff = -height - ((signed int)(face->size.y_ppem >> 6) - face->size.internal_leading);
1758 if(!best || (diff > 0 && newdiff < diff && newdiff >= 0) ||
1759 (diff < 0 && newdiff > diff)) {
1760 TRACE("%ld is better for %d diff was %d\n", face->size.y_ppem >> 6, height, diff);
1772 for(face = family->FirstFace; face; face = face->next) {
1776 newdiff = height - (signed int)(face->size.y_ppem >> 6);
1778 newdiff = -height - ((signed int)(face->size.y_ppem >> 6) - face->size.internal_leading);
1779 if(!best || (diff > 0 && newdiff < diff && newdiff >= 0) ||
1780 (diff < 0 && newdiff > diff)) {
1781 TRACE("%ld is better for %d diff was %d\n", face->size.y_ppem >> 6, height, diff);
1790 if(it && !face->Italic) ret->fake_italic = TRUE;
1791 if(bd && !face->Bold) ret->fake_bold = TRUE;
1794 memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
1797 ret->charset = lf.lfCharSet;
1799 ret->charset = get_nearest_charset(face);
1801 TRACE("Chosen: %s %s\n", debugstr_w(family->FamilyName),
1802 debugstr_w(face->StyleName));
1804 if(!face->scalable) {
1805 width = face->size.x_ppem >> 6;
1806 height = face->size.y_ppem >> 6;
1808 ret->ft_face = OpenFontFile(ret, face->file, face->face_index, width, height);
1816 if (ret->charset == SYMBOL_CHARSET &&
1817 !pFT_Select_Charmap(ret->ft_face, ft_encoding_symbol)) {
1820 else if (!pFT_Select_Charmap(ret->ft_face, ft_encoding_unicode)) {
1824 pFT_Select_Charmap(ret->ft_face, ft_encoding_apple_roman);
1827 ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
1828 ret->name = strdupW(family->FamilyName);
1829 ret->underline = lf.lfUnderline ? 0xff : 0;
1830 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
1832 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
1834 ret->aveWidth = FT_IS_SCALABLE(ret->ft_face) ? lf.lfWidth : 0;
1835 list_add_head(&gdi_font_list, &ret->entry);
1839 static void dump_gdi_font_list(void)
1842 struct list *elem_ptr;
1844 TRACE("---------- gdiFont Cache ----------\n");
1845 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
1846 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
1847 TRACE("gdiFont=%p %s %ld\n",
1848 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
1851 TRACE("---------- Unused gdiFont Cache ----------\n");
1852 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
1853 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
1854 TRACE("gdiFont=%p %s %ld\n",
1855 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
1859 /*************************************************************
1860 * WineEngDestroyFontInstance
1862 * free the gdiFont associated with this handle
1865 BOOL WineEngDestroyFontInstance(HFONT handle)
1870 struct list *font_elem_ptr, *hfontlist_elem_ptr;
1873 TRACE("destroying hfont=%p\n", handle);
1875 dump_gdi_font_list();
1877 font_elem_ptr = list_head(&gdi_font_list);
1878 while(font_elem_ptr) {
1879 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
1880 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
1882 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
1883 while(hfontlist_elem_ptr) {
1884 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
1885 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
1886 if(hflist->hfont == handle) {
1887 list_remove(&hflist->entry);
1888 HeapFree(GetProcessHeap(), 0, hflist);
1892 if(list_empty(&gdiFont->hfontlist)) {
1893 TRACE("Moving to Unused list\n");
1894 list_remove(&gdiFont->entry);
1895 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
1900 font_elem_ptr = list_head(&unused_gdi_font_list);
1901 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
1902 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
1903 while(font_elem_ptr) {
1904 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
1905 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
1906 TRACE("freeing %p\n", gdiFont);
1907 list_remove(&gdiFont->entry);
1913 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
1914 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
1916 OUTLINETEXTMETRICW *potm = NULL;
1918 TEXTMETRICW tm, *ptm;
1919 GdiFont font = alloc_font();
1922 if(face->scalable) {
1926 height = face->size.y_ppem >> 6;
1927 width = face->size.x_ppem >> 6;
1930 if (!(font->ft_face = OpenFontFile(font, face->file, face->face_index, width, height)))
1936 font->name = strdupW(face->family->FamilyName);
1938 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
1940 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
1942 potm = HeapAlloc(GetProcessHeap(), 0, size);
1943 WineEngGetOutlineTextMetrics(font, size, potm);
1944 ptm = (TEXTMETRICW*)&potm->otmTextMetrics;
1946 WineEngGetTextMetrics(font, &tm);
1950 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = ptm->tmHeight;
1951 pntm->ntmTm.tmAscent = ptm->tmAscent;
1952 pntm->ntmTm.tmDescent = ptm->tmDescent;
1953 pntm->ntmTm.tmInternalLeading = ptm->tmInternalLeading;
1954 pntm->ntmTm.tmExternalLeading = ptm->tmExternalLeading;
1955 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = ptm->tmAveCharWidth;
1956 pntm->ntmTm.tmMaxCharWidth = ptm->tmMaxCharWidth;
1957 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = ptm->tmWeight;
1958 pntm->ntmTm.tmOverhang = ptm->tmOverhang;
1959 pntm->ntmTm.tmDigitizedAspectX = ptm->tmDigitizedAspectX;
1960 pntm->ntmTm.tmDigitizedAspectY = ptm->tmDigitizedAspectY;
1961 pntm->ntmTm.tmFirstChar = ptm->tmFirstChar;
1962 pntm->ntmTm.tmLastChar = ptm->tmLastChar;
1963 pntm->ntmTm.tmDefaultChar = ptm->tmDefaultChar;
1964 pntm->ntmTm.tmBreakChar = ptm->tmBreakChar;
1965 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = ptm->tmItalic;
1966 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = ptm->tmUnderlined;
1967 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = ptm->tmStruckOut;
1968 pntm->ntmTm.tmPitchAndFamily = ptm->tmPitchAndFamily;
1969 pelf->elfLogFont.lfPitchAndFamily = (ptm->tmPitchAndFamily & 0xf1) + 1;
1970 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = ptm->tmCharSet;
1971 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
1972 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
1973 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
1975 *ptype = ptm->tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
1976 if(!(ptm->tmPitchAndFamily & TMPF_VECTOR))
1977 *ptype |= RASTER_FONTTYPE;
1980 pntm->ntmTm.ntmFlags = ptm->tmItalic ? NTM_ITALIC : 0;
1981 if(ptm->tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
1982 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
1984 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
1985 pntm->ntmTm.ntmCellHeight = 0;
1986 pntm->ntmTm.ntmAvgWidth = 0;
1988 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
1990 strncpyW(pelf->elfLogFont.lfFaceName,
1991 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
1993 strncpyW(pelf->elfFullName,
1994 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
1996 strncpyW(pelf->elfStyle,
1997 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
2001 strncpyW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
2002 strncpyW(pelf->elfFullName, face->family->FamilyName, LF_FACESIZE);
2003 pelf->elfStyle[0] = '\0';
2006 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
2008 HeapFree(GetProcessHeap(), 0, potm);
2013 /*************************************************************
2017 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
2022 NEWTEXTMETRICEXW ntm;
2023 DWORD type, ret = 1;
2029 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
2031 if(plf->lfFaceName[0]) {
2033 for(psub = substlist; psub; psub = psub->next)
2034 if(!strcmpiW(plf->lfFaceName, psub->from.name) &&
2035 (psub->from.charset == -1 ||
2036 psub->from.charset == plf->lfCharSet))
2039 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
2040 debugstr_w(psub->to.name));
2041 memcpy(&lf, plf, sizeof(lf));
2042 strcpyW(lf.lfFaceName, psub->to.name);
2045 for(family = FontList; family; family = family->next) {
2046 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
2047 for(face = family->FirstFace; face; face = face->next) {
2048 GetEnumStructs(face, &elf, &ntm, &type);
2049 for(i = 0; i < 32; i++) {
2050 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
2051 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2052 strcpyW(elf.elfScript, OEM_DOSW);
2053 i = 32; /* break out of loop */
2054 } else if(!(face->fs.fsCsb[0] & (1L << i)))
2057 fs.fsCsb[0] = 1L << i;
2059 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
2061 csi.ciCharset = DEFAULT_CHARSET;
2062 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
2063 if(csi.ciCharset != DEFAULT_CHARSET) {
2064 elf.elfLogFont.lfCharSet =
2065 ntm.ntmTm.tmCharSet = csi.ciCharset;
2067 strcpyW(elf.elfScript, ElfScriptsW[i]);
2069 FIXME("Unknown elfscript for bit %d\n", i);
2072 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2073 debugstr_w(elf.elfLogFont.lfFaceName),
2074 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2075 csi.ciCharset, type, debugstr_w(elf.elfScript),
2076 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
2077 ntm.ntmTm.ntmFlags);
2078 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
2085 for(family = FontList; family; family = family->next) {
2086 GetEnumStructs(family->FirstFace, &elf, &ntm, &type);
2087 for(i = 0; i < 32; i++) {
2088 if(!family->FirstFace->scalable && family->FirstFace->fs.fsCsb[0] == 0) { /* OEM bitmap */
2089 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2090 strcpyW(elf.elfScript, OEM_DOSW);
2091 i = 32; /* break out of loop */
2092 } else if(!(family->FirstFace->fs.fsCsb[0] & (1L << i)))
2095 fs.fsCsb[0] = 1L << i;
2097 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
2099 csi.ciCharset = DEFAULT_CHARSET;
2100 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
2101 if(csi.ciCharset != DEFAULT_CHARSET) {
2102 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
2105 strcpyW(elf.elfScript, ElfScriptsW[i]);
2107 FIXME("Unknown elfscript for bit %d\n", i);
2110 TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2111 debugstr_w(elf.elfLogFont.lfFaceName),
2112 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2113 csi.ciCharset, type, debugstr_w(elf.elfScript),
2114 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
2115 ntm.ntmTm.ntmFlags);
2116 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
2125 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
2127 pt->x.value = vec->x >> 6;
2128 pt->x.fract = (vec->x & 0x3f) << 10;
2129 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
2130 pt->y.value = vec->y >> 6;
2131 pt->y.fract = (vec->y & 0x3f) << 10;
2132 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
2136 static FT_UInt get_glyph_index(GdiFont font, UINT glyph)
2138 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
2139 glyph = glyph + 0xf000;
2140 return pFT_Get_Char_Index(font->ft_face, glyph);
2143 /*************************************************************
2144 * WineEngGetGlyphIndices
2146 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
2148 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
2149 LPWORD pgi, DWORD flags)
2153 for(i = 0; i < count; i++)
2154 pgi[i] = get_glyph_index(font, lpstr[i]);
2159 /*************************************************************
2160 * WineEngGetGlyphOutline
2162 * Behaves in exactly the same way as the win32 api GetGlyphOutline
2163 * except that the first parameter is the HWINEENGFONT of the font in
2164 * question rather than an HDC.
2167 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
2168 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
2171 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
2172 FT_Face ft_face = font->ft_face;
2173 FT_UInt glyph_index;
2174 DWORD width, height, pitch, needed = 0;
2175 FT_Bitmap ft_bitmap;
2177 INT left, right, top = 0, bottom = 0;
2179 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
2180 float widthRatio = 1.0;
2181 FT_Matrix transMat = identityMat;
2182 BOOL needsTransform = FALSE;
2185 TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font, glyph, format, lpgm,
2186 buflen, buf, lpmat);
2188 if(format & GGO_GLYPH_INDEX) {
2189 glyph_index = glyph;
2190 format &= ~GGO_GLYPH_INDEX;
2192 glyph_index = get_glyph_index(font, glyph);
2194 if(glyph_index >= font->gmsize) {
2195 font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
2196 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
2197 font->gmsize * sizeof(*font->gm));
2199 if(format == GGO_METRICS && font->gm[glyph_index].init) {
2200 memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
2201 return 1; /* FIXME */
2205 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP) || font->aveWidth || lpmat)
2206 load_flags |= FT_LOAD_NO_BITMAP;
2208 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
2211 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
2215 /* Scaling factor */
2216 if (font->aveWidth && font->potm) {
2217 widthRatio = (float)font->aveWidth * font->font_desc.matrix.eM11 / (float) font->potm->otmTextMetrics.tmAveCharWidth;
2220 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
2221 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
2223 font->gm[glyph_index].adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
2224 font->gm[glyph_index].lsb = left >> 6;
2225 font->gm[glyph_index].bbx = (right - left) >> 6;
2227 /* Scaling transform */
2228 if(font->aveWidth) {
2230 scaleMat.xx = FT_FixedFromFloat(widthRatio);
2233 scaleMat.yy = (1 << 16);
2235 pFT_Matrix_Multiply(&scaleMat, &transMat);
2236 needsTransform = TRUE;
2239 /* Rotation transform */
2240 if(font->orientation) {
2241 FT_Matrix rotationMat;
2243 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
2244 pFT_Vector_Unit(&vecAngle, angle);
2245 rotationMat.xx = vecAngle.x;
2246 rotationMat.xy = -vecAngle.y;
2247 rotationMat.yx = -rotationMat.xy;
2248 rotationMat.yy = rotationMat.xx;
2250 pFT_Matrix_Multiply(&rotationMat, &transMat);
2251 needsTransform = TRUE;
2254 /* Extra transformation specified by caller */
2257 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
2258 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
2259 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
2260 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
2261 pFT_Matrix_Multiply(&extraMat, &transMat);
2262 needsTransform = TRUE;
2265 if(!needsTransform) {
2266 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
2267 bottom = (ft_face->glyph->metrics.horiBearingY -
2268 ft_face->glyph->metrics.height) & -64;
2269 lpgm->gmCellIncX = font->gm[glyph_index].adv;
2270 lpgm->gmCellIncY = 0;
2274 for(xc = 0; xc < 2; xc++) {
2275 for(yc = 0; yc < 2; yc++) {
2276 vec.x = (ft_face->glyph->metrics.horiBearingX +
2277 xc * ft_face->glyph->metrics.width);
2278 vec.y = ft_face->glyph->metrics.horiBearingY -
2279 yc * ft_face->glyph->metrics.height;
2280 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
2281 pFT_Vector_Transform(&vec, &transMat);
2282 if(xc == 0 && yc == 0) {
2283 left = right = vec.x;
2284 top = bottom = vec.y;
2286 if(vec.x < left) left = vec.x;
2287 else if(vec.x > right) right = vec.x;
2288 if(vec.y < bottom) bottom = vec.y;
2289 else if(vec.y > top) top = vec.y;
2294 right = (right + 63) & -64;
2295 bottom = bottom & -64;
2296 top = (top + 63) & -64;
2298 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
2299 vec.x = ft_face->glyph->metrics.horiAdvance;
2301 pFT_Vector_Transform(&vec, &transMat);
2302 lpgm->gmCellIncX = (vec.x+63) >> 6;
2303 lpgm->gmCellIncY = -((vec.y+63) >> 6);
2305 lpgm->gmBlackBoxX = (right - left) >> 6;
2306 lpgm->gmBlackBoxY = (top - bottom) >> 6;
2307 lpgm->gmptGlyphOrigin.x = left >> 6;
2308 lpgm->gmptGlyphOrigin.y = top >> 6;
2310 memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
2311 font->gm[glyph_index].init = TRUE;
2313 if(format == GGO_METRICS)
2314 return 1; /* FIXME */
2316 if (buf && !buflen){
2320 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP) {
2321 TRACE("loaded a bitmap\n");
2327 width = lpgm->gmBlackBoxX;
2328 height = lpgm->gmBlackBoxY;
2329 pitch = ((width + 31) >> 5) << 2;
2330 needed = pitch * height;
2332 if(!buf || !buflen) break;
2334 switch(ft_face->glyph->format) {
2335 case ft_glyph_format_bitmap:
2337 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
2338 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
2339 INT h = ft_face->glyph->bitmap.rows;
2341 memcpy(dst, src, w);
2342 src += ft_face->glyph->bitmap.pitch;
2348 case ft_glyph_format_outline:
2349 ft_bitmap.width = width;
2350 ft_bitmap.rows = height;
2351 ft_bitmap.pitch = pitch;
2352 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
2353 ft_bitmap.buffer = buf;
2355 if(needsTransform) {
2356 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
2359 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
2361 /* Note: FreeType will only set 'black' bits for us. */
2362 memset(buf, 0, needed);
2363 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
2367 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
2372 case GGO_GRAY2_BITMAP:
2373 case GGO_GRAY4_BITMAP:
2374 case GGO_GRAY8_BITMAP:
2375 case WINE_GGO_GRAY16_BITMAP:
2380 width = lpgm->gmBlackBoxX;
2381 height = lpgm->gmBlackBoxY;
2382 pitch = (width + 3) / 4 * 4;
2383 needed = pitch * height;
2385 if(!buf || !buflen) break;
2386 ft_bitmap.width = width;
2387 ft_bitmap.rows = height;
2388 ft_bitmap.pitch = pitch;
2389 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
2390 ft_bitmap.buffer = buf;
2392 if(needsTransform) {
2393 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
2396 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
2398 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
2400 if(format == GGO_GRAY2_BITMAP)
2402 else if(format == GGO_GRAY4_BITMAP)
2404 else if(format == GGO_GRAY8_BITMAP)
2406 else if(format == WINE_GGO_GRAY16_BITMAP)
2414 for(row = 0; row < height; row++) {
2416 for(col = 0; col < width; col++, ptr++) {
2417 *ptr = (*(unsigned int*)ptr * mult + 128) / 256;
2426 int contour, point = 0, first_pt;
2427 FT_Outline *outline = &ft_face->glyph->outline;
2428 TTPOLYGONHEADER *pph;
2430 DWORD pph_start, cpfx, type;
2432 if(buflen == 0) buf = NULL;
2434 if (needsTransform && buf) {
2435 pFT_Outline_Transform(outline, &transMat);
2438 for(contour = 0; contour < outline->n_contours; contour++) {
2440 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
2443 pph->dwType = TT_POLYGON_TYPE;
2444 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2446 needed += sizeof(*pph);
2448 while(point <= outline->contours[contour]) {
2449 ppc = (TTPOLYCURVE *)((char *)buf + needed);
2450 type = (outline->tags[point] & FT_Curve_Tag_On) ?
2451 TT_PRIM_LINE : TT_PRIM_QSPLINE;
2455 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2458 } while(point <= outline->contours[contour] &&
2459 (outline->tags[point] & FT_Curve_Tag_On) ==
2460 (outline->tags[point-1] & FT_Curve_Tag_On));
2461 /* At the end of a contour Windows adds the start point, but
2463 if(point > outline->contours[contour] &&
2464 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
2466 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
2468 } else if(point <= outline->contours[contour] &&
2469 outline->tags[point] & FT_Curve_Tag_On) {
2470 /* add closing pt for bezier */
2472 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2480 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2483 pph->cb = needed - pph_start;
2489 /* Convert the quadratic Beziers to cubic Beziers.
2490 The parametric eqn for a cubic Bezier is, from PLRM:
2491 r(t) = at^3 + bt^2 + ct + r0
2492 with the control points:
2497 A quadratic Beizer has the form:
2498 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
2500 So equating powers of t leads to:
2501 r1 = 2/3 p1 + 1/3 p0
2502 r2 = 2/3 p1 + 1/3 p2
2503 and of course r0 = p0, r3 = p2
2506 int contour, point = 0, first_pt;
2507 FT_Outline *outline = &ft_face->glyph->outline;
2508 TTPOLYGONHEADER *pph;
2510 DWORD pph_start, cpfx, type;
2511 FT_Vector cubic_control[4];
2512 if(buflen == 0) buf = NULL;
2514 if (needsTransform && buf) {
2515 pFT_Outline_Transform(outline, &transMat);
2518 for(contour = 0; contour < outline->n_contours; contour++) {
2520 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
2523 pph->dwType = TT_POLYGON_TYPE;
2524 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2526 needed += sizeof(*pph);
2528 while(point <= outline->contours[contour]) {
2529 ppc = (TTPOLYCURVE *)((char *)buf + needed);
2530 type = (outline->tags[point] & FT_Curve_Tag_On) ?
2531 TT_PRIM_LINE : TT_PRIM_CSPLINE;
2534 if(type == TT_PRIM_LINE) {
2536 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2540 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
2543 /* FIXME: Possible optimization in endpoint calculation
2544 if there are two consecutive curves */
2545 cubic_control[0] = outline->points[point-1];
2546 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
2547 cubic_control[0].x += outline->points[point].x + 1;
2548 cubic_control[0].y += outline->points[point].y + 1;
2549 cubic_control[0].x >>= 1;
2550 cubic_control[0].y >>= 1;
2552 if(point+1 > outline->contours[contour])
2553 cubic_control[3] = outline->points[first_pt];
2555 cubic_control[3] = outline->points[point+1];
2556 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
2557 cubic_control[3].x += outline->points[point].x + 1;
2558 cubic_control[3].y += outline->points[point].y + 1;
2559 cubic_control[3].x >>= 1;
2560 cubic_control[3].y >>= 1;
2563 /* r1 = 1/3 p0 + 2/3 p1
2564 r2 = 1/3 p2 + 2/3 p1 */
2565 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
2566 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
2567 cubic_control[2] = cubic_control[1];
2568 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
2569 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
2570 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
2571 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
2573 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
2574 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
2575 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
2580 } while(point <= outline->contours[contour] &&
2581 (outline->tags[point] & FT_Curve_Tag_On) ==
2582 (outline->tags[point-1] & FT_Curve_Tag_On));
2583 /* At the end of a contour Windows adds the start point,
2584 but only for Beziers and we've already done that.
2586 if(point <= outline->contours[contour] &&
2587 outline->tags[point] & FT_Curve_Tag_On) {
2588 /* This is the closing pt of a bezier, but we've already
2589 added it, so just inc point and carry on */
2596 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2599 pph->cb = needed - pph_start;
2605 FIXME("Unsupported format %d\n", format);
2611 static BOOL get_bitmap_text_metrics(GdiFont font)
2613 FT_Face ft_face = font->ft_face;
2614 #ifdef HAVE_FREETYPE_FTWINFNT_H
2615 FT_WinFNT_HeaderRec winfnt_header;
2617 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
2618 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
2619 font->potm->otmSize = size;
2621 #define TM font->potm->otmTextMetrics
2622 #ifdef HAVE_FREETYPE_FTWINFNT_H
2623 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
2625 TM.tmHeight = winfnt_header.pixel_height;
2626 TM.tmAscent = winfnt_header.ascent;
2627 TM.tmDescent = TM.tmHeight - TM.tmAscent;
2628 TM.tmInternalLeading = winfnt_header.internal_leading;
2629 TM.tmExternalLeading = winfnt_header.external_leading;
2630 TM.tmAveCharWidth = winfnt_header.avg_width;
2631 TM.tmMaxCharWidth = winfnt_header.max_width;
2632 TM.tmWeight = winfnt_header.weight;
2634 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
2635 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
2636 TM.tmFirstChar = winfnt_header.first_char;
2637 TM.tmLastChar = winfnt_header.last_char;
2638 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
2639 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
2640 TM.tmItalic = winfnt_header.italic;
2641 TM.tmUnderlined = font->underline;
2642 TM.tmStruckOut = font->strikeout;
2643 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
2644 TM.tmCharSet = winfnt_header.charset;
2649 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
2650 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
2651 TM.tmHeight = TM.tmAscent + TM.tmDescent;
2652 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
2653 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
2654 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
2655 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
2656 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
2658 TM.tmDigitizedAspectX = 96; /* FIXME */
2659 TM.tmDigitizedAspectY = 96; /* FIXME */
2661 TM.tmLastChar = 255;
2662 TM.tmDefaultChar = 32;
2663 TM.tmBreakChar = 32;
2664 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
2665 TM.tmUnderlined = font->underline;
2666 TM.tmStruckOut = font->strikeout;
2667 /* NB inverted meaning of TMPF_FIXED_PITCH */
2668 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
2669 TM.tmCharSet = font->charset;
2676 /*************************************************************
2677 * WineEngGetTextMetrics
2680 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
2683 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
2684 if(!get_bitmap_text_metrics(font))
2687 if(!font->potm) return FALSE;
2688 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
2690 if (font->aveWidth) {
2691 ptm->tmAveCharWidth = font->aveWidth * font->font_desc.matrix.eM11;
2697 /*************************************************************
2698 * WineEngGetOutlineTextMetrics
2701 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
2702 OUTLINETEXTMETRICW *potm)
2704 FT_Face ft_face = font->ft_face;
2705 UINT needed, lenfam, lensty, ret;
2707 TT_HoriHeader *pHori;
2708 TT_Postscript *pPost;
2709 FT_Fixed x_scale, y_scale;
2710 WCHAR *family_nameW, *style_nameW;
2711 static const WCHAR spaceW[] = {' ', '\0'};
2713 INT ascent, descent;
2715 TRACE("font=%p\n", font);
2717 if(!FT_IS_SCALABLE(ft_face))
2721 if(cbSize >= font->potm->otmSize)
2722 memcpy(potm, font->potm, font->potm->otmSize);
2723 return font->potm->otmSize;
2727 needed = sizeof(*potm);
2729 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
2730 family_nameW = strdupW(font->name);
2732 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
2734 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
2735 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
2736 style_nameW, lensty);
2738 /* These names should be read from the TT name table */
2740 /* length of otmpFamilyName */
2743 /* length of otmpFaceName */
2744 if(!strcasecmp(ft_face->style_name, "regular")) {
2745 needed += lenfam; /* just the family name */
2747 needed += lenfam + lensty; /* family + " " + style */
2750 /* length of otmpStyleName */
2753 /* length of otmpFullName */
2754 needed += lenfam + lensty;
2757 x_scale = ft_face->size->metrics.x_scale;
2758 y_scale = ft_face->size->metrics.y_scale;
2760 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2762 FIXME("Can't find OS/2 table - not TT font?\n");
2767 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2769 FIXME("Can't find HHEA table - not TT font?\n");
2774 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
2776 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",
2777 pOS2->usWinAscent, pOS2->usWinDescent,
2778 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
2779 ft_face->ascender, ft_face->descender, ft_face->height,
2780 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
2781 ft_face->bbox.yMax, ft_face->bbox.yMin);
2783 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
2784 font->potm->otmSize = needed;
2786 #define TM font->potm->otmTextMetrics
2788 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
2789 ascent = pHori->Ascender;
2790 descent = -pHori->Descender;
2792 ascent = pOS2->usWinAscent;
2793 descent = pOS2->usWinDescent;
2797 TM.tmAscent = font->yMax;
2798 TM.tmDescent = -font->yMin;
2799 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
2801 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
2802 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
2803 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
2804 - ft_face->units_per_EM, y_scale) + 32) >> 6;
2807 TM.tmHeight = TM.tmAscent + TM.tmDescent;
2810 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
2812 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
2813 ((ascent + descent) -
2814 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
2816 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
2817 if (TM.tmAveCharWidth == 0) {
2818 TM.tmAveCharWidth = 1;
2820 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
2821 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
2823 TM.tmDigitizedAspectX = 300;
2824 TM.tmDigitizedAspectY = 300;
2825 TM.tmFirstChar = pOS2->usFirstCharIndex;
2826 TM.tmLastChar = pOS2->usLastCharIndex;
2827 TM.tmDefaultChar = pOS2->usDefaultChar;
2828 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
2829 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
2830 TM.tmUnderlined = font->underline;
2831 TM.tmStruckOut = font->strikeout;
2833 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
2834 if(!FT_IS_FIXED_WIDTH(ft_face))
2835 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
2837 TM.tmPitchAndFamily = 0;
2839 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
2840 case PAN_FAMILY_SCRIPT:
2841 TM.tmPitchAndFamily |= FF_SCRIPT;
2843 case PAN_FAMILY_DECORATIVE:
2844 case PAN_FAMILY_PICTORIAL:
2845 TM.tmPitchAndFamily |= FF_DECORATIVE;
2847 case PAN_FAMILY_TEXT_DISPLAY:
2848 if(TM.tmPitchAndFamily == 0) /* fixed */
2849 TM.tmPitchAndFamily = FF_MODERN;
2851 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
2852 case PAN_SERIF_NORMAL_SANS:
2853 case PAN_SERIF_OBTUSE_SANS:
2854 case PAN_SERIF_PERP_SANS:
2855 TM.tmPitchAndFamily |= FF_SWISS;
2858 TM.tmPitchAndFamily |= FF_ROMAN;
2863 TM.tmPitchAndFamily |= FF_DONTCARE;
2866 if(FT_IS_SCALABLE(ft_face))
2867 TM.tmPitchAndFamily |= TMPF_VECTOR;
2868 if(FT_IS_SFNT(ft_face))
2869 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
2871 TM.tmCharSet = font->charset;
2874 font->potm->otmFiller = 0;
2875 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
2876 font->potm->otmfsSelection = pOS2->fsSelection;
2877 font->potm->otmfsType = pOS2->fsType;
2878 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
2879 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
2880 font->potm->otmItalicAngle = 0; /* POST table */
2881 font->potm->otmEMSquare = ft_face->units_per_EM;
2882 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
2883 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
2884 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
2885 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
2886 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
2887 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
2888 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
2889 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
2890 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
2891 font->potm->otmMacAscent = 0; /* where do these come from ? */
2892 font->potm->otmMacDescent = 0;
2893 font->potm->otmMacLineGap = 0;
2894 font->potm->otmusMinimumPPEM = 0; /* TT Header */
2895 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
2896 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
2897 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
2898 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
2899 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
2900 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
2901 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
2902 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
2903 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
2904 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
2906 font->potm->otmsUnderscoreSize = 0;
2907 font->potm->otmsUnderscorePosition = 0;
2909 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
2910 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
2913 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
2914 cp = (char*)font->potm + sizeof(*font->potm);
2915 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
2916 strcpyW((WCHAR*)cp, family_nameW);
2918 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
2919 strcpyW((WCHAR*)cp, style_nameW);
2921 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
2922 strcpyW((WCHAR*)cp, family_nameW);
2923 if(strcasecmp(ft_face->style_name, "regular")) {
2924 strcatW((WCHAR*)cp, spaceW);
2925 strcatW((WCHAR*)cp, style_nameW);
2926 cp += lenfam + lensty;
2929 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
2930 strcpyW((WCHAR*)cp, family_nameW);
2931 strcatW((WCHAR*)cp, spaceW);
2932 strcatW((WCHAR*)cp, style_nameW);
2935 if(potm && needed <= cbSize)
2936 memcpy(potm, font->potm, font->potm->otmSize);
2939 HeapFree(GetProcessHeap(), 0, style_nameW);
2940 HeapFree(GetProcessHeap(), 0, family_nameW);
2946 /*************************************************************
2947 * WineEngGetCharWidth
2950 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
2955 FT_UInt glyph_index;
2957 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
2959 for(c = firstChar; c <= lastChar; c++) {
2960 glyph_index = get_glyph_index(font, c);
2961 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
2962 &gm, 0, NULL, NULL);
2963 buffer[c - firstChar] = font->gm[glyph_index].adv;
2968 /*************************************************************
2969 * WineEngGetCharABCWidths
2972 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
2977 FT_UInt glyph_index;
2979 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
2981 if(!FT_IS_SCALABLE(font->ft_face))
2984 for(c = firstChar; c <= lastChar; c++) {
2985 glyph_index = get_glyph_index(font, c);
2986 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
2987 &gm, 0, NULL, NULL);
2988 buffer[c - firstChar].abcA = font->gm[glyph_index].lsb;
2989 buffer[c - firstChar].abcB = font->gm[glyph_index].bbx;
2990 buffer[c - firstChar].abcC = font->gm[glyph_index].adv - font->gm[glyph_index].lsb -
2991 font->gm[glyph_index].bbx;
2996 /*************************************************************
2997 * WineEngGetTextExtentPoint
3000 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
3006 FT_UInt glyph_index;
3008 TRACE("%p, %s, %d, %p\n", font, debugstr_wn(wstr, count), count,
3012 WineEngGetTextMetrics(font, &tm);
3013 size->cy = tm.tmHeight;
3015 for(idx = 0; idx < count; idx++) {
3016 glyph_index = get_glyph_index(font, wstr[idx]);
3017 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3018 &gm, 0, NULL, NULL);
3019 size->cx += font->gm[glyph_index].adv;
3021 TRACE("return %ld,%ld\n", size->cx, size->cy);
3025 /*************************************************************
3026 * WineEngGetTextExtentPointI
3029 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
3036 TRACE("%p, %p, %d, %p\n", font, indices, count, size);
3039 WineEngGetTextMetrics(font, &tm);
3040 size->cy = tm.tmHeight;
3042 for(idx = 0; idx < count; idx++) {
3043 WineEngGetGlyphOutline(font, indices[idx],
3044 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
3046 size->cx += font->gm[indices[idx]].adv;
3048 TRACE("return %ld,%ld\n", size->cx, size->cy);
3052 /*************************************************************
3053 * WineEngGetFontData
3056 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
3059 FT_Face ft_face = font->ft_face;
3063 TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
3064 font, table, offset, buf, cbData);
3066 if(!FT_IS_SFNT(ft_face))
3074 if(table) { /* MS tags differ in endidness from FT ones */
3075 table = table >> 24 | table << 24 |
3076 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
3079 /* If the FT_Load_Sfnt_Table function is there we'll use it */
3080 if(pFT_Load_Sfnt_Table)
3081 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
3082 else { /* Do it the hard way */
3083 TT_Face tt_face = (TT_Face) ft_face;
3084 SFNT_Interface *sfnt;
3085 if (FT_Version.major==2 && FT_Version.minor==0)
3088 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
3092 /* A field was added in the middle of the structure in 2.1.x */
3093 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
3095 err = sfnt->load_any(tt_face, table, offset, buf, &len);
3098 TRACE("Can't find table %08lx.\n", table);
3104 /*************************************************************
3105 * WineEngGetTextFace
3108 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
3111 lstrcpynW(str, font->name, count);
3112 return strlenW(font->name);
3114 return strlenW(font->name) + 1;
3117 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
3119 if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
3120 return font->charset;
3123 #else /* HAVE_FREETYPE */
3125 BOOL WineEngInit(void)
3129 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
3133 BOOL WineEngDestroyFontInstance(HFONT hfont)
3138 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3143 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
3144 LPWORD pgi, DWORD flags)
3149 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
3150 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
3153 ERR("called but we don't have FreeType\n");
3157 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
3159 ERR("called but we don't have FreeType\n");
3163 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
3164 OUTLINETEXTMETRICW *potm)
3166 ERR("called but we don't have FreeType\n");
3170 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
3173 ERR("called but we don't have FreeType\n");
3177 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
3180 ERR("called but we don't have FreeType\n");
3184 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
3187 ERR("called but we don't have FreeType\n");
3191 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
3194 ERR("called but we don't have FreeType\n");
3198 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
3201 ERR("called but we don't have FreeType\n");
3205 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
3207 ERR("called but we don't have FreeType\n");
3211 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3217 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3223 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
3226 return DEFAULT_CHARSET;
3229 #endif /* HAVE_FREETYPE */