ref: 744d1b6b4e6b1f04bdcad77af14771d7e2f3b8ce
parent: 8d156fc62c40b6a7d854c314e5c0ad01c3d4b0d5
author: Ali Gholami Rudi <ali@rudi.ir>
date: Wed Aug 13 06:36:10 EDT 2014
font: perform substitution rules in font order
--- a/font.c
+++ b/font.c
@@ -169,7 +169,7 @@
else
l = m + 1;
}
- return rules[l].hash == hash ? l : -1;
+ return l;
}
static int font_gpatmatch(struct font *fn, struct gpat *p, int g)
@@ -212,83 +212,137 @@
return 1;
}
-static struct grule *font_findrule(struct font *fn, struct grule *rules, int n,
- int *src, int slen, int *dst, int dlen)
+/* perform all possible gpos rules on src */
+static void font_performgpos(struct font *fn, int *src, int slen,
+ int *x, int *y, int *xadv, int *yadv)
{
- int idx[4] = {-1, -1, -1, -1};
- int hash[4];
+ struct grule *gpos = fn->gpos;
+ int n = fn->gpos_n;
+ int i, j, k;
+ for (i = 0; i < slen; i++) {
+ /* possible hash values for matching gpos rules at src + slen */
+ for (j = 0; j < 4 && j < (slen << 1); j++) {
+ int hash = GHASH(j & 1 ? src[i] : -1, j & 2 ? src[i + 1] : -1);
+ int idx = grule_find(gpos, n, hash);
+ while (idx < n && gpos[idx].hash == hash) {
+ if (font_rulematch(fn, &gpos[idx],
+ src + i, slen - i, src + i, i)) {
+ struct gpat *pats = gpos[idx].pats;
+ /* we should accumulate the values... */
+ for (k = 0; k < gpos[idx].len; k++) {
+ x[i + k] = pats[k].x;
+ y[i + k] = pats[k].y;
+ xadv[i + k] = pats[k].xadv;
+ yadv[i + k] = pats[k].yadv;
+ }
+ }
+ idx++;
+ }
+ }
+ }
+}
+
+/* find the first gsub rule after pos that matches any glyph in src */
+static struct grule *font_firstgsub(struct font *fn, int pos, int *src, int slen)
+{
+ struct grule *rules = fn->gsub;
+ int n = fn->gsub_n;
+ struct grule *best = NULL;
int i, j;
- for (j = 0; j < 4 && j < (slen << 1); j++) {
- hash[j] = GHASH(j & 1 ? src[0] : -1, j & 2 ? src[1] : -1);
- idx[j] = grule_find(rules, n, hash[j]);
+ for (i = 0; i < slen; i++) {
+ /* possible hash values for matching gsub rules at src + slen */
+ for (j = 0; j < 2 && i + j < slen; j++) {
+ int hash = GHASH(src[i], j ? src[i + 1] : -1);
+ int idx = grule_find(rules, n, hash);
+ while (idx < n && rules[idx].hash == hash &&
+ (!best || rules[idx].pos < best->pos)) {
+ if (rules[idx].pos >= pos)
+ if (font_rulematch(fn, &rules[idx],
+ src + i, slen - i, src + i, i))
+ best = &rules[idx];
+ idx++;
+ }
+ }
}
- while (1) {
- i = -1; /* finding the first rule among idx[] */
- for (j = 0; j < 4; j++)
- if (idx[j] >= 0 && idx[j] < n && rules[idx[j]].hash == hash[j])
- if (i < 0 || rules[idx[j]].pos <= rules[idx[i]].pos)
- i = j;
- if (i < 0)
- break;
- if (font_rulematch(fn, rules + idx[i], src, slen, dst, dlen))
- return rules + idx[i];
- idx[i]++;
- }
- return NULL;
+ return best;
}
-int font_layout(struct font *fn, struct glyph **gsrc, int nsrc, int sz,
- struct glyph **gdst, int *dmap,
- int *x, int *y, int *xadv, int *yadv, int lg, int kn)
+/* apply the given gsub rule to all matches in src */
+static int font_gsubapply(struct font *fn, struct grule *rule,
+ int *src, int slen, int *smap)
{
- int src[WORDLEN], dst[WORDLEN];
- int ndst = 0;
+ int dst[WORDLEN];
+ int dlen = 0;
+ int dmap[WORDLEN];
int i, j;
- int featlg, featkn;
- for (i = 0; i < nsrc; i++)
- src[i] = font_idx(fn, gsrc[i]);
- if (lg)
- featlg = font_featlg(fn, 3);
- for (i = 0; i < nsrc; i++) {
- struct grule *rule = font_findrule(fn, fn->gsub, fn->gsub_n,
- src + i, nsrc - i, dst + ndst, ndst);
- dmap[ndst] = i;
- if (rule) {
+ memset(dmap, 0, slen * sizeof(dmap[i]));
+ for (i = 0; i < slen; i++) {
+ int hash1 = GHASH(src[i], -1);
+ int hash2 = GHASH(src[i], i + 1 < slen ? src[i + 1] : -1);
+ int hmatch = rule->hash == hash1 || rule->hash == hash2;
+ dmap[dlen] = smap[i];
+ if (hmatch && font_rulematch(fn, rule, src + i,
+ slen - i, dst + dlen, dlen)) {
for (j = 0; j < rule->len; j++) {
if (rule->pats[j].flg & GF_REP)
- dst[ndst++] = rule->pats[j].g;
+ dst[dlen++] = rule->pats[j].g;
if (rule->pats[j].flg & GF_PAT)
i++;
}
i--;
} else {
- dst[ndst++] = src[i];
+ dst[dlen++] = src[i];
}
}
- if (lg)
- font_featlg(fn, featlg);
+ memcpy(src, dst, dlen * sizeof(dst[0]));
+ memcpy(smap, dmap, dlen * sizeof(dmap[0]));
+ return dlen;
+}
+
+/* perform all possible gsub rules on src */
+static int font_performgsub(struct font *fn, int *src, int slen, int *smap)
+{
+ int i = 0;
+ while (i >= 0) {
+ struct grule *rule = font_firstgsub(fn, i, src, slen);
+ if (rule)
+ slen = font_gsubapply(fn, rule, src, slen, smap);
+ i = rule ? rule->pos + 1 : -1;
+ }
+ return slen;
+}
+
+int font_layout(struct font *fn, struct glyph **gsrc, int nsrc, int sz,
+ struct glyph **gdst, int *dmap,
+ int *x, int *y, int *xadv, int *yadv, int lg, int kn)
+{
+ int dst[WORDLEN];
+ int ndst = nsrc;
+ int i;
+ int featlg, featkn;
+ /* initialising dst */
+ for (i = 0; i < nsrc; i++)
+ dst[i] = font_idx(fn, gsrc[i]);
+ for (i = 0; i < ndst; i++)
+ dmap[i] = i;
memset(x, 0, ndst * sizeof(x[0]));
memset(y, 0, ndst * sizeof(y[0]));
memset(xadv, 0, ndst * sizeof(xadv[0]));
memset(yadv, 0, ndst * sizeof(yadv[0]));
- for (i = 0; i < ndst; i++)
- gdst[i] = fn->gl + dst[i];
+ /* substitution rules */
+ if (lg)
+ featlg = font_featlg(fn, 3);
+ ndst = font_performgsub(fn, dst, ndst, dmap);
+ if (lg)
+ font_featlg(fn, featlg);
+ /* positioning rules */
if (kn)
featkn = font_featkn(fn, 1);
- for (i = 0; i < ndst; 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++) {
- 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;
- }
- }
+ font_performgpos(fn, dst, ndst, x, y, xadv, yadv);
if (kn)
font_featkn(fn, featkn);
+ for (i = 0; i < ndst; i++)
+ gdst[i] = fn->gl + dst[i];
return ndst;
}