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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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_FT2BUILD_H
41 #ifdef HAVE_FREETYPE_FREETYPE_H
42 #include <freetype/freetype.h>
44 #ifdef HAVE_FREETYPE_FTGLYPH_H
45 #include <freetype/ftglyph.h>
47 #ifdef HAVE_FREETYPE_TTTABLES_H
48 #include <freetype/tttables.h>
50 #ifdef HAVE_FREETYPE_FTSNAMES_H
51 #include <freetype/ftsnames.h>
53 # ifdef HAVE_FREETYPE_FTNAMES_H
54 # include <freetype/ftnames.h>
57 #ifdef HAVE_FREETYPE_TTNAMEID_H
58 #include <freetype/ttnameid.h>
61 #include <sys/types.h>
75 #include "wine/debug.h"
77 WINE_DEFAULT_DEBUG_CHANNEL(psdrv);
79 #define REQUIRED_FACE_FLAGS ( FT_FACE_FLAG_SCALABLE | \
80 FT_FACE_FLAG_HORIZONTAL | \
82 FT_FACE_FLAG_GLYPH_NAMES )
84 #define GLYPH_LOAD_FLAGS ( FT_LOAD_NO_SCALE | \
85 FT_LOAD_IGNORE_TRANSFORM | \
86 FT_LOAD_LINEAR_DESIGN )
88 static void *ft_handle = NULL;
90 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL;
91 MAKE_FUNCPTR(FT_Done_Face)
92 MAKE_FUNCPTR(FT_Done_FreeType)
93 MAKE_FUNCPTR(FT_Get_Char_Index)
94 MAKE_FUNCPTR(FT_Get_Glyph_Name)
95 MAKE_FUNCPTR(FT_Get_Sfnt_Name)
96 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count)
97 MAKE_FUNCPTR(FT_Get_Sfnt_Table)
98 MAKE_FUNCPTR(FT_Init_FreeType)
99 MAKE_FUNCPTR(FT_Load_Glyph)
100 MAKE_FUNCPTR(FT_New_Face)
101 MAKE_FUNCPTR(FT_Set_Charmap)
104 /*******************************************************************************
107 * Finds Windows character map and creates "EncodingScheme" string. Returns
108 * FALSE to indicate memory allocation or FreeType error; sets *p_charmap to
109 * NULL if no Windows encoding is present.
111 * Returns Unicode character map if present; otherwise uses the first Windows
112 * character map found.
115 static const LPCSTR encoding_names[7] =
117 "WindowsSymbol", /* TT_MS_ID_SYMBOL_CS */
118 "WindowsUnicode", /* TT_MS_ID_UNICODE_CS */
119 "WindowsShiftJIS", /* TT_MS_ID_SJIS */
120 "WindowsPRC", /* TT_MS_ID_GB2312 */
121 "WindowsBig5", /* TT_MS_ID_BIG_5 */
122 "WindowsWansung", /* TT_MS_ID_WANSUNG */
123 "WindowsJohab" /* TT_MS_ID_JOHAB */
124 /* "WindowsUnknown65535" is the longest possible (encoding_id is a UShort) */
127 static BOOL FindCharMap(FT_Face face, FT_CharMap *p_charmap, LPSTR *p_sz)
131 FT_CharMap charmap = NULL;
133 for (i = 0; i < face->num_charmaps; ++i)
135 if (face->charmaps[i]->platform_id != TT_PLATFORM_MICROSOFT)
138 if (face->charmaps[i]->encoding_id == TT_MS_ID_UNICODE_CS)
140 charmap = face->charmaps[i];
145 charmap = face->charmaps[i];
148 *p_charmap = charmap;
152 WARN("No Windows character map found\n");
156 error = pFT_Set_Charmap(face, charmap);
157 if (error != FT_Err_Ok)
159 ERR("%s returned %i\n", "FT_Set_Charmap", error);
163 *p_sz = HeapAlloc(PSDRV_Heap, 0, sizeof("WindowsUnknown65535"));
167 if (charmap->encoding_id < 7)
168 strcpy(*p_sz, encoding_names[charmap->encoding_id]);
170 sprintf(*p_sz, "%s%u", "WindowsUnknown", charmap->encoding_id);
175 /*******************************************************************************
178 * Converts a string in the TrueType NAME table to a null-terminated ASCII
179 * character string. Space for the string is allocated from the driver heap.
180 * Only handles platform_id = 3 (TT_PLATFORM_MICROSOFT) strings (16-bit, big
181 * endian). It also only handles ASCII character codes (< 128).
183 * Sets *p_sz to NULL if string cannot be converted; only returns FALSE for
184 * memory allocation failure.
187 static BOOL MSTTStrToSz(const FT_SfntName *name, LPSTR *p_sz)
194 len = name->string_len / 2; /* # of 16-bit chars */
196 *p_sz = sz = HeapAlloc(PSDRV_Heap, 0, len + 1);
200 wsz = (BYTE *)name->string;
202 for (i = 0; i < len; ++i, ++sz)
204 USHORT wc = (wsz[0] << 8) + wsz[1];
209 WARN("Non-ASCII character 0x%.4x\n", wc);
210 HeapFree(PSDRV_Heap, 0, *p_sz);
223 /*******************************************************************************
226 * Finds the requested Microsoft platform string in the TrueType NAME table and
227 * converts it to a null-terminated ASCII string. Currently looks for U.S.
228 * English names only.
230 * Sets string to NULL if not present or cannot be converted; returns FALSE
231 * only for memory allocation failure.
234 static BOOL FindMSTTString(FT_Face face, FT_CharMap charmap, FT_UShort name_id,
237 FT_UInt num_strings, string_index;
241 num_strings = pFT_Get_Sfnt_Name_Count(face);
243 for (string_index = 0; string_index < num_strings; ++string_index)
245 error = pFT_Get_Sfnt_Name(face, string_index, &name);
246 if (error != FT_Err_Ok)
248 ERR("%s returned %i\n", "FT_Get_Sfnt_Name", error);
252 /* FIXME - Handle other languages? */
254 if (name.platform_id != TT_PLATFORM_MICROSOFT ||
255 name.language_id != TT_MS_LANGID_ENGLISH_UNITED_STATES)
258 if (name.platform_id != charmap->platform_id ||
259 name.encoding_id != charmap->encoding_id)
262 if (name.name_id != name_id)
265 return MSTTStrToSz(&name, p_sz);
268 *p_sz = NULL; /* didn't find it */
273 /*******************************************************************************
276 * Convert TrueType font units (relative to font em square) to PostScript
280 static inline float PSUnits(LONG x, USHORT em_size)
282 return 1000.0 * (float)x / (float)em_size;
285 /*******************************************************************************
288 * Allocates space for the AFM on the driver heap and reads basic font metrics
289 * from the HEAD, POST, HHEA, and OS/2 tables. Returns FALSE for memory
290 * allocation error; sets *p_afm to NULL if required information is missing.
293 static BOOL StartAFM(FT_Face face, AFM **p_afm)
302 head = pFT_Get_Sfnt_Table(face, ft_sfnt_head);
303 post = pFT_Get_Sfnt_Table(face, ft_sfnt_post);
304 os2 = pFT_Get_Sfnt_Table(face, ft_sfnt_os2);
305 hhea = pFT_Get_Sfnt_Table(face, ft_sfnt_hhea);
307 if (head == NULL || post == NULL || os2 == NULL || hhea == NULL ||
308 os2->version == 0xffff) /* old Macintosh font */
310 WARN("Required table(s) missing\n");
315 *p_afm = afm = HeapAlloc(PSDRV_Heap, 0, sizeof(*afm));
319 afm->WinMetrics.usUnitsPerEm = em_size = head->Units_Per_EM;
320 afm->WinMetrics.sAscender = hhea->Ascender;
321 afm->WinMetrics.sDescender = hhea->Descender;
322 afm->WinMetrics.sLineGap = hhea->Line_Gap;
323 afm->WinMetrics.sTypoAscender = os2->sTypoAscender;
324 afm->WinMetrics.sTypoDescender = os2->sTypoDescender;
325 afm->WinMetrics.sTypoLineGap = os2->sTypoLineGap;
326 afm->WinMetrics.usWinAscent = os2->usWinAscent;
327 afm->WinMetrics.usWinDescent = os2->usWinDescent;
328 afm->WinMetrics.sAvgCharWidth = os2->xAvgCharWidth;
330 afm->Weight = os2->usWeightClass;
331 afm->ItalicAngle = ((float)(post->italicAngle)) / 65536.0;
332 afm->IsFixedPitch = (post-> isFixedPitch == 0) ? FALSE : TRUE;
333 afm->UnderlinePosition = PSUnits(post->underlinePosition, em_size);
334 afm->UnderlineThickness = PSUnits(post->underlineThickness, em_size);
336 afm->FontBBox.llx = PSUnits(head->xMin, em_size);
337 afm->FontBBox.lly = PSUnits(head->yMin, em_size);
338 afm->FontBBox.urx = PSUnits(head->xMax, em_size);
339 afm->FontBBox.ury = PSUnits(head->yMax, em_size);
341 afm->Ascender = PSUnits(os2->sTypoAscender, em_size);
342 afm->Descender = PSUnits(os2->sTypoDescender, em_size);
347 /*******************************************************************************
350 * Reads metrics for each glyph in a TrueType font. Returns false for memory
351 * allocation or FreeType error; sets *p_metrics to NULL for non-fatal error.
354 static BOOL ReadCharMetrics(FT_Face face, AFM *afm, AFMMETRICS **p_metrics)
356 FT_ULong charcode, index;
358 USHORT em_size = afm->WinMetrics.usUnitsPerEm;
360 for (charcode = 0, index = 0; charcode < 65536; ++charcode)
361 if (pFT_Get_Char_Index(face, charcode) != 0)
362 ++index; /* count # of glyphs */
364 afm->NumofMetrics = index;
366 *p_metrics = metrics = HeapAlloc(PSDRV_Heap, 0, index * sizeof(*metrics));
370 for (charcode = 0, index = 0; charcode < 65536; ++charcode)
372 FT_UInt glyph_index = pFT_Get_Char_Index(face, charcode);
374 CHAR buffer[128]; /* for glyph names */
376 if (glyph_index == 0)
379 error = pFT_Load_Glyph(face, glyph_index, GLYPH_LOAD_FLAGS);
380 if (error != FT_Err_Ok)
382 ERR("%s returned %i\n", "FT_Load_Glyph", error);
386 error = pFT_Get_Glyph_Name(face, glyph_index, buffer, sizeof(buffer));
387 if (error != FT_Err_Ok)
389 ERR("%s returned %i\n", "FT_Get_Glyph_Name", error);
393 metrics[index].N = PSDRV_GlyphName(buffer);
394 if (metrics[index].N == NULL)
397 metrics[index].C = metrics[index].UV = charcode;
398 metrics[index].WX = PSUnits(face->glyph->metrics.horiAdvance, em_size);
403 if (afm->WinMetrics.sAvgCharWidth == 0)
404 afm->WinMetrics.sAvgCharWidth = PSDRV_CalcAvgCharWidth(afm);
409 HeapFree(PSDRV_Heap, 0, metrics);
414 /*******************************************************************************
417 * Builds the AFM for a TrueType font and adds it to the driver font list.
418 * Returns FALSE only on an unexpected error (memory allocation failure or
422 static BOOL BuildTrueTypeAFM(FT_Face face)
426 LPSTR font_name, full_name, family_name, encoding_scheme = NULL;
430 retval = StartAFM(face, &afm);
431 if (retval == FALSE || afm == NULL)
434 retval = FindCharMap(face, &charmap, &encoding_scheme);
435 if (retval == FALSE || charmap == NULL)
438 retval = FindMSTTString(face, charmap, TT_NAME_ID_PS_NAME, &font_name);
439 if (retval == FALSE || font_name == NULL)
440 goto cleanup_encoding_scheme;
442 retval = FindMSTTString(face, charmap, TT_NAME_ID_FULL_NAME, &full_name);
443 if (retval == FALSE || full_name == NULL)
444 goto cleanup_font_name;
446 retval = FindMSTTString(face, charmap, TT_NAME_ID_FONT_FAMILY,
448 if (retval == FALSE || family_name == NULL)
449 goto cleanup_full_name;
451 retval = ReadCharMetrics(face, afm, &metrics);
452 if (retval == FALSE || metrics == NULL)
453 goto cleanup_family_name;
455 afm->EncodingScheme = encoding_scheme; afm->FontName = font_name;
456 afm->FullName = full_name; afm->FamilyName = family_name;
457 afm->Metrics = metrics;
459 retval = PSDRV_AddAFMtoList(&PSDRV_AFMFontList, afm, &added);
460 if (retval == FALSE || added == FALSE)
461 goto cleanup_family_name;
465 /* clean up after fatal or non-fatal errors */
468 HeapFree(PSDRV_Heap, 0, family_name);
470 HeapFree(PSDRV_Heap, 0, full_name);
472 HeapFree(PSDRV_Heap, 0, font_name);
473 cleanup_encoding_scheme:
474 HeapFree(PSDRV_Heap, 0, encoding_scheme);
476 HeapFree(PSDRV_Heap, 0, afm);
481 /*******************************************************************************
484 * Reads font metrics from TrueType font file. Only returns FALSE for
485 * unexpected errors (memory allocation failure or FreeType error).
488 static BOOL ReadTrueTypeFile(FT_Library library, LPCSTR filename)
493 TRACE("%s\n", filename);
495 error = pFT_New_Face(library, filename, 0, &face);
496 if (error != FT_Err_Ok)
498 WARN("FreeType error %i opening %s\n", error, filename);
502 if ((face->face_flags & REQUIRED_FACE_FLAGS) == REQUIRED_FACE_FLAGS)
504 if (BuildTrueTypeAFM(face) == FALSE)
512 WARN("Required information missing from %s\n", filename);
515 error = pFT_Done_Face(face);
516 if (error != FT_Err_Ok)
518 ERR("%s returned %i\n", "FT_Done_Face", error);
525 /*******************************************************************************
528 * Reads all TrueType font files in a directory.
531 static BOOL ReadTrueTypeDir(FT_Library library, LPCSTR dirname)
537 dir = opendir(dirname);
540 WARN("'%s' opening %s\n", strerror(errno), dirname);
544 while ((dent = readdir(dir)) != NULL)
546 CHAR *file_extension = strrchr(dent->d_name, '.');
549 if (file_extension == NULL || strcasecmp(file_extension, ".ttf") != 0)
552 fn_len = snprintf(filename, 256, "%s/%s", dirname, dent->d_name);
553 if (fn_len < 0 || fn_len > sizeof(filename) - 1)
555 WARN("Path '%s/%s' is too long\n", dirname, dent->d_name);
559 if (ReadTrueTypeFile(library, filename) == FALSE)
571 /*******************************************************************************
572 * PSDRV_GetTrueTypeMetrics
574 * Reads font metrics from TrueType font files in directories listed in the
575 * [TrueType Font Directories] section of the Wine configuration file.
577 * If this function fails (returns FALSE), the driver will fail to initialize
578 * and the driver heap will be destroyed, so it's not necessary to HeapFree
579 * everything in that event.
582 BOOL PSDRV_GetTrueTypeMetrics(void)
584 static const WCHAR pathW[] = {'P','a','t','h',0};
592 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
593 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &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");
607 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(ft_handle, #f, NULL, 0)) == NULL) goto sym_not_found;
608 LOAD_FUNCPTR(FT_Done_Face)
609 LOAD_FUNCPTR(FT_Done_FreeType)
610 LOAD_FUNCPTR(FT_Get_Char_Index)
611 LOAD_FUNCPTR(FT_Get_Glyph_Name)
612 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
613 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
614 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
615 LOAD_FUNCPTR(FT_Init_FreeType)
616 LOAD_FUNCPTR(FT_Load_Glyph)
617 LOAD_FUNCPTR(FT_New_Face)
618 LOAD_FUNCPTR(FT_Set_Charmap)
621 error = pFT_Init_FreeType(&library);
622 if (error != FT_Err_Ok)
624 ERR("%s returned %i\n", "FT_Init_FreeType", error);
625 wine_dlclose(ft_handle, NULL, 0);
630 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
632 len += sizeof(WCHAR);
633 valueW = HeapAlloc( GetProcessHeap(), 0, len );
634 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
636 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
637 valueA = HeapAlloc( GetProcessHeap(), 0, len );
638 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
639 TRACE( "got font path %s\n", debugstr_a(valueA) );
643 LPSTR next = strchr( ptr, ':' );
644 if (next) *next++ = 0;
645 ReadTrueTypeDir( library, ptr );
648 HeapFree( GetProcessHeap(), 0, valueA );
650 HeapFree( GetProcessHeap(), 0, valueW );
654 pFT_Done_FreeType(library);
655 wine_dlclose(ft_handle, NULL, 0);
661 "Wine cannot find certain functions that it needs inside the FreeType\n"
662 "font library. To enable Wine to use TrueType fonts please upgrade\n"
663 "FreeType to at least version 2.0.5.\n"
664 "http://www.freetype.org\n");
666 wine_dlclose(ft_handle, NULL, 0);
671 #endif /* HAVE_FREETYPE */