Optimize build speed
This commit is contained in:
parent
2ec275667e
commit
9ebfa830f6
15 changed files with 167 additions and 67 deletions
|
@ -13,9 +13,11 @@ export async function buildFont(argv, para) {
|
||||||
const baseFont = CreateEmptyFont(argv);
|
const baseFont = CreateEmptyFont(argv);
|
||||||
assignFontNames(baseFont, para.naming, para.isQuasiProportional);
|
assignFontNames(baseFont, para.naming, para.isQuasiProportional);
|
||||||
|
|
||||||
|
// Build glyphs
|
||||||
const gs = buildGlyphs(para);
|
const gs = buildGlyphs(para);
|
||||||
copyFontMetrics(gs.fontMetrics, baseFont);
|
copyFontMetrics(gs.fontMetrics, baseFont);
|
||||||
|
|
||||||
|
// Build OTL
|
||||||
const otl = buildOtl(para, gs.glyphStore);
|
const otl = buildOtl(para, gs.glyphStore);
|
||||||
|
|
||||||
// Regulate
|
// Regulate
|
||||||
|
@ -25,12 +27,13 @@ export async function buildFont(argv, para) {
|
||||||
for (let p = start; p <= end; p++) excludeChars.add(p);
|
for (let p = start; p <= end; p++) excludeChars.add(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finalize (like geometry conversion)
|
// Finalize (like geometry conversion)
|
||||||
const cache = await Caching.load(argv.iCache, argv.menu.version, argv.cacheFreshAgeKey);
|
const cache = await Caching.load(argv.iCache, argv.menu.version, argv.cacheFreshAgeKey);
|
||||||
const finalGs = finalizeFont(cache, para, gs.glyphStore, excludeChars, otl);
|
const finalGs = finalizeFont(cache, para, gs.glyphStore, excludeChars, otl);
|
||||||
if (cache.isUpdated()) {
|
if (cache.isUpdated()) await Caching.save(argv.oCache, argv.menu.version, cache, true);
|
||||||
await Caching.save(argv.oCache, argv.menu.version, cache, true);
|
|
||||||
}
|
// Convert to TTF
|
||||||
const font = await convertOtd(baseFont, otl, finalGs);
|
const font = await convertOtd(baseFont, otl, finalGs);
|
||||||
const ttfaControls = await generateTtfaControls(finalGs, font.glyphs);
|
const ttfaControls = await generateTtfaControls(finalGs, font.glyphs);
|
||||||
return { font, glyphStore: finalGs, cacheUpdated: cache.isUpdated(), ttfaControls };
|
return { font, glyphStore: finalGs, cacheUpdated: cache.isUpdated(), ttfaControls };
|
||||||
|
|
|
@ -253,7 +253,7 @@ glyph-block AutoBuild-Enclosure : begin
|
||||||
define ItalicSpacing : object
|
define ItalicSpacing : object
|
||||||
gniPrefix 'i'
|
gniPrefix 'i'
|
||||||
getPara : function[pp digits rows width] : begin
|
getPara : function[pp digits rows width] : begin
|
||||||
define pp1 : pp.reinit : function [a] : begin
|
define pp1 : pp.createFork : function [a] : begin
|
||||||
set a.shape.slope 'italic'
|
set a.shape.slope 'italic'
|
||||||
set a.shape.slopeAngle : mix (para.slopeAngle || 0) 15 (95 / 150)
|
set a.shape.slopeAngle : mix (para.slopeAngle || 0) 15 (95 / 150)
|
||||||
return : StandardSpacing.getPara pp1 digits rows width
|
return : StandardSpacing.getPara pp1 digits rows width
|
||||||
|
@ -261,7 +261,7 @@ glyph-block AutoBuild-Enclosure : begin
|
||||||
define SansSerifSpacing : object
|
define SansSerifSpacing : object
|
||||||
gniPrefix 'ss'
|
gniPrefix 'ss'
|
||||||
getPara : function [pp digits rows width] : begin
|
getPara : function [pp digits rows width] : begin
|
||||||
define pp1 : pp.reinit : function [a] : begin
|
define pp1 : pp.createFork : function [a] : begin
|
||||||
set a.shape.serifs 'sans'
|
set a.shape.serifs 'sans'
|
||||||
return : StandardSpacing.getPara pp1 digits rows width
|
return : StandardSpacing.getPara pp1 digits rows width
|
||||||
|
|
||||||
|
|
|
@ -674,7 +674,7 @@ glyph-block Autobuild-Transformed : begin
|
||||||
: where : [createReversed _records] : begin
|
: where : [createReversed _records] : begin
|
||||||
local { records relSets targetNameMap } : extendRelatedGlyphs 'reversed' _records
|
local { records relSets targetNameMap } : extendRelatedGlyphs 'reversed' _records
|
||||||
local pendingGlyphs : records.map : [record] => record.1
|
local pendingGlyphs : records.map : [record] => record.1
|
||||||
local forkedPara : para.reinit : function p : begin
|
local forkedPara : para.createFork : function p : begin
|
||||||
set p.shape.slopeAngle (-p.shape.slopeAngle)
|
set p.shape.slopeAngle (-p.shape.slopeAngle)
|
||||||
|
|
||||||
local miniatureFont : Fork pendingGlyphs forkedPara
|
local miniatureFont : Fork pendingGlyphs forkedPara
|
||||||
|
@ -702,7 +702,7 @@ glyph-block Autobuild-Transformed-Mathematical : begin
|
||||||
define [createMathDerivedSeriesImpl groupName tfm _records] : begin
|
define [createMathDerivedSeriesImpl groupName tfm _records] : begin
|
||||||
local { records relSets targetNameMap } : extendRelatedGlyphs groupName _records
|
local { records relSets targetNameMap } : extendRelatedGlyphs groupName _records
|
||||||
local pendingGlyphs : records.map : [record] => record.1
|
local pendingGlyphs : records.map : [record] => record.1
|
||||||
local forkedPara : para.reinit tfm
|
local forkedPara : para.createFork tfm
|
||||||
local forked : Fork pendingGlyphs forkedPara
|
local forked : Fork pendingGlyphs forkedPara
|
||||||
foreach {unicode glyphid} [items-of records] : if [not : query-glyph targetNameMap.(glyphid)]
|
foreach {unicode glyphid} [items-of records] : if [not : query-glyph targetNameMap.(glyphid)]
|
||||||
create-glyph targetNameMap.(glyphid) unicode : glyph-proc
|
create-glyph targetNameMap.(glyphid) unicode : glyph-proc
|
||||||
|
|
|
@ -15,7 +15,7 @@ $$include '../meta/macros.ptl'
|
||||||
|
|
||||||
export : define [buildGlyphs para recursive] : begin
|
export : define [buildGlyphs para recursive] : begin
|
||||||
# Execution and dependency management
|
# Execution and dependency management
|
||||||
local $Exec$ : new GlyphBuildExecutor
|
local $Exec$ : new GlyphBuildExecutor recursive
|
||||||
define [glyph-is-needed name] : [not recursive] || [recursive.glyphIsNeeded name]
|
define [glyph-is-needed name] : [not recursive] || [recursive.glyphIsNeeded name]
|
||||||
|
|
||||||
# Initialize glyph store
|
# Initialize glyph store
|
||||||
|
@ -138,7 +138,7 @@ export : define [buildGlyphs para recursive] : begin
|
||||||
run-glyph-module "./auto-build/transformed.mjs"
|
run-glyph-module "./auto-build/transformed.mjs"
|
||||||
run-glyph-module "./auto-build/composite.mjs"
|
run-glyph-module "./auto-build/composite.mjs"
|
||||||
|
|
||||||
foreach [gb : items-of $Exec$.pendingGlyphBlocks] : gb.resolve
|
$Exec$.executePendingBlocks
|
||||||
|
|
||||||
Gr.linkSuffixPairGr glyphStore 'NWID' 'WWID' Gr.Nwid Gr.Wwid
|
Gr.linkSuffixPairGr glyphStore 'NWID' 'WWID' Gr.Nwid Gr.Wwid
|
||||||
Gr.linkSuffixPairGr glyphStore 'lnum' 'onum' Gr.Lnum Gr.Onum
|
Gr.linkSuffixPairGr glyphStore 'lnum' 'onum' Gr.Lnum Gr.Onum
|
||||||
|
|
|
@ -2,7 +2,7 @@ $$include '../../../meta/macros.ptl'
|
||||||
|
|
||||||
glyph-module
|
glyph-module
|
||||||
|
|
||||||
glyph-block Letter-Cyrillic-Orthography : begin
|
glyph-block Letter-Latin-Orthography : begin
|
||||||
glyph-block-import Common-Derivatives
|
glyph-block-import Common-Derivatives
|
||||||
|
|
||||||
# orthographic-italic 'f_i' 0xFB01
|
# orthographic-italic 'f_i' 0xFB01
|
||||||
|
|
|
@ -6,7 +6,7 @@ import [bitOr] from"../../../support/util/mask-bit.mjs"
|
||||||
|
|
||||||
glyph-module
|
glyph-module
|
||||||
|
|
||||||
glyph-block Letter-Latin-Upper-AE-OE : begin
|
glyph-block Letter-Latin-Upper-AA-AO : begin
|
||||||
glyph-block-import CommonShapes
|
glyph-block-import CommonShapes
|
||||||
glyph-block-import Common-Derivatives
|
glyph-block-import Common-Derivatives
|
||||||
glyph-block-import Letter-Latin-Upper-F : EFVJutLength
|
glyph-block-import Letter-Latin-Upper-F : EFVJutLength
|
||||||
|
|
|
@ -5,7 +5,7 @@ import [Joining] from"../../support/gr.mjs"
|
||||||
|
|
||||||
glyph-module
|
glyph-module
|
||||||
|
|
||||||
glyph-block Symbol-Mosaic-NotDef : begin
|
glyph-block Spaces : begin
|
||||||
glyph-block-import CommonShapes
|
glyph-block-import CommonShapes
|
||||||
glyph-block-import Common-Derivatives
|
glyph-block-import Common-Derivatives
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ import [DesignParameters] from"../../../meta/aesthetics.mjs"
|
||||||
|
|
||||||
glyph-module
|
glyph-module
|
||||||
|
|
||||||
glyph-block Symbol-Geometric-Dice : for-width-kinds WideWidth1
|
glyph-block Symbol-Geometric-Ballot-Box : for-width-kinds WideWidth1
|
||||||
glyph-block-import CommonShapes
|
glyph-block-import CommonShapes
|
||||||
glyph-block-import Common-Derivatives
|
glyph-block-import Common-Derivatives
|
||||||
glyph-block-import Symbol-Geometric-Shared : GeometricDim UnicodeWeightGrade GeometricSizes
|
glyph-block-import Symbol-Geometric-Shared : GeometricDim UnicodeWeightGrade GeometricSizes
|
||||||
|
|
|
@ -5,7 +5,7 @@ import [mix linreg clamp fallback] from"../../../support/utils.mjs"
|
||||||
|
|
||||||
glyph-module
|
glyph-module
|
||||||
|
|
||||||
glyph-block Symbol-Punctuation-ParagraphAndSection : begin
|
glyph-block Symbol-Punctuation-Pilcrow : begin
|
||||||
glyph-block-import CommonShapes
|
glyph-block-import CommonShapes
|
||||||
glyph-block-import Common-Derivatives
|
glyph-block-import Common-Derivatives
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ import [mix linreg clamp fallback] from"../../../support/utils.mjs"
|
||||||
|
|
||||||
glyph-module
|
glyph-module
|
||||||
|
|
||||||
glyph-block Symbol-Punctuation-ParagraphAndSection : begin
|
glyph-block Symbol-Punctuation-Section : begin
|
||||||
glyph-block-import CommonShapes
|
glyph-block-import CommonShapes
|
||||||
glyph-block-import Common-Derivatives
|
glyph-block-import Common-Derivatives
|
||||||
|
|
||||||
|
|
|
@ -70,16 +70,16 @@ async function getParameters() {
|
||||||
};
|
};
|
||||||
return para;
|
return para;
|
||||||
}
|
}
|
||||||
function reinit(argv) {
|
function paraT(argv) {
|
||||||
const para = createParaImpl(argv);
|
const para = createParaImpl(argv);
|
||||||
para.reinit = function (tf) {
|
para.createFork = function (tf) {
|
||||||
const argv1 = deepClone(argv);
|
const argv1 = deepClone(argv);
|
||||||
tf(argv1, argv);
|
tf(argv1, argv);
|
||||||
return reinit(argv1);
|
return paraT(argv1);
|
||||||
};
|
};
|
||||||
return para;
|
return para;
|
||||||
}
|
}
|
||||||
return reinit;
|
return paraT;
|
||||||
}
|
}
|
||||||
async function tryParseToml(str) {
|
async function tryParseToml(str) {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -92,11 +92,11 @@ export : define [buildCVSS gsub para glyphStore] : begin
|
||||||
if (variant.tag && variant.rank) : cvGrs.push variant
|
if (variant.tag && variant.rank) : cvGrs.push variant
|
||||||
cvGrs.sort AnyCv.compare
|
cvGrs.sort AnyCv.compare
|
||||||
|
|
||||||
foreach gr [items-of cvGrs] : begin
|
foreach {gn glyph} [glyphStore.namedEntries] : if [not : CvDecompose.get glyph] : begin
|
||||||
local cvAlt : [cvs.get gr.tag].createAlternateSubst
|
foreach gr [items-of cvGrs] : begin
|
||||||
foreach {gn glyph} [glyphStore.namedEntries] : if [not : CvDecompose.get glyph] : begin
|
|
||||||
local subst : gr.get glyph
|
local subst : gr.get glyph
|
||||||
if (subst && subst != gn) : begin
|
if (subst && subst != gn) : begin
|
||||||
|
local cvAlt : [cvs.get gr.tag].createAlternateSubst
|
||||||
if [not cvAlt.substitutions.(gn)] : set cvAlt.substitutions.(gn) { }
|
if [not cvAlt.substitutions.(gn)] : set cvAlt.substitutions.(gn) { }
|
||||||
set cvAlt.substitutions.(gn).(gr.rank - 1) : glyphStore.ensureExists subst
|
set cvAlt.substitutions.(gn).(gr.rank - 1) : glyphStore.ensureExists subst
|
||||||
|
|
||||||
|
@ -114,9 +114,12 @@ export : define [buildCVSS gsub para glyphStore] : begin
|
||||||
foreach gr [items-of ssGrs] : begin
|
foreach gr [items-of ssGrs] : begin
|
||||||
local cvSingle : [cvs.get gr.tag].createSingleSubstFor gr.rank
|
local cvSingle : [cvs.get gr.tag].createSingleSubstFor gr.rank
|
||||||
feature.addLookup cvSingle
|
feature.addLookup cvSingle
|
||||||
foreach {gn glyph} [glyphStore.namedEntries] : if [not : CvDecompose.get glyph] : begin
|
|
||||||
|
foreach {gn glyph} [glyphStore.namedEntries] : if [not : CvDecompose.get glyph] : begin
|
||||||
|
foreach gr [items-of ssGrs] : begin
|
||||||
local subst : gr.get glyph
|
local subst : gr.get glyph
|
||||||
if (subst && subst != gn) : begin
|
if (subst && subst != gn) : begin
|
||||||
|
local cvSingle : [cvs.get gr.tag].createSingleSubstFor gr.rank
|
||||||
set cvSingle.substitutions.(gn) : glyphStore.ensureExists subst
|
set cvSingle.substitutions.(gn) : glyphStore.ensureExists subst
|
||||||
|
|
||||||
do "Cleanup and link dependency"
|
do "Cleanup and link dependency"
|
||||||
|
|
|
@ -1,35 +1,57 @@
|
||||||
export class GlyphBuildExecutor {
|
export class GlyphBuildExecutor {
|
||||||
constructor() {
|
constructor(recursiveBuildFilter) {
|
||||||
this.currentBlockName = null;
|
this.recursiveBuildFilter = recursiveBuildFilter;
|
||||||
|
this.currentBlockId = null;
|
||||||
this.dependencyManager = new DependencyManager();
|
this.dependencyManager = new DependencyManager();
|
||||||
this.pendingGlyphBlocks = [];
|
this.pendingGlyphBlocks = [];
|
||||||
this.glyphBlockStore = {};
|
this.glyphBlockStore = {};
|
||||||
}
|
}
|
||||||
setGlyphToBlockDependency(glyph) {
|
setGlyphToBlockDependency(glyph) {
|
||||||
if (this.currentBlockName) {
|
if (this.currentBlockId) {
|
||||||
this.dependencyManager.glyphToBlock.set(glyph, this.currentBlockName);
|
this.dependencyManager.glyphToBlock.set(glyph, this.currentBlockId);
|
||||||
|
|
||||||
|
let s = this.dependencyManager.blockToGlyph.get(this.currentBlockId);
|
||||||
|
if (!s) {
|
||||||
|
s = new Set();
|
||||||
|
this.dependencyManager.blockToGlyph.set(this.currentBlockId, s);
|
||||||
|
}
|
||||||
|
s.add(glyph);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
defineGlyphBlock(capture, blockName, body) {
|
executePendingBlocks() {
|
||||||
const block = new GlyphBlock(capture, this, blockName, body);
|
// if (!this.recursiveBuildFilter) {
|
||||||
this.glyphBlockStore[blockName] = block;
|
for (const block of this.pendingGlyphBlocks) block.resolve();
|
||||||
|
// } else {
|
||||||
|
// for (const block of this.pendingGlyphBlocks)
|
||||||
|
// if (this.recursiveBuildFilter.blockIsNeeded(block.id)) block.resolve();
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
defineGlyphBlock(capture, id, body) {
|
||||||
|
const block = new GlyphBlock(capture, this, id, body);
|
||||||
|
if (this.glyphBlockStore[id]) throw new Error(`Duplicate glyph block: ${id}`);
|
||||||
|
this.glyphBlockStore[id] = block;
|
||||||
this.pendingGlyphBlocks.push(block);
|
this.pendingGlyphBlocks.push(block);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class RecursiveBuildFilter {
|
export class RecursiveBuildFilter {
|
||||||
constructor(glyphIdFilter) {
|
constructor(glyphIdFilter, blockIdFilter) {
|
||||||
this.glyphIdFilter = glyphIdFilter;
|
this.glyphIdFilter = glyphIdFilter;
|
||||||
|
this.blockIdFilter = blockIdFilter;
|
||||||
}
|
}
|
||||||
glyphIsNeeded(id) {
|
glyphIsNeeded(id) {
|
||||||
return this.glyphIdFilter.has(id);
|
return this.glyphIdFilter.has(id);
|
||||||
}
|
}
|
||||||
|
blockIsNeeded(id) {
|
||||||
|
return this.blockIdFilter.has(id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class DependencyManager {
|
export class DependencyManager {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.glyphToGlyph = new WeakMap();
|
this.glyphToGlyph = new WeakMap();
|
||||||
this.glyphToBlock = new WeakMap();
|
this.glyphToBlock = new WeakMap();
|
||||||
|
this.blockToGlyph = new Map();
|
||||||
}
|
}
|
||||||
addDependency(dependent, dependency) {
|
addDependency(dependent, dependency) {
|
||||||
let s = this.glyphToGlyph.get(dependent);
|
let s = this.glyphToGlyph.get(dependent);
|
||||||
|
@ -39,12 +61,31 @@ export class DependencyManager {
|
||||||
}
|
}
|
||||||
s.add(dependency);
|
s.add(dependency);
|
||||||
}
|
}
|
||||||
traverseDependencies(glyphs) {
|
|
||||||
|
traverseGlyphDependenciesImpl(glyphs, fBlockwiseExpand) {
|
||||||
let state = new Map();
|
let state = new Map();
|
||||||
const PENDING = 1,
|
const PENDING = 1,
|
||||||
CHECKED = 2;
|
CHECKED = 2;
|
||||||
|
|
||||||
for (const glyph of glyphs) state.set(glyph, PENDING);
|
for (const glyph of glyphs) state.set(glyph, PENDING);
|
||||||
|
|
||||||
|
// When fBlockwiseExpand is true, we need to expand the initial glyph set
|
||||||
|
// to include all glyphs in the same block.
|
||||||
|
if (fBlockwiseExpand) {
|
||||||
|
let blocks = new Set();
|
||||||
|
for (const glyph of glyphs) {
|
||||||
|
let b = this.glyphToBlock.get(glyph);
|
||||||
|
if (b) blocks.add(b);
|
||||||
|
}
|
||||||
|
for (const b of blocks) {
|
||||||
|
const glyphs = this.blockToGlyph.get(b);
|
||||||
|
if (glyphs) {
|
||||||
|
for (const g of glyphs) state.set(g, PENDING);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Traverse the dependency graph
|
||||||
for (;;) {
|
for (;;) {
|
||||||
let found = false;
|
let found = false;
|
||||||
for (const [glyph, s] of state) {
|
for (const [glyph, s] of state) {
|
||||||
|
@ -59,11 +100,24 @@ export class DependencyManager {
|
||||||
if (!found) break;
|
if (!found) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
traverseDependencies(glyphs) {
|
||||||
|
const gGlyphGraph = this.traverseGlyphDependenciesImpl(glyphs, false);
|
||||||
|
const gBlockGraph = this.traverseGlyphDependenciesImpl(glyphs, true);
|
||||||
|
|
||||||
let glyphIdFilter = new Set();
|
let glyphIdFilter = new Set();
|
||||||
for (const g of state.keys()) {
|
let blockIdFilter = new Set();
|
||||||
|
for (const g of gGlyphGraph.keys()) {
|
||||||
if (g.identifier) glyphIdFilter.add(g.identifier);
|
if (g.identifier) glyphIdFilter.add(g.identifier);
|
||||||
}
|
}
|
||||||
return new RecursiveBuildFilter(glyphIdFilter);
|
for (const g of gBlockGraph.keys()) {
|
||||||
|
let b = this.glyphToBlock.get(g);
|
||||||
|
if (b) blockIdFilter.add(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new RecursiveBuildFilter(glyphIdFilter, blockIdFilter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,18 +125,18 @@ export class GlyphBlock {
|
||||||
constructor(capture, execState, blockName, body) {
|
constructor(capture, execState, blockName, body) {
|
||||||
this.capture = capture;
|
this.capture = capture;
|
||||||
this.execState = execState;
|
this.execState = execState;
|
||||||
this.blockName = blockName;
|
this.id = blockName;
|
||||||
this.body = body;
|
this.body = body;
|
||||||
this.resolved = 0;
|
this.resolved = 0;
|
||||||
this.exports = {};
|
this.exports = {};
|
||||||
}
|
}
|
||||||
resolve() {
|
resolve() {
|
||||||
if (this.resolved == 2) return this.exports;
|
if (this.resolved == 2) return this.exports;
|
||||||
if (this.resolved == 1) throw new Error(`Circular dependency detected: ${this.blockName}`);
|
if (this.resolved == 1) throw new Error(`Circular dependency detected: ${this.id}`);
|
||||||
this.resolved = 1;
|
this.resolved = 1;
|
||||||
|
|
||||||
const prevBlockName = this.execState.currentBlockName;
|
const prevBlockName = this.execState.currentBlockId;
|
||||||
this.execState.currentBlockName = this.blockName;
|
this.execState.currentBlockId = this.id;
|
||||||
|
|
||||||
const pendingApplications = [];
|
const pendingApplications = [];
|
||||||
const ExportCapture = fnObj => {
|
const ExportCapture = fnObj => {
|
||||||
|
@ -95,7 +149,7 @@ export class GlyphBlock {
|
||||||
this.body(this.capture, ExportCapture);
|
this.body(this.capture, ExportCapture);
|
||||||
for (const f of pendingApplications) f();
|
for (const f of pendingApplications) f();
|
||||||
|
|
||||||
this.execState.currentBlockName = prevBlockName;
|
this.execState.currentBlockId = prevBlockName;
|
||||||
this.resolved = 2;
|
this.resolved = 2;
|
||||||
return this.exports;
|
return this.exports;
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,6 +112,7 @@ async function processSsStyles() {
|
||||||
if (!gr.rank) continue;
|
if (!gr.rank) continue;
|
||||||
md.log(` - \`${gr.tag}\`: Set character variant to “${gr.description}”.`);
|
md.log(` - \`${gr.tag}\`: Set character variant to “${gr.description}”.`);
|
||||||
}
|
}
|
||||||
|
md.log(` - Other build plans’ configuration, using \`inherits = "buildPlans.<Plan name>"\`.`);
|
||||||
return md;
|
return md;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ const DIST_SUPER_TTC = "dist/.super-ttc";
|
||||||
const ARCHIVE_DIR = "release-archives";
|
const ARCHIVE_DIR = "release-archives";
|
||||||
|
|
||||||
const PATEL_C = ["node", "node_modules/patel/bin/patel-c"];
|
const PATEL_C = ["node", "node_modules/patel/bin/patel-c"];
|
||||||
const TTCIZE = ["node", "node_modules/otb-ttc-bundle/bin/otb-ttc-bundle"];
|
const MAKE_TTC = ["node", "node_modules/otb-ttc-bundle/bin/otb-ttc-bundle"];
|
||||||
const SEVEN_ZIP = process.env.SEVEN_ZIP_PATH || "7z";
|
const SEVEN_ZIP = process.env.SEVEN_ZIP_PATH || "7z";
|
||||||
const TTFAUTOHINT = process.env.TTFAUTOHINT_PATH || "ttfautohint";
|
const TTFAUTOHINT = process.env.TTFAUTOHINT_PATH || "ttfautohint";
|
||||||
|
|
||||||
|
@ -130,13 +130,25 @@ const BuildPlans = computed("metadata:build-plans", async target => {
|
||||||
const [rp] = await target.need(RawPlans);
|
const [rp] = await target.need(RawPlans);
|
||||||
const rawBuildPlans = rp.buildPlans;
|
const rawBuildPlans = rp.buildPlans;
|
||||||
|
|
||||||
|
// Initialize build plans
|
||||||
const returnBuildPlans = {};
|
const returnBuildPlans = {};
|
||||||
const fileNameToBpMap = {};
|
|
||||||
for (const prefix in rawBuildPlans) {
|
for (const prefix in rawBuildPlans) {
|
||||||
const bp = { ...rawBuildPlans[prefix] };
|
const bp = { ...rawBuildPlans[prefix] };
|
||||||
validateAndShimBuildPlans(prefix, bp, rp.weights, rp.slopes, rp.widths);
|
if (!bp.family) fail(`Build plan for ${prefix} does not have a family name. Exit.`);
|
||||||
bp.webfontFormats = bp["webfont-formats"] || defaultWebFontFormats;
|
bp.webfontFormats = bp["webfont-formats"] || defaultWebFontFormats;
|
||||||
bp.targets = [];
|
bp.targets = [];
|
||||||
|
returnBuildPlans[prefix] = bp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve WWS, including inheritance and default config
|
||||||
|
for (const prefix in rawBuildPlans) {
|
||||||
|
resolveWws(prefix, returnBuildPlans, rp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create file name to BP mapping
|
||||||
|
const fileNameToBpMap = {};
|
||||||
|
for (const prefix in rawBuildPlans) {
|
||||||
|
const bp = returnBuildPlans[prefix];
|
||||||
const weights = bp.weights,
|
const weights = bp.weights,
|
||||||
slopes = bp.slopes,
|
slopes = bp.slopes,
|
||||||
widths = bp.widths;
|
widths = bp.widths;
|
||||||
|
@ -157,31 +169,31 @@ const BuildPlans = computed("metadata:build-plans", async target => {
|
||||||
|
|
||||||
function linkSpacingDerivableBuildPlans(bps) {
|
function linkSpacingDerivableBuildPlans(bps) {
|
||||||
for (const pfxTo in bps) {
|
for (const pfxTo in bps) {
|
||||||
const planTo = bps[pfxTo];
|
const bpTo = bps[pfxTo];
|
||||||
const planToVal = rectifyPlanForSpacingDerivation(planTo);
|
if (blockSpacingDerivation(bpTo)) continue;
|
||||||
if (blockSpacingDerivation(planTo)) continue;
|
if (!isDeriveToSpacing(bpTo.spacing)) continue;
|
||||||
if (!isLinkDeriveToSpacing(planTo.spacing)) continue;
|
|
||||||
for (const pfxFrom in bps) {
|
for (const pfxFrom in bps) {
|
||||||
const planFrom = bps[pfxFrom];
|
const bpFrom = bps[pfxFrom];
|
||||||
if (!isLinkDeriveFromSpacing(planFrom.spacing)) continue;
|
if (!isDeriveFromSpacing(bpFrom.spacing)) continue;
|
||||||
const planFromVal = rectifyPlanForSpacingDerivation(planFrom);
|
if (!spacingDeriveCompatible(pfxTo, bpTo, pfxFrom, bpFrom)) continue;
|
||||||
if (!deepEqual(planToVal, planFromVal)) continue;
|
bpTo.spacingDeriveFrom = pfxFrom;
|
||||||
planTo.spacingDeriveFrom = pfxFrom;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function blockSpacingDerivation(bp) {
|
function blockSpacingDerivation(bp) {
|
||||||
return !!bp["compatibility-ligatures"];
|
return !!bp["compatibility-ligatures"];
|
||||||
}
|
}
|
||||||
function isLinkDeriveToSpacing(spacing) {
|
function isDeriveToSpacing(spacing) {
|
||||||
return spacing === "term" || spacing === "fontconfig-mono" || spacing === "fixed";
|
return spacing === "term" || spacing === "fontconfig-mono" || spacing === "fixed";
|
||||||
}
|
}
|
||||||
function isLinkDeriveFromSpacing(spacing) {
|
function isDeriveFromSpacing(spacing) {
|
||||||
return !spacing || spacing === "normal";
|
return !spacing || spacing === "normal";
|
||||||
}
|
}
|
||||||
|
function spacingDeriveCompatible(pfxTo, bpTo, pfxFrom, bpFrom) {
|
||||||
function rectifyPlanForSpacingDerivation(p) {
|
// If the two build plans are the same, then they are compatible.
|
||||||
|
return deepEqual(rectifyPlanForSpacingDerive(bpTo), rectifyPlanForSpacingDerive(bpFrom));
|
||||||
|
}
|
||||||
|
function rectifyPlanForSpacingDerive(p) {
|
||||||
return {
|
return {
|
||||||
...p,
|
...p,
|
||||||
family: "#Validation",
|
family: "#Validation",
|
||||||
|
@ -749,7 +761,7 @@ const GlyfTtc = file.make(
|
||||||
async function buildCompositeTtc(out, inputs) {
|
async function buildCompositeTtc(out, inputs) {
|
||||||
const inputPaths = inputs.map(f => f.full);
|
const inputPaths = inputs.map(f => f.full);
|
||||||
echo.action(echo.hl.command(`Create TTC`), out.full, echo.hl.operator("<-"), inputPaths);
|
echo.action(echo.hl.command(`Create TTC`), out.full, echo.hl.operator("<-"), inputPaths);
|
||||||
await absolutelySilently.run(TTCIZE, ["-o", out.full], inputPaths);
|
await absolutelySilently.run(MAKE_TTC, ["-o", out.full], inputPaths);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function buildGlyphSharingTtc(target, parts, out) {
|
async function buildGlyphSharingTtc(target, parts, out) {
|
||||||
|
@ -757,7 +769,7 @@ async function buildGlyphSharingTtc(target, parts, out) {
|
||||||
const [ttfInputs] = await target.need(parts.map(part => BuildNoGcTtf(part.dir, part.file)));
|
const [ttfInputs] = await target.need(parts.map(part => BuildNoGcTtf(part.dir, part.file)));
|
||||||
const ttfInputPaths = ttfInputs.map(p => p.full);
|
const ttfInputPaths = ttfInputs.map(p => p.full);
|
||||||
echo.action(echo.hl.command(`Create TTC`), out.full, echo.hl.operator("<-"), ttfInputPaths);
|
echo.action(echo.hl.command(`Create TTC`), out.full, echo.hl.operator("<-"), ttfInputPaths);
|
||||||
await silently.run(TTCIZE, "-u", ["-o", out.full], ttfInputPaths);
|
await silently.run(MAKE_TTC, "-u", ["-o", out.full], ttfInputPaths);
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////
|
||||||
|
@ -1179,21 +1191,48 @@ const Parameters = task(`meta:parameters`, async target => {
|
||||||
///////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// Build plan validation
|
// Build plan validation
|
||||||
function validateAndShimBuildPlans(prefix, bp, dWeights, dSlopes, dWidths) {
|
|
||||||
if (!bp.family) {
|
function resolveWws(bpName, buildPlans, defaultConfig) {
|
||||||
fail(`Build plan for ${prefix} does not have a family name. Exit.`);
|
const bp = buildPlans[bpName];
|
||||||
}
|
if (!bp) fail(`Build plan ${bpName} not found.`);
|
||||||
|
|
||||||
if (!bp.slopes && bp.slants) {
|
if (!bp.slopes && bp.slants) {
|
||||||
echo.warn(
|
fail(
|
||||||
`Build plan for ${prefix} uses legacy "slants" to define slopes. ` +
|
`Build plan for ${bpName} uses legacy "slants" to define slopes. ` +
|
||||||
`Use "slopes" instead.`
|
`Use "slopes" instead.`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
bp.weights = shimBpAspect("weights", bp.weights, dWeights);
|
bp.weights = resolveWwsAspect("weights", bpName, buildPlans, defaultConfig, []);
|
||||||
bp.slopes = shimBpAspect("slopes", bp.slopes || bp.slants, dSlopes);
|
bp.widths = resolveWwsAspect("widths", bpName, buildPlans, defaultConfig, []);
|
||||||
bp.widths = shimBpAspect("widths", bp.widths, dWidths);
|
bp.slopes = resolveWwsAspect("slopes", bpName, buildPlans, defaultConfig, []);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resolveWwsAspect(aspectName, bpName, buildPlans, defaultConfig, deps) {
|
||||||
|
const bp = buildPlans[bpName];
|
||||||
|
if (!bp) fail(`Build plan ${bpName} not found.`);
|
||||||
|
|
||||||
|
if (bp[aspectName]) {
|
||||||
|
return shimBpAspect(aspectName, bp[aspectName], defaultConfig[aspectName]);
|
||||||
|
} else if (bp[`${aspectName}-inherits`]) {
|
||||||
|
const inheritedPlanName = bp[`${aspectName}-inherits`];
|
||||||
|
const inheritedPlan = buildPlans[inheritedPlanName];
|
||||||
|
if (deps.includes(inheritedPlan))
|
||||||
|
fail(`Circular dependency detected when resolving ${aspectName} of ${bp.family}.`);
|
||||||
|
|
||||||
|
const updatedDes = [...deps, bpName];
|
||||||
|
return resolveWwsAspect(
|
||||||
|
aspectName,
|
||||||
|
inheritedPlanName,
|
||||||
|
buildPlans,
|
||||||
|
defaultConfig,
|
||||||
|
updatedDes
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return defaultConfig[aspectName];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function shimBpAspect(aspectName, aspect, defaultAspect) {
|
function shimBpAspect(aspectName, aspect, defaultAspect) {
|
||||||
if (!aspect) return defaultAspect;
|
if (!aspect) return defaultAspect;
|
||||||
const result = {};
|
const result = {};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue