Iosevka/font-src/gen/otd-conv/glyphs.js
2021-06-03 23:42:12 -07:00

135 lines
3.6 KiB
JavaScript

const { Ot } = require("ot-builder");
const Point = require("../../support/point");
const { nameSingleGlyph1, nameSingleGlyph2, nameSingleGlyph3 } = require("./glyph-name");
class MappedGlyphStore {
constructor() {
this.m_nameMapping = new Map();
this.m_mapping = new Map();
this.m_primaryUnicodeMapping = new Map();
}
declare(name, source) {
const g = new Ot.Glyph();
this.m_nameMapping.set(name, g);
this.m_mapping.set(source, g);
}
setPrimaryUnicode(source, u) {
this.m_primaryUnicodeMapping.set(u, source);
}
queryBySourceGlyph(source) {
return this.m_mapping.get(source);
}
queryByName(name) {
return this.m_nameMapping.get(name);
}
decideOrder() {
const gs = Ot.ListGlyphStoreFactory.createStoreFromList([...this.m_mapping.values()]);
return gs.decideOrder();
}
fill(name, source) {
const g = this.queryBySourceGlyph(source);
if (!g) throw new Error("Unreachable");
// Fill metrics
g.horizontal = { start: 0, end: source.advanceWidth };
// Fill Geometry
if (source.geometry.isEmpty()) return;
const rs = source.geometry.asReferences();
if (rs) {
this.fillReferences(g, rs);
} else {
this.fillContours(g, source.geometry.asContours());
}
}
fillOtGlyphNames() {
let gid = 0;
let conflictSet = new Set();
let rev = new Map();
for (const [u, g] of this.m_primaryUnicodeMapping) rev.set(g, u);
for (const [gSrc, gOt] of this.m_mapping) gOt.name = undefined;
// Name by Unicode
gid = 0;
for (const [gSrc, gOt] of this.m_mapping) {
gOt.name = nameSingleGlyph1(gid, gSrc, rev.get(gSrc), conflictSet);
gid++;
}
// Name by CV
for (const [gSrcBase, gOtBase] of this.m_mapping) {
nameSingleGlyph2(gSrcBase, gOtBase.name, this.m_nameMapping, conflictSet);
}
// Name rest
gid = 0;
for (const [gSrc, gOt] of this.m_mapping) {
gOt.name = nameSingleGlyph3(gid, gSrc, gOt.name);
gid++;
}
}
fillReferences(g, rs) {
const gl = new Ot.Glyph.GeometryList();
for (const ref of rs) {
const target = this.queryBySourceGlyph(ref.glyph);
if (!target) throw new Error("Unreachable");
const tfm = Ot.Glyph.Transform2X3.Translate(ref.x, ref.y);
gl.items.push(new Ot.Glyph.TtReference(target, tfm));
}
g.geometry = gl;
}
fillContours(g, contours) {
const cs = new Ot.Glyph.ContourSet();
for (const c of contours) {
const c1 = [];
for (const z of c) {
c1.push(
Ot.Glyph.Point.create(
z.x,
z.y,
z.type === Point.Type.Quadratic
? Ot.Glyph.PointType.Quad
: Ot.Glyph.PointType.Corner
)
);
}
cs.contours.push(c1);
}
g.geometry = cs;
}
}
module.exports = convertGlyphs;
function convertGlyphs(gsOrig) {
const sortedEntries = Array.from(gsOrig.indexedNamedEntries())
.map(([j, gn, g]) => [j, gn, queryOrderingUnicode(gsOrig, g), g])
.sort(byRank);
const gs = new MappedGlyphStore();
const cmap = new Ot.Cmap.Table();
for (const [origIndex, name, uOrd, gSrc] of sortedEntries) {
gs.declare(name, gSrc);
const us = gsOrig.queryUnicodeOf(gSrc);
if (us) {
for (const u of us) {
if (!(isFinite(u - 0) && u)) continue;
cmap.unicode.set(u, gs.queryBySourceGlyph(gSrc));
gs.setPrimaryUnicode(gSrc, u);
}
}
}
for (const [origIndex, name, uOrd, gSrc] of sortedEntries) gs.fill(name, gSrc);
gs.fillOtGlyphNames();
return { glyphs: gs, cmap };
}
function queryOrderingUnicode(gs, g) {
const us = gs.queryUnicodeOf(g);
if (us && us.size) return Array.from(us).sort((a, b) => a - b)[0];
else return 0xffffff;
}
function byRank([ja, gna, ua, a], [jb, gnb, ub, b]) {
return (
(b.glyphRank || 0) - (a.glyphRank || 0) || (ua || 0) - (ub || 0) || (ja || 0) - (jb || 0)
);
}