mscms: One more LastError code fixed.
[wine.git] / dlls / wineps / truetype.c
blob373bc1da49dbe33d33031782e26f86b9ab5b8c6f
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_FT2BUILD_H
39 #include <ft2build.h>
40 #endif
41 #ifdef HAVE_FREETYPE_FREETYPE_H
42 #include <freetype/freetype.h>
43 #endif
44 #ifdef HAVE_FREETYPE_FTGLYPH_H
45 #include <freetype/ftglyph.h>
46 #endif
47 #ifdef HAVE_FREETYPE_TTTABLES_H
48 #include <freetype/tttables.h>
49 #endif
50 #ifdef HAVE_FREETYPE_FTSNAMES_H
51 #include <freetype/ftsnames.h>
52 #else
53 # ifdef HAVE_FREETYPE_FTNAMES_H
54 # include <freetype/ftnames.h>
55 # endif
56 #endif
57 #ifdef HAVE_FREETYPE_TTNAMEID_H
58 #include <freetype/ttnameid.h>
59 #endif
61 #include <sys/types.h>
62 #include <dirent.h>
63 #include <string.h>
64 #include <stdarg.h>
65 #include <stdio.h>
66 #include <errno.h>
68 #include "windef.h"
69 #include "winbase.h"
70 #include "winerror.h"
71 #include "winreg.h"
72 #include "psdrv.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 | \
79 FT_FACE_FLAG_SFNT | \
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 #ifndef SONAME_LIBFREETYPE
87 #define SONAME_LIBFREETYPE "libfreetype.so"
88 #endif
90 static void *ft_handle = NULL;
92 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL;
93 MAKE_FUNCPTR(FT_Done_Face)
94 MAKE_FUNCPTR(FT_Done_FreeType)
95 MAKE_FUNCPTR(FT_Get_Char_Index)
96 MAKE_FUNCPTR(FT_Get_Glyph_Name)
97 MAKE_FUNCPTR(FT_Get_Sfnt_Name)
98 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count)
99 MAKE_FUNCPTR(FT_Get_Sfnt_Table)
100 MAKE_FUNCPTR(FT_Init_FreeType)
101 MAKE_FUNCPTR(FT_Load_Glyph)
102 MAKE_FUNCPTR(FT_New_Face)
103 MAKE_FUNCPTR(FT_Set_Charmap)
104 #undef MAKE_FUNCPTR
106 /*******************************************************************************
107 * FindCharMap
109 * Finds Windows character map and creates "EncodingScheme" string. Returns
110 * FALSE to indicate memory allocation or FreeType error; sets *p_charmap to
111 * NULL if no Windows encoding is present.
113 * Returns Unicode character map if present; otherwise uses the first Windows
114 * character map found.
117 static const LPCSTR encoding_names[7] =
119 "WindowsSymbol", /* TT_MS_ID_SYMBOL_CS */
120 "WindowsUnicode", /* TT_MS_ID_UNICODE_CS */
121 "WindowsShiftJIS", /* TT_MS_ID_SJIS */
122 "WindowsPRC", /* TT_MS_ID_GB2312 */
123 "WindowsBig5", /* TT_MS_ID_BIG_5 */
124 "WindowsWansung", /* TT_MS_ID_WANSUNG */
125 "WindowsJohab" /* TT_MS_ID_JOHAB */
126 /* "WindowsUnknown65535" is the longest possible (encoding_id is a UShort) */
129 static BOOL FindCharMap(FT_Face face, FT_CharMap *p_charmap, LPSTR *p_sz)
131 FT_Int i;
132 FT_Error error;
133 FT_CharMap charmap = NULL;
135 for (i = 0; i < face->num_charmaps; ++i)
137 if (face->charmaps[i]->platform_id != TT_PLATFORM_MICROSOFT)
138 continue;
140 if (face->charmaps[i]->encoding_id == TT_MS_ID_UNICODE_CS)
142 charmap = face->charmaps[i];
143 break;
146 if (charmap == NULL)
147 charmap = face->charmaps[i];
150 *p_charmap = charmap;
152 if (charmap == NULL)
154 WARN("No Windows character map found\n");
155 return TRUE;
158 error = pFT_Set_Charmap(face, charmap);
159 if (error != FT_Err_Ok)
161 ERR("%s returned %i\n", "FT_Set_Charmap", error);
162 return FALSE;
165 *p_sz = HeapAlloc(PSDRV_Heap, 0, sizeof("WindowsUnknown65535"));
166 if (*p_sz == NULL)
167 return FALSE;
169 if (charmap->encoding_id < 7)
170 strcpy(*p_sz, encoding_names[charmap->encoding_id]);
171 else
172 sprintf(*p_sz, "%s%u", "WindowsUnknown", charmap->encoding_id);
174 return TRUE;
177 /*******************************************************************************
178 * MSTTStrToSz
180 * Converts a string in the TrueType NAME table to a null-terminated ASCII
181 * character string. Space for the string is allocated from the driver heap.
182 * Only handles platform_id = 3 (TT_PLATFORM_MICROSOFT) strings (16-bit, big
183 * endian). It also only handles ASCII character codes (< 128).
185 * Sets *p_sz to NULL if string cannot be converted; only returns FALSE for
186 * memory allocation failure.
189 static BOOL MSTTStrToSz(const FT_SfntName *name, LPSTR *p_sz)
191 FT_UShort i;
192 INT len;
193 BYTE *wsz;
194 LPSTR sz;
196 len = name->string_len / 2; /* # of 16-bit chars */
198 *p_sz = sz = HeapAlloc(PSDRV_Heap, 0, len + 1);
199 if (sz == NULL)
200 return FALSE;
202 wsz = (BYTE *)name->string;
204 for (i = 0; i < len; ++i, ++sz)
206 USHORT wc = (wsz[0] << 8) + wsz[1];
207 wsz += 2;
209 if (wc > 127)
211 WARN("Non-ASCII character 0x%.4x\n", wc);
212 HeapFree(PSDRV_Heap, 0, *p_sz);
213 *p_sz = NULL;
214 return TRUE;
217 *sz = (CHAR)wc;
220 *sz = '\0';
222 return TRUE;
225 /*******************************************************************************
226 * FindMSTTString
228 * Finds the requested Microsoft platform string in the TrueType NAME table and
229 * converts it to a null-terminated ASCII string. Currently looks for U.S.
230 * English names only.
232 * Sets string to NULL if not present or cannot be converted; returns FALSE
233 * only for memory allocation failure.
236 static BOOL FindMSTTString(FT_Face face, FT_CharMap charmap, FT_UShort name_id,
237 LPSTR *p_sz)
239 FT_UInt num_strings, string_index;
240 FT_SfntName name;
241 FT_Error error;
243 num_strings = pFT_Get_Sfnt_Name_Count(face);
245 for (string_index = 0; string_index < num_strings; ++string_index)
247 error = pFT_Get_Sfnt_Name(face, string_index, &name);
248 if (error != FT_Err_Ok)
250 ERR("%s returned %i\n", "FT_Get_Sfnt_Name", error);
251 return FALSE;
254 /* FIXME - Handle other languages? */
256 if (name.platform_id != TT_PLATFORM_MICROSOFT ||
257 name.language_id != TT_MS_LANGID_ENGLISH_UNITED_STATES)
258 continue;
260 if (name.platform_id != charmap->platform_id ||
261 name.encoding_id != charmap->encoding_id)
262 continue;
264 if (name.name_id != name_id)
265 continue;
267 return MSTTStrToSz(&name, p_sz);
270 *p_sz = NULL; /* didn't find it */
272 return TRUE;
275 /*******************************************************************************
276 * PSUnits
278 * Convert TrueType font units (relative to font em square) to PostScript
279 * units.
282 inline static float PSUnits(LONG x, USHORT em_size)
284 return 1000.0 * (float)x / (float)em_size;
287 /*******************************************************************************
288 * StartAFM
290 * Allocates space for the AFM on the driver heap and reads basic font metrics
291 * from the HEAD, POST, HHEA, and OS/2 tables. Returns FALSE for memory
292 * allocation error; sets *p_afm to NULL if required information is missing.
295 static BOOL StartAFM(FT_Face face, AFM **p_afm)
297 TT_Header *head;
298 TT_Postscript *post;
299 TT_OS2 *os2;
300 TT_HoriHeader *hhea;
301 USHORT em_size;
302 AFM *afm;
304 head = pFT_Get_Sfnt_Table(face, ft_sfnt_head);
305 post = pFT_Get_Sfnt_Table(face, ft_sfnt_post);
306 os2 = pFT_Get_Sfnt_Table(face, ft_sfnt_os2);
307 hhea = pFT_Get_Sfnt_Table(face, ft_sfnt_hhea);
309 if (head == NULL || post == NULL || os2 == NULL || hhea == NULL ||
310 os2->version == 0xffff) /* old Macintosh font */
312 WARN("Required table(s) missing\n");
313 *p_afm = NULL;
314 return TRUE;
317 *p_afm = afm = HeapAlloc(PSDRV_Heap, 0, sizeof(*afm));
318 if (afm == NULL)
319 return FALSE;
321 afm->WinMetrics.usUnitsPerEm = em_size = head->Units_Per_EM;
322 afm->WinMetrics.sAscender = hhea->Ascender;
323 afm->WinMetrics.sDescender = hhea->Descender;
324 afm->WinMetrics.sLineGap = hhea->Line_Gap;
325 afm->WinMetrics.sTypoAscender = os2->sTypoAscender;
326 afm->WinMetrics.sTypoDescender = os2->sTypoDescender;
327 afm->WinMetrics.sTypoLineGap = os2->sTypoLineGap;
328 afm->WinMetrics.usWinAscent = os2->usWinAscent;
329 afm->WinMetrics.usWinDescent = os2->usWinDescent;
330 afm->WinMetrics.sAvgCharWidth = os2->xAvgCharWidth;
332 afm->Weight = os2->usWeightClass;
333 afm->ItalicAngle = ((float)(post->italicAngle)) / 65536.0;
334 afm->IsFixedPitch = (post-> isFixedPitch == 0) ? FALSE : TRUE;
335 afm->UnderlinePosition = PSUnits(post->underlinePosition, em_size);
336 afm->UnderlineThickness = PSUnits(post->underlineThickness, em_size);
338 afm->FontBBox.llx = PSUnits(head->xMin, em_size);
339 afm->FontBBox.lly = PSUnits(head->yMin, em_size);
340 afm->FontBBox.urx = PSUnits(head->xMax, em_size);
341 afm->FontBBox.ury = PSUnits(head->yMax, em_size);
343 afm->Ascender = PSUnits(os2->sTypoAscender, em_size);
344 afm->Descender = PSUnits(os2->sTypoDescender, em_size);
346 return TRUE;
349 /*******************************************************************************
350 * ReadCharMetrics
352 * Reads metrics for each glyph in a TrueType font. Returns false for memory
353 * allocation or FreeType error; sets *p_metrics to NULL for non-fatal error.
356 static BOOL ReadCharMetrics(FT_Face face, AFM *afm, AFMMETRICS **p_metrics)
358 FT_ULong charcode, index;
359 AFMMETRICS *metrics;
360 USHORT em_size = afm->WinMetrics.usUnitsPerEm;
362 for (charcode = 0, index = 0; charcode < 65536; ++charcode)
363 if (pFT_Get_Char_Index(face, charcode) != 0)
364 ++index; /* count # of glyphs */
366 afm->NumofMetrics = index;
368 *p_metrics = metrics = HeapAlloc(PSDRV_Heap, 0, index * sizeof(*metrics));
369 if (metrics == NULL)
370 return FALSE;
372 for (charcode = 0, index = 0; charcode < 65536; ++charcode)
374 FT_UInt glyph_index = pFT_Get_Char_Index(face, charcode);
375 FT_Error error;
376 CHAR buffer[128]; /* for glyph names */
378 if (glyph_index == 0)
379 continue;
381 error = pFT_Load_Glyph(face, glyph_index, GLYPH_LOAD_FLAGS);
382 if (error != FT_Err_Ok)
384 ERR("%s returned %i\n", "FT_Load_Glyph", error);
385 goto cleanup;
388 error = pFT_Get_Glyph_Name(face, glyph_index, buffer, sizeof(buffer));
389 if (error != FT_Err_Ok)
391 ERR("%s returned %i\n", "FT_Get_Glyph_Name", error);
392 goto cleanup;
395 metrics[index].N = PSDRV_GlyphName(buffer);
396 if (metrics[index].N == NULL)
397 goto cleanup;
399 metrics[index].C = metrics[index].UV = charcode;
400 metrics[index].WX = PSUnits(face->glyph->metrics.horiAdvance, em_size);
402 ++index;
405 if (afm->WinMetrics.sAvgCharWidth == 0)
406 afm->WinMetrics.sAvgCharWidth = PSDRV_CalcAvgCharWidth(afm);
408 return TRUE;
410 cleanup:
411 HeapFree(PSDRV_Heap, 0, metrics);
413 return FALSE;
416 /*******************************************************************************
417 * BuildTrueTypeAFM
419 * Builds the AFM for a TrueType font and adds it to the driver font list.
420 * Returns FALSE only on an unexpected error (memory allocation failure or
421 * FreeType error).
424 static BOOL BuildTrueTypeAFM(FT_Face face)
426 AFM *afm;
427 AFMMETRICS *metrics;
428 LPSTR font_name, full_name, family_name, encoding_scheme = NULL;
429 FT_CharMap charmap;
430 BOOL retval, added;
432 retval = StartAFM(face, &afm);
433 if (retval == FALSE || afm == NULL)
434 return retval;
436 retval = FindCharMap(face, &charmap, &encoding_scheme);
437 if (retval == FALSE || charmap == NULL)
438 goto cleanup_afm;
440 retval = FindMSTTString(face, charmap, TT_NAME_ID_PS_NAME, &font_name);
441 if (retval == FALSE || font_name == NULL)
442 goto cleanup_encoding_scheme;
444 retval = FindMSTTString(face, charmap, TT_NAME_ID_FULL_NAME, &full_name);
445 if (retval == FALSE || full_name == NULL)
446 goto cleanup_font_name;
448 retval = FindMSTTString(face, charmap, TT_NAME_ID_FONT_FAMILY,
449 &family_name);
450 if (retval == FALSE || family_name == NULL)
451 goto cleanup_full_name;
453 retval = ReadCharMetrics(face, afm, &metrics);
454 if (retval == FALSE || metrics == NULL)
455 goto cleanup_family_name;
457 afm->EncodingScheme = encoding_scheme; afm->FontName = font_name;
458 afm->FullName = full_name; afm->FamilyName = family_name;
459 afm->Metrics = metrics;
461 retval = PSDRV_AddAFMtoList(&PSDRV_AFMFontList, afm, &added);
462 if (retval == FALSE || added == FALSE)
463 goto cleanup_family_name;
465 return TRUE;
467 /* clean up after fatal or non-fatal errors */
469 cleanup_family_name:
470 HeapFree(PSDRV_Heap, 0, family_name);
471 cleanup_full_name:
472 HeapFree(PSDRV_Heap, 0, full_name);
473 cleanup_font_name:
474 HeapFree(PSDRV_Heap, 0, font_name);
475 cleanup_encoding_scheme:
476 HeapFree(PSDRV_Heap, 0, encoding_scheme);
477 cleanup_afm:
478 HeapFree(PSDRV_Heap, 0, afm);
480 return retval;
483 /*******************************************************************************
484 * ReadTrueTypeFile
486 * Reads font metrics from TrueType font file. Only returns FALSE for
487 * unexpected errors (memory allocation failure or FreeType error).
490 static BOOL ReadTrueTypeFile(FT_Library library, LPCSTR filename)
492 FT_Error error;
493 FT_Face face;
495 TRACE("%s\n", filename);
497 error = pFT_New_Face(library, filename, 0, &face);
498 if (error != FT_Err_Ok)
500 WARN("FreeType error %i opening %s\n", error, filename);
501 return TRUE;
504 if ((face->face_flags & REQUIRED_FACE_FLAGS) == REQUIRED_FACE_FLAGS)
506 if (BuildTrueTypeAFM(face) == FALSE)
508 pFT_Done_Face(face);
509 return FALSE;
512 else
514 WARN("Required information missing from %s\n", filename);
517 error = pFT_Done_Face(face);
518 if (error != FT_Err_Ok)
520 ERR("%s returned %i\n", "FT_Done_Face", error);
521 return FALSE;
524 return TRUE;
527 /*******************************************************************************
528 * ReadTrueTypeDir
530 * Reads all TrueType font files in a directory.
533 static BOOL ReadTrueTypeDir(FT_Library library, LPCSTR dirname)
535 struct dirent *dent;
536 DIR *dir;
537 CHAR filename[256];
539 dir = opendir(dirname);
540 if (dir == NULL)
542 WARN("'%s' opening %s\n", strerror(errno), dirname);
543 return TRUE;
546 while ((dent = readdir(dir)) != NULL)
548 CHAR *file_extension = strrchr(dent->d_name, '.');
549 int fn_len;
551 if (file_extension == NULL || strcasecmp(file_extension, ".ttf") != 0)
552 continue;
554 fn_len = snprintf(filename, 256, "%s/%s", dirname, dent->d_name);
555 if (fn_len < 0 || fn_len > sizeof(filename) - 1)
557 WARN("Path '%s/%s' is too long\n", dirname, dent->d_name);
558 continue;
561 if (ReadTrueTypeFile(library, filename) == FALSE)
563 closedir(dir);
564 return FALSE;
568 closedir(dir);
570 return TRUE;
573 /*******************************************************************************
574 * PSDRV_GetTrueTypeMetrics
576 * Reads font metrics from TrueType font files in directories listed in the
577 * [TrueType Font Directories] section of the Wine configuration file.
579 * If this function fails (returns FALSE), the driver will fail to initialize
580 * and the driver heap will be destroyed, so it's not necessary to HeapFree
581 * everything in that event.
584 BOOL PSDRV_GetTrueTypeMetrics(void)
586 static const WCHAR pathW[] = {'P','a','t','h',0};
587 FT_Error error;
588 FT_Library library;
589 HKEY hkey;
590 DWORD len;
591 LPWSTR valueW;
592 LPSTR valueA, ptr;
594 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
595 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) != ERROR_SUCCESS)
596 return TRUE;
598 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
599 if(!ft_handle) {
600 WINE_MESSAGE(
601 "Wine cannot find the FreeType font library. To enable Wine to\n"
602 "use TrueType fonts please install a version of FreeType greater than\n"
603 "or equal to 2.0.5.\n"
604 "http://www.freetype.org\n");
605 RegCloseKey(hkey);
606 return TRUE;
609 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(ft_handle, #f, NULL, 0)) == NULL) goto sym_not_found;
610 LOAD_FUNCPTR(FT_Done_Face)
611 LOAD_FUNCPTR(FT_Done_FreeType)
612 LOAD_FUNCPTR(FT_Get_Char_Index)
613 LOAD_FUNCPTR(FT_Get_Glyph_Name)
614 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
615 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
616 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
617 LOAD_FUNCPTR(FT_Init_FreeType)
618 LOAD_FUNCPTR(FT_Load_Glyph)
619 LOAD_FUNCPTR(FT_New_Face)
620 LOAD_FUNCPTR(FT_Set_Charmap)
621 #undef LOAD_FUNCPTR
623 error = pFT_Init_FreeType(&library);
624 if (error != FT_Err_Ok)
626 ERR("%s returned %i\n", "FT_Init_FreeType", error);
627 wine_dlclose(ft_handle, NULL, 0);
628 RegCloseKey(hkey);
629 return FALSE;
632 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
634 len += sizeof(WCHAR);
635 valueW = HeapAlloc( GetProcessHeap(), 0, len );
636 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
638 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
639 valueA = HeapAlloc( GetProcessHeap(), 0, len );
640 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
641 TRACE( "got font path %s\n", debugstr_a(valueA) );
642 ptr = valueA;
643 while (ptr)
645 LPSTR next = strchr( ptr, ':' );
646 if (next) *next++ = 0;
647 ReadTrueTypeDir( library, ptr );
648 ptr = next;
650 HeapFree( GetProcessHeap(), 0, valueA );
652 HeapFree( GetProcessHeap(), 0, valueW );
655 RegCloseKey(hkey);
656 pFT_Done_FreeType(library);
657 wine_dlclose(ft_handle, NULL, 0);
658 ft_handle = NULL;
659 return TRUE;
661 sym_not_found:
662 WINE_MESSAGE(
663 "Wine cannot find certain functions that it needs inside the FreeType\n"
664 "font library. To enable Wine to use TrueType fonts please upgrade\n"
665 "FreeType to at least version 2.0.5.\n"
666 "http://www.freetype.org\n");
667 RegCloseKey(hkey);
668 wine_dlclose(ft_handle, NULL, 0);
669 ft_handle = NULL;
670 return TRUE;
673 #endif /* HAVE_FREETYPE */