117 lines
3.3 KiB
JavaScript
117 lines
3.3 KiB
JavaScript
import ugc from "@unicode/unicode-15.0.0/General_Category/index.js";
|
|
import ucdNames from "@unicode/unicode-15.0.0/Names/index.js";
|
|
|
|
import { collectBlockData } from "./block-data.mjs";
|
|
|
|
function findFirstLastChar(lchBlockStart, lchBlockEnd, cov) {
|
|
let lchFirst = 0,
|
|
lchLast = 0;
|
|
for (const [lchFont] of cov) {
|
|
if (lchFont < 0x20 || lchFont < lchBlockStart || lchFont > lchBlockEnd) continue;
|
|
if (!lchFirst || lchFont < lchFirst) lchFirst = lchFont;
|
|
if (!lchLast || lchFont > lchLast) lchLast = lchFont;
|
|
}
|
|
if (!lchFirst || !lchLast) return [0, 0];
|
|
if (lchBlockEnd - lchBlockStart <= 0x100 && lchBlockStart > 0xff) {
|
|
lchFirst = lchBlockStart;
|
|
lchLast = lchBlockEnd;
|
|
}
|
|
const lchStart = (lchFirst >>> 4) << 4;
|
|
const lchEnd = ((lchLast >>> 4) << 4) + 0x10;
|
|
return [lchStart, lchEnd];
|
|
}
|
|
|
|
export async function gatherCoverageData(covUpright, covItalic, covOblique) {
|
|
const featureSeriesStore = new Map();
|
|
const unicodeCoverage = [];
|
|
|
|
for (const [[lchBlockStart, lchBlockEnd], block] of await collectBlockData()) {
|
|
let blockResults = [];
|
|
const [lchStart, lchEnd] = findFirstLastChar(lchBlockStart, lchBlockEnd, covUpright);
|
|
if (!lchStart || !lchEnd) continue;
|
|
for (let lch = lchStart; lch < lchEnd; lch++) {
|
|
const chName = ucdNames.get(lch);
|
|
const gc = ugc.get(lch);
|
|
const cdUpright = covUpright.get(lch);
|
|
const cdItalic = covItalic.get(lch);
|
|
const cdOblique = covOblique.get(lch);
|
|
if (cdUpright && cdItalic && cdOblique) {
|
|
const [glyphName, typoFs, uprightFs] = cdUpright;
|
|
const [, , italicFs] = cdItalic;
|
|
const [, , obliqueFs] = cdOblique;
|
|
blockResults.push({
|
|
lch,
|
|
gc,
|
|
charName: chName,
|
|
inFont: true,
|
|
glyphName: glyphName,
|
|
...putFeatSeries(featureSeriesStore, "typographicFeatureSets", typoFs),
|
|
...putFeatSeries(featureSeriesStore, "cvFeatureSetsUpright", uprightFs),
|
|
...putFeatSeries(featureSeriesStore, "cvFeatureSetsItalic", italicFs),
|
|
...putFeatSeries(featureSeriesStore, "cvFeatureSetsOblique", obliqueFs)
|
|
});
|
|
} else {
|
|
blockResults.push({
|
|
lch,
|
|
gc,
|
|
charName: chName,
|
|
inFont: false,
|
|
glyphName: undefined
|
|
});
|
|
}
|
|
}
|
|
if (blockResults.length) {
|
|
unicodeCoverage.push({
|
|
name: block,
|
|
characters: blockResults.sort((a, b) => a.lch - b.lch)
|
|
});
|
|
}
|
|
}
|
|
|
|
let featureSeries = [];
|
|
for (const [id, x] of featureSeriesStore.values()) {
|
|
for (let gr of x.groups) gr.sort((a, b) => a.css.localeCompare(b.css));
|
|
featureSeries[id] = x;
|
|
}
|
|
|
|
return { unicodeCoverage, featureSeries };
|
|
}
|
|
|
|
function putFeatSeries(store, k, featSeriesList) {
|
|
if (!featSeriesList) return null;
|
|
|
|
let reduced = [];
|
|
for (const _featSeries of featSeriesList) {
|
|
const featSeries = ValidateFeatureSeries(_featSeries);
|
|
|
|
const key =
|
|
featSeries.name +
|
|
";;" +
|
|
featSeries.groups.map(g => g.map(a => a.css).join(";;")).join(";;");
|
|
|
|
let vs = store.get(key);
|
|
if (vs) {
|
|
reduced.push(vs[0]);
|
|
} else {
|
|
const idNeo = store.size;
|
|
if (!featSeries) continue;
|
|
store.set(key, [idNeo, featSeries]);
|
|
reduced.push(idNeo);
|
|
}
|
|
}
|
|
|
|
if (!reduced || !reduced.length) return null;
|
|
return { [k]: reduced };
|
|
}
|
|
|
|
function ValidateFeatureSeries(s) {
|
|
let size = 0;
|
|
let reducedGroups = [];
|
|
for (const g of s.groups) {
|
|
if (!g || !g.length) continue;
|
|
reducedGroups.push(g);
|
|
size += g.length;
|
|
}
|
|
if (!size) return null;
|
|
return { name: s.name, size, groups: reducedGroups };
|
|
}
|