shithub: neatmkfn

Download patch

ref: 25138e475ff9e5cef62dd0e8a455bf9812f84d6e
parent: eafe059b9305cd63401fd075b2b219bf4862bf84
author: Ali Gholami Rudi <ali@rudi.ir>
date: Tue Aug 12 18:57:17 EDT 2014

otf: sort lookup tables according to their index in the lookup list

This also merges extracting lookup tables for GSUB and GPOS tables.

--- a/otf.c
+++ b/otf.c
@@ -7,6 +7,7 @@
 #include "trfn.h"
 
 #define NGLYPHS		(1 << 14)
+#define NLOOKUPS	(1 << 12)
 #define GNLEN		(64)
 #define BUFLEN		(1 << 23)
 #define NGRPS		2048
@@ -474,89 +475,6 @@
 	}
 }
 
-/* parse the given gpos feature table */
-static void otf_gposfeatrec(void *otf, void *gpos, void *featrec)
-{
-	void *feats = gpos + U16(gpos, 6);
-	void *lookups = gpos + U16(gpos, 8);
-	void *feat;
-	int nlookups;
-	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++) {
-		void *lookup = lookups + U16(lookups, 2 + 2 * U16(feat, 4 + 2 * i));
-		int ltype = U16(lookup, 0);
-		int ntabs = U16(lookup, 4);
-		for (j = 0; j < ntabs; j++) {
-			void *tab = lookup + U16(lookup, 6 + 2 * j);
-			int type = ltype;
-			if (type == 9) {	/* extension positioning */
-				type = U16(tab, 2);
-				tab = tab + U32(tab, 4);
-			}
-			switch (type) {
-			case 1:
-				otf_gpostype1(otf, tab, tag);
-				break;
-			case 2:
-				otf_gpostype2(otf, tab, tag);
-				break;
-			case 3:
-				otf_gpostype3(otf, tab, tag);
-				break;
-			default:
-				otf_unsupported("GPOS", type, 0);
-			}
-		}
-	}
-}
-
-/* parse the given gpos language table and its feature tables */
-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, *lrec;
-	char tag[8];
-	int i, j;
-	nscripts = U16(scripts, 0);
-	for (i = 0; i < nscripts; i++) {
-		grec = scripts + 2 + 6 * i;
-		memcpy(tag, grec, 4);
-		tag[4] = '\0';
-		if (!trfn_script(tag, nscripts))
-			continue;
-		script = scripts + U16(grec, 4);
-		nlangs = U16(script, 2);
-		if (U16(script, 0) && trfn_lang(NULL, nlangs + (U16(script, 0) != 0)))
-			otf_gposlang(otf, gpos, script + U16(script, 0));
-		for (j = 0; j < nlangs; j++) {
-			lrec = script + 4 + 6 * j;
-			memcpy(tag, lrec, 4);
-			tag[4] = '\0';
-			if (trfn_lang(tag, nlangs + (U16(script, 0) != 0)))
-				otf_gposlang(otf, gpos, script + U16(lrec, 4));
-		}
-	}
-}
-
 /* gsub context */
 struct gctx {
 	int bgrp[GCTXLEN];	/* backtrack coverage arrays */
@@ -732,71 +650,58 @@
 	}
 }
 
-/* parse the given gsub feature table */
-static void otf_gsubfeatrec(void *otf, void *gsub, void *featrec)
+/* an otf gsub/gpos lookup */
+struct otflookup {
+	char feat[8];		/* feature name */
+	int lookup;		/* index into the lookup table */
+};
+
+/* parse the given gsub/gpos feature table */
+static int otf_featrec(void *otf, void *gtab, void *featrec, struct otflookup *lookups)
 {
-	void *feats = gsub + U16(gsub, 6);
-	void *lookups = gsub + U16(gsub, 8);
-	void *feat;
-	int nlookups;
-	char tag[8] = "";
-	int i, j;
-	memcpy(tag, featrec, 4);
-	feat = feats + U16(featrec, 4);
-	nlookups = U16(feat, 2);
+	void *feats = gtab + U16(gtab, 6);
+	void *feat = feats + U16(featrec, 4);
+	int nlookups = U16(feat, 2);
+	int i;
 	for (i = 0; i < nlookups; i++) {
-		void *lookup = lookups + U16(lookups, 2 + 2 * U16(feat, 4 + 2 * i));
-		int ltype = U16(lookup, 0);
-		int ntabs = U16(lookup, 4);
-		for (j = 0; j < ntabs; j++) {
-			void *tab = lookup + U16(lookup, 6 + 2 * j);
-			int type = ltype;
-			if (type == 7) {	/* extension substitution */
-				type = U16(tab, 2);
-				tab = tab + U32(tab, 4);
-			}
-			switch (type) {
-			case 1:
-				otf_gsubtype1(otf, tab, tag, NULL);
-				break;
-			case 3:
-				otf_gsubtype3(otf, tab, tag, NULL);
-				break;
-			case 4:
-				otf_gsubtype4(otf, tab, tag, NULL);
-				break;
-			case 6:
-				otf_gsubtype6(otf, tab, tag, gsub);
-				break;
-			default:
-				otf_unsupported("GSUB", type, 0);
-			}
-		}
+		memcpy(lookups[i].feat, featrec, 4);
+		lookups[i].feat[4] = '\0';
+		lookups[i].lookup = U16(feat, 4 + 2 * i);
 	}
+	return nlookups;
 }
 
-/* parse the given gsub language table and its feature tables */
-static void otf_gsublang(void *otf, void *gsub, void *lang)
+/* parse the given language table and its feature tables */
+static int otf_lang(void *otf, void *gtab, void *lang, struct otflookup *lookups)
 {
-	void *feats = gsub + U16(gsub, 6);
+	void *feats = gtab + U16(gtab, 6);
 	int featidx = U16(lang, 2);
 	int nfeat = U16(lang, 4);
+	int n = 0;
 	int i;
 	if (featidx != 0xffff)
-		otf_gsubfeatrec(otf, gsub, feats + 2 + 6 * featidx);
+		n += otf_featrec(otf, gtab, feats + 2 + 6 * featidx, lookups + n);
 	for (i = 0; i < nfeat; i++)
-		otf_gsubfeatrec(otf, gsub,
-				feats + 2 + 6 * U16(lang, 6 + 2 * i));
+		n += otf_featrec(otf, gtab,
+				feats + 2 + 6 * U16(lang, 6 + 2 * i), lookups + n);
+	return n;
 }
 
-static void otf_gsub(void *otf, void *gsub)
+static int lookupcmp(void *v1, void *v2)
 {
-	void *scripts = gsub + U16(gsub, 4);
+	return ((struct otflookup *) v1)->lookup - ((struct otflookup *) v2)->lookup;
+}
+
+/* extract lookup tables for all features of the given gsub/gpos table */
+static int otf_gtab(void *otf, void *gpos, struct otflookup *lookups)
+{
+	void *scripts = gpos + U16(gpos, 4);
 	int nscripts, nlangs;
 	void *script;
 	void *grec, *lrec;
 	char tag[8];
 	int i, j;
+	int n = 0;
 	nscripts = U16(scripts, 0);
 	for (i = 0; i < nscripts; i++) {
 		grec = scripts + 2 + 6 * i;
@@ -804,16 +709,91 @@
 		tag[4] = '\0';
 		if (!trfn_script(tag, nscripts))
 			continue;
-		script = scripts + U16(scripts + 2 + 6 * i, 4);
+		script = scripts + U16(grec, 4);
 		nlangs = U16(script, 2);
 		if (U16(script, 0) && trfn_lang(NULL, nlangs + (U16(script, 0) != 0)))
-			otf_gsublang(otf, gsub, script + U16(script, 0));
+			n += otf_lang(otf, gpos, script + U16(script, 0), lookups + n);
 		for (j = 0; j < nlangs; j++) {
 			lrec = script + 4 + 6 * j;
 			memcpy(tag, lrec, 4);
 			tag[4] = '\0';
 			if (trfn_lang(tag, nlangs + (U16(script, 0) != 0)))
-				otf_gsublang(otf, gsub, script + U16(lrec, 4));
+				n += otf_lang(otf, gpos, script + U16(lrec, 4), lookups + n);
+		}
+	}
+	qsort(lookups, n, sizeof(lookups[0]), (void *) lookupcmp);
+	return n;
+}
+
+static void otf_gpos(void *otf, void *gpos)
+{
+	struct otflookup lookups[NLOOKUPS];
+	void *lookuplist = gpos + U16(gpos, 8);
+	int nlookups = otf_gtab(otf, gpos, lookups);
+	int i, j;
+	for (i = 0; i < nlookups; i++) {
+		void *lookup = lookuplist + U16(lookuplist, 2 + 2 * lookups[i].lookup);
+		char *tag = lookups[i].feat;
+		int ltype = U16(lookup, 0);
+		int ntabs = U16(lookup, 4);
+		for (j = 0; j < ntabs; j++) {
+			void *tab = lookup + U16(lookup, 6 + 2 * j);
+			int type = ltype;
+			if (type == 9) {	/* extension positioning */
+				type = U16(tab, 2);
+				tab = tab + U32(tab, 4);
+			}
+			switch (type) {
+			case 1:
+				otf_gpostype1(otf, tab, tag);
+				break;
+			case 2:
+				otf_gpostype2(otf, tab, tag);
+				break;
+			case 3:
+				otf_gpostype3(otf, tab, tag);
+				break;
+			default:
+				otf_unsupported("GPOS", type, 0);
+			}
+		}
+	}
+}
+
+static void otf_gsub(void *otf, void *gsub)
+{
+	struct otflookup lookups[NLOOKUPS];
+	void *lookuplist = gsub + U16(gsub, 8);
+	int nlookups = otf_gtab(otf, gsub, lookups);
+	int i, j;
+	for (i = 0; i < nlookups; i++) {
+		void *lookup = lookuplist + U16(lookuplist, 2 + 2 * lookups[i].lookup);
+		char *tag = lookups[i].feat;
+		int ltype = U16(lookup, 0);
+		int ntabs = U16(lookup, 4);
+		for (j = 0; j < ntabs; j++) {
+			void *tab = lookup + U16(lookup, 6 + 2 * j);
+			int type = ltype;
+			if (type == 7) {	/* extension substitution */
+				type = U16(tab, 2);
+				tab = tab + U32(tab, 4);
+			}
+			switch (type) {
+			case 1:
+				otf_gsubtype1(otf, tab, tag, NULL);
+				break;
+			case 3:
+				otf_gsubtype3(otf, tab, tag, NULL);
+				break;
+			case 4:
+				otf_gsubtype4(otf, tab, tag, NULL);
+				break;
+			case 6:
+				otf_gsubtype6(otf, tab, tag, gsub);
+				break;
+			default:
+				otf_unsupported("GSUB", type, 0);
+			}
 		}
 	}
 }