shithub: neatpost

Download patch

ref: ea0c54be10e8583554cde266847588e0d5734039
parent: c1d1442713a74a60c81bcaab17377916ef5161e2
author: Ali Gholami Rudi <ali@rudi.ir>
date: Fri Mar 30 10:26:25 EDT 2018

font: include only used glyphs in the encoding

--- a/dev.c
+++ b/dev.c
@@ -24,17 +24,22 @@
 	} while (c != '\n' && c != EOF);
 }
 
-int dev_mnt(int pos, char *id, char *name)
+struct font *dev_fontopen(char *name)
 {
 	char path[PATHLEN];
-	struct font *fn;
-	if (pos >= NFONTS)
-		return -1;
 	if (strchr(name, '/'))
 		strcpy(path, name);
 	else
 		sprintf(path, "%s/dev%s/%s", dev_dir, dev_dev, name);
-	fn = font_open(path);
+	return font_open(path);
+}
+
+int dev_mnt(int pos, char *id, char *name)
+{
+	struct font *fn;
+	if (pos >= NFONTS)
+		return -1;
+	fn = dev_fontopen(name);
 	if (!fn)
 		return -1;
 	if (fn_font[pos])
--- a/font.c
+++ b/font.c
@@ -6,6 +6,7 @@
 
 struct font {
 	char name[FNLEN];
+	char desc[1024];
 	char fontname[FNLEN];
 	char fontpath[1024];
 	int spacewid;
@@ -115,6 +116,7 @@
 		return NULL;
 	}
 	memset(fn, 0, sizeof(*fn));
+	snprintf(fn->desc, sizeof(fn->desc), "%s", path);
 	fn->gl_dict = dict_make(-1, 1);
 	fn->ch_dict = dict_make(-1, 1);
 	fn->ch_map = dict_make(-1, 1);
@@ -187,4 +189,9 @@
 struct glyph *font_glget(struct font *fn, int id)
 {
 	return id >= 0 && id < fn->gl_n ? &fn->gl[id] : NULL;
+}
+
+char *font_desc(struct font *fn)
+{
+	return fn->desc;
 }
--- a/pdf.c
+++ b/pdf.c
@@ -14,11 +14,6 @@
 static int obj_sz, obj_n;	/* number of pdf objects */
 static int *page_id;		/* page object ids */
 static int page_sz, page_n;	/* number of pages */
-static char **font_ps;		/* document font names */
-static int *font_id;		/* font object */
-static int *font_ct;		/* font content stream object */
-static int *font_ix;		/* font index */
-static int font_sz, font_n;	/* number of fonts */
 
 static struct sbuf *pg;		/* current page contents */
 static int o_f, o_s, o_m;	/* font and size */
@@ -30,6 +25,26 @@
 static int *o_fs;		/* page fonts */
 static int o_fsn, o_fssz;	/* page fonts */
 
+#define PSFN_MK(fn, ix)		(((fn) << 16) | (ix))
+#define PSFN_FN(fi)		((fi) >> 16)
+#define PSFN_IX(fi)		((fi) & 0xffff)
+
+struct psfont {
+	char name[128];		/* font PostScript name */
+	char path[1024];	/* font path */
+	char desc[1024];	/* font descriptor path */
+	int *gmap;		/* the sub-font assigned to each glyph */
+	int *gpos;		/* the location of the glyph in its sub-font */
+	int gcnt;		/* glyph count */
+	int lastfn;		/* the last sub-font */
+	int lastgl;		/* the number of glyphs in the last subfont */
+	int obj[64];		/* sub-font object ids */
+	int objdes;		/* font descriptor object id */
+};
+
+static struct psfont *psfonts;
+static int psfonts_n, psfonts_sz;
+
 /* print pdf output */
 static void pdfout(char *s, ...)
 {
@@ -65,69 +80,46 @@
 	pdfout("endobj\n\n");
 }
 
-/* embed font; return stream object identifier */
-static int font_outdat(char *path, char *name, int ix)
+void out(char *s, ...)
 {
-	struct sbuf *sb;
-	FILE *fp;
-	int c, i, id;
-	for (i = 0; i < font_n; i++)
-		if (!strcmp(name, font_ps[i]) && font_ct[i] >= 0)
-			return font_ct[i];
-	fp = fopen(path, "r");
-	if (!fp)
-		return -1;
-	sb = sbuf_make();
-	c = fgetc(fp);
-	for (i = 0; c != EOF; i++) {
-		sbuf_printf(sb, "%02x", c);
-		c = fgetc(fp);
-		if (i % 40 == 39 && c != EOF)
-			sbuf_chr(sb, '\n');
-	}
-	sbuf_str(sb, ">\n");
-	fclose(fp);
-	id = obj_beg(0);
-	pdfout("<<\n");
-	pdfout("  /Filter /ASCIIHexDecode\n");
-	pdfout("  /Length %d\n", sbuf_len(sb));
-	pdfout("  /Length1 %d\n", i);
-	pdfout(">>\n");
-	pdfout("stream\n");
-	pdfout("%s", sbuf_buf(sb));
-	pdfout("endstream\n");
-	obj_end();
-	sbuf_free(sb);
-	return id;
 }
 
-/* write the object corresponding to font font_id[f] */
-static void font_out(struct font *fn, int f)
+/* include font descriptor; returns object id */
+static int psfont_writedesc(struct psfont *ps)
 {
-	int i;
-	int enc_obj, des_obj;
-	char *path = font_path(fn);
-	char *ext = path ? strrchr(path, '.') : NULL;
-	/* the encoding object */
-	enc_obj = obj_beg(0);
-	pdfout("<<\n");
-	pdfout("  /Type /Encoding\n");
-	pdfout("  /Differences [ 0");
-	for (i = 0; i < 256; i++) {
-		struct glyph *g = font_glget(fn, font_ix[f] * 256 + i);
-		pdfout(" /%s", g ? g->id : ".notdef");
+	int c, i;
+	int str_obj = -1;
+	int des_obj;
+	char *ext = strrchr(ps->path, '.');
+	if (ext && !strcmp(".ttf", ext)) {
+		FILE *fp = fopen(ps->path, "r");
+		struct sbuf *sb = sbuf_make();
+		c = fgetc(fp);
+		for (i = 0; c != EOF; i++) {
+			sbuf_printf(sb, "%02x", c);
+			c = fgetc(fp);
+			if (i % 40 == 39 && c != EOF)
+				sbuf_chr(sb, '\n');
+		}
+		sbuf_str(sb, ">\n");
+		fclose(fp);
+		str_obj = obj_beg(0);
+		pdfout("<<\n");
+		pdfout("  /Filter /ASCIIHexDecode\n");
+		pdfout("  /Length %d\n", sbuf_len(sb));
+		pdfout("  /Length1 %d\n", i);
+		pdfout(">>\n");
+		pdfout("stream\n");
+		pdfout("%s", sbuf_buf(sb));
+		pdfout("endstream\n");
+		obj_end();
+		sbuf_free(sb);
 	}
-	pdfout(" ]\n");
-	pdfout(">>\n");
-	obj_end();
-	/* embedding the font */
-	if (ext && !strcmp(".ttf", ext))
-		font_ct[f] = font_outdat(path, font_ps[f], font_ix[f]);
 	/* the font descriptor */
 	des_obj = obj_beg(0);
 	pdfout("<<\n");
 	pdfout("  /Type /FontDescriptor\n");
-	pdfout("  /FontName /%s\n", font_ps[f]);
+	pdfout("  /FontName /%s\n", ps->name);
 	pdfout("  /Flags 4\n");
 	pdfout("  /FontBBox [-1000 -1000 1000 1000]\n");
 	pdfout("  /MissingWidth 1000\n");
@@ -136,82 +128,141 @@
 	pdfout("  /CapHeight 100\n");
 	pdfout("  /Ascent 100\n");
 	pdfout("  /Descent 100\n");
-	if (font_ct[f] >= 0)
-		pdfout("  /FontFile2 %d 0 R\n", font_ct[f]);
+	if (str_obj >= 0)
+		pdfout("  /FontFile2 %d 0 R\n", str_obj);
 	pdfout(">>\n");
 	obj_end();
+	return des_obj;
+}
+
+/* write the object corresponding to font font_id[f] */
+static void psfont_write(struct psfont *ps, int ix)
+{
+	int i;
+	int enc_obj;
+	char *ext = strrchr(ps->path, '.');
+	struct font *fn = dev_fontopen(ps->desc);
+	int map[256] = {0};
+	/* finding out the mapping */
+	for (i = 0; i < 256; i++)
+		map[i] = -1;
+	for (i = 0; i < ps->gcnt; i++)
+		if (ps->gmap[i] == ix)
+			map[ps->gpos[i]] = i;
+	/* the encoding object */
+	enc_obj = obj_beg(0);
+	pdfout("<<\n");
+	pdfout("  /Type /Encoding\n");
+	pdfout("  /Differences [ 0");
+	for (i = 0; i < 256; i++)
+		pdfout(" /%s", map[i] >= 0 ? font_glget(fn, map[i])->id : ".notdef");
+	pdfout(" ]\n");
+	pdfout(">>\n");
+	obj_end();
 	/* the font object */
-	obj_beg(font_id[f]);
+	obj_beg(ps->obj[ix]);
 	pdfout("<<\n");
 	pdfout("  /Type /Font\n");
 	pdfout("  /Subtype /%s\n",
 		ext && !strcmp(".ttf", ext) ? "TrueType" : "Type1");
-	pdfout("  /BaseFont /%s\n", font_ps[f]);
+	pdfout("  /BaseFont /%s\n", ps->name);
 	pdfout("  /FirstChar 0\n");
 	pdfout("  /LastChar 255\n");
 	pdfout("  /Widths [");
-	for (i = 0; i < 256; i++) {
-		struct glyph *g = font_glget(fn, font_ix[f] * 256 + i);
-		pdfout(" %d", (g ? g->wid : 0) * dev_res / 72);
-	}
+	for (i = 0; i < 256; i++)
+		pdfout(" %d", (map[i] >= 0 ? font_glget(fn, map[i])->wid : 0)
+				* dev_res / 72);
 	pdfout(" ]\n");
-	pdfout("  /FontDescriptor %d 0 R\n", des_obj);
+	pdfout("  /FontDescriptor %d 0 R\n", ps->objdes);
 	pdfout("  /Encoding %d 0 R\n", enc_obj);
 	pdfout(">>\n");
 	obj_end();
+	font_close(fn);
 }
 
-static int font_put(struct font *fn, int ix)
+static int psfont_find(struct glyph *g)
 {
-	int i;
+	struct font *fn = g->font;
 	char *name = font_name(fn);
-	for (i = 0; i < font_n; i++)
-		if (!strcmp(font_ps[i], font_name(fn)) && font_ix[i] == ix)
-			return i;
-	if (font_n == font_sz) {
-		font_sz += 128;
-		font_id = mextend(font_id, font_n, font_sz, sizeof(font_id[0]));
-		font_ps = mextend(font_ps, font_n, font_sz, sizeof(font_ps[0]));
-		font_ix = mextend(font_ix, font_n, font_sz, sizeof(font_ix[0]));
-		font_ct = mextend(font_ct, font_n, font_sz, sizeof(font_ct[0]));
+	struct psfont *ps = NULL;
+	int gidx;
+	int i;
+	for (i = 0; i < psfonts_n; i++)
+		if (!strcmp(name, psfonts[i].name))
+			break;
+	if (i == psfonts_n) {
+		if (psfonts_n == psfonts_sz) {
+			psfonts_sz += 16;
+			psfonts = mextend(psfonts, psfonts_n,
+					psfonts_sz, sizeof(psfonts[0]));
+		}
+		psfonts_n++;
+		ps = &psfonts[i];
+		snprintf(ps->name, sizeof(ps->name), "%s", name);
+		snprintf(ps->path, sizeof(ps->path), "%s", font_path(fn));
+		snprintf(ps->desc, sizeof(ps->desc), "%s", font_desc(fn));
+		while (font_glget(fn, ps->gcnt))
+			ps->gcnt++;
+		ps->gmap = calloc(ps->gcnt, sizeof(ps->gmap));
+		ps->gpos = calloc(ps->gcnt, sizeof(ps->gpos));
+		ps->lastfn = 0;
+		ps->lastgl = 256;
 	}
-	font_id[font_n] = obj_map();
-	font_ix[font_n] = ix;
-	font_ps[font_n] = malloc(strlen(name) + 1);
-	font_ct[font_n] = -1;
-	strcpy(font_ps[font_n], name);
-	font_n++;
-	font_out(fn, font_n - 1);
-	return font_n - 1;
+	ps = &psfonts[i];
+	gidx = font_glnum(fn, g);
+	if (!ps->gmap[gidx]) {
+		if (ps->lastgl == 256) {
+			ps->lastgl = 0;
+			ps->lastfn++;
+			ps->obj[ps->lastfn] = obj_map();
+		}
+		ps->gmap[gidx] = ps->lastfn;
+		ps->gpos[gidx] = ps->lastgl++;
+	}
+	return PSFN_MK(i, ps->gmap[gidx]);
 }
 
-void out(char *s, ...)
+static int psfont_gpos(struct glyph *g)
 {
+	int fn = psfont_find(g);
+	return psfonts[PSFN_FN(fn)].gpos[font_glnum(g->font, g)];
 }
 
+static void psfont_done(void)
+{
+	int i, j;
+	for (i = 0; i < psfonts_n; i++) {
+		struct psfont *ps = &psfonts[i];
+		ps->objdes = psfont_writedesc(ps);
+		for (j = 1; j <= ps->lastfn; j++)
+			psfont_write(ps, j);
+	}
+	for (i = 0; i < psfonts_n; i++) {
+		free(psfonts[i].gmap);
+		free(psfonts[i].gpos);
+	}
+	free(psfonts);
+}
+
 static void o_flush(void)
 {
 	if (o_queued == 1)
-		sbuf_printf(pg, ") Tj\n");
+		sbuf_printf(pg, "> Tj\n");
 	o_queued = 0;
 }
 
 static int o_loadfont(struct glyph *g)
 {
-	struct font *fn = g ? g->font : dev_font(o_f);
-	int ix = font_glnum(fn, g) / 256;
-	char *name = font_name(fn);
+	int fn = psfont_find(g);
 	int i;
-	int id;
 	for (i = 0; i < o_fsn; i++)
-		if (!strcmp(name, font_ps[o_fs[i]]) && font_ix[o_fs[i]] == ix)
+		if (o_fs[i] == fn)
 			return i;
-	id = font_put(fn, ix);
 	if (o_fsn == o_fssz) {
 		o_fssz += 128;
 		o_fs = mextend(o_fs, o_fsn, o_fssz, sizeof(o_fs[0]));
 	}
-	o_fs[o_fsn++] = id;
+	o_fs[o_fsn++] = fn;
 	return o_fsn - 1;
 }
 
@@ -243,7 +294,6 @@
 
 static void o_queue(struct glyph *g)
 {
-	int pos;
 	if (o_h != p_h || o_v != p_v) {
 		o_flush();
 		sbuf_printf(pg, "1 0 0 1 %s Tm\n", pdfpos(o_h, o_v));
@@ -251,10 +301,9 @@
 		p_v = o_v;
 	}
 	if (!o_queued)
-		sbuf_printf(pg, "(");
+		sbuf_printf(pg, "<");
 	o_queued = 1;
-	pos = font_glnum(g->font, g) % 256;
-	sbuf_printf(pg, "\\%d%d%d", (pos >> 6) & 7, (pos >> 3) & 7, pos & 7);
+	sbuf_printf(pg, "%02x", psfont_gpos(g));
 	p_h += font_wid(g->font, o_s, g->wid);
 }
 
@@ -266,9 +315,10 @@
 		p_m = o_m;
 	}
 	if (o_pf != p_pf || o_s != p_s) {
-		int f = o_fs[o_pf];
+		int fn = PSFN_FN(o_fs[o_pf]);
+		int ix = PSFN_IX(o_fs[o_pf]);
 		o_flush();
-		sbuf_printf(pg, "/%s.%d %d Tf\n", font_ps[f], font_ix[f], o_s);
+		sbuf_printf(pg, "/%s.%d %d Tf\n", psfonts[fn].name, ix, o_s);
 		p_pf = o_pf;
 		p_s = o_s;
 	}
@@ -358,13 +408,6 @@
 static int draw_path;	/* number of path segments */
 static int draw_point;	/* point was set for postscript newpath */
 
-static void drawmv(void)
-{
-	if (!draw_point)
-		sbuf_printf(pg, "%d %d m ", o_h, o_v);
-	draw_point = 1;
-}
-
 void drawbeg(void)
 {
 	o_flush();
@@ -458,6 +501,8 @@
 	pdfout("  /Pages %d 0 R\n", pdf_pages);
 	pdfout(">>\n");
 	obj_end();
+	/* fonts */
+	psfont_done();
 	/* info object */
 	info_id = obj_beg(0);
 	pdfout("<<\n");
@@ -486,12 +531,6 @@
 	pdfout("%%%%EOF\n");
 	free(page_id);
 	free(obj_off);
-	for (i = 0; i < font_n; i++)
-		free(font_ps[i]);
-	free(font_ps);
-	free(font_ct);
-	free(font_id);
-	free(font_ix);
 }
 
 void ps_pagebeg(int n)
@@ -526,9 +565,12 @@
 	pdfout("  /Parent %d 0 R\n", pdf_pages);
 	pdfout("  /Resources <<\n");
 	pdfout("    /Font <<");
-	for (i = 0; i < o_fsn; i++)
+	for (i = 0; i < o_fsn; i++) {
+		int fn = PSFN_FN(o_fs[i]);
+		int ix = PSFN_IX(o_fs[i]);
 		pdfout(" /%s.%d %d 0 R",
-			font_ps[o_fs[i]], font_ix[o_fs[i]], font_id[o_fs[i]]);
+			psfonts[fn].name, ix, psfonts[fn].obj[ix]);
+	}
 	pdfout(" >>\n");
 	pdfout("  >>\n");
 	pdfout("  /Contents %d 0 R\n", cont_id);
--- a/post.h
+++ b/post.h
@@ -32,6 +32,7 @@
 struct font *dev_font(int fn);
 int dev_fontid(struct font *fn);
 struct glyph *dev_glyph(char *c, int fn);
+struct font *dev_fontopen(char *name);
 
 /* font-related functions */
 struct font *font_open(char *path);
@@ -44,6 +45,7 @@
 char *font_path(struct font *fn);
 int font_glnum(struct font *fn, struct glyph *g);
 struct glyph *font_glget(struct font *fn, int id);
+char *font_desc(struct font *fn);
 
 /* output functions */
 void out(char *s, ...);