dplayx: Code to forward player creation
[wine/gsoc_dplay.git] / dlls / wineps.drv / truetype.c
blob59ebe19d6bdd5f3a3961085e2069e1d4c742ba80
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-
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 #endif
53 #ifdef HAVE_FREETYPE_TTNAMEID_H
54 #include <freetype/ttnameid.h>
55 #endif
57 #include <sys/types.h>
58 #ifdef HAVE_DIRENT_H
59 # include <dirent.h>
60 #endif
61 #include <string.h>
62 #include <stdarg.h>
63 #include <stdio.h>
64 #include <errno.h>
66 #include "windef.h"
67 #include "winbase.h"
68 #include "winerror.h"
69 #include "winreg.h"
70 #include "psdrv.h"
71 #include "wine/debug.h"
73 WINE_DEFAULT_DEBUG_CHANNEL(psdrv);
75 #define REQUIRED_FACE_FLAGS ( FT_FACE_FLAG_SCALABLE | \
76 FT_FACE_FLAG_HORIZONTAL | \
77 FT_FACE_FLAG_SFNT | \
78 FT_FACE_FLAG_GLYPH_NAMES )
80 #define GLYPH_LOAD_FLAGS ( FT_LOAD_NO_SCALE | \
81 FT_LOAD_IGNORE_TRANSFORM | \
82 FT_LOAD_LINEAR_DESIGN )
84 static void *ft_handle = NULL;
86 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL;
87 MAKE_FUNCPTR(FT_Done_Face)
88 MAKE_FUNCPTR(FT_Done_FreeType)
89 MAKE_FUNCPTR(FT_Get_Char_Index)
90 MAKE_FUNCPTR(FT_Get_Glyph_Name)
91 MAKE_FUNCPTR(FT_Get_Sfnt_Name)
92 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count)
93 MAKE_FUNCPTR(FT_Get_Sfnt_Table)
94 MAKE_FUNCPTR(FT_Init_FreeType)
95 MAKE_FUNCPTR(FT_Load_Glyph)
96 MAKE_FUNCPTR(FT_New_Face)
97 MAKE_FUNCPTR(FT_Set_Charmap)
98 #undef MAKE_FUNCPTR
100 /*******************************************************************************
101 * FindCharMap
103 * Finds Windows character map and creates "EncodingScheme" string. Returns
104 * FALSE to indicate memory allocation or FreeType error; sets *p_charmap to
105 * NULL if no Windows encoding is present.
107 * Returns Unicode character map if present; otherwise uses the first Windows
108 * character map found.
111 static const LPCSTR encoding_names[7] =
113 "WindowsSymbol", /* TT_MS_ID_SYMBOL_CS */
114 "WindowsUnicode", /* TT_MS_ID_UNICODE_CS */
115 "WindowsShiftJIS", /* TT_MS_ID_SJIS */
116 "WindowsPRC", /* TT_MS_ID_GB2312 */
117 "WindowsBig5", /* TT_MS_ID_BIG_5 */
118 "WindowsWansung", /* TT_MS_ID_WANSUNG */
119 "WindowsJohab" /* TT_MS_ID_JOHAB */
120 /* "WindowsUnknown65535" is the longest possible (encoding_id is a UShort) */
123 static BOOL FindCharMap(FT_Face face, FT_CharMap *p_charmap, LPSTR *p_sz)
125 FT_Int i;
126 FT_Error error;
127 FT_CharMap charmap = NULL;
129 for (i = 0; i < face->num_charmaps; ++i)
131 if (face->charmaps[i]->platform_id != TT_PLATFORM_MICROSOFT)
132 continue;
134 if (face->charmaps[i]->encoding_id == TT_MS_ID_UNICODE_CS)
136 charmap = face->charmaps[i];
137 break;
140 if (charmap == NULL)
141 charmap = face->charmaps[i];
144 *p_charmap = charmap;
146 if (charmap == NULL)
148 WARN("No Windows character map found\n");
149 return TRUE;
152 error = pFT_Set_Charmap(face, charmap);
153 if (error != FT_Err_Ok)
155 ERR("%s returned %i\n", "FT_Set_Charmap", error);
156 return FALSE;
159 *p_sz = HeapAlloc(PSDRV_Heap, 0, sizeof("WindowsUnknown65535"));
160 if (*p_sz == NULL)
161 return FALSE;
163 if (charmap->encoding_id < 7)
164 strcpy(*p_sz, encoding_names[charmap->encoding_id]);
165 else
166 sprintf(*p_sz, "%s%u", "WindowsUnknown", charmap->encoding_id);
168 return TRUE;
171 /*******************************************************************************
172 * MSTTStrToSz
174 * Converts a string in the TrueType NAME table to a null-terminated ASCII
175 * character string. Space for the string is allocated from the driver heap.
176 * Only handles platform_id = 3 (TT_PLATFORM_MICROSOFT) strings (16-bit, big
177 * endian). It also only handles ASCII character codes (< 128).
179 * Sets *p_sz to NULL if string cannot be converted; only returns FALSE for
180 * memory allocation failure.
183 static BOOL MSTTStrToSz(const FT_SfntName *name, LPSTR *p_sz)
185 FT_UShort i;
186 INT len;
187 BYTE *wsz;
188 LPSTR sz;
190 len = name->string_len / 2; /* # of 16-bit chars */
192 *p_sz = sz = HeapAlloc(PSDRV_Heap, 0, len + 1);
193 if (sz == NULL)
194 return FALSE;
196 wsz = (BYTE *)name->string;
198 for (i = 0; i < len; ++i, ++sz)
200 USHORT wc = (wsz[0] << 8) + wsz[1];
201 wsz += 2;
203 if (wc > 127)
205 WARN("Non-ASCII character 0x%.4x\n", wc);
206 HeapFree(PSDRV_Heap, 0, *p_sz);
207 *p_sz = NULL;
208 return TRUE;
211 *sz = (CHAR)wc;
214 *sz = '\0';
216 return TRUE;
219 /*******************************************************************************
220 * FindMSTTString
222 * Finds the requested Microsoft platform string in the TrueType NAME table and
223 * converts it to a null-terminated ASCII string. Currently looks for U.S.
224 * English names only.
226 * Sets string to NULL if not present or cannot be converted; returns FALSE
227 * only for memory allocation failure.
230 static BOOL FindMSTTString(FT_Face face, FT_CharMap charmap, FT_UShort name_id,
231 LPSTR *p_sz)
233 FT_UInt num_strings, string_index;
234 FT_SfntName name;
235 FT_Error error;
237 num_strings = pFT_Get_Sfnt_Name_Count(face);
239 for (string_index = 0; string_index < num_strings; ++string_index)
241 error = pFT_Get_Sfnt_Name(face, string_index, &name);
242 if (error != FT_Err_Ok)
244 ERR("%s returned %i\n", "FT_Get_Sfnt_Name", error);
245 return FALSE;
248 /* FIXME - Handle other languages? */
250 if (name.platform_id != TT_PLATFORM_MICROSOFT ||
251 name.language_id != TT_MS_LANGID_ENGLISH_UNITED_STATES)
252 continue;
254 if (name.platform_id != charmap->platform_id ||
255 name.encoding_id != charmap->encoding_id)
256 continue;
258 if (name.name_id != name_id)
259 continue;
261 return MSTTStrToSz(&name, p_sz);
264 *p_sz = NULL; /* didn't find it */
266 return TRUE;
269 /*******************************************************************************
270 * PSUnits
272 * Convert TrueType font units (relative to font em square) to PostScript
273 * units.
276 static inline float PSUnits(LONG x, USHORT em_size)
278 return 1000.0 * (float)x / (float)em_size;
281 /*******************************************************************************
282 * StartAFM
284 * Allocates space for the AFM on the driver heap and reads basic font metrics
285 * from the HEAD, POST, HHEA, and OS/2 tables. Returns FALSE for memory
286 * allocation error; sets *p_afm to NULL if required information is missing.
289 static BOOL StartAFM(FT_Face face, AFM **p_afm)
291 TT_Header *head;
292 TT_Postscript *post;
293 TT_OS2 *os2;
294 TT_HoriHeader *hhea;
295 USHORT em_size;
296 AFM *afm;
298 head = pFT_Get_Sfnt_Table(face, ft_sfnt_head);
299 post = pFT_Get_Sfnt_Table(face, ft_sfnt_post);
300 os2 = pFT_Get_Sfnt_Table(face, ft_sfnt_os2);
301 hhea = pFT_Get_Sfnt_Table(face, ft_sfnt_hhea);
303 if (head == NULL || post == NULL || os2 == NULL || hhea == NULL ||
304 os2->version == 0xffff) /* old Macintosh font */
306 WARN("Required table(s) missing\n");
307 *p_afm = NULL;
308 return TRUE;
311 *p_afm = afm = HeapAlloc(PSDRV_Heap, 0, sizeof(*afm));
312 if (afm == NULL)
313 return FALSE;
315 afm->WinMetrics.usUnitsPerEm = em_size = head->Units_Per_EM;
316 afm->WinMetrics.sAscender = hhea->Ascender;
317 afm->WinMetrics.sDescender = hhea->Descender;
318 afm->WinMetrics.sLineGap = hhea->Line_Gap;
319 afm->WinMetrics.sTypoAscender = os2->sTypoAscender;
320 afm->WinMetrics.sTypoDescender = os2->sTypoDescender;
321 afm->WinMetrics.sTypoLineGap = os2->sTypoLineGap;
322 afm->WinMetrics.usWinAscent = os2->usWinAscent;
323 afm->WinMetrics.usWinDescent = os2->usWinDescent;
324 afm->WinMetrics.sAvgCharWidth = os2->xAvgCharWidth;
326 afm->Weight = os2->usWeightClass;
327 afm->ItalicAngle = ((float)(post->italicAngle)) / 65536.0;
328 afm->IsFixedPitch = (post-> isFixedPitch == 0) ? FALSE : TRUE;
329 afm->UnderlinePosition = PSUnits(post->underlinePosition, em_size);
330 afm->UnderlineThickness = PSUnits(post->underlineThickness, em_size);
332 afm->FontBBox.llx = PSUnits(head->xMin, em_size);
333 afm->FontBBox.lly = PSUnits(head->yMin, em_size);
334 afm->FontBBox.urx = PSUnits(head->xMax, em_size);
335 afm->FontBBox.ury = PSUnits(head->yMax, em_size);
337 afm->Ascender = PSUnits(os2->sTypoAscender, em_size);
338 afm->Descender = PSUnits(os2->sTypoDescender, em_size);
340 return TRUE;
343 /*******************************************************************************
344 * ReadCharMetrics
346 * Reads metrics for each glyph in a TrueType font. Returns false for memory
347 * allocation or FreeType error; sets *p_metrics to NULL for non-fatal error.
350 static BOOL ReadCharMetrics(FT_Face face, AFM *afm, AFMMETRICS **p_metrics)
352 FT_ULong charcode, index;
353 AFMMETRICS *metrics;
354 USHORT em_size = afm->WinMetrics.usUnitsPerEm;
356 for (charcode = 0, index = 0; charcode < 65536; ++charcode)
357 if (pFT_Get_Char_Index(face, charcode) != 0)
358 ++index; /* count # of glyphs */
360 afm->NumofMetrics = index;
362 *p_metrics = metrics = HeapAlloc(PSDRV_Heap, 0, index * sizeof(*metrics));
363 if (metrics == NULL)
364 return FALSE;
366 for (charcode = 0, index = 0; charcode < 65536; ++charcode)
368 FT_UInt glyph_index = pFT_Get_Char_Index(face, charcode);
369 FT_Error error;
370 CHAR buffer[128]; /* for glyph names */
372 if (glyph_index == 0)
373 continue;
375 error = pFT_Load_Glyph(face, glyph_index, GLYPH_LOAD_FLAGS);
376 if (error != FT_Err_Ok)
378 ERR("%s returned %i\n", "FT_Load_Glyph", error);
379 goto cleanup;
382 error = pFT_Get_Glyph_Name(face, glyph_index, buffer, sizeof(buffer));
383 if (error != FT_Err_Ok)
385 ERR("%s returned %i\n", "FT_Get_Glyph_Name", error);
386 goto cleanup;
389 metrics[index].N = PSDRV_GlyphName(buffer);
390 if (metrics[index].N == NULL)
391 goto cleanup;
393 metrics[index].C = metrics[index].UV = charcode;
394 metrics[index].WX = PSUnits(face->glyph->metrics.horiAdvance, em_size);
396 ++index;
399 if (afm->WinMetrics.sAvgCharWidth == 0)
400 afm->WinMetrics.sAvgCharWidth = PSDRV_CalcAvgCharWidth(afm);
402 return TRUE;
404 cleanup:
405 HeapFree(PSDRV_Heap, 0, metrics);
407 return FALSE;
410 /*******************************************************************************
411 * BuildTrueTypeAFM
413 * Builds the AFM for a TrueType font and adds it to the driver font list.
414 * Returns FALSE only on an unexpected error (memory allocation failure or
415 * FreeType error).
418 static BOOL BuildTrueTypeAFM(FT_Face face)
420 AFM *afm;
421 AFMMETRICS *metrics;
422 LPSTR font_name, full_name, family_name, encoding_scheme = NULL;
423 FT_CharMap charmap;
424 BOOL retval, added;
426 retval = StartAFM(face, &afm);
427 if (retval == FALSE || afm == NULL)
428 return retval;
430 retval = FindCharMap(face, &charmap, &encoding_scheme);
431 if (retval == FALSE || charmap == NULL)
432 goto cleanup_afm;
434 retval = FindMSTTString(face, charmap, TT_NAME_ID_PS_NAME, &font_name);
435 if (retval == FALSE || font_name == NULL)
436 goto cleanup_encoding_scheme;
438 retval = FindMSTTString(face, charmap, TT_NAME_ID_FULL_NAME, &full_name);
439 if (retval == FALSE || full_name == NULL)
440 goto cleanup_font_name;
442 retval = FindMSTTString(face, charmap, TT_NAME_ID_FONT_FAMILY,
443 &family_name);
444 if (retval == FALSE || family_name == NULL)
445 goto cleanup_full_name;
447 retval = ReadCharMetrics(face, afm, &metrics);
448 if (retval == FALSE || metrics == NULL)
449 goto cleanup_family_name;
451 afm->EncodingScheme = encoding_scheme; afm->FontName = font_name;
452 afm->FullName = full_name; afm->FamilyName = family_name;
453 afm->Metrics = metrics;
455 retval = PSDRV_AddAFMtoList(&PSDRV_AFMFontList, afm, &added);
456 if (retval == FALSE || added == FALSE)
457 goto cleanup_family_name;
459 return TRUE;
461 /* clean up after fatal or non-fatal errors */
463 cleanup_family_name:
464 HeapFree(PSDRV_Heap, 0, family_name);
465 cleanup_full_name:
466 HeapFree(PSDRV_Heap, 0, full_name);
467 cleanup_font_name:
468 HeapFree(PSDRV_Heap, 0, font_name);
469 cleanup_encoding_scheme:
470 HeapFree(PSDRV_Heap, 0, encoding_scheme);
471 cleanup_afm:
472 HeapFree(PSDRV_Heap, 0, afm);
474 return retval;
477 /*******************************************************************************
478 * ReadTrueTypeFile
480 * Reads font metrics from TrueType font file. Only returns FALSE for
481 * unexpected errors (memory allocation failure or FreeType error).
484 static BOOL ReadTrueTypeFile(FT_Library library, LPCSTR filename)
486 FT_Error error;
487 FT_Face face;
489 TRACE("%s\n", filename);
491 error = pFT_New_Face(library, filename, 0, &face);
492 if (error != FT_Err_Ok)
494 WARN("FreeType error %i opening %s\n", error, filename);
495 return TRUE;
498 if ((face->face_flags & REQUIRED_FACE_FLAGS) == REQUIRED_FACE_FLAGS)
500 if (BuildTrueTypeAFM(face) == FALSE)
502 pFT_Done_Face(face);
503 return FALSE;
506 else
508 WARN("Required information missing from %s\n", filename);
511 error = pFT_Done_Face(face);
512 if (error != FT_Err_Ok)
514 ERR("%s returned %i\n", "FT_Done_Face", error);
515 return FALSE;
518 return TRUE;
521 /*******************************************************************************
522 * ReadTrueTypeDir
524 * Reads all TrueType font files in a directory.
527 static BOOL ReadTrueTypeDir(FT_Library library, LPCSTR dirname)
529 struct dirent *dent;
530 DIR *dir;
531 CHAR filename[256];
533 dir = opendir(dirname);
534 if (dir == NULL)
536 WARN("'%s' opening %s\n", strerror(errno), dirname);
537 return TRUE;
540 while ((dent = readdir(dir)) != NULL)
542 CHAR *file_extension = strrchr(dent->d_name, '.');
543 int fn_len;
545 if (file_extension == NULL || strcasecmp(file_extension, ".ttf") != 0)
546 continue;
548 fn_len = snprintf(filename, 256, "%s/%s", dirname, dent->d_name);
549 if (fn_len < 0 || fn_len > sizeof(filename) - 1)
551 WARN("Path '%s/%s' is too long\n", dirname, dent->d_name);
552 continue;
555 if (ReadTrueTypeFile(library, filename) == FALSE)
557 closedir(dir);
558 return FALSE;
562 closedir(dir);
564 return TRUE;
567 /*******************************************************************************
568 * PSDRV_GetTrueTypeMetrics
570 * Reads font metrics from TrueType font files in directories listed in the
571 * [TrueType Font Directories] section of the Wine configuration file.
573 * If this function fails (returns FALSE), the driver will fail to initialize
574 * and the driver heap will be destroyed, so it's not necessary to HeapFree
575 * everything in that event.
578 BOOL PSDRV_GetTrueTypeMetrics(void)
580 static const WCHAR pathW[] = {'P','a','t','h',0};
581 FT_Error error;
582 FT_Library library;
583 HKEY hkey;
584 DWORD len;
585 LPWSTR valueW;
586 LPSTR valueA, ptr;
588 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
589 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) != ERROR_SUCCESS)
590 return TRUE;
592 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
593 if(!ft_handle) {
594 WINE_MESSAGE(
595 "Wine cannot find the FreeType font library. To enable Wine to\n"
596 "use TrueType fonts please install a version of FreeType greater than\n"
597 "or equal to 2.0.5.\n"
598 "http://www.freetype.org\n");
599 RegCloseKey(hkey);
600 return TRUE;
603 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(ft_handle, #f, NULL, 0)) == NULL) goto sym_not_found;
604 LOAD_FUNCPTR(FT_Done_Face)
605 LOAD_FUNCPTR(FT_Done_FreeType)
606 LOAD_FUNCPTR(FT_Get_Char_Index)
607 LOAD_FUNCPTR(FT_Get_Glyph_Name)
608 LOAD_FUNCPTR(FT_Get_Sfnt_Name)
609 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count)
610 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
611 LOAD_FUNCPTR(FT_Init_FreeType)
612 LOAD_FUNCPTR(FT_Load_Glyph)
613 LOAD_FUNCPTR(FT_New_Face)
614 LOAD_FUNCPTR(FT_Set_Charmap)
615 #undef LOAD_FUNCPTR
617 error = pFT_Init_FreeType(&library);
618 if (error != FT_Err_Ok)
620 ERR("%s returned %i\n", "FT_Init_FreeType", error);
621 wine_dlclose(ft_handle, NULL, 0);
622 RegCloseKey(hkey);
623 return FALSE;
626 if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
628 len += sizeof(WCHAR);
629 valueW = HeapAlloc( GetProcessHeap(), 0, len );
630 if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
632 len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
633 valueA = HeapAlloc( GetProcessHeap(), 0, len );
634 WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
635 TRACE( "got font path %s\n", debugstr_a(valueA) );
636 ptr = valueA;
637 while (ptr)
639 LPSTR next = strchr( ptr, ':' );
640 if (next) *next++ = 0;
641 ReadTrueTypeDir( library, ptr );
642 ptr = next;
644 HeapFree( GetProcessHeap(), 0, valueA );
646 HeapFree( GetProcessHeap(), 0, valueW );
649 RegCloseKey(hkey);
650 pFT_Done_FreeType(library);
651 wine_dlclose(ft_handle, NULL, 0);
652 ft_handle = NULL;
653 return TRUE;
655 sym_not_found:
656 WINE_MESSAGE(
657 "Wine cannot find certain functions that it needs inside the FreeType\n"
658 "font library. To enable Wine to use TrueType fonts please upgrade\n"
659 "FreeType to at least version 2.0.5.\n"
660 "http://www.freetype.org\n");
661 RegCloseKey(hkey);
662 wine_dlclose(ft_handle, NULL, 0);
663 ft_handle = NULL;
664 return TRUE;
667 #endif /* HAVE_FREETYPE */