shithub: neatpost

Download patch

ref: c223c57a8b7d86b7e89f74fe3c4b8a5d6af754d1
parent: 8509d0b1f86126dda8af06b928b30d9ca485cc92
author: Ali Gholami Rudi <ali@rudi.ir>
date: Tue Jul 30 11:19:15 EDT 2013

font: update from neatroff

--- a/font.c
+++ b/font.c
@@ -13,10 +13,12 @@
 
 struct glyph *font_find(struct font *fn, char *name)
 {
-	int i;
-	for (i = 0; i < fn->n; i++)
-		if (name[0] == fn->c[i][0] && !strcmp(name, fn->c[i]))
+	int i = fn->head[(unsigned char) name[0]];
+	while (i >= 0) {
+		if (!strcmp(name, fn->c[i]))
 			return fn->g[i];
+		i = fn->next[i];
+	}
 	return NULL;
 }
 
@@ -29,6 +31,57 @@
 	return NULL;
 }
 
+static int font_idx(struct font *fn, struct glyph *g)
+{
+	return g ? g - fn->glyphs : -1;
+}
+
+/*
+ * Given a list of characters in the reverse order, font_lig()
+ * returns the number of characters from the beginning of this
+ * list that form a ligature in this font.  Zero naturally means
+ * no ligature was matched.
+ */
+int font_lig(struct font *fn, char **c, int n)
+{
+	int i;
+	/* concatenated characters in c[], in the correct order */
+	char s[GNLEN * 2] = "";
+	/* b[i] is the number of character of c[] in s + i */
+	int b[GNLEN * 2] = {0};
+	int len = 0;
+	for (i = 0; i < n; i++) {
+		char *cur = c[n - i - 1];
+		b[len] = n - i;
+		strcpy(s + len, cur);
+		len += strlen(cur);
+	}
+	for (i = 0; i < fn->nlig; i++) {
+		int l = strlen(fn->lig[i]);
+		if (b[len - l] && !strcmp(s + len - l, fn->lig[i]))
+			if (font_find(fn, fn->lig[i]))
+				return b[len - l];
+	}
+	return 0;
+}
+
+/* return pairwise kerning value between c1 and c2 */
+int font_kern(struct font *fn, char *c1, char *c2)
+{
+	int i1, i2, i;
+	i1 = font_idx(fn, font_find(fn, c1));
+	i2 = font_idx(fn, font_find(fn, c2));
+	if (i1 < 0 || i2 < 0)
+		return 0;
+	i = fn->knhead[i1];
+	while (i >= 0) {
+		if (fn->knpair[i] == i2)
+			return fn->knval[i];
+		i = fn->knnext[i];
+	}
+	return 0;
+}
+
 static int font_section(struct font *fn, FILE *fin, char *name);
 
 static void font_charset(struct font *fn, FILE *fin)
@@ -64,6 +117,8 @@
 		prev = glyph;
 		strcpy(fn->c[fn->n], name);
 		fn->g[fn->n] = glyph;
+		fn->next[fn->n] = fn->head[(unsigned char) name[0]];
+		fn->head[(unsigned char) name[0]] = fn->n;
 		fn->n++;
 	}
 }
@@ -71,17 +126,22 @@
 static void font_kernpairs(struct font *fn, FILE *fin)
 {
 	char c1[ILNLEN], c2[ILNLEN];
-	int val;
+	int i1, i2, val;
 	while (fscanf(fin, "%s", c1) == 1) {
 		if (!font_section(fn, fin, c1))
 			break;
 		if (fscanf(fin, "%s %d", c2, &val) != 2)
 			break;
-		if (fn->nkern < NKERNS) {
-			strcpy(fn->kern_c1[fn->nkern], c1);
-			strcpy(fn->kern_c2[fn->nkern], c2);
-			fn->kern[fn->nkern] = val;
-			fn->nkern++;
+		if (fn->knn < NKERNS) {
+			i1 = font_idx(fn, font_find(fn, c1));
+			i2 = font_idx(fn, font_find(fn, c2));
+			if (i1 >= 0 && i2 >= 0) {
+				fn->knnext[fn->knn] = fn->knhead[i1];
+				fn->knhead[i1] = fn->knn;
+				fn->knval[fn->knn] = val;
+				fn->knpair[fn->knn] = i2;
+				fn->knn++;
+			}
 		}
 	}
 }
@@ -99,33 +159,18 @@
 	return 1;
 }
 
-/* return 1 if lig is a ligature */
-int font_lig(struct font *fn, char *lig)
-{
-	int i;
-	for (i = 0; i < fn->nlig; i++)
-		if (!strcmp(lig, fn->lig[i]))
-			return font_find(fn, lig) != NULL;
-	return 0;
-}
-
-/* return pairwise kerning value between c1 and c2 */
-int font_kern(struct font *fn, char *c1, char *c2)
-{
-	int i;
-	for (i = 0; i < fn->nkern; i++)
-		if (!strcmp(fn->kern_c1[i], c1) && !strcmp(fn->kern_c2[i], c2))
-			return fn->kern[i];
-	return 0;
-}
-
 struct font *font_open(char *path)
 {
 	struct font *fn = malloc(sizeof(*fn));
 	char tok[ILNLEN];
 	FILE *fin;
+	int i;
 	fin = fopen(path, "r");
 	memset(fn, 0, sizeof(*fn));
+	for (i = 0; i < LEN(fn->head); i++)
+		fn->head[i] = -1;
+	for (i = 0; i < LEN(fn->knhead); i++)
+		fn->knhead[i] = -1;
 	while (fscanf(fin, "%s", tok) == 1) {
 		if (tok[0] == '#') {
 			skipline(fin);
@@ -163,6 +208,7 @@
 		}
 		if (!font_section(fn, fin, tok))
 			break;
+		skipline(fin);
 	}
 	fclose(fin);
 	return fn;
--- a/post.h
+++ b/post.h
@@ -1,13 +1,14 @@
 /* predefined array limits */
 #define PATHLEN		1024	/* path length */
 #define NFONTS		32	/* number of fonts */
+#define NGLYPHS		1024	/* glyphs in fonts */
 #define NLIGS		32	/* number of font ligatures */
-#define NKERNS		128	/* number of font pairwise kerning pairs */
+#define NKERNS		512	/* number of font pairwise kerning pairs */
 #define FNLEN		64	/* font name length */
-#define NGLYPHS		512	/* glyphs in fonts */
 #define GNLEN		32	/* glyph name length */
 #define ILNLEN		1000	/* line limit of input files */
 #define LNLEN		4000	/* line buffer length (ren.c/out.c) */
+#define LIGLEN		4	/* length of ligatures */
 
 #define MIN(a, b)	((a) < (b) ? (a) : (b))
 #define MAX(a, b)	((a) < (b) ? (b) : (a))
@@ -37,12 +38,18 @@
 	char c[NGLYPHS][FNLEN];		/* character names in charset */
 	struct glyph *g[NGLYPHS];	/* character glyphs in charset */
 	int n;				/* number of characters in charset */
-	char lig[NLIGS][GNLEN * 4];	/* font ligatures */
+	/* font ligatures */
+	char lig[NLIGS][LIGLEN * GNLEN];
 	int nlig;
-	int kern[NKERNS];		/* font pairwise kerning */
-	char kern_c1[NKERNS][GNLEN];
-	char kern_c2[NKERNS][GNLEN];
-	int nkern;
+	/* glyph list based on the first character of glyph names */
+	int head[256];			/* glyph list head */
+	int next[NGLYPHS];		/* next item in glyph list */
+	/* kerning pair list per glyph */
+	int knhead[NGLYPHS];		/* kerning pairs of glyphs[] */
+	int knnext[NKERNS];		/* next item in knhead[] list */
+	int knpair[NKERNS];		/* kerning pair 2nd glyphs */
+	int knval[NKERNS];		/* font pairwise kerning value */
+	int knn;			/* number of kerning pairs */
 };
 
 /* output device functions */
@@ -60,7 +67,7 @@
 void font_close(struct font *fn);
 struct glyph *font_glyph(struct font *fn, char *id);
 struct glyph *font_find(struct font *fn, char *name);
-int font_lig(struct font *fn, char *c);
+int font_lig(struct font *fn, char **c, int n);
 int font_kern(struct font *fn, char *c1, char *c2);
 
 /* output functions */