Release 20030408.
[wine/gsoc-2012-control.git] / dlls / wineps / truetype.c
blob573c7eeda5ea2924284e598feef66c742dc9f6b2
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-
25 * fatal errors.
28 #include "config.h"
29 #include "wine/port.h"
31 #ifdef HAVE_FREETYPE
34 * These stupid #ifdefs should work for FreeType 2.0.1 and 2.0.2. Beyond that
35 * is anybody's guess.
38 #ifdef HAVE_FREETYPE_FREETYPE_H
39 #include <freetype/freetype.h>
40 #endif
41 #ifdef HAVE_FREETYPE_FTGLYPH_H
42 #include <freetype/ftglyph.h>
43 #endif
44 #ifdef HAVE_FREETYPE_TTTABLES_H
45 #include <freetype/tttables.h>
46 #endif
47 #ifdef HAVE_FREETYPE_FTSNAMES_H
48 #include <freetype/ftsnames.h>
49 #else
50 # ifdef HAVE_FREETYPE_FTNAMES_H
51 # include <freetype/ftnames.h>
52 # endif
53 #endif
54 #ifdef HAVE_FREETYPE_TTNAMEID_H
55 #include <freetype/ttnameid.h>
56 #endif
58 #include <sys/types.h>
59 #include <dirent.h>
60 #include <string.h>
61 #include <stdio.h>
62 #include <errno.h>
64 #include "windef.h"
65 #include "winerror.h"
66 #include "winreg.h"
67 #include "psdrv.h"
68 #include "wine/debug.h"
70 WINE_DEFAULT_DEBUG_CHANNEL(psdrv);
72 #define REQUIRED_FACE_FLAGS ( FT_FACE_FLAG_SCALABLE | \
73 FT_FACE_FLAG_HORIZONTAL | \
74 FT_FACE_FLAG_SFNT | \
75 FT_FACE_FLAG_GLYPH_NAMES )
77 #define GLYPH_LOAD_FLAGS ( FT_LOAD_NO_SCALE | \
78 FT_LOAD_IGNORE_TRANSFORM | \
79 FT_LOAD_LINEAR_DESIGN )
81 #ifndef SONAME_LIBFREETYPE
82 #define SONAME_LIBFREETYPE "libfreetype.so"
83 #endif
85 static void *ft_handle = NULL;
87 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL;
88 MAKE_FUNCPTR(FT_Done_Face)
89 MAKE_FUNCPTR(FT_Done_FreeType)
90 MAKE_FUNCPTR(FT_Get_Char_Index)
91 MAKE_FUNCPTR(FT_Get_Glyph_Name)
92 MAKE_FUNCPTR(FT_Get_Sfnt_Name)
93 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count)
94 MAKE_FUNCPTR(FT_Get_Sfnt_Table)
95 MAKE_FUNCPTR(FT_Init_FreeType)
96 MAKE_FUNCPTR(FT_Load_Glyph)
97 MAKE_FUNCPTR(FT_New_Face)
98 MAKE_FUNCPTR(FT_Set_Charmap)
99 #undef MAKE_FUNCPTR
101 /*******************************************************************************
102 * FindCharMap
104 * Finds Windows character map and creates "EncodingScheme" string. Returns
105 * FALSE to indicate memory allocation or FreeType error; sets *p_charmap to
106 * NULL if no Windows encoding is present.
108 * Returns Unicode character map if present; otherwise uses the first Windows
109 * character map found.
112 static const LPCSTR encoding_names[7] =
114 "WindowsSymbol", /* TT_MS_ID_SYMBOL_CS */
115 "WindowsUnicode", /* TT_MS_ID_UNICODE_CS */
116 "WindowsShiftJIS", /* TT_MS_ID_SJIS */
117 "WindowsPRC", /* TT_MS_ID_GB2312 */
118 "WindowsBig5", /* TT_MS_ID_BIG_5 */
119 "WindowsWansung", /* TT_MS_ID_WANSUNG */
120 "WindowsJohab" /* TT_MS_ID_JOHAB */
121 /* "WindowsUnknown65535" is the longest possible (encoding_id is a UShort) */
124 static BOOL FindCharMap(FT_Face face, FT_CharMap *p_charmap, LPSTR *p_sz)
126 FT_Int i;
127 FT_Error error;
128 FT_CharMap charmap = NULL;
130 for (i = 0; i < face->num_charmaps; ++i)
132 if (face->charmaps[i]->platform_id != TT_PLATFORM_MICROSOFT)
133 continue;
135 if (face->charmaps[i]->encoding_id == TT_MS_ID_UNICODE_CS)
137 charmap = face->charmaps[i];
138 break;
141 if (charmap == NULL)
142 charmap = face->charmaps[i];
145 *p_charmap = charmap;
147 if (charmap == NULL)
149 WARN("No Windows character map found\n");
150 return TRUE;
153 error = pFT_Set_Charmap(face, charmap);
154 if (error != FT_Err_Ok)
156 ERR("%s returned %i\n", "FT_Set_Charmap", error);
157 return FALSE;
160 *p_sz = HeapAlloc(PSDRV_Heap, 0, sizeof("WindowsUnknown65535"));
161 if (*p_sz == NULL)
162 return FALSE;
164 if (charmap->encoding_id < 7)
165 strcpy(*p_sz, encoding_names[charmap->encoding_id]);
166 else
167 sprintf(*p_sz, "%s%u", "WindowsUnknown", charmap->encoding_id);
169 return TRUE;
172 /*******************************************************************************
173 * MSTTStrToSz
175 * Converts a string in the TrueType NAME table to a null-terminated ASCII
176 * character string. Space for the string is allocated from the driver heap.
177 * Only handles platform_id = 3 (TT_PLATFORM_MICROSOFT) strings (16-bit, big
178 * endian). It also only handles ASCII character codes (< 128).
180 * Sets *p_sz to NULL if string cannot be converted; only returns FALSE for
181 * memory allocation failure.
184 static BOOL MSTTStrToSz(const FT_SfntName *name, LPSTR *p_sz)
186 FT_UShort i;
187 INT len;
188 BYTE *wsz;
189 LPSTR sz;
191 len = name->string_len / 2; /* # of 16-bit chars */
193 *p_sz = sz = HeapAlloc(PSDRV_Heap, 0, len + 1);
194 if (sz == NULL)
195 return FALSE;
197 wsz = (BYTE *)name->string;
199 for (i = 0; i < len; ++i, ++sz)
201 USHORT wc = (wsz[0] << 8) + wsz[1];
202 wsz += 2;
204 if (wc > 127)
206 WARN("Non-ASCII character 0x%.4x\n", wc);
207 HeapFree(PSDRV_Heap, 0, *p_sz);
208 *p_sz = NULL;
209 return TRUE;
212 *sz = (CHAR)wc;
215 *sz = '\0';
217 return TRUE;
220 /*******************************************************************************
221 * FindMSTTString
223 * Finds the requested Microsoft platform string in the TrueType NAME table and
224 * converts it to a null-terminated ASCII string. Currently looks for U.S.
225 * English names only.
227 * Sets string to NULL if not present or cannot be converted; returns FALSE
228 * only for memory allocation failure.
231 static BOOL FindMSTTString(FT_Face face, FT_CharMap charmap, FT_UShort name_id,
232 LPSTR *p_sz)
234 FT_UInt num_strings, string_index;
235 FT_SfntName name;
236 FT_Error error;
238 num_strings = pFT_Get_Sfnt_Name_Count(face);
240 for (string_index = 0; string_index < num_strings; ++string_index)
242 error = pFT_Get_Sfnt_Name(face, string_index, &name);
243 if (error != FT_Err_Ok)
245 ERR("%s returned %i\n", "FT_Get_Sfnt_Name", error);
246 return FALSE;
249 /* FIXME - Handle other languages? */
251 if (name.platform_id != TT_PLATFORM_MICROSOFT ||
252 name.language_id != TT_MS_LANGID_ENGLISH_UNITED_STATES)
253 continue;
255 if (name.platform_id != charmap->platform_id ||
256 name.encoding_id != charmap->encoding_id)
257 continue;
259 if (name.name_id != name_id)
260 continue;
262 return MSTTStrToSz(&name, p_sz);
265 *p_sz = NULL; /* didn't find it */
267 return TRUE;
270 /*******************************************************************************
271 * PSUnits
273 * Convert TrueType font units (relative to font em square) to PostScript
274 * units.
277 inline static float PSUnits(LONG x, USHORT em_size)
279 return 1000.0 * (float)x / (float)em_size;
282 /*******************************************************************************
283 * StartAFM
285 * Allocates space for the AFM on the driver heap and reads basic font metrics
286 * from the HEAD, POST, HHEA, and OS/2 tables. Returns FALSE for memory
287 * allocation error; sets *p_afm to NULL if required information is missing.
290 static BOOL StartAFM(FT_Face face, AFM **p_afm)
292 TT_Header *head;
293 TT_Postscript *post;
294 TT_OS2 *os2;
295 TT_HoriHeader *hhea;
296 USHORT em_size;
297 AFM *afm;
299 head = pFT_Get_Sfnt_Table(face, ft_sfnt_head);
300 post = pFT_Get_Sfnt_Table(face, ft_sfnt_post);
301 os2 = pFT_Get_Sfnt_Table(face, ft_sfnt_os2);
302 hhea = pFT_Get_Sfnt_Table(face, ft_sfnt_hhea);
304 if (head == NULL || post == NULL || os2 == NULL || hhea == NULL ||
305 os2->version == 0xffff) /* old Macintosh font */
307 WARN("Required table(s) missing\n");
308 *p_afm = NULL;
309 return TRUE;
312 *p_afm = afm = HeapAlloc(PSDRV_Heap, 0, sizeof(*afm));
313 if (afm == NULL)
314 return FALSE;
316 afm->WinMetrics.usUnitsPerEm = em_size = head->Units_Per_EM;
317 afm->WinMetrics.sAscender = hhea->Ascender;
318 afm->WinMetrics.sDescender = hhea->Descender;
319 afm->WinMetrics.sLineGap = hhea->Line_Gap;
320 afm->WinMetrics.sTypoAscender = os2->sTypoAscender;
321 afm->WinMetrics.sTypoDescender = os2->sTypoDescender;
322 afm->WinMetrics.sTypoLineGap = os2->sTypoLineGap;
323 afm->WinMetrics.usWinAscent = os2->usWinAscent;
324 afm->WinMetrics.usWinDescent = os2->usWinDescent;
325 afm->WinMetrics.sAvgCharWidth = os2->xAvgCharWidth;
327 afm->Weight = os2->usWeightClass;
328 afm->ItalicAngle = ((float)(post->italicAngle)) / 65536.0;
329 afm->IsFixedPitch = (post-> isFixedPitch == 0) ? FALSE : TRUE;
330 afm->UnderlinePosition = PSUnits(post->underlinePosition, em_size);
331 afm->UnderlineThickness = PSUnits(post->underlineThickness, em_size);
333 afm->FontBBox.llx = PSUnits(head->xMin, em_size);
334 afm->FontBBox.lly = PSUnits(head->yMin, em_size);
335 afm->FontBBox.urx = PSUnits(head->xMax, em_size);
336 afm->FontBBox.ury = PSUnits(head->yMax, em_size);
338 afm->Ascender = PSUnits(os2->sTypoAscender, em_size);
339 afm->Descender = PSUnits(os2->sTypoDescender, em_size);
341 return TRUE;
344 /*******************************************************************************
345 * ReadCharMetrics
347 * Reads metrics for each glyph in a TrueType font. Returns false for memory
348 * allocation or FreeType error; sets *p_metrics to NULL for non-fatal error.
351 static BOOL ReadCharMetrics(FT_Face face, AFM *afm, AFMMETRICS **p_metrics)
353 FT_ULong charcode, index;
354 AFMMETRICS *metrics;
355 USHORT em_size = afm->WinMetrics.usUnitsPerEm;
357 for (charcode = 0, index = 0; charcode < 65536; ++charcode)
358 if (pFT_Get_Char_Index(face, charcode) != 0)
359 ++index; /* count # of glyphs */
361 afm->NumofMetrics = index;
363 *p_metrics = metrics = HeapAlloc(PSDRV_Heap, 0, index * sizeof(*metrics));
364 if (metrics == NULL)
365 return FALSE;
367 for (charcode = 0, index = 0; charcode < 65536; ++charcode)
369 FT_UInt glyph_index = pFT_Get_Char_Index(face, charcode);
370 FT_Error error;
371 CHAR buffer[128]; /* for glyph names */
373 if (glyph_index == 0)
374 continue;
376 error = pFT_Load_Glyph(face, glyph_index, GLYPH_LOAD_FLAGS);
377 if (error != FT_Err_Ok)
379 ERR("%s returned %i\n", "FT_Load_Glyph", error);
380 goto cleanup;
383 error = pFT_Get_Glyph_Name(face, glyph_index, buffer, sizeof(buffer));
384 if (error != FT_Err_Ok)
386 ERR("%s returned %i\n", "FT_Get_Glyph_Name", error);
387 goto cleanup;
390 metrics[index].N = PSDRV_GlyphName(buffer);
391 if (metrics[index].N == NULL)
392 goto cleanup;
394 metrics[index].C = metrics[index].UV = charcode;
395 metrics[index].WX = PSUnits(face->glyph->metrics.horiAdvance, em_size);
397 ++index;
400 if (afm->WinMetrics.sAvgCharWidth == 0)
401 afm->WinMetrics.sAvgCharWidth = PSDRV_CalcAvgCharWidth(afm);
403 return TRUE;
405 cleanup:
406 HeapFree(PSDRV_Heap, 0, metrics);
408 return FALSE;
411 /*******************************************************************************
412 * BuildTrueTypeAFM
414 * Builds the AFM for a TrueType font and adds it to the driver font list.
415 * Returns FALSE only on an unexpected error (memory allocation failure or
416 * FreeType error).
419 static BOOL BuildTrueTypeAFM(FT_Face face)
421 AFM *afm;
422 AFMMETRICS *metrics;
423 LPSTR font_name, full_name, family_name, encoding_scheme;
424 FT_CharMap charmap;
425 BOOL retval, added;
427 retval = StartAFM(face, &afm);
428 if (retval == FALSE || afm == NULL)
429 return retval;
431 retval = FindCharMap(face, &charmap, &encoding_scheme);
432 if (retval == FALSE || charmap == NULL)
433 goto cleanup_afm;
435 retval = FindMSTTString(face, charmap, TT_NAME_ID_PS_NAME, &font_name);
436 if (retval == FALSE || font_name == NULL)
437 goto cleanup_encoding_scheme;
439 retval = FindMSTTString(face, charmap, TT_NAME_ID_FULL_NAME, &full_name);
440 if (retval == FALSE || full_name == NULL)
441 goto cleanup_font_name;
443 retval = FindMSTTString(face, charmap, TT_NAME_ID_FONT_FAMILY,
444 &family_name);
445 if (retval == FALSE || family_name == NULL)
446 goto cleanup_full_name;
448 retval = ReadCharMetrics(face, afm, &metrics);
449 if (retval == FALSE || metrics == NULL)
450 goto cleanup_family_name;
452 afm->EncodingScheme = encoding_scheme; afm->FontName = font_name;
453 afm->FullName = full_name; afm->FamilyName = family_name;
454 afm->Metrics = metrics;
456 retval = PSDRV_AddAFMtoList(&PSDRV_AFMFontList, afm, &added);
457 if (retval == FALSE || added == FALSE)
458 goto cleanup_family_name;
460 return TRUE;
462 /* clean up after fatal or non-fatal errors */
464 cleanup_family_name:
465 HeapFree(PSDRV_Heap, 0, family_name);
466 cleanup_full_name:
467 HeapFree(PSDRV_Heap, 0, full_name);
468 cleanup_font_name:
469 HeapFree(PSDRV_Heap, 0, font_name);
470 cleanup_encoding_scheme:
471 HeapFree(PSDRV_Heap, 0, encoding_scheme);
472 cleanup_afm:
473 HeapFree(PSDRV_Heap, 0, afm);
475 return retval;
478 /*******************************************************************************
479 * ReadTrueTypeFile
481 * Reads font metrics from TrueType font file. Only returns FALSE for
482 * unexpected errors (memory allocation failure or FreeType error).
485 static BOOL ReadTrueTypeFile(FT_Library library, LPCSTR filename)
487 FT_Error error;
488 FT_Face face;
490 TRACE("%s\n", filename);
492 error = pFT_New_Face(library, filename, 0, &face);
493 if (error != FT_Err_Ok)
495 WARN("FreeType error %i opening %s\n", error, filename);
496 return TRUE;
499 if ((face->face_flags & REQUIRED_FACE_FLAGS) == REQUIRED_FACE_FLAGS)
501 if (BuildTrueTypeAFM(face) == FALSE)
503 pFT_Done_Face(face);
504 return FALSE;
507 else
509 WARN("Required information missing from %s\n", filename);
512 error = pFT_Done_Face(face);
513 if (error != FT_Err_Ok)
515 ERR("%s returned %i\n", "FT_Done_Face", error);
516 return FALSE;
519 return TRUE;
522 /*******************************************************************************
523 * ReadTrueTypeDir
525 * Reads all TrueType font files in a directory.
528 static BOOL ReadTrueTypeDir(FT_Library library, LPCSTR dirname)
530 struct dirent *dent;
531 DIR *dir;
532 CHAR filename[256];
534 dir = opendir(dirname);
535 if (dir == NULL)
537 WARN("'%s' opening %s\n", strerror(errno), dirname);
538 return TRUE;
541 while ((dent = readdir(dir)) != NULL)
543 CHAR *file_extension = strrchr(dent->d_name, '.');
544 int fn_len;
546 if (file_extension == NULL || strcasecmp(file_extension, ".ttf") != 0)
547 continue;
549 fn_len = snprintf(filename, 256, "%s/%s", dirname, dent->d_name);
550 if (fn_len < 0 || fn_len > sizeof(filename) - 1)
552 WARN("Path '%s/%s' is too long\n", dirname, dent->d_name);
553 continue;
556 if (ReadTrueTypeFile(library, filename) == FALSE)
558 closedir(dir);
559 return FALSE;
563 closedir(dir);
565 return TRUE;
568 /*******************************************************************************
569 * PSDRV_GetTrueTypeMetrics
571 * Reads font metrics from TrueType font files in directories listed in the
572 * [TrueType Font Directories] section of the Wine configuration file.
574 * If this function fails (returns FALSE), the driver will fail to initialize
575 * and the driver heap will be destroyed, so it's not necessary to HeapFree
576 * everything in that event.
579 BOOL PSDRV_GetTrueTypeMetrics(void)
581 CHAR name_buf[256], value_buf[256];
582 INT i = 0;
583 FT_Error error;
584 FT_Library library;
585 HKEY hkey;
586 DWORD type, name_len, value_len;
588 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,
589 "Software\\Wine\\Wine\\Config\\TrueType Font Directories",
590 0, KEY_READ, &hkey) != ERROR_SUCCESS)
591 return TRUE;
594 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
595 if(!ft_handle) {
596 WINE_MESSAGE(
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");
601 return TRUE;
604 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(ft_handle, #f, NULL, 0)) == NULL) goto sym_not_found;
605 LOAD_FUNCPTR(FT_Done_Face)
606 LOAD_FUNCPTR(FT_Done_FreeType)
607 LOAD_FUNCPTR(FT_Get_Char_Index)
608 LOAD_FUNCPTR(FT_Get_Glyph_Name)
609 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
610 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
611 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
612 LOAD_FUNCPTR(FT_Init_FreeType)
613 LOAD_FUNCPTR(FT_Load_Glyph)
614 LOAD_FUNCPTR(FT_New_Face)
615 LOAD_FUNCPTR(FT_Set_Charmap)
616 #undef LOAD_FUNCPTR
618 error = pFT_Init_FreeType(&library);
619 if (error != FT_Err_Ok)
621 ERR("%s returned %i\n", "FT_Init_FreeType", error);
622 wine_dlclose(ft_handle, NULL, 0);
623 RegCloseKey(hkey);
624 return FALSE;
627 name_len = sizeof(name_buf);
628 value_len = sizeof(value_buf);
630 while (RegEnumValueA(hkey, i++, name_buf, &name_len, NULL, &type, value_buf,
631 &value_len) == ERROR_SUCCESS)
633 value_buf[sizeof(value_buf) - 1] = '\0';
635 if (ReadTrueTypeDir(library, value_buf) == FALSE)
637 RegCloseKey(hkey);
638 pFT_Done_FreeType(library);
639 return FALSE;
642 /* initialize lengths for new iteration */
644 name_len = sizeof(name_buf);
645 value_len = sizeof(value_buf);
648 RegCloseKey(hkey);
649 pFT_Done_FreeType(library);
650 wine_dlclose(ft_handle, NULL, 0);
651 ft_handle = NULL;
652 return TRUE;
654 sym_not_found:
655 WINE_MESSAGE(
656 "Wine cannot find certain functions that it needs inside the FreeType\n"
657 "font library. To enable Wine to use TrueType fonts please upgrade\n"
658 "FreeType to at least version 2.0.5.\n"
659 "http://www.freetype.org\n");
660 wine_dlclose(ft_handle, NULL, 0);
661 ft_handle = NULL;
662 return TRUE;
665 #endif /* HAVE_FREETYPE */