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