Optimize spacing variants' building

This commit is contained in:
be5invis 2022-09-15 18:50:29 -07:00
parent b7a59ee481
commit 12a4f1edb1
14 changed files with 775 additions and 372 deletions

View file

@ -0,0 +1,241 @@
import { Ot } from "ot-builder";
import semver from "semver";
export function createNamingDictFromArgv(argv) {
return {
family: argv.menu.family,
version: argv.menu.version,
weight: argv.menu.weight - 0,
width: argv.menu.width - 0,
slope: argv.menu.slope
};
}
export function assignFontNames(font, naming, isQuasiProportional) {
// Clear existing names
font.name.records.length = 0;
// Preferred names
const family = naming.family.trim();
const style = getStyle(naming.weight, naming.width, naming.slope);
nameFont(font, Ot.Name.NameID.PreferredFamily, family);
nameFont(font, Ot.Name.NameID.PreferredSubfamily, style);
nameFont(font, Ot.Name.NameID.WwsFamily, family);
nameFont(font, Ot.Name.NameID.WwsSubfamily, style);
// Compat banes
const compat = getStyleLinkedStyles(naming.weight, naming.width, naming.slope);
let compatFamily = family;
if (compat.familySuffix !== " Regular") compatFamily = family + " " + compat.familySuffix;
if (compatFamily.length >= 31) compatFamily = family + " " + compat.familySuffixShort;
nameFont(font, Ot.Name.NameID.LegacyFamily, compatFamily);
nameFont(font, Ot.Name.NameID.LegacySubfamily, compat.style);
// Unique and Full name
const uniqueName = `${family} ${style} ${naming.version}`;
const fullName = style !== "Regular" ? `${family} ${style}` : family;
const postscriptName = fullName.replace(/ /g, "-");
nameFont(font, Ot.Name.NameID.UniqueFontId, uniqueName);
nameFont(font, Ot.Name.NameID.FullFontName, fullName);
nameFont(font, Ot.Name.NameID.PostscriptName, postscriptName);
// Weight, width and slope numbers
font.os2.usWeightClass = naming.weight;
font.os2.usWidthClass = naming.width;
font.os2.panose.bWeight = 1 + naming.weight / 100;
font.os2.sFamilyClass = 0x809;
// HEAD and OS/2 flags
const isItalic = naming.slope === "italic";
const isOblique = naming.slope === "oblique";
const isBold = naming.weight > 650;
// prettier-ignore
font.os2.fsSelection = accumulateFlags(
[Ot.Os2.FsSelection.OBLIQUE, isOblique],
[Ot.Os2.FsSelection.BOLD, isBold],
[Ot.Os2.FsSelection.ITALIC, isItalic || isOblique],
[Ot.Os2.FsSelection.REGULAR, !isBold && !isItalic && !isOblique],
[Ot.Os2.FsSelection.USE_TYPO_METRICS, true]
);
// prettier-ignore
font.head.macStyle = accumulateFlags(
[Ot.Head.MacStyle.Bold, isBold],
[Ot.Head.MacStyle.Italic, isItalic || isOblique],
[Ot.Head.MacStyle.Condensed, naming.width < 5],
[Ot.Head.MacStyle.Extended, naming.width > 5]
);
// Panose
font.os2.panose.bFamilyType = 2;
font.os2.panose.bContrast = 3;
font.os2.panose.bXHeight = 4;
// Pitch
if (!isQuasiProportional) {
font.os2.panose.bProportion = 9; // Monospaced
font.post.isFixedPitch = true;
} else {
font.os2.panose.bProportion = 0;
font.post.isFixedPitch = false;
}
// Licensing
if (naming.miscNames) {
nameFont(font, Ot.Name.NameID.Copyright, naming.miscNames.copyright);
nameFont(font, Ot.Name.NameID.Manufacturer, naming.miscNames.manufacturer);
nameFont(font, Ot.Name.NameID.Designer, naming.miscNames.designer);
nameFont(font, Ot.Name.NameID.Description, naming.miscNames.description);
nameFont(font, Ot.Name.NameID.LicenseDescription, naming.miscNames.licence);
}
// Version
nameFont(font, Ot.Name.NameID.VersionString, `Version ${naming.version}`);
const majorVersion = semver.major(naming.version);
const minorVersion = semver.minor(naming.version);
const patchVersion = semver.patch(naming.version);
if (minorVersion > 99 || patchVersion > 99) throw new RangeError("Version number overflow");
font.head.fontRevision = majorVersion + (minorVersion * 10 + patchVersion) / 1000;
// Misc
font.os2.ulCodePageRange1 = 0x2000011f;
font.os2.ulCodePageRange2 = 0xc4000000;
font.head.flags = accumulateFlags(
[Ot.Head.Flags.BaseLineYAt0, true],
[Ot.Head.Flags.LeftSidebearingAtX0, true],
[Ot.Head.Flags.InstructionsMayDependOnPointSize, true],
[Ot.Head.Flags.ForcePpemToBeInteger, true],
[Ot.Head.Flags.InstructionMayAlterAdvanceWidth, true]
);
}
function accumulateFlags(...entries) {
let s = 0;
for (const [flag, cond] of entries) {
if (cond) s |= flag;
}
return s;
}
function getStyleLinkedStyles(weight, width, slope) {
let linkWeight = weight;
let linkSlope = slope;
let nameSuffixWeight = 400;
let nameSuffixWidth = width;
let nameSuffixSlope = "normal";
if (!(linkWeight === 400 || linkWeight == 700)) {
nameSuffixWeight = linkWeight;
linkWeight = 400;
}
if (!(linkSlope === "normal" || linkSlope === "italic")) {
nameSuffixSlope = linkSlope;
linkSlope = "normal";
}
return {
style: getStyle(linkWeight, 5, linkSlope),
familySuffix: getStyle(nameSuffixWeight, nameSuffixWidth, nameSuffixSlope),
familySuffixShort: getShortStyle(nameSuffixWeight, nameSuffixWidth, nameSuffixSlope)
};
}
function nameFont(font, nameID, str) {
// Mac Roman
font.name.records.push({
platformID: 1,
encodingID: 0,
languageID: 0,
nameID,
value: Buffer.from(str, "utf-8")
});
// Windows Unicode English
font.name.records.push({
platformID: 3,
encodingID: 1,
languageID: 1033,
nameID,
value: str
});
}
function isRBIZ(weight, slope) {
return (weight === 400 || weight === 700) && (slope === "normal" || slope === "italic");
}
function getStyle(weight, width, slope) {
const weightPart = weightToMenuStyleMap[weight] ?? "W" + weight;
const widthPart = widthToMenuStyleMap[width] ?? "Wd" + width;
const slopePart = slopeToMenuStyleMap[slope] ?? "";
const rawName = weightPart + " " + widthPart + " " + slopePart;
return rawName.replace(/ +/g, " ").trim() || "Regular";
}
function getShortStyle(weight, width, slope) {
const weightPart = weightToMenuStyleMapShort[weight] ?? "W" + weight;
const widthPart = widthToMenuStyleMapShort[width] ?? "Wd" + width;
const slopePart = slopeToMenuStyleMapShort[slope] ?? "";
const rawName = weightPart + " " + widthPart + " " + slopePart;
return rawName.replace(/ +/g, " ").trim() || "Regular";
}
const weightToMenuStyleMap = {
100: "Thin",
200: "Extralight",
300: "Light",
400: "",
450: "Book",
500: "Medium",
600: "Semibold",
700: "Bold",
800: "Extrabold",
900: "Heavy"
};
const widthToMenuStyleMap = {
1: "Ultra-Condensed",
2: "Extra-Condensed",
3: "Condensed",
4: "Semi-Condensed",
5: "",
6: "Semi-Extended",
7: "Extended",
8: "Extra-Extended",
9: "Ultra-Extended"
};
const slopeToMenuStyleMap = {
normal: "",
italic: "Italic",
oblique: "Oblique"
};
const weightToMenuStyleMapShort = {
100: "Th",
200: "XLt",
300: "Lt",
400: "",
450: "Bk",
500: "Md",
600: "SmBd",
700: "Bd",
800: "XBd",
900: "Hv"
};
const widthToMenuStyleMapShort = {
1: "UltCn",
2: "XCn",
3: "Cn",
4: "SmCn",
5: "",
6: "SmEx",
7: "Ex",
8: "XEx",
9: "UltEx"
};
const slopeToMenuStyleMapShort = {
normal: "",
italic: "It",
oblique: "Obl"
};