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 */
207 OUTLINETEXTMETRICW *potm;
209 struct tagGdiFont *next;
212 #define INIT_GM_SIZE 128
214 static GdiFont GdiFontList = NULL;
216 static Family *FontList = NULL;
218 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ',
219 'R','o','m','a','n','\0'};
220 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
221 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
223 static const WCHAR defSystem[] = {'A','r','i','a','l','\0'};
224 static const WCHAR SystemW[] = {'S','y','s','t','e','m','\0'};
225 static const WCHAR MSSansSerifW[] = {'M','S',' ','S','a','n','s',' ',
226 'S','e','r','i','f','\0'};
227 static const WCHAR HelvW[] = {'H','e','l','v','\0'};
228 static const WCHAR RegularW[] = {'R','e','g','u','l','a','r','\0'};
230 static const WCHAR fontsW[] = {'\\','F','o','n','t','s','\0'};
231 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
232 'W','i','n','d','o','w','s','\\',
233 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
234 'F','o','n','t','s','\0'};
236 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
237 'W','i','n','d','o','w','s',' ','N','T','\\',
238 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
239 'F','o','n','t','s','\0'};
241 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
242 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
243 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
244 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
246 static const WCHAR *SystemFontValues[4] = {
253 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\','W','i','n','e','\\',
254 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
256 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
257 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
258 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
259 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
260 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
261 'E','u','r','o','p','e','a','n','\0'};
262 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
263 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
264 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
265 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
266 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
267 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
268 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
269 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
270 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
271 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
272 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
273 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
275 static const WCHAR *ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
285 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
293 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
302 typedef struct tagFontSubst {
305 struct tagFontSubst *next;
308 static FontSubst *substlist = NULL;
309 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
311 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
314 /****************************************
315 * Notes on .fon files
317 * The fonts System, FixedSys and Terminal are special. There are typically multiple
318 * versions installed for different resolutions and codepages. Windows stores which one to use
319 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
321 * FIXEDFON.FON FixedSys
323 * OEMFONT.FON Termial
324 * LogPixels Current dpi set by the display control panel applet
325 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
326 * also has a LogPixels value that appears to mirror this)
328 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
329 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
330 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
331 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
332 * so that makes sense.
334 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
335 * to be mapped into the registry on Windows 2000 at least).
338 * ega80woa.fon=ega80850.fon
339 * ega40woa.fon=ega40850.fon
340 * cga80woa.fon=cga80850.fon
341 * cga40woa.fon=cga40850.fon
345 static inline BOOL is_win9x(void)
347 return GetVersion() & 0x80000000;
350 This function builds an FT_Fixed from a float. It puts the integer part
351 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
352 It fails if the integer part of the float number is greater than SHORT_MAX.
354 static inline FT_Fixed FT_FixedFromFloat(float f)
357 unsigned short fract = (f - value) * 0xFFFF;
358 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
362 This function builds an FT_Fixed from a FIXED. It simply put f.value
363 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
365 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
367 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
370 #define ADDFONT_EXTERNAL_FONT 0x01
371 #define ADDFONT_FORCE_BITMAP 0x02
372 static BOOL AddFontFileToList(const char *file, char *fake_family, DWORD flags)
376 TT_Header *pHeader = NULL;
377 WCHAR *FamilyW, *StyleW;
380 Face **insertface, *next;
382 FT_Long face_index = 0, num_faces;
383 #ifdef HAVE_FREETYPE_FTWINFNT_H
384 FT_WinFNT_HeaderRec winfnt_header;
389 char *family_name = fake_family;
391 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
392 if((err = pFT_New_Face(library, file, face_index, &ft_face)) != 0) {
393 WARN("Unable to load font file %s err = %x\n", debugstr_a(file), err);
397 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*/
398 pFT_Done_Face(ft_face);
402 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
403 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
404 pFT_Done_Face(ft_face);
408 if(FT_IS_SFNT(ft_face) && (!pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2) ||
409 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
410 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))) {
411 TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
412 "Skipping this font.\n", debugstr_a(file));
413 pFT_Done_Face(ft_face);
417 if(!ft_face->family_name || !ft_face->style_name) {
418 TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file));
419 pFT_Done_Face(ft_face);
424 family_name = ft_face->family_name;
428 My_FT_Bitmap_Size *size = NULL;
430 if(!FT_IS_SCALABLE(ft_face))
431 size = (My_FT_Bitmap_Size *)ft_face->available_sizes + bitmap_num;
433 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
434 FamilyW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
435 MultiByteToWideChar(CP_ACP, 0, family_name, -1, FamilyW, len);
439 if(!strcmpW((*pfamily)->FamilyName, FamilyW))
441 pfamily = &(*pfamily)->next;
444 *pfamily = HeapAlloc(GetProcessHeap(), 0, sizeof(**pfamily));
445 (*pfamily)->FamilyName = FamilyW;
446 (*pfamily)->FirstFace = NULL;
447 (*pfamily)->next = NULL;
449 HeapFree(GetProcessHeap(), 0, FamilyW);
452 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
453 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
454 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
457 for(insertface = &(*pfamily)->FirstFace; *insertface;
458 insertface = &(*insertface)->next) {
459 if(!strcmpW((*insertface)->StyleName, StyleW) && (FT_IS_SCALABLE(ft_face) || (size->y_ppem == (*insertface)->size.y_ppem))) {
460 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
461 debugstr_w((*pfamily)->FamilyName), debugstr_w(StyleW),
462 (*insertface)->font_version, pHeader ? pHeader->Font_Revision : 0);
465 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
466 HeapFree(GetProcessHeap(), 0, StyleW);
467 pFT_Done_Face(ft_face);
470 if(!pHeader || pHeader->Font_Revision <= (*insertface)->font_version) {
471 TRACE("Original font is newer so skipping this one\n");
472 HeapFree(GetProcessHeap(), 0, StyleW);
473 pFT_Done_Face(ft_face);
476 TRACE("Replacing original with this one\n");
477 next = (*insertface)->next;
478 HeapFree(GetProcessHeap(), 0, (*insertface)->file);
479 HeapFree(GetProcessHeap(), 0, (*insertface)->StyleName);
480 HeapFree(GetProcessHeap(), 0, *insertface);
485 *insertface = HeapAlloc(GetProcessHeap(), 0, sizeof(**insertface));
486 (*insertface)->StyleName = StyleW;
487 (*insertface)->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
488 strcpy((*insertface)->file, file);
489 (*insertface)->face_index = face_index;
490 (*insertface)->next = next;
491 (*insertface)->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
492 (*insertface)->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
493 (*insertface)->font_version = pHeader ? pHeader->Font_Revision : 0;
494 (*insertface)->family = *pfamily;
495 (*insertface)->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
497 if(FT_IS_SCALABLE(ft_face)) {
498 memset(&(*insertface)->size, 0, sizeof((*insertface)->size));
499 (*insertface)->scalable = TRUE;
501 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
502 size->height, size->width, size->size >> 6,
503 size->x_ppem >> 6, size->y_ppem >> 6);
504 (*insertface)->size.height = size->height;
505 (*insertface)->size.width = size->width;
506 (*insertface)->size.size = size->size;
507 (*insertface)->size.x_ppem = size->x_ppem;
508 (*insertface)->size.y_ppem = size->y_ppem;
509 (*insertface)->size.internal_leading = 0;
510 (*insertface)->scalable = FALSE;
513 memset(&(*insertface)->fs, 0, sizeof((*insertface)->fs));
515 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
517 (*insertface)->fs.fsCsb[0] = pOS2->ulCodePageRange1;
518 (*insertface)->fs.fsCsb[1] = pOS2->ulCodePageRange2;
519 (*insertface)->fs.fsUsb[0] = pOS2->ulUnicodeRange1;
520 (*insertface)->fs.fsUsb[1] = pOS2->ulUnicodeRange2;
521 (*insertface)->fs.fsUsb[2] = pOS2->ulUnicodeRange3;
522 (*insertface)->fs.fsUsb[3] = pOS2->ulUnicodeRange4;
523 if(pOS2->version == 0) {
526 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
527 (*insertface)->fs.fsCsb[0] |= 1;
529 (*insertface)->fs.fsCsb[0] |= 1L << 31;
532 #ifdef HAVE_FREETYPE_FTWINFNT_H
533 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
535 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
536 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
537 if(TranslateCharsetInfo((DWORD*)(UINT)winfnt_header.charset, &csi, TCI_SRCCHARSET))
538 memcpy(&(*insertface)->fs, &csi.fs, sizeof(csi.fs));
539 (*insertface)->size.internal_leading = winfnt_header.internal_leading;
542 TRACE("fsCsb = %08lx %08lx/%08lx %08lx %08lx %08lx\n",
543 (*insertface)->fs.fsCsb[0], (*insertface)->fs.fsCsb[1],
544 (*insertface)->fs.fsUsb[0], (*insertface)->fs.fsUsb[1],
545 (*insertface)->fs.fsUsb[2], (*insertface)->fs.fsUsb[3]);
548 if((*insertface)->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
549 for(i = 0; i < ft_face->num_charmaps; i++) {
550 switch(ft_face->charmaps[i]->encoding) {
551 case ft_encoding_unicode:
552 case ft_encoding_apple_roman:
553 (*insertface)->fs.fsCsb[0] |= 1;
555 case ft_encoding_symbol:
556 (*insertface)->fs.fsCsb[0] |= 1L << 31;
564 if((*insertface)->fs.fsCsb[0] & ~(1L << 31))
565 have_installed_roman_font = TRUE;
566 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
568 num_faces = ft_face->num_faces;
569 pFT_Done_Face(ft_face);
570 TRACE("Added font %s %s\n", debugstr_w((*pfamily)->FamilyName),
572 } while(num_faces > ++face_index);
576 static void DumpFontList(void)
581 for(family = FontList; family; family = family->next) {
582 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
583 for(face = family->FirstFace; face; face = face->next) {
584 TRACE("\t%s", debugstr_w(face->StyleName));
586 TRACE(" %ld", face->size.y_ppem >> 6);
593 static void DumpSubstList(void)
597 for(psub = substlist; psub; psub = psub->next)
598 if(psub->from.charset != -1 || psub->to.charset != -1)
599 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
600 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
602 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
603 debugstr_w(psub->to.name));
607 static LPWSTR strdupW(LPWSTR p)
610 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
611 ret = HeapAlloc(GetProcessHeap(), 0, len);
616 static void split_subst_info(NameCs *nc, LPSTR str)
618 CHAR *p = strrchr(str, ',');
623 nc->charset = strtol(p+1, NULL, 10);
626 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
627 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
628 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
631 static void LoadSubstList(void)
633 FontSubst *psub, **ppsub;
635 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
640 for(psub = substlist; psub;) {
642 HeapFree(GetProcessHeap(), 0, psub->to.name);
643 HeapFree(GetProcessHeap(), 0, psub->from.name);
646 HeapFree(GetProcessHeap(), 0, ptmp);
651 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
652 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
653 &hkey) == ERROR_SUCCESS) {
655 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
656 &valuelen, &datalen, NULL, NULL);
658 valuelen++; /* returned value doesn't include room for '\0' */
659 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
660 data = HeapAlloc(GetProcessHeap(), 0, datalen);
665 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
666 &dlen) == ERROR_SUCCESS) {
667 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
669 *ppsub = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppsub));
670 (*ppsub)->next = NULL;
671 split_subst_info(&((*ppsub)->from), value);
672 split_subst_info(&((*ppsub)->to), data);
674 /* Win 2000 doesn't allow mapping between different charsets
675 or mapping of DEFAULT_CHARSET */
676 if(((*ppsub)->to.charset != (*ppsub)->from.charset) ||
677 (*ppsub)->to.charset == DEFAULT_CHARSET) {
678 HeapFree(GetProcessHeap(), 0, (*ppsub)->to.name);
679 HeapFree(GetProcessHeap(), 0, (*ppsub)->from.name);
680 HeapFree(GetProcessHeap(), 0, *ppsub);
683 ppsub = &((*ppsub)->next);
685 /* reset dlen and vlen */
689 HeapFree(GetProcessHeap(), 0, data);
690 HeapFree(GetProcessHeap(), 0, value);
695 /***********************************************************
696 * The replacement list is a way to map an entire font
697 * family onto another family. For example adding
699 * [HKLM\Software\Wine\Wine\FontReplacements]
700 * "Wingdings"="Winedings"
702 * would enumerate the Winedings font both as Winedings and
703 * Wingdings. However if a real Wingdings font is present the
704 * replacement does not take place.
707 static void LoadReplaceList(void)
710 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
715 WCHAR old_nameW[200];
717 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
718 "Software\\Wine\\Wine\\FontReplacements",
719 &hkey) == ERROR_SUCCESS) {
721 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
722 &valuelen, &datalen, NULL, NULL);
724 valuelen++; /* returned value doesn't include room for '\0' */
725 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
726 data = HeapAlloc(GetProcessHeap(), 0, datalen);
730 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
731 &dlen) == ERROR_SUCCESS) {
732 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
733 /* "NewName"="Oldname" */
734 if(!MultiByteToWideChar(CP_ACP, 0, data, -1, old_nameW, sizeof(old_nameW)))
737 /* Find the old family and hence all of the font files
739 for(family = FontList; family; family = family->next) {
740 if(!strcmpiW(family->FamilyName, old_nameW)) {
741 for(face = family->FirstFace; face; face = face->next) {
742 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
743 debugstr_w(face->StyleName), value);
744 /* Now add a new entry with the new family name */
745 AddFontFileToList(face->file, value, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0));
750 /* reset dlen and vlen */
754 HeapFree(GetProcessHeap(), 0, data);
755 HeapFree(GetProcessHeap(), 0, value);
761 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
767 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
769 dir = opendir(dirname);
771 ERR("Can't open directory %s\n", debugstr_a(dirname));
774 while((dent = readdir(dir)) != NULL) {
777 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
780 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
782 sprintf(path, "%s/%s", dirname, dent->d_name);
784 if(stat(path, &statbuf) == -1)
786 WARN("Can't stat %s\n", debugstr_a(path));
789 if(S_ISDIR(statbuf.st_mode))
790 ReadFontDir(path, external_fonts);
792 AddFontFileToList(path, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
798 static void load_fontconfig_fonts(void)
800 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
801 void *fc_handle = NULL;
810 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
812 TRACE("Wine cannot find the fontconfig library (%s).\n",
813 SONAME_LIBFONTCONFIG);
816 #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;}
817 LOAD_FUNCPTR(FcConfigGetCurrent);
818 LOAD_FUNCPTR(FcFontList);
819 LOAD_FUNCPTR(FcFontSetDestroy);
820 LOAD_FUNCPTR(FcInit);
821 LOAD_FUNCPTR(FcObjectSetAdd);
822 LOAD_FUNCPTR(FcObjectSetCreate);
823 LOAD_FUNCPTR(FcObjectSetDestroy);
824 LOAD_FUNCPTR(FcPatternCreate);
825 LOAD_FUNCPTR(FcPatternDestroy);
826 LOAD_FUNCPTR(FcPatternGet);
829 if(!pFcInit()) return;
831 config = pFcConfigGetCurrent();
832 pat = pFcPatternCreate();
833 os = pFcObjectSetCreate();
834 pFcObjectSetAdd(os, FC_FILE);
835 fontset = pFcFontList(config, pat, os);
837 for(i = 0; i < fontset->nfont; i++) {
838 if(pFcPatternGet(fontset->fonts[i], FC_FILE, 0, &v) != FcResultMatch)
840 if(v.type != FcTypeString) continue;
841 TRACE("fontconfig: %s\n", v.u.s);
843 /* We're just interested in OT/TT fonts for now, so this hack just
844 picks up the standard extensions to save time loading every other
847 if(len < 4) continue;
848 ext = v.u.s + len - 3;
849 if(!strcasecmp(ext, "ttf") || !strcasecmp(ext, "ttc") || !strcasecmp(ext, "otf"))
850 AddFontFileToList(v.u.s, NULL, ADDFONT_EXTERNAL_FONT);
852 pFcFontSetDestroy(fontset);
853 pFcObjectSetDestroy(os);
854 pFcPatternDestroy(pat);
861 void load_system_fonts(void)
864 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
867 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
870 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
871 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
872 strcatW(windowsdir, fontsW);
873 for(value = SystemFontValues; *value; value++) {
875 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
877 sprintfW(pathW, fmtW, windowsdir, data);
878 if((unixname = wine_get_unix_file_name(pathW))) {
879 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
880 HeapFree(GetProcessHeap(), 0, unixname);
888 /*************************************************************
890 * This adds registry entries for any externally loaded fonts
891 * (fonts from fontconfig or FontDirs). It also deletes entries
892 * of no longer existing fonts.
895 void update_reg_entries(void)
897 HKEY winkey = 0, externalkey = 0;
900 DWORD dlen, vlen, datalen, valuelen, i, type, len, len_fam;
904 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
905 static const WCHAR spaceW[] = {' ', '\0'};
908 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
909 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winkey, NULL) != ERROR_SUCCESS) {
910 ERR("Can't create Windows font reg key\n");
913 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, external_fonts_reg_key,
914 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
915 ERR("Can't create external font reg key\n");
919 /* Delete all external fonts added last time */
921 RegQueryInfoKeyW(externalkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
922 &valuelen, &datalen, NULL, NULL);
923 valuelen++; /* returned value doesn't include room for '\0' */
924 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
925 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
927 dlen = datalen * sizeof(WCHAR);
930 while(RegEnumValueW(externalkey, i++, valueW, &vlen, NULL, &type, data,
931 &dlen) == ERROR_SUCCESS) {
933 RegDeleteValueW(winkey, valueW);
934 /* reset dlen and vlen */
938 HeapFree(GetProcessHeap(), 0, data);
939 HeapFree(GetProcessHeap(), 0, valueW);
941 /* Delete the old external fonts key */
942 RegCloseKey(externalkey);
944 RegDeleteKeyW(HKEY_LOCAL_MACHINE, external_fonts_reg_key);
946 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, external_fonts_reg_key,
947 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
948 ERR("Can't create external font reg key\n");
952 /* enumerate the fonts and add external ones to the two keys */
954 for(family = FontList; family; family = family->next) {
955 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
956 for(face = family->FirstFace; face; face = face->next) {
957 if(!face->external) continue;
959 if(strcmpiW(face->StyleName, RegularW))
960 len = len_fam + strlenW(face->StyleName) + 1;
961 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
962 strcpyW(valueW, family->FamilyName);
964 strcatW(valueW, spaceW);
965 strcatW(valueW, face->StyleName);
967 strcatW(valueW, TrueType);
968 if((path = strrchr(face->file, '/')) == NULL)
972 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
974 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
975 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
976 RegSetValueExW(winkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
977 RegSetValueExW(externalkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
979 HeapFree(GetProcessHeap(), 0, file);
980 HeapFree(GetProcessHeap(), 0, valueW);
985 RegCloseKey(externalkey);
992 /*************************************************************
993 * WineEngAddFontResourceEx
996 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
998 if (ft_handle) /* do it only if we have freetype up and running */
1003 FIXME("Ignoring flags %lx\n", flags);
1005 if((unixname = wine_get_unix_file_name(file)))
1007 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1008 HeapFree(GetProcessHeap(), 0, unixname);
1014 /*************************************************************
1015 * WineEngRemoveFontResourceEx
1018 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1024 /*************************************************************
1027 * Initialize FreeType library and create a list of available faces
1029 BOOL WineEngInit(void)
1031 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
1033 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1035 WCHAR windowsdir[MAX_PATH];
1041 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
1044 "Wine cannot find the FreeType font library. To enable Wine to\n"
1045 "use TrueType fonts please install a version of FreeType greater than\n"
1046 "or equal to 2.0.5.\n"
1047 "http://www.freetype.org\n");
1051 #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;}
1053 LOAD_FUNCPTR(FT_Vector_Unit)
1054 LOAD_FUNCPTR(FT_Done_Face)
1055 LOAD_FUNCPTR(FT_Get_Char_Index)
1056 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
1057 LOAD_FUNCPTR(FT_Init_FreeType)
1058 LOAD_FUNCPTR(FT_Load_Glyph)
1059 LOAD_FUNCPTR(FT_Matrix_Multiply)
1060 LOAD_FUNCPTR(FT_MulFix)
1061 LOAD_FUNCPTR(FT_New_Face)
1062 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
1063 LOAD_FUNCPTR(FT_Outline_Transform)
1064 LOAD_FUNCPTR(FT_Outline_Translate)
1065 LOAD_FUNCPTR(FT_Select_Charmap)
1066 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
1067 LOAD_FUNCPTR(FT_Vector_Transform)
1070 /* Don't warn if this one is missing */
1071 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
1072 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
1073 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
1074 #ifdef HAVE_FREETYPE_FTWINFNT_H
1075 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
1077 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
1078 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
1079 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
1080 <= 2.0.3 has FT_Sqrt64 */
1084 if(pFT_Init_FreeType(&library) != 0) {
1085 ERR("Can't init FreeType library\n");
1086 wine_dlclose(ft_handle, NULL, 0);
1090 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
1091 if (pFT_Library_Version)
1093 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
1095 if (FT_Version.major<=0)
1101 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
1102 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
1103 ((FT_Version.minor << 8) & 0x00ff00) |
1104 ((FT_Version.patch ) & 0x0000ff);
1106 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
1107 ERR("Failed to create font mutex\n");
1110 WaitForSingleObject(font_mutex, INFINITE);
1112 /* load the system fonts */
1113 load_system_fonts();
1115 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
1116 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1117 strcatW(windowsdir, fontsW);
1118 if((unixname = wine_get_unix_file_name(windowsdir)))
1120 ReadFontDir(unixname, FALSE);
1121 HeapFree(GetProcessHeap(), 0, unixname);
1124 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
1125 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
1126 full path as the entry. Also look for any .fon fonts, since ReadFontDir
1128 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
1129 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1130 &hkey) == ERROR_SUCCESS) {
1132 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1133 &valuelen, &datalen, NULL, NULL);
1135 valuelen++; /* returned value doesn't include room for '\0' */
1136 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1137 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1140 dlen = datalen * sizeof(WCHAR);
1142 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
1143 &dlen) == ERROR_SUCCESS) {
1144 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
1146 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
1148 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1149 HeapFree(GetProcessHeap(), 0, unixname);
1152 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
1154 WCHAR pathW[MAX_PATH];
1155 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1156 sprintfW(pathW, fmtW, windowsdir, data);
1157 if((unixname = wine_get_unix_file_name(pathW)))
1159 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1160 HeapFree(GetProcessHeap(), 0, unixname);
1163 /* reset dlen and vlen */
1168 if (data) HeapFree(GetProcessHeap(), 0, data);
1169 if (valueW) HeapFree(GetProcessHeap(), 0, valueW);
1173 load_fontconfig_fonts();
1175 /* then look in any directories that we've specified in the config file */
1176 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1177 "Software\\Wine\\Wine\\Config\\FontDirs",
1178 &hkey) == ERROR_SUCCESS) {
1180 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1181 &valuelen, &datalen, NULL, NULL);
1183 valuelen++; /* returned value doesn't include room for '\0' */
1184 value = HeapAlloc(GetProcessHeap(), 0, valuelen);
1185 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1190 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1191 &dlen) == ERROR_SUCCESS) {
1192 TRACE("Got %s=%s\n", value, (LPSTR)data);
1193 ReadFontDir((LPSTR)data, TRUE);
1194 /* reset dlen and vlen */
1198 HeapFree(GetProcessHeap(), 0, data);
1199 HeapFree(GetProcessHeap(), 0, value);
1207 update_reg_entries();
1209 ReleaseMutex(font_mutex);
1213 "Wine cannot find certain functions that it needs inside the FreeType\n"
1214 "font library. To enable Wine to use TrueType fonts please upgrade\n"
1215 "FreeType to at least version 2.0.5.\n"
1216 "http://www.freetype.org\n");
1217 wine_dlclose(ft_handle, NULL, 0);
1223 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
1226 TT_HoriHeader *pHori;
1230 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1231 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1233 if(height == 0) height = 16;
1235 /* Calc. height of EM square:
1237 * For +ve lfHeight we have
1238 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
1239 * Re-arranging gives:
1240 * ppem = units_per_em * lfheight / (winAscent + winDescent)
1242 * For -ve lfHeight we have
1244 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
1245 * with il = winAscent + winDescent - units_per_em]
1250 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
1251 ppem = ft_face->units_per_EM * height /
1252 (pHori->Ascender - pHori->Descender);
1254 ppem = ft_face->units_per_EM * height /
1255 (pOS2->usWinAscent + pOS2->usWinDescent);
1263 static LONG load_VDMX(GdiFont, LONG);
1265 static FT_Face OpenFontFile(GdiFont font, char *file, FT_Long face_index, LONG width, LONG height)
1271 err = pFT_New_Face(library, file, face_index, &ft_face);
1273 ERR("FT_New_Face rets %d\n", err);
1277 /* set it here, as load_VDMX needs it */
1278 font->ft_face = ft_face;
1280 if(FT_IS_SCALABLE(ft_face)) {
1281 /* load the VDMX table if we have one */
1282 ppem = load_VDMX(font, height);
1284 ppem = calc_ppem_for_height(ft_face, height);
1286 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, ppem)) != 0)
1287 WARN("FT_Set_Pixel_Sizes %d, %ld rets %x\n", 0, ppem, err);
1289 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
1290 WARN("FT_Set_Pixel_Sizes %ld, %ld rets %x\n", width, height, err);
1296 static int get_nearest_charset(Face *face)
1298 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
1299 a single face with the requested charset. The idea is to check if
1300 the selected font supports the current ANSI codepage, if it does
1301 return the corresponding charset, else return the first charset */
1304 int acp = GetACP(), i;
1307 if(TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE))
1308 if(csi.fs.fsCsb[0] & face->fs.fsCsb[0])
1309 return csi.ciCharset;
1311 for(i = 0; i < 32; i++) {
1313 if(face->fs.fsCsb[0] & fs0) {
1314 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG))
1315 return csi.ciCharset;
1317 FIXME("TCI failing on %lx\n", fs0);
1321 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08lx file = %s\n",
1322 face->fs.fsCsb[0], face->file);
1323 return DEFAULT_CHARSET;
1326 static GdiFont alloc_font(void)
1328 GdiFont ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
1329 ret->gmsize = INIT_GM_SIZE;
1330 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1331 ret->gmsize * sizeof(*ret->gm));
1334 ret->xform.eM11 = ret->xform.eM22 = 1.0;
1338 static void free_font(GdiFont font)
1340 if (font->ft_face) pFT_Done_Face(font->ft_face);
1341 if (font->potm) HeapFree(GetProcessHeap(), 0, font->potm);
1342 if (font->name) HeapFree(GetProcessHeap(), 0, font->name);
1343 HeapFree(GetProcessHeap(), 0, font->gm);
1344 HeapFree(GetProcessHeap(), 0, font);
1348 /*************************************************************
1351 * load the vdmx entry for the specified height
1354 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
1355 ( ( (FT_ULong)_x4 << 24 ) | \
1356 ( (FT_ULong)_x3 << 16 ) | \
1357 ( (FT_ULong)_x2 << 8 ) | \
1360 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
1370 static LONG load_VDMX(GdiFont font, LONG height)
1372 BYTE hdr[6], tmp[2], group[4];
1373 BYTE devXRatio, devYRatio;
1374 USHORT numRecs, numRatios;
1379 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
1381 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
1384 /* FIXME: need the real device aspect ratio */
1388 numRecs = GET_BE_WORD(&hdr[2]);
1389 numRatios = GET_BE_WORD(&hdr[4]);
1391 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
1392 for(i = 0; i < numRatios; i++) {
1395 offset = (3 * 2) + (i * sizeof(Ratios));
1396 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
1399 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
1401 if(ratio.bCharSet != 1)
1404 if((ratio.xRatio == 0 &&
1405 ratio.yStartRatio == 0 &&
1406 ratio.yEndRatio == 0) ||
1407 (devXRatio == ratio.xRatio &&
1408 devYRatio >= ratio.yStartRatio &&
1409 devYRatio <= ratio.yEndRatio))
1411 offset = (3 * 2) + (numRatios * 4) + (i * 2);
1412 WineEngGetFontData(font, MS_VDMX_TAG, offset, tmp, 2);
1413 offset = GET_BE_WORD(tmp);
1419 FIXME("No suitable ratio found\n");
1423 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, group, 4) != GDI_ERROR) {
1425 BYTE startsz, endsz;
1428 recs = GET_BE_WORD(group);
1432 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
1434 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
1435 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
1436 if(result == GDI_ERROR) {
1437 FIXME("Failed to retrieve vTable\n");
1442 for(i = 0; i < recs; i++) {
1443 SHORT yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1444 SHORT yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1445 ppem = GET_BE_WORD(&vTable[i * 6]);
1447 if(yMax + -yMin == height) {
1450 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1453 if(yMax + -yMin > height) {
1456 goto end; /* failed */
1458 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1459 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1460 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1466 TRACE("ppem not found for height %ld\n", height);
1470 if(ppem < startsz || ppem > endsz)
1473 for(i = 0; i < recs; i++) {
1475 yPelHeight = GET_BE_WORD(&vTable[i * 6]);
1477 if(yPelHeight > ppem)
1480 if(yPelHeight == ppem) {
1481 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1482 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1483 TRACE("ppem %ld found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
1489 HeapFree(GetProcessHeap(), 0, vTable);
1496 /*************************************************************
1497 * WineEngCreateFontInstance
1500 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
1504 Family *family = NULL;
1505 INT height, width = 0;
1506 signed int diff = 0, newdiff;
1507 BOOL bd, it, can_use_bitmap;
1511 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
1512 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
1514 TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
1515 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
1516 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
1519 /* check the cache first */
1520 for(ret = GdiFontList; ret; ret = ret->next) {
1521 if(ret->hfont == hfont && !memcmp(&ret->xform, &dc->xformWorld2Vport, offsetof(XFORM, eDx)) &&
1522 (can_use_bitmap || FT_IS_SCALABLE(ret->ft_face))) {
1524 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
1529 if(!FontList || !have_installed_roman_font) /* No fonts installed */
1531 TRACE("No fonts installed\n");
1536 memcpy(&ret->xform, &dc->xformWorld2Vport, sizeof(XFORM));
1538 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
1539 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
1540 original value lfCharSet. Note this is a special case for
1541 Symbol and doesn't happen at least for "Wingdings*" */
1543 if(!strcmpiW(lf.lfFaceName, SymbolW))
1544 lf.lfCharSet = SYMBOL_CHARSET;
1546 if(!TranslateCharsetInfo((DWORD*)(INT)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
1547 switch(lf.lfCharSet) {
1548 case DEFAULT_CHARSET:
1549 csi.fs.fsCsb[0] = 0;
1552 FIXME("Untranslated charset %d\n", lf.lfCharSet);
1553 csi.fs.fsCsb[0] = 0;
1558 if(lf.lfFaceName[0] != '\0') {
1560 for(psub = substlist; psub; psub = psub->next)
1561 if(!strcmpiW(lf.lfFaceName, psub->from.name) &&
1562 (psub->from.charset == -1 ||
1563 psub->from.charset == lf.lfCharSet))
1566 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
1567 debugstr_w(psub->to.name));
1568 strcpyW(lf.lfFaceName, psub->to.name);
1571 /* We want a match on name and charset or just name if
1572 charset was DEFAULT_CHARSET. If the latter then
1573 we fixup the returned charset later in get_nearest_charset
1574 where we'll either use the charset of the current ansi codepage
1575 or if that's unavailable the first charset that the font supports.
1577 for(family = FontList; family; family = family->next) {
1578 if(!strcmpiW(family->FamilyName, lf.lfFaceName))
1579 if((csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0]) || !csi.fs.fsCsb[0])
1580 if(family->FirstFace->scalable || can_use_bitmap)
1586 /* If requested charset was DEFAULT_CHARSET then try using charset
1587 corresponding to the current ansi codepage */
1588 if(!csi.fs.fsCsb[0]) {
1590 if(!TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE)) {
1591 FIXME("TCI failed on codepage %d\n", acp);
1592 csi.fs.fsCsb[0] = 0;
1594 lf.lfCharSet = csi.ciCharset;
1597 /* Face families are in the top 4 bits of lfPitchAndFamily,
1598 so mask with 0xF0 before testing */
1600 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
1601 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
1602 strcpyW(lf.lfFaceName, defFixed);
1603 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
1604 strcpyW(lf.lfFaceName, defSerif);
1605 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
1606 strcpyW(lf.lfFaceName, defSans);
1608 strcpyW(lf.lfFaceName, defSans);
1609 for(family = FontList; family; family = family->next) {
1610 if(!strcmpiW(family->FamilyName, lf.lfFaceName) &&
1611 (csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0]))
1612 if(family->FirstFace->scalable || can_use_bitmap)
1618 for(family = FontList; family; family = family->next) {
1619 if(csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0])
1620 if(family->FirstFace->scalable || can_use_bitmap)
1627 csi.fs.fsCsb[0] = 0;
1628 FIXME("just using first face for now\n");
1631 it = lf.lfItalic ? 1 : 0;
1632 bd = lf.lfWeight > 550 ? 1 : 0;
1634 height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
1635 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
1638 for(face = family->FirstFace; face; face = face->next) {
1639 if(!(face->Italic ^ it) && !(face->Bold ^ bd)) {
1643 newdiff = height - (signed int)(face->size.y_ppem >> 6);
1645 newdiff = -height - ((signed int)(face->size.y_ppem >> 6) - face->size.internal_leading);
1646 if(!best || (diff > 0 && newdiff < diff && newdiff >= 0) ||
1647 (diff < 0 && newdiff > diff)) {
1648 TRACE("%ld is better for %d diff was %d\n", face->size.y_ppem >> 6, height, diff);
1659 face = family->FirstFace;
1660 if(it && !face->Italic) ret->fake_italic = TRUE;
1661 if(bd && !face->Bold) ret->fake_bold = TRUE;
1664 memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
1667 ret->charset = lf.lfCharSet;
1669 ret->charset = get_nearest_charset(face);
1671 TRACE("Chosen: %s %s\n", debugstr_w(family->FamilyName),
1672 debugstr_w(face->StyleName));
1674 if(!face->scalable) {
1675 width = face->size.x_ppem >> 6;
1676 height = face->size.y_ppem >> 6;
1678 ret->ft_face = OpenFontFile(ret, face->file, face->face_index, width, height);
1686 if (ret->charset == SYMBOL_CHARSET &&
1687 !pFT_Select_Charmap(ret->ft_face, ft_encoding_symbol)) {
1690 else if (!pFT_Select_Charmap(ret->ft_face, ft_encoding_unicode)) {
1694 pFT_Select_Charmap(ret->ft_face, ft_encoding_apple_roman);
1697 ret->orientation = lf.lfOrientation;
1698 ret->name = strdupW(family->FamilyName);
1699 ret->underline = lf.lfUnderline ? 0xff : 0;
1700 ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
1702 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
1704 ret->aveWidth= lf.lfWidth;
1705 ret->next = GdiFontList;
1711 static void DumpGdiFontList(void)
1715 TRACE("---------- gdiFont Cache ----------\n");
1716 for(gdiFont = GdiFontList; gdiFont; gdiFont = gdiFont->next) {
1718 GetObjectW( gdiFont->hfont, sizeof(lf), &lf );
1719 TRACE("gdiFont=%p hfont=%p (%s)\n",
1720 gdiFont, gdiFont->hfont, debugstr_w(lf.lfFaceName));
1724 /*************************************************************
1725 * WineEngDestroyFontInstance
1727 * free the gdiFont associated with this handle
1730 BOOL WineEngDestroyFontInstance(HFONT handle)
1733 GdiFont gdiPrev = NULL;
1736 TRACE("destroying hfont=%p\n", handle);
1740 gdiFont = GdiFontList;
1742 if(gdiFont->hfont == handle) {
1744 gdiPrev->next = gdiFont->next;
1746 gdiFont = gdiPrev->next;
1748 GdiFontList = gdiFont->next;
1750 gdiFont = GdiFontList;
1755 gdiFont = gdiFont->next;
1761 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
1762 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
1764 OUTLINETEXTMETRICW *potm = NULL;
1766 TEXTMETRICW tm, *ptm;
1767 GdiFont font = alloc_font();
1770 if(face->scalable) {
1774 height = face->size.y_ppem >> 6;
1775 width = face->size.x_ppem >> 6;
1778 if (!(font->ft_face = OpenFontFile(font, face->file, face->face_index, width, height)))
1784 font->name = strdupW(face->family->FamilyName);
1786 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
1788 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
1790 potm = HeapAlloc(GetProcessHeap(), 0, size);
1791 WineEngGetOutlineTextMetrics(font, size, potm);
1792 ptm = (TEXTMETRICW*)&potm->otmTextMetrics;
1794 WineEngGetTextMetrics(font, &tm);
1798 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = ptm->tmHeight;
1799 pntm->ntmTm.tmAscent = ptm->tmAscent;
1800 pntm->ntmTm.tmDescent = ptm->tmDescent;
1801 pntm->ntmTm.tmInternalLeading = ptm->tmInternalLeading;
1802 pntm->ntmTm.tmExternalLeading = ptm->tmExternalLeading;
1803 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = ptm->tmAveCharWidth;
1804 pntm->ntmTm.tmMaxCharWidth = ptm->tmMaxCharWidth;
1805 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = ptm->tmWeight;
1806 pntm->ntmTm.tmOverhang = ptm->tmOverhang;
1807 pntm->ntmTm.tmDigitizedAspectX = ptm->tmDigitizedAspectX;
1808 pntm->ntmTm.tmDigitizedAspectY = ptm->tmDigitizedAspectY;
1809 pntm->ntmTm.tmFirstChar = ptm->tmFirstChar;
1810 pntm->ntmTm.tmLastChar = ptm->tmLastChar;
1811 pntm->ntmTm.tmDefaultChar = ptm->tmDefaultChar;
1812 pntm->ntmTm.tmBreakChar = ptm->tmBreakChar;
1813 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = ptm->tmItalic;
1814 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = ptm->tmUnderlined;
1815 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = ptm->tmStruckOut;
1816 pntm->ntmTm.tmPitchAndFamily = ptm->tmPitchAndFamily;
1817 pelf->elfLogFont.lfPitchAndFamily = (ptm->tmPitchAndFamily & 0xf1) + 1;
1818 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = ptm->tmCharSet;
1819 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
1820 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
1821 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
1823 *ptype = ptm->tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
1824 if(!(ptm->tmPitchAndFamily & TMPF_VECTOR))
1825 *ptype |= RASTER_FONTTYPE;
1828 pntm->ntmTm.ntmFlags = ptm->tmItalic ? NTM_ITALIC : 0;
1829 if(ptm->tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
1830 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
1832 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
1833 pntm->ntmTm.ntmCellHeight = 0;
1834 pntm->ntmTm.ntmAvgWidth = 0;
1836 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
1838 strncpyW(pelf->elfLogFont.lfFaceName,
1839 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
1841 strncpyW(pelf->elfFullName,
1842 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
1844 strncpyW(pelf->elfStyle,
1845 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
1849 strncpyW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
1850 strncpyW(pelf->elfFullName, face->family->FamilyName, LF_FACESIZE);
1851 pelf->elfStyle[0] = '\0';
1854 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
1856 HeapFree(GetProcessHeap(), 0, potm);
1861 /*************************************************************
1865 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
1870 NEWTEXTMETRICEXW ntm;
1871 DWORD type, ret = 1;
1877 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
1879 if(plf->lfFaceName[0]) {
1881 for(psub = substlist; psub; psub = psub->next)
1882 if(!strcmpiW(plf->lfFaceName, psub->from.name) &&
1883 (psub->from.charset == -1 ||
1884 psub->from.charset == plf->lfCharSet))
1887 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
1888 debugstr_w(psub->to.name));
1889 memcpy(&lf, plf, sizeof(lf));
1890 strcpyW(lf.lfFaceName, psub->to.name);
1893 for(family = FontList; family; family = family->next) {
1894 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
1895 for(face = family->FirstFace; face; face = face->next) {
1896 GetEnumStructs(face, &elf, &ntm, &type);
1897 for(i = 0; i < 32; i++) {
1898 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
1899 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
1900 strcpyW(elf.elfScript, OEM_DOSW);
1901 i = 32; /* break out of loop */
1902 } else if(!(face->fs.fsCsb[0] & (1L << i)))
1905 fs.fsCsb[0] = 1L << i;
1907 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
1909 csi.ciCharset = DEFAULT_CHARSET;
1910 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
1911 if(csi.ciCharset != DEFAULT_CHARSET) {
1912 elf.elfLogFont.lfCharSet =
1913 ntm.ntmTm.tmCharSet = csi.ciCharset;
1915 strcpyW(elf.elfScript, ElfScriptsW[i]);
1917 FIXME("Unknown elfscript for bit %d\n", i);
1920 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
1921 debugstr_w(elf.elfLogFont.lfFaceName),
1922 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
1923 csi.ciCharset, type, debugstr_w(elf.elfScript),
1924 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
1925 ntm.ntmTm.ntmFlags);
1926 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
1933 for(family = FontList; family; family = family->next) {
1934 GetEnumStructs(family->FirstFace, &elf, &ntm, &type);
1935 for(i = 0; i < 32; i++) {
1936 if(!family->FirstFace->scalable && family->FirstFace->fs.fsCsb[0] == 0) { /* OEM bitmap */
1937 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
1938 strcpyW(elf.elfScript, OEM_DOSW);
1939 i = 32; /* break out of loop */
1940 } else if(!(family->FirstFace->fs.fsCsb[0] & (1L << i)))
1943 fs.fsCsb[0] = 1L << i;
1945 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
1947 csi.ciCharset = DEFAULT_CHARSET;
1948 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
1949 if(csi.ciCharset != DEFAULT_CHARSET) {
1950 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
1953 strcpyW(elf.elfScript, ElfScriptsW[i]);
1955 FIXME("Unknown elfscript for bit %d\n", i);
1958 TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
1959 debugstr_w(elf.elfLogFont.lfFaceName),
1960 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
1961 csi.ciCharset, type, debugstr_w(elf.elfScript),
1962 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
1963 ntm.ntmTm.ntmFlags);
1964 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
1973 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
1975 pt->x.value = vec->x >> 6;
1976 pt->x.fract = (vec->x & 0x3f) << 10;
1977 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
1978 pt->y.value = vec->y >> 6;
1979 pt->y.fract = (vec->y & 0x3f) << 10;
1980 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
1984 static FT_UInt get_glyph_index(GdiFont font, UINT glyph)
1986 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
1987 glyph = glyph + 0xf000;
1988 return pFT_Get_Char_Index(font->ft_face, glyph);
1991 /*************************************************************
1992 * WineEngGetGlyphIndices
1994 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
1996 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
1997 LPWORD pgi, DWORD flags)
2001 for(i = 0; i < count; i++)
2002 pgi[i] = get_glyph_index(font, lpstr[i]);
2007 /*************************************************************
2008 * WineEngGetGlyphOutline
2010 * Behaves in exactly the same way as the win32 api GetGlyphOutline
2011 * except that the first parameter is the HWINEENGFONT of the font in
2012 * question rather than an HDC.
2015 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
2016 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
2019 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
2020 FT_Face ft_face = font->ft_face;
2021 FT_UInt glyph_index;
2022 DWORD width, height, pitch, needed = 0;
2023 FT_Bitmap ft_bitmap;
2025 INT left, right, top = 0, bottom = 0;
2027 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
2028 float widthRatio = 1.0;
2029 FT_Matrix transMat = identityMat;
2030 BOOL needsTransform = FALSE;
2033 TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font, glyph, format, lpgm,
2034 buflen, buf, lpmat);
2036 if(format & GGO_GLYPH_INDEX) {
2037 glyph_index = glyph;
2038 format &= ~GGO_GLYPH_INDEX;
2040 glyph_index = get_glyph_index(font, glyph);
2042 if(glyph_index >= font->gmsize) {
2043 font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
2044 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
2045 font->gmsize * sizeof(*font->gm));
2047 if(format == GGO_METRICS && font->gm[glyph_index].init) {
2048 memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
2049 return 1; /* FIXME */
2053 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP) || font->aveWidth || lpmat)
2054 load_flags |= FT_LOAD_NO_BITMAP;
2056 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
2059 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
2063 /* Scaling factor */
2064 if (font->aveWidth && font->potm) {
2065 widthRatio = (float)font->aveWidth * font->xform.eM11 / (float) font->potm->otmTextMetrics.tmAveCharWidth;
2068 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
2069 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
2071 font->gm[glyph_index].adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
2072 font->gm[glyph_index].lsb = left >> 6;
2073 font->gm[glyph_index].bbx = (right - left) >> 6;
2075 /* Scaling transform */
2076 if(font->aveWidth) {
2078 scaleMat.xx = FT_FixedFromFloat(widthRatio);
2081 scaleMat.yy = (1 << 16);
2083 pFT_Matrix_Multiply(&scaleMat, &transMat);
2084 needsTransform = TRUE;
2087 /* Rotation transform */
2088 if(font->orientation) {
2089 FT_Matrix rotationMat;
2091 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
2092 pFT_Vector_Unit(&vecAngle, angle);
2093 rotationMat.xx = vecAngle.x;
2094 rotationMat.xy = -vecAngle.y;
2095 rotationMat.yx = -rotationMat.xy;
2096 rotationMat.yy = rotationMat.xx;
2098 pFT_Matrix_Multiply(&rotationMat, &transMat);
2099 needsTransform = TRUE;
2102 /* Extra transformation specified by caller */
2105 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
2106 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
2107 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
2108 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
2109 pFT_Matrix_Multiply(&extraMat, &transMat);
2110 needsTransform = TRUE;
2113 if(!needsTransform) {
2114 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
2115 bottom = (ft_face->glyph->metrics.horiBearingY -
2116 ft_face->glyph->metrics.height) & -64;
2117 lpgm->gmCellIncX = font->gm[glyph_index].adv;
2118 lpgm->gmCellIncY = 0;
2122 for(xc = 0; xc < 2; xc++) {
2123 for(yc = 0; yc < 2; yc++) {
2124 vec.x = (ft_face->glyph->metrics.horiBearingX +
2125 xc * ft_face->glyph->metrics.width);
2126 vec.y = ft_face->glyph->metrics.horiBearingY -
2127 yc * ft_face->glyph->metrics.height;
2128 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
2129 pFT_Vector_Transform(&vec, &transMat);
2130 if(xc == 0 && yc == 0) {
2131 left = right = vec.x;
2132 top = bottom = vec.y;
2134 if(vec.x < left) left = vec.x;
2135 else if(vec.x > right) right = vec.x;
2136 if(vec.y < bottom) bottom = vec.y;
2137 else if(vec.y > top) top = vec.y;
2142 right = (right + 63) & -64;
2143 bottom = bottom & -64;
2144 top = (top + 63) & -64;
2146 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
2147 vec.x = ft_face->glyph->metrics.horiAdvance;
2149 pFT_Vector_Transform(&vec, &transMat);
2150 lpgm->gmCellIncX = (vec.x+63) >> 6;
2151 lpgm->gmCellIncY = -((vec.y+63) >> 6);
2153 lpgm->gmBlackBoxX = (right - left) >> 6;
2154 lpgm->gmBlackBoxY = (top - bottom) >> 6;
2155 lpgm->gmptGlyphOrigin.x = left >> 6;
2156 lpgm->gmptGlyphOrigin.y = top >> 6;
2158 memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
2159 font->gm[glyph_index].init = TRUE;
2161 if(format == GGO_METRICS)
2162 return 1; /* FIXME */
2164 if (buf && !buflen){
2168 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP) {
2169 TRACE("loaded a bitmap\n");
2175 width = lpgm->gmBlackBoxX;
2176 height = lpgm->gmBlackBoxY;
2177 pitch = ((width + 31) >> 5) << 2;
2178 needed = pitch * height;
2180 if(!buf || !buflen) break;
2182 switch(ft_face->glyph->format) {
2183 case ft_glyph_format_bitmap:
2185 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
2186 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
2187 INT h = ft_face->glyph->bitmap.rows;
2189 memcpy(dst, src, w);
2190 src += ft_face->glyph->bitmap.pitch;
2196 case ft_glyph_format_outline:
2197 ft_bitmap.width = width;
2198 ft_bitmap.rows = height;
2199 ft_bitmap.pitch = pitch;
2200 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
2201 ft_bitmap.buffer = buf;
2203 if(needsTransform) {
2204 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
2207 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
2209 /* Note: FreeType will only set 'black' bits for us. */
2210 memset(buf, 0, needed);
2211 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
2215 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
2220 case GGO_GRAY2_BITMAP:
2221 case GGO_GRAY4_BITMAP:
2222 case GGO_GRAY8_BITMAP:
2223 case WINE_GGO_GRAY16_BITMAP:
2228 width = lpgm->gmBlackBoxX;
2229 height = lpgm->gmBlackBoxY;
2230 pitch = (width + 3) / 4 * 4;
2231 needed = pitch * height;
2233 if(!buf || !buflen) break;
2234 ft_bitmap.width = width;
2235 ft_bitmap.rows = height;
2236 ft_bitmap.pitch = pitch;
2237 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
2238 ft_bitmap.buffer = buf;
2240 if(needsTransform) {
2241 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
2244 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
2246 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
2248 if(format == GGO_GRAY2_BITMAP)
2250 else if(format == GGO_GRAY4_BITMAP)
2252 else if(format == GGO_GRAY8_BITMAP)
2254 else if(format == WINE_GGO_GRAY16_BITMAP)
2262 for(row = 0; row < height; row++) {
2264 for(col = 0; col < width; col++, ptr++) {
2265 *ptr = (*(unsigned int*)ptr * mult + 128) / 256;
2274 int contour, point = 0, first_pt;
2275 FT_Outline *outline = &ft_face->glyph->outline;
2276 TTPOLYGONHEADER *pph;
2278 DWORD pph_start, cpfx, type;
2280 if(buflen == 0) buf = NULL;
2282 if (needsTransform && buf) {
2283 pFT_Outline_Transform(outline, &transMat);
2286 for(contour = 0; contour < outline->n_contours; contour++) {
2288 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
2291 pph->dwType = TT_POLYGON_TYPE;
2292 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2294 needed += sizeof(*pph);
2296 while(point <= outline->contours[contour]) {
2297 ppc = (TTPOLYCURVE *)((char *)buf + needed);
2298 type = (outline->tags[point] & FT_Curve_Tag_On) ?
2299 TT_PRIM_LINE : TT_PRIM_QSPLINE;
2303 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2306 } while(point <= outline->contours[contour] &&
2307 (outline->tags[point] & FT_Curve_Tag_On) ==
2308 (outline->tags[point-1] & FT_Curve_Tag_On));
2309 /* At the end of a contour Windows adds the start point, but
2311 if(point > outline->contours[contour] &&
2312 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
2314 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
2316 } else if(point <= outline->contours[contour] &&
2317 outline->tags[point] & FT_Curve_Tag_On) {
2318 /* add closing pt for bezier */
2320 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2328 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2331 pph->cb = needed - pph_start;
2337 /* Convert the quadratic Beziers to cubic Beziers.
2338 The parametric eqn for a cubic Bezier is, from PLRM:
2339 r(t) = at^3 + bt^2 + ct + r0
2340 with the control points:
2345 A quadratic Beizer has the form:
2346 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
2348 So equating powers of t leads to:
2349 r1 = 2/3 p1 + 1/3 p0
2350 r2 = 2/3 p1 + 1/3 p2
2351 and of course r0 = p0, r3 = p2
2354 int contour, point = 0, first_pt;
2355 FT_Outline *outline = &ft_face->glyph->outline;
2356 TTPOLYGONHEADER *pph;
2358 DWORD pph_start, cpfx, type;
2359 FT_Vector cubic_control[4];
2360 if(buflen == 0) buf = NULL;
2362 if (needsTransform && buf) {
2363 pFT_Outline_Transform(outline, &transMat);
2366 for(contour = 0; contour < outline->n_contours; contour++) {
2368 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
2371 pph->dwType = TT_POLYGON_TYPE;
2372 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2374 needed += sizeof(*pph);
2376 while(point <= outline->contours[contour]) {
2377 ppc = (TTPOLYCURVE *)((char *)buf + needed);
2378 type = (outline->tags[point] & FT_Curve_Tag_On) ?
2379 TT_PRIM_LINE : TT_PRIM_CSPLINE;
2382 if(type == TT_PRIM_LINE) {
2384 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2388 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
2391 /* FIXME: Possible optimization in endpoint calculation
2392 if there are two consecutive curves */
2393 cubic_control[0] = outline->points[point-1];
2394 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
2395 cubic_control[0].x += outline->points[point].x + 1;
2396 cubic_control[0].y += outline->points[point].y + 1;
2397 cubic_control[0].x >>= 1;
2398 cubic_control[0].y >>= 1;
2400 if(point+1 > outline->contours[contour])
2401 cubic_control[3] = outline->points[first_pt];
2403 cubic_control[3] = outline->points[point+1];
2404 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
2405 cubic_control[3].x += outline->points[point].x + 1;
2406 cubic_control[3].y += outline->points[point].y + 1;
2407 cubic_control[3].x >>= 1;
2408 cubic_control[3].y >>= 1;
2411 /* r1 = 1/3 p0 + 2/3 p1
2412 r2 = 1/3 p2 + 2/3 p1 */
2413 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
2414 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
2415 cubic_control[2] = cubic_control[1];
2416 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
2417 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
2418 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
2419 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
2421 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
2422 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
2423 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
2428 } while(point <= outline->contours[contour] &&
2429 (outline->tags[point] & FT_Curve_Tag_On) ==
2430 (outline->tags[point-1] & FT_Curve_Tag_On));
2431 /* At the end of a contour Windows adds the start point,
2432 but only for Beziers and we've already done that.
2434 if(point <= outline->contours[contour] &&
2435 outline->tags[point] & FT_Curve_Tag_On) {
2436 /* This is the closing pt of a bezier, but we've already
2437 added it, so just inc point and carry on */
2444 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2447 pph->cb = needed - pph_start;
2453 FIXME("Unsupported format %d\n", format);
2459 static BOOL get_bitmap_text_metrics(GdiFont font)
2461 FT_Face ft_face = font->ft_face;
2462 #ifdef HAVE_FREETYPE_FTWINFNT_H
2463 FT_WinFNT_HeaderRec winfnt_header;
2465 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
2466 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
2467 font->potm->otmSize = size;
2469 #define TM font->potm->otmTextMetrics
2470 #ifdef HAVE_FREETYPE_FTWINFNT_H
2471 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
2473 TM.tmHeight = winfnt_header.pixel_height;
2474 TM.tmAscent = winfnt_header.ascent;
2475 TM.tmDescent = TM.tmHeight - TM.tmAscent;
2476 TM.tmInternalLeading = winfnt_header.internal_leading;
2477 TM.tmExternalLeading = winfnt_header.external_leading;
2478 TM.tmAveCharWidth = winfnt_header.avg_width;
2479 TM.tmMaxCharWidth = winfnt_header.max_width;
2480 TM.tmWeight = winfnt_header.weight;
2482 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
2483 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
2484 TM.tmFirstChar = winfnt_header.first_char;
2485 TM.tmLastChar = winfnt_header.last_char;
2486 TM.tmDefaultChar = winfnt_header.default_char;
2487 TM.tmBreakChar = winfnt_header.break_char;
2488 TM.tmItalic = winfnt_header.italic;
2489 TM.tmUnderlined = font->underline;
2490 TM.tmStruckOut = font->strikeout;
2491 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
2492 TM.tmCharSet = winfnt_header.charset;
2497 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
2498 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
2499 TM.tmHeight = TM.tmAscent + TM.tmDescent;
2500 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
2501 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
2502 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
2503 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
2504 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
2506 TM.tmDigitizedAspectX = 96; /* FIXME */
2507 TM.tmDigitizedAspectY = 96; /* FIXME */
2509 TM.tmLastChar = 255;
2510 TM.tmDefaultChar = 32;
2511 TM.tmBreakChar = 32;
2512 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
2513 TM.tmUnderlined = font->underline;
2514 TM.tmStruckOut = font->strikeout;
2515 /* NB inverted meaning of TMPF_FIXED_PITCH */
2516 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
2517 TM.tmCharSet = font->charset;
2524 /*************************************************************
2525 * WineEngGetTextMetrics
2528 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
2531 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
2532 if(!get_bitmap_text_metrics(font))
2535 if(!font->potm) return FALSE;
2536 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
2538 if (font->aveWidth) {
2539 ptm->tmAveCharWidth = font->aveWidth * font->xform.eM11;
2545 /*************************************************************
2546 * WineEngGetOutlineTextMetrics
2549 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
2550 OUTLINETEXTMETRICW *potm)
2552 FT_Face ft_face = font->ft_face;
2553 UINT needed, lenfam, lensty, ret;
2555 TT_HoriHeader *pHori;
2556 TT_Postscript *pPost;
2557 FT_Fixed x_scale, y_scale;
2558 WCHAR *family_nameW, *style_nameW;
2559 static const WCHAR spaceW[] = {' ', '\0'};
2561 INT ascent, descent;
2563 TRACE("font=%p\n", font);
2565 if(!FT_IS_SCALABLE(ft_face))
2569 if(cbSize >= font->potm->otmSize)
2570 memcpy(potm, font->potm, font->potm->otmSize);
2571 return font->potm->otmSize;
2575 needed = sizeof(*potm);
2577 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
2578 family_nameW = strdupW(font->name);
2580 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
2582 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
2583 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
2584 style_nameW, lensty);
2586 /* These names should be read from the TT name table */
2588 /* length of otmpFamilyName */
2591 /* length of otmpFaceName */
2592 if(!strcasecmp(ft_face->style_name, "regular")) {
2593 needed += lenfam; /* just the family name */
2595 needed += lenfam + lensty; /* family + " " + style */
2598 /* length of otmpStyleName */
2601 /* length of otmpFullName */
2602 needed += lenfam + lensty;
2605 x_scale = ft_face->size->metrics.x_scale;
2606 y_scale = ft_face->size->metrics.y_scale;
2608 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2610 FIXME("Can't find OS/2 table - not TT font?\n");
2615 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2617 FIXME("Can't find HHEA table - not TT font?\n");
2622 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
2624 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",
2625 pOS2->usWinAscent, pOS2->usWinDescent,
2626 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
2627 ft_face->ascender, ft_face->descender, ft_face->height,
2628 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
2629 ft_face->bbox.yMax, ft_face->bbox.yMin);
2631 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
2632 font->potm->otmSize = needed;
2634 #define TM font->potm->otmTextMetrics
2636 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
2637 ascent = pHori->Ascender;
2638 descent = -pHori->Descender;
2640 ascent = pOS2->usWinAscent;
2641 descent = pOS2->usWinDescent;
2645 TM.tmAscent = font->yMax;
2646 TM.tmDescent = -font->yMin;
2647 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
2649 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
2650 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
2651 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
2652 - ft_face->units_per_EM, y_scale) + 32) >> 6;
2655 TM.tmHeight = TM.tmAscent + TM.tmDescent;
2658 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
2660 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
2661 ((ascent + descent) -
2662 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
2664 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
2665 if (TM.tmAveCharWidth == 0) {
2666 TM.tmAveCharWidth = 1;
2668 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
2669 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
2671 TM.tmDigitizedAspectX = 300;
2672 TM.tmDigitizedAspectY = 300;
2673 TM.tmFirstChar = pOS2->usFirstCharIndex;
2674 TM.tmLastChar = pOS2->usLastCharIndex;
2675 TM.tmDefaultChar = pOS2->usDefaultChar;
2676 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
2677 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
2678 TM.tmUnderlined = font->underline;
2679 TM.tmStruckOut = font->strikeout;
2681 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
2682 if(!FT_IS_FIXED_WIDTH(ft_face))
2683 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
2685 TM.tmPitchAndFamily = 0;
2687 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
2688 case PAN_FAMILY_SCRIPT:
2689 TM.tmPitchAndFamily |= FF_SCRIPT;
2691 case PAN_FAMILY_DECORATIVE:
2692 case PAN_FAMILY_PICTORIAL:
2693 TM.tmPitchAndFamily |= FF_DECORATIVE;
2695 case PAN_FAMILY_TEXT_DISPLAY:
2696 if(TM.tmPitchAndFamily == 0) /* fixed */
2697 TM.tmPitchAndFamily = FF_MODERN;
2699 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
2700 case PAN_SERIF_NORMAL_SANS:
2701 case PAN_SERIF_OBTUSE_SANS:
2702 case PAN_SERIF_PERP_SANS:
2703 TM.tmPitchAndFamily |= FF_SWISS;
2706 TM.tmPitchAndFamily |= FF_ROMAN;
2711 TM.tmPitchAndFamily |= FF_DONTCARE;
2714 if(FT_IS_SCALABLE(ft_face))
2715 TM.tmPitchAndFamily |= TMPF_VECTOR;
2716 if(FT_IS_SFNT(ft_face))
2717 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
2719 TM.tmCharSet = font->charset;
2722 font->potm->otmFiller = 0;
2723 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
2724 font->potm->otmfsSelection = pOS2->fsSelection;
2725 font->potm->otmfsType = pOS2->fsType;
2726 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
2727 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
2728 font->potm->otmItalicAngle = 0; /* POST table */
2729 font->potm->otmEMSquare = ft_face->units_per_EM;
2730 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
2731 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
2732 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
2733 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
2734 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
2735 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
2736 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
2737 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
2738 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
2739 font->potm->otmMacAscent = 0; /* where do these come from ? */
2740 font->potm->otmMacDescent = 0;
2741 font->potm->otmMacLineGap = 0;
2742 font->potm->otmusMinimumPPEM = 0; /* TT Header */
2743 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
2744 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
2745 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
2746 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
2747 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
2748 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
2749 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
2750 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
2751 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
2752 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
2754 font->potm->otmsUnderscoreSize = 0;
2755 font->potm->otmsUnderscorePosition = 0;
2757 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
2758 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
2761 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
2762 cp = (char*)font->potm + sizeof(*font->potm);
2763 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
2764 strcpyW((WCHAR*)cp, family_nameW);
2766 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
2767 strcpyW((WCHAR*)cp, style_nameW);
2769 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
2770 strcpyW((WCHAR*)cp, family_nameW);
2771 if(strcasecmp(ft_face->style_name, "regular")) {
2772 strcatW((WCHAR*)cp, spaceW);
2773 strcatW((WCHAR*)cp, style_nameW);
2774 cp += lenfam + lensty;
2777 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
2778 strcpyW((WCHAR*)cp, family_nameW);
2779 strcatW((WCHAR*)cp, spaceW);
2780 strcatW((WCHAR*)cp, style_nameW);
2783 if(potm && needed <= cbSize)
2784 memcpy(potm, font->potm, font->potm->otmSize);
2787 HeapFree(GetProcessHeap(), 0, style_nameW);
2788 HeapFree(GetProcessHeap(), 0, family_nameW);
2794 /*************************************************************
2795 * WineEngGetCharWidth
2798 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
2803 FT_UInt glyph_index;
2805 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
2807 for(c = firstChar; c <= lastChar; c++) {
2808 glyph_index = get_glyph_index(font, c);
2809 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
2810 &gm, 0, NULL, NULL);
2811 buffer[c - firstChar] = font->gm[glyph_index].adv;
2816 /*************************************************************
2817 * WineEngGetCharABCWidths
2820 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
2825 FT_UInt glyph_index;
2827 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
2829 for(c = firstChar; c <= lastChar; c++) {
2830 glyph_index = get_glyph_index(font, c);
2831 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
2832 &gm, 0, NULL, NULL);
2833 buffer[c - firstChar].abcA = font->gm[glyph_index].lsb;
2834 buffer[c - firstChar].abcB = font->gm[glyph_index].bbx;
2835 buffer[c - firstChar].abcC = font->gm[glyph_index].adv - font->gm[glyph_index].lsb -
2836 font->gm[glyph_index].bbx;
2841 /*************************************************************
2842 * WineEngGetTextExtentPoint
2845 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
2851 FT_UInt glyph_index;
2853 TRACE("%p, %s, %d, %p\n", font, debugstr_wn(wstr, count), count,
2857 WineEngGetTextMetrics(font, &tm);
2858 size->cy = tm.tmHeight;
2860 for(idx = 0; idx < count; idx++) {
2861 glyph_index = get_glyph_index(font, wstr[idx]);
2862 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
2863 &gm, 0, NULL, NULL);
2864 size->cx += font->gm[glyph_index].adv;
2866 TRACE("return %ld,%ld\n", size->cx, size->cy);
2870 /*************************************************************
2871 * WineEngGetTextExtentPointI
2874 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
2881 TRACE("%p, %p, %d, %p\n", font, indices, count, size);
2884 WineEngGetTextMetrics(font, &tm);
2885 size->cy = tm.tmHeight;
2887 for(idx = 0; idx < count; idx++) {
2888 WineEngGetGlyphOutline(font, indices[idx],
2889 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
2891 size->cx += font->gm[indices[idx]].adv;
2893 TRACE("return %ld,%ld\n", size->cx, size->cy);
2897 /*************************************************************
2898 * WineEngGetFontData
2901 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
2904 FT_Face ft_face = font->ft_face;
2908 TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
2909 font, table, offset, buf, cbData);
2911 if(!FT_IS_SFNT(ft_face))
2919 if(table) { /* MS tags differ in endidness from FT ones */
2920 table = table >> 24 | table << 24 |
2921 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
2924 /* If the FT_Load_Sfnt_Table function is there we'll use it */
2925 if(pFT_Load_Sfnt_Table)
2926 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
2927 else { /* Do it the hard way */
2928 TT_Face tt_face = (TT_Face) ft_face;
2929 SFNT_Interface *sfnt;
2930 if (FT_Version.major==2 && FT_Version.minor==0)
2933 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
2937 /* A field was added in the middle of the structure in 2.1.x */
2938 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
2940 err = sfnt->load_any(tt_face, table, offset, buf, &len);
2943 TRACE("Can't find table %08lx.\n", table);
2949 /*************************************************************
2950 * WineEngGetTextFace
2953 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
2956 lstrcpynW(str, font->name, count);
2957 return strlenW(font->name);
2959 return strlenW(font->name) + 1;
2962 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
2964 if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
2965 return font->charset;
2968 #else /* HAVE_FREETYPE */
2970 BOOL WineEngInit(void)
2974 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
2978 BOOL WineEngDestroyFontInstance(HFONT hfont)
2983 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
2988 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
2989 LPWORD pgi, DWORD flags)
2994 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
2995 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
2998 ERR("called but we don't have FreeType\n");
3002 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
3004 ERR("called but we don't have FreeType\n");
3008 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
3009 OUTLINETEXTMETRICW *potm)
3011 ERR("called but we don't have FreeType\n");
3015 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
3018 ERR("called but we don't have FreeType\n");
3022 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
3025 ERR("called but we don't have FreeType\n");
3029 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
3032 ERR("called but we don't have FreeType\n");
3036 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
3039 ERR("called but we don't have FreeType\n");
3043 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
3046 ERR("called but we don't have FreeType\n");
3050 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
3052 ERR("called but we don't have FreeType\n");
3056 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3062 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3068 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
3071 return DEFAULT_CHARSET;
3074 #endif /* HAVE_FREETYPE */