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-
29 #include "wine/port.h"
34 * These stupid #ifdefs should work for FreeType 2.0.1 and 2.0.2. Beyond that
38 #ifdef HAVE_FREETYPE_FREETYPE_H
39 #include <freetype/freetype.h>
41 #ifdef HAVE_FREETYPE_FTGLYPH_H
42 #include <freetype/ftglyph.h>
44 #ifdef HAVE_FREETYPE_TTTABLES_H
45 #include <freetype/tttables.h>
47 #ifdef HAVE_FREETYPE_FTSNAMES_H
48 #include <freetype/ftsnames.h>
50 # ifdef HAVE_FREETYPE_FTNAMES_H
51 # include <freetype/ftnames.h>
54 #ifdef HAVE_FREETYPE_TTNAMEID_H
55 #include <freetype/ttnameid.h>
58 #include <sys/types.h>
70 #include "wine/debug.h"
72 WINE_DEFAULT_DEBUG_CHANNEL(psdrv);
74 #define REQUIRED_FACE_FLAGS ( FT_FACE_FLAG_SCALABLE | \
75 FT_FACE_FLAG_HORIZONTAL | \
77 FT_FACE_FLAG_GLYPH_NAMES )
79 #define GLYPH_LOAD_FLAGS ( FT_LOAD_NO_SCALE | \
80 FT_LOAD_IGNORE_TRANSFORM | \
81 FT_LOAD_LINEAR_DESIGN )
83 #ifndef SONAME_LIBFREETYPE
84 #define SONAME_LIBFREETYPE "libfreetype.so"
87 static void *ft_handle = NULL;
89 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL;
90 MAKE_FUNCPTR(FT_Done_Face)
91 MAKE_FUNCPTR(FT_Done_FreeType)
92 MAKE_FUNCPTR(FT_Get_Char_Index)
93 MAKE_FUNCPTR(FT_Get_Glyph_Name)
94 MAKE_FUNCPTR(FT_Get_Sfnt_Name)
95 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count)
96 MAKE_FUNCPTR(FT_Get_Sfnt_Table)
97 MAKE_FUNCPTR(FT_Init_FreeType)
98 MAKE_FUNCPTR(FT_Load_Glyph)
99 MAKE_FUNCPTR(FT_New_Face)
100 MAKE_FUNCPTR(FT_Set_Charmap)
103 /*******************************************************************************
106 * Finds Windows character map and creates "EncodingScheme" string. Returns
107 * FALSE to indicate memory allocation or FreeType error; sets *p_charmap to
108 * NULL if no Windows encoding is present.
110 * Returns Unicode character map if present; otherwise uses the first Windows
111 * character map found.
114 static const LPCSTR encoding_names[7] =
116 "WindowsSymbol", /* TT_MS_ID_SYMBOL_CS */
117 "WindowsUnicode", /* TT_MS_ID_UNICODE_CS */
118 "WindowsShiftJIS", /* TT_MS_ID_SJIS */
119 "WindowsPRC", /* TT_MS_ID_GB2312 */
120 "WindowsBig5", /* TT_MS_ID_BIG_5 */
121 "WindowsWansung", /* TT_MS_ID_WANSUNG */
122 "WindowsJohab" /* TT_MS_ID_JOHAB */
123 /* "WindowsUnknown65535" is the longest possible (encoding_id is a UShort) */
126 static BOOL FindCharMap(FT_Face face, FT_CharMap *p_charmap, LPSTR *p_sz)
130 FT_CharMap charmap = NULL;
132 for (i = 0; i < face->num_charmaps; ++i)
134 if (face->charmaps[i]->platform_id != TT_PLATFORM_MICROSOFT)
137 if (face->charmaps[i]->encoding_id == TT_MS_ID_UNICODE_CS)
139 charmap = face->charmaps[i];
144 charmap = face->charmaps[i];
147 *p_charmap = charmap;
151 WARN("No Windows character map found\n");
155 error = pFT_Set_Charmap(face, charmap);
156 if (error != FT_Err_Ok)
158 ERR("%s returned %i\n", "FT_Set_Charmap", error);
162 *p_sz = HeapAlloc(PSDRV_Heap, 0, sizeof("WindowsUnknown65535"));
166 if (charmap->encoding_id < 7)
167 strcpy(*p_sz, encoding_names[charmap->encoding_id]);
169 sprintf(*p_sz, "%s%u", "WindowsUnknown", charmap->encoding_id);
174 /*******************************************************************************
177 * Converts a string in the TrueType NAME table to a null-terminated ASCII
178 * character string. Space for the string is allocated from the driver heap.
179 * Only handles platform_id = 3 (TT_PLATFORM_MICROSOFT) strings (16-bit, big
180 * endian). It also only handles ASCII character codes (< 128).
182 * Sets *p_sz to NULL if string cannot be converted; only returns FALSE for
183 * memory allocation failure.
186 static BOOL MSTTStrToSz(const FT_SfntName *name, LPSTR *p_sz)
193 len = name->string_len / 2; /* # of 16-bit chars */
195 *p_sz = sz = HeapAlloc(PSDRV_Heap, 0, len + 1);
199 wsz = (BYTE *)name->string;
201 for (i = 0; i < len; ++i, ++sz)
203 USHORT wc = (wsz[0] << 8) + wsz[1];
208 WARN("Non-ASCII character 0x%.4x\n", wc);
209 HeapFree(PSDRV_Heap, 0, *p_sz);
222 /*******************************************************************************
225 * Finds the requested Microsoft platform string in the TrueType NAME table and
226 * converts it to a null-terminated ASCII string. Currently looks for U.S.
227 * English names only.
229 * Sets string to NULL if not present or cannot be converted; returns FALSE
230 * only for memory allocation failure.
233 static BOOL FindMSTTString(FT_Face face, FT_CharMap charmap, FT_UShort name_id,
236 FT_UInt num_strings, string_index;
240 num_strings = pFT_Get_Sfnt_Name_Count(face);
242 for (string_index = 0; string_index < num_strings; ++string_index)
244 error = pFT_Get_Sfnt_Name(face, string_index, &name);
245 if (error != FT_Err_Ok)
247 ERR("%s returned %i\n", "FT_Get_Sfnt_Name", error);
251 /* FIXME - Handle other languages? */
253 if (name.platform_id != TT_PLATFORM_MICROSOFT ||
254 name.language_id != TT_MS_LANGID_ENGLISH_UNITED_STATES)
257 if (name.platform_id != charmap->platform_id ||
258 name.encoding_id != charmap->encoding_id)
261 if (name.name_id != name_id)
264 return MSTTStrToSz(&name, p_sz);
267 *p_sz = NULL; /* didn't find it */
272 /*******************************************************************************
275 * Convert TrueType font units (relative to font em square) to PostScript
279 inline static float PSUnits(LONG x, USHORT em_size)
281 return 1000.0 * (float)x / (float)em_size;
284 /*******************************************************************************
287 * Allocates space for the AFM on the driver heap and reads basic font metrics
288 * from the HEAD, POST, HHEA, and OS/2 tables. Returns FALSE for memory
289 * allocation error; sets *p_afm to NULL if required information is missing.
292 static BOOL StartAFM(FT_Face face, AFM **p_afm)
301 head = pFT_Get_Sfnt_Table(face, ft_sfnt_head);
302 post = pFT_Get_Sfnt_Table(face, ft_sfnt_post);
303 os2 = pFT_Get_Sfnt_Table(face, ft_sfnt_os2);
304 hhea = pFT_Get_Sfnt_Table(face, ft_sfnt_hhea);
306 if (head == NULL || post == NULL || os2 == NULL || hhea == NULL ||
307 os2->version == 0xffff) /* old Macintosh font */
309 WARN("Required table(s) missing\n");
314 *p_afm = afm = HeapAlloc(PSDRV_Heap, 0, sizeof(*afm));
318 afm->WinMetrics.usUnitsPerEm = em_size = head->Units_Per_EM;
319 afm->WinMetrics.sAscender = hhea->Ascender;
320 afm->WinMetrics.sDescender = hhea->Descender;
321 afm->WinMetrics.sLineGap = hhea->Line_Gap;
322 afm->WinMetrics.sTypoAscender = os2->sTypoAscender;
323 afm->WinMetrics.sTypoDescender = os2->sTypoDescender;
324 afm->WinMetrics.sTypoLineGap = os2->sTypoLineGap;
325 afm->WinMetrics.usWinAscent = os2->usWinAscent;
326 afm->WinMetrics.usWinDescent = os2->usWinDescent;
327 afm->WinMetrics.sAvgCharWidth = os2->xAvgCharWidth;
329 afm->Weight = os2->usWeightClass;
330 afm->ItalicAngle = ((float)(post->italicAngle)) / 65536.0;
331 afm->IsFixedPitch = (post-> isFixedPitch == 0) ? FALSE : TRUE;
332 afm->UnderlinePosition = PSUnits(post->underlinePosition, em_size);
333 afm->UnderlineThickness = PSUnits(post->underlineThickness, em_size);
335 afm->FontBBox.llx = PSUnits(head->xMin, em_size);
336 afm->FontBBox.lly = PSUnits(head->yMin, em_size);
337 afm->FontBBox.urx = PSUnits(head->xMax, em_size);
338 afm->FontBBox.ury = PSUnits(head->yMax, em_size);
340 afm->Ascender = PSUnits(os2->sTypoAscender, em_size);
341 afm->Descender = PSUnits(os2->sTypoDescender, em_size);
346 /*******************************************************************************
349 * Reads metrics for each glyph in a TrueType font. Returns false for memory
350 * allocation or FreeType error; sets *p_metrics to NULL for non-fatal error.
353 static BOOL ReadCharMetrics(FT_Face face, AFM *afm, AFMMETRICS **p_metrics)
355 FT_ULong charcode, index;
357 USHORT em_size = afm->WinMetrics.usUnitsPerEm;
359 for (charcode = 0, index = 0; charcode < 65536; ++charcode)
360 if (pFT_Get_Char_Index(face, charcode) != 0)
361 ++index; /* count # of glyphs */
363 afm->NumofMetrics = index;
365 *p_metrics = metrics = HeapAlloc(PSDRV_Heap, 0, index * sizeof(*metrics));
369 for (charcode = 0, index = 0; charcode < 65536; ++charcode)
371 FT_UInt glyph_index = pFT_Get_Char_Index(face, charcode);
373 CHAR buffer[128]; /* for glyph names */
375 if (glyph_index == 0)
378 error = pFT_Load_Glyph(face, glyph_index, GLYPH_LOAD_FLAGS);
379 if (error != FT_Err_Ok)
381 ERR("%s returned %i\n", "FT_Load_Glyph", error);
385 error = pFT_Get_Glyph_Name(face, glyph_index, buffer, sizeof(buffer));
386 if (error != FT_Err_Ok)
388 ERR("%s returned %i\n", "FT_Get_Glyph_Name", error);
392 metrics[index].N = PSDRV_GlyphName(buffer);
393 if (metrics[index].N == NULL)
396 metrics[index].C = metrics[index].UV = charcode;
397 metrics[index].WX = PSUnits(face->glyph->metrics.horiAdvance, em_size);
402 if (afm->WinMetrics.sAvgCharWidth == 0)
403 afm->WinMetrics.sAvgCharWidth = PSDRV_CalcAvgCharWidth(afm);
408 HeapFree(PSDRV_Heap, 0, metrics);
413 /*******************************************************************************
416 * Builds the AFM for a TrueType font and adds it to the driver font list.
417 * Returns FALSE only on an unexpected error (memory allocation failure or
421 static BOOL BuildTrueTypeAFM(FT_Face face)
425 LPSTR font_name, full_name, family_name, encoding_scheme;
429 retval = StartAFM(face, &afm);
430 if (retval == FALSE || afm == NULL)
433 retval = FindCharMap(face, &charmap, &encoding_scheme);
434 if (retval == FALSE || charmap == NULL)
437 retval = FindMSTTString(face, charmap, TT_NAME_ID_PS_NAME, &font_name);
438 if (retval == FALSE || font_name == NULL)
439 goto cleanup_encoding_scheme;
441 retval = FindMSTTString(face, charmap, TT_NAME_ID_FULL_NAME, &full_name);
442 if (retval == FALSE || full_name == NULL)
443 goto cleanup_font_name;
445 retval = FindMSTTString(face, charmap, TT_NAME_ID_FONT_FAMILY,
447 if (retval == FALSE || family_name == NULL)
448 goto cleanup_full_name;
450 retval = ReadCharMetrics(face, afm, &metrics);
451 if (retval == FALSE || metrics == NULL)
452 goto cleanup_family_name;
454 afm->EncodingScheme = encoding_scheme; afm->FontName = font_name;
455 afm->FullName = full_name; afm->FamilyName = family_name;
456 afm->Metrics = metrics;
458 retval = PSDRV_AddAFMtoList(&PSDRV_AFMFontList, afm, &added);
459 if (retval == FALSE || added == FALSE)
460 goto cleanup_family_name;
464 /* clean up after fatal or non-fatal errors */
467 HeapFree(PSDRV_Heap, 0, family_name);
469 HeapFree(PSDRV_Heap, 0, full_name);
471 HeapFree(PSDRV_Heap, 0, font_name);
472 cleanup_encoding_scheme:
473 HeapFree(PSDRV_Heap, 0, encoding_scheme);
475 HeapFree(PSDRV_Heap, 0, afm);
480 /*******************************************************************************
483 * Reads font metrics from TrueType font file. Only returns FALSE for
484 * unexpected errors (memory allocation failure or FreeType error).
487 static BOOL ReadTrueTypeFile(FT_Library library, LPCSTR filename)
492 TRACE("%s\n", filename);
494 error = pFT_New_Face(library, filename, 0, &face);
495 if (error != FT_Err_Ok)
497 WARN("FreeType error %i opening %s\n", error, filename);
501 if ((face->face_flags & REQUIRED_FACE_FLAGS) == REQUIRED_FACE_FLAGS)
503 if (BuildTrueTypeAFM(face) == FALSE)
511 WARN("Required information missing from %s\n", filename);
514 error = pFT_Done_Face(face);
515 if (error != FT_Err_Ok)
517 ERR("%s returned %i\n", "FT_Done_Face", error);
524 /*******************************************************************************
527 * Reads all TrueType font files in a directory.
530 static BOOL ReadTrueTypeDir(FT_Library library, LPCSTR dirname)
536 dir = opendir(dirname);
539 WARN("'%s' opening %s\n", strerror(errno), dirname);
543 while ((dent = readdir(dir)) != NULL)
545 CHAR *file_extension = strrchr(dent->d_name, '.');
548 if (file_extension == NULL || strcasecmp(file_extension, ".ttf") != 0)
551 fn_len = snprintf(filename, 256, "%s/%s", dirname, dent->d_name);
552 if (fn_len < 0 || fn_len > sizeof(filename) - 1)
554 WARN("Path '%s/%s' is too long\n", dirname, dent->d_name);
558 if (ReadTrueTypeFile(library, filename) == FALSE)
570 /*******************************************************************************
571 * PSDRV_GetTrueTypeMetrics
573 * Reads font metrics from TrueType font files in directories listed in the
574 * [TrueType Font Directories] section of the Wine configuration file.
576 * If this function fails (returns FALSE), the driver will fail to initialize
577 * and the driver heap will be destroyed, so it's not necessary to HeapFree
578 * everything in that event.
581 BOOL PSDRV_GetTrueTypeMetrics(void)
583 CHAR name_buf[256], value_buf[256];
588 DWORD type, name_len, value_len;
590 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,
591 "Software\\Wine\\Wine\\Config\\TrueType Font Directories",
592 0, KEY_READ, &hkey) != ERROR_SUCCESS)
596 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
599 "Wine cannot find the FreeType font library. To enable Wine to\n"
600 "use TrueType fonts please install a version of FreeType greater than\n"
601 "or equal to 2.0.5.\n"
602 "http://www.freetype.org\n");
606 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(ft_handle, #f, NULL, 0)) == NULL) goto sym_not_found;
607 LOAD_FUNCPTR(FT_Done_Face)
608 LOAD_FUNCPTR(FT_Done_FreeType)
609 LOAD_FUNCPTR(FT_Get_Char_Index)
610 LOAD_FUNCPTR(FT_Get_Glyph_Name)
611 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
612 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
613 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
614 LOAD_FUNCPTR(FT_Init_FreeType)
615 LOAD_FUNCPTR(FT_Load_Glyph)
616 LOAD_FUNCPTR(FT_New_Face)
617 LOAD_FUNCPTR(FT_Set_Charmap)
620 error = pFT_Init_FreeType(&library);
621 if (error != FT_Err_Ok)
623 ERR("%s returned %i\n", "FT_Init_FreeType", error);
624 wine_dlclose(ft_handle, NULL, 0);
629 name_len = sizeof(name_buf);
630 value_len = sizeof(value_buf);
632 while (RegEnumValueA(hkey, i++, name_buf, &name_len, NULL, &type, value_buf,
633 &value_len) == ERROR_SUCCESS)
635 value_buf[sizeof(value_buf) - 1] = '\0';
637 if (ReadTrueTypeDir(library, value_buf) == FALSE)
640 pFT_Done_FreeType(library);
644 /* initialize lengths for new iteration */
646 name_len = sizeof(name_buf);
647 value_len = sizeof(value_buf);
651 pFT_Done_FreeType(library);
652 wine_dlclose(ft_handle, NULL, 0);
658 "Wine cannot find certain functions that it needs inside the FreeType\n"
659 "font library. To enable Wine to use TrueType fonts please upgrade\n"
660 "FreeType to at least version 2.0.5.\n"
661 "http://www.freetype.org\n");
662 wine_dlclose(ft_handle, NULL, 0);
667 #endif /* HAVE_FREETYPE */