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 typedef struct tagFace {
161 FT_Fixed font_version;
163 Bitmap_Size size; /* set if face is a bitmap */
164 BOOL external; /* TRUE if we should manually add this font to the registry */
165 struct tagFace *next;
166 struct tagFamily *family;
169 typedef struct tagFamily {
172 struct tagFamily *next;
177 INT adv; /* These three hold to widths of the unrotated chars */
197 OUTLINETEXTMETRICW *potm;
199 struct tagGdiFont *next;
202 #define INIT_GM_SIZE 128
204 static GdiFont GdiFontList = NULL;
206 static Family *FontList = NULL;
208 static const WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ',
209 'R','o','m','a','n','\0'};
210 static const WCHAR defSans[] = {'A','r','i','a','l','\0'};
211 static const WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
213 static const WCHAR defSystem[] = {'A','r','i','a','l','\0'};
214 static const WCHAR SystemW[] = {'S','y','s','t','e','m','\0'};
215 static const WCHAR MSSansSerifW[] = {'M','S',' ','S','a','n','s',' ',
216 'S','e','r','i','f','\0'};
217 static const WCHAR HelvW[] = {'H','e','l','v','\0'};
218 static const WCHAR RegularW[] = {'R','e','g','u','l','a','r','\0'};
220 static const WCHAR fontsW[] = {'\\','F','o','n','t','s','\0'};
221 static const WCHAR win9x_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
222 'W','i','n','d','o','w','s','\\',
223 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
224 'F','o','n','t','s','\0'};
226 static const WCHAR winnt_font_reg_key[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
227 'W','i','n','d','o','w','s',' ','N','T','\\',
228 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
229 'F','o','n','t','s','\0'};
231 static const WCHAR system_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
232 static const WCHAR FixedSys_Value[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
233 static const WCHAR System_Value[] = {'F','O','N','T','S','.','F','O','N','\0'};
234 static const WCHAR OEMFont_Value[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
236 static const WCHAR *SystemFontValues[4] = {
243 static const WCHAR external_fonts_reg_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\','W','i','n','e','\\',
244 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
246 static const WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
247 static const WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
248 static const WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
249 static const WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
250 static const WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
251 'E','u','r','o','p','e','a','n','\0'};
252 static const WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
253 static const WCHAR GreekW[] = {'G','r','e','e','k','\0'};
254 static const WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
255 static const WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
256 static const WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
257 static const WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
258 static const WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
259 static const WCHAR ThaiW[] = {'T','h','a','i','\0'};
260 static const WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
261 static const WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
262 static const WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
263 static const WCHAR OEM_DOSW[] = {'O','E','M','/','D','O','S','\0'};
265 static const WCHAR *ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
275 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
283 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
292 typedef struct tagFontSubst {
295 struct tagFontSubst *next;
298 static FontSubst *substlist = NULL;
299 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
301 static const WCHAR font_mutex_nameW[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
304 /****************************************
305 * Notes on .fon files
307 * The fonts System, FixedSys and Terminal are special. There are typically multiple
308 * versions installed for different resolutions and codepages. Windows stores which one to use
309 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
311 * FIXEDFON.FON FixedSys
313 * OEMFONT.FON Termial
314 * LogPixels Current dpi set by the display control panel applet
315 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
316 * also has a LogPixels value that appears to mirror this)
318 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
319 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
320 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
321 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
322 * so that makes sense.
324 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
325 * to be mapped into the registry on Windows 2000 at least).
328 * ega80woa.fon=ega80850.fon
329 * ega40woa.fon=ega40850.fon
330 * cga80woa.fon=cga80850.fon
331 * cga40woa.fon=cga40850.fon
335 static inline BOOL is_win9x(void)
337 return GetVersion() & 0x80000000;
340 This function builds an FT_Fixed from a float. It puts the integer part
341 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
342 It fails if the integer part of the float number is greater than SHORT_MAX.
344 static inline FT_Fixed FT_FixedFromFloat(float f)
347 unsigned short fract = (f - value) * 0xFFFF;
348 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
352 This function builds an FT_Fixed from a FIXED. It simply put f.value
353 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
355 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
357 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
360 #define ADDFONT_EXTERNAL_FONT 0x01
361 #define ADDFONT_FORCE_BITMAP 0x02
362 static BOOL AddFontFileToList(const char *file, char *fake_family, DWORD flags)
366 TT_Header *pHeader = NULL;
367 WCHAR *FamilyW, *StyleW;
370 Face **insertface, *next;
372 FT_Long face_index = 0, num_faces;
373 #ifdef HAVE_FREETYPE_FTWINFNT_H
374 FT_WinFNT_HeaderRec winfnt_header;
379 char *family_name = fake_family;
381 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
382 if((err = pFT_New_Face(library, file, face_index, &ft_face)) != 0) {
383 WARN("Unable to load font file %s err = %x\n", debugstr_a(file), err);
387 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*/
388 pFT_Done_Face(ft_face);
392 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
393 if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) {
394 pFT_Done_Face(ft_face);
398 if(FT_IS_SFNT(ft_face) && (!pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2) ||
399 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
400 !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))) {
401 TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
402 "Skipping this font.\n", debugstr_a(file));
403 pFT_Done_Face(ft_face);
407 if(!ft_face->family_name || !ft_face->style_name) {
408 TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file));
409 pFT_Done_Face(ft_face);
414 family_name = ft_face->family_name;
418 len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
419 FamilyW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
420 MultiByteToWideChar(CP_ACP, 0, family_name, -1, FamilyW, len);
424 if(!strcmpW((*pfamily)->FamilyName, FamilyW))
426 pfamily = &(*pfamily)->next;
429 *pfamily = HeapAlloc(GetProcessHeap(), 0, sizeof(**pfamily));
430 (*pfamily)->FamilyName = FamilyW;
431 (*pfamily)->FirstFace = NULL;
432 (*pfamily)->next = NULL;
434 HeapFree(GetProcessHeap(), 0, FamilyW);
437 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
438 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
439 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
442 for(insertface = &(*pfamily)->FirstFace; *insertface;
443 insertface = &(*insertface)->next) {
444 if(!strcmpW((*insertface)->StyleName, StyleW) && FT_IS_SCALABLE(ft_face)) {
445 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
446 debugstr_w((*pfamily)->FamilyName), debugstr_w(StyleW),
447 (*insertface)->font_version, pHeader->Font_Revision);
450 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
451 HeapFree(GetProcessHeap(), 0, StyleW);
452 pFT_Done_Face(ft_face);
455 if(pHeader->Font_Revision <= (*insertface)->font_version) {
456 TRACE("Original font is newer so skipping this one\n");
457 HeapFree(GetProcessHeap(), 0, StyleW);
458 pFT_Done_Face(ft_face);
461 TRACE("Replacing original with this one\n");
462 next = (*insertface)->next;
463 HeapFree(GetProcessHeap(), 0, (*insertface)->file);
464 HeapFree(GetProcessHeap(), 0, (*insertface)->StyleName);
465 HeapFree(GetProcessHeap(), 0, *insertface);
470 *insertface = HeapAlloc(GetProcessHeap(), 0, sizeof(**insertface));
471 (*insertface)->StyleName = StyleW;
472 (*insertface)->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
473 strcpy((*insertface)->file, file);
474 (*insertface)->face_index = face_index;
475 (*insertface)->next = next;
476 (*insertface)->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
477 (*insertface)->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
478 (*insertface)->font_version = pHeader ? pHeader->Font_Revision : 0;
479 (*insertface)->family = *pfamily;
480 (*insertface)->external = (flags & ADDFONT_EXTERNAL_FONT) ? TRUE : FALSE;
482 if(FT_IS_SCALABLE(ft_face)) {
483 memset(&(*insertface)->size, 0, sizeof((*insertface)->size));
484 (*insertface)->scalable = TRUE;
486 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
487 So to let this compile on older versions of FreeType we'll define the
488 new structure here. Note that this code is never executed when run with
489 earlier versions of the library because of the version check above */
490 struct my_bitmap_size {
491 FT_Short height, width;
492 FT_Pos size, x_ppem, y_ppem;
495 size = (struct my_bitmap_size *)ft_face->available_sizes + bitmap_num;
496 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
497 size->height, size->width, size->size >> 6,
498 size->x_ppem >> 6, size->y_ppem >> 6);
499 (*insertface)->size.height = size->height;
500 (*insertface)->size.width = size->width;
501 (*insertface)->size.size = size->size;
502 (*insertface)->size.x_ppem = size->x_ppem;
503 (*insertface)->size.y_ppem = size->y_ppem;
504 (*insertface)->size.internal_leading = 0;
505 (*insertface)->scalable = FALSE;
508 memset(&(*insertface)->fs, 0, sizeof((*insertface)->fs));
510 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
512 (*insertface)->fs.fsCsb[0] = pOS2->ulCodePageRange1;
513 (*insertface)->fs.fsCsb[1] = pOS2->ulCodePageRange2;
514 (*insertface)->fs.fsUsb[0] = pOS2->ulUnicodeRange1;
515 (*insertface)->fs.fsUsb[1] = pOS2->ulUnicodeRange2;
516 (*insertface)->fs.fsUsb[2] = pOS2->ulUnicodeRange3;
517 (*insertface)->fs.fsUsb[3] = pOS2->ulUnicodeRange4;
518 if(pOS2->version == 0) {
521 if(!pFT_Get_First_Char || (pFT_Get_First_Char( ft_face, &dummy ) < 0x100))
522 (*insertface)->fs.fsCsb[0] |= 1;
524 (*insertface)->fs.fsCsb[0] |= 1L << 31;
527 #ifdef HAVE_FREETYPE_FTWINFNT_H
528 else if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header)) {
530 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header.pixel_height, winfnt_header.charset,
531 winfnt_header.vertical_resolution,winfnt_header.horizontal_resolution, winfnt_header.nominal_point_size);
532 if(TranslateCharsetInfo((DWORD*)(UINT)winfnt_header.charset, &csi, TCI_SRCCHARSET))
533 memcpy(&(*insertface)->fs, &csi.fs, sizeof(csi.fs));
534 (*insertface)->size.internal_leading = winfnt_header.internal_leading;
537 TRACE("fsCsb = %08lx %08lx/%08lx %08lx %08lx %08lx\n",
538 (*insertface)->fs.fsCsb[0], (*insertface)->fs.fsCsb[1],
539 (*insertface)->fs.fsUsb[0], (*insertface)->fs.fsUsb[1],
540 (*insertface)->fs.fsUsb[2], (*insertface)->fs.fsUsb[3]);
543 if((*insertface)->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
544 for(i = 0; i < ft_face->num_charmaps; i++) {
545 switch(ft_face->charmaps[i]->encoding) {
546 case ft_encoding_unicode:
547 case ft_encoding_apple_roman:
548 (*insertface)->fs.fsCsb[0] |= 1;
550 case ft_encoding_symbol:
551 (*insertface)->fs.fsCsb[0] |= 1L << 31;
559 if((*insertface)->fs.fsCsb[0] & ~(1L << 31))
560 have_installed_roman_font = TRUE;
561 } while(!FT_IS_SCALABLE(ft_face) && ++bitmap_num < ft_face->num_fixed_sizes);
563 num_faces = ft_face->num_faces;
564 pFT_Done_Face(ft_face);
565 TRACE("Added font %s %s\n", debugstr_w((*pfamily)->FamilyName),
567 } while(num_faces > ++face_index);
571 static void DumpFontList(void)
576 for(family = FontList; family; family = family->next) {
577 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
578 for(face = family->FirstFace; face; face = face->next) {
579 TRACE("\t%s", debugstr_w(face->StyleName));
581 TRACE(" %ld", face->size.y_ppem >> 6);
588 static void DumpSubstList(void)
592 for(psub = substlist; psub; psub = psub->next)
593 if(psub->from.charset != -1 || psub->to.charset != -1)
594 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
595 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
597 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
598 debugstr_w(psub->to.name));
602 static LPWSTR strdupW(LPWSTR p)
605 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
606 ret = HeapAlloc(GetProcessHeap(), 0, len);
611 static void split_subst_info(NameCs *nc, LPSTR str)
613 CHAR *p = strrchr(str, ',');
618 nc->charset = strtol(p+1, NULL, 10);
621 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
622 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
623 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
626 static void LoadSubstList(void)
628 FontSubst *psub, **ppsub;
630 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
635 for(psub = substlist; psub;) {
637 HeapFree(GetProcessHeap(), 0, psub->to.name);
638 HeapFree(GetProcessHeap(), 0, psub->from.name);
641 HeapFree(GetProcessHeap(), 0, ptmp);
646 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
647 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
648 &hkey) == ERROR_SUCCESS) {
650 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
651 &valuelen, &datalen, NULL, NULL);
653 valuelen++; /* returned value doesn't include room for '\0' */
654 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
655 data = HeapAlloc(GetProcessHeap(), 0, datalen);
660 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
661 &dlen) == ERROR_SUCCESS) {
662 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
664 *ppsub = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppsub));
665 (*ppsub)->next = NULL;
666 split_subst_info(&((*ppsub)->from), value);
667 split_subst_info(&((*ppsub)->to), data);
669 /* Win 2000 doesn't allow mapping between different charsets
670 or mapping of DEFAULT_CHARSET */
671 if(((*ppsub)->to.charset != (*ppsub)->from.charset) ||
672 (*ppsub)->to.charset == DEFAULT_CHARSET) {
673 HeapFree(GetProcessHeap(), 0, (*ppsub)->to.name);
674 HeapFree(GetProcessHeap(), 0, (*ppsub)->from.name);
675 HeapFree(GetProcessHeap(), 0, *ppsub);
678 ppsub = &((*ppsub)->next);
680 /* reset dlen and vlen */
684 HeapFree(GetProcessHeap(), 0, data);
685 HeapFree(GetProcessHeap(), 0, value);
690 /***********************************************************
691 * The replacement list is a way to map an entire font
692 * family onto another family. For example adding
694 * [HKLM\Software\Wine\Wine\FontReplacements]
695 * "Wingdings"="Winedings"
697 * would enumerate the Winedings font both as Winedings and
698 * Wingdings. However if a real Wingdings font is present the
699 * replacement does not take place.
702 static void LoadReplaceList(void)
705 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
710 WCHAR old_nameW[200];
712 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
713 "Software\\Wine\\Wine\\FontReplacements",
714 &hkey) == ERROR_SUCCESS) {
716 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
717 &valuelen, &datalen, NULL, NULL);
719 valuelen++; /* returned value doesn't include room for '\0' */
720 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
721 data = HeapAlloc(GetProcessHeap(), 0, datalen);
725 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
726 &dlen) == ERROR_SUCCESS) {
727 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
728 /* "NewName"="Oldname" */
729 if(!MultiByteToWideChar(CP_ACP, 0, data, -1, old_nameW, sizeof(old_nameW)))
732 /* Find the old family and hence all of the font files
734 for(family = FontList; family; family = family->next) {
735 if(!strcmpiW(family->FamilyName, old_nameW)) {
736 for(face = family->FirstFace; face; face = face->next) {
737 TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
738 debugstr_w(face->StyleName), value);
739 /* Now add a new entry with the new family name */
740 AddFontFileToList(face->file, value, face->external ? ADDFONT_EXTERNAL_FONT : 0);
745 /* reset dlen and vlen */
749 HeapFree(GetProcessHeap(), 0, data);
750 HeapFree(GetProcessHeap(), 0, value);
756 static BOOL ReadFontDir(const char *dirname, BOOL external_fonts)
762 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
764 dir = opendir(dirname);
766 ERR("Can't open directory %s\n", debugstr_a(dirname));
769 while((dent = readdir(dir)) != NULL) {
772 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
775 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
777 sprintf(path, "%s/%s", dirname, dent->d_name);
779 if(stat(path, &statbuf) == -1)
781 WARN("Can't stat %s\n", debugstr_a(path));
784 if(S_ISDIR(statbuf.st_mode))
785 ReadFontDir(path, external_fonts);
787 AddFontFileToList(path, NULL, external_fonts ? ADDFONT_EXTERNAL_FONT : 0);
793 static void load_fontconfig_fonts(void)
795 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
796 void *fc_handle = NULL;
805 fc_handle = wine_dlopen(SONAME_LIBFONTCONFIG, RTLD_NOW, NULL, 0);
807 TRACE("Wine cannot find the fontconfig library (%s).\n",
808 SONAME_LIBFONTCONFIG);
811 #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;}
812 LOAD_FUNCPTR(FcConfigGetCurrent);
813 LOAD_FUNCPTR(FcFontList);
814 LOAD_FUNCPTR(FcFontSetDestroy);
815 LOAD_FUNCPTR(FcInit);
816 LOAD_FUNCPTR(FcObjectSetAdd);
817 LOAD_FUNCPTR(FcObjectSetCreate);
818 LOAD_FUNCPTR(FcObjectSetDestroy);
819 LOAD_FUNCPTR(FcPatternCreate);
820 LOAD_FUNCPTR(FcPatternDestroy);
821 LOAD_FUNCPTR(FcPatternGet);
824 if(!pFcInit()) return;
826 config = pFcConfigGetCurrent();
827 pat = pFcPatternCreate();
828 os = pFcObjectSetCreate();
829 pFcObjectSetAdd(os, FC_FILE);
830 fontset = pFcFontList(config, pat, os);
832 for(i = 0; i < fontset->nfont; i++) {
833 if(pFcPatternGet(fontset->fonts[i], FC_FILE, 0, &v) != FcResultMatch)
835 if(v.type != FcTypeString) continue;
836 TRACE("fontconfig: %s\n", v.u.s);
838 /* We're just interested in OT/TT fonts for now, so this hack just
839 picks up the standard extensions to save time loading every other
842 if(len < 4) continue;
843 ext = v.u.s + len - 3;
844 if(!strcasecmp(ext, "ttf") || !strcasecmp(ext, "ttc") || !strcasecmp(ext, "otf"))
845 AddFontFileToList(v.u.s, NULL, ADDFONT_EXTERNAL_FONT);
847 pFcFontSetDestroy(fontset);
848 pFcObjectSetDestroy(os);
849 pFcPatternDestroy(pat);
856 void load_system_fonts(void)
859 WCHAR data[MAX_PATH], windowsdir[MAX_PATH], pathW[MAX_PATH];
862 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
865 if(RegOpenKeyW(HKEY_CURRENT_CONFIG, system_fonts_reg_key, &hkey) == ERROR_SUCCESS) {
866 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
867 strcatW(windowsdir, fontsW);
868 for(value = SystemFontValues; *value; value++) {
870 if(RegQueryValueExW(hkey, *value, 0, &type, (void*)data, &dlen) == ERROR_SUCCESS &&
872 sprintfW(pathW, fmtW, windowsdir, data);
873 if((unixname = wine_get_unix_file_name(pathW))) {
874 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
875 HeapFree(GetProcessHeap(), 0, unixname);
883 /*************************************************************
885 * This adds registry entries for any externally loaded fonts
886 * (fonts from fontconfig or FontDirs). It also deletes entries
887 * of no longer existing fonts.
890 void update_reg_entries(void)
892 HKEY winkey = 0, externalkey = 0;
895 DWORD dlen, vlen, datalen, valuelen, i, type, len, len_fam;
899 static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
900 static const WCHAR spaceW[] = {' ', '\0'};
903 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
904 0, NULL, 0, KEY_ALL_ACCESS, NULL, &winkey, NULL) != ERROR_SUCCESS) {
905 ERR("Can't create Windows font reg key\n");
908 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, external_fonts_reg_key,
909 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
910 ERR("Can't create external font reg key\n");
914 /* Delete all external fonts added last time */
916 RegQueryInfoKeyW(externalkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
917 &valuelen, &datalen, NULL, NULL);
918 valuelen++; /* returned value doesn't include room for '\0' */
919 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
920 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
922 dlen = datalen * sizeof(WCHAR);
925 while(RegEnumValueW(externalkey, i++, valueW, &vlen, NULL, &type, data,
926 &dlen) == ERROR_SUCCESS) {
928 RegDeleteValueW(winkey, valueW);
929 /* reset dlen and vlen */
933 HeapFree(GetProcessHeap(), 0, data);
934 HeapFree(GetProcessHeap(), 0, valueW);
936 /* Delete the old external fonts key */
937 RegCloseKey(externalkey);
939 RegDeleteKeyW(HKEY_LOCAL_MACHINE, external_fonts_reg_key);
941 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, external_fonts_reg_key,
942 0, NULL, 0, KEY_ALL_ACCESS, NULL, &externalkey, NULL) != ERROR_SUCCESS) {
943 ERR("Can't create external font reg key\n");
947 /* enumerate the fonts and add external ones to the two keys */
949 for(family = FontList; family; family = family->next) {
950 len_fam = strlenW(family->FamilyName) + sizeof(TrueType) / sizeof(WCHAR) + 1;
951 for(face = family->FirstFace; face; face = face->next) {
952 if(!face->external) continue;
954 if(strcmpiW(face->StyleName, RegularW))
955 len = len_fam + strlenW(face->StyleName) + 1;
956 valueW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
957 strcpyW(valueW, family->FamilyName);
959 strcatW(valueW, spaceW);
960 strcatW(valueW, face->StyleName);
962 strcatW(valueW, TrueType);
963 if((path = strrchr(face->file, '/')) == NULL)
967 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
969 file = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
970 MultiByteToWideChar(CP_ACP, 0, path, -1, file, len);
971 RegSetValueExW(winkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
972 RegSetValueExW(externalkey, valueW, 0, REG_SZ, (BYTE*)file, len * sizeof(WCHAR));
974 HeapFree(GetProcessHeap(), 0, file);
975 HeapFree(GetProcessHeap(), 0, valueW);
980 RegCloseKey(externalkey);
987 /*************************************************************
988 * WineEngAddFontResourceEx
991 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
993 if (ft_handle) /* do it only if we have freetype up and running */
998 FIXME("Ignoring flags %lx\n", flags);
1000 if((unixname = wine_get_unix_file_name(file)))
1002 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1003 HeapFree(GetProcessHeap(), 0, unixname);
1009 /*************************************************************
1010 * WineEngRemoveFontResourceEx
1013 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
1019 /*************************************************************
1022 * Initialize FreeType library and create a list of available faces
1024 BOOL WineEngInit(void)
1026 static const WCHAR dot_fonW[] = {'.','f','o','n','\0'};
1028 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
1030 WCHAR windowsdir[MAX_PATH];
1036 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
1039 "Wine cannot find the FreeType font library. To enable Wine to\n"
1040 "use TrueType fonts please install a version of FreeType greater than\n"
1041 "or equal to 2.0.5.\n"
1042 "http://www.freetype.org\n");
1046 #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;}
1048 LOAD_FUNCPTR(FT_Vector_Unit)
1049 LOAD_FUNCPTR(FT_Done_Face)
1050 LOAD_FUNCPTR(FT_Get_Char_Index)
1051 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
1052 LOAD_FUNCPTR(FT_Init_FreeType)
1053 LOAD_FUNCPTR(FT_Load_Glyph)
1054 LOAD_FUNCPTR(FT_Matrix_Multiply)
1055 LOAD_FUNCPTR(FT_MulFix)
1056 LOAD_FUNCPTR(FT_New_Face)
1057 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
1058 LOAD_FUNCPTR(FT_Outline_Transform)
1059 LOAD_FUNCPTR(FT_Outline_Translate)
1060 LOAD_FUNCPTR(FT_Select_Charmap)
1061 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
1062 LOAD_FUNCPTR(FT_Vector_Transform)
1065 /* Don't warn if this one is missing */
1066 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
1067 pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
1068 pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
1069 #ifdef HAVE_FREETYPE_FTWINFNT_H
1070 pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
1072 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
1073 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
1074 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
1075 <= 2.0.3 has FT_Sqrt64 */
1079 if(pFT_Init_FreeType(&library) != 0) {
1080 ERR("Can't init FreeType library\n");
1081 wine_dlclose(ft_handle, NULL, 0);
1085 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
1086 if (pFT_Library_Version)
1088 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
1090 if (FT_Version.major<=0)
1096 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
1097 FT_SimpleVersion = ((FT_Version.major << 16) & 0xff0000) |
1098 ((FT_Version.minor << 8) & 0x00ff00) |
1099 ((FT_Version.patch ) & 0x0000ff);
1101 if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
1102 ERR("Failed to create font mutex\n");
1105 WaitForSingleObject(font_mutex, INFINITE);
1107 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
1108 GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
1109 strcatW(windowsdir, fontsW);
1110 if((unixname = wine_get_unix_file_name(windowsdir)))
1112 ReadFontDir(unixname, FALSE);
1113 HeapFree(GetProcessHeap(), 0, unixname);
1116 /* now load the system fonts */
1117 load_system_fonts();
1119 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
1120 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
1121 full path as the entry. Also look for any .fon fonts, since ReadFontDir
1123 if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
1124 is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
1125 &hkey) == ERROR_SUCCESS) {
1127 RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1128 &valuelen, &datalen, NULL, NULL);
1130 valuelen++; /* returned value doesn't include room for '\0' */
1131 valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
1132 data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
1135 dlen = datalen * sizeof(WCHAR);
1137 while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
1138 &dlen) == ERROR_SUCCESS) {
1139 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
1141 if((unixname = wine_get_unix_file_name((LPWSTR)data)))
1143 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1144 HeapFree(GetProcessHeap(), 0, unixname);
1147 else if(dlen / 2 >= 6 && !strcmpiW(((LPWSTR)data) + dlen / 2 - 5, dot_fonW))
1149 WCHAR pathW[MAX_PATH];
1150 static const WCHAR fmtW[] = {'%','s','\\','%','s','\0'};
1151 sprintfW(pathW, fmtW, windowsdir, data);
1152 if((unixname = wine_get_unix_file_name(pathW)))
1154 AddFontFileToList(unixname, NULL, ADDFONT_FORCE_BITMAP);
1155 HeapFree(GetProcessHeap(), 0, unixname);
1158 /* reset dlen and vlen */
1163 if (data) HeapFree(GetProcessHeap(), 0, data);
1164 if (valueW) HeapFree(GetProcessHeap(), 0, valueW);
1168 load_fontconfig_fonts();
1170 /* then look in any directories that we've specified in the config file */
1171 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1172 "Software\\Wine\\Wine\\Config\\FontDirs",
1173 &hkey) == ERROR_SUCCESS) {
1175 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1176 &valuelen, &datalen, NULL, NULL);
1178 valuelen++; /* returned value doesn't include room for '\0' */
1179 value = HeapAlloc(GetProcessHeap(), 0, valuelen);
1180 data = HeapAlloc(GetProcessHeap(), 0, datalen);
1185 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1186 &dlen) == ERROR_SUCCESS) {
1187 TRACE("Got %s=%s\n", value, (LPSTR)data);
1188 ReadFontDir((LPSTR)data, TRUE);
1189 /* reset dlen and vlen */
1193 HeapFree(GetProcessHeap(), 0, data);
1194 HeapFree(GetProcessHeap(), 0, value);
1202 update_reg_entries();
1204 ReleaseMutex(font_mutex);
1208 "Wine cannot find certain functions that it needs inside the FreeType\n"
1209 "font library. To enable Wine to use TrueType fonts please upgrade\n"
1210 "FreeType to at least version 2.0.5.\n"
1211 "http://www.freetype.org\n");
1212 wine_dlclose(ft_handle, NULL, 0);
1218 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
1221 TT_HoriHeader *pHori;
1225 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1226 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1228 if(height == 0) height = 16;
1230 /* Calc. height of EM square:
1232 * For +ve lfHeight we have
1233 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
1234 * Re-arranging gives:
1235 * ppem = units_per_em * lfheight / (winAscent + winDescent)
1237 * For -ve lfHeight we have
1239 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
1240 * with il = winAscent + winDescent - units_per_em]
1245 if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
1246 ppem = ft_face->units_per_EM * height /
1247 (pHori->Ascender - pHori->Descender);
1249 ppem = ft_face->units_per_EM * height /
1250 (pOS2->usWinAscent + pOS2->usWinDescent);
1258 static LONG load_VDMX(GdiFont, LONG);
1260 static FT_Face OpenFontFile(GdiFont font, char *file, FT_Long face_index, LONG width, LONG height)
1266 err = pFT_New_Face(library, file, face_index, &ft_face);
1268 ERR("FT_New_Face rets %d\n", err);
1272 /* set it here, as load_VDMX needs it */
1273 font->ft_face = ft_face;
1275 if(FT_IS_SCALABLE(ft_face)) {
1276 /* load the VDMX table if we have one */
1277 ppem = load_VDMX(font, height);
1279 ppem = calc_ppem_for_height(ft_face, height);
1281 if((err = pFT_Set_Pixel_Sizes(ft_face, 0, ppem)) != 0)
1282 WARN("FT_Set_Pixel_Sizes %d, %ld rets %x\n", 0, ppem, err);
1284 if((err = pFT_Set_Pixel_Sizes(ft_face, width, height)) != 0)
1285 WARN("FT_Set_Pixel_Sizes %ld, %ld rets %x\n", width, height, err);
1291 static int get_nearest_charset(Face *face)
1293 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
1294 a single face with the requested charset. The idea is to check if
1295 the selected font supports the current ANSI codepage, if it does
1296 return the corresponding charset, else return the first charset */
1299 int acp = GetACP(), i;
1302 if(TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE))
1303 if(csi.fs.fsCsb[0] & face->fs.fsCsb[0])
1304 return csi.ciCharset;
1306 for(i = 0; i < 32; i++) {
1308 if(face->fs.fsCsb[0] & fs0) {
1309 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG))
1310 return csi.ciCharset;
1312 FIXME("TCI failing on %lx\n", fs0);
1316 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08lx file = %s\n",
1317 face->fs.fsCsb[0], face->file);
1318 return DEFAULT_CHARSET;
1321 static GdiFont alloc_font(void)
1323 GdiFont ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
1324 ret->gmsize = INIT_GM_SIZE;
1325 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1326 ret->gmsize * sizeof(*ret->gm));
1329 ret->xform.eM11 = ret->xform.eM22 = 1.0;
1333 static void free_font(GdiFont font)
1335 if (font->ft_face) pFT_Done_Face(font->ft_face);
1336 if (font->potm) HeapFree(GetProcessHeap(), 0, font->potm);
1337 if (font->name) HeapFree(GetProcessHeap(), 0, font->name);
1338 HeapFree(GetProcessHeap(), 0, font->gm);
1339 HeapFree(GetProcessHeap(), 0, font);
1343 /*************************************************************
1346 * load the vdmx entry for the specified height
1349 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
1350 ( ( (FT_ULong)_x4 << 24 ) | \
1351 ( (FT_ULong)_x3 << 16 ) | \
1352 ( (FT_ULong)_x2 << 8 ) | \
1355 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
1365 static LONG load_VDMX(GdiFont font, LONG height)
1367 BYTE hdr[6], tmp[2], group[4];
1368 BYTE devXRatio, devYRatio;
1369 USHORT numRecs, numRatios;
1374 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
1376 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
1379 /* FIXME: need the real device aspect ratio */
1383 numRecs = GET_BE_WORD(&hdr[2]);
1384 numRatios = GET_BE_WORD(&hdr[4]);
1386 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
1387 for(i = 0; i < numRatios; i++) {
1390 offset = (3 * 2) + (i * sizeof(Ratios));
1391 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
1394 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
1396 if(ratio.bCharSet != 1)
1399 if((ratio.xRatio == 0 &&
1400 ratio.yStartRatio == 0 &&
1401 ratio.yEndRatio == 0) ||
1402 (devXRatio == ratio.xRatio &&
1403 devYRatio >= ratio.yStartRatio &&
1404 devYRatio <= ratio.yEndRatio))
1406 offset = (3 * 2) + (numRatios * 4) + (i * 2);
1407 WineEngGetFontData(font, MS_VDMX_TAG, offset, tmp, 2);
1408 offset = GET_BE_WORD(tmp);
1414 FIXME("No suitable ratio found\n");
1418 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, group, 4) != GDI_ERROR) {
1420 BYTE startsz, endsz;
1423 recs = GET_BE_WORD(group);
1427 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
1429 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
1430 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
1431 if(result == GDI_ERROR) {
1432 FIXME("Failed to retrieve vTable\n");
1437 for(i = 0; i < recs; i++) {
1438 SHORT yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1439 SHORT yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1440 ppem = GET_BE_WORD(&vTable[i * 6]);
1442 if(yMax + -yMin == height) {
1445 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1448 if(yMax + -yMin > height) {
1451 goto end; /* failed */
1453 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1454 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1455 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
1461 TRACE("ppem not found for height %ld\n", height);
1465 if(ppem < startsz || ppem > endsz)
1468 for(i = 0; i < recs; i++) {
1470 yPelHeight = GET_BE_WORD(&vTable[i * 6]);
1472 if(yPelHeight > ppem)
1475 if(yPelHeight == ppem) {
1476 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1477 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1478 TRACE("ppem %ld found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
1484 HeapFree(GetProcessHeap(), 0, vTable);
1491 /*************************************************************
1492 * WineEngCreateFontInstance
1495 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
1499 Family *family = NULL;
1500 INT height, width = 0;
1501 signed int diff = 0, newdiff;
1502 BOOL bd, it, can_use_bitmap;
1506 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
1507 can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
1509 TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
1510 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
1511 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
1514 /* check the cache first */
1515 for(ret = GdiFontList; ret; ret = ret->next) {
1516 if(ret->hfont == hfont && !memcmp(&ret->xform, &dc->xformWorld2Vport, offsetof(XFORM, eDx)) &&
1517 (can_use_bitmap || FT_IS_SCALABLE(ret->ft_face))) {
1519 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
1524 if(!FontList || !have_installed_roman_font) /* No fonts installed */
1526 TRACE("No fonts installed\n");
1531 memcpy(&ret->xform, &dc->xformWorld2Vport, sizeof(XFORM));
1533 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
1534 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
1535 original value lfCharSet. Note this is a special case for
1536 Symbol and doesn't happen at least for "Wingdings*" */
1538 if(!strcmpiW(lf.lfFaceName, SymbolW))
1539 lf.lfCharSet = SYMBOL_CHARSET;
1541 if(!TranslateCharsetInfo((DWORD*)(INT)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
1542 switch(lf.lfCharSet) {
1543 case DEFAULT_CHARSET:
1544 csi.fs.fsCsb[0] = 0;
1547 FIXME("Untranslated charset %d\n", lf.lfCharSet);
1548 csi.fs.fsCsb[0] = 0;
1553 if(lf.lfFaceName[0] != '\0') {
1555 for(psub = substlist; psub; psub = psub->next)
1556 if(!strcmpiW(lf.lfFaceName, psub->from.name) &&
1557 (psub->from.charset == -1 ||
1558 psub->from.charset == lf.lfCharSet))
1561 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
1562 debugstr_w(psub->to.name));
1563 strcpyW(lf.lfFaceName, psub->to.name);
1566 /* We want a match on name and charset or just name if
1567 charset was DEFAULT_CHARSET. If the latter then
1568 we fixup the returned charset later in get_nearest_charset
1569 where we'll either use the charset of the current ansi codepage
1570 or if that's unavailable the first charset that the font supports.
1572 for(family = FontList; family; family = family->next) {
1573 if(!strcmpiW(family->FamilyName, lf.lfFaceName))
1574 if((csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0]) || !csi.fs.fsCsb[0])
1575 if(family->FirstFace->scalable || can_use_bitmap)
1581 /* If requested charset was DEFAULT_CHARSET then try using charset
1582 corresponding to the current ansi codepage */
1583 if(!csi.fs.fsCsb[0]) {
1585 if(!TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE)) {
1586 FIXME("TCI failed on codepage %d\n", acp);
1587 csi.fs.fsCsb[0] = 0;
1589 lf.lfCharSet = csi.ciCharset;
1592 /* Face families are in the top 4 bits of lfPitchAndFamily,
1593 so mask with 0xF0 before testing */
1595 if((lf.lfPitchAndFamily & FIXED_PITCH) ||
1596 (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
1597 strcpyW(lf.lfFaceName, defFixed);
1598 else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
1599 strcpyW(lf.lfFaceName, defSerif);
1600 else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
1601 strcpyW(lf.lfFaceName, defSans);
1603 strcpyW(lf.lfFaceName, defSans);
1604 for(family = FontList; family; family = family->next) {
1605 if(!strcmpiW(family->FamilyName, lf.lfFaceName) &&
1606 (csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0]))
1607 if(family->FirstFace->scalable || can_use_bitmap)
1613 for(family = FontList; family; family = family->next) {
1614 if(csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0])
1615 if(family->FirstFace->scalable || can_use_bitmap)
1622 csi.fs.fsCsb[0] = 0;
1623 FIXME("just using first face for now\n");
1626 it = lf.lfItalic ? 1 : 0;
1627 bd = lf.lfWeight > 550 ? 1 : 0;
1629 height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
1630 height = lf.lfHeight < 0 ? -abs(height) : abs(height);
1633 for(face = family->FirstFace; face; face = face->next) {
1634 if(!(face->Italic ^ it) && !(face->Bold ^ bd)) {
1638 newdiff = height - (signed int)(face->size.y_ppem >> 6);
1640 newdiff = -height - ((signed int)(face->size.y_ppem >> 6) - face->size.internal_leading);
1641 if(!best || (diff > 0 && newdiff < diff && newdiff >= 0) ||
1642 (diff < 0 && newdiff > diff)) {
1643 TRACE("%ld is better for %d diff was %d\n", face->size.y_ppem >> 6, height, diff);
1654 face = family->FirstFace;
1655 if(it && !face->Italic) ret->fake_italic = TRUE;
1656 if(bd && !face->Bold) ret->fake_bold = TRUE;
1659 memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
1662 ret->charset = lf.lfCharSet;
1664 ret->charset = get_nearest_charset(face);
1666 TRACE("Chosen: %s %s\n", debugstr_w(family->FamilyName),
1667 debugstr_w(face->StyleName));
1669 if(!face->scalable) {
1670 width = face->size.x_ppem >> 6;
1671 height = face->size.y_ppem >> 6;
1673 ret->ft_face = OpenFontFile(ret, face->file, face->face_index, width, height);
1681 if (ret->charset == SYMBOL_CHARSET &&
1682 !pFT_Select_Charmap(ret->ft_face, ft_encoding_symbol)) {
1685 else if (!pFT_Select_Charmap(ret->ft_face, ft_encoding_unicode)) {
1689 pFT_Select_Charmap(ret->ft_face, ft_encoding_apple_roman);
1692 ret->orientation = lf.lfOrientation;
1693 ret->name = strdupW(family->FamilyName);
1695 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
1697 ret->aveWidth= lf.lfWidth;
1698 ret->next = GdiFontList;
1704 static void DumpGdiFontList(void)
1708 TRACE("---------- gdiFont Cache ----------\n");
1709 for(gdiFont = GdiFontList; gdiFont; gdiFont = gdiFont->next) {
1711 GetObjectW( gdiFont->hfont, sizeof(lf), &lf );
1712 TRACE("gdiFont=%p hfont=%p (%s)\n",
1713 gdiFont, gdiFont->hfont, debugstr_w(lf.lfFaceName));
1717 /*************************************************************
1718 * WineEngDestroyFontInstance
1720 * free the gdiFont associated with this handle
1723 BOOL WineEngDestroyFontInstance(HFONT handle)
1726 GdiFont gdiPrev = NULL;
1729 TRACE("destroying hfont=%p\n", handle);
1733 gdiFont = GdiFontList;
1735 if(gdiFont->hfont == handle) {
1737 gdiPrev->next = gdiFont->next;
1739 gdiFont = gdiPrev->next;
1741 GdiFontList = gdiFont->next;
1743 gdiFont = GdiFontList;
1748 gdiFont = gdiFont->next;
1754 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
1755 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
1757 OUTLINETEXTMETRICW *potm = NULL;
1759 TEXTMETRICW tm, *ptm;
1760 GdiFont font = alloc_font();
1763 if(face->scalable) {
1767 height = face->size.y_ppem >> 6;
1768 width = face->size.x_ppem >> 6;
1771 if (!(font->ft_face = OpenFontFile(font, face->file, face->face_index, width, height)))
1777 font->name = strdupW(face->family->FamilyName);
1779 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
1781 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
1783 potm = HeapAlloc(GetProcessHeap(), 0, size);
1784 WineEngGetOutlineTextMetrics(font, size, potm);
1785 ptm = (TEXTMETRICW*)&potm->otmTextMetrics;
1787 WineEngGetTextMetrics(font, &tm);
1791 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = ptm->tmHeight;
1792 pntm->ntmTm.tmAscent = ptm->tmAscent;
1793 pntm->ntmTm.tmDescent = ptm->tmDescent;
1794 pntm->ntmTm.tmInternalLeading = ptm->tmInternalLeading;
1795 pntm->ntmTm.tmExternalLeading = ptm->tmExternalLeading;
1796 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = ptm->tmAveCharWidth;
1797 pntm->ntmTm.tmMaxCharWidth = ptm->tmMaxCharWidth;
1798 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = ptm->tmWeight;
1799 pntm->ntmTm.tmOverhang = ptm->tmOverhang;
1800 pntm->ntmTm.tmDigitizedAspectX = ptm->tmDigitizedAspectX;
1801 pntm->ntmTm.tmDigitizedAspectY = ptm->tmDigitizedAspectY;
1802 pntm->ntmTm.tmFirstChar = ptm->tmFirstChar;
1803 pntm->ntmTm.tmLastChar = ptm->tmLastChar;
1804 pntm->ntmTm.tmDefaultChar = ptm->tmDefaultChar;
1805 pntm->ntmTm.tmBreakChar = ptm->tmBreakChar;
1806 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = ptm->tmItalic;
1807 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = ptm->tmUnderlined;
1808 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = ptm->tmStruckOut;
1809 pntm->ntmTm.tmPitchAndFamily = ptm->tmPitchAndFamily;
1810 pelf->elfLogFont.lfPitchAndFamily = (ptm->tmPitchAndFamily & 0xf1) + 1;
1811 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = ptm->tmCharSet;
1812 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
1813 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
1814 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
1816 *ptype = ptm->tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
1817 if(!(ptm->tmPitchAndFamily & TMPF_VECTOR))
1818 *ptype |= RASTER_FONTTYPE;
1821 pntm->ntmTm.ntmFlags = ptm->tmItalic ? NTM_ITALIC : 0;
1822 if(ptm->tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
1823 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
1825 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
1826 pntm->ntmTm.ntmCellHeight = 0;
1827 pntm->ntmTm.ntmAvgWidth = 0;
1829 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
1831 strncpyW(pelf->elfLogFont.lfFaceName,
1832 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
1834 strncpyW(pelf->elfFullName,
1835 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
1837 strncpyW(pelf->elfStyle,
1838 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
1842 strncpyW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
1843 strncpyW(pelf->elfFullName, face->family->FamilyName, LF_FACESIZE);
1844 pelf->elfStyle[0] = '\0';
1847 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
1849 HeapFree(GetProcessHeap(), 0, potm);
1854 /*************************************************************
1858 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
1863 NEWTEXTMETRICEXW ntm;
1864 DWORD type, ret = 1;
1870 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
1872 if(plf->lfFaceName[0]) {
1874 for(psub = substlist; psub; psub = psub->next)
1875 if(!strcmpiW(plf->lfFaceName, psub->from.name) &&
1876 (psub->from.charset == -1 ||
1877 psub->from.charset == plf->lfCharSet))
1880 TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
1881 debugstr_w(psub->to.name));
1882 memcpy(&lf, plf, sizeof(lf));
1883 strcpyW(lf.lfFaceName, psub->to.name);
1886 for(family = FontList; family; family = family->next) {
1887 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
1888 for(face = family->FirstFace; face; face = face->next) {
1889 GetEnumStructs(face, &elf, &ntm, &type);
1890 for(i = 0; i < 32; i++) {
1891 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
1892 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
1893 strcpyW(elf.elfScript, OEM_DOSW);
1894 i = 32; /* break out of loop */
1895 } else if(!(face->fs.fsCsb[0] & (1L << i)))
1898 fs.fsCsb[0] = 1L << i;
1900 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
1902 csi.ciCharset = DEFAULT_CHARSET;
1903 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
1904 if(csi.ciCharset != DEFAULT_CHARSET) {
1905 elf.elfLogFont.lfCharSet =
1906 ntm.ntmTm.tmCharSet = csi.ciCharset;
1908 strcpyW(elf.elfScript, ElfScriptsW[i]);
1910 FIXME("Unknown elfscript for bit %d\n", i);
1913 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
1914 debugstr_w(elf.elfLogFont.lfFaceName),
1915 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
1916 csi.ciCharset, type, debugstr_w(elf.elfScript),
1917 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
1918 ntm.ntmTm.ntmFlags);
1919 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
1926 for(family = FontList; family; family = family->next) {
1927 GetEnumStructs(family->FirstFace, &elf, &ntm, &type);
1928 for(i = 0; i < 32; i++) {
1929 if(!family->FirstFace->scalable && family->FirstFace->fs.fsCsb[0] == 0) { /* OEM bitmap */
1930 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
1931 strcpyW(elf.elfScript, OEM_DOSW);
1932 i = 32; /* break out of loop */
1933 } else if(!(family->FirstFace->fs.fsCsb[0] & (1L << i)))
1936 fs.fsCsb[0] = 1L << i;
1938 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
1940 csi.ciCharset = DEFAULT_CHARSET;
1941 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
1942 if(csi.ciCharset != DEFAULT_CHARSET) {
1943 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
1946 strcpyW(elf.elfScript, ElfScriptsW[i]);
1948 FIXME("Unknown elfscript for bit %d\n", i);
1951 TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
1952 debugstr_w(elf.elfLogFont.lfFaceName),
1953 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
1954 csi.ciCharset, type, debugstr_w(elf.elfScript),
1955 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
1956 ntm.ntmTm.ntmFlags);
1957 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
1966 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
1968 pt->x.value = vec->x >> 6;
1969 pt->x.fract = (vec->x & 0x3f) << 10;
1970 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
1971 pt->y.value = vec->y >> 6;
1972 pt->y.fract = (vec->y & 0x3f) << 10;
1973 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
1977 static FT_UInt get_glyph_index(GdiFont font, UINT glyph)
1979 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
1980 glyph = glyph + 0xf000;
1981 return pFT_Get_Char_Index(font->ft_face, glyph);
1984 /*************************************************************
1985 * WineEngGetGlyphIndices
1987 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
1989 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
1990 LPWORD pgi, DWORD flags)
1994 for(i = 0; i < count; i++)
1995 pgi[i] = get_glyph_index(font, lpstr[i]);
2000 /*************************************************************
2001 * WineEngGetGlyphOutline
2003 * Behaves in exactly the same way as the win32 api GetGlyphOutline
2004 * except that the first parameter is the HWINEENGFONT of the font in
2005 * question rather than an HDC.
2008 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
2009 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
2012 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
2013 FT_Face ft_face = font->ft_face;
2014 FT_UInt glyph_index;
2015 DWORD width, height, pitch, needed = 0;
2016 FT_Bitmap ft_bitmap;
2018 INT left, right, top = 0, bottom = 0;
2020 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
2021 float widthRatio = 1.0;
2022 FT_Matrix transMat = identityMat;
2023 BOOL needsTransform = FALSE;
2026 TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font, glyph, format, lpgm,
2027 buflen, buf, lpmat);
2029 if(format & GGO_GLYPH_INDEX) {
2030 glyph_index = glyph;
2031 format &= ~GGO_GLYPH_INDEX;
2033 glyph_index = get_glyph_index(font, glyph);
2035 if(glyph_index >= font->gmsize) {
2036 font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
2037 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
2038 font->gmsize * sizeof(*font->gm));
2040 if(format == GGO_METRICS && font->gm[glyph_index].init) {
2041 memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
2042 return 1; /* FIXME */
2046 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP) || font->aveWidth || lpmat)
2047 load_flags |= FT_LOAD_NO_BITMAP;
2049 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
2052 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
2056 /* Scaling factor */
2057 if (font->aveWidth && font->potm) {
2058 widthRatio = (float)font->aveWidth * font->xform.eM11 / (float) font->potm->otmTextMetrics.tmAveCharWidth;
2061 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
2062 right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
2064 font->gm[glyph_index].adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
2065 font->gm[glyph_index].lsb = left >> 6;
2066 font->gm[glyph_index].bbx = (right - left) >> 6;
2068 /* Scaling transform */
2069 if(font->aveWidth) {
2071 scaleMat.xx = FT_FixedFromFloat(widthRatio);
2074 scaleMat.yy = (1 << 16);
2076 pFT_Matrix_Multiply(&scaleMat, &transMat);
2077 needsTransform = TRUE;
2080 /* Rotation transform */
2081 if(font->orientation) {
2082 FT_Matrix rotationMat;
2084 angle = FT_FixedFromFloat((float)font->orientation / 10.0);
2085 pFT_Vector_Unit(&vecAngle, angle);
2086 rotationMat.xx = vecAngle.x;
2087 rotationMat.xy = -vecAngle.y;
2088 rotationMat.yx = -rotationMat.xy;
2089 rotationMat.yy = rotationMat.xx;
2091 pFT_Matrix_Multiply(&rotationMat, &transMat);
2092 needsTransform = TRUE;
2095 /* Extra transformation specified by caller */
2098 extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
2099 extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
2100 extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
2101 extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
2102 pFT_Matrix_Multiply(&extraMat, &transMat);
2103 needsTransform = TRUE;
2106 if(!needsTransform) {
2107 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
2108 bottom = (ft_face->glyph->metrics.horiBearingY -
2109 ft_face->glyph->metrics.height) & -64;
2110 lpgm->gmCellIncX = font->gm[glyph_index].adv;
2111 lpgm->gmCellIncY = 0;
2115 for(xc = 0; xc < 2; xc++) {
2116 for(yc = 0; yc < 2; yc++) {
2117 vec.x = (ft_face->glyph->metrics.horiBearingX +
2118 xc * ft_face->glyph->metrics.width);
2119 vec.y = ft_face->glyph->metrics.horiBearingY -
2120 yc * ft_face->glyph->metrics.height;
2121 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
2122 pFT_Vector_Transform(&vec, &transMat);
2123 if(xc == 0 && yc == 0) {
2124 left = right = vec.x;
2125 top = bottom = vec.y;
2127 if(vec.x < left) left = vec.x;
2128 else if(vec.x > right) right = vec.x;
2129 if(vec.y < bottom) bottom = vec.y;
2130 else if(vec.y > top) top = vec.y;
2135 right = (right + 63) & -64;
2136 bottom = bottom & -64;
2137 top = (top + 63) & -64;
2139 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
2140 vec.x = ft_face->glyph->metrics.horiAdvance;
2142 pFT_Vector_Transform(&vec, &transMat);
2143 lpgm->gmCellIncX = (vec.x+63) >> 6;
2144 lpgm->gmCellIncY = -((vec.y+63) >> 6);
2146 lpgm->gmBlackBoxX = (right - left) >> 6;
2147 lpgm->gmBlackBoxY = (top - bottom) >> 6;
2148 lpgm->gmptGlyphOrigin.x = left >> 6;
2149 lpgm->gmptGlyphOrigin.y = top >> 6;
2151 memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
2152 font->gm[glyph_index].init = TRUE;
2154 if(format == GGO_METRICS)
2155 return 1; /* FIXME */
2157 if (buf && !buflen){
2161 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP) {
2162 TRACE("loaded a bitmap\n");
2168 width = lpgm->gmBlackBoxX;
2169 height = lpgm->gmBlackBoxY;
2170 pitch = ((width + 31) >> 5) << 2;
2171 needed = pitch * height;
2173 if(!buf || !buflen) break;
2175 switch(ft_face->glyph->format) {
2176 case ft_glyph_format_bitmap:
2178 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
2179 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
2180 INT h = ft_face->glyph->bitmap.rows;
2182 memcpy(dst, src, w);
2183 src += ft_face->glyph->bitmap.pitch;
2189 case ft_glyph_format_outline:
2190 ft_bitmap.width = width;
2191 ft_bitmap.rows = height;
2192 ft_bitmap.pitch = pitch;
2193 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
2194 ft_bitmap.buffer = buf;
2196 if(needsTransform) {
2197 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
2200 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
2202 /* Note: FreeType will only set 'black' bits for us. */
2203 memset(buf, 0, needed);
2204 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
2208 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
2213 case GGO_GRAY2_BITMAP:
2214 case GGO_GRAY4_BITMAP:
2215 case GGO_GRAY8_BITMAP:
2216 case WINE_GGO_GRAY16_BITMAP:
2221 width = lpgm->gmBlackBoxX;
2222 height = lpgm->gmBlackBoxY;
2223 pitch = (width + 3) / 4 * 4;
2224 needed = pitch * height;
2226 if(!buf || !buflen) break;
2227 ft_bitmap.width = width;
2228 ft_bitmap.rows = height;
2229 ft_bitmap.pitch = pitch;
2230 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
2231 ft_bitmap.buffer = buf;
2233 if(needsTransform) {
2234 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
2237 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
2239 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
2241 if(format == GGO_GRAY2_BITMAP)
2243 else if(format == GGO_GRAY4_BITMAP)
2245 else if(format == GGO_GRAY8_BITMAP)
2247 else if(format == WINE_GGO_GRAY16_BITMAP)
2255 for(row = 0; row < height; row++) {
2257 for(col = 0; col < width; col++, ptr++) {
2258 *ptr = (*(unsigned int*)ptr * mult + 128) / 256;
2267 int contour, point = 0, first_pt;
2268 FT_Outline *outline = &ft_face->glyph->outline;
2269 TTPOLYGONHEADER *pph;
2271 DWORD pph_start, cpfx, type;
2273 if(buflen == 0) buf = NULL;
2275 if (needsTransform && buf) {
2276 pFT_Outline_Transform(outline, &transMat);
2279 for(contour = 0; contour < outline->n_contours; contour++) {
2281 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
2284 pph->dwType = TT_POLYGON_TYPE;
2285 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2287 needed += sizeof(*pph);
2289 while(point <= outline->contours[contour]) {
2290 ppc = (TTPOLYCURVE *)((char *)buf + needed);
2291 type = (outline->tags[point] & FT_Curve_Tag_On) ?
2292 TT_PRIM_LINE : TT_PRIM_QSPLINE;
2296 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2299 } while(point <= outline->contours[contour] &&
2300 (outline->tags[point] & FT_Curve_Tag_On) ==
2301 (outline->tags[point-1] & FT_Curve_Tag_On));
2302 /* At the end of a contour Windows adds the start point, but
2304 if(point > outline->contours[contour] &&
2305 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
2307 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
2309 } else if(point <= outline->contours[contour] &&
2310 outline->tags[point] & FT_Curve_Tag_On) {
2311 /* add closing pt for bezier */
2313 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2321 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2324 pph->cb = needed - pph_start;
2330 /* Convert the quadratic Beziers to cubic Beziers.
2331 The parametric eqn for a cubic Bezier is, from PLRM:
2332 r(t) = at^3 + bt^2 + ct + r0
2333 with the control points:
2338 A quadratic Beizer has the form:
2339 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
2341 So equating powers of t leads to:
2342 r1 = 2/3 p1 + 1/3 p0
2343 r2 = 2/3 p1 + 1/3 p2
2344 and of course r0 = p0, r3 = p2
2347 int contour, point = 0, first_pt;
2348 FT_Outline *outline = &ft_face->glyph->outline;
2349 TTPOLYGONHEADER *pph;
2351 DWORD pph_start, cpfx, type;
2352 FT_Vector cubic_control[4];
2353 if(buflen == 0) buf = NULL;
2355 if (needsTransform && buf) {
2356 pFT_Outline_Transform(outline, &transMat);
2359 for(contour = 0; contour < outline->n_contours; contour++) {
2361 pph = (TTPOLYGONHEADER *)((char *)buf + needed);
2364 pph->dwType = TT_POLYGON_TYPE;
2365 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2367 needed += sizeof(*pph);
2369 while(point <= outline->contours[contour]) {
2370 ppc = (TTPOLYCURVE *)((char *)buf + needed);
2371 type = (outline->tags[point] & FT_Curve_Tag_On) ?
2372 TT_PRIM_LINE : TT_PRIM_CSPLINE;
2375 if(type == TT_PRIM_LINE) {
2377 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2381 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
2384 /* FIXME: Possible optimization in endpoint calculation
2385 if there are two consecutive curves */
2386 cubic_control[0] = outline->points[point-1];
2387 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
2388 cubic_control[0].x += outline->points[point].x + 1;
2389 cubic_control[0].y += outline->points[point].y + 1;
2390 cubic_control[0].x >>= 1;
2391 cubic_control[0].y >>= 1;
2393 if(point+1 > outline->contours[contour])
2394 cubic_control[3] = outline->points[first_pt];
2396 cubic_control[3] = outline->points[point+1];
2397 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
2398 cubic_control[3].x += outline->points[point].x + 1;
2399 cubic_control[3].y += outline->points[point].y + 1;
2400 cubic_control[3].x >>= 1;
2401 cubic_control[3].y >>= 1;
2404 /* r1 = 1/3 p0 + 2/3 p1
2405 r2 = 1/3 p2 + 2/3 p1 */
2406 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
2407 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
2408 cubic_control[2] = cubic_control[1];
2409 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
2410 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
2411 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
2412 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
2414 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
2415 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
2416 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
2421 } while(point <= outline->contours[contour] &&
2422 (outline->tags[point] & FT_Curve_Tag_On) ==
2423 (outline->tags[point-1] & FT_Curve_Tag_On));
2424 /* At the end of a contour Windows adds the start point,
2425 but only for Beziers and we've already done that.
2427 if(point <= outline->contours[contour] &&
2428 outline->tags[point] & FT_Curve_Tag_On) {
2429 /* This is the closing pt of a bezier, but we've already
2430 added it, so just inc point and carry on */
2437 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2440 pph->cb = needed - pph_start;
2446 FIXME("Unsupported format %d\n", format);
2452 static BOOL get_bitmap_text_metrics(GdiFont font)
2454 FT_Face ft_face = font->ft_face;
2455 #ifdef HAVE_FREETYPE_FTWINFNT_H
2456 FT_WinFNT_HeaderRec winfnt_header;
2458 const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller);
2459 font->potm = HeapAlloc(GetProcessHeap(), 0, size);
2460 font->potm->otmSize = size;
2462 #define TM font->potm->otmTextMetrics
2463 #ifdef HAVE_FREETYPE_FTWINFNT_H
2464 if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
2466 TM.tmHeight = winfnt_header.pixel_height;
2467 TM.tmAscent = winfnt_header.ascent;
2468 TM.tmDescent = TM.tmHeight - TM.tmAscent;
2469 TM.tmInternalLeading = winfnt_header.internal_leading;
2470 TM.tmExternalLeading = winfnt_header.external_leading;
2471 TM.tmAveCharWidth = winfnt_header.avg_width;
2472 TM.tmMaxCharWidth = winfnt_header.max_width;
2473 TM.tmWeight = winfnt_header.weight;
2475 TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
2476 TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
2477 TM.tmFirstChar = winfnt_header.first_char;
2478 TM.tmLastChar = winfnt_header.last_char;
2479 TM.tmDefaultChar = winfnt_header.default_char;
2480 TM.tmBreakChar = winfnt_header.break_char;
2481 TM.tmItalic = winfnt_header.italic;
2482 TM.tmUnderlined = winfnt_header.underline;
2483 TM.tmStruckOut = winfnt_header.strike_out;
2484 TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
2485 TM.tmCharSet = winfnt_header.charset;
2490 TM.tmAscent = ft_face->size->metrics.ascender >> 6;
2491 TM.tmDescent = -ft_face->size->metrics.descender >> 6;
2492 TM.tmHeight = TM.tmAscent + TM.tmDescent;
2493 TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
2494 TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
2495 TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
2496 TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
2497 TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
2499 TM.tmDigitizedAspectX = 96; /* FIXME */
2500 TM.tmDigitizedAspectY = 96; /* FIXME */
2502 TM.tmLastChar = 255;
2503 TM.tmDefaultChar = 32;
2504 TM.tmBreakChar = 32;
2505 TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
2506 TM.tmUnderlined = 0;
2508 /* NB inverted meaning of TMPF_FIXED_PITCH */
2509 TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
2510 TM.tmCharSet = font->charset;
2517 /*************************************************************
2518 * WineEngGetTextMetrics
2521 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
2524 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
2525 if(!get_bitmap_text_metrics(font))
2528 if(!font->potm) return FALSE;
2529 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
2531 if (font->aveWidth) {
2532 ptm->tmAveCharWidth = font->aveWidth * font->xform.eM11;
2538 /*************************************************************
2539 * WineEngGetOutlineTextMetrics
2542 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
2543 OUTLINETEXTMETRICW *potm)
2545 FT_Face ft_face = font->ft_face;
2546 UINT needed, lenfam, lensty, ret;
2548 TT_HoriHeader *pHori;
2549 TT_Postscript *pPost;
2550 FT_Fixed x_scale, y_scale;
2551 WCHAR *family_nameW, *style_nameW;
2552 static const WCHAR spaceW[] = {' ', '\0'};
2554 INT ascent, descent;
2556 TRACE("font=%p\n", font);
2558 if(!FT_IS_SCALABLE(ft_face))
2562 if(cbSize >= font->potm->otmSize)
2563 memcpy(potm, font->potm, font->potm->otmSize);
2564 return font->potm->otmSize;
2568 needed = sizeof(*potm);
2570 lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
2571 family_nameW = strdupW(font->name);
2573 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
2575 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
2576 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
2577 style_nameW, lensty);
2579 /* These names should be read from the TT name table */
2581 /* length of otmpFamilyName */
2584 /* length of otmpFaceName */
2585 if(!strcasecmp(ft_face->style_name, "regular")) {
2586 needed += lenfam; /* just the family name */
2588 needed += lenfam + lensty; /* family + " " + style */
2591 /* length of otmpStyleName */
2594 /* length of otmpFullName */
2595 needed += lenfam + lensty;
2598 x_scale = ft_face->size->metrics.x_scale;
2599 y_scale = ft_face->size->metrics.y_scale;
2601 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2603 FIXME("Can't find OS/2 table - not TT font?\n");
2608 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2610 FIXME("Can't find HHEA table - not TT font?\n");
2615 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
2617 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",
2618 pOS2->usWinAscent, pOS2->usWinDescent,
2619 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
2620 ft_face->ascender, ft_face->descender, ft_face->height,
2621 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
2622 ft_face->bbox.yMax, ft_face->bbox.yMin);
2624 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
2625 font->potm->otmSize = needed;
2627 #define TM font->potm->otmTextMetrics
2629 if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
2630 ascent = pHori->Ascender;
2631 descent = -pHori->Descender;
2633 ascent = pOS2->usWinAscent;
2634 descent = pOS2->usWinDescent;
2638 TM.tmAscent = font->yMax;
2639 TM.tmDescent = -font->yMin;
2640 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
2642 TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
2643 TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
2644 TM.tmInternalLeading = (pFT_MulFix(ascent + descent
2645 - ft_face->units_per_EM, y_scale) + 32) >> 6;
2648 TM.tmHeight = TM.tmAscent + TM.tmDescent;
2651 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
2653 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
2654 ((ascent + descent) -
2655 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
2657 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
2658 if (TM.tmAveCharWidth == 0) {
2659 TM.tmAveCharWidth = 1;
2661 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
2662 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
2664 TM.tmDigitizedAspectX = 300;
2665 TM.tmDigitizedAspectY = 300;
2666 TM.tmFirstChar = pOS2->usFirstCharIndex;
2667 TM.tmLastChar = pOS2->usLastCharIndex;
2668 TM.tmDefaultChar = pOS2->usDefaultChar;
2669 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
2670 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
2671 TM.tmUnderlined = 0; /* entry in OS2 table */
2672 TM.tmStruckOut = 0; /* entry in OS2 table */
2674 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
2675 if(!FT_IS_FIXED_WIDTH(ft_face))
2676 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
2678 TM.tmPitchAndFamily = 0;
2680 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
2681 case PAN_FAMILY_SCRIPT:
2682 TM.tmPitchAndFamily |= FF_SCRIPT;
2684 case PAN_FAMILY_DECORATIVE:
2685 case PAN_FAMILY_PICTORIAL:
2686 TM.tmPitchAndFamily |= FF_DECORATIVE;
2688 case PAN_FAMILY_TEXT_DISPLAY:
2689 if(TM.tmPitchAndFamily == 0) /* fixed */
2690 TM.tmPitchAndFamily = FF_MODERN;
2692 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
2693 case PAN_SERIF_NORMAL_SANS:
2694 case PAN_SERIF_OBTUSE_SANS:
2695 case PAN_SERIF_PERP_SANS:
2696 TM.tmPitchAndFamily |= FF_SWISS;
2699 TM.tmPitchAndFamily |= FF_ROMAN;
2704 TM.tmPitchAndFamily |= FF_DONTCARE;
2707 if(FT_IS_SCALABLE(ft_face))
2708 TM.tmPitchAndFamily |= TMPF_VECTOR;
2709 if(FT_IS_SFNT(ft_face))
2710 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
2712 TM.tmCharSet = font->charset;
2715 font->potm->otmFiller = 0;
2716 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
2717 font->potm->otmfsSelection = pOS2->fsSelection;
2718 font->potm->otmfsType = pOS2->fsType;
2719 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
2720 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
2721 font->potm->otmItalicAngle = 0; /* POST table */
2722 font->potm->otmEMSquare = ft_face->units_per_EM;
2723 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
2724 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
2725 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
2726 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
2727 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
2728 font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
2729 font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
2730 font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
2731 font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
2732 font->potm->otmMacAscent = 0; /* where do these come from ? */
2733 font->potm->otmMacDescent = 0;
2734 font->potm->otmMacLineGap = 0;
2735 font->potm->otmusMinimumPPEM = 0; /* TT Header */
2736 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
2737 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
2738 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
2739 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
2740 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
2741 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
2742 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
2743 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
2744 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
2745 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
2747 font->potm->otmsUnderscoreSize = 0;
2748 font->potm->otmsUnderscorePosition = 0;
2750 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
2751 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
2754 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
2755 cp = (char*)font->potm + sizeof(*font->potm);
2756 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
2757 strcpyW((WCHAR*)cp, family_nameW);
2759 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
2760 strcpyW((WCHAR*)cp, style_nameW);
2762 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
2763 strcpyW((WCHAR*)cp, family_nameW);
2764 if(strcasecmp(ft_face->style_name, "regular")) {
2765 strcatW((WCHAR*)cp, spaceW);
2766 strcatW((WCHAR*)cp, style_nameW);
2767 cp += lenfam + lensty;
2770 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
2771 strcpyW((WCHAR*)cp, family_nameW);
2772 strcatW((WCHAR*)cp, spaceW);
2773 strcatW((WCHAR*)cp, style_nameW);
2776 if(potm && needed <= cbSize)
2777 memcpy(potm, font->potm, font->potm->otmSize);
2780 HeapFree(GetProcessHeap(), 0, style_nameW);
2781 HeapFree(GetProcessHeap(), 0, family_nameW);
2787 /*************************************************************
2788 * WineEngGetCharWidth
2791 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
2796 FT_UInt glyph_index;
2798 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
2800 for(c = firstChar; c <= lastChar; c++) {
2801 glyph_index = get_glyph_index(font, c);
2802 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
2803 &gm, 0, NULL, NULL);
2804 buffer[c - firstChar] = font->gm[glyph_index].adv;
2809 /*************************************************************
2810 * WineEngGetCharABCWidths
2813 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
2818 FT_UInt glyph_index;
2820 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
2822 for(c = firstChar; c <= lastChar; c++) {
2823 glyph_index = get_glyph_index(font, c);
2824 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
2825 &gm, 0, NULL, NULL);
2826 buffer[c - firstChar].abcA = font->gm[glyph_index].lsb;
2827 buffer[c - firstChar].abcB = font->gm[glyph_index].bbx;
2828 buffer[c - firstChar].abcC = font->gm[glyph_index].adv - font->gm[glyph_index].lsb -
2829 font->gm[glyph_index].bbx;
2834 /*************************************************************
2835 * WineEngGetTextExtentPoint
2838 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
2844 FT_UInt glyph_index;
2846 TRACE("%p, %s, %d, %p\n", font, debugstr_wn(wstr, count), count,
2850 WineEngGetTextMetrics(font, &tm);
2851 size->cy = tm.tmHeight;
2853 for(idx = 0; idx < count; idx++) {
2854 glyph_index = get_glyph_index(font, wstr[idx]);
2855 WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
2856 &gm, 0, NULL, NULL);
2857 size->cx += font->gm[glyph_index].adv;
2859 TRACE("return %ld,%ld\n", size->cx, size->cy);
2863 /*************************************************************
2864 * WineEngGetTextExtentPointI
2867 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
2874 TRACE("%p, %p, %d, %p\n", font, indices, count, size);
2877 WineEngGetTextMetrics(font, &tm);
2878 size->cy = tm.tmHeight;
2880 for(idx = 0; idx < count; idx++) {
2881 WineEngGetGlyphOutline(font, indices[idx],
2882 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
2884 size->cx += font->gm[indices[idx]].adv;
2886 TRACE("return %ld,%ld\n", size->cx, size->cy);
2890 /*************************************************************
2891 * WineEngGetFontData
2894 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
2897 FT_Face ft_face = font->ft_face;
2901 TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
2902 font, table, offset, buf, cbData);
2904 if(!FT_IS_SFNT(ft_face))
2912 if(table) { /* MS tags differ in endidness from FT ones */
2913 table = table >> 24 | table << 24 |
2914 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
2917 /* If the FT_Load_Sfnt_Table function is there we'll use it */
2918 if(pFT_Load_Sfnt_Table)
2919 err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
2920 else { /* Do it the hard way */
2921 TT_Face tt_face = (TT_Face) ft_face;
2922 SFNT_Interface *sfnt;
2923 if (FT_Version.major==2 && FT_Version.minor==0)
2926 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
2930 /* A field was added in the middle of the structure in 2.1.x */
2931 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
2933 err = sfnt->load_any(tt_face, table, offset, buf, &len);
2936 TRACE("Can't find table %08lx.\n", table);
2942 /*************************************************************
2943 * WineEngGetTextFace
2946 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
2949 lstrcpynW(str, font->name, count);
2950 return strlenW(font->name);
2952 return strlenW(font->name) + 1;
2955 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
2957 if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
2958 return font->charset;
2961 #else /* HAVE_FREETYPE */
2963 BOOL WineEngInit(void)
2967 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
2971 BOOL WineEngDestroyFontInstance(HFONT hfont)
2976 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
2981 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
2982 LPWORD pgi, DWORD flags)
2987 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
2988 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
2991 ERR("called but we don't have FreeType\n");
2995 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
2997 ERR("called but we don't have FreeType\n");
3001 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
3002 OUTLINETEXTMETRICW *potm)
3004 ERR("called but we don't have FreeType\n");
3008 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
3011 ERR("called but we don't have FreeType\n");
3015 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
3018 ERR("called but we don't have FreeType\n");
3022 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
3025 ERR("called but we don't have FreeType\n");
3029 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
3032 ERR("called but we don't have FreeType\n");
3036 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
3039 ERR("called but we don't have FreeType\n");
3043 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
3045 ERR("called but we don't have FreeType\n");
3049 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3055 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3061 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
3064 return DEFAULT_CHARSET;
3067 #endif /* HAVE_FREETYPE */