ref: dd686dbd3509c79eecd46458dd3a5f367ceee367
parent: 549f1d468ddd93c51785305931a8f15dcea4bfb6
author: Ali Gholami Rudi <ali@rudi.ir>
date: Fri Jun 18 11:27:31 EDT 2021
otf: basic GPOS type 5 table support
--- a/otf.c
+++ b/otf.c
@@ -528,7 +528,9 @@
ccnt = U16(sub, 6);
marks = sub + U16(sub, 8);
bases = sub + U16(sub, 10);
+ /* define a group for base glyphs */
bgrp = ggrp_coverage(bcov, bcnt);
+ /* define a group for each mark class */
for (i = 0; i < ccnt; i++) {
int *grp = malloc(mcnt * sizeof(grp[0]));
int cnt = 0;
@@ -538,6 +540,7 @@
cgrp[i] = ggrp_coverage(grp, cnt);
free(grp);
}
+ /* GPOS rules for each mark after base glyphs */
printf("gsec %d\n", sec);
for (i = 0; i < mcnt; i++) {
void *mark = marks + U16(marks, 2 + 4 * i + 2); /* mark anchor */
@@ -550,6 +553,7 @@
printf("gpos %s 2 @%d %s:%+d%+d%+d%+d\n",
feat, bgrp, glyph_name[mcov[i]], dx, dy, 0, 0);
}
+ /* GPOS rules for each base glyph before a mark */
printf("gsec %d\n", sec + 1);
for (i = 0; i < bcnt; i++) {
for (j = 0; j < ccnt; j++) {
@@ -568,6 +572,80 @@
free(bcov);
}
+/* mark-to-ligature attachment positioning */
+static void otf_gpostype5(struct otf *otf, void *sub, char *feat)
+{
+ int fmt = U16(sub, 0);
+ int *mcov; /* mark coverage */
+ int *lcov; /* ligature coverage */
+ int cgrp[1024]; /* glyph groups assigned to classes */
+ int lgrp; /* the group assigned to base glyphs */
+ int mcnt; /* mark coverage size */
+ int lcnt; /* ligature coverage size */
+ int ccnt; /* class count */
+ void *marks; /* mark array table */
+ void *ligas; /* ligature array table */
+ int i, j, k;
+ /* only marks at the end of ligatures are supported */
+ if (fmt != 1)
+ return;
+ mcov = coverage(sub + U16(sub, 2), &mcnt);
+ lcov = coverage(sub + U16(sub, 4), &lcnt);
+ ccnt = U16(sub, 6);
+ marks = sub + U16(sub, 8);
+ ligas = sub + U16(sub, 10);
+ /* define a group for ligatures */
+ lgrp = ggrp_coverage(lcov, lcnt);
+ /* define a group for each mark class */
+ for (i = 0; i < ccnt; i++) {
+ int *grp = malloc(mcnt * sizeof(grp[0]));
+ int cnt = 0;
+ for (j = 0; j < mcnt; j++)
+ if (U16(marks, 2 + 4 * j) == i)
+ grp[cnt++] = mcov[j];
+ cgrp[i] = ggrp_coverage(grp, cnt);
+ free(grp);
+ }
+ /* GPOS rules for each mark after a ligature */
+ printf("gsec %d\n", sec);
+ for (i = 0; i < mcnt; i++) {
+ void *mark = marks + U16(marks, 2 + 4 * i + 2); /* mark anchor */
+ int dx = -uwid(S16(mark, 2));
+ int dy = -uwid(S16(mark, 4));
+ if (otf_r2l(feat)) {
+ dx += uwid(glyph_wid[mcov[i]]);
+ dy = -dy;
+ }
+ printf("gpos %s 2 @%d %s:%+d%+d%+d%+d\n",
+ feat, lgrp, glyph_name[mcov[i]], dx, dy, 0, 0);
+ }
+ printf("gsec %d\n", sec + 1);
+ /* GPOS rules for each ligature before a mark */
+ for (i = 0; i < lcnt; i++) {
+ void *ligattach = ligas + U16(ligas, 2 + 2 * i);
+ int comcnt = U16(ligattach, 0); /* component count */
+ /* considering only the last component */
+ k = comcnt - 1;
+ if (comcnt == 0)
+ continue;
+ if (!U16(ligattach, 2 + 2 * ccnt * k))
+ continue;
+ for (j = 0; j < ccnt; j++) {
+ char *base = ligattach + U16(ligattach, 2 + 2 * ccnt * k + 2 * j);
+ int dx = uwid(S16(base, 2)) - uwid(glyph_wid[lcov[i]]);
+ int dy = uwid(S16(base, 4));
+ if (otf_r2l(feat)) {
+ dx += uwid(glyph_wid[lcov[i]]);
+ dy = -dy;
+ }
+ printf("gpos %s 2 %s @%d:%+d%+d%+d%+d\n",
+ feat, glyph_name[lcov[i]], cgrp[j], dx, dy, 0, 0);
+ }
+ }
+ free(mcov);
+ free(lcov);
+}
+
/* gsub context */
struct gctx {
int bgrp[GCTXLEN]; /* backtrack coverage arrays */
@@ -892,6 +970,9 @@
break;
case 4:
otf_gpostype4(otf, tab, tag);
+ break;
+ case 5:
+ otf_gpostype5(otf, tab, tag);
break;
default:
otf_unsupported("GPOS", type, 0);