Finish any pending WaitCommEvents if the event mask is set to 0.
[wine.git] / dlls / wineps / truetype.c
blob1605b62660a4a08063ad3bf081e265a3bd10c514
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"
30 #ifdef HAVE_FREETYPE
33 * These stupid #ifdefs should work for FreeType 2.0.1 and 2.0.2. Beyond that
34 * is anybody's guess.
37 #ifdef HAVE_FREETYPE_FREETYPE_H
38 #include <freetype/freetype.h>
39 #endif
40 #ifdef HAVE_FREETYPE_FTGLYPH_H
41 #include <freetype/ftglyph.h>
42 #endif
43 #ifdef HAVE_FREETYPE_TTTABLES_H
44 #include <freetype/tttables.h>
45 #endif
46 #ifdef HAVE_FREETYPE_FTSNAMES_H
47 #include <freetype/ftsnames.h>
48 #else
49 # ifdef HAVE_FREETYPE_FTNAMES_H
50 # include <freetype/ftnames.h>
51 # endif
52 #endif
53 #ifdef HAVE_FREETYPE_TTNAMEID_H
54 #include <freetype/ttnameid.h>
55 #endif
57 #include <sys/types.h>
58 #include <dirent.h>
59 #include <string.h>
60 #include <stdio.h>
61 #include <errno.h>
63 #include "winnt.h"
64 #include "winerror.h"
65 #include "winreg.h"
66 #include "psdrv.h"
67 #include "wine/debug.h"
69 WINE_DEFAULT_DEBUG_CHANNEL(psdrv);
71 #define REQUIRED_FACE_FLAGS ( FT_FACE_FLAG_SCALABLE | \
72 FT_FACE_FLAG_HORIZONTAL | \
73 FT_FACE_FLAG_SFNT | \
74 FT_FACE_FLAG_GLYPH_NAMES )
76 #define GLYPH_LOAD_FLAGS ( FT_LOAD_NO_SCALE | \
77 FT_LOAD_IGNORE_TRANSFORM | \
78 FT_LOAD_LINEAR_DESIGN )
80 /*******************************************************************************
81 * FindCharMap
83 * Finds Windows character map and creates "EncodingScheme" string. Returns
84 * FALSE to indicate memory allocation or FreeType error; sets *p_charmap to
85 * NULL if no Windows encoding is present.
87 * Returns Unicode character map if present; otherwise uses the first Windows
88 * character map found.
91 static const LPCSTR encoding_names[7] =
93 "WindowsSymbol", /* TT_MS_ID_SYMBOL_CS */
94 "WindowsUnicode", /* TT_MS_ID_UNICODE_CS */
95 "WindowsShiftJIS", /* TT_MS_ID_SJIS */
96 "WindowsPRC", /* TT_MS_ID_GB2312 */
97 "WindowsBig5", /* TT_MS_ID_BIG_5 */
98 "WindowsWansung", /* TT_MS_ID_WANSUNG */
99 "WindowsJohab" /* TT_MS_ID_JOHAB */
100 /* "WindowsUnknown65535" is the longest possible (encoding_id is a UShort) */
103 static BOOL FindCharMap(FT_Face face, FT_CharMap *p_charmap, LPSTR *p_sz)
105 FT_Int i;
106 FT_Error error;
107 FT_CharMap charmap = NULL;
109 for (i = 0; i < face->num_charmaps; ++i)
111 if (face->charmaps[i]->platform_id != TT_PLATFORM_MICROSOFT)
112 continue;
114 if (face->charmaps[i]->encoding_id == TT_MS_ID_UNICODE_CS)
116 charmap = face->charmaps[i];
117 break;
120 if (charmap == NULL)
121 charmap = face->charmaps[i];
124 *p_charmap = charmap;
126 if (charmap == NULL)
128 WARN("No Windows character map found\n");
129 return TRUE;
132 error = FT_Set_Charmap(face, charmap);
133 if (error != FT_Err_Ok)
135 ERR("%s returned %i\n", "FT_Set_Charmap", error);
136 return FALSE;
139 *p_sz = HeapAlloc(PSDRV_Heap, 0, sizeof("WindowsUnknown65535"));
140 if (*p_sz == NULL)
141 return FALSE;
143 if (charmap->encoding_id < 7)
144 strcpy(*p_sz, encoding_names[charmap->encoding_id]);
145 else
146 sprintf(*p_sz, "%s%u", "WindowsUnknown", charmap->encoding_id);
148 return TRUE;
151 /*******************************************************************************
152 * MSTTStrToSz
154 * Converts a string in the TrueType NAME table to a null-terminated ASCII
155 * character string. Space for the string is allocated from the driver heap.
156 * Only handles platform_id = 3 (TT_PLATFORM_MICROSOFT) strings (16-bit, big
157 * endian). It also only handles ASCII character codes (< 128).
159 * Sets *p_sz to NULL if string cannot be converted; only returns FALSE for
160 * memory allocation failure.
163 static BOOL MSTTStrToSz(const FT_SfntName *name, LPSTR *p_sz)
165 FT_UShort i;
166 INT len;
167 USHORT *wsz;
168 LPSTR sz;
170 len = name->string_len / 2; /* # of 16-bit chars */
172 *p_sz = sz = HeapAlloc(PSDRV_Heap, 0, len + 1);
173 if (sz == NULL)
174 return FALSE;
176 wsz = (USHORT *)(name->string);
178 for (i = 0; i < len; ++i, ++sz, ++wsz)
180 USHORT wc = *wsz;
182 #ifndef WORDS_BIGENDIAN
183 wc = (wc >> 8) | (wc << 8);
184 #endif
186 if (wc > 127)
188 WARN("Non-ASCII character 0x%.4x\n", wc);
189 HeapFree(PSDRV_Heap, 0, *p_sz);
190 *p_sz = NULL;
191 return TRUE;
194 *sz = (CHAR)wc;
197 *sz = '\0';
199 return TRUE;
202 /*******************************************************************************
203 * FindMSTTString
205 * Finds the requested Microsoft platform string in the TrueType NAME table and
206 * converts it to a null-terminated ASCII string. Currently looks for U.S.
207 * English names only.
209 * Sets string to NULL if not present or cannot be converted; returns FALSE
210 * only for memory allocation failure.
213 static BOOL FindMSTTString(FT_Face face, FT_CharMap charmap, FT_UShort name_id,
214 LPSTR *p_sz)
216 FT_UInt num_strings, string_index;
217 FT_SfntName name;
218 FT_Error error;
220 num_strings = FT_Get_Sfnt_Name_Count(face);
222 for (string_index = 0; string_index < num_strings; ++string_index)
224 error = FT_Get_Sfnt_Name(face, string_index, &name);
225 if (error != FT_Err_Ok)
227 ERR("%s returned %i\n", "FT_Get_Sfnt_Name", error);
228 return FALSE;
231 /* FIXME - Handle other languages? */
233 if (name.platform_id != TT_PLATFORM_MICROSOFT ||
234 name.language_id != TT_MS_LANGID_ENGLISH_UNITED_STATES)
235 continue;
237 if (name.platform_id != charmap->platform_id ||
238 name.encoding_id != charmap->encoding_id)
239 continue;
241 if (name.name_id != name_id)
242 continue;
244 return MSTTStrToSz(&name, p_sz);
247 *p_sz = NULL; /* didn't find it */
249 return TRUE;
252 /*******************************************************************************
253 * PSUnits
255 * Convert TrueType font units (relative to font em square) to PostScript
256 * units.
259 inline static float PSUnits(LONG x, USHORT em_size)
261 return 1000.0 * (float)x / (float)em_size;
264 /*******************************************************************************
265 * StartAFM
267 * Allocates space for the AFM on the driver heap and reads basic font metrics
268 * from the HEAD, POST, HHEA, and OS/2 tables. Returns FALSE for memory
269 * allocation error; sets *p_afm to NULL if required information is missing.
272 static BOOL StartAFM(FT_Face face, AFM **p_afm)
274 TT_Header *head;
275 TT_Postscript *post;
276 TT_OS2 *os2;
277 TT_HoriHeader *hhea;
278 USHORT em_size;
279 AFM *afm;
281 head = FT_Get_Sfnt_Table(face, ft_sfnt_head);
282 post = FT_Get_Sfnt_Table(face, ft_sfnt_post);
283 os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2);
284 hhea = FT_Get_Sfnt_Table(face, ft_sfnt_hhea);
286 if (head == NULL || post == NULL || os2 == NULL || hhea == NULL ||
287 os2->version == 0xffff) /* old Macintosh font */
289 WARN("Required table(s) missing\n");
290 *p_afm = NULL;
291 return TRUE;
294 *p_afm = afm = HeapAlloc(PSDRV_Heap, 0, sizeof(*afm));
295 if (afm == NULL)
296 return FALSE;
298 afm->WinMetrics.usUnitsPerEm = em_size = head->Units_Per_EM;
299 afm->WinMetrics.sAscender = hhea->Ascender;
300 afm->WinMetrics.sDescender = hhea->Descender;
301 afm->WinMetrics.sLineGap = hhea->Line_Gap;
302 afm->WinMetrics.sTypoAscender = os2->sTypoAscender;
303 afm->WinMetrics.sTypoDescender = os2->sTypoDescender;
304 afm->WinMetrics.sTypoLineGap = os2->sTypoLineGap;
305 afm->WinMetrics.usWinAscent = os2->usWinAscent;
306 afm->WinMetrics.usWinDescent = os2->usWinDescent;
307 afm->WinMetrics.sAvgCharWidth = os2->xAvgCharWidth;
309 afm->Weight = os2->usWeightClass;
310 afm->ItalicAngle = ((float)(post->italicAngle)) / 65536.0;
311 afm->IsFixedPitch = (post-> isFixedPitch == 0) ? FALSE : TRUE;
312 afm->UnderlinePosition = PSUnits(post->underlinePosition, em_size);
313 afm->UnderlineThickness = PSUnits(post->underlineThickness, em_size);
315 afm->FontBBox.llx = PSUnits(head->xMin, em_size);
316 afm->FontBBox.lly = PSUnits(head->yMin, em_size);
317 afm->FontBBox.urx = PSUnits(head->xMax, em_size);
318 afm->FontBBox.ury = PSUnits(head->yMax, em_size);
320 afm->Ascender = PSUnits(os2->sTypoAscender, em_size);
321 afm->Descender = PSUnits(os2->sTypoDescender, em_size);
323 return TRUE;
326 /*******************************************************************************
327 * ReadCharMetrics
329 * Reads metrics for each glyph in a TrueType font. Returns false for memory
330 * allocation or FreeType error; sets *p_metrics to NULL for non-fatal error.
333 static BOOL ReadCharMetrics(FT_Face face, AFM *afm, AFMMETRICS **p_metrics)
335 FT_ULong charcode, index;
336 AFMMETRICS *metrics;
337 USHORT em_size = afm->WinMetrics.usUnitsPerEm;
339 for (charcode = 0, index = 0; charcode < 65536; ++charcode)
340 if (FT_Get_Char_Index(face, charcode) != 0)
341 ++index; /* count # of glyphs */
343 afm->NumofMetrics = index;
345 *p_metrics = metrics = HeapAlloc(PSDRV_Heap, 0, index * sizeof(*metrics));
346 if (metrics == NULL)
347 return FALSE;
349 for (charcode = 0, index = 0; charcode < 65536; ++charcode)
351 FT_UInt glyph_index = FT_Get_Char_Index(face, charcode);
352 FT_Error error;
353 CHAR buffer[128]; /* for glyph names */
355 if (glyph_index == 0)
356 continue;
358 error = FT_Load_Glyph(face, glyph_index, GLYPH_LOAD_FLAGS);
359 if (error != FT_Err_Ok)
361 ERR("%s returned %i\n", "FT_Load_Glyph", error);
362 goto cleanup;
365 error = FT_Get_Glyph_Name(face, glyph_index, buffer, sizeof(buffer));
366 if (error != FT_Err_Ok)
368 ERR("%s returned %i\n", "FT_Get_Glyph_Name", error);
369 goto cleanup;
372 metrics[index].N = PSDRV_GlyphName(buffer);
373 if (metrics[index].N == NULL)
374 goto cleanup;
376 metrics[index].C = metrics[index].UV = charcode;
377 metrics[index].WX = PSUnits(face->glyph->metrics.horiAdvance, em_size);
379 ++index;
382 if (afm->WinMetrics.sAvgCharWidth == 0)
383 afm->WinMetrics.sAvgCharWidth = PSDRV_CalcAvgCharWidth(afm);
385 return TRUE;
387 cleanup:
388 HeapFree(PSDRV_Heap, 0, metrics);
390 return FALSE;
393 /*******************************************************************************
394 * BuildTrueTypeAFM
396 * Builds the AFM for a TrueType font and adds it to the driver font list.
397 * Returns FALSE only on an unexpected error (memory allocation failure or
398 * FreeType error).
401 static BOOL BuildTrueTypeAFM(FT_Face face)
403 AFM *afm;
404 AFMMETRICS *metrics;
405 LPSTR font_name, full_name, family_name, encoding_scheme;
406 FT_CharMap charmap;
407 BOOL retval, added;
409 retval = StartAFM(face, &afm);
410 if (retval == FALSE || afm == NULL)
411 return retval;
413 retval = FindCharMap(face, &charmap, &encoding_scheme);
414 if (retval == FALSE || charmap == NULL)
415 goto cleanup_afm;
417 retval = FindMSTTString(face, charmap, TT_NAME_ID_PS_NAME, &font_name);
418 if (retval == FALSE || font_name == NULL)
419 goto cleanup_encoding_scheme;
421 retval = FindMSTTString(face, charmap, TT_NAME_ID_FULL_NAME, &full_name);
422 if (retval == FALSE || full_name == NULL)
423 goto cleanup_font_name;
425 retval = FindMSTTString(face, charmap, TT_NAME_ID_FONT_FAMILY,
426 &family_name);
427 if (retval == FALSE || family_name == NULL)
428 goto cleanup_full_name;
430 retval = ReadCharMetrics(face, afm, &metrics);
431 if (retval == FALSE || metrics == NULL)
432 goto cleanup_family_name;
434 afm->EncodingScheme = encoding_scheme; afm->FontName = font_name;
435 afm->FullName = full_name; afm->FamilyName = family_name;
436 afm->Metrics = metrics;
438 retval = PSDRV_AddAFMtoList(&PSDRV_AFMFontList, afm, &added);
439 if (retval == FALSE || added == FALSE)
440 goto cleanup_family_name;
442 return TRUE;
444 /* clean up after fatal or non-fatal errors */
446 cleanup_family_name:
447 HeapFree(PSDRV_Heap, 0, family_name);
448 cleanup_full_name:
449 HeapFree(PSDRV_Heap, 0, full_name);
450 cleanup_font_name:
451 HeapFree(PSDRV_Heap, 0, font_name);
452 cleanup_encoding_scheme:
453 HeapFree(PSDRV_Heap, 0, encoding_scheme);
454 cleanup_afm:
455 HeapFree(PSDRV_Heap, 0, afm);
457 return retval;
460 /*******************************************************************************
461 * ReadTrueTypeFile
463 * Reads font metrics from TrueType font file. Only returns FALSE for
464 * unexpected errors (memory allocation failure or FreeType error).
467 static BOOL ReadTrueTypeFile(FT_Library library, LPCSTR filename)
469 FT_Error error;
470 FT_Face face;
472 TRACE("%s\n", filename);
474 error = FT_New_Face(library, filename, 0, &face);
475 if (error != FT_Err_Ok)
477 WARN("FreeType error %i opening %s\n", error, filename);
478 return TRUE;
481 if ((face->face_flags & REQUIRED_FACE_FLAGS) == REQUIRED_FACE_FLAGS)
483 if (BuildTrueTypeAFM(face) == FALSE)
485 FT_Done_Face(face);
486 return FALSE;
489 else
491 WARN("Required information missing from %s\n", filename);
494 error = FT_Done_Face(face);
495 if (error != FT_Err_Ok)
497 ERR("%s returned %i\n", "FT_Done_Face", error);
498 return FALSE;
501 return TRUE;
504 /*******************************************************************************
505 * ReadTrueTypeDir
507 * Reads all TrueType font files in a directory.
510 static BOOL ReadTrueTypeDir(FT_Library library, LPCSTR dirname)
512 struct dirent *dent;
513 DIR *dir;
514 CHAR filename[256];
516 dir = opendir(dirname);
517 if (dir == NULL)
519 WARN("'%s' opening %s\n", strerror(errno), dirname);
520 return TRUE;;
523 while ((dent = readdir(dir)) != NULL)
525 CHAR *file_extension = strrchr(dent->d_name, '.');
526 int fn_len;
528 if (file_extension == NULL || strcasecmp(file_extension, ".ttf") != 0)
529 continue;
531 fn_len = snprintf(filename, 256, "%s/%s", dirname, dent->d_name);
532 if (fn_len < 0 || fn_len > sizeof(filename) - 1)
534 WARN("Path '%s/%s' is too long\n", dirname, dent->d_name);
535 continue;
538 if (ReadTrueTypeFile(library, filename) == FALSE)
540 closedir(dir);
541 return FALSE;
545 closedir(dir);
547 return TRUE;
550 /*******************************************************************************
551 * PSDRV_GetTrueTypeMetrics
553 * Reads font metrics from TrueType font files in directories listed in the
554 * [TrueType Font Directories] section of the Wine configuration file.
556 * If this function fails (returns FALSE), the driver will fail to initialize
557 * and the driver heap will be destroyed, so it's not necessary to HeapFree
558 * everything in that event.
561 BOOL PSDRV_GetTrueTypeMetrics(void)
563 CHAR name_buf[256], value_buf[256];
564 INT i = 0;
565 FT_Error error;
566 FT_Library library;
567 HKEY hkey;
568 DWORD type, name_len, value_len;
570 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,
571 "Software\\Wine\\Wine\\Config\\TrueType Font Directories",
572 0, KEY_READ, &hkey) != ERROR_SUCCESS)
573 return TRUE;
575 error = FT_Init_FreeType(&library);
576 if (error != FT_Err_Ok)
578 ERR("%s returned %i\n", "FT_Init_FreeType", error);
579 RegCloseKey(hkey);
580 return FALSE;
583 name_len = sizeof(name_buf);
584 value_len = sizeof(value_buf);
586 while (RegEnumValueA(hkey, i++, name_buf, &name_len, NULL, &type, value_buf,
587 &value_len) == ERROR_SUCCESS)
589 value_buf[sizeof(value_buf) - 1] = '\0';
591 if (ReadTrueTypeDir(library, value_buf) == FALSE)
593 RegCloseKey(hkey);
594 FT_Done_FreeType(library);
595 return FALSE;
598 /* initialize lengths for new iteration */
600 name_len = sizeof(name_buf);
601 value_len = sizeof(value_buf);
604 RegCloseKey(hkey);
605 FT_Done_FreeType(library);
606 return TRUE;
609 #endif /* HAVE_FREETYPE */