9 #define NGLYPHS (1 << 14)
11 #define BUFLEN (1 << 23)
12 #define MAX(a, b) ((a) < (b) ? (b) : (a))
14 #define U32(buf, off) (htonl(*(u32 *) ((buf) + (off))))
15 #define U16(buf, off) (htons(*(u16 *) ((buf) + (off))))
16 #define U8(buf, off) (*(u8 *) ((buf) + (off)))
17 #define S16(buf, off) ((s16) htons(*(u16 *) ((buf) + (off))))
18 #define S32(buf, off) ((s32) htonl(*(u32 *) ((buf) + (off))))
20 #define OTFLEN 12 /* otf header length */
21 #define OTFRECLEN 16 /* otf header record length */
22 #define CMAPLEN 4 /* cmap header length */
23 #define CMAPRECLEN 8 /* cmap record length */
24 #define CMAP4LEN 8 /* format 4 cmap subtable header length */
26 typedef unsigned int u32
;
27 typedef unsigned short u16
;
28 typedef unsigned char u8
;
32 static char glyph_name
[NGLYPHS
][GNLEN
];
33 static int glyph_code
[NGLYPHS
];
34 static int glyph_bbox
[NGLYPHS
][4];
35 static int glyph_wid
[NGLYPHS
];
37 static int upm
; /* units per em */
38 static int res
; /* device resolution */
39 static int kmin
; /* minimum kerning value */
41 static char *macset
[];
43 static int owid(int w
)
45 return (w
< 0 ? w
* 1000 - upm
/ 2 : w
* 1000 + upm
/ 2) / upm
;
48 static int uwid(int w
)
51 return (w
< 0 ? owid(w
) - d
/ 2 : owid(w
) + d
/ 2) / d
;
54 /* find the otf table with the given name */
55 static void *otf_table(void *otf
, char *name
)
57 void *recs
= otf
+ OTFLEN
; /* otf table records */
58 void *rec
; /* beginning of a table record */
59 int nrecs
= U16(otf
, 4);
61 for (i
= 0; i
< nrecs
; i
++) {
62 rec
= recs
+ i
* OTFRECLEN
;
63 if (!strncmp(rec
, name
, 4))
64 return otf
+ U32(rec
, 8);
69 /* parse otf cmap format 4 subtable */
70 static void otf_cmap4(void *otf
, void *cmap4
)
73 void *ends
, *begs
, *deltas
, *offsets
;
74 int beg
, end
, delta
, offset
;
76 nsegs
= U16(cmap4
, 6) / 2;
78 begs
= ends
+ 2 * nsegs
+ 2;
79 deltas
= begs
+ 2 * nsegs
;
80 offsets
= deltas
+ 2 * nsegs
;
81 for (i
= 0; i
< nsegs
; i
++) {
82 beg
= U16(begs
, 2 * i
);
83 end
= U16(ends
, 2 * i
);
84 delta
= U16(deltas
, 2 * i
);
85 offset
= U16(offsets
, 2 * i
);
87 for (j
= beg
; j
<= end
; j
++)
88 glyph_code
[U16(offsets
,
89 offset
+ (j
- beg
) * 2)] = j
;
91 for (j
= beg
; j
<= end
; j
++)
92 glyph_code
[(j
+ delta
) & 0xffff] = j
;
97 /* parse otf cmap header */
98 static void otf_cmap(void *otf
, void *cmap
)
100 void *recs
= cmap
+ CMAPLEN
; /* cmap records */
101 void *rec
; /* a cmap record */
102 void *tab
; /* a cmap subtable */
105 int nrecs
= U16(cmap
, 2);
107 for (i
= 0; i
< nrecs
; i
++) {
108 rec
= recs
+ i
* CMAPRECLEN
;
111 tab
= cmap
+ U32(rec
, 4);
113 if (plat
== 3 && enc
== 1 && fmt
== 4)
118 static void otf_post(void *otf
, void *post
)
120 void *post2
; /* version 2.0 header */
121 void *index
; /* glyph name indices */
122 void *names
; /* glyph names */
125 if (U32(post
, 0) != 0x00020000)
128 glyph_n
= U16(post2
, 0);
130 names
= index
+ 2 * glyph_n
;
131 for (i
= 0; i
< glyph_n
; i
++) {
132 idx
= U16(index
, 2 * i
);
134 strcpy(glyph_name
[i
], macset
[idx
]);
136 memcpy(glyph_name
[i
], names
+ cname
+ 1,
138 glyph_name
[i
][U8(names
, cname
)] = '\0';
139 cname
+= U8(names
, cname
) + 1;
144 static void otf_glyf(void *otf
, void *glyf
)
146 void *maxp
= otf_table(otf
, "maxp");
147 void *head
= otf_table(otf
, "head");
148 void *loca
= otf_table(otf
, "loca");
151 int n
= U16(maxp
, 4);
152 int fmt
= U16(head
, 50);
154 for (i
= 0; i
< n
; i
++) {
156 gdat
= glyf
+ U32(loca
, 4 * i
);
157 gdat_next
= glyf
+ U32(loca
, 4 * (i
+ 1));
159 gdat
= glyf
+ U16(loca
, 2 * i
) * 2;
160 gdat_next
= glyf
+ U16(loca
, 2 * (i
+ 1)) * 2;
162 if (gdat
< gdat_next
)
163 for (j
= 0; j
< 4; j
++)
164 glyph_bbox
[i
][j
] = S16(gdat
, 2 + 2 * j
);
168 static void otf_hmtx(void *otf
, void *hmtx
)
170 void *hhea
= otf_table(otf
, "hhea");
174 for (i
= 0; i
< n
; i
++)
175 glyph_wid
[i
] = U16(hmtx
, i
* 4);
176 for (i
= n
; i
< glyph_n
; i
++)
177 glyph_wid
[i
] = glyph_wid
[n
- 1];
180 static void otf_kern(void *otf
, void *kern
)
182 int n
; /* number of kern subtables */
183 void *tab
; /* a kern subtable */
190 for (i
= 0; i
< n
; i
++) {
194 if ((cov
>> 8) == 0 && (cov
& 1)) { /* format 0 */
195 npairs
= U16(tab
, 6);
196 for (j
= 0; j
< npairs
; j
++) {
197 c1
= U16(tab
, 14 + 6 * j
);
198 c2
= U16(tab
, 14 + 6 * j
+ 2);
199 val
= S16(tab
, 14 + 6 * j
+ 4);
200 trfn_kern(glyph_name
[c1
], glyph_name
[c2
],
207 static int coverage(void *cov
, int *out
)
209 int fmt
= U16(cov
, 0);
215 for (i
= 0; i
< n
; i
++)
216 out
[ncov
++] = U16(cov
, 4 + 2 * i
);
219 for (i
= 0; i
< n
; i
++) {
220 beg
= U16(cov
, 4 + 6 * i
);
221 end
= U16(cov
, 4 + 6 * i
+ 2);
222 for (j
= beg
; j
<= end
; j
++)
229 static int classdef(void *tab
, int *gl
, int *cls
)
231 int fmt
= U16(tab
, 0);
238 for (i
= 0; i
< ngl
; i
++) {
240 cls
[i
] = U16(tab
, 6 + 2 * i
);
245 for (i
= 0; i
< n
; i
++) {
246 beg
= U16(tab
, 4 + 6 * i
);
247 end
= U16(tab
, 4 + 6 * i
+ 2);
248 for (j
= beg
; j
<= end
; j
++) {
250 cls
[ngl
] = U16(tab
, 4 + 6 * i
+ 4);
258 static int valuerecord_len(int fmt
)
262 for (i
= 0; i
< 8; i
++)
268 static void valuerecord_print(int fmt
, void *rec
)
273 for (i
= 0; i
< 8; i
++) {
274 if (fmt
& (1 << i
)) {
275 vals
[i
] = uwid(S16(rec
, off
));
280 printf(":%+d%+d%+d%+d", vals
[0], vals
[1], vals
[2], vals
[3]);
283 static int valuerecord_small(int fmt
, void *rec
)
287 for (i
= 0; i
< 8; i
++) {
288 if (fmt
& (1 << i
)) {
289 if (abs(uwid(S16(rec
, off
))) >= MAX(1, kmin
))
297 static void otf_gpostype1(void *otf
, char *feat
, char *sub
)
299 int fmt
= U16(sub
, 0);
300 int vfmt
= U16(sub
, 4);
303 int vlen
= valuerecord_len(vfmt
);
305 ncov
= coverage(sub
+ U16(sub
, 2), cov
);
307 for (i
= 0; i
< ncov
; i
++) {
308 printf("gpos %s %s", feat
, glyph_name
[cov
[i
]]);
309 valuerecord_print(vfmt
, sub
+ 6);
315 for (i
= 0; i
< nvals
; i
++) {
316 printf("gpos %s %s", feat
, glyph_name
[cov
[i
]]);
317 valuerecord_print(vfmt
, sub
+ 8 + i
* vlen
);
323 static void otf_gpostype2(void *otf
, char *feat
, char *sub
)
325 int fmt
= U16(sub
, 0);
326 int vfmt1
= U16(sub
, 4);
327 int vfmt2
= U16(sub
, 6);
328 int fmtoff1
, fmtoff2
;
329 int vrlen
; /* valuerecord1 and valuerecord2 length */
331 vrlen
= valuerecord_len(vfmt1
) + valuerecord_len(vfmt2
);
334 int nc1
= U16(sub
, 8);
335 coverage(sub
+ U16(sub
, 2), cov
);
336 for (i
= 0; i
< nc1
; i
++) {
337 void *c2
= sub
+ U16(sub
, 10 + 2 * i
);
338 int nc2
= U16(c2
, 0);
339 for (j
= 0; j
< nc2
; j
++) {
340 int second
= U16(c2
+ 2 + (2 + vrlen
) * j
, 0);
341 fmtoff1
= 2 + (2 + vrlen
) * j
+ 2;
342 fmtoff2
= fmtoff1
+ valuerecord_len(vfmt2
);
343 if (valuerecord_small(vfmt1
, c2
+ fmtoff1
) &&
344 valuerecord_small(vfmt2
, c2
+ fmtoff2
))
346 printf("gpos %s 2", feat
);
347 printf(" %s", glyph_name
[cov
[i
]]);
348 valuerecord_print(vfmt1
, c2
+ fmtoff1
);
349 printf(" %s", glyph_name
[second
]);
350 valuerecord_print(vfmt2
, c2
+ fmtoff2
);
356 int gl1
[NGLYPHS
], gl2
[NGLYPHS
];
357 int cls1
[NGLYPHS
], cls2
[NGLYPHS
];
358 int ngl1
= classdef(sub
+ U16(sub
, 8), gl1
, cls1
);
359 int ngl2
= classdef(sub
+ U16(sub
, 10), gl2
, cls2
);
360 int ncls1
= U16(sub
, 12);
361 int ncls2
= U16(sub
, 14);
362 for (i
= 0; i
< ngl1
; i
++) {
363 for (j
= 0; j
< ngl2
; j
++) {
364 if (cls1
[i
] >= ncls1
|| cls2
[j
] >= ncls2
)
366 fmtoff1
= 16 + (cls1
[i
] * ncls2
+ cls2
[j
]) * vrlen
;
367 fmtoff2
= fmtoff1
+ valuerecord_len(vfmt1
);
368 if (valuerecord_small(vfmt1
, sub
+ fmtoff1
) &&
369 valuerecord_small(vfmt2
, sub
+ fmtoff2
))
371 printf("gpos %s 2", feat
);
372 printf(" %s", glyph_name
[gl1
[i
]]);
373 valuerecord_print(vfmt1
, sub
+ fmtoff1
);
374 printf(" %s", glyph_name
[gl2
[j
]]);
375 valuerecord_print(vfmt2
, sub
+ fmtoff2
);
382 static void otf_gpostype3(void *otf
, char *feat
, char *sub
)
384 int fmt
= U16(sub
, 0);
387 coverage(sub
+ U16(sub
, 2), cov
);
391 for (i
= 0; i
< n
; i
++) {
392 int prev
= U16(sub
, 6 + 4 * i
);
393 int next
= U16(sub
, 6 + 4 * i
+ 2);
394 printf("gcur %s %s", feat
, glyph_name
[cov
[i
]]);
396 printf(" %d %d", uwid(S16(sub
, prev
+ 2)),
397 uwid(S16(sub
, prev
+ 4)));
401 printf(" %d %d", uwid(S16(sub
, next
+ 2)),
402 uwid(S16(sub
, next
+ 4)));
409 static void otf_gposfeatrec(void *otf
, void *gpos
, void *featrec
)
411 void *feats
= gpos
+ U16(gpos
, 6);
412 void *lookups
= gpos
+ U16(gpos
, 8);
413 void *feat
, *lookup
, *tab
;
414 int nlookups
, type
, ntabs
;
417 memcpy(tag
, featrec
, 4);
418 feat
= feats
+ U16(featrec
, 4);
419 nlookups
= U16(feat
, 2);
420 for (i
= 0; i
< nlookups
; i
++) {
421 lookup
= lookups
+ U16(lookups
, 2 + 2 * U16(feat
, 4 + 2 * i
));
422 type
= U16(lookup
, 0);
423 ntabs
= U16(lookup
, 4);
424 for (j
= 0; j
< ntabs
; j
++) {
425 tab
= lookup
+ U16(lookup
, 6 + 2 * j
);
427 otf_gpostype1(otf
, tag
, tab
);
429 otf_gpostype2(otf
, tag
, tab
);
431 otf_gpostype3(otf
, tag
, tab
);
436 static void otf_gposlang(void *otf
, void *gpos
, void *lang
)
438 void *feats
= gpos
+ U16(gpos
, 6);
439 int featidx
= U16(lang
, 2);
440 int nfeat
= U16(lang
, 4);
442 if (featidx
!= 0xffff)
443 otf_gposfeatrec(otf
, gpos
, feats
+ 2 + 6 * featidx
);
444 for (i
= 0; i
< nfeat
; i
++)
445 otf_gposfeatrec(otf
, gpos
,
446 feats
+ 2 + 6 * U16(lang
, 6 + 2 * i
));
449 static void otf_gpos(void *otf
, void *gpos
)
451 void *scripts
= gpos
+ U16(gpos
, 4);
452 int nscripts
, nlangs
;
456 nscripts
= U16(scripts
, 0);
457 for (i
= 0; i
< nscripts
; i
++) {
458 grec
= scripts
+ 2 + 6 * i
;
459 script
= scripts
+ U16(grec
, 4);
461 otf_gposlang(otf
, gpos
, script
+ U16(script
, 0));
462 nlangs
= U16(script
, 2);
463 for (j
= 0; j
< nlangs
; j
++)
464 otf_gposlang(otf
, gpos
, script
+
465 U16(script
, 4 + 6 * j
+ 4));
469 static void otf_gsubtype1(void *otf
, char *feat
, char *sub
)
472 int fmt
= U16(sub
, 0);
476 ncov
= coverage(sub
+ U16(sub
, 2), cov
);
478 for (i
= 0; i
< ncov
; i
++)
479 printf("gsub %s 2 -%s +%s\n",
480 feat
, glyph_name
[cov
[i
]],
481 glyph_name
[cov
[i
] + S16(sub
, 4)]);
485 for (i
= 0; i
< n
; i
++)
486 printf("gsub %s 2 -%s +%s\n",
487 feat
, glyph_name
[cov
[i
]],
488 glyph_name
[U16(sub
, 6 + 2 * i
)]);
492 static void otf_gsubtype3(void *otf
, char *feat
, char *sub
)
495 int fmt
= U16(sub
, 0);
499 coverage(sub
+ U16(sub
, 2), cov
);
501 for (i
= 0; i
< n
; i
++) {
502 void *alt
= sub
+ U16(sub
, 6 + 2 * i
);
503 int nalt
= U16(alt
, 0);
504 for (j
= 0; j
< nalt
; j
++)
505 printf("gsub %s 2 -%s +%s\n",
506 feat
, glyph_name
[cov
[i
]],
507 glyph_name
[U16(alt
, 2 + 2 * j
)]);
511 static void otf_gsubtype4(void *otf
, char *feat
, char *sub
)
513 int fmt
= U16(sub
, 0);
518 coverage(sub
+ U16(sub
, 2), cov
);
520 for (i
= 0; i
< n
; i
++) {
521 void *set
= sub
+ U16(sub
, 6 + 2 * i
);
522 int nset
= U16(set
, 0);
523 for (j
= 0; j
< nset
; j
++) {
524 void *lig
= set
+ U16(set
, 2 + 2 * j
);
525 int nlig
= U16(lig
, 2);
526 printf("gsub %s %d -%s",
527 feat
, nlig
+ 1, glyph_name
[cov
[i
]]);
528 for (k
= 0; k
< nlig
- 1; k
++)
529 printf(" -%s", glyph_name
[U16(lig
, 4 + 2 * k
)]);
530 printf(" +%s\n", glyph_name
[U16(lig
, 0)]);
535 static void otf_gsubfeatrec(void *otf
, void *gsub
, void *featrec
)
537 void *feats
= gsub
+ U16(gsub
, 6);
538 void *lookups
= gsub
+ U16(gsub
, 8);
539 void *feat
, *lookup
, *tab
;
540 int nlookups
, type
, ntabs
;
543 memcpy(tag
, featrec
, 4);
544 feat
= feats
+ U16(featrec
, 4);
545 nlookups
= U16(feat
, 2);
546 for (i
= 0; i
< nlookups
; i
++) {
547 lookup
= lookups
+ U16(lookups
, 2 + 2 * U16(feat
, 4 + 2 * i
));
548 type
= U16(lookup
, 0);
549 ntabs
= U16(lookup
, 4);
550 for (j
= 0; j
< ntabs
; j
++) {
551 tab
= lookup
+ U16(lookup
, 6 + 2 * j
);
553 otf_gsubtype1(otf
, tag
, tab
);
555 otf_gsubtype3(otf
, tag
, tab
);
557 otf_gsubtype4(otf
, tag
, tab
);
562 static void otf_gsublang(void *otf
, void *gsub
, void *lang
)
564 void *feats
= gsub
+ U16(gsub
, 6);
565 int featidx
= U16(lang
, 2);
566 int nfeat
= U16(lang
, 4);
568 if (featidx
!= 0xffff)
569 otf_gsubfeatrec(otf
, gsub
, feats
+ 2 + 6 * featidx
);
570 for (i
= 0; i
< nfeat
; i
++)
571 otf_gsubfeatrec(otf
, gsub
,
572 feats
+ 2 + 6 * U16(lang
, 6 + 2 * i
));
575 static void otf_gsub(void *otf
, void *gsub
)
577 void *scripts
= gsub
+ U16(gsub
, 4);
578 int nscripts
, nlangs
;
581 nscripts
= U16(scripts
, 0);
582 for (i
= 0; i
< nscripts
; i
++) {
583 script
= scripts
+ U16(scripts
+ 2 + 6 * i
, 4);
584 nlangs
= U16(script
, 2);
586 otf_gsublang(otf
, gsub
, script
+ U16(script
, 0));
587 for (j
= 0; j
< nlangs
; j
++)
588 otf_gsublang(otf
, gsub
, script
+
589 U16(script
, 4 + 6 * j
+ 4));
593 int xread(int fd
, char *buf
, int len
)
597 int ret
= read(fd
, buf
+ nr
, len
- nr
);
598 if (ret
== -1 && (errno
== EAGAIN
|| errno
== EINTR
))
607 static char buf
[BUFLEN
];
612 if (xread(0, buf
, sizeof(buf
)) <= 0)
614 upm
= U16(otf_table(buf
, "head"), 18);
615 otf_cmap(buf
, otf_table(buf
, "cmap"));
616 otf_post(buf
, otf_table(buf
, "post"));
617 if (otf_table(buf
, "glyf"))
618 otf_glyf(buf
, otf_table(buf
, "glyf"));
619 otf_hmtx(buf
, otf_table(buf
, "hmtx"));
620 for (i
= 0; i
< glyph_n
; i
++) {
621 trfn_char(glyph_name
[i
], -1,
622 glyph_code
[i
] != 0xffff ? glyph_code
[i
] : 0,
624 owid(glyph_bbox
[i
][0]), owid(glyph_bbox
[i
][1]),
625 owid(glyph_bbox
[i
][2]), owid(glyph_bbox
[i
][3]));
627 if (otf_table(buf
, "kern"))
628 otf_kern(buf
, otf_table(buf
, "kern"));
632 void otf_feat(int r
, int k
)
636 if (otf_table(buf
, "GSUB"))
637 otf_gsub(buf
, otf_table(buf
, "GSUB"));
638 if (otf_table(buf
, "GPOS"))
639 otf_gpos(buf
, otf_table(buf
, "GPOS"));
642 static char *macset
[] = {
643 ".notdef", ".null", "nonmarkingreturn", "space", "exclam",
644 "quotedbl", "numbersign", "dollar", "percent", "ampersand",
645 "quotesingle", "parenleft", "parenright", "asterisk", "plus",
646 "comma", "hyphen", "period", "slash", "zero",
647 "one", "two", "three", "four", "five",
648 "six", "seven", "eight", "nine", "colon",
649 "semicolon", "less", "equal", "greater", "question",
650 "at", "A", "B", "C", "D",
651 "E", "F", "G", "H", "I",
652 "J", "K", "L", "M", "N",
653 "O", "P", "Q", "R", "S",
654 "T", "U", "V", "W", "X",
655 "Y", "Z", "bracketleft", "backslash", "bracketright",
656 "asciicircum", "underscore", "grave", "a", "b",
657 "c", "d", "e", "f", "g",
658 "h", "i", "j", "k", "l",
659 "m", "n", "o", "p", "q",
660 "r", "s", "t", "u", "v",
661 "w", "x", "y", "z", "braceleft",
662 "bar", "braceright", "asciitilde", "Adieresis", "Aring",
663 "Ccedilla", "Eacute", "Ntilde", "Odieresis", "Udieresis",
664 "aacute", "agrave", "acircumflex", "adieresis", "atilde",
665 "aring", "ccedilla", "eacute", "egrave", "ecircumflex",
666 "edieresis", "iacute", "igrave", "icircumflex", "idieresis",
667 "ntilde", "oacute", "ograve", "ocircumflex", "odieresis",
668 "otilde", "uacute", "ugrave", "ucircumflex", "udieresis",
669 "dagger", "degree", "cent", "sterling", "section",
670 "bullet", "paragraph", "germandbls", "registered", "copyright",
671 "trademark", "acute", "dieresis", "notequal", "AE",
672 "Oslash", "infinity", "plusminus", "lessequal", "greaterequal",
673 "yen", "mu", "partialdiff", "summation", "product",
674 "pi", "integral", "ordfeminine", "ordmasculine", "Omega",
675 "ae", "oslash", "questiondown", "exclamdown", "logicalnot",
676 "radical", "florin", "approxequal", "Delta", "guillemotleft",
677 "guillemotright", "ellipsis", "nonbreakingspace", "Agrave", "Atilde",
678 "Otilde", "OE", "oe", "endash", "emdash",
679 "quotedblleft", "quotedblright", "quoteleft", "quoteright", "divide",
680 "lozenge", "ydieresis", "Ydieresis", "fraction", "currency",
681 "guilsinglleft", "guilsinglright", "fi", "fl", "daggerdbl",
682 "periodcentered", "quotesinglbase", "quotedblbase", "perthousand", "Acircumflex",
683 "Ecircumflex", "Aacute", "Edieresis", "Egrave", "Iacute",
684 "Icircumflex", "Idieresis", "Igrave", "Oacute", "Ocircumflex",
685 "apple", "Ograve", "Uacute", "Ucircumflex", "Ugrave",
686 "dotlessi", "circumflex", "tilde", "macron", "breve",
687 "dotaccent", "ring", "cedilla", "hungarumlaut", "ogonek",
688 "caron", "Lslash", "lslash", "Scaron", "scaron",
689 "Zcaron", "zcaron", "brokenbar", "Eth", "eth",
690 "Yacute", "yacute", "Thorn", "thorn", "minus",
691 "multiply", "onesuperior", "twosuperior", "threesuperior", "onehalf",
692 "onequarter", "threequarters", "franc", "Gbreve", "gbreve",
693 "Idotaccent", "Scedilla", "scedilla", "Cacute", "cacute",
694 "Ccaron", "ccaron", "dcroat",