2 * Support for sfnt-housed fonts for Halibut
4 * sfnt-housed fonts include TrueType, OpenType, sfnt-housed Type 1
5 * fonts and a couple of bitmap formats.
7 * The various tables that can appear in sfnt-housed fonts are defined
8 * in several places. These include:
10 * The OpenType Specification:
11 * <http://partners.adobe.com/public/developer/opentype/index_spec.html>
13 * The TrueType Reference Manual:
14 * <http://developer.apple.com/textfonts/TTRefMan/>
16 * Microsoft typography specifications:
17 * <http://www.microsoft.com/typography/SpecificationsOverview.mspx>
27 typedef struct sfnt_decode_Tag sfnt_decode
;
28 struct sfnt_decode_Tag
{
29 void (*decoder
)(void *src
, void *dest
);
35 static void decode_uint8(void *src
, void *dest
) {
36 *(unsigned int *)dest
= *(unsigned char *)src
;
38 #define d_uint8 decode_uint8, 1
42 static void decode_int8(void *src
, void *dest
) {
43 *(int *)dest
= *(signed char *)src
;
45 #define d_int8 decode_int8, 1
48 static void decode_uint16(void *src
, void *dest
) {
49 unsigned char *cp
= src
;
50 *(unsigned int *)dest
= (cp
[0] << 8) + cp
[1];
52 #define d_uint16 decode_uint16, 2
54 static 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];
59 #define d_int16 decode_int16, 2
61 static 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];
66 #define d_uint32 decode_uint32, 4
68 static 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];
73 #define d_int32 decode_int32, 4
75 static void decode_skip(void *src
, void *dest
) {
80 #define d_skip(n) decode_skip, (n), 0
82 static void decode_end(void *src
, void *dest
) {
87 #define d_end decode_end, 0, 0
89 static 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
;
99 static void *decoden(sfnt_decode
*dec
, void *src
, void *end
, void *dest
,
100 size_t size
, size_t n
) {
102 src
= decode(dec
, src
, end
, dest
);
103 dest
= (char *)dest
+ size
;
108 /* Decoding specs for simple data types */
109 sfnt_decode uint16_decode
[] = { { d_uint16
, 0 }, { d_end
} };
110 sfnt_decode int16_decode
[] = { { d_int16
, 0 }, { d_end
} };
111 sfnt_decode uint32_decode
[] = { { d_uint32
, 0 }, { d_end
} };
113 /* Offset subdirectory -- the start of the file */
114 typedef struct offsubdir_Tag offsubdir
;
115 struct offsubdir_Tag
{
116 unsigned scaler_type
;
119 sfnt_decode offsubdir_decode
[] = {
120 { d_uint32
, offsetof(offsubdir
, scaler_type
) },
121 { d_uint16
, offsetof(offsubdir
, numTables
) },
126 #define sfnt_00010000 0x00010000
127 #define TAG_OS_2 0x4f532f32
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
133 #define TAG_kern 0x6b65726e
134 #define TAG_loca 0x6c6f6361
135 #define TAG_maxp 0x6d617870
136 #define TAG_name 0x6e616d65
137 #define TAG_post 0x706f7374
138 #define sfnt_true 0x74727565
140 /* Table directory */
141 typedef struct tabledir_Tag tabledir
;
142 struct tabledir_Tag
{
148 sfnt_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
) },
156 /* OS/2 and Windows compatibility table */
157 typedef struct t_OS_2_Tag t_OS_2
;
160 int sTypoAscender
, sTypoDescender
;
161 int sxHeight
, sCapHeight
;
163 sfnt_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 */
173 sfnt_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 */
187 sfnt_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 */
205 /* Character to Glyph ('cmap') table */
206 typedef struct t_cmap_Tag t_cmap
;
210 sfnt_decode t_cmap_decode
[] = {
212 { d_uint16
, offsetof(t_cmap
, numTables
) },
215 typedef struct encodingrec_Tag encodingrec
;
216 struct encodingrec_Tag
{
221 sfnt_decode encodingrec_decode
[] = {
222 { d_uint16
, offsetof(encodingrec
, platformID
) },
223 { d_uint16
, offsetof(encodingrec
, encodingID
) },
224 { d_uint32
, offsetof(encodingrec
, offset
) },
227 typedef struct cmap4_Tag cmap4
;
232 sfnt_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 */
241 /* Font Header ('head') table */
242 typedef struct t_head_Tag t_head
;
245 unsigned fontRevision
;
248 int xMin
, yMin
, xMax
, yMax
;
249 int indexToLocFormat
;
251 sfnt_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
) },
268 /* Horizontal Header ('hhea') table */
269 typedef struct t_hhea_Tag t_hhea
;
275 int metricDataFormat
;
276 unsigned numOfLongHorMetrics
;
278 sfnt_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
) },
284 { d_int16
, offsetof(t_hhea
, metricDataFormat
) },
285 { d_uint16
, offsetof(t_hhea
, numOfLongHorMetrics
) },
289 /* Horizontal Metrics ('hmtx') table */
290 sfnt_decode longhormetric_decode
[] = {
296 /* Kerning ('kern') table */
297 typedef struct t_kern_Tag t_kern
;
302 sfnt_decode t_kern_v0_decode
[] = {
303 { d_uint16
, offsetof(t_kern
, version
) },
304 { d_uint16
, offsetof(t_kern
, nTables
) },
307 typedef struct kern_v0_subhdr_Tag kern_v0_subhdr
;
308 struct kern_v0_subhdr_Tag
{
313 sfnt_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
) },
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
325 sfnt_decode t_kern_v1_decode
[] = {
326 { d_uint32
, offsetof(t_kern
, version
) },
327 { d_uint32
, offsetof(t_kern
, nTables
) },
330 typedef struct kern_v1_subhdr_Tag kern_v1_subhdr
;
331 struct kern_v1_subhdr_Tag
{
335 sfnt_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 */
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
346 typedef struct kern_f0_Tag kern_f0
;
350 sfnt_decode kern_f0_decode
[] = {
351 { d_uint16
, offsetof(kern_f0
, nPairs
) },
352 { d_skip(6) }, /* searchRange, entrySelector, rangeShift */
355 typedef struct kern_f0_pair_Tag kern_f0_pair
;
356 struct kern_f0_pair_Tag
{
361 sfnt_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
) },
368 /* Maximum profile ('maxp') table */
369 typedef struct t_maxp_Tag t_maxp
;
374 sfnt_decode t_maxp_decode
[] = {
375 { d_uint32
, offsetof(t_maxp
, version
) },
376 { d_uint16
, offsetof(t_maxp
, numGlyphs
) },
380 /* Naming ('name') table */
381 typedef struct t_name_Tag t_name
;
382 typedef struct namerecord_Tag namerecord
;
386 unsigned stringOffset
;
387 namerecord
*nameRecord
;
389 sfnt_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
) },
395 struct namerecord_Tag
{
403 sfnt_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
) },
413 /* PostScript compatibility ('post') table */
414 typedef struct t_post_Tag t_post
;
418 int underlinePosition
;
419 int underlineThickness
;
420 unsigned isFixedPitch
;
421 unsigned minMemType42
;
422 unsigned maxMemType42
;
424 sfnt_decode t_post_decode
[] = {
425 { d_uint32
, offsetof(t_post
, format
) },
426 { d_int32
, offsetof(t_post
, italicAngle
) },
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 */
438 unsigned short index
;
450 glyph
*glyphsbyindex
;
451 unsigned short *glyphsbyname
;
452 unsigned minmem
, maxmem
;
455 static int sfnt_findtable(sfnt
*sf
, unsigned tag
,
456 void **startp
, void **endp
) {
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
;
469 static char *sfnt_psname(font_info
*fi
) {
470 sfnt
*sf
= fi
->fontfile
;
477 if (!sfnt_findtable(sf
, TAG_name
, &ptr
, &end
)) {
478 error(err_sfntnotable
, &sf
->pos
, "name");
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
);
499 error(err_sfntnopsname
, &sf
->pos
);
503 static unsigned short *cmp_glyphsbyindex
;
504 static 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 /* For de-duping, we'd prefer to have the first glyph stay first */
510 if (*(unsigned short *)a
< *(unsigned short *)b
) return -1;
511 if (*(unsigned short *)a
> *(unsigned short *)b
) return 1;
514 static int glyphsbyname_cmp_search(void const *a
, void const *b
) {
515 glyph ga
= *(glyph
*)a
;
516 glyph gb
= cmp_glyphsbyindex
[*(unsigned short *)b
];
517 if (ga
< gb
) return -1;
518 if (ga
> gb
) return 1;
522 /* Generate an name for a glyph that doesn't have one. */
523 static glyph
genglyph(unsigned idx
) {
525 if (idx
== 0) return glyph_intern(".notdef");
526 sprintf(buf
, "glyph%u", idx
);
527 return glyph_intern(buf
);
531 * Extract data from the 'post' table (mostly glyph mappings)
533 * TODO: cope better with duplicated glyph names (usually .notdef)
534 * TODO: when presented with format 3.0, try to use 'CFF' if present.
536 static void sfnt_mapglyphs(font_info
*fi
) {
537 sfnt
*sf
= fi
->fontfile
;
542 glyph
*extraglyphs
, prev
, this;
543 unsigned nextras
, i
, g
, suflen
;
545 sf
->glyphsbyname
= sf
->glyphsbyindex
= NULL
;
546 if (sfnt_findtable(sf
, TAG_post
, &ptr
, &end
)) {
547 ptr
= decode(t_post_decode
, ptr
, end
, &post
);
549 error(err_sfntbadtable
, &sf
->pos
, "post");
553 sf
->minmem
= post
.minMemType42
;
554 sf
->maxmem
= post
.maxMemType42
;
555 fi
->italicangle
= post
.italicAngle
/ 65536.0;
556 switch (post
.format
) {
558 if (sf
->nglyphs
!= 258) {
559 error(err_sfntbadtable
, &sf
->pos
, "post");
562 sf
->glyphsbyindex
= (glyph
*)tt_std_glyphs
;
565 if ((char *)ptr
+ 2 > (char *)end
) {
566 error(err_sfntbadtable
, &sf
->pos
, "post");
569 ptr
= (char *)ptr
+ 2;
570 if ((char *)ptr
+ 2*sf
->nglyphs
> (char *)end
) {
571 error(err_sfntbadtable
, &sf
->pos
, "post");
575 for (sptr
= (unsigned char *)ptr
+ 2*sf
->nglyphs
;
576 sptr
< (unsigned char *)end
;
579 extraglyphs
= snewn(nextras
, glyph
);
581 for (sptr
= (unsigned char *)ptr
+ 2*sf
->nglyphs
;
582 sptr
< (unsigned char *)end
;
584 memcpy(tmp
, sptr
+ 1, *sptr
);
587 extraglyphs
[i
++] = glyph_intern(tmp
);
589 sf
->glyphsbyindex
= snewn(sf
->nglyphs
, glyph
);
590 for (i
= 0; i
< sf
->nglyphs
; i
++) {
591 decode_uint16((char *)ptr
+ 2*i
, &g
);
593 sf
->glyphsbyindex
[i
] = tt_std_glyphs
[g
];
594 else if (g
< 258 + nextras
)
595 sf
->glyphsbyindex
[i
] = extraglyphs
[g
- 258];
597 error(err_sfntbadtable
, &sf
->pos
, "post");
598 sf
->glyphsbyindex
[i
] = genglyph(i
);
606 error(err_sfnttablevers
, &sf
->pos
, "post");
611 if (!sf
->glyphsbyindex
) {
612 sf
->glyphsbyindex
= snewn(sf
->nglyphs
, glyph
);
613 for (i
= 0; i
< sf
->nglyphs
; i
++)
614 sf
->glyphsbyindex
[i
] = genglyph(i
);
616 /* Construct glyphsbyname */
617 sf
->glyphsbyname
= snewn(sf
->nglyphs
, unsigned short);
618 for (i
= 0; i
< sf
->nglyphs
; i
++)
619 sf
->glyphsbyname
[i
] = i
;
620 cmp_glyphsbyindex
= sf
->glyphsbyindex
;
621 qsort(sf
->glyphsbyname
, sf
->nglyphs
, sizeof(*sf
->glyphsbyname
),
624 * It's possible for fonts to specify the same name for multiple
625 * glyphs, which would make one of them inaccessible. Check for
626 * that, and rename all but one of each set.
628 * To ensure that we don't clash with any existing glyph names,
629 * our renaming involves appending the glyph number formatted with
630 * enough leading zeroes to make it longer than any all-digit
631 * suffix that already exists in the font.
634 for (i
= 0; i
< sf
->nglyphs
; i
++) {
636 p
= strrchr(glyph_extern(sfnt_indextoglyph(sf
, i
)), '.');
637 if (p
&& !(p
+1)[strspn(p
+1, "0123456789")] && strlen(p
+1) > suflen
)
638 suflen
= strlen(p
+1);
641 prev
= sfnt_indextoglyph(sf
, sf
->glyphsbyname
[0]);
642 for (i
= 1; i
< sf
->nglyphs
; i
++) {
643 if (prev
== (this = sfnt_indextoglyph(sf
, sf
->glyphsbyname
[i
]))) {
644 char const *basename
;
646 basename
= glyph_extern(this);
647 buf
= snewn(strlen(basename
) + 2 + suflen
, char);
648 strcpy(buf
, basename
);
649 sprintf(buf
+ strlen(basename
), ".%0*hu", suflen
,
650 sf
->glyphsbyname
[i
]);
651 sf
->glyphsbyindex
[sf
->glyphsbyname
[i
]] = glyph_intern(buf
);
656 /* We may have renamed some glyphs, so re-sort the array. */
657 qsort(sf
->glyphsbyname
, sf
->nglyphs
, sizeof(*sf
->glyphsbyname
),
661 glyph
sfnt_indextoglyph(sfnt
*sf
, unsigned idx
) {
662 return sf
->glyphsbyindex
[idx
];
665 unsigned sfnt_nglyphs(sfnt
*sf
) {
669 unsigned sfnt_glyphtoindex(sfnt
*sf
, glyph g
) {
670 cmp_glyphsbyindex
= sf
->glyphsbyindex
;
671 return *(unsigned short *)bsearch(&g
, sf
->glyphsbyname
, sf
->nglyphs
,
672 sizeof(*sf
->glyphsbyname
),
673 glyphsbyname_cmp_search
);
677 * Get data from 'hhea', 'hmtx', and 'OS/2' tables
679 void sfnt_getmetrics(font_info
*fi
) {
680 sfnt
*sf
= fi
->fontfile
;
687 /* First, the bounding box from the 'head' table. */
688 fi
->fontbbox
[0] = sf
->head
.xMin
* FUNITS_PER_PT
/ sf
->head
.unitsPerEm
;
689 fi
->fontbbox
[1] = sf
->head
.yMin
* FUNITS_PER_PT
/ sf
->head
.unitsPerEm
;
690 fi
->fontbbox
[2] = sf
->head
.xMax
* FUNITS_PER_PT
/ sf
->head
.unitsPerEm
;
691 fi
->fontbbox
[3] = sf
->head
.yMax
* FUNITS_PER_PT
/ sf
->head
.unitsPerEm
;
692 if (!sfnt_findtable(sf
, TAG_hhea
, &ptr
, &end
)) {
693 error(err_sfntnotable
, &sf
->pos
, "hhea");
696 if (decode(t_hhea_decode
, ptr
, end
, &hhea
) == NULL
) {
697 error(err_sfntbadtable
, &sf
->pos
, "hhea");
700 if ((hhea
.version
& 0xffff0000) != 0x00010000) {
701 error(err_sfnttablevers
, &sf
->pos
, "hhea");
704 fi
->ascent
= hhea
.ascent
;
705 fi
->descent
= hhea
.descent
;
706 if (hhea
.metricDataFormat
!= 0) {
707 error(err_sfnttablevers
, &sf
->pos
, "hmtx");
710 if (!sfnt_findtable(sf
, TAG_hmtx
, &ptr
, &end
)) {
711 error(err_sfntnotable
, &sf
->pos
, "hmtx");
714 hmtx
= snewn(hhea
.numOfLongHorMetrics
, unsigned);
715 if (decoden(longhormetric_decode
, ptr
, end
, hmtx
, sizeof(*hmtx
),
716 hhea
.numOfLongHorMetrics
) == NULL
) {
717 error(err_sfntbadtable
, &sf
->pos
, "hmtx");
720 for (i
= 0; i
< sf
->nglyphs
; i
++) {
721 glyph_width
*w
= snew(glyph_width
);
722 w
->glyph
= sfnt_indextoglyph(sf
, i
);
723 j
= i
< hhea
.numOfLongHorMetrics ? i
: hhea
.numOfLongHorMetrics
- 1;
724 w
->width
= hmtx
[j
] * UNITS_PER_PT
/ sf
->head
.unitsPerEm
;
725 add234(fi
->widths
, w
);
727 /* Now see if the 'OS/2' table has any useful metrics */
728 if (!sfnt_findtable(sf
, TAG_OS_2
, &ptr
, &end
))
730 if (decode(uint16_decode
, ptr
, end
, &OS_2
.version
) == NULL
)
732 if (OS_2
.version
>= 2) {
733 if (decode(t_OS_2_v2_decode
, ptr
, end
, &OS_2
) == NULL
)
735 fi
->xheight
= OS_2
.sxHeight
* FUNITS_PER_PT
/ sf
->head
.unitsPerEm
;
736 fi
->capheight
= OS_2
.sCapHeight
* FUNITS_PER_PT
/ sf
->head
.unitsPerEm
;
737 } else if (OS_2
.version
== 1) {
738 if (decode(t_OS_2_v1_decode
, ptr
, end
, &OS_2
) == NULL
)
742 fi
->ascent
= OS_2
.sTypoAscender
* FUNITS_PER_PT
/ sf
->head
.unitsPerEm
;
743 fi
->descent
= OS_2
.sTypoDescender
* FUNITS_PER_PT
/ sf
->head
.unitsPerEm
;
746 error(err_sfntbadtable
, &sf
->pos
, "OS/2");
750 * Get kerning data from a 'kern' table
752 * 'kern' tables have two gratuitously different header formats, one
753 * used by Apple and one by Microsoft. Happily, the kerning tables
754 * themselves use the same formats. Halibut only supports simple kern
755 * pairs for horizontal kerning of horizontal text, and ignores
758 static void sfnt_getkern(font_info
*fi
) {
759 sfnt
*sf
= fi
->fontfile
;
761 unsigned version
, i
, j
;
764 if (!sfnt_findtable(sf
, TAG_kern
, &ptr
, &end
))
766 if (!decode(uint16_decode
, ptr
, end
, &version
))
769 ptr
= decode(t_kern_v0_decode
, ptr
, end
, &kern
);
770 else if (version
== 1)
771 ptr
= decode(t_kern_v1_decode
, ptr
, end
, &kern
);
773 if (ptr
== NULL
) goto bad
;
774 for (i
= 0; i
< kern
.nTables
; i
++) {
779 ptr
= decode(kern_v0_subhdr_decode
, ptr
, end
, &sub
);
780 if (ptr
== NULL
) goto bad
;
781 if (sub
.version
!= 0 ||
782 (sub
.coverage
& (KERN_V0_HORIZ
| KERN_V0_MINIMUM
|
783 KERN_V0_CROSSSTREAM
| KERN_V0_FORMAT
)) !=
784 (KERN_V0_HORIZ
| KERN_V0_FORMAT_0
)) {
785 ptr
= (char *)ptr
+ sub
.length
- 6;
790 ptr
= decode(kern_v1_subhdr_decode
, ptr
, end
, &sub
);
791 if (ptr
== NULL
) goto bad
;
792 if ((sub
.coverage
& (KERN_V1_VERTICAL
| KERN_V1_CROSSSTREAM
|
793 KERN_V1_VARIATION
| KERN_V1_FORMAT
)) !=
795 ptr
= (char *)ptr
+ sub
.length
- 8;
799 ptr
= decode(kern_f0_decode
, ptr
, end
, &f0
);
800 if (ptr
== NULL
) goto bad
;
801 kerns
= snewn(f0
.nPairs
, kern_pair
);
802 for (j
= 0; j
< f0
.nPairs
; j
++) {
804 kern_pair
*kp
= kerns
+ j
;
805 ptr
= decode(kern_f0_pair_decode
, ptr
, end
, &p
);
806 if (ptr
== NULL
) goto bad
;
807 if (p
.left
>= sf
->nglyphs
|| p
.right
>= sf
->nglyphs
) goto bad
;
808 kp
->left
= sfnt_indextoglyph(sf
, p
.left
);
809 kp
->right
= sfnt_indextoglyph(sf
, p
.right
);
810 kp
->kern
= p
.value
* UNITS_PER_PT
/ (int)sf
->head
.unitsPerEm
;
811 add234(fi
->kerns
, kp
);
816 error(err_sfntbadtable
, &sf
->pos
, "kern");
821 * Get mapping data from 'cmap' table
823 * We look for either a (0, 0), (0, 2), (0, 3), or (3, 1) table, all
824 * of these being versions of UCS-2. We ignore (0, 1), since it's
825 * Unicode 1.1 with precomposed Hangul syllables. We only handle
826 * format 4 of this table, since that seems to be the only one in use.
828 void sfnt_getmap(font_info
*fi
) {
829 sfnt
*sf
= fi
->fontfile
;
832 void *base
, *ptr
, *end
;
837 for (i
= 0; i
< lenof(fi
->bmp
); i
++)
839 if (!sfnt_findtable(sf
, TAG_cmap
, &ptr
, &end
)) {
840 error(err_sfntnotable
, &sf
->pos
, "cmap");
843 ptr
= decode(t_cmap_decode
, ptr
, end
, &cmap
);
844 if (ptr
== NULL
) goto bad
;
845 esd
= snewn(cmap
.numTables
, encodingrec
);
846 ptr
= decoden(encodingrec_decode
, ptr
, end
, esd
, sizeof(*esd
),
848 if (ptr
== NULL
) goto bad
;
849 for (i
= 0; i
< cmap
.numTables
; i
++) {
850 if (!decode(uint16_decode
, (char *)base
+ esd
[i
].offset
, end
, &format
))
852 if ((esd
[i
].platformID
== 0 && esd
[i
].encodingID
== 0) ||
853 (esd
[i
].platformID
== 0 && esd
[i
].encodingID
== 2) ||
854 (esd
[i
].platformID
== 0 && esd
[i
].encodingID
== 3) ||
855 (esd
[i
].platformID
== 3 && esd
[i
].encodingID
== 1)) {
857 if (!decode(uint16_decode
, (char *)base
+ esd
[i
].offset
, end
,
861 unsigned *data
, *endCode
, *startCode
, *idDelta
, *idRangeOffset
;
862 unsigned *glyphIndexArray
;
863 unsigned segcount
, nword
, nglyphindex
, j
;
866 ptr
= decode(cmap4_decode
, (char *)base
+ esd
[i
].offset
, end
,
869 segcount
= cmap4
.segCountX2
/ 2;
870 nword
= cmap4
.length
/ 2 - 7;
871 data
= snewn(nword
, unsigned);
872 if (!decoden(uint16_decode
, ptr
, (char *)ptr
+ nword
* 2,
873 data
, sizeof(*data
), nword
)) goto bad
;
875 startCode
= data
+ segcount
+ 1;
876 idDelta
= startCode
+ segcount
;
877 idRangeOffset
= idDelta
+ segcount
;
878 glyphIndexArray
= idRangeOffset
+ segcount
;
879 nglyphindex
= nword
- segcount
* 4 - 1;
881 for (j
= 0; j
< segcount
; j
++) {
884 if (idRangeOffset
[j
] == 0) {
885 for (k
= startCode
[j
]; k
<= endCode
[j
]; k
++) {
886 idx
= (k
+ idDelta
[j
]) & 0xffff;
888 if (idx
> sf
->nglyphs
) {
889 error(err_sfntbadglyph
, &sf
->pos
, k
);
892 fi
->bmp
[k
] = sfnt_indextoglyph(sf
, idx
);
896 unsigned startidx
= idRangeOffset
[j
]/2 - segcount
+ j
;
897 for (k
= startCode
[j
]; k
<= endCode
[j
]; k
++) {
898 if (startidx
+ k
- startCode
[j
] >=
900 error(err_sfntbadglyph
, &sf
->pos
, k
);
903 idx
= glyphIndexArray
[startidx
+ k
- startCode
[j
]];
905 idx
= (idx
+ idDelta
[j
]) & 0xffff;
906 if (idx
> sf
->nglyphs
) {
907 error(err_sfntbadglyph
, &sf
->pos
, k
);
910 fi
->bmp
[k
] = sfnt_indextoglyph(sf
, idx
);
920 error(err_sfntnounicmap
, &sf
->pos
);
923 error(err_sfntbadtable
, &sf
->pos
, "cmap");
926 void read_sfnt_file(input
*in
) {
927 sfnt
*sf
= snew(sfnt
);
929 FILE *fp
= in
->currfp
;
930 font_info
*fi
= snew(font_info
);
935 fi
->widths
= newtree234(width_cmp
);
936 fi
->kerns
= newtree234(kern_cmp
);
937 fi
->ligs
= newtree234(lig_cmp
);
938 fi
->fontbbox
[0] = fi
->fontbbox
[1] = fi
->fontbbox
[2] = fi
->fontbbox
[3] = 0;
939 fi
->capheight
= fi
->xheight
= fi
->ascent
= fi
->descent
= 0;
940 fi
->stemh
= fi
->stemv
= fi
->italicangle
= 0;
942 fi
->filetype
= TRUETYPE
;
945 sf
->data
= snewn(sf
->len
, unsigned char);
947 got
= fread((char *)sf
->data
+ off
, 1, sf
->len
- off
, fp
);
949 if (off
!= sf
->len
) break;
951 sf
->data
= sresize(sf
->data
, sf
->len
, unsigned char);
955 sf
->data
= sresize(sf
->data
, sf
->len
, unsigned char);
956 sf
->end
= (char *)sf
->data
+ sf
->len
;
960 ptr
= decode(offsubdir_decode
, sf
->data
, sf
->end
, &sf
->osd
);
962 error(err_sfntbadhdr
, &sf
->pos
);
965 sf
->td
= snewn(sf
->osd
.numTables
, tabledir
);
966 ptr
= decoden(tabledir_decode
, ptr
, sf
->end
, sf
->td
, sizeof(*sf
->td
),
969 error(err_sfntbadhdr
, &sf
->pos
);
972 if (!sfnt_findtable(sf
, TAG_head
, &ptr
, &end
)) {
973 error(err_sfntnotable
, &sf
->pos
, "head");
976 if (decode(t_head_decode
, ptr
, end
, &sf
->head
) == NULL
) {
977 error(err_sfntbadtable
, &sf
->pos
, "head");
980 if ((sf
->head
.version
& 0xffff0000) != 0x00010000) {
981 error(err_sfnttablevers
, &sf
->pos
, "head");
984 if (!sfnt_findtable(sf
, TAG_maxp
, &ptr
, &end
)) {
985 error(err_sfntnotable
, &sf
->pos
, "maxp");
988 if (decode(t_maxp_decode
, ptr
, end
, &maxp
) == NULL
) {
989 error(err_sfntbadtable
, &sf
->pos
, "maxp");
992 if (maxp
.version
< 0x00005000 || maxp
.version
> 0x0001ffff) {
993 error(err_sfnttablevers
, &sf
->pos
, "maxp");
996 sf
->nglyphs
= maxp
.numGlyphs
;
997 fi
->name
= sfnt_psname(fi
);
998 if (fi
->name
== NULL
) return;
1000 sfnt_getmetrics(fi
);
1003 fi
->next
= all_fonts
;
1007 static int sizecmp(const void *a
, const void *b
) {
1008 if (*(size_t *)a
< *(size_t *)b
) return -1;
1009 if (*(size_t *)a
> *(size_t *)b
) return 1;
1014 * The format for embedding TrueType fonts in Postscript is defined in
1015 * Adobe Technical Note #5012: The Type 42 Font Format Specification.
1016 * <http://partners.adobe.com/public/developer/en/font/5012.Type42_Spec.pdf>
1019 void sfnt_writeps(font_info
const *fi
, FILE *ofp
) {
1020 unsigned i
, j
, lastbreak
;
1021 sfnt
*sf
= fi
->fontfile
;
1022 size_t *breaks
, glyfoff
, glyflen
;
1023 void *glyfptr
, *glyfend
, *locaptr
, *locaend
;
1027 /* XXX Unclear that this is the correct format. */
1028 fprintf(ofp
, "%%!PS-TrueTypeFont-%u-%u\n", sf
->osd
.scaler_type
,
1029 sf
->head
.fontRevision
);
1031 fprintf(ofp
, "%%%%VMUsage: %u %u\n", sf
->minmem
, sf
->maxmem
);
1032 fprintf(ofp
, "9 dict dup begin\n");
1033 fprintf(ofp
, "/FontType 42 def\n");
1034 fprintf(ofp
, "/FontMatrix [1 0 0 1 0 0] def\n");
1035 fprintf(ofp
, "/FontName /%s def\n", fi
->name
);
1036 fprintf(ofp
, "/Encoding StandardEncoding def\n");
1037 if ((sf
->head
.flags
& 0x0003) == 0x0003) {
1039 * Sensible font with the origin in the right place, such that
1040 * the bounding box is meaningful.
1042 fprintf(ofp
, "/FontBBox [%g %g %g %g] readonly def\n",
1043 (double)sf
->head
.xMin
/ sf
->head
.unitsPerEm
,
1044 (double)sf
->head
.yMin
/ sf
->head
.unitsPerEm
,
1045 (double)sf
->head
.xMax
/ sf
->head
.unitsPerEm
,
1046 (double)sf
->head
.yMax
/ sf
->head
.unitsPerEm
);
1048 /* Non-sensible font. */
1049 fprintf(ofp
, "/FontBBox [0 0 0 0] readonly def\n");
1051 fprintf(ofp
, "/PaintType 0 def\n");
1052 fprintf(ofp
, "/CharStrings %u dict dup begin\n", sf
->nglyphs
);
1053 fprintf(ofp
, "0 1 %u{currentfile token pop exch def}bind for\n",
1055 for (i
= 0; i
< sf
->nglyphs
; i
++)
1056 ps_token(ofp
, &cc
, "/%s", glyph_extern(sfnt_indextoglyph(sf
, i
)));
1057 fprintf(ofp
, "\nend readonly def\n");
1058 fprintf(ofp
, "/sfnts [<");
1059 breaks
= snewn(sf
->osd
.numTables
+ sf
->nglyphs
, size_t);
1060 for (i
= 0; i
< sf
->osd
.numTables
; i
++) {
1061 breaks
[i
] = sf
->td
[i
].offset
;
1063 if (!sfnt_findtable(sf
, TAG_glyf
, &glyfptr
, &glyfend
)) {
1064 error(err_sfntnotable
, &sf
->pos
, "glyf");
1067 glyfoff
= (char *)glyfptr
- (char *)sf
->data
;
1068 glyflen
= (char *)glyfend
- (char *)glyfptr
;
1069 if (!sfnt_findtable(sf
, TAG_loca
, &locaptr
, &locaend
)) {
1070 error(err_sfntnotable
, &sf
->pos
, "loca");
1073 loca
= snewn(sf
->nglyphs
, unsigned);
1074 if (sf
->head
.indexToLocFormat
== 0) {
1075 if (!decoden(uint16_decode
, locaptr
, locaend
, loca
, sizeof(*loca
),
1076 sf
->nglyphs
)) goto badloca
;
1077 for (i
= 0; i
< sf
->nglyphs
; i
++) loca
[i
] *= 2;
1079 if (!decoden(uint32_decode
, locaptr
, locaend
, loca
, sizeof(*loca
),
1080 sf
->nglyphs
)) goto badloca
;
1082 for (i
= 1; i
< sf
->nglyphs
; i
++) {
1083 if (loca
[i
] > glyflen
) goto badloca
;
1084 breaks
[sf
->osd
.numTables
+ i
- 1] = loca
[i
] + glyfoff
;
1086 breaks
[sf
->osd
.numTables
+ sf
->nglyphs
- 1] = sf
->len
;
1087 qsort(breaks
, sf
->osd
.numTables
+ sf
->nglyphs
, sizeof(*breaks
), sizecmp
);
1089 for (i
= 0; i
< sf
->len
; i
++) {
1090 if ((i
- lastbreak
) % 38 == 0) fprintf(ofp
, "\n");
1091 if (i
== breaks
[j
]) {
1092 while (i
== breaks
[j
]) j
++;
1094 fprintf(ofp
, "00><\n");
1096 fprintf(ofp
, "%02x", *((unsigned char *)sf
->data
+ i
));
1098 fprintf(ofp
, "00>] readonly def\n");
1100 fprintf(ofp
, "end /%s exch definefont\n", fi
->name
);
1103 error(err_sfntbadtable
, &sf
->pos
, "loca");
1106 void sfnt_data(font_info
*fi
, char **bufp
, size_t *lenp
) {
1107 sfnt
*sf
= fi
->fontfile
;