1 /*******************************************************************************
2 * TrueType font-related functions for Wine PostScript driver. Currently just
3 * uses FreeType to read font metrics.
5 * Copyright 2001 Ian Pilcher
8 * NOTE: Many of the functions in this file can return either fatal errors
9 * (memory allocation failure or unexpected FreeType error) or non-fatal
10 * errors (unusable font file). Fatal errors are indicated by returning
11 * FALSE; see individual function descriptions for how they indicate non-
20 * These stupid #ifdefs should work for FreeType 2.0.1 and 2.0.2. Beyond that
24 #ifdef HAVE_FREETYPE_FREETYPE_H
25 #include <freetype/freetype.h>
27 #ifdef HAVE_FREETYPE_FTGLYPH_H
28 #include <freetype/ftglyph.h>
30 #ifdef HAVE_FREETYPE_TTTABLES_H
31 #include <freetype/tttables.h>
33 #ifdef HAVE_FREETYPE_FTSNAMES_H
34 #include <freetype/ftsnames.h>
36 # ifdef HAVE_FREETYPE_FTNAMES_H
37 # include <freetype/ftnames.h>
40 #ifdef HAVE_FREETYPE_TTNAMEID_H
41 #include <freetype/ttnameid.h>
44 #include <sys/types.h>
54 #include "debugtools.h"
56 DEFAULT_DEBUG_CHANNEL(psdrv);
58 #define REQUIRED_FACE_FLAGS ( FT_FACE_FLAG_SCALABLE | \
59 FT_FACE_FLAG_HORIZONTAL | \
61 FT_FACE_FLAG_GLYPH_NAMES )
63 #define GLYPH_LOAD_FLAGS ( FT_LOAD_NO_SCALE | \
64 FT_LOAD_IGNORE_TRANSFORM | \
65 FT_LOAD_LINEAR_DESIGN )
67 /*******************************************************************************
70 * Finds Windows character map and creates "EncodingScheme" string. Returns
71 * FALSE to indicate memory allocation or FreeType error; sets *p_charmap to
72 * NULL if no Windows encoding is present.
74 * Returns Unicode character map if present; otherwise uses the first Windows
75 * character map found.
78 static const LPCSTR encoding_names[7] =
80 "WindowsSymbol", /* TT_MS_ID_SYMBOL_CS */
81 "WindowsUnicode", /* TT_MS_ID_UNICODE_CS */
82 "WindowsShiftJIS", /* TT_MS_ID_SJIS */
83 "WindowsPRC", /* TT_MS_ID_GB2312 */
84 "WindowsBig5", /* TT_MS_ID_BIG_5 */
85 "WindowsWansung", /* TT_MS_ID_WANSUNG */
86 "WindowsJohab" /* TT_MS_ID_JOHAB */
87 /* "WindowsUnknown65535" is the longest possible (encoding_id is a UShort) */
90 static BOOL FindCharMap(FT_Face face, FT_CharMap *p_charmap, LPSTR *p_sz)
94 FT_CharMap charmap = NULL;
96 for (i = 0; i < face->num_charmaps; ++i)
98 if (face->charmaps[i]->platform_id != TT_PLATFORM_MICROSOFT)
101 if (face->charmaps[i]->encoding_id == TT_MS_ID_UNICODE_CS)
103 charmap = face->charmaps[i];
108 charmap = face->charmaps[i];
111 *p_charmap = charmap;
115 WARN("No Windows character map found\n");
119 error = FT_Set_Charmap(face, charmap);
120 if (error != FT_Err_Ok)
122 ERR("%s returned %i\n", "FT_Set_Charmap", error);
126 *p_sz = HeapAlloc(PSDRV_Heap, 0, sizeof("WindowsUnknown65535"));
130 if (charmap->encoding_id < 7)
131 strcpy(*p_sz, encoding_names[charmap->encoding_id]);
133 sprintf(*p_sz, "%s%u", "WindowsUnknown", charmap->encoding_id);
138 /*******************************************************************************
141 * Converts a string in the TrueType NAME table to a null-terminated ASCII
142 * character string. Space for the string is allocated from the driver heap.
143 * Only handles platform_id = 3 (TT_PLATFORM_MICROSOFT) strings (16-bit, big
144 * endian). It also only handles ASCII character codes (< 128).
146 * Sets *p_sz to NULL if string cannot be converted; only returns FALSE for
147 * memory allocation failure.
150 static BOOL MSTTStrToSz(const FT_SfntName *name, LPSTR *p_sz)
157 len = name->string_len / 2; /* # of 16-bit chars */
159 *p_sz = sz = HeapAlloc(PSDRV_Heap, 0, len + 1);
163 wsz = (USHORT *)(name->string);
165 for (i = 0; i < len; ++i, ++sz, ++wsz)
169 #ifndef WORDS_BIGENDIAN
170 wc = (wc >> 8) | (wc << 8);
175 WARN("Non-ASCII character 0x%.4x\n", wc);
176 HeapFree(PSDRV_Heap, 0, *p_sz);
189 /*******************************************************************************
192 * Finds the requested Microsoft platform string in the TrueType NAME table and
193 * converts it to a null-terminated ASCII string. Currently looks for U.S.
194 * English names only.
196 * Sets string to NULL if not present or cannot be converted; returns FALSE
197 * only for memory allocation failure.
200 static BOOL FindMSTTString(FT_Face face, FT_CharMap charmap, FT_UShort name_id,
203 FT_UInt num_strings, string_index;
207 num_strings = FT_Get_Sfnt_Name_Count(face);
209 for (string_index = 0; string_index < num_strings; ++string_index)
211 error = FT_Get_Sfnt_Name(face, string_index, &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.platform_id != TT_PLATFORM_MICROSOFT ||
221 name.language_id != TT_MS_LANGID_ENGLISH_UNITED_STATES)
224 if (name.platform_id != charmap->platform_id ||
225 name.encoding_id != charmap->encoding_id)
228 if (name.name_id != name_id)
231 return MSTTStrToSz(&name, p_sz);
234 *p_sz = NULL; /* didn't find it */
239 /*******************************************************************************
242 * Convert TrueType font units (relative to font em square) to PostScript
246 inline static float PSUnits(LONG x, USHORT em_size)
248 return 1000.0 * (float)x / (float)em_size;
251 /*******************************************************************************
254 * Allocates space for the AFM on the driver heap and reads basic font metrics
255 * from the HEAD, POST, HHEA, and OS/2 tables. Returns FALSE for memory
256 * allocation error; sets *p_afm to NULL if required information is missing.
259 static BOOL StartAFM(FT_Face face, AFM **p_afm)
268 head = FT_Get_Sfnt_Table(face, ft_sfnt_head);
269 post = FT_Get_Sfnt_Table(face, ft_sfnt_post);
270 os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2);
271 hhea = FT_Get_Sfnt_Table(face, ft_sfnt_hhea);
273 if (head == NULL || post == NULL || os2 == NULL || hhea == NULL ||
274 os2->version == 0xffff) /* old Macintosh font */
276 WARN("Required table(s) missing\n");
281 *p_afm = afm = HeapAlloc(PSDRV_Heap, 0, sizeof(*afm));
285 afm->WinMetrics.usUnitsPerEm = em_size = head->Units_Per_EM;
286 afm->WinMetrics.sAscender = hhea->Ascender;
287 afm->WinMetrics.sDescender = hhea->Descender;
288 afm->WinMetrics.sLineGap = hhea->Line_Gap;
289 afm->WinMetrics.sTypoAscender = os2->sTypoAscender;
290 afm->WinMetrics.sTypoDescender = os2->sTypoDescender;
291 afm->WinMetrics.sTypoLineGap = os2->sTypoLineGap;
292 afm->WinMetrics.usWinAscent = os2->usWinAscent;
293 afm->WinMetrics.usWinDescent = os2->usWinDescent;
294 afm->WinMetrics.sAvgCharWidth = os2->xAvgCharWidth;
296 afm->Weight = os2->usWeightClass;
297 afm->ItalicAngle = ((float)(post->italicAngle)) / 65536.0;
298 afm->IsFixedPitch = (post-> isFixedPitch == 0) ? FALSE : TRUE;
299 afm->UnderlinePosition = PSUnits(post->underlinePosition, em_size);
300 afm->UnderlineThickness = PSUnits(post->underlineThickness, em_size);
302 afm->FontBBox.llx = PSUnits(head->xMin, em_size);
303 afm->FontBBox.lly = PSUnits(head->yMin, em_size);
304 afm->FontBBox.urx = PSUnits(head->xMax, em_size);
305 afm->FontBBox.ury = PSUnits(head->yMax, em_size);
307 afm->Ascender = PSUnits(os2->sTypoAscender, em_size);
308 afm->Descender = PSUnits(os2->sTypoDescender, em_size);
313 /*******************************************************************************
316 * Reads metrics for each glyph in a TrueType font. Returns false for memory
317 * allocation or FreeType error; sets *p_metrics to NULL for non-fatal error.
320 static BOOL ReadCharMetrics(FT_Face face, AFM *afm, AFMMETRICS **p_metrics)
322 FT_ULong charcode, index;
324 USHORT em_size = afm->WinMetrics.usUnitsPerEm;
326 for (charcode = 0, index = 0; charcode < 65536; ++charcode)
327 if (FT_Get_Char_Index(face, charcode) != 0)
328 ++index; /* count # of glyphs */
330 afm->NumofMetrics = index;
332 *p_metrics = metrics = HeapAlloc(PSDRV_Heap, 0, index * sizeof(*metrics));
336 for (charcode = 0, index = 0; charcode < 65536; ++charcode)
338 FT_UInt glyph_index = FT_Get_Char_Index(face, charcode);
340 CHAR buffer[128]; /* for glyph names */
342 if (glyph_index == 0)
345 error = FT_Load_Glyph(face, glyph_index, GLYPH_LOAD_FLAGS);
346 if (error != FT_Err_Ok)
348 ERR("%s returned %i\n", "FT_Load_Glyph", error);
352 error = FT_Get_Glyph_Name(face, glyph_index, buffer, sizeof(buffer));
353 if (error != FT_Err_Ok)
355 ERR("%s returned %i\n", "FT_Get_Glyph_Name", error);
359 metrics[index].N = PSDRV_GlyphName(buffer);
360 if (metrics[index].N == NULL)
363 metrics[index].C = metrics[index].UV = charcode;
364 metrics[index].WX = PSUnits(face->glyph->metrics.horiAdvance, em_size);
369 if (afm->WinMetrics.sAvgCharWidth == 0)
370 afm->WinMetrics.sAvgCharWidth = PSDRV_CalcAvgCharWidth(afm);
375 HeapFree(PSDRV_Heap, 0, metrics);
380 /*******************************************************************************
383 * Builds the AFM for a TrueType font and adds it to the driver font list.
384 * Returns FALSE only on an unexpected error (memory allocation failure or
388 static BOOL BuildTrueTypeAFM(FT_Face face)
392 LPSTR font_name, full_name, family_name, encoding_scheme;
396 retval = StartAFM(face, &afm);
397 if (retval == FALSE || afm == NULL)
400 retval = FindCharMap(face, &charmap, &encoding_scheme);
401 if (retval == FALSE || charmap == NULL)
404 retval = FindMSTTString(face, charmap, TT_NAME_ID_PS_NAME, &font_name);
405 if (retval == FALSE || font_name == NULL)
406 goto cleanup_encoding_scheme;
408 retval = FindMSTTString(face, charmap, TT_NAME_ID_FULL_NAME, &full_name);
409 if (retval == FALSE || full_name == NULL)
410 goto cleanup_font_name;
412 retval = FindMSTTString(face, charmap, TT_NAME_ID_FONT_FAMILY,
414 if (retval == FALSE || family_name == NULL)
415 goto cleanup_full_name;
417 retval = ReadCharMetrics(face, afm, &metrics);
418 if (retval == FALSE || metrics == NULL)
419 goto cleanup_family_name;
421 afm->EncodingScheme = encoding_scheme; afm->FontName = font_name;
422 afm->FullName = full_name; afm->FamilyName = family_name;
423 afm->Metrics = metrics;
425 retval = PSDRV_AddAFMtoList(&PSDRV_AFMFontList, afm, &added);
426 if (retval == FALSE || added == FALSE)
427 goto cleanup_family_name;
431 /* clean up after fatal or non-fatal errors */
434 HeapFree(PSDRV_Heap, 0, family_name);
436 HeapFree(PSDRV_Heap, 0, full_name);
438 HeapFree(PSDRV_Heap, 0, font_name);
439 cleanup_encoding_scheme:
440 HeapFree(PSDRV_Heap, 0, encoding_scheme);
442 HeapFree(PSDRV_Heap, 0, afm);
447 /*******************************************************************************
450 * Reads font metrics from TrueType font file. Only returns FALSE for
451 * unexpected errors (memory allocation failure or FreeType error).
454 static BOOL ReadTrueTypeFile(FT_Library library, LPCSTR filename)
459 TRACE("%s\n", filename);
461 error = FT_New_Face(library, filename, 0, &face);
462 if (error != FT_Err_Ok)
464 WARN("FreeType error %i opening %s\n", error, filename);
468 if ((face->face_flags & REQUIRED_FACE_FLAGS) == REQUIRED_FACE_FLAGS)
470 if (BuildTrueTypeAFM(face) == FALSE)
478 WARN("Required information missing from %s\n", filename);
481 error = FT_Done_Face(face);
482 if (error != FT_Err_Ok)
484 ERR("%s returned %i\n", "FT_Done_Face", error);
491 /*******************************************************************************
494 * Reads all TrueType font files in a directory.
497 static BOOL ReadTrueTypeDir(FT_Library library, LPCSTR dirname)
503 dir = opendir(dirname);
506 WARN("'%s' opening %s\n", strerror(errno), dirname);
510 while ((dent = readdir(dir)) != NULL)
512 CHAR *file_extension = strrchr(dent->d_name, '.');
515 if (file_extension == NULL || strcasecmp(file_extension, ".ttf") != 0)
518 fn_len = snprintf(filename, 256, "%s/%s", dirname, dent->d_name);
519 if (fn_len < 0 || fn_len > sizeof(filename) - 1)
521 WARN("Path '%s/%s' is too long\n", dirname, dent->d_name);
525 if (ReadTrueTypeFile(library, filename) == FALSE)
537 /*******************************************************************************
538 * PSDRV_GetTrueTypeMetrics
540 * Reads font metrics from TrueType font files in directories listed in the
541 * [TrueType Font Directories] section of the Wine configuration file.
543 * If this function fails (returns FALSE), the driver will fail to initialize
544 * and the driver heap will be destroyed, so it's not necessary to HeapFree
545 * everything in that event.
548 BOOL PSDRV_GetTrueTypeMetrics(void)
550 CHAR name_buf[256], value_buf[256];
555 DWORD type, name_len, value_len;
557 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,
558 "Software\\Wine\\Wine\\Config\\TrueType Font Directories",
559 0, KEY_READ, &hkey) != ERROR_SUCCESS)
562 error = FT_Init_FreeType(&library);
563 if (error != FT_Err_Ok)
565 ERR("%s returned %i\n", "FT_Init_FreeType", error);
570 name_len = sizeof(name_buf);
571 value_len = sizeof(value_buf);
573 while (RegEnumValueA(hkey, i++, name_buf, &name_len, NULL, &type, value_buf,
574 &value_len) == ERROR_SUCCESS)
576 value_buf[sizeof(value_buf) - 1] = '\0';
578 if (ReadTrueTypeDir(library, value_buf) == FALSE)
581 FT_Done_FreeType(library);
585 /* initialize lengths for new iteration */
587 name_len = sizeof(name_buf);
588 value_len = sizeof(value_buf);
592 FT_Done_FreeType(library);
596 #endif /* HAVE_FREETYPE */