Optimize spacing variants' building
This commit is contained in:
parent
b7a59ee481
commit
12a4f1edb1
14 changed files with 775 additions and 372 deletions
80
font-src/derive-spacing.mjs
Normal file
80
font-src/derive-spacing.mjs
Normal file
|
@ -0,0 +1,80 @@
|
|||
import fs from "fs";
|
||||
|
||||
import { FontIo, Ot } from "ot-builder";
|
||||
|
||||
import { assignFontNames, createNamingDictFromArgv } from "./gen/meta/naming.mjs";
|
||||
|
||||
export default main;
|
||||
|
||||
async function main(argv) {
|
||||
const font = await readTTF(argv);
|
||||
|
||||
const naming = createNamingDictFromArgv(argv);
|
||||
assignFontNames(font, naming, false);
|
||||
|
||||
switch (argv.shape.spacing) {
|
||||
case "term":
|
||||
deriveTerm(font);
|
||||
break;
|
||||
case "fixed":
|
||||
deriveTerm(font);
|
||||
deriveFixed(font);
|
||||
break;
|
||||
}
|
||||
|
||||
await saveTTF(argv, font);
|
||||
}
|
||||
|
||||
// To derive -Term variants, simply apply NWID
|
||||
function deriveTerm(font) {
|
||||
const gsub = font.gsub;
|
||||
let nwidMap = new Map();
|
||||
for (const feature of gsub.features) {
|
||||
if (feature.tag !== "NWID") continue;
|
||||
for (const lookup of feature.lookups) {
|
||||
if (!(lookup instanceof Ot.Gsub.Single)) continue;
|
||||
for (const [from, to] of lookup.mapping) {
|
||||
nwidMap.set(from, to);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const [ch, g] of [...font.cmap.unicode.entries()]) {
|
||||
const narrow = nwidMap.get(g);
|
||||
if (narrow) font.cmap.unicode.set(ch, narrow);
|
||||
}
|
||||
for (const [ch, vs, g] of [...font.cmap.vs.entries()]) {
|
||||
const narrow = nwidMap.get(g);
|
||||
if (narrow) font.cmap.vs.set(ch, vs, narrow);
|
||||
}
|
||||
}
|
||||
|
||||
// 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 deriveFixed(font) {
|
||||
const unitWidth = font.os2.xAvgCharWidth;
|
||||
for (const [ch, g] of [...font.cmap.unicode.entries()]) {
|
||||
const advanceWidth = g.horizontal.end - g.horizontal.start;
|
||||
if (!(advanceWidth === 0 || advanceWidth === unitWidth)) font.cmap.unicode.delete(ch);
|
||||
}
|
||||
for (const [ch, vs, g] of [...font.cmap.vs.entries()]) {
|
||||
const advanceWidth = g.horizontal.end - g.horizontal.start;
|
||||
if (!(advanceWidth === 0 || advanceWidth === unitWidth)) font.cmap.vs.delete(ch, vs);
|
||||
}
|
||||
}
|
||||
|
||||
async function readTTF(argv) {
|
||||
const buf = await fs.promises.readFile(argv.i);
|
||||
const sfnt = FontIo.readSfntOtf(buf);
|
||||
const font = FontIo.readFont(sfnt, Ot.ListGlyphStoreFactory);
|
||||
return font;
|
||||
}
|
||||
async function saveTTF(argv, font) {
|
||||
const sfnt = FontIo.writeFont(font, {
|
||||
glyphStore: { statOs2XAvgCharWidth: false },
|
||||
generateDummyDigitalSignature: true
|
||||
});
|
||||
const buf = FontIo.writeSfntOtf(sfnt);
|
||||
await fs.promises.writeFile(argv.o, buf);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue