shithub: neatmkfn

Download patch

ref: 255f5bc5964dc335d01bd2694d22de7702787c12
parent: c895fdcb6006d9ff27e1bdc7082897294dffadab
author: Ali Gholami Rudi <ali@rudi.ir>
date: Tue Jul 29 10:48:15 EDT 2014

otf: parse some of otf gsub and gpos tables

--- a/mkfn.c
+++ b/mkfn.c
@@ -101,6 +101,7 @@
 }
 
 int otf_read(void);
+void otf_feat(int res);
 
 static char *usage =
 	"Usage: mktrfn [options] <input >output\n"
@@ -159,6 +160,8 @@
 	else
 		otf_read();
 	trfn_print();
+	if (!afm)
+		otf_feat(res);
 	trfn_done();
 	return 0;
 }
--- a/otf.c
+++ b/otf.c
@@ -5,10 +5,9 @@
 #include <unistd.h>
 #include "trfn.h"
 
-#define NGLYPHS			(1 << 14)
-#define GNLEN			(64)
-#define BUFLEN			(1 << 23)
-#define OWID(w)			((w) * 1000 / (upm))
+#define NGLYPHS		(1 << 14)
+#define GNLEN		(64)
+#define BUFLEN		(1 << 23)
 
 #define U32(buf, off)		(htonl(*(u32 *) ((buf) + (off))))
 #define U16(buf, off)		(htons(*(u16 *) ((buf) + (off))))
@@ -34,9 +33,21 @@
 static int glyph_wid[NGLYPHS];
 static int glyph_n;
 static int upm;			/* units per em */
+static int res;			/* device resolution */
 
 static char *macset[];
 
+static int owid(int w)
+{
+	return (w < 0 ? w * 1000 - upm / 2 : w * 1000 + upm / 2) / upm;
+}
+
+static int uwid(int w)
+{
+	int d = 7200 / res;
+	return (w < 0 ? owid(w) - d / 2 : owid(w) + d / 2) / d;
+}
+
 /* find the otf table with the given name */
 static void *otf_table(void *otf, char *name)
 {
@@ -186,12 +197,329 @@
 				c2 = U16(tab, 14 + 6 * j + 2);
 				val = S16(tab, 14 + 6 * j + 4);
 				trfn_kern(glyph_name[c1], glyph_name[c2],
-					OWID(val));
+					owid(val));
 			}
 		}
 	}
 }
 
+static int coverage(void *cov, int *out)
+{
+	int fmt = U16(cov, 0);
+	int n = U16(cov, 2);
+	int beg, end;
+	int ncov = 0;
+	int i, j;
+	if (fmt == 1) {
+		for (i = 0; i < n; i++)
+			out[ncov++] = U16(cov, 4 + 2 * i);
+	}
+	if (fmt == 2) {
+		for (i = 0; i < n; i++) {
+			beg = U16(cov, 4 + 6 * i);
+			end = U16(cov, 4 + 6 * i + 2);
+			for (j = beg; j <= end; j++)
+				out[ncov++] = j;
+		}
+	}
+	return ncov;
+}
+
+static int valuerecord_len(int fmt)
+{
+	int off = 0;
+	int i;
+	for (i = 0; i < 8; i++)
+		if (fmt & (1 << i))
+			off += 2;
+	return off;
+}
+
+static void valuerecord_print(int fmt, void *rec)
+{
+	int vals[8] = {0};
+	int off = 0;
+	int i;
+	for (i = 0; i < 8; i++) {
+		if (fmt & (1 << i)) {
+			vals[i] = uwid(S16(rec, off));
+			off += 2;
+		}
+	}
+	if (fmt)
+		printf(":%+d%+d%+d%+d", vals[0], vals[1], vals[2], vals[3]);
+}
+
+static void otf_gpostype1(void *otf, char *feat, char *sub)
+{
+	int fmt = U16(sub, 0);
+	int vfmt = U16(sub, 4);
+	int cov[NGLYPHS];
+	int ncov, nvals;
+	int vlen = valuerecord_len(vfmt);
+	int i;
+	ncov = coverage(sub + U16(sub, 2), cov);
+	if (fmt == 1) {
+		for (i = 0; i < ncov; i++) {
+			printf("gpos %s %s", feat, glyph_name[cov[i]]);
+			valuerecord_print(vfmt, sub + 6);
+			printf("\n");
+		}
+	}
+	if (fmt == 2) {
+		nvals = U16(sub, 6);
+		for (i = 0; i < nvals; i++) {
+			printf("gpos %s %s", feat, glyph_name[cov[i]]);
+			valuerecord_print(vfmt, sub + 8 + i * vlen);
+			printf("\n");
+		}
+	}
+}
+
+static void otf_gpostype2(void *otf, char *feat, char *sub)
+{
+	int fmt = U16(sub, 0);
+	int vfmt1 = U16(sub, 4);
+	int vfmt2 = U16(sub, 6);
+	int c2len;
+	int nc1 = U16(sub, 8);
+	int cov[NGLYPHS];
+	void *c2;
+	int ncov, nc2, second;
+	int i, j;
+	if (fmt != 1)
+		return;
+	ncov = coverage(sub + U16(sub, 2), cov);
+	c2len = 2 + valuerecord_len(vfmt1) + valuerecord_len(vfmt2);
+	for (i = 0; i < nc1; i++) {
+		c2 = sub + U16(sub, 10 + 2 * i);
+		nc2 = U16(c2, 0);
+		for (j = 0; j < nc2; j++) {
+			printf("gpos %s 2", feat);
+			second = U16(c2 + 2 + c2len * j, 0);
+			printf(" %s", glyph_name[cov[i]]);
+			valuerecord_print(vfmt1, c2 + 2 + c2len * j + 2);
+			printf(" %s", glyph_name[second]);
+			valuerecord_print(vfmt2, c2 + 2 + c2len * j + 2 +
+					valuerecord_len(vfmt1));
+			printf("\n");
+		}
+	}
+}
+
+static void otf_gpostype3(void *otf, char *feat, char *sub)
+{
+	int fmt = U16(sub, 0);
+	int cov[NGLYPHS];
+	int ncov, i, n;
+	ncov = coverage(sub + U16(sub, 2), cov);
+	if (fmt != 1)
+		return;
+	n = U16(sub, 4);
+	for (i = 0; i < n; i++) {
+		int prev = U16(sub, 6 + 4 * i);
+		int next = U16(sub, 6 + 4 * i + 2);
+		printf("gcur %s %s", feat, glyph_name[cov[i]]);
+		if (prev)
+			printf(" %d %d", uwid(S16(sub, prev + 2)),
+					uwid(S16(sub, prev + 4)));
+		else
+			printf(" - -");
+		if (next)
+			printf(" %d %d", uwid(S16(sub, next + 2)),
+					uwid(S16(sub, next + 4)));
+		else
+			printf(" - -");
+		printf("\n");
+	}
+}
+
+static void otf_gposfeatrec(void *otf, void *gpos, void *featrec)
+{
+	void *feats = gpos + U16(gpos, 6);
+	void *lookups = gpos + U16(gpos, 8);
+	void *feat, *lookup, *tab;
+	int nlookups, type, flag, ntabs;
+	char tag[8] = "";
+	int i, j;
+	memcpy(tag, featrec, 4);
+	feat = feats + U16(featrec, 4);
+	nlookups = U16(feat, 2);
+	for (i = 0; i < nlookups; i++) {
+		lookup = lookups + U16(lookups, 2 + 2 * U16(feat, 4 + 2 * i));
+		type = U16(lookup, 0);
+		flag = U16(lookup, 2);
+		ntabs = U16(lookup, 4);
+		for (j = 0; j < ntabs; j++) {
+			tab = lookup + U16(lookup, 6 + 2 * j);
+			if (type == 1)
+				otf_gpostype1(otf, tag, tab);
+			if (type == 2)
+				otf_gpostype2(otf, tag, tab);
+			if (type == 3)
+				otf_gpostype3(otf, tag, tab);
+		}
+	}
+}
+
+static void otf_gposlang(void *otf, void *gpos, void *lang)
+{
+	void *feats = gpos + U16(gpos, 6);
+	int featidx = U16(lang, 2);
+	int nfeat = U16(lang, 4);
+	int i;
+	if (featidx != 0xffff)
+		otf_gposfeatrec(otf, gpos, feats + 2 + 6 * featidx);
+	for (i = 0; i < nfeat; i++)
+		otf_gposfeatrec(otf, gpos,
+				feats + 2 + 6 * U16(lang, 6 + 2 * i));
+}
+
+static void otf_gpos(void *otf, void *gpos)
+{
+	void *scripts = gpos + U16(gpos, 4);
+	int nscripts, nlangs;
+	void *script;
+	void *grec;
+	int i, j;
+	nscripts = U16(scripts, 0);
+	for (i = 0; i < nscripts; i++) {
+		grec = scripts + 2 + 6 * i;
+		script = scripts + U16(grec, 4);
+		if (U16(script, 0))
+			otf_gposlang(otf, gpos, script + U16(script, 0));
+		nlangs = U16(script, 2);
+		for (j = 0; j < nlangs; j++)
+			otf_gposlang(otf, gpos, script +
+					U16(script, 4 + 6 * j + 4));
+	}
+}
+
+static void otf_gsubtype1(void *otf, char *feat, char *sub)
+{
+	int cov[NGLYPHS];
+	int fmt = U16(sub, 0);
+	int ncov;
+	int n;
+	int i;
+	ncov = coverage(sub + U16(sub, 2), cov);
+	if (fmt == 1) {
+		for (i = 0; i < ncov; i++)
+			printf("gsub %s 2 -%s +%s\n",
+				feat, glyph_name[cov[i]],
+				glyph_name[cov[i] + S16(sub, 4)]);
+	}
+	if (fmt == 2) {
+		n = U16(sub, 4);
+		for (i = 0; i < n; i++)
+			printf("gsub %s 2 -%s +%s\n",
+				feat, glyph_name[cov[i]],
+				glyph_name[U16(sub, 6 + 2 * i)]);
+	}
+}
+
+static void otf_gsubtype3(void *otf, char *feat, char *sub)
+{
+	int cov[NGLYPHS];
+	int fmt = U16(sub, 0);
+	int ncov, n, i, j;
+	if (fmt != 1)
+		return;
+	ncov = coverage(sub + U16(sub, 2), cov);
+	n = U16(sub, 4);
+	for (i = 0; i < n; i++) {
+		void *alt = sub + U16(sub, 6 + 2 * i);
+		int nalt = U16(alt, 0);
+		for (j = 0; j < nalt; j++)
+			printf("gsub %s 2 -%s +%s\n",
+				feat, glyph_name[cov[i]],
+				glyph_name[U16(alt, 2 + 2 * j)]);
+	}
+}
+
+static void otf_gsubtype4(void *otf, char *feat, char *sub)
+{
+	int fmt = U16(sub, 0);
+	int cov[NGLYPHS];
+	int ncov, n, i, j, k;
+	if (fmt != 1)
+		return;
+	ncov = coverage(sub + U16(sub, 2), cov);
+	n = U16(sub, 4);
+	for (i = 0; i < n; i++) {
+		void *set = sub + U16(sub, 6 + 2 * i);
+		int nset = U16(set, 0);
+		for (j = 0; j < nset; j++) {
+			void *lig = set + U16(set, 2 + 2 * j);
+			int nlig = U16(lig, 2);
+			printf("gsub %s %d -%s",
+				feat, nlig + 1, glyph_name[cov[i]]);
+			for (k = 0; k < nlig - 1; k++)
+				printf(" -%s", glyph_name[U16(lig, 4 + 2 * k)]);
+			printf(" +%s\n", glyph_name[U16(lig, 0)]);
+		}
+	}
+}
+
+static void otf_gsubfeatrec(void *otf, void *gsub, void *featrec)
+{
+	void *feats = gsub + U16(gsub, 6);
+	void *lookups = gsub + U16(gsub, 8);
+	void *feat, *lookup, *tab;
+	int nlookups, type, flag, ntabs;
+	char tag[8] = "";
+	int i, j;
+	memcpy(tag, featrec, 4);
+	feat = feats + U16(featrec, 4);
+	nlookups = U16(feat, 2);
+	for (i = 0; i < nlookups; i++) {
+		lookup = lookups + U16(lookups, 2 + 2 * U16(feat, 4 + 2 * i));
+		type = U16(lookup, 0);
+		flag = U16(lookup, 2);
+		ntabs = U16(lookup, 4);
+		for (j = 0; j < ntabs; j++) {
+			tab = lookup + U16(lookup, 6 + 2 * j);
+			if (type == 1)
+				otf_gsubtype1(otf, tag, tab);
+			if (type == 3)
+				otf_gsubtype3(otf, tag, tab);
+			if (type == 4)
+				otf_gsubtype4(otf, tag, tab);
+		}
+	}
+}
+
+static void otf_gsublang(void *otf, void *gsub, void *lang)
+{
+	void *feats = gsub + U16(gsub, 6);
+	int featidx = U16(lang, 2);
+	int nfeat = U16(lang, 4);
+	int i;
+	if (featidx != 0xffff)
+		otf_gsubfeatrec(otf, gsub, feats + 2 + 6 * featidx);
+	for (i = 0; i < nfeat; i++)
+		otf_gsubfeatrec(otf, gsub,
+				feats + 2 + 6 * U16(lang, 6 + 2 * i));
+}
+
+static void otf_gsub(void *otf, void *gsub)
+{
+	void *scripts = gsub + U16(gsub, 4);
+	int nscripts, nlangs;
+	void *script;
+	int i, j;
+	nscripts = U16(scripts, 0);
+	for (i = 0; i < nscripts; i++) {
+		script = scripts + U16(scripts + 2 + 6 * i, 4);
+		nlangs = U16(script, 2);
+		if (U16(script, 0))
+			otf_gsublang(otf, gsub, script + U16(script, 0));
+		for (j = 0; j < nlangs; j++)
+			otf_gsublang(otf, gsub, script +
+					U16(script, 4 + 6 * j + 4));
+	}
+}
+
 int xread(int fd, char *buf, int len)
 {
 	int nr = 0;
@@ -222,12 +550,22 @@
 	for (i = 0; i < glyph_n; i++) {
 		trfn_char(glyph_name[i], -1,
 			glyph_code[i] != 0xffff ? glyph_code[i] : 0,
-			OWID(glyph_wid[i]),
-			OWID(glyph_bbox[i][0]), OWID(glyph_bbox[i][1]),
-			OWID(glyph_bbox[i][2]), OWID(glyph_bbox[i][3]));
+			owid(glyph_wid[i]),
+			owid(glyph_bbox[i][0]), owid(glyph_bbox[i][1]),
+			owid(glyph_bbox[i][2]), owid(glyph_bbox[i][3]));
 	}
-	otf_kern(buf, otf_table(buf, "kern"));
+	if (otf_table(buf, "kern"))
+		otf_kern(buf, otf_table(buf, "kern"));
 	return 0;
+}
+
+void otf_feat(int r)
+{
+	res = r;
+	if (otf_table(buf, "GSUB"))
+		otf_gsub(buf, otf_table(buf, "GSUB"));
+	if (otf_table(buf, "GPOS"))
+		otf_gpos(buf, otf_table(buf, "GPOS"));
 }
 
 static char *macset[] = {