10 #define MAX(a, b) ((a) < (b) ? (b) : (a))
11 #define LEN(a) (sizeof(a) / sizeof((a)[0]))
13 #define NGLYPHS (1 << 14)
14 #define NLOOKUPS (1 << 12)
18 #define U32(buf, off) (htonl(*(u32 *) ((buf) + (off))))
19 #define U16(buf, off) (htons(*(u16 *) ((buf) + (off))))
20 #define U8(buf, off) (*(u8 *) ((buf) + (off)))
21 #define S16(buf, off) ((s16) htons(*(u16 *) ((buf) + (off))))
22 #define S32(buf, off) ((s32) htonl(*(u32 *) ((buf) + (off))))
24 #define GCTXLEN 16 /* number of context backtrack coverage arrays */
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 */
40 static int warn
; /* report unsupported tables */
42 static char *macset
[];
43 static char *stdset
[];
45 static int owid(int w
)
47 return (w
< 0 ? w
* 1000 - upm
/ 2 : w
* 1000 + upm
/ 2) / upm
;
50 static int uwid(int w
)
53 return (w
< 0 ? owid(w
) - d
/ 2 : owid(w
) + d
/ 2) / d
;
56 /* weather the script is right-to-left */
57 static int otf_r2l(char *feat
)
59 char *scrp
= strchr(feat
, ':') + 1;
60 return !strcmp("arab", scrp
) || !strcmp("hebr", scrp
);
63 /* report unsupported otf tables */
64 static void otf_unsupported(char *sub
, int type
, int fmt
)
67 fprintf(stderr
, "neatmkfn: unsupported %s lookup %d", sub
, type
);
69 fprintf(stderr
, " format %d", fmt
);
70 fprintf(stderr
, "\n");
74 /* find the otf table with the given name */
75 static void *otf_table(void *otf
, char *name
)
77 int nrecs
= U16(otf
, 4);
79 for (i
= 0; i
< nrecs
; i
++) {
80 void *rec
= otf
+ 12 + i
* 16; /* an otf table record */
81 if (!strncmp(rec
, name
, 4))
82 return otf
+ U32(rec
, 8);
87 /* obtain postscript font name from name table */
88 static void otf_name(void *otf
, void *tab
)
91 void *str
= tab
+ U16(tab
, 4); /* storage area */
92 int n
= U16(tab
, 2); /* number of name records */
94 for (i
= 0; i
< n
; i
++) {
95 void *rec
= tab
+ 6 + 12 * i
;
96 int pid
= U16(rec
, 0); /* platform id */
97 int eid
= U16(rec
, 2); /* encoding id */
98 int lid
= U16(rec
, 4); /* language id */
99 int nid
= U16(rec
, 6); /* name id */
100 int len
= U16(rec
, 8); /* string length */
101 int off
= U16(rec
, 10); /* string offset */
102 if (pid
== 1 && eid
== 0 && lid
== 0 && nid
== 6) {
103 memcpy(name
, str
+ off
, len
);
110 /* parse otf cmap format 4 subtable */
111 static void otf_cmap4(void *otf
, void *cmap4
)
114 void *ends
, *begs
, *deltas
, *offsets
;
115 int beg
, end
, delta
, offset
;
117 nsegs
= U16(cmap4
, 6) / 2;
119 begs
= ends
+ 2 * nsegs
+ 2;
120 deltas
= begs
+ 2 * nsegs
;
121 offsets
= deltas
+ 2 * nsegs
;
122 for (i
= 0; i
< nsegs
; i
++) {
123 beg
= U16(begs
, 2 * i
);
124 end
= U16(ends
, 2 * i
);
125 delta
= U16(deltas
, 2 * i
);
126 offset
= U16(offsets
, 2 * i
);
128 for (j
= beg
; j
<= end
; j
++)
129 glyph_code
[(U16(offsets
+ 2 * i
,
130 offset
+ (j
- beg
) * 2) + delta
) & 0xffff] = j
;
132 for (j
= beg
; j
<= end
; j
++)
133 glyph_code
[(j
+ delta
) & 0xffff] = j
;
138 /* parse otf cmap header */
139 static void otf_cmap(void *otf
, void *cmap
)
141 int nrecs
= U16(cmap
, 2);
143 for (i
= 0; i
< nrecs
; i
++) {
144 void *rec
= cmap
+ 4 + i
* 8; /* a cmap record */
145 int plat
= U16(rec
, 0);
146 int enc
= U16(rec
, 2);
147 void *tab
= cmap
+ U32(rec
, 4); /* a cmap subtable */
148 int fmt
= U16(tab
, 0);
149 if (plat
== 3 && enc
== 1 && fmt
== 4)
154 static void otf_post(void *otf
, void *post
)
156 void *post2
; /* version 2.0 header */
157 void *index
; /* glyph name indices */
158 void *names
; /* glyph names */
162 glyph_n
= U16(post2
, 0);
163 if (U32(post
, 0) != 0x20000)
166 names
= index
+ 2 * glyph_n
;
167 for (i
= 0; i
< glyph_n
; i
++) {
168 int idx
= U16(index
, 2 * i
);
170 strcpy(glyph_name
[i
], macset
[idx
]);
172 memcpy(glyph_name
[i
], names
+ cname
+ 1,
174 glyph_name
[i
][U8(names
, cname
)] = '\0';
175 cname
+= U8(names
, cname
) + 1;
180 static void otf_glyf(void *otf
, void *glyf
)
182 void *maxp
= otf_table(otf
, "maxp");
183 void *head
= otf_table(otf
, "head");
184 void *loca
= otf_table(otf
, "loca");
187 int n
= U16(maxp
, 4);
188 int fmt
= U16(head
, 50);
190 for (i
= 0; i
< n
; i
++) {
192 gdat
= glyf
+ U32(loca
, 4 * i
);
193 gdat_next
= glyf
+ U32(loca
, 4 * (i
+ 1));
195 gdat
= glyf
+ U16(loca
, 2 * i
) * 2;
196 gdat_next
= glyf
+ U16(loca
, 2 * (i
+ 1)) * 2;
198 if (gdat
< gdat_next
)
199 for (j
= 0; j
< 4; j
++)
200 glyph_bbox
[i
][j
] = S16(gdat
, 2 + 2 * j
);
204 static void otf_hmtx(void *otf
, void *hmtx
)
206 void *hhea
= otf_table(otf
, "hhea");
210 for (i
= 0; i
< n
; i
++)
211 glyph_wid
[i
] = U16(hmtx
, i
* 4);
212 for (i
= n
; i
< glyph_n
; i
++)
213 glyph_wid
[i
] = glyph_wid
[n
- 1];
216 static void otf_kern(void *otf
, void *kern
)
220 int n
= U16(kern
, 2); /* number of kern subtables */
221 for (i
= 0; i
< n
; i
++) {
222 void *tab
= kern
+ off
; /* a kern subtable */
223 int cov
= U16(tab
, 4);
225 if ((cov
>> 8) == 0 && (cov
& 1)) { /* format 0 */
226 int npairs
= U16(tab
, 6);
227 for (j
= 0; j
< npairs
; j
++) {
228 int c1
= U16(tab
, 14 + 6 * j
);
229 int c2
= U16(tab
, 14 + 6 * j
+ 2);
230 int val
= S16(tab
, 14 + 6 * j
+ 4);
231 trfn_kern(glyph_name
[c1
], glyph_name
[c2
],
238 static int coverage(void *cov
, int *out
)
240 int fmt
= U16(cov
, 0);
246 for (i
= 0; i
< n
; i
++)
247 out
[ncov
++] = U16(cov
, 4 + 2 * i
);
250 for (i
= 0; i
< n
; i
++) {
251 beg
= U16(cov
, 4 + 6 * i
);
252 end
= U16(cov
, 4 + 6 * i
+ 2);
253 for (j
= beg
; j
<= end
; j
++)
260 static int classdef(void *tab
, int *gl
, int *cls
)
262 int fmt
= U16(tab
, 0);
266 int beg
= U16(tab
, 2);
268 for (i
= 0; i
< ngl
; i
++) {
270 cls
[i
] = U16(tab
, 6 + 2 * i
);
275 for (i
= 0; i
< n
; i
++) {
276 int beg
= U16(tab
, 4 + 6 * i
);
277 int end
= U16(tab
, 4 + 6 * i
+ 2);
278 for (j
= beg
; j
<= end
; j
++) {
280 cls
[ngl
] = U16(tab
, 4 + 6 * i
+ 4);
288 static int intcmp(void *v1
, void *v2
)
290 return *(int *) v1
- *(int *) v2
;
293 static int ggrp_make(int *src
, int n
);
295 static int ggrp_class(int *src
, int *cls
, int nsrc
, int id
)
300 for (i
= 0; i
< nsrc
; i
++)
303 qsort(g
, n
, sizeof(g
[0]), (void *) intcmp
);
304 return ggrp_make(g
, n
);
307 static int ggrp_coverage(int *g
, int n
)
309 qsort(g
, n
, sizeof(g
[0]), (void *) intcmp
);
310 return ggrp_make(g
, n
);
313 static int valuerecord_len(int fmt
)
317 for (i
= 0; i
< 8; i
++)
323 static void valuerecord_print(int fmt
, void *rec
)
328 for (i
= 0; i
< 8; i
++) {
329 if (fmt
& (1 << i
)) {
330 vals
[i
] = uwid(S16(rec
, off
));
335 printf(":%+d%+d%+d%+d", vals
[0], vals
[1], vals
[2], vals
[3]);
338 static int valuerecord_small(int fmt
, void *rec
)
342 for (i
= 0; i
< 8; i
++) {
343 if (fmt
& (1 << i
)) {
344 if (abs(uwid(S16(rec
, off
))) >= MAX(1, kmin
))
352 /* single adjustment positioning */
353 static void otf_gpostype1(void *otf
, void *sub
, char *feat
)
355 int fmt
= U16(sub
, 0);
356 int vfmt
= U16(sub
, 4);
359 int vlen
= valuerecord_len(vfmt
);
361 ncov
= coverage(sub
+ U16(sub
, 2), cov
);
363 for (i
= 0; i
< ncov
; i
++) {
364 if (valuerecord_small(vfmt
, sub
+ 6))
366 printf("gpos %s 1 %s", feat
, glyph_name
[cov
[i
]]);
367 valuerecord_print(vfmt
, sub
+ 6);
373 for (i
= 0; i
< nvals
; i
++) {
374 if (valuerecord_small(vfmt
, sub
+ 6))
376 printf("gpos %s 1 %s", feat
, glyph_name
[cov
[i
]]);
377 valuerecord_print(vfmt
, sub
+ 8 + i
* vlen
);
383 /* pair adjustment positioning */
384 static void otf_gpostype2(void *otf
, void *sub
, char *feat
)
386 int fmt
= U16(sub
, 0);
387 int vfmt1
= U16(sub
, 4); /* valuerecord 1 */
388 int vfmt2
= U16(sub
, 6); /* valuerecord 2 */
389 int fmtoff1
, fmtoff2
;
390 int vrlen
; /* the length of vfmt1 and vfmt2 */
392 vrlen
= valuerecord_len(vfmt1
) + valuerecord_len(vfmt2
);
395 int nc1
= U16(sub
, 8);
396 coverage(sub
+ U16(sub
, 2), cov
);
397 for (i
= 0; i
< nc1
; i
++) {
398 void *c2
= sub
+ U16(sub
, 10 + 2 * i
);
399 int nc2
= U16(c2
, 0);
400 for (j
= 0; j
< nc2
; j
++) {
401 int second
= U16(c2
+ 2 + (2 + vrlen
) * j
, 0);
402 fmtoff1
= 2 + (2 + vrlen
) * j
+ 2;
403 fmtoff2
= fmtoff1
+ valuerecord_len(vfmt1
);
404 if (valuerecord_small(vfmt1
, c2
+ fmtoff1
) &&
405 valuerecord_small(vfmt2
, c2
+ fmtoff2
))
407 printf("gpos %s 2", feat
);
408 printf(" %s", glyph_name
[cov
[i
]]);
409 valuerecord_print(vfmt1
, c2
+ fmtoff1
);
410 printf(" %s", glyph_name
[second
]);
411 valuerecord_print(vfmt2
, c2
+ fmtoff2
);
417 int gl1
[NGLYPHS
], gl2
[NGLYPHS
];
418 int cls1
[NGLYPHS
], cls2
[NGLYPHS
];
419 int grp1
[NGLYPHS
], grp2
[NGLYPHS
];
420 int ngl1
= classdef(sub
+ U16(sub
, 8), gl1
, cls1
);
421 int ngl2
= classdef(sub
+ U16(sub
, 10), gl2
, cls2
);
422 int ncls1
= U16(sub
, 12);
423 int ncls2
= U16(sub
, 14);
424 for (i
= 0; i
< ncls1
; i
++)
425 grp1
[i
] = ggrp_class(gl1
, cls1
, ngl1
, i
);
426 for (i
= 0; i
< ncls2
; i
++)
427 grp2
[i
] = ggrp_class(gl2
, cls2
, ngl2
, i
);
428 for (i
= 0; i
< ncls1
; i
++) {
429 for (j
= 0; j
< ncls2
; j
++) {
430 fmtoff1
= 16 + (i
* ncls2
+ j
) * vrlen
;
431 fmtoff2
= fmtoff1
+ valuerecord_len(vfmt1
);
432 if (valuerecord_small(vfmt1
, sub
+ fmtoff1
) &&
433 valuerecord_small(vfmt2
, sub
+ fmtoff2
))
435 printf("gpos %s %d", feat
, 2);
436 printf(" @%d", grp1
[i
]);
437 valuerecord_print(vfmt1
, sub
+ fmtoff1
);
438 printf(" @%d", grp2
[j
]);
439 valuerecord_print(vfmt2
, sub
+ fmtoff2
);
446 /* cursive attachment positioning */
447 static void otf_gpostype3(void *otf
, void *sub
, char *feat
)
449 int fmt
= U16(sub
, 0);
457 coverage(sub
+ U16(sub
, 2), cov
);
461 for (i
= 0; i
< n
; i
++)
462 if (U16(sub
, 6 + 4 * i
))
463 ocov
[ocnt
++] = cov
[i
];
464 for (i
= 0; i
< n
; i
++)
465 if (U16(sub
, 6 + 4 * i
+ 2))
466 icov
[icnt
++] = cov
[i
];
467 igrp
= ggrp_coverage(icov
, icnt
);
468 ogrp
= ggrp_coverage(ocov
, ocnt
);
469 for (i
= 0; i
< n
; i
++) {
470 int prev
= U16(sub
, 6 + 4 * i
);
471 int next
= U16(sub
, 6 + 4 * i
+ 2);
473 int dx
= -uwid(S16(sub
, prev
+ 2));
474 int dy
= -uwid(S16(sub
, prev
+ 4));
476 dx
+= uwid(glyph_wid
[cov
[i
]]);
478 printf("gpos %s 2 @%d %s:%+d%+d%+d%+d\n",
479 feat
, igrp
, glyph_name
[cov
[i
]],
483 int dx
= uwid(S16(sub
, next
+ 2)) - uwid(glyph_wid
[cov
[i
]]);
484 int dy
= uwid(S16(sub
, next
+ 4));
486 dx
+= uwid(glyph_wid
[cov
[i
]]);
488 printf("gpos %s 2 %s @%d:%+d%+d%+d%+d\n",
489 feat
, glyph_name
[cov
[i
]], ogrp
,
495 /* mark-to-base attachment positioning */
496 static void otf_gpostype4(void *otf
, void *sub
, char *feat
)
498 int fmt
= U16(sub
, 0);
499 int mcov
[NGLYPHS
]; /* mark coverage */
500 int bcov
[NGLYPHS
]; /* base coverage */
501 int cgrp
[1024]; /* glyph groups assigned to classes */
502 int bgrp
; /* the group assigned to base glyphs */
503 int mcnt
; /* mark coverage size */
504 int bcnt
; /* base coverage size */
505 int ccnt
; /* class count */
506 void *marks
; /* mark array table */
507 void *bases
; /* base array table */
511 mcnt
= coverage(sub
+ U16(sub
, 2), mcov
);
512 bcnt
= coverage(sub
+ U16(sub
, 4), bcov
);
514 marks
= sub
+ U16(sub
, 8);
515 bases
= sub
+ U16(sub
, 10);
516 bgrp
= ggrp_coverage(bcov
, bcnt
);
517 for (i
= 0; i
< ccnt
; i
++) {
520 for (j
= 0; j
< mcnt
; j
++)
521 if (U16(marks
, 2 + 4 * j
) == i
)
522 grp
[cnt
++] = mcov
[j
];
523 cgrp
[i
] = ggrp_coverage(grp
, cnt
);
525 for (i
= 0; i
< mcnt
; i
++) {
526 void *mark
= marks
+ U16(marks
, 2 + 4 * i
+ 2); /* mark anchor */
527 int dx
= -uwid(S16(mark
, 2));
528 int dy
= -uwid(S16(mark
, 4));
530 dx
+= uwid(glyph_wid
[mcov
[i
]]);
533 printf("gpos %s 2 @%d %s:%+d%+d%+d%+d\n",
534 feat
, bgrp
, glyph_name
[mcov
[i
]], dx
, dy
, 0, 0);
536 for (i
= 0; i
< bcnt
; i
++) {
537 for (j
= 0; j
< ccnt
; j
++) {
538 void *base
= bases
+ U16(bases
, 2 + ccnt
* 2 * i
+ 2 * j
);
539 int dx
= uwid(S16(base
, 2)) - uwid(glyph_wid
[bcov
[i
]]);
540 int dy
= uwid(S16(base
, 4));
542 dx
+= uwid(glyph_wid
[bcov
[i
]]);
545 printf("gpos %s 2 %s @%d:%+d%+d%+d%+d\n",
546 feat
, glyph_name
[bcov
[i
]], cgrp
[j
], dx
, dy
, 0, 0);
553 int bgrp
[GCTXLEN
]; /* backtrack coverage arrays */
554 int igrp
[GCTXLEN
]; /* input coverage arrays */
555 int lgrp
[GCTXLEN
]; /* lookahead coverage arrays*/
556 int bn
, in
, ln
; /* size of b[], i[], l[] */
557 int seqidx
; /* sequence index */
560 static int gctx_len(struct gctx
*ctx
, int patlen
)
562 return ctx
? ctx
->bn
+ ctx
->in
+ ctx
->ln
- patlen
: 0;
565 static void gctx_backtrack(struct gctx
*ctx
)
570 for (i
= 0; i
< ctx
->bn
; i
++)
571 printf(" =@%d", ctx
->bgrp
[i
]);
572 for (i
= 0; i
< ctx
->seqidx
; i
++)
573 printf(" =@%d", ctx
->igrp
[i
]);
576 static void gctx_lookahead(struct gctx
*ctx
, int patlen
)
581 for (i
= ctx
->seqidx
+ patlen
; i
< ctx
->in
; i
++)
582 printf(" =@%d", ctx
->igrp
[i
]);
583 for (i
= 0; i
< ctx
->ln
; i
++)
584 printf(" =@%d", ctx
->lgrp
[i
]);
587 /* single substitution */
588 static void otf_gsubtype1(void *otf
, void *sub
, char *feat
, struct gctx
*ctx
)
591 int fmt
= U16(sub
, 0);
594 ncov
= coverage(sub
+ U16(sub
, 2), cov
);
596 for (i
= 0; i
< ncov
; i
++) {
597 printf("gsub %s %d", feat
, 2 + gctx_len(ctx
, 1));
599 printf(" -%s +%s", glyph_name
[cov
[i
]],
600 glyph_name
[cov
[i
] + S16(sub
, 4)]);
601 gctx_lookahead(ctx
, 1);
607 for (i
= 0; i
< n
; i
++) {
608 printf("gsub %s %d", feat
, 2 + gctx_len(ctx
, 1));
610 printf(" -%s +%s", glyph_name
[cov
[i
]],
611 glyph_name
[U16(sub
, 6 + 2 * i
)]);
612 gctx_lookahead(ctx
, 1);
618 /* alternate substitution */
619 static void otf_gsubtype3(void *otf
, void *sub
, char *feat
, struct gctx
*ctx
)
622 int fmt
= U16(sub
, 0);
626 coverage(sub
+ U16(sub
, 2), cov
);
628 for (i
= 0; i
< n
; i
++) {
629 void *alt
= sub
+ U16(sub
, 6 + 2 * i
);
630 int nalt
= U16(alt
, 0);
631 for (j
= 0; j
< nalt
; j
++) {
632 printf("gsub %s %d", feat
, 2 + gctx_len(ctx
, 1));
634 printf(" -%s +%s", glyph_name
[cov
[i
]],
635 glyph_name
[U16(alt
, 2 + 2 * j
)]);
636 gctx_lookahead(ctx
, 1);
642 /* ligature substitution */
643 static void otf_gsubtype4(void *otf
, void *sub
, char *feat
, struct gctx
*ctx
)
645 int fmt
= U16(sub
, 0);
650 coverage(sub
+ U16(sub
, 2), cov
);
652 for (i
= 0; i
< n
; i
++) {
653 void *set
= sub
+ U16(sub
, 6 + 2 * i
);
654 int nset
= U16(set
, 0);
655 for (j
= 0; j
< nset
; j
++) {
656 void *lig
= set
+ U16(set
, 2 + 2 * j
);
657 int nlig
= U16(lig
, 2);
658 printf("gsub %s %d", feat
, nlig
+ 1 + gctx_len(ctx
, nlig
));
660 printf(" -%s", glyph_name
[cov
[i
]]);
661 for (k
= 0; k
< nlig
- 1; k
++)
662 printf(" -%s", glyph_name
[U16(lig
, 4 + 2 * k
)]);
663 printf(" +%s", glyph_name
[U16(lig
, 0)]);
664 gctx_lookahead(ctx
, nlig
);
670 /* chaining contextual substitution */
671 static void otf_gsubtype6(void *otf
, void *sub
, char *feat
, void *gsub
)
673 struct gctx ctx
= {{0}};
674 void *lookups
= gsub
+ U16(gsub
, 8);
675 int fmt
= U16(sub
, 0);
677 int i
, j
, nsub
, ncov
;
680 otf_unsupported("GSUB", 6, fmt
);
683 ctx
.bn
= U16(sub
, off
);
684 for (i
= 0; i
< ctx
.bn
; i
++) {
685 ncov
= coverage(sub
+ U16(sub
, off
+ 2 + 2 * i
), cov
);
686 ctx
.bgrp
[i
] = ggrp_coverage(cov
, ncov
);
688 off
+= 2 + 2 * ctx
.bn
;
689 ctx
.in
= U16(sub
, off
);
690 for (i
= 0; i
< ctx
.in
; i
++) {
691 ncov
= coverage(sub
+ U16(sub
, off
+ 2 + 2 * i
), cov
);
692 ctx
.igrp
[i
] = ggrp_coverage(cov
, ncov
);
694 off
+= 2 + 2 * ctx
.in
;
695 ctx
.ln
= U16(sub
, off
);
696 for (i
= 0; i
< ctx
.ln
; i
++) {
697 ncov
= coverage(sub
+ U16(sub
, off
+ 2 + 2 * i
), cov
);
698 ctx
.lgrp
[i
] = ggrp_coverage(cov
, ncov
);
700 off
+= 2 + 2 * ctx
.ln
;
701 nsub
= U16(sub
, off
); /* nsub > 1 is not supported */
702 for (i
= 0; i
< nsub
&& i
< 1; i
++) {
703 int lidx
= U16(sub
, off
+ 2 + 4 * i
+ 2);
704 void *lookup
= lookups
+ U16(lookups
, 2 + 2 * lidx
);
705 int ltype
= U16(lookup
, 0);
706 int ntabs
= U16(lookup
, 4);
707 ctx
.seqidx
= U16(sub
, off
+ 2 + 4 * i
);
708 for (j
= 0; j
< ntabs
; j
++) {
709 void *tab
= lookup
+ U16(lookup
, 6 + 2 * j
);
711 if (type
== 7) { /* extension substitution */
713 tab
= tab
+ U32(tab
, 4);
716 otf_gsubtype1(otf
, tab
, feat
, &ctx
);
718 otf_gsubtype3(otf
, tab
, feat
, &ctx
);
720 otf_gsubtype4(otf
, tab
, feat
, &ctx
);
725 /* an otf gsub/gpos lookup */
727 char scrp
[8]; /* script name */
728 char lang
[8]; /* language name */
729 char feat
[8]; /* feature name */
730 int lookup
; /* index into the lookup table */
733 /* parse the given gsub/gpos feature table */
734 static int otf_featrec(void *otf
, void *gtab
, void *featrec
,
735 char *stag
, char *ltag
,
736 struct otflookup
*lookups
, int lookups_n
)
738 void *feats
= gtab
+ U16(gtab
, 6);
739 void *feat
= feats
+ U16(featrec
, 4);
740 int n
= U16(feat
, 2);
742 for (i
= 0; i
< n
; i
++) {
743 int lookup
= U16(feat
, 4 + 2 * i
); /* lookup index */
744 /* do not store features common to all languages in a script */
745 for (j
= 0; j
< lookups_n
; j
++)
746 if (lookups
[j
].lookup
== lookup
&& !lookups
[j
].lang
[0])
747 if (!strcmp(lookups
[j
].scrp
, stag
))
749 if (j
== lookups_n
) {
750 memcpy(lookups
[j
].feat
, featrec
, 4);
751 lookups
[j
].feat
[4] = '\0';
752 strcpy(lookups
[j
].scrp
, stag
);
753 strcpy(lookups
[j
].lang
, ltag
);
754 lookups
[j
].lookup
= U16(feat
, 4 + 2 * i
);
761 /* parse the given language table and its feature tables */
762 static int otf_lang(void *otf
, void *gtab
, void *lang
, char *stag
, char *ltag
,
763 struct otflookup
*lookups
, int lookups_n
)
765 void *feats
= gtab
+ U16(gtab
, 6);
766 int featidx
= U16(lang
, 2);
767 int nfeat
= U16(lang
, 4);
769 if (featidx
!= 0xffff)
770 lookups_n
= otf_featrec(otf
, gtab
, feats
+ 2 + 6 * featidx
,
771 stag
, ltag
, lookups
, lookups_n
);
772 for (i
= 0; i
< nfeat
; i
++)
773 lookups_n
= otf_featrec(otf
, gtab
, feats
+ 2 + 6 * U16(lang
, 6 + 2 * i
),
774 stag
, ltag
, lookups
, lookups_n
);
778 /* return lookup table tag (i.e. liga:latn:ENG); returns a static buffer */
779 static char *lookuptag(struct otflookup
*lu
)
782 sprintf(tag
, "%s:%s", lu
->feat
, lu
->scrp
[0] ? lu
->scrp
: "DFLT");
784 sprintf(strchr(tag
, '\0'), ":%s", lu
->lang
);
788 static int lookupcmp(void *v1
, void *v2
)
790 struct otflookup
*l1
= v1
;
791 struct otflookup
*l2
= v2
;
792 if (strcmp(l1
->scrp
, l2
->scrp
))
793 return strcmp(l1
->scrp
, l2
->scrp
);
794 if (trfn_featrank(l1
->scrp
, l1
->feat
) != trfn_featrank(l1
->scrp
, l2
->feat
))
795 return trfn_featrank(l1
->scrp
, l1
->feat
) - trfn_featrank(l1
->scrp
, l2
->feat
);
796 return l1
->lookup
- l2
->lookup
;
799 /* extract lookup tables for all features of the given gsub/gpos table */
800 static int otf_gtab(void *otf
, void *gpos
, struct otflookup
*lookups
)
802 void *scripts
= gpos
+ U16(gpos
, 4);
803 int nscripts
, nlangs
;
805 char stag
[8], ltag
[8]; /* script and language tags */
808 nscripts
= U16(scripts
, 0);
809 for (i
= 0; i
< nscripts
; i
++) {
810 void *grec
= scripts
+ 2 + 6 * i
;
811 memcpy(stag
, grec
, 4);
813 if (!trfn_script(stag
, nscripts
))
815 script
= scripts
+ U16(grec
, 4);
816 nlangs
= U16(script
, 2);
817 if (U16(script
, 0) && trfn_lang(NULL
, nlangs
+ (U16(script
, 0) != 0)))
818 n
= otf_lang(otf
, gpos
, script
+ U16(script
, 0),
819 stag
, "", lookups
, n
);
820 for (j
= 0; j
< nlangs
; j
++) {
821 void *lrec
= script
+ 4 + 6 * j
;
822 memcpy(ltag
, lrec
, 4);
824 if (trfn_lang(ltag
, nlangs
+ (U16(script
, 0) != 0)))
825 n
= otf_lang(otf
, gpos
, script
+ U16(lrec
, 4),
826 stag
, ltag
, lookups
, n
);
829 qsort(lookups
, n
, sizeof(lookups
[0]), (void *) lookupcmp
);
833 static void otf_gpos(void *otf
, void *gpos
)
835 struct otflookup lookups
[NLOOKUPS
];
836 void *lookuplist
= gpos
+ U16(gpos
, 8);
837 int nlookups
= otf_gtab(otf
, gpos
, lookups
);
839 for (i
= 0; i
< nlookups
; i
++) {
840 void *lookup
= lookuplist
+ U16(lookuplist
, 2 + 2 * lookups
[i
].lookup
);
841 int ltype
= U16(lookup
, 0);
842 int ntabs
= U16(lookup
, 4);
843 char *tag
= lookuptag(&lookups
[i
]);
844 for (j
= 0; j
< ntabs
; j
++) {
845 void *tab
= lookup
+ U16(lookup
, 6 + 2 * j
);
847 if (type
== 9) { /* extension positioning */
849 tab
= tab
+ U32(tab
, 4);
853 otf_gpostype1(otf
, tab
, tag
);
856 otf_gpostype2(otf
, tab
, tag
);
859 otf_gpostype3(otf
, tab
, tag
);
862 otf_gpostype4(otf
, tab
, tag
);
865 otf_unsupported("GPOS", type
, 0);
871 static void otf_gsub(void *otf
, void *gsub
)
873 struct otflookup lookups
[NLOOKUPS
];
874 void *lookuplist
= gsub
+ U16(gsub
, 8);
875 int nlookups
= otf_gtab(otf
, gsub
, lookups
);
877 for (i
= 0; i
< nlookups
; i
++) {
878 void *lookup
= lookuplist
+ U16(lookuplist
, 2 + 2 * lookups
[i
].lookup
);
879 int ltype
= U16(lookup
, 0);
880 int ntabs
= U16(lookup
, 4);
881 char *tag
= lookuptag(&lookups
[i
]);
882 for (j
= 0; j
< ntabs
; j
++) {
883 void *tab
= lookup
+ U16(lookup
, 6 + 2 * j
);
885 if (type
== 7) { /* extension substitution */
887 tab
= tab
+ U32(tab
, 4);
891 otf_gsubtype1(otf
, tab
, tag
, NULL
);
894 otf_gsubtype3(otf
, tab
, tag
, NULL
);
897 otf_gsubtype4(otf
, tab
, tag
, NULL
);
900 otf_gsubtype6(otf
, tab
, tag
, gsub
);
903 otf_unsupported("GSUB", type
, 0);
909 /* read a cff offset, which has sz bytes */
910 static int cff_int(void *tab
, int off
, int sz
)
914 for (i
= 0; i
< sz
; i
++)
915 n
= n
* 256 + U8(tab
, off
+ i
);
919 /* cff dict operand/operator */
920 static int cff_op(void *tab
, int off
, int *val
)
922 int b0
= U8(tab
, off
);
924 if (b0
>= 32 && b0
<= 246) {
928 if (b0
>= 247 && b0
<= 250) {
929 *val
= (b0
- 247) * 256 + U8(tab
, off
+ 1) + 108;
932 if (b0
>= 251 && b0
<= 254) {
933 *val
= -(b0
- 251) * 256 - U8(tab
, off
+ 1) - 108;
937 *val
= (U8(tab
, off
+ 1) << 8) | U8(tab
, off
+ 2);
941 *val
= (U8(tab
, off
+ 1) << 24) | (U8(tab
, off
+ 2) << 16) |
942 (U8(tab
, off
+ 3) << 8) | U8(tab
, off
+ 4);
946 for (i
= 1; i
< 32; i
++) {
947 int nib
= U8(tab
, off
+ i
);
948 if ((nib
& 0x0f) == 0x0f || (nib
& 0xf0) == 0xf0)
958 static int cffidx_cnt(void *idx
)
963 static void *cffidx_get(void *idx
, int i
)
965 int cnt
= U16(idx
, 0);
967 return idx
+ 3 + (cnt
+ 1) * sz
- 1 + cff_int(idx
, 3 + i
* sz
, sz
);
970 static int cffidx_len(void *idx
, int i
)
972 return cffidx_get(idx
, i
+ 1) - cffidx_get(idx
, i
);
975 static void *cffidx_end(void *idx
)
977 return cffidx_get(idx
, cffidx_cnt(idx
));
980 /* obtain the value of the given key from a cff dict */
981 static int cffdict_get(void *dict
, int len
, int key
, int *args
)
986 /* operators: keys (one or two bytes); operands: values */
990 memmove(args
+ 1, args
+ 0, 3 * sizeof(args
[0]));
993 off
+= cff_op(dict
, off
, &op
);
994 if (op
== 12) { /* two-byte operator */
995 off
+= cff_op(dict
, off
, &op
);
1004 static void cff_char(void *stridx
, int id
, char *dst
)
1008 strcpy(dst
, stdset
[id
]);
1012 len
= cffidx_len(stridx
, id
);
1013 memcpy(dst
, cffidx_get(stridx
, id
), len
);
1017 static void otf_cff(void *otf
, void *cff
)
1019 void *nameidx
; /* name index */
1020 void *topidx
; /* top dict index */
1021 void *stridx
; /* string idx */
1022 void *chridx
; /* charstrings index */
1023 void *charset
; /* charset offset of top dict table */
1026 if (U8(cff
, 0) != 1)
1028 nameidx
= cff
+ U8(cff
, 2);
1029 topidx
= cffidx_end(nameidx
);
1030 if (cffidx_cnt(nameidx
) < 1)
1032 stridx
= cffidx_end(topidx
);
1033 chridx
= cff
+ cffdict_get(cffidx_get(topidx
, 0),
1034 cffidx_len(topidx
, 0), 17, NULL
);
1035 charset
= cff
+ cffdict_get(cffidx_get(topidx
, 0),
1036 cffidx_len(topidx
, 0), 15, NULL
);
1037 glyph_n
= cffidx_cnt(chridx
);
1038 strcpy(glyph_name
[0], ".notdef");
1039 if (U8(charset
, 0) == 0) {
1040 for (i
= 0; i
< glyph_n
; i
++)
1041 cff_char(stridx
, U16(charset
, 1 + i
* 2),
1044 if (U8(charset
, 0) == 1 || U8(charset
, 0) == 2) {
1046 int sz
= U8(charset
, 0) == 1 ? 3 : 4;
1047 for (i
= 0; g
< glyph_n
; i
++) {
1048 int sid
= U16(charset
, 1 + i
* sz
);
1049 int cnt
= cff_int(charset
, 1 + i
* sz
+ 2, sz
- 2);
1050 for (j
= 0; j
<= cnt
&& g
< glyph_n
; j
++) {
1051 cff_char(stridx
, sid
+ j
, glyph_name
[g
]);
1056 /* use font bbox for all glyphs */
1057 cffdict_get(cffidx_get(topidx
, 0), cffidx_len(topidx
, 0), 5, bbox
);
1058 for (i
= 1; i
< glyph_n
; i
++)
1059 for (j
= 0; j
< 4; j
++)
1060 glyph_bbox
[i
][j
] = bbox
[3 - j
];
1063 static void *otf_input(int fd
)
1065 struct sbuf
*sb
= sbuf_make();
1068 while ((nr
= read(fd
, buf
, sizeof(buf
))) > 0)
1069 sbuf_mem(sb
, buf
, nr
);
1070 return sbuf_done(sb
);
1073 static char *otf_buf
;
1078 otf_buf
= otf_input(0);
1079 upm
= U16(otf_table(otf_buf
, "head"), 18);
1080 otf_name(otf_buf
, otf_table(otf_buf
, "name"));
1081 otf_cmap(otf_buf
, otf_table(otf_buf
, "cmap"));
1082 otf_post(otf_buf
, otf_table(otf_buf
, "post"));
1083 if (otf_table(otf_buf
, "glyf"))
1084 otf_glyf(otf_buf
, otf_table(otf_buf
, "glyf"));
1085 if (otf_table(otf_buf
, "CFF "))
1086 otf_cff(otf_buf
, otf_table(otf_buf
, "CFF "));
1087 otf_hmtx(otf_buf
, otf_table(otf_buf
, "hmtx"));
1088 for (i
= 0; i
< glyph_n
; i
++) {
1089 trfn_char(glyph_name
[i
], -1,
1090 glyph_code
[i
] != 0xffff ? glyph_code
[i
] : 0,
1092 owid(glyph_bbox
[i
][0]), owid(glyph_bbox
[i
][1]),
1093 owid(glyph_bbox
[i
][2]), owid(glyph_bbox
[i
][3]));
1095 if (otf_table(otf_buf
, "kern"))
1096 otf_kern(otf_buf
, otf_table(otf_buf
, "kern"));
1100 void otf_feat(int r
, int k
, int w
)
1105 if (otf_table(otf_buf
, "GSUB"))
1106 otf_gsub(otf_buf
, otf_table(otf_buf
, "GSUB"));
1107 if (otf_table(otf_buf
, "GPOS"))
1108 otf_gpos(otf_buf
, otf_table(otf_buf
, "GPOS"));
1112 static int *ggrp_g
[NGRPS
];
1113 static int ggrp_len
[NGRPS
];
1116 static int ggrp_find(int *src
, int n
)
1119 for (i
= 0; i
< ggrp_n
; i
++) {
1120 if (ggrp_len
[i
] == n
) {
1121 for (j
= 0; j
< n
; j
++)
1122 if (src
[j
] != ggrp_g
[i
][j
])
1131 static int ggrp_make(int *src
, int n
)
1133 int id
= ggrp_find(src
, n
);
1138 ggrp_g
[id
] = malloc(n
* sizeof(ggrp_g
[id
][0]));
1140 for (i
= 0; i
< n
; i
++)
1141 ggrp_g
[id
][i
] = src
[i
];
1142 printf("ggrp %d %d", id
, n
);
1143 for (i
= 0; i
< n
; i
++)
1144 printf(" %s", glyph_name
[src
[i
]]);
1149 static char *macset
[] = {
1150 ".notdef", ".null", "nonmarkingreturn", "space", "exclam",
1151 "quotedbl", "numbersign", "dollar", "percent", "ampersand",
1152 "quotesingle", "parenleft", "parenright", "asterisk", "plus",
1153 "comma", "hyphen", "period", "slash", "zero",
1154 "one", "two", "three", "four", "five",
1155 "six", "seven", "eight", "nine", "colon",
1156 "semicolon", "less", "equal", "greater", "question",
1157 "at", "A", "B", "C", "D",
1158 "E", "F", "G", "H", "I",
1159 "J", "K", "L", "M", "N",
1160 "O", "P", "Q", "R", "S",
1161 "T", "U", "V", "W", "X",
1162 "Y", "Z", "bracketleft", "backslash", "bracketright",
1163 "asciicircum", "underscore", "grave", "a", "b",
1164 "c", "d", "e", "f", "g",
1165 "h", "i", "j", "k", "l",
1166 "m", "n", "o", "p", "q",
1167 "r", "s", "t", "u", "v",
1168 "w", "x", "y", "z", "braceleft",
1169 "bar", "braceright", "asciitilde", "Adieresis", "Aring",
1170 "Ccedilla", "Eacute", "Ntilde", "Odieresis", "Udieresis",
1171 "aacute", "agrave", "acircumflex", "adieresis", "atilde",
1172 "aring", "ccedilla", "eacute", "egrave", "ecircumflex",
1173 "edieresis", "iacute", "igrave", "icircumflex", "idieresis",
1174 "ntilde", "oacute", "ograve", "ocircumflex", "odieresis",
1175 "otilde", "uacute", "ugrave", "ucircumflex", "udieresis",
1176 "dagger", "degree", "cent", "sterling", "section",
1177 "bullet", "paragraph", "germandbls", "registered", "copyright",
1178 "trademark", "acute", "dieresis", "notequal", "AE",
1179 "Oslash", "infinity", "plusminus", "lessequal", "greaterequal",
1180 "yen", "mu", "partialdiff", "summation", "product",
1181 "pi", "integral", "ordfeminine", "ordmasculine", "Omega",
1182 "ae", "oslash", "questiondown", "exclamdown", "logicalnot",
1183 "radical", "florin", "approxequal", "Delta", "guillemotleft",
1184 "guillemotright", "ellipsis", "nonbreakingspace", "Agrave", "Atilde",
1185 "Otilde", "OE", "oe", "endash", "emdash",
1186 "quotedblleft", "quotedblright", "quoteleft", "quoteright", "divide",
1187 "lozenge", "ydieresis", "Ydieresis", "fraction", "currency",
1188 "guilsinglleft", "guilsinglright", "fi", "fl", "daggerdbl",
1189 "periodcentered", "quotesinglbase", "quotedblbase", "perthousand", "Acircumflex",
1190 "Ecircumflex", "Aacute", "Edieresis", "Egrave", "Iacute",
1191 "Icircumflex", "Idieresis", "Igrave", "Oacute", "Ocircumflex",
1192 "apple", "Ograve", "Uacute", "Ucircumflex", "Ugrave",
1193 "dotlessi", "circumflex", "tilde", "macron", "breve",
1194 "dotaccent", "ring", "cedilla", "hungarumlaut", "ogonek",
1195 "caron", "Lslash", "lslash", "Scaron", "scaron",
1196 "Zcaron", "zcaron", "brokenbar", "Eth", "eth",
1197 "Yacute", "yacute", "Thorn", "thorn", "minus",
1198 "multiply", "onesuperior", "twosuperior", "threesuperior", "onehalf",
1199 "onequarter", "threequarters", "franc", "Gbreve", "gbreve",
1200 "Idotaccent", "Scedilla", "scedilla", "Cacute", "cacute",
1201 "Ccaron", "ccaron", "dcroat",
1204 static char *stdset
[] = {
1205 ".notdef", "space", "exclam", "quotedbl", "numbersign",
1206 "dollar", "percent", "ampersand", "quoteright", "parenleft",
1207 "parenright", "asterisk", "plus", "comma", "hyphen",
1208 "period", "slash", "zero", "one", "two",
1209 "three", "four", "five", "six", "seven",
1210 "eight", "nine", "colon", "semicolon", "less",
1211 "equal", "greater", "question", "at", "A",
1212 "B", "C", "D", "E", "F",
1213 "G", "H", "I", "J", "K",
1214 "L", "M", "N", "O", "P",
1215 "Q", "R", "S", "T", "U",
1216 "V", "W", "X", "Y", "Z",
1217 "bracketleft", "backslash", "bracketright", "asciicircum", "underscore",
1218 "quoteleft", "a", "b", "c", "d",
1219 "e", "f", "g", "h", "i",
1220 "j", "k", "l", "m", "n",
1221 "o", "p", "q", "r", "s",
1222 "t", "u", "v", "w", "x",
1223 "y", "z", "braceleft", "bar", "braceright",
1224 "asciitilde", "exclamdown", "cent", "sterling", "fraction",
1225 "yen", "florin", "section", "currency", "quotesingle",
1226 "quotedblleft", "guillemotleft", "guilsinglleft", "guilsinglright", "fi",
1227 "fl", "endash", "dagger", "daggerdbl", "periodcentered",
1228 "paragraph", "bullet", "quotesinglbase", "quotedblbase", "quotedblright",
1229 "guillemotright", "ellipsis", "perthousand", "questiondown", "grave",
1230 "acute", "circumflex", "tilde", "macron", "breve",
1231 "dotaccent", "dieresis", "ring", "cedilla", "hungarumlaut",
1232 "ogonek", "caron", "emdash", "AE", "ordfeminine",
1233 "Lslash", "Oslash", "OE", "ordmasculine", "ae",
1234 "dotlessi", "lslash", "oslash", "oe", "germandbls",
1235 "onesuperior", "logicalnot", "mu", "trademark", "Eth",
1236 "onehalf", "plusminus", "Thorn", "onequarter", "divide",
1237 "brokenbar", "degree", "thorn", "threequarters", "twosuperior",
1238 "registered", "minus", "eth", "multiply", "threesuperior",
1239 "copyright", "Aacute", "Acircumflex", "Adieresis", "Agrave",
1240 "Aring", "Atilde", "Ccedilla", "Eacute", "Ecircumflex",
1241 "Edieresis", "Egrave", "Iacute", "Icircumflex", "Idieresis",
1242 "Igrave", "Ntilde", "Oacute", "Ocircumflex", "Odieresis",
1243 "Ograve", "Otilde", "Scaron", "Uacute", "Ucircumflex",
1244 "Udieresis", "Ugrave", "Yacute", "Ydieresis", "Zcaron",
1245 "aacute", "acircumflex", "adieresis", "agrave", "aring",
1246 "atilde", "ccedilla", "eacute", "ecircumflex", "edieresis",
1247 "egrave", "iacute", "icircumflex", "idieresis", "igrave",
1248 "ntilde", "oacute", "ocircumflex", "odieresis", "ograve",
1249 "otilde", "scaron", "uacute", "ucircumflex", "udieresis",
1250 "ugrave", "yacute", "ydieresis", "zcaron", "exclamsmall",
1251 "Hungarumlautsmall", "dollaroldstyle", "dollarsuperior", "ampersandsmall", "Acutesmall",
1252 "parenleftsuperior", "parenrightsuperior", "twodotenleader", "onedotenleader", "zerooldstyle",
1253 "oneoldstyle", "twooldstyle", "threeoldstyle", "fouroldstyle", "fiveoldstyle",
1254 "sixoldstyle", "sevenoldstyle", "eightoldstyle", "nineoldstyle", "commasuperior",
1255 "threequartersemdash", "periodsuperior", "questionsmall", "asuperior", "bsuperior",
1256 "centsuperior", "dsuperior", "esuperior", "isuperior", "lsuperior",
1257 "msuperior", "nsuperior", "osuperior", "rsuperior", "ssuperior",
1258 "tsuperior", "ff", "ffi", "ffl", "parenleftinferior",
1259 "parenrightinferior", "Circumflexsmall", "hyphensuperior", "Gravesmall", "Asmall",
1260 "Bsmall", "Csmall", "Dsmall", "Esmall", "Fsmall",
1261 "Gsmall", "Hsmall", "Ismall", "Jsmall", "Ksmall",
1262 "Lsmall", "Msmall", "Nsmall", "Osmall", "Psmall",
1263 "Qsmall", "Rsmall", "Ssmall", "Tsmall", "Usmall",
1264 "Vsmall", "Wsmall", "Xsmall", "Ysmall", "Zsmall",
1265 "colonmonetary", "onefitted", "rupiah", "Tildesmall", "exclamdownsmall",
1266 "centoldstyle", "Lslashsmall", "Scaronsmall", "Zcaronsmall", "Dieresissmall",
1267 "Brevesmall", "Caronsmall", "Dotaccentsmall", "Macronsmall", "figuredash",
1268 "hypheninferior", "Ogoneksmall", "Ringsmall", "Cedillasmall", "questiondownsmall",
1269 "oneeighth", "threeeighths", "fiveeighths", "seveneighths", "onethird",
1270 "twothirds", "zerosuperior", "foursuperior", "fivesuperior", "sixsuperior",
1271 "sevensuperior", "eightsuperior", "ninesuperior", "zeroinferior", "oneinferior",
1272 "twoinferior", "threeinferior", "fourinferior", "fiveinferior", "sixinferior",
1273 "seveninferior", "eightinferior", "nineinferior", "centinferior", "dollarinferior",
1274 "periodinferior", "commainferior", "Agravesmall", "Aacutesmall", "Acircumflexsmall",
1275 "Atildesmall", "Adieresissmall", "Aringsmall", "AEsmall", "Ccedillasmall",
1276 "Egravesmall", "Eacutesmall", "Ecircumflexsmall", "Edieresissmall", "Igravesmall",
1277 "Iacutesmall", "Icircumflexsmall", "Idieresissmall", "Ethsmall", "Ntildesmall",
1278 "Ogravesmall", "Oacutesmall", "Ocircumflexsmall", "Otildesmall", "Odieresissmall",
1279 "OEsmall", "Oslashsmall", "Ugravesmall", "Uacutesmall", "Ucircumflexsmall",
1280 "Udieresissmall", "Yacutesmall", "Thornsmall", "Ydieresissmall", "001.000",
1281 "001.001", "001.002", "001.003", "Black", "Bold",
1282 "Book", "Light", "Medium", "Regular", "Roman",