shithub: neatmkfn

Download patch

ref: 7bdbe6ec17412d7c9fedf2598d0daab01e61f4b6
parent: a0bb8b067926bb3882e2950828d24fcb56608665
author: Ali Gholami Rudi <ali@rudi.ir>
date: Sat Aug 2 10:30:48 EDT 2014

otf: read pairwise kerning values for glyph classes

--- a/mkfn.c
+++ b/mkfn.c
@@ -101,7 +101,7 @@
 }
 
 int otf_read(void);
-void otf_feat(int res);
+void otf_feat(int res, int kmin);
 
 static char *usage =
 	"Usage: mktrfn [options] <input >output\n"
@@ -161,7 +161,7 @@
 		otf_read();
 	trfn_print();
 	if (!afm)
-		otf_feat(res);
+		otf_feat(res, kmin);
 	trfn_done();
 	return 0;
 }
--- a/otf.c
+++ b/otf.c
@@ -1,6 +1,7 @@
 #include <arpa/inet.h>
 #include <errno.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 #include "trfn.h"
@@ -8,6 +9,7 @@
 #define NGLYPHS		(1 << 14)
 #define GNLEN		(64)
 #define BUFLEN		(1 << 23)
+#define MAX(a, b)	((a) < (b) ? (b) : (a))
 
 #define U32(buf, off)		(htonl(*(u32 *) ((buf) + (off))))
 #define U16(buf, off)		(htons(*(u16 *) ((buf) + (off))))
@@ -34,6 +36,7 @@
 static int glyph_n;
 static int upm;			/* units per em */
 static int res;			/* device resolution */
+static int kmin;		/* minimum kerning value */
 
 static char *macset[];
 
@@ -225,6 +228,35 @@
 	return ncov;
 }
 
+static int classdef(void *tab, int *gl, int *cls)
+{
+	int fmt = U16(tab, 0);
+	int beg, end;
+	int n, ngl = 0;
+	int i, j;
+	if (fmt == 1) {
+		beg = U16(tab, 2);
+		ngl = U16(tab, 4);
+		for (i = 0; i < ngl; i++) {
+			gl[i] = beg + i;
+			cls[i] = U16(tab, 6 + 2 * i);
+		}
+	}
+	if (fmt == 2) {
+		n = U16(tab, 2);
+		for (i = 0; i < n; i++) {
+			beg = U16(tab, 4 + 6 * i);
+			end = U16(tab, 4 + 6 * i + 2);
+			for (j = beg; j <= end; j++) {
+				gl[ngl] = j;
+				cls[ngl] = U16(tab, 4 + 6 * i + 4);
+				ngl++;
+			}
+		}
+	}
+	return ngl;
+}
+
 static int valuerecord_len(int fmt)
 {
 	int off = 0;
@@ -250,6 +282,20 @@
 		printf(":%+d%+d%+d%+d", vals[0], vals[1], vals[2], vals[3]);
 }
 
+static int valuerecord_small(int fmt, void *rec)
+{
+	int off = 0;
+	int i;
+	for (i = 0; i < 8; i++) {
+		if (fmt & (1 << i)) {
+			if (abs(uwid(S16(rec, off))) >= MAX(1, kmin))
+				return 0;
+			off += 2;
+		}
+	}
+	return 1;
+}
+
 static void otf_gpostype1(void *otf, char *feat, char *sub)
 {
 	int fmt = U16(sub, 0);
@@ -281,30 +327,58 @@
 	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 fmtoff1, fmtoff2;
+	int vrlen;		/* valuerecord1 and valuerecord2 length */
 	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");
+	vrlen = valuerecord_len(vfmt1) + valuerecord_len(vfmt2);
+	if (fmt == 1) {
+		int cov[NGLYPHS];
+		int nc1 = U16(sub, 8);
+		coverage(sub + U16(sub, 2), cov);
+		for (i = 0; i < nc1; i++) {
+			void *c2 = sub + U16(sub, 10 + 2 * i);
+			int nc2 = U16(c2, 0);
+			for (j = 0; j < nc2; j++) {
+				int second = U16(c2 + 2 + (2 + vrlen) * j, 0);
+				fmtoff1 = 2 + (2 + vrlen) * j + 2;
+				fmtoff2 = fmtoff1 + valuerecord_len(vfmt2);
+				if (valuerecord_small(vfmt1, c2 + fmtoff1) &&
+					valuerecord_small(vfmt2, c2 + fmtoff2))
+					continue;
+				printf("gpos %s 2", feat);
+				printf(" %s", glyph_name[cov[i]]);
+				valuerecord_print(vfmt1, c2 + fmtoff1);
+				printf(" %s", glyph_name[second]);
+				valuerecord_print(vfmt2, c2 + fmtoff2);
+				printf("\n");
+			}
 		}
 	}
+	if (fmt == 2) {
+		int gl1[NGLYPHS], gl2[NGLYPHS];
+		int cls1[NGLYPHS], cls2[NGLYPHS];
+		int ngl1 = classdef(sub + U16(sub, 8), gl1, cls1);
+		int ngl2 = classdef(sub + U16(sub, 10), gl2, cls2);
+		int ncls1 = U16(sub, 12);
+		int ncls2 = U16(sub, 14);
+		for (i = 0; i < ngl1; i++) {
+			for (j = 0; j < ngl2; j++) {
+				if (cls1[i] >= ncls1 || cls2[j] >= ncls2)
+					continue;
+				fmtoff1 = 16 + (cls1[i] * ncls2 + cls2[j]) * vrlen;
+				fmtoff2 = fmtoff1 + valuerecord_len(vfmt1);
+				if (valuerecord_small(vfmt1, sub + fmtoff1) &&
+					valuerecord_small(vfmt2, sub + fmtoff2))
+					continue;
+				printf("gpos %s 2", feat);
+				printf(" %s", glyph_name[gl1[i]]);
+				valuerecord_print(vfmt1, sub + fmtoff1);
+				printf(" %s", glyph_name[gl2[j]]);
+				valuerecord_print(vfmt2, sub + fmtoff2);
+				printf("\n");
+			}
+		}
+	}
 }
 
 static void otf_gpostype3(void *otf, char *feat, char *sub)
@@ -559,9 +633,10 @@
 	return 0;
 }
 
-void otf_feat(int r)
+void otf_feat(int r, int k)
 {
 	res = r;
+	kmin = k;
 	if (otf_table(buf, "GSUB"))
 		otf_gsub(buf, otf_table(buf, "GSUB"));
 	if (otf_table(buf, "GPOS"))