Support for embedding TrueType fonts in PDF output. The code isn't the most
[sgt/halibut] / in_sfnt.c
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/>
15 */
16
17 #include <assert.h>
18 #include <stddef.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include "halibut.h"
22 #include "paper.h"
23
24 typedef struct sfnt_decode_Tag sfnt_decode;
25 struct sfnt_decode_Tag {
26 void (*decoder)(void *src, void *dest);
27 size_t src_len;
28 size_t dest_offset;
29 };
30
31 #if 0 /* unused */
32 static void decode_uint8(void *src, void *dest) {
33 *(unsigned int *)dest = *(unsigned char *)src;
34 }
35 #define d_uint8 decode_uint8, 1
36 #endif
37
38 #if 0 /* unused */
39 static void decode_int8(void *src, void *dest) {
40 *(int *)dest = *(signed char *)src;
41 }
42 #define d_int8 decode_int8, 1
43 #endif
44
45 static void decode_uint16(void *src, void *dest) {
46 unsigned char *cp = src;
47 *(unsigned int *)dest = (cp[0] << 8) + cp[1];
48 }
49 #define d_uint16 decode_uint16, 2
50
51 static void decode_int16(void *src, void *dest) {
52 signed char *cp = src;
53 unsigned char *ucp = src;
54 *(int *)dest = (cp[0] << 8) + ucp[1];
55 }
56 #define d_int16 decode_int16, 2
57
58 static void decode_uint32(void *src, void *dest) {
59 unsigned char *cp = src;
60 *(unsigned int *)dest =
61 (cp[0] << 24) + (cp[1] << 16) + (cp[2] << 8) + cp[3];
62 }
63 #define d_uint32 decode_uint32, 4
64
65 static void decode_int32(void *src, void *dest) {
66 signed char *cp = src;
67 unsigned char *ucp = src;
68 *(int *)dest = (cp[0] << 24) + (ucp[1] << 16) + (ucp[2] << 8) + ucp[3];
69 }
70 #define d_int32 decode_int32, 4
71
72 static void decode_skip(void *src, void *dest) {
73 IGNORE(src);
74 IGNORE(dest);
75 /* do nothing */
76 }
77 #define d_skip(n) decode_skip, (n), 0
78
79 static void decode_end(void *src, void *dest) {
80 IGNORE(src);
81 IGNORE(dest);
82 /* never called */
83 }
84 #define d_end decode_end, 0, 0
85
86 static void *decode(sfnt_decode *dec, void *src, void *end, void *dest) {
87 while (dec->decoder != decode_end) {
88 if ((char *)src + dec->src_len > (char *)end) return NULL;
89 dec->decoder(src, (char *)dest + dec->dest_offset);
90 src = (char *)src + dec->src_len;
91 dec++;
92 }
93 return src;
94 }
95
96 static void *decoden(sfnt_decode *dec, void *src, void *end, void *dest,
97 size_t size, size_t n) {
98 while (n-- && src) {
99 src = decode(dec, src, end, dest);
100 dest = (char *)dest + size;
101 }
102 return src;
103 }
104
105 /* Decoding specs for simple data types */
106 sfnt_decode uint16_decode[] = { { d_uint16, 0 }, { d_end } };
107 sfnt_decode int16_decode[] = { { d_int16, 0 }, { d_end } };
108 sfnt_decode uint32_decode[] = { { d_uint32, 0 }, { d_end } };
109
110 /* Offset subdirectory -- the start of the file */
111 typedef struct offsubdir_Tag offsubdir;
112 struct offsubdir_Tag {
113 unsigned scaler_type;
114 unsigned numTables;
115 };
116 sfnt_decode offsubdir_decode[] = {
117 { d_uint32, offsetof(offsubdir, scaler_type) },
118 { d_uint16, offsetof(offsubdir, numTables) },
119 { d_skip(6) },
120 { d_end }
121 };
122
123 #define sfnt_00010000 0x00010000
124 #define TAG_OS_2 0x4f532f32
125 #define TAG_cmap 0x636d6170
126 #define TAG_glyf 0x676c7966
127 #define TAG_head 0x68656164
128 #define TAG_hhea 0x68686561
129 #define TAG_hmtx 0x686d7478
130 #define TAG_loca 0x6c6f6361
131 #define TAG_name 0x6e616d65
132 #define TAG_post 0x706f7374
133 #define sfnt_true 0x74727565
134
135 /* Table directory */
136 typedef struct tabledir_Tag tabledir;
137 struct tabledir_Tag {
138 unsigned tag;
139 unsigned checkSum;
140 unsigned offset;
141 unsigned length;
142 };
143 sfnt_decode tabledir_decode[] = {
144 { d_uint32, offsetof(tabledir, tag) },
145 { d_uint32, offsetof(tabledir, checkSum) },
146 { d_uint32, offsetof(tabledir, offset) },
147 { d_uint32, offsetof(tabledir, length) },
148 { d_end }
149 };
150
151 /* OS/2 and Windows compatibility table */
152 typedef struct t_OS_2_Tag t_OS_2;
153 struct t_OS_2_Tag {
154 unsigned version;
155 int sTypoAscender, sTypoDescender;
156 int sxHeight, sCapHeight;
157 };
158 sfnt_decode t_OS_2_v0_decode[] = {
159 { d_uint16, offsetof(t_OS_2, version) },
160 { d_skip(66) }, /* xAvgCharWidth, usWeightClass, usWidthClass, fsType, */
161 /* ySubscriptXSize, ySubscriptYSize, ySubscriptXOffset, */
162 /* ySubscriptYOffset, ySuperscriptXSize, ySuperscriptYSize, */
163 /* ySuperscriptXOffset, ySupercriptYOffset, sFamilyClass, panose, */
164 /* ulUnicodeRange1, ulUnicodeRange2, ulUnicodeRange3, ulUnicodeRange4, */
165 /* achVendID, fsSelection, usFirstCharIndex, usLastCharIndex */
166 { d_end }
167 };
168 sfnt_decode t_OS_2_v1_decode[] = {
169 { d_uint16, offsetof(t_OS_2, version) },
170 { d_skip(66) }, /* xAvgCharWidth, usWeightClass, usWidthClass, fsType, */
171 /* ySubscriptXSize, ySubscriptYSize, ySubscriptXOffset, */
172 /* ySubscriptYOffset, ySuperscriptXSize, ySuperscriptYSize, */
173 /* ySuperscriptXOffset, ySupercriptYOffset, sFamilyClass, panose, */
174 /* ulUnicodeRange1, ulUnicodeRange2, ulUnicodeRange3, ulUnicodeRange4, */
175 /* achVendID, fsSelection, usFirstCharIndex, usLastCharIndex */
176 { d_int16, offsetof(t_OS_2, sTypoAscender) },
177 { d_int16, offsetof(t_OS_2, sTypoDescender) },
178 { d_skip(14) }, /* sTypoLineGap, usWinAscent, usWinDescent, */
179 /* ulCodePageRange1, ulCodePageRange2 */
180 { d_end }
181 };
182 sfnt_decode t_OS_2_v2_decode[] = {
183 { d_uint16, offsetof(t_OS_2, version) },
184 { d_skip(66) }, /* xAvgCharWidth, usWeightClass, usWidthClass, fsType, */
185 /* ySubscriptXSize, ySubscriptYSize, ySubscriptXOffset, */
186 /* ySubscriptYOffset, ySuperscriptXSize, ySuperscriptYSize, */
187 /* ySuperscriptXOffset, ySupercriptYOffset, sFamilyClass, panose, */
188 /* ulUnicodeRange1, ulUnicodeRange2, ulUnicodeRange3, ulUnicodeRange4, */
189 /* achVendID, fsSelection, usFirstCharIndex, usLastCharIndex */
190 { d_int16, offsetof(t_OS_2, sTypoAscender) },
191 { d_int16, offsetof(t_OS_2, sTypoDescender) },
192 { d_skip(14) }, /* sTypoLineGap, usWinAscent, usWinDescent, */
193 /* ulCodePageRange1, ulCodePageRange2 */
194 { d_int16, offsetof(t_OS_2, sxHeight) },
195 { d_int16, offsetof(t_OS_2, sCapHeight) },
196 { d_skip(6) }, /* usDefaultChar, usBreakChar, usMaxContext */
197 { d_end }
198 };
199
200 /* Character to Glyph ('cmap') table */
201 typedef struct t_cmap_Tag t_cmap;
202 struct t_cmap_Tag {
203 unsigned numTables;
204 };
205 sfnt_decode t_cmap_decode[] = {
206 { d_skip(2) },
207 { d_uint16, offsetof(t_cmap, numTables) },
208 { d_end }
209 };
210 typedef struct encodingrec_Tag encodingrec;
211 struct encodingrec_Tag {
212 unsigned platformID;
213 unsigned encodingID;
214 unsigned offset;
215 };
216 sfnt_decode encodingrec_decode[] = {
217 { d_uint16, offsetof(encodingrec, platformID) },
218 { d_uint16, offsetof(encodingrec, encodingID) },
219 { d_uint32, offsetof(encodingrec, offset) },
220 { d_end }
221 };
222 typedef struct cmap4_Tag cmap4;
223 struct cmap4_Tag {
224 unsigned length;
225 unsigned segCountX2;
226 };
227 sfnt_decode cmap4_decode[] = {
228 { d_skip(2) }, /* format */
229 { d_uint16, offsetof(cmap4, length) },
230 { d_skip(2) }, /* language */
231 { d_uint16, offsetof(cmap4, segCountX2) },
232 { d_skip(6) }, /* searchRange, entrySelector, rangeShift */
233 { d_end }
234 };
235
236 /* Font Header ('head') table */
237 typedef struct t_head_Tag t_head;
238 struct t_head_Tag {
239 unsigned version;
240 unsigned fontRevision;
241 unsigned flags;
242 unsigned unitsPerEm;
243 int xMin, yMin, xMax, yMax;
244 int indexToLocFormat;
245 };
246 sfnt_decode t_head_decode[] = {
247 { d_uint32, offsetof(t_head, version) },
248 { d_uint32, offsetof(t_head, fontRevision) },
249 { d_skip(8) }, /* checkSumAdjustment, magicNumber, flags */
250 { d_uint16, offsetof(t_head, flags) },
251 { d_uint16, offsetof(t_head, unitsPerEm) },
252 { d_skip(16) }, /* created, modified */
253 { d_int16, offsetof(t_head, xMin) },
254 { d_int16, offsetof(t_head, yMin) },
255 { d_int16, offsetof(t_head, xMax) },
256 { d_int16, offsetof(t_head, yMax) },
257 { d_skip(6) }, /* macStyle, lowestRecPPEM, fontDirectionHint */
258 { d_int16, offsetof(t_head, indexToLocFormat) },
259 { d_skip(2) },
260 { d_end }
261 };
262
263 /* Horizontal Header ('hhea') table */
264 typedef struct t_hhea_Tag t_hhea;
265 struct t_hhea_Tag {
266 unsigned version;
267 int ascent;
268 int descent;
269 int lineGap;
270 int metricDataFormat;
271 unsigned numOfLongHorMetrics;
272 };
273 sfnt_decode t_hhea_decode[] = {
274 { d_uint32, offsetof(t_hhea, version) },
275 { d_int16, offsetof(t_hhea, ascent) },
276 { d_int16, offsetof(t_hhea, descent) },
277 { d_int16, offsetof(t_hhea, lineGap) },
278 { d_skip(22) },
279 { d_int16, offsetof(t_hhea, metricDataFormat) },
280 { d_uint16, offsetof(t_hhea, numOfLongHorMetrics) },
281 { d_end }
282 };
283
284 /* Horizontal Metrics ('hmtx') table */
285 sfnt_decode longhormetric_decode[] = {
286 { d_uint16, 0 },
287 { d_skip(2) },
288 { d_end }
289 };
290
291 /* Naming ('name') table */
292 typedef struct t_name_Tag t_name;
293 typedef struct namerecord_Tag namerecord;
294 struct t_name_Tag {
295 unsigned format;
296 unsigned count;
297 unsigned stringOffset;
298 namerecord *nameRecord;
299 };
300 sfnt_decode t_name_decode[] = {
301 { d_uint16, offsetof(t_name, format) },
302 { d_uint16, offsetof(t_name, count) },
303 { d_uint16, offsetof(t_name, stringOffset) },
304 { d_end }
305 };
306 struct namerecord_Tag {
307 unsigned platformID;
308 unsigned encodingID;
309 unsigned languageID;
310 unsigned nameID;
311 unsigned length;
312 unsigned offset;
313 };
314 sfnt_decode namerecord_decode[] = {
315 { d_uint16, offsetof(namerecord, platformID) },
316 { d_uint16, offsetof(namerecord, encodingID) },
317 { d_uint16, offsetof(namerecord, languageID) },
318 { d_uint16, offsetof(namerecord, nameID) },
319 { d_uint16, offsetof(namerecord, length) },
320 { d_uint16, offsetof(namerecord, offset) },
321 { d_end }
322 };
323
324 /* PostScript compatibility ('post') table */
325 typedef struct t_post_Tag t_post;
326 struct t_post_Tag {
327 unsigned format;
328 int italicAngle;
329 int underlinePosition;
330 int underlineThickness;
331 unsigned isFixedPitch;
332 unsigned minMemType42;
333 unsigned maxMemType42;
334 };
335 sfnt_decode t_post_decode[] = {
336 { d_uint32, offsetof(t_post, format) },
337 { d_int32, offsetof(t_post, italicAngle) },
338 { d_int16, offsetof(t_post, underlinePosition) },
339 { d_int16, offsetof(t_post, underlineThickness) },
340 { d_uint32, offsetof(t_post, isFixedPitch) },
341 { d_uint32, offsetof(t_post, minMemType42) },
342 { d_uint32, offsetof(t_post, maxMemType42) },
343 { d_skip(8) }, /* minMemType1, maxMemType1 */
344 { d_end }
345 };
346
347 typedef struct {
348 glyph name;
349 unsigned short index;
350 } glyphmap;
351
352 typedef struct sfnt_Tag sfnt;
353 struct sfnt_Tag {
354 void *data;
355 size_t len;
356 void *end;
357 offsubdir osd;
358 tabledir *td;
359 t_head head;
360 unsigned nglyphs;
361 glyph *glyphsbyindex;
362 unsigned short *glyphsbyname;
363 unsigned minmem, maxmem;
364 };
365
366 static int sfnt_findtable(sfnt *sf, unsigned tag,
367 void **startp, void **endp) {
368 size_t i;
369
370 for (i = 0; i < sf->osd.numTables; i++) {
371 if (sf->td[i].tag == tag) {
372 *startp = (char *)sf->data + sf->td[i].offset;
373 *endp = (char *)*startp + sf->td[i].length;
374 return TRUE;
375 }
376 }
377 return FALSE;
378 }
379
380 static char *sfnt_psname(font_info *fi) {
381 sfnt *sf = fi->fontfile;
382 t_name name;
383 void *ptr, *end;
384 size_t i;
385 char *psname;
386 namerecord *nr;
387
388 if (!sfnt_findtable(sf, TAG_name, &ptr, &end))
389 abort();
390 ptr = decode(t_name_decode, ptr, end, &name);
391 name.nameRecord = snewn(name.count, namerecord);
392 ptr = decoden(namerecord_decode, ptr, sf->end, name.nameRecord,
393 sizeof(*name.nameRecord), name.count);
394 for (i = 0; i < name.count; i++) {
395 nr = name.nameRecord + i;
396 if (nr->nameID == 6) {
397 /* PostScript name, but can we make sense of it? */
398 if (nr->platformID == 1 && nr->encodingID == 0) {
399 /* Mac Roman, which is ASCII for our purposes */
400 psname = snewn(nr->length + 1, char);
401 memcpy(psname, (char *)ptr + nr->offset, nr->length);
402 psname[nr->length] = 0;
403 sfree(name.nameRecord);
404 return psname;
405 }
406 }
407 }
408 return NULL;
409 }
410
411 static unsigned short *cmp_glyphsbyindex;
412 static int glyphsbyname_cmp(void const *a, void const *b) {
413 glyph ga = cmp_glyphsbyindex[*(unsigned short *)a];
414 glyph gb = cmp_glyphsbyindex[*(unsigned short *)b];
415 if (ga < gb) return -1;
416 if (ga > gb) return 1;
417 return 0;
418 }
419 static int glyphsbyname_cmp_search(void const *a, void const *b) {
420 glyph ga = *(glyph *)a;
421 glyph gb = cmp_glyphsbyindex[*(unsigned short *)b];
422 if (ga < gb) return -1;
423 if (ga > gb) return 1;
424 return 0;
425 }
426
427 /*
428 * Extract data from the 'post' table (mostly glyph mappings)
429 *
430 * TODO: cope better with duplicated glyph names (usually .notdef)
431 * TODO: when presented with format 3.0, try to use 'CFF' if present.
432 */
433 static void sfnt_mapglyphs(font_info *fi) {
434 sfnt *sf = fi->fontfile;
435 t_post post;
436 void *ptr, *end;
437 unsigned char *sptr;
438 char tmp[256];
439 glyph *extraglyphs;
440 unsigned nextras, i, g;
441
442 sf->glyphsbyname = sf->glyphsbyindex = NULL;
443 if (!sfnt_findtable(sf, TAG_post, &ptr, &end))
444 abort();
445 ptr = decode(t_post_decode, ptr, end, &post);
446
447 sf->minmem = post.minMemType42;
448 sf->maxmem = post.maxMemType42;
449 fi->italicangle = post.italicAngle / 65536.0;
450 if (ptr == NULL) abort();
451 switch (post.format) {
452 case 0x00010000:
453 sf->nglyphs = 258;
454 sf->glyphsbyindex = (glyph *)tt_std_glyphs;
455 break;
456 case 0x00020000:
457 if ((char *)ptr + 2 > (char *)end) return;
458 decode_uint16(ptr, &sf->nglyphs);
459 ptr = (char *)ptr + 2;
460 if ((char *)ptr + 2*sf->nglyphs > (char *)end) return;
461 nextras = 0;
462 for (sptr = (unsigned char *)ptr + 2*sf->nglyphs;
463 sptr < (unsigned char *)end;
464 sptr += *sptr+1)
465 nextras++;
466 extraglyphs = snewn(nextras, glyph);
467 i = 0;
468 for (sptr = (unsigned char *)ptr + 2*sf->nglyphs;
469 sptr < (unsigned char *)end;
470 sptr += *sptr+1) {
471 memcpy(tmp, sptr + 1, *sptr);
472 tmp[*sptr] = 0;
473 assert(i < nextras);
474 extraglyphs[i++] = glyph_intern(tmp);
475 }
476 sf->glyphsbyindex = snewn(sf->nglyphs, glyph);
477 for (i = 0; i < sf->nglyphs; i++) {
478 decode_uint16((char *)ptr + 2*i, &g);
479 if (g <= 257)
480 sf->glyphsbyindex[i] = tt_std_glyphs[g];
481 else if (g < 258 + nextras)
482 sf->glyphsbyindex[i] = extraglyphs[g - 258];
483 else
484 sf->glyphsbyindex[i] = NOGLYPH;
485 }
486 sfree(extraglyphs);
487 break;
488 default:
489 abort();
490 }
491 /* Construct glyphsbyname */
492 sf->glyphsbyname = snewn(sf->nglyphs, unsigned short);
493 for (i = 0; i < sf->nglyphs; i++)
494 sf->glyphsbyname[i] = i;
495 cmp_glyphsbyindex = sf->glyphsbyindex;
496 qsort(sf->glyphsbyname, sf->nglyphs, sizeof(*sf->glyphsbyname),
497 glyphsbyname_cmp);
498 }
499
500 static glyph sfnt_indextoglyph(sfnt *sf, unsigned short idx) {
501 return sf->glyphsbyindex[idx];
502 }
503
504 static unsigned short sfnt_glyphtoindex(sfnt *sf, glyph g) {
505 cmp_glyphsbyindex = sf->glyphsbyindex;
506 return *(unsigned short *)bsearch(&g, sf->glyphsbyname, sf->nglyphs,
507 sizeof(*sf->glyphsbyname),
508 glyphsbyname_cmp_search);
509 }
510
511 /*
512 * Get data from 'hhea', 'hmtx', and 'OS/2' tables
513 */
514 void sfnt_getmetrics(font_info *fi) {
515 sfnt *sf = fi->fontfile;
516 t_hhea hhea;
517 t_OS_2 OS_2;
518 void *ptr, *end;
519 unsigned i, j;
520 unsigned *hmtx;
521
522 /* First, the bounding box from the 'head' table. */
523 fi->fontbbox[0] = sf->head.xMin * FUNITS_PER_PT / sf->head.unitsPerEm;
524 fi->fontbbox[1] = sf->head.yMin * FUNITS_PER_PT / sf->head.unitsPerEm;
525 fi->fontbbox[2] = sf->head.xMax * FUNITS_PER_PT / sf->head.unitsPerEm;
526 fi->fontbbox[3] = sf->head.yMax * FUNITS_PER_PT / sf->head.unitsPerEm;
527 if (!sfnt_findtable(sf, TAG_hhea, &ptr, &end))
528 abort();
529 if (decode(t_hhea_decode, ptr, end, &hhea) == NULL)
530 abort();
531 if ((hhea.version & 0xffff0000) != 0x00010000)
532 abort();
533 fi->ascent = hhea.ascent;
534 fi->descent = hhea.descent;
535 if (hhea.metricDataFormat != 0)
536 abort();
537 if (!sfnt_findtable(sf, TAG_hmtx, &ptr, &end))
538 abort();
539 hmtx = snewn(hhea.numOfLongHorMetrics, unsigned);
540 if (decoden(longhormetric_decode, ptr, end, hmtx, sizeof(*hmtx),
541 hhea.numOfLongHorMetrics) == NULL)
542 abort();
543 for (i = 0; i < sf->nglyphs; i++) {
544 glyph_width *w = snew(glyph_width);
545 w->glyph = sfnt_indextoglyph(sf, i);
546 j = i < hhea.numOfLongHorMetrics ? i : hhea.numOfLongHorMetrics - 1;
547 w->width = hmtx[j] * UNITS_PER_PT / sf->head.unitsPerEm;
548 add234(fi->widths, w);
549 }
550 /* Now see if the 'OS/2' table has any useful metrics */
551 if (!sfnt_findtable(sf, TAG_OS_2, &ptr, &end))
552 return;
553 if (decode(uint16_decode, ptr, end, &OS_2.version) == NULL)
554 return;
555 if (OS_2.version >= 2) {
556 if (decode(t_OS_2_v2_decode, ptr, end, &OS_2) == NULL)
557 return;
558 fi->xheight = OS_2.sxHeight * FUNITS_PER_PT / sf->head.unitsPerEm;
559 fi->capheight = OS_2.sCapHeight * FUNITS_PER_PT / sf->head.unitsPerEm;
560 } else if (OS_2.version == 1) {
561 if (decode(t_OS_2_v1_decode, ptr, end, &OS_2) == NULL)
562 return;
563 } else
564 return;
565 fi->ascent = OS_2.sTypoAscender * FUNITS_PER_PT / sf->head.unitsPerEm;
566 fi->descent = OS_2.sTypoDescender * FUNITS_PER_PT / sf->head.unitsPerEm;
567 }
568
569 /*
570 * Get mapping data from 'cmap' table
571 *
572 * We look for either a (0, 3), or (3, 1) table, both of these being
573 * versions of UCS-2. We only handle format 4 of this table, since
574 * that seems to be the only one in use.
575 */
576 void sfnt_getmap(font_info *fi) {
577 sfnt *sf = fi->fontfile;
578 t_cmap cmap;
579 encodingrec *esd;
580 void *base, *ptr, *end;
581 unsigned i;
582 unsigned format;
583
584
585 for (i = 0; i < lenof(fi->bmp); i++)
586 fi->bmp[i] = 0xFFFF;
587 if (!sfnt_findtable(sf, TAG_cmap, &ptr, &end))
588 abort();
589 base = ptr;
590 ptr = decode(t_cmap_decode, ptr, end, &cmap);
591 if (ptr == NULL) abort();
592 esd = snewn(cmap.numTables, encodingrec);
593 ptr = decoden(encodingrec_decode, ptr, end, esd, sizeof(*esd),
594 cmap.numTables);
595 if (ptr == NULL) abort();
596 for (i = 0; i < cmap.numTables; i++) {
597 if (!decode(uint16_decode, (char *)base + esd[i].offset, end, &format))
598 abort();
599 if ((esd[i].platformID == 0 && esd[i].encodingID == 3) ||
600 (esd[i].platformID == 3 && esd[i].encodingID == 1)) {
601 /* UCS-2 encoding */
602 if (!decode(uint16_decode, (char *)base + esd[i].offset, end,
603 &format))
604 abort();
605 if (format == 4) {
606 unsigned *data, *endCode, *startCode, *idDelta, *idRangeOffset;
607 unsigned *glyphIndexArray;
608 unsigned segcount, nword, nglyphindex, j;
609 cmap4 cmap4;
610
611 ptr = decode(cmap4_decode, (char *)base + esd[i].offset, end,
612 &cmap4);
613 if (!ptr) abort();
614 segcount = cmap4.segCountX2 / 2;
615 nword = cmap4.length / 2 - 7;
616 data = snewn(nword, unsigned);
617 if (!decoden(uint16_decode, ptr, (char *)ptr + nword * 2,
618 data, sizeof(*data), nword)) abort();
619 endCode = data;
620 startCode = data + segcount + 1;
621 idDelta = startCode + segcount;
622 idRangeOffset = idDelta + segcount;
623 glyphIndexArray = idRangeOffset + segcount;
624 nglyphindex = nword - segcount * 4 - 1;
625
626 for (j = 0; j < segcount; j++) {
627 unsigned k, idx;
628
629 if (idRangeOffset[j] == 0) {
630 for (k = startCode[j]; k <= endCode[j]; k++) {
631 idx = (k + idDelta[j]) & 0xffff;
632 if (idx != 0) {
633 if (idx > sf->nglyphs) abort();
634 fi->bmp[k] = sfnt_indextoglyph(sf, idx);
635 }
636 }
637 } else {
638 unsigned startidx = idRangeOffset[j]/2 - segcount + j;
639 for (k = startCode[j]; k <= endCode[j]; k++) {
640 idx = glyphIndexArray[startidx + k - startCode[j]];
641 if (idx != 0) {
642 idx = (idx + idDelta[j]) & 0xffff;
643 if (idx > sf->nglyphs) abort();
644 fi->bmp[k] = sfnt_indextoglyph(sf, idx);
645 }
646 }
647 }
648 }
649
650 sfree(data);
651 }
652 }
653 }
654 }
655
656 void read_sfnt_file(input *in) {
657 sfnt *sf = snew(sfnt);
658 size_t off = 0, got;
659 FILE *fp = in->currfp;
660 font_info *fi = snew(font_info);
661 /* size_t i; */
662 void *ptr, *end;
663
664 fi->name = NULL;
665 fi->widths = newtree234(width_cmp);
666 fi->kerns = newtree234(kern_cmp);
667 fi->ligs = newtree234(lig_cmp);
668 fi->fontbbox[0] = fi->fontbbox[1] = fi->fontbbox[2] = fi->fontbbox[3] = 0;
669 fi->capheight = fi->xheight = fi->ascent = fi->descent = 0;
670 fi->stemh = fi->stemv = fi->italicangle = 0;
671 fi->fontfile = sf;
672 fi->filetype = TRUETYPE;
673
674 sf->len = 32768;
675 sf->data = snewn(sf->len, unsigned char);
676 for (;;) {
677 got = fread((char *)sf->data + off, 1, sf->len - off, fp);
678 off += got;
679 if (off != sf->len) break;
680 sf->len *= 2;
681 sf->data = sresize(sf->data, sf->len, unsigned char);
682 }
683 sf->len = off;
684 sf->data = sresize(sf->data, sf->len, unsigned char);
685 sf->end = (char *)sf->data + sf->len;
686 decode(offsubdir_decode, sf->data, sf->end, &sf->osd);
687 /*
688 fprintf(stderr, "scaler type = 0x%x; numTables = %u\n",
689 sf->osd.scaler_type, sf->osd.numTables);
690 */
691 sf->td = snewn(sf->osd.numTables, tabledir);
692 decoden(tabledir_decode, (char *)sf->data + 12, sf->end,
693 sf->td, sizeof(*sf->td), sf->osd.numTables);
694 /*
695 for (i = 0; i < sf->osd.numTables; i++)
696 fprintf(stderr, "table tag = '%c%c%c%c'; offset = %#10x; length = %#10x\n",
697 sf->td[i].tag >> 24, sf->td[i].tag >> 16, sf->td[i].tag >> 8, sf->td[i].tag, sf->td[i].offset, sf->td[i].length);
698 */
699 if (!sfnt_findtable(sf, TAG_head, &ptr, &end))
700 abort();
701 if (decode(t_head_decode, ptr, end, &sf->head) == NULL)
702 abort();
703 if ((sf->head.version & 0xffff0000) != 0x00010000)
704 abort();
705 fi->name = sfnt_psname(fi);
706 sfnt_mapglyphs(fi);
707 sfnt_getmetrics(fi);
708 sfnt_getmap(fi);
709 fi->next = all_fonts;
710 all_fonts = fi;
711 fclose(in->currfp);
712 }
713
714 static int sizecmp(const void *a, const void *b) {
715 if (*(size_t *)a < *(size_t *)b) return -1;
716 if (*(size_t *)a > *(size_t *)b) return 1;
717 return 0;
718 }
719
720 /*
721 * The format for embedding TrueType fonts in Postscript is defined in
722 * Adobe Technical Note #5012: The Type 42 Font Format Specification.
723 * <http://partners.adobe.com/public/developer/en/font/5012.Type42_Spec.pdf>
724 */
725
726 void sfnt_writeps(font_info const *fi, FILE *ofp) {
727 unsigned i, j, lastbreak;
728 sfnt *sf = fi->fontfile;
729 size_t *breaks, glyfoff, glyflen;
730 void *glyfptr, *glyfend, *locaptr, *locaend;
731 unsigned *loca;
732 int cc = 0;
733
734 /* XXX Unclear that this is the correct format. */
735 fprintf(ofp, "%%!PS-TrueTypeFont-%u-%u\n", sf->osd.scaler_type,
736 sf->head.fontRevision);
737 if (sf->minmem)
738 fprintf(ofp, "%%%%VMUsage: %u %u\n", sf->minmem, sf->maxmem);
739 fprintf(ofp, "9 dict dup begin\n");
740 fprintf(ofp, "/FontType 42 def\n");
741 fprintf(ofp, "/FontMatrix [1 0 0 1 0 0] def\n");
742 fprintf(ofp, "/FontName /%s def\n", fi->name);
743 fprintf(ofp, "/Encoding StandardEncoding def\n");
744 if ((sf->head.flags & 0x0003) == 0x0003) {
745 /*
746 * Sensible font with the origin in the right place, such that
747 * the bounding box is meaningful.
748 */
749 fprintf(ofp, "/FontBBox [%g %g %g %g] readonly def\n",
750 (double)sf->head.xMin / sf->head.unitsPerEm,
751 (double)sf->head.yMin / sf->head.unitsPerEm,
752 (double)sf->head.xMax / sf->head.unitsPerEm,
753 (double)sf->head.yMax / sf->head.unitsPerEm);
754 } else {
755 /* Non-sensible font. */
756 fprintf(ofp, "/FontBBox [0 0 0 0] readonly def\n");
757 }
758 fprintf(ofp, "/PaintType 0 def\n");
759 fprintf(ofp, "/CharStrings %u dict dup begin\n", sf->nglyphs);
760 fprintf(ofp, "0 1 %u{currentfile token pop exch def}bind for\n",
761 sf->nglyphs - 1);
762 for (i = 0; i < sf->nglyphs; i++)
763 ps_token(ofp, &cc, "/%s", glyph_extern(sfnt_indextoglyph(sf, i)));
764 fprintf(ofp, "\nend readonly def\n");
765 fprintf(ofp, "/sfnts [<");
766 breaks = snewn(sf->osd.numTables + sf->nglyphs, size_t);
767 for (i = 0; i < sf->osd.numTables; i++) {
768 breaks[i] = sf->td[i].offset;
769 }
770 if (!sfnt_findtable(sf, TAG_glyf, &glyfptr, &glyfend))
771 abort();
772 glyfoff = (char *)glyfptr - (char *)sf->data;
773 glyflen = (char *)glyfend - (char *)glyfptr;
774 if (!sfnt_findtable(sf, TAG_loca, &locaptr, &locaend))
775 abort();
776 loca = snewn(sf->nglyphs, unsigned);
777 if (sf->head.indexToLocFormat == 0) {
778 if (!decoden(uint16_decode, locaptr, locaend, loca, sizeof(*loca),
779 sf->nglyphs)) abort();
780 for (i = 0; i < sf->nglyphs; i++) loca[i] *= 2;
781 } else {
782 if (!decoden(uint32_decode, locaptr, locaend, loca, sizeof(*loca),
783 sf->nglyphs)) abort();
784 }
785 for (i = 1; i < sf->nglyphs; i++) {
786 if (loca[i] > glyflen) abort();
787 breaks[sf->osd.numTables + i - 1] = loca[i] + glyfoff;
788 }
789 breaks[sf->osd.numTables + sf->nglyphs - 1] = sf->len;
790 qsort(breaks, sf->osd.numTables + sf->nglyphs, sizeof(*breaks), sizecmp);
791 j = lastbreak = 0;
792 for (i = 0; i < sf->len; i++) {
793 if ((i - lastbreak) % 38 == 0) fprintf(ofp, "\n");
794 if (i == breaks[j]) {
795 while (i == breaks[j]) j++;
796 lastbreak = i;
797 fprintf(ofp, "00><\n");
798 }
799 fprintf(ofp, "%02x", *((unsigned char *)sf->data + i));
800 }
801 fprintf(ofp, "00>] readonly def\n");
802 sfree(breaks);
803 fprintf(ofp, "end /%s exch definefont\n", fi->name);
804 }
805
806 void sfnt_cmap(font_encoding *fe, object *cmap) {
807 unsigned i;
808
809 objtext(cmap, "<</Type/CMap\n/CMapName/");
810 objtext(cmap, fe->name);
811 objtext(cmap, "\n/CIDSystemInfo<</Registry(Adobe)/Ordering(Identity)"
812 "/Supplement 0>>\n");
813 objstream(cmap, "%!PS-Adobe-3.0 Resource-CMap\n"
814 "%%DocumentNeededResources: procset CIDInit\n"
815 "%%IncludeResource: procset CIDInit\n"
816 "%%BeginResource: CMap ");
817 objstream(cmap, fe->name);
818 objstream(cmap, "\n%%Title (");
819 objstream(cmap, fe->name);
820 objstream(cmap, " Adobe Identity 0)\n%%Version: 1\n%%EndComments\n");
821 objstream(cmap, "/CIDInit/ProcSet findresource begin\n");
822 objstream(cmap, "12 dict begin begincmap\n");
823 objstream(cmap, "/CIDSystemInfo 3 dict dup begin\n"
824 "/Registry(Adobe)def/Ordering(Identity)def/Supplement 0 def "
825 "end def\n");
826 objstream(cmap, "/CMapName/");
827 objstream(cmap, fe->name);
828 objstream(cmap, " def/CMapType 0 def/WMode 0 def\n");
829 objstream(cmap, "1 begincodespacerange<00><FF>endcodespacerange\n");
830 for (i = 0; i < 256; i++) {
831 char buf[20];
832 if (fe->vector[i] == NOGLYPH)
833 continue;
834 objstream(cmap, "1 begincidchar");
835 sprintf(buf, "<%02X>", i);
836 objstream(cmap, buf);
837 sprintf(buf, "%hu", sfnt_glyphtoindex(fe->font->info->fontfile,
838 fe->vector[i]));
839 objstream(cmap, buf);
840 objstream(cmap, " endcidchar\n");
841 }
842 objstream(cmap, "endcmap CMapName currentdict /CMap defineresource pop "
843 "end end\n%%EndResource\n%%EOF\n");
844 }
845
846 void sfnt_data(font_info *fi, char **bufp, size_t *lenp) {
847 sfnt *sf = fi->fontfile;
848 *bufp = sf->data;
849 *lenp = sf->len;
850 }