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_FTNAMES_H
34 #include <freetype/ftnames.h>
36 #ifdef HAVE_FREETYPE_FTSNAMES_H
37 #include <freetype/ftsnames.h>
39 #ifdef HAVE_FREETYPE_TTNAMEID_H
40 #include <freetype/ttnameid.h>
43 #include <sys/types.h>
53 #include "debugtools.h"
55 DEFAULT_DEBUG_CHANNEL(psdrv);
57 #define REQUIRED_FACE_FLAGS ( FT_FACE_FLAG_SCALABLE | \
58 FT_FACE_FLAG_HORIZONTAL | \
60 FT_FACE_FLAG_GLYPH_NAMES )
62 #define GLYPH_LOAD_FLAGS ( FT_LOAD_NO_SCALE | \
63 FT_LOAD_IGNORE_TRANSFORM | \
64 FT_LOAD_LINEAR_DESIGN )
66 /*******************************************************************************
69 * Finds Windows character map and creates "EncodingScheme" string. Returns
70 * FALSE to indicate memory allocation or FreeType error; sets *p_charmap to
71 * NULL if no Windows encoding is present.
73 * Returns Unicode character map if present; otherwise uses the first Windows
74 * character map found.
77 static const LPCSTR encoding_names[7] =
79 "WindowsSymbol", /* TT_MS_ID_SYMBOL_CS */
80 "WindowsUnicode", /* TT_MS_ID_UNICODE_CS */
81 "WindowsShiftJIS", /* TT_MS_ID_SJIS */
82 "WindowsPRC", /* TT_MS_ID_GB2312 */
83 "WindowsBig5", /* TT_MS_ID_BIG_5 */
84 "WindowsWansung", /* TT_MS_ID_WANSUNG */
85 "WindowsJohab" /* TT_MS_ID_JOHAB */
86 /* "WindowsUnknown65535" is the longest possible (encoding_id is a UShort) */
89 static BOOL FindCharMap(FT_Face face, FT_CharMap *p_charmap, LPSTR *p_sz)
93 FT_CharMap charmap = NULL;
95 for (i = 0; i < face->num_charmaps; ++i)
97 if (face->charmaps[i]->platform_id != TT_PLATFORM_MICROSOFT)
100 if (face->charmaps[i]->encoding_id == TT_MS_ID_UNICODE_CS)
102 charmap = face->charmaps[i];
107 charmap = face->charmaps[i];
110 *p_charmap = charmap;
114 WARN("No Windows character map found\n");
118 error = FT_Set_Charmap(face, charmap);
119 if (error != FT_Err_Ok)
121 ERR("%s returned %i\n", "FT_Set_Charmap", error);
125 *p_sz = HeapAlloc(PSDRV_Heap, 0, sizeof("WindowsUnknown65535"));
129 if (charmap->encoding_id < 7)
130 strcpy(*p_sz, encoding_names[charmap->encoding_id]);
132 sprintf(*p_sz, "%s%u", "WindowsUnknown", charmap->encoding_id);
137 /*******************************************************************************
140 * Converts a string in the TrueType NAME table to a null-terminated ASCII
141 * character string. Space for the string is allocated from the driver heap.
142 * Only handles platform_id = 3 (TT_PLATFORM_MICROSOFT) strings (16-bit, big
143 * endian). It also only handles ASCII character codes (< 128).
145 * Sets *p_sz to NULL if string cannot be converted; only returns FALSE for
146 * memory allocation failure.
149 static BOOL MSTTStrToSz(const FT_SfntName *name, LPSTR *p_sz)
156 len = name->string_len / 2; /* # of 16-bit chars */
158 *p_sz = sz = HeapAlloc(PSDRV_Heap, 0, len + 1);
162 wsz = (USHORT *)(name->string);
164 for (i = 0; i < len; ++i, ++sz, ++wsz)
168 #ifndef WORDS_BIGENDIAN
169 wc = (wc >> 8) | (wc << 8);
174 WARN("Non-ASCII character 0x%.4x\n", wc);
175 HeapFree(PSDRV_Heap, 0, *p_sz);
188 /*******************************************************************************
191 * Finds the requested Microsoft platform string in the TrueType NAME table and
192 * converts it to a null-terminated ASCII string. Currently looks for U.S.
193 * English names only.
195 * Sets string to NULL if not present or cannot be converted; returns FALSE
196 * only for memory allocation failure.
199 static BOOL FindMSTTString(FT_Face face, FT_CharMap charmap, FT_UShort name_id,
202 FT_UInt num_strings, string_index;
206 num_strings = FT_Get_Sfnt_Name_Count(face);
208 for (string_index = 0; string_index < num_strings; ++string_index)
210 error = FT_Get_Sfnt_Name(face, string_index, &name);
211 if (error != FT_Err_Ok)
213 ERR("%s returned %i\n", "FT_Get_Sfnt_Name", error);
217 /* FIXME - Handle other languages? */
219 if (name.platform_id != TT_PLATFORM_MICROSOFT ||
220 name.language_id != TT_MS_LANGID_ENGLISH_UNITED_STATES)
223 if (name.platform_id != charmap->platform_id ||
224 name.encoding_id != charmap->encoding_id)
227 if (name.name_id != name_id)
230 return MSTTStrToSz(&name, p_sz);
233 *p_sz = NULL; /* didn't find it */
238 /*******************************************************************************
241 * Convert TrueType font units (relative to font em square) to PostScript
245 inline static float PSUnits(LONG x, USHORT em_size)
247 return 1000.0 * (float)x / (float)em_size;
250 /*******************************************************************************
253 * Allocates space for the AFM on the driver heap and reads basic font metrics
254 * from the HEAD, POST, HHEA, and OS/2 tables. Returns FALSE for memory
255 * allocation error; sets *p_afm to NULL if required information is missing.
258 static BOOL StartAFM(FT_Face face, AFM **p_afm)
267 head = FT_Get_Sfnt_Table(face, ft_sfnt_head);
268 post = FT_Get_Sfnt_Table(face, ft_sfnt_post);
269 os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2);
270 hhea = FT_Get_Sfnt_Table(face, ft_sfnt_hhea);
272 if (head == NULL || post == NULL || os2 == NULL || hhea == NULL ||
273 os2->version == 0xffff) /* old Macintosh font */
275 WARN("Required table(s) missing\n");
280 *p_afm = afm = HeapAlloc(PSDRV_Heap, 0, sizeof(*afm));
284 afm->WinMetrics.usUnitsPerEm = em_size = head->Units_Per_EM;
285 afm->WinMetrics.sAscender = hhea->Ascender;
286 afm->WinMetrics.sDescender = hhea->Descender;
287 afm->WinMetrics.sLineGap = hhea->Line_Gap;
288 afm->WinMetrics.sTypoAscender = os2->sTypoAscender;
289 afm->WinMetrics.sTypoDescender = os2->sTypoDescender;
290 afm->WinMetrics.sTypoLineGap = os2->sTypoLineGap;
291 afm->WinMetrics.usWinAscent = os2->usWinAscent;
292 afm->WinMetrics.usWinDescent = os2->usWinDescent;
293 afm->WinMetrics.sAvgCharWidth = os2->xAvgCharWidth;
295 afm->Weight = os2->usWeightClass;
296 afm->ItalicAngle = ((float)(post->italicAngle)) / 65536.0;
297 afm->IsFixedPitch = (post-> isFixedPitch == 0) ? FALSE : TRUE;
298 afm->UnderlinePosition = PSUnits(post->underlinePosition, em_size);
299 afm->UnderlineThickness = PSUnits(post->underlineThickness, em_size);
301 afm->FontBBox.llx = PSUnits(head->xMin, em_size);
302 afm->FontBBox.lly = PSUnits(head->yMin, em_size);
303 afm->FontBBox.urx = PSUnits(head->xMax, em_size);
304 afm->FontBBox.ury = PSUnits(head->yMax, em_size);
306 afm->Ascender = PSUnits(os2->sTypoAscender, em_size);
307 afm->Descender = PSUnits(os2->sTypoDescender, em_size);
312 /*******************************************************************************
315 * Reads metrics for each glyph in a TrueType font. Returns false for memory
316 * allocation or FreeType error; sets *p_metrics to NULL for non-fatal error.
319 static BOOL ReadCharMetrics(FT_Face face, AFM *afm, AFMMETRICS **p_metrics)
321 FT_ULong charcode, index;
323 USHORT em_size = afm->WinMetrics.usUnitsPerEm;
325 for (charcode = 0, index = 0; charcode < 65536; ++charcode)
326 if (FT_Get_Char_Index(face, charcode) != 0)
327 ++index; /* count # of glyphs */
329 afm->NumofMetrics = index;
331 *p_metrics = metrics = HeapAlloc(PSDRV_Heap, 0, index * sizeof(*metrics));
335 for (charcode = 0, index = 0; charcode < 65536; ++charcode)
337 FT_UInt glyph_index = FT_Get_Char_Index(face, charcode);
339 CHAR buffer[128]; /* for glyph names */
341 if (glyph_index == 0)
344 error = FT_Load_Glyph(face, glyph_index, GLYPH_LOAD_FLAGS);
345 if (error != FT_Err_Ok)
347 ERR("%s returned %i\n", "FT_Load_Glyph", error);
351 error = FT_Get_Glyph_Name(face, glyph_index, buffer, sizeof(buffer));
352 if (error != FT_Err_Ok)
354 ERR("%s returned %i\n", "FT_Get_Glyph_Name", error);
358 metrics[index].N = PSDRV_GlyphName(buffer);
359 if (metrics[index].N == NULL)
362 metrics[index].C = metrics[index].UV = charcode;
363 metrics[index].WX = PSUnits(face->glyph->metrics.horiAdvance, em_size);
368 if (afm->WinMetrics.sAvgCharWidth == 0)
369 afm->WinMetrics.sAvgCharWidth = PSDRV_CalcAvgCharWidth(afm);
374 HeapFree(PSDRV_Heap, 0, metrics);
379 /*******************************************************************************
382 * Builds the AFM for a TrueType font and adds it to the driver font list.
383 * Returns FALSE only on an unexpected error (memory allocation failure or
387 static BOOL BuildTrueTypeAFM(FT_Face face)
391 LPSTR font_name, full_name, family_name, encoding_scheme;
395 retval = StartAFM(face, &afm);
396 if (retval == FALSE || afm == NULL)
399 retval = FindCharMap(face, &charmap, &encoding_scheme);
400 if (retval == FALSE || charmap == NULL)
403 retval = FindMSTTString(face, charmap, TT_NAME_ID_PS_NAME, &font_name);
404 if (retval == FALSE || font_name == NULL)
405 goto cleanup_encoding_scheme;
407 retval = FindMSTTString(face, charmap, TT_NAME_ID_FULL_NAME, &full_name);
408 if (retval == FALSE || full_name == NULL)
409 goto cleanup_font_name;
411 retval = FindMSTTString(face, charmap, TT_NAME_ID_FONT_FAMILY,
413 if (retval == FALSE || family_name == NULL)
414 goto cleanup_full_name;
416 retval = ReadCharMetrics(face, afm, &metrics);
417 if (retval == FALSE || metrics == NULL)
418 goto cleanup_family_name;
420 afm->EncodingScheme = encoding_scheme; afm->FontName = font_name;
421 afm->FullName = full_name; afm->FamilyName = family_name;
422 afm->Metrics = metrics;
424 retval = PSDRV_AddAFMtoList(&PSDRV_AFMFontList, afm, &added);
425 if (retval == FALSE || added == FALSE)
426 goto cleanup_family_name;
430 /* clean up after fatal or non-fatal errors */
433 HeapFree(PSDRV_Heap, 0, family_name);
435 HeapFree(PSDRV_Heap, 0, full_name);
437 HeapFree(PSDRV_Heap, 0, font_name);
438 cleanup_encoding_scheme:
439 HeapFree(PSDRV_Heap, 0, encoding_scheme);
441 HeapFree(PSDRV_Heap, 0, afm);
446 /*******************************************************************************
449 * Reads font metrics from TrueType font file. Only returns FALSE for
450 * unexpected errors (memory allocation failure or FreeType error).
453 static BOOL ReadTrueTypeFile(FT_Library library, LPCSTR filename)
458 TRACE("%s\n", filename);
460 error = FT_New_Face(library, filename, 0, &face);
461 if (error != FT_Err_Ok)
463 WARN("FreeType error %i opening %s\n", error, filename);
467 if ((face->face_flags & REQUIRED_FACE_FLAGS) == REQUIRED_FACE_FLAGS)
469 if (BuildTrueTypeAFM(face) == FALSE)
477 WARN("Required information missing from %s\n", filename);
480 error = FT_Done_Face(face);
481 if (error != FT_Err_Ok)
483 ERR("%s returned %i\n", "FT_Done_Face", error);
490 /*******************************************************************************
493 * Reads all TrueType font files in a directory.
496 static BOOL ReadTrueTypeDir(FT_Library library, LPCSTR dirname)
502 dir = opendir(dirname);
505 WARN("'%s' opening %s\n", strerror(errno), dirname);
509 while ((dent = readdir(dir)) != NULL)
511 CHAR *file_extension = strrchr(dent->d_name, '.');
514 if (file_extension == NULL || strcasecmp(file_extension, ".ttf") != 0)
517 fn_len = snprintf(filename, 256, "%s/%s", dirname, dent->d_name);
518 if (fn_len < 0 || fn_len > sizeof(filename) - 1)
520 WARN("Path '%s/%s' is too long\n", dirname, dent->d_name);
524 if (ReadTrueTypeFile(library, filename) == FALSE)
536 /*******************************************************************************
537 * PSDRV_GetTrueTypeMetrics
539 * Reads font metrics from TrueType font files in directories listed in the
540 * [TrueType Font Directories] section of the Wine configuration file.
542 * If this function fails (returns FALSE), the driver will fail to initialize
543 * and the driver heap will be destroyed, so it's not necessary to HeapFree
544 * everything in that event.
547 BOOL PSDRV_GetTrueTypeMetrics(void)
549 CHAR name_buf[256], value_buf[256];
554 DWORD type, name_len, value_len;
556 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,
557 "Software\\Wine\\Wine\\Config\\TrueType Font Directories",
558 0, KEY_READ, &hkey) != ERROR_SUCCESS)
561 error = FT_Init_FreeType(&library);
562 if (error != FT_Err_Ok)
564 ERR("%s returned %i\n", "FT_Init_FreeType", error);
569 name_len = sizeof(name_buf);
570 value_len = sizeof(value_buf);
572 while (RegEnumValueA(hkey, i++, name_buf, &name_len, NULL, &type, value_buf,
573 &value_len) == ERROR_SUCCESS)
575 value_buf[sizeof(value_buf) - 1] = '\0';
577 if (ReadTrueTypeDir(library, value_buf) == FALSE)
580 FT_Done_FreeType(library);
584 /* initialize lengths for new iteration */
586 name_len = sizeof(name_buf);
587 value_len = sizeof(value_buf);
591 FT_Done_FreeType(library);
595 #endif /* HAVE_FREETYPE */