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_TTNAMEID_H
54 #include <freetype/ttnameid.h>
57 #include <sys/types.h>
72 #include "wine/library.h"
73 #include "wine/debug.h"
75 WINE_DEFAULT_DEBUG_CHANNEL(psdrv);
77 #define REQUIRED_FACE_FLAGS ( FT_FACE_FLAG_SCALABLE | \
78 FT_FACE_FLAG_HORIZONTAL | \
80 FT_FACE_FLAG_GLYPH_NAMES )
82 #define GLYPH_LOAD_FLAGS ( FT_LOAD_NO_SCALE | \
83 FT_LOAD_IGNORE_TRANSFORM | \
84 FT_LOAD_LINEAR_DESIGN )
86 static void *ft_handle = NULL;
88 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL;
89 MAKE_FUNCPTR(FT_Done_Face)
90 MAKE_FUNCPTR(FT_Done_FreeType)
91 MAKE_FUNCPTR(FT_Get_Char_Index)
92 MAKE_FUNCPTR(FT_Get_Glyph_Name)
93 MAKE_FUNCPTR(FT_Get_Sfnt_Name)
94 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count)
95 MAKE_FUNCPTR(FT_Get_Sfnt_Table)
96 MAKE_FUNCPTR(FT_Init_FreeType)
97 MAKE_FUNCPTR(FT_Load_Glyph)
98 MAKE_FUNCPTR(FT_New_Face)
99 MAKE_FUNCPTR(FT_Set_Charmap)
102 /*******************************************************************************
105 * Finds Windows character map and creates "EncodingScheme" string. Returns
106 * FALSE to indicate memory allocation or FreeType error; sets *p_charmap to
107 * NULL if no Windows encoding is present.
109 * Returns Unicode character map if present; otherwise uses the first Windows
110 * character map found.
113 static const LPCSTR encoding_names[7] =
115 "WindowsSymbol", /* TT_MS_ID_SYMBOL_CS */
116 "WindowsUnicode", /* TT_MS_ID_UNICODE_CS */
117 "WindowsShiftJIS", /* TT_MS_ID_SJIS */
118 "WindowsPRC", /* TT_MS_ID_GB2312 */
119 "WindowsBig5", /* TT_MS_ID_BIG_5 */
120 "WindowsWansung", /* TT_MS_ID_WANSUNG */
121 "WindowsJohab" /* TT_MS_ID_JOHAB */
122 /* "WindowsUnknown65535" is the longest possible (encoding_id is a UShort) */
125 static BOOL FindCharMap(FT_Face face, FT_CharMap *p_charmap, LPSTR *p_sz)
129 FT_CharMap charmap = NULL;
131 for (i = 0; i < face->num_charmaps; ++i)
133 if (face->charmaps[i]->platform_id != TT_PLATFORM_MICROSOFT)
136 if (face->charmaps[i]->encoding_id == TT_MS_ID_UNICODE_CS)
138 charmap = face->charmaps[i];
143 charmap = face->charmaps[i];
146 *p_charmap = charmap;
150 WARN("No Windows character map found\n");
154 error = pFT_Set_Charmap(face, charmap);
155 if (error != FT_Err_Ok)
157 ERR("%s returned %i\n", "FT_Set_Charmap", error);
161 *p_sz = HeapAlloc(PSDRV_Heap, 0, sizeof("WindowsUnknown65535"));
165 if (charmap->encoding_id < 7)
166 strcpy(*p_sz, encoding_names[charmap->encoding_id]);
168 sprintf(*p_sz, "%s%u", "WindowsUnknown", charmap->encoding_id);
173 /*******************************************************************************
176 * Converts a string in the TrueType NAME table to a null-terminated ASCII
177 * character string. Space for the string is allocated from the driver heap.
178 * Only handles platform_id = 3 (TT_PLATFORM_MICROSOFT) strings (16-bit, big
179 * endian). It also only handles ASCII character codes (< 128).
181 * Sets *p_sz to NULL if string cannot be converted; only returns FALSE for
182 * memory allocation failure.
185 static BOOL MSTTStrToSz(const FT_SfntName *name, LPSTR *p_sz)
192 len = name->string_len / 2; /* # of 16-bit chars */
194 *p_sz = sz = HeapAlloc(PSDRV_Heap, 0, len + 1);
198 wsz = (BYTE *)name->string;
200 for (i = 0; i < len; ++i, ++sz)
202 USHORT wc = (wsz[0] << 8) + wsz[1];
207 WARN("Non-ASCII character 0x%.4x\n", wc);
208 HeapFree(PSDRV_Heap, 0, *p_sz);
221 /*******************************************************************************
224 * Finds the requested Microsoft platform string in the TrueType NAME table and
225 * converts it to a null-terminated ASCII string. Currently looks for U.S.
226 * English names only.
228 * Sets string to NULL if not present or cannot be converted; returns FALSE
229 * only for memory allocation failure.
232 static BOOL FindMSTTString(FT_Face face, FT_CharMap charmap, FT_UShort name_id,
235 FT_UInt num_strings, string_index;
239 num_strings = pFT_Get_Sfnt_Name_Count(face);
241 for (string_index = 0; string_index < num_strings; ++string_index)
243 error = pFT_Get_Sfnt_Name(face, string_index, &name);
244 if (error != FT_Err_Ok)
246 ERR("%s returned %i\n", "FT_Get_Sfnt_Name", error);
250 /* FIXME - Handle other languages? */
252 if (name.platform_id != TT_PLATFORM_MICROSOFT ||
253 name.language_id != TT_MS_LANGID_ENGLISH_UNITED_STATES)
256 if (name.platform_id != charmap->platform_id ||
257 name.encoding_id != charmap->encoding_id)
260 if (name.name_id != name_id)
263 return MSTTStrToSz(&name, p_sz);
266 *p_sz = NULL; /* didn't find it */
271 /*******************************************************************************
274 * Convert TrueType font units (relative to font em square) to PostScript
278 static inline float PSUnits(LONG x, USHORT em_size)
280 return 1000.0 * (float)x / (float)em_size;
283 /*******************************************************************************
286 * Allocates space for the AFM on the driver heap and reads basic font metrics
287 * from the HEAD, POST, HHEA, and OS/2 tables. Returns FALSE for memory
288 * allocation error; sets *p_afm to NULL if required information is missing.
291 static BOOL StartAFM(FT_Face face, AFM **p_afm)
300 head = pFT_Get_Sfnt_Table(face, ft_sfnt_head);
301 post = pFT_Get_Sfnt_Table(face, ft_sfnt_post);
302 os2 = pFT_Get_Sfnt_Table(face, ft_sfnt_os2);
303 hhea = pFT_Get_Sfnt_Table(face, ft_sfnt_hhea);
305 if (head == NULL || post == NULL || os2 == NULL || hhea == NULL ||
306 os2->version == 0xffff) /* old Macintosh font */
308 WARN("Required table(s) missing\n");
313 *p_afm = afm = HeapAlloc(PSDRV_Heap, 0, sizeof(*afm));
317 afm->WinMetrics.usUnitsPerEm = em_size = head->Units_Per_EM;
318 afm->WinMetrics.sAscender = hhea->Ascender;
319 afm->WinMetrics.sDescender = hhea->Descender;
320 afm->WinMetrics.sLineGap = hhea->Line_Gap;
321 afm->WinMetrics.sTypoAscender = os2->sTypoAscender;
322 afm->WinMetrics.sTypoDescender = os2->sTypoDescender;
323 afm->WinMetrics.sTypoLineGap = os2->sTypoLineGap;
324 afm->WinMetrics.usWinAscent = os2->usWinAscent;
325 afm->WinMetrics.usWinDescent = os2->usWinDescent;
326 afm->WinMetrics.sAvgCharWidth = os2->xAvgCharWidth;
328 afm->Weight = os2->usWeightClass;
329 afm->ItalicAngle = ((float)(post->italicAngle)) / 65536.0;
330 afm->IsFixedPitch = (post-> isFixedPitch == 0) ? FALSE : TRUE;
331 afm->UnderlinePosition = PSUnits(post->underlinePosition, em_size);
332 afm->UnderlineThickness = PSUnits(post->underlineThickness, em_size);
334 afm->FontBBox.llx = PSUnits(head->xMin, em_size);
335 afm->FontBBox.lly = PSUnits(head->yMin, em_size);
336 afm->FontBBox.urx = PSUnits(head->xMax, em_size);
337 afm->FontBBox.ury = PSUnits(head->yMax, em_size);
339 afm->Ascender = PSUnits(os2->sTypoAscender, em_size);
340 afm->Descender = PSUnits(os2->sTypoDescender, em_size);
345 /*******************************************************************************
348 * Reads metrics for each glyph in a TrueType font. Returns false for memory
349 * allocation or FreeType error; sets *p_metrics to NULL for non-fatal error.
352 static BOOL ReadCharMetrics(FT_Face face, AFM *afm, AFMMETRICS **p_metrics)
354 FT_ULong charcode, index;
356 USHORT em_size = afm->WinMetrics.usUnitsPerEm;
358 for (charcode = 0, index = 0; charcode < 65536; ++charcode)
359 if (pFT_Get_Char_Index(face, charcode) != 0)
360 ++index; /* count # of glyphs */
362 afm->NumofMetrics = index;
364 *p_metrics = metrics = HeapAlloc(PSDRV_Heap, 0, index * sizeof(*metrics));
368 for (charcode = 0, index = 0; charcode < 65536; ++charcode)
370 FT_UInt glyph_index = pFT_Get_Char_Index(face, charcode);
372 CHAR buffer[128]; /* for glyph names */
374 if (glyph_index == 0)
377 error = pFT_Load_Glyph(face, glyph_index, GLYPH_LOAD_FLAGS);
378 if (error != FT_Err_Ok)
380 ERR("%s returned %i\n", "FT_Load_Glyph", error);
384 error = pFT_Get_Glyph_Name(face, glyph_index, buffer, sizeof(buffer));
385 if (error != FT_Err_Ok)
387 ERR("%s returned %i\n", "FT_Get_Glyph_Name", error);
391 metrics[index].N = PSDRV_GlyphName(buffer);
392 if (metrics[index].N == NULL)
395 metrics[index].C = metrics[index].UV = charcode;
396 metrics[index].WX = PSUnits(face->glyph->metrics.horiAdvance, em_size);
401 if (afm->WinMetrics.sAvgCharWidth == 0)
402 afm->WinMetrics.sAvgCharWidth = PSDRV_CalcAvgCharWidth(afm);
407 HeapFree(PSDRV_Heap, 0, metrics);
412 /*******************************************************************************
415 * Builds the AFM for a TrueType font and adds it to the driver font list.
416 * Returns FALSE only on an unexpected error (memory allocation failure or
420 static BOOL BuildTrueTypeAFM(FT_Face face)
424 LPSTR font_name, full_name, family_name, encoding_scheme = NULL;
428 retval = StartAFM(face, &afm);
429 if (retval == FALSE || afm == NULL)
432 retval = FindCharMap(face, &charmap, &encoding_scheme);
433 if (retval == FALSE || charmap == NULL)
436 retval = FindMSTTString(face, charmap, TT_NAME_ID_PS_NAME, &font_name);
437 if (retval == FALSE || font_name == NULL)
438 goto cleanup_encoding_scheme;
440 retval = FindMSTTString(face, charmap, TT_NAME_ID_FULL_NAME, &full_name);
441 if (retval == FALSE || full_name == NULL)
442 goto cleanup_font_name;
444 retval = FindMSTTString(face, charmap, TT_NAME_ID_FONT_FAMILY,
446 if (retval == FALSE || family_name == NULL)
447 goto cleanup_full_name;
449 retval = ReadCharMetrics(face, afm, &metrics);
450 if (retval == FALSE || metrics == NULL)
451 goto cleanup_family_name;
453 afm->EncodingScheme = encoding_scheme; afm->FontName = font_name;
454 afm->FullName = full_name; afm->FamilyName = family_name;
455 afm->Metrics = metrics;
457 retval = PSDRV_AddAFMtoList(&PSDRV_AFMFontList, afm, &added);
458 if (retval == FALSE || added == FALSE)
459 goto cleanup_family_name;
463 /* clean up after fatal or non-fatal errors */
466 HeapFree(PSDRV_Heap, 0, family_name);
468 HeapFree(PSDRV_Heap, 0, full_name);
470 HeapFree(PSDRV_Heap, 0, font_name);
471 cleanup_encoding_scheme:
472 HeapFree(PSDRV_Heap, 0, encoding_scheme);
474 HeapFree(PSDRV_Heap, 0, afm);
479 /*******************************************************************************
482 * Reads font metrics from TrueType font file. Only returns FALSE for
483 * unexpected errors (memory allocation failure or FreeType error).
486 static BOOL ReadTrueTypeFile(FT_Library library, LPCSTR filename)
491 TRACE("%s\n", filename);
493 error = pFT_New_Face(library, filename, 0, &face);
494 if (error != FT_Err_Ok)
496 WARN("FreeType error %i opening %s\n", error, filename);
500 if ((face->face_flags & REQUIRED_FACE_FLAGS) == REQUIRED_FACE_FLAGS)
502 if (BuildTrueTypeAFM(face) == FALSE)
510 WARN("Required information missing from %s\n", filename);
513 error = pFT_Done_Face(face);
514 if (error != FT_Err_Ok)
516 ERR("%s returned %i\n", "FT_Done_Face", error);
523 /*******************************************************************************
526 * Reads all TrueType font files in a directory.
529 static BOOL ReadTrueTypeDir(FT_Library library, LPCSTR dirname)
535 dir = opendir(dirname);
538 WARN("'%s' opening %s\n", strerror(errno), dirname);
542 while ((dent = readdir(dir)) != NULL)
544 CHAR *file_extension = strrchr(dent->d_name, '.');
547 if (file_extension == NULL || strcasecmp(file_extension, ".ttf") != 0)
550 fn_len = snprintf(filename, 256, "%s/%s", dirname, dent->d_name);
551 if (fn_len < 0 || fn_len > sizeof(filename) - 1)
553 WARN("Path '%s/%s' is too long\n", dirname, dent->d_name);
557 if (ReadTrueTypeFile(library, filename) == FALSE)
569 /*******************************************************************************
570 * PSDRV_GetTrueTypeMetrics
572 * Reads font metrics from TrueType font files in directories listed in the
573 * HKEY_CURRENT_USER\\Software\\Wine\\Fonts\\Path registry string.
575 * If this function fails (returns FALSE), the driver will fail to initialize
576 * and the driver heap will be destroyed, so it's not necessary to HeapFree
577 * everything in that event.
580 BOOL PSDRV_GetTrueTypeMetrics(void)
582 static const WCHAR pathW[] = {'P','a','t','h',0};
590 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
591 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) != ERROR_SUCCESS)
594 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
597 "Wine cannot find the FreeType font library. To enable Wine to\n"
598 "use TrueType fonts please install a version of FreeType greater than\n"
599 "or equal to 2.0.5.\n"
600 "http://www.freetype.org\n");
605 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(ft_handle, #f, NULL, 0)) == NULL) goto sym_not_found;
606 LOAD_FUNCPTR(FT_Done_Face)
607 LOAD_FUNCPTR(FT_Done_FreeType)
608 LOAD_FUNCPTR(FT_Get_Char_Index)
609 LOAD_FUNCPTR(FT_Get_Glyph_Name)
610 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
611 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
612 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
613 LOAD_FUNCPTR(FT_Init_FreeType)
614 LOAD_FUNCPTR(FT_Load_Glyph)
615 LOAD_FUNCPTR(FT_New_Face)
616 LOAD_FUNCPTR(FT_Set_Charmap)
619 error = pFT_Init_FreeType(&library);
620 if (error != FT_Err_Ok)
622 ERR("%s returned %i\n", "FT_Init_FreeType", error);
623 wine_dlclose(ft_handle, NULL, 0);
628 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
630 len += sizeof(WCHAR);
631 valueW = HeapAlloc( GetProcessHeap(), 0, len );
632 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
634 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
635 valueA = HeapAlloc( GetProcessHeap(), 0, len );
636 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
637 TRACE( "got font path %s\n", debugstr_a(valueA) );
641 LPSTR next = strchr( ptr, ':' );
642 if (next) *next++ = 0;
643 ReadTrueTypeDir( library, ptr );
646 HeapFree( GetProcessHeap(), 0, valueA );
648 HeapFree( GetProcessHeap(), 0, valueW );
652 pFT_Done_FreeType(library);
653 wine_dlclose(ft_handle, NULL, 0);
659 "Wine cannot find certain functions that it needs inside the FreeType\n"
660 "font library. To enable Wine to use TrueType fonts please upgrade\n"
661 "FreeType to at least version 2.0.5.\n"
662 "http://www.freetype.org\n");
664 wine_dlclose(ft_handle, NULL, 0);
669 #endif /* HAVE_FREETYPE */