website overhaul
This commit is contained in:
parent
beace051c7
commit
2fce3d1f13
7 changed files with 237 additions and 189 deletions
|
@ -17,7 +17,7 @@ glyph-block Common-Derivatives : begin
|
||||||
local dst : glyphStore.queryByName dstName
|
local dst : glyphStore.queryByName dstName
|
||||||
if dst : g.dependsOn dst
|
if dst : g.dependsOn dst
|
||||||
if (para.enableCvSs && h.tag && h.rank) : begin
|
if (para.enableCvSs && h.tag && h.rank) : begin
|
||||||
[Cv h.tag h.rank].set g dstName
|
[Cv h.tag h.rank h.rankGroup h.description].set g dstName
|
||||||
if h.nonDeriving : [Cv h.tag h.rank].setPreventDeriving g
|
if h.nonDeriving : [Cv h.tag h.rank].setPreventDeriving g
|
||||||
|
|
||||||
glyph-block-export select-variant
|
glyph-block-export select-variant
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
$$include '../../../meta/macros.ptl'
|
$$include '../../../meta/macros.ptl'
|
||||||
|
|
||||||
import [mix linreg clamp fallback] from"../../../support/utils.mjs"
|
import [mix fallback SuffixCfg] from"../../../support/utils.mjs"
|
||||||
import [Dotless CvDecompose MathSansSerif] from"../../../support/gr.mjs"
|
import [Dotless CvDecompose MathSansSerif] from"../../../support/gr.mjs"
|
||||||
import [maskBits bitOr] from"../../../support/util/mask-bit.mjs"
|
import [maskBits bitOr] from"../../../support/util/mask-bit.mjs"
|
||||||
|
|
||||||
|
@ -27,15 +27,16 @@ glyph-block Letter-Latin-Upper-A : begin
|
||||||
define [ABarPosition fBaseSlabs top] : mix [if fBaseSlabs Stroke 0] top (XH / 2 / CAP)
|
define [ABarPosition fBaseSlabs top] : mix [if fBaseSlabs Stroke 0] top (XH / 2 / CAP)
|
||||||
|
|
||||||
glyph-block-export AConfig
|
glyph-block-export AConfig
|
||||||
define AConfig : object
|
define AConfig : SuffixCfg.weave
|
||||||
straightSerifless { true SLAB-NONE }
|
object
|
||||||
curlySerifless { false SLAB-NONE }
|
straight true
|
||||||
straightTopSerifed { true SLAB-TOP }
|
curly false
|
||||||
curlyTopSerifed { false SLAB-TOP }
|
|
||||||
straightBaseSerifed { true [bitOr SLAB-LEFT SLAB-RIGHT] }
|
object
|
||||||
curlyBaseSerifed { false [bitOr SLAB-LEFT SLAB-RIGHT] }
|
serifless SLAB-NONE
|
||||||
straightTriSerifed { true [bitOr SLAB-TOP SLAB-LEFT SLAB-RIGHT] }
|
topSerifed SLAB-TOP
|
||||||
curlyTriSerifed { false [bitOr SLAB-TOP SLAB-LEFT SLAB-RIGHT] }
|
baseSerifed [bitOr SLAB-LEFT SLAB-RIGHT]
|
||||||
|
triSerifed [bitOr SLAB-TOP SLAB-LEFT SLAB-RIGHT]
|
||||||
|
|
||||||
define [ASerifs df top sw slabKind] : glyph-proc : begin
|
define [ASerifs df top sw slabKind] : glyph-proc : begin
|
||||||
local sf : SerifFrame.fromDf df top 0
|
local sf : SerifFrame.fromDf df top 0
|
||||||
|
|
|
@ -34,15 +34,15 @@ function LinkedGlyphProp(key) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Nwid = OtlTaggedProp("Nwid", "NWID");
|
export const Nwid = OtlTaggedProp("Nwid", "NWID", "Wide cell");
|
||||||
export const Wwid = OtlTaggedProp("Wwid", "WWID");
|
export const Wwid = OtlTaggedProp("Wwid", "WWID", "Narrow cell");
|
||||||
export const Lnum = OtlTaggedProp("Lnum", "lnum");
|
export const Lnum = OtlTaggedProp("Lnum", "lnum", "Lining number");
|
||||||
export const Onum = OtlTaggedProp("Onum", "onum");
|
export const Onum = OtlTaggedProp("Onum", "onum", "Old-style number");
|
||||||
export const AplForm = OtlTaggedProp("AplForm", "APLF");
|
export const AplForm = OtlTaggedProp("AplForm", "APLF", "APL form");
|
||||||
export const NumeratorForm = OtlTaggedProp("Numerator", "numr");
|
export const NumeratorForm = OtlTaggedProp("Numerator", "numr");
|
||||||
export const DenominatorForm = OtlTaggedProp("Denominator", "dnom");
|
export const DenominatorForm = OtlTaggedProp("Denominator", "dnom");
|
||||||
function OtlTaggedProp(key, otlTag) {
|
function OtlTaggedProp(key, otlTag, description) {
|
||||||
return { ...LinkedGlyphProp(key), otlTag };
|
return { ...LinkedGlyphProp(key), otlTag, description };
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CvDecompose = DecompositionProp("CvDecompose");
|
export const CvDecompose = DecompositionProp("CvDecompose");
|
||||||
|
@ -145,12 +145,14 @@ export const Joining = {
|
||||||
|
|
||||||
const CvTagCache = new Map();
|
const CvTagCache = new Map();
|
||||||
|
|
||||||
export function Cv(tag, rank) {
|
export function Cv(tag, rank, rankGroup, description) {
|
||||||
const key = tag + "#" + rank;
|
const key = tag + "#" + rank;
|
||||||
if (CvTagCache.has(key)) return CvTagCache.get(key);
|
if (CvTagCache.has(key)) return CvTagCache.get(key);
|
||||||
const rel = {
|
const rel = {
|
||||||
tag,
|
tag,
|
||||||
rank,
|
rank,
|
||||||
|
rankGroup,
|
||||||
|
description,
|
||||||
get(glyph) {
|
get(glyph) {
|
||||||
if (glyph && glyph.related && glyph.related.cv) return glyph.related.cv[key];
|
if (glyph && glyph.related && glyph.related.cv) return glyph.related.cv[key];
|
||||||
else return null;
|
else return null;
|
||||||
|
@ -320,39 +322,63 @@ export function createGrDisplaySheet(glyphStore, gid) {
|
||||||
if (!glyph) return [];
|
if (!glyph) return [];
|
||||||
// Query selected typographic features -- mostly NWID and WWID
|
// Query selected typographic features -- mostly NWID and WWID
|
||||||
let typographicFeatures = [];
|
let typographicFeatures = [];
|
||||||
displayQueryPairFeatures(glyphStore, gid, Nwid, Wwid, typographicFeatures);
|
displayQueryPairFeatures(glyphStore, gid, "Width", Nwid, Wwid, typographicFeatures);
|
||||||
displayQueryPairFeatures(glyphStore, gid, Lnum, Onum, typographicFeatures);
|
displayQueryPairFeatures(glyphStore, gid, "Number Form", Lnum, Onum, typographicFeatures);
|
||||||
displayQuerySingleFeature(glyphStore, gid, AplForm, typographicFeatures);
|
displayQuerySingleFeature(glyphStore, gid, "APL Form", AplForm, typographicFeatures);
|
||||||
|
|
||||||
|
// Query selected character variants
|
||||||
let charVariantFeatures = [];
|
let charVariantFeatures = [];
|
||||||
const decomposition = CvDecompose.get(glyph) || PseudoCvDecompose.get(glyph);
|
const decomposition = CvDecompose.get(glyph) || PseudoCvDecompose.get(glyph);
|
||||||
if (decomposition) {
|
if (decomposition) {
|
||||||
const variantAssignmentSet = new Set();
|
const tagSet = new Set();
|
||||||
for (const componentGn of decomposition) {
|
for (const componentGn of decomposition) {
|
||||||
const component = glyphStore.queryByName(componentGn);
|
const component = glyphStore.queryByName(componentGn);
|
||||||
if (!component) continue;
|
if (!component) continue;
|
||||||
queryCvFeatureTagsOf(charVariantFeatures, componentGn, component, variantAssignmentSet);
|
queryCvFeatureTagsOf(charVariantFeatures, componentGn, component, tagSet);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
queryCvFeatureTagsOf(charVariantFeatures, gid, glyph, null);
|
queryCvFeatureTagsOf(charVariantFeatures, gid, glyph, null);
|
||||||
}
|
}
|
||||||
return [typographicFeatures, charVariantFeatures];
|
return [typographicFeatures, charVariantFeatures];
|
||||||
}
|
}
|
||||||
function displayQueryPairFeatures(gs, gid, grCis, grTrans, sink) {
|
|
||||||
|
function FeatureSeries(name, groups) {
|
||||||
|
return {
|
||||||
|
name,
|
||||||
|
groups
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function displayQueryPairFeatures(gs, gid, name, grCis, grTrans, sink) {
|
||||||
const g = gs.queryByName(gid);
|
const g = gs.queryByName(gid);
|
||||||
if (!g) return;
|
if (!g) return;
|
||||||
const glyphIsHidden = /^\./.test(gid);
|
const glyphIsHidden = /^\./.test(gid);
|
||||||
if (glyphIsHidden) return;
|
if (glyphIsHidden) return;
|
||||||
if (grCis.get(g) || grTrans.get(g)) {
|
if (grCis.get(g) || grTrans.get(g)) {
|
||||||
sink.push(`'${grCis.otlTag}' 1`, `'${grTrans.otlTag}' 1`);
|
sink.push(
|
||||||
|
FeatureSeries(name, [
|
||||||
|
[
|
||||||
|
{ css: `'${grCis.otlTag}' 1`, description: grCis.description },
|
||||||
|
{ css: `'${grTrans.otlTag}' 1`, description: grTrans.description }
|
||||||
|
]
|
||||||
|
])
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function displayQuerySingleFeature(gs, gid, grCis, sink) {
|
function displayQuerySingleFeature(gs, gid, name, grCis, sink) {
|
||||||
const g = gs.queryByName(gid);
|
const g = gs.queryByName(gid);
|
||||||
if (!g) return;
|
if (!g) return;
|
||||||
const glyphIsHidden = /^\./.test(gid);
|
const glyphIsHidden = /^\./.test(gid);
|
||||||
if (glyphIsHidden) return;
|
if (glyphIsHidden) return;
|
||||||
if (grCis.get(g)) {
|
if (grCis.get(g)) {
|
||||||
sink.push(`'${grCis.otlTag}' 0`, `'${grCis.otlTag}' 1`);
|
sink.push(
|
||||||
|
FeatureSeries(name, [
|
||||||
|
[
|
||||||
|
{ css: `'${grCis.otlTag}' 0`, description: grCis.description + " disabled" },
|
||||||
|
{ css: `'${grCis.otlTag}' 1`, description: grCis.description + " enabled" }
|
||||||
|
]
|
||||||
|
])
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function byTagPreference(a, b) {
|
function byTagPreference(a, b) {
|
||||||
|
@ -362,30 +388,29 @@ function byTagPreference(a, b) {
|
||||||
if (ua > ub) return 1;
|
if (ua > ub) return 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
function queryCvFeatureTagsOf(sink, gid, glyph, variantAssignmentSet) {
|
function queryCvFeatureTagsOf(sink, gid, glyph, tagSet) {
|
||||||
const cvs = AnyCv.query(glyph).sort(byTagPreference);
|
const cvs = AnyCv.query(glyph).sort(byTagPreference);
|
||||||
let existingGlyphs = new Set();
|
let existingFeatures = new Map();
|
||||||
let m = new Map();
|
|
||||||
for (const gr of cvs) {
|
for (const gr of cvs) {
|
||||||
const tag = gr.tag;
|
|
||||||
const target = gr.get(glyph);
|
const target = gr.get(glyph);
|
||||||
if (target === gid) continue;
|
if (target === gid) continue;
|
||||||
if (existingGlyphs.has(target)) continue;
|
|
||||||
existingGlyphs.add(target);
|
let series = existingFeatures.get(gr.tag);
|
||||||
let g = m.get(tag);
|
if (!series) {
|
||||||
if (!g) {
|
if (tagSet) {
|
||||||
g = [];
|
if (tagSet.has(gr.tag)) continue;
|
||||||
m.set(tag, g);
|
tagSet.add(gr.tag);
|
||||||
}
|
}
|
||||||
const assignCss = `'${tag}' ${gr.rank}`;
|
series = FeatureSeries(gr.tag, [[]]);
|
||||||
if (!variantAssignmentSet) {
|
existingFeatures.set(gr.tag, series);
|
||||||
g.push(assignCss);
|
|
||||||
} else if (!variantAssignmentSet.has(assignCss)) {
|
|
||||||
g.push(assignCss);
|
|
||||||
variantAssignmentSet.add(assignCss);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const featureApp = { css: `'${gr.tag}' ${gr.rank}`, description: gr.description };
|
||||||
|
if (!series.groups[gr.rankGroup]) series.groups[gr.rankGroup] = [];
|
||||||
|
series.groups[gr.rankGroup].push(featureApp);
|
||||||
}
|
}
|
||||||
for (const g of m.values()) if (g.length) sink.push(g);
|
for (const g of existingFeatures.values()) sink.push(g);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function linkSuffixGr(gs, suffix, gr) {
|
export function linkSuffixGr(gs, suffix, gr) {
|
||||||
|
|
|
@ -215,10 +215,12 @@ class VariantBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
process() {
|
process() {
|
||||||
const globalState = new VbGlobalState(this.stages);
|
const globalState = new VbGlobalState(this.entry, this.stages);
|
||||||
const localState = new VbLocalState();
|
const localState = new VbLocalState();
|
||||||
localState.descriptionLeader = this.descriptionLeader;
|
localState.descriptionLeader = this.descriptionLeader;
|
||||||
|
|
||||||
globalState.stages.get(this.entry).accept(globalState, localState);
|
globalState.stages.get(this.entry).accept(globalState, localState);
|
||||||
|
|
||||||
let ans = {};
|
let ans = {};
|
||||||
for (const item of globalState.sink) {
|
for (const item of globalState.sink) {
|
||||||
let cfg = item.createPrimeVariant();
|
let cfg = item.createPrimeVariant();
|
||||||
|
@ -285,6 +287,7 @@ class VbStageAlternative {
|
||||||
const ans = localState.clone();
|
const ans = localState.clone();
|
||||||
ans.stage = this.next;
|
ans.stage = this.next;
|
||||||
ans.assignments.set(this.stage, this.key);
|
ans.assignments.set(this.stage, this.key);
|
||||||
|
if (this.stage === globalState.entry) ans.rankGroup = this.rank;
|
||||||
if (this.keyAffix) ans.addKeyAffix(this.mode, this.keyAffix);
|
if (this.keyAffix) ans.addKeyAffix(this.mode, this.keyAffix);
|
||||||
if (this.descriptionJoiner && this.descriptionAffix)
|
if (this.descriptionJoiner && this.descriptionAffix)
|
||||||
ans.addDescription(this.mode, this.descriptionJoiner, this.descriptionAffix);
|
ans.addDescription(this.mode, this.descriptionJoiner, this.descriptionAffix);
|
||||||
|
@ -328,7 +331,8 @@ class VbStageAlternative {
|
||||||
}
|
}
|
||||||
|
|
||||||
class VbGlobalState {
|
class VbGlobalState {
|
||||||
constructor(stages) {
|
constructor(entry, stages) {
|
||||||
|
this.entry = entry;
|
||||||
this.stages = stages;
|
this.stages = stages;
|
||||||
this.rank = 0;
|
this.rank = 0;
|
||||||
this.sink = [];
|
this.sink = [];
|
||||||
|
@ -339,6 +343,7 @@ class VbLocalState {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.stage = ".start";
|
this.stage = ".start";
|
||||||
this.rank = 0;
|
this.rank = 0;
|
||||||
|
this.rankGroup = 0;
|
||||||
this.descriptionLeader = "";
|
this.descriptionLeader = "";
|
||||||
|
|
||||||
this.assignments = new Map();
|
this.assignments = new Map();
|
||||||
|
@ -351,6 +356,7 @@ class VbLocalState {
|
||||||
const ans = new VbLocalState();
|
const ans = new VbLocalState();
|
||||||
ans.stage = this.stage;
|
ans.stage = this.stage;
|
||||||
ans.rank = this.rank;
|
ans.rank = this.rank;
|
||||||
|
ans.rankGroup = this.rankGroup;
|
||||||
ans.descriptionLeader = this.descriptionLeader;
|
ans.descriptionLeader = this.descriptionLeader;
|
||||||
ans.assignments = new Map(this.assignments);
|
ans.assignments = new Map(this.assignments);
|
||||||
ans.key = [...this.key];
|
ans.key = [...this.key];
|
||||||
|
@ -428,6 +434,7 @@ class VbLocalState {
|
||||||
return {
|
return {
|
||||||
key: this.produceKey(),
|
key: this.produceKey(),
|
||||||
rank: this.rank,
|
rank: this.rank,
|
||||||
|
rankGroup: this.rankGroup,
|
||||||
description: this.produceDescription(),
|
description: this.produceDescription(),
|
||||||
selector: Object.fromEntries(this.selector)
|
selector: Object.fromEntries(this.selector)
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,61 +3,55 @@
|
||||||
sampler = "A"
|
sampler = "A"
|
||||||
tag = "cv01"
|
tag = "cv01"
|
||||||
|
|
||||||
[prime.capital-a.variants.straight-serifless]
|
[prime.capital-a.variants-buildup]
|
||||||
|
entry = "body"
|
||||||
|
descriptionLeader = "`A`"
|
||||||
|
|
||||||
|
[prime.capital-a.variants-buildup.stages.body."*"]
|
||||||
|
next = "serifs"
|
||||||
|
|
||||||
|
[prime.capital-a.variants-buildup.stages.body.straight]
|
||||||
rank = 1
|
rank = 1
|
||||||
description = "Standard, straight `A`, without serifs"
|
descriptionAffix = "straight shape"
|
||||||
selector.A = "straightSerifless"
|
selectorAffix.A = "straight"
|
||||||
selector."A/sansSerif" = "straightSerifless"
|
selectorAffix."A/sansSerif" = "straight"
|
||||||
selector.AE = "straight"
|
selectorAffix.AE = "straight"
|
||||||
|
|
||||||
[prime.capital-a.variants.straight-top-serifed]
|
[prime.capital-a.variants-buildup.stages.body.curly]
|
||||||
rank = 2
|
rank = 2
|
||||||
description = "Straight `A` with serif at top"
|
descriptionAffix = "curly shape"
|
||||||
selector.A = "straightTopSerifed"
|
selectorAffix.A = "curly"
|
||||||
selector."A/sansSerif" = "straightSerifless"
|
selectorAffix."A/sansSerif" = "curly"
|
||||||
selector.AE = "straight"
|
selectorAffix.AE = "curly"
|
||||||
|
|
||||||
[prime.capital-a.variants.straight-base-serifed]
|
[prime.capital-a.variants-buildup.stages.serifs.serifless]
|
||||||
|
rank = 1
|
||||||
|
descriptionAffix = "serifs"
|
||||||
|
descriptionJoiner = "without"
|
||||||
|
selectorAffix.A = "serifless"
|
||||||
|
selectorAffix."A/sansSerif" = "serifless"
|
||||||
|
selectorAffix.AE = ""
|
||||||
|
|
||||||
|
[prime.capital-a.variants-buildup.stages.serifs.top-serifed]
|
||||||
|
rank = 2
|
||||||
|
descriptionAffix = "serifs at top"
|
||||||
|
selectorAffix.A = "topSerifed"
|
||||||
|
selectorAffix."A/sansSerif" = "serifless"
|
||||||
|
selectorAffix.AE = ""
|
||||||
|
|
||||||
|
[prime.capital-a.variants-buildup.stages.serifs.base-serifed]
|
||||||
rank = 3
|
rank = 3
|
||||||
description = "Straight `A` with serif at both top and bottom"
|
descriptionAffix = "serifs at base"
|
||||||
selector.A = "straightBaseSerifed"
|
selectorAffix.A = "baseSerifed"
|
||||||
selector."A/sansSerif" = "straightSerifless"
|
selectorAffix."A/sansSerif" = "serifless"
|
||||||
selector.AE = "straight"
|
selectorAffix.AE = ""
|
||||||
|
|
||||||
[prime.capital-a.variants.straight-tri-serifed]
|
[prime.capital-a.variants-buildup.stages.serifs.tri-serifed]
|
||||||
rank = 4
|
rank = 4
|
||||||
description = "Straight `A` with serif at both top and bottom"
|
descriptionAffix = "serifs at both top and base"
|
||||||
selector.A = "straightTriSerifed"
|
selectorAffix.A = "triSerifed"
|
||||||
selector."A/sansSerif" = "straightSerifless"
|
selectorAffix."A/sansSerif" = "serifless"
|
||||||
selector.AE = "straight"
|
selectorAffix.AE = ""
|
||||||
|
|
||||||
[prime.capital-a.variants.curly-serifless]
|
|
||||||
rank = 5
|
|
||||||
description = "Slightly curly `A`, like Iosevka 2.x, without serifs"
|
|
||||||
selector.A = "curlySerifless"
|
|
||||||
selector."A/sansSerif" = "curlySerifless"
|
|
||||||
selector.AE = "curly"
|
|
||||||
|
|
||||||
[prime.capital-a.variants.curly-top-serifed]
|
|
||||||
rank = 6
|
|
||||||
description = "Slightly curly `A`, like Iosevka 2.x, with serif at top"
|
|
||||||
selector.A = "curlyTopSerifed"
|
|
||||||
selector."A/sansSerif" = "curlySerifless"
|
|
||||||
selector.AE = "curly"
|
|
||||||
|
|
||||||
[prime.capital-a.variants.curly-base-serifed]
|
|
||||||
rank = 7
|
|
||||||
description = "Slightly curly `A`, like Iosevka 2.x, with serif at both top and bottom"
|
|
||||||
selector.A = "curlyBaseSerifed"
|
|
||||||
selector."A/sansSerif" = "curlySerifless"
|
|
||||||
selector.AE = "curly"
|
|
||||||
|
|
||||||
[prime.capital-a.variants.curly-tri-serifed]
|
|
||||||
rank = 8
|
|
||||||
description = "Slightly curly `A`, like Iosevka 2.x, with serif at both top and bottom"
|
|
||||||
selector.A = "curlyTriSerifed"
|
|
||||||
selector."A/sansSerif" = "curlySerifless"
|
|
||||||
selector.AE = "curly"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -65,89 +59,65 @@ selector.AE = "curly"
|
||||||
sampler = "B"
|
sampler = "B"
|
||||||
tag = "cv02"
|
tag = "cv02"
|
||||||
|
|
||||||
[prime.capital-b.variants.standard-serifless]
|
[prime.capital-b.variants-buildup]
|
||||||
|
entry = "symmetry"
|
||||||
|
descriptionLeader = "`B`"
|
||||||
|
|
||||||
|
[prime.capital-b.variants-buildup.stages.symmetry."*"]
|
||||||
|
next = "openness"
|
||||||
|
|
||||||
|
[prime.capital-b.variants-buildup.stages.symmetry.standard]
|
||||||
rank = 1
|
rank = 1
|
||||||
description = "`B` in near-symmetric proportion, without serifs"
|
descriptionAffix = "mostly symmetric shape"
|
||||||
selector.B = "standardSerifless"
|
selectorAffix.B = "standard"
|
||||||
selector."B/sansSerif" = "standardSerifless"
|
selectorAffix."B/sansSerif" = "standard"
|
||||||
selector.smcpB = "standardSerifless"
|
selectorAffix.smcpB = "standard"
|
||||||
|
|
||||||
[prime.capital-b.variants.standard-unilateral-serifed]
|
[prime.capital-b.variants-buildup.stages.symmetry.more-asymmetric]
|
||||||
rank = 2
|
rank = 2
|
||||||
description = "`B` in near-symmetric proportion with motion serifs at top"
|
descriptionAffix = "more asymmetric shape"
|
||||||
selector.B = "standardUnilateralSerifed"
|
selectorAffix.B = "moreAsymmetric"
|
||||||
selector."B/sansSerif" = "standardSerifless"
|
selectorAffix."B/sansSerif" = "moreAsymmetric"
|
||||||
selector.smcpB = "standardUnilateralSerifed"
|
selectorAffix.smcpB = "moreAsymmetric"
|
||||||
|
|
||||||
[prime.capital-b.variants.standard-bilateral-serifed]
|
[prime.capital-b.variants-buildup.stages.openness."*"]
|
||||||
|
next = "serifs"
|
||||||
|
|
||||||
|
[prime.capital-b.variants-buildup.stages.openness.closed]
|
||||||
|
rank = 1
|
||||||
|
keyAffix = ""
|
||||||
|
selectorAffix.B = ""
|
||||||
|
selectorAffix."B/sansSerif" = ""
|
||||||
|
selectorAffix.smcpB = ""
|
||||||
|
|
||||||
|
[prime.capital-b.variants-buildup.stages.openness.interrupted]
|
||||||
|
rank = 2
|
||||||
|
descriptionAffix = "interrupted middle bar"
|
||||||
|
selectorAffix.B = "interrupted"
|
||||||
|
selectorAffix."B/sansSerif" = "interrupted"
|
||||||
|
selectorAffix.smcpB = "interrupted"
|
||||||
|
|
||||||
|
[prime.capital-b.variants-buildup.stages.serifs.serifless]
|
||||||
|
rank = 1
|
||||||
|
descriptionAffix = "serifs"
|
||||||
|
descriptionJoiner = "without"
|
||||||
|
selectorAffix.B = "serifless"
|
||||||
|
selectorAffix."B/sansSerif" = "serifless"
|
||||||
|
selectorAffix.smcpB = "serifless"
|
||||||
|
|
||||||
|
[prime.capital-b.variants-buildup.stages.serifs.unilateral-serifed]
|
||||||
|
rank = 2
|
||||||
|
descriptionAffix = "serifs at top"
|
||||||
|
selectorAffix.B = "unilateralSerifed"
|
||||||
|
selectorAffix."B/sansSerif" = "serifless"
|
||||||
|
selectorAffix.smcpB = "unilateralSerifed"
|
||||||
|
|
||||||
|
[prime.capital-b.variants-buildup.stages.serifs.bilateral-serifed]
|
||||||
rank = 3
|
rank = 3
|
||||||
description = "`B` in near-symmetric proportion with motion serifs at both top and bottom"
|
descriptionAffix = "serifs at both top and bottom"
|
||||||
selector.B = "standardBilateralSerifed"
|
selectorAffix.B = "bilateralSerifed"
|
||||||
selector."B/sansSerif" = "standardSerifless"
|
selectorAffix."B/sansSerif" = "serifless"
|
||||||
selector.smcpB = "standardBilateralSerifed"
|
selectorAffix.smcpB = "bilateralSerifed"
|
||||||
|
|
||||||
[prime.capital-b.variants.more-asymmetric-serifless]
|
|
||||||
rank = 4
|
|
||||||
description = "`B` in more asymmetric proportion to differentiate with `8`, without serifs"
|
|
||||||
selector.B = "moreAsymmetricSerifless"
|
|
||||||
selector."B/sansSerif" = "moreAsymmetricSerifless"
|
|
||||||
selector.smcpB = "standardSerifless"
|
|
||||||
|
|
||||||
[prime.capital-b.variants.more-asymmetric-unilateral-serifed]
|
|
||||||
rank = 5
|
|
||||||
description = "`B` in more asymmetric proportion with motion serifs at top"
|
|
||||||
selector.B = "moreAsymmetricUnilateralSerifed"
|
|
||||||
selector."B/sansSerif" = "moreAsymmetricSerifless"
|
|
||||||
selector.smcpB = "standardUnilateralSerifed"
|
|
||||||
|
|
||||||
[prime.capital-b.variants.more-asymmetric-bilateral-serifed]
|
|
||||||
rank = 6
|
|
||||||
description = "`B` in more asymmetric proportion with motion serifs at both top and bottom"
|
|
||||||
selector.B = "moreAsymmetricBilateralSerifed"
|
|
||||||
selector."B/sansSerif" = "moreAsymmetricSerifless"
|
|
||||||
selector.smcpB = "standardBilateralSerifed"
|
|
||||||
|
|
||||||
[prime.capital-b.variants.standard-interrupted-serifless]
|
|
||||||
rank = 7
|
|
||||||
description = "`B` in near-symmetric proportion with interrupted middle bar, without serifs"
|
|
||||||
selector.B = "standardInterruptedSerifless"
|
|
||||||
selector."B/sansSerif" = "standardInterruptedSerifless"
|
|
||||||
selector.smcpB = "standardInterruptedSerifless"
|
|
||||||
|
|
||||||
[prime.capital-b.variants.standard-interrupted-unilateral-serifed]
|
|
||||||
rank = 8
|
|
||||||
description = "`B` in near-symmetric proportion with interrupted middle bar and motion serifs at top"
|
|
||||||
selector.B = "standardInterruptedUnilateralSerifed"
|
|
||||||
selector."B/sansSerif" = "standardInterruptedSerifless"
|
|
||||||
selector.smcpB = "standardInterruptedUnilateralSerifed"
|
|
||||||
|
|
||||||
[prime.capital-b.variants.standard-interrupted-bilateral-serifed]
|
|
||||||
rank = 9
|
|
||||||
description = "`B` in near-symmetric proportion with interrupted middle bar and motion serifs at both top and bottom"
|
|
||||||
selector.B = "standardInterruptedBilateralSerifed"
|
|
||||||
selector."B/sansSerif" = "standardInterruptedSerifless"
|
|
||||||
selector.smcpB = "standardInterruptedBilateralSerifed"
|
|
||||||
|
|
||||||
[prime.capital-b.variants.more-asymmetric-interrupted-serifless]
|
|
||||||
rank = 10
|
|
||||||
description = "`B` in more asymmetric proportion to differentiate with `8`, with interrupted middle bar, without serifs"
|
|
||||||
selector.B = "moreAsymmetricInterruptedSerifless"
|
|
||||||
selector."B/sansSerif" = "moreAsymmetricInterruptedSerifless"
|
|
||||||
selector.smcpB = "standardInterruptedSerifless"
|
|
||||||
|
|
||||||
[prime.capital-b.variants.more-asymmetric-interrupted-unilateral-serifed]
|
|
||||||
rank = 11
|
|
||||||
description = "`B` in more asymmetric proportion with interrupted middle bar and `8` with motion serifs at top"
|
|
||||||
selector.B = "moreAsymmetricInterruptedUnilateralSerifed"
|
|
||||||
selector."B/sansSerif" = "moreAsymmetricInterruptedSerifless"
|
|
||||||
selector.smcpB = "standardInterruptedUnilateralSerifed"
|
|
||||||
|
|
||||||
[prime.capital-b.variants.more-asymmetric-interrupted-bilateral-serifed]
|
|
||||||
rank = 12
|
|
||||||
description = "`B` in more asymmetric proportion with interrupted middle bar and `8` with motion serifs at both top and bottom"
|
|
||||||
selector.B = "moreAsymmetricInterruptedBilateralSerifed"
|
|
||||||
selector."B/sansSerif" = "moreAsymmetricInterruptedSerifless"
|
|
||||||
selector.smcpB = "standardInterruptedBilateralSerifed"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -20,8 +20,11 @@ function findFirstLastChar(lchBlockStart, lchBlockEnd, cov) {
|
||||||
const lchEnd = ((lchLast >>> 4) << 4) + 0x10;
|
const lchEnd = ((lchLast >>> 4) << 4) + 0x10;
|
||||||
return [lchStart, lchEnd];
|
return [lchStart, lchEnd];
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function gatherCoverageData(covUpright, covItalic, covOblique) {
|
export async function gatherCoverageData(covUpright, covItalic, covOblique) {
|
||||||
const result = [];
|
const featureSeriesStore = new Map();
|
||||||
|
const unicodeCoverage = [];
|
||||||
|
|
||||||
for (const [[lchBlockStart, lchBlockEnd], block] of await collectBlockData()) {
|
for (const [[lchBlockStart, lchBlockEnd], block] of await collectBlockData()) {
|
||||||
let blockResults = [];
|
let blockResults = [];
|
||||||
const [lchStart, lchEnd] = findFirstLastChar(lchBlockStart, lchBlockEnd, covUpright);
|
const [lchStart, lchEnd] = findFirstLastChar(lchBlockStart, lchBlockEnd, covUpright);
|
||||||
|
@ -33,19 +36,19 @@ export async function gatherCoverageData(covUpright, covItalic, covOblique) {
|
||||||
const cdItalic = covItalic.get(lch);
|
const cdItalic = covItalic.get(lch);
|
||||||
const cdOblique = covOblique.get(lch);
|
const cdOblique = covOblique.get(lch);
|
||||||
if (cdUpright && cdItalic && cdOblique) {
|
if (cdUpright && cdItalic && cdOblique) {
|
||||||
const [glyphName, typographicVariants, charVariantsUpright] = cdUpright;
|
const [glyphName, typoFs, uprightFs] = cdUpright;
|
||||||
const [, , charVariantsItalic] = cdItalic;
|
const [, , italicFs] = cdItalic;
|
||||||
const [, , charVariantsOblique] = cdOblique;
|
const [, , obliqueFs] = cdOblique;
|
||||||
blockResults.push({
|
blockResults.push({
|
||||||
lch,
|
lch,
|
||||||
gc,
|
gc,
|
||||||
charName: chName,
|
charName: chName,
|
||||||
inFont: true,
|
inFont: true,
|
||||||
glyphName: glyphName,
|
glyphName: glyphName,
|
||||||
typographicVariants: typographicVariants,
|
...putFeatSeries(featureSeriesStore, "typographicFeatureSets", typoFs),
|
||||||
charVariantsUpright,
|
...putFeatSeries(featureSeriesStore, "cvFeatureSetsUpright", uprightFs),
|
||||||
charVariantsItalic,
|
...putFeatSeries(featureSeriesStore, "cvFeatureSetsItalic", italicFs),
|
||||||
charVariantsOblique
|
...putFeatSeries(featureSeriesStore, "cvFeatureSetsOblique", obliqueFs)
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
blockResults.push({
|
blockResults.push({
|
||||||
|
@ -58,11 +61,53 @@ export async function gatherCoverageData(covUpright, covItalic, covOblique) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (blockResults.length) {
|
if (blockResults.length) {
|
||||||
result.push({
|
unicodeCoverage.push({
|
||||||
name: block,
|
name: block,
|
||||||
characters: blockResults.sort((a, b) => a.lch - b.lch)
|
characters: blockResults.sort((a, b) => a.lch - b.lch)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
|
||||||
|
let featureSeries = [];
|
||||||
|
for (const [id, x] of featureSeriesStore.values()) featureSeries[id] = x;
|
||||||
|
|
||||||
|
return { unicodeCoverage, featureSeries };
|
||||||
|
}
|
||||||
|
|
||||||
|
function putFeatSeries(store, k, featSeriesList) {
|
||||||
|
if (!featSeriesList) return null;
|
||||||
|
|
||||||
|
let reduced = [];
|
||||||
|
for (const featSeries of featSeriesList) {
|
||||||
|
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;
|
||||||
|
const validated = ValidateFeatureSeries(featSeries);
|
||||||
|
if (!validated) continue;
|
||||||
|
store.set(key, [idNeo, validated]);
|
||||||
|
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 };
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,16 +93,16 @@ export async function getCharMapAndSupportedLanguageList(cmpUpright, cmpItalic,
|
||||||
const rawCoverage = getRawCoverage(charMap);
|
const rawCoverage = getRawCoverage(charMap);
|
||||||
const rawCoverageItalic = getRawCoverage(charMapItalic);
|
const rawCoverageItalic = getRawCoverage(charMapItalic);
|
||||||
const rawCoverageOblique = getRawCoverage(charMapOblique);
|
const rawCoverageOblique = getRawCoverage(charMapOblique);
|
||||||
|
|
||||||
|
const covData = await gatherCoverageData(rawCoverage, rawCoverageItalic, rawCoverageOblique);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
stats: {
|
stats: {
|
||||||
glyphCount: charMap.length,
|
glyphCount: charMap.length,
|
||||||
codePointCount: rawCoverage.size
|
codePointCount: rawCoverage.size
|
||||||
},
|
},
|
||||||
unicodeCoverage: await gatherCoverageData(
|
featureSeries: covData.featureSeries,
|
||||||
rawCoverage,
|
unicodeCoverage: covData.unicodeCoverage,
|
||||||
rawCoverageItalic,
|
|
||||||
rawCoverageOblique
|
|
||||||
),
|
|
||||||
languages: Array.from(getSupportedLanguageSet(rawCoverage)).sort()
|
languages: Array.from(getSupportedLanguageSet(rawCoverage)).sort()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue