Code reorg for building
This commit is contained in:
parent
d32599e0e2
commit
d461934be1
16 changed files with 210 additions and 187 deletions
44
packages/font/src/build-font/index.mjs
Normal file
44
packages/font/src/build-font/index.mjs
Normal file
|
@ -0,0 +1,44 @@
|
|||
import { buildGlyphs } from "@iosevka/font-glyphs";
|
||||
import { copyFontMetrics } from "@iosevka/font-glyphs/aesthetics";
|
||||
import { buildOtl } from "@iosevka/font-otl";
|
||||
|
||||
import { cleanupGlyphStore } from "../cleanup/index.mjs";
|
||||
import { CreateEmptyFont } from "../font-io/index.mjs";
|
||||
import { buildCompatLigatures } from "../hb-compat-ligature/index.mjs";
|
||||
import { assignFontNames } from "../naming/index.mjs";
|
||||
import { convertOtd } from "../otd-conv/index.mjs";
|
||||
import { generateTtfaControls } from "../ttfa-controls/index.mjs";
|
||||
import { validateFontConfigMono } from "../validate/metrics.mjs";
|
||||
|
||||
export async function buildFont(para, cache) {
|
||||
const baseFont = CreateEmptyFont(para);
|
||||
assignFontNames(baseFont, para.naming, para.isQuasiProportional);
|
||||
|
||||
// Build glyphs
|
||||
const gs = buildGlyphs(para);
|
||||
copyFontMetrics(gs.fontMetrics, baseFont);
|
||||
|
||||
// Build OTL
|
||||
const otl = buildOtl(para, gs.glyphStore);
|
||||
|
||||
// Regulate (like geometry conversion)
|
||||
const excludeChars = new Set();
|
||||
if (para.excludedCharRanges) {
|
||||
for (const [start, end] of para.excludedCharRanges) {
|
||||
for (let p = start; p <= end; p++) excludeChars.add(p);
|
||||
}
|
||||
}
|
||||
const cleanGs = cleanupGlyphStore(cache, para, gs.glyphStore, excludeChars, otl);
|
||||
|
||||
// Convert to TTF
|
||||
const font = await convertOtd(baseFont, otl, cleanGs);
|
||||
// Build compatibility ligatures
|
||||
if (para.compatibilityLigatures) await buildCompatLigatures(para, font);
|
||||
// Generate ttfaControls
|
||||
const ttfaControls = await generateTtfaControls(cleanGs, font.glyphs);
|
||||
|
||||
// Validation : Metrics
|
||||
if (para.forceMonospace) validateFontConfigMono(font);
|
||||
|
||||
return { font, glyphStore: cleanGs, cacheUpdated: cache && cache.isUpdated(), ttfaControls };
|
||||
}
|
56
packages/font/src/cleanup/glyphs.mjs
Normal file
56
packages/font/src/cleanup/glyphs.mjs
Normal file
|
@ -0,0 +1,56 @@
|
|||
import * as Geom from "@iosevka/geometry";
|
||||
import { Transform } from "@iosevka/geometry/transform";
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
export function finalizeGlyphs(cache, para, glyphStore) {
|
||||
const skew = Math.tan(((para.slopeAngle || 0) / 180) * Math.PI);
|
||||
regulateGlyphStore(cache, skew, glyphStore);
|
||||
return glyphStore;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
function regulateGlyphStore(cache, skew, glyphStore) {
|
||||
for (const g of glyphStore.glyphs()) {
|
||||
if (!(g.geometry.measureComplexity() & Geom.CPLX_NON_EMPTY)) continue;
|
||||
if (!g.geometry.toReferences()) flattenSimpleGlyph(cache, skew, g);
|
||||
}
|
||||
}
|
||||
|
||||
function flattenSimpleGlyph(cache, skew, g) {
|
||||
// Check if the geometry is already in the cache. If so, use the cached geometry.
|
||||
const ck = Geom.hashGeometry(g.geometry);
|
||||
if (ck && cache) {
|
||||
const cachedGeometry = cache && cache.getGF(ck);
|
||||
if (cachedGeometry) {
|
||||
g.clearGeometry();
|
||||
g.includeContours(cachedGeometry);
|
||||
cache.refreshGF(ck);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Perform the actual simplification
|
||||
try {
|
||||
let gSimplified;
|
||||
if (skew) {
|
||||
const tfBack = g.gizmo ? g.gizmo.inverse() : new Transform(1, -skew, 0, 1, 0, 0);
|
||||
const tfForward = g.gizmo ? g.gizmo : new Transform(1, +skew, 0, 1, 0, 0);
|
||||
gSimplified = new Geom.TransformedGeometry(
|
||||
tfForward,
|
||||
new Geom.SimplifyGeometry(new Geom.TransformedGeometry(tfBack, g.geometry)),
|
||||
);
|
||||
} else {
|
||||
gSimplified = new Geom.SimplifyGeometry(g.geometry);
|
||||
}
|
||||
|
||||
const cs = gSimplified.toContours();
|
||||
g.clearGeometry();
|
||||
g.includeContours(cs);
|
||||
if (ck && cache) cache.saveGF(ck, cs);
|
||||
} catch (e) {
|
||||
console.error("Detected broken geometry when processing", g._m_identifier);
|
||||
throw e;
|
||||
}
|
||||
}
|
25
packages/font/src/cleanup/index.mjs
Normal file
25
packages/font/src/cleanup/index.mjs
Normal file
|
@ -0,0 +1,25 @@
|
|||
import { Nwid, Wwid } from "@iosevka/glyph/relation";
|
||||
|
||||
import { gcFont } from "./gc.mjs";
|
||||
import { finalizeGlyphs } from "./glyphs.mjs";
|
||||
|
||||
export function cleanupGlyphStore(cache, para, glyphStore, excludedCodePoints, restFont) {
|
||||
assignGrAndCodeRank(glyphStore, Wwid, Nwid);
|
||||
assignSubRank(glyphStore);
|
||||
glyphStore = gcFont(glyphStore, excludedCodePoints, restFont);
|
||||
glyphStore = finalizeGlyphs(cache, para, glyphStore);
|
||||
return glyphStore;
|
||||
}
|
||||
|
||||
function assignGrAndCodeRank(glyphStore, ...flatteners) {
|
||||
for (const g of glyphStore.glyphs()) {
|
||||
g.codeRank = 0xffffffff;
|
||||
for (const c of glyphStore.flattenCodes(g, flatteners)) if (c < g.codeRank) g.codeRank = c;
|
||||
g.grRank = 0;
|
||||
for (let i = 0; i < flatteners.length; i++) if (flatteners[i].get(g)) g.grRank |= 1 << i;
|
||||
}
|
||||
}
|
||||
function assignSubRank(glyphStore) {
|
||||
let sr = 0;
|
||||
for (const g of glyphStore.glyphs()) g.subRank = sr++;
|
||||
}
|
|
@ -6,6 +6,7 @@ import { CliProc, Ot } from "ot-builder";
|
|||
|
||||
import { readTTF, saveTTF } from "./font-io/index.mjs";
|
||||
import { assignFontNames, createNamingDictFromArgv } from "./naming/index.mjs";
|
||||
import { validateFontConfigMono } from "./validate/metrics.mjs";
|
||||
|
||||
export default main;
|
||||
async function main(argv) {
|
||||
|
@ -112,21 +113,3 @@ async function deriveFixed_DropFeatures(font, argv, fFixed) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// In FontConfig, a font is considered "monospace" if and only if all encoded non-combining
|
||||
// characters (AW > 0) have the same width. We use this method to validate whether our
|
||||
// "Fixed" subfamilies are properly built.
|
||||
function validateFontConfigMono(font) {
|
||||
let awSet = new Set();
|
||||
for (const [ch, g] of [...font.cmap.unicode.entries()]) {
|
||||
const aw = g.horizontal.end - g.horizontal.start;
|
||||
if (aw > 0) awSet.add(aw);
|
||||
}
|
||||
for (const [ch, vs, g] of [...font.cmap.vs.entries()]) {
|
||||
const aw = g.horizontal.end - g.horizontal.start;
|
||||
if (aw > 0) awSet.add(aw);
|
||||
}
|
||||
if (awSet.size > 1) {
|
||||
console.error("Fixed variant has wide characters");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,51 +0,0 @@
|
|||
import * as Geom from "@iosevka/geometry";
|
||||
import { Transform } from "@iosevka/geometry/transform";
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
export function finalizeGlyphs(cache, para, glyphStore) {
|
||||
const skew = Math.tan(((para.slopeAngle || 0) / 180) * Math.PI);
|
||||
regulateGlyphStore(cache, skew, glyphStore);
|
||||
return glyphStore;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
function regulateGlyphStore(cache, skew, glyphStore) {
|
||||
for (const g of glyphStore.glyphs()) {
|
||||
if (!(g.geometry.measureComplexity() & Geom.CPLX_NON_EMPTY)) continue;
|
||||
if (!g.geometry.toReferences()) flattenSimpleGlyph(cache, skew, g);
|
||||
}
|
||||
}
|
||||
|
||||
function flattenSimpleGlyph(cache, skew, g) {
|
||||
const ck = Geom.hashGeometry(g.geometry);
|
||||
const cached = cache.getGF(ck);
|
||||
if (ck && cached) {
|
||||
g.clearGeometry();
|
||||
g.includeContours(cached);
|
||||
cache.refreshGF(ck);
|
||||
} else {
|
||||
try {
|
||||
let gSimplified;
|
||||
if (skew) {
|
||||
const tfBack = g.gizmo ? g.gizmo.inverse() : new Transform(1, -skew, 0, 1, 0, 0);
|
||||
const tfForward = g.gizmo ? g.gizmo : new Transform(1, +skew, 0, 1, 0, 0);
|
||||
gSimplified = new Geom.TransformedGeometry(
|
||||
tfForward,
|
||||
new Geom.SimplifyGeometry(new Geom.TransformedGeometry(tfBack, g.geometry)),
|
||||
);
|
||||
} else {
|
||||
gSimplified = new Geom.SimplifyGeometry(g.geometry);
|
||||
}
|
||||
|
||||
const cs = gSimplified.toContours();
|
||||
g.clearGeometry();
|
||||
g.includeContours(cs);
|
||||
if (ck) cache.saveGF(ck, cs);
|
||||
} catch (e) {
|
||||
console.error("Detected broken geometry when processing", g._m_identifier);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
import { Nwid, Wwid } from "@iosevka/glyph/relation";
|
||||
|
||||
import { gcFont } from "./gc.mjs";
|
||||
import { finalizeGlyphs } from "./glyphs.mjs";
|
||||
|
||||
export function finalizeFont(cache, para, glyphStore, excludedCodePoints, restFont) {
|
||||
assignGrAndCodeRank(glyphStore, Wwid, Nwid);
|
||||
assignSubRank(glyphStore);
|
||||
glyphStore = gcFont(glyphStore, excludedCodePoints, restFont);
|
||||
glyphStore = finalizeGlyphs(cache, para, glyphStore);
|
||||
validateMonospace(para, glyphStore);
|
||||
return glyphStore;
|
||||
}
|
||||
|
||||
function assignGrAndCodeRank(glyphStore, ...flatteners) {
|
||||
for (const g of glyphStore.glyphs()) {
|
||||
g.codeRank = 0xffffffff;
|
||||
for (const c of glyphStore.flattenCodes(g, flatteners)) if (c < g.codeRank) g.codeRank = c;
|
||||
g.grRank = 0;
|
||||
for (let i = 0; i < flatteners.length; i++) if (flatteners[i].get(g)) g.grRank |= 1 << i;
|
||||
}
|
||||
}
|
||||
function assignSubRank(glyphStore) {
|
||||
let sr = 0;
|
||||
for (const g of glyphStore.glyphs()) g.subRank = sr++;
|
||||
}
|
||||
|
||||
// In FontConfig, a font is considered "monospace" if and only if all encoded non-combining
|
||||
// characters (AW > 0) have the same width. We use this method to validate whether our
|
||||
// "Fixed" subfamilies are properly built.
|
||||
function validateMonospace(para, glyphStore) {
|
||||
let awSet = new Set();
|
||||
for (const [u, n, g] of glyphStore.encodedEntries()) {
|
||||
const aw = Math.round(g.advanceWidth || 0);
|
||||
if (aw > 0) awSet.add(aw);
|
||||
}
|
||||
if (para.forceMonospace && awSet.size > 1) {
|
||||
throw new Error("Unreachable! Fixed variant has wide characters");
|
||||
}
|
||||
if (!para.isQuasiProportional && !para.compLig && awSet.size > 2) {
|
||||
throw new Error("Unreachable! Building monospace with more than 2 character widths");
|
||||
}
|
||||
}
|
|
@ -2,12 +2,12 @@ import fs from "fs";
|
|||
|
||||
import { FontIo, Ot } from "ot-builder";
|
||||
|
||||
export function CreateEmptyFont(argv) {
|
||||
export function CreateEmptyFont(para) {
|
||||
let font = {
|
||||
head: new Ot.Head.Table(),
|
||||
hhea: new Ot.MetricHead.Hhea(),
|
||||
os2: new Ot.Os2.Table(4),
|
||||
post: new Ot.Post.Table(argv.featureControl.exportGlyphNames ? 2 : 3, 0),
|
||||
post: new Ot.Post.Table(para.exportGlyphNames ? 2 : 3, 0),
|
||||
maxp: Ot.Maxp.Table.TrueType(),
|
||||
name: new Ot.Name.Table(),
|
||||
};
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
import { buildGlyphs } from "@iosevka/font-glyphs";
|
||||
import { copyFontMetrics } from "@iosevka/font-glyphs/aesthetics";
|
||||
import { buildOtl } from "@iosevka/font-otl";
|
||||
import * as Caching from "@iosevka/geometry-cache";
|
||||
|
||||
import { finalizeFont } from "./finalize/index.mjs";
|
||||
import { CreateEmptyFont } from "./font-io/index.mjs";
|
||||
import { assignFontNames } from "./naming/index.mjs";
|
||||
import { convertOtd } from "./otd-conv/index.mjs";
|
||||
import { generateTtfaControls } from "./ttfa-controls/index.mjs";
|
||||
|
||||
export async function buildFont(argv, para) {
|
||||
const baseFont = CreateEmptyFont(argv);
|
||||
assignFontNames(baseFont, para.naming, para.isQuasiProportional);
|
||||
|
||||
// Build glyphs
|
||||
const gs = buildGlyphs(para);
|
||||
copyFontMetrics(gs.fontMetrics, baseFont);
|
||||
|
||||
// Build OTL
|
||||
const otl = buildOtl(para, gs.glyphStore);
|
||||
|
||||
// Regulate (like geometry conversion)
|
||||
const excludeChars = new Set();
|
||||
if (para.excludedCharRanges) {
|
||||
for (const [start, end] of para.excludedCharRanges) {
|
||||
for (let p = start; p <= end; p++) excludeChars.add(p);
|
||||
}
|
||||
}
|
||||
const cache = await Caching.load(argv.iCache, argv.menu.version, argv.cacheFreshAgeKey);
|
||||
const finalGs = finalizeFont(cache, para, gs.glyphStore, excludeChars, otl);
|
||||
if (cache.isUpdated()) await Caching.save(argv.oCache, argv.menu.version, cache, true);
|
||||
|
||||
// Convert to TTF
|
||||
const font = await convertOtd(baseFont, otl, finalGs);
|
||||
const ttfaControls = await generateTtfaControls(finalGs, font.glyphs);
|
||||
return { font, glyphStore: finalGs, cacheUpdated: cache.isUpdated(), ttfaControls };
|
||||
}
|
|
@ -3,12 +3,11 @@ import { Ot } from "ot-builder";
|
|||
import { buildTTF } from "../font-io/index.mjs";
|
||||
|
||||
export async function buildCompatLigatures(para, font) {
|
||||
// We need to fix the glyph order before building the TTF
|
||||
// MappedGlyphStore is append-only, so we do not need to worry about the order of glyphs
|
||||
const glyphList = font.glyphs.decideOrder();
|
||||
const gsFixed = Ot.ListGlyphStoreFactory.createStoreFromList(Array.from(glyphList));
|
||||
font.glyphs = gsFixed;
|
||||
|
||||
const completedCodePoints = new Set();
|
||||
const jobs = [];
|
||||
|
||||
// Build a provisional in-memory TTF for shaping
|
||||
const provisionalTtf = buildTTF(font);
|
||||
|
@ -55,12 +54,17 @@ export async function buildCompatLigatures(para, font) {
|
|||
}
|
||||
|
||||
// Save the ligature glyph
|
||||
font.glyphs.items.push(ligature);
|
||||
font.cmap.unicode.set(entry.unicode, ligature);
|
||||
if (font.gdef) font.gdef.glyphClassDef.set(ligature, Ot.Gdef.GlyphClass.Ligature);
|
||||
jobs.push({ name: ligature.name, unicode: entry.unicode, glyph: ligature });
|
||||
completedCodePoints.add(entry.unicode);
|
||||
}
|
||||
|
||||
// Commit jobs
|
||||
for (const job of jobs) {
|
||||
font.glyphs.addOtGlyph(job.name, job.glyph);
|
||||
font.cmap.unicode.set(job.unicode, job.glyph);
|
||||
if (font.gdef) font.gdef.glyphClassDef.set(job.glyph, Ot.Gdef.GlyphClass.Ligature);
|
||||
}
|
||||
|
||||
hbFont.destroy();
|
||||
hbFace.destroy();
|
||||
hbBlob.destroy();
|
||||
|
|
|
@ -3,6 +3,7 @@ import path from "path";
|
|||
import zlib from "zlib";
|
||||
|
||||
import * as Toml from "@iarna/toml";
|
||||
import * as Caching from "@iosevka/geometry-cache";
|
||||
import { createGrDisplaySheet } from "@iosevka/glyph/relation";
|
||||
import * as Parameters from "@iosevka/param";
|
||||
import { applyLigationData } from "@iosevka/param/ligation";
|
||||
|
@ -10,33 +11,41 @@ import { applyMetricOverride } from "@iosevka/param/metric-override";
|
|||
import * as VariantData from "@iosevka/param/variant";
|
||||
import { encode } from "@msgpack/msgpack";
|
||||
|
||||
import { buildFont } from "./build-font/index.mjs";
|
||||
import { saveTTF } from "./font-io/index.mjs";
|
||||
import { buildFont } from "./font.mjs";
|
||||
import { buildCompatLigatures } from "./hb-compat-ligature/index.mjs";
|
||||
import { createNamingDictFromArgv } from "./naming/index.mjs";
|
||||
|
||||
export default main;
|
||||
async function main(argv) {
|
||||
const paraT = await getParameters(argv);
|
||||
// Set up parameters
|
||||
const paraT = await getParametersT(argv);
|
||||
const para = paraT(argv);
|
||||
const { font, glyphStore, cacheUpdated, ttfaControls } = await buildFont(argv, para);
|
||||
if (argv.oCharMap) {
|
||||
await saveCharMap(argv, glyphStore);
|
||||
}
|
||||
if (argv.oTtfaControls) {
|
||||
await fs.promises.writeFile(argv.oTtfaControls, ttfaControls.join("\n") + "\n");
|
||||
}
|
||||
if (argv.o) {
|
||||
if (para.compatibilityLigatures) await buildCompatLigatures(para, font);
|
||||
await saveTTF(argv.o, font);
|
||||
|
||||
// Set up cache
|
||||
const cache = argv.cache
|
||||
? await Caching.load(argv.cache.input, argv.menu.version, argv.cache.freshAgeKey)
|
||||
: null;
|
||||
// Build font
|
||||
const { font, glyphStore, cacheUpdated, ttfaControls } = await buildFont(para, cache);
|
||||
|
||||
// Save charmap
|
||||
if (argv.oCharMap) await saveCharMap(argv, glyphStore);
|
||||
// Save ttfaControls
|
||||
if (argv.oTtfaControls) await fs.promises.writeFile(argv.oTtfaControls, ttfaControls);
|
||||
// Save TTF
|
||||
if (argv.o) await saveTTF(argv.o, font);
|
||||
// Save cache
|
||||
if (argv.cache && cache && cache.isUpdated()) {
|
||||
await Caching.save(argv.cache.output, argv.menu.version, cache, true);
|
||||
}
|
||||
|
||||
return { cacheUpdated };
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Parameter preparation
|
||||
async function getParameters(argv) {
|
||||
async function getParametersT(argv) {
|
||||
const PARAMETERS_TOML = path.resolve(argv.paramsDir, "./parameters.toml");
|
||||
const WEIGHTS_TOML = path.resolve(argv.paramsDir, "./shape-weight.toml");
|
||||
const WIDTHS_TOML = path.resolve(argv.paramsDir, "./shape-width.toml");
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import * as Geom from "@iosevka/geometry";
|
||||
import { Point } from "@iosevka/geometry/point";
|
||||
import { Glyph } from "@iosevka/glyph";
|
||||
import * as Gr from "@iosevka/glyph/relation";
|
||||
import { Ot } from "ot-builder";
|
||||
|
||||
|
@ -57,6 +58,13 @@ class MappedGlyphStore {
|
|||
if (!name) return undefined;
|
||||
return this.m_nameMapping.get(name);
|
||||
}
|
||||
|
||||
// Add directly from Ot.Glyphs
|
||||
addOtGlyph(name, g) {
|
||||
this.m_nameMapping.set(name, g);
|
||||
this.m_mapping.set(new Glyph(name), g);
|
||||
}
|
||||
|
||||
decideOrder() {
|
||||
const gs = Ot.ListGlyphStoreFactory.createStoreFromList([...this.m_mapping.values()]);
|
||||
return gs.decideOrder();
|
||||
|
|
|
@ -30,7 +30,7 @@ export async function generateTtfaControls(gsOrig, gsTtf) {
|
|||
alignment.write(ttfaControls, gsTtf);
|
||||
}
|
||||
|
||||
return ttfaControls;
|
||||
return ttfaControls.join("\n") + "\n";
|
||||
}
|
||||
|
||||
class Alignment {
|
||||
|
|
17
packages/font/src/validate/metrics.mjs
Normal file
17
packages/font/src/validate/metrics.mjs
Normal file
|
@ -0,0 +1,17 @@
|
|||
// In FontConfig, a font is considered "monospace" if and only if all encoded non-combining
|
||||
// characters (AW > 0) have the same width. We use this method to validate whether our
|
||||
// "Fixed" subfamilies are properly built.
|
||||
export function validateFontConfigMono(font) {
|
||||
let awSet = new Set();
|
||||
for (const [ch, g] of [...font.cmap.unicode.entries()]) {
|
||||
const aw = g.horizontal.end - g.horizontal.start;
|
||||
if (aw > 0) awSet.add(aw);
|
||||
}
|
||||
for (const [ch, vs, g] of [...font.cmap.vs.entries()]) {
|
||||
const aw = g.horizontal.end - g.horizontal.start;
|
||||
if (aw > 0) awSet.add(aw);
|
||||
}
|
||||
if (awSet.size > 1) {
|
||||
console.error("Fixed variant has wide characters");
|
||||
}
|
||||
}
|
|
@ -12,6 +12,7 @@ export function init(data, argv) {
|
|||
if (argv.featureControl.noCvSs) para.enableCvSs = false;
|
||||
if (argv.featureControl.noLigation) para.enableLigation = false;
|
||||
if (argv.featureControl.buildTextureFeature) para.buildTextureFeature = true;
|
||||
if (argv.featureControl.exportGlyphNames) para.exportGlyphNames = true;
|
||||
return para;
|
||||
}
|
||||
function applyBlendingParam(argv, para, data, key, keyArgv) {
|
||||
|
|
|
@ -254,6 +254,8 @@ const FontInfoOf = computed.group("metadata:font-info-of", async (target, fileNa
|
|||
};
|
||||
}
|
||||
|
||||
const [compositesFromBuildPlan] = await target.need(CompositesFromBuildPlan);
|
||||
|
||||
return {
|
||||
name: fileName,
|
||||
variants: bp.variants || null,
|
||||
|
@ -304,6 +306,9 @@ const FontInfoOf = computed.group("metadata:font-info-of", async (target, fileNa
|
|||
|
||||
// Spacing derivation -- creating faster build for spacing variants
|
||||
spacingDerive,
|
||||
|
||||
// Composite variants from build plan -- used for variant resolution when building fonts
|
||||
compositesFromBuildPlan,
|
||||
};
|
||||
});
|
||||
|
||||
|
@ -428,24 +433,27 @@ const DistUnhintedTTF = file.make(
|
|||
const cachePath = `${SHARED_CACHE}/${cacheFileName}.mpz`;
|
||||
const cacheDiffPath = `${charMapPath.dir}/${fn}.cache.mpz`;
|
||||
|
||||
const [comps] = await target.need(
|
||||
CompositesFromBuildPlan,
|
||||
de(charMapPath.dir),
|
||||
de(ttfaControlsPath.dir),
|
||||
de(SHARED_CACHE),
|
||||
);
|
||||
await target.need(de(charMapPath.dir), de(ttfaControlsPath.dir), de(SHARED_CACHE));
|
||||
|
||||
echo.action(echo.hl.command(`Create TTF`), out.full);
|
||||
const { cacheUpdated } = await silently.node("packages/font/src/index.mjs", {
|
||||
o: out.full,
|
||||
...(fi.buildCharMap ? { oCharMap: charMapPath.full } : {}),
|
||||
paramsDir: Path.resolve("params"),
|
||||
oTtfaControls: ttfaControlsPath.full,
|
||||
cacheFreshAgeKey: ageKey,
|
||||
iCache: cachePath,
|
||||
oCache: cacheDiffPath,
|
||||
compositesFromBuildPlan: comps,
|
||||
// INPUT: font info
|
||||
...fi,
|
||||
// INPUT: path to parameters
|
||||
paramsDir: Path.resolve("params"),
|
||||
// TTF output. Optional.
|
||||
o: out.full,
|
||||
// Charmap output. Optional.
|
||||
...(fi.buildCharMap ? { oCharMap: charMapPath.full } : {}),
|
||||
// TTFAutohint controls output. Optional.
|
||||
oTtfaControls: ttfaControlsPath.full,
|
||||
|
||||
// Geometry cache parameters. Optional.
|
||||
cache: {
|
||||
input: cachePath,
|
||||
output: cacheDiffPath,
|
||||
freshAgeKey: ageKey,
|
||||
},
|
||||
});
|
||||
|
||||
if (cacheUpdated) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue