ref: bdd79e148a88c7c6484cf008004e743b4aec2ff4
parent: edb320d46818178c542c7e8a4d1ab37b0c49e1ea
author: Ali Gholami Rudi <ali@rudi.ir>
date: Fri Aug 8 04:59:33 EDT 2014
otf: use ggrp lines to define groups of glyphs Neatroff no longer supports the syntax |glyph for specifying alternative glyphs. That was very inefficient and produced large font descriptions.
--- a/otf.c
+++ b/otf.c
@@ -9,6 +9,7 @@
#define NGLYPHS (1 << 14)
#define GNLEN (64)
#define BUFLEN (1 << 23)
+#define NGRPS 2048
#define MAX(a, b) ((a) < (b) ? (b) : (a))
#define U32(buf, off) (htonl(*(u32 *) ((buf) + (off))))
@@ -268,6 +269,31 @@
return ngl;
}
+static int intcmp(void *v1, void *v2)
+{
+ return *(int *) v1 - *(int *) v2;
+}
+
+int ggrp_make(int *src, int n);
+
+static int ggrp_class(int *src, int *cls, int nsrc, int id)
+{
+ int g[NGLYPHS];
+ int n = 0;
+ int i;
+ for (i = 0; i < nsrc; i++)
+ if (cls[i] == id)
+ g[n++] = src[i];
+ qsort(g, n, sizeof(g[0]), (void *) intcmp);
+ return ggrp_make(g, n);
+}
+
+static int ggrp_coverage(int *g, int n)
+{
+ qsort(g, n, sizeof(g[0]), (void *) intcmp);
+ return ggrp_make(g, n);
+}
+
static int valuerecord_len(int fmt)
{
int off = 0;
@@ -319,7 +345,7 @@
ncov = coverage(sub + U16(sub, 2), cov);
if (fmt == 1) {
for (i = 0; i < ncov; i++) {
- printf("gpos %s 1 =%s", feat, glyph_name[cov[i]]);
+ printf("gpos %s 1 %s", feat, glyph_name[cov[i]]);
valuerecord_print(vfmt, sub + 6);
printf("\n");
}
@@ -327,7 +353,7 @@
if (fmt == 2) {
nvals = U16(sub, 6);
for (i = 0; i < nvals; i++) {
- printf("gpos %s 1 =%s", feat, glyph_name[cov[i]]);
+ printf("gpos %s 1 %s", feat, glyph_name[cov[i]]);
valuerecord_print(vfmt, sub + 8 + i * vlen);
printf("\n");
}
@@ -342,7 +368,7 @@
int vfmt2 = U16(sub, 6); /* valuerecord 2 */
int fmtoff1, fmtoff2;
int vrlen; /* the length of vfmt1 and vfmt2 */
- int i, j, k, l;
+ int i, j;
vrlen = valuerecord_len(vfmt1) + valuerecord_len(vfmt2);
if (fmt == 1) {
int cov[NGLYPHS];
@@ -359,9 +385,9 @@
valuerecord_small(vfmt2, c2 + fmtoff2))
continue;
printf("gpos %s 2", feat);
- printf(" =%s", glyph_name[cov[i]]);
+ printf(" %s", glyph_name[cov[i]]);
valuerecord_print(vfmt1, c2 + fmtoff1);
- printf(" =%s", glyph_name[second]);
+ printf(" %s", glyph_name[second]);
valuerecord_print(vfmt2, c2 + fmtoff2);
printf("\n");
}
@@ -370,41 +396,27 @@
if (fmt == 2) {
int gl1[NGLYPHS], gl2[NGLYPHS];
int cls1[NGLYPHS], cls2[NGLYPHS];
+ int grp1[NGLYPHS], grp2[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 < ncls1; i++)
+ grp1[i] = ggrp_class(gl1, cls1, ngl1, i);
+ for (i = 0; i < ncls2; i++)
+ grp2[i] = ggrp_class(gl2, cls2, ngl2, i);
for (i = 0; i < ncls1; i++) {
for (j = 0; j < ncls2; j++) {
- int n1 = 0, n2 = 0;
fmtoff1 = 16 + (i * ncls2 + j) * vrlen;
fmtoff2 = fmtoff1 + valuerecord_len(vfmt1);
if (valuerecord_small(vfmt1, sub + fmtoff1) &&
valuerecord_small(vfmt2, sub + fmtoff2))
continue;
- for (k = 0; k < ngl1; k++)
- if (cls1[k] == i)
- n1++;
- for (k = 0; k < ngl2; k++)
- if (cls2[k] == j)
- n2++;
- printf("gpos %s %d", feat, n1 + n2);
- l = 0;
- for (k = 0; k < ngl1; k++) {
- if (cls1[k] == i) {
- printf(" %c%s", !l++ ? '=' : '|',
- glyph_name[gl1[k]]);
- valuerecord_print(vfmt1, sub + fmtoff1);
- }
- }
- l = 0;
- for (k = 0; k < ngl2; k++) {
- if (cls2[k] == j) {
- printf(" %c%s", !l++ ? '=' : '|',
- glyph_name[gl2[k]]);
- valuerecord_print(vfmt2, sub + fmtoff2);
- }
- }
+ printf("gpos %s %d", feat, 2);
+ printf(" @%d", grp1[i]);
+ valuerecord_print(vfmt1, sub + fmtoff1);
+ printf(" @%d", grp2[j]);
+ valuerecord_print(vfmt2, sub + fmtoff2);
printf("\n");
}
}
@@ -524,53 +536,38 @@
/* gsub context */
struct gctx {
- int *b[GCTXLEN], blen[GCTXLEN]; /* backtrack coverage arrays */
- int *i[GCTXLEN], ilen[GCTXLEN]; /* input coverage arrays */
- int *l[GCTXLEN], llen[GCTXLEN]; /* lookahead coverage arrays*/
- int bn, in, ln; /* size of b[], i[], l[] */
- int seqidx; /* sequence index */
+ int bgrp[GCTXLEN]; /* backtrack coverage arrays */
+ int igrp[GCTXLEN]; /* input coverage arrays */
+ int lgrp[GCTXLEN]; /* lookahead coverage arrays*/
+ int bn, in, ln; /* size of b[], i[], l[] */
+ int seqidx; /* sequence index */
};
static int gctx_len(struct gctx *ctx, int patlen)
{
- int i, n = 0;
- if (!ctx)
- return 0;
- for (i = 0; i < ctx->bn; i++)
- n += ctx->blen[i];
- for (i = 0; i < ctx->seqidx; i++)
- n += ctx->ilen[i];
- for (i = ctx->seqidx + patlen; i < ctx->in; i++)
- n += ctx->ilen[i];
- for (i = 0; i < ctx->ln; i++)
- n += ctx->llen[i];
- return n;
+ return ctx ? ctx->bn + ctx->in + ctx->ln - patlen : 0;
}
static void gctx_backtrack(struct gctx *ctx)
{
- int i, j;
+ int i;
if (!ctx)
return;
for (i = 0; i < ctx->bn; i++)
- for (j = 0; j < ctx->blen[i]; j++)
- printf(" %c%s", !j ? '=' : '|', glyph_name[ctx->b[i][j]]);
+ printf(" =@%d", ctx->bgrp[i]);
for (i = 0; i < ctx->seqidx; i++)
- for (j = 0; j < ctx->ilen[i]; j++)
- printf(" %c%s", !j ? '=' : '|', glyph_name[ctx->i[i][j]]);
+ printf(" =@%d", ctx->igrp[i]);
}
static void gctx_lookahead(struct gctx *ctx, int patlen)
{
- int i, j;
+ int i;
if (!ctx)
return;
for (i = ctx->seqidx + patlen; i < ctx->in; i++)
- for (j = 0; j < ctx->ilen[i]; j++)
- printf(" %c%s", !j ? '=' : '|', glyph_name[ctx->i[i][j]]);
+ printf(" =@%d", ctx->igrp[i]);
for (i = 0; i < ctx->ln; i++)
- for (j = 0; j < ctx->llen[i]; j++)
- printf(" %c%s", !j ? '=' : '|', glyph_name[ctx->l[i][j]]);
+ printf(" =@%d", ctx->lgrp[i]);
}
/* single substitution */
@@ -660,12 +657,11 @@
/* chaining contextual substitution */
static void otf_gsubtype6(void *otf, void *sub, char *feat, void *gsub)
{
- struct gctx ctx = {{NULL}};
+ struct gctx ctx = {{0}};
void *lookups = gsub + U16(gsub, 8);
int fmt = U16(sub, 0);
- int gbank[NGLYPHS];
- int gbank_pos = 0;
- int n, i, j, nsub;
+ int cov[NGLYPHS];
+ int i, j, nsub, ncov;
int off = 2;
if (fmt != 3) {
otf_unsupported("GSUB", 6, fmt);
@@ -673,26 +669,20 @@
}
ctx.bn = U16(sub, off);
for (i = 0; i < ctx.bn; i++) {
- n = coverage(sub + U16(sub, off + 2 + 2 * i), gbank + gbank_pos);
- ctx.b[i] = gbank + gbank_pos;
- ctx.blen[i] = n;
- gbank_pos += n;
+ ncov = coverage(sub + U16(sub, off + 2 + 2 * i), cov);
+ ctx.bgrp[i] = ggrp_coverage(cov, ncov);
}
off += 2 + 2 * ctx.bn;
ctx.in = U16(sub, off);
- for (i = 0; i < ctx.in; i ++) {
- n = coverage(sub + U16(sub, off + 2 + 2 * i), gbank + gbank_pos);
- ctx.i[i] = gbank + gbank_pos;
- ctx.ilen[i] = n;
- gbank_pos += n;
+ for (i = 0; i < ctx.in; i++) {
+ ncov = coverage(sub + U16(sub, off + 2 + 2 * i), cov);
+ ctx.igrp[i] = ggrp_coverage(cov, ncov);
}
off += 2 + 2 * ctx.in;
ctx.ln = U16(sub, off);
for (i = 0; i < ctx.ln; i ++) {
- n = coverage(sub + U16(sub, off + 2 + 2 * i), gbank + gbank_pos);
- ctx.l[i] = gbank + gbank_pos;
- ctx.llen[i] = n;
- gbank_pos += n;
+ ncov = coverage(sub + U16(sub, off + 2 + 2 * i), cov);
+ ctx.lgrp[i] = ggrp_coverage(cov, ncov);
}
off += 2 + 2 * ctx.ln;
nsub = U16(sub, off); /* nsub > 1 is not supported */
@@ -853,6 +843,44 @@
otf_gsub(buf, otf_table(buf, "GSUB"));
if (otf_table(buf, "GPOS"))
otf_gpos(buf, otf_table(buf, "GPOS"));
+}
+
+/* glyph groups */
+static int *ggrp_g[NGRPS];
+static int ggrp_len[NGRPS];
+static int ggrp_n;
+
+static int ggrp_find(int *src, int n)
+{
+ int i, j;
+ for (i = 0; i < ggrp_n; i++) {
+ if (ggrp_len[i] == n) {
+ for (j = 0; j < n; j++)
+ if (src[j] != ggrp_g[i][j])
+ break;
+ if (j == n)
+ return i;
+ }
+ }
+ return -1;
+}
+
+int ggrp_make(int *src, int n)
+{
+ int id = ggrp_find(src, n);
+ int i;
+ if (id >= 0)
+ return id;
+ id = ggrp_n++;
+ ggrp_g[id] = malloc(n * sizeof(ggrp_g[id][0]));
+ ggrp_len[id] = n;
+ for (i = 0; i < n; i++)
+ ggrp_g[id][i] = src[i];
+ printf("ggrp %d %d", id, n);
+ for (i = 0; i < n; i++)
+ printf(" %s", glyph_name[src[i]]);
+ printf("\n");
+ return id;
}
static char *macset[] = {