otf: mark-to-base attachment positioning GPOS subtable
[neatmkfn.git] / otf.c
blob629c531d7b725012d150c6220b7e68de3cf178df
1 #include <arpa/inet.h>
2 #include <errno.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <unistd.h>
7 #include "trfn.h"
9 #define NGLYPHS (1 << 14)
10 #define NLOOKUPS (1 << 12)
11 #define GNLEN (64)
12 #define BUFLEN (1 << 23)
13 #define NGRPS 2048
14 #define MAX(a, b) ((a) < (b) ? (b) : (a))
16 #define U32(buf, off) (htonl(*(u32 *) ((buf) + (off))))
17 #define U16(buf, off) (htons(*(u16 *) ((buf) + (off))))
18 #define U8(buf, off) (*(u8 *) ((buf) + (off)))
19 #define S16(buf, off) ((s16) htons(*(u16 *) ((buf) + (off))))
20 #define S32(buf, off) ((s32) htonl(*(u32 *) ((buf) + (off))))
22 #define GCTXLEN 16 /* number of context backtrack coverage arrays */
24 typedef unsigned int u32;
25 typedef unsigned short u16;
26 typedef unsigned char u8;
27 typedef int s32;
28 typedef short s16;
30 static char glyph_name[NGLYPHS][GNLEN];
31 static int glyph_code[NGLYPHS];
32 static int glyph_bbox[NGLYPHS][4];
33 static int glyph_wid[NGLYPHS];
34 static int glyph_n;
35 static int upm; /* units per em */
36 static int res; /* device resolution */
37 static int kmin; /* minimum kerning value */
38 static int warn;
40 static char *macset[];
42 static int owid(int w)
44 return (w < 0 ? w * 1000 - upm / 2 : w * 1000 + upm / 2) / upm;
47 static int uwid(int w)
49 int d = 7200 / res;
50 return (w < 0 ? owid(w) - d / 2 : owid(w) + d / 2) / d;
53 /* report unsupported otf tables */
54 static void otf_unsupported(char *sub, int type, int fmt)
56 if (warn) {
57 fprintf(stderr, "neatmkfn: unsupported %s lookup %d", sub, type);
58 if (fmt > 0)
59 fprintf(stderr, " format %d", fmt);
60 fprintf(stderr, "\n");
64 /* find the otf table with the given name */
65 static void *otf_table(void *otf, char *name)
67 int nrecs = U16(otf, 4);
68 int i;
69 for (i = 0; i < nrecs; i++) {
70 void *rec = otf + 12 + i * 16; /* an otf table record */
71 if (!strncmp(rec, name, 4))
72 return otf + U32(rec, 8);
74 return NULL;
77 /* obtain postscript font name from name table */
78 static void otf_name(void *otf, void *tab)
80 char name[256];
81 void *str = tab + U16(tab, 4); /* storage area */
82 int n = U16(tab, 2); /* number of name records */
83 int i;
84 for (i = 0; i < n; i++) {
85 void *rec = tab + 6 + 12 * i;
86 int pid = U16(rec, 0); /* platform id */
87 int eid = U16(rec, 2); /* encoding id */
88 int lid = U16(rec, 4); /* language id */
89 int nid = U16(rec, 6); /* name id */
90 int len = U16(rec, 8); /* string length */
91 int off = U16(rec, 10); /* string offset */
92 if (pid == 1 && eid == 0 && lid == 0 && nid == 6) {
93 memcpy(name, str + off, len);
94 name[len] = '\0';
95 trfn_psfont(name);
100 /* parse otf cmap format 4 subtable */
101 static void otf_cmap4(void *otf, void *cmap4)
103 int nsegs;
104 void *ends, *begs, *deltas, *offsets;
105 int beg, end, delta, offset;
106 int i, j;
107 nsegs = U16(cmap4, 6) / 2;
108 ends = cmap4 + 14;
109 begs = ends + 2 * nsegs + 2;
110 deltas = begs + 2 * nsegs;
111 offsets = deltas + 2 * nsegs;
112 for (i = 0; i < nsegs; i++) {
113 beg = U16(begs, 2 * i);
114 end = U16(ends, 2 * i);
115 delta = U16(deltas, 2 * i);
116 offset = U16(offsets, 2 * i);
117 if (offset) {
118 for (j = beg; j <= end; j++)
119 glyph_code[(U16(offsets + 2 * i,
120 offset + (j - beg) * 2) + delta) & 0xffff] = j;
121 } else {
122 for (j = beg; j <= end; j++)
123 glyph_code[(j + delta) & 0xffff] = j;
128 /* parse otf cmap header */
129 static void otf_cmap(void *otf, void *cmap)
131 int nrecs = U16(cmap, 2);
132 int i;
133 for (i = 0; i < nrecs; i++) {
134 void *rec = cmap + 4 + i * 8; /* a cmap record */
135 int plat = U16(rec, 0);
136 int enc = U16(rec, 2);
137 void *tab = cmap + U32(rec, 4); /* a cmap subtable */
138 int fmt = U16(tab, 0);
139 if (plat == 3 && enc == 1 && fmt == 4)
140 otf_cmap4(otf, tab);
144 static void otf_post(void *otf, void *post)
146 void *post2; /* version 2.0 header */
147 void *index; /* glyph name indices */
148 void *names; /* glyph names */
149 int cname = 0;
150 int i;
151 if (U32(post, 0) != 0x00020000)
152 return;
153 post2 = post + 32;
154 glyph_n = U16(post2, 0);
155 index = post2 + 2;
156 names = index + 2 * glyph_n;
157 for (i = 0; i < glyph_n; i++) {
158 int idx = U16(index, 2 * i);
159 if (idx <= 257) {
160 strcpy(glyph_name[i], macset[idx]);
161 } else {
162 memcpy(glyph_name[i], names + cname + 1,
163 U8(names, cname));
164 glyph_name[i][U8(names, cname)] = '\0';
165 cname += U8(names, cname) + 1;
170 static void otf_glyf(void *otf, void *glyf)
172 void *maxp = otf_table(otf, "maxp");
173 void *head = otf_table(otf, "head");
174 void *loca = otf_table(otf, "loca");
175 void *gdat;
176 void *gdat_next;
177 int n = U16(maxp, 4);
178 int fmt = U16(head, 50);
179 int i, j;
180 for (i = 0; i < n; i++) {
181 if (fmt) {
182 gdat = glyf + U32(loca, 4 * i);
183 gdat_next = glyf + U32(loca, 4 * (i + 1));
184 } else {
185 gdat = glyf + U16(loca, 2 * i) * 2;
186 gdat_next = glyf + U16(loca, 2 * (i + 1)) * 2;
188 if (gdat < gdat_next)
189 for (j = 0; j < 4; j++)
190 glyph_bbox[i][j] = S16(gdat, 2 + 2 * j);
194 static void otf_hmtx(void *otf, void *hmtx)
196 void *hhea = otf_table(otf, "hhea");
197 int n;
198 int i;
199 n = U16(hhea, 34);
200 for (i = 0; i < n; i++)
201 glyph_wid[i] = U16(hmtx, i * 4);
202 for (i = n; i < glyph_n; i++)
203 glyph_wid[i] = glyph_wid[n - 1];
206 static void otf_kern(void *otf, void *kern)
208 int off = 4;
209 int i, j;
210 int n = U16(kern, 2); /* number of kern subtables */
211 for (i = 0; i < n; i++) {
212 void *tab = kern + off; /* a kern subtable */
213 int cov = U16(tab, 4);
214 off += U16(tab, 2);
215 if ((cov >> 8) == 0 && (cov & 1)) { /* format 0 */
216 int npairs = U16(tab, 6);
217 for (j = 0; j < npairs; j++) {
218 int c1 = U16(tab, 14 + 6 * j);
219 int c2 = U16(tab, 14 + 6 * j + 2);
220 int val = S16(tab, 14 + 6 * j + 4);
221 trfn_kern(glyph_name[c1], glyph_name[c2],
222 owid(val));
228 static int coverage(void *cov, int *out)
230 int fmt = U16(cov, 0);
231 int n = U16(cov, 2);
232 int beg, end;
233 int ncov = 0;
234 int i, j;
235 if (fmt == 1) {
236 for (i = 0; i < n; i++)
237 out[ncov++] = U16(cov, 4 + 2 * i);
239 if (fmt == 2) {
240 for (i = 0; i < n; i++) {
241 beg = U16(cov, 4 + 6 * i);
242 end = U16(cov, 4 + 6 * i + 2);
243 for (j = beg; j <= end; j++)
244 out[ncov++] = j;
247 return ncov;
250 static int classdef(void *tab, int *gl, int *cls)
252 int fmt = U16(tab, 0);
253 int ngl = 0;
254 int i, j;
255 if (fmt == 1) {
256 int beg = U16(tab, 2);
257 ngl = U16(tab, 4);
258 for (i = 0; i < ngl; i++) {
259 gl[i] = beg + i;
260 cls[i] = U16(tab, 6 + 2 * i);
263 if (fmt == 2) {
264 int n = U16(tab, 2);
265 for (i = 0; i < n; i++) {
266 int beg = U16(tab, 4 + 6 * i);
267 int end = U16(tab, 4 + 6 * i + 2);
268 for (j = beg; j <= end; j++) {
269 gl[ngl] = j;
270 cls[ngl] = U16(tab, 4 + 6 * i + 4);
271 ngl++;
275 return ngl;
278 static int intcmp(void *v1, void *v2)
280 return *(int *) v1 - *(int *) v2;
283 int ggrp_make(int *src, int n);
285 static int ggrp_class(int *src, int *cls, int nsrc, int id)
287 int g[NGLYPHS];
288 int n = 0;
289 int i;
290 for (i = 0; i < nsrc; i++)
291 if (cls[i] == id)
292 g[n++] = src[i];
293 qsort(g, n, sizeof(g[0]), (void *) intcmp);
294 return ggrp_make(g, n);
297 static int ggrp_coverage(int *g, int n)
299 qsort(g, n, sizeof(g[0]), (void *) intcmp);
300 return ggrp_make(g, n);
303 static int valuerecord_len(int fmt)
305 int off = 0;
306 int i;
307 for (i = 0; i < 8; i++)
308 if (fmt & (1 << i))
309 off += 2;
310 return off;
313 static void valuerecord_print(int fmt, void *rec)
315 int vals[8] = {0};
316 int off = 0;
317 int i;
318 for (i = 0; i < 8; i++) {
319 if (fmt & (1 << i)) {
320 vals[i] = uwid(S16(rec, off));
321 off += 2;
324 if (fmt)
325 printf(":%+d%+d%+d%+d", vals[0], vals[1], vals[2], vals[3]);
328 static int valuerecord_small(int fmt, void *rec)
330 int off = 0;
331 int i;
332 for (i = 0; i < 8; i++) {
333 if (fmt & (1 << i)) {
334 if (abs(uwid(S16(rec, off))) >= MAX(1, kmin))
335 return 0;
336 off += 2;
339 return 1;
342 /* single adjustment positioning */
343 static void otf_gpostype1(void *otf, void *sub, char *feat)
345 int fmt = U16(sub, 0);
346 int vfmt = U16(sub, 4);
347 int cov[NGLYPHS];
348 int ncov, nvals;
349 int vlen = valuerecord_len(vfmt);
350 int i;
351 ncov = coverage(sub + U16(sub, 2), cov);
352 if (fmt == 1) {
353 for (i = 0; i < ncov; i++) {
354 if (valuerecord_small(vfmt, sub + 6))
355 continue;
356 printf("gpos %s 1 %s", feat, glyph_name[cov[i]]);
357 valuerecord_print(vfmt, sub + 6);
358 printf("\n");
361 if (fmt == 2) {
362 nvals = U16(sub, 6);
363 for (i = 0; i < nvals; i++) {
364 if (valuerecord_small(vfmt, sub + 6))
365 continue;
366 printf("gpos %s 1 %s", feat, glyph_name[cov[i]]);
367 valuerecord_print(vfmt, sub + 8 + i * vlen);
368 printf("\n");
373 /* pair adjustment positioning */
374 static void otf_gpostype2(void *otf, void *sub, char *feat)
376 int fmt = U16(sub, 0);
377 int vfmt1 = U16(sub, 4); /* valuerecord 1 */
378 int vfmt2 = U16(sub, 6); /* valuerecord 2 */
379 int fmtoff1, fmtoff2;
380 int vrlen; /* the length of vfmt1 and vfmt2 */
381 int i, j;
382 vrlen = valuerecord_len(vfmt1) + valuerecord_len(vfmt2);
383 if (fmt == 1) {
384 int cov[NGLYPHS];
385 int nc1 = U16(sub, 8);
386 coverage(sub + U16(sub, 2), cov);
387 for (i = 0; i < nc1; i++) {
388 void *c2 = sub + U16(sub, 10 + 2 * i);
389 int nc2 = U16(c2, 0);
390 for (j = 0; j < nc2; j++) {
391 int second = U16(c2 + 2 + (2 + vrlen) * j, 0);
392 fmtoff1 = 2 + (2 + vrlen) * j + 2;
393 fmtoff2 = fmtoff1 + valuerecord_len(vfmt1);
394 if (valuerecord_small(vfmt1, c2 + fmtoff1) &&
395 valuerecord_small(vfmt2, c2 + fmtoff2))
396 continue;
397 printf("gpos %s 2", feat);
398 printf(" %s", glyph_name[cov[i]]);
399 valuerecord_print(vfmt1, c2 + fmtoff1);
400 printf(" %s", glyph_name[second]);
401 valuerecord_print(vfmt2, c2 + fmtoff2);
402 printf("\n");
406 if (fmt == 2) {
407 int gl1[NGLYPHS], gl2[NGLYPHS];
408 int cls1[NGLYPHS], cls2[NGLYPHS];
409 int grp1[NGLYPHS], grp2[NGLYPHS];
410 int ngl1 = classdef(sub + U16(sub, 8), gl1, cls1);
411 int ngl2 = classdef(sub + U16(sub, 10), gl2, cls2);
412 int ncls1 = U16(sub, 12);
413 int ncls2 = U16(sub, 14);
414 for (i = 0; i < ncls1; i++)
415 grp1[i] = ggrp_class(gl1, cls1, ngl1, i);
416 for (i = 0; i < ncls2; i++)
417 grp2[i] = ggrp_class(gl2, cls2, ngl2, i);
418 for (i = 0; i < ncls1; i++) {
419 for (j = 0; j < ncls2; j++) {
420 fmtoff1 = 16 + (i * ncls2 + j) * vrlen;
421 fmtoff2 = fmtoff1 + valuerecord_len(vfmt1);
422 if (valuerecord_small(vfmt1, sub + fmtoff1) &&
423 valuerecord_small(vfmt2, sub + fmtoff2))
424 continue;
425 printf("gpos %s %d", feat, 2);
426 printf(" @%d", grp1[i]);
427 valuerecord_print(vfmt1, sub + fmtoff1);
428 printf(" @%d", grp2[j]);
429 valuerecord_print(vfmt2, sub + fmtoff2);
430 printf("\n");
436 /* cursive attachment positioning */
437 static void otf_gpostype3(void *otf, void *sub, char *feat)
439 int fmt = U16(sub, 0);
440 int cov[NGLYPHS];
441 int i, n;
442 coverage(sub + U16(sub, 2), cov);
443 if (fmt != 1)
444 return;
445 n = U16(sub, 4);
446 for (i = 0; i < n; i++) {
447 int prev = U16(sub, 6 + 4 * i);
448 int next = U16(sub, 6 + 4 * i + 2);
449 printf("gcur %s %s", feat, glyph_name[cov[i]]);
450 if (prev)
451 printf(" %d %d", uwid(S16(sub, prev + 2)),
452 uwid(S16(sub, prev + 4)));
453 else
454 printf(" - -");
455 if (next)
456 printf(" %d %d", uwid(S16(sub, next + 2)),
457 uwid(S16(sub, next + 4)));
458 else
459 printf(" - -");
460 printf("\n");
464 /* mark-to-base attachment positioning */
465 static void otf_gpostype4(void *otf, void *sub, char *feat)
467 int fmt = U16(sub, 0);
468 int mcov[NGLYPHS]; /* mark coverage */
469 int bcov[NGLYPHS]; /* base coverage */
470 int cgrp[1024]; /* glyph groups assigned to classes */
471 int bgrp; /* the group assigned to base glyphs */
472 int mcnt; /* mark coverage size */
473 int bcnt; /* base coverage size */
474 int ccnt; /* class count */
475 void *marks; /* mark array table */
476 void *bases; /* base array table */
477 int i, j;
478 if (fmt != 1)
479 return;
480 mcnt = coverage(sub + U16(sub, 2), mcov);
481 bcnt = coverage(sub + U16(sub, 4), bcov);
482 ccnt = U16(sub, 6);
483 marks = sub + U16(sub, 8);
484 bases = sub + U16(sub, 10);
485 bgrp = ggrp_coverage(bcov, bcnt);
486 for (i = 0; i < ccnt; i++) {
487 int grp[NGLYPHS];
488 int cnt = 0;
489 for (j = 0; j < mcnt; j++)
490 if (U16(marks, 2 + 4 * j) == i)
491 grp[cnt++] = mcov[j];
492 cgrp[i] = ggrp_coverage(grp, cnt);
494 for (i = 0; i < mcnt; i++) {
495 void *mark = marks + U16(marks, 2 + 4 * i + 2); /* mark anchor */
496 int dx = -uwid(S16(mark, 2));
497 int dy = uwid(S16(mark, 4));
498 printf("gpos %s 2 @%d %s:%+d%+d%+d%+d\n",
499 feat, bgrp, glyph_name[mcov[i]], dx, dy, 0, 0);
501 for (i = 0; i < bcnt; i++) {
502 for (j = 0; j < ccnt; j++) {
503 void *base = bases + U16(bases, 2 + ccnt * 2 * i + 2 * j);
504 int dx = uwid(S16(base, 2));
505 int dy = -uwid(S16(base, 4));
506 printf("gpos %s 2 %s @%d:%+d%+d%+d%+d\n",
507 feat, glyph_name[bcov[i]], cgrp[j], dx, dy, 0, 0);
512 /* gsub context */
513 struct gctx {
514 int bgrp[GCTXLEN]; /* backtrack coverage arrays */
515 int igrp[GCTXLEN]; /* input coverage arrays */
516 int lgrp[GCTXLEN]; /* lookahead coverage arrays*/
517 int bn, in, ln; /* size of b[], i[], l[] */
518 int seqidx; /* sequence index */
521 static int gctx_len(struct gctx *ctx, int patlen)
523 return ctx ? ctx->bn + ctx->in + ctx->ln - patlen : 0;
526 static void gctx_backtrack(struct gctx *ctx)
528 int i;
529 if (!ctx)
530 return;
531 for (i = 0; i < ctx->bn; i++)
532 printf(" =@%d", ctx->bgrp[i]);
533 for (i = 0; i < ctx->seqidx; i++)
534 printf(" =@%d", ctx->igrp[i]);
537 static void gctx_lookahead(struct gctx *ctx, int patlen)
539 int i;
540 if (!ctx)
541 return;
542 for (i = ctx->seqidx + patlen; i < ctx->in; i++)
543 printf(" =@%d", ctx->igrp[i]);
544 for (i = 0; i < ctx->ln; i++)
545 printf(" =@%d", ctx->lgrp[i]);
548 /* single substitution */
549 static void otf_gsubtype1(void *otf, void *sub, char *feat, struct gctx *ctx)
551 int cov[NGLYPHS];
552 int fmt = U16(sub, 0);
553 int ncov;
554 int i;
555 ncov = coverage(sub + U16(sub, 2), cov);
556 if (fmt == 1) {
557 for (i = 0; i < ncov; i++) {
558 printf("gsub %s %d", feat, 2 + gctx_len(ctx, 1));
559 gctx_backtrack(ctx);
560 printf(" -%s +%s", glyph_name[cov[i]],
561 glyph_name[cov[i] + S16(sub, 4)]);
562 gctx_lookahead(ctx, 1);
563 printf("\n");
566 if (fmt == 2) {
567 int n = U16(sub, 4);
568 for (i = 0; i < n; i++) {
569 printf("gsub %s %d", feat, 2 + gctx_len(ctx, 1));
570 gctx_backtrack(ctx);
571 printf(" -%s +%s", glyph_name[cov[i]],
572 glyph_name[U16(sub, 6 + 2 * i)]);
573 gctx_lookahead(ctx, 1);
574 printf("\n");
579 /* alternate substitution */
580 static void otf_gsubtype3(void *otf, void *sub, char *feat, struct gctx *ctx)
582 int cov[NGLYPHS];
583 int fmt = U16(sub, 0);
584 int n, i, j;
585 if (fmt != 1)
586 return;
587 coverage(sub + U16(sub, 2), cov);
588 n = U16(sub, 4);
589 for (i = 0; i < n; i++) {
590 void *alt = sub + U16(sub, 6 + 2 * i);
591 int nalt = U16(alt, 0);
592 for (j = 0; j < nalt; j++) {
593 printf("gsub %s %d", feat, 2 + gctx_len(ctx, 1));
594 gctx_backtrack(ctx);
595 printf(" -%s +%s", glyph_name[cov[i]],
596 glyph_name[U16(alt, 2 + 2 * j)]);
597 gctx_lookahead(ctx, 1);
598 printf("\n");
603 /* ligature substitution */
604 static void otf_gsubtype4(void *otf, void *sub, char *feat, struct gctx *ctx)
606 int fmt = U16(sub, 0);
607 int cov[NGLYPHS];
608 int n, i, j, k;
609 if (fmt != 1)
610 return;
611 coverage(sub + U16(sub, 2), cov);
612 n = U16(sub, 4);
613 for (i = 0; i < n; i++) {
614 void *set = sub + U16(sub, 6 + 2 * i);
615 int nset = U16(set, 0);
616 for (j = 0; j < nset; j++) {
617 void *lig = set + U16(set, 2 + 2 * j);
618 int nlig = U16(lig, 2);
619 printf("gsub %s %d", feat, nlig + 1 + gctx_len(ctx, nlig));
620 gctx_backtrack(ctx);
621 printf(" -%s", glyph_name[cov[i]]);
622 for (k = 0; k < nlig - 1; k++)
623 printf(" -%s", glyph_name[U16(lig, 4 + 2 * k)]);
624 printf(" +%s", glyph_name[U16(lig, 0)]);
625 gctx_lookahead(ctx, nlig);
626 printf("\n");
631 /* chaining contextual substitution */
632 static void otf_gsubtype6(void *otf, void *sub, char *feat, void *gsub)
634 struct gctx ctx = {{0}};
635 void *lookups = gsub + U16(gsub, 8);
636 int fmt = U16(sub, 0);
637 int cov[NGLYPHS];
638 int i, j, nsub, ncov;
639 int off = 2;
640 if (fmt != 3) {
641 otf_unsupported("GSUB", 6, fmt);
642 return;
644 ctx.bn = U16(sub, off);
645 for (i = 0; i < ctx.bn; i++) {
646 ncov = coverage(sub + U16(sub, off + 2 + 2 * i), cov);
647 ctx.bgrp[i] = ggrp_coverage(cov, ncov);
649 off += 2 + 2 * ctx.bn;
650 ctx.in = U16(sub, off);
651 for (i = 0; i < ctx.in; i++) {
652 ncov = coverage(sub + U16(sub, off + 2 + 2 * i), cov);
653 ctx.igrp[i] = ggrp_coverage(cov, ncov);
655 off += 2 + 2 * ctx.in;
656 ctx.ln = U16(sub, off);
657 for (i = 0; i < ctx.ln; i ++) {
658 ncov = coverage(sub + U16(sub, off + 2 + 2 * i), cov);
659 ctx.lgrp[i] = ggrp_coverage(cov, ncov);
661 off += 2 + 2 * ctx.ln;
662 nsub = U16(sub, off); /* nsub > 1 is not supported */
663 for (i = 0; i < nsub && i < 1; i++) {
664 int lidx = U16(sub, off + 2 + 4 * i + 2);
665 void *lookup = lookups + U16(lookups, 2 + 2 * lidx);
666 int ltype = U16(lookup, 0);
667 int ntabs = U16(lookup, 4);
668 ctx.seqidx = U16(sub, off + 2 + 4 * i);
669 for (j = 0; j < ntabs; j++) {
670 void *tab = lookup + U16(lookup, 6 + 2 * j);
671 int type = ltype;
672 if (type == 7) { /* extension substitution */
673 type = U16(tab, 2);
674 tab = tab + U32(tab, 4);
676 if (type == 1)
677 otf_gsubtype1(otf, tab, feat, &ctx);
678 if (type == 3)
679 otf_gsubtype3(otf, tab, feat, &ctx);
680 if (type == 4)
681 otf_gsubtype4(otf, tab, feat, &ctx);
686 /* an otf gsub/gpos lookup */
687 struct otflookup {
688 char feat[8]; /* feature name */
689 int lookup; /* index into the lookup table */
692 /* parse the given gsub/gpos feature table */
693 static int otf_featrec(void *otf, void *gtab, void *featrec, struct otflookup *lookups)
695 void *feats = gtab + U16(gtab, 6);
696 void *feat = feats + U16(featrec, 4);
697 int nlookups = U16(feat, 2);
698 int i;
699 for (i = 0; i < nlookups; i++) {
700 memcpy(lookups[i].feat, featrec, 4);
701 lookups[i].feat[4] = '\0';
702 lookups[i].lookup = U16(feat, 4 + 2 * i);
704 return nlookups;
707 /* parse the given language table and its feature tables */
708 static int otf_lang(void *otf, void *gtab, void *lang, struct otflookup *lookups)
710 void *feats = gtab + U16(gtab, 6);
711 int featidx = U16(lang, 2);
712 int nfeat = U16(lang, 4);
713 int n = 0;
714 int i;
715 if (featidx != 0xffff)
716 n += otf_featrec(otf, gtab, feats + 2 + 6 * featidx, lookups + n);
717 for (i = 0; i < nfeat; i++)
718 n += otf_featrec(otf, gtab,
719 feats + 2 + 6 * U16(lang, 6 + 2 * i), lookups + n);
720 return n;
723 static int lookupcmp(void *v1, void *v2)
725 struct otflookup *l1 = v1;
726 struct otflookup *l2 = v2;
727 if (trfn_featrank(l1->feat) != trfn_featrank(l2->feat))
728 return trfn_featrank(l1->feat) - trfn_featrank(l2->feat);
729 return l1->lookup - l2->lookup;
732 /* extract lookup tables for all features of the given gsub/gpos table */
733 static int otf_gtab(void *otf, void *gpos, struct otflookup *lookups)
735 void *scripts = gpos + U16(gpos, 4);
736 int nscripts, nlangs;
737 void *script;
738 char tag[8];
739 int i, j;
740 int n = 0;
741 nscripts = U16(scripts, 0);
742 for (i = 0; i < nscripts; i++) {
743 void *grec = scripts + 2 + 6 * i;
744 memcpy(tag, grec, 4);
745 tag[4] = '\0';
746 if (!trfn_script(tag, nscripts))
747 continue;
748 script = scripts + U16(grec, 4);
749 nlangs = U16(script, 2);
750 if (U16(script, 0) && trfn_lang(NULL, nlangs + (U16(script, 0) != 0)))
751 n += otf_lang(otf, gpos, script + U16(script, 0), lookups + n);
752 for (j = 0; j < nlangs; j++) {
753 void *lrec = script + 4 + 6 * j;
754 memcpy(tag, lrec, 4);
755 tag[4] = '\0';
756 if (trfn_lang(tag, nlangs + (U16(script, 0) != 0)))
757 n += otf_lang(otf, gpos, script + U16(lrec, 4), lookups + n);
760 qsort(lookups, n, sizeof(lookups[0]), (void *) lookupcmp);
761 return n;
764 static void otf_gpos(void *otf, void *gpos)
766 struct otflookup lookups[NLOOKUPS];
767 void *lookuplist = gpos + U16(gpos, 8);
768 int nlookups = otf_gtab(otf, gpos, lookups);
769 int i, j;
770 for (i = 0; i < nlookups; i++) {
771 void *lookup = lookuplist + U16(lookuplist, 2 + 2 * lookups[i].lookup);
772 char *tag = lookups[i].feat;
773 int ltype = U16(lookup, 0);
774 int ntabs = U16(lookup, 4);
775 for (j = 0; j < ntabs; j++) {
776 void *tab = lookup + U16(lookup, 6 + 2 * j);
777 int type = ltype;
778 if (type == 9) { /* extension positioning */
779 type = U16(tab, 2);
780 tab = tab + U32(tab, 4);
782 switch (type) {
783 case 1:
784 otf_gpostype1(otf, tab, tag);
785 break;
786 case 2:
787 otf_gpostype2(otf, tab, tag);
788 break;
789 case 3:
790 otf_gpostype3(otf, tab, tag);
791 break;
792 case 4:
793 otf_gpostype4(otf, tab, tag);
794 break;
795 default:
796 otf_unsupported("GPOS", type, 0);
802 static void otf_gsub(void *otf, void *gsub)
804 struct otflookup lookups[NLOOKUPS];
805 void *lookuplist = gsub + U16(gsub, 8);
806 int nlookups = otf_gtab(otf, gsub, lookups);
807 int i, j;
808 for (i = 0; i < nlookups; i++) {
809 void *lookup = lookuplist + U16(lookuplist, 2 + 2 * lookups[i].lookup);
810 char *tag = lookups[i].feat;
811 int ltype = U16(lookup, 0);
812 int ntabs = U16(lookup, 4);
813 for (j = 0; j < ntabs; j++) {
814 void *tab = lookup + U16(lookup, 6 + 2 * j);
815 int type = ltype;
816 if (type == 7) { /* extension substitution */
817 type = U16(tab, 2);
818 tab = tab + U32(tab, 4);
820 switch (type) {
821 case 1:
822 otf_gsubtype1(otf, tab, tag, NULL);
823 break;
824 case 3:
825 otf_gsubtype3(otf, tab, tag, NULL);
826 break;
827 case 4:
828 otf_gsubtype4(otf, tab, tag, NULL);
829 break;
830 case 6:
831 otf_gsubtype6(otf, tab, tag, gsub);
832 break;
833 default:
834 otf_unsupported("GSUB", type, 0);
840 static int xread(int fd, char *buf, int len)
842 int nr = 0;
843 while (nr < len) {
844 int ret = read(fd, buf + nr, len - nr);
845 if (ret == -1 && (errno == EAGAIN || errno == EINTR))
846 continue;
847 if (ret <= 0)
848 break;
849 nr += ret;
851 return nr;
854 static char buf[BUFLEN];
856 int otf_read(void)
858 int i;
859 if (xread(0, buf, sizeof(buf)) <= 0)
860 return 1;
861 upm = U16(otf_table(buf, "head"), 18);
862 otf_name(buf, otf_table(buf, "name"));
863 otf_cmap(buf, otf_table(buf, "cmap"));
864 otf_post(buf, otf_table(buf, "post"));
865 if (otf_table(buf, "glyf"))
866 otf_glyf(buf, otf_table(buf, "glyf"));
867 otf_hmtx(buf, otf_table(buf, "hmtx"));
868 for (i = 0; i < glyph_n; i++) {
869 trfn_char(glyph_name[i], -1,
870 glyph_code[i] != 0xffff ? glyph_code[i] : 0,
871 owid(glyph_wid[i]),
872 owid(glyph_bbox[i][0]), owid(glyph_bbox[i][1]),
873 owid(glyph_bbox[i][2]), owid(glyph_bbox[i][3]));
875 if (otf_table(buf, "kern"))
876 otf_kern(buf, otf_table(buf, "kern"));
877 return 0;
880 void otf_feat(int r, int k, int w)
882 res = r;
883 kmin = k;
884 warn = w;
885 if (otf_table(buf, "GSUB"))
886 otf_gsub(buf, otf_table(buf, "GSUB"));
887 if (otf_table(buf, "GPOS"))
888 otf_gpos(buf, otf_table(buf, "GPOS"));
891 /* glyph groups */
892 static int *ggrp_g[NGRPS];
893 static int ggrp_len[NGRPS];
894 static int ggrp_n;
896 static int ggrp_find(int *src, int n)
898 int i, j;
899 for (i = 0; i < ggrp_n; i++) {
900 if (ggrp_len[i] == n) {
901 for (j = 0; j < n; j++)
902 if (src[j] != ggrp_g[i][j])
903 break;
904 if (j == n)
905 return i;
908 return -1;
911 int ggrp_make(int *src, int n)
913 int id = ggrp_find(src, n);
914 int i;
915 if (id >= 0)
916 return id;
917 id = ggrp_n++;
918 ggrp_g[id] = malloc(n * sizeof(ggrp_g[id][0]));
919 ggrp_len[id] = n;
920 for (i = 0; i < n; i++)
921 ggrp_g[id][i] = src[i];
922 printf("ggrp %d %d", id, n);
923 for (i = 0; i < n; i++)
924 printf(" %s", glyph_name[src[i]]);
925 printf("\n");
926 return id;
929 static char *macset[] = {
930 ".notdef", ".null", "nonmarkingreturn", "space", "exclam",
931 "quotedbl", "numbersign", "dollar", "percent", "ampersand",
932 "quotesingle", "parenleft", "parenright", "asterisk", "plus",
933 "comma", "hyphen", "period", "slash", "zero",
934 "one", "two", "three", "four", "five",
935 "six", "seven", "eight", "nine", "colon",
936 "semicolon", "less", "equal", "greater", "question",
937 "at", "A", "B", "C", "D",
938 "E", "F", "G", "H", "I",
939 "J", "K", "L", "M", "N",
940 "O", "P", "Q", "R", "S",
941 "T", "U", "V", "W", "X",
942 "Y", "Z", "bracketleft", "backslash", "bracketright",
943 "asciicircum", "underscore", "grave", "a", "b",
944 "c", "d", "e", "f", "g",
945 "h", "i", "j", "k", "l",
946 "m", "n", "o", "p", "q",
947 "r", "s", "t", "u", "v",
948 "w", "x", "y", "z", "braceleft",
949 "bar", "braceright", "asciitilde", "Adieresis", "Aring",
950 "Ccedilla", "Eacute", "Ntilde", "Odieresis", "Udieresis",
951 "aacute", "agrave", "acircumflex", "adieresis", "atilde",
952 "aring", "ccedilla", "eacute", "egrave", "ecircumflex",
953 "edieresis", "iacute", "igrave", "icircumflex", "idieresis",
954 "ntilde", "oacute", "ograve", "ocircumflex", "odieresis",
955 "otilde", "uacute", "ugrave", "ucircumflex", "udieresis",
956 "dagger", "degree", "cent", "sterling", "section",
957 "bullet", "paragraph", "germandbls", "registered", "copyright",
958 "trademark", "acute", "dieresis", "notequal", "AE",
959 "Oslash", "infinity", "plusminus", "lessequal", "greaterequal",
960 "yen", "mu", "partialdiff", "summation", "product",
961 "pi", "integral", "ordfeminine", "ordmasculine", "Omega",
962 "ae", "oslash", "questiondown", "exclamdown", "logicalnot",
963 "radical", "florin", "approxequal", "Delta", "guillemotleft",
964 "guillemotright", "ellipsis", "nonbreakingspace", "Agrave", "Atilde",
965 "Otilde", "OE", "oe", "endash", "emdash",
966 "quotedblleft", "quotedblright", "quoteleft", "quoteright", "divide",
967 "lozenge", "ydieresis", "Ydieresis", "fraction", "currency",
968 "guilsinglleft", "guilsinglright", "fi", "fl", "daggerdbl",
969 "periodcentered", "quotesinglbase", "quotedblbase", "perthousand", "Acircumflex",
970 "Ecircumflex", "Aacute", "Edieresis", "Egrave", "Iacute",
971 "Icircumflex", "Idieresis", "Igrave", "Oacute", "Ocircumflex",
972 "apple", "Ograve", "Uacute", "Ucircumflex", "Ugrave",
973 "dotlessi", "circumflex", "tilde", "macron", "breve",
974 "dotaccent", "ring", "cedilla", "hungarumlaut", "ogonek",
975 "caron", "Lslash", "lslash", "Scaron", "scaron",
976 "Zcaron", "zcaron", "brokenbar", "Eth", "eth",
977 "Yacute", "yacute", "Thorn", "thorn", "minus",
978 "multiply", "onesuperior", "twosuperior", "threesuperior", "onehalf",
979 "onequarter", "threequarters", "franc", "Gbreve", "gbreve",
980 "Idotaccent", "Scedilla", "scedilla", "Cacute", "cacute",
981 "Ccaron", "ccaron", "dcroat",