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/>
24 typedef struct sfnt_decode_Tag sfnt_decode
;
25 struct sfnt_decode_Tag
{
26 void (*decoder
)(void *src
, void *dest
);
32 static void decode_uint8(void *src
, void *dest
) {
33 *(unsigned int *)dest
= *(unsigned char *)src
;
35 #define d_uint8 decode_uint8, 1
39 static void decode_int8(void *src
, void *dest
) {
40 *(int *)dest
= *(signed char *)src
;
42 #define d_int8 decode_int8, 1
45 static void decode_uint16(void *src
, void *dest
) {
46 unsigned char *cp
= src
;
47 *(unsigned int *)dest
= (cp
[0] << 8) + cp
[1];
49 #define d_uint16 decode_uint16, 2
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];
56 #define d_int16 decode_int16, 2
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];
63 #define d_uint32 decode_uint32, 4
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];
70 #define d_int32 decode_int32, 4
72 static void decode_skip(void *src
, void *dest
) {
77 #define d_skip(n) decode_skip, (n), 0
79 static void decode_end(void *src
, void *dest
) {
84 #define d_end decode_end, 0, 0
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
;
96 static void *decoden(sfnt_decode
*dec
, void *src
, void *end
, void *dest
,
97 size_t size
, size_t n
) {
99 src
= decode(dec
, src
, end
, dest
);
100 dest
= (char *)dest
+ size
;
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
} };
110 /* Offset subdirectory -- the start of the file */
111 typedef struct offsubdir_Tag offsubdir
;
112 struct offsubdir_Tag
{
113 unsigned scaler_type
;
116 sfnt_decode offsubdir_decode
[] = {
117 { d_uint32
, offsetof(offsubdir
, scaler_type
) },
118 { d_uint16
, offsetof(offsubdir
, numTables
) },
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
135 /* Table directory */
136 typedef struct tabledir_Tag tabledir
;
137 struct tabledir_Tag
{
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
) },
151 /* OS/2 and Windows compatibility table */
152 typedef struct t_OS_2_Tag t_OS_2
;
155 int sTypoAscender
, sTypoDescender
;
156 int sxHeight
, sCapHeight
;
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 */
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 */
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 */
200 /* Character to Glyph ('cmap') table */
201 typedef struct t_cmap_Tag t_cmap
;
205 sfnt_decode t_cmap_decode
[] = {
207 { d_uint16
, offsetof(t_cmap
, numTables
) },
210 typedef struct encodingrec_Tag encodingrec
;
211 struct encodingrec_Tag
{
216 sfnt_decode encodingrec_decode
[] = {
217 { d_uint16
, offsetof(encodingrec
, platformID
) },
218 { d_uint16
, offsetof(encodingrec
, encodingID
) },
219 { d_uint32
, offsetof(encodingrec
, offset
) },
222 typedef struct cmap4_Tag cmap4
;
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 */
236 /* Font Header ('head') table */
237 typedef struct t_head_Tag t_head
;
240 unsigned fontRevision
;
243 int xMin
, yMin
, xMax
, yMax
;
244 int indexToLocFormat
;
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
) },
263 /* Horizontal Header ('hhea') table */
264 typedef struct t_hhea_Tag t_hhea
;
270 int metricDataFormat
;
271 unsigned numOfLongHorMetrics
;
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
) },
279 { d_int16
, offsetof(t_hhea
, metricDataFormat
) },
280 { d_uint16
, offsetof(t_hhea
, numOfLongHorMetrics
) },
284 /* Horizontal Metrics ('hmtx') table */
285 sfnt_decode longhormetric_decode
[] = {
291 /* Naming ('name') table */
292 typedef struct t_name_Tag t_name
;
293 typedef struct namerecord_Tag namerecord
;
297 unsigned stringOffset
;
298 namerecord
*nameRecord
;
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
) },
306 struct namerecord_Tag
{
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
) },
324 /* PostScript compatibility ('post') table */
325 typedef struct t_post_Tag t_post
;
329 int underlinePosition
;
330 int underlineThickness
;
331 unsigned isFixedPitch
;
332 unsigned minMemType42
;
333 unsigned maxMemType42
;
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 */
349 unsigned short index
;
360 glyph
*glyphsbyindex
;
361 unsigned short *glyphsbyname
;
362 unsigned minmem
, maxmem
;
365 static int sfnt_findtable(sfnt
*sf
, unsigned tag
,
366 void **startp
, void **endp
) {
369 for (i
= 0; i
< sf
->osd
.numTables
; i
++) {
370 if (sf
->td
[i
].tag
== tag
) {
371 *startp
= (char *)sf
->data
+ sf
->td
[i
].offset
;
372 *endp
= (char *)*startp
+ sf
->td
[i
].length
;
379 static char *sfnt_psname(font_info
*fi
) {
380 sfnt
*sf
= fi
->fontfile
;
387 if (!sfnt_findtable(sf
, TAG_name
, &ptr
, &end
))
389 ptr
= decode(t_name_decode
, ptr
, end
, &name
);
390 name
.nameRecord
= snewn(name
.count
, namerecord
);
391 ptr
= decoden(namerecord_decode
, ptr
, sf
->end
, name
.nameRecord
,
392 sizeof(*name
.nameRecord
), name
.count
);
393 for (i
= 0; i
< name
.count
; i
++) {
394 nr
= name
.nameRecord
+ i
;
395 if (nr
->nameID
== 6) {
396 /* PostScript name, but can we make sense of it? */
397 if (nr
->platformID
== 1 && nr
->encodingID
== 0) {
398 /* Mac Roman, which is ASCII for our purposes */
399 psname
= snewn(nr
->length
+ 1, char);
400 memcpy(psname
, (char *)ptr
+ nr
->offset
, nr
->length
);
401 psname
[nr
->length
] = 0;
402 sfree(name
.nameRecord
);
410 static unsigned short *cmp_glyphsbyindex
;
411 static int glyphsbyname_cmp(void const *a
, void const *b
) {
412 glyph ga
= cmp_glyphsbyindex
[*(unsigned short *)a
];
413 glyph gb
= cmp_glyphsbyindex
[*(unsigned short *)b
];
414 if (ga
< gb
) return -1;
415 if (ga
> gb
) return 1;
418 static int glyphsbyname_cmp_search(void const *a
, void const *b
) {
419 glyph ga
= *(glyph
*)a
;
420 glyph gb
= cmp_glyphsbyindex
[*(unsigned short *)b
];
421 if (ga
< gb
) return -1;
422 if (ga
> gb
) return 1;
427 * Extract data from the 'post' table (mostly glyph mappings)
429 * TODO: cope better with duplicated glyph names (usually .notdef)
430 * TODO: when presented with format 3.0, try to use 'CFF' if present.
432 static void sfnt_mapglyphs(font_info
*fi
) {
433 sfnt
*sf
= fi
->fontfile
;
439 unsigned nextras
, i
, g
;
441 sf
->glyphsbyname
= sf
->glyphsbyindex
= NULL
;
442 if (!sfnt_findtable(sf
, TAG_post
, &ptr
, &end
))
444 ptr
= decode(t_post_decode
, ptr
, end
, &post
);
446 sf
->minmem
= post
.minMemType42
;
447 sf
->maxmem
= post
.maxMemType42
;
448 fi
->italicangle
= post
.italicAngle
/ 65536.0;
449 if (ptr
== NULL
) abort();
450 switch (post
.format
) {
453 sf
->glyphsbyindex
= (glyph
*)tt_std_glyphs
;
456 if ((char *)ptr
+ 2 > (char *)end
) return;
457 decode_uint16(ptr
, &sf
->nglyphs
);
458 ptr
= (char *)ptr
+ 2;
459 if ((char *)ptr
+ 2*sf
->nglyphs
> (char *)end
) return;
461 for (sptr
= (unsigned char *)ptr
+ 2*sf
->nglyphs
;
462 sptr
< (unsigned char *)end
;
465 extraglyphs
= snewn(nextras
, glyph
);
467 for (sptr
= (unsigned char *)ptr
+ 2*sf
->nglyphs
;
468 sptr
< (unsigned char *)end
;
470 memcpy(tmp
, sptr
+ 1, *sptr
);
473 extraglyphs
[i
++] = glyph_intern(tmp
);
475 sf
->glyphsbyindex
= snewn(sf
->nglyphs
, glyph
);
476 for (i
= 0; i
< sf
->nglyphs
; i
++) {
477 decode_uint16((char *)ptr
+ 2*i
, &g
);
479 sf
->glyphsbyindex
[i
] = tt_std_glyphs
[g
];
480 else if (g
< 258 + nextras
)
481 sf
->glyphsbyindex
[i
] = extraglyphs
[g
- 258];
483 sf
->glyphsbyindex
[i
] = NOGLYPH
;
490 /* Construct glyphsbyname */
491 sf
->glyphsbyname
= snewn(sf
->nglyphs
, unsigned short);
492 for (i
= 0; i
< sf
->nglyphs
; i
++)
493 sf
->glyphsbyname
[i
] = i
;
494 cmp_glyphsbyindex
= sf
->glyphsbyindex
;
495 qsort(sf
->glyphsbyname
, sf
->nglyphs
, sizeof(*sf
->glyphsbyname
),
499 glyph
sfnt_indextoglyph(sfnt
*sf
, unsigned idx
) {
500 return sf
->glyphsbyindex
[idx
];
503 unsigned sfnt_nglyphs(sfnt
*sf
) {
507 unsigned sfnt_glyphtoindex(sfnt
*sf
, glyph g
) {
508 cmp_glyphsbyindex
= sf
->glyphsbyindex
;
509 return *(unsigned short *)bsearch(&g
, sf
->glyphsbyname
, sf
->nglyphs
,
510 sizeof(*sf
->glyphsbyname
),
511 glyphsbyname_cmp_search
);
515 * Get data from 'hhea', 'hmtx', and 'OS/2' tables
517 void sfnt_getmetrics(font_info
*fi
) {
518 sfnt
*sf
= fi
->fontfile
;
525 /* First, the bounding box from the 'head' table. */
526 fi
->fontbbox
[0] = sf
->head
.xMin
* FUNITS_PER_PT
/ sf
->head
.unitsPerEm
;
527 fi
->fontbbox
[1] = sf
->head
.yMin
* FUNITS_PER_PT
/ sf
->head
.unitsPerEm
;
528 fi
->fontbbox
[2] = sf
->head
.xMax
* FUNITS_PER_PT
/ sf
->head
.unitsPerEm
;
529 fi
->fontbbox
[3] = sf
->head
.yMax
* FUNITS_PER_PT
/ sf
->head
.unitsPerEm
;
530 if (!sfnt_findtable(sf
, TAG_hhea
, &ptr
, &end
))
532 if (decode(t_hhea_decode
, ptr
, end
, &hhea
) == NULL
)
534 if ((hhea
.version
& 0xffff0000) != 0x00010000)
536 fi
->ascent
= hhea
.ascent
;
537 fi
->descent
= hhea
.descent
;
538 if (hhea
.metricDataFormat
!= 0)
540 if (!sfnt_findtable(sf
, TAG_hmtx
, &ptr
, &end
))
542 hmtx
= snewn(hhea
.numOfLongHorMetrics
, unsigned);
543 if (decoden(longhormetric_decode
, ptr
, end
, hmtx
, sizeof(*hmtx
),
544 hhea
.numOfLongHorMetrics
) == NULL
)
546 for (i
= 0; i
< sf
->nglyphs
; i
++) {
547 glyph_width
*w
= snew(glyph_width
);
548 w
->glyph
= sfnt_indextoglyph(sf
, i
);
549 j
= i
< hhea
.numOfLongHorMetrics ? i
: hhea
.numOfLongHorMetrics
- 1;
550 w
->width
= hmtx
[j
] * UNITS_PER_PT
/ sf
->head
.unitsPerEm
;
551 add234(fi
->widths
, w
);
553 /* Now see if the 'OS/2' table has any useful metrics */
554 if (!sfnt_findtable(sf
, TAG_OS_2
, &ptr
, &end
))
556 if (decode(uint16_decode
, ptr
, end
, &OS_2
.version
) == NULL
)
558 if (OS_2
.version
>= 2) {
559 if (decode(t_OS_2_v2_decode
, ptr
, end
, &OS_2
) == NULL
)
561 fi
->xheight
= OS_2
.sxHeight
* FUNITS_PER_PT
/ sf
->head
.unitsPerEm
;
562 fi
->capheight
= OS_2
.sCapHeight
* FUNITS_PER_PT
/ sf
->head
.unitsPerEm
;
563 } else if (OS_2
.version
== 1) {
564 if (decode(t_OS_2_v1_decode
, ptr
, end
, &OS_2
) == NULL
)
568 fi
->ascent
= OS_2
.sTypoAscender
* FUNITS_PER_PT
/ sf
->head
.unitsPerEm
;
569 fi
->descent
= OS_2
.sTypoDescender
* FUNITS_PER_PT
/ sf
->head
.unitsPerEm
;
573 * Get mapping data from 'cmap' table
575 * We look for either a (0, 3), or (3, 1) table, both of these being
576 * versions of UCS-2. We only handle format 4 of this table, since
577 * that seems to be the only one in use.
579 void sfnt_getmap(font_info
*fi
) {
580 sfnt
*sf
= fi
->fontfile
;
583 void *base
, *ptr
, *end
;
588 for (i
= 0; i
< lenof(fi
->bmp
); i
++)
590 if (!sfnt_findtable(sf
, TAG_cmap
, &ptr
, &end
))
593 ptr
= decode(t_cmap_decode
, ptr
, end
, &cmap
);
594 if (ptr
== NULL
) abort();
595 esd
= snewn(cmap
.numTables
, encodingrec
);
596 ptr
= decoden(encodingrec_decode
, ptr
, end
, esd
, sizeof(*esd
),
598 if (ptr
== NULL
) abort();
599 for (i
= 0; i
< cmap
.numTables
; i
++) {
600 if (!decode(uint16_decode
, (char *)base
+ esd
[i
].offset
, end
, &format
))
602 if ((esd
[i
].platformID
== 0 && esd
[i
].encodingID
== 3) ||
603 (esd
[i
].platformID
== 3 && esd
[i
].encodingID
== 1)) {
605 if (!decode(uint16_decode
, (char *)base
+ esd
[i
].offset
, end
,
609 unsigned *data
, *endCode
, *startCode
, *idDelta
, *idRangeOffset
;
610 unsigned *glyphIndexArray
;
611 unsigned segcount
, nword
, nglyphindex
, j
;
614 ptr
= decode(cmap4_decode
, (char *)base
+ esd
[i
].offset
, end
,
617 segcount
= cmap4
.segCountX2
/ 2;
618 nword
= cmap4
.length
/ 2 - 7;
619 data
= snewn(nword
, unsigned);
620 if (!decoden(uint16_decode
, ptr
, (char *)ptr
+ nword
* 2,
621 data
, sizeof(*data
), nword
)) abort();
623 startCode
= data
+ segcount
+ 1;
624 idDelta
= startCode
+ segcount
;
625 idRangeOffset
= idDelta
+ segcount
;
626 glyphIndexArray
= idRangeOffset
+ segcount
;
627 nglyphindex
= nword
- segcount
* 4 - 1;
629 for (j
= 0; j
< segcount
; j
++) {
632 if (idRangeOffset
[j
] == 0) {
633 for (k
= startCode
[j
]; k
<= endCode
[j
]; k
++) {
634 idx
= (k
+ idDelta
[j
]) & 0xffff;
636 if (idx
> sf
->nglyphs
) abort();
637 fi
->bmp
[k
] = sfnt_indextoglyph(sf
, idx
);
641 unsigned startidx
= idRangeOffset
[j
]/2 - segcount
+ j
;
642 for (k
= startCode
[j
]; k
<= endCode
[j
]; k
++) {
643 idx
= glyphIndexArray
[startidx
+ k
- startCode
[j
]];
645 idx
= (idx
+ idDelta
[j
]) & 0xffff;
646 if (idx
> sf
->nglyphs
) abort();
647 fi
->bmp
[k
] = sfnt_indextoglyph(sf
, idx
);
659 void read_sfnt_file(input
*in
) {
660 sfnt
*sf
= snew(sfnt
);
662 FILE *fp
= in
->currfp
;
663 font_info
*fi
= snew(font_info
);
668 fi
->widths
= newtree234(width_cmp
);
669 fi
->kerns
= newtree234(kern_cmp
);
670 fi
->ligs
= newtree234(lig_cmp
);
671 fi
->fontbbox
[0] = fi
->fontbbox
[1] = fi
->fontbbox
[2] = fi
->fontbbox
[3] = 0;
672 fi
->capheight
= fi
->xheight
= fi
->ascent
= fi
->descent
= 0;
673 fi
->stemh
= fi
->stemv
= fi
->italicangle
= 0;
675 fi
->filetype
= TRUETYPE
;
678 sf
->data
= snewn(sf
->len
, unsigned char);
680 got
= fread((char *)sf
->data
+ off
, 1, sf
->len
- off
, fp
);
682 if (off
!= sf
->len
) break;
684 sf
->data
= sresize(sf
->data
, sf
->len
, unsigned char);
687 sf
->data
= sresize(sf
->data
, sf
->len
, unsigned char);
688 sf
->end
= (char *)sf
->data
+ sf
->len
;
689 decode(offsubdir_decode
, sf
->data
, sf
->end
, &sf
->osd
);
691 fprintf(stderr, "scaler type = 0x%x; numTables = %u\n",
692 sf->osd.scaler_type, sf->osd.numTables);
694 sf
->td
= snewn(sf
->osd
.numTables
, tabledir
);
695 decoden(tabledir_decode
, (char *)sf
->data
+ 12, sf
->end
,
696 sf
->td
, sizeof(*sf
->td
), sf
->osd
.numTables
);
698 for (i = 0; i < sf->osd.numTables; i++)
699 fprintf(stderr, "table tag = '%c%c%c%c'; offset = %#10x; length = %#10x\n",
700 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);
702 if (!sfnt_findtable(sf
, TAG_head
, &ptr
, &end
))
704 if (decode(t_head_decode
, ptr
, end
, &sf
->head
) == NULL
)
706 if ((sf
->head
.version
& 0xffff0000) != 0x00010000)
708 fi
->name
= sfnt_psname(fi
);
712 fi
->next
= all_fonts
;
717 static int sizecmp(const void *a
, const void *b
) {
718 if (*(size_t *)a
< *(size_t *)b
) return -1;
719 if (*(size_t *)a
> *(size_t *)b
) return 1;
724 * The format for embedding TrueType fonts in Postscript is defined in
725 * Adobe Technical Note #5012: The Type 42 Font Format Specification.
726 * <http://partners.adobe.com/public/developer/en/font/5012.Type42_Spec.pdf>
729 void sfnt_writeps(font_info
const *fi
, FILE *ofp
) {
730 unsigned i
, j
, lastbreak
;
731 sfnt
*sf
= fi
->fontfile
;
732 size_t *breaks
, glyfoff
, glyflen
;
733 void *glyfptr
, *glyfend
, *locaptr
, *locaend
;
737 /* XXX Unclear that this is the correct format. */
738 fprintf(ofp
, "%%!PS-TrueTypeFont-%u-%u\n", sf
->osd
.scaler_type
,
739 sf
->head
.fontRevision
);
741 fprintf(ofp
, "%%%%VMUsage: %u %u\n", sf
->minmem
, sf
->maxmem
);
742 fprintf(ofp
, "9 dict dup begin\n");
743 fprintf(ofp
, "/FontType 42 def\n");
744 fprintf(ofp
, "/FontMatrix [1 0 0 1 0 0] def\n");
745 fprintf(ofp
, "/FontName /%s def\n", fi
->name
);
746 fprintf(ofp
, "/Encoding StandardEncoding def\n");
747 if ((sf
->head
.flags
& 0x0003) == 0x0003) {
749 * Sensible font with the origin in the right place, such that
750 * the bounding box is meaningful.
752 fprintf(ofp
, "/FontBBox [%g %g %g %g] readonly def\n",
753 (double)sf
->head
.xMin
/ sf
->head
.unitsPerEm
,
754 (double)sf
->head
.yMin
/ sf
->head
.unitsPerEm
,
755 (double)sf
->head
.xMax
/ sf
->head
.unitsPerEm
,
756 (double)sf
->head
.yMax
/ sf
->head
.unitsPerEm
);
758 /* Non-sensible font. */
759 fprintf(ofp
, "/FontBBox [0 0 0 0] readonly def\n");
761 fprintf(ofp
, "/PaintType 0 def\n");
762 fprintf(ofp
, "/CharStrings %u dict dup begin\n", sf
->nglyphs
);
763 fprintf(ofp
, "0 1 %u{currentfile token pop exch def}bind for\n",
765 for (i
= 0; i
< sf
->nglyphs
; i
++)
766 ps_token(ofp
, &cc
, "/%s", glyph_extern(sfnt_indextoglyph(sf
, i
)));
767 fprintf(ofp
, "\nend readonly def\n");
768 fprintf(ofp
, "/sfnts [<");
769 breaks
= snewn(sf
->osd
.numTables
+ sf
->nglyphs
, size_t);
770 for (i
= 0; i
< sf
->osd
.numTables
; i
++) {
771 breaks
[i
] = sf
->td
[i
].offset
;
773 if (!sfnt_findtable(sf
, TAG_glyf
, &glyfptr
, &glyfend
))
775 glyfoff
= (char *)glyfptr
- (char *)sf
->data
;
776 glyflen
= (char *)glyfend
- (char *)glyfptr
;
777 if (!sfnt_findtable(sf
, TAG_loca
, &locaptr
, &locaend
))
779 loca
= snewn(sf
->nglyphs
, unsigned);
780 if (sf
->head
.indexToLocFormat
== 0) {
781 if (!decoden(uint16_decode
, locaptr
, locaend
, loca
, sizeof(*loca
),
782 sf
->nglyphs
)) abort();
783 for (i
= 0; i
< sf
->nglyphs
; i
++) loca
[i
] *= 2;
785 if (!decoden(uint32_decode
, locaptr
, locaend
, loca
, sizeof(*loca
),
786 sf
->nglyphs
)) abort();
788 for (i
= 1; i
< sf
->nglyphs
; i
++) {
789 if (loca
[i
] > glyflen
) abort();
790 breaks
[sf
->osd
.numTables
+ i
- 1] = loca
[i
] + glyfoff
;
792 breaks
[sf
->osd
.numTables
+ sf
->nglyphs
- 1] = sf
->len
;
793 qsort(breaks
, sf
->osd
.numTables
+ sf
->nglyphs
, sizeof(*breaks
), sizecmp
);
795 for (i
= 0; i
< sf
->len
; i
++) {
796 if ((i
- lastbreak
) % 38 == 0) fprintf(ofp
, "\n");
797 if (i
== breaks
[j
]) {
798 while (i
== breaks
[j
]) j
++;
800 fprintf(ofp
, "00><\n");
802 fprintf(ofp
, "%02x", *((unsigned char *)sf
->data
+ i
));
804 fprintf(ofp
, "00>] readonly def\n");
806 fprintf(ofp
, "end /%s exch definefont\n", fi
->name
);
809 void sfnt_cmap(font_encoding
*fe
, object
*cmap
) {
812 objtext(cmap
, "<</Type/CMap\n/CMapName/");
813 objtext(cmap
, fe
->name
);
814 objtext(cmap
, "\n/CIDSystemInfo<</Registry(Adobe)/Ordering(Identity)"
815 "/Supplement 0>>\n");
816 objstream(cmap
, "%!PS-Adobe-3.0 Resource-CMap\n"
817 "%%DocumentNeededResources: procset CIDInit\n"
818 "%%IncludeResource: procset CIDInit\n"
819 "%%BeginResource: CMap ");
820 objstream(cmap
, fe
->name
);
821 objstream(cmap
, "\n%%Title (");
822 objstream(cmap
, fe
->name
);
823 objstream(cmap
, " Adobe Identity 0)\n%%Version: 1\n%%EndComments\n");
824 objstream(cmap
, "/CIDInit/ProcSet findresource begin\n");
825 objstream(cmap
, "12 dict begin begincmap\n");
826 objstream(cmap
, "/CIDSystemInfo 3 dict dup begin\n"
827 "/Registry(Adobe)def/Ordering(Identity)def/Supplement 0 def "
829 objstream(cmap
, "/CMapName/");
830 objstream(cmap
, fe
->name
);
831 objstream(cmap
, " def/CMapType 0 def/WMode 0 def\n");
832 objstream(cmap
, "1 begincodespacerange<00><FF>endcodespacerange\n");
833 for (i
= 0; i
< 256; i
++) {
835 if (fe
->vector
[i
] == NOGLYPH
)
837 objstream(cmap
, "1 begincidchar");
838 sprintf(buf
, "<%02X>", i
);
839 objstream(cmap
, buf
);
840 sprintf(buf
, "%hu", sfnt_glyphtoindex(fe
->font
->info
->fontfile
,
842 objstream(cmap
, buf
);
843 objstream(cmap
, " endcidchar\n");
845 objstream(cmap
, "endcmap CMapName currentdict /CMap defineresource pop "
846 "end end\n%%EndResource\n%%EOF\n");
849 void sfnt_data(font_info
*fi
, char **bufp
, size_t *lenp
) {
850 sfnt
*sf
= fi
->fontfile
;