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);
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 *);
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");
/* 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"); */
glyphs[i].name, (int)(XSIZE * XPIX),
(int)realglyph(&glyphs[i])->left_sidebearing);
printf(" </hmtx>\n");
+ dogsub();
printf("</ttFont>\n");
return EXIT_SUCCESS;
}
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)
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);
}