1 /*******************************************************************************
2 * TrueType font-related functions for Wine PostScript driver. Currently just
3 * uses FreeType to read font metrics.
5 * Copyright 2001 Ian Pilcher
13 * These stupid #ifdefs should work for FreeType 2.0.1 and 2.0.2. Beyond that
17 #ifdef HAVE_FREETYPE_FREETYPE_H
18 #include <freetype/freetype.h>
20 #ifdef HAVE_FREETYPE_FTGLYPH_H
21 #include <freetype/ftglyph.h>
23 #ifdef HAVE_FREETYPE_TTTABLES_H
24 #include <freetype/tttables.h>
26 #ifdef HAVE_FREETYPE_FTNAMES_H
27 #include <freetype/ftnames.h>
29 #ifdef HAVE_FREETYPE_FTSNAMES_H
30 #include <freetype/ftsnames.h>
32 #ifdef HAVE_FREETYPE_TTNAMEID_H
33 #include <freetype/ttnameid.h>
36 #include <sys/types.h>
44 #include "debugtools.h"
47 DEFAULT_DEBUG_CHANNEL(psdrv
);
50 #define REQUIRED_FACE_FLAGS ( FT_FACE_FLAG_SCALABLE | \
51 FT_FACE_FLAG_HORIZONTAL | \
53 FT_FACE_FLAG_GLYPH_NAMES )
55 static FT_Library library
;
57 static FT_CharMap charmap
;
58 static TT_Header
*head
;
59 static TT_Postscript
*post
;
61 static TT_HoriHeader
*hhea
;
63 /*******************************************************************************
67 * Sets charmap and points afm->EncodingScheme to encoding name (in driver
68 * heap). Leaves both uninitialized if font contains no Windows encoding.
70 * Returns FALSE to indicate memory allocation error.
73 static const char *encoding_names
[7] =
75 "WindowsSymbol", /* TT_MS_ID_SYMBOL_CS */
76 "WindowsUnicode", /* TT_MS_ID_UNICODE_CS */
77 "WindowsShiftJIS", /* TT_MS_ID_SJIS */
78 "WindowsPRC", /* TT_MS_ID_GB2312 */
79 "WindowsBig5", /* TT_MS_ID_BIG_5 */
80 "WindowsWansung", /* TT_MS_ID_WANSUNG */
81 "WindowsJohab" /* TT_MS_ID_JOHAB */
84 static BOOL
FindCharMap(AFM
*afm
)
91 for (i
= 0; i
< face
->num_charmaps
; ++i
)
93 if (face
->charmaps
[i
]->platform_id
!= TT_PLATFORM_MICROSOFT
)
96 if (face
->charmaps
[i
]->encoding_id
== TT_MS_ID_UNICODE_CS
)
98 charmap
= face
->charmaps
[i
];
103 charmap
= face
->charmaps
[i
];
109 error
= FT_Set_Charmap(face
, charmap
);
110 if (error
!= FT_Err_Ok
)
112 ERR("%s returned %i\n", "FT_Set_CharMap", error
);
116 if (charmap
->encoding_id
< 7)
118 afm
->EncodingScheme
= HEAP_strdupA(PSDRV_Heap
, 0,
119 encoding_names
[charmap
->encoding_id
]);
120 if (afm
->EncodingScheme
== NULL
)
125 afm
->EncodingScheme
= HeapAlloc(PSDRV_Heap
, 0, /* encoding_id */
126 sizeof("WindowsUnknown65535")); /* is a UShort */
127 if (afm
->EncodingScheme
== NULL
)
130 sprintf(afm
->EncodingScheme
, "%s%u", "WindowsUnknown",
131 charmap
->encoding_id
);
137 /*******************************************************************************
140 * Converts a name table string to a null-terminated character string. The
141 * space for the character string is allocated from the driver heap.
143 * This function handles only platform_id = 3 (TT_PLATFORM_MICROSOFT) -- 16-bit
144 * big-endian strings. It also only handles ASCII character codes (< 128).
146 * This function will set *sz to NULL if it cannot parse the string, but it
147 * will only return FALSE in the event of an unexpected error (memory
148 * allocation failure).
151 static BOOL
NameTableString(LPSTR
*sz
, const FT_SfntName
*name
)
153 FT_UShort i
, len
, *ws
;
156 if (name
->platform_id
!= TT_PLATFORM_MICROSOFT
)
158 ERR("Unsupported encoding %i\n", name
->platform_id
);
159 return FALSE
; /* should never get here */
162 len
= name
->string_len
/ 2;
163 s
= *sz
= HeapAlloc(PSDRV_Heap
, 0, len
+ 1);
166 ws
= (FT_UShort
*)(name
->string
);
168 for (i
= 0; i
< len
; ++i
, ++s
, ++ws
)
172 #ifndef WORDS_BIGENDIAN
173 wc
= (wc
>> 8) | (wc
<< 8);
178 WARN("Non-ASCII character 0x%.4x\n", wc
);
179 HeapFree(PSDRV_Heap
, 0, *sz
);
191 /*******************************************************************************
194 * Reads various font names from the TrueType 'NAME' table. Currently looks
195 * for U.S. English names only,
197 * May leave a pointer uninitialized if the desired string is not present;
198 * returns FALSE only in the event of an unexpected error.
201 static BOOL
ReadNameTable(AFM
*afm
)
203 FT_UInt numStrings
, stringIndex
;
207 numStrings
= FT_Get_Sfnt_Name_Count(face
);
209 for (stringIndex
= 0; stringIndex
< numStrings
; ++stringIndex
)
211 error
= FT_Get_Sfnt_Name(face
, stringIndex
, &name
);
212 if (error
!= FT_Err_Ok
)
214 ERR("%s returned %i\n", "FT_Get_Sfnt_Name", error
);
218 /* FIXME - Handle other languages? */
220 if (name
.language_id
!= TT_MS_LANGID_ENGLISH_UNITED_STATES
||
221 name
.platform_id
!= charmap
->platform_id
||
222 name
.encoding_id
!= charmap
->encoding_id
)
225 switch (name
.name_id
)
227 case TT_NAME_ID_FONT_FAMILY
:
229 if (NameTableString(&(afm
->FamilyName
), &name
) == FALSE
)
233 case TT_NAME_ID_FULL_NAME
:
235 if (NameTableString(&(afm
->FullName
), &name
) == FALSE
)
239 case TT_NAME_ID_PS_NAME
:
241 if (NameTableString(&(afm
->FontName
), &name
) == FALSE
)
250 /*******************************************************************************
253 * Frees an AFM and all subsidiary objects. For this function to work
254 * properly, the AFM must have been allocated with HEAP_ZERO_MEMORY, and the
255 * UNICODEVECTOR and it's associated array of UNICODEGLYPHs must have been
256 * allocated as a single object.
258 static void FreeAFM(AFM
*afm
)
260 if (afm
->FontName
!= NULL
)
261 HeapFree(PSDRV_Heap
, 0, afm
->FontName
);
262 if (afm
->FullName
!= NULL
)
263 HeapFree(PSDRV_Heap
, 0, afm
->FullName
);
264 if (afm
->FamilyName
!= NULL
)
265 HeapFree(PSDRV_Heap
, 0, afm
->FamilyName
);
266 if (afm
->EncodingScheme
!= NULL
)
267 HeapFree(PSDRV_Heap
, 0, afm
->EncodingScheme
);
268 if (afm
->Metrics
!= NULL
)
269 HeapFree(PSDRV_Heap
, 0, afm
->Metrics
);
270 if (afm
->Encoding
!= NULL
)
271 HeapFree(PSDRV_Heap
, 0, afm
->Encoding
);
273 HeapFree(PSDRV_Heap
, 0, afm
);
276 /*******************************************************************************
279 * Convert TrueType font units (relative to font em square) to PostScript
280 * units. This is defined as a macro, so it can handle different TrueType
281 * data types as inputs.
284 #define PSUnits(x) (((float)(x)) * 1000.0 / ((float)(head->Units_Per_EM)))
286 /*******************************************************************************
289 * Reads basic font metrics from the 'head', 'post', and 'OS/2' tables.
290 * Returns FALSE if any table is missing.
293 static BOOL
ReadMetricsTables(AFM
*afm
)
295 head
= FT_Get_Sfnt_Table(face
, ft_sfnt_head
);
296 post
= FT_Get_Sfnt_Table(face
, ft_sfnt_post
);
297 hhea
= FT_Get_Sfnt_Table(face
, ft_sfnt_hhea
);
298 os2
= FT_Get_Sfnt_Table(face
, ft_sfnt_os2
);
300 if (head
== NULL
|| post
== NULL
|| hhea
== NULL
|| os2
== NULL
)
303 if (os2
->version
== 0xffff) /* Old Macintosh font */
306 afm
->Weight
= os2
->usWeightClass
;
307 afm
->ItalicAngle
= ((float)(post
->italicAngle
)) / 65536.0;
308 afm
->IsFixedPitch
= (post
->isFixedPitch
== 0) ? FALSE
: TRUE
;
309 afm
->UnderlinePosition
= PSUnits(post
->underlinePosition
);
310 afm
->UnderlineThickness
= PSUnits(post
->underlineThickness
);
312 afm
->FontBBox
.llx
= PSUnits(head
->xMin
);
313 afm
->FontBBox
.lly
= PSUnits(head
->yMin
);
314 afm
->FontBBox
.urx
= PSUnits(head
->xMax
);
315 afm
->FontBBox
.ury
= PSUnits(head
->yMax
);
317 /* CapHeight & XHeight set by ReadCharMetrics */
319 afm
->Ascender
= PSUnits(os2
->sTypoAscender
);
320 afm
->Descender
= PSUnits(os2
->sTypoDescender
);
321 afm
->FullAscender
= afm
->FontBBox
.ury
; /* get rid of this */
323 afm
->WinMetrics
.usUnitsPerEm
= head
->Units_Per_EM
;
324 afm
->WinMetrics
.sAscender
= hhea
->Ascender
;
325 afm
->WinMetrics
.sDescender
= hhea
->Descender
;
326 afm
->WinMetrics
.sLineGap
= hhea
->Line_Gap
;
327 afm
->WinMetrics
.sTypoAscender
= os2
->sTypoAscender
;
328 afm
->WinMetrics
.sTypoDescender
= os2
->sTypoDescender
;
329 afm
->WinMetrics
.sTypoLineGap
= os2
->sTypoLineGap
;
330 afm
->WinMetrics
.usWinAscent
= os2
->usWinAscent
;
331 afm
->WinMetrics
.usWinDescent
= os2
->usWinDescent
;
336 /*******************************************************************************
339 * Reads metrics for each glyph in a TrueType font. Since FreeAFM will try to
340 * free afm->Metrics and afm->Encoding if they are non-NULL, don't free them
341 * in the event of an error. (FreeAFM depends on the fact that afm->Encoding
342 * and its associated array of UNICODEGLYPHs are allocated as a single object.)
345 static BOOL
ReadCharMetrics(AFM
*afm
)
347 FT_ULong charcode
, index
;
348 UNICODEGLYPH
*glyphs
;
351 * There does not seem to be an easy way to get the number of characters
352 * in an encoding out of a TrueType font.
354 for (charcode
= 0, index
= 0; charcode
< 65536; ++charcode
)
356 if (FT_Get_Char_Index(face
, charcode
) != 0)
360 afm
->NumofMetrics
= index
;
362 afm
->Metrics
= HeapAlloc(PSDRV_Heap
, 0, index
* sizeof(AFMMETRICS
));
363 afm
->Encoding
= HeapAlloc(PSDRV_Heap
, 0, sizeof(UNICODEVECTOR
) +
364 index
* sizeof(UNICODEGLYPH
));
365 if (afm
->Metrics
== NULL
|| afm
->Encoding
== NULL
)
368 glyphs
= (UNICODEGLYPH
*)(afm
->Encoding
+ 1);
369 afm
->Encoding
->size
= index
;
370 afm
->Encoding
->glyphs
= glyphs
;
372 for (charcode
= 0, index
= 0; charcode
<= 65536; ++charcode
)
374 FT_UInt glyph_index
= FT_Get_Char_Index(face
, charcode
);
380 if (glyph_index
== 0)
383 error
= FT_Load_Glyph(face
, glyph_index
, FT_LOAD_NO_SCALE
|
384 FT_LOAD_IGNORE_TRANSFORM
| FT_LOAD_LINEAR_DESIGN
);
385 if (error
!= FT_Err_Ok
)
387 ERR("%s returned %i\n", "FT_Load_Glyph", error
);
391 error
= FT_Get_Glyph(face
->glyph
, &glyph
);
392 if (error
!= FT_Err_Ok
)
394 ERR("%s returned %i\n", "FT_Get_Glyph", error
);
398 FT_Glyph_Get_CBox(glyph
, ft_glyph_bbox_unscaled
, &bbox
);
400 error
= FT_Get_Glyph_Name(face
, glyph_index
, buffer
, 255);
401 if (error
!= FT_Err_Ok
)
403 ERR("%s returned %i\n", "FT_Get_Glyph_Name", error
);
407 afm
->Metrics
[index
].N
= PSDRV_GlyphName(buffer
);
408 if (afm
->Metrics
[index
].N
== NULL
)
411 afm
->Metrics
[index
].C
= charcode
;
412 afm
->Metrics
[index
].UV
= charcode
;
413 afm
->Metrics
[index
].WX
= PSUnits(face
->glyph
->metrics
.horiAdvance
);
414 afm
->Metrics
[index
].B
.llx
= PSUnits(bbox
.xMin
);
415 afm
->Metrics
[index
].B
.lly
= PSUnits(bbox
.yMin
);
416 afm
->Metrics
[index
].B
.urx
= PSUnits(bbox
.xMax
);
417 afm
->Metrics
[index
].B
.ury
= PSUnits(bbox
.yMax
);
418 afm
->Metrics
[index
].L
= NULL
;
420 TRACE("Metrics for '%s' WX = %f B = %f,%f - %f,%f\n",
421 afm
->Metrics
[index
].N
->sz
, afm
->Metrics
[index
].WX
,
422 afm
->Metrics
[index
].B
.llx
, afm
->Metrics
[index
].B
.lly
,
423 afm
->Metrics
[index
].B
.urx
, afm
->Metrics
[index
].B
.ury
);
425 glyphs
[index
].UV
= charcode
;
426 glyphs
[index
].name
= afm
->Metrics
[index
].N
;
428 if (charcode
== 0x0048) /* 'H' */
429 afm
->CapHeight
= PSUnits(bbox
.yMax
);
430 if (charcode
== 0x0078) /* 'x' */
431 afm
->XHeight
= PSUnits(bbox
.yMax
);
439 /*******************************************************************************
442 * Fills in AFM structure for opened TrueType font file. Returns FALSE only on
443 * an unexpected error (memory allocation failure or FreeType error); otherwise
444 * returns TRUE. Leaves it to the caller (ReadTrueTypeFile) to clean up.
447 static BOOL
ReadTrueTypeAFM(AFM
*afm
)
450 if ((face
->face_flags
& REQUIRED_FACE_FLAGS
) != REQUIRED_FACE_FLAGS
)
452 WARN("Font flags do not match requirements\n");
456 if (FindCharMap(afm
) == FALSE
)
461 WARN("No Windows encodings in font\n");
465 TRACE("Using encoding '%s'\n", afm
->EncodingScheme
);
467 if (ReadNameTable(afm
) == FALSE
)
470 if (afm
->FamilyName
== NULL
|| afm
->FullName
== NULL
||
471 afm
->FontName
== NULL
)
473 WARN("Required strings missing from font\n");
477 if (ReadMetricsTables(afm
) == FALSE
) /* Non-fatal */
479 WARN("Required metrics tables missing from font\n");
483 if (ReadCharMetrics(afm
) == FALSE
)
489 /*******************************************************************************
492 * Reads PostScript-style font metrics from a TrueType font file. Only returns
493 * FALSE for unexpected errors (memory allocation, etc.); returns TRUE if it's
494 * just a bad font file.
497 static BOOL
ReadTrueTypeFile(LPCSTR filename
)
502 TRACE("'%s'\n", filename
);
504 afm
= HeapAlloc(PSDRV_Heap
, HEAP_ZERO_MEMORY
, sizeof(AFM
));
508 error
= FT_New_Face(library
, filename
, 0, &face
);
510 if (error
!= FT_Err_Ok
)
512 WARN("FreeType error %i opening '%s'\n", error
, filename
);
513 HeapFree(PSDRV_Heap
, 0, afm
);
517 if (ReadTrueTypeAFM(afm
) == FALSE
)
524 error
= FT_Done_Face(face
);
525 if (error
!= FT_Err_Ok
)
527 ERR("%s returned %i\n", "FT_Done_Face", error
);
532 if (afm
->Encoding
== NULL
) /* last element to be set */
538 if (PSDRV_AddAFMtoList(&PSDRV_AFMFontList
, afm
) == FALSE
)
549 /*******************************************************************************
550 * PSDRV_GetTrueTypeMetrics
552 * Reads PostScript-stype font metrics from TrueType font files in directories
553 * listed in the [TrueType Font Directories] section of the Wine configuration
556 * If this function fails, the driver will fail to initialize and the driver
557 * heap will be destroyed, so it's not necessary to HeapFree everything in
561 BOOL
PSDRV_GetTrueTypeMetrics(void)
563 CHAR keybuf
[256], namebuf
[256];
567 DWORD type
, key_len
, name_len
;
569 error
= FT_Init_FreeType(&library
);
570 if (error
!= FT_Err_Ok
)
572 ERR("%s returned %i\n", "FT_Init_FreeType", error
);
576 if(RegOpenKeyExA(HKEY_LOCAL_MACHINE
, "Software\\Wine\\Wine\\Config\\TrueType Font Directories",
580 key_len
= sizeof(keybuf
);
581 name_len
= sizeof(namebuf
);
582 while(!RegEnumValueA(hkey
, i
++, keybuf
, &key_len
, NULL
, &type
, namebuf
, &name_len
))
586 INT dnlen
; /* directory name length */
588 namebuf
[sizeof(namebuf
) - 1] = '\0';
589 dir
= opendir(namebuf
);
592 WARN("Error opening directory '%s'\n", namebuf
);
596 dnlen
= strlen(namebuf
);
597 namebuf
[dnlen
] = '/'; /* 2 slashes is OK, 0 is not */
600 while ((dent
= readdir(dir
)) != NULL
)
602 INT fnlen
; /* file name length */
604 fnlen
= strlen(dent
->d_name
);
606 if (fnlen
< 5 || strcasecmp(dent
->d_name
+ fnlen
- 4, ".ttf") != 0)
608 TRACE("Skipping filename '%s'\n", dent
->d_name
);
612 if (dnlen
+ fnlen
+ 1 > sizeof(namebuf
)) /* allow for '\0' */
614 WARN("Path '%s/%s' is too long\n", namebuf
, dent
->d_name
);
618 memcpy(namebuf
+ dnlen
, dent
->d_name
, fnlen
+ 1);
620 if (ReadTrueTypeFile(namebuf
) == FALSE
)
622 ERR("Error reading '%s'\n", namebuf
);
625 FT_Done_FreeType(library
);
632 /* initialize lengths for new iteration */
633 key_len
= sizeof(keybuf
);
634 name_len
= sizeof(namebuf
);
639 FT_Done_FreeType(library
);
643 #endif /* HAVE_FREETYPE */