chiark / gitweb /
'aalt' feature implemented via TTX
authorBen Harris <bjh21@bjh21.me.uk>
Tue, 5 Nov 2024 23:57:51 +0000 (23:57 +0000)
committerBen Harris <bjh21@bjh21.me.uk>
Thu, 14 Nov 2024 22:27:18 +0000 (22:27 +0000)
bedstead.c

index 324490b367ef8da522621bf2e66a8c40cec9ac6a..b82753bdbe4c489cd84057deaf2f00551346dc52 100644 (file)
@@ -2620,27 +2620,38 @@ static int const nglyphs = NGLYPHS;
 
 static struct glyph const *glyphs_by_name[NGLYPHS];
 
-static struct gsub_lookup {
+static struct gsub_feature {
        char const *tag;
-       char const *suffix;
+       char const *suffix; /* NULL for all alternative glyphs. */
 #define SCRIPT_DFLT 0x01
 #define SCRIPT_LATN 0x02
-#define SCRIPT_ALL  0x03       
+#define SCRIPT_ALL  0x03
        unsigned int scripts;
        char const *name;
-} const gsub_lookups[] = {
-       { "aalt", NULL,      SCRIPT_ALL },
-       { "smcp", "sc",      SCRIPT_LATN },
-       { "c2sc", "c2sc",    SCRIPT_LATN },
-       { "rtlm", "rtlm",    SCRIPT_ALL },
-       { "ss01", "saa5051", SCRIPT_ALL, "SAA5051" },
-       { "ss02", "saa5052", SCRIPT_ALL, "SAA5052" },
-       { "ss04", "saa5054", SCRIPT_ALL, "SAA5054" },
-       { "ss14", "sep4",    SCRIPT_ALL, "4-cell separated graphics" },
-       { "ss16", "sep6",    SCRIPT_ALL, "6-cell separated graphics" },
+} const gsub_features[] = {
+       { "aalt", NULL,       SCRIPT_ALL },
+       { "smcp", ".sc",      SCRIPT_LATN },
+       { "c2sc", ".c2sc",    SCRIPT_LATN },
+       { "rtlm", ".rtlm",    SCRIPT_ALL },
+       { "ss01", ".saa5051", SCRIPT_ALL, "SAA5051" },
+       { "ss02", ".saa5052", SCRIPT_ALL, "SAA5052" },
+       { "ss04", ".saa5054", SCRIPT_ALL, "SAA5054" },
+       { "ss14", ".sep4",    SCRIPT_ALL, "4-cell separated graphics" },
+       { "ss16", ".sep6",    SCRIPT_ALL, "6-cell separated graphics" },
+};
+
+static int const ngsub_features =
+       sizeof(gsub_features) / sizeof(gsub_features[0]);
+
+struct gsub_script {
+       char const *tag;
+       unsigned int flag;
+} const gsub_scripts[] = {
+       { "DFLT", SCRIPT_DFLT },
+       { "latn", SCRIPT_LATN },
 };
 
-#define NGSUB_LOOKUPS (sizeof(gsub_lookups) / sizeof(gsub_lookups[0]))
+static int const ngsub_scripts = sizeof(gsub_scripts) / sizeof(gsub_scripts[0]);
 
 static void dochar(struct glyph *g);
 static void dochar_plotter(struct glyph *g);
@@ -2648,6 +2659,8 @@ static void domosaic(struct glyph *g);
 static void domosaic4(struct glyph *g);
 static void dopanose(void);
 static void docmap(int pid, int eid, int format);
+static void dogsub(void);
+static void doaltsubs(void);
 static void glyph_complement(void);
 static void bdf_gen(int size);
 static void dolookups(struct glyph *);
@@ -3017,9 +3030,9 @@ main(int argc, char **argv)
        NAME(6, fullname_to_fontname(get_fullname()));
        /* Stylistic set names. */
 #define NAMEBASE_GSUB 0x100
-       for (i = 0; i < NGSUB_LOOKUPS; i++)
-               if (gsub_lookups[i].name != NULL)
-                       NAME(NAMEBASE_GSUB + i, gsub_lookups[i].name);
+       for (i = 0; i < ngsub_features; i++)
+               if (gsub_features[i].name != NULL)
+                       NAME(NAMEBASE_GSUB + i, gsub_features[i].name);
        printf(" </name>\n");
 
        printf(" <cmap><tableVersion version='0'/>\n");
@@ -3071,8 +3084,6 @@ main(int argc, char **argv)
        /*      printf("StrokedFont: 1\n"); */
        /*      printf("StrokeWidth: 50\n"); */
        /* } */
-       /* printf("Lookup: 3 0 0 \"aalt: all alternates\" {\"aalt\"} " */
-       /*     "['aalt' ('DFLT' <'dflt'> 'latn' <'dflt'>)]\n"); */
        /* printf("Lookup: 1 0 0 \"smcp: lower-case to small caps\" " */
        /*     "{\"smcp\" (\"sc\")} " */
        /*     "['smcp' ('latn' <'dflt'>)]\n"); */
@@ -3141,6 +3152,7 @@ main(int argc, char **argv)
                       glyphs[i].name, (int)(XSIZE * XPIX),
                       (int)realglyph(&glyphs[i])->left_sidebearing);
        printf(" </hmtx>\n");
+       dogsub();
        printf("</ttFont>\n");
        return EXIT_SUCCESS;
 }
@@ -3317,6 +3329,93 @@ docmap(int pid, int eid, int format)
        printf("  </cmap_format_%d>\n", format);
 }
 
+static void
+dogsub(void)
+{
+       int i, j;
+
+       printf(" <GSUB>\n");
+       TTXS(Version, "0x00010000");
+       printf("  <ScriptList>\n");
+       for (i = 0; i < ngsub_scripts; i++) {
+               printf("   <ScriptRecord>\n");
+               TTXS(ScriptTag, gsub_scripts[i].tag);
+               printf("    <Script><DefaultLangSys>\n");
+               TTXI(ReqFeatureIndex, 0xffff); /* No required feature. */
+               for (j = 0; j < ngsub_features; j++)
+                       if (gsub_features[j].scripts & gsub_scripts[i].flag)
+                               TTXI(FeatureIndex, j);
+               printf("    </DefaultLangSys></Script>\n");
+               printf("   </ScriptRecord>\n");
+       }
+       printf("  </ScriptList>\n");
+       printf("  <FeatureList>\n");
+       for (i = 0; i < ngsub_features; i++) {
+               printf("    <FeatureRecord>\n");
+               TTXS(FeatureTag, gsub_features[i].tag);
+               printf("     <Feature>\n");
+               if (gsub_features[i].name != NULL) {
+                       printf("      <FeatureParamsStylisticSet>\n");
+                       TTXI(Version, 0);
+                       TTXI(UINameID, NAMEBASE_GSUB + i);
+                       printf("      </FeatureParamsStylisticSet>\n");
+               }
+               /* We only have one GSUB lookup per feature, thankfully. */
+               TTXI(LookupListIndex, i);
+               printf("     </Feature>\n");
+               printf("    </FeatureRecord>\n");
+       }
+       printf("  </FeatureList>\n");
+       printf("  <LookupList>\n");
+       for (i = 0; i < ngsub_features; i++) {
+               printf("    <Lookup>\n");
+               if (gsub_features[i].suffix == NULL) {
+                       /* This is 'aalt' */
+                       TTXI(LookupType, 3);
+                       TTXI(LookupFlag, 0);
+                       printf("     <AlternateSubst>\n");
+                       doaltsubs();
+                       printf("     </AlternateSubst>\n");
+               } else {
+                       TTXI(LookupType, 1);
+                       TTXI(LookupFlag, 0);
+                       printf("     <SingleSubst>\n");
+                       printf("     </SingleSubst>\n");
+               }
+               printf("    </Lookup>\n");
+       }
+       printf("  </LookupList>\n");
+       printf(" </GSUB>\n");
+
+}
+
+/* Find all the mappings from normal to alternative glyphs. */
+static void
+doaltsubs(void)
+{
+       int i;
+
+       for (i = 1; i < nglyphs; i++) {
+#define HASDOT(x) (strchr(glyphs_by_name[x]->name, '.') != NULL)
+               /*
+                * We want to map each glyph with a name that doesn't
+                * contain a '.' to all the glyphs whose names start
+                * with that name followed by a '.'.  By sorting them
+                * by name, we guarantee that each qualified glyph
+                * name comes immediately after the unqualified one.
+                * [Does that depend on ASCII ordering?]
+                */
+               if (HASDOT(i)) {
+                       printf("      <AlternateSet glyph='%s'>",
+                              glyphs_by_name[i-1]->name);
+                       for (; i < nglyphs && HASDOT(i); i++)
+                               printf("<Alternate glyph='%s'/>",
+                                      glyphs_by_name[i]->name);
+                       printf("</AlternateSet>\n");
+               }
+       }
+}
+
 /* Emit a charstring for a glyph. */
 static void
 doglyph(struct glyph *g)
@@ -3405,14 +3504,6 @@ dolookups(struct glyph *g)
                if (strcmp((*gp)->name + plen, "rtlm") == 0)
                        printf("Substitution2: \"rtlm\" %s\n", (*gp)->name);
        }
-       if (any_alt) {
-               printf("AlternateSubs2: \"aalt\"");
-               for (gp = found + 1; gp < glyphs_by_name + nglyphs; gp++) {
-                       if (strncmp(prefix, (*gp)->name, plen) != 0) break;
-                       printf(" %s", (*gp)->name);
-               }
-               printf("\n");
-       }
        dopalt(g);
 }