Use macros for FreeType includes.
[wine/testsucceed.git] / dlls / wineps / truetype.c
blob9d6296d2218a75f012057e6051d25fcfe2adbeb9
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 */
8 #include "config.h"
10 #ifdef HAVE_FREETYPE
12 #include <freetype/freetype.h>
13 #include FT_NAMES_H
14 #include FT_TRUETYPE_NAMES_H
15 #include FT_TRUETYPE_TABLES_H
16 #include FT_GLYPH_H
17 #include <sys/types.h>
18 #include <dirent.h>
19 #include <string.h>
20 #include <stdio.h>
22 #include "winnt.h"
23 #include "options.h"
24 #include "psdrv.h"
25 #include "debugtools.h"
26 #include "heap.h"
28 DEFAULT_DEBUG_CHANNEL(psdrv);
31 #define REQUIRED_FACE_FLAGS ( FT_FACE_FLAG_SCALABLE | \
32 FT_FACE_FLAG_HORIZONTAL | \
33 FT_FACE_FLAG_SFNT | \
34 FT_FACE_FLAG_GLYPH_NAMES )
36 static FT_Library library;
37 static FT_Face face;
38 static FT_CharMap charmap;
39 static TT_Header *head;
40 static TT_Postscript *post;
41 static TT_OS2 *os2;
42 static TT_HoriHeader *hhea;
44 /*******************************************************************************
46 * FindCharMap
48 * Sets charmap and points afm->EncodingScheme to encoding name (in driver
49 * heap). Leaves both uninitialized if font contains no Windows encoding.
51 * Returns FALSE to indicate memory allocation error.
54 static const char *encoding_names[7] =
56 "WindowsSymbol", /* TT_MS_ID_SYMBOL_CS */
57 "WindowsUnicode", /* TT_MS_ID_UNICODE_CS */
58 "WindowsShiftJIS", /* TT_MS_ID_SJIS */
59 "WindowsPRC", /* TT_MS_ID_GB2312 */
60 "WindowsBig5", /* TT_MS_ID_BIG_5 */
61 "WindowsWansung", /* TT_MS_ID_WANSUNG */
62 "WindowsJohab" /* TT_MS_ID_JOHAB */
65 static BOOL FindCharMap(AFM *afm)
67 FT_Int i;
68 FT_Error error;
70 charmap = NULL;
72 for (i = 0; i < face->num_charmaps; ++i)
74 if (face->charmaps[i]->platform_id != TT_PLATFORM_MICROSOFT)
75 continue;
77 if (face->charmaps[i]->encoding_id == TT_MS_ID_UNICODE_CS)
79 charmap = face->charmaps[i];
80 break;
83 if (charmap == NULL)
84 charmap = face->charmaps[i];
87 if (charmap == NULL)
88 return TRUE;
90 error = FT_Set_Charmap(face, charmap);
91 if (error != FT_Err_Ok)
93 ERR("%s returned %i\n", "FT_Set_CharMap", error);
94 return FALSE;
97 if (charmap->encoding_id < 7)
99 afm->EncodingScheme = HEAP_strdupA(PSDRV_Heap, 0,
100 encoding_names[charmap->encoding_id]);
101 if (afm->EncodingScheme == NULL)
102 return FALSE;
104 else
106 afm->EncodingScheme = HeapAlloc(PSDRV_Heap, 0,
107 sizeof("WindowsUnknown") + 1 + charmap->encoding_id / 10);
108 if (afm->EncodingScheme == NULL)
109 return FALSE;
111 sprintf(afm->EncodingScheme, "%s%u", "WindowsUnknown",
112 charmap->encoding_id);
115 return TRUE;
118 /*******************************************************************************
119 * NameTableString
121 * Converts a name table string to a null-terminated character string. The
122 * space for the character string is allocated from the driver heap.
124 * This function handles only platform_id = 3 (TT_PLATFORM_MICROSOFT) -- 16-bit
125 * big-endian strings. It also only handles ASCII character codes (< 128).
127 * This function will set *sz to NULL if it cannot parse the string, but it
128 * will only return FALSE in the event of an unexpected error (memory
129 * allocation failure).
132 static BOOL NameTableString(LPSTR *sz, const FT_SfntName *name)
134 FT_UShort i, len, *ws;
135 LPSTR s;
137 if (name->platform_id != TT_PLATFORM_MICROSOFT)
139 ERR("Unsupported encoding %i\n", name->platform_id);
140 return FALSE; /* should never get here */
143 len = name->string_len / 2;
144 s = *sz = HeapAlloc(PSDRV_Heap, 0, len + 1);
145 if (s == NULL)
146 return FALSE;
147 ws = (FT_UShort *)(name->string);
149 for (i = 0; i < len; ++i, ++s, ++ws)
151 FT_UShort wc = *ws;
153 #ifndef WORDS_BIGENDIAN
154 wc = (wc >> 8) | (wc << 8);
155 #endif
157 if (wc > 127)
159 WARN("Non-ASCII character 0x%.4x\n", wc);
160 HeapFree(PSDRV_Heap, 0, *sz);
161 *sz = NULL;
162 return TRUE;
165 *s = (CHAR)wc;
168 *s = '\0';
169 return TRUE;
172 /*******************************************************************************
173 * ReadNameTable
175 * Reads various font names from the TrueType 'NAME' table. Currently looks
176 * for U.S. English names only,
178 * May leave a pointer uninitialized if the desired string is not present;
179 * returns FALSE only in the event of an unexpected error.
182 static BOOL ReadNameTable(AFM *afm)
184 FT_UInt numStrings, stringIndex;
185 FT_SfntName name;
186 FT_Error error;
188 numStrings = FT_Get_Sfnt_Name_Count(face);
190 for (stringIndex = 0; stringIndex < numStrings; ++stringIndex)
192 error = FT_Get_Sfnt_Name(face, stringIndex, &name);
193 if (error != FT_Err_Ok)
195 ERR("%s returned %i\n", "FT_Get_Sfnt_Name", error);
196 return FALSE;
199 /* FIXME - Handle other languages? */
201 if (name.language_id != TT_MS_LANGID_ENGLISH_UNITED_STATES ||
202 name.platform_id != charmap->platform_id ||
203 name.encoding_id != charmap->encoding_id)
204 continue;
206 switch (name.name_id)
208 case TT_NAME_ID_FONT_FAMILY:
210 if (NameTableString(&(afm->FamilyName), &name) == FALSE)
211 return FALSE;
212 break;
214 case TT_NAME_ID_FULL_NAME:
216 if (NameTableString(&(afm->FullName), &name) == FALSE)
217 return FALSE;
218 break;
220 case TT_NAME_ID_PS_NAME:
222 if (NameTableString(&(afm->FontName), &name) == FALSE)
223 return FALSE;
224 break;
228 return TRUE;
231 /*******************************************************************************
232 * FreeAFM
234 * Frees an AFM and all subsidiary objects. For this function to work
235 * properly, the AFM must have been allocated with HEAP_ZERO_MEMORY, and the
236 * UNICODEVECTOR and it's associated array of UNICODEGLYPHs must have been
237 * allocated as a single object.
239 static void FreeAFM(AFM *afm)
241 if (afm->FontName != NULL)
242 HeapFree(PSDRV_Heap, 0, afm->FontName);
243 if (afm->FullName != NULL)
244 HeapFree(PSDRV_Heap, 0, afm->FullName);
245 if (afm->FamilyName != NULL)
246 HeapFree(PSDRV_Heap, 0, afm->FamilyName);
247 if (afm->EncodingScheme != NULL)
248 HeapFree(PSDRV_Heap, 0, afm->EncodingScheme);
249 if (afm->Metrics != NULL)
250 HeapFree(PSDRV_Heap, 0, afm->Metrics);
251 if (afm->Encoding != NULL)
252 HeapFree(PSDRV_Heap, 0, afm->Encoding);
254 HeapFree(PSDRV_Heap, 0, afm);
257 /*******************************************************************************
258 * PSUnits
260 * Convert TrueType font units (relative to font em square) to PostScript
261 * units. This is defined as a macro, so it can handle different TrueType
262 * data types as inputs.
265 #define PSUnits(x) (((float)(x)) * 1000.0 / ((float)(head->Units_Per_EM)))
267 /*******************************************************************************
268 * ReadMetricsTables
270 * Reads basic font metrics from the 'head', 'post', and 'OS/2' tables.
271 * Returns FALSE if any table is missing.
274 static BOOL ReadMetricsTables(AFM *afm)
276 head = FT_Get_Sfnt_Table(face, ft_sfnt_head);
277 post = FT_Get_Sfnt_Table(face, ft_sfnt_post);
278 hhea = FT_Get_Sfnt_Table(face, ft_sfnt_hhea);
279 os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2);
281 if (head == NULL || post == NULL || hhea == NULL || os2 == NULL)
282 return FALSE;
284 if (os2->version == 0xffff) /* Old Macintosh font */
285 return FALSE;
287 afm->Weight = os2->usWeightClass;
288 afm->ItalicAngle = ((float)(post->italicAngle)) / 65536.0;
289 afm->IsFixedPitch = (post->isFixedPitch == 0) ? FALSE : TRUE;
290 afm->UnderlinePosition = PSUnits(post->underlinePosition);
291 afm->UnderlineThickness = PSUnits(post->underlineThickness);
293 afm->FontBBox.llx = PSUnits(head->xMin);
294 afm->FontBBox.lly = PSUnits(head->yMin);
295 afm->FontBBox.urx = PSUnits(head->xMax);
296 afm->FontBBox.ury = PSUnits(head->yMax);
298 /* CapHeight & XHeight set by ReadCharMetrics */
300 afm->Ascender = PSUnits(os2->sTypoAscender);
301 afm->Descender = PSUnits(os2->sTypoDescender);
302 afm->FullAscender = afm->FontBBox.ury; /* get rid of this */
304 afm->WinMetrics.usUnitsPerEm = head->Units_Per_EM;
305 afm->WinMetrics.sAscender = hhea->Ascender;
306 afm->WinMetrics.sDescender = hhea->Descender;
307 afm->WinMetrics.sLineGap = hhea->Line_Gap;
308 afm->WinMetrics.sTypoAscender = os2->sTypoAscender;
309 afm->WinMetrics.sTypoDescender = os2->sTypoDescender;
310 afm->WinMetrics.sTypoLineGap = os2->sTypoLineGap;
311 afm->WinMetrics.usWinAscent = os2->usWinAscent;
312 afm->WinMetrics.usWinDescent = os2->usWinDescent;
314 return TRUE;
317 /*******************************************************************************
318 * ReadCharMetrics
320 * Reads metrics for each glyph in a TrueType font. Since FreeAFM will try to
321 * free afm->Metrics and afm->Encoding if they are non-NULL, don't free them
322 * in the event of an error. (FreeAFM depends on the fact that afm->Encoding
323 * and its associated array of UNICODEGLYPHs are allocated as a single object.)
326 static BOOL ReadCharMetrics(AFM *afm)
328 FT_ULong charcode, index;
329 UNICODEGLYPH *glyphs;
332 * There does not seem to be an easy way to get the number of characters
333 * in an encoding out of a TrueType font.
335 for (charcode = 0, index = 0; charcode < 65536; ++charcode)
337 if (FT_Get_Char_Index(face, charcode) != 0)
338 ++index;
341 afm->NumofMetrics = index;
343 afm->Metrics = HeapAlloc(PSDRV_Heap, 0, index * sizeof(AFMMETRICS));
344 afm->Encoding = HeapAlloc(PSDRV_Heap, 0, sizeof(UNICODEVECTOR) +
345 index * sizeof(UNICODEGLYPH));
346 if (afm->Metrics == NULL || afm->Encoding == NULL)
347 return FALSE;
349 glyphs = (UNICODEGLYPH *)(afm->Encoding + 1);
350 afm->Encoding->size = index;
351 afm->Encoding->glyphs = glyphs;
353 for (charcode = 0, index = 0; charcode <= 65536; ++charcode)
355 FT_UInt glyph_index = FT_Get_Char_Index(face, charcode);
356 FT_Error error;
357 FT_Glyph glyph;
358 FT_BBox bbox;
359 char buffer[256];
361 if (glyph_index == 0)
362 continue;
364 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_SCALE |
365 FT_LOAD_IGNORE_TRANSFORM | FT_LOAD_LINEAR_DESIGN);
366 if (error != FT_Err_Ok)
368 ERR("%s returned %i\n", "FT_Load_Glyph", error);
369 return FALSE;
372 error = FT_Get_Glyph(face->glyph, &glyph);
373 if (error != FT_Err_Ok)
375 ERR("%s returned %i\n", "FT_Get_Glyph", error);
376 return FALSE;
379 FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_unscaled, &bbox);
381 error = FT_Get_Glyph_Name(face, glyph_index, buffer, 255);
382 if (error != FT_Err_Ok)
384 ERR("%s returned %i\n", "FT_Get_Glyph_Name", error);
385 return FALSE;
388 afm->Metrics[index].N = PSDRV_GlyphName(buffer);
389 if (afm->Metrics[index].N == NULL)
390 return FALSE;
392 afm->Metrics[index].C = charcode;
393 afm->Metrics[index].UV = charcode;
394 afm->Metrics[index].WX = PSUnits(face->glyph->metrics.horiAdvance);
395 afm->Metrics[index].B.llx = PSUnits(bbox.xMin);
396 afm->Metrics[index].B.lly = PSUnits(bbox.yMin);
397 afm->Metrics[index].B.urx = PSUnits(bbox.xMax);
398 afm->Metrics[index].B.ury = PSUnits(bbox.yMax);
399 afm->Metrics[index].L = NULL;
401 TRACE("Metrics for '%s' WX = %f B = %f,%f - %f,%f\n",
402 afm->Metrics[index].N->sz, afm->Metrics[index].WX,
403 afm->Metrics[index].B.llx, afm->Metrics[index].B.lly,
404 afm->Metrics[index].B.urx, afm->Metrics[index].B.ury);
406 glyphs[index].UV = charcode;
407 glyphs[index].name = afm->Metrics[index].N;
409 if (charcode == 0x0048) /* 'H' */
410 afm->CapHeight = PSUnits(bbox.yMax);
411 if (charcode == 0x0078) /* 'x' */
412 afm->XHeight = PSUnits(bbox.yMax);
414 ++index;
417 return TRUE;
420 /*******************************************************************************
421 * ReadTrueTypeAFM
423 * Fills in AFM structure for opened TrueType font file. Returns FALSE only on
424 * an unexpected error (memory allocation failure or FreeType error); otherwise
425 * returns TRUE. Leaves it to the caller (ReadTrueTypeFile) to clean up.
428 static BOOL ReadTrueTypeAFM(AFM *afm)
431 if ((face->face_flags & REQUIRED_FACE_FLAGS) != REQUIRED_FACE_FLAGS)
433 WARN("Font flags do not match requirements\n");
434 return TRUE;
437 if (FindCharMap(afm) == FALSE)
438 return FALSE;
440 if (charmap == NULL)
442 WARN("No Windows encodings in font\n");
443 return TRUE;
446 TRACE("Using encoding '%s'\n", afm->EncodingScheme);
448 if (ReadNameTable(afm) == FALSE)
449 return FALSE;
451 if (afm->FamilyName == NULL || afm->FullName == NULL ||
452 afm->FontName == NULL)
454 WARN("Required strings missing from font\n");
455 return TRUE;
458 if (ReadMetricsTables(afm) == FALSE) /* Non-fatal */
460 WARN("Required metrics tables missing from font\n");
461 return TRUE;
464 if (ReadCharMetrics(afm) == FALSE)
465 return FALSE;
467 return TRUE;
470 /*******************************************************************************
471 * ReadTrueTypeFile
473 * Reads PostScript-style font metrics from a TrueType font file. Only returns
474 * FALSE for unexpected errors (memory allocation, etc.); returns TRUE if it's
475 * just a bad font file.
478 static BOOL ReadTrueTypeFile(LPCSTR filename)
480 FT_Error error;
481 AFM *afm;
483 TRACE("'%s'\n", filename);
485 afm = HeapAlloc(PSDRV_Heap, HEAP_ZERO_MEMORY, sizeof(AFM));
486 if (afm == NULL)
487 return FALSE;
489 error = FT_New_Face(library, filename, 0, &face);
491 if (error != FT_Err_Ok)
493 WARN("FreeType error %i opening '%s'\n", error, filename);
494 HeapFree(PSDRV_Heap, 0, afm);
495 return TRUE;
498 if (ReadTrueTypeAFM(afm) == FALSE)
500 FreeAFM(afm);
501 FT_Done_Face(face);
502 return FALSE;
505 error = FT_Done_Face(face);
506 if (error != FT_Err_Ok)
508 ERR("%s returned %i\n", "FT_Done_Face", error);
509 FreeAFM(afm);
510 return FALSE;
513 if (afm->Encoding == NULL) /* last element to be set */
515 FreeAFM(afm);
516 return TRUE;
519 if (PSDRV_AddAFMtoList(&PSDRV_AFMFontList, afm) == FALSE)
521 FreeAFM(afm);
522 return FALSE;
525 return TRUE;
530 /*******************************************************************************
531 * PSDRV_GetTrueTypeMetrics
533 * Reads PostScript-stype font metrics from TrueType font files in directories
534 * listed in the [TrueType Font Directories] section of the Wine configuration
535 * file.
537 * If this function fails, the driver will fail to initialize and the driver
538 * heap will be destroyed, so it's not necessary to HeapFree everything in
539 * that event.
542 BOOL PSDRV_GetTrueTypeMetrics()
544 CHAR keybuf[256], namebuf[256];
545 INT i = 0;
546 FT_Error error;
548 error = FT_Init_FreeType(&library);
549 if (error != FT_Err_Ok)
551 ERR("%s returned %i\n", "FT_Init_FreeType", error);
552 return FALSE;
555 while (PROFILE_EnumWineIniString("TrueType Font Directories", i++, keybuf,
556 sizeof(keybuf), namebuf, sizeof(namebuf)))
558 struct dirent *dent;
559 DIR *dir;
560 INT dnlen; /* directory name length */
562 namebuf[sizeof(namebuf) - 1] = '\0';
563 dir = opendir(namebuf);
564 if (dir == NULL)
566 WARN("Error opening directory '%s'\n", namebuf);
567 continue;
570 dnlen = strlen(namebuf);
571 namebuf[dnlen] = '/'; /* 2 slashes is OK, 0 is not */
572 ++dnlen;
574 while ((dent = readdir(dir)) != NULL)
576 INT fnlen; /* file name length */
578 fnlen = strlen(dent->d_name);
580 if (fnlen < 5 || strcasecmp(dent->d_name + fnlen - 4, ".ttf") != 0)
582 TRACE("Skipping filename '%s'\n", dent->d_name);
583 continue;
586 if (dnlen + fnlen + 1 > sizeof(namebuf)) /* allow for '\0' */
588 WARN("Path '%s/%s' is too long\n", namebuf, dent->d_name);
589 continue;
592 memcpy(namebuf + dnlen, dent->d_name, fnlen + 1);
594 if (ReadTrueTypeFile(namebuf) == FALSE)
596 ERR("Error reading '%s'\n", namebuf);
597 closedir(dir);
598 FT_Done_FreeType(library);
599 return FALSE;
603 closedir(dir);
606 FT_Done_FreeType(library);
607 return TRUE;
610 #endif /* HAVE_FREETYPE */