1 /*******************************************************************************
2 * TrueType font-related functions for Wine PostScript driver. Currently just
3 * uses FreeType to read font metrics.
5 * Copyright 2001 Ian Pilcher
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 * NOTE: Many of the functions in this file can return either fatal errors
22 * (memory allocation failure or unexpected FreeType error) or non-fatal
23 * errors (unusable font file). Fatal errors are indicated by returning
24 * FALSE; see individual function descriptions for how they indicate non-
33 * These stupid #ifdefs should work for FreeType 2.0.1 and 2.0.2. Beyond that
37 #ifdef HAVE_FREETYPE_FREETYPE_H
38 #include <freetype/freetype.h>
40 #ifdef HAVE_FREETYPE_FTGLYPH_H
41 #include <freetype/ftglyph.h>
43 #ifdef HAVE_FREETYPE_TTTABLES_H
44 #include <freetype/tttables.h>
46 #ifdef HAVE_FREETYPE_FTSNAMES_H
47 #include <freetype/ftsnames.h>
49 # ifdef HAVE_FREETYPE_FTNAMES_H
50 # include <freetype/ftnames.h>
53 #ifdef HAVE_FREETYPE_TTNAMEID_H
54 #include <freetype/ttnameid.h>
57 #include <sys/types.h>
67 #include "wine/debug.h"
69 WINE_DEFAULT_DEBUG_CHANNEL(psdrv
);
71 #define REQUIRED_FACE_FLAGS ( FT_FACE_FLAG_SCALABLE | \
72 FT_FACE_FLAG_HORIZONTAL | \
74 FT_FACE_FLAG_GLYPH_NAMES )
76 #define GLYPH_LOAD_FLAGS ( FT_LOAD_NO_SCALE | \
77 FT_LOAD_IGNORE_TRANSFORM | \
78 FT_LOAD_LINEAR_DESIGN )
80 /*******************************************************************************
83 * Finds Windows character map and creates "EncodingScheme" string. Returns
84 * FALSE to indicate memory allocation or FreeType error; sets *p_charmap to
85 * NULL if no Windows encoding is present.
87 * Returns Unicode character map if present; otherwise uses the first Windows
88 * character map found.
91 static const LPCSTR encoding_names
[7] =
93 "WindowsSymbol", /* TT_MS_ID_SYMBOL_CS */
94 "WindowsUnicode", /* TT_MS_ID_UNICODE_CS */
95 "WindowsShiftJIS", /* TT_MS_ID_SJIS */
96 "WindowsPRC", /* TT_MS_ID_GB2312 */
97 "WindowsBig5", /* TT_MS_ID_BIG_5 */
98 "WindowsWansung", /* TT_MS_ID_WANSUNG */
99 "WindowsJohab" /* TT_MS_ID_JOHAB */
100 /* "WindowsUnknown65535" is the longest possible (encoding_id is a UShort) */
103 static BOOL
FindCharMap(FT_Face face
, FT_CharMap
*p_charmap
, LPSTR
*p_sz
)
107 FT_CharMap charmap
= NULL
;
109 for (i
= 0; i
< face
->num_charmaps
; ++i
)
111 if (face
->charmaps
[i
]->platform_id
!= TT_PLATFORM_MICROSOFT
)
114 if (face
->charmaps
[i
]->encoding_id
== TT_MS_ID_UNICODE_CS
)
116 charmap
= face
->charmaps
[i
];
121 charmap
= face
->charmaps
[i
];
124 *p_charmap
= charmap
;
128 WARN("No Windows character map found\n");
132 error
= FT_Set_Charmap(face
, charmap
);
133 if (error
!= FT_Err_Ok
)
135 ERR("%s returned %i\n", "FT_Set_Charmap", error
);
139 *p_sz
= HeapAlloc(PSDRV_Heap
, 0, sizeof("WindowsUnknown65535"));
143 if (charmap
->encoding_id
< 7)
144 strcpy(*p_sz
, encoding_names
[charmap
->encoding_id
]);
146 sprintf(*p_sz
, "%s%u", "WindowsUnknown", charmap
->encoding_id
);
151 /*******************************************************************************
154 * Converts a string in the TrueType NAME table to a null-terminated ASCII
155 * character string. Space for the string is allocated from the driver heap.
156 * Only handles platform_id = 3 (TT_PLATFORM_MICROSOFT) strings (16-bit, big
157 * endian). It also only handles ASCII character codes (< 128).
159 * Sets *p_sz to NULL if string cannot be converted; only returns FALSE for
160 * memory allocation failure.
163 static BOOL
MSTTStrToSz(const FT_SfntName
*name
, LPSTR
*p_sz
)
170 len
= name
->string_len
/ 2; /* # of 16-bit chars */
172 *p_sz
= sz
= HeapAlloc(PSDRV_Heap
, 0, len
+ 1);
176 wsz
= (USHORT
*)(name
->string
);
178 for (i
= 0; i
< len
; ++i
, ++sz
, ++wsz
)
182 #ifndef WORDS_BIGENDIAN
183 wc
= (wc
>> 8) | (wc
<< 8);
188 WARN("Non-ASCII character 0x%.4x\n", wc
);
189 HeapFree(PSDRV_Heap
, 0, *p_sz
);
202 /*******************************************************************************
205 * Finds the requested Microsoft platform string in the TrueType NAME table and
206 * converts it to a null-terminated ASCII string. Currently looks for U.S.
207 * English names only.
209 * Sets string to NULL if not present or cannot be converted; returns FALSE
210 * only for memory allocation failure.
213 static BOOL
FindMSTTString(FT_Face face
, FT_CharMap charmap
, FT_UShort name_id
,
216 FT_UInt num_strings
, string_index
;
220 num_strings
= FT_Get_Sfnt_Name_Count(face
);
222 for (string_index
= 0; string_index
< num_strings
; ++string_index
)
224 error
= FT_Get_Sfnt_Name(face
, string_index
, &name
);
225 if (error
!= FT_Err_Ok
)
227 ERR("%s returned %i\n", "FT_Get_Sfnt_Name", error
);
231 /* FIXME - Handle other languages? */
233 if (name
.platform_id
!= TT_PLATFORM_MICROSOFT
||
234 name
.language_id
!= TT_MS_LANGID_ENGLISH_UNITED_STATES
)
237 if (name
.platform_id
!= charmap
->platform_id
||
238 name
.encoding_id
!= charmap
->encoding_id
)
241 if (name
.name_id
!= name_id
)
244 return MSTTStrToSz(&name
, p_sz
);
247 *p_sz
= NULL
; /* didn't find it */
252 /*******************************************************************************
255 * Convert TrueType font units (relative to font em square) to PostScript
259 inline static float PSUnits(LONG x
, USHORT em_size
)
261 return 1000.0 * (float)x
/ (float)em_size
;
264 /*******************************************************************************
267 * Allocates space for the AFM on the driver heap and reads basic font metrics
268 * from the HEAD, POST, HHEA, and OS/2 tables. Returns FALSE for memory
269 * allocation error; sets *p_afm to NULL if required information is missing.
272 static BOOL
StartAFM(FT_Face face
, AFM
**p_afm
)
281 head
= FT_Get_Sfnt_Table(face
, ft_sfnt_head
);
282 post
= FT_Get_Sfnt_Table(face
, ft_sfnt_post
);
283 os2
= FT_Get_Sfnt_Table(face
, ft_sfnt_os2
);
284 hhea
= FT_Get_Sfnt_Table(face
, ft_sfnt_hhea
);
286 if (head
== NULL
|| post
== NULL
|| os2
== NULL
|| hhea
== NULL
||
287 os2
->version
== 0xffff) /* old Macintosh font */
289 WARN("Required table(s) missing\n");
294 *p_afm
= afm
= HeapAlloc(PSDRV_Heap
, 0, sizeof(*afm
));
298 afm
->WinMetrics
.usUnitsPerEm
= em_size
= head
->Units_Per_EM
;
299 afm
->WinMetrics
.sAscender
= hhea
->Ascender
;
300 afm
->WinMetrics
.sDescender
= hhea
->Descender
;
301 afm
->WinMetrics
.sLineGap
= hhea
->Line_Gap
;
302 afm
->WinMetrics
.sTypoAscender
= os2
->sTypoAscender
;
303 afm
->WinMetrics
.sTypoDescender
= os2
->sTypoDescender
;
304 afm
->WinMetrics
.sTypoLineGap
= os2
->sTypoLineGap
;
305 afm
->WinMetrics
.usWinAscent
= os2
->usWinAscent
;
306 afm
->WinMetrics
.usWinDescent
= os2
->usWinDescent
;
307 afm
->WinMetrics
.sAvgCharWidth
= os2
->xAvgCharWidth
;
309 afm
->Weight
= os2
->usWeightClass
;
310 afm
->ItalicAngle
= ((float)(post
->italicAngle
)) / 65536.0;
311 afm
->IsFixedPitch
= (post
-> isFixedPitch
== 0) ? FALSE
: TRUE
;
312 afm
->UnderlinePosition
= PSUnits(post
->underlinePosition
, em_size
);
313 afm
->UnderlineThickness
= PSUnits(post
->underlineThickness
, em_size
);
315 afm
->FontBBox
.llx
= PSUnits(head
->xMin
, em_size
);
316 afm
->FontBBox
.lly
= PSUnits(head
->yMin
, em_size
);
317 afm
->FontBBox
.urx
= PSUnits(head
->xMax
, em_size
);
318 afm
->FontBBox
.ury
= PSUnits(head
->yMax
, em_size
);
320 afm
->Ascender
= PSUnits(os2
->sTypoAscender
, em_size
);
321 afm
->Descender
= PSUnits(os2
->sTypoDescender
, em_size
);
326 /*******************************************************************************
329 * Reads metrics for each glyph in a TrueType font. Returns false for memory
330 * allocation or FreeType error; sets *p_metrics to NULL for non-fatal error.
333 static BOOL
ReadCharMetrics(FT_Face face
, AFM
*afm
, AFMMETRICS
**p_metrics
)
335 FT_ULong charcode
, index
;
337 USHORT em_size
= afm
->WinMetrics
.usUnitsPerEm
;
339 for (charcode
= 0, index
= 0; charcode
< 65536; ++charcode
)
340 if (FT_Get_Char_Index(face
, charcode
) != 0)
341 ++index
; /* count # of glyphs */
343 afm
->NumofMetrics
= index
;
345 *p_metrics
= metrics
= HeapAlloc(PSDRV_Heap
, 0, index
* sizeof(*metrics
));
349 for (charcode
= 0, index
= 0; charcode
< 65536; ++charcode
)
351 FT_UInt glyph_index
= FT_Get_Char_Index(face
, charcode
);
353 CHAR buffer
[128]; /* for glyph names */
355 if (glyph_index
== 0)
358 error
= FT_Load_Glyph(face
, glyph_index
, GLYPH_LOAD_FLAGS
);
359 if (error
!= FT_Err_Ok
)
361 ERR("%s returned %i\n", "FT_Load_Glyph", error
);
365 error
= FT_Get_Glyph_Name(face
, glyph_index
, buffer
, sizeof(buffer
));
366 if (error
!= FT_Err_Ok
)
368 ERR("%s returned %i\n", "FT_Get_Glyph_Name", error
);
372 metrics
[index
].N
= PSDRV_GlyphName(buffer
);
373 if (metrics
[index
].N
== NULL
)
376 metrics
[index
].C
= metrics
[index
].UV
= charcode
;
377 metrics
[index
].WX
= PSUnits(face
->glyph
->metrics
.horiAdvance
, em_size
);
382 if (afm
->WinMetrics
.sAvgCharWidth
== 0)
383 afm
->WinMetrics
.sAvgCharWidth
= PSDRV_CalcAvgCharWidth(afm
);
388 HeapFree(PSDRV_Heap
, 0, metrics
);
393 /*******************************************************************************
396 * Builds the AFM for a TrueType font and adds it to the driver font list.
397 * Returns FALSE only on an unexpected error (memory allocation failure or
401 static BOOL
BuildTrueTypeAFM(FT_Face face
)
405 LPSTR font_name
, full_name
, family_name
, encoding_scheme
;
409 retval
= StartAFM(face
, &afm
);
410 if (retval
== FALSE
|| afm
== NULL
)
413 retval
= FindCharMap(face
, &charmap
, &encoding_scheme
);
414 if (retval
== FALSE
|| charmap
== NULL
)
417 retval
= FindMSTTString(face
, charmap
, TT_NAME_ID_PS_NAME
, &font_name
);
418 if (retval
== FALSE
|| font_name
== NULL
)
419 goto cleanup_encoding_scheme
;
421 retval
= FindMSTTString(face
, charmap
, TT_NAME_ID_FULL_NAME
, &full_name
);
422 if (retval
== FALSE
|| full_name
== NULL
)
423 goto cleanup_font_name
;
425 retval
= FindMSTTString(face
, charmap
, TT_NAME_ID_FONT_FAMILY
,
427 if (retval
== FALSE
|| family_name
== NULL
)
428 goto cleanup_full_name
;
430 retval
= ReadCharMetrics(face
, afm
, &metrics
);
431 if (retval
== FALSE
|| metrics
== NULL
)
432 goto cleanup_family_name
;
434 afm
->EncodingScheme
= encoding_scheme
; afm
->FontName
= font_name
;
435 afm
->FullName
= full_name
; afm
->FamilyName
= family_name
;
436 afm
->Metrics
= metrics
;
438 retval
= PSDRV_AddAFMtoList(&PSDRV_AFMFontList
, afm
, &added
);
439 if (retval
== FALSE
|| added
== FALSE
)
440 goto cleanup_family_name
;
444 /* clean up after fatal or non-fatal errors */
447 HeapFree(PSDRV_Heap
, 0, family_name
);
449 HeapFree(PSDRV_Heap
, 0, full_name
);
451 HeapFree(PSDRV_Heap
, 0, font_name
);
452 cleanup_encoding_scheme
:
453 HeapFree(PSDRV_Heap
, 0, encoding_scheme
);
455 HeapFree(PSDRV_Heap
, 0, afm
);
460 /*******************************************************************************
463 * Reads font metrics from TrueType font file. Only returns FALSE for
464 * unexpected errors (memory allocation failure or FreeType error).
467 static BOOL
ReadTrueTypeFile(FT_Library library
, LPCSTR filename
)
472 TRACE("%s\n", filename
);
474 error
= FT_New_Face(library
, filename
, 0, &face
);
475 if (error
!= FT_Err_Ok
)
477 WARN("FreeType error %i opening %s\n", error
, filename
);
481 if ((face
->face_flags
& REQUIRED_FACE_FLAGS
) == REQUIRED_FACE_FLAGS
)
483 if (BuildTrueTypeAFM(face
) == FALSE
)
491 WARN("Required information missing from %s\n", filename
);
494 error
= FT_Done_Face(face
);
495 if (error
!= FT_Err_Ok
)
497 ERR("%s returned %i\n", "FT_Done_Face", error
);
504 /*******************************************************************************
507 * Reads all TrueType font files in a directory.
510 static BOOL
ReadTrueTypeDir(FT_Library library
, LPCSTR dirname
)
516 dir
= opendir(dirname
);
519 WARN("'%s' opening %s\n", strerror(errno
), dirname
);
523 while ((dent
= readdir(dir
)) != NULL
)
525 CHAR
*file_extension
= strrchr(dent
->d_name
, '.');
528 if (file_extension
== NULL
|| strcasecmp(file_extension
, ".ttf") != 0)
531 fn_len
= snprintf(filename
, 256, "%s/%s", dirname
, dent
->d_name
);
532 if (fn_len
< 0 || fn_len
> sizeof(filename
) - 1)
534 WARN("Path '%s/%s' is too long\n", dirname
, dent
->d_name
);
538 if (ReadTrueTypeFile(library
, filename
) == FALSE
)
550 /*******************************************************************************
551 * PSDRV_GetTrueTypeMetrics
553 * Reads font metrics from TrueType font files in directories listed in the
554 * [TrueType Font Directories] section of the Wine configuration file.
556 * If this function fails (returns FALSE), the driver will fail to initialize
557 * and the driver heap will be destroyed, so it's not necessary to HeapFree
558 * everything in that event.
561 BOOL
PSDRV_GetTrueTypeMetrics(void)
563 CHAR name_buf
[256], value_buf
[256];
568 DWORD type
, name_len
, value_len
;
570 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE
,
571 "Software\\Wine\\Wine\\Config\\TrueType Font Directories",
572 0, KEY_READ
, &hkey
) != ERROR_SUCCESS
)
575 error
= FT_Init_FreeType(&library
);
576 if (error
!= FT_Err_Ok
)
578 ERR("%s returned %i\n", "FT_Init_FreeType", error
);
583 name_len
= sizeof(name_buf
);
584 value_len
= sizeof(value_buf
);
586 while (RegEnumValueA(hkey
, i
++, name_buf
, &name_len
, NULL
, &type
, value_buf
,
587 &value_len
) == ERROR_SUCCESS
)
589 value_buf
[sizeof(value_buf
) - 1] = '\0';
591 if (ReadTrueTypeDir(library
, value_buf
) == FALSE
)
594 FT_Done_FreeType(library
);
598 /* initialize lengths for new iteration */
600 name_len
= sizeof(name_buf
);
601 value_len
= sizeof(value_buf
);
605 FT_Done_FreeType(library
);
609 #endif /* HAVE_FREETYPE */