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_Sfnt_Table
);
107 MAKE_FUNCPTR(FT_Init_FreeType
);
108 MAKE_FUNCPTR(FT_Load_Glyph
);
109 MAKE_FUNCPTR(FT_Matrix_Multiply
);
110 MAKE_FUNCPTR(FT_MulFix
);
111 MAKE_FUNCPTR(FT_New_Face
);
112 MAKE_FUNCPTR(FT_Outline_Get_Bitmap
);
113 MAKE_FUNCPTR(FT_Outline_Transform
);
114 MAKE_FUNCPTR(FT_Outline_Translate
);
115 MAKE_FUNCPTR(FT_Select_Charmap
);
116 MAKE_FUNCPTR(FT_Set_Pixel_Sizes
);
117 MAKE_FUNCPTR(FT_Vector_Transform
);
118 static void (*pFT_Library_Version
)(FT_Library
,FT_Int
*,FT_Int
*,FT_Int
*);
119 static FT_Error (*pFT_Load_Sfnt_Table
)(FT_Face
,FT_ULong
,FT_Long
,FT_Byte
*,FT_ULong
*);
120 static FT_ULong (*pFT_Get_First_Char
)(FT_Face
,FT_UInt
*);
121 #ifdef HAVE_FREETYPE_FTWINFNT_H
122 MAKE_FUNCPTR(FT_Get_WinFNT_Header
);
125 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
126 #include <fontconfig/fontconfig.h>
127 MAKE_FUNCPTR(FcConfigGetCurrent
);
128 MAKE_FUNCPTR(FcFontList
);
129 MAKE_FUNCPTR(FcFontSetDestroy
);
130 MAKE_FUNCPTR(FcInit
);
131 MAKE_FUNCPTR(FcObjectSetAdd
);
132 MAKE_FUNCPTR(FcObjectSetCreate
);
133 MAKE_FUNCPTR(FcObjectSetDestroy
);
134 MAKE_FUNCPTR(FcPatternCreate
);
135 MAKE_FUNCPTR(FcPatternDestroy
);
136 MAKE_FUNCPTR(FcPatternGet
);
137 #ifndef SONAME_LIBFONTCONFIG
138 #define SONAME_LIBFONTCONFIG "libfontconfig.so"
144 #ifndef ft_encoding_none
145 #define FT_ENCODING_NONE ft_encoding_none
147 #ifndef ft_encoding_ms_symbol
148 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
150 #ifndef ft_encoding_unicode
151 #define FT_ENCODING_UNICODE ft_encoding_unicode
153 #ifndef ft_encoding_apple_roman
154 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
157 #define GET_BE_WORD(ptr) MAKEWORD( ((BYTE *)(ptr))[1], ((BYTE *)(ptr))[0] )
159 /* This is bascially a copy of FT_Bitmap_Size with an extra element added */
166 FT_Short internal_leading
;
169 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
170 So to let this compile on older versions of FreeType we'll define the
171 new structure here. */
173 FT_Short height
, width
;
174 FT_Pos size
, x_ppem
, y_ppem
;
177 typedef struct tagFace
{
185 FONTSIGNATURE fs_links
;
186 FT_Fixed font_version
;
188 Bitmap_Size size
; /* set if face is a bitmap */
189 BOOL external
; /* TRUE if we should manually add this font to the registry */
190 struct tagFamily
*family
;
193 typedef struct tagFamily
{
201 INT adv
; /* These three hold to widths of the unrotated chars */
218 typedef struct tagHFONTLIST
{
243 struct list hfontlist
;
248 OUTLINETEXTMETRICW
*potm
;
251 struct list child_fonts
;
261 #define INIT_GM_SIZE 128
263 static struct list gdi_font_list
= LIST_INIT(gdi_font_list
);
264 static struct list unused_gdi_font_list
= LIST_INIT(unused_gdi_font_list
);
265 #define UNUSED_CACHE_SIZE 10
266 static struct list child_font_list
= LIST_INIT(child_font_list
);
267 static struct list system_links
= LIST_INIT(system_links
);
269 static struct list font_list
= LIST_INIT(font_list
);
271 static const WCHAR defSerif
[] = {'T','i','m','e','s',' ','N','e','w',' ',
272 'R','o','m','a','n','\0'};
273 static const WCHAR defSans
[] = {'A','r','i','a','l','\0'};
274 static const WCHAR defFixed
[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
276 static const WCHAR defSystem
[] = {'A','r','i','a','l','\0'};
277 static const WCHAR SystemW
[] = {'S','y','s','t','e','m','\0'};
278 static const WCHAR MSSansSerifW
[] = {'M','S',' ','S','a','n','s',' ',
279 'S','e','r','i','f','\0'};
280 static const WCHAR HelvW
[] = {'H','e','l','v','\0'};
281 static const WCHAR RegularW
[] = {'R','e','g','u','l','a','r','\0'};
283 static const WCHAR fontsW
[] = {'\\','F','o','n','t','s','\0'};
284 static const WCHAR win9x_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
285 'W','i','n','d','o','w','s','\\',
286 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
287 'F','o','n','t','s','\0'};
289 static const WCHAR winnt_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
290 'W','i','n','d','o','w','s',' ','N','T','\\',
291 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
292 'F','o','n','t','s','\0'};
294 static const WCHAR system_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
295 static const WCHAR FixedSys_Value
[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
296 static const WCHAR System_Value
[] = {'F','O','N','T','S','.','F','O','N','\0'};
297 static const WCHAR OEMFont_Value
[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
299 static const WCHAR
*SystemFontValues
[4] = {
306 static const WCHAR external_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
307 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
309 static const WCHAR ArabicW
[] = {'A','r','a','b','i','c','\0'};
310 static const WCHAR BalticW
[] = {'B','a','l','t','i','c','\0'};
311 static const WCHAR CHINESE_BIG5W
[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
312 static const WCHAR CHINESE_GB2312W
[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
313 static const WCHAR Central_EuropeanW
[] = {'C','e','n','t','r','a','l',' ',
314 'E','u','r','o','p','e','a','n','\0'};
315 static const WCHAR CyrillicW
[] = {'C','y','r','i','l','l','i','c','\0'};
316 static const WCHAR GreekW
[] = {'G','r','e','e','k','\0'};
317 static const WCHAR HangulW
[] = {'H','a','n','g','u','l','\0'};
318 static const WCHAR Hangul_Johab_W
[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
319 static const WCHAR HebrewW
[] = {'H','e','b','r','e','w','\0'};
320 static const WCHAR JapaneseW
[] = {'J','a','p','a','n','e','s','e','\0'};
321 static const WCHAR SymbolW
[] = {'S','y','m','b','o','l','\0'};
322 static const WCHAR ThaiW
[] = {'T','h','a','i','\0'};
323 static const WCHAR TurkishW
[] = {'T','u','r','k','i','s','h','\0'};
324 static const WCHAR VietnameseW
[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
325 static const WCHAR WesternW
[] = {'W','e','s','t','e','r','n','\0'};
326 static const WCHAR OEM_DOSW
[] = {'O','E','M','/','D','O','S','\0'};
328 static const WCHAR
*ElfScriptsW
[32] = { /* these are in the order of the fsCsb[0] bits */
338 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, /*15*/
346 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
355 typedef struct tagFontSubst
{
358 struct tagFontSubst
*next
;
361 static FontSubst
*substlist
= NULL
;
362 static BOOL have_installed_roman_font
= FALSE
; /* CreateFontInstance will fail if this is still FALSE */
364 static const WCHAR font_mutex_nameW
[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
367 /****************************************
368 * Notes on .fon files
370 * The fonts System, FixedSys and Terminal are special. There are typically multiple
371 * versions installed for different resolutions and codepages. Windows stores which one to use
372 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
374 * FIXEDFON.FON FixedSys
376 * OEMFONT.FON Terminal
377 * LogPixels Current dpi set by the display control panel applet
378 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
379 * also has a LogPixels value that appears to mirror this)
381 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
382 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
383 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
384 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
385 * so that makes sense.
387 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
388 * to be mapped into the registry on Windows 2000 at least).
391 * ega80woa.fon=ega80850.fon
392 * ega40woa.fon=ega40850.fon
393 * cga80woa.fon=cga80850.fon
394 * cga40woa.fon=cga40850.fon
398 static inline BOOL
is_win9x(void)
400 return GetVersion() & 0x80000000;
403 This function builds an FT_Fixed from a float. It puts the integer part
404 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
405 It fails if the integer part of the float number is greater than SHORT_MAX.
407 static inline FT_Fixed
FT_FixedFromFloat(float f
)
410 unsigned short fract
= (f
- value
) * 0xFFFF;
411 return (FT_Fixed
)((long)value
<< 16 | (unsigned long)fract
);
415 This function builds an FT_Fixed from a FIXED. It simply put f.value
416 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
418 static inline FT_Fixed
FT_FixedFromFIXED(FIXED f
)
420 return (FT_Fixed
)((long)f
.value
<< 16 | (unsigned long)f
.fract
);
423 #define ADDFONT_EXTERNAL_FONT 0x01
424 #define ADDFONT_FORCE_BITMAP 0x02
425 static BOOL
AddFontFileToList(const char *file
, char *fake_family
, DWORD flags
)
429 TT_Header
*pHeader
= NULL
;
430 WCHAR
*FamilyW
, *StyleW
;
434 struct list
*family_elem_ptr
, *face_elem_ptr
;
436 FT_Long face_index
= 0, num_faces
;
437 #ifdef HAVE_FREETYPE_FTWINFNT_H
438 FT_WinFNT_HeaderRec winfnt_header
;
440 int i
, bitmap_num
, internal_leading
;
444 char *family_name
= fake_family
;
446 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
447 if((err
= pFT_New_Face(library
, file
, face_index
, &ft_face
)) != 0) {
448 WARN("Unable to load font file %s err = %x\n", debugstr_a(file
), err
);
452 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*/
453 WARN("Ignoring font %s\n", debugstr_a(file
));
454 pFT_Done_Face(ft_face
);
458 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
459 if(!FT_IS_SCALABLE(ft_face
) && FT_SimpleVersion
< ((2 << 16) | (1 << 8) | (9 << 0))) {
460 WARN("FreeType version < 2.1.9, skipping bitmap font %s\n", debugstr_a(file
));
461 pFT_Done_Face(ft_face
);
465 if(FT_IS_SFNT(ft_face
) && (!pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
) ||
466 !pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
) ||
467 !(pHeader
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_head
)))) {
468 TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
469 "Skipping this font.\n", debugstr_a(file
));
470 pFT_Done_Face(ft_face
);
474 if(!ft_face
->family_name
|| !ft_face
->style_name
) {
475 TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file
));
476 pFT_Done_Face(ft_face
);
481 family_name
= ft_face
->family_name
;
485 My_FT_Bitmap_Size
*size
= NULL
;
487 if(!FT_IS_SCALABLE(ft_face
))
488 size
= (My_FT_Bitmap_Size
*)ft_face
->available_sizes
+ bitmap_num
;
490 len
= MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, NULL
, 0);
491 FamilyW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
492 MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, FamilyW
, len
);
495 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
496 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
497 if(!strcmpW(family
->FamilyName
, FamilyW
))
502 family
= HeapAlloc(GetProcessHeap(), 0, sizeof(*family
));
503 family
->FamilyName
= FamilyW
;
504 list_init(&family
->faces
);
505 list_add_tail(&font_list
, &family
->entry
);
507 HeapFree(GetProcessHeap(), 0, FamilyW
);
510 len
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0);
511 StyleW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
512 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, StyleW
, len
);
514 internal_leading
= 0;
515 memset(&fs
, 0, sizeof(fs
));
517 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
519 fs
.fsCsb
[0] = pOS2
->ulCodePageRange1
;
520 fs
.fsCsb
[1] = pOS2
->ulCodePageRange2
;
521 fs
.fsUsb
[0] = pOS2
->ulUnicodeRange1
;
522 fs
.fsUsb
[1] = pOS2
->ulUnicodeRange2
;
523 fs
.fsUsb
[2] = pOS2
->ulUnicodeRange3
;
524 fs
.fsUsb
[3] = pOS2
->ulUnicodeRange4
;
525 if(pOS2
->version
== 0) {
528 if(!pFT_Get_First_Char
|| (pFT_Get_First_Char( ft_face
, &dummy
) < 0x100))
531 fs
.fsCsb
[0] |= 1L << 31;
534 #ifdef HAVE_FREETYPE_FTWINFNT_H
535 else if(pFT_Get_WinFNT_Header
&& !pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
)) {
537 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header
.pixel_height
, winfnt_header
.charset
,
538 winfnt_header
.vertical_resolution
,winfnt_header
.horizontal_resolution
, winfnt_header
.nominal_point_size
);
539 if(TranslateCharsetInfo((DWORD
*)(UINT
)winfnt_header
.charset
, &csi
, TCI_SRCCHARSET
))
540 memcpy(&fs
, &csi
.fs
, sizeof(csi
.fs
));
541 internal_leading
= winfnt_header
.internal_leading
;
545 face_elem_ptr
= list_head(&family
->faces
);
546 while(face_elem_ptr
) {
547 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
548 face_elem_ptr
= list_next(&family
->faces
, face_elem_ptr
);
549 if(!strcmpW(face
->StyleName
, StyleW
) &&
550 (FT_IS_SCALABLE(ft_face
) || ((size
->y_ppem
== face
->size
.y_ppem
) && !memcmp(&fs
, &face
->fs
, sizeof(fs
)) ))) {
551 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
552 debugstr_w(family
->FamilyName
), debugstr_w(StyleW
),
553 face
->font_version
, pHeader
? pHeader
->Font_Revision
: 0);
556 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
557 HeapFree(GetProcessHeap(), 0, StyleW
);
558 pFT_Done_Face(ft_face
);
561 if(!pHeader
|| pHeader
->Font_Revision
<= face
->font_version
) {
562 TRACE("Original font is newer so skipping this one\n");
563 HeapFree(GetProcessHeap(), 0, StyleW
);
564 pFT_Done_Face(ft_face
);
567 TRACE("Replacing original with this one\n");
568 list_remove(&face
->entry
);
569 HeapFree(GetProcessHeap(), 0, face
->file
);
570 HeapFree(GetProcessHeap(), 0, face
->StyleName
);
571 HeapFree(GetProcessHeap(), 0, face
);
576 face
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
));
577 list_add_tail(&family
->faces
, &face
->entry
);
578 face
->StyleName
= StyleW
;
579 face
->file
= HeapAlloc(GetProcessHeap(),0,strlen(file
)+1);
580 strcpy(face
->file
, file
);
581 face
->face_index
= face_index
;
582 face
->Italic
= (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 1 : 0;
583 face
->Bold
= (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
) ? 1 : 0;
584 face
->font_version
= pHeader
? pHeader
->Font_Revision
: 0;
585 face
->family
= family
;
586 face
->external
= (flags
& ADDFONT_EXTERNAL_FONT
) ? TRUE
: FALSE
;
587 memcpy(&face
->fs
, &fs
, sizeof(face
->fs
));
588 memset(&face
->fs_links
, 0, sizeof(face
->fs_links
));
590 if(FT_IS_SCALABLE(ft_face
)) {
591 memset(&face
->size
, 0, sizeof(face
->size
));
592 face
->scalable
= TRUE
;
594 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
595 size
->height
, size
->width
, size
->size
>> 6,
596 size
->x_ppem
>> 6, size
->y_ppem
>> 6);
597 face
->size
.height
= size
->height
;
598 face
->size
.width
= size
->width
;
599 face
->size
.size
= size
->size
;
600 face
->size
.x_ppem
= size
->x_ppem
;
601 face
->size
.y_ppem
= size
->y_ppem
;
602 face
->size
.internal_leading
= internal_leading
;
603 face
->scalable
= FALSE
;
606 TRACE("fsCsb = %08lx %08lx/%08lx %08lx %08lx %08lx\n",
607 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
608 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
609 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
612 if(face
->fs
.fsCsb
[0] == 0) { /* let's see if we can find any interesting cmaps */
613 for(i
= 0; i
< ft_face
->num_charmaps
; i
++) {
614 switch(ft_face
->charmaps
[i
]->encoding
) {
615 case FT_ENCODING_UNICODE
:
616 case FT_ENCODING_APPLE_ROMAN
:
617 face
->fs
.fsCsb
[0] |= 1;
619 case FT_ENCODING_MS_SYMBOL
:
620 face
->fs
.fsCsb
[0] |= 1L << 31;
628 if(face
->fs
.fsCsb
[0] & ~(1L << 31))
629 have_installed_roman_font
= TRUE
;
630 } while(!FT_IS_SCALABLE(ft_face
) && ++bitmap_num
< ft_face
->num_fixed_sizes
);
632 num_faces
= ft_face
->num_faces
;
633 pFT_Done_Face(ft_face
);
634 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
),
636 } while(num_faces
> ++face_index
);
640 static void DumpFontList(void)
644 struct list
*family_elem_ptr
, *face_elem_ptr
;
646 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
647 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
648 TRACE("Family: %s\n", debugstr_w(family
->FamilyName
));
649 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
650 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
651 TRACE("\t%s\t%08lx", debugstr_w(face
->StyleName
), face
->fs
.fsCsb
[0]);
653 TRACE(" %ld", face
->size
.y_ppem
>> 6);
660 static Face
*find_face_from_filename(const WCHAR
*name
)
665 DWORD len
= WideCharToMultiByte(CP_UNIXCP
, 0, name
, -1, NULL
, 0, NULL
, NULL
);
666 char *nameA
= HeapAlloc(GetProcessHeap(), 0, len
);
669 WideCharToMultiByte(CP_UNIXCP
, 0, name
, -1, nameA
, len
, NULL
, NULL
);
670 TRACE("looking for %s\n", debugstr_a(nameA
));
672 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
674 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
676 file
= strrchr(face
->file
, '/');
681 if(!strcmp(file
, nameA
))
686 HeapFree(GetProcessHeap(), 0, nameA
);
690 static Family
*find_family_from_name(const WCHAR
*name
)
694 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
696 if(!strcmpiW(family
->FamilyName
, name
))
703 static void DumpSubstList(void)
707 for(psub
= substlist
; psub
; psub
= psub
->next
)
708 if(psub
->from
.charset
!= -1 || psub
->to
.charset
!= -1)
709 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub
->from
.name
),
710 psub
->from
.charset
, debugstr_w(psub
->to
.name
), psub
->to
.charset
);
712 TRACE("%s -> %s\n", debugstr_w(psub
->from
.name
),
713 debugstr_w(psub
->to
.name
));
717 static LPWSTR
strdupW(LPCWSTR p
)
720 DWORD len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
721 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
726 static LPSTR
strdupA(LPCSTR p
)
729 DWORD len
= (strlen(p
) + 1);
730 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
735 static void split_subst_info(NameCs
*nc
, LPSTR str
)
737 CHAR
*p
= strrchr(str
, ',');
742 nc
->charset
= strtol(p
+1, NULL
, 10);
745 len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, NULL
, 0);
746 nc
->name
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
747 MultiByteToWideChar(CP_ACP
, 0, str
, -1, nc
->name
, len
);
750 static void LoadSubstList(void)
752 FontSubst
*psub
, **ppsub
;
754 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
759 for(psub
= substlist
; psub
;) {
761 HeapFree(GetProcessHeap(), 0, psub
->to
.name
);
762 HeapFree(GetProcessHeap(), 0, psub
->from
.name
);
765 HeapFree(GetProcessHeap(), 0, ptmp
);
770 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
771 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
772 &hkey
) == ERROR_SUCCESS
) {
774 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
775 &valuelen
, &datalen
, NULL
, NULL
);
777 valuelen
++; /* returned value doesn't include room for '\0' */
778 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
779 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
784 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
785 &dlen
) == ERROR_SUCCESS
) {
786 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
788 *ppsub
= HeapAlloc(GetProcessHeap(), 0, sizeof(**ppsub
));
789 (*ppsub
)->next
= NULL
;
790 split_subst_info(&((*ppsub
)->from
), value
);
791 split_subst_info(&((*ppsub
)->to
), data
);
793 /* Win 2000 doesn't allow mapping between different charsets
794 or mapping of DEFAULT_CHARSET */
795 if(((*ppsub
)->to
.charset
!= (*ppsub
)->from
.charset
) ||
796 (*ppsub
)->to
.charset
== DEFAULT_CHARSET
) {
797 HeapFree(GetProcessHeap(), 0, (*ppsub
)->to
.name
);
798 HeapFree(GetProcessHeap(), 0, (*ppsub
)->from
.name
);
799 HeapFree(GetProcessHeap(), 0, *ppsub
);
802 ppsub
= &((*ppsub
)->next
);
804 /* reset dlen and vlen */
808 HeapFree(GetProcessHeap(), 0, data
);
809 HeapFree(GetProcessHeap(), 0, value
);
814 /***********************************************************
815 * The replacement list is a way to map an entire font
816 * family onto another family. For example adding
818 * [HKCU\Software\Wine\Fonts\Replacements]
819 * "Wingdings"="Winedings"
821 * would enumerate the Winedings font both as Winedings and
822 * Wingdings. However if a real Wingdings font is present the
823 * replacement does not take place.
826 static void LoadReplaceList(void)
829 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
834 struct list
*family_elem_ptr
, *face_elem_ptr
;
835 WCHAR old_nameW
[200];
837 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
838 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts\\Replacements", &hkey
) == ERROR_SUCCESS
)
840 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
841 &valuelen
, &datalen
, NULL
, NULL
);
843 valuelen
++; /* returned value doesn't include room for '\0' */
844 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
845 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
849 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
850 &dlen
) == ERROR_SUCCESS
) {
851 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
852 /* "NewName"="Oldname" */
853 if(!MultiByteToWideChar(CP_ACP
, 0, data
, -1, old_nameW
, sizeof(old_nameW
)/sizeof(WCHAR
)))
856 /* Find the old family and hence all of the font files
858 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
859 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
860 if(!strcmpiW(family
->FamilyName
, old_nameW
)) {
861 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
862 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
863 TRACE("mapping %s %s to %s\n", debugstr_w(family
->FamilyName
),
864 debugstr_w(face
->StyleName
), value
);
865 /* Now add a new entry with the new family name */
866 AddFontFileToList(face
->file
, value
, ADDFONT_FORCE_BITMAP
| (face
->external
? ADDFONT_EXTERNAL_FONT
: 0));
871 /* reset dlen and vlen */
875 HeapFree(GetProcessHeap(), 0, data
);
876 HeapFree(GetProcessHeap(), 0, value
);
881 /*************************************************************
884 static BOOL
init_system_links(void)
886 static const WCHAR system_link
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
887 'W','i','n','d','o','w','s',' ','N','T','\\',
888 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
889 'S','y','s','t','e','m','L','i','n','k',0};
892 DWORD type
, max_val
, max_data
, val_len
, data_len
, index
;
895 SYSTEM_LINKS
*font_link
, *system_font_link
;
896 CHILD_FONT
*child_font
;
897 static const WCHAR Tahoma
[] = {'T','a','h','o','m','a',0};
898 static const WCHAR tahoma_ttf
[] = {'t','a','h','o','m','a','.','t','t','f',0};
899 static const WCHAR System
[] = {'S','y','s','t','e','m',0};
904 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, system_link
, &hkey
) == ERROR_SUCCESS
)
906 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &max_val
, &max_data
, NULL
, NULL
);
907 value
= HeapAlloc(GetProcessHeap(), 0, (max_val
+ 1) * sizeof(WCHAR
));
908 data
= HeapAlloc(GetProcessHeap(), 0, max_data
);
909 val_len
= max_val
+ 1;
912 while(RegEnumValueW(hkey
, index
++, value
, &val_len
, NULL
, &type
, (LPBYTE
)data
, &data_len
) == ERROR_SUCCESS
)
914 TRACE("%s:\n", debugstr_w(value
));
916 memset(&fs
, 0, sizeof(fs
));
917 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
918 font_link
->font_name
= strdupW(value
);
919 list_init(&font_link
->links
);
920 for(entry
= data
; (char*)entry
< (char*)data
+ data_len
&& *entry
!= 0; entry
= next
)
924 CHILD_FONT
*child_font
;
926 TRACE("\t%s\n", debugstr_w(entry
));
928 next
= entry
+ strlenW(entry
) + 1;
930 face_name
= strchrW(entry
, ',');
935 FIXME("don't yet handle ttc's correctly in linking. Assuming index 0\n");
937 while(isspaceW(*face_name
))
942 face
= find_face_from_filename(entry
);
945 TRACE("Unable to find file %s\n", debugstr_w(entry
));
949 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
950 child_font
->file_name
= strdupA(face
->file
);
951 child_font
->index
= index
;
952 child_font
->font
= NULL
;
953 fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
954 fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
955 list_add_tail(&font_link
->links
, &child_font
->entry
);
957 family
= find_family_from_name(font_link
->font_name
);
960 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
962 memcpy(&face
->fs_links
, &fs
, sizeof(fs
));
965 list_add_tail(&system_links
, &font_link
->entry
);
966 val_len
= max_val
+ 1;
970 HeapFree(GetProcessHeap(), 0, value
);
971 HeapFree(GetProcessHeap(), 0, data
);
975 /* Explicitly add an entry for the system font, this links to Tahoma and any links
978 system_font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link
));
979 system_font_link
->font_name
= strdupW(System
);
980 list_init(&system_font_link
->links
);
982 face
= find_face_from_filename(tahoma_ttf
);
985 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
986 child_font
->file_name
= strdupA(face
->file
);
987 child_font
->index
= 0;
988 child_font
->font
= NULL
;
989 list_add_tail(&system_font_link
->links
, &child_font
->entry
);
991 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
993 if(!strcmpiW(font_link
->font_name
, Tahoma
))
995 CHILD_FONT
*font_link_entry
;
996 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
998 CHILD_FONT
*new_child
;
999 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
1000 new_child
->file_name
= strdupA(font_link_entry
->file_name
);
1001 new_child
->index
= font_link_entry
->index
;
1002 new_child
->font
= NULL
;
1003 list_add_tail(&system_font_link
->links
, &new_child
->entry
);
1008 list_add_tail(&system_links
, &system_font_link
->entry
);
1012 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
1015 struct dirent
*dent
;
1016 char path
[MAX_PATH
];
1018 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
1020 dir
= opendir(dirname
);
1022 ERR("Can't open directory %s\n", debugstr_a(dirname
));
1025 while((dent
= readdir(dir
)) != NULL
) {
1026 struct stat statbuf
;
1028 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
1031 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
1033 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
1035 if(stat(path
, &statbuf
) == -1)
1037 WARN("Can't stat %s\n", debugstr_a(path
));
1040 if(S_ISDIR(statbuf
.st_mode
))
1041 ReadFontDir(path
, external_fonts
);
1043 AddFontFileToList(path
, NULL
, external_fonts
? ADDFONT_EXTERNAL_FONT
: 0);
1049 static void load_fontconfig_fonts(void)
1051 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
1052 void *fc_handle
= NULL
;
1059 const char *file
, *ext
;
1061 fc_handle
= wine_dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
, NULL
, 0);
1063 TRACE("Wine cannot find the fontconfig library (%s).\n",
1064 SONAME_LIBFONTCONFIG
);
1067 #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;}
1068 LOAD_FUNCPTR(FcConfigGetCurrent
);
1069 LOAD_FUNCPTR(FcFontList
);
1070 LOAD_FUNCPTR(FcFontSetDestroy
);
1071 LOAD_FUNCPTR(FcInit
);
1072 LOAD_FUNCPTR(FcObjectSetAdd
);
1073 LOAD_FUNCPTR(FcObjectSetCreate
);
1074 LOAD_FUNCPTR(FcObjectSetDestroy
);
1075 LOAD_FUNCPTR(FcPatternCreate
);
1076 LOAD_FUNCPTR(FcPatternDestroy
);
1077 LOAD_FUNCPTR(FcPatternGet
);
1080 if(!pFcInit()) return;
1082 config
= pFcConfigGetCurrent();
1083 pat
= pFcPatternCreate();
1084 os
= pFcObjectSetCreate();
1085 pFcObjectSetAdd(os
, FC_FILE
);
1086 fontset
= pFcFontList(config
, pat
, os
);
1087 if(!fontset
) return;
1088 for(i
= 0; i
< fontset
->nfont
; i
++) {
1089 if(pFcPatternGet(fontset
->fonts
[i
], FC_FILE
, 0, &v
) != FcResultMatch
)
1091 if(v
.type
!= FcTypeString
) continue;
1092 file
= (LPCSTR
) v
.u
.s
;
1093 TRACE("fontconfig: %s\n", file
);
1095 /* We're just interested in OT/TT fonts for now, so this hack just
1096 picks up the standard extensions to save time loading every other
1098 len
= strlen( file
);
1099 if(len
< 4) continue;
1100 ext
= &file
[ len
- 3 ];
1101 if(!strcasecmp(ext
, "ttf") || !strcasecmp(ext
, "ttc") || !strcasecmp(ext
, "otf"))
1102 AddFontFileToList(file
, NULL
, ADDFONT_EXTERNAL_FONT
);
1104 pFcFontSetDestroy(fontset
);
1105 pFcObjectSetDestroy(os
);
1106 pFcPatternDestroy(pat
);
1113 static void load_system_fonts(void)
1116 WCHAR data
[MAX_PATH
], windowsdir
[MAX_PATH
], pathW
[MAX_PATH
];
1117 const WCHAR
**value
;
1119 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
1122 if(RegOpenKeyW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, &hkey
) == ERROR_SUCCESS
) {
1123 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
1124 strcatW(windowsdir
, fontsW
);
1125 for(value
= SystemFontValues
; *value
; value
++) {
1126 dlen
= sizeof(data
);
1127 if(RegQueryValueExW(hkey
, *value
, 0, &type
, (void*)data
, &dlen
) == ERROR_SUCCESS
&&
1129 sprintfW(pathW
, fmtW
, windowsdir
, data
);
1130 if((unixname
= wine_get_unix_file_name(pathW
))) {
1131 AddFontFileToList(unixname
, NULL
, ADDFONT_FORCE_BITMAP
);
1132 HeapFree(GetProcessHeap(), 0, unixname
);
1140 /*************************************************************
1142 * This adds registry entries for any externally loaded fonts
1143 * (fonts from fontconfig or FontDirs). It also deletes entries
1144 * of no longer existing fonts.
1147 static void update_reg_entries(void)
1149 HKEY winkey
= 0, externalkey
= 0;
1152 DWORD dlen
, vlen
, datalen
, valuelen
, i
, type
, len
, len_fam
;
1155 struct list
*family_elem_ptr
, *face_elem_ptr
;
1157 static const WCHAR TrueType
[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1158 static const WCHAR spaceW
[] = {' ', '\0'};
1161 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
1162 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winkey
, NULL
) != ERROR_SUCCESS
) {
1163 ERR("Can't create Windows font reg key\n");
1166 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1167 if(RegCreateKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
, &externalkey
) != ERROR_SUCCESS
) {
1168 ERR("Can't create external font reg key\n");
1172 /* Delete all external fonts added last time */
1174 RegQueryInfoKeyW(externalkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1175 &valuelen
, &datalen
, NULL
, NULL
);
1176 valuelen
++; /* returned value doesn't include room for '\0' */
1177 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
1178 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
1180 dlen
= datalen
* sizeof(WCHAR
);
1183 while(RegEnumValueW(externalkey
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
1184 &dlen
) == ERROR_SUCCESS
) {
1186 RegDeleteValueW(winkey
, valueW
);
1187 /* reset dlen and vlen */
1191 HeapFree(GetProcessHeap(), 0, data
);
1192 HeapFree(GetProcessHeap(), 0, valueW
);
1194 /* Delete the old external fonts key */
1195 RegCloseKey(externalkey
);
1197 RegDeleteKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
);
1199 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1200 if(RegCreateKeyExW(HKEY_CURRENT_USER
, external_fonts_reg_key
,
1201 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &externalkey
, NULL
) != ERROR_SUCCESS
) {
1202 ERR("Can't create external font reg key\n");
1206 /* enumerate the fonts and add external ones to the two keys */
1208 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1209 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1210 len_fam
= strlenW(family
->FamilyName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
1211 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1212 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1213 if(!face
->external
) continue;
1215 if(strcmpiW(face
->StyleName
, RegularW
))
1216 len
= len_fam
+ strlenW(face
->StyleName
) + 1;
1217 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1218 strcpyW(valueW
, family
->FamilyName
);
1219 if(len
!= len_fam
) {
1220 strcatW(valueW
, spaceW
);
1221 strcatW(valueW
, face
->StyleName
);
1223 strcatW(valueW
, TrueType
);
1224 if((path
= strrchr(face
->file
, '/')) == NULL
)
1228 len
= MultiByteToWideChar(CP_ACP
, 0, path
, -1, NULL
, 0);
1230 file
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1231 MultiByteToWideChar(CP_ACP
, 0, path
, -1, file
, len
);
1232 RegSetValueExW(winkey
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
1233 RegSetValueExW(externalkey
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
1235 HeapFree(GetProcessHeap(), 0, file
);
1236 HeapFree(GetProcessHeap(), 0, valueW
);
1241 RegCloseKey(externalkey
);
1243 RegCloseKey(winkey
);
1248 /*************************************************************
1249 * WineEngAddFontResourceEx
1252 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
1254 if (ft_handle
) /* do it only if we have freetype up and running */
1259 FIXME("Ignoring flags %lx\n", flags
);
1261 if((unixname
= wine_get_unix_file_name(file
)))
1263 AddFontFileToList(unixname
, NULL
, ADDFONT_FORCE_BITMAP
);
1264 HeapFree(GetProcessHeap(), 0, unixname
);
1270 /*************************************************************
1271 * WineEngRemoveFontResourceEx
1274 BOOL
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
1280 static const struct nls_update_font_list
1282 UINT ansi_cp
, oem_cp
;
1283 const char *oem
, *fixed
, *system
;
1284 const char *courier
, *serif
, *small
, *sserif
;
1285 } nls_update_font_list
[] =
1287 /* Latin 1 (United States) */
1288 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
1289 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1291 /* Latin 1 (Multilingual) */
1292 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
1293 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1295 /* Eastern Europe */
1296 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
1297 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
1300 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
1301 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
1304 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
1305 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
1308 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
1309 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
1312 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
1313 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
1316 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
1317 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
1320 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
1321 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
1324 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
1325 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1328 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
1329 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
1332 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
1333 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
1335 /* Chinese Simplified */
1336 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
1337 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1340 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
1341 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1343 /* Chinese Traditional */
1344 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
1345 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1349 inline static HKEY
create_fonts_NT_registry_key(void)
1353 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
, 0, NULL
,
1354 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
1358 inline static HKEY
create_fonts_9x_registry_key(void)
1362 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
, 0, NULL
,
1363 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
1367 inline static HKEY
create_config_fonts_registry_key(void)
1371 RegCreateKeyExW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, 0, NULL
,
1372 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
1376 static void add_font_list(HKEY hkey
, const struct nls_update_font_list
*fl
)
1378 RegSetValueExA(hkey
, "Courier", 0, REG_SZ
, (const BYTE
*)fl
->courier
, strlen(fl
->courier
)+1);
1379 RegSetValueExA(hkey
, "MS Serif", 0, REG_SZ
, (const BYTE
*)fl
->serif
, strlen(fl
->serif
)+1);
1380 RegSetValueExA(hkey
, "MS Sans Serif", 0, REG_SZ
, (const BYTE
*)fl
->sserif
, strlen(fl
->sserif
)+1);
1381 RegSetValueExA(hkey
, "Small Fonts", 0, REG_SZ
, (const BYTE
*)fl
->small
, strlen(fl
->small
)+1);
1384 static void update_font_info(void)
1389 UINT i
, ansi_cp
= 0, oem_cp
= 0;
1390 LCID lcid
= GetUserDefaultLCID();
1392 if (RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", &hkey
) != ERROR_SUCCESS
)
1396 if (RegQueryValueExA(hkey
, "Locale", 0, &type
, (BYTE
*)buf
, &len
) == ERROR_SUCCESS
&& type
== REG_SZ
)
1398 if (strtoul(buf
, NULL
, 16 ) == lcid
) /* already set correctly */
1403 TRACE("updating registry, locale changed %s -> %08lx\n", debugstr_a(buf
), lcid
);
1405 else TRACE("updating registry, locale changed none -> %08lx\n", lcid
);
1407 sprintf(buf
, "%08lx", lcid
);
1408 RegSetValueExA(hkey
, "Locale", 0, REG_SZ
, (const BYTE
*)buf
, strlen(buf
)+1);
1411 GetLocaleInfoW(lcid
, LOCALE_IDEFAULTANSICODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
1412 (WCHAR
*)&ansi_cp
, sizeof(ansi_cp
)/sizeof(WCHAR
));
1413 GetLocaleInfoW(lcid
, LOCALE_IDEFAULTCODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
1414 (WCHAR
*)&oem_cp
, sizeof(oem_cp
)/sizeof(WCHAR
));
1416 for (i
= 0; i
< sizeof(nls_update_font_list
)/sizeof(nls_update_font_list
[0]); i
++)
1418 if (nls_update_font_list
[i
].ansi_cp
== ansi_cp
&&
1419 nls_update_font_list
[i
].oem_cp
== oem_cp
)
1423 hkey
= create_config_fonts_registry_key();
1424 RegSetValueExA(hkey
, "OEMFONT.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].oem
, strlen(nls_update_font_list
[i
].oem
)+1);
1425 RegSetValueExA(hkey
, "FIXED.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].fixed
, strlen(nls_update_font_list
[i
].fixed
)+1);
1426 RegSetValueExA(hkey
, "FONTS.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].system
, strlen(nls_update_font_list
[i
].system
)+1);
1429 hkey
= create_fonts_NT_registry_key();
1430 add_font_list(hkey
, &nls_update_font_list
[i
]);
1433 hkey
= create_fonts_9x_registry_key();
1434 add_font_list(hkey
, &nls_update_font_list
[i
]);
1440 FIXME("there is no font defaults for lcid %04lx/ansi_cp %u", lcid
, ansi_cp
);
1443 /*************************************************************
1446 * Initialize FreeType library and create a list of available faces
1448 BOOL
WineEngInit(void)
1450 static const WCHAR dot_fonW
[] = {'.','f','o','n','\0'};
1451 static const WCHAR pathW
[] = {'P','a','t','h',0};
1453 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1455 WCHAR windowsdir
[MAX_PATH
];
1461 /* update locale dependent font info in registry */
1464 ft_handle
= wine_dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
, NULL
, 0);
1467 "Wine cannot find the FreeType font library. To enable Wine to\n"
1468 "use TrueType fonts please install a version of FreeType greater than\n"
1469 "or equal to 2.0.5.\n"
1470 "http://www.freetype.org\n");
1474 #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;}
1476 LOAD_FUNCPTR(FT_Vector_Unit
)
1477 LOAD_FUNCPTR(FT_Done_Face
)
1478 LOAD_FUNCPTR(FT_Get_Char_Index
)
1479 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
1480 LOAD_FUNCPTR(FT_Init_FreeType
)
1481 LOAD_FUNCPTR(FT_Load_Glyph
)
1482 LOAD_FUNCPTR(FT_Matrix_Multiply
)
1483 LOAD_FUNCPTR(FT_MulFix
)
1484 LOAD_FUNCPTR(FT_New_Face
)
1485 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
1486 LOAD_FUNCPTR(FT_Outline_Transform
)
1487 LOAD_FUNCPTR(FT_Outline_Translate
)
1488 LOAD_FUNCPTR(FT_Select_Charmap
)
1489 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
1490 LOAD_FUNCPTR(FT_Vector_Transform
)
1493 /* Don't warn if this one is missing */
1494 pFT_Library_Version
= wine_dlsym(ft_handle
, "FT_Library_Version", NULL
, 0);
1495 pFT_Load_Sfnt_Table
= wine_dlsym(ft_handle
, "FT_Load_Sfnt_Table", NULL
, 0);
1496 pFT_Get_First_Char
= wine_dlsym(ft_handle
, "FT_Get_First_Char", NULL
, 0);
1497 #ifdef HAVE_FREETYPE_FTWINFNT_H
1498 pFT_Get_WinFNT_Header
= wine_dlsym(ft_handle
, "FT_Get_WinFNT_Header", NULL
, 0);
1500 if(!wine_dlsym(ft_handle
, "FT_Get_Postscript_Name", NULL
, 0) &&
1501 !wine_dlsym(ft_handle
, "FT_Sqrt64", NULL
, 0)) {
1502 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
1503 <= 2.0.3 has FT_Sqrt64 */
1507 if(pFT_Init_FreeType(&library
) != 0) {
1508 ERR("Can't init FreeType library\n");
1509 wine_dlclose(ft_handle
, NULL
, 0);
1513 FT_Version
.major
=FT_Version
.minor
=FT_Version
.patch
=-1;
1514 if (pFT_Library_Version
)
1516 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
1518 if (FT_Version
.major
<=0)
1524 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
1525 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
1526 ((FT_Version
.minor
<< 8) & 0x00ff00) |
1527 ((FT_Version
.patch
) & 0x0000ff);
1529 if((font_mutex
= CreateMutexW(NULL
, FALSE
, font_mutex_nameW
)) == NULL
) {
1530 ERR("Failed to create font mutex\n");
1533 WaitForSingleObject(font_mutex
, INFINITE
);
1535 /* load the system fonts */
1536 load_system_fonts();
1538 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
1539 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
1540 strcatW(windowsdir
, fontsW
);
1541 if((unixname
= wine_get_unix_file_name(windowsdir
)))
1543 ReadFontDir(unixname
, FALSE
);
1544 HeapFree(GetProcessHeap(), 0, unixname
);
1547 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
1548 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
1549 full path as the entry. Also look for any .fon fonts, since ReadFontDir
1551 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
,
1552 is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
1553 &hkey
) == ERROR_SUCCESS
) {
1555 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1556 &valuelen
, &datalen
, NULL
, NULL
);
1558 valuelen
++; /* returned value doesn't include room for '\0' */
1559 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
1560 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
1563 dlen
= datalen
* sizeof(WCHAR
);
1565 while(RegEnumValueW(hkey
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
1566 &dlen
) == ERROR_SUCCESS
) {
1567 if(((LPWSTR
)data
)[0] && ((LPWSTR
)data
)[1] == ':')
1569 if((unixname
= wine_get_unix_file_name((LPWSTR
)data
)))
1571 AddFontFileToList(unixname
, NULL
, ADDFONT_FORCE_BITMAP
);
1572 HeapFree(GetProcessHeap(), 0, unixname
);
1575 else if(dlen
/ 2 >= 6 && !strcmpiW(((LPWSTR
)data
) + dlen
/ 2 - 5, dot_fonW
))
1577 WCHAR pathW
[MAX_PATH
];
1578 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
1579 sprintfW(pathW
, fmtW
, windowsdir
, data
);
1580 if((unixname
= wine_get_unix_file_name(pathW
)))
1582 AddFontFileToList(unixname
, NULL
, ADDFONT_FORCE_BITMAP
);
1583 HeapFree(GetProcessHeap(), 0, unixname
);
1586 /* reset dlen and vlen */
1591 HeapFree(GetProcessHeap(), 0, data
);
1592 HeapFree(GetProcessHeap(), 0, valueW
);
1596 load_fontconfig_fonts();
1598 /* then look in any directories that we've specified in the config file */
1599 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
1600 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", &hkey
) == ERROR_SUCCESS
)
1606 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
)
1608 len
+= sizeof(WCHAR
);
1609 valueW
= HeapAlloc( GetProcessHeap(), 0, len
);
1610 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, (LPBYTE
)valueW
, &len
) == ERROR_SUCCESS
)
1612 len
= WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, NULL
, 0, NULL
, NULL
);
1613 valueA
= HeapAlloc( GetProcessHeap(), 0, len
);
1614 WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, valueA
, len
, NULL
, NULL
);
1615 TRACE( "got font path %s\n", debugstr_a(valueA
) );
1619 LPSTR next
= strchr( ptr
, ':' );
1620 if (next
) *next
++ = 0;
1621 ReadFontDir( ptr
, TRUE
);
1624 HeapFree( GetProcessHeap(), 0, valueA
);
1626 HeapFree( GetProcessHeap(), 0, valueW
);
1635 update_reg_entries();
1637 init_system_links();
1639 ReleaseMutex(font_mutex
);
1643 "Wine cannot find certain functions that it needs inside the FreeType\n"
1644 "font library. To enable Wine to use TrueType fonts please upgrade\n"
1645 "FreeType to at least version 2.0.5.\n"
1646 "http://www.freetype.org\n");
1647 wine_dlclose(ft_handle
, NULL
, 0);
1653 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
1656 TT_HoriHeader
*pHori
;
1660 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
1661 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
1663 if(height
== 0) height
= 16;
1665 /* Calc. height of EM square:
1667 * For +ve lfHeight we have
1668 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
1669 * Re-arranging gives:
1670 * ppem = units_per_em * lfheight / (winAscent + winDescent)
1672 * For -ve lfHeight we have
1674 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
1675 * with il = winAscent + winDescent - units_per_em]
1680 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0)
1681 ppem
= ft_face
->units_per_EM
* height
/
1682 (pHori
->Ascender
- pHori
->Descender
);
1684 ppem
= ft_face
->units_per_EM
* height
/
1685 (pOS2
->usWinAscent
+ pOS2
->usWinDescent
);
1693 static LONG
load_VDMX(GdiFont
, LONG
);
1695 static FT_Face
OpenFontFile(GdiFont font
, char *file
, FT_Long face_index
, LONG width
, LONG height
)
1700 TRACE("%s, %ld, %ld x %ld\n", debugstr_a(file
), face_index
, width
, height
);
1701 err
= pFT_New_Face(library
, file
, face_index
, &ft_face
);
1703 ERR("FT_New_Face rets %d\n", err
);
1707 /* set it here, as load_VDMX needs it */
1708 font
->ft_face
= ft_face
;
1710 if(FT_IS_SCALABLE(ft_face
)) {
1711 /* load the VDMX table if we have one */
1712 font
->ppem
= load_VDMX(font
, height
);
1714 font
->ppem
= calc_ppem_for_height(ft_face
, height
);
1716 if((err
= pFT_Set_Pixel_Sizes(ft_face
, 0, font
->ppem
)) != 0)
1717 WARN("FT_Set_Pixel_Sizes %d, %ld rets %x\n", 0, font
->ppem
, err
);
1719 font
->ppem
= height
;
1720 if((err
= pFT_Set_Pixel_Sizes(ft_face
, width
, height
)) != 0)
1721 WARN("FT_Set_Pixel_Sizes %ld, %ld rets %x\n", width
, height
, err
);
1727 static int get_nearest_charset(Face
*face
, int *cp
)
1729 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
1730 a single face with the requested charset. The idea is to check if
1731 the selected font supports the current ANSI codepage, if it does
1732 return the corresponding charset, else return the first charset */
1735 int acp
= GetACP(), i
;
1739 if(TranslateCharsetInfo((DWORD
*)acp
, &csi
, TCI_SRCCODEPAGE
))
1740 if(csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
1741 return csi
.ciCharset
;
1743 for(i
= 0; i
< 32; i
++) {
1745 if(face
->fs
.fsCsb
[0] & fs0
) {
1746 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
)) {
1748 return csi
.ciCharset
;
1751 FIXME("TCI failing on %lx\n", fs0
);
1755 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08lx file = %s\n",
1756 face
->fs
.fsCsb
[0], face
->file
);
1758 return DEFAULT_CHARSET
;
1761 static GdiFont
alloc_font(void)
1763 GdiFont ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
1764 ret
->gmsize
= INIT_GM_SIZE
;
1765 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
1766 ret
->gmsize
* sizeof(*ret
->gm
));
1768 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
1769 list_init(&ret
->hfontlist
);
1770 list_init(&ret
->child_fonts
);
1774 static void free_font(GdiFont font
)
1776 struct list
*cursor
, *cursor2
;
1778 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &font
->child_fonts
)
1780 CHILD_FONT
*child
= LIST_ENTRY(cursor
, CHILD_FONT
, entry
);
1781 struct list
*first_hfont
;
1782 HFONTLIST
*hfontlist
;
1783 list_remove(cursor
);
1786 first_hfont
= list_head(&child
->font
->hfontlist
);
1787 hfontlist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
1788 DeleteObject(hfontlist
->hfont
);
1789 HeapFree(GetProcessHeap(), 0, hfontlist
);
1790 free_font(child
->font
);
1792 HeapFree(GetProcessHeap(), 0, child
->file_name
);
1793 HeapFree(GetProcessHeap(), 0, child
);
1796 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
1797 HeapFree(GetProcessHeap(), 0, font
->potm
);
1798 HeapFree(GetProcessHeap(), 0, font
->name
);
1799 HeapFree(GetProcessHeap(), 0, font
->gm
);
1800 HeapFree(GetProcessHeap(), 0, font
);
1804 /*************************************************************
1807 * load the vdmx entry for the specified height
1810 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
1811 ( ( (FT_ULong)_x4 << 24 ) | \
1812 ( (FT_ULong)_x3 << 16 ) | \
1813 ( (FT_ULong)_x2 << 8 ) | \
1816 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
1826 static LONG
load_VDMX(GdiFont font
, LONG height
)
1828 BYTE hdr
[6], tmp
[2], group
[4];
1829 BYTE devXRatio
, devYRatio
;
1830 USHORT numRecs
, numRatios
;
1831 DWORD result
, offset
= -1;
1835 /* For documentation on VDMX records, see
1836 * http://www.microsoft.com/OpenType/OTSpec/vdmx.htm
1839 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, 0, hdr
, 6);
1841 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
1844 /* FIXME: need the real device aspect ratio */
1848 numRecs
= GET_BE_WORD(&hdr
[2]);
1849 numRatios
= GET_BE_WORD(&hdr
[4]);
1851 TRACE("numRecs = %d numRatios = %d\n", numRecs
, numRatios
);
1852 for(i
= 0; i
< numRatios
; i
++) {
1855 offset
= (3 * 2) + (i
* sizeof(Ratios
));
1856 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
1859 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
1861 if((ratio
.xRatio
== 0 &&
1862 ratio
.yStartRatio
== 0 &&
1863 ratio
.yEndRatio
== 0) ||
1864 (devXRatio
== ratio
.xRatio
&&
1865 devYRatio
>= ratio
.yStartRatio
&&
1866 devYRatio
<= ratio
.yEndRatio
))
1868 offset
= (3 * 2) + (numRatios
* 4) + (i
* 2);
1869 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, tmp
, 2);
1870 offset
= GET_BE_WORD(tmp
);
1876 FIXME("No suitable ratio found\n");
1880 if(WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, group
, 4) != GDI_ERROR
) {
1882 BYTE startsz
, endsz
;
1885 recs
= GET_BE_WORD(group
);
1889 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
1891 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* 6);
1892 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, offset
+ 4, vTable
, recs
* 6);
1893 if(result
== GDI_ERROR
) {
1894 FIXME("Failed to retrieve vTable\n");
1899 for(i
= 0; i
< recs
; i
++) {
1900 SHORT yMax
= GET_BE_WORD(&vTable
[(i
* 6) + 2]);
1901 SHORT yMin
= GET_BE_WORD(&vTable
[(i
* 6) + 4]);
1902 ppem
= GET_BE_WORD(&vTable
[i
* 6]);
1904 if(yMax
+ -yMin
== height
) {
1907 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
1910 if(yMax
+ -yMin
> height
) {
1913 goto end
; /* failed */
1915 font
->yMax
= GET_BE_WORD(&vTable
[(i
* 6) + 2]);
1916 font
->yMin
= GET_BE_WORD(&vTable
[(i
* 6) + 4]);
1917 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
1923 TRACE("ppem not found for height %ld\n", height
);
1927 if(ppem
< startsz
|| ppem
> endsz
)
1930 for(i
= 0; i
< recs
; i
++) {
1932 yPelHeight
= GET_BE_WORD(&vTable
[i
* 6]);
1934 if(yPelHeight
> ppem
)
1937 if(yPelHeight
== ppem
) {
1938 font
->yMax
= GET_BE_WORD(&vTable
[(i
* 6) + 2]);
1939 font
->yMin
= GET_BE_WORD(&vTable
[(i
* 6) + 4]);
1940 TRACE("ppem %ld found; yMax=%d yMin=%d\n", ppem
, font
->yMax
, font
->yMin
);
1946 HeapFree(GetProcessHeap(), 0, vTable
);
1952 static BOOL
fontcmp(GdiFont font
, FONT_DESC
*fd
)
1954 if(font
->font_desc
.hash
!= fd
->hash
) return TRUE
;
1955 if(memcmp(&font
->font_desc
.matrix
, &fd
->matrix
, sizeof(fd
->matrix
))) return TRUE
;
1956 if(memcmp(&font
->font_desc
.lf
, &fd
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
1957 return strcmpiW(font
->font_desc
.lf
.lfFaceName
, fd
->lf
.lfFaceName
);
1960 static void calc_hash(FONT_DESC
*pfd
)
1962 DWORD hash
= 0, *ptr
, two_chars
;
1966 for(i
= 0, ptr
= (DWORD
*)&pfd
->matrix
; i
< sizeof(FMAT2
)/sizeof(DWORD
); i
++, ptr
++)
1968 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
; i
< 7; i
++, ptr
++)
1970 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
1972 pwc
= (WCHAR
*)&two_chars
;
1974 *pwc
= toupperW(*pwc
);
1976 *pwc
= toupperW(*pwc
);
1984 static GdiFont
find_in_cache(HFONT hfont
, LOGFONTW
*plf
, XFORM
*pxf
, BOOL can_use_bitmap
)
1989 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
1991 memcpy(&fd
.lf
, plf
, sizeof(LOGFONTW
));
1992 memcpy(&fd
.matrix
, pxf
, sizeof(FMAT2
));
1995 /* try the in-use list */
1996 LIST_FOR_EACH(font_elem_ptr
, &gdi_font_list
) {
1997 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
1998 if(!fontcmp(ret
, &fd
)) {
1999 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
2000 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
2001 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
2002 if(hflist
->hfont
== hfont
)
2005 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
2006 hflist
->hfont
= hfont
;
2007 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
2012 /* then the unused list */
2013 font_elem_ptr
= list_head(&unused_gdi_font_list
);
2014 while(font_elem_ptr
) {
2015 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
2016 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
2017 if(!fontcmp(ret
, &fd
)) {
2018 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
2019 assert(list_empty(&ret
->hfontlist
));
2020 TRACE("Found %p in unused list\n", ret
);
2021 list_remove(&ret
->entry
);
2022 list_add_head(&gdi_font_list
, &ret
->entry
);
2023 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
2024 hflist
->hfont
= hfont
;
2025 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
2033 /*************************************************************
2034 * create_child_font_list
2036 static BOOL
create_child_font_list(GdiFont font
)
2039 SYSTEM_LINKS
*font_link
;
2040 CHILD_FONT
*font_link_entry
, *new_child
;
2042 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
2044 if(!strcmpW(font_link
->font_name
, font
->name
))
2046 TRACE("found entry in system list\n");
2047 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
2049 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
2050 new_child
->file_name
= strdupA(font_link_entry
->file_name
);
2051 new_child
->index
= font_link_entry
->index
;
2052 new_child
->font
= NULL
;
2053 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
2054 TRACE("font %s %d\n", debugstr_a(new_child
->file_name
), new_child
->index
);
2064 /*************************************************************
2065 * WineEngCreateFontInstance
2068 GdiFont
WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
2073 struct list
*family_elem_ptr
, *face_elem_ptr
;
2074 INT height
, width
= 0;
2075 signed int diff
= 0, newdiff
;
2076 BOOL bd
, it
, can_use_bitmap
;
2081 LIST_FOR_EACH_ENTRY(ret
, &child_font_list
, struct tagGdiFont
, entry
)
2083 struct list
*first_hfont
= list_head(&ret
->hfontlist
);
2084 hflist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
2085 if(hflist
->hfont
== hfont
)
2089 if (!GetObjectW( hfont
, sizeof(lf
), &lf
)) return NULL
;
2090 can_use_bitmap
= GetDeviceCaps(dc
->hSelf
, TEXTCAPS
) & TC_RA_ABLE
;
2092 TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
2093 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
2094 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
2097 /* check the cache first */
2098 if((ret
= find_in_cache(hfont
, &lf
, &dc
->xformWorld2Vport
, can_use_bitmap
)) != NULL
) {
2099 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
2103 TRACE("not in cache\n");
2104 if(list_empty(&font_list
)) /* No fonts installed */
2106 TRACE("No fonts installed\n");
2109 if(!have_installed_roman_font
)
2111 TRACE("No roman font installed\n");
2117 memcpy(&ret
->font_desc
.matrix
, &dc
->xformWorld2Vport
, sizeof(FMAT2
));
2118 memcpy(&ret
->font_desc
.lf
, &lf
, sizeof(LOGFONTW
));
2119 calc_hash(&ret
->font_desc
);
2120 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
2121 hflist
->hfont
= hfont
;
2122 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
2125 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
2126 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
2127 original value lfCharSet. Note this is a special case for
2128 Symbol and doesn't happen at least for "Wingdings*" */
2130 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
2131 lf
.lfCharSet
= SYMBOL_CHARSET
;
2133 if(!TranslateCharsetInfo((DWORD
*)(INT
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
2134 switch(lf
.lfCharSet
) {
2135 case DEFAULT_CHARSET
:
2136 csi
.fs
.fsCsb
[0] = 0;
2139 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
2140 csi
.fs
.fsCsb
[0] = 0;
2146 if(lf
.lfFaceName
[0] != '\0') {
2148 for(psub
= substlist
; psub
; psub
= psub
->next
)
2149 if(!strcmpiW(lf
.lfFaceName
, psub
->from
.name
) &&
2150 (psub
->from
.charset
== -1 ||
2151 psub
->from
.charset
== lf
.lfCharSet
))
2154 TRACE("substituting %s -> %s\n", debugstr_w(lf
.lfFaceName
),
2155 debugstr_w(psub
->to
.name
));
2156 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
2159 /* We want a match on name and charset or just name if
2160 charset was DEFAULT_CHARSET. If the latter then
2161 we fixup the returned charset later in get_nearest_charset
2162 where we'll either use the charset of the current ansi codepage
2163 or if that's unavailable the first charset that the font supports.
2165 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
2166 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
2167 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
2168 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
2169 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2170 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])
2171 if(face
->scalable
|| can_use_bitmap
)
2178 /* If requested charset was DEFAULT_CHARSET then try using charset
2179 corresponding to the current ansi codepage */
2180 if(!csi
.fs
.fsCsb
[0]) {
2182 if(!TranslateCharsetInfo((DWORD
*)acp
, &csi
, TCI_SRCCODEPAGE
)) {
2183 FIXME("TCI failed on codepage %d\n", acp
);
2184 csi
.fs
.fsCsb
[0] = 0;
2186 lf
.lfCharSet
= csi
.ciCharset
;
2189 /* Face families are in the top 4 bits of lfPitchAndFamily,
2190 so mask with 0xF0 before testing */
2192 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
2193 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
2194 strcpyW(lf
.lfFaceName
, defFixed
);
2195 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
2196 strcpyW(lf
.lfFaceName
, defSerif
);
2197 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
2198 strcpyW(lf
.lfFaceName
, defSans
);
2200 strcpyW(lf
.lfFaceName
, defSans
);
2201 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
2202 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
2203 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
2204 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
2205 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2206 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))
2207 if(face
->scalable
|| can_use_bitmap
)
2213 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
2214 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
2215 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
2216 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2217 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))
2218 if(face
->scalable
|| can_use_bitmap
)
2224 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
2225 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
2226 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
2227 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2228 if(face
->scalable
|| can_use_bitmap
) {
2229 csi
.fs
.fsCsb
[0] = 0;
2230 FIXME("just using first face for now\n");
2235 FIXME("can't find a single appropriate font - bailing\n");
2240 it
= lf
.lfItalic
? 1 : 0;
2241 bd
= lf
.lfWeight
> 550 ? 1 : 0;
2243 height
= GDI_ROUND( (FLOAT
)lf
.lfHeight
* dc
->xformWorld2Vport
.eM22
);
2244 height
= lf
.lfHeight
< 0 ? -abs(height
) : abs(height
);
2247 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
2248 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2249 if(!(face
->Italic
^ it
) && !(face
->Bold
^ bd
) &&
2250 ((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])) {
2254 newdiff
= height
- (signed int)(face
->size
.y_ppem
>> 6);
2256 newdiff
= -height
- ((signed int)(face
->size
.y_ppem
>> 6) - face
->size
.internal_leading
);
2257 if(!best
|| (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) ||
2258 (diff
< 0 && newdiff
> diff
)) {
2259 TRACE("%ld is better for %d diff was %d\n", face
->size
.y_ppem
>> 6, height
, diff
);
2272 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
2273 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2274 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0]) {
2278 newdiff
= height
- (signed int)(face
->size
.y_ppem
>> 6);
2280 newdiff
= -height
- ((signed int)(face
->size
.y_ppem
>> 6) - face
->size
.internal_leading
);
2281 if(!best
|| (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) ||
2282 (diff
< 0 && newdiff
> diff
)) {
2283 TRACE("%ld is better for %d diff was %d\n", face
->size
.y_ppem
>> 6, height
, diff
);
2294 if(it
&& !face
->Italic
) ret
->fake_italic
= TRUE
;
2295 if(bd
&& !face
->Bold
) ret
->fake_bold
= TRUE
;
2298 memcpy(&ret
->fs
, &face
->fs
, sizeof(FONTSIGNATURE
));
2300 if(csi
.fs
.fsCsb
[0]) {
2301 ret
->charset
= lf
.lfCharSet
;
2302 ret
->codepage
= csi
.ciACP
;
2305 ret
->charset
= get_nearest_charset(face
, &ret
->codepage
);
2307 TRACE("Chosen: %s %s (%s:%ld)\n", debugstr_w(family
->FamilyName
),
2308 debugstr_w(face
->StyleName
), face
->file
, face
->face_index
);
2310 if(!face
->scalable
) {
2311 width
= face
->size
.x_ppem
>> 6;
2312 height
= face
->size
.y_ppem
>> 6;
2314 ret
->ft_face
= OpenFontFile(ret
, face
->file
, face
->face_index
, width
, height
);
2322 if (ret
->charset
== SYMBOL_CHARSET
&&
2323 !pFT_Select_Charmap(ret
->ft_face
, FT_ENCODING_MS_SYMBOL
)) {
2326 else if (!pFT_Select_Charmap(ret
->ft_face
, FT_ENCODING_UNICODE
)) {
2330 pFT_Select_Charmap(ret
->ft_face
, FT_ENCODING_APPLE_ROMAN
);
2333 ret
->orientation
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfOrientation
: 0;
2334 ret
->name
= strdupW(family
->FamilyName
);
2335 ret
->underline
= lf
.lfUnderline
? 0xff : 0;
2336 ret
->strikeout
= lf
.lfStrikeOut
? 0xff : 0;
2337 create_child_font_list(ret
);
2339 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
2341 ret
->aveWidth
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfWidth
: 0;
2342 list_add_head(&gdi_font_list
, &ret
->entry
);
2346 static void dump_gdi_font_list(void)
2349 struct list
*elem_ptr
;
2351 TRACE("---------- gdiFont Cache ----------\n");
2352 LIST_FOR_EACH(elem_ptr
, &gdi_font_list
) {
2353 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
2354 TRACE("gdiFont=%p %s %ld\n",
2355 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
2358 TRACE("---------- Unused gdiFont Cache ----------\n");
2359 LIST_FOR_EACH(elem_ptr
, &unused_gdi_font_list
) {
2360 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
2361 TRACE("gdiFont=%p %s %ld\n",
2362 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
2366 /*************************************************************
2367 * WineEngDestroyFontInstance
2369 * free the gdiFont associated with this handle
2372 BOOL
WineEngDestroyFontInstance(HFONT handle
)
2377 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
2380 LIST_FOR_EACH_ENTRY(gdiFont
, &child_font_list
, struct tagGdiFont
, entry
)
2382 struct list
*first_hfont
= list_head(&gdiFont
->hfontlist
);
2383 hflist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
2384 if(hflist
->hfont
== handle
)
2386 TRACE("removing child font %p from child list\n", gdiFont
);
2387 list_remove(&gdiFont
->entry
);
2392 TRACE("destroying hfont=%p\n", handle
);
2394 dump_gdi_font_list();
2396 font_elem_ptr
= list_head(&gdi_font_list
);
2397 while(font_elem_ptr
) {
2398 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
2399 font_elem_ptr
= list_next(&gdi_font_list
, font_elem_ptr
);
2401 hfontlist_elem_ptr
= list_head(&gdiFont
->hfontlist
);
2402 while(hfontlist_elem_ptr
) {
2403 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
2404 hfontlist_elem_ptr
= list_next(&gdiFont
->hfontlist
, hfontlist_elem_ptr
);
2405 if(hflist
->hfont
== handle
) {
2406 list_remove(&hflist
->entry
);
2407 HeapFree(GetProcessHeap(), 0, hflist
);
2411 if(list_empty(&gdiFont
->hfontlist
)) {
2412 TRACE("Moving to Unused list\n");
2413 list_remove(&gdiFont
->entry
);
2414 list_add_head(&unused_gdi_font_list
, &gdiFont
->entry
);
2419 font_elem_ptr
= list_head(&unused_gdi_font_list
);
2420 while(font_elem_ptr
&& i
++ < UNUSED_CACHE_SIZE
)
2421 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
2422 while(font_elem_ptr
) {
2423 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
2424 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
2425 TRACE("freeing %p\n", gdiFont
);
2426 list_remove(&gdiFont
->entry
);
2432 static void GetEnumStructs(Face
*face
, LPENUMLOGFONTEXW pelf
,
2433 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
2435 OUTLINETEXTMETRICW
*potm
= NULL
;
2437 TEXTMETRICW tm
, *ptm
;
2438 GdiFont font
= alloc_font();
2441 if(face
->scalable
) {
2445 height
= face
->size
.y_ppem
>> 6;
2446 width
= face
->size
.x_ppem
>> 6;
2449 if (!(font
->ft_face
= OpenFontFile(font
, face
->file
, face
->face_index
, width
, height
)))
2455 font
->name
= strdupW(face
->family
->FamilyName
);
2457 memset(&pelf
->elfLogFont
, 0, sizeof(LOGFONTW
));
2459 size
= WineEngGetOutlineTextMetrics(font
, 0, NULL
);
2461 potm
= HeapAlloc(GetProcessHeap(), 0, size
);
2462 WineEngGetOutlineTextMetrics(font
, size
, potm
);
2463 ptm
= (TEXTMETRICW
*)&potm
->otmTextMetrics
;
2465 WineEngGetTextMetrics(font
, &tm
);
2469 pntm
->ntmTm
.tmHeight
= pelf
->elfLogFont
.lfHeight
= ptm
->tmHeight
;
2470 pntm
->ntmTm
.tmAscent
= ptm
->tmAscent
;
2471 pntm
->ntmTm
.tmDescent
= ptm
->tmDescent
;
2472 pntm
->ntmTm
.tmInternalLeading
= ptm
->tmInternalLeading
;
2473 pntm
->ntmTm
.tmExternalLeading
= ptm
->tmExternalLeading
;
2474 pntm
->ntmTm
.tmAveCharWidth
= pelf
->elfLogFont
.lfWidth
= ptm
->tmAveCharWidth
;
2475 pntm
->ntmTm
.tmMaxCharWidth
= ptm
->tmMaxCharWidth
;
2476 pntm
->ntmTm
.tmWeight
= pelf
->elfLogFont
.lfWeight
= ptm
->tmWeight
;
2477 pntm
->ntmTm
.tmOverhang
= ptm
->tmOverhang
;
2478 pntm
->ntmTm
.tmDigitizedAspectX
= ptm
->tmDigitizedAspectX
;
2479 pntm
->ntmTm
.tmDigitizedAspectY
= ptm
->tmDigitizedAspectY
;
2480 pntm
->ntmTm
.tmFirstChar
= ptm
->tmFirstChar
;
2481 pntm
->ntmTm
.tmLastChar
= ptm
->tmLastChar
;
2482 pntm
->ntmTm
.tmDefaultChar
= ptm
->tmDefaultChar
;
2483 pntm
->ntmTm
.tmBreakChar
= ptm
->tmBreakChar
;
2484 pntm
->ntmTm
.tmItalic
= pelf
->elfLogFont
.lfItalic
= ptm
->tmItalic
;
2485 pntm
->ntmTm
.tmUnderlined
= pelf
->elfLogFont
.lfUnderline
= ptm
->tmUnderlined
;
2486 pntm
->ntmTm
.tmStruckOut
= pelf
->elfLogFont
.lfStrikeOut
= ptm
->tmStruckOut
;
2487 pntm
->ntmTm
.tmPitchAndFamily
= ptm
->tmPitchAndFamily
;
2488 pelf
->elfLogFont
.lfPitchAndFamily
= (ptm
->tmPitchAndFamily
& 0xf1) + 1;
2489 pntm
->ntmTm
.tmCharSet
= pelf
->elfLogFont
.lfCharSet
= ptm
->tmCharSet
;
2490 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
2491 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
2492 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
2494 *ptype
= ptm
->tmPitchAndFamily
& TMPF_TRUETYPE
? TRUETYPE_FONTTYPE
: 0;
2495 if(!(ptm
->tmPitchAndFamily
& TMPF_VECTOR
))
2496 *ptype
|= RASTER_FONTTYPE
;
2498 pntm
->ntmTm
.ntmFlags
= ptm
->tmItalic
? NTM_ITALIC
: 0;
2499 if(ptm
->tmWeight
> 550) pntm
->ntmTm
.ntmFlags
|= NTM_BOLD
;
2500 if(pntm
->ntmTm
.ntmFlags
== 0) pntm
->ntmTm
.ntmFlags
= NTM_REGULAR
;
2502 pntm
->ntmTm
.ntmCellHeight
= pntm
->ntmTm
.tmHeight
;
2503 pntm
->ntmTm
.ntmAvgWidth
= pntm
->ntmTm
.tmAveCharWidth
;
2504 memset(&pntm
->ntmFontSig
, 0, sizeof(FONTSIGNATURE
));
2507 pntm
->ntmTm
.ntmSizeEM
= potm
->otmEMSquare
;
2509 lstrcpynW(pelf
->elfLogFont
.lfFaceName
,
2510 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpFamilyName
),
2512 lstrcpynW(pelf
->elfFullName
,
2513 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpFaceName
),
2515 lstrcpynW(pelf
->elfStyle
,
2516 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpStyleName
),
2519 HeapFree(GetProcessHeap(), 0, potm
);
2521 pntm
->ntmTm
.ntmSizeEM
= pntm
->ntmTm
.tmHeight
- pntm
->ntmTm
.tmInternalLeading
;
2523 lstrcpynW(pelf
->elfLogFont
.lfFaceName
, face
->family
->FamilyName
, LF_FACESIZE
);
2524 lstrcpynW(pelf
->elfFullName
, face
->family
->FamilyName
, LF_FACESIZE
);
2525 pelf
->elfStyle
[0] = '\0';
2528 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
2533 /*************************************************************
2537 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
2541 struct list
*family_elem_ptr
, *face_elem_ptr
;
2543 NEWTEXTMETRICEXW ntm
;
2544 DWORD type
, ret
= 1;
2550 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
2552 if(plf
->lfFaceName
[0]) {
2554 for(psub
= substlist
; psub
; psub
= psub
->next
)
2555 if(!strcmpiW(plf
->lfFaceName
, psub
->from
.name
) &&
2556 (psub
->from
.charset
== -1 ||
2557 psub
->from
.charset
== plf
->lfCharSet
))
2560 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
2561 debugstr_w(psub
->to
.name
));
2562 memcpy(&lf
, plf
, sizeof(lf
));
2563 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
2567 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
2568 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
2569 if(!strcmpiW(plf
->lfFaceName
, family
->FamilyName
)) {
2570 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
2571 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2572 GetEnumStructs(face
, &elf
, &ntm
, &type
);
2573 for(i
= 0; i
< 32; i
++) {
2574 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
2575 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
2576 strcpyW(elf
.elfScript
, OEM_DOSW
);
2577 i
= 32; /* break out of loop */
2578 } else if(!(face
->fs
.fsCsb
[0] & (1L << i
)))
2581 fs
.fsCsb
[0] = 1L << i
;
2583 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
2585 csi
.ciCharset
= DEFAULT_CHARSET
;
2586 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
2587 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
2588 elf
.elfLogFont
.lfCharSet
=
2589 ntm
.ntmTm
.tmCharSet
= csi
.ciCharset
;
2591 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
2593 FIXME("Unknown elfscript for bit %d\n", i
);
2596 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2597 debugstr_w(elf
.elfLogFont
.lfFaceName
),
2598 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
2599 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
2600 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
2601 ntm
.ntmTm
.ntmFlags
);
2602 ret
= proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
);
2609 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
2610 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
2611 face_elem_ptr
= list_head(&family
->faces
);
2612 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2613 GetEnumStructs(face
, &elf
, &ntm
, &type
);
2614 for(i
= 0; i
< 32; i
++) {
2615 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
2616 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
2617 strcpyW(elf
.elfScript
, OEM_DOSW
);
2618 i
= 32; /* break out of loop */
2619 } else if(!(face
->fs
.fsCsb
[0] & (1L << i
)))
2622 fs
.fsCsb
[0] = 1L << i
;
2624 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
2626 csi
.ciCharset
= DEFAULT_CHARSET
;
2627 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
2628 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
2629 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
=
2632 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
2634 FIXME("Unknown elfscript for bit %d\n", i
);
2637 TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2638 debugstr_w(elf
.elfLogFont
.lfFaceName
),
2639 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
2640 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
2641 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
2642 ntm
.ntmTm
.ntmFlags
);
2643 ret
= proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
);
2652 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
2654 pt
->x
.value
= vec
->x
>> 6;
2655 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
2656 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
2657 pt
->y
.value
= vec
->y
>> 6;
2658 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
2659 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
2663 static FT_UInt
get_glyph_index(GdiFont font
, UINT glyph
)
2665 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
2666 WCHAR wc
= (WCHAR
)glyph
;
2670 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, &default_used
) || default_used
)
2673 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)buf
);
2674 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, buf
, ret
, default_used
);
2678 if(font
->charset
== SYMBOL_CHARSET
&& glyph
< 0x100)
2679 glyph
= glyph
+ 0xf000;
2680 return pFT_Get_Char_Index(font
->ft_face
, glyph
);
2683 /*************************************************************
2684 * WineEngGetGlyphIndices
2686 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
2688 DWORD
WineEngGetGlyphIndices(GdiFont font
, LPCWSTR lpstr
, INT count
,
2689 LPWORD pgi
, DWORD flags
)
2693 for(i
= 0; i
< count
; i
++)
2694 pgi
[i
] = get_glyph_index(font
, lpstr
[i
]);
2699 /*************************************************************
2700 * WineEngGetGlyphOutline
2702 * Behaves in exactly the same way as the win32 api GetGlyphOutline
2703 * except that the first parameter is the HWINEENGFONT of the font in
2704 * question rather than an HDC.
2707 DWORD
WineEngGetGlyphOutline(GdiFont font
, UINT glyph
, UINT format
,
2708 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
2711 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
2712 FT_Face ft_face
= font
->ft_face
;
2713 FT_UInt glyph_index
;
2714 DWORD width
, height
, pitch
, needed
= 0;
2715 FT_Bitmap ft_bitmap
;
2717 INT left
, right
, top
= 0, bottom
= 0;
2719 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
2720 float widthRatio
= 1.0;
2721 FT_Matrix transMat
= identityMat
;
2722 BOOL needsTransform
= FALSE
;
2725 TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font
, glyph
, format
, lpgm
,
2726 buflen
, buf
, lpmat
);
2728 if(format
& GGO_GLYPH_INDEX
) {
2729 glyph_index
= glyph
;
2730 format
&= ~GGO_GLYPH_INDEX
;
2732 glyph_index
= get_glyph_index(font
, glyph
);
2734 if(glyph_index
>= font
->gmsize
) {
2735 font
->gmsize
= (glyph_index
/ INIT_GM_SIZE
+ 1) * INIT_GM_SIZE
;
2736 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
2737 font
->gmsize
* sizeof(*font
->gm
));
2739 if(format
== GGO_METRICS
&& font
->gm
[glyph_index
].init
) {
2740 memcpy(lpgm
, &font
->gm
[glyph_index
].gm
, sizeof(*lpgm
));
2741 return 1; /* FIXME */
2745 if(font
->orientation
|| (format
!= GGO_METRICS
&& format
!= GGO_BITMAP
) || font
->aveWidth
|| lpmat
)
2746 load_flags
|= FT_LOAD_NO_BITMAP
;
2748 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
2751 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
2755 /* Scaling factor */
2756 if (font
->aveWidth
&& font
->potm
) {
2757 widthRatio
= (float)font
->aveWidth
* font
->font_desc
.matrix
.eM11
/ (float) font
->potm
->otmTextMetrics
.tmAveCharWidth
;
2760 left
= (INT
)(ft_face
->glyph
->metrics
.horiBearingX
* widthRatio
) & -64;
2761 right
= (INT
)((ft_face
->glyph
->metrics
.horiBearingX
+ ft_face
->glyph
->metrics
.width
) * widthRatio
+ 63) & -64;
2763 font
->gm
[glyph_index
].adv
= (INT
)((ft_face
->glyph
->metrics
.horiAdvance
* widthRatio
) + 63) >> 6;
2764 font
->gm
[glyph_index
].lsb
= left
>> 6;
2765 font
->gm
[glyph_index
].bbx
= (right
- left
) >> 6;
2767 /* Scaling transform */
2768 if(font
->aveWidth
) {
2770 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
2773 scaleMat
.yy
= (1 << 16);
2775 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
2776 needsTransform
= TRUE
;
2779 /* Rotation transform */
2780 if(font
->orientation
) {
2781 FT_Matrix rotationMat
;
2783 angle
= FT_FixedFromFloat((float)font
->orientation
/ 10.0);
2784 pFT_Vector_Unit(&vecAngle
, angle
);
2785 rotationMat
.xx
= vecAngle
.x
;
2786 rotationMat
.xy
= -vecAngle
.y
;
2787 rotationMat
.yx
= -rotationMat
.xy
;
2788 rotationMat
.yy
= rotationMat
.xx
;
2790 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
2791 needsTransform
= TRUE
;
2794 /* Extra transformation specified by caller */
2797 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
2798 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM21
);
2799 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM12
);
2800 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
2801 pFT_Matrix_Multiply(&extraMat
, &transMat
);
2802 needsTransform
= TRUE
;
2805 if(!needsTransform
) {
2806 top
= (ft_face
->glyph
->metrics
.horiBearingY
+ 63) & -64;
2807 bottom
= (ft_face
->glyph
->metrics
.horiBearingY
-
2808 ft_face
->glyph
->metrics
.height
) & -64;
2809 lpgm
->gmCellIncX
= font
->gm
[glyph_index
].adv
;
2810 lpgm
->gmCellIncY
= 0;
2814 for(xc
= 0; xc
< 2; xc
++) {
2815 for(yc
= 0; yc
< 2; yc
++) {
2816 vec
.x
= (ft_face
->glyph
->metrics
.horiBearingX
+
2817 xc
* ft_face
->glyph
->metrics
.width
);
2818 vec
.y
= ft_face
->glyph
->metrics
.horiBearingY
-
2819 yc
* ft_face
->glyph
->metrics
.height
;
2820 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
2821 pFT_Vector_Transform(&vec
, &transMat
);
2822 if(xc
== 0 && yc
== 0) {
2823 left
= right
= vec
.x
;
2824 top
= bottom
= vec
.y
;
2826 if(vec
.x
< left
) left
= vec
.x
;
2827 else if(vec
.x
> right
) right
= vec
.x
;
2828 if(vec
.y
< bottom
) bottom
= vec
.y
;
2829 else if(vec
.y
> top
) top
= vec
.y
;
2834 right
= (right
+ 63) & -64;
2835 bottom
= bottom
& -64;
2836 top
= (top
+ 63) & -64;
2838 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
2839 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
2841 pFT_Vector_Transform(&vec
, &transMat
);
2842 lpgm
->gmCellIncX
= (vec
.x
+63) >> 6;
2843 lpgm
->gmCellIncY
= -((vec
.y
+63) >> 6);
2845 lpgm
->gmBlackBoxX
= (right
- left
) >> 6;
2846 lpgm
->gmBlackBoxY
= (top
- bottom
) >> 6;
2847 lpgm
->gmptGlyphOrigin
.x
= left
>> 6;
2848 lpgm
->gmptGlyphOrigin
.y
= top
>> 6;
2850 memcpy(&font
->gm
[glyph_index
].gm
, lpgm
, sizeof(*lpgm
));
2851 font
->gm
[glyph_index
].init
= TRUE
;
2853 if(format
== GGO_METRICS
)
2854 return 1; /* FIXME */
2856 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&& format
!= GGO_BITMAP
) {
2857 TRACE("loaded a bitmap\n");
2863 width
= lpgm
->gmBlackBoxX
;
2864 height
= lpgm
->gmBlackBoxY
;
2865 pitch
= ((width
+ 31) >> 5) << 2;
2866 needed
= pitch
* height
;
2868 if(!buf
|| !buflen
) break;
2870 switch(ft_face
->glyph
->format
) {
2871 case ft_glyph_format_bitmap
:
2873 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
2874 INT w
= (ft_face
->glyph
->bitmap
.width
+ 7) >> 3;
2875 INT h
= ft_face
->glyph
->bitmap
.rows
;
2877 memcpy(dst
, src
, w
);
2878 src
+= ft_face
->glyph
->bitmap
.pitch
;
2884 case ft_glyph_format_outline
:
2885 ft_bitmap
.width
= width
;
2886 ft_bitmap
.rows
= height
;
2887 ft_bitmap
.pitch
= pitch
;
2888 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
2889 ft_bitmap
.buffer
= buf
;
2891 if(needsTransform
) {
2892 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
2895 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
2897 /* Note: FreeType will only set 'black' bits for us. */
2898 memset(buf
, 0, needed
);
2899 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
2903 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
2908 case GGO_GRAY2_BITMAP
:
2909 case GGO_GRAY4_BITMAP
:
2910 case GGO_GRAY8_BITMAP
:
2911 case WINE_GGO_GRAY16_BITMAP
:
2913 unsigned int mult
, row
, col
;
2916 width
= lpgm
->gmBlackBoxX
;
2917 height
= lpgm
->gmBlackBoxY
;
2918 pitch
= (width
+ 3) / 4 * 4;
2919 needed
= pitch
* height
;
2921 if(!buf
|| !buflen
) break;
2922 ft_bitmap
.width
= width
;
2923 ft_bitmap
.rows
= height
;
2924 ft_bitmap
.pitch
= pitch
;
2925 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
2926 ft_bitmap
.buffer
= buf
;
2928 if(needsTransform
) {
2929 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
2932 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
2934 memset(ft_bitmap
.buffer
, 0, buflen
);
2936 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
2938 if(format
== GGO_GRAY2_BITMAP
)
2940 else if(format
== GGO_GRAY4_BITMAP
)
2942 else if(format
== GGO_GRAY8_BITMAP
)
2944 else if(format
== WINE_GGO_GRAY16_BITMAP
)
2952 for(row
= 0; row
< height
; row
++) {
2954 for(col
= 0; col
< width
; col
++, ptr
++) {
2955 *ptr
= (((int)*ptr
) * mult
+ 128) / 256;
2964 int contour
, point
= 0, first_pt
;
2965 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
2966 TTPOLYGONHEADER
*pph
;
2968 DWORD pph_start
, cpfx
, type
;
2970 if(buflen
== 0) buf
= NULL
;
2972 if (needsTransform
&& buf
) {
2973 pFT_Outline_Transform(outline
, &transMat
);
2976 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
2978 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
2981 pph
->dwType
= TT_POLYGON_TYPE
;
2982 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
2984 needed
+= sizeof(*pph
);
2986 while(point
<= outline
->contours
[contour
]) {
2987 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
2988 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
2989 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
2993 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
2996 } while(point
<= outline
->contours
[contour
] &&
2997 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
2998 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
2999 /* At the end of a contour Windows adds the start point, but
3001 if(point
> outline
->contours
[contour
] &&
3002 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
3004 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
3006 } else if(point
<= outline
->contours
[contour
] &&
3007 outline
->tags
[point
] & FT_Curve_Tag_On
) {
3008 /* add closing pt for bezier */
3010 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
3018 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
3021 pph
->cb
= needed
- pph_start
;
3027 /* Convert the quadratic Beziers to cubic Beziers.
3028 The parametric eqn for a cubic Bezier is, from PLRM:
3029 r(t) = at^3 + bt^2 + ct + r0
3030 with the control points:
3035 A quadratic Beizer has the form:
3036 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3038 So equating powers of t leads to:
3039 r1 = 2/3 p1 + 1/3 p0
3040 r2 = 2/3 p1 + 1/3 p2
3041 and of course r0 = p0, r3 = p2
3044 int contour
, point
= 0, first_pt
;
3045 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
3046 TTPOLYGONHEADER
*pph
;
3048 DWORD pph_start
, cpfx
, type
;
3049 FT_Vector cubic_control
[4];
3050 if(buflen
== 0) buf
= NULL
;
3052 if (needsTransform
&& buf
) {
3053 pFT_Outline_Transform(outline
, &transMat
);
3056 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
3058 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
3061 pph
->dwType
= TT_POLYGON_TYPE
;
3062 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
3064 needed
+= sizeof(*pph
);
3066 while(point
<= outline
->contours
[contour
]) {
3067 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
3068 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
3069 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
3072 if(type
== TT_PRIM_LINE
) {
3074 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
3078 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
3081 /* FIXME: Possible optimization in endpoint calculation
3082 if there are two consecutive curves */
3083 cubic_control
[0] = outline
->points
[point
-1];
3084 if(!(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
3085 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
3086 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
3087 cubic_control
[0].x
>>= 1;
3088 cubic_control
[0].y
>>= 1;
3090 if(point
+1 > outline
->contours
[contour
])
3091 cubic_control
[3] = outline
->points
[first_pt
];
3093 cubic_control
[3] = outline
->points
[point
+1];
3094 if(!(outline
->tags
[point
+1] & FT_Curve_Tag_On
)) {
3095 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
3096 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
3097 cubic_control
[3].x
>>= 1;
3098 cubic_control
[3].y
>>= 1;
3101 /* r1 = 1/3 p0 + 2/3 p1
3102 r2 = 1/3 p2 + 2/3 p1 */
3103 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
3104 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
3105 cubic_control
[2] = cubic_control
[1];
3106 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
3107 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
3108 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
3109 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
3111 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
3112 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
3113 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
3118 } while(point
<= outline
->contours
[contour
] &&
3119 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
3120 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
3121 /* At the end of a contour Windows adds the start point,
3122 but only for Beziers and we've already done that.
3124 if(point
<= outline
->contours
[contour
] &&
3125 outline
->tags
[point
] & FT_Curve_Tag_On
) {
3126 /* This is the closing pt of a bezier, but we've already
3127 added it, so just inc point and carry on */
3134 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
3137 pph
->cb
= needed
- pph_start
;
3143 FIXME("Unsupported format %d\n", format
);
3149 static BOOL
get_bitmap_text_metrics(GdiFont font
)
3151 FT_Face ft_face
= font
->ft_face
;
3152 #ifdef HAVE_FREETYPE_FTWINFNT_H
3153 FT_WinFNT_HeaderRec winfnt_header
;
3155 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
3156 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
3157 font
->potm
->otmSize
= size
;
3159 #define TM font->potm->otmTextMetrics
3160 #ifdef HAVE_FREETYPE_FTWINFNT_H
3161 if(pFT_Get_WinFNT_Header
&& !pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
3163 TM
.tmHeight
= winfnt_header
.pixel_height
;
3164 TM
.tmAscent
= winfnt_header
.ascent
;
3165 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
3166 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
3167 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
3168 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
3169 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
3170 TM
.tmWeight
= winfnt_header
.weight
;
3172 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
3173 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
3174 TM
.tmFirstChar
= winfnt_header
.first_char
;
3175 TM
.tmLastChar
= winfnt_header
.last_char
;
3176 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
3177 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
3178 TM
.tmItalic
= winfnt_header
.italic
;
3179 TM
.tmUnderlined
= font
->underline
;
3180 TM
.tmStruckOut
= font
->strikeout
;
3181 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
3182 TM
.tmCharSet
= winfnt_header
.charset
;
3187 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
3188 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
3189 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
3190 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
3191 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
3192 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
3193 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
3194 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
3196 TM
.tmDigitizedAspectX
= 96; /* FIXME */
3197 TM
.tmDigitizedAspectY
= 96; /* FIXME */
3199 TM
.tmLastChar
= 255;
3200 TM
.tmDefaultChar
= 32;
3201 TM
.tmBreakChar
= 32;
3202 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
3203 TM
.tmUnderlined
= font
->underline
;
3204 TM
.tmStruckOut
= font
->strikeout
;
3205 /* NB inverted meaning of TMPF_FIXED_PITCH */
3206 TM
.tmPitchAndFamily
= ft_face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
? 0 : TMPF_FIXED_PITCH
;
3207 TM
.tmCharSet
= font
->charset
;
3214 /*************************************************************
3215 * WineEngGetTextMetrics
3218 BOOL
WineEngGetTextMetrics(GdiFont font
, LPTEXTMETRICW ptm
)
3221 if(!WineEngGetOutlineTextMetrics(font
, 0, NULL
))
3222 if(!get_bitmap_text_metrics(font
))
3225 if(!font
->potm
) return FALSE
;
3226 memcpy(ptm
, &font
->potm
->otmTextMetrics
, sizeof(*ptm
));
3228 if (font
->aveWidth
) {
3229 ptm
->tmAveCharWidth
= font
->aveWidth
* font
->font_desc
.matrix
.eM11
;
3235 /*************************************************************
3236 * WineEngGetOutlineTextMetrics
3239 UINT
WineEngGetOutlineTextMetrics(GdiFont font
, UINT cbSize
,
3240 OUTLINETEXTMETRICW
*potm
)
3242 FT_Face ft_face
= font
->ft_face
;
3243 UINT needed
, lenfam
, lensty
, ret
;
3245 TT_HoriHeader
*pHori
;
3246 TT_Postscript
*pPost
;
3247 FT_Fixed x_scale
, y_scale
;
3248 WCHAR
*family_nameW
, *style_nameW
;
3249 static const WCHAR spaceW
[] = {' ', '\0'};
3251 INT ascent
, descent
;
3253 TRACE("font=%p\n", font
);
3255 if(!FT_IS_SCALABLE(ft_face
))
3259 if(cbSize
>= font
->potm
->otmSize
)
3260 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
3261 return font
->potm
->otmSize
;
3265 needed
= sizeof(*potm
);
3267 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
3268 family_nameW
= strdupW(font
->name
);
3270 lensty
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0)
3272 style_nameW
= HeapAlloc(GetProcessHeap(), 0, lensty
);
3273 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1,
3274 style_nameW
, lensty
/sizeof(WCHAR
));
3276 /* These names should be read from the TT name table */
3278 /* length of otmpFamilyName */
3281 /* length of otmpFaceName */
3282 if(!strcasecmp(ft_face
->style_name
, "regular")) {
3283 needed
+= lenfam
; /* just the family name */
3285 needed
+= lenfam
+ lensty
; /* family + " " + style */
3288 /* length of otmpStyleName */
3291 /* length of otmpFullName */
3292 needed
+= lenfam
+ lensty
;
3295 x_scale
= ft_face
->size
->metrics
.x_scale
;
3296 y_scale
= ft_face
->size
->metrics
.y_scale
;
3298 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
3300 FIXME("Can't find OS/2 table - not TT font?\n");
3305 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
3307 FIXME("Can't find HHEA table - not TT font?\n");
3312 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
3314 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",
3315 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
3316 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
3317 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
3318 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
3319 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
3321 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
3322 font
->potm
->otmSize
= needed
;
3324 #define TM font->potm->otmTextMetrics
3326 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0) {
3327 ascent
= pHori
->Ascender
;
3328 descent
= -pHori
->Descender
;
3330 ascent
= pOS2
->usWinAscent
;
3331 descent
= pOS2
->usWinDescent
;
3335 TM
.tmAscent
= font
->yMax
;
3336 TM
.tmDescent
= -font
->yMin
;
3337 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
3339 TM
.tmAscent
= (pFT_MulFix(ascent
, y_scale
) + 32) >> 6;
3340 TM
.tmDescent
= (pFT_MulFix(descent
, y_scale
) + 32) >> 6;
3341 TM
.tmInternalLeading
= (pFT_MulFix(ascent
+ descent
3342 - ft_face
->units_per_EM
, y_scale
) + 32) >> 6;
3345 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
3348 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
3350 TM
.tmExternalLeading
= max(0, (pFT_MulFix(pHori
->Line_Gap
-
3351 ((ascent
+ descent
) -
3352 (pHori
->Ascender
- pHori
->Descender
)), y_scale
) + 32) >> 6);
3354 TM
.tmAveCharWidth
= (pFT_MulFix(pOS2
->xAvgCharWidth
, x_scale
) + 32) >> 6;
3355 if (TM
.tmAveCharWidth
== 0) {
3356 TM
.tmAveCharWidth
= 1;
3358 TM
.tmMaxCharWidth
= (pFT_MulFix(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
3359 TM
.tmWeight
= font
->fake_bold
? FW_BOLD
: pOS2
->usWeightClass
;
3361 TM
.tmDigitizedAspectX
= 300;
3362 TM
.tmDigitizedAspectY
= 300;
3363 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
;
3364 TM
.tmLastChar
= pOS2
->usLastCharIndex
;
3365 TM
.tmDefaultChar
= pOS2
->usDefaultChar
;
3366 TM
.tmBreakChar
= pOS2
->usBreakChar
? pOS2
->usBreakChar
: ' ';
3367 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
3368 TM
.tmUnderlined
= font
->underline
;
3369 TM
.tmStruckOut
= font
->strikeout
;
3371 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
3372 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
3373 (pOS2
->version
== 0xFFFFU
||
3374 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
3375 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
3377 TM
.tmPitchAndFamily
= 0;
3379 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
]) {
3380 case PAN_FAMILY_SCRIPT
:
3381 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
3383 case PAN_FAMILY_DECORATIVE
:
3384 case PAN_FAMILY_PICTORIAL
:
3385 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
3387 case PAN_FAMILY_TEXT_DISPLAY
:
3388 if(TM
.tmPitchAndFamily
== 0) /* fixed */
3389 TM
.tmPitchAndFamily
= FF_MODERN
;
3391 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
]) {
3392 case PAN_SERIF_NORMAL_SANS
:
3393 case PAN_SERIF_OBTUSE_SANS
:
3394 case PAN_SERIF_PERP_SANS
:
3395 TM
.tmPitchAndFamily
|= FF_SWISS
;
3398 TM
.tmPitchAndFamily
|= FF_ROMAN
;
3403 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
3406 if(FT_IS_SCALABLE(ft_face
))
3407 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
3408 if(FT_IS_SFNT(ft_face
))
3409 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
3411 TM
.tmCharSet
= font
->charset
;
3414 font
->potm
->otmFiller
= 0;
3415 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
3416 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
3417 font
->potm
->otmfsType
= pOS2
->fsType
;
3418 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
3419 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
3420 font
->potm
->otmItalicAngle
= 0; /* POST table */
3421 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
3422 font
->potm
->otmAscent
= (pFT_MulFix(pOS2
->sTypoAscender
, y_scale
) + 32) >> 6;
3423 font
->potm
->otmDescent
= (pFT_MulFix(pOS2
->sTypoDescender
, y_scale
) + 32) >> 6;
3424 font
->potm
->otmLineGap
= (pFT_MulFix(pOS2
->sTypoLineGap
, y_scale
) + 32) >> 6;
3425 font
->potm
->otmsCapEmHeight
= (pFT_MulFix(pOS2
->sCapHeight
, y_scale
) + 32) >> 6;
3426 font
->potm
->otmsXHeight
= (pFT_MulFix(pOS2
->sxHeight
, y_scale
) + 32) >> 6;
3427 font
->potm
->otmrcFontBox
.left
= (pFT_MulFix(ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
3428 font
->potm
->otmrcFontBox
.right
= (pFT_MulFix(ft_face
->bbox
.xMax
, x_scale
) + 32) >> 6;
3429 font
->potm
->otmrcFontBox
.top
= (pFT_MulFix(ft_face
->bbox
.yMax
, y_scale
) + 32) >> 6;
3430 font
->potm
->otmrcFontBox
.bottom
= (pFT_MulFix(ft_face
->bbox
.yMin
, y_scale
) + 32) >> 6;
3431 font
->potm
->otmMacAscent
= 0; /* where do these come from ? */
3432 font
->potm
->otmMacDescent
= 0;
3433 font
->potm
->otmMacLineGap
= 0;
3434 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
3435 font
->potm
->otmptSubscriptSize
.x
= (pFT_MulFix(pOS2
->ySubscriptXSize
, x_scale
) + 32) >> 6;
3436 font
->potm
->otmptSubscriptSize
.y
= (pFT_MulFix(pOS2
->ySubscriptYSize
, y_scale
) + 32) >> 6;
3437 font
->potm
->otmptSubscriptOffset
.x
= (pFT_MulFix(pOS2
->ySubscriptXOffset
, x_scale
) + 32) >> 6;
3438 font
->potm
->otmptSubscriptOffset
.y
= (pFT_MulFix(pOS2
->ySubscriptYOffset
, y_scale
) + 32) >> 6;
3439 font
->potm
->otmptSuperscriptSize
.x
= (pFT_MulFix(pOS2
->ySuperscriptXSize
, x_scale
) + 32) >> 6;
3440 font
->potm
->otmptSuperscriptSize
.y
= (pFT_MulFix(pOS2
->ySuperscriptYSize
, y_scale
) + 32) >> 6;
3441 font
->potm
->otmptSuperscriptOffset
.x
= (pFT_MulFix(pOS2
->ySuperscriptXOffset
, x_scale
) + 32) >> 6;
3442 font
->potm
->otmptSuperscriptOffset
.y
= (pFT_MulFix(pOS2
->ySuperscriptYOffset
, y_scale
) + 32) >> 6;
3443 font
->potm
->otmsStrikeoutSize
= (pFT_MulFix(pOS2
->yStrikeoutSize
, y_scale
) + 32) >> 6;
3444 font
->potm
->otmsStrikeoutPosition
= (pFT_MulFix(pOS2
->yStrikeoutPosition
, y_scale
) + 32) >> 6;
3446 font
->potm
->otmsUnderscoreSize
= 0;
3447 font
->potm
->otmsUnderscorePosition
= 0;
3449 font
->potm
->otmsUnderscoreSize
= (pFT_MulFix(pPost
->underlineThickness
, y_scale
) + 32) >> 6;
3450 font
->potm
->otmsUnderscorePosition
= (pFT_MulFix(pPost
->underlinePosition
, y_scale
) + 32) >> 6;
3453 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
3454 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
3455 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
3456 strcpyW((WCHAR
*)cp
, family_nameW
);
3458 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
3459 strcpyW((WCHAR
*)cp
, style_nameW
);
3461 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
3462 strcpyW((WCHAR
*)cp
, family_nameW
);
3463 if(strcasecmp(ft_face
->style_name
, "regular")) {
3464 strcatW((WCHAR
*)cp
, spaceW
);
3465 strcatW((WCHAR
*)cp
, style_nameW
);
3466 cp
+= lenfam
+ lensty
;
3469 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
3470 strcpyW((WCHAR
*)cp
, family_nameW
);
3471 strcatW((WCHAR
*)cp
, spaceW
);
3472 strcatW((WCHAR
*)cp
, style_nameW
);
3475 if(potm
&& needed
<= cbSize
)
3476 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
3479 HeapFree(GetProcessHeap(), 0, style_nameW
);
3480 HeapFree(GetProcessHeap(), 0, family_nameW
);
3485 static BOOL
load_child_font(GdiFont font
, CHILD_FONT
*child
)
3487 HFONTLIST
*hfontlist
;
3488 child
->font
= alloc_font();
3489 child
->font
->ft_face
= OpenFontFile(child
->font
, child
->file_name
, child
->index
, 0, -font
->ppem
);
3490 if(!child
->font
->ft_face
)
3492 free_font(child
->font
);
3497 child
->font
->orientation
= font
->orientation
;
3498 hfontlist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist
));
3499 hfontlist
->hfont
= CreateFontIndirectW(&font
->font_desc
.lf
);
3500 list_add_head(&child
->font
->hfontlist
, &hfontlist
->entry
);
3501 child
->font
->base_font
= font
;
3502 list_add_head(&child_font_list
, &child
->font
->entry
);
3503 TRACE("created child font hfont %p for base %p child %p\n", hfontlist
->hfont
, font
, child
->font
);
3507 static BOOL
get_glyph_index_linked(GdiFont font
, UINT c
, GdiFont
*linked_font
, FT_UInt
*glyph
)
3510 CHILD_FONT
*child_font
;
3513 font
= font
->base_font
;
3515 *linked_font
= font
;
3517 if((*glyph
= get_glyph_index(font
, c
)))
3520 LIST_FOR_EACH_ENTRY(child_font
, &font
->child_fonts
, CHILD_FONT
, entry
)
3522 if(!child_font
->font
)
3523 if(!load_child_font(font
, child_font
))
3526 if(!child_font
->font
->ft_face
)
3528 g
= get_glyph_index(child_font
->font
, c
);
3532 *linked_font
= child_font
->font
;
3539 /*************************************************************
3540 * WineEngGetCharWidth
3543 BOOL
WineEngGetCharWidth(GdiFont font
, UINT firstChar
, UINT lastChar
,
3548 FT_UInt glyph_index
;
3549 GdiFont linked_font
;
3551 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
3553 for(c
= firstChar
; c
<= lastChar
; c
++) {
3554 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
3555 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
3556 &gm
, 0, NULL
, NULL
);
3557 buffer
[c
- firstChar
] = linked_font
->gm
[glyph_index
].adv
;
3562 /*************************************************************
3563 * WineEngGetCharABCWidths
3566 BOOL
WineEngGetCharABCWidths(GdiFont font
, UINT firstChar
, UINT lastChar
,
3571 FT_UInt glyph_index
;
3572 GdiFont linked_font
;
3574 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
3576 if(!FT_IS_SCALABLE(font
->ft_face
))
3579 for(c
= firstChar
; c
<= lastChar
; c
++) {
3580 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
3581 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
3582 &gm
, 0, NULL
, NULL
);
3583 buffer
[c
- firstChar
].abcA
= linked_font
->gm
[glyph_index
].lsb
;
3584 buffer
[c
- firstChar
].abcB
= linked_font
->gm
[glyph_index
].bbx
;
3585 buffer
[c
- firstChar
].abcC
= linked_font
->gm
[glyph_index
].adv
- linked_font
->gm
[glyph_index
].lsb
-
3586 linked_font
->gm
[glyph_index
].bbx
;
3591 /*************************************************************
3592 * WineEngGetTextExtentPoint
3595 BOOL
WineEngGetTextExtentPoint(GdiFont font
, LPCWSTR wstr
, INT count
,
3601 FT_UInt glyph_index
;
3602 GdiFont linked_font
;
3604 TRACE("%p, %s, %d, %p\n", font
, debugstr_wn(wstr
, count
), count
,
3608 WineEngGetTextMetrics(font
, &tm
);
3609 size
->cy
= tm
.tmHeight
;
3611 for(idx
= 0; idx
< count
; idx
++) {
3612 get_glyph_index_linked(font
, wstr
[idx
], &linked_font
, &glyph_index
);
3613 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
3614 &gm
, 0, NULL
, NULL
);
3615 size
->cx
+= linked_font
->gm
[glyph_index
].adv
;
3617 TRACE("return %ld,%ld\n", size
->cx
, size
->cy
);
3621 /*************************************************************
3622 * WineEngGetTextExtentPointI
3625 BOOL
WineEngGetTextExtentPointI(GdiFont font
, const WORD
*indices
, INT count
,
3632 TRACE("%p, %p, %d, %p\n", font
, indices
, count
, size
);
3635 WineEngGetTextMetrics(font
, &tm
);
3636 size
->cy
= tm
.tmHeight
;
3638 for(idx
= 0; idx
< count
; idx
++) {
3639 WineEngGetGlyphOutline(font
, indices
[idx
],
3640 GGO_METRICS
| GGO_GLYPH_INDEX
, &gm
, 0, NULL
,
3642 size
->cx
+= font
->gm
[indices
[idx
]].adv
;
3644 TRACE("return %ld,%ld\n", size
->cx
, size
->cy
);
3648 /*************************************************************
3649 * WineEngGetFontData
3652 DWORD
WineEngGetFontData(GdiFont font
, DWORD table
, DWORD offset
, LPVOID buf
,
3655 FT_Face ft_face
= font
->ft_face
;
3659 TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
3660 font
, table
, offset
, buf
, cbData
);
3662 if(!FT_IS_SFNT(ft_face
))
3670 if(table
) { /* MS tags differ in endidness from FT ones */
3671 table
= table
>> 24 | table
<< 24 |
3672 (table
>> 8 & 0xff00) | (table
<< 8 & 0xff0000);
3675 /* If the FT_Load_Sfnt_Table function is there we'll use it */
3676 if(pFT_Load_Sfnt_Table
)
3677 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, buf
, &len
);
3678 else { /* Do it the hard way */
3679 TT_Face tt_face
= (TT_Face
) ft_face
;
3680 SFNT_Interface
*sfnt
;
3681 if (FT_Version
.major
==2 && FT_Version
.minor
==0)
3684 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 528);
3688 /* A field was added in the middle of the structure in 2.1.x */
3689 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 532);
3691 err
= sfnt
->load_any(tt_face
, table
, offset
, buf
, &len
);
3694 TRACE("Can't find table %08lx.\n", table
);
3700 /*************************************************************
3701 * WineEngGetTextFace
3704 INT
WineEngGetTextFace(GdiFont font
, INT count
, LPWSTR str
)
3707 lstrcpynW(str
, font
->name
, count
);
3708 return strlenW(font
->name
);
3710 return strlenW(font
->name
) + 1;
3713 UINT
WineEngGetTextCharsetInfo(GdiFont font
, LPFONTSIGNATURE fs
, DWORD flags
)
3715 if (fs
) memcpy(fs
, &font
->fs
, sizeof(FONTSIGNATURE
));
3716 return font
->charset
;
3719 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
3721 GdiFont font
= dc
->gdiFont
, linked_font
;
3722 struct list
*first_hfont
;
3725 ret
= get_glyph_index_linked(font
, c
, &linked_font
, glyph
);
3726 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph
, linked_font
);
3727 if(font
== linked_font
)
3728 *new_hfont
= dc
->hFont
;
3731 first_hfont
= list_head(&linked_font
->hfontlist
);
3732 *new_hfont
= LIST_ENTRY(first_hfont
, struct tagHFONTLIST
, entry
)->hfont
;
3739 /*************************************************************
3742 BOOL WINAPI
FontIsLinked(HDC hdc
)
3744 DC
*dc
= DC_GetDCPtr(hdc
);
3747 if(!dc
) return FALSE
;
3748 if(dc
->gdiFont
&& !list_empty(&dc
->gdiFont
->child_fonts
))
3750 GDI_ReleaseObj(hdc
);
3751 TRACE("returning %d\n", ret
);
3755 #else /* HAVE_FREETYPE */
3757 BOOL
WineEngInit(void)
3761 GdiFont
WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
3765 BOOL
WineEngDestroyFontInstance(HFONT hfont
)
3770 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
3775 DWORD
WineEngGetGlyphIndices(GdiFont font
, LPCWSTR lpstr
, INT count
,
3776 LPWORD pgi
, DWORD flags
)
3781 DWORD
WineEngGetGlyphOutline(GdiFont font
, UINT glyph
, UINT format
,
3782 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
3785 ERR("called but we don't have FreeType\n");
3789 BOOL
WineEngGetTextMetrics(GdiFont font
, LPTEXTMETRICW ptm
)
3791 ERR("called but we don't have FreeType\n");
3795 UINT
WineEngGetOutlineTextMetrics(GdiFont font
, UINT cbSize
,
3796 OUTLINETEXTMETRICW
*potm
)
3798 ERR("called but we don't have FreeType\n");
3802 BOOL
WineEngGetCharWidth(GdiFont font
, UINT firstChar
, UINT lastChar
,
3805 ERR("called but we don't have FreeType\n");
3809 BOOL
WineEngGetCharABCWidths(GdiFont font
, UINT firstChar
, UINT lastChar
,
3812 ERR("called but we don't have FreeType\n");
3816 BOOL
WineEngGetTextExtentPoint(GdiFont font
, LPCWSTR wstr
, INT count
,
3819 ERR("called but we don't have FreeType\n");
3823 BOOL
WineEngGetTextExtentPointI(GdiFont font
, const WORD
*indices
, INT count
,
3826 ERR("called but we don't have FreeType\n");
3830 DWORD
WineEngGetFontData(GdiFont font
, DWORD table
, DWORD offset
, LPVOID buf
,
3833 ERR("called but we don't have FreeType\n");
3837 INT
WineEngGetTextFace(GdiFont font
, INT count
, LPWSTR str
)
3839 ERR("called but we don't have FreeType\n");
3843 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
3849 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
3855 UINT
WineEngGetTextCharsetInfo(GdiFont font
, LPFONTSIGNATURE fs
, DWORD flags
)
3858 return DEFAULT_CHARSET
;
3861 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
3866 BOOL WINAPI
FontIsLinked(HDC hdc
)
3870 #endif /* HAVE_FREETYPE */