Website: add multiple-dimensional variation export

This commit is contained in:
be5invis 2020-07-26 18:20:45 -07:00
parent 6b853b520b
commit 1130f0bee6
3 changed files with 69 additions and 63 deletions

View file

@ -7,7 +7,7 @@ const BuildFont = require("./gen/build-font.js");
const Parameters = require("./support/parameters");
const FormVariantData = require("./support/variant-data");
const FormLigationData = require("./support/ligation-data");
const { AnyCv, CvDecompose } = require("./support/gr");
const { createGrDisplaySheet } = require("./support/gr");
const Toml = require("@iarna/toml");
module.exports = async function main(argv) {
@ -101,33 +101,7 @@ async function saveCharMap(argv, font) {
for (const gid in font.glyf) {
const glyph = font.glyf[gid];
if (!glyph) continue;
const glyphIsHidden = /^\./.test(gid);
const typographicFeatures = [];
if (!glyphIsHidden) {
if (/\.NWID$/.test(gid) || /\.WWID$/.test(gid))
typographicFeatures.push("NWID", "WWID");
if (/\.lnum$/.test(gid) || /\.onum$/.test(gid))
typographicFeatures.push("lnum", "onum");
}
let variantFeatures;
if (CvDecompose.get(glyph)) {
const variantFeatureSet = new Set();
const decomposition = CvDecompose.get(glyph);
for (const gn of decomposition) {
const component = font.glyf[gn];
if (!component) continue;
for (const cv of AnyCv.query(component)) variantFeatureSet.add(cv.tag);
}
variantFeatures = Array.from(variantFeatureSet).sort();
} else {
variantFeatures = AnyCv.query(glyph)
.map(gr => gr.tag)
.sort();
}
charMap.push([glyph.name, glyph.unicode, typographicFeatures, variantFeatures]);
charMap.push([glyph.name, glyph.unicode, ...createGrDisplaySheet(font, gid)]);
}
await fs.writeFile(argv.oCharMap, JSON.stringify(charMap), "utf8");
}

View file

@ -224,6 +224,68 @@ function getGrMesh(gidList, grq, fnGidToGlyph) {
return ret;
}
function createGrDisplaySheet(font, gid) {
const glyph = font.glyf[gid];
if (!glyph) return [];
// Query selected typographic features -- mostly NWID and WWID
let typographicFeatures = [];
queryPairFeatureTags(gid, "NWID", "WWID", typographicFeatures);
queryPairFeatureTags(gid, "lnum", "onum", typographicFeatures);
let charVariantFeatures = [];
const decomposition = CvDecompose.get(glyph);
if (decomposition) {
const variantFeatureSet = new Set();
for (const componentGn of decomposition) {
const component = font.glyf[componentGn];
if (!component) continue;
const cvRow = queryCvFeatureTagsOf(componentGn, component, variantFeatureSet);
if (cvRow.length) charVariantFeatures.push(cvRow);
}
} else {
const cvRow = queryCvFeatureTagsOf(gid, glyph, null);
if (cvRow.length) charVariantFeatures.push(cvRow);
}
return [typographicFeatures, charVariantFeatures];
}
function queryPairFeatureTags(gid, f1, f2, sink) {
const glyphIsHidden = /^\./.test(gid);
if (!glyphIsHidden) {
const re1 = new RegExp(`\\.${f1}$`),
re2 = new RegExp(`\\.${f2}$`);
if (re1.test(gid) || re2.test(gid)) {
sink.push(f1, f2);
}
}
}
function byTagPreference(a, b) {
const ua = a.tag.toUpperCase(),
ub = b.tag.toUpperCase();
if (ua < ub) return -1;
if (ua > ub) return 1;
return 0;
}
function queryCvFeatureTagsOf(gid, glyph, vfs) {
const cvs = AnyCv.query(glyph).sort(byTagPreference);
let results = [];
let existingGlyphs = new Set();
for (const gr of cvs) {
const tag = gr.tag;
const target = gr.get(glyph);
if (target === gid) continue;
if (existingGlyphs.has(target)) continue;
existingGlyphs.add(target);
if (!vfs) results.push(tag);
else if (!vfs.has(tag)) {
results.push(tag);
vfs.add(tag);
}
}
return results;
}
exports.Dotless = Dotless;
exports.Cv = Cv;
exports.AnyCv = AnyCv;
@ -236,3 +298,4 @@ exports.DoNotDeriveVariants = DoNotDeriveVariants;
exports.AnyDerivingCv = AnyDerivingCv;
exports.CcmpDecompose = CcmpDecompose;
exports.CvDecompose = CvDecompose;
exports.createGrDisplaySheet = createGrDisplaySheet;

View file

@ -23,11 +23,6 @@ module.exports = function (covUpright, covItalic, covOblique) {
const [glyphName, typographicVariants, charVariantsUpright] = cdUpright;
const [, , charVariantsItalic] = cdItalic;
const [, , charVariantsOblique] = cdOblique;
const interleaved = interleaveCharacterVariants(
new Set(charVariantsUpright),
new Set(charVariantsItalic),
new Set(charVariantsOblique)
);
blockResults.push({
lch,
gc,
@ -35,10 +30,9 @@ module.exports = function (covUpright, covItalic, covOblique) {
inFont: true,
glyphName: glyphName,
typographicVariants: typographicVariants,
charVariants: interleaved.common,
charVariantsUpright: interleaved.uprightSpecific,
charVariantsItalic: interleaved.italicSpecific,
charVariantsOblique: interleaved.obliqueSpecific
charVariantsUpright,
charVariantsItalic,
charVariantsOblique
});
} else {
blockResults.push({
@ -46,12 +40,7 @@ module.exports = function (covUpright, covItalic, covOblique) {
gc,
charName: chName,
inFont: false,
glyphName: undefined,
typographicVariants: undefined,
charVariants: undefined,
charVariantsUpright: undefined,
charVariantsItalic: undefined,
charVariantsOblique: undefined
glyphName: undefined
});
}
processed.add(lch);
@ -66,23 +55,3 @@ module.exports = function (covUpright, covItalic, covOblique) {
}
return result;
};
function interleaveCharacterVariants(up, it, ob) {
const common = new Set();
for (const cv of up) {
if (it.has(cv) && ob.has(cv)) common.add(cv);
}
const upS = new Set(),
itS = new Set(),
obS = new Set();
for (const cv of up) if (!common.has(cv)) upS.add(cv);
for (const cv of it) if (!common.has(cv)) itS.add(cv);
for (const cv of ob) if (!common.has(cv)) obS.add(cv);
return {
common: [...common],
uprightSpecific: [...upS],
italicSpecific: [...itS],
obliqueSpecific: [...obS]
};
}