diff --git a/font-src/index.js b/font-src/index.js index 1bb22ee78..bde5f2f3e 100644 --- a/font-src/index.js +++ b/font-src/index.js @@ -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"); } diff --git a/font-src/support/gr.js b/font-src/support/gr.js index b77b14a6c..849c1c910 100644 --- a/font-src/support/gr.js +++ b/font-src/support/gr.js @@ -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; diff --git a/utility/export-data/coverage-export/gather-coverage-data.js b/utility/export-data/coverage-export/gather-coverage-data.js index b48a5ea25..699ad16ac 100644 --- a/utility/export-data/coverage-export/gather-coverage-data.js +++ b/utility/export-data/coverage-export/gather-coverage-data.js @@ -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] - }; -}