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"
28 #ifdef HAVE_SYS_STAT_H
29 # include <sys/stat.h>
42 #include "gdi_private.h"
43 #include "wine/unicode.h"
44 #include "wine/debug.h"
45 #include "wine/list.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(font
);
51 #ifdef HAVE_FT2BUILD_H
54 #ifdef HAVE_FREETYPE_FREETYPE_H
55 #include <freetype/freetype.h>
57 #ifdef HAVE_FREETYPE_FTGLYPH_H
58 #include <freetype/ftglyph.h>
60 #ifdef HAVE_FREETYPE_TTTABLES_H
61 #include <freetype/tttables.h>
63 #ifdef HAVE_FREETYPE_FTSNAMES_H
64 #include <freetype/ftsnames.h>
66 # ifdef HAVE_FREETYPE_FTNAMES_H
67 # include <freetype/ftnames.h>
70 #ifdef HAVE_FREETYPE_TTNAMEID_H
71 #include <freetype/ttnameid.h>
73 #ifdef HAVE_FREETYPE_FTOUTLN_H
74 #include <freetype/ftoutln.h>
76 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
77 #include <freetype/internal/sfnt.h>
79 #ifdef HAVE_FREETYPE_FTTRIGON_H
80 #include <freetype/fttrigon.h>
82 #ifdef HAVE_FREETYPE_FTWINFNT_H
83 #include <freetype/ftwinfnt.h>
86 #ifndef SONAME_LIBFREETYPE
87 #define SONAME_LIBFREETYPE "libfreetype.so"
90 static FT_Library library
= 0;
97 static FT_Version_t FT_Version
;
98 static DWORD FT_SimpleVersion
;
100 static void *ft_handle
= NULL
;
102 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
103 MAKE_FUNCPTR(FT_Vector_Unit
);
104 MAKE_FUNCPTR(FT_Done_Face
);
105 MAKE_FUNCPTR(FT_Get_Char_Index
);
106 MAKE_FUNCPTR(FT_Get_Module
);
107 MAKE_FUNCPTR(FT_Get_Sfnt_Table
);
108 MAKE_FUNCPTR(FT_Init_FreeType
);
109 MAKE_FUNCPTR(FT_Load_Glyph
);
110 MAKE_FUNCPTR(FT_Matrix_Multiply
);
111 MAKE_FUNCPTR(FT_MulFix
);
112 MAKE_FUNCPTR(FT_New_Face
);
113 MAKE_FUNCPTR(FT_Outline_Get_Bitmap
);
114 MAKE_FUNCPTR(FT_Outline_Transform
);
115 MAKE_FUNCPTR(FT_Outline_Translate
);
116 MAKE_FUNCPTR(FT_Select_Charmap
);
117 MAKE_FUNCPTR(FT_Set_Pixel_Sizes
);
118 MAKE_FUNCPTR(FT_Vector_Transform
);
119 static void (*pFT_Library_Version
)(FT_Library
,FT_Int
*,FT_Int
*,FT_Int
*);
120 static FT_Error (*pFT_Load_Sfnt_Table
)(FT_Face
,FT_ULong
,FT_Long
,FT_Byte
*,FT_ULong
*);
121 static FT_ULong (*pFT_Get_First_Char
)(FT_Face
,FT_UInt
*);
122 #ifdef HAVE_FREETYPE_FTWINFNT_H
123 MAKE_FUNCPTR(FT_Get_WinFNT_Header
);
126 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
127 #include <fontconfig/fontconfig.h>
128 MAKE_FUNCPTR(FcConfigGetCurrent
);
129 MAKE_FUNCPTR(FcFontList
);
130 MAKE_FUNCPTR(FcFontSetDestroy
);
131 MAKE_FUNCPTR(FcInit
);
132 MAKE_FUNCPTR(FcObjectSetAdd
);
133 MAKE_FUNCPTR(FcObjectSetCreate
);
134 MAKE_FUNCPTR(FcObjectSetDestroy
);
135 MAKE_FUNCPTR(FcPatternCreate
);
136 MAKE_FUNCPTR(FcPatternDestroy
);
137 MAKE_FUNCPTR(FcPatternGet
);
138 #ifndef SONAME_LIBFONTCONFIG
139 #define SONAME_LIBFONTCONFIG "libfontconfig.so"
145 #ifndef ft_encoding_none
146 #define FT_ENCODING_NONE ft_encoding_none
148 #ifndef ft_encoding_ms_symbol
149 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
151 #ifndef ft_encoding_unicode
152 #define FT_ENCODING_UNICODE ft_encoding_unicode
154 #ifndef ft_encoding_apple_roman
155 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
158 #define GET_BE_WORD(ptr) MAKEWORD( ((BYTE *)(ptr))[1], ((BYTE *)(ptr))[0] )
160 /* This is bascially a copy of FT_Bitmap_Size with an extra element added */
167 FT_Short internal_leading
;
170 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
171 So to let this compile on older versions of FreeType we'll define the
172 new structure here. */
174 FT_Short height
, width
;
175 FT_Pos size
, x_ppem
, y_ppem
;
178 typedef struct tagFace
{
186 FONTSIGNATURE fs_links
;
187 FT_Fixed font_version
;
189 Bitmap_Size size
; /* set if face is a bitmap */
190 BOOL external
; /* TRUE if we should manually add this font to the registry */
191 struct tagFamily
*family
;
194 typedef struct tagFamily
{
202 INT adv
; /* These three hold to widths of the unrotated chars */
219 typedef struct tagHFONTLIST
{
244 struct list hfontlist
;
249 OUTLINETEXTMETRICW
*potm
;
252 struct list child_fonts
;
262 #define INIT_GM_SIZE 128
264 static struct list gdi_font_list
= LIST_INIT(gdi_font_list
);
265 static struct list unused_gdi_font_list
= LIST_INIT(unused_gdi_font_list
);
266 #define UNUSED_CACHE_SIZE 10
267 static struct list child_font_list
= LIST_INIT(child_font_list
);
268 static struct list system_links
= LIST_INIT(system_links
);
270 static struct list font_list
= LIST_INIT(font_list
);
272 static const WCHAR defSerif
[] = {'T','i','m','e','s',' ','N','e','w',' ',
273 'R','o','m','a','n','\0'};
274 static const WCHAR defSans
[] = {'A','r','i','a','l','\0'};
275 static const WCHAR defFixed
[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
277 static const WCHAR defSystem
[] = {'A','r','i','a','l','\0'};
278 static const WCHAR SystemW
[] = {'S','y','s','t','e','m','\0'};
279 static const WCHAR MSSansSerifW
[] = {'M','S',' ','S','a','n','s',' ',
280 'S','e','r','i','f','\0'};
281 static const WCHAR HelvW
[] = {'H','e','l','v','\0'};
282 static const WCHAR RegularW
[] = {'R','e','g','u','l','a','r','\0'};
284 static const WCHAR fontsW
[] = {'\\','F','o','n','t','s','\0'};
285 static const WCHAR win9x_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
286 'W','i','n','d','o','w','s','\\',
287 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
288 'F','o','n','t','s','\0'};
290 static const WCHAR winnt_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
291 'W','i','n','d','o','w','s',' ','N','T','\\',
292 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
293 'F','o','n','t','s','\0'};
295 static const WCHAR system_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
296 static const WCHAR FixedSys_Value
[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
297 static const WCHAR System_Value
[] = {'F','O','N','T','S','.','F','O','N','\0'};
298 static const WCHAR OEMFont_Value
[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
300 static const WCHAR
*SystemFontValues
[4] = {
307 static const WCHAR external_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
308 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
310 static const WCHAR ArabicW
[] = {'A','r','a','b','i','c','\0'};
311 static const WCHAR BalticW
[] = {'B','a','l','t','i','c','\0'};
312 static const WCHAR CHINESE_BIG5W
[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
313 static const WCHAR CHINESE_GB2312W
[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
314 static const WCHAR Central_EuropeanW
[] = {'C','e','n','t','r','a','l',' ',
315 'E','u','r','o','p','e','a','n','\0'};
316 static const WCHAR CyrillicW
[] = {'C','y','r','i','l','l','i','c','\0'};
317 static const WCHAR GreekW
[] = {'G','r','e','e','k','\0'};
318 static const WCHAR HangulW
[] = {'H','a','n','g','u','l','\0'};
319 static const WCHAR Hangul_Johab_W
[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
320 static const WCHAR HebrewW
[] = {'H','e','b','r','e','w','\0'};
321 static const WCHAR JapaneseW
[] = {'J','a','p','a','n','e','s','e','\0'};
322 static const WCHAR SymbolW
[] = {'S','y','m','b','o','l','\0'};
323 static const WCHAR ThaiW
[] = {'T','h','a','i','\0'};
324 static const WCHAR TurkishW
[] = {'T','u','r','k','i','s','h','\0'};
325 static const WCHAR VietnameseW
[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
326 static const WCHAR WesternW
[] = {'W','e','s','t','e','r','n','\0'};
327 static const WCHAR OEM_DOSW
[] = {'O','E','M','/','D','O','S','\0'};
329 static const WCHAR
*ElfScriptsW
[32] = { /* these are in the order of the fsCsb[0] bits */
339 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, /*15*/
347 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
356 typedef struct tagFontSubst
{
359 struct tagFontSubst
*next
;
362 static FontSubst
*substlist
= NULL
;
363 static BOOL have_installed_roman_font
= FALSE
; /* CreateFontInstance will fail if this is still FALSE */
365 static const WCHAR font_mutex_nameW
[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
368 /****************************************
369 * Notes on .fon files
371 * The fonts System, FixedSys and Terminal are special. There are typically multiple
372 * versions installed for different resolutions and codepages. Windows stores which one to use
373 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
375 * FIXEDFON.FON FixedSys
377 * OEMFONT.FON Terminal
378 * LogPixels Current dpi set by the display control panel applet
379 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
380 * also has a LogPixels value that appears to mirror this)
382 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
383 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
384 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
385 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
386 * so that makes sense.
388 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
389 * to be mapped into the registry on Windows 2000 at least).
392 * ega80woa.fon=ega80850.fon
393 * ega40woa.fon=ega40850.fon
394 * cga80woa.fon=cga80850.fon
395 * cga40woa.fon=cga40850.fon
399 static inline BOOL
is_win9x(void)
401 return GetVersion() & 0x80000000;
404 This function builds an FT_Fixed from a float. It puts the integer part
405 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
406 It fails if the integer part of the float number is greater than SHORT_MAX.
408 static inline FT_Fixed
FT_FixedFromFloat(float f
)
411 unsigned short fract
= (f
- value
) * 0xFFFF;
412 return (FT_Fixed
)((long)value
<< 16 | (unsigned long)fract
);
416 This function builds an FT_Fixed from a FIXED. It simply put f.value
417 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
419 static inline FT_Fixed
FT_FixedFromFIXED(FIXED f
)
421 return (FT_Fixed
)((long)f
.value
<< 16 | (unsigned long)f
.fract
);
424 #define ADDFONT_EXTERNAL_FONT 0x01
425 #define ADDFONT_FORCE_BITMAP 0x02
426 static BOOL
AddFontFileToList(const char *file
, char *fake_family
, DWORD flags
)
430 TT_Header
*pHeader
= NULL
;
431 WCHAR
*FamilyW
, *StyleW
;
435 struct list
*family_elem_ptr
, *face_elem_ptr
;
437 FT_Long face_index
= 0, num_faces
;
438 #ifdef HAVE_FREETYPE_FTWINFNT_H
439 FT_WinFNT_HeaderRec winfnt_header
;
441 int i
, bitmap_num
, internal_leading
;
445 char *family_name
= fake_family
;
447 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
448 if((err
= pFT_New_Face(library
, file
, face_index
, &ft_face
)) != 0) {
449 WARN("Unable to load font file %s err = %x\n", debugstr_a(file
), err
);
453 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*/
454 WARN("Ignoring font %s\n", debugstr_a(file
));
455 pFT_Done_Face(ft_face
);
459 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
460 if(!FT_IS_SCALABLE(ft_face
) && FT_SimpleVersion
< ((2 << 16) | (1 << 8) | (9 << 0))) {
461 WARN("FreeType version < 2.1.9, skipping bitmap font %s\n", debugstr_a(file
));
462 pFT_Done_Face(ft_face
);
466 if(FT_IS_SFNT(ft_face
) && (!pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
) ||
467 !pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
) ||
468 !(pHeader
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_head
)))) {
469 TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
470 "Skipping this font.\n", debugstr_a(file
));
471 pFT_Done_Face(ft_face
);
475 if(!ft_face
->family_name
|| !ft_face
->style_name
) {
476 TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file
));
477 pFT_Done_Face(ft_face
);
482 family_name
= ft_face
->family_name
;
486 My_FT_Bitmap_Size
*size
= NULL
;
488 if(!FT_IS_SCALABLE(ft_face
))
489 size
= (My_FT_Bitmap_Size
*)ft_face
->available_sizes
+ bitmap_num
;
491 len
= MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, NULL
, 0);
492 FamilyW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
493 MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, FamilyW
, len
);
496 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
497 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
498 if(!strcmpW(family
->FamilyName
, FamilyW
))
503 family
= HeapAlloc(GetProcessHeap(), 0, sizeof(*family
));
504 family
->FamilyName
= FamilyW
;
505 list_init(&family
->faces
);
506 list_add_tail(&font_list
, &family
->entry
);
508 HeapFree(GetProcessHeap(), 0, FamilyW
);
511 len
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0);
512 StyleW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
513 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, StyleW
, len
);
515 internal_leading
= 0;
516 memset(&fs
, 0, sizeof(fs
));
518 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
520 fs
.fsCsb
[0] = pOS2
->ulCodePageRange1
;
521 fs
.fsCsb
[1] = pOS2
->ulCodePageRange2
;
522 fs
.fsUsb
[0] = pOS2
->ulUnicodeRange1
;
523 fs
.fsUsb
[1] = pOS2
->ulUnicodeRange2
;
524 fs
.fsUsb
[2] = pOS2
->ulUnicodeRange3
;
525 fs
.fsUsb
[3] = pOS2
->ulUnicodeRange4
;
526 if(pOS2
->version
== 0) {
529 if(!pFT_Get_First_Char
|| (pFT_Get_First_Char( ft_face
, &dummy
) < 0x100))
532 fs
.fsCsb
[0] |= 1L << 31;
535 #ifdef HAVE_FREETYPE_FTWINFNT_H
536 else if(pFT_Get_WinFNT_Header
&& !pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
)) {
538 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header
.pixel_height
, winfnt_header
.charset
,
539 winfnt_header
.vertical_resolution
,winfnt_header
.horizontal_resolution
, winfnt_header
.nominal_point_size
);
540 if(TranslateCharsetInfo((DWORD
*)(UINT
)winfnt_header
.charset
, &csi
, TCI_SRCCHARSET
))
541 memcpy(&fs
, &csi
.fs
, sizeof(csi
.fs
));
542 internal_leading
= winfnt_header
.internal_leading
;
546 face_elem_ptr
= list_head(&family
->faces
);
547 while(face_elem_ptr
) {
548 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
549 face_elem_ptr
= list_next(&family
->faces
, face_elem_ptr
);
550 if(!strcmpW(face
->StyleName
, StyleW
) &&
551 (FT_IS_SCALABLE(ft_face
) || ((size
->y_ppem
== face
->size
.y_ppem
) && !memcmp(&fs
, &face
->fs
, sizeof(fs
)) ))) {
552 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
553 debugstr_w(family
->FamilyName
), debugstr_w(StyleW
),
554 face
->font_version
, pHeader
? pHeader
->Font_Revision
: 0);
557 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
558 HeapFree(GetProcessHeap(), 0, StyleW
);
559 pFT_Done_Face(ft_face
);
562 if(!pHeader
|| pHeader
->Font_Revision
<= face
->font_version
) {
563 TRACE("Original font is newer so skipping this one\n");
564 HeapFree(GetProcessHeap(), 0, StyleW
);
565 pFT_Done_Face(ft_face
);
568 TRACE("Replacing original with this one\n");
569 list_remove(&face
->entry
);
570 HeapFree(GetProcessHeap(), 0, face
->file
);
571 HeapFree(GetProcessHeap(), 0, face
->StyleName
);
572 HeapFree(GetProcessHeap(), 0, face
);
577 face
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
));
578 list_add_tail(&family
->faces
, &face
->entry
);
579 face
->StyleName
= StyleW
;
580 face
->file
= HeapAlloc(GetProcessHeap(),0,strlen(file
)+1);
581 strcpy(face
->file
, file
);
582 face
->face_index
= face_index
;
583 face
->Italic
= (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 1 : 0;
584 face
->Bold
= (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
) ? 1 : 0;
585 face
->font_version
= pHeader
? pHeader
->Font_Revision
: 0;
586 face
->family
= family
;
587 face
->external
= (flags
& ADDFONT_EXTERNAL_FONT
) ? TRUE
: FALSE
;
588 memcpy(&face
->fs
, &fs
, sizeof(face
->fs
));
589 memset(&face
->fs_links
, 0, sizeof(face
->fs_links
));
591 if(FT_IS_SCALABLE(ft_face
)) {
592 memset(&face
->size
, 0, sizeof(face
->size
));
593 face
->scalable
= TRUE
;
595 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
596 size
->height
, size
->width
, size
->size
>> 6,
597 size
->x_ppem
>> 6, size
->y_ppem
>> 6);
598 face
->size
.height
= size
->height
;
599 face
->size
.width
= size
->width
;
600 face
->size
.size
= size
->size
;
601 face
->size
.x_ppem
= size
->x_ppem
;
602 face
->size
.y_ppem
= size
->y_ppem
;
603 face
->size
.internal_leading
= internal_leading
;
604 face
->scalable
= FALSE
;
607 TRACE("fsCsb = %08lx %08lx/%08lx %08lx %08lx %08lx\n",
608 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
609 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
610 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
613 if(face
->fs
.fsCsb
[0] == 0) { /* let's see if we can find any interesting cmaps */
614 for(i
= 0; i
< ft_face
->num_charmaps
; i
++) {
615 switch(ft_face
->charmaps
[i
]->encoding
) {
616 case FT_ENCODING_UNICODE
:
617 case FT_ENCODING_APPLE_ROMAN
:
618 face
->fs
.fsCsb
[0] |= 1;
620 case FT_ENCODING_MS_SYMBOL
:
621 face
->fs
.fsCsb
[0] |= 1L << 31;
629 if(face
->fs
.fsCsb
[0] & ~(1L << 31))
630 have_installed_roman_font
= TRUE
;
631 } while(!FT_IS_SCALABLE(ft_face
) && ++bitmap_num
< ft_face
->num_fixed_sizes
);
633 num_faces
= ft_face
->num_faces
;
634 pFT_Done_Face(ft_face
);
635 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
),
637 } while(num_faces
> ++face_index
);
641 static void DumpFontList(void)
645 struct list
*family_elem_ptr
, *face_elem_ptr
;
647 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
648 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
649 TRACE("Family: %s\n", debugstr_w(family
->FamilyName
));
650 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
651 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
652 TRACE("\t%s\t%08lx", debugstr_w(face
->StyleName
), face
->fs
.fsCsb
[0]);
654 TRACE(" %ld", face
->size
.y_ppem
>> 6);
661 static Face
*find_face_from_filename(const WCHAR
*name
)
666 DWORD len
= WideCharToMultiByte(CP_UNIXCP
, 0, name
, -1, NULL
, 0, NULL
, NULL
);
667 char *nameA
= HeapAlloc(GetProcessHeap(), 0, len
);
670 WideCharToMultiByte(CP_UNIXCP
, 0, name
, -1, nameA
, len
, NULL
, NULL
);
671 TRACE("looking for %s\n", debugstr_a(nameA
));
673 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
675 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
677 file
= strrchr(face
->file
, '/');
682 if(!strcmp(file
, nameA
))
687 HeapFree(GetProcessHeap(), 0, nameA
);
691 static Family
*find_family_from_name(const WCHAR
*name
)
695 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
697 if(!strcmpiW(family
->FamilyName
, name
))
704 static void DumpSubstList(void)
708 for(psub
= substlist
; psub
; psub
= psub
->next
)
709 if(psub
->from
.charset
!= -1 || psub
->to
.charset
!= -1)
710 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub
->from
.name
),
711 psub
->from
.charset
, debugstr_w(psub
->to
.name
), psub
->to
.charset
);
713 TRACE("%s -> %s\n", debugstr_w(psub
->from
.name
),
714 debugstr_w(psub
->to
.name
));
718 static LPWSTR
strdupW(LPCWSTR p
)
721 DWORD len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
722 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
727 static LPSTR
strdupA(LPCSTR p
)
730 DWORD len
= (strlen(p
) + 1);
731 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
736 static void split_subst_info(NameCs
*nc
, LPSTR str
)
738 CHAR
*p
= strrchr(str
, ',');
743 nc
->charset
= strtol(p
+1, NULL
, 10);
746 len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, NULL
, 0);
747 nc
->name
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
748 MultiByteToWideChar(CP_ACP
, 0, str
, -1, nc
->name
, len
);
751 static void LoadSubstList(void)
753 FontSubst
*psub
, **ppsub
;
755 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
760 for(psub
= substlist
; psub
;) {
762 HeapFree(GetProcessHeap(), 0, psub
->to
.name
);
763 HeapFree(GetProcessHeap(), 0, psub
->from
.name
);
766 HeapFree(GetProcessHeap(), 0, ptmp
);
771 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
772 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
773 &hkey
) == ERROR_SUCCESS
) {
775 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
776 &valuelen
, &datalen
, NULL
, NULL
);
778 valuelen
++; /* returned value doesn't include room for '\0' */
779 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
780 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
785 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
786 &dlen
) == ERROR_SUCCESS
) {
787 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
789 *ppsub
= HeapAlloc(GetProcessHeap(), 0, sizeof(**ppsub
));
790 (*ppsub
)->next
= NULL
;
791 split_subst_info(&((*ppsub
)->from
), value
);
792 split_subst_info(&((*ppsub
)->to
), data
);
794 /* Win 2000 doesn't allow mapping between different charsets
795 or mapping of DEFAULT_CHARSET */
796 if(((*ppsub
)->to
.charset
!= (*ppsub
)->from
.charset
) ||
797 (*ppsub
)->to
.charset
== DEFAULT_CHARSET
) {
798 HeapFree(GetProcessHeap(), 0, (*ppsub
)->to
.name
);
799 HeapFree(GetProcessHeap(), 0, (*ppsub
)->from
.name
);
800 HeapFree(GetProcessHeap(), 0, *ppsub
);
803 ppsub
= &((*ppsub
)->next
);
805 /* reset dlen and vlen */
809 HeapFree(GetProcessHeap(), 0, data
);
810 HeapFree(GetProcessHeap(), 0, value
);
815 /***********************************************************
816 * The replacement list is a way to map an entire font
817 * family onto another family. For example adding
819 * [HKCU\Software\Wine\Fonts\Replacements]
820 * "Wingdings"="Winedings"
822 * would enumerate the Winedings font both as Winedings and
823 * Wingdings. However if a real Wingdings font is present the
824 * replacement does not take place.
827 static void LoadReplaceList(void)
830 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
835 struct list
*family_elem_ptr
, *face_elem_ptr
;
836 WCHAR old_nameW
[200];
838 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
839 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts\\Replacements", &hkey
) == ERROR_SUCCESS
)
841 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
842 &valuelen
, &datalen
, NULL
, NULL
);
844 valuelen
++; /* returned value doesn't include room for '\0' */
845 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
846 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
850 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
851 &dlen
) == ERROR_SUCCESS
) {
852 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
853 /* "NewName"="Oldname" */
854 if(!MultiByteToWideChar(CP_ACP
, 0, data
, -1, old_nameW
, sizeof(old_nameW
)/sizeof(WCHAR
)))
857 /* Find the old family and hence all of the font files
859 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
860 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
861 if(!strcmpiW(family
->FamilyName
, old_nameW
)) {
862 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
863 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
864 TRACE("mapping %s %s to %s\n", debugstr_w(family
->FamilyName
),
865 debugstr_w(face
->StyleName
), value
);
866 /* Now add a new entry with the new family name */
867 AddFontFileToList(face
->file
, value
, ADDFONT_FORCE_BITMAP
| (face
->external
? ADDFONT_EXTERNAL_FONT
: 0));
872 /* reset dlen and vlen */
876 HeapFree(GetProcessHeap(), 0, data
);
877 HeapFree(GetProcessHeap(), 0, value
);
882 /*************************************************************
885 static BOOL
init_system_links(void)
887 static const WCHAR system_link
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
888 'W','i','n','d','o','w','s',' ','N','T','\\',
889 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
890 'S','y','s','t','e','m','L','i','n','k',0};
893 DWORD type
, max_val
, max_data
, val_len
, data_len
, index
;
896 SYSTEM_LINKS
*font_link
, *system_font_link
;
897 CHILD_FONT
*child_font
;
898 static const WCHAR Tahoma
[] = {'T','a','h','o','m','a',0};
899 static const WCHAR tahoma_ttf
[] = {'t','a','h','o','m','a','.','t','t','f',0};
900 static const WCHAR System
[] = {'S','y','s','t','e','m',0};
905 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, system_link
, &hkey
) == ERROR_SUCCESS
)
907 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &max_val
, &max_data
, NULL
, NULL
);
908 value
= HeapAlloc(GetProcessHeap(), 0, (max_val
+ 1) * sizeof(WCHAR
));
909 data
= HeapAlloc(GetProcessHeap(), 0, max_data
);
910 val_len
= max_val
+ 1;
913 while(RegEnumValueW(hkey
, index
++, value
, &val_len
, NULL
, &type
, (LPBYTE
)data
, &data_len
) == ERROR_SUCCESS
)
915 TRACE("%s:\n", debugstr_w(value
));
917 memset(&fs
, 0, sizeof(fs
));
918 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
919 font_link
->font_name
= strdupW(value
);
920 list_init(&font_link
->links
);
921 for(entry
= data
; (char*)entry
< (char*)data
+ data_len
&& *entry
!= 0; entry
= next
)
925 CHILD_FONT
*child_font
;
927 TRACE("\t%s\n", debugstr_w(entry
));
929 next
= entry
+ strlenW(entry
) + 1;
931 face_name
= strchrW(entry
, ',');
936 FIXME("don't yet handle ttc's correctly in linking. Assuming index 0\n");
938 while(isspaceW(*face_name
))
943 face
= find_face_from_filename(entry
);
946 TRACE("Unable to find file %s\n", debugstr_w(entry
));
950 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
951 child_font
->file_name
= strdupA(face
->file
);
952 child_font
->index
= index
;
953 child_font
->font
= NULL
;
954 fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
955 fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
956 list_add_tail(&font_link
->links
, &child_font
->entry
);
958 family
= find_family_from_name(font_link
->font_name
);
961 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
963 memcpy(&face
->fs_links
, &fs
, sizeof(fs
));
966 list_add_tail(&system_links
, &font_link
->entry
);
967 val_len
= max_val
+ 1;
971 HeapFree(GetProcessHeap(), 0, value
);
972 HeapFree(GetProcessHeap(), 0, data
);
976 /* Explicitly add an entry for the system font, this links to Tahoma and any links
979 system_font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link
));
980 system_font_link
->font_name
= strdupW(System
);
981 list_init(&system_font_link
->links
);
983 face
= find_face_from_filename(tahoma_ttf
);
986 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
987 child_font
->file_name
= strdupA(face
->file
);
988 child_font
->index
= 0;
989 child_font
->font
= NULL
;
990 list_add_tail(&system_font_link
->links
, &child_font
->entry
);
992 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
994 if(!strcmpiW(font_link
->font_name
, Tahoma
))
996 CHILD_FONT
*font_link_entry
;
997 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
999 CHILD_FONT
*new_child
;
1000 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
1001 new_child
->file_name
= strdupA(font_link_entry
->file_name
);
1002 new_child
->index
= font_link_entry
->index
;
1003 new_child
->font
= NULL
;
1004 list_add_tail(&system_font_link
->links
, &new_child
->entry
);
1009 list_add_tail(&system_links
, &system_font_link
->entry
);
1013 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
1016 struct dirent
*dent
;
1017 char path
[MAX_PATH
];
1019 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
1021 dir
= opendir(dirname
);
1023 ERR("Can't open directory %s\n", debugstr_a(dirname
));
1026 while((dent
= readdir(dir
)) != NULL
) {
1027 struct stat statbuf
;
1029 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
1032 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
1034 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
1036 if(stat(path
, &statbuf
) == -1)
1038 WARN("Can't stat %s\n", debugstr_a(path
));
1041 if(S_ISDIR(statbuf
.st_mode
))
1042 ReadFontDir(path
, external_fonts
);
1044 AddFontFileToList(path
, NULL
, external_fonts
? ADDFONT_EXTERNAL_FONT
: 0);
1050 static void load_fontconfig_fonts(void)
1052 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
1053 void *fc_handle
= NULL
;
1060 const char *file
, *ext
;
1062 fc_handle
= wine_dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
, NULL
, 0);
1064 TRACE("Wine cannot find the fontconfig library (%s).\n",
1065 SONAME_LIBFONTCONFIG
);
1068 #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;}
1069 LOAD_FUNCPTR(FcConfigGetCurrent
);
1070 LOAD_FUNCPTR(FcFontList
);
1071 LOAD_FUNCPTR(FcFontSetDestroy
);
1072 LOAD_FUNCPTR(FcInit
);
1073 LOAD_FUNCPTR(FcObjectSetAdd
);
1074 LOAD_FUNCPTR(FcObjectSetCreate
);
1075 LOAD_FUNCPTR(FcObjectSetDestroy
);
1076 LOAD_FUNCPTR(FcPatternCreate
);
1077 LOAD_FUNCPTR(FcPatternDestroy
);
1078 LOAD_FUNCPTR(FcPatternGet
);
1081 if(!pFcInit()) return;
1083 config
= pFcConfigGetCurrent();
1084 pat
= pFcPatternCreate();
1085 os
= pFcObjectSetCreate();
1086 pFcObjectSetAdd(os
, FC_FILE
);
1087 fontset
= pFcFontList(config
, pat
, os
);
1088 if(!fontset
) return;
1089 for(i
= 0; i
< fontset
->nfont
; i
++) {
1090 if(pFcPatternGet(fontset
->fonts
[i
], FC_FILE
, 0, &v
) != FcResultMatch
)
1092 if(v
.type
!= FcTypeString
) continue;
1093 file
= (LPCSTR
) v
.u
.s
;
1094 TRACE("fontconfig: %s\n", file
);
1096 /* We're just interested in OT/TT fonts for now, so this hack just
1097 picks up the standard extensions to save time loading every other
1099 len
= strlen( file
);
1100 if(len
< 4) continue;
1101 ext
= &file
[ len
- 3 ];
1102 if(!strcasecmp(ext
, "ttf") || !strcasecmp(ext
, "ttc") || !strcasecmp(ext
, "otf"))
1103 AddFontFileToList(file
, NULL
, ADDFONT_EXTERNAL_FONT
);
1105 pFcFontSetDestroy(fontset
);
1106 pFcObjectSetDestroy(os
);
1107 pFcPatternDestroy(pat
);
1114 static void load_system_fonts(void)
1117 WCHAR data
[MAX_PATH
], windowsdir
[MAX_PATH
], pathW
[MAX_PATH
];
1118 const WCHAR
**value
;
1120 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
1123 if(RegOpenKeyW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, &hkey
) == ERROR_SUCCESS
) {
1124 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
1125 strcatW(windowsdir
, fontsW
);
1126 for(value
= SystemFontValues
; *value
; value
++) {
1127 dlen
= sizeof(data
);
1128 if(RegQueryValueExW(hkey
, *value
, 0, &type
, (void*)data
, &dlen
) == ERROR_SUCCESS
&&
1130 sprintfW(pathW
, fmtW
, windowsdir
, data
);
1131 if((unixname
= wine_get_unix_file_name(pathW
))) {
1132 AddFontFileToList(unixname
, NULL
, ADDFONT_FORCE_BITMAP
);
1133 HeapFree(GetProcessHeap(), 0, unixname
);
1141 /*************************************************************
1143 * This adds registry entries for any externally loaded fonts
1144 * (fonts from fontconfig or FontDirs). It also deletes entries
1145 * of no longer existing fonts.
1148 static void update_reg_entries(void)
1150 HKEY winkey
= 0, externalkey
= 0;
1153 DWORD dlen
, vlen
, datalen
, valuelen
, i
, type
, len
, len_fam
;
1156 struct list
*family_elem_ptr
, *face_elem_ptr
;
1158 static const WCHAR TrueType
[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1159 static const WCHAR spaceW
[] = {' ', '\0'};
1162 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
1163 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winkey
, NULL
) != ERROR_SUCCESS
) {
1164 ERR("Can't create Windows font reg key\n");
1167 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1168 if(RegCreateKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
, &externalkey
) != ERROR_SUCCESS
) {
1169 ERR("Can't create external font reg key\n");
1173 /* Delete all external fonts added last time */
1175 RegQueryInfoKeyW(externalkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1176 &valuelen
, &datalen
, NULL
, NULL
);
1177 valuelen
++; /* returned value doesn't include room for '\0' */
1178 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
1179 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
1181 dlen
= datalen
* sizeof(WCHAR
);
1184 while(RegEnumValueW(externalkey
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
1185 &dlen
) == ERROR_SUCCESS
) {
1187 RegDeleteValueW(winkey
, valueW
);
1188 /* reset dlen and vlen */
1192 HeapFree(GetProcessHeap(), 0, data
);
1193 HeapFree(GetProcessHeap(), 0, valueW
);
1195 /* Delete the old external fonts key */
1196 RegCloseKey(externalkey
);
1198 RegDeleteKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
);
1200 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1201 if(RegCreateKeyExW(HKEY_CURRENT_USER
, external_fonts_reg_key
,
1202 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &externalkey
, NULL
) != ERROR_SUCCESS
) {
1203 ERR("Can't create external font reg key\n");
1207 /* enumerate the fonts and add external ones to the two keys */
1209 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1210 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1211 len_fam
= strlenW(family
->FamilyName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
1212 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1213 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1214 if(!face
->external
) continue;
1216 if(strcmpiW(face
->StyleName
, RegularW
))
1217 len
= len_fam
+ strlenW(face
->StyleName
) + 1;
1218 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1219 strcpyW(valueW
, family
->FamilyName
);
1220 if(len
!= len_fam
) {
1221 strcatW(valueW
, spaceW
);
1222 strcatW(valueW
, face
->StyleName
);
1224 strcatW(valueW
, TrueType
);
1225 if((path
= strrchr(face
->file
, '/')) == NULL
)
1229 len
= MultiByteToWideChar(CP_ACP
, 0, path
, -1, NULL
, 0);
1231 file
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1232 MultiByteToWideChar(CP_ACP
, 0, path
, -1, file
, len
);
1233 RegSetValueExW(winkey
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
1234 RegSetValueExW(externalkey
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
1236 HeapFree(GetProcessHeap(), 0, file
);
1237 HeapFree(GetProcessHeap(), 0, valueW
);
1242 RegCloseKey(externalkey
);
1244 RegCloseKey(winkey
);
1249 /*************************************************************
1250 * WineEngAddFontResourceEx
1253 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
1255 if (ft_handle
) /* do it only if we have freetype up and running */
1260 FIXME("Ignoring flags %lx\n", flags
);
1262 if((unixname
= wine_get_unix_file_name(file
)))
1264 AddFontFileToList(unixname
, NULL
, ADDFONT_FORCE_BITMAP
);
1265 HeapFree(GetProcessHeap(), 0, unixname
);
1271 /*************************************************************
1272 * WineEngRemoveFontResourceEx
1275 BOOL
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
1281 static const struct nls_update_font_list
1283 UINT ansi_cp
, oem_cp
;
1284 const char *oem
, *fixed
, *system
;
1285 const char *courier
, *serif
, *small
, *sserif
;
1286 } nls_update_font_list
[] =
1288 /* Latin 1 (United States) */
1289 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
1290 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1292 /* Latin 1 (Multilingual) */
1293 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
1294 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1296 /* Eastern Europe */
1297 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
1298 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
1301 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
1302 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
1305 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
1306 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
1309 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
1310 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
1313 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
1314 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
1317 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
1318 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
1321 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
1322 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
1325 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
1326 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1329 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
1330 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
1333 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
1334 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
1336 /* Chinese Simplified */
1337 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
1338 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1341 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
1342 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1344 /* Chinese Traditional */
1345 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
1346 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1350 inline static HKEY
create_fonts_NT_registry_key(void)
1354 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
, 0, NULL
,
1355 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
1359 inline static HKEY
create_fonts_9x_registry_key(void)
1363 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
, 0, NULL
,
1364 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
1368 inline static HKEY
create_config_fonts_registry_key(void)
1372 RegCreateKeyExW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, 0, NULL
,
1373 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
1377 static void add_font_list(HKEY hkey
, const struct nls_update_font_list
*fl
)
1379 RegSetValueExA(hkey
, "Courier", 0, REG_SZ
, (const BYTE
*)fl
->courier
, strlen(fl
->courier
)+1);
1380 RegSetValueExA(hkey
, "MS Serif", 0, REG_SZ
, (const BYTE
*)fl
->serif
, strlen(fl
->serif
)+1);
1381 RegSetValueExA(hkey
, "MS Sans Serif", 0, REG_SZ
, (const BYTE
*)fl
->sserif
, strlen(fl
->sserif
)+1);
1382 RegSetValueExA(hkey
, "Small Fonts", 0, REG_SZ
, (const BYTE
*)fl
->small
, strlen(fl
->small
)+1);
1385 static void update_font_info(void)
1390 UINT i
, ansi_cp
= 0, oem_cp
= 0;
1391 LCID lcid
= GetUserDefaultLCID();
1393 if (RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", &hkey
) != ERROR_SUCCESS
)
1397 if (RegQueryValueExA(hkey
, "Locale", 0, &type
, (BYTE
*)buf
, &len
) == ERROR_SUCCESS
&& type
== REG_SZ
)
1399 if (strtoul(buf
, NULL
, 16 ) == lcid
) /* already set correctly */
1404 TRACE("updating registry, locale changed %s -> %08lx\n", debugstr_a(buf
), lcid
);
1406 else TRACE("updating registry, locale changed none -> %08lx\n", lcid
);
1408 sprintf(buf
, "%08lx", lcid
);
1409 RegSetValueExA(hkey
, "Locale", 0, REG_SZ
, (const BYTE
*)buf
, strlen(buf
)+1);
1412 GetLocaleInfoW(lcid
, LOCALE_IDEFAULTANSICODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
1413 (WCHAR
*)&ansi_cp
, sizeof(ansi_cp
)/sizeof(WCHAR
));
1414 GetLocaleInfoW(lcid
, LOCALE_IDEFAULTCODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
1415 (WCHAR
*)&oem_cp
, sizeof(oem_cp
)/sizeof(WCHAR
));
1417 for (i
= 0; i
< sizeof(nls_update_font_list
)/sizeof(nls_update_font_list
[0]); i
++)
1419 if (nls_update_font_list
[i
].ansi_cp
== ansi_cp
&&
1420 nls_update_font_list
[i
].oem_cp
== oem_cp
)
1424 hkey
= create_config_fonts_registry_key();
1425 RegSetValueExA(hkey
, "OEMFONT.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].oem
, strlen(nls_update_font_list
[i
].oem
)+1);
1426 RegSetValueExA(hkey
, "FIXED.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].fixed
, strlen(nls_update_font_list
[i
].fixed
)+1);
1427 RegSetValueExA(hkey
, "FONTS.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].system
, strlen(nls_update_font_list
[i
].system
)+1);
1430 hkey
= create_fonts_NT_registry_key();
1431 add_font_list(hkey
, &nls_update_font_list
[i
]);
1434 hkey
= create_fonts_9x_registry_key();
1435 add_font_list(hkey
, &nls_update_font_list
[i
]);
1441 FIXME("there is no font defaults for lcid %04lx/ansi_cp %u", lcid
, ansi_cp
);
1444 /*************************************************************
1447 * Initialize FreeType library and create a list of available faces
1449 BOOL
WineEngInit(void)
1451 static const WCHAR dot_fonW
[] = {'.','f','o','n','\0'};
1452 static const WCHAR pathW
[] = {'P','a','t','h',0};
1454 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1456 WCHAR windowsdir
[MAX_PATH
];
1462 /* update locale dependent font info in registry */
1465 ft_handle
= wine_dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
, NULL
, 0);
1468 "Wine cannot find the FreeType font library. To enable Wine to\n"
1469 "use TrueType fonts please install a version of FreeType greater than\n"
1470 "or equal to 2.0.5.\n"
1471 "http://www.freetype.org\n");
1475 #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;}
1477 LOAD_FUNCPTR(FT_Vector_Unit
)
1478 LOAD_FUNCPTR(FT_Done_Face
)
1479 LOAD_FUNCPTR(FT_Get_Char_Index
)
1480 LOAD_FUNCPTR(FT_Get_Module
)
1481 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
1482 LOAD_FUNCPTR(FT_Init_FreeType
)
1483 LOAD_FUNCPTR(FT_Load_Glyph
)
1484 LOAD_FUNCPTR(FT_Matrix_Multiply
)
1485 LOAD_FUNCPTR(FT_MulFix
)
1486 LOAD_FUNCPTR(FT_New_Face
)
1487 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
1488 LOAD_FUNCPTR(FT_Outline_Transform
)
1489 LOAD_FUNCPTR(FT_Outline_Translate
)
1490 LOAD_FUNCPTR(FT_Select_Charmap
)
1491 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
1492 LOAD_FUNCPTR(FT_Vector_Transform
)
1495 /* Don't warn if this one is missing */
1496 pFT_Library_Version
= wine_dlsym(ft_handle
, "FT_Library_Version", NULL
, 0);
1497 pFT_Load_Sfnt_Table
= wine_dlsym(ft_handle
, "FT_Load_Sfnt_Table", NULL
, 0);
1498 pFT_Get_First_Char
= wine_dlsym(ft_handle
, "FT_Get_First_Char", NULL
, 0);
1499 #ifdef HAVE_FREETYPE_FTWINFNT_H
1500 pFT_Get_WinFNT_Header
= wine_dlsym(ft_handle
, "FT_Get_WinFNT_Header", NULL
, 0);
1502 if(!wine_dlsym(ft_handle
, "FT_Get_Postscript_Name", NULL
, 0) &&
1503 !wine_dlsym(ft_handle
, "FT_Sqrt64", NULL
, 0)) {
1504 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
1505 <= 2.0.3 has FT_Sqrt64 */
1509 if(pFT_Init_FreeType(&library
) != 0) {
1510 ERR("Can't init FreeType library\n");
1511 wine_dlclose(ft_handle
, NULL
, 0);
1515 FT_Version
.major
=FT_Version
.minor
=FT_Version
.patch
=-1;
1516 if (pFT_Library_Version
)
1518 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
1520 if (FT_Version
.major
<=0)
1526 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
1527 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
1528 ((FT_Version
.minor
<< 8) & 0x00ff00) |
1529 ((FT_Version
.patch
) & 0x0000ff);
1531 if((font_mutex
= CreateMutexW(NULL
, FALSE
, font_mutex_nameW
)) == NULL
) {
1532 ERR("Failed to create font mutex\n");
1535 WaitForSingleObject(font_mutex
, INFINITE
);
1537 /* load the system fonts */
1538 load_system_fonts();
1540 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
1541 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
1542 strcatW(windowsdir
, fontsW
);
1543 if((unixname
= wine_get_unix_file_name(windowsdir
)))
1545 ReadFontDir(unixname
, FALSE
);
1546 HeapFree(GetProcessHeap(), 0, unixname
);
1549 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
1550 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
1551 full path as the entry. Also look for any .fon fonts, since ReadFontDir
1553 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
,
1554 is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
1555 &hkey
) == ERROR_SUCCESS
) {
1557 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1558 &valuelen
, &datalen
, NULL
, NULL
);
1560 valuelen
++; /* returned value doesn't include room for '\0' */
1561 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
1562 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
1565 dlen
= datalen
* sizeof(WCHAR
);
1567 while(RegEnumValueW(hkey
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
1568 &dlen
) == ERROR_SUCCESS
) {
1569 if(((LPWSTR
)data
)[0] && ((LPWSTR
)data
)[1] == ':')
1571 if((unixname
= wine_get_unix_file_name((LPWSTR
)data
)))
1573 AddFontFileToList(unixname
, NULL
, ADDFONT_FORCE_BITMAP
);
1574 HeapFree(GetProcessHeap(), 0, unixname
);
1577 else if(dlen
/ 2 >= 6 && !strcmpiW(((LPWSTR
)data
) + dlen
/ 2 - 5, dot_fonW
))
1579 WCHAR pathW
[MAX_PATH
];
1580 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
1581 sprintfW(pathW
, fmtW
, windowsdir
, data
);
1582 if((unixname
= wine_get_unix_file_name(pathW
)))
1584 AddFontFileToList(unixname
, NULL
, ADDFONT_FORCE_BITMAP
);
1585 HeapFree(GetProcessHeap(), 0, unixname
);
1588 /* reset dlen and vlen */
1593 HeapFree(GetProcessHeap(), 0, data
);
1594 HeapFree(GetProcessHeap(), 0, valueW
);
1598 load_fontconfig_fonts();
1600 /* then look in any directories that we've specified in the config file */
1601 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
1602 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", &hkey
) == ERROR_SUCCESS
)
1608 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
)
1610 len
+= sizeof(WCHAR
);
1611 valueW
= HeapAlloc( GetProcessHeap(), 0, len
);
1612 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, (LPBYTE
)valueW
, &len
) == ERROR_SUCCESS
)
1614 len
= WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, NULL
, 0, NULL
, NULL
);
1615 valueA
= HeapAlloc( GetProcessHeap(), 0, len
);
1616 WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, valueA
, len
, NULL
, NULL
);
1617 TRACE( "got font path %s\n", debugstr_a(valueA
) );
1621 LPSTR next
= strchr( ptr
, ':' );
1622 if (next
) *next
++ = 0;
1623 ReadFontDir( ptr
, TRUE
);
1626 HeapFree( GetProcessHeap(), 0, valueA
);
1628 HeapFree( GetProcessHeap(), 0, valueW
);
1637 update_reg_entries();
1639 init_system_links();
1641 ReleaseMutex(font_mutex
);
1645 "Wine cannot find certain functions that it needs inside the FreeType\n"
1646 "font library. To enable Wine to use TrueType fonts please upgrade\n"
1647 "FreeType to at least version 2.0.5.\n"
1648 "http://www.freetype.org\n");
1649 wine_dlclose(ft_handle
, NULL
, 0);
1655 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
1658 TT_HoriHeader
*pHori
;
1662 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
1663 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
1665 if(height
== 0) height
= 16;
1667 /* Calc. height of EM square:
1669 * For +ve lfHeight we have
1670 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
1671 * Re-arranging gives:
1672 * ppem = units_per_em * lfheight / (winAscent + winDescent)
1674 * For -ve lfHeight we have
1676 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
1677 * with il = winAscent + winDescent - units_per_em]
1682 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0)
1683 ppem
= ft_face
->units_per_EM
* height
/
1684 (pHori
->Ascender
- pHori
->Descender
);
1686 ppem
= ft_face
->units_per_EM
* height
/
1687 (pOS2
->usWinAscent
+ pOS2
->usWinDescent
);
1695 static LONG
load_VDMX(GdiFont
, LONG
);
1697 static FT_Face
OpenFontFile(GdiFont font
, char *file
, FT_Long face_index
, LONG width
, LONG height
)
1702 TRACE("%s, %ld, %ld x %ld\n", debugstr_a(file
), face_index
, width
, height
);
1703 err
= pFT_New_Face(library
, file
, face_index
, &ft_face
);
1705 ERR("FT_New_Face rets %d\n", err
);
1709 /* set it here, as load_VDMX needs it */
1710 font
->ft_face
= ft_face
;
1712 if(FT_IS_SCALABLE(ft_face
)) {
1713 /* load the VDMX table if we have one */
1714 font
->ppem
= load_VDMX(font
, height
);
1716 font
->ppem
= calc_ppem_for_height(ft_face
, height
);
1718 if((err
= pFT_Set_Pixel_Sizes(ft_face
, 0, font
->ppem
)) != 0)
1719 WARN("FT_Set_Pixel_Sizes %d, %ld rets %x\n", 0, font
->ppem
, err
);
1721 font
->ppem
= height
;
1722 if((err
= pFT_Set_Pixel_Sizes(ft_face
, width
, height
)) != 0)
1723 WARN("FT_Set_Pixel_Sizes %ld, %ld rets %x\n", width
, height
, err
);
1729 static int get_nearest_charset(Face
*face
, int *cp
)
1731 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
1732 a single face with the requested charset. The idea is to check if
1733 the selected font supports the current ANSI codepage, if it does
1734 return the corresponding charset, else return the first charset */
1737 int acp
= GetACP(), i
;
1741 if(TranslateCharsetInfo((DWORD
*)acp
, &csi
, TCI_SRCCODEPAGE
))
1742 if(csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
1743 return csi
.ciCharset
;
1745 for(i
= 0; i
< 32; i
++) {
1747 if(face
->fs
.fsCsb
[0] & fs0
) {
1748 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
)) {
1750 return csi
.ciCharset
;
1753 FIXME("TCI failing on %lx\n", fs0
);
1757 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08lx file = %s\n",
1758 face
->fs
.fsCsb
[0], face
->file
);
1760 return DEFAULT_CHARSET
;
1763 static GdiFont
alloc_font(void)
1765 GdiFont ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
1766 ret
->gmsize
= INIT_GM_SIZE
;
1767 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
1768 ret
->gmsize
* sizeof(*ret
->gm
));
1770 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
1771 list_init(&ret
->hfontlist
);
1772 list_init(&ret
->child_fonts
);
1776 static void free_font(GdiFont font
)
1778 struct list
*cursor
, *cursor2
;
1780 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &font
->child_fonts
)
1782 CHILD_FONT
*child
= LIST_ENTRY(cursor
, CHILD_FONT
, entry
);
1783 struct list
*first_hfont
;
1784 HFONTLIST
*hfontlist
;
1785 list_remove(cursor
);
1788 first_hfont
= list_head(&child
->font
->hfontlist
);
1789 hfontlist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
1790 DeleteObject(hfontlist
->hfont
);
1791 HeapFree(GetProcessHeap(), 0, hfontlist
);
1792 free_font(child
->font
);
1794 HeapFree(GetProcessHeap(), 0, child
->file_name
);
1795 HeapFree(GetProcessHeap(), 0, child
);
1798 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
1799 HeapFree(GetProcessHeap(), 0, font
->potm
);
1800 HeapFree(GetProcessHeap(), 0, font
->name
);
1801 HeapFree(GetProcessHeap(), 0, font
->gm
);
1802 HeapFree(GetProcessHeap(), 0, font
);
1806 /*************************************************************
1809 * load the vdmx entry for the specified height
1812 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
1813 ( ( (FT_ULong)_x4 << 24 ) | \
1814 ( (FT_ULong)_x3 << 16 ) | \
1815 ( (FT_ULong)_x2 << 8 ) | \
1818 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
1828 static LONG
load_VDMX(GdiFont font
, LONG height
)
1830 BYTE hdr
[6], tmp
[2], group
[4];
1831 BYTE devXRatio
, devYRatio
;
1832 USHORT numRecs
, numRatios
;
1833 DWORD result
, offset
= -1;
1837 /* For documentation on VDMX records, see
1838 * http://www.microsoft.com/OpenType/OTSpec/vdmx.htm
1841 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, 0, hdr
, 6);
1843 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
1846 /* FIXME: need the real device aspect ratio */
1850 numRecs
= GET_BE_WORD(&hdr
[2]);
1851 numRatios
= GET_BE_WORD(&hdr
[4]);
1853 TRACE("numRecs = %d numRatios = %d\n", numRecs
, numRatios
);
1854 for(i
= 0; i
< numRatios
; i
++) {
1857 offset
= (3 * 2) + (i
* sizeof(Ratios
));
1858 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
1861 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
1863 if((ratio
.xRatio
== 0 &&
1864 ratio
.yStartRatio
== 0 &&
1865 ratio
.yEndRatio
== 0) ||
1866 (devXRatio
== ratio
.xRatio
&&
1867 devYRatio
>= ratio
.yStartRatio
&&
1868 devYRatio
<= ratio
.yEndRatio
))
1870 offset
= (3 * 2) + (numRatios
* 4) + (i
* 2);
1871 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, tmp
, 2);
1872 offset
= GET_BE_WORD(tmp
);
1878 FIXME("No suitable ratio found\n");
1882 if(WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, group
, 4) != GDI_ERROR
) {
1884 BYTE startsz
, endsz
;
1887 recs
= GET_BE_WORD(group
);
1891 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
1893 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* 6);
1894 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, offset
+ 4, vTable
, recs
* 6);
1895 if(result
== GDI_ERROR
) {
1896 FIXME("Failed to retrieve vTable\n");
1901 for(i
= 0; i
< recs
; i
++) {
1902 SHORT yMax
= GET_BE_WORD(&vTable
[(i
* 6) + 2]);
1903 SHORT yMin
= GET_BE_WORD(&vTable
[(i
* 6) + 4]);
1904 ppem
= GET_BE_WORD(&vTable
[i
* 6]);
1906 if(yMax
+ -yMin
== height
) {
1909 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
1912 if(yMax
+ -yMin
> height
) {
1915 goto end
; /* failed */
1917 font
->yMax
= GET_BE_WORD(&vTable
[(i
* 6) + 2]);
1918 font
->yMin
= GET_BE_WORD(&vTable
[(i
* 6) + 4]);
1919 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
1925 TRACE("ppem not found for height %ld\n", height
);
1929 if(ppem
< startsz
|| ppem
> endsz
)
1932 for(i
= 0; i
< recs
; i
++) {
1934 yPelHeight
= GET_BE_WORD(&vTable
[i
* 6]);
1936 if(yPelHeight
> ppem
)
1939 if(yPelHeight
== ppem
) {
1940 font
->yMax
= GET_BE_WORD(&vTable
[(i
* 6) + 2]);
1941 font
->yMin
= GET_BE_WORD(&vTable
[(i
* 6) + 4]);
1942 TRACE("ppem %ld found; yMax=%d yMin=%d\n", ppem
, font
->yMax
, font
->yMin
);
1948 HeapFree(GetProcessHeap(), 0, vTable
);
1954 static BOOL
fontcmp(GdiFont font
, FONT_DESC
*fd
)
1956 if(font
->font_desc
.hash
!= fd
->hash
) return TRUE
;
1957 if(memcmp(&font
->font_desc
.matrix
, &fd
->matrix
, sizeof(fd
->matrix
))) return TRUE
;
1958 if(memcmp(&font
->font_desc
.lf
, &fd
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
1959 return strcmpiW(font
->font_desc
.lf
.lfFaceName
, fd
->lf
.lfFaceName
);
1962 static void calc_hash(FONT_DESC
*pfd
)
1964 DWORD hash
= 0, *ptr
, two_chars
;
1968 for(i
= 0, ptr
= (DWORD
*)&pfd
->matrix
; i
< sizeof(FMAT2
)/sizeof(DWORD
); i
++, ptr
++)
1970 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
; i
< 7; i
++, ptr
++)
1972 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
1974 pwc
= (WCHAR
*)&two_chars
;
1976 *pwc
= toupperW(*pwc
);
1978 *pwc
= toupperW(*pwc
);
1986 static GdiFont
find_in_cache(HFONT hfont
, LOGFONTW
*plf
, XFORM
*pxf
, BOOL can_use_bitmap
)
1991 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
1993 memcpy(&fd
.lf
, plf
, sizeof(LOGFONTW
));
1994 memcpy(&fd
.matrix
, pxf
, sizeof(FMAT2
));
1997 /* try the in-use list */
1998 LIST_FOR_EACH(font_elem_ptr
, &gdi_font_list
) {
1999 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
2000 if(!fontcmp(ret
, &fd
)) {
2001 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
2002 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
2003 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
2004 if(hflist
->hfont
== hfont
)
2007 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
2008 hflist
->hfont
= hfont
;
2009 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
2014 /* then the unused list */
2015 font_elem_ptr
= list_head(&unused_gdi_font_list
);
2016 while(font_elem_ptr
) {
2017 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
2018 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
2019 if(!fontcmp(ret
, &fd
)) {
2020 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
2021 assert(list_empty(&ret
->hfontlist
));
2022 TRACE("Found %p in unused list\n", ret
);
2023 list_remove(&ret
->entry
);
2024 list_add_head(&gdi_font_list
, &ret
->entry
);
2025 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
2026 hflist
->hfont
= hfont
;
2027 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
2035 /*************************************************************
2036 * create_child_font_list
2038 static BOOL
create_child_font_list(GdiFont font
)
2041 SYSTEM_LINKS
*font_link
;
2042 CHILD_FONT
*font_link_entry
, *new_child
;
2044 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
2046 if(!strcmpW(font_link
->font_name
, font
->name
))
2048 TRACE("found entry in system list\n");
2049 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
2051 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
2052 new_child
->file_name
= strdupA(font_link_entry
->file_name
);
2053 new_child
->index
= font_link_entry
->index
;
2054 new_child
->font
= NULL
;
2055 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
2056 TRACE("font %s %d\n", debugstr_a(new_child
->file_name
), new_child
->index
);
2066 /*************************************************************
2067 * WineEngCreateFontInstance
2070 GdiFont
WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
2074 Family
*family
, *last_resort_family
;
2075 struct list
*family_elem_ptr
, *face_elem_ptr
;
2076 INT height
, width
= 0;
2077 signed int diff
= 0, newdiff
;
2078 BOOL bd
, it
, can_use_bitmap
;
2083 LIST_FOR_EACH_ENTRY(ret
, &child_font_list
, struct tagGdiFont
, entry
)
2085 struct list
*first_hfont
= list_head(&ret
->hfontlist
);
2086 hflist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
2087 if(hflist
->hfont
== hfont
)
2091 if (!GetObjectW( hfont
, sizeof(lf
), &lf
)) return NULL
;
2092 can_use_bitmap
= GetDeviceCaps(dc
->hSelf
, TEXTCAPS
) & TC_RA_ABLE
;
2094 TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
2095 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
2096 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
2099 /* check the cache first */
2100 if((ret
= find_in_cache(hfont
, &lf
, &dc
->xformWorld2Vport
, can_use_bitmap
)) != NULL
) {
2101 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
2105 TRACE("not in cache\n");
2106 if(list_empty(&font_list
)) /* No fonts installed */
2108 TRACE("No fonts installed\n");
2111 if(!have_installed_roman_font
)
2113 TRACE("No roman font installed\n");
2119 memcpy(&ret
->font_desc
.matrix
, &dc
->xformWorld2Vport
, sizeof(FMAT2
));
2120 memcpy(&ret
->font_desc
.lf
, &lf
, sizeof(LOGFONTW
));
2121 calc_hash(&ret
->font_desc
);
2122 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
2123 hflist
->hfont
= hfont
;
2124 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
2127 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
2128 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
2129 original value lfCharSet. Note this is a special case for
2130 Symbol and doesn't happen at least for "Wingdings*" */
2132 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
2133 lf
.lfCharSet
= SYMBOL_CHARSET
;
2135 if(!TranslateCharsetInfo((DWORD
*)(INT
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
2136 switch(lf
.lfCharSet
) {
2137 case DEFAULT_CHARSET
:
2138 csi
.fs
.fsCsb
[0] = 0;
2141 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
2142 csi
.fs
.fsCsb
[0] = 0;
2148 if(lf
.lfFaceName
[0] != '\0') {
2150 for(psub
= substlist
; psub
; psub
= psub
->next
)
2151 if(!strcmpiW(lf
.lfFaceName
, psub
->from
.name
) &&
2152 (psub
->from
.charset
== -1 ||
2153 psub
->from
.charset
== lf
.lfCharSet
))
2156 TRACE("substituting %s -> %s\n", debugstr_w(lf
.lfFaceName
),
2157 debugstr_w(psub
->to
.name
));
2158 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
2161 /* We want a match on name and charset or just name if
2162 charset was DEFAULT_CHARSET. If the latter then
2163 we fixup the returned charset later in get_nearest_charset
2164 where we'll either use the charset of the current ansi codepage
2165 or if that's unavailable the first charset that the font supports.
2167 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
2168 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
2169 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
2170 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
2171 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2172 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])
2173 if(face
->scalable
|| can_use_bitmap
)
2180 /* If requested charset was DEFAULT_CHARSET then try using charset
2181 corresponding to the current ansi codepage */
2182 if(!csi
.fs
.fsCsb
[0]) {
2184 if(!TranslateCharsetInfo((DWORD
*)acp
, &csi
, TCI_SRCCODEPAGE
)) {
2185 FIXME("TCI failed on codepage %d\n", acp
);
2186 csi
.fs
.fsCsb
[0] = 0;
2188 lf
.lfCharSet
= csi
.ciCharset
;
2191 /* Face families are in the top 4 bits of lfPitchAndFamily,
2192 so mask with 0xF0 before testing */
2194 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
2195 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
2196 strcpyW(lf
.lfFaceName
, defFixed
);
2197 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
2198 strcpyW(lf
.lfFaceName
, defSerif
);
2199 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
2200 strcpyW(lf
.lfFaceName
, defSans
);
2202 strcpyW(lf
.lfFaceName
, defSans
);
2203 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
2204 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
2205 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
2206 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
2207 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2208 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))
2209 if(face
->scalable
|| can_use_bitmap
)
2215 last_resort_family
= NULL
;
2216 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
2217 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
2218 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
2219 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2220 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) {
2223 if(can_use_bitmap
&& !last_resort_family
)
2224 last_resort_family
= family
;
2229 if(last_resort_family
) {
2230 family
= last_resort_family
;
2231 csi
.fs
.fsCsb
[0] = 0;
2235 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
2236 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
2237 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
2238 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2239 if(face
->scalable
) {
2240 csi
.fs
.fsCsb
[0] = 0;
2241 FIXME("just using first face for now\n");
2244 if(can_use_bitmap
&& !last_resort_family
)
2245 last_resort_family
= family
;
2248 if(!last_resort_family
) {
2249 FIXME("can't find a single appropriate font - bailing\n");
2254 WARN("could only find a bitmap font - this will probably look awful!\n");
2255 family
= last_resort_family
;
2256 csi
.fs
.fsCsb
[0] = 0;
2259 it
= lf
.lfItalic
? 1 : 0;
2260 bd
= lf
.lfWeight
> 550 ? 1 : 0;
2262 height
= GDI_ROUND( (FLOAT
)lf
.lfHeight
* dc
->xformWorld2Vport
.eM22
);
2263 height
= lf
.lfHeight
< 0 ? -abs(height
) : abs(height
);
2266 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
2267 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2268 if(!(face
->Italic
^ it
) && !(face
->Bold
^ bd
) &&
2269 ((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])) {
2273 newdiff
= height
- (signed int)(face
->size
.y_ppem
>> 6);
2275 newdiff
= -height
- ((signed int)(face
->size
.y_ppem
>> 6) - face
->size
.internal_leading
);
2276 if(!best
|| (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) ||
2277 (diff
< 0 && newdiff
> diff
)) {
2278 TRACE("%ld is better for %d diff was %d\n", face
->size
.y_ppem
>> 6, height
, diff
);
2291 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
2292 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2293 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0]) {
2297 newdiff
= height
- (signed int)(face
->size
.y_ppem
>> 6);
2299 newdiff
= -height
- ((signed int)(face
->size
.y_ppem
>> 6) - face
->size
.internal_leading
);
2300 if(!best
|| (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) ||
2301 (diff
< 0 && newdiff
> diff
)) {
2302 TRACE("%ld is better for %d diff was %d\n", face
->size
.y_ppem
>> 6, height
, diff
);
2313 if(it
&& !face
->Italic
) ret
->fake_italic
= TRUE
;
2314 if(bd
&& !face
->Bold
) ret
->fake_bold
= TRUE
;
2317 memcpy(&ret
->fs
, &face
->fs
, sizeof(FONTSIGNATURE
));
2319 if(csi
.fs
.fsCsb
[0]) {
2320 ret
->charset
= lf
.lfCharSet
;
2321 ret
->codepage
= csi
.ciACP
;
2324 ret
->charset
= get_nearest_charset(face
, &ret
->codepage
);
2326 TRACE("Chosen: %s %s (%s:%ld)\n", debugstr_w(family
->FamilyName
),
2327 debugstr_w(face
->StyleName
), face
->file
, face
->face_index
);
2329 if(!face
->scalable
) {
2330 width
= face
->size
.x_ppem
>> 6;
2331 height
= face
->size
.y_ppem
>> 6;
2333 ret
->ft_face
= OpenFontFile(ret
, face
->file
, face
->face_index
, width
, height
);
2341 if (ret
->charset
== SYMBOL_CHARSET
&&
2342 !pFT_Select_Charmap(ret
->ft_face
, FT_ENCODING_MS_SYMBOL
)) {
2345 else if (!pFT_Select_Charmap(ret
->ft_face
, FT_ENCODING_UNICODE
)) {
2349 pFT_Select_Charmap(ret
->ft_face
, FT_ENCODING_APPLE_ROMAN
);
2352 ret
->orientation
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfOrientation
: 0;
2353 ret
->name
= strdupW(family
->FamilyName
);
2354 ret
->underline
= lf
.lfUnderline
? 0xff : 0;
2355 ret
->strikeout
= lf
.lfStrikeOut
? 0xff : 0;
2356 create_child_font_list(ret
);
2358 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
2360 ret
->aveWidth
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfWidth
: 0;
2361 list_add_head(&gdi_font_list
, &ret
->entry
);
2365 static void dump_gdi_font_list(void)
2368 struct list
*elem_ptr
;
2370 TRACE("---------- gdiFont Cache ----------\n");
2371 LIST_FOR_EACH(elem_ptr
, &gdi_font_list
) {
2372 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
2373 TRACE("gdiFont=%p %s %ld\n",
2374 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
2377 TRACE("---------- Unused gdiFont Cache ----------\n");
2378 LIST_FOR_EACH(elem_ptr
, &unused_gdi_font_list
) {
2379 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
2380 TRACE("gdiFont=%p %s %ld\n",
2381 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
2385 /*************************************************************
2386 * WineEngDestroyFontInstance
2388 * free the gdiFont associated with this handle
2391 BOOL
WineEngDestroyFontInstance(HFONT handle
)
2396 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
2399 LIST_FOR_EACH_ENTRY(gdiFont
, &child_font_list
, struct tagGdiFont
, entry
)
2401 struct list
*first_hfont
= list_head(&gdiFont
->hfontlist
);
2402 hflist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
2403 if(hflist
->hfont
== handle
)
2405 TRACE("removing child font %p from child list\n", gdiFont
);
2406 list_remove(&gdiFont
->entry
);
2411 TRACE("destroying hfont=%p\n", handle
);
2413 dump_gdi_font_list();
2415 font_elem_ptr
= list_head(&gdi_font_list
);
2416 while(font_elem_ptr
) {
2417 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
2418 font_elem_ptr
= list_next(&gdi_font_list
, font_elem_ptr
);
2420 hfontlist_elem_ptr
= list_head(&gdiFont
->hfontlist
);
2421 while(hfontlist_elem_ptr
) {
2422 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
2423 hfontlist_elem_ptr
= list_next(&gdiFont
->hfontlist
, hfontlist_elem_ptr
);
2424 if(hflist
->hfont
== handle
) {
2425 list_remove(&hflist
->entry
);
2426 HeapFree(GetProcessHeap(), 0, hflist
);
2430 if(list_empty(&gdiFont
->hfontlist
)) {
2431 TRACE("Moving to Unused list\n");
2432 list_remove(&gdiFont
->entry
);
2433 list_add_head(&unused_gdi_font_list
, &gdiFont
->entry
);
2438 font_elem_ptr
= list_head(&unused_gdi_font_list
);
2439 while(font_elem_ptr
&& i
++ < UNUSED_CACHE_SIZE
)
2440 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
2441 while(font_elem_ptr
) {
2442 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
2443 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
2444 TRACE("freeing %p\n", gdiFont
);
2445 list_remove(&gdiFont
->entry
);
2451 static void GetEnumStructs(Face
*face
, LPENUMLOGFONTEXW pelf
,
2452 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
2454 OUTLINETEXTMETRICW
*potm
= NULL
;
2456 TEXTMETRICW tm
, *ptm
;
2457 GdiFont font
= alloc_font();
2460 if(face
->scalable
) {
2464 height
= face
->size
.y_ppem
>> 6;
2465 width
= face
->size
.x_ppem
>> 6;
2468 if (!(font
->ft_face
= OpenFontFile(font
, face
->file
, face
->face_index
, width
, height
)))
2474 font
->name
= strdupW(face
->family
->FamilyName
);
2476 memset(&pelf
->elfLogFont
, 0, sizeof(LOGFONTW
));
2478 size
= WineEngGetOutlineTextMetrics(font
, 0, NULL
);
2480 potm
= HeapAlloc(GetProcessHeap(), 0, size
);
2481 WineEngGetOutlineTextMetrics(font
, size
, potm
);
2482 ptm
= (TEXTMETRICW
*)&potm
->otmTextMetrics
;
2484 WineEngGetTextMetrics(font
, &tm
);
2488 pntm
->ntmTm
.tmHeight
= pelf
->elfLogFont
.lfHeight
= ptm
->tmHeight
;
2489 pntm
->ntmTm
.tmAscent
= ptm
->tmAscent
;
2490 pntm
->ntmTm
.tmDescent
= ptm
->tmDescent
;
2491 pntm
->ntmTm
.tmInternalLeading
= ptm
->tmInternalLeading
;
2492 pntm
->ntmTm
.tmExternalLeading
= ptm
->tmExternalLeading
;
2493 pntm
->ntmTm
.tmAveCharWidth
= pelf
->elfLogFont
.lfWidth
= ptm
->tmAveCharWidth
;
2494 pntm
->ntmTm
.tmMaxCharWidth
= ptm
->tmMaxCharWidth
;
2495 pntm
->ntmTm
.tmWeight
= pelf
->elfLogFont
.lfWeight
= ptm
->tmWeight
;
2496 pntm
->ntmTm
.tmOverhang
= ptm
->tmOverhang
;
2497 pntm
->ntmTm
.tmDigitizedAspectX
= ptm
->tmDigitizedAspectX
;
2498 pntm
->ntmTm
.tmDigitizedAspectY
= ptm
->tmDigitizedAspectY
;
2499 pntm
->ntmTm
.tmFirstChar
= ptm
->tmFirstChar
;
2500 pntm
->ntmTm
.tmLastChar
= ptm
->tmLastChar
;
2501 pntm
->ntmTm
.tmDefaultChar
= ptm
->tmDefaultChar
;
2502 pntm
->ntmTm
.tmBreakChar
= ptm
->tmBreakChar
;
2503 pntm
->ntmTm
.tmItalic
= pelf
->elfLogFont
.lfItalic
= ptm
->tmItalic
;
2504 pntm
->ntmTm
.tmUnderlined
= pelf
->elfLogFont
.lfUnderline
= ptm
->tmUnderlined
;
2505 pntm
->ntmTm
.tmStruckOut
= pelf
->elfLogFont
.lfStrikeOut
= ptm
->tmStruckOut
;
2506 pntm
->ntmTm
.tmPitchAndFamily
= ptm
->tmPitchAndFamily
;
2507 pelf
->elfLogFont
.lfPitchAndFamily
= (ptm
->tmPitchAndFamily
& 0xf1) + 1;
2508 pntm
->ntmTm
.tmCharSet
= pelf
->elfLogFont
.lfCharSet
= ptm
->tmCharSet
;
2509 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
2510 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
2511 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
2513 *ptype
= ptm
->tmPitchAndFamily
& TMPF_TRUETYPE
? TRUETYPE_FONTTYPE
: 0;
2514 if(!(ptm
->tmPitchAndFamily
& TMPF_VECTOR
))
2515 *ptype
|= RASTER_FONTTYPE
;
2517 pntm
->ntmTm
.ntmFlags
= ptm
->tmItalic
? NTM_ITALIC
: 0;
2518 if(ptm
->tmWeight
> 550) pntm
->ntmTm
.ntmFlags
|= NTM_BOLD
;
2519 if(pntm
->ntmTm
.ntmFlags
== 0) pntm
->ntmTm
.ntmFlags
= NTM_REGULAR
;
2521 pntm
->ntmTm
.ntmCellHeight
= pntm
->ntmTm
.tmHeight
;
2522 pntm
->ntmTm
.ntmAvgWidth
= pntm
->ntmTm
.tmAveCharWidth
;
2523 memset(&pntm
->ntmFontSig
, 0, sizeof(FONTSIGNATURE
));
2526 pntm
->ntmTm
.ntmSizeEM
= potm
->otmEMSquare
;
2528 lstrcpynW(pelf
->elfLogFont
.lfFaceName
,
2529 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpFamilyName
),
2531 lstrcpynW(pelf
->elfFullName
,
2532 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpFaceName
),
2534 lstrcpynW(pelf
->elfStyle
,
2535 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpStyleName
),
2538 HeapFree(GetProcessHeap(), 0, potm
);
2540 pntm
->ntmTm
.ntmSizeEM
= pntm
->ntmTm
.tmHeight
- pntm
->ntmTm
.tmInternalLeading
;
2542 lstrcpynW(pelf
->elfLogFont
.lfFaceName
, face
->family
->FamilyName
, LF_FACESIZE
);
2543 lstrcpynW(pelf
->elfFullName
, face
->family
->FamilyName
, LF_FACESIZE
);
2544 pelf
->elfStyle
[0] = '\0';
2547 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
2552 /*************************************************************
2556 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
2560 struct list
*family_elem_ptr
, *face_elem_ptr
;
2562 NEWTEXTMETRICEXW ntm
;
2563 DWORD type
, ret
= 1;
2569 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
2571 if(plf
->lfFaceName
[0]) {
2573 for(psub
= substlist
; psub
; psub
= psub
->next
)
2574 if(!strcmpiW(plf
->lfFaceName
, psub
->from
.name
) &&
2575 (psub
->from
.charset
== -1 ||
2576 psub
->from
.charset
== plf
->lfCharSet
))
2579 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
2580 debugstr_w(psub
->to
.name
));
2581 memcpy(&lf
, plf
, sizeof(lf
));
2582 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
2586 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
2587 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
2588 if(!strcmpiW(plf
->lfFaceName
, family
->FamilyName
)) {
2589 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
2590 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2591 GetEnumStructs(face
, &elf
, &ntm
, &type
);
2592 for(i
= 0; i
< 32; i
++) {
2593 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
2594 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
2595 strcpyW(elf
.elfScript
, OEM_DOSW
);
2596 i
= 32; /* break out of loop */
2597 } else if(!(face
->fs
.fsCsb
[0] & (1L << i
)))
2600 fs
.fsCsb
[0] = 1L << i
;
2602 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
2604 csi
.ciCharset
= DEFAULT_CHARSET
;
2605 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
2606 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
2607 elf
.elfLogFont
.lfCharSet
=
2608 ntm
.ntmTm
.tmCharSet
= csi
.ciCharset
;
2610 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
2612 FIXME("Unknown elfscript for bit %d\n", i
);
2615 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2616 debugstr_w(elf
.elfLogFont
.lfFaceName
),
2617 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
2618 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
2619 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
2620 ntm
.ntmTm
.ntmFlags
);
2621 ret
= proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
);
2628 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
2629 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
2630 face_elem_ptr
= list_head(&family
->faces
);
2631 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2632 GetEnumStructs(face
, &elf
, &ntm
, &type
);
2633 for(i
= 0; i
< 32; i
++) {
2634 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
2635 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
2636 strcpyW(elf
.elfScript
, OEM_DOSW
);
2637 i
= 32; /* break out of loop */
2638 } else if(!(face
->fs
.fsCsb
[0] & (1L << i
)))
2641 fs
.fsCsb
[0] = 1L << i
;
2643 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
2645 csi
.ciCharset
= DEFAULT_CHARSET
;
2646 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
2647 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
2648 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
=
2651 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
2653 FIXME("Unknown elfscript for bit %d\n", i
);
2656 TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2657 debugstr_w(elf
.elfLogFont
.lfFaceName
),
2658 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
2659 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
2660 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
2661 ntm
.ntmTm
.ntmFlags
);
2662 ret
= proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
);
2671 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
2673 pt
->x
.value
= vec
->x
>> 6;
2674 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
2675 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
2676 pt
->y
.value
= vec
->y
>> 6;
2677 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
2678 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
2682 static FT_UInt
get_glyph_index(GdiFont font
, UINT glyph
)
2684 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
2685 WCHAR wc
= (WCHAR
)glyph
;
2689 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, &default_used
) || default_used
)
2692 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)buf
);
2693 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, buf
, ret
, default_used
);
2697 if(font
->charset
== SYMBOL_CHARSET
&& glyph
< 0x100)
2698 glyph
= glyph
+ 0xf000;
2699 return pFT_Get_Char_Index(font
->ft_face
, glyph
);
2702 /*************************************************************
2703 * WineEngGetGlyphIndices
2705 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
2707 DWORD
WineEngGetGlyphIndices(GdiFont font
, LPCWSTR lpstr
, INT count
,
2708 LPWORD pgi
, DWORD flags
)
2712 for(i
= 0; i
< count
; i
++)
2713 pgi
[i
] = get_glyph_index(font
, lpstr
[i
]);
2718 /*************************************************************
2719 * WineEngGetGlyphOutline
2721 * Behaves in exactly the same way as the win32 api GetGlyphOutline
2722 * except that the first parameter is the HWINEENGFONT of the font in
2723 * question rather than an HDC.
2726 DWORD
WineEngGetGlyphOutline(GdiFont font
, UINT glyph
, UINT format
,
2727 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
2730 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
2731 FT_Face ft_face
= font
->ft_face
;
2732 FT_UInt glyph_index
;
2733 DWORD width
, height
, pitch
, needed
= 0;
2734 FT_Bitmap ft_bitmap
;
2736 INT left
, right
, top
= 0, bottom
= 0;
2738 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
2739 float widthRatio
= 1.0;
2740 FT_Matrix transMat
= identityMat
;
2741 BOOL needsTransform
= FALSE
;
2744 TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font
, glyph
, format
, lpgm
,
2745 buflen
, buf
, lpmat
);
2747 if(format
& GGO_GLYPH_INDEX
) {
2748 glyph_index
= glyph
;
2749 format
&= ~GGO_GLYPH_INDEX
;
2751 glyph_index
= get_glyph_index(font
, glyph
);
2753 if(glyph_index
>= font
->gmsize
) {
2754 font
->gmsize
= (glyph_index
/ INIT_GM_SIZE
+ 1) * INIT_GM_SIZE
;
2755 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
2756 font
->gmsize
* sizeof(*font
->gm
));
2758 if(format
== GGO_METRICS
&& font
->gm
[glyph_index
].init
) {
2759 memcpy(lpgm
, &font
->gm
[glyph_index
].gm
, sizeof(*lpgm
));
2760 return 1; /* FIXME */
2764 if(font
->orientation
|| (format
!= GGO_METRICS
&& format
!= GGO_BITMAP
) || font
->aveWidth
|| lpmat
)
2765 load_flags
|= FT_LOAD_NO_BITMAP
;
2767 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
2770 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
2774 /* Scaling factor */
2775 if (font
->aveWidth
&& font
->potm
) {
2776 widthRatio
= (float)font
->aveWidth
* font
->font_desc
.matrix
.eM11
/ (float) font
->potm
->otmTextMetrics
.tmAveCharWidth
;
2779 left
= (INT
)(ft_face
->glyph
->metrics
.horiBearingX
* widthRatio
) & -64;
2780 right
= (INT
)((ft_face
->glyph
->metrics
.horiBearingX
+ ft_face
->glyph
->metrics
.width
) * widthRatio
+ 63) & -64;
2782 font
->gm
[glyph_index
].adv
= (INT
)((ft_face
->glyph
->metrics
.horiAdvance
* widthRatio
) + 63) >> 6;
2783 font
->gm
[glyph_index
].lsb
= left
>> 6;
2784 font
->gm
[glyph_index
].bbx
= (right
- left
) >> 6;
2786 /* Scaling transform */
2787 if(font
->aveWidth
) {
2789 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
2792 scaleMat
.yy
= (1 << 16);
2794 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
2795 needsTransform
= TRUE
;
2798 /* Rotation transform */
2799 if(font
->orientation
) {
2800 FT_Matrix rotationMat
;
2802 angle
= FT_FixedFromFloat((float)font
->orientation
/ 10.0);
2803 pFT_Vector_Unit(&vecAngle
, angle
);
2804 rotationMat
.xx
= vecAngle
.x
;
2805 rotationMat
.xy
= -vecAngle
.y
;
2806 rotationMat
.yx
= -rotationMat
.xy
;
2807 rotationMat
.yy
= rotationMat
.xx
;
2809 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
2810 needsTransform
= TRUE
;
2813 /* Extra transformation specified by caller */
2816 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
2817 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM21
);
2818 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM12
);
2819 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
2820 pFT_Matrix_Multiply(&extraMat
, &transMat
);
2821 needsTransform
= TRUE
;
2824 if(!needsTransform
) {
2825 top
= (ft_face
->glyph
->metrics
.horiBearingY
+ 63) & -64;
2826 bottom
= (ft_face
->glyph
->metrics
.horiBearingY
-
2827 ft_face
->glyph
->metrics
.height
) & -64;
2828 lpgm
->gmCellIncX
= font
->gm
[glyph_index
].adv
;
2829 lpgm
->gmCellIncY
= 0;
2833 for(xc
= 0; xc
< 2; xc
++) {
2834 for(yc
= 0; yc
< 2; yc
++) {
2835 vec
.x
= (ft_face
->glyph
->metrics
.horiBearingX
+
2836 xc
* ft_face
->glyph
->metrics
.width
);
2837 vec
.y
= ft_face
->glyph
->metrics
.horiBearingY
-
2838 yc
* ft_face
->glyph
->metrics
.height
;
2839 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
2840 pFT_Vector_Transform(&vec
, &transMat
);
2841 if(xc
== 0 && yc
== 0) {
2842 left
= right
= vec
.x
;
2843 top
= bottom
= vec
.y
;
2845 if(vec
.x
< left
) left
= vec
.x
;
2846 else if(vec
.x
> right
) right
= vec
.x
;
2847 if(vec
.y
< bottom
) bottom
= vec
.y
;
2848 else if(vec
.y
> top
) top
= vec
.y
;
2853 right
= (right
+ 63) & -64;
2854 bottom
= bottom
& -64;
2855 top
= (top
+ 63) & -64;
2857 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
2858 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
2860 pFT_Vector_Transform(&vec
, &transMat
);
2861 lpgm
->gmCellIncX
= (vec
.x
+63) >> 6;
2862 lpgm
->gmCellIncY
= -((vec
.y
+63) >> 6);
2864 lpgm
->gmBlackBoxX
= (right
- left
) >> 6;
2865 lpgm
->gmBlackBoxY
= (top
- bottom
) >> 6;
2866 lpgm
->gmptGlyphOrigin
.x
= left
>> 6;
2867 lpgm
->gmptGlyphOrigin
.y
= top
>> 6;
2869 memcpy(&font
->gm
[glyph_index
].gm
, lpgm
, sizeof(*lpgm
));
2870 font
->gm
[glyph_index
].init
= TRUE
;
2872 if(format
== GGO_METRICS
)
2873 return 1; /* FIXME */
2875 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&& format
!= GGO_BITMAP
) {
2876 TRACE("loaded a bitmap\n");
2882 width
= lpgm
->gmBlackBoxX
;
2883 height
= lpgm
->gmBlackBoxY
;
2884 pitch
= ((width
+ 31) >> 5) << 2;
2885 needed
= pitch
* height
;
2887 if(!buf
|| !buflen
) break;
2889 switch(ft_face
->glyph
->format
) {
2890 case ft_glyph_format_bitmap
:
2892 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
2893 INT w
= (ft_face
->glyph
->bitmap
.width
+ 7) >> 3;
2894 INT h
= ft_face
->glyph
->bitmap
.rows
;
2896 memcpy(dst
, src
, w
);
2897 src
+= ft_face
->glyph
->bitmap
.pitch
;
2903 case ft_glyph_format_outline
:
2904 ft_bitmap
.width
= width
;
2905 ft_bitmap
.rows
= height
;
2906 ft_bitmap
.pitch
= pitch
;
2907 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
2908 ft_bitmap
.buffer
= buf
;
2910 if(needsTransform
) {
2911 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
2914 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
2916 /* Note: FreeType will only set 'black' bits for us. */
2917 memset(buf
, 0, needed
);
2918 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
2922 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
2927 case GGO_GRAY2_BITMAP
:
2928 case GGO_GRAY4_BITMAP
:
2929 case GGO_GRAY8_BITMAP
:
2930 case WINE_GGO_GRAY16_BITMAP
:
2932 unsigned int mult
, row
, col
;
2935 width
= lpgm
->gmBlackBoxX
;
2936 height
= lpgm
->gmBlackBoxY
;
2937 pitch
= (width
+ 3) / 4 * 4;
2938 needed
= pitch
* height
;
2940 if(!buf
|| !buflen
) break;
2941 ft_bitmap
.width
= width
;
2942 ft_bitmap
.rows
= height
;
2943 ft_bitmap
.pitch
= pitch
;
2944 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
2945 ft_bitmap
.buffer
= buf
;
2947 if(needsTransform
) {
2948 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
2951 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
2953 memset(ft_bitmap
.buffer
, 0, buflen
);
2955 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
2957 if(format
== GGO_GRAY2_BITMAP
)
2959 else if(format
== GGO_GRAY4_BITMAP
)
2961 else if(format
== GGO_GRAY8_BITMAP
)
2963 else if(format
== WINE_GGO_GRAY16_BITMAP
)
2971 for(row
= 0; row
< height
; row
++) {
2973 for(col
= 0; col
< width
; col
++, ptr
++) {
2974 *ptr
= (((int)*ptr
) * mult
+ 128) / 256;
2983 int contour
, point
= 0, first_pt
;
2984 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
2985 TTPOLYGONHEADER
*pph
;
2987 DWORD pph_start
, cpfx
, type
;
2989 if(buflen
== 0) buf
= NULL
;
2991 if (needsTransform
&& buf
) {
2992 pFT_Outline_Transform(outline
, &transMat
);
2995 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
2997 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
3000 pph
->dwType
= TT_POLYGON_TYPE
;
3001 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
3003 needed
+= sizeof(*pph
);
3005 while(point
<= outline
->contours
[contour
]) {
3006 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
3007 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
3008 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
3012 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
3015 } while(point
<= outline
->contours
[contour
] &&
3016 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
3017 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
3018 /* At the end of a contour Windows adds the start point, but
3020 if(point
> outline
->contours
[contour
] &&
3021 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
3023 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
3025 } else if(point
<= outline
->contours
[contour
] &&
3026 outline
->tags
[point
] & FT_Curve_Tag_On
) {
3027 /* add closing pt for bezier */
3029 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
3037 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
3040 pph
->cb
= needed
- pph_start
;
3046 /* Convert the quadratic Beziers to cubic Beziers.
3047 The parametric eqn for a cubic Bezier is, from PLRM:
3048 r(t) = at^3 + bt^2 + ct + r0
3049 with the control points:
3054 A quadratic Beizer has the form:
3055 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3057 So equating powers of t leads to:
3058 r1 = 2/3 p1 + 1/3 p0
3059 r2 = 2/3 p1 + 1/3 p2
3060 and of course r0 = p0, r3 = p2
3063 int contour
, point
= 0, first_pt
;
3064 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
3065 TTPOLYGONHEADER
*pph
;
3067 DWORD pph_start
, cpfx
, type
;
3068 FT_Vector cubic_control
[4];
3069 if(buflen
== 0) buf
= NULL
;
3071 if (needsTransform
&& buf
) {
3072 pFT_Outline_Transform(outline
, &transMat
);
3075 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
3077 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
3080 pph
->dwType
= TT_POLYGON_TYPE
;
3081 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
3083 needed
+= sizeof(*pph
);
3085 while(point
<= outline
->contours
[contour
]) {
3086 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
3087 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
3088 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
3091 if(type
== TT_PRIM_LINE
) {
3093 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
3097 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
3100 /* FIXME: Possible optimization in endpoint calculation
3101 if there are two consecutive curves */
3102 cubic_control
[0] = outline
->points
[point
-1];
3103 if(!(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
3104 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
3105 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
3106 cubic_control
[0].x
>>= 1;
3107 cubic_control
[0].y
>>= 1;
3109 if(point
+1 > outline
->contours
[contour
])
3110 cubic_control
[3] = outline
->points
[first_pt
];
3112 cubic_control
[3] = outline
->points
[point
+1];
3113 if(!(outline
->tags
[point
+1] & FT_Curve_Tag_On
)) {
3114 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
3115 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
3116 cubic_control
[3].x
>>= 1;
3117 cubic_control
[3].y
>>= 1;
3120 /* r1 = 1/3 p0 + 2/3 p1
3121 r2 = 1/3 p2 + 2/3 p1 */
3122 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
3123 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
3124 cubic_control
[2] = cubic_control
[1];
3125 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
3126 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
3127 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
3128 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
3130 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
3131 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
3132 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
3137 } while(point
<= outline
->contours
[contour
] &&
3138 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
3139 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
3140 /* At the end of a contour Windows adds the start point,
3141 but only for Beziers and we've already done that.
3143 if(point
<= outline
->contours
[contour
] &&
3144 outline
->tags
[point
] & FT_Curve_Tag_On
) {
3145 /* This is the closing pt of a bezier, but we've already
3146 added it, so just inc point and carry on */
3153 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
3156 pph
->cb
= needed
- pph_start
;
3162 FIXME("Unsupported format %d\n", format
);
3168 static BOOL
get_bitmap_text_metrics(GdiFont font
)
3170 FT_Face ft_face
= font
->ft_face
;
3171 #ifdef HAVE_FREETYPE_FTWINFNT_H
3172 FT_WinFNT_HeaderRec winfnt_header
;
3174 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
3175 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
3176 font
->potm
->otmSize
= size
;
3178 #define TM font->potm->otmTextMetrics
3179 #ifdef HAVE_FREETYPE_FTWINFNT_H
3180 if(pFT_Get_WinFNT_Header
&& !pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
3182 TM
.tmHeight
= winfnt_header
.pixel_height
;
3183 TM
.tmAscent
= winfnt_header
.ascent
;
3184 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
3185 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
3186 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
3187 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
3188 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
3189 TM
.tmWeight
= winfnt_header
.weight
;
3191 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
3192 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
3193 TM
.tmFirstChar
= winfnt_header
.first_char
;
3194 TM
.tmLastChar
= winfnt_header
.last_char
;
3195 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
3196 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
3197 TM
.tmItalic
= winfnt_header
.italic
;
3198 TM
.tmUnderlined
= font
->underline
;
3199 TM
.tmStruckOut
= font
->strikeout
;
3200 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
3201 TM
.tmCharSet
= winfnt_header
.charset
;
3206 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
3207 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
3208 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
3209 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
3210 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
3211 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
3212 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
3213 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
3215 TM
.tmDigitizedAspectX
= 96; /* FIXME */
3216 TM
.tmDigitizedAspectY
= 96; /* FIXME */
3218 TM
.tmLastChar
= 255;
3219 TM
.tmDefaultChar
= 32;
3220 TM
.tmBreakChar
= 32;
3221 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
3222 TM
.tmUnderlined
= font
->underline
;
3223 TM
.tmStruckOut
= font
->strikeout
;
3224 /* NB inverted meaning of TMPF_FIXED_PITCH */
3225 TM
.tmPitchAndFamily
= ft_face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
? 0 : TMPF_FIXED_PITCH
;
3226 TM
.tmCharSet
= font
->charset
;
3233 /*************************************************************
3234 * WineEngGetTextMetrics
3237 BOOL
WineEngGetTextMetrics(GdiFont font
, LPTEXTMETRICW ptm
)
3240 if(!WineEngGetOutlineTextMetrics(font
, 0, NULL
))
3241 if(!get_bitmap_text_metrics(font
))
3244 if(!font
->potm
) return FALSE
;
3245 memcpy(ptm
, &font
->potm
->otmTextMetrics
, sizeof(*ptm
));
3247 if (font
->aveWidth
) {
3248 ptm
->tmAveCharWidth
= font
->aveWidth
* font
->font_desc
.matrix
.eM11
;
3254 /*************************************************************
3255 * WineEngGetOutlineTextMetrics
3258 UINT
WineEngGetOutlineTextMetrics(GdiFont font
, UINT cbSize
,
3259 OUTLINETEXTMETRICW
*potm
)
3261 FT_Face ft_face
= font
->ft_face
;
3262 UINT needed
, lenfam
, lensty
, ret
;
3264 TT_HoriHeader
*pHori
;
3265 TT_Postscript
*pPost
;
3266 FT_Fixed x_scale
, y_scale
;
3267 WCHAR
*family_nameW
, *style_nameW
;
3268 static const WCHAR spaceW
[] = {' ', '\0'};
3270 INT ascent
, descent
;
3272 TRACE("font=%p\n", font
);
3274 if(!FT_IS_SCALABLE(ft_face
))
3278 if(cbSize
>= font
->potm
->otmSize
)
3279 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
3280 return font
->potm
->otmSize
;
3284 needed
= sizeof(*potm
);
3286 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
3287 family_nameW
= strdupW(font
->name
);
3289 lensty
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0)
3291 style_nameW
= HeapAlloc(GetProcessHeap(), 0, lensty
);
3292 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1,
3293 style_nameW
, lensty
/sizeof(WCHAR
));
3295 /* These names should be read from the TT name table */
3297 /* length of otmpFamilyName */
3300 /* length of otmpFaceName */
3301 if(!strcasecmp(ft_face
->style_name
, "regular")) {
3302 needed
+= lenfam
; /* just the family name */
3304 needed
+= lenfam
+ lensty
; /* family + " " + style */
3307 /* length of otmpStyleName */
3310 /* length of otmpFullName */
3311 needed
+= lenfam
+ lensty
;
3314 x_scale
= ft_face
->size
->metrics
.x_scale
;
3315 y_scale
= ft_face
->size
->metrics
.y_scale
;
3317 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
3319 FIXME("Can't find OS/2 table - not TT font?\n");
3324 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
3326 FIXME("Can't find HHEA table - not TT font?\n");
3331 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
3333 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",
3334 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
3335 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
3336 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
3337 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
3338 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
3340 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
3341 font
->potm
->otmSize
= needed
;
3343 #define TM font->potm->otmTextMetrics
3345 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0) {
3346 ascent
= pHori
->Ascender
;
3347 descent
= -pHori
->Descender
;
3349 ascent
= pOS2
->usWinAscent
;
3350 descent
= pOS2
->usWinDescent
;
3354 TM
.tmAscent
= font
->yMax
;
3355 TM
.tmDescent
= -font
->yMin
;
3356 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
3358 TM
.tmAscent
= (pFT_MulFix(ascent
, y_scale
) + 32) >> 6;
3359 TM
.tmDescent
= (pFT_MulFix(descent
, y_scale
) + 32) >> 6;
3360 TM
.tmInternalLeading
= (pFT_MulFix(ascent
+ descent
3361 - ft_face
->units_per_EM
, y_scale
) + 32) >> 6;
3364 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
3367 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
3369 TM
.tmExternalLeading
= max(0, (pFT_MulFix(pHori
->Line_Gap
-
3370 ((ascent
+ descent
) -
3371 (pHori
->Ascender
- pHori
->Descender
)), y_scale
) + 32) >> 6);
3373 TM
.tmAveCharWidth
= (pFT_MulFix(pOS2
->xAvgCharWidth
, x_scale
) + 32) >> 6;
3374 if (TM
.tmAveCharWidth
== 0) {
3375 TM
.tmAveCharWidth
= 1;
3377 TM
.tmMaxCharWidth
= (pFT_MulFix(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
3378 TM
.tmWeight
= font
->fake_bold
? FW_BOLD
: pOS2
->usWeightClass
;
3380 TM
.tmDigitizedAspectX
= 300;
3381 TM
.tmDigitizedAspectY
= 300;
3382 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
;
3383 TM
.tmLastChar
= pOS2
->usLastCharIndex
;
3384 TM
.tmDefaultChar
= pOS2
->usDefaultChar
;
3385 TM
.tmBreakChar
= pOS2
->usBreakChar
? pOS2
->usBreakChar
: ' ';
3386 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
3387 TM
.tmUnderlined
= font
->underline
;
3388 TM
.tmStruckOut
= font
->strikeout
;
3390 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
3391 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
3392 (pOS2
->version
== 0xFFFFU
||
3393 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
3394 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
3396 TM
.tmPitchAndFamily
= 0;
3398 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
]) {
3399 case PAN_FAMILY_SCRIPT
:
3400 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
3402 case PAN_FAMILY_DECORATIVE
:
3403 case PAN_FAMILY_PICTORIAL
:
3404 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
3406 case PAN_FAMILY_TEXT_DISPLAY
:
3407 if(TM
.tmPitchAndFamily
== 0) /* fixed */
3408 TM
.tmPitchAndFamily
= FF_MODERN
;
3410 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
]) {
3411 case PAN_SERIF_NORMAL_SANS
:
3412 case PAN_SERIF_OBTUSE_SANS
:
3413 case PAN_SERIF_PERP_SANS
:
3414 TM
.tmPitchAndFamily
|= FF_SWISS
;
3417 TM
.tmPitchAndFamily
|= FF_ROMAN
;
3422 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
3425 if(FT_IS_SCALABLE(ft_face
))
3426 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
3427 if(FT_IS_SFNT(ft_face
))
3428 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
3430 TM
.tmCharSet
= font
->charset
;
3433 font
->potm
->otmFiller
= 0;
3434 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
3435 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
3436 font
->potm
->otmfsType
= pOS2
->fsType
;
3437 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
3438 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
3439 font
->potm
->otmItalicAngle
= 0; /* POST table */
3440 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
3441 font
->potm
->otmAscent
= (pFT_MulFix(pOS2
->sTypoAscender
, y_scale
) + 32) >> 6;
3442 font
->potm
->otmDescent
= (pFT_MulFix(pOS2
->sTypoDescender
, y_scale
) + 32) >> 6;
3443 font
->potm
->otmLineGap
= (pFT_MulFix(pOS2
->sTypoLineGap
, y_scale
) + 32) >> 6;
3444 font
->potm
->otmsCapEmHeight
= (pFT_MulFix(pOS2
->sCapHeight
, y_scale
) + 32) >> 6;
3445 font
->potm
->otmsXHeight
= (pFT_MulFix(pOS2
->sxHeight
, y_scale
) + 32) >> 6;
3446 font
->potm
->otmrcFontBox
.left
= (pFT_MulFix(ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
3447 font
->potm
->otmrcFontBox
.right
= (pFT_MulFix(ft_face
->bbox
.xMax
, x_scale
) + 32) >> 6;
3448 font
->potm
->otmrcFontBox
.top
= (pFT_MulFix(ft_face
->bbox
.yMax
, y_scale
) + 32) >> 6;
3449 font
->potm
->otmrcFontBox
.bottom
= (pFT_MulFix(ft_face
->bbox
.yMin
, y_scale
) + 32) >> 6;
3450 font
->potm
->otmMacAscent
= 0; /* where do these come from ? */
3451 font
->potm
->otmMacDescent
= 0;
3452 font
->potm
->otmMacLineGap
= 0;
3453 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
3454 font
->potm
->otmptSubscriptSize
.x
= (pFT_MulFix(pOS2
->ySubscriptXSize
, x_scale
) + 32) >> 6;
3455 font
->potm
->otmptSubscriptSize
.y
= (pFT_MulFix(pOS2
->ySubscriptYSize
, y_scale
) + 32) >> 6;
3456 font
->potm
->otmptSubscriptOffset
.x
= (pFT_MulFix(pOS2
->ySubscriptXOffset
, x_scale
) + 32) >> 6;
3457 font
->potm
->otmptSubscriptOffset
.y
= (pFT_MulFix(pOS2
->ySubscriptYOffset
, y_scale
) + 32) >> 6;
3458 font
->potm
->otmptSuperscriptSize
.x
= (pFT_MulFix(pOS2
->ySuperscriptXSize
, x_scale
) + 32) >> 6;
3459 font
->potm
->otmptSuperscriptSize
.y
= (pFT_MulFix(pOS2
->ySuperscriptYSize
, y_scale
) + 32) >> 6;
3460 font
->potm
->otmptSuperscriptOffset
.x
= (pFT_MulFix(pOS2
->ySuperscriptXOffset
, x_scale
) + 32) >> 6;
3461 font
->potm
->otmptSuperscriptOffset
.y
= (pFT_MulFix(pOS2
->ySuperscriptYOffset
, y_scale
) + 32) >> 6;
3462 font
->potm
->otmsStrikeoutSize
= (pFT_MulFix(pOS2
->yStrikeoutSize
, y_scale
) + 32) >> 6;
3463 font
->potm
->otmsStrikeoutPosition
= (pFT_MulFix(pOS2
->yStrikeoutPosition
, y_scale
) + 32) >> 6;
3465 font
->potm
->otmsUnderscoreSize
= 0;
3466 font
->potm
->otmsUnderscorePosition
= 0;
3468 font
->potm
->otmsUnderscoreSize
= (pFT_MulFix(pPost
->underlineThickness
, y_scale
) + 32) >> 6;
3469 font
->potm
->otmsUnderscorePosition
= (pFT_MulFix(pPost
->underlinePosition
, y_scale
) + 32) >> 6;
3472 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
3473 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
3474 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
3475 strcpyW((WCHAR
*)cp
, family_nameW
);
3477 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
3478 strcpyW((WCHAR
*)cp
, style_nameW
);
3480 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
3481 strcpyW((WCHAR
*)cp
, family_nameW
);
3482 if(strcasecmp(ft_face
->style_name
, "regular")) {
3483 strcatW((WCHAR
*)cp
, spaceW
);
3484 strcatW((WCHAR
*)cp
, style_nameW
);
3485 cp
+= lenfam
+ lensty
;
3488 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
3489 strcpyW((WCHAR
*)cp
, family_nameW
);
3490 strcatW((WCHAR
*)cp
, spaceW
);
3491 strcatW((WCHAR
*)cp
, style_nameW
);
3494 if(potm
&& needed
<= cbSize
)
3495 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
3498 HeapFree(GetProcessHeap(), 0, style_nameW
);
3499 HeapFree(GetProcessHeap(), 0, family_nameW
);
3504 static BOOL
load_child_font(GdiFont font
, CHILD_FONT
*child
)
3506 HFONTLIST
*hfontlist
;
3507 child
->font
= alloc_font();
3508 child
->font
->ft_face
= OpenFontFile(child
->font
, child
->file_name
, child
->index
, 0, -font
->ppem
);
3509 if(!child
->font
->ft_face
)
3511 free_font(child
->font
);
3516 child
->font
->orientation
= font
->orientation
;
3517 hfontlist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist
));
3518 hfontlist
->hfont
= CreateFontIndirectW(&font
->font_desc
.lf
);
3519 list_add_head(&child
->font
->hfontlist
, &hfontlist
->entry
);
3520 child
->font
->base_font
= font
;
3521 list_add_head(&child_font_list
, &child
->font
->entry
);
3522 TRACE("created child font hfont %p for base %p child %p\n", hfontlist
->hfont
, font
, child
->font
);
3526 static BOOL
get_glyph_index_linked(GdiFont font
, UINT c
, GdiFont
*linked_font
, FT_UInt
*glyph
)
3529 CHILD_FONT
*child_font
;
3532 font
= font
->base_font
;
3534 *linked_font
= font
;
3536 if((*glyph
= get_glyph_index(font
, c
)))
3539 LIST_FOR_EACH_ENTRY(child_font
, &font
->child_fonts
, CHILD_FONT
, entry
)
3541 if(!child_font
->font
)
3542 if(!load_child_font(font
, child_font
))
3545 if(!child_font
->font
->ft_face
)
3547 g
= get_glyph_index(child_font
->font
, c
);
3551 *linked_font
= child_font
->font
;
3558 /*************************************************************
3559 * WineEngGetCharWidth
3562 BOOL
WineEngGetCharWidth(GdiFont font
, UINT firstChar
, UINT lastChar
,
3567 FT_UInt glyph_index
;
3568 GdiFont linked_font
;
3570 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
3572 for(c
= firstChar
; c
<= lastChar
; c
++) {
3573 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
3574 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
3575 &gm
, 0, NULL
, NULL
);
3576 buffer
[c
- firstChar
] = linked_font
->gm
[glyph_index
].adv
;
3581 /*************************************************************
3582 * WineEngGetCharABCWidths
3585 BOOL
WineEngGetCharABCWidths(GdiFont font
, UINT firstChar
, UINT lastChar
,
3590 FT_UInt glyph_index
;
3591 GdiFont linked_font
;
3593 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
3595 if(!FT_IS_SCALABLE(font
->ft_face
))
3598 for(c
= firstChar
; c
<= lastChar
; c
++) {
3599 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
3600 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
3601 &gm
, 0, NULL
, NULL
);
3602 buffer
[c
- firstChar
].abcA
= linked_font
->gm
[glyph_index
].lsb
;
3603 buffer
[c
- firstChar
].abcB
= linked_font
->gm
[glyph_index
].bbx
;
3604 buffer
[c
- firstChar
].abcC
= linked_font
->gm
[glyph_index
].adv
- linked_font
->gm
[glyph_index
].lsb
-
3605 linked_font
->gm
[glyph_index
].bbx
;
3610 /*************************************************************
3611 * WineEngGetTextExtentPoint
3614 BOOL
WineEngGetTextExtentPoint(GdiFont font
, LPCWSTR wstr
, INT count
,
3620 FT_UInt glyph_index
;
3621 GdiFont linked_font
;
3623 TRACE("%p, %s, %d, %p\n", font
, debugstr_wn(wstr
, count
), count
,
3627 WineEngGetTextMetrics(font
, &tm
);
3628 size
->cy
= tm
.tmHeight
;
3630 for(idx
= 0; idx
< count
; idx
++) {
3631 get_glyph_index_linked(font
, wstr
[idx
], &linked_font
, &glyph_index
);
3632 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
3633 &gm
, 0, NULL
, NULL
);
3634 size
->cx
+= linked_font
->gm
[glyph_index
].adv
;
3636 TRACE("return %ld,%ld\n", size
->cx
, size
->cy
);
3640 /*************************************************************
3641 * WineEngGetTextExtentPointI
3644 BOOL
WineEngGetTextExtentPointI(GdiFont font
, const WORD
*indices
, INT count
,
3651 TRACE("%p, %p, %d, %p\n", font
, indices
, count
, size
);
3654 WineEngGetTextMetrics(font
, &tm
);
3655 size
->cy
= tm
.tmHeight
;
3657 for(idx
= 0; idx
< count
; idx
++) {
3658 WineEngGetGlyphOutline(font
, indices
[idx
],
3659 GGO_METRICS
| GGO_GLYPH_INDEX
, &gm
, 0, NULL
,
3661 size
->cx
+= font
->gm
[indices
[idx
]].adv
;
3663 TRACE("return %ld,%ld\n", size
->cx
, size
->cy
);
3667 /*************************************************************
3668 * WineEngGetFontData
3671 DWORD
WineEngGetFontData(GdiFont font
, DWORD table
, DWORD offset
, LPVOID buf
,
3674 FT_Face ft_face
= font
->ft_face
;
3678 TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
3679 font
, table
, offset
, buf
, cbData
);
3681 if(!FT_IS_SFNT(ft_face
))
3689 if(table
) { /* MS tags differ in endidness from FT ones */
3690 table
= table
>> 24 | table
<< 24 |
3691 (table
>> 8 & 0xff00) | (table
<< 8 & 0xff0000);
3694 /* If the FT_Load_Sfnt_Table function is there we'll use it */
3695 if(pFT_Load_Sfnt_Table
) {
3696 /* make sure value of len is the value freetype says it needs */
3699 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, NULL
, &needed
);
3700 if( !err
&& needed
< len
) len
= needed
;
3702 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, buf
, &len
);
3703 } else { /* Do it the hard way */
3704 TT_Face tt_face
= (TT_Face
) ft_face
;
3705 SFNT_Interface
*sfnt
;
3706 if (FT_Version
.major
==2 && FT_Version
.minor
==0)
3709 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 528);
3713 /* A field was added in the middle of the structure in 2.1.x */
3714 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 532);
3716 /* make sure value of len is the value freetype says it needs */
3719 err
= sfnt
->load_any(tt_face
, table
, offset
, NULL
, &needed
);
3720 if( !err
&& needed
< len
) len
= needed
;
3722 err
= sfnt
->load_any(tt_face
, table
, offset
, buf
, &len
);
3725 TRACE("Can't find table %08lx.\n", table
);
3731 /*************************************************************
3732 * WineEngGetTextFace
3735 INT
WineEngGetTextFace(GdiFont font
, INT count
, LPWSTR str
)
3738 lstrcpynW(str
, font
->name
, count
);
3739 return strlenW(font
->name
);
3741 return strlenW(font
->name
) + 1;
3744 UINT
WineEngGetTextCharsetInfo(GdiFont font
, LPFONTSIGNATURE fs
, DWORD flags
)
3746 if (fs
) memcpy(fs
, &font
->fs
, sizeof(FONTSIGNATURE
));
3747 return font
->charset
;
3750 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
3752 GdiFont font
= dc
->gdiFont
, linked_font
;
3753 struct list
*first_hfont
;
3756 ret
= get_glyph_index_linked(font
, c
, &linked_font
, glyph
);
3757 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph
, linked_font
);
3758 if(font
== linked_font
)
3759 *new_hfont
= dc
->hFont
;
3762 first_hfont
= list_head(&linked_font
->hfontlist
);
3763 *new_hfont
= LIST_ENTRY(first_hfont
, struct tagHFONTLIST
, entry
)->hfont
;
3770 /*************************************************************
3773 BOOL WINAPI
FontIsLinked(HDC hdc
)
3775 DC
*dc
= DC_GetDCPtr(hdc
);
3778 if(!dc
) return FALSE
;
3779 if(dc
->gdiFont
&& !list_empty(&dc
->gdiFont
->child_fonts
))
3781 GDI_ReleaseObj(hdc
);
3782 TRACE("returning %d\n", ret
);
3786 static BOOL
is_hinting_enabled(void)
3788 FT_Module mod
= pFT_Get_Module(library
, "truetype");
3789 if(mod
&& FT_DRIVER_HAS_HINTER(mod
))
3795 /*************************************************************************
3796 * GetRasterizerCaps (GDI32.@)
3798 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
3800 static int hinting
= -1;
3803 hinting
= is_hinting_enabled();
3805 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
3806 lprs
->wFlags
= TT_AVAILABLE
| TT_ENABLED
| (hinting
? WINE_TT_HINTER_ENABLED
: 0);
3807 lprs
->nLanguageID
= 0;
3812 #else /* HAVE_FREETYPE */
3814 BOOL
WineEngInit(void)
3818 GdiFont
WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
3822 BOOL
WineEngDestroyFontInstance(HFONT hfont
)
3827 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
3832 DWORD
WineEngGetGlyphIndices(GdiFont font
, LPCWSTR lpstr
, INT count
,
3833 LPWORD pgi
, DWORD flags
)
3838 DWORD
WineEngGetGlyphOutline(GdiFont font
, UINT glyph
, UINT format
,
3839 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
3842 ERR("called but we don't have FreeType\n");
3846 BOOL
WineEngGetTextMetrics(GdiFont font
, LPTEXTMETRICW ptm
)
3848 ERR("called but we don't have FreeType\n");
3852 UINT
WineEngGetOutlineTextMetrics(GdiFont font
, UINT cbSize
,
3853 OUTLINETEXTMETRICW
*potm
)
3855 ERR("called but we don't have FreeType\n");
3859 BOOL
WineEngGetCharWidth(GdiFont font
, UINT firstChar
, UINT lastChar
,
3862 ERR("called but we don't have FreeType\n");
3866 BOOL
WineEngGetCharABCWidths(GdiFont font
, UINT firstChar
, UINT lastChar
,
3869 ERR("called but we don't have FreeType\n");
3873 BOOL
WineEngGetTextExtentPoint(GdiFont font
, LPCWSTR wstr
, INT count
,
3876 ERR("called but we don't have FreeType\n");
3880 BOOL
WineEngGetTextExtentPointI(GdiFont font
, const WORD
*indices
, INT count
,
3883 ERR("called but we don't have FreeType\n");
3887 DWORD
WineEngGetFontData(GdiFont font
, DWORD table
, DWORD offset
, LPVOID buf
,
3890 ERR("called but we don't have FreeType\n");
3894 INT
WineEngGetTextFace(GdiFont font
, INT count
, LPWSTR str
)
3896 ERR("called but we don't have FreeType\n");
3900 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
3906 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
3912 UINT
WineEngGetTextCharsetInfo(GdiFont font
, LPFONTSIGNATURE fs
, DWORD flags
)
3915 return DEFAULT_CHARSET
;
3918 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
3923 BOOL WINAPI
FontIsLinked(HDC hdc
)
3928 /*************************************************************************
3929 * GetRasterizerCaps (GDI32.@)
3931 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
3933 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
3935 lprs
->nLanguageID
= 0;
3939 #endif /* HAVE_FREETYPE */