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"
44 WINE_DEFAULT_DEBUG_CHANNEL(font);
48 #ifdef HAVE_FT2BUILD_H
51 #ifdef HAVE_FREETYPE_FREETYPE_H
52 #include <freetype/freetype.h>
54 #ifdef HAVE_FREETYPE_FTGLYPH_H
55 #include <freetype/ftglyph.h>
57 #ifdef HAVE_FREETYPE_TTTABLES_H
58 #include <freetype/tttables.h>
60 #ifdef HAVE_FREETYPE_FTSNAMES_H
61 #include <freetype/ftsnames.h>
63 # ifdef HAVE_FREETYPE_FTNAMES_H
64 # include <freetype/ftnames.h>
67 #ifdef HAVE_FREETYPE_TTNAMEID_H
68 #include <freetype/ttnameid.h>
70 #ifdef HAVE_FREETYPE_FTOUTLN_H
71 #include <freetype/ftoutln.h>
73 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
74 #include <freetype/internal/sfnt.h>
76 #ifdef HAVE_FREETYPE_FTTRIGON_H
77 #include <freetype/fttrigon.h>
79 #ifdef HAVE_FREETYPE_FTWINFNT_H
80 #include <freetype/ftwinfnt.h>
83 #ifndef SONAME_LIBFREETYPE
84 #define SONAME_LIBFREETYPE "libfreetype.so"
87 static FT_Library library = 0;
94 static FT_Version_t FT_Version;
95 static DWORD FT_SimpleVersion;
97 static void *ft_handle = NULL;
99 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
100 MAKE_FUNCPTR(FT_Vector_Unit);
101 MAKE_FUNCPTR(FT_Done_Face);
102 MAKE_FUNCPTR(FT_Get_Char_Index);
103 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
104 MAKE_FUNCPTR(FT_Init_FreeType);
105 MAKE_FUNCPTR(FT_Load_Glyph);
106 MAKE_FUNCPTR(FT_Matrix_Multiply);
107 MAKE_FUNCPTR(FT_MulFix);
108 MAKE_FUNCPTR(FT_New_Face);
109 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
110 MAKE_FUNCPTR(FT_Outline_Transform);
111 MAKE_FUNCPTR(FT_Outline_Translate);
112 MAKE_FUNCPTR(FT_Select_Charmap);
113 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
114 MAKE_FUNCPTR(FT_Vector_Transform);
115 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
116 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
117 static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*);
118 #ifdef HAVE_FREETYPE_FTWINFNT_H
119 MAKE_FUNCPTR(FT_Get_WinFNT_Header);
122 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
123 #include <fontconfig/fontconfig.h>
124 MAKE_FUNCPTR(FcConfigGetCurrent);
125 MAKE_FUNCPTR(FcFontList);
126 MAKE_FUNCPTR(FcFontSetDestroy);
127 MAKE_FUNCPTR(FcInit);
128 MAKE_FUNCPTR(FcObjectSetAdd);
129 MAKE_FUNCPTR(FcObjectSetCreate);
130 MAKE_FUNCPTR(FcObjectSetDestroy);
131 MAKE_FUNCPTR(FcPatternCreate);
132 MAKE_FUNCPTR(FcPatternDestroy);
133 MAKE_FUNCPTR(FcPatternGet);
134 #ifndef SONAME_LIBFONTCONFIG
135 #define SONAME_LIBFONTCONFIG "libfontconfig.so"
142 #define GET_BE_WORD(ptr) MAKEWORD( ((BYTE *)(ptr))[1], ((BYTE *)(ptr))[0] )
144 /* This is bascially a copy of FT_Bitmap_Size with an extra element added */
151 FT_Short internal_leading;
154 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
155 So to let this compile on older versions of FreeType we'll define the
156 new structure here. */
158 FT_Short height, width;
159 FT_Pos size, x_ppem, y_ppem;
162 typedef struct tagFace {
169 FT_Fixed font_version;
171 Bitmap_Size size; /* set if face is a bitmap */
172 BOOL external; /* TRUE if we should manually add this font to the registry */
173 struct tagFace *next;
174 struct tagFamily *family;
177 typedef struct tagFamily {
180 struct tagFamily *next;
185 INT adv; /* These three hold to widths of the unrotated chars */
205 OUTLINETEXTMETRICW *potm;
207 struct tagGdiFont *next;
210 #define INIT_GM_SIZE 128
212 static GdiFont GdiFontList = NULL;
214 static Family *FontList = NULL;
216 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ',
217 'R','o','m','a','n','\0'};
218 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
219 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
221 static const WCHAR defSystem[] = {'A','r','i','a','l','\0'};
222 static const WCHAR SystemW[] = {'S','y','s','t','e','m','\0'};
223 static const WCHAR MSSansSerifW[] = {'M','S',' ','S','a','n','s',' ',
224 'S','e','r','i','f','\0'};
225 static const WCHAR HelvW[] = {'H','e','l','v','\0'};
226 static const WCHAR RegularW[] = {'R','e','g','u','l','a','r','\0'};
228 static const WCHAR fontsW[] = {'\\','F','o','n','t','s','\0'};
229 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
230 'W','i','n','d','o','w','s','\\',
231 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
232 'F','o','n','t','s','\0'};
234 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
235 'W','i','n','d','o','w','s',' ','N','T','\\',
236 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
237 'F','o','n','t','s','\0'};
239 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
240 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
241 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
242 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
244 static const WCHAR *SystemFontValues[4] = {
251 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\','W','i','n','e','\\',
252 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
254 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
255 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
256 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
257 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
258 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
259 'E','u','r','o','p','e','a','n','\0'};
260 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
261 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
262 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
263 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
264 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
265 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
266 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
267 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
268 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
269 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
270 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
271 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
273 static const WCHAR *ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
283 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
291 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
300 typedef struct tagFontSubst {
303 struct tagFontSubst *next;
306 static FontSubst *substlist = NULL;
307 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
309 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
312 /****************************************
313 * Notes on .fon files
315 * The fonts System, FixedSys and Terminal are special. There are typically multiple
316 * versions installed for different resolutions and codepages. Windows stores which one to use
317 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
319 * FIXEDFON.FON FixedSys
321 * OEMFONT.FON Termial
322 * LogPixels Current dpi set by the display control panel applet
323 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
324 * also has a LogPixels value that appears to mirror this)
326 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
327 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
328 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
329 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
330 * so that makes sense.
332 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
333 * to be mapped into the registry on Windows 2000 at least).
336 * ega80woa.fon=ega80850.fon
337 * ega40woa.fon=ega40850.fon
338 * cga80woa.fon=cga80850.fon
339 * cga40woa.fon=cga40850.fon
343 static inline BOOL is_win9x(void)
345 return GetVersion() & 0x80000000;
348 This function builds an FT_Fixed from a float. It puts the integer part
349 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
350 It fails if the integer part of the float number is greater than SHORT_MAX.
352 static inline FT_Fixed FT_FixedFromFloat(float f)
355 unsigned short fract = (f - value) * 0xFFFF;
356 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
360 This function builds an FT_Fixed from a FIXED. It simply put f.value
361 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
363 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
365 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
368 #define ADDFONT_EXTERNAL_FONT 0x01
369 #define ADDFONT_FORCE_BITMAP 0x02
370 static BOOL AddFontFileToList(const char *file, char *fake_family, DWORD flags)
374 TT_Header *pHeader = NULL;
375 WCHAR *FamilyW, *StyleW;
378 Face **insertface, *next;
380 FT_Long face_index = 0, num_faces;
381 #ifdef HAVE_FREETYPE_FTWINFNT_H
382 FT_WinFNT_HeaderRec winfnt_header;
387 char *family_name = fake_family;
389 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
390 if((err = pFT_New_Face(library, file, face_index, &ft_face)) != 0) {
391 WARN("Unable to load font file %s err = %x\n", debugstr_a(file), err);
395 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*/
396 pFT_Done_Face(ft_face);
400 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
401 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
402 pFT_Done_Face(ft_face);
406 if(FT_IS_SFNT(ft_face) && (!pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2) ||
407 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
408 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))) {
409 TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
410 "Skipping this font.\n", debugstr_a(file));
411 pFT_Done_Face(ft_face);
415 if(!ft_face->family_name || !ft_face->style_name) {
416 TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file));
417 pFT_Done_Face(ft_face);
422 family_name = ft_face->family_name;
426 My_FT_Bitmap_Size *size = NULL;
428 if(!FT_IS_SCALABLE(ft_face))
429 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
431 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
432 FamilyW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
433 MultiByteToWideChar(CP_ACP, 0, family_name, -1, FamilyW, len);
437 if(!strcmpW((*pfamily)->FamilyName, FamilyW))
439 pfamily = &(*pfamily)->next;
442 *pfamily = HeapAlloc(GetProcessHeap(), 0, sizeof(**pfamily));
443 (*pfamily)->FamilyName = FamilyW;
444 (*pfamily)->FirstFace = NULL;
445 (*pfamily)->next = NULL;
447 HeapFree(GetProcessHeap(), 0, FamilyW);
450 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
451 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
452 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
455 for(insertface = &(*pfamily)->FirstFace; *insertface;
456 insertface = &(*insertface)->next) {
457 if(!strcmpW((*insertface)->StyleName, StyleW) && (FT_IS_SCALABLE(ft_face) || (size->y_ppem == (*insertface)->size.y_ppem))) {
458 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
459 debugstr_w((*pfamily)->FamilyName), debugstr_w(StyleW),
460 (*insertface)->font_version, pHeader ? pHeader->Font_Revision : 0);
463 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
464 HeapFree(GetProcessHeap(), 0, StyleW);
465 pFT_Done_Face(ft_face);
468 if(!pHeader || pHeader->Font_Revision <= (*insertface)->font_version) {
469 TRACE("Original font is newer so skipping this one\n");
470 HeapFree(GetProcessHeap(), 0, StyleW);
471 pFT_Done_Face(ft_face);
474 TRACE("Replacing original with this one\n");
475 next = (*insertface)->next;
476 HeapFree(GetProcessHeap(), 0, (*insertface)->file);
477 HeapFree(GetProcessHeap(), 0, (*insertface)->StyleName);
478 HeapFree(GetProcessHeap(), 0, *insertface);
483 *insertface = HeapAlloc(GetProcessHeap(), 0, sizeof(**insertface));
484 (*insertface)->StyleName = StyleW;
485 (*insertface)->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
486 strcpy((*insertface)->file, file);
487 (*insertface)->face_index = face_index;
488 (*insertface)->next = next;
489 (*insertface)->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
490 (*insertface)->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
491 (*insertface)->font_version = pHeader ? pHeader->Font_Revision : 0;
492 (*insertface)->family = *pfamily;
493 (*insertface)->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
495 if(FT_IS_SCALABLE(ft_face)) {
496 memset(&(*insertface)->size, 0, sizeof((*insertface)->size));
497 (*insertface)->scalable = TRUE;
499 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
500 size->height, size->width, size->size >> 6,
501 size->x_ppem >> 6, size->y_ppem >> 6);
502 (*insertface)->size.height = size->height;
503 (*insertface)->size.width = size->width;
504 (*insertface)->size.size = size->size;
505 (*insertface)->size.x_ppem = size->x_ppem;
506 (*insertface)->size.y_ppem = size->y_ppem;
507 (*insertface)->size.internal_leading = 0;
508 (*insertface)->scalable = FALSE;
511 memset(&(*insertface)->fs, 0, sizeof((*insertface)->fs));
513 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
515 (*insertface)->fs.fsCsb[0] = pOS2->ulCodePageRange1;
516 (*insertface)->fs.fsCsb[1] = pOS2->ulCodePageRange2;
517 (*insertface)->fs.fsUsb[0] = pOS2->ulUnicodeRange1;
518 (*insertface)->fs.fsUsb[1] = pOS2->ulUnicodeRange2;
519 (*insertface)->fs.fsUsb[2] = pOS2->ulUnicodeRange3;
520 (*insertface)->fs.fsUsb[3] = pOS2->ulUnicodeRange4;
521 if(pOS2->version == 0) {
524 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
525 (*insertface)->fs.fsCsb[0] |= 1;
527 (*insertface)->fs.fsCsb[0] |= 1L << 31;
530 #ifdef HAVE_FREETYPE_FTWINFNT_H
531 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
533 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
534 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
535 if(TranslateCharsetInfo((DWORD*)(UINT)winfnt_header.charset, &csi, TCI_SRCCHARSET))
536 memcpy(&(*insertface)->fs, &csi.fs, sizeof(csi.fs));
537 (*insertface)->size.internal_leading = winfnt_header.internal_leading;
540 TRACE("fsCsb = %08lx %08lx/%08lx %08lx %08lx %08lx\n",
541 (*insertface)->fs.fsCsb[0], (*insertface)->fs.fsCsb[1],
542 (*insertface)->fs.fsUsb[0], (*insertface)->fs.fsUsb[1],
543 (*insertface)->fs.fsUsb[2], (*insertface)->fs.fsUsb[3]);
546 if((*insertface)->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
547 for(i = 0; i < ft_face->num_charmaps; i++) {
548 switch(ft_face->charmaps[i]->encoding) {
549 case ft_encoding_unicode:
550 case ft_encoding_apple_roman:
551 (*insertface)->fs.fsCsb[0] |= 1;
553 case ft_encoding_symbol:
554 (*insertface)->fs.fsCsb[0] |= 1L << 31;
562 if((*insertface)->fs.fsCsb[0] & ~(1L << 31))
563 have_installed_roman_font = TRUE;
564 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
566 num_faces = ft_face->num_faces;
567 pFT_Done_Face(ft_face);
568 TRACE("Added font %s %s\n", debugstr_w((*pfamily)->FamilyName),
570 } while(num_faces > ++face_index);
574 static void DumpFontList(void)
579 for(family = FontList; family; family = family->next) {
580 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
581 for(face = family->FirstFace; face; face = face->next) {
582 TRACE("\t%s", debugstr_w(face->StyleName));
584 TRACE(" %ld", face->size.y_ppem >> 6);
591 static void DumpSubstList(void)
595 for(psub = substlist; psub; psub = psub->next)
596 if(psub->from.charset != -1 || psub->to.charset != -1)
597 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
598 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
600 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
601 debugstr_w(psub->to.name));
605 static LPWSTR strdupW(LPWSTR p)
608 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
609 ret = HeapAlloc(GetProcessHeap(), 0, len);
614 static void split_subst_info(NameCs *nc, LPSTR str)
616 CHAR *p = strrchr(str, ',');
621 nc->charset = strtol(p+1, NULL, 10);
624 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
625 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
626 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
629 static void LoadSubstList(void)
631 FontSubst *psub, **ppsub;
633 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
638 for(psub = substlist; psub;) {
640 HeapFree(GetProcessHeap(), 0, psub->to.name);
641 HeapFree(GetProcessHeap(), 0, psub->from.name);
644 HeapFree(GetProcessHeap(), 0, ptmp);
649 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
650 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
651 &hkey) == ERROR_SUCCESS) {
653 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
654 &valuelen, &datalen, NULL, NULL);
656 valuelen++; /* returned value doesn't include room for '\0' */
657 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
658 data = HeapAlloc(GetProcessHeap(), 0, datalen);
663 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
664 &dlen) == ERROR_SUCCESS) {
665 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
667 *ppsub = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppsub));
668 (*ppsub)->next = NULL;
669 split_subst_info(&((*ppsub)->from), value);
670 split_subst_info(&((*ppsub)->to), data);
672 /* Win 2000 doesn't allow mapping between different charsets
673 or mapping of DEFAULT_CHARSET */
674 if(((*ppsub)->to.charset != (*ppsub)->from.charset) ||
675 (*ppsub)->to.charset == DEFAULT_CHARSET) {
676 HeapFree(GetProcessHeap(), 0, (*ppsub)->to.name);
677 HeapFree(GetProcessHeap(), 0, (*ppsub)->from.name);
678 HeapFree(GetProcessHeap(), 0, *ppsub);
681 ppsub = &((*ppsub)->next);
683 /* reset dlen and vlen */
687 HeapFree(GetProcessHeap(), 0, data);
688 HeapFree(GetProcessHeap(), 0, value);
693 /***********************************************************
694 * The replacement list is a way to map an entire font
695 * family onto another family. For example adding
697 * [HKLM\Software\Wine\Wine\FontReplacements]
698 * "Wingdings"="Winedings"
700 * would enumerate the Winedings font both as Winedings and
701 * Wingdings. However if a real Wingdings font is present the
702 * replacement does not take place.
705 static void LoadReplaceList(void)
708 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
713 WCHAR old_nameW[200];
715 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
716 "Software\\Wine\\Wine\\FontReplacements",
717 &hkey) == ERROR_SUCCESS) {
719 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
720 &valuelen, &datalen, NULL, NULL);
722 valuelen++; /* returned value doesn't include room for '\0' */
723 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
724 data = HeapAlloc(GetProcessHeap(), 0, datalen);
728 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
729 &dlen) == ERROR_SUCCESS) {
730 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
731 /* "NewName"="Oldname" */
732 if(!MultiByteToWideChar(CP_ACP, 0, data, -1, old_nameW, sizeof(old_nameW)))
735 /* Find the old family and hence all of the font files
737 for(family = FontList; family; family = family->next) {
738 if(!strcmpiW(family->FamilyName, old_nameW)) {
739 for(face = family->FirstFace; face; face = face->next) {
740 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
741 debugstr_w(face->StyleName), value);
742 /* Now add a new entry with the new family name */
743 AddFontFileToList(face->file, value, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
748 /* reset dlen and vlen */
752 HeapFree(GetProcessHeap(), 0, data);
753 HeapFree(GetProcessHeap(), 0, value);
759 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
765 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
767 dir = opendir(dirname);
769 ERR("Can't open directory %s\n", debugstr_a(dirname));
772 while((dent = readdir(dir)) != NULL) {
775 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
778 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
780 sprintf(path, "%s/%s", dirname, dent->d_name);
782 if(stat(path, &statbuf) == -1)
784 WARN("Can't stat %s\n", debugstr_a(path));
787 if(S_ISDIR(statbuf.st_mode))
788 ReadFontDir(path, external_fonts);
790 AddFontFileToList(path, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
796 static void load_fontconfig_fonts(void)
798 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
799 void *fc_handle = NULL;
808 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
810 TRACE("Wine cannot find the fontconfig library (%s).\n",
811 SONAME_LIBFONTCONFIG);
814 #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;}
815 LOAD_FUNCPTR(FcConfigGetCurrent);
816 LOAD_FUNCPTR(FcFontList);
817 LOAD_FUNCPTR(FcFontSetDestroy);
818 LOAD_FUNCPTR(FcInit);
819 LOAD_FUNCPTR(FcObjectSetAdd);
820 LOAD_FUNCPTR(FcObjectSetCreate);
821 LOAD_FUNCPTR(FcObjectSetDestroy);
822 LOAD_FUNCPTR(FcPatternCreate);
823 LOAD_FUNCPTR(FcPatternDestroy);
824 LOAD_FUNCPTR(FcPatternGet);
827 if(!pFcInit()) return;
829 config = pFcConfigGetCurrent();
830 pat = pFcPatternCreate();
831 os = pFcObjectSetCreate();
832 pFcObjectSetAdd(os, FC_FILE);
833 fontset = pFcFontList(config, pat, os);
835 for(i = 0; i < fontset->nfont; i++) {
836 if(pFcPatternGet(fontset->fonts[i], FC_FILE, 0, &v) != FcResultMatch)
838 if(v.type != FcTypeString) continue;
839 TRACE("fontconfig: %s\n", v.u.s);
841 /* We're just interested in OT/TT fonts for now, so this hack just
842 picks up the standard extensions to save time loading every other
845 if(len < 4) continue;
846 ext = v.u.s + len - 3;
847 if(!strcasecmp(ext, "ttf") || !strcasecmp(ext, "ttc") || !strcasecmp(ext, "otf"))
848 AddFontFileToList(v.u.s, NULL, ADDFONT_EXTERNAL_FONT);
850 pFcFontSetDestroy(fontset);
851 pFcObjectSetDestroy(os);
852 pFcPatternDestroy(pat);
859 void load_system_fonts(void)
862 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
865 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
868 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
869 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
870 strcatW(windowsdir, fontsW);
871 for(value = SystemFontValues; *value; value++) {
873 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
875 sprintfW(pathW, fmtW, windowsdir, data);
876 if((unixname = wine_get_unix_file_name(pathW))) {
877 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
878 HeapFree(GetProcessHeap(), 0, unixname);
886 /*************************************************************
888 * This adds registry entries for any externally loaded fonts
889 * (fonts from fontconfig or FontDirs). It also deletes entries
890 * of no longer existing fonts.
893 void update_reg_entries(void)
895 HKEY winkey = 0, externalkey = 0;
898 DWORD dlen, vlen, datalen, valuelen, i, type, len, len_fam;
902 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
903 static const WCHAR spaceW[] = {' ', '\0'};
906 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
907 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winkey, NULL) != ERROR_SUCCESS) {
908 ERR("Can't create Windows font reg key\n");
911 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, external_fonts_reg_key,
912 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
913 ERR("Can't create external font reg key\n");
917 /* Delete all external fonts added last time */
919 RegQueryInfoKeyW(externalkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
920 &valuelen, &datalen, NULL, NULL);
921 valuelen++; /* returned value doesn't include room for '\0' */
922 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
923 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
925 dlen = datalen * sizeof(WCHAR);
928 while(RegEnumValueW(externalkey, i++, valueW, &vlen, NULL, &type, data,
929 &dlen) == ERROR_SUCCESS) {
931 RegDeleteValueW(winkey, valueW);
932 /* reset dlen and vlen */
936 HeapFree(GetProcessHeap(), 0, data);
937 HeapFree(GetProcessHeap(), 0, valueW);
939 /* Delete the old external fonts key */
940 RegCloseKey(externalkey);
942 RegDeleteKeyW(HKEY_LOCAL_MACHINE, external_fonts_reg_key);
944 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, external_fonts_reg_key,
945 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
946 ERR("Can't create external font reg key\n");
950 /* enumerate the fonts and add external ones to the two keys */
952 for(family = FontList; family; family = family->next) {
953 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
954 for(face = family->FirstFace; face; face = face->next) {
955 if(!face->external) continue;
957 if(strcmpiW(face->StyleName, RegularW))
958 len = len_fam + strlenW(face->StyleName) + 1;
959 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
960 strcpyW(valueW, family->FamilyName);
962 strcatW(valueW, spaceW);
963 strcatW(valueW, face->StyleName);
965 strcatW(valueW, TrueType);
966 if((path = strrchr(face->file, '/')) == NULL)
970 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
972 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
973 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
974 RegSetValueExW(winkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
975 RegSetValueExW(externalkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
977 HeapFree(GetProcessHeap(), 0, file);
978 HeapFree(GetProcessHeap(), 0, valueW);
983 RegCloseKey(externalkey);
990 /*************************************************************
991 * WineEngAddFontResourceEx
994 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
996 if (ft_handle) /* do it only if we have freetype up and running */
1001 FIXME("Ignoring flags %lx\n", flags);
1003 if((unixname = wine_get_unix_file_name(file)))
1005 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1006 HeapFree(GetProcessHeap(), 0, unixname);
1012 /*************************************************************
1013 * WineEngRemoveFontResourceEx
1016 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1022 /*************************************************************
1025 * Initialize FreeType library and create a list of available faces
1027 BOOL WineEngInit(void)
1029 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
1031 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1033 WCHAR windowsdir[MAX_PATH];
1039 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
1042 "Wine cannot find the FreeType font library. To enable Wine to\n"
1043 "use TrueType fonts please install a version of FreeType greater than\n"
1044 "or equal to 2.0.5.\n"
1045 "http://www.freetype.org\n");
1049 #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;}
1051 LOAD_FUNCPTR(FT_Vector_Unit)
1052 LOAD_FUNCPTR(FT_Done_Face)
1053 LOAD_FUNCPTR(FT_Get_Char_Index)
1054 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
1055 LOAD_FUNCPTR(FT_Init_FreeType)
1056 LOAD_FUNCPTR(FT_Load_Glyph)
1057 LOAD_FUNCPTR(FT_Matrix_Multiply)
1058 LOAD_FUNCPTR(FT_MulFix)
1059 LOAD_FUNCPTR(FT_New_Face)
1060 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
1061 LOAD_FUNCPTR(FT_Outline_Transform)
1062 LOAD_FUNCPTR(FT_Outline_Translate)
1063 LOAD_FUNCPTR(FT_Select_Charmap)
1064 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
1065 LOAD_FUNCPTR(FT_Vector_Transform)
1068 /* Don't warn if this one is missing */
1069 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
1070 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
1071 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
1072 #ifdef HAVE_FREETYPE_FTWINFNT_H
1073 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
1075 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
1076 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
1077 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
1078 <= 2.0.3 has FT_Sqrt64 */
1082 if(pFT_Init_FreeType(&library) != 0) {
1083 ERR("Can't init FreeType library\n");
1084 wine_dlclose(ft_handle, NULL, 0);
1088 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
1089 if (pFT_Library_Version)
1091 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
1093 if (FT_Version.major<=0)
1099 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
1100 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
1101 ((FT_Version.minor << 8) & 0x00ff00) |
1102 ((FT_Version.patch ) & 0x0000ff);
1104 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
1105 ERR("Failed to create font mutex\n");
1108 WaitForSingleObject(font_mutex, INFINITE);
1110 /* load the system fonts */
1111 load_system_fonts();
1113 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
1114 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1115 strcatW(windowsdir, fontsW);
1116 if((unixname = wine_get_unix_file_name(windowsdir)))
1118 ReadFontDir(unixname, FALSE);
1119 HeapFree(GetProcessHeap(), 0, unixname);
1122 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
1123 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
1124 full path as the entry. Also look for any .fon fonts, since ReadFontDir
1126 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
1127 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1128 &hkey) == ERROR_SUCCESS) {
1130 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1131 &valuelen, &datalen, NULL, NULL);
1133 valuelen++; /* returned value doesn't include room for '\0' */
1134 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1135 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1138 dlen = datalen * sizeof(WCHAR);
1140 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
1141 &dlen) == ERROR_SUCCESS) {
1142 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
1144 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
1146 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1147 HeapFree(GetProcessHeap(), 0, unixname);
1150 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
1152 WCHAR pathW[MAX_PATH];
1153 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1154 sprintfW(pathW, fmtW, windowsdir, data);
1155 if((unixname = wine_get_unix_file_name(pathW)))
1157 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1158 HeapFree(GetProcessHeap(), 0, unixname);
1161 /* reset dlen and vlen */
1166 if (data) HeapFree(GetProcessHeap(), 0, data);
1167 if (valueW) HeapFree(GetProcessHeap(), 0, valueW);
1171 load_fontconfig_fonts();
1173 /* then look in any directories that we've specified in the config file */
1174 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1175 "Software\\Wine\\Wine\\Config\\FontDirs",
1176 &hkey) == ERROR_SUCCESS) {
1178 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1179 &valuelen, &datalen, NULL, NULL);
1181 valuelen++; /* returned value doesn't include room for '\0' */
1182 value = HeapAlloc(GetProcessHeap(), 0, valuelen);
1183 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1188 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1189 &dlen) == ERROR_SUCCESS) {
1190 TRACE("Got %s=%s\n", value, (LPSTR)data);
1191 ReadFontDir((LPSTR)data, TRUE);
1192 /* reset dlen and vlen */
1196 HeapFree(GetProcessHeap(), 0, data);
1197 HeapFree(GetProcessHeap(), 0, value);
1205 update_reg_entries();
1207 ReleaseMutex(font_mutex);
1211 "Wine cannot find certain functions that it needs inside the FreeType\n"
1212 "font library. To enable Wine to use TrueType fonts please upgrade\n"
1213 "FreeType to at least version 2.0.5.\n"
1214 "http://www.freetype.org\n");
1215 wine_dlclose(ft_handle, NULL, 0);
1221 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
1224 TT_HoriHeader *pHori;
1228 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1229 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1231 if(height == 0) height = 16;
1233 /* Calc. height of EM square:
1235 * For +ve lfHeight we have
1236 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
1237 * Re-arranging gives:
1238 * ppem = units_per_em * lfheight / (winAscent + winDescent)
1240 * For -ve lfHeight we have
1242 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
1243 * with il = winAscent + winDescent - units_per_em]
1248 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
1249 ppem = ft_face->units_per_EM * height /
1250 (pHori->Ascender - pHori->Descender);
1252 ppem = ft_face->units_per_EM * height /
1253 (pOS2->usWinAscent + pOS2->usWinDescent);
1261 static LONG load_VDMX(GdiFont, LONG);
1263 static FT_Face OpenFontFile(GdiFont font, char *file, FT_Long face_index, LONG width, LONG height)
1269 err = pFT_New_Face(library, file, face_index, &ft_face);
1271 ERR("FT_New_Face rets %d\n", err);
1275 /* set it here, as load_VDMX needs it */
1276 font->ft_face = ft_face;
1278 if(FT_IS_SCALABLE(ft_face)) {
1279 /* load the VDMX table if we have one */
1280 ppem = load_VDMX(font, height);
1282 ppem = calc_ppem_for_height(ft_face, height);
1284 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, ppem)) != 0)
1285 WARN("FT_Set_Pixel_Sizes %d, %ld rets %x\n", 0, ppem, err);
1287 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
1288 WARN("FT_Set_Pixel_Sizes %ld, %ld rets %x\n", width, height, err);
1294 static int get_nearest_charset(Face *face)
1296 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
1297 a single face with the requested charset. The idea is to check if
1298 the selected font supports the current ANSI codepage, if it does
1299 return the corresponding charset, else return the first charset */
1302 int acp = GetACP(), i;
1305 if(TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE))
1306 if(csi.fs.fsCsb[0] & face->fs.fsCsb[0])
1307 return csi.ciCharset;
1309 for(i = 0; i < 32; i++) {
1311 if(face->fs.fsCsb[0] & fs0) {
1312 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG))
1313 return csi.ciCharset;
1315 FIXME("TCI failing on %lx\n", fs0);
1319 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08lx file = %s\n",
1320 face->fs.fsCsb[0], face->file);
1321 return DEFAULT_CHARSET;
1324 static GdiFont alloc_font(void)
1326 GdiFont ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
1327 ret->gmsize = INIT_GM_SIZE;
1328 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1329 ret->gmsize * sizeof(*ret->gm));
1332 ret->xform.eM11 = ret->xform.eM22 = 1.0;
1336 static void free_font(GdiFont font)
1338 if (font->ft_face) pFT_Done_Face(font->ft_face);
1339 if (font->potm) HeapFree(GetProcessHeap(), 0, font->potm);
1340 if (font->name) HeapFree(GetProcessHeap(), 0, font->name);
1341 HeapFree(GetProcessHeap(), 0, font->gm);
1342 HeapFree(GetProcessHeap(), 0, font);
1346 /*************************************************************
1349 * load the vdmx entry for the specified height
1352 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
1353 ( ( (FT_ULong)_x4 << 24 ) | \
1354 ( (FT_ULong)_x3 << 16 ) | \
1355 ( (FT_ULong)_x2 << 8 ) | \
1358 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
1368 static LONG load_VDMX(GdiFont font, LONG height)
1370 BYTE hdr[6], tmp[2], group[4];
1371 BYTE devXRatio, devYRatio;
1372 USHORT numRecs, numRatios;
1377 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
1379 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
1382 /* FIXME: need the real device aspect ratio */
1386 numRecs = GET_BE_WORD(&hdr[2]);
1387 numRatios = GET_BE_WORD(&hdr[4]);
1389 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
1390 for(i = 0; i < numRatios; i++) {
1393 offset = (3 * 2) + (i * sizeof(Ratios));
1394 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
1397 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
1399 if(ratio.bCharSet != 1)
1402 if((ratio.xRatio == 0 &&
1403 ratio.yStartRatio == 0 &&
1404 ratio.yEndRatio == 0) ||
1405 (devXRatio == ratio.xRatio &&
1406 devYRatio >= ratio.yStartRatio &&
1407 devYRatio <= ratio.yEndRatio))
1409 offset = (3 * 2) + (numRatios * 4) + (i * 2);
1410 WineEngGetFontData(font, MS_VDMX_TAG, offset, tmp, 2);
1411 offset = GET_BE_WORD(tmp);
1417 FIXME("No suitable ratio found\n");
1421 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, group, 4) != GDI_ERROR) {
1423 BYTE startsz, endsz;
1426 recs = GET_BE_WORD(group);
1430 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
1432 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
1433 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
1434 if(result == GDI_ERROR) {
1435 FIXME("Failed to retrieve vTable\n");
1440 for(i = 0; i < recs; i++) {
1441 SHORT yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1442 SHORT yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1443 ppem = GET_BE_WORD(&vTable[i * 6]);
1445 if(yMax + -yMin == height) {
1448 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1451 if(yMax + -yMin > height) {
1454 goto end; /* failed */
1456 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1457 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1458 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1464 TRACE("ppem not found for height %ld\n", height);
1468 if(ppem < startsz || ppem > endsz)
1471 for(i = 0; i < recs; i++) {
1473 yPelHeight = GET_BE_WORD(&vTable[i * 6]);
1475 if(yPelHeight > ppem)
1478 if(yPelHeight == ppem) {
1479 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1480 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1481 TRACE("ppem %ld found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
1487 HeapFree(GetProcessHeap(), 0, vTable);
1494 /*************************************************************
1495 * WineEngCreateFontInstance
1498 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
1502 Family *family = NULL;
1503 INT height, width = 0;
1504 signed int diff = 0, newdiff;
1505 BOOL bd, it, can_use_bitmap;
1509 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
1510 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
1512 TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
1513 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
1514 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
1517 /* check the cache first */
1518 for(ret = GdiFontList; ret; ret = ret->next) {
1519 if(ret->hfont == hfont && !memcmp(&ret->xform, &dc->xformWorld2Vport, offsetof(XFORM, eDx)) &&
1520 (can_use_bitmap || FT_IS_SCALABLE(ret->ft_face))) {
1522 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
1527 if(!FontList || !have_installed_roman_font) /* No fonts installed */
1529 TRACE("No fonts installed\n");
1534 memcpy(&ret->xform, &dc->xformWorld2Vport, sizeof(XFORM));
1536 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
1537 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
1538 original value lfCharSet. Note this is a special case for
1539 Symbol and doesn't happen at least for "Wingdings*" */
1541 if(!strcmpiW(lf.lfFaceName, SymbolW))
1542 lf.lfCharSet = SYMBOL_CHARSET;
1544 if(!TranslateCharsetInfo((DWORD*)(INT)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
1545 switch(lf.lfCharSet) {
1546 case DEFAULT_CHARSET:
1547 csi.fs.fsCsb[0] = 0;
1550 FIXME("Untranslated charset %d\n", lf.lfCharSet);
1551 csi.fs.fsCsb[0] = 0;
1556 if(lf.lfFaceName[0] != '\0') {
1558 for(psub = substlist; psub; psub = psub->next)
1559 if(!strcmpiW(lf.lfFaceName, psub->from.name) &&
1560 (psub->from.charset == -1 ||
1561 psub->from.charset == lf.lfCharSet))
1564 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
1565 debugstr_w(psub->to.name));
1566 strcpyW(lf.lfFaceName, psub->to.name);
1569 /* We want a match on name and charset or just name if
1570 charset was DEFAULT_CHARSET. If the latter then
1571 we fixup the returned charset later in get_nearest_charset
1572 where we'll either use the charset of the current ansi codepage
1573 or if that's unavailable the first charset that the font supports.
1575 for(family = FontList; family; family = family->next) {
1576 if(!strcmpiW(family->FamilyName, lf.lfFaceName))
1577 if((csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0]) || !csi.fs.fsCsb[0])
1578 if(family->FirstFace->scalable || can_use_bitmap)
1584 /* If requested charset was DEFAULT_CHARSET then try using charset
1585 corresponding to the current ansi codepage */
1586 if(!csi.fs.fsCsb[0]) {
1588 if(!TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE)) {
1589 FIXME("TCI failed on codepage %d\n", acp);
1590 csi.fs.fsCsb[0] = 0;
1592 lf.lfCharSet = csi.ciCharset;
1595 /* Face families are in the top 4 bits of lfPitchAndFamily,
1596 so mask with 0xF0 before testing */
1598 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
1599 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
1600 strcpyW(lf.lfFaceName, defFixed);
1601 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
1602 strcpyW(lf.lfFaceName, defSerif);
1603 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
1604 strcpyW(lf.lfFaceName, defSans);
1606 strcpyW(lf.lfFaceName, defSans);
1607 for(family = FontList; family; family = family->next) {
1608 if(!strcmpiW(family->FamilyName, lf.lfFaceName) &&
1609 (csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0]))
1610 if(family->FirstFace->scalable || can_use_bitmap)
1616 for(family = FontList; family; family = family->next) {
1617 if(csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0])
1618 if(family->FirstFace->scalable || can_use_bitmap)
1625 csi.fs.fsCsb[0] = 0;
1626 FIXME("just using first face for now\n");
1629 it = lf.lfItalic ? 1 : 0;
1630 bd = lf.lfWeight > 550 ? 1 : 0;
1632 height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
1633 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
1636 for(face = family->FirstFace; face; face = face->next) {
1637 if(!(face->Italic ^ it) && !(face->Bold ^ bd)) {
1641 newdiff = height - (signed int)(face->size.y_ppem >> 6);
1643 newdiff = -height - ((signed int)(face->size.y_ppem >> 6) - face->size.internal_leading);
1644 if(!best || (diff > 0 && newdiff < diff && newdiff >= 0) ||
1645 (diff < 0 && newdiff > diff)) {
1646 TRACE("%ld is better for %d diff was %d\n", face->size.y_ppem >> 6, height, diff);
1657 face = family->FirstFace;
1658 if(it && !face->Italic) ret->fake_italic = TRUE;
1659 if(bd && !face->Bold) ret->fake_bold = TRUE;
1662 memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
1665 ret->charset = lf.lfCharSet;
1667 ret->charset = get_nearest_charset(face);
1669 TRACE("Chosen: %s %s\n", debugstr_w(family->FamilyName),
1670 debugstr_w(face->StyleName));
1672 if(!face->scalable) {
1673 width = face->size.x_ppem >> 6;
1674 height = face->size.y_ppem >> 6;
1676 ret->ft_face = OpenFontFile(ret, face->file, face->face_index, width, height);
1684 if (ret->charset == SYMBOL_CHARSET &&
1685 !pFT_Select_Charmap(ret->ft_face, ft_encoding_symbol)) {
1688 else if (!pFT_Select_Charmap(ret->ft_face, ft_encoding_unicode)) {
1692 pFT_Select_Charmap(ret->ft_face, ft_encoding_apple_roman);
1695 ret->orientation = lf.lfOrientation;
1696 ret->name = strdupW(family->FamilyName);
1698 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
1700 ret->aveWidth= lf.lfWidth;
1701 ret->next = GdiFontList;
1707 static void DumpGdiFontList(void)
1711 TRACE("---------- gdiFont Cache ----------\n");
1712 for(gdiFont = GdiFontList; gdiFont; gdiFont = gdiFont->next) {
1714 GetObjectW( gdiFont->hfont, sizeof(lf), &lf );
1715 TRACE("gdiFont=%p hfont=%p (%s)\n",
1716 gdiFont, gdiFont->hfont, debugstr_w(lf.lfFaceName));
1720 /*************************************************************
1721 * WineEngDestroyFontInstance
1723 * free the gdiFont associated with this handle
1726 BOOL WineEngDestroyFontInstance(HFONT handle)
1729 GdiFont gdiPrev = NULL;
1732 TRACE("destroying hfont=%p\n", handle);
1736 gdiFont = GdiFontList;
1738 if(gdiFont->hfont == handle) {
1740 gdiPrev->next = gdiFont->next;
1742 gdiFont = gdiPrev->next;
1744 GdiFontList = gdiFont->next;
1746 gdiFont = GdiFontList;
1751 gdiFont = gdiFont->next;
1757 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
1758 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
1760 OUTLINETEXTMETRICW *potm = NULL;
1762 TEXTMETRICW tm, *ptm;
1763 GdiFont font = alloc_font();
1766 if(face->scalable) {
1770 height = face->size.y_ppem >> 6;
1771 width = face->size.x_ppem >> 6;
1774 if (!(font->ft_face = OpenFontFile(font, face->file, face->face_index, width, height)))
1780 font->name = strdupW(face->family->FamilyName);
1782 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
1784 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
1786 potm = HeapAlloc(GetProcessHeap(), 0, size);
1787 WineEngGetOutlineTextMetrics(font, size, potm);
1788 ptm = (TEXTMETRICW*)&potm->otmTextMetrics;
1790 WineEngGetTextMetrics(font, &tm);
1794 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = ptm->tmHeight;
1795 pntm->ntmTm.tmAscent = ptm->tmAscent;
1796 pntm->ntmTm.tmDescent = ptm->tmDescent;
1797 pntm->ntmTm.tmInternalLeading = ptm->tmInternalLeading;
1798 pntm->ntmTm.tmExternalLeading = ptm->tmExternalLeading;
1799 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = ptm->tmAveCharWidth;
1800 pntm->ntmTm.tmMaxCharWidth = ptm->tmMaxCharWidth;
1801 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = ptm->tmWeight;
1802 pntm->ntmTm.tmOverhang = ptm->tmOverhang;
1803 pntm->ntmTm.tmDigitizedAspectX = ptm->tmDigitizedAspectX;
1804 pntm->ntmTm.tmDigitizedAspectY = ptm->tmDigitizedAspectY;
1805 pntm->ntmTm.tmFirstChar = ptm->tmFirstChar;
1806 pntm->ntmTm.tmLastChar = ptm->tmLastChar;
1807 pntm->ntmTm.tmDefaultChar = ptm->tmDefaultChar;
1808 pntm->ntmTm.tmBreakChar = ptm->tmBreakChar;
1809 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = ptm->tmItalic;
1810 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = ptm->tmUnderlined;
1811 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = ptm->tmStruckOut;
1812 pntm->ntmTm.tmPitchAndFamily = ptm->tmPitchAndFamily;
1813 pelf->elfLogFont.lfPitchAndFamily = (ptm->tmPitchAndFamily & 0xf1) + 1;
1814 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = ptm->tmCharSet;
1815 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
1816 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
1817 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
1819 *ptype = ptm->tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
1820 if(!(ptm->tmPitchAndFamily & TMPF_VECTOR))
1821 *ptype |= RASTER_FONTTYPE;
1824 pntm->ntmTm.ntmFlags = ptm->tmItalic ? NTM_ITALIC : 0;
1825 if(ptm->tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
1826 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
1828 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
1829 pntm->ntmTm.ntmCellHeight = 0;
1830 pntm->ntmTm.ntmAvgWidth = 0;
1832 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
1834 strncpyW(pelf->elfLogFont.lfFaceName,
1835 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
1837 strncpyW(pelf->elfFullName,
1838 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
1840 strncpyW(pelf->elfStyle,
1841 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
1845 strncpyW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
1846 strncpyW(pelf->elfFullName, face->family->FamilyName, LF_FACESIZE);
1847 pelf->elfStyle[0] = '\0';
1850 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
1852 HeapFree(GetProcessHeap(), 0, potm);
1857 /*************************************************************
1861 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
1866 NEWTEXTMETRICEXW ntm;
1867 DWORD type, ret = 1;
1873 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
1875 if(plf->lfFaceName[0]) {
1877 for(psub = substlist; psub; psub = psub->next)
1878 if(!strcmpiW(plf->lfFaceName, psub->from.name) &&
1879 (psub->from.charset == -1 ||
1880 psub->from.charset == plf->lfCharSet))
1883 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
1884 debugstr_w(psub->to.name));
1885 memcpy(&lf, plf, sizeof(lf));
1886 strcpyW(lf.lfFaceName, psub->to.name);
1889 for(family = FontList; family; family = family->next) {
1890 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
1891 for(face = family->FirstFace; face; face = face->next) {
1892 GetEnumStructs(face, &elf, &ntm, &type);
1893 for(i = 0; i < 32; i++) {
1894 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
1895 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
1896 strcpyW(elf.elfScript, OEM_DOSW);
1897 i = 32; /* break out of loop */
1898 } else if(!(face->fs.fsCsb[0] & (1L << i)))
1901 fs.fsCsb[0] = 1L << i;
1903 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
1905 csi.ciCharset = DEFAULT_CHARSET;
1906 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
1907 if(csi.ciCharset != DEFAULT_CHARSET) {
1908 elf.elfLogFont.lfCharSet =
1909 ntm.ntmTm.tmCharSet = csi.ciCharset;
1911 strcpyW(elf.elfScript, ElfScriptsW[i]);
1913 FIXME("Unknown elfscript for bit %d\n", i);
1916 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
1917 debugstr_w(elf.elfLogFont.lfFaceName),
1918 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
1919 csi.ciCharset, type, debugstr_w(elf.elfScript),
1920 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
1921 ntm.ntmTm.ntmFlags);
1922 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
1929 for(family = FontList; family; family = family->next) {
1930 GetEnumStructs(family->FirstFace, &elf, &ntm, &type);
1931 for(i = 0; i < 32; i++) {
1932 if(!family->FirstFace->scalable && family->FirstFace->fs.fsCsb[0] == 0) { /* OEM bitmap */
1933 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
1934 strcpyW(elf.elfScript, OEM_DOSW);
1935 i = 32; /* break out of loop */
1936 } else if(!(family->FirstFace->fs.fsCsb[0] & (1L << i)))
1939 fs.fsCsb[0] = 1L << i;
1941 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
1943 csi.ciCharset = DEFAULT_CHARSET;
1944 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
1945 if(csi.ciCharset != DEFAULT_CHARSET) {
1946 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
1949 strcpyW(elf.elfScript, ElfScriptsW[i]);
1951 FIXME("Unknown elfscript for bit %d\n", i);
1954 TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
1955 debugstr_w(elf.elfLogFont.lfFaceName),
1956 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
1957 csi.ciCharset, type, debugstr_w(elf.elfScript),
1958 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
1959 ntm.ntmTm.ntmFlags);
1960 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
1969 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
1971 pt->x.value = vec->x >> 6;
1972 pt->x.fract = (vec->x & 0x3f) << 10;
1973 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
1974 pt->y.value = vec->y >> 6;
1975 pt->y.fract = (vec->y & 0x3f) << 10;
1976 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
1980 static FT_UInt get_glyph_index(GdiFont font, UINT glyph)
1982 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
1983 glyph = glyph + 0xf000;
1984 return pFT_Get_Char_Index(font->ft_face, glyph);
1987 /*************************************************************
1988 * WineEngGetGlyphIndices
1990 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
1992 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
1993 LPWORD pgi, DWORD flags)
1997 for(i = 0; i < count; i++)
1998 pgi[i] = get_glyph_index(font, lpstr[i]);
2003 /*************************************************************
2004 * WineEngGetGlyphOutline
2006 * Behaves in exactly the same way as the win32 api GetGlyphOutline
2007 * except that the first parameter is the HWINEENGFONT of the font in
2008 * question rather than an HDC.
2011 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
2012 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
2015 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
2016 FT_Face ft_face = font->ft_face;
2017 FT_UInt glyph_index;
2018 DWORD width, height, pitch, needed = 0;
2019 FT_Bitmap ft_bitmap;
2021 INT left, right, top = 0, bottom = 0;
2023 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
2024 float widthRatio = 1.0;
2025 FT_Matrix transMat = identityMat;
2026 BOOL needsTransform = FALSE;
2029 TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font, glyph, format, lpgm,
2030 buflen, buf, lpmat);
2032 if(format & GGO_GLYPH_INDEX) {
2033 glyph_index = glyph;
2034 format &= ~GGO_GLYPH_INDEX;
2036 glyph_index = get_glyph_index(font, glyph);
2038 if(glyph_index >= font->gmsize) {
2039 font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
2040 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
2041 font->gmsize * sizeof(*font->gm));
2043 if(format == GGO_METRICS && font->gm[glyph_index].init) {
2044 memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
2045 return 1; /* FIXME */
2049 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP) || font->aveWidth || lpmat)
2050 load_flags |= FT_LOAD_NO_BITMAP;
2052 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
2055 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
2059 /* Scaling factor */
2060 if (font->aveWidth && font->potm) {
2061 widthRatio = (float)font->aveWidth * font->xform.eM11 / (float) font->potm->otmTextMetrics.tmAveCharWidth;
2064 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
2065 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
2067 font->gm[glyph_index].adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
2068 font->gm[glyph_index].lsb = left >> 6;
2069 font->gm[glyph_index].bbx = (right - left) >> 6;
2071 /* Scaling transform */
2072 if(font->aveWidth) {
2074 scaleMat.xx = FT_FixedFromFloat(widthRatio);
2077 scaleMat.yy = (1 << 16);
2079 pFT_Matrix_Multiply(&scaleMat, &transMat);
2080 needsTransform = TRUE;
2083 /* Rotation transform */
2084 if(font->orientation) {
2085 FT_Matrix rotationMat;
2087 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
2088 pFT_Vector_Unit(&vecAngle, angle);
2089 rotationMat.xx = vecAngle.x;
2090 rotationMat.xy = -vecAngle.y;
2091 rotationMat.yx = -rotationMat.xy;
2092 rotationMat.yy = rotationMat.xx;
2094 pFT_Matrix_Multiply(&rotationMat, &transMat);
2095 needsTransform = TRUE;
2098 /* Extra transformation specified by caller */
2101 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
2102 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
2103 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
2104 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
2105 pFT_Matrix_Multiply(&extraMat, &transMat);
2106 needsTransform = TRUE;
2109 if(!needsTransform) {
2110 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
2111 bottom = (ft_face->glyph->metrics.horiBearingY -
2112 ft_face->glyph->metrics.height) & -64;
2113 lpgm->gmCellIncX = font->gm[glyph_index].adv;
2114 lpgm->gmCellIncY = 0;
2118 for(xc = 0; xc < 2; xc++) {
2119 for(yc = 0; yc < 2; yc++) {
2120 vec.x = (ft_face->glyph->metrics.horiBearingX +
2121 xc * ft_face->glyph->metrics.width);
2122 vec.y = ft_face->glyph->metrics.horiBearingY -
2123 yc * ft_face->glyph->metrics.height;
2124 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
2125 pFT_Vector_Transform(&vec, &transMat);
2126 if(xc == 0 && yc == 0) {
2127 left = right = vec.x;
2128 top = bottom = vec.y;
2130 if(vec.x < left) left = vec.x;
2131 else if(vec.x > right) right = vec.x;
2132 if(vec.y < bottom) bottom = vec.y;
2133 else if(vec.y > top) top = vec.y;
2138 right = (right + 63) & -64;
2139 bottom = bottom & -64;
2140 top = (top + 63) & -64;
2142 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
2143 vec.x = ft_face->glyph->metrics.horiAdvance;
2145 pFT_Vector_Transform(&vec, &transMat);
2146 lpgm->gmCellIncX = (vec.x+63) >> 6;
2147 lpgm->gmCellIncY = -((vec.y+63) >> 6);
2149 lpgm->gmBlackBoxX = (right - left) >> 6;
2150 lpgm->gmBlackBoxY = (top - bottom) >> 6;
2151 lpgm->gmptGlyphOrigin.x = left >> 6;
2152 lpgm->gmptGlyphOrigin.y = top >> 6;
2154 memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
2155 font->gm[glyph_index].init = TRUE;
2157 if(format == GGO_METRICS)
2158 return 1; /* FIXME */
2160 if (buf && !buflen){
2164 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP) {
2165 TRACE("loaded a bitmap\n");
2171 width = lpgm->gmBlackBoxX;
2172 height = lpgm->gmBlackBoxY;
2173 pitch = ((width + 31) >> 5) << 2;
2174 needed = pitch * height;
2176 if(!buf || !buflen) break;
2178 switch(ft_face->glyph->format) {
2179 case ft_glyph_format_bitmap:
2181 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
2182 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
2183 INT h = ft_face->glyph->bitmap.rows;
2185 memcpy(dst, src, w);
2186 src += ft_face->glyph->bitmap.pitch;
2192 case ft_glyph_format_outline:
2193 ft_bitmap.width = width;
2194 ft_bitmap.rows = height;
2195 ft_bitmap.pitch = pitch;
2196 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
2197 ft_bitmap.buffer = buf;
2199 if(needsTransform) {
2200 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
2203 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
2205 /* Note: FreeType will only set 'black' bits for us. */
2206 memset(buf, 0, needed);
2207 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
2211 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
2216 case GGO_GRAY2_BITMAP:
2217 case GGO_GRAY4_BITMAP:
2218 case GGO_GRAY8_BITMAP:
2219 case WINE_GGO_GRAY16_BITMAP:
2224 width = lpgm->gmBlackBoxX;
2225 height = lpgm->gmBlackBoxY;
2226 pitch = (width + 3) / 4 * 4;
2227 needed = pitch * height;
2229 if(!buf || !buflen) break;
2230 ft_bitmap.width = width;
2231 ft_bitmap.rows = height;
2232 ft_bitmap.pitch = pitch;
2233 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
2234 ft_bitmap.buffer = buf;
2236 if(needsTransform) {
2237 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
2240 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
2242 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
2244 if(format == GGO_GRAY2_BITMAP)
2246 else if(format == GGO_GRAY4_BITMAP)
2248 else if(format == GGO_GRAY8_BITMAP)
2250 else if(format == WINE_GGO_GRAY16_BITMAP)
2258 for(row = 0; row < height; row++) {
2260 for(col = 0; col < width; col++, ptr++) {
2261 *ptr = (*(unsigned int*)ptr * mult + 128) / 256;
2270 int contour, point = 0, first_pt;
2271 FT_Outline *outline = &ft_face->glyph->outline;
2272 TTPOLYGONHEADER *pph;
2274 DWORD pph_start, cpfx, type;
2276 if(buflen == 0) buf = NULL;
2278 if (needsTransform && buf) {
2279 pFT_Outline_Transform(outline, &transMat);
2282 for(contour = 0; contour < outline->n_contours; contour++) {
2284 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
2287 pph->dwType = TT_POLYGON_TYPE;
2288 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2290 needed += sizeof(*pph);
2292 while(point <= outline->contours[contour]) {
2293 ppc = (TTPOLYCURVE *)((char *)buf + needed);
2294 type = (outline->tags[point] & FT_Curve_Tag_On) ?
2295 TT_PRIM_LINE : TT_PRIM_QSPLINE;
2299 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2302 } while(point <= outline->contours[contour] &&
2303 (outline->tags[point] & FT_Curve_Tag_On) ==
2304 (outline->tags[point-1] & FT_Curve_Tag_On));
2305 /* At the end of a contour Windows adds the start point, but
2307 if(point > outline->contours[contour] &&
2308 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
2310 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
2312 } else if(point <= outline->contours[contour] &&
2313 outline->tags[point] & FT_Curve_Tag_On) {
2314 /* add closing pt for bezier */
2316 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2324 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2327 pph->cb = needed - pph_start;
2333 /* Convert the quadratic Beziers to cubic Beziers.
2334 The parametric eqn for a cubic Bezier is, from PLRM:
2335 r(t) = at^3 + bt^2 + ct + r0
2336 with the control points:
2341 A quadratic Beizer has the form:
2342 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
2344 So equating powers of t leads to:
2345 r1 = 2/3 p1 + 1/3 p0
2346 r2 = 2/3 p1 + 1/3 p2
2347 and of course r0 = p0, r3 = p2
2350 int contour, point = 0, first_pt;
2351 FT_Outline *outline = &ft_face->glyph->outline;
2352 TTPOLYGONHEADER *pph;
2354 DWORD pph_start, cpfx, type;
2355 FT_Vector cubic_control[4];
2356 if(buflen == 0) buf = NULL;
2358 if (needsTransform && buf) {
2359 pFT_Outline_Transform(outline, &transMat);
2362 for(contour = 0; contour < outline->n_contours; contour++) {
2364 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
2367 pph->dwType = TT_POLYGON_TYPE;
2368 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2370 needed += sizeof(*pph);
2372 while(point <= outline->contours[contour]) {
2373 ppc = (TTPOLYCURVE *)((char *)buf + needed);
2374 type = (outline->tags[point] & FT_Curve_Tag_On) ?
2375 TT_PRIM_LINE : TT_PRIM_CSPLINE;
2378 if(type == TT_PRIM_LINE) {
2380 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2384 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
2387 /* FIXME: Possible optimization in endpoint calculation
2388 if there are two consecutive curves */
2389 cubic_control[0] = outline->points[point-1];
2390 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
2391 cubic_control[0].x += outline->points[point].x + 1;
2392 cubic_control[0].y += outline->points[point].y + 1;
2393 cubic_control[0].x >>= 1;
2394 cubic_control[0].y >>= 1;
2396 if(point+1 > outline->contours[contour])
2397 cubic_control[3] = outline->points[first_pt];
2399 cubic_control[3] = outline->points[point+1];
2400 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
2401 cubic_control[3].x += outline->points[point].x + 1;
2402 cubic_control[3].y += outline->points[point].y + 1;
2403 cubic_control[3].x >>= 1;
2404 cubic_control[3].y >>= 1;
2407 /* r1 = 1/3 p0 + 2/3 p1
2408 r2 = 1/3 p2 + 2/3 p1 */
2409 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
2410 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
2411 cubic_control[2] = cubic_control[1];
2412 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
2413 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
2414 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
2415 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
2417 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
2418 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
2419 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
2424 } while(point <= outline->contours[contour] &&
2425 (outline->tags[point] & FT_Curve_Tag_On) ==
2426 (outline->tags[point-1] & FT_Curve_Tag_On));
2427 /* At the end of a contour Windows adds the start point,
2428 but only for Beziers and we've already done that.
2430 if(point <= outline->contours[contour] &&
2431 outline->tags[point] & FT_Curve_Tag_On) {
2432 /* This is the closing pt of a bezier, but we've already
2433 added it, so just inc point and carry on */
2440 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2443 pph->cb = needed - pph_start;
2449 FIXME("Unsupported format %d\n", format);
2455 static BOOL get_bitmap_text_metrics(GdiFont font)
2457 FT_Face ft_face = font->ft_face;
2458 #ifdef HAVE_FREETYPE_FTWINFNT_H
2459 FT_WinFNT_HeaderRec winfnt_header;
2461 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
2462 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
2463 font->potm->otmSize = size;
2465 #define TM font->potm->otmTextMetrics
2466 #ifdef HAVE_FREETYPE_FTWINFNT_H
2467 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
2469 TM.tmHeight = winfnt_header.pixel_height;
2470 TM.tmAscent = winfnt_header.ascent;
2471 TM.tmDescent = TM.tmHeight - TM.tmAscent;
2472 TM.tmInternalLeading = winfnt_header.internal_leading;
2473 TM.tmExternalLeading = winfnt_header.external_leading;
2474 TM.tmAveCharWidth = winfnt_header.avg_width;
2475 TM.tmMaxCharWidth = winfnt_header.max_width;
2476 TM.tmWeight = winfnt_header.weight;
2478 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
2479 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
2480 TM.tmFirstChar = winfnt_header.first_char;
2481 TM.tmLastChar = winfnt_header.last_char;
2482 TM.tmDefaultChar = winfnt_header.default_char;
2483 TM.tmBreakChar = winfnt_header.break_char;
2484 TM.tmItalic = winfnt_header.italic;
2485 TM.tmUnderlined = winfnt_header.underline;
2486 TM.tmStruckOut = winfnt_header.strike_out;
2487 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
2488 TM.tmCharSet = winfnt_header.charset;
2493 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
2494 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
2495 TM.tmHeight = TM.tmAscent + TM.tmDescent;
2496 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
2497 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
2498 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
2499 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
2500 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
2502 TM.tmDigitizedAspectX = 96; /* FIXME */
2503 TM.tmDigitizedAspectY = 96; /* FIXME */
2505 TM.tmLastChar = 255;
2506 TM.tmDefaultChar = 32;
2507 TM.tmBreakChar = 32;
2508 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
2509 TM.tmUnderlined = 0;
2511 /* NB inverted meaning of TMPF_FIXED_PITCH */
2512 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
2513 TM.tmCharSet = font->charset;
2520 /*************************************************************
2521 * WineEngGetTextMetrics
2524 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
2527 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
2528 if(!get_bitmap_text_metrics(font))
2531 if(!font->potm) return FALSE;
2532 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
2534 if (font->aveWidth) {
2535 ptm->tmAveCharWidth = font->aveWidth * font->xform.eM11;
2541 /*************************************************************
2542 * WineEngGetOutlineTextMetrics
2545 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
2546 OUTLINETEXTMETRICW *potm)
2548 FT_Face ft_face = font->ft_face;
2549 UINT needed, lenfam, lensty, ret;
2551 TT_HoriHeader *pHori;
2552 TT_Postscript *pPost;
2553 FT_Fixed x_scale, y_scale;
2554 WCHAR *family_nameW, *style_nameW;
2555 static const WCHAR spaceW[] = {' ', '\0'};
2557 INT ascent, descent;
2559 TRACE("font=%p\n", font);
2561 if(!FT_IS_SCALABLE(ft_face))
2565 if(cbSize >= font->potm->otmSize)
2566 memcpy(potm, font->potm, font->potm->otmSize);
2567 return font->potm->otmSize;
2571 needed = sizeof(*potm);
2573 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
2574 family_nameW = strdupW(font->name);
2576 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
2578 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
2579 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
2580 style_nameW, lensty);
2582 /* These names should be read from the TT name table */
2584 /* length of otmpFamilyName */
2587 /* length of otmpFaceName */
2588 if(!strcasecmp(ft_face->style_name, "regular")) {
2589 needed += lenfam; /* just the family name */
2591 needed += lenfam + lensty; /* family + " " + style */
2594 /* length of otmpStyleName */
2597 /* length of otmpFullName */
2598 needed += lenfam + lensty;
2601 x_scale = ft_face->size->metrics.x_scale;
2602 y_scale = ft_face->size->metrics.y_scale;
2604 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2606 FIXME("Can't find OS/2 table - not TT font?\n");
2611 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2613 FIXME("Can't find HHEA table - not TT font?\n");
2618 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
2620 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",
2621 pOS2->usWinAscent, pOS2->usWinDescent,
2622 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
2623 ft_face->ascender, ft_face->descender, ft_face->height,
2624 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
2625 ft_face->bbox.yMax, ft_face->bbox.yMin);
2627 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
2628 font->potm->otmSize = needed;
2630 #define TM font->potm->otmTextMetrics
2632 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
2633 ascent = pHori->Ascender;
2634 descent = -pHori->Descender;
2636 ascent = pOS2->usWinAscent;
2637 descent = pOS2->usWinDescent;
2641 TM.tmAscent = font->yMax;
2642 TM.tmDescent = -font->yMin;
2643 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
2645 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
2646 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
2647 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
2648 - ft_face->units_per_EM, y_scale) + 32) >> 6;
2651 TM.tmHeight = TM.tmAscent + TM.tmDescent;
2654 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
2656 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
2657 ((ascent + descent) -
2658 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
2660 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
2661 if (TM.tmAveCharWidth == 0) {
2662 TM.tmAveCharWidth = 1;
2664 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
2665 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
2667 TM.tmDigitizedAspectX = 300;
2668 TM.tmDigitizedAspectY = 300;
2669 TM.tmFirstChar = pOS2->usFirstCharIndex;
2670 TM.tmLastChar = pOS2->usLastCharIndex;
2671 TM.tmDefaultChar = pOS2->usDefaultChar;
2672 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
2673 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
2674 TM.tmUnderlined = 0; /* entry in OS2 table */
2675 TM.tmStruckOut = 0; /* entry in OS2 table */
2677 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
2678 if(!FT_IS_FIXED_WIDTH(ft_face))
2679 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
2681 TM.tmPitchAndFamily = 0;
2683 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
2684 case PAN_FAMILY_SCRIPT:
2685 TM.tmPitchAndFamily |= FF_SCRIPT;
2687 case PAN_FAMILY_DECORATIVE:
2688 case PAN_FAMILY_PICTORIAL:
2689 TM.tmPitchAndFamily |= FF_DECORATIVE;
2691 case PAN_FAMILY_TEXT_DISPLAY:
2692 if(TM.tmPitchAndFamily == 0) /* fixed */
2693 TM.tmPitchAndFamily = FF_MODERN;
2695 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
2696 case PAN_SERIF_NORMAL_SANS:
2697 case PAN_SERIF_OBTUSE_SANS:
2698 case PAN_SERIF_PERP_SANS:
2699 TM.tmPitchAndFamily |= FF_SWISS;
2702 TM.tmPitchAndFamily |= FF_ROMAN;
2707 TM.tmPitchAndFamily |= FF_DONTCARE;
2710 if(FT_IS_SCALABLE(ft_face))
2711 TM.tmPitchAndFamily |= TMPF_VECTOR;
2712 if(FT_IS_SFNT(ft_face))
2713 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
2715 TM.tmCharSet = font->charset;
2718 font->potm->otmFiller = 0;
2719 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
2720 font->potm->otmfsSelection = pOS2->fsSelection;
2721 font->potm->otmfsType = pOS2->fsType;
2722 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
2723 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
2724 font->potm->otmItalicAngle = 0; /* POST table */
2725 font->potm->otmEMSquare = ft_face->units_per_EM;
2726 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
2727 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
2728 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
2729 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
2730 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
2731 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
2732 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
2733 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
2734 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
2735 font->potm->otmMacAscent = 0; /* where do these come from ? */
2736 font->potm->otmMacDescent = 0;
2737 font->potm->otmMacLineGap = 0;
2738 font->potm->otmusMinimumPPEM = 0; /* TT Header */
2739 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
2740 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
2741 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
2742 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
2743 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
2744 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
2745 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
2746 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
2747 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
2748 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
2750 font->potm->otmsUnderscoreSize = 0;
2751 font->potm->otmsUnderscorePosition = 0;
2753 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
2754 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
2757 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
2758 cp = (char*)font->potm + sizeof(*font->potm);
2759 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
2760 strcpyW((WCHAR*)cp, family_nameW);
2762 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
2763 strcpyW((WCHAR*)cp, style_nameW);
2765 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
2766 strcpyW((WCHAR*)cp, family_nameW);
2767 if(strcasecmp(ft_face->style_name, "regular")) {
2768 strcatW((WCHAR*)cp, spaceW);
2769 strcatW((WCHAR*)cp, style_nameW);
2770 cp += lenfam + lensty;
2773 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
2774 strcpyW((WCHAR*)cp, family_nameW);
2775 strcatW((WCHAR*)cp, spaceW);
2776 strcatW((WCHAR*)cp, style_nameW);
2779 if(potm && needed <= cbSize)
2780 memcpy(potm, font->potm, font->potm->otmSize);
2783 HeapFree(GetProcessHeap(), 0, style_nameW);
2784 HeapFree(GetProcessHeap(), 0, family_nameW);
2790 /*************************************************************
2791 * WineEngGetCharWidth
2794 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
2799 FT_UInt glyph_index;
2801 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
2803 for(c = firstChar; c <= lastChar; c++) {
2804 glyph_index = get_glyph_index(font, c);
2805 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
2806 &gm, 0, NULL, NULL);
2807 buffer[c - firstChar] = font->gm[glyph_index].adv;
2812 /*************************************************************
2813 * WineEngGetCharABCWidths
2816 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
2821 FT_UInt glyph_index;
2823 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
2825 for(c = firstChar; c <= lastChar; c++) {
2826 glyph_index = get_glyph_index(font, c);
2827 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
2828 &gm, 0, NULL, NULL);
2829 buffer[c - firstChar].abcA = font->gm[glyph_index].lsb;
2830 buffer[c - firstChar].abcB = font->gm[glyph_index].bbx;
2831 buffer[c - firstChar].abcC = font->gm[glyph_index].adv - font->gm[glyph_index].lsb -
2832 font->gm[glyph_index].bbx;
2837 /*************************************************************
2838 * WineEngGetTextExtentPoint
2841 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
2847 FT_UInt glyph_index;
2849 TRACE("%p, %s, %d, %p\n", font, debugstr_wn(wstr, count), count,
2853 WineEngGetTextMetrics(font, &tm);
2854 size->cy = tm.tmHeight;
2856 for(idx = 0; idx < count; idx++) {
2857 glyph_index = get_glyph_index(font, wstr[idx]);
2858 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
2859 &gm, 0, NULL, NULL);
2860 size->cx += font->gm[glyph_index].adv;
2862 TRACE("return %ld,%ld\n", size->cx, size->cy);
2866 /*************************************************************
2867 * WineEngGetTextExtentPointI
2870 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
2877 TRACE("%p, %p, %d, %p\n", font, indices, count, size);
2880 WineEngGetTextMetrics(font, &tm);
2881 size->cy = tm.tmHeight;
2883 for(idx = 0; idx < count; idx++) {
2884 WineEngGetGlyphOutline(font, indices[idx],
2885 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
2887 size->cx += font->gm[indices[idx]].adv;
2889 TRACE("return %ld,%ld\n", size->cx, size->cy);
2893 /*************************************************************
2894 * WineEngGetFontData
2897 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
2900 FT_Face ft_face = font->ft_face;
2904 TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
2905 font, table, offset, buf, cbData);
2907 if(!FT_IS_SFNT(ft_face))
2915 if(table) { /* MS tags differ in endidness from FT ones */
2916 table = table >> 24 | table << 24 |
2917 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
2920 /* If the FT_Load_Sfnt_Table function is there we'll use it */
2921 if(pFT_Load_Sfnt_Table)
2922 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
2923 else { /* Do it the hard way */
2924 TT_Face tt_face = (TT_Face) ft_face;
2925 SFNT_Interface *sfnt;
2926 if (FT_Version.major==2 && FT_Version.minor==0)
2929 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
2933 /* A field was added in the middle of the structure in 2.1.x */
2934 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
2936 err = sfnt->load_any(tt_face, table, offset, buf, &len);
2939 TRACE("Can't find table %08lx.\n", table);
2945 /*************************************************************
2946 * WineEngGetTextFace
2949 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
2952 lstrcpynW(str, font->name, count);
2953 return strlenW(font->name);
2955 return strlenW(font->name) + 1;
2958 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
2960 if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
2961 return font->charset;
2964 #else /* HAVE_FREETYPE */
2966 BOOL WineEngInit(void)
2970 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
2974 BOOL WineEngDestroyFontInstance(HFONT hfont)
2979 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
2984 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
2985 LPWORD pgi, DWORD flags)
2990 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
2991 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
2994 ERR("called but we don't have FreeType\n");
2998 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
3000 ERR("called but we don't have FreeType\n");
3004 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
3005 OUTLINETEXTMETRICW *potm)
3007 ERR("called but we don't have FreeType\n");
3011 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
3014 ERR("called but we don't have FreeType\n");
3018 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
3021 ERR("called but we don't have FreeType\n");
3025 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
3028 ERR("called but we don't have FreeType\n");
3032 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
3035 ERR("called but we don't have FreeType\n");
3039 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
3042 ERR("called but we don't have FreeType\n");
3046 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
3048 ERR("called but we don't have FreeType\n");
3052 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3058 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3064 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
3067 return DEFAULT_CHARSET;
3070 #endif /* HAVE_FREETYPE */