ref: cc916744b83db65cc98e88729b1d5ceec0a38ae0
parent: 43cd1d55e135a83bf803145c5bc2f7a9feb9d62e
author: Ali Gholami Rudi <ali@rudi.ir>
date: Fri Aug 8 05:03:22 EDT 2014
font: "ggrp" lines in font descriptions define character groups Neatroff no longer supports the syntax |glyph for specifying alternative glyphs. That was very inefficient and produced large font descriptions. Instead, it is possible to define character groups: ggrp id n gl1 gl2 ... gln In gpos and gsub lines, groups can be referenced using an @: ggrp 25 3 a c o gpos kern 2 T:+0+0-5+0 @25
--- a/font.c
+++ b/font.c
@@ -9,7 +9,7 @@
#define GF_PAT 1 /* gsub/gpos pattern glyph */
#define GF_REP 2 /* gsub replacement glyph */
#define GF_CON 4 /* context glyph */
-#define GF_ALT 8 /* glyph followed by alternative glyphs */
+#define GF_GRP 8 /* glyph group */
/* glyph pattern for gsub and gpos tables; each grule has some gpats */
struct gpat {
@@ -51,6 +51,8 @@
int gsub_n;
struct grule gpos[NGRULES]; /* glyph positioning rules */
int gpos_n;
+ int *ggrp[NGRULES]; /* glyph groups */
+ int ggrp_len[NGRULES];
};
/* find a glyph by its name */
@@ -120,7 +122,7 @@
/* enable/disable pairwise kerning */
static int font_featkn(struct font *fn, int val)
{
- return font_feat(fn, "kern", n_kn);
+ return font_feat(fn, "kern", val);
}
/* glyph index in fn->glyphs[] */
@@ -142,17 +144,15 @@
{
int g1 = -1, g2 = -1;
int i = 0;
- /* finding the first glyph; -1 if it matches more than one glyph */
+ /* finding the first glyph; -1 if FG_GRP */
while (i < rule->len && rule->pats[i].flg & (GF_REP | GF_CON))
i++; /* skipping replacement and context glyphs */
g1 = i < rule->len && rule->pats[i].flg == GF_PAT ? rule->pats[i].g : -1;
- while (g1 < 0 && i < rule->len && rule->pats[i].flg & GF_ALT)
- i++;
i++;
- /* finding the second glyph; -1 if it matches more than one glyph */
+ /* finding the second glyph; -1 if FG_GRP */
while (i < rule->len && rule->pats[i].flg & GF_REP)
i++; /* skipping replacement glyphs */
- g2 = i < rule->len && rule->pats[i].flg == GF_PAT ? rule->pats[i++].g : -1;
+ g2 = i < rule->len && rule->pats[i].flg == GF_PAT ? rule->pats[i].g : -1;
return GHASH(g1, g2);
}
@@ -170,11 +170,21 @@
return rules[l].hash == hash ? l : -1;
}
-static int font_rulematches(struct font *fn, struct grule *rule,
+static int font_gpatmatch(struct font *fn, struct gpat *p, int g)
+{
+ int i;
+ if (!(p->flg & GF_GRP))
+ return p->g == g;
+ for (i = 0; i < fn->ggrp_len[p->g]; i++)
+ if (fn->ggrp[p->g][i] == g)
+ return 1;
+ return 0;
+}
+
+static int font_rulematch(struct font *fn, struct grule *rule,
int *src, int slen, int *dst, int dlen)
{
int sidx = 0; /* the index of matched glyphs in src */
- int didx = 0; /* the index of matched glyphs in dst */
int ncon = 0; /* number of initial context glyphs */
struct gpat *pats = rule->pats;
int j;
@@ -182,8 +192,7 @@
return 0;
/* the number of initial context glyphs */
for (j = 0; j < rule->len && pats[j].flg & GF_CON; j++)
- if (pats[j].flg == GF_CON)
- ncon++;
+ ncon++;
if (dlen < ncon)
return 0;
/* matching the base pattern */
@@ -190,26 +199,14 @@
for (; j < rule->len; j++) {
if (pats[j].flg & GF_REP)
continue;
- if (sidx < slen && pats[j].g == src[sidx]) {
- sidx++;
- while (pats[j].flg & GF_ALT)
- j++;
- } else if (!(pats[j].flg & GF_ALT)) {
+ if (sidx >= slen || !font_gpatmatch(fn, &pats[j], src[sidx]))
return 0;
- }
+ sidx++;
}
- if (j != rule->len)
- return 0;
/* matching the initial context */
- for (j = 0; j < rule->len && pats[j].flg & GF_CON; j++) {
- if (pats[j].g == dst[didx - ncon]) {
- didx++;
- while (pats[j].flg & GF_ALT)
- j++;
- } else if (!(pats[j].flg & GF_ALT)) {
+ for (j = 0; j < rule->len && pats[j].flg & GF_CON; j++)
+ if (!font_gpatmatch(fn, &pats[j], dst[j - ncon]))
return 0;
- }
- }
return 1;
}
@@ -231,7 +228,7 @@
i = j;
if (i < 0)
break;
- if (font_rulematches(fn, rules + idx[i], src, slen, dst, dlen))
+ if (font_rulematch(fn, rules + idx[i], src, slen, dst, dlen))
return rules + idx[i];
idx[i]++;
}
@@ -256,9 +253,9 @@
dmap[ndst] = i;
if (rule) {
for (j = 0; j < rule->len; j++) {
- if (rule->pats[j].flg == GF_REP)
+ if (rule->pats[j].flg & GF_REP)
dst[ndst++] = rule->pats[j].g;
- if (rule->pats[j].flg == GF_PAT)
+ if (rule->pats[j].flg & GF_PAT)
i++;
}
i--;
@@ -275,23 +272,17 @@
for (i = 0; i < ndst; i++)
gdst[i] = fn->glyphs + dst[i];
if (kn)
- font_featkn(fn, 1);
+ featkn = font_featkn(fn, 1);
for (i = 0; i < ndst; i++) {
- int didx = i;
struct grule *rule = font_findrule(fn, fn->gpos, fn->gpos_n,
dst + i, ndst - i, dst + i, i);
if (!rule)
continue;
for (j = 0; j < rule->len; j++) {
- if (rule->pats[j].g == dst[didx]) {
- x[didx] = rule->pats[j].x;
- y[didx] = rule->pats[j].y;
- xadv[didx] = rule->pats[j].xadv;
- yadv[didx] = rule->pats[j].yadv;
- didx++;
- while (rule->pats[j].flg & GF_ALT)
- j++;
- }
+ x[i + j] = rule->pats[j].x;
+ y[i + j] = rule->pats[j].y;
+ xadv[i + j] = rule->pats[j].xadv;
+ yadv[i + j] = rule->pats[j].yadv;
}
}
if (kn)
@@ -382,11 +373,21 @@
return rule;
}
+static int font_readgpat(struct font *fn, struct gpat *p, char *s)
+{
+ if (s[0] == '@') {
+ p->flg |= GF_GRP;
+ p->g = atoi(s + 1);
+ } else {
+ p->g = font_idx(fn, font_glyph(fn, s));
+ }
+ return p->g < 0;
+}
+
static int font_readgsub(struct font *fn, FILE *fin)
{
char tok[128];
struct grule *rule;
- struct glyph *g;
int i, n;
if (fscanf(fin, "%s %d", tok, &n) != 2)
return 1;
@@ -395,9 +396,6 @@
for (i = 0; i < n; i++) {
if (fscanf(fin, "%s", tok) != 1)
return 1;
- if (!tok[0] || !(g = font_glyph(fn, tok + 1)))
- return 0;
- rule->pats[i].g = font_idx(fn, g);
if (tok[0] == '-')
rule->pats[i].flg = GF_PAT;
if (tok[0] == '=')
@@ -404,10 +402,8 @@
rule->pats[i].flg = GF_CON;
if (tok[0] == '+')
rule->pats[i].flg = GF_REP;
- if (i > 0 && tok[0] == '|') {
- rule->pats[i].flg = rule->pats[i - 1].flg;
- rule->pats[i - 1].flg |= GF_ALT;
- }
+ if (!tok[0] || font_readgpat(fn, &rule->pats[i], tok + 1))
+ return 0;
}
return 0;
}
@@ -417,7 +413,6 @@
char tok[128];
char *col;
struct grule *rule;
- struct glyph *g;
int i, n;
if (fscanf(fin, "%s %d", tok, &n) != 2)
return 1;
@@ -429,12 +424,9 @@
col = strchr(tok, ':');
if (col)
*col = '\0';
- if (!(g = font_glyph(fn, tok + 1)))
- return 0;
- rule->pats[i].g = font_idx(fn, g);
rule->pats[i].flg = GF_PAT;
- if (tok[0] == '|' && i > 0)
- rule->pats[i - 1].flg |= GF_ALT;
+ if (!tok[0] || font_readgpat(fn, &rule->pats[i], tok))
+ return 0;
if (col)
sscanf(col + 1, "%hd%hd%hd%hd",
&rule->pats[i].x, &rule->pats[i].y,
@@ -443,6 +435,30 @@
return 0;
}
+static int font_readggrp(struct font *fn, FILE *fin)
+{
+ char tok[ILNLEN];
+ int id, n, i, g;
+ if (fscanf(fin, "%d %d", &id, &n) != 2)
+ return 1;
+ if (id >= LEN(fn->ggrp)) {
+ errmsg("neatroff: NGRULES too low\n");
+ return 0;
+ }
+ if (fn->ggrp[id])
+ free(fn->ggrp[id]);
+ fn->ggrp[id] = xmalloc(n * sizeof(fn->ggrp[id][0]));
+ fn->ggrp_len[id] = 0;
+ for (i = 0; i < n; i++) {
+ if (fscanf(fin, "%s", tok) != 1)
+ return 1;
+ g = font_idx(fn, font_glyph(fn, tok));
+ if (g >= 0)
+ fn->ggrp[id][fn->ggrp_len[id]++] = g;
+ }
+ return 0;
+}
+
static int font_readkern(struct font *fn, FILE *fin)
{
char c1[ILNLEN], c2[ILNLEN];
@@ -522,6 +538,8 @@
font_readgsub(fn, fin);
} else if (!strcmp("gpos", tok)) {
font_readgpos(fn, fin);
+ } else if (!strcmp("ggrp", tok)) {
+ font_readggrp(fn, fin);
} else if (!strcmp("spacewidth", tok)) {
fscanf(fin, "%d", &fn->spacewid);
} else if (!strcmp("special", tok)) {
@@ -560,6 +578,8 @@
free(fn->gsub[i].pats);
for (i = 0; i < fn->gpos_n; i++)
free(fn->gpos[i].pats);
+ for (i = 0; i < LEN(fn->ggrp); i++)
+ free(fn->ggrp[i]);
dict_done(&fn->gdict);
dict_done(&fn->cdict);
free(fn);