Cope with TrueType fonts without a 'post' table or with a format 3 'post'
[sgt/halibut] / in_sfnt.c
CommitLineData
2729eafc 1/*
2 * Support for sfnt-housed fonts for Halibut
3 *
4 * sfnt-housed fonts include TrueType, OpenType, sfnt-housed Type 1
5 * fonts and a couple of bitmap formats.
6 *
7 * The various tables that can appear in sfnt-housed fonts are defined
8 * in several places. These include:
9 *
10 * The OpenType Specification:
11 * <http://partners.adobe.com/public/developer/opentype/index_spec.html>
12 *
13 * The TrueType Reference Manual:
14 * <http://developer.apple.com/textfonts/TTRefMan/>
1a61f569 15 *
16 * Microsoft typography specifications:
17 * <http://www.microsoft.com/typography/SpecificationsOverview.mspx>
2729eafc 18 */
19
20#include <assert.h>
21#include <stddef.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include "halibut.h"
25#include "paper.h"
26
27typedef struct sfnt_decode_Tag sfnt_decode;
28struct sfnt_decode_Tag {
29 void (*decoder)(void *src, void *dest);
30 size_t src_len;
31 size_t dest_offset;
32};
33
18e7663a 34#if 0 /* unused */
2729eafc 35static void decode_uint8(void *src, void *dest) {
36 *(unsigned int *)dest = *(unsigned char *)src;
37}
38#define d_uint8 decode_uint8, 1
18e7663a 39#endif
2729eafc 40
18e7663a 41#if 0 /* unused */
2729eafc 42static void decode_int8(void *src, void *dest) {
43 *(int *)dest = *(signed char *)src;
44}
45#define d_int8 decode_int8, 1
18e7663a 46#endif
2729eafc 47
48static void decode_uint16(void *src, void *dest) {
49 unsigned char *cp = src;
50 *(unsigned int *)dest = (cp[0] << 8) + cp[1];
51}
52#define d_uint16 decode_uint16, 2
53
54static void decode_int16(void *src, void *dest) {
55 signed char *cp = src;
56 unsigned char *ucp = src;
57 *(int *)dest = (cp[0] << 8) + ucp[1];
58}
59#define d_int16 decode_int16, 2
60
61static void decode_uint32(void *src, void *dest) {
62 unsigned char *cp = src;
63 *(unsigned int *)dest =
64 (cp[0] << 24) + (cp[1] << 16) + (cp[2] << 8) + cp[3];
65}
66#define d_uint32 decode_uint32, 4
67
68static void decode_int32(void *src, void *dest) {
69 signed char *cp = src;
70 unsigned char *ucp = src;
71 *(int *)dest = (cp[0] << 24) + (ucp[1] << 16) + (ucp[2] << 8) + ucp[3];
72}
73#define d_int32 decode_int32, 4
74
75static void decode_skip(void *src, void *dest) {
18e7663a 76 IGNORE(src);
77 IGNORE(dest);
2729eafc 78 /* do nothing */
79}
80#define d_skip(n) decode_skip, (n), 0
81
82static void decode_end(void *src, void *dest) {
18e7663a 83 IGNORE(src);
84 IGNORE(dest);
2729eafc 85 /* never called */
86}
87#define d_end decode_end, 0, 0
88
89static void *decode(sfnt_decode *dec, void *src, void *end, void *dest) {
90 while (dec->decoder != decode_end) {
91 if ((char *)src + dec->src_len > (char *)end) return NULL;
92 dec->decoder(src, (char *)dest + dec->dest_offset);
93 src = (char *)src + dec->src_len;
94 dec++;
95 }
96 return src;
97}
98
99static void *decoden(sfnt_decode *dec, void *src, void *end, void *dest,
100 size_t size, size_t n) {
101 while (n-- && src) {
102 src = decode(dec, src, end, dest);
103 dest = (char *)dest + size;
104 }
105 return src;
106}
107
108/* Decoding specs for simple data types */
109sfnt_decode uint16_decode[] = { { d_uint16, 0 }, { d_end } };
110sfnt_decode int16_decode[] = { { d_int16, 0 }, { d_end } };
111sfnt_decode uint32_decode[] = { { d_uint32, 0 }, { d_end } };
112
113/* Offset subdirectory -- the start of the file */
114typedef struct offsubdir_Tag offsubdir;
115struct offsubdir_Tag {
116 unsigned scaler_type;
117 unsigned numTables;
118};
119sfnt_decode offsubdir_decode[] = {
120 { d_uint32, offsetof(offsubdir, scaler_type) },
121 { d_uint16, offsetof(offsubdir, numTables) },
122 { d_skip(6) },
123 { d_end }
124};
125
126#define sfnt_00010000 0x00010000
39d3d900 127#define TAG_OS_2 0x4f532f32
2729eafc 128#define TAG_cmap 0x636d6170
129#define TAG_glyf 0x676c7966
130#define TAG_head 0x68656164
131#define TAG_hhea 0x68686561
132#define TAG_hmtx 0x686d7478
1a61f569 133#define TAG_kern 0x6b65726e
2729eafc 134#define TAG_loca 0x6c6f6361
cb93ccb7 135#define TAG_maxp 0x6d617870
2729eafc 136#define TAG_name 0x6e616d65
137#define TAG_post 0x706f7374
138#define sfnt_true 0x74727565
139
140/* Table directory */
141typedef struct tabledir_Tag tabledir;
142struct tabledir_Tag {
143 unsigned tag;
144 unsigned checkSum;
145 unsigned offset;
146 unsigned length;
147};
148sfnt_decode tabledir_decode[] = {
149 { d_uint32, offsetof(tabledir, tag) },
150 { d_uint32, offsetof(tabledir, checkSum) },
151 { d_uint32, offsetof(tabledir, offset) },
152 { d_uint32, offsetof(tabledir, length) },
153 { d_end }
154};
155
39d3d900 156/* OS/2 and Windows compatibility table */
157typedef struct t_OS_2_Tag t_OS_2;
158struct t_OS_2_Tag {
159 unsigned version;
160 int sTypoAscender, sTypoDescender;
161 int sxHeight, sCapHeight;
162};
163sfnt_decode t_OS_2_v0_decode[] = {
164 { d_uint16, offsetof(t_OS_2, version) },
165 { d_skip(66) }, /* xAvgCharWidth, usWeightClass, usWidthClass, fsType, */
166 /* ySubscriptXSize, ySubscriptYSize, ySubscriptXOffset, */
167 /* ySubscriptYOffset, ySuperscriptXSize, ySuperscriptYSize, */
168 /* ySuperscriptXOffset, ySupercriptYOffset, sFamilyClass, panose, */
169 /* ulUnicodeRange1, ulUnicodeRange2, ulUnicodeRange3, ulUnicodeRange4, */
170 /* achVendID, fsSelection, usFirstCharIndex, usLastCharIndex */
171 { d_end }
172};
173sfnt_decode t_OS_2_v1_decode[] = {
174 { d_uint16, offsetof(t_OS_2, version) },
175 { d_skip(66) }, /* xAvgCharWidth, usWeightClass, usWidthClass, fsType, */
176 /* ySubscriptXSize, ySubscriptYSize, ySubscriptXOffset, */
177 /* ySubscriptYOffset, ySuperscriptXSize, ySuperscriptYSize, */
178 /* ySuperscriptXOffset, ySupercriptYOffset, sFamilyClass, panose, */
179 /* ulUnicodeRange1, ulUnicodeRange2, ulUnicodeRange3, ulUnicodeRange4, */
180 /* achVendID, fsSelection, usFirstCharIndex, usLastCharIndex */
181 { d_int16, offsetof(t_OS_2, sTypoAscender) },
182 { d_int16, offsetof(t_OS_2, sTypoDescender) },
183 { d_skip(14) }, /* sTypoLineGap, usWinAscent, usWinDescent, */
184 /* ulCodePageRange1, ulCodePageRange2 */
185 { d_end }
186};
187sfnt_decode t_OS_2_v2_decode[] = {
188 { d_uint16, offsetof(t_OS_2, version) },
189 { d_skip(66) }, /* xAvgCharWidth, usWeightClass, usWidthClass, fsType, */
190 /* ySubscriptXSize, ySubscriptYSize, ySubscriptXOffset, */
191 /* ySubscriptYOffset, ySuperscriptXSize, ySuperscriptYSize, */
192 /* ySuperscriptXOffset, ySupercriptYOffset, sFamilyClass, panose, */
193 /* ulUnicodeRange1, ulUnicodeRange2, ulUnicodeRange3, ulUnicodeRange4, */
194 /* achVendID, fsSelection, usFirstCharIndex, usLastCharIndex */
195 { d_int16, offsetof(t_OS_2, sTypoAscender) },
196 { d_int16, offsetof(t_OS_2, sTypoDescender) },
197 { d_skip(14) }, /* sTypoLineGap, usWinAscent, usWinDescent, */
198 /* ulCodePageRange1, ulCodePageRange2 */
199 { d_int16, offsetof(t_OS_2, sxHeight) },
200 { d_int16, offsetof(t_OS_2, sCapHeight) },
201 { d_skip(6) }, /* usDefaultChar, usBreakChar, usMaxContext */
202 { d_end }
203};
204
2729eafc 205/* Character to Glyph ('cmap') table */
206typedef struct t_cmap_Tag t_cmap;
207struct t_cmap_Tag {
208 unsigned numTables;
209};
210sfnt_decode t_cmap_decode[] = {
211 { d_skip(2) },
212 { d_uint16, offsetof(t_cmap, numTables) },
213 { d_end }
214};
215typedef struct encodingrec_Tag encodingrec;
216struct encodingrec_Tag {
217 unsigned platformID;
218 unsigned encodingID;
219 unsigned offset;
220};
221sfnt_decode encodingrec_decode[] = {
222 { d_uint16, offsetof(encodingrec, platformID) },
223 { d_uint16, offsetof(encodingrec, encodingID) },
224 { d_uint32, offsetof(encodingrec, offset) },
225 { d_end }
226};
227typedef struct cmap4_Tag cmap4;
228struct cmap4_Tag {
229 unsigned length;
230 unsigned segCountX2;
231};
232sfnt_decode cmap4_decode[] = {
233 { d_skip(2) }, /* format */
234 { d_uint16, offsetof(cmap4, length) },
235 { d_skip(2) }, /* language */
236 { d_uint16, offsetof(cmap4, segCountX2) },
237 { d_skip(6) }, /* searchRange, entrySelector, rangeShift */
238 { d_end }
239};
240
241/* Font Header ('head') table */
242typedef struct t_head_Tag t_head;
243struct t_head_Tag {
244 unsigned version;
245 unsigned fontRevision;
246 unsigned flags;
247 unsigned unitsPerEm;
248 int xMin, yMin, xMax, yMax;
249 int indexToLocFormat;
250};
251sfnt_decode t_head_decode[] = {
252 { d_uint32, offsetof(t_head, version) },
253 { d_uint32, offsetof(t_head, fontRevision) },
254 { d_skip(8) }, /* checkSumAdjustment, magicNumber, flags */
255 { d_uint16, offsetof(t_head, flags) },
256 { d_uint16, offsetof(t_head, unitsPerEm) },
257 { d_skip(16) }, /* created, modified */
258 { d_int16, offsetof(t_head, xMin) },
259 { d_int16, offsetof(t_head, yMin) },
260 { d_int16, offsetof(t_head, xMax) },
261 { d_int16, offsetof(t_head, yMax) },
262 { d_skip(6) }, /* macStyle, lowestRecPPEM, fontDirectionHint */
263 { d_int16, offsetof(t_head, indexToLocFormat) },
264 { d_skip(2) },
265 { d_end }
266};
267
268/* Horizontal Header ('hhea') table */
269typedef struct t_hhea_Tag t_hhea;
270struct t_hhea_Tag {
271 unsigned version;
272 int ascent;
273 int descent;
274 int lineGap;
275 int metricDataFormat;
276 unsigned numOfLongHorMetrics;
277};
278sfnt_decode t_hhea_decode[] = {
279 { d_uint32, offsetof(t_hhea, version) },
280 { d_int16, offsetof(t_hhea, ascent) },
281 { d_int16, offsetof(t_hhea, descent) },
282 { d_int16, offsetof(t_hhea, lineGap) },
283 { d_skip(22) },
284 { d_int16, offsetof(t_hhea, metricDataFormat) },
285 { d_uint16, offsetof(t_hhea, numOfLongHorMetrics) },
286 { d_end }
287};
288
289/* Horizontal Metrics ('hmtx') table */
290sfnt_decode longhormetric_decode[] = {
291 { d_uint16, 0 },
292 { d_skip(2) },
293 { d_end }
294};
295
1a61f569 296/* Kerning ('kern') table */
297typedef struct t_kern_Tag t_kern;
298struct t_kern_Tag {
299 unsigned version;
300 unsigned nTables;
301};
302sfnt_decode t_kern_v0_decode[] = {
303 { d_uint16, offsetof(t_kern, version) },
304 { d_uint16, offsetof(t_kern, nTables) },
305 { d_end }
306};
307typedef struct kern_v0_subhdr_Tag kern_v0_subhdr;
308struct kern_v0_subhdr_Tag {
309 unsigned version;
310 unsigned length;
311 unsigned coverage;
312};
313sfnt_decode kern_v0_subhdr_decode[] = {
314 { d_uint16, offsetof(kern_v0_subhdr, version) },
315 { d_uint16, offsetof(kern_v0_subhdr, length) },
316 { d_uint16, offsetof(kern_v0_subhdr, coverage) },
317 { d_end }
318};
319#define KERN_V0_HORIZ 0x0001
320#define KERN_V0_MINIMUM 0x0002
321#define KERN_V0_CROSSSTREAM 0x0004
322#define KERN_V0_OVERRIDE 0x0008
323#define KERN_V0_FORMAT 0xff00
324#define KERN_V0_FORMAT_0 0x0000
325sfnt_decode t_kern_v1_decode[] = {
326 { d_uint32, offsetof(t_kern, version) },
327 { d_uint32, offsetof(t_kern, nTables) },
328 { d_end }
329};
330typedef struct kern_v1_subhdr_Tag kern_v1_subhdr;
331struct kern_v1_subhdr_Tag {
332 unsigned length;
333 unsigned coverage;
334};
335sfnt_decode kern_v1_subhdr_decode[] = {
336 { d_uint32, offsetof(kern_v1_subhdr, length) },
337 { d_uint16, offsetof(kern_v1_subhdr, coverage) },
338 { d_skip(2) }, /* tupleIndex */
339 { d_end }
340};
341#define KERN_V1_VERTICAL 0x8000
342#define KERN_V1_CROSSSTREAM 0x4000
343#define KERN_V1_VARIATION 0x2000
344#define KERN_V1_FORMAT 0x00ff
345#define KERN_V1_FORMAT_0 0x0000
346typedef struct kern_f0_Tag kern_f0;
347struct kern_f0_Tag {
348 unsigned nPairs;
349};
350sfnt_decode kern_f0_decode[] = {
351 { d_uint16, offsetof(kern_f0, nPairs) },
352 { d_skip(6) }, /* searchRange, entrySelector, rangeShift */
353 { d_end }
354};
355typedef struct kern_f0_pair_Tag kern_f0_pair;
356struct kern_f0_pair_Tag {
357 unsigned left;
358 unsigned right;
359 int value;
360};
361sfnt_decode kern_f0_pair_decode[] = {
362 { d_uint16, offsetof(kern_f0_pair, left) },
363 { d_uint16, offsetof(kern_f0_pair, right) },
364 { d_int16, offsetof(kern_f0_pair, value) },
365 { d_end }
366};
367
cb93ccb7 368/* Maximum profile ('maxp') table */
369typedef struct t_maxp_Tag t_maxp;
370struct t_maxp_Tag {
371 unsigned version;
372 unsigned numGlyphs;
373};
374sfnt_decode t_maxp_decode[] = {
375 { d_uint32, offsetof(t_maxp, version) },
376 { d_uint16, offsetof(t_maxp, numGlyphs) },
377 { d_end }
378};
379
2729eafc 380/* Naming ('name') table */
381typedef struct t_name_Tag t_name;
382typedef struct namerecord_Tag namerecord;
383struct t_name_Tag {
384 unsigned format;
385 unsigned count;
386 unsigned stringOffset;
387 namerecord *nameRecord;
388};
389sfnt_decode t_name_decode[] = {
390 { d_uint16, offsetof(t_name, format) },
391 { d_uint16, offsetof(t_name, count) },
392 { d_uint16, offsetof(t_name, stringOffset) },
393 { d_end }
394};
395struct namerecord_Tag {
396 unsigned platformID;
397 unsigned encodingID;
398 unsigned languageID;
399 unsigned nameID;
400 unsigned length;
401 unsigned offset;
402};
403sfnt_decode namerecord_decode[] = {
404 { d_uint16, offsetof(namerecord, platformID) },
405 { d_uint16, offsetof(namerecord, encodingID) },
406 { d_uint16, offsetof(namerecord, languageID) },
407 { d_uint16, offsetof(namerecord, nameID) },
408 { d_uint16, offsetof(namerecord, length) },
409 { d_uint16, offsetof(namerecord, offset) },
410 { d_end }
411};
412
413/* PostScript compatibility ('post') table */
414typedef struct t_post_Tag t_post;
415struct t_post_Tag {
416 unsigned format;
47d88706 417 int italicAngle;
2729eafc 418 int underlinePosition;
419 int underlineThickness;
420 unsigned isFixedPitch;
421 unsigned minMemType42;
422 unsigned maxMemType42;
423};
424sfnt_decode t_post_decode[] = {
425 { d_uint32, offsetof(t_post, format) },
47d88706 426 { d_int32, offsetof(t_post, italicAngle) },
2729eafc 427 { d_int16, offsetof(t_post, underlinePosition) },
428 { d_int16, offsetof(t_post, underlineThickness) },
429 { d_uint32, offsetof(t_post, isFixedPitch) },
430 { d_uint32, offsetof(t_post, minMemType42) },
431 { d_uint32, offsetof(t_post, maxMemType42) },
432 { d_skip(8) }, /* minMemType1, maxMemType1 */
433 { d_end }
434};
435
436typedef struct {
437 glyph name;
438 unsigned short index;
439} glyphmap;
440
2729eafc 441struct sfnt_Tag {
442 void *data;
443 size_t len;
444 void *end;
d41ae9ad 445 filepos pos;
2729eafc 446 offsubdir osd;
447 tabledir *td;
448 t_head head;
449 unsigned nglyphs;
450 glyph *glyphsbyindex;
451 unsigned short *glyphsbyname;
452 unsigned minmem, maxmem;
453};
454
455static int sfnt_findtable(sfnt *sf, unsigned tag,
456 void **startp, void **endp) {
457 size_t i;
458
459 for (i = 0; i < sf->osd.numTables; i++) {
460 if (sf->td[i].tag == tag) {
461 *startp = (char *)sf->data + sf->td[i].offset;
462 *endp = (char *)*startp + sf->td[i].length;
463 return TRUE;
464 }
465 }
466 return FALSE;
467}
468
469static char *sfnt_psname(font_info *fi) {
470 sfnt *sf = fi->fontfile;
471 t_name name;
472 void *ptr, *end;
473 size_t i;
474 char *psname;
475 namerecord *nr;
476
d41ae9ad 477 if (!sfnt_findtable(sf, TAG_name, &ptr, &end)) {
478 error(err_sfntnotable, &sf->pos, "name");
479 return NULL;
480 }
2729eafc 481 ptr = decode(t_name_decode, ptr, end, &name);
482 name.nameRecord = snewn(name.count, namerecord);
483 ptr = decoden(namerecord_decode, ptr, sf->end, name.nameRecord,
484 sizeof(*name.nameRecord), name.count);
485 for (i = 0; i < name.count; i++) {
486 nr = name.nameRecord + i;
487 if (nr->nameID == 6) {
488 /* PostScript name, but can we make sense of it? */
489 if (nr->platformID == 1 && nr->encodingID == 0) {
490 /* Mac Roman, which is ASCII for our purposes */
491 psname = snewn(nr->length + 1, char);
492 memcpy(psname, (char *)ptr + nr->offset, nr->length);
493 psname[nr->length] = 0;
494 sfree(name.nameRecord);
495 return psname;
496 }
497 }
498 }
d41ae9ad 499 error(err_sfntnopsname, &sf->pos);
2729eafc 500 return NULL;
501}
502
47d88706 503static unsigned short *cmp_glyphsbyindex;
504static int glyphsbyname_cmp(void const *a, void const *b) {
505 glyph ga = cmp_glyphsbyindex[*(unsigned short *)a];
506 glyph gb = cmp_glyphsbyindex[*(unsigned short *)b];
507 if (ga < gb) return -1;
508 if (ga > gb) return 1;
509 return 0;
510}
511static int glyphsbyname_cmp_search(void const *a, void const *b) {
512 glyph ga = *(glyph *)a;
513 glyph gb = cmp_glyphsbyindex[*(unsigned short *)b];
514 if (ga < gb) return -1;
515 if (ga > gb) return 1;
516 return 0;
517}
518
cb93ccb7 519/* Generate an name for a glyph that doesn't have one. */
520static glyph genglyph(unsigned idx) {
521 char buf[11];
522 if (idx == 0) return glyph_intern(".notdef");
523 sprintf(buf, "glyph%u", idx);
524 return glyph_intern(buf);
525}
526
2729eafc 527/*
528 * Extract data from the 'post' table (mostly glyph mappings)
529 *
530 * TODO: cope better with duplicated glyph names (usually .notdef)
531 * TODO: when presented with format 3.0, try to use 'CFF' if present.
532 */
47d88706 533static void sfnt_mapglyphs(font_info *fi) {
534 sfnt *sf = fi->fontfile;
2729eafc 535 t_post post;
536 void *ptr, *end;
18e7663a 537 unsigned char *sptr;
538 char tmp[256];
2729eafc 539 glyph *extraglyphs;
540 unsigned nextras, i, g;
541
542 sf->glyphsbyname = sf->glyphsbyindex = NULL;
cb93ccb7 543 if (sfnt_findtable(sf, TAG_post, &ptr, &end)) {
544 ptr = decode(t_post_decode, ptr, end, &post);
545 if (ptr == NULL) {
546 error(err_sfntbadtable, &sf->pos, "post");
547 goto noglyphs;
548 }
47d88706 549
cb93ccb7 550 sf->minmem = post.minMemType42;
551 sf->maxmem = post.maxMemType42;
552 fi->italicangle = post.italicAngle / 65536.0;
553 switch (post.format) {
554 case 0x00010000:
555 if (sf->nglyphs != 258) {
556 error(err_sfntbadtable, &sf->pos, "post");
557 break;
558 }
559 sf->glyphsbyindex = (glyph *)tt_std_glyphs;
560 break;
561 case 0x00020000:
562 if ((char *)ptr + 2 > (char *)end) {
563 error(err_sfntbadtable, &sf->pos, "post");
564 break;
565 }
566 ptr = (char *)ptr + 2;
567 if ((char *)ptr + 2*sf->nglyphs > (char *)end) {
568 error(err_sfntbadtable, &sf->pos, "post");
569 break;
570 }
571 nextras = 0;
572 for (sptr = (unsigned char *)ptr + 2*sf->nglyphs;
573 sptr < (unsigned char *)end;
574 sptr += *sptr+1)
575 nextras++;
576 extraglyphs = snewn(nextras, glyph);
577 i = 0;
578 for (sptr = (unsigned char *)ptr + 2*sf->nglyphs;
579 sptr < (unsigned char *)end;
580 sptr += *sptr+1) {
581 memcpy(tmp, sptr + 1, *sptr);
582 tmp[*sptr] = 0;
583 assert(i < nextras);
584 extraglyphs[i++] = glyph_intern(tmp);
585 }
586 sf->glyphsbyindex = snewn(sf->nglyphs, glyph);
587 for (i = 0; i < sf->nglyphs; i++) {
588 decode_uint16((char *)ptr + 2*i, &g);
589 if (g <= 257)
590 sf->glyphsbyindex[i] = tt_std_glyphs[g];
591 else if (g < 258 + nextras)
592 sf->glyphsbyindex[i] = extraglyphs[g - 258];
593 else {
594 error(err_sfntbadtable, &sf->pos, "post");
595 sf->glyphsbyindex[i] = genglyph(i);
596 }
597 }
598 sfree(extraglyphs);
599 break;
600 case 0x00030000:
601 break;
602 default:
603 error(err_sfnttablevers, &sf->pos, "post");
604 break;
2729eafc 605 }
cb93ccb7 606 }
607 noglyphs:
608 if (!sf->glyphsbyindex) {
2729eafc 609 sf->glyphsbyindex = snewn(sf->nglyphs, glyph);
cb93ccb7 610 for (i = 0; i < sf->nglyphs; i++)
611 sf->glyphsbyindex[i] = genglyph(i);
2729eafc 612 }
47d88706 613 /* Construct glyphsbyname */
614 sf->glyphsbyname = snewn(sf->nglyphs, unsigned short);
615 for (i = 0; i < sf->nglyphs; i++)
616 sf->glyphsbyname[i] = i;
617 cmp_glyphsbyindex = sf->glyphsbyindex;
618 qsort(sf->glyphsbyname, sf->nglyphs, sizeof(*sf->glyphsbyname),
619 glyphsbyname_cmp);
620}
621
e7d4c88f 622glyph sfnt_indextoglyph(sfnt *sf, unsigned idx) {
47d88706 623 return sf->glyphsbyindex[idx];
624}
625
e7d4c88f 626unsigned sfnt_nglyphs(sfnt *sf) {
627 return sf->nglyphs;
628}
629
630unsigned sfnt_glyphtoindex(sfnt *sf, glyph g) {
47d88706 631 cmp_glyphsbyindex = sf->glyphsbyindex;
632 return *(unsigned short *)bsearch(&g, sf->glyphsbyname, sf->nglyphs,
633 sizeof(*sf->glyphsbyname),
634 glyphsbyname_cmp_search);
2729eafc 635}
636
637/*
39d3d900 638 * Get data from 'hhea', 'hmtx', and 'OS/2' tables
2729eafc 639 */
640void sfnt_getmetrics(font_info *fi) {
641 sfnt *sf = fi->fontfile;
642 t_hhea hhea;
39d3d900 643 t_OS_2 OS_2;
2729eafc 644 void *ptr, *end;
645 unsigned i, j;
646 unsigned *hmtx;
647
39d3d900 648 /* First, the bounding box from the 'head' table. */
649 fi->fontbbox[0] = sf->head.xMin * FUNITS_PER_PT / sf->head.unitsPerEm;
650 fi->fontbbox[1] = sf->head.yMin * FUNITS_PER_PT / sf->head.unitsPerEm;
651 fi->fontbbox[2] = sf->head.xMax * FUNITS_PER_PT / sf->head.unitsPerEm;
652 fi->fontbbox[3] = sf->head.yMax * FUNITS_PER_PT / sf->head.unitsPerEm;
d41ae9ad 653 if (!sfnt_findtable(sf, TAG_hhea, &ptr, &end)) {
654 error(err_sfntnotable, &sf->pos, "hhea");
655 return;
656 }
657 if (decode(t_hhea_decode, ptr, end, &hhea) == NULL) {
658 error(err_sfntbadtable, &sf->pos, "hhea");
659 return;
660 }
661 if ((hhea.version & 0xffff0000) != 0x00010000) {
662 error(err_sfnttablevers, &sf->pos, "hhea");
663 return;
664 }
2729eafc 665 fi->ascent = hhea.ascent;
666 fi->descent = hhea.descent;
d41ae9ad 667 if (hhea.metricDataFormat != 0) {
668 error(err_sfnttablevers, &sf->pos, "hmtx");
669 return;
670 }
671 if (!sfnt_findtable(sf, TAG_hmtx, &ptr, &end)) {
672 error(err_sfntnotable, &sf->pos, "hmtx");
673 return;
674 }
2729eafc 675 hmtx = snewn(hhea.numOfLongHorMetrics, unsigned);
676 if (decoden(longhormetric_decode, ptr, end, hmtx, sizeof(*hmtx),
d41ae9ad 677 hhea.numOfLongHorMetrics) == NULL) {
678 error(err_sfntbadtable, &sf->pos, "hmtx");
679 return;
680 }
2729eafc 681 for (i = 0; i < sf->nglyphs; i++) {
682 glyph_width *w = snew(glyph_width);
47d88706 683 w->glyph = sfnt_indextoglyph(sf, i);
2729eafc 684 j = i < hhea.numOfLongHorMetrics ? i : hhea.numOfLongHorMetrics - 1;
685 w->width = hmtx[j] * UNITS_PER_PT / sf->head.unitsPerEm;
686 add234(fi->widths, w);
687 }
39d3d900 688 /* Now see if the 'OS/2' table has any useful metrics */
689 if (!sfnt_findtable(sf, TAG_OS_2, &ptr, &end))
690 return;
691 if (decode(uint16_decode, ptr, end, &OS_2.version) == NULL)
d41ae9ad 692 goto bados2;
39d3d900 693 if (OS_2.version >= 2) {
694 if (decode(t_OS_2_v2_decode, ptr, end, &OS_2) == NULL)
d41ae9ad 695 goto bados2;
39d3d900 696 fi->xheight = OS_2.sxHeight * FUNITS_PER_PT / sf->head.unitsPerEm;
697 fi->capheight = OS_2.sCapHeight * FUNITS_PER_PT / sf->head.unitsPerEm;
698 } else if (OS_2.version == 1) {
699 if (decode(t_OS_2_v1_decode, ptr, end, &OS_2) == NULL)
d41ae9ad 700 goto bados2;
39d3d900 701 } else
702 return;
703 fi->ascent = OS_2.sTypoAscender * FUNITS_PER_PT / sf->head.unitsPerEm;
704 fi->descent = OS_2.sTypoDescender * FUNITS_PER_PT / sf->head.unitsPerEm;
d41ae9ad 705 return;
706 bados2:
707 error(err_sfntbadtable, &sf->pos, "OS/2");
2729eafc 708}
709
710/*
1a61f569 711 * Get kerning data from a 'kern' table
712 *
713 * 'kern' tables have two gratuitously different header formats, one
714 * used by Apple and one by Microsoft. Happily, the kerning tables
715 * themselves use the same formats. Halibut only supports simple kern
716 * pairs for horizontal kerning of horizontal text, and ignores
717 * everything else.
718 */
719static void sfnt_getkern(font_info *fi) {
720 sfnt *sf = fi->fontfile;
721 t_kern kern;
722 unsigned version, i, j;
723 void *ptr, *end;
724
725 if (!sfnt_findtable(sf, TAG_kern, &ptr, &end))
726 return;
727 if (!decode(uint16_decode, ptr, end, &version))
d41ae9ad 728 goto bad;
1a61f569 729 if (version == 0)
730 ptr = decode(t_kern_v0_decode, ptr, end, &kern);
731 else if (version == 1)
732 ptr = decode(t_kern_v1_decode, ptr, end, &kern);
733 else return;
d41ae9ad 734 if (ptr == NULL) goto bad;
1a61f569 735 for (i = 0; i < kern.nTables; i++) {
736 kern_f0 f0;
737 kern_pair *kerns;
738 if (version == 0) {
739 kern_v0_subhdr sub;
740 ptr = decode(kern_v0_subhdr_decode, ptr, end, &sub);
d41ae9ad 741 if (ptr == NULL) goto bad;
1a61f569 742 if (sub.version != 0 ||
743 (sub.coverage & (KERN_V0_HORIZ | KERN_V0_MINIMUM |
744 KERN_V0_CROSSSTREAM | KERN_V0_FORMAT)) !=
745 (KERN_V0_HORIZ | KERN_V0_FORMAT_0)) {
746 ptr = (char *)ptr + sub.length - 6;
747 continue;
748 }
749 } else {
750 kern_v1_subhdr sub;
751 ptr = decode(kern_v1_subhdr_decode, ptr, end, &sub);
d41ae9ad 752 if (ptr == NULL) goto bad;
1a61f569 753 if ((sub.coverage & (KERN_V1_VERTICAL | KERN_V1_CROSSSTREAM |
754 KERN_V1_VARIATION | KERN_V1_FORMAT)) !=
755 KERN_V0_FORMAT_0) {
756 ptr = (char *)ptr + sub.length - 8;
757 continue;
758 }
759 }
760 ptr = decode(kern_f0_decode, ptr, end, &f0);
d41ae9ad 761 if (ptr == NULL) goto bad;
1a61f569 762 kerns = snewn(f0.nPairs, kern_pair);
763 for (j = 0; j < f0.nPairs; j++) {
764 kern_f0_pair p;
765 kern_pair *kp = kerns + j;
766 ptr = decode(kern_f0_pair_decode, ptr, end, &p);
d41ae9ad 767 if (ptr == NULL) goto bad;
768 if (p.left >= sf->nglyphs || p.right >= sf->nglyphs) goto bad;
1a61f569 769 kp->left = sfnt_indextoglyph(sf, p.left);
770 kp->right = sfnt_indextoglyph(sf, p.right);
771 kp->kern = p.value * UNITS_PER_PT / (int)sf->head.unitsPerEm;
772 add234(fi->kerns, kp);
773 }
774 }
d41ae9ad 775 return;
776 bad:
777 error(err_sfntbadtable, &sf->pos, "kern");
778 return;
1a61f569 779}
780
781/*
2729eafc 782 * Get mapping data from 'cmap' table
783 *
d274495f 784 * We look for either a (0, 3), or (3, 1) table, both of these being
785 * versions of UCS-2. We only handle format 4 of this table, since
786 * that seems to be the only one in use.
2729eafc 787 */
788void sfnt_getmap(font_info *fi) {
789 sfnt *sf = fi->fontfile;
790 t_cmap cmap;
791 encodingrec *esd;
792 void *base, *ptr, *end;
793 unsigned i;
794 unsigned format;
795
796
797 for (i = 0; i < lenof(fi->bmp); i++)
798 fi->bmp[i] = 0xFFFF;
d41ae9ad 799 if (!sfnt_findtable(sf, TAG_cmap, &ptr, &end)) {
800 error(err_sfntnotable, &sf->pos, "cmap");
801 }
2729eafc 802 base = ptr;
803 ptr = decode(t_cmap_decode, ptr, end, &cmap);
d41ae9ad 804 if (ptr == NULL) goto bad;
2729eafc 805 esd = snewn(cmap.numTables, encodingrec);
806 ptr = decoden(encodingrec_decode, ptr, end, esd, sizeof(*esd),
807 cmap.numTables);
d41ae9ad 808 if (ptr == NULL) goto bad;
2729eafc 809 for (i = 0; i < cmap.numTables; i++) {
810 if (!decode(uint16_decode, (char *)base + esd[i].offset, end, &format))
d41ae9ad 811 goto bad;
2729eafc 812 if ((esd[i].platformID == 0 && esd[i].encodingID == 3) ||
813 (esd[i].platformID == 3 && esd[i].encodingID == 1)) {
814 /* UCS-2 encoding */
815 if (!decode(uint16_decode, (char *)base + esd[i].offset, end,
816 &format))
d41ae9ad 817 goto bad;
2729eafc 818 if (format == 4) {
819 unsigned *data, *endCode, *startCode, *idDelta, *idRangeOffset;
820 unsigned *glyphIndexArray;
821 unsigned segcount, nword, nglyphindex, j;
822 cmap4 cmap4;
823
824 ptr = decode(cmap4_decode, (char *)base + esd[i].offset, end,
825 &cmap4);
d41ae9ad 826 if (!ptr) goto bad;
2729eafc 827 segcount = cmap4.segCountX2 / 2;
828 nword = cmap4.length / 2 - 7;
829 data = snewn(nword, unsigned);
830 if (!decoden(uint16_decode, ptr, (char *)ptr + nword * 2,
d41ae9ad 831 data, sizeof(*data), nword)) goto bad;
2729eafc 832 endCode = data;
833 startCode = data + segcount + 1;
834 idDelta = startCode + segcount;
835 idRangeOffset = idDelta + segcount;
836 glyphIndexArray = idRangeOffset + segcount;
837 nglyphindex = nword - segcount * 4 - 1;
838
839 for (j = 0; j < segcount; j++) {
840 unsigned k, idx;
841
842 if (idRangeOffset[j] == 0) {
843 for (k = startCode[j]; k <= endCode[j]; k++) {
844 idx = (k + idDelta[j]) & 0xffff;
845 if (idx != 0) {
d41ae9ad 846 if (idx > sf->nglyphs) goto bad;
47d88706 847 fi->bmp[k] = sfnt_indextoglyph(sf, idx);
2729eafc 848 }
849 }
850 } else {
851 unsigned startidx = idRangeOffset[j]/2 - segcount + j;
852 for (k = startCode[j]; k <= endCode[j]; k++) {
853 idx = glyphIndexArray[startidx + k - startCode[j]];
854 if (idx != 0) {
855 idx = (idx + idDelta[j]) & 0xffff;
d41ae9ad 856 if (idx > sf->nglyphs) goto bad;
47d88706 857 fi->bmp[k] = sfnt_indextoglyph(sf, idx);
2729eafc 858 }
859 }
860 }
861 }
2729eafc 862 sfree(data);
d41ae9ad 863 return;
2729eafc 864 }
865 }
866 }
d41ae9ad 867 error(err_sfntnounicmap, &sf->pos);
868 return;
869 bad:
870 error(err_sfntbadtable, &sf->pos, "cmap");
2729eafc 871}
872
873void read_sfnt_file(input *in) {
874 sfnt *sf = snew(sfnt);
875 size_t off = 0, got;
876 FILE *fp = in->currfp;
877 font_info *fi = snew(font_info);
2729eafc 878 void *ptr, *end;
cb93ccb7 879 t_maxp maxp;
2729eafc 880
881 fi->name = NULL;
882 fi->widths = newtree234(width_cmp);
883 fi->kerns = newtree234(kern_cmp);
884 fi->ligs = newtree234(lig_cmp);
885 fi->fontbbox[0] = fi->fontbbox[1] = fi->fontbbox[2] = fi->fontbbox[3] = 0;
886 fi->capheight = fi->xheight = fi->ascent = fi->descent = 0;
887 fi->stemh = fi->stemv = fi->italicangle = 0;
888 fi->fontfile = sf;
889 fi->filetype = TRUETYPE;
890
891 sf->len = 32768;
892 sf->data = snewn(sf->len, unsigned char);
893 for (;;) {
894 got = fread((char *)sf->data + off, 1, sf->len - off, fp);
895 off += got;
896 if (off != sf->len) break;
897 sf->len *= 2;
898 sf->data = sresize(sf->data, sf->len, unsigned char);
899 }
d41ae9ad 900 fclose(in->currfp);
2729eafc 901 sf->len = off;
902 sf->data = sresize(sf->data, sf->len, unsigned char);
903 sf->end = (char *)sf->data + sf->len;
d41ae9ad 904 sf->pos = in->pos;
905 sf->pos.line = 0;
906 sf->nglyphs = 0;
907 ptr = decode(offsubdir_decode, sf->data, sf->end, &sf->osd);
908 if (ptr == NULL) {
909 error(err_sfntbadhdr, &sf->pos);
910 return;
911 }
2729eafc 912 sf->td = snewn(sf->osd.numTables, tabledir);
d41ae9ad 913 ptr = decoden(tabledir_decode, ptr, sf->end, sf->td, sizeof(*sf->td),
914 sf->osd.numTables);
915 if (ptr == NULL) {
916 error(err_sfntbadhdr, &sf->pos);
917 return;
918 }
919 if (!sfnt_findtable(sf, TAG_head, &ptr, &end)) {
920 error(err_sfntnotable, &sf->pos, "head");
921 return;
922 }
923 if (decode(t_head_decode, ptr, end, &sf->head) == NULL) {
924 error(err_sfntbadtable, &sf->pos, "head");
925 return;
926 }
927 if ((sf->head.version & 0xffff0000) != 0x00010000) {
928 error(err_sfnttablevers, &sf->pos, "head");
929 return;
930 }
cb93ccb7 931 if (!sfnt_findtable(sf, TAG_maxp, &ptr, &end)) {
932 error(err_sfntnotable, &sf->pos, "maxp");
933 return;
934 }
935 if (decode(t_maxp_decode, ptr, end, &maxp) == NULL) {
936 error(err_sfntbadtable, &sf->pos, "maxp");
937 return;
938 }
939 if (maxp.version < 0x00005000 || maxp.version > 0x0001ffff) {
940 error(err_sfnttablevers, &sf->pos, "maxp");
941 return;
942 }
943 sf->nglyphs = maxp.numGlyphs;
2729eafc 944 fi->name = sfnt_psname(fi);
d41ae9ad 945 if (fi->name == NULL) return;
47d88706 946 sfnt_mapglyphs(fi);
2729eafc 947 sfnt_getmetrics(fi);
1a61f569 948 sfnt_getkern(fi);
2729eafc 949 sfnt_getmap(fi);
950 fi->next = all_fonts;
951 all_fonts = fi;
2729eafc 952}
953
954static int sizecmp(const void *a, const void *b) {
955 if (*(size_t *)a < *(size_t *)b) return -1;
956 if (*(size_t *)a > *(size_t *)b) return 1;
957 return 0;
958}
959
960/*
961 * The format for embedding TrueType fonts in Postscript is defined in
962 * Adobe Technical Note #5012: The Type 42 Font Format Specification.
963 * <http://partners.adobe.com/public/developer/en/font/5012.Type42_Spec.pdf>
964 */
965
966void sfnt_writeps(font_info const *fi, FILE *ofp) {
967 unsigned i, j, lastbreak;
968 sfnt *sf = fi->fontfile;
969 size_t *breaks, glyfoff, glyflen;
970 void *glyfptr, *glyfend, *locaptr, *locaend;
971 unsigned *loca;
c358bf5b 972 int cc = 0;
2729eafc 973
974 /* XXX Unclear that this is the correct format. */
975 fprintf(ofp, "%%!PS-TrueTypeFont-%u-%u\n", sf->osd.scaler_type,
976 sf->head.fontRevision);
977 if (sf->minmem)
978 fprintf(ofp, "%%%%VMUsage: %u %u\n", sf->minmem, sf->maxmem);
979 fprintf(ofp, "9 dict dup begin\n");
980 fprintf(ofp, "/FontType 42 def\n");
981 fprintf(ofp, "/FontMatrix [1 0 0 1 0 0] def\n");
982 fprintf(ofp, "/FontName /%s def\n", fi->name);
983 fprintf(ofp, "/Encoding StandardEncoding def\n");
984 if ((sf->head.flags & 0x0003) == 0x0003) {
985 /*
986 * Sensible font with the origin in the right place, such that
987 * the bounding box is meaningful.
988 */
989 fprintf(ofp, "/FontBBox [%g %g %g %g] readonly def\n",
990 (double)sf->head.xMin / sf->head.unitsPerEm,
991 (double)sf->head.yMin / sf->head.unitsPerEm,
992 (double)sf->head.xMax / sf->head.unitsPerEm,
993 (double)sf->head.yMax / sf->head.unitsPerEm);
994 } else {
995 /* Non-sensible font. */
b554f0ec 996 fprintf(ofp, "/FontBBox [0 0 0 0] readonly def\n");
2729eafc 997 }
998 fprintf(ofp, "/PaintType 0 def\n");
999 fprintf(ofp, "/CharStrings %u dict dup begin\n", sf->nglyphs);
a2bd2219 1000 fprintf(ofp, "0 1 %u{currentfile token pop exch def}bind for\n",
1001 sf->nglyphs - 1);
2729eafc 1002 for (i = 0; i < sf->nglyphs; i++)
c358bf5b 1003 ps_token(ofp, &cc, "/%s", glyph_extern(sfnt_indextoglyph(sf, i)));
1004 fprintf(ofp, "\nend readonly def\n");
2729eafc 1005 fprintf(ofp, "/sfnts [<");
1006 breaks = snewn(sf->osd.numTables + sf->nglyphs, size_t);
1007 for (i = 0; i < sf->osd.numTables; i++) {
1008 breaks[i] = sf->td[i].offset;
1009 }
d41ae9ad 1010 if (!sfnt_findtable(sf, TAG_glyf, &glyfptr, &glyfend)) {
4691e240 1011 error(err_sfntnotable, &sf->pos, "glyf");
d41ae9ad 1012 return;
1013 }
2729eafc 1014 glyfoff = (char *)glyfptr - (char *)sf->data;
1015 glyflen = (char *)glyfend - (char *)glyfptr;
d41ae9ad 1016 if (!sfnt_findtable(sf, TAG_loca, &locaptr, &locaend)) {
4691e240 1017 error(err_sfntnotable, &sf->pos, "loca");
d41ae9ad 1018 return;
1019 }
2729eafc 1020 loca = snewn(sf->nglyphs, unsigned);
1021 if (sf->head.indexToLocFormat == 0) {
1022 if (!decoden(uint16_decode, locaptr, locaend, loca, sizeof(*loca),
d41ae9ad 1023 sf->nglyphs)) goto badloca;
2729eafc 1024 for (i = 0; i < sf->nglyphs; i++) loca[i] *= 2;
1025 } else {
1026 if (!decoden(uint32_decode, locaptr, locaend, loca, sizeof(*loca),
d41ae9ad 1027 sf->nglyphs)) goto badloca;
2729eafc 1028 }
1029 for (i = 1; i < sf->nglyphs; i++) {
d41ae9ad 1030 if (loca[i] > glyflen) goto badloca;
2729eafc 1031 breaks[sf->osd.numTables + i - 1] = loca[i] + glyfoff;
1032 }
1033 breaks[sf->osd.numTables + sf->nglyphs - 1] = sf->len;
1034 qsort(breaks, sf->osd.numTables + sf->nglyphs, sizeof(*breaks), sizecmp);
1035 j = lastbreak = 0;
1036 for (i = 0; i < sf->len; i++) {
1037 if ((i - lastbreak) % 38 == 0) fprintf(ofp, "\n");
1038 if (i == breaks[j]) {
1039 while (i == breaks[j]) j++;
1040 lastbreak = i;
1041 fprintf(ofp, "00><\n");
1042 }
1043 fprintf(ofp, "%02x", *((unsigned char *)sf->data + i));
1044 }
1045 fprintf(ofp, "00>] readonly def\n");
1046 sfree(breaks);
1047 fprintf(ofp, "end /%s exch definefont\n", fi->name);
d41ae9ad 1048 return;
1049 badloca:
1050 error(err_sfntbadtable, &sf->pos, "loca");
2729eafc 1051}
dde3b989 1052
dde3b989 1053void sfnt_data(font_info *fi, char **bufp, size_t *lenp) {
1054 sfnt *sf = fi->fontfile;
1055 *bufp = sf->data;
1056 *lenp = sf->len;
1057}