Complexity cleanup
This commit is contained in:
parent
f38901ba7a
commit
97920d0f4d
4 changed files with 212 additions and 192 deletions
|
@ -18,6 +18,7 @@
|
|||
"no-console": 0,
|
||||
"no-constant-condition": ["error", { "checkLoops": false }],
|
||||
"no-mixed-spaces-and-tabs": ["error", "smart-tabs"],
|
||||
"no-unused-vars": ["off"]
|
||||
"no-unused-vars": ["off"],
|
||||
"complexity": ["warn", 16]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,78 +3,22 @@
|
|||
const { Radical } = require("../../support/gr");
|
||||
|
||||
module.exports = function gcFont(glyphStore, excludedChars, restFont, cfg) {
|
||||
markSweepOtl(restFont.GSUB);
|
||||
markSweepOtl(restFont.GPOS);
|
||||
const sink = mark(glyphStore, excludedChars, restFont, cfg);
|
||||
markSweepOtlLookups(restFont.GSUB);
|
||||
markSweepOtlLookups(restFont.GPOS);
|
||||
const sink = markGlyphs(glyphStore, excludedChars, restFont, cfg);
|
||||
return sweep(glyphStore, sink);
|
||||
};
|
||||
|
||||
function markSweepOtl(table) {
|
||||
function markSweepOtlLookups(table) {
|
||||
if (!table || !table.features || !table.lookups) return;
|
||||
const accessibleLookupsIds = new Set();
|
||||
markLookups(table, accessibleLookupsIds);
|
||||
let lookups1 = {};
|
||||
for (const l in table.lookups) {
|
||||
if (accessibleLookupsIds.has(l)) lookups1[l] = table.lookups[l];
|
||||
}
|
||||
table.lookups = lookups1;
|
||||
|
||||
let features1 = {};
|
||||
for (let f in table.features) {
|
||||
const feature = table.features[f];
|
||||
if (!feature) continue;
|
||||
const featureFiltered = [];
|
||||
for (const l of feature) if (accessibleLookupsIds.has(l)) featureFiltered.push(l);
|
||||
if (!featureFiltered.length) continue;
|
||||
features1[f] = featureFiltered;
|
||||
}
|
||||
table.features = features1;
|
||||
sweepLookups(table, accessibleLookupsIds);
|
||||
sweepFeatures(table, accessibleLookupsIds);
|
||||
}
|
||||
|
||||
function mark(glyphStore, excludedChars, restFont, cfg) {
|
||||
const sink = markInitial(glyphStore, excludedChars);
|
||||
while (markStep(glyphStore, sink, restFont, cfg));
|
||||
return sink;
|
||||
}
|
||||
|
||||
function markInitial(glyphStore, excludedChars) {
|
||||
let sink = new Set();
|
||||
for (const [gName, g] of glyphStore.namedEntries()) {
|
||||
if (!g) continue;
|
||||
if (g.glyphRank > 0) sink.add(gName);
|
||||
if (Radical.get(g)) sink.add(gName);
|
||||
const unicodeSet = glyphStore.queryUnicodeOf(g);
|
||||
if (unicodeSet) {
|
||||
for (const u of unicodeSet) {
|
||||
if (!excludedChars.has(u)) sink.add(gName);
|
||||
}
|
||||
}
|
||||
}
|
||||
return sink;
|
||||
}
|
||||
|
||||
function markStep(glyphStore, sink, restFont, cfg) {
|
||||
const glyphCount = sink.size;
|
||||
if (restFont.GSUB) {
|
||||
for (const l in restFont.GSUB.lookups) {
|
||||
const lookup = restFont.GSUB.lookups[l];
|
||||
if (!lookup || !lookup.subtables) continue;
|
||||
for (let st of lookup.subtables) {
|
||||
markSubtable(sink, lookup.type, st, cfg);
|
||||
}
|
||||
}
|
||||
}
|
||||
const glyphCount1 = sink.size;
|
||||
return glyphCount1 > glyphCount;
|
||||
}
|
||||
|
||||
function markLookups(table, sink) {
|
||||
if (!table || !table.features) return;
|
||||
for (let f in table.features) {
|
||||
const feature = table.features[f];
|
||||
if (!feature) continue;
|
||||
for (const l of feature) sink.add(l);
|
||||
}
|
||||
markLookupsStart(table, sink);
|
||||
let loop = 0,
|
||||
lookupSetChanged = false;
|
||||
do {
|
||||
|
@ -94,38 +38,111 @@ function markLookups(table, sink) {
|
|||
lookupSetChanged = sizeBefore !== sink.size;
|
||||
} while (loop < 0xff && lookupSetChanged);
|
||||
}
|
||||
function markLookupsStart(table, sink) {
|
||||
for (let f in table.features) {
|
||||
const feature = table.features[f];
|
||||
if (!feature) continue;
|
||||
for (const l of feature) sink.add(l);
|
||||
}
|
||||
}
|
||||
function sweepLookups(table, accessibleLookupsIds) {
|
||||
let lookups1 = {};
|
||||
for (const l in table.lookups) {
|
||||
if (accessibleLookupsIds.has(l)) lookups1[l] = table.lookups[l];
|
||||
}
|
||||
table.lookups = lookups1;
|
||||
return accessibleLookupsIds;
|
||||
}
|
||||
function sweepFeatures(table, accessibleLookupsIds) {
|
||||
let features1 = {};
|
||||
for (let f in table.features) {
|
||||
const feature = table.features[f];
|
||||
if (!feature) continue;
|
||||
const featureFiltered = [];
|
||||
for (const l of feature) if (accessibleLookupsIds.has(l)) featureFiltered.push(l);
|
||||
if (!featureFiltered.length) continue;
|
||||
features1[f] = featureFiltered;
|
||||
}
|
||||
table.features = features1;
|
||||
}
|
||||
|
||||
function markSubtable(sink, type, st, cfg) {
|
||||
function markGlyphs(glyphStore, excludedChars, restFont, cfg) {
|
||||
const sink = markGlyphsInitial(glyphStore, excludedChars);
|
||||
while (markGlyphsStep(glyphStore, sink, restFont, cfg));
|
||||
return sink;
|
||||
}
|
||||
function markGlyphsInitial(glyphStore, excludedChars) {
|
||||
let sink = new Set();
|
||||
for (const [gName, g] of glyphStore.namedEntries()) {
|
||||
if (!g) continue;
|
||||
if (g.glyphRank > 0) sink.add(gName);
|
||||
if (Radical.get(g)) sink.add(gName);
|
||||
const unicodeSet = glyphStore.queryUnicodeOf(g);
|
||||
if (unicodeSet) {
|
||||
for (const u of unicodeSet) {
|
||||
if (!excludedChars.has(u)) sink.add(gName);
|
||||
}
|
||||
}
|
||||
}
|
||||
return sink;
|
||||
}
|
||||
function markGlyphsStep(glyphStore, sink, restFont, cfg) {
|
||||
const glyphCount = sink.size;
|
||||
if (restFont.GSUB) {
|
||||
for (const l in restFont.GSUB.lookups) {
|
||||
const lookup = restFont.GSUB.lookups[l];
|
||||
if (!lookup || !lookup.subtables) continue;
|
||||
for (let st of lookup.subtables) {
|
||||
markGlyphsSubtable(sink, lookup.type, st, cfg);
|
||||
}
|
||||
}
|
||||
}
|
||||
const glyphCount1 = sink.size;
|
||||
return glyphCount1 > glyphCount;
|
||||
}
|
||||
|
||||
function markGlyphsSubtable(sink, type, st, cfg) {
|
||||
switch (type) {
|
||||
case "gsub_single":
|
||||
for (const k in st) if (sink.has(k) && st[k]) sink.add(st[k]);
|
||||
break;
|
||||
return markGlyphsGsubSingle(sink, st, cfg);
|
||||
case "gsub_multiple":
|
||||
for (const k in st) if (sink.has(k) && st[k]) for (const g of st[k]) sink.add(g);
|
||||
break;
|
||||
return markGlyphsGsubMultiple(sink, st, cfg);
|
||||
case "gsub_alternate":
|
||||
return markGlyphsGsubAlternate(sink, st, cfg);
|
||||
case "gsub_ligature":
|
||||
return markGlyphsGsubLigature(sink, st, cfg);
|
||||
case "gsub_chaining":
|
||||
break;
|
||||
case "gsub_reverse":
|
||||
return markGlyphsGsubReverse(sink, st, cfg);
|
||||
}
|
||||
}
|
||||
|
||||
function markGlyphsGsubSingle(sink, st, cfg) {
|
||||
for (const k in st) if (sink.has(k) && st[k]) sink.add(st[k]);
|
||||
}
|
||||
function markGlyphsGsubMultiple(sink, st, cfg) {
|
||||
for (const k in st) if (sink.has(k) && st[k]) for (const g of st[k]) sink.add(g);
|
||||
}
|
||||
function markGlyphsGsubAlternate(sink, st, cfg) {
|
||||
if (!cfg || !cfg.ignoreAltSub) {
|
||||
for (const k in st) if (sink.has(k) && st[k]) for (const g of st[k]) sink.add(g);
|
||||
}
|
||||
break;
|
||||
case "gsub_ligature":
|
||||
}
|
||||
function markGlyphsGsubLigature(sink, st, cfg) {
|
||||
for (const sub of st.substitutions) {
|
||||
let check = true;
|
||||
for (const g of sub.from) if (!sink.has(g)) check = false;
|
||||
if (check && sub.to) sink.add(sub.to);
|
||||
}
|
||||
break;
|
||||
case "gsub_chaining":
|
||||
break;
|
||||
case "gsub_reverse":
|
||||
}
|
||||
function markGlyphsGsubReverse(sink, st, cfg) {
|
||||
if (st.match && st.to) {
|
||||
const matchCoverage = st.match[st.inputIndex];
|
||||
for (let j = 0; j < matchCoverage.length; j++) {
|
||||
if (sink.has(matchCoverage[j]) && st.to[j]) sink.add(st.to[j]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function sweep(glyphStore, gnSet) {
|
||||
|
|
|
@ -25,6 +25,11 @@ module.exports = async function (charMapPath, charMapItalicPath, charMapObliqueP
|
|||
};
|
||||
|
||||
function getSupportedLanguageSet(rawCoverage) {
|
||||
const supportLocaleSet = getSupportLocaleSet(rawCoverage);
|
||||
addSimilarLocales(supportLocaleSet);
|
||||
return getSupportedLangs(supportLocaleSet);
|
||||
}
|
||||
function getSupportLocaleSet(rawCoverage) {
|
||||
const supportLocaleSet = new Set();
|
||||
|
||||
for (const locale of cldr.localeIds) {
|
||||
|
@ -52,6 +57,9 @@ function getSupportedLanguageSet(rawCoverage) {
|
|||
supportLocaleSet.add(locale);
|
||||
}
|
||||
}
|
||||
return supportLocaleSet;
|
||||
}
|
||||
function addSimilarLocales(supportLocaleSet) {
|
||||
for (const loc of supportLocaleSet) {
|
||||
const seg = loc.split("_");
|
||||
if (seg.length < 2) continue;
|
||||
|
@ -62,6 +70,8 @@ function getSupportedLanguageSet(rawCoverage) {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
function getSupportedLangs(supportLocaleSet) {
|
||||
const supportLangSet = new Set(overrideSupportedLanguages);
|
||||
for (const loc of supportLocaleSet) {
|
||||
const seg = loc.split("_");
|
||||
|
@ -74,7 +84,6 @@ function getSupportedLanguageSet(rawCoverage) {
|
|||
}
|
||||
if (displayName) supportLangSet.add(displayName);
|
||||
}
|
||||
|
||||
return supportLangSet;
|
||||
}
|
||||
|
||||
|
|
203
verdafile.js
203
verdafile.js
|
@ -23,11 +23,7 @@ const ARCHIVE_DIR = "release-archives";
|
|||
|
||||
const TTX = "ttx";
|
||||
const PATEL_C = ["node", "./node_modules/patel/bin/patel-c"];
|
||||
const TTCIZE = [
|
||||
"node",
|
||||
"--max-old-space-size=8192",
|
||||
"node_modules/otb-ttc-bundle/bin/otb-ttc-bundle"
|
||||
];
|
||||
const TTCIZE = ["node", "node_modules/otb-ttc-bundle/bin/otb-ttc-bundle"];
|
||||
const webfontFormats = [
|
||||
["woff2", "woff2"],
|
||||
["ttf", "truetype"]
|
||||
|
@ -147,29 +143,6 @@ const BuildPlans = computed("metadata:build-plans", async target => {
|
|||
return { fileNameToBpMap, buildPlans: returnBuildPlans };
|
||||
});
|
||||
|
||||
function validateAndShimBuildPlans(prefix, bp, dWeights, dSlopes, dWidths) {
|
||||
if (!bp.family) {
|
||||
fail(`Build plan for ${prefix} does not have a family name. Exit.`);
|
||||
}
|
||||
if (!bp.slopes && bp.slants) {
|
||||
echo.warn(
|
||||
`Build plan for ${prefix} uses legacy "slants" to define slopes. ` +
|
||||
`Use "slopes" instead.`
|
||||
);
|
||||
}
|
||||
|
||||
if (!bp.pre) bp.pre = {};
|
||||
|
||||
if (!bp.pre.design) bp.pre.design = bp.design || [];
|
||||
if (!bp.pre.upright) bp.pre.upright = bp.upright || [];
|
||||
if (!bp.pre.oblique) bp.pre.oblique = bp.oblique || [];
|
||||
if (!bp.pre.italic) bp.pre.italic = bp.italic || [];
|
||||
|
||||
bp.weights = bp.weights || dWeights;
|
||||
bp.slopes = bp.slopes || bp.slants || dSlopes;
|
||||
bp.widths = bp.widths || dWidths;
|
||||
}
|
||||
|
||||
const BuildPlanOf = computed.group("metadata:build-plan-of", async (target, gid) => {
|
||||
const [{ buildPlans }] = await target.need(BuildPlans);
|
||||
const plan = buildPlans[gid];
|
||||
|
@ -241,29 +214,32 @@ function getSuffixMapping(weights, slopes, widths) {
|
|||
for (const s in slopes) {
|
||||
for (const wd in widths) {
|
||||
const suffix = makeSuffix(w, wd, s, DEFAULT_SUBFAMILY);
|
||||
mapping[suffix] = {
|
||||
weight: w,
|
||||
shapeWeight: nValidate("Shape weight of " + w, weights[w].shape, vlShapeWeight),
|
||||
cssWeight: nValidate("CSS weight of " + w, weights[w].css, vlCssWeight),
|
||||
menuWeight: nValidate("Menu weight of " + w, weights[w].menu, vlMenuWeight),
|
||||
width: wd,
|
||||
shapeWidth: nValidate(
|
||||
"Shape width of " + wd,
|
||||
widths[wd].shape,
|
||||
vlShapeWidth,
|
||||
fixShapeWidth
|
||||
),
|
||||
cssStretch: widths[wd].css || wd,
|
||||
menuWidth: nValidate("Menu width of " + wd, widths[wd].menu, vlMenuWidth),
|
||||
slope: s,
|
||||
cssStyle: slopes[s] || s,
|
||||
menuSlope: slopes[s] || s
|
||||
};
|
||||
mapping[suffix] = getSuffixMappingItem(weights, w, slopes, s, widths, wd);
|
||||
}
|
||||
}
|
||||
}
|
||||
return mapping;
|
||||
}
|
||||
function getSuffixMappingItem(weights, w, slopes, s, widths, wd) {
|
||||
return {
|
||||
// Weights
|
||||
weight: w,
|
||||
shapeWeight: nValidate("Shape weight of " + w, weights[w].shape, VlShapeWeight),
|
||||
cssWeight: nValidate("CSS weight of " + w, weights[w].css, VlCssWeight),
|
||||
menuWeight: nValidate("Menu weight of " + w, weights[w].menu, VlMenuWeight),
|
||||
|
||||
// Widths
|
||||
width: wd,
|
||||
shapeWidth: nValidate("Shape width of " + wd, widths[wd].shape, VlShapeWidth),
|
||||
cssStretch: widths[wd].css || wd,
|
||||
menuWidth: nValidate("Menu width of " + wd, widths[wd].menu, VlMenuWidth),
|
||||
|
||||
// Slopes
|
||||
slope: s,
|
||||
cssStyle: slopes[s] || s,
|
||||
menuSlope: slopes[s] || s
|
||||
};
|
||||
}
|
||||
|
||||
function makeFileName(prefix, suffix) {
|
||||
return prefix + "-" + suffix;
|
||||
|
@ -276,65 +252,6 @@ function makeSuffix(w, wd, s, fallback) {
|
|||
);
|
||||
}
|
||||
|
||||
function validateRecommendedWeight(w, value, label) {
|
||||
if (recommendedMenuWeights[w] && recommendedMenuWeights[w] !== value) {
|
||||
echo.warn(
|
||||
`${label} weight settings of ${w} ( = ${value}) doesn't match ` +
|
||||
`the recommended value ( = ${recommendedMenuWeights[w]}).`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function nValidate(key, v, f, ft) {
|
||||
if (ft) v = ft(v);
|
||||
if (typeof v !== "number" || !isFinite(v) || (f && !f(v))) {
|
||||
throw new TypeError(`${key} = ${v} is not a valid number.`);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
function vlShapeWeight(x) {
|
||||
return x >= 100 && x <= 900;
|
||||
}
|
||||
function vlCssWeight(x) {
|
||||
return x > 0 && x < 1000;
|
||||
}
|
||||
function vlMenuWeight(x) {
|
||||
return vlCssWeight(x);
|
||||
}
|
||||
const g_widthFixupMemory = new Map();
|
||||
function fixShapeWidth(x) {
|
||||
if (x >= 3 && x <= 9) {
|
||||
if (g_widthFixupMemory.has(x)) return g_widthFixupMemory.get(x);
|
||||
const xCorrected = Math.round(500 * Math.pow(Math.sqrt(576 / 500), x - 5));
|
||||
echo.warn(
|
||||
`The build plan is using legacy width grade ${x}. ` +
|
||||
`Converting to unit width ${xCorrected}.`
|
||||
);
|
||||
g_widthFixupMemory.set(x, xCorrected);
|
||||
return xCorrected;
|
||||
} else {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
function vlShapeWidth(x) {
|
||||
return x >= 433 && x <= 665;
|
||||
}
|
||||
function vlMenuWidth(x) {
|
||||
return x >= 1 && x <= 9 && x % 1 === 0;
|
||||
}
|
||||
const recommendedMenuWeights = {
|
||||
thin: 100,
|
||||
extralight: 200,
|
||||
light: 300,
|
||||
regular: 400,
|
||||
book: 450,
|
||||
medium: 500,
|
||||
semibold: 600,
|
||||
bold: 700,
|
||||
extrabold: 800,
|
||||
heavy: 900
|
||||
};
|
||||
|
||||
function whyBuildPlanIsnNotThere(gid) {
|
||||
if (!fs.existsSync(PRIVATE_BUILD_PLANS))
|
||||
return "\n -- Possible reason: Config file 'private-build-plans.toml' does not exist.";
|
||||
|
@ -939,3 +856,79 @@ const Parameters = task(`meta:parameters`, async target => {
|
|||
sfu`params/ligation-set.toml`
|
||||
);
|
||||
});
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
////// Config Validation //////
|
||||
///////////////////////////////////////////////////////////
|
||||
|
||||
// Build plan validation
|
||||
function validateAndShimBuildPlans(prefix, bp, dWeights, dSlopes, dWidths) {
|
||||
if (!bp.family) {
|
||||
fail(`Build plan for ${prefix} does not have a family name. Exit.`);
|
||||
}
|
||||
if (!bp.slopes && bp.slants) {
|
||||
echo.warn(
|
||||
`Build plan for ${prefix} uses legacy "slants" to define slopes. ` +
|
||||
`Use "slopes" instead.`
|
||||
);
|
||||
}
|
||||
|
||||
bp.weights = bp.weights || dWeights;
|
||||
bp.slopes = bp.slopes || bp.slants || dSlopes;
|
||||
bp.widths = bp.widths || dWidths;
|
||||
}
|
||||
|
||||
// Recommended weight validation
|
||||
function validateRecommendedWeight(w, value, label) {
|
||||
const RecommendedMenuWeights = {
|
||||
thin: 100,
|
||||
extralight: 200,
|
||||
light: 300,
|
||||
regular: 400,
|
||||
book: 450,
|
||||
medium: 500,
|
||||
semibold: 600,
|
||||
bold: 700,
|
||||
extrabold: 800,
|
||||
heavy: 900
|
||||
};
|
||||
if (RecommendedMenuWeights[w] && RecommendedMenuWeights[w] !== value) {
|
||||
echo.warn(
|
||||
`${label} weight settings of ${w} ( = ${value}) doesn't match ` +
|
||||
`the recommended value ( = ${RecommendedMenuWeights[w]}).`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Value validation
|
||||
function nValidate(key, v, validator) {
|
||||
if (validator.fixup) v = validator.fix(v);
|
||||
if (typeof v !== "number" || !isFinite(v) || !validator.validate(v)) {
|
||||
throw new TypeError(`${key} = ${v} is not a valid number.`);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
const VlShapeWeight = { validate: x => x >= 100 && x <= 900 };
|
||||
const VlCssWeight = { validate: x => x > 0 && x < 1000 };
|
||||
const VlMenuWeight = VlCssWeight;
|
||||
|
||||
const g_widthFixupMemory = new Map();
|
||||
const VlShapeWidth = {
|
||||
validate: x => x >= 433 && x <= 665,
|
||||
fix(x) {
|
||||
if (x >= 3 && x <= 9) {
|
||||
if (g_widthFixupMemory.has(x)) return g_widthFixupMemory.get(x);
|
||||
const xCorrected = Math.round(500 * Math.pow(Math.sqrt(576 / 500), x - 5));
|
||||
echo.warn(
|
||||
`The build plan is using legacy width grade ${x}. ` +
|
||||
`Converting to unit width ${xCorrected}.`
|
||||
);
|
||||
g_widthFixupMemory.set(x, xCorrected);
|
||||
return xCorrected;
|
||||
} else {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
};
|
||||
const VlMenuWidth = { validate: x => x >= 1 && x <= 9 && x % 1 === 0 };
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue