2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
6 * This file contains the WineEng* functions.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "wine/port.h"
40 #include "gdi_private.h"
41 #include "wine/unicode.h"
42 #include "wine/debug.h"
43 #include "wine/list.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(font);
49 #ifdef HAVE_FT2BUILD_H
52 #ifdef HAVE_FREETYPE_FREETYPE_H
53 #include <freetype/freetype.h>
55 #ifdef HAVE_FREETYPE_FTGLYPH_H
56 #include <freetype/ftglyph.h>
58 #ifdef HAVE_FREETYPE_TTTABLES_H
59 #include <freetype/tttables.h>
61 #ifdef HAVE_FREETYPE_FTSNAMES_H
62 #include <freetype/ftsnames.h>
64 # ifdef HAVE_FREETYPE_FTNAMES_H
65 # include <freetype/ftnames.h>
68 #ifdef HAVE_FREETYPE_TTNAMEID_H
69 #include <freetype/ttnameid.h>
71 #ifdef HAVE_FREETYPE_FTOUTLN_H
72 #include <freetype/ftoutln.h>
74 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
75 #include <freetype/internal/sfnt.h>
77 #ifdef HAVE_FREETYPE_FTTRIGON_H
78 #include <freetype/fttrigon.h>
80 #ifdef HAVE_FREETYPE_FTWINFNT_H
81 #include <freetype/ftwinfnt.h>
84 #ifndef SONAME_LIBFREETYPE
85 #define SONAME_LIBFREETYPE "libfreetype.so"
88 static FT_Library library = 0;
95 static FT_Version_t FT_Version;
96 static DWORD FT_SimpleVersion;
98 static void *ft_handle = NULL;
100 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
101 MAKE_FUNCPTR(FT_Vector_Unit);
102 MAKE_FUNCPTR(FT_Done_Face);
103 MAKE_FUNCPTR(FT_Get_Char_Index);
104 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
105 MAKE_FUNCPTR(FT_Init_FreeType);
106 MAKE_FUNCPTR(FT_Load_Glyph);
107 MAKE_FUNCPTR(FT_Matrix_Multiply);
108 MAKE_FUNCPTR(FT_MulFix);
109 MAKE_FUNCPTR(FT_New_Face);
110 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
111 MAKE_FUNCPTR(FT_Outline_Transform);
112 MAKE_FUNCPTR(FT_Outline_Translate);
113 MAKE_FUNCPTR(FT_Select_Charmap);
114 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
115 MAKE_FUNCPTR(FT_Vector_Transform);
116 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
117 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
118 static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*);
119 #ifdef HAVE_FREETYPE_FTWINFNT_H
120 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
123 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
124 #include <fontconfig/fontconfig.h>
125 MAKE_FUNCPTR(FcConfigGetCurrent);
126 MAKE_FUNCPTR(FcFontList);
127 MAKE_FUNCPTR(FcFontSetDestroy);
128 MAKE_FUNCPTR(FcInit);
129 MAKE_FUNCPTR(FcObjectSetAdd);
130 MAKE_FUNCPTR(FcObjectSetCreate);
131 MAKE_FUNCPTR(FcObjectSetDestroy);
132 MAKE_FUNCPTR(FcPatternCreate);
133 MAKE_FUNCPTR(FcPatternDestroy);
134 MAKE_FUNCPTR(FcPatternGet);
135 #ifndef SONAME_LIBFONTCONFIG
136 #define SONAME_LIBFONTCONFIG "libfontconfig.so"
143 #define GET_BE_WORD(ptr) MAKEWORD( ((BYTE *)(ptr))[1], ((BYTE *)(ptr))[0] )
145 /* This is bascially a copy of FT_Bitmap_Size with an extra element added */
152 FT_Short internal_leading;
155 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
156 So to let this compile on older versions of FreeType we'll define the
157 new structure here. */
159 FT_Short height, width;
160 FT_Pos size, x_ppem, y_ppem;
163 typedef struct tagFace {
170 FT_Fixed font_version;
172 Bitmap_Size size; /* set if face is a bitmap */
173 BOOL external; /* TRUE if we should manually add this font to the registry */
174 struct tagFace *next;
175 struct tagFamily *family;
178 typedef struct tagFamily {
181 struct tagFamily *next;
186 INT adv; /* These three hold to widths of the unrotated chars */
203 typedef struct tagHFONTLIST {
220 struct list hfontlist;
225 OUTLINETEXTMETRICW *potm;
229 #define INIT_GM_SIZE 128
231 static struct list gdi_font_list = LIST_INIT(gdi_font_list);
232 static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
233 #define UNUSED_CACHE_SIZE 10
235 static Family *FontList = NULL;
237 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ',
238 'R','o','m','a','n','\0'};
239 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
240 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
242 static const WCHAR defSystem[] = {'A','r','i','a','l','\0'};
243 static const WCHAR SystemW[] = {'S','y','s','t','e','m','\0'};
244 static const WCHAR MSSansSerifW[] = {'M','S',' ','S','a','n','s',' ',
245 'S','e','r','i','f','\0'};
246 static const WCHAR HelvW[] = {'H','e','l','v','\0'};
247 static const WCHAR RegularW[] = {'R','e','g','u','l','a','r','\0'};
249 static const WCHAR fontsW[] = {'\\','F','o','n','t','s','\0'};
250 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
251 'W','i','n','d','o','w','s','\\',
252 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
253 'F','o','n','t','s','\0'};
255 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
256 'W','i','n','d','o','w','s',' ','N','T','\\',
257 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
258 'F','o','n','t','s','\0'};
260 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
261 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
262 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
263 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
265 static const WCHAR *SystemFontValues[4] = {
272 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\','W','i','n','e','\\',
273 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
275 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
276 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
277 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
278 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
279 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
280 'E','u','r','o','p','e','a','n','\0'};
281 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
282 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
283 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
284 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
285 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
286 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
287 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
288 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
289 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
290 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
291 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
292 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
294 static const WCHAR *ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
304 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
312 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
321 typedef struct tagFontSubst {
324 struct tagFontSubst *next;
327 static FontSubst *substlist = NULL;
328 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
330 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
333 /****************************************
334 * Notes on .fon files
336 * The fonts System, FixedSys and Terminal are special. There are typically multiple
337 * versions installed for different resolutions and codepages. Windows stores which one to use
338 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
340 * FIXEDFON.FON FixedSys
342 * OEMFONT.FON Termial
343 * LogPixels Current dpi set by the display control panel applet
344 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
345 * also has a LogPixels value that appears to mirror this)
347 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
348 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
349 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
350 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
351 * so that makes sense.
353 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
354 * to be mapped into the registry on Windows 2000 at least).
357 * ega80woa.fon=ega80850.fon
358 * ega40woa.fon=ega40850.fon
359 * cga80woa.fon=cga80850.fon
360 * cga40woa.fon=cga40850.fon
364 static inline BOOL is_win9x(void)
366 return GetVersion() & 0x80000000;
369 This function builds an FT_Fixed from a float. It puts the integer part
370 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
371 It fails if the integer part of the float number is greater than SHORT_MAX.
373 static inline FT_Fixed FT_FixedFromFloat(float f)
376 unsigned short fract = (f - value) * 0xFFFF;
377 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
381 This function builds an FT_Fixed from a FIXED. It simply put f.value
382 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
384 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
386 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
389 #define ADDFONT_EXTERNAL_FONT 0x01
390 #define ADDFONT_FORCE_BITMAP 0x02
391 static BOOL AddFontFileToList(const char *file, char *fake_family, DWORD flags)
395 TT_Header *pHeader = NULL;
396 WCHAR *FamilyW, *StyleW;
399 Face **insertface, *next;
401 FT_Long face_index = 0, num_faces;
402 #ifdef HAVE_FREETYPE_FTWINFNT_H
403 FT_WinFNT_HeaderRec winfnt_header;
408 char *family_name = fake_family;
410 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
411 if((err = pFT_New_Face(library, file, face_index, &ft_face)) != 0) {
412 WARN("Unable to load font file %s err = %x\n", debugstr_a(file), err);
416 if(!FT_IS_SFNT(ft_face) && (FT_IS_SCALABLE(ft_face) || !(flags & ADDFONT_FORCE_BITMAP))) { /* for now we'll accept TT/OT or bitmap fonts*/
417 pFT_Done_Face(ft_face);
421 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
422 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
423 pFT_Done_Face(ft_face);
427 if(FT_IS_SFNT(ft_face) && (!pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2) ||
428 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
429 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))) {
430 TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
431 "Skipping this font.\n", debugstr_a(file));
432 pFT_Done_Face(ft_face);
436 if(!ft_face->family_name || !ft_face->style_name) {
437 TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file));
438 pFT_Done_Face(ft_face);
443 family_name = ft_face->family_name;
447 My_FT_Bitmap_Size *size = NULL;
449 if(!FT_IS_SCALABLE(ft_face))
450 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
452 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
453 FamilyW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
454 MultiByteToWideChar(CP_ACP, 0, family_name, -1, FamilyW, len);
458 if(!strcmpW((*pfamily)->FamilyName, FamilyW))
460 pfamily = &(*pfamily)->next;
463 *pfamily = HeapAlloc(GetProcessHeap(), 0, sizeof(**pfamily));
464 (*pfamily)->FamilyName = FamilyW;
465 (*pfamily)->FirstFace = NULL;
466 (*pfamily)->next = NULL;
468 HeapFree(GetProcessHeap(), 0, FamilyW);
471 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
472 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
473 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
476 for(insertface = &(*pfamily)->FirstFace; *insertface;
477 insertface = &(*insertface)->next) {
478 if(!strcmpW((*insertface)->StyleName, StyleW) && (FT_IS_SCALABLE(ft_face) || (size->y_ppem == (*insertface)->size.y_ppem))) {
479 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
480 debugstr_w((*pfamily)->FamilyName), debugstr_w(StyleW),
481 (*insertface)->font_version, pHeader ? pHeader->Font_Revision : 0);
484 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
485 HeapFree(GetProcessHeap(), 0, StyleW);
486 pFT_Done_Face(ft_face);
489 if(!pHeader || pHeader->Font_Revision <= (*insertface)->font_version) {
490 TRACE("Original font is newer so skipping this one\n");
491 HeapFree(GetProcessHeap(), 0, StyleW);
492 pFT_Done_Face(ft_face);
495 TRACE("Replacing original with this one\n");
496 next = (*insertface)->next;
497 HeapFree(GetProcessHeap(), 0, (*insertface)->file);
498 HeapFree(GetProcessHeap(), 0, (*insertface)->StyleName);
499 HeapFree(GetProcessHeap(), 0, *insertface);
504 *insertface = HeapAlloc(GetProcessHeap(), 0, sizeof(**insertface));
505 (*insertface)->StyleName = StyleW;
506 (*insertface)->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
507 strcpy((*insertface)->file, file);
508 (*insertface)->face_index = face_index;
509 (*insertface)->next = next;
510 (*insertface)->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
511 (*insertface)->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
512 (*insertface)->font_version = pHeader ? pHeader->Font_Revision : 0;
513 (*insertface)->family = *pfamily;
514 (*insertface)->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
516 if(FT_IS_SCALABLE(ft_face)) {
517 memset(&(*insertface)->size, 0, sizeof((*insertface)->size));
518 (*insertface)->scalable = TRUE;
520 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
521 size->height, size->width, size->size >> 6,
522 size->x_ppem >> 6, size->y_ppem >> 6);
523 (*insertface)->size.height = size->height;
524 (*insertface)->size.width = size->width;
525 (*insertface)->size.size = size->size;
526 (*insertface)->size.x_ppem = size->x_ppem;
527 (*insertface)->size.y_ppem = size->y_ppem;
528 (*insertface)->size.internal_leading = 0;
529 (*insertface)->scalable = FALSE;
532 memset(&(*insertface)->fs, 0, sizeof((*insertface)->fs));
534 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
536 (*insertface)->fs.fsCsb[0] = pOS2->ulCodePageRange1;
537 (*insertface)->fs.fsCsb[1] = pOS2->ulCodePageRange2;
538 (*insertface)->fs.fsUsb[0] = pOS2->ulUnicodeRange1;
539 (*insertface)->fs.fsUsb[1] = pOS2->ulUnicodeRange2;
540 (*insertface)->fs.fsUsb[2] = pOS2->ulUnicodeRange3;
541 (*insertface)->fs.fsUsb[3] = pOS2->ulUnicodeRange4;
542 if(pOS2->version == 0) {
545 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
546 (*insertface)->fs.fsCsb[0] |= 1;
548 (*insertface)->fs.fsCsb[0] |= 1L << 31;
551 #ifdef HAVE_FREETYPE_FTWINFNT_H
552 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
554 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
555 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
556 if(TranslateCharsetInfo((DWORD*)(UINT)winfnt_header.charset, &csi, TCI_SRCCHARSET))
557 memcpy(&(*insertface)->fs, &csi.fs, sizeof(csi.fs));
558 (*insertface)->size.internal_leading = winfnt_header.internal_leading;
561 TRACE("fsCsb = %08lx %08lx/%08lx %08lx %08lx %08lx\n",
562 (*insertface)->fs.fsCsb[0], (*insertface)->fs.fsCsb[1],
563 (*insertface)->fs.fsUsb[0], (*insertface)->fs.fsUsb[1],
564 (*insertface)->fs.fsUsb[2], (*insertface)->fs.fsUsb[3]);
567 if((*insertface)->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
568 for(i = 0; i < ft_face->num_charmaps; i++) {
569 switch(ft_face->charmaps[i]->encoding) {
570 case ft_encoding_unicode:
571 case ft_encoding_apple_roman:
572 (*insertface)->fs.fsCsb[0] |= 1;
574 case ft_encoding_symbol:
575 (*insertface)->fs.fsCsb[0] |= 1L << 31;
583 if((*insertface)->fs.fsCsb[0] & ~(1L << 31))
584 have_installed_roman_font = TRUE;
585 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
587 num_faces = ft_face->num_faces;
588 pFT_Done_Face(ft_face);
589 TRACE("Added font %s %s\n", debugstr_w((*pfamily)->FamilyName),
591 } while(num_faces > ++face_index);
595 static void DumpFontList(void)
600 for(family = FontList; family; family = family->next) {
601 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
602 for(face = family->FirstFace; face; face = face->next) {
603 TRACE("\t%s", debugstr_w(face->StyleName));
605 TRACE(" %ld", face->size.y_ppem >> 6);
612 static void DumpSubstList(void)
616 for(psub = substlist; psub; psub = psub->next)
617 if(psub->from.charset != -1 || psub->to.charset != -1)
618 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
619 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
621 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
622 debugstr_w(psub->to.name));
626 static LPWSTR strdupW(LPWSTR p)
629 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
630 ret = HeapAlloc(GetProcessHeap(), 0, len);
635 static void split_subst_info(NameCs *nc, LPSTR str)
637 CHAR *p = strrchr(str, ',');
642 nc->charset = strtol(p+1, NULL, 10);
645 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
646 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
647 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
650 static void LoadSubstList(void)
652 FontSubst *psub, **ppsub;
654 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
659 for(psub = substlist; psub;) {
661 HeapFree(GetProcessHeap(), 0, psub->to.name);
662 HeapFree(GetProcessHeap(), 0, psub->from.name);
665 HeapFree(GetProcessHeap(), 0, ptmp);
670 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
671 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
672 &hkey) == ERROR_SUCCESS) {
674 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
675 &valuelen, &datalen, NULL, NULL);
677 valuelen++; /* returned value doesn't include room for '\0' */
678 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
679 data = HeapAlloc(GetProcessHeap(), 0, datalen);
684 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
685 &dlen) == ERROR_SUCCESS) {
686 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
688 *ppsub = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppsub));
689 (*ppsub)->next = NULL;
690 split_subst_info(&((*ppsub)->from), value);
691 split_subst_info(&((*ppsub)->to), data);
693 /* Win 2000 doesn't allow mapping between different charsets
694 or mapping of DEFAULT_CHARSET */
695 if(((*ppsub)->to.charset != (*ppsub)->from.charset) ||
696 (*ppsub)->to.charset == DEFAULT_CHARSET) {
697 HeapFree(GetProcessHeap(), 0, (*ppsub)->to.name);
698 HeapFree(GetProcessHeap(), 0, (*ppsub)->from.name);
699 HeapFree(GetProcessHeap(), 0, *ppsub);
702 ppsub = &((*ppsub)->next);
704 /* reset dlen and vlen */
708 HeapFree(GetProcessHeap(), 0, data);
709 HeapFree(GetProcessHeap(), 0, value);
714 /***********************************************************
715 * The replacement list is a way to map an entire font
716 * family onto another family. For example adding
718 * [HKLM\Software\Wine\Wine\FontReplacements]
719 * "Wingdings"="Winedings"
721 * would enumerate the Winedings font both as Winedings and
722 * Wingdings. However if a real Wingdings font is present the
723 * replacement does not take place.
726 static void LoadReplaceList(void)
729 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
734 WCHAR old_nameW[200];
736 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
737 "Software\\Wine\\Wine\\FontReplacements",
738 &hkey) == ERROR_SUCCESS) {
740 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
741 &valuelen, &datalen, NULL, NULL);
743 valuelen++; /* returned value doesn't include room for '\0' */
744 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
745 data = HeapAlloc(GetProcessHeap(), 0, datalen);
749 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
750 &dlen) == ERROR_SUCCESS) {
751 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
752 /* "NewName"="Oldname" */
753 if(!MultiByteToWideChar(CP_ACP, 0, data, -1, old_nameW, sizeof(old_nameW)))
756 /* Find the old family and hence all of the font files
758 for(family = FontList; family; family = family->next) {
759 if(!strcmpiW(family->FamilyName, old_nameW)) {
760 for(face = family->FirstFace; face; face = face->next) {
761 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
762 debugstr_w(face->StyleName), value);
763 /* Now add a new entry with the new family name */
764 AddFontFileToList(face->file, value, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
769 /* reset dlen and vlen */
773 HeapFree(GetProcessHeap(), 0, data);
774 HeapFree(GetProcessHeap(), 0, value);
780 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
786 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
788 dir = opendir(dirname);
790 ERR("Can't open directory %s\n", debugstr_a(dirname));
793 while((dent = readdir(dir)) != NULL) {
796 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
799 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
801 sprintf(path, "%s/%s", dirname, dent->d_name);
803 if(stat(path, &statbuf) == -1)
805 WARN("Can't stat %s\n", debugstr_a(path));
808 if(S_ISDIR(statbuf.st_mode))
809 ReadFontDir(path, external_fonts);
811 AddFontFileToList(path, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
817 static void load_fontconfig_fonts(void)
819 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
820 void *fc_handle = NULL;
829 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
831 TRACE("Wine cannot find the fontconfig library (%s).\n",
832 SONAME_LIBFONTCONFIG);
835 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
836 LOAD_FUNCPTR(FcConfigGetCurrent);
837 LOAD_FUNCPTR(FcFontList);
838 LOAD_FUNCPTR(FcFontSetDestroy);
839 LOAD_FUNCPTR(FcInit);
840 LOAD_FUNCPTR(FcObjectSetAdd);
841 LOAD_FUNCPTR(FcObjectSetCreate);
842 LOAD_FUNCPTR(FcObjectSetDestroy);
843 LOAD_FUNCPTR(FcPatternCreate);
844 LOAD_FUNCPTR(FcPatternDestroy);
845 LOAD_FUNCPTR(FcPatternGet);
848 if(!pFcInit()) return;
850 config = pFcConfigGetCurrent();
851 pat = pFcPatternCreate();
852 os = pFcObjectSetCreate();
853 pFcObjectSetAdd(os, FC_FILE);
854 fontset = pFcFontList(config, pat, os);
856 for(i = 0; i < fontset->nfont; i++) {
857 if(pFcPatternGet(fontset->fonts[i], FC_FILE, 0, &v) != FcResultMatch)
859 if(v.type != FcTypeString) continue;
860 TRACE("fontconfig: %s\n", v.u.s);
862 /* We're just interested in OT/TT fonts for now, so this hack just
863 picks up the standard extensions to save time loading every other
866 if(len < 4) continue;
867 ext = v.u.s + len - 3;
868 if(!strcasecmp(ext, "ttf") || !strcasecmp(ext, "ttc") || !strcasecmp(ext, "otf"))
869 AddFontFileToList(v.u.s, NULL, ADDFONT_EXTERNAL_FONT);
871 pFcFontSetDestroy(fontset);
872 pFcObjectSetDestroy(os);
873 pFcPatternDestroy(pat);
880 void load_system_fonts(void)
883 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
886 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
889 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
890 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
891 strcatW(windowsdir, fontsW);
892 for(value = SystemFontValues; *value; value++) {
894 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
896 sprintfW(pathW, fmtW, windowsdir, data);
897 if((unixname = wine_get_unix_file_name(pathW))) {
898 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
899 HeapFree(GetProcessHeap(), 0, unixname);
907 /*************************************************************
909 * This adds registry entries for any externally loaded fonts
910 * (fonts from fontconfig or FontDirs). It also deletes entries
911 * of no longer existing fonts.
914 void update_reg_entries(void)
916 HKEY winkey = 0, externalkey = 0;
919 DWORD dlen, vlen, datalen, valuelen, i, type, len, len_fam;
923 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
924 static const WCHAR spaceW[] = {' ', '\0'};
927 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
928 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winkey, NULL) != ERROR_SUCCESS) {
929 ERR("Can't create Windows font reg key\n");
932 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, external_fonts_reg_key,
933 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
934 ERR("Can't create external font reg key\n");
938 /* Delete all external fonts added last time */
940 RegQueryInfoKeyW(externalkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
941 &valuelen, &datalen, NULL, NULL);
942 valuelen++; /* returned value doesn't include room for '\0' */
943 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
944 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
946 dlen = datalen * sizeof(WCHAR);
949 while(RegEnumValueW(externalkey, i++, valueW, &vlen, NULL, &type, data,
950 &dlen) == ERROR_SUCCESS) {
952 RegDeleteValueW(winkey, valueW);
953 /* reset dlen and vlen */
957 HeapFree(GetProcessHeap(), 0, data);
958 HeapFree(GetProcessHeap(), 0, valueW);
960 /* Delete the old external fonts key */
961 RegCloseKey(externalkey);
963 RegDeleteKeyW(HKEY_LOCAL_MACHINE, external_fonts_reg_key);
965 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, external_fonts_reg_key,
966 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
967 ERR("Can't create external font reg key\n");
971 /* enumerate the fonts and add external ones to the two keys */
973 for(family = FontList; family; family = family->next) {
974 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
975 for(face = family->FirstFace; face; face = face->next) {
976 if(!face->external) continue;
978 if(strcmpiW(face->StyleName, RegularW))
979 len = len_fam + strlenW(face->StyleName) + 1;
980 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
981 strcpyW(valueW, family->FamilyName);
983 strcatW(valueW, spaceW);
984 strcatW(valueW, face->StyleName);
986 strcatW(valueW, TrueType);
987 if((path = strrchr(face->file, '/')) == NULL)
991 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
993 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
994 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
995 RegSetValueExW(winkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
996 RegSetValueExW(externalkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
998 HeapFree(GetProcessHeap(), 0, file);
999 HeapFree(GetProcessHeap(), 0, valueW);
1004 RegCloseKey(externalkey);
1006 RegCloseKey(winkey);
1011 /*************************************************************
1012 * WineEngAddFontResourceEx
1015 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1017 if (ft_handle) /* do it only if we have freetype up and running */
1022 FIXME("Ignoring flags %lx\n", flags);
1024 if((unixname = wine_get_unix_file_name(file)))
1026 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1027 HeapFree(GetProcessHeap(), 0, unixname);
1033 /*************************************************************
1034 * WineEngRemoveFontResourceEx
1037 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1043 /*************************************************************
1046 * Initialize FreeType library and create a list of available faces
1048 BOOL WineEngInit(void)
1050 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
1052 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1054 WCHAR windowsdir[MAX_PATH];
1060 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
1063 "Wine cannot find the FreeType font library. To enable Wine to\n"
1064 "use TrueType fonts please install a version of FreeType greater than\n"
1065 "or equal to 2.0.5.\n"
1066 "http://www.freetype.org\n");
1070 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(ft_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
1072 LOAD_FUNCPTR(FT_Vector_Unit)
1073 LOAD_FUNCPTR(FT_Done_Face)
1074 LOAD_FUNCPTR(FT_Get_Char_Index)
1075 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
1076 LOAD_FUNCPTR(FT_Init_FreeType)
1077 LOAD_FUNCPTR(FT_Load_Glyph)
1078 LOAD_FUNCPTR(FT_Matrix_Multiply)
1079 LOAD_FUNCPTR(FT_MulFix)
1080 LOAD_FUNCPTR(FT_New_Face)
1081 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
1082 LOAD_FUNCPTR(FT_Outline_Transform)
1083 LOAD_FUNCPTR(FT_Outline_Translate)
1084 LOAD_FUNCPTR(FT_Select_Charmap)
1085 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
1086 LOAD_FUNCPTR(FT_Vector_Transform)
1089 /* Don't warn if this one is missing */
1090 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
1091 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
1092 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
1093 #ifdef HAVE_FREETYPE_FTWINFNT_H
1094 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
1096 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
1097 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
1098 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
1099 <= 2.0.3 has FT_Sqrt64 */
1103 if(pFT_Init_FreeType(&library) != 0) {
1104 ERR("Can't init FreeType library\n");
1105 wine_dlclose(ft_handle, NULL, 0);
1109 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
1110 if (pFT_Library_Version)
1112 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
1114 if (FT_Version.major<=0)
1120 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
1121 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
1122 ((FT_Version.minor << 8) & 0x00ff00) |
1123 ((FT_Version.patch ) & 0x0000ff);
1125 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
1126 ERR("Failed to create font mutex\n");
1129 WaitForSingleObject(font_mutex, INFINITE);
1131 /* load the system fonts */
1132 load_system_fonts();
1134 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
1135 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1136 strcatW(windowsdir, fontsW);
1137 if((unixname = wine_get_unix_file_name(windowsdir)))
1139 ReadFontDir(unixname, FALSE);
1140 HeapFree(GetProcessHeap(), 0, unixname);
1143 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
1144 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
1145 full path as the entry. Also look for any .fon fonts, since ReadFontDir
1147 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
1148 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1149 &hkey) == ERROR_SUCCESS) {
1151 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1152 &valuelen, &datalen, NULL, NULL);
1154 valuelen++; /* returned value doesn't include room for '\0' */
1155 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1156 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1159 dlen = datalen * sizeof(WCHAR);
1161 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
1162 &dlen) == ERROR_SUCCESS) {
1163 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
1165 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
1167 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1168 HeapFree(GetProcessHeap(), 0, unixname);
1171 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
1173 WCHAR pathW[MAX_PATH];
1174 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1175 sprintfW(pathW, fmtW, windowsdir, data);
1176 if((unixname = wine_get_unix_file_name(pathW)))
1178 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1179 HeapFree(GetProcessHeap(), 0, unixname);
1182 /* reset dlen and vlen */
1187 if (data) HeapFree(GetProcessHeap(), 0, data);
1188 if (valueW) HeapFree(GetProcessHeap(), 0, valueW);
1192 load_fontconfig_fonts();
1194 /* then look in any directories that we've specified in the config file */
1195 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1196 "Software\\Wine\\Wine\\Config\\FontDirs",
1197 &hkey) == ERROR_SUCCESS) {
1199 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1200 &valuelen, &datalen, NULL, NULL);
1202 valuelen++; /* returned value doesn't include room for '\0' */
1203 value = HeapAlloc(GetProcessHeap(), 0, valuelen);
1204 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1209 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1210 &dlen) == ERROR_SUCCESS) {
1211 TRACE("Got %s=%s\n", value, (LPSTR)data);
1212 ReadFontDir((LPSTR)data, TRUE);
1213 /* reset dlen and vlen */
1217 HeapFree(GetProcessHeap(), 0, data);
1218 HeapFree(GetProcessHeap(), 0, value);
1226 update_reg_entries();
1228 ReleaseMutex(font_mutex);
1232 "Wine cannot find certain functions that it needs inside the FreeType\n"
1233 "font library. To enable Wine to use TrueType fonts please upgrade\n"
1234 "FreeType to at least version 2.0.5.\n"
1235 "http://www.freetype.org\n");
1236 wine_dlclose(ft_handle, NULL, 0);
1242 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
1245 TT_HoriHeader *pHori;
1249 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1250 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1252 if(height == 0) height = 16;
1254 /* Calc. height of EM square:
1256 * For +ve lfHeight we have
1257 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
1258 * Re-arranging gives:
1259 * ppem = units_per_em * lfheight / (winAscent + winDescent)
1261 * For -ve lfHeight we have
1263 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
1264 * with il = winAscent + winDescent - units_per_em]
1269 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
1270 ppem = ft_face->units_per_EM * height /
1271 (pHori->Ascender - pHori->Descender);
1273 ppem = ft_face->units_per_EM * height /
1274 (pOS2->usWinAscent + pOS2->usWinDescent);
1282 static LONG load_VDMX(GdiFont, LONG);
1284 static FT_Face OpenFontFile(GdiFont font, char *file, FT_Long face_index, LONG width, LONG height)
1290 err = pFT_New_Face(library, file, face_index, &ft_face);
1292 ERR("FT_New_Face rets %d\n", err);
1296 /* set it here, as load_VDMX needs it */
1297 font->ft_face = ft_face;
1299 if(FT_IS_SCALABLE(ft_face)) {
1300 /* load the VDMX table if we have one */
1301 ppem = load_VDMX(font, height);
1303 ppem = calc_ppem_for_height(ft_face, height);
1305 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, ppem)) != 0)
1306 WARN("FT_Set_Pixel_Sizes %d, %ld rets %x\n", 0, ppem, err);
1308 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
1309 WARN("FT_Set_Pixel_Sizes %ld, %ld rets %x\n", width, height, err);
1315 static int get_nearest_charset(Face *face)
1317 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
1318 a single face with the requested charset. The idea is to check if
1319 the selected font supports the current ANSI codepage, if it does
1320 return the corresponding charset, else return the first charset */
1323 int acp = GetACP(), i;
1326 if(TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE))
1327 if(csi.fs.fsCsb[0] & face->fs.fsCsb[0])
1328 return csi.ciCharset;
1330 for(i = 0; i < 32; i++) {
1332 if(face->fs.fsCsb[0] & fs0) {
1333 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG))
1334 return csi.ciCharset;
1336 FIXME("TCI failing on %lx\n", fs0);
1340 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08lx file = %s\n",
1341 face->fs.fsCsb[0], face->file);
1342 return DEFAULT_CHARSET;
1345 static GdiFont alloc_font(void)
1347 GdiFont ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
1348 ret->gmsize = INIT_GM_SIZE;
1349 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1350 ret->gmsize * sizeof(*ret->gm));
1352 ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
1353 list_init(&ret->hfontlist);
1357 static void free_font(GdiFont font)
1359 if (font->ft_face) pFT_Done_Face(font->ft_face);
1360 if (font->potm) HeapFree(GetProcessHeap(), 0, font->potm);
1361 if (font->name) HeapFree(GetProcessHeap(), 0, font->name);
1362 HeapFree(GetProcessHeap(), 0, font->gm);
1363 HeapFree(GetProcessHeap(), 0, font);
1367 /*************************************************************
1370 * load the vdmx entry for the specified height
1373 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
1374 ( ( (FT_ULong)_x4 << 24 ) | \
1375 ( (FT_ULong)_x3 << 16 ) | \
1376 ( (FT_ULong)_x2 << 8 ) | \
1379 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
1389 static LONG load_VDMX(GdiFont font, LONG height)
1391 BYTE hdr[6], tmp[2], group[4];
1392 BYTE devXRatio, devYRatio;
1393 USHORT numRecs, numRatios;
1398 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
1400 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
1403 /* FIXME: need the real device aspect ratio */
1407 numRecs = GET_BE_WORD(&hdr[2]);
1408 numRatios = GET_BE_WORD(&hdr[4]);
1410 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
1411 for(i = 0; i < numRatios; i++) {
1414 offset = (3 * 2) + (i * sizeof(Ratios));
1415 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
1418 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
1420 if(ratio.bCharSet != 1)
1423 if((ratio.xRatio == 0 &&
1424 ratio.yStartRatio == 0 &&
1425 ratio.yEndRatio == 0) ||
1426 (devXRatio == ratio.xRatio &&
1427 devYRatio >= ratio.yStartRatio &&
1428 devYRatio <= ratio.yEndRatio))
1430 offset = (3 * 2) + (numRatios * 4) + (i * 2);
1431 WineEngGetFontData(font, MS_VDMX_TAG, offset, tmp, 2);
1432 offset = GET_BE_WORD(tmp);
1438 FIXME("No suitable ratio found\n");
1442 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, group, 4) != GDI_ERROR) {
1444 BYTE startsz, endsz;
1447 recs = GET_BE_WORD(group);
1451 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
1453 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
1454 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
1455 if(result == GDI_ERROR) {
1456 FIXME("Failed to retrieve vTable\n");
1461 for(i = 0; i < recs; i++) {
1462 SHORT yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1463 SHORT yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1464 ppem = GET_BE_WORD(&vTable[i * 6]);
1466 if(yMax + -yMin == height) {
1469 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1472 if(yMax + -yMin > height) {
1475 goto end; /* failed */
1477 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1478 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1479 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1485 TRACE("ppem not found for height %ld\n", height);
1489 if(ppem < startsz || ppem > endsz)
1492 for(i = 0; i < recs; i++) {
1494 yPelHeight = GET_BE_WORD(&vTable[i * 6]);
1496 if(yPelHeight > ppem)
1499 if(yPelHeight == ppem) {
1500 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1501 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1502 TRACE("ppem %ld found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
1508 HeapFree(GetProcessHeap(), 0, vTable);
1514 static BOOL fontcmp(GdiFont font, FONT_DESC *fd)
1516 if(font->font_desc.hash != fd->hash) return TRUE;
1517 if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
1518 if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
1519 return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
1522 static void calc_hash(FONT_DESC *pfd)
1524 DWORD hash = 0, *ptr, two_chars;
1528 for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
1530 for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
1532 for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
1534 pwc = (WCHAR *)&two_chars;
1536 *pwc = toupperW(*pwc);
1538 *pwc = toupperW(*pwc);
1546 static GdiFont find_in_cache(HFONT hfont, LOGFONTW *plf, XFORM *pxf, BOOL can_use_bitmap)
1551 struct list *font_elem_ptr, *hfontlist_elem_ptr;
1553 memcpy(&fd.lf, plf, sizeof(LOGFONTW));
1554 memcpy(&fd.matrix, pxf, sizeof(FMAT2));
1557 /* try the in-use list */
1558 LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
1559 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
1560 if(!fontcmp(ret, &fd)) {
1561 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
1562 LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
1563 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
1564 if(hflist->hfont == hfont)
1567 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
1568 hflist->hfont = hfont;
1569 list_add_head(&ret->hfontlist, &hflist->entry);
1574 /* then the unused list */
1575 font_elem_ptr = list_head(&unused_gdi_font_list);
1576 while(font_elem_ptr) {
1577 ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
1578 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
1579 if(!fontcmp(ret, &fd)) {
1580 if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
1581 assert(list_empty(&ret->hfontlist));
1582 TRACE("Found %p in unused list\n", ret);
1583 list_remove(&ret->entry);
1584 list_add_head(&gdi_font_list, &ret->entry);
1585 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
1586 hflist->hfont = hfont;
1587 list_add_head(&ret->hfontlist, &hflist->entry);
1594 /*************************************************************
1595 * WineEngCreateFontInstance
1598 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
1602 Family *family = NULL;
1603 INT height, width = 0;
1604 signed int diff = 0, newdiff;
1605 BOOL bd, it, can_use_bitmap;
1610 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
1611 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
1613 TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
1614 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
1615 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
1618 /* check the cache first */
1619 if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
1620 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
1624 TRACE("not in cache\n");
1625 if(!FontList || !have_installed_roman_font) /* No fonts installed */
1627 TRACE("No fonts installed\n");
1633 memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
1634 memcpy(&ret->font_desc.lf, &lf, sizeof(LOGFONTW));
1635 calc_hash(&ret->font_desc);
1636 hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
1637 hflist->hfont = hfont;
1638 list_add_head(&ret->hfontlist, &hflist->entry);
1641 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
1642 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
1643 original value lfCharSet. Note this is a special case for
1644 Symbol and doesn't happen at least for "Wingdings*" */
1646 if(!strcmpiW(lf.lfFaceName, SymbolW))
1647 lf.lfCharSet = SYMBOL_CHARSET;
1649 if(!TranslateCharsetInfo((DWORD*)(INT)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
1650 switch(lf.lfCharSet) {
1651 case DEFAULT_CHARSET:
1652 csi.fs.fsCsb[0] = 0;
1655 FIXME("Untranslated charset %d\n", lf.lfCharSet);
1656 csi.fs.fsCsb[0] = 0;
1661 if(lf.lfFaceName[0] != '\0') {
1663 for(psub = substlist; psub; psub = psub->next)
1664 if(!strcmpiW(lf.lfFaceName, psub->from.name) &&
1665 (psub->from.charset == -1 ||
1666 psub->from.charset == lf.lfCharSet))
1669 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
1670 debugstr_w(psub->to.name));
1671 strcpyW(lf.lfFaceName, psub->to.name);
1674 /* We want a match on name and charset or just name if
1675 charset was DEFAULT_CHARSET. If the latter then
1676 we fixup the returned charset later in get_nearest_charset
1677 where we'll either use the charset of the current ansi codepage
1678 or if that's unavailable the first charset that the font supports.
1680 for(family = FontList; family; family = family->next) {
1681 if(!strcmpiW(family->FamilyName, lf.lfFaceName))
1682 if((csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0]) || !csi.fs.fsCsb[0])
1683 if(family->FirstFace->scalable || can_use_bitmap)
1689 /* If requested charset was DEFAULT_CHARSET then try using charset
1690 corresponding to the current ansi codepage */
1691 if(!csi.fs.fsCsb[0]) {
1693 if(!TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE)) {
1694 FIXME("TCI failed on codepage %d\n", acp);
1695 csi.fs.fsCsb[0] = 0;
1697 lf.lfCharSet = csi.ciCharset;
1700 /* Face families are in the top 4 bits of lfPitchAndFamily,
1701 so mask with 0xF0 before testing */
1703 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
1704 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
1705 strcpyW(lf.lfFaceName, defFixed);
1706 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
1707 strcpyW(lf.lfFaceName, defSerif);
1708 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
1709 strcpyW(lf.lfFaceName, defSans);
1711 strcpyW(lf.lfFaceName, defSans);
1712 for(family = FontList; family; family = family->next) {
1713 if(!strcmpiW(family->FamilyName, lf.lfFaceName) &&
1714 (csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0]))
1715 if(family->FirstFace->scalable || can_use_bitmap)
1721 for(family = FontList; family; family = family->next) {
1722 if(csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0])
1723 if(family->FirstFace->scalable || can_use_bitmap)
1730 csi.fs.fsCsb[0] = 0;
1731 FIXME("just using first face for now\n");
1734 it = lf.lfItalic ? 1 : 0;
1735 bd = lf.lfWeight > 550 ? 1 : 0;
1737 height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
1738 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
1741 for(face = family->FirstFace; face; face = face->next) {
1742 if(!(face->Italic ^ it) && !(face->Bold ^ bd)) {
1746 newdiff = height - (signed int)(face->size.y_ppem >> 6);
1748 newdiff = -height - ((signed int)(face->size.y_ppem >> 6) - face->size.internal_leading);
1749 if(!best || (diff > 0 && newdiff < diff && newdiff >= 0) ||
1750 (diff < 0 && newdiff > diff)) {
1751 TRACE("%ld is better for %d diff was %d\n", face->size.y_ppem >> 6, height, diff);
1762 face = family->FirstFace;
1763 if(it && !face->Italic) ret->fake_italic = TRUE;
1764 if(bd && !face->Bold) ret->fake_bold = TRUE;
1767 memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
1770 ret->charset = lf.lfCharSet;
1772 ret->charset = get_nearest_charset(face);
1774 TRACE("Chosen: %s %s\n", debugstr_w(family->FamilyName),
1775 debugstr_w(face->StyleName));
1777 if(!face->scalable) {
1778 width = face->size.x_ppem >> 6;
1779 height = face->size.y_ppem >> 6;
1781 ret->ft_face = OpenFontFile(ret, face->file, face->face_index, width, height);
1789 if (ret->charset == SYMBOL_CHARSET &&
1790 !pFT_Select_Charmap(ret->ft_face, ft_encoding_symbol)) {
1793 else if (!pFT_Select_Charmap(ret->ft_face, ft_encoding_unicode)) {
1797 pFT_Select_Charmap(ret->ft_face, ft_encoding_apple_roman);
1800 ret->orientation = lf.lfOrientation;
1801 ret->name = strdupW(family->FamilyName);
1802 ret->underline = lf.lfUnderline ? 0xff : 0;
1803 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
1805 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
1806 ret->aveWidth= lf.lfWidth;
1807 list_add_head(&gdi_font_list, &ret->entry);
1811 static void dump_gdi_font_list(void)
1814 struct list *elem_ptr;
1816 TRACE("---------- gdiFont Cache ----------\n");
1817 LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
1818 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
1819 TRACE("gdiFont=%p %s %ld\n",
1820 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
1823 TRACE("---------- Unused gdiFont Cache ----------\n");
1824 LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
1825 gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
1826 TRACE("gdiFont=%p %s %ld\n",
1827 gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
1831 /*************************************************************
1832 * WineEngDestroyFontInstance
1834 * free the gdiFont associated with this handle
1837 BOOL WineEngDestroyFontInstance(HFONT handle)
1842 struct list *font_elem_ptr, *hfontlist_elem_ptr;
1845 TRACE("destroying hfont=%p\n", handle);
1847 dump_gdi_font_list();
1849 font_elem_ptr = list_head(&gdi_font_list);
1850 while(font_elem_ptr) {
1851 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
1852 font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
1854 hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
1855 while(hfontlist_elem_ptr) {
1856 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
1857 hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
1858 if(hflist->hfont == handle) {
1859 list_remove(&hflist->entry);
1860 HeapFree(GetProcessHeap(), 0, hflist);
1864 if(list_empty(&gdiFont->hfontlist)) {
1865 TRACE("Moving to Unused list\n");
1866 list_remove(&gdiFont->entry);
1867 list_add_head(&unused_gdi_font_list, &gdiFont->entry);
1872 font_elem_ptr = list_head(&unused_gdi_font_list);
1873 while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
1874 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
1875 while(font_elem_ptr) {
1876 gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
1877 font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
1878 TRACE("freeing %p\n", gdiFont);
1879 list_remove(&gdiFont->entry);
1885 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
1886 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
1888 OUTLINETEXTMETRICW *potm = NULL;
1890 TEXTMETRICW tm, *ptm;
1891 GdiFont font = alloc_font();
1894 if(face->scalable) {
1898 height = face->size.y_ppem >> 6;
1899 width = face->size.x_ppem >> 6;
1902 if (!(font->ft_face = OpenFontFile(font, face->file, face->face_index, width, height)))
1908 font->name = strdupW(face->family->FamilyName);
1910 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
1912 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
1914 potm = HeapAlloc(GetProcessHeap(), 0, size);
1915 WineEngGetOutlineTextMetrics(font, size, potm);
1916 ptm = (TEXTMETRICW*)&potm->otmTextMetrics;
1918 WineEngGetTextMetrics(font, &tm);
1922 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = ptm->tmHeight;
1923 pntm->ntmTm.tmAscent = ptm->tmAscent;
1924 pntm->ntmTm.tmDescent = ptm->tmDescent;
1925 pntm->ntmTm.tmInternalLeading = ptm->tmInternalLeading;
1926 pntm->ntmTm.tmExternalLeading = ptm->tmExternalLeading;
1927 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = ptm->tmAveCharWidth;
1928 pntm->ntmTm.tmMaxCharWidth = ptm->tmMaxCharWidth;
1929 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = ptm->tmWeight;
1930 pntm->ntmTm.tmOverhang = ptm->tmOverhang;
1931 pntm->ntmTm.tmDigitizedAspectX = ptm->tmDigitizedAspectX;
1932 pntm->ntmTm.tmDigitizedAspectY = ptm->tmDigitizedAspectY;
1933 pntm->ntmTm.tmFirstChar = ptm->tmFirstChar;
1934 pntm->ntmTm.tmLastChar = ptm->tmLastChar;
1935 pntm->ntmTm.tmDefaultChar = ptm->tmDefaultChar;
1936 pntm->ntmTm.tmBreakChar = ptm->tmBreakChar;
1937 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = ptm->tmItalic;
1938 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = ptm->tmUnderlined;
1939 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = ptm->tmStruckOut;
1940 pntm->ntmTm.tmPitchAndFamily = ptm->tmPitchAndFamily;
1941 pelf->elfLogFont.lfPitchAndFamily = (ptm->tmPitchAndFamily & 0xf1) + 1;
1942 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = ptm->tmCharSet;
1943 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
1944 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
1945 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
1947 *ptype = ptm->tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
1948 if(!(ptm->tmPitchAndFamily & TMPF_VECTOR))
1949 *ptype |= RASTER_FONTTYPE;
1952 pntm->ntmTm.ntmFlags = ptm->tmItalic ? NTM_ITALIC : 0;
1953 if(ptm->tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
1954 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
1956 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
1957 pntm->ntmTm.ntmCellHeight = 0;
1958 pntm->ntmTm.ntmAvgWidth = 0;
1960 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
1962 strncpyW(pelf->elfLogFont.lfFaceName,
1963 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
1965 strncpyW(pelf->elfFullName,
1966 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
1968 strncpyW(pelf->elfStyle,
1969 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
1973 strncpyW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
1974 strncpyW(pelf->elfFullName, face->family->FamilyName, LF_FACESIZE);
1975 pelf->elfStyle[0] = '\0';
1978 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
1980 HeapFree(GetProcessHeap(), 0, potm);
1985 /*************************************************************
1989 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
1994 NEWTEXTMETRICEXW ntm;
1995 DWORD type, ret = 1;
2001 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
2003 if(plf->lfFaceName[0]) {
2005 for(psub = substlist; psub; psub = psub->next)
2006 if(!strcmpiW(plf->lfFaceName, psub->from.name) &&
2007 (psub->from.charset == -1 ||
2008 psub->from.charset == plf->lfCharSet))
2011 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
2012 debugstr_w(psub->to.name));
2013 memcpy(&lf, plf, sizeof(lf));
2014 strcpyW(lf.lfFaceName, psub->to.name);
2017 for(family = FontList; family; family = family->next) {
2018 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
2019 for(face = family->FirstFace; face; face = face->next) {
2020 GetEnumStructs(face, &elf, &ntm, &type);
2021 for(i = 0; i < 32; i++) {
2022 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
2023 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2024 strcpyW(elf.elfScript, OEM_DOSW);
2025 i = 32; /* break out of loop */
2026 } else if(!(face->fs.fsCsb[0] & (1L << i)))
2029 fs.fsCsb[0] = 1L << i;
2031 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
2033 csi.ciCharset = DEFAULT_CHARSET;
2034 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
2035 if(csi.ciCharset != DEFAULT_CHARSET) {
2036 elf.elfLogFont.lfCharSet =
2037 ntm.ntmTm.tmCharSet = csi.ciCharset;
2039 strcpyW(elf.elfScript, ElfScriptsW[i]);
2041 FIXME("Unknown elfscript for bit %d\n", i);
2044 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2045 debugstr_w(elf.elfLogFont.lfFaceName),
2046 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2047 csi.ciCharset, type, debugstr_w(elf.elfScript),
2048 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
2049 ntm.ntmTm.ntmFlags);
2050 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
2057 for(family = FontList; family; family = family->next) {
2058 GetEnumStructs(family->FirstFace, &elf, &ntm, &type);
2059 for(i = 0; i < 32; i++) {
2060 if(!family->FirstFace->scalable && family->FirstFace->fs.fsCsb[0] == 0) { /* OEM bitmap */
2061 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2062 strcpyW(elf.elfScript, OEM_DOSW);
2063 i = 32; /* break out of loop */
2064 } else if(!(family->FirstFace->fs.fsCsb[0] & (1L << i)))
2067 fs.fsCsb[0] = 1L << i;
2069 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
2071 csi.ciCharset = DEFAULT_CHARSET;
2072 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
2073 if(csi.ciCharset != DEFAULT_CHARSET) {
2074 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
2077 strcpyW(elf.elfScript, ElfScriptsW[i]);
2079 FIXME("Unknown elfscript for bit %d\n", i);
2082 TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2083 debugstr_w(elf.elfLogFont.lfFaceName),
2084 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2085 csi.ciCharset, type, debugstr_w(elf.elfScript),
2086 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
2087 ntm.ntmTm.ntmFlags);
2088 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
2097 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
2099 pt->x.value = vec->x >> 6;
2100 pt->x.fract = (vec->x & 0x3f) << 10;
2101 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
2102 pt->y.value = vec->y >> 6;
2103 pt->y.fract = (vec->y & 0x3f) << 10;
2104 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
2108 static FT_UInt get_glyph_index(GdiFont font, UINT glyph)
2110 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
2111 glyph = glyph + 0xf000;
2112 return pFT_Get_Char_Index(font->ft_face, glyph);
2115 /*************************************************************
2116 * WineEngGetGlyphIndices
2118 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
2120 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
2121 LPWORD pgi, DWORD flags)
2125 for(i = 0; i < count; i++)
2126 pgi[i] = get_glyph_index(font, lpstr[i]);
2131 /*************************************************************
2132 * WineEngGetGlyphOutline
2134 * Behaves in exactly the same way as the win32 api GetGlyphOutline
2135 * except that the first parameter is the HWINEENGFONT of the font in
2136 * question rather than an HDC.
2139 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
2140 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
2143 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
2144 FT_Face ft_face = font->ft_face;
2145 FT_UInt glyph_index;
2146 DWORD width, height, pitch, needed = 0;
2147 FT_Bitmap ft_bitmap;
2149 INT left, right, top = 0, bottom = 0;
2151 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
2152 float widthRatio = 1.0;
2153 FT_Matrix transMat = identityMat;
2154 BOOL needsTransform = FALSE;
2157 TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font, glyph, format, lpgm,
2158 buflen, buf, lpmat);
2160 if(format & GGO_GLYPH_INDEX) {
2161 glyph_index = glyph;
2162 format &= ~GGO_GLYPH_INDEX;
2164 glyph_index = get_glyph_index(font, glyph);
2166 if(glyph_index >= font->gmsize) {
2167 font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
2168 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
2169 font->gmsize * sizeof(*font->gm));
2171 if(format == GGO_METRICS && font->gm[glyph_index].init) {
2172 memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
2173 return 1; /* FIXME */
2177 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP) || font->aveWidth || lpmat)
2178 load_flags |= FT_LOAD_NO_BITMAP;
2180 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
2183 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
2187 /* Scaling factor */
2188 if (font->aveWidth && font->potm) {
2189 widthRatio = (float)font->aveWidth * font->font_desc.matrix.eM11 / (float) font->potm->otmTextMetrics.tmAveCharWidth;
2192 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
2193 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
2195 font->gm[glyph_index].adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
2196 font->gm[glyph_index].lsb = left >> 6;
2197 font->gm[glyph_index].bbx = (right - left) >> 6;
2199 /* Scaling transform */
2200 if(font->aveWidth) {
2202 scaleMat.xx = FT_FixedFromFloat(widthRatio);
2205 scaleMat.yy = (1 << 16);
2207 pFT_Matrix_Multiply(&scaleMat, &transMat);
2208 needsTransform = TRUE;
2211 /* Rotation transform */
2212 if(font->orientation) {
2213 FT_Matrix rotationMat;
2215 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
2216 pFT_Vector_Unit(&vecAngle, angle);
2217 rotationMat.xx = vecAngle.x;
2218 rotationMat.xy = -vecAngle.y;
2219 rotationMat.yx = -rotationMat.xy;
2220 rotationMat.yy = rotationMat.xx;
2222 pFT_Matrix_Multiply(&rotationMat, &transMat);
2223 needsTransform = TRUE;
2226 /* Extra transformation specified by caller */
2229 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
2230 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
2231 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
2232 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
2233 pFT_Matrix_Multiply(&extraMat, &transMat);
2234 needsTransform = TRUE;
2237 if(!needsTransform) {
2238 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
2239 bottom = (ft_face->glyph->metrics.horiBearingY -
2240 ft_face->glyph->metrics.height) & -64;
2241 lpgm->gmCellIncX = font->gm[glyph_index].adv;
2242 lpgm->gmCellIncY = 0;
2246 for(xc = 0; xc < 2; xc++) {
2247 for(yc = 0; yc < 2; yc++) {
2248 vec.x = (ft_face->glyph->metrics.horiBearingX +
2249 xc * ft_face->glyph->metrics.width);
2250 vec.y = ft_face->glyph->metrics.horiBearingY -
2251 yc * ft_face->glyph->metrics.height;
2252 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
2253 pFT_Vector_Transform(&vec, &transMat);
2254 if(xc == 0 && yc == 0) {
2255 left = right = vec.x;
2256 top = bottom = vec.y;
2258 if(vec.x < left) left = vec.x;
2259 else if(vec.x > right) right = vec.x;
2260 if(vec.y < bottom) bottom = vec.y;
2261 else if(vec.y > top) top = vec.y;
2266 right = (right + 63) & -64;
2267 bottom = bottom & -64;
2268 top = (top + 63) & -64;
2270 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
2271 vec.x = ft_face->glyph->metrics.horiAdvance;
2273 pFT_Vector_Transform(&vec, &transMat);
2274 lpgm->gmCellIncX = (vec.x+63) >> 6;
2275 lpgm->gmCellIncY = -((vec.y+63) >> 6);
2277 lpgm->gmBlackBoxX = (right - left) >> 6;
2278 lpgm->gmBlackBoxY = (top - bottom) >> 6;
2279 lpgm->gmptGlyphOrigin.x = left >> 6;
2280 lpgm->gmptGlyphOrigin.y = top >> 6;
2282 memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
2283 font->gm[glyph_index].init = TRUE;
2285 if(format == GGO_METRICS)
2286 return 1; /* FIXME */
2288 if (buf && !buflen){
2292 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP) {
2293 TRACE("loaded a bitmap\n");
2299 width = lpgm->gmBlackBoxX;
2300 height = lpgm->gmBlackBoxY;
2301 pitch = ((width + 31) >> 5) << 2;
2302 needed = pitch * height;
2304 if(!buf || !buflen) break;
2306 switch(ft_face->glyph->format) {
2307 case ft_glyph_format_bitmap:
2309 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
2310 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
2311 INT h = ft_face->glyph->bitmap.rows;
2313 memcpy(dst, src, w);
2314 src += ft_face->glyph->bitmap.pitch;
2320 case ft_glyph_format_outline:
2321 ft_bitmap.width = width;
2322 ft_bitmap.rows = height;
2323 ft_bitmap.pitch = pitch;
2324 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
2325 ft_bitmap.buffer = buf;
2327 if(needsTransform) {
2328 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
2331 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
2333 /* Note: FreeType will only set 'black' bits for us. */
2334 memset(buf, 0, needed);
2335 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
2339 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
2344 case GGO_GRAY2_BITMAP:
2345 case GGO_GRAY4_BITMAP:
2346 case GGO_GRAY8_BITMAP:
2347 case WINE_GGO_GRAY16_BITMAP:
2352 width = lpgm->gmBlackBoxX;
2353 height = lpgm->gmBlackBoxY;
2354 pitch = (width + 3) / 4 * 4;
2355 needed = pitch * height;
2357 if(!buf || !buflen) break;
2358 ft_bitmap.width = width;
2359 ft_bitmap.rows = height;
2360 ft_bitmap.pitch = pitch;
2361 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
2362 ft_bitmap.buffer = buf;
2364 if(needsTransform) {
2365 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
2368 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
2370 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
2372 if(format == GGO_GRAY2_BITMAP)
2374 else if(format == GGO_GRAY4_BITMAP)
2376 else if(format == GGO_GRAY8_BITMAP)
2378 else if(format == WINE_GGO_GRAY16_BITMAP)
2386 for(row = 0; row < height; row++) {
2388 for(col = 0; col < width; col++, ptr++) {
2389 *ptr = (*(unsigned int*)ptr * mult + 128) / 256;
2398 int contour, point = 0, first_pt;
2399 FT_Outline *outline = &ft_face->glyph->outline;
2400 TTPOLYGONHEADER *pph;
2402 DWORD pph_start, cpfx, type;
2404 if(buflen == 0) buf = NULL;
2406 if (needsTransform && buf) {
2407 pFT_Outline_Transform(outline, &transMat);
2410 for(contour = 0; contour < outline->n_contours; contour++) {
2412 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
2415 pph->dwType = TT_POLYGON_TYPE;
2416 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2418 needed += sizeof(*pph);
2420 while(point <= outline->contours[contour]) {
2421 ppc = (TTPOLYCURVE *)((char *)buf + needed);
2422 type = (outline->tags[point] & FT_Curve_Tag_On) ?
2423 TT_PRIM_LINE : TT_PRIM_QSPLINE;
2427 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2430 } while(point <= outline->contours[contour] &&
2431 (outline->tags[point] & FT_Curve_Tag_On) ==
2432 (outline->tags[point-1] & FT_Curve_Tag_On));
2433 /* At the end of a contour Windows adds the start point, but
2435 if(point > outline->contours[contour] &&
2436 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
2438 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
2440 } else if(point <= outline->contours[contour] &&
2441 outline->tags[point] & FT_Curve_Tag_On) {
2442 /* add closing pt for bezier */
2444 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2452 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2455 pph->cb = needed - pph_start;
2461 /* Convert the quadratic Beziers to cubic Beziers.
2462 The parametric eqn for a cubic Bezier is, from PLRM:
2463 r(t) = at^3 + bt^2 + ct + r0
2464 with the control points:
2469 A quadratic Beizer has the form:
2470 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
2472 So equating powers of t leads to:
2473 r1 = 2/3 p1 + 1/3 p0
2474 r2 = 2/3 p1 + 1/3 p2
2475 and of course r0 = p0, r3 = p2
2478 int contour, point = 0, first_pt;
2479 FT_Outline *outline = &ft_face->glyph->outline;
2480 TTPOLYGONHEADER *pph;
2482 DWORD pph_start, cpfx, type;
2483 FT_Vector cubic_control[4];
2484 if(buflen == 0) buf = NULL;
2486 if (needsTransform && buf) {
2487 pFT_Outline_Transform(outline, &transMat);
2490 for(contour = 0; contour < outline->n_contours; contour++) {
2492 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
2495 pph->dwType = TT_POLYGON_TYPE;
2496 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2498 needed += sizeof(*pph);
2500 while(point <= outline->contours[contour]) {
2501 ppc = (TTPOLYCURVE *)((char *)buf + needed);
2502 type = (outline->tags[point] & FT_Curve_Tag_On) ?
2503 TT_PRIM_LINE : TT_PRIM_CSPLINE;
2506 if(type == TT_PRIM_LINE) {
2508 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2512 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
2515 /* FIXME: Possible optimization in endpoint calculation
2516 if there are two consecutive curves */
2517 cubic_control[0] = outline->points[point-1];
2518 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
2519 cubic_control[0].x += outline->points[point].x + 1;
2520 cubic_control[0].y += outline->points[point].y + 1;
2521 cubic_control[0].x >>= 1;
2522 cubic_control[0].y >>= 1;
2524 if(point+1 > outline->contours[contour])
2525 cubic_control[3] = outline->points[first_pt];
2527 cubic_control[3] = outline->points[point+1];
2528 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
2529 cubic_control[3].x += outline->points[point].x + 1;
2530 cubic_control[3].y += outline->points[point].y + 1;
2531 cubic_control[3].x >>= 1;
2532 cubic_control[3].y >>= 1;
2535 /* r1 = 1/3 p0 + 2/3 p1
2536 r2 = 1/3 p2 + 2/3 p1 */
2537 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
2538 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
2539 cubic_control[2] = cubic_control[1];
2540 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
2541 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
2542 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
2543 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
2545 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
2546 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
2547 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
2552 } while(point <= outline->contours[contour] &&
2553 (outline->tags[point] & FT_Curve_Tag_On) ==
2554 (outline->tags[point-1] & FT_Curve_Tag_On));
2555 /* At the end of a contour Windows adds the start point,
2556 but only for Beziers and we've already done that.
2558 if(point <= outline->contours[contour] &&
2559 outline->tags[point] & FT_Curve_Tag_On) {
2560 /* This is the closing pt of a bezier, but we've already
2561 added it, so just inc point and carry on */
2568 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2571 pph->cb = needed - pph_start;
2577 FIXME("Unsupported format %d\n", format);
2583 static BOOL get_bitmap_text_metrics(GdiFont font)
2585 FT_Face ft_face = font->ft_face;
2586 #ifdef HAVE_FREETYPE_FTWINFNT_H
2587 FT_WinFNT_HeaderRec winfnt_header;
2589 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
2590 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
2591 font->potm->otmSize = size;
2593 #define TM font->potm->otmTextMetrics
2594 #ifdef HAVE_FREETYPE_FTWINFNT_H
2595 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
2597 TM.tmHeight = winfnt_header.pixel_height;
2598 TM.tmAscent = winfnt_header.ascent;
2599 TM.tmDescent = TM.tmHeight - TM.tmAscent;
2600 TM.tmInternalLeading = winfnt_header.internal_leading;
2601 TM.tmExternalLeading = winfnt_header.external_leading;
2602 TM.tmAveCharWidth = winfnt_header.avg_width;
2603 TM.tmMaxCharWidth = winfnt_header.max_width;
2604 TM.tmWeight = winfnt_header.weight;
2606 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
2607 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
2608 TM.tmFirstChar = winfnt_header.first_char;
2609 TM.tmLastChar = winfnt_header.last_char;
2610 TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
2611 TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
2612 TM.tmItalic = winfnt_header.italic;
2613 TM.tmUnderlined = font->underline;
2614 TM.tmStruckOut = font->strikeout;
2615 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
2616 TM.tmCharSet = winfnt_header.charset;
2621 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
2622 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
2623 TM.tmHeight = TM.tmAscent + TM.tmDescent;
2624 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
2625 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
2626 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
2627 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
2628 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
2630 TM.tmDigitizedAspectX = 96; /* FIXME */
2631 TM.tmDigitizedAspectY = 96; /* FIXME */
2633 TM.tmLastChar = 255;
2634 TM.tmDefaultChar = 32;
2635 TM.tmBreakChar = 32;
2636 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
2637 TM.tmUnderlined = font->underline;
2638 TM.tmStruckOut = font->strikeout;
2639 /* NB inverted meaning of TMPF_FIXED_PITCH */
2640 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
2641 TM.tmCharSet = font->charset;
2648 /*************************************************************
2649 * WineEngGetTextMetrics
2652 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
2655 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
2656 if(!get_bitmap_text_metrics(font))
2659 if(!font->potm) return FALSE;
2660 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
2662 if (font->aveWidth) {
2663 ptm->tmAveCharWidth = font->aveWidth * font->font_desc.matrix.eM11;
2669 /*************************************************************
2670 * WineEngGetOutlineTextMetrics
2673 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
2674 OUTLINETEXTMETRICW *potm)
2676 FT_Face ft_face = font->ft_face;
2677 UINT needed, lenfam, lensty, ret;
2679 TT_HoriHeader *pHori;
2680 TT_Postscript *pPost;
2681 FT_Fixed x_scale, y_scale;
2682 WCHAR *family_nameW, *style_nameW;
2683 static const WCHAR spaceW[] = {' ', '\0'};
2685 INT ascent, descent;
2687 TRACE("font=%p\n", font);
2689 if(!FT_IS_SCALABLE(ft_face))
2693 if(cbSize >= font->potm->otmSize)
2694 memcpy(potm, font->potm, font->potm->otmSize);
2695 return font->potm->otmSize;
2699 needed = sizeof(*potm);
2701 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
2702 family_nameW = strdupW(font->name);
2704 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
2706 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
2707 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
2708 style_nameW, lensty);
2710 /* These names should be read from the TT name table */
2712 /* length of otmpFamilyName */
2715 /* length of otmpFaceName */
2716 if(!strcasecmp(ft_face->style_name, "regular")) {
2717 needed += lenfam; /* just the family name */
2719 needed += lenfam + lensty; /* family + " " + style */
2722 /* length of otmpStyleName */
2725 /* length of otmpFullName */
2726 needed += lenfam + lensty;
2729 x_scale = ft_face->size->metrics.x_scale;
2730 y_scale = ft_face->size->metrics.y_scale;
2732 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2734 FIXME("Can't find OS/2 table - not TT font?\n");
2739 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2741 FIXME("Can't find HHEA table - not TT font?\n");
2746 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
2748 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",
2749 pOS2->usWinAscent, pOS2->usWinDescent,
2750 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
2751 ft_face->ascender, ft_face->descender, ft_face->height,
2752 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
2753 ft_face->bbox.yMax, ft_face->bbox.yMin);
2755 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
2756 font->potm->otmSize = needed;
2758 #define TM font->potm->otmTextMetrics
2760 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
2761 ascent = pHori->Ascender;
2762 descent = -pHori->Descender;
2764 ascent = pOS2->usWinAscent;
2765 descent = pOS2->usWinDescent;
2769 TM.tmAscent = font->yMax;
2770 TM.tmDescent = -font->yMin;
2771 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
2773 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
2774 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
2775 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
2776 - ft_face->units_per_EM, y_scale) + 32) >> 6;
2779 TM.tmHeight = TM.tmAscent + TM.tmDescent;
2782 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
2784 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
2785 ((ascent + descent) -
2786 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
2788 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
2789 if (TM.tmAveCharWidth == 0) {
2790 TM.tmAveCharWidth = 1;
2792 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
2793 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
2795 TM.tmDigitizedAspectX = 300;
2796 TM.tmDigitizedAspectY = 300;
2797 TM.tmFirstChar = pOS2->usFirstCharIndex;
2798 TM.tmLastChar = pOS2->usLastCharIndex;
2799 TM.tmDefaultChar = pOS2->usDefaultChar;
2800 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
2801 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
2802 TM.tmUnderlined = font->underline;
2803 TM.tmStruckOut = font->strikeout;
2805 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
2806 if(!FT_IS_FIXED_WIDTH(ft_face))
2807 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
2809 TM.tmPitchAndFamily = 0;
2811 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
2812 case PAN_FAMILY_SCRIPT:
2813 TM.tmPitchAndFamily |= FF_SCRIPT;
2815 case PAN_FAMILY_DECORATIVE:
2816 case PAN_FAMILY_PICTORIAL:
2817 TM.tmPitchAndFamily |= FF_DECORATIVE;
2819 case PAN_FAMILY_TEXT_DISPLAY:
2820 if(TM.tmPitchAndFamily == 0) /* fixed */
2821 TM.tmPitchAndFamily = FF_MODERN;
2823 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
2824 case PAN_SERIF_NORMAL_SANS:
2825 case PAN_SERIF_OBTUSE_SANS:
2826 case PAN_SERIF_PERP_SANS:
2827 TM.tmPitchAndFamily |= FF_SWISS;
2830 TM.tmPitchAndFamily |= FF_ROMAN;
2835 TM.tmPitchAndFamily |= FF_DONTCARE;
2838 if(FT_IS_SCALABLE(ft_face))
2839 TM.tmPitchAndFamily |= TMPF_VECTOR;
2840 if(FT_IS_SFNT(ft_face))
2841 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
2843 TM.tmCharSet = font->charset;
2846 font->potm->otmFiller = 0;
2847 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
2848 font->potm->otmfsSelection = pOS2->fsSelection;
2849 font->potm->otmfsType = pOS2->fsType;
2850 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
2851 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
2852 font->potm->otmItalicAngle = 0; /* POST table */
2853 font->potm->otmEMSquare = ft_face->units_per_EM;
2854 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
2855 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
2856 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
2857 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
2858 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
2859 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
2860 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
2861 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
2862 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
2863 font->potm->otmMacAscent = 0; /* where do these come from ? */
2864 font->potm->otmMacDescent = 0;
2865 font->potm->otmMacLineGap = 0;
2866 font->potm->otmusMinimumPPEM = 0; /* TT Header */
2867 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
2868 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
2869 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
2870 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
2871 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
2872 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
2873 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
2874 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
2875 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
2876 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
2878 font->potm->otmsUnderscoreSize = 0;
2879 font->potm->otmsUnderscorePosition = 0;
2881 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
2882 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
2885 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
2886 cp = (char*)font->potm + sizeof(*font->potm);
2887 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
2888 strcpyW((WCHAR*)cp, family_nameW);
2890 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
2891 strcpyW((WCHAR*)cp, style_nameW);
2893 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
2894 strcpyW((WCHAR*)cp, family_nameW);
2895 if(strcasecmp(ft_face->style_name, "regular")) {
2896 strcatW((WCHAR*)cp, spaceW);
2897 strcatW((WCHAR*)cp, style_nameW);
2898 cp += lenfam + lensty;
2901 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
2902 strcpyW((WCHAR*)cp, family_nameW);
2903 strcatW((WCHAR*)cp, spaceW);
2904 strcatW((WCHAR*)cp, style_nameW);
2907 if(potm && needed <= cbSize)
2908 memcpy(potm, font->potm, font->potm->otmSize);
2911 HeapFree(GetProcessHeap(), 0, style_nameW);
2912 HeapFree(GetProcessHeap(), 0, family_nameW);
2918 /*************************************************************
2919 * WineEngGetCharWidth
2922 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
2927 FT_UInt glyph_index;
2929 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
2931 for(c = firstChar; c <= lastChar; c++) {
2932 glyph_index = get_glyph_index(font, c);
2933 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
2934 &gm, 0, NULL, NULL);
2935 buffer[c - firstChar] = font->gm[glyph_index].adv;
2940 /*************************************************************
2941 * WineEngGetCharABCWidths
2944 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
2949 FT_UInt glyph_index;
2951 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
2953 for(c = firstChar; c <= lastChar; c++) {
2954 glyph_index = get_glyph_index(font, c);
2955 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
2956 &gm, 0, NULL, NULL);
2957 buffer[c - firstChar].abcA = font->gm[glyph_index].lsb;
2958 buffer[c - firstChar].abcB = font->gm[glyph_index].bbx;
2959 buffer[c - firstChar].abcC = font->gm[glyph_index].adv - font->gm[glyph_index].lsb -
2960 font->gm[glyph_index].bbx;
2965 /*************************************************************
2966 * WineEngGetTextExtentPoint
2969 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
2975 FT_UInt glyph_index;
2977 TRACE("%p, %s, %d, %p\n", font, debugstr_wn(wstr, count), count,
2981 WineEngGetTextMetrics(font, &tm);
2982 size->cy = tm.tmHeight;
2984 for(idx = 0; idx < count; idx++) {
2985 glyph_index = get_glyph_index(font, wstr[idx]);
2986 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
2987 &gm, 0, NULL, NULL);
2988 size->cx += font->gm[glyph_index].adv;
2990 TRACE("return %ld,%ld\n", size->cx, size->cy);
2994 /*************************************************************
2995 * WineEngGetTextExtentPointI
2998 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
3005 TRACE("%p, %p, %d, %p\n", font, indices, count, size);
3008 WineEngGetTextMetrics(font, &tm);
3009 size->cy = tm.tmHeight;
3011 for(idx = 0; idx < count; idx++) {
3012 WineEngGetGlyphOutline(font, indices[idx],
3013 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
3015 size->cx += font->gm[indices[idx]].adv;
3017 TRACE("return %ld,%ld\n", size->cx, size->cy);
3021 /*************************************************************
3022 * WineEngGetFontData
3025 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
3028 FT_Face ft_face = font->ft_face;
3032 TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
3033 font, table, offset, buf, cbData);
3035 if(!FT_IS_SFNT(ft_face))
3043 if(table) { /* MS tags differ in endidness from FT ones */
3044 table = table >> 24 | table << 24 |
3045 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
3048 /* If the FT_Load_Sfnt_Table function is there we'll use it */
3049 if(pFT_Load_Sfnt_Table)
3050 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
3051 else { /* Do it the hard way */
3052 TT_Face tt_face = (TT_Face) ft_face;
3053 SFNT_Interface *sfnt;
3054 if (FT_Version.major==2 && FT_Version.minor==0)
3057 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
3061 /* A field was added in the middle of the structure in 2.1.x */
3062 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
3064 err = sfnt->load_any(tt_face, table, offset, buf, &len);
3067 TRACE("Can't find table %08lx.\n", table);
3073 /*************************************************************
3074 * WineEngGetTextFace
3077 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
3080 lstrcpynW(str, font->name, count);
3081 return strlenW(font->name);
3083 return strlenW(font->name) + 1;
3086 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
3088 if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
3089 return font->charset;
3092 #else /* HAVE_FREETYPE */
3094 BOOL WineEngInit(void)
3098 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
3102 BOOL WineEngDestroyFontInstance(HFONT hfont)
3107 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3112 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
3113 LPWORD pgi, DWORD flags)
3118 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
3119 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
3122 ERR("called but we don't have FreeType\n");
3126 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
3128 ERR("called but we don't have FreeType\n");
3132 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
3133 OUTLINETEXTMETRICW *potm)
3135 ERR("called but we don't have FreeType\n");
3139 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
3142 ERR("called but we don't have FreeType\n");
3146 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
3149 ERR("called but we don't have FreeType\n");
3153 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
3156 ERR("called but we don't have FreeType\n");
3160 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
3163 ERR("called but we don't have FreeType\n");
3167 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
3170 ERR("called but we don't have FreeType\n");
3174 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
3176 ERR("called but we don't have FreeType\n");
3180 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3186 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3192 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
3195 return DEFAULT_CHARSET;
3198 #endif /* HAVE_FREETYPE */