Refactor geometry system

This commit is contained in:
be5invis 2021-02-01 19:25:55 -08:00
parent 855a812758
commit 3fd1ebfec3
11 changed files with 208 additions and 159 deletions

View file

@ -16,14 +16,7 @@ function finalizeGlyphs(para, glyphStore) {
function suppressNaN(glyphStore) {
for (const g of glyphStore.glyphs()) {
if (!g.contours) continue;
for (let k = 0; k < g.contours.length; k++) {
let contour = g.contours[k];
for (let z of contour) {
if (!isFinite(z.x)) z.x = 0;
if (!isFinite(z.y)) z.y = 0;
}
}
if (g.geometry) g.geometry.suppressNaN();
}
}
@ -31,32 +24,38 @@ function suppressNaN(glyphStore) {
function regulateGlyphStore(skew, glyphStore) {
for (const g of glyphStore.glyphs()) {
if (!g.semanticInclusions || !g.contours) continue;
if (g.isPureComposite()) regulateCompositeGlyph(glyphStore, g);
if (g.geometry.isEmpty()) continue;
if (!regulateCompositeGlyph(glyphStore, g)) {
const cs = g.geometry.asContours();
g.clearGeometry();
for (const c of cs) g.geometry.addContour(c);
}
}
for (const g of glyphStore.glyphs()) {
if (!g.geometry.asReferences()) regulateSimpleGlyph(g, skew);
}
for (const g of glyphStore.glyphs()) regulateSimpleGlyph(g, skew);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
function regulateCompositeGlyph(glyphStore, g) {
const references = [];
for (const sr of g.semanticInclusions) {
const refs = g.geometry.asReferences();
if (!refs) return false;
for (const sr of refs) {
const gn = glyphStore.queryNameOf(sr.glyph);
if (!gn || sr.glyph.autoRefPriority < 0) return;
references.push({ glyph: gn, x: sr.x, y: sr.y });
if (!gn || sr.glyph.autoRefPriority < 0) return false;
}
g.semanticInclusions = [];
g.contours = [];
g.references = references;
return true;
}
function regulateSimpleGlyph(g, skew) {
if (!g.contours || !g.contours.length) return;
for (const contour of g.contours) for (const z of contour) z.x -= z.y * skew;
g.contours = simplifyContours(g.contours);
for (const contour of g.contours) for (const z of contour) z.x += z.y * skew;
let cs = g.geometry.asContours();
for (const contour of cs) for (const z of contour) z.x -= z.y * skew;
cs = simplifyContours(cs);
for (const contour of cs) for (const z of contour) z.x += z.y * skew;
g.clearGeometry();
for (const c of cs) g.geometry.addContour(c);
}
///////////////////////////////////////////////////////////////////////////////////////////////////

View file

@ -1,48 +1,58 @@
const { Ot } = require("ot-builder");
const Point = require("../../support/point");
class NamedGlyphStore {
class MappedGlyphStore {
constructor() {
this.m_nameMapping = new Map();
this.m_mapping = new Map();
}
declare(name) {
declare(name, source) {
const g = new Ot.Glyph();
g.name = name;
this.m_mapping.set(name, g);
this.m_nameMapping.set(name, g);
this.m_mapping.set(source, g);
}
query(name) {
return this.m_mapping.get(name);
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, data) {
const g = this.query(name);
if (!g) return;
fill(name, source) {
const g = this.queryBySourceGlyph(source);
if (!g) throw new Error("Unreachable");
g.horizontal = { start: 0, end: data.advanceWidth };
if (data.references && data.references.length) {
this.fillReferences(g, data);
} else if (data.contours && data.contours.length) {
this.fillContours(g, data);
// 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());
}
}
fillReferences(g, data) {
fillReferences(g, rs) {
const gl = new Ot.Glyph.GeometryList();
for (const ref of data.references) {
const target = this.query(ref.glyph);
if (!target) continue;
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, data) {
fillContours(g, contours) {
const cs = new Ot.Glyph.ContourSet();
for (const c of data.contours) {
for (const c of contours) {
const c1 = [];
for (const z of c) {
c1.push(
@ -67,21 +77,21 @@ function convertGlyphs(gsOrig) {
.map(([j, gn, g]) => [j, gn, queryOrderingUnicode(gsOrig, g), g])
.sort(byRank);
const gs = new NamedGlyphStore();
const gs = new MappedGlyphStore();
const cmap = new Ot.Cmap.Table();
for (const [origIndex, name, uOrd, g] of sortedEntries) {
gs.declare(name);
const us = gsOrig.queryUnicodeOf(g);
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) {
cmap.unicode.set(u, gs.query(name));
cmap.unicode.set(u, gs.queryBySourceGlyph(gSrc));
}
}
}
}
for (const [origIndex, name, uOrd, g] of sortedEntries) gs.fill(name, g);
for (const [origIndex, name, uOrd, gSrc] of sortedEntries) gs.fill(name, gSrc);
return { glyphs: gs, cmap };
}

View file

@ -35,8 +35,8 @@ const GsubSingleHandler = {
fill(dst, src, store) {
const st = src.substitutions;
for (const k in st) {
const from = store.glyphs.query(k);
const to = store.glyphs.query(st[k]);
const from = store.glyphs.queryByName(k);
const to = store.glyphs.queryByName(st[k]);
if (from && to) dst.mapping.set(from, to);
}
}
@ -48,7 +48,7 @@ const GsubMultipleHandler = {
fill(dst, src, store) {
const st = src.substitutions;
for (const k in st) {
const from = store.glyphs.query(k);
const from = store.glyphs.queryByName(k);
const to = mapGlyphListAll(st[k], store);
if (!from || !to) continue;
dst.mapping.set(from, to);
@ -68,7 +68,7 @@ const GsubLigatureHandler = {
fill(dst, src, store) {
const st = src.substitutions;
for (const { from: _from, to: _to } of st) {
const to = store.glyphs.query(_to);
const to = store.glyphs.queryByName(_to);
const from = mapGlyphListAll(_from, store);
if (!from || !to) continue;
dst.mapping.push({ from, to });
@ -114,7 +114,7 @@ const GsubReverseHandler = {
{
const m1 = new Set();
for (let k = 0; k < st.match[j].length; k++) {
const gFrom = store.glyphs.query(st.match[j][k]);
const gFrom = store.glyphs.queryByName(st.match[j][k]);
if (gFrom) m1.add(gFrom);
}
if (!m1.size) continue out;
@ -123,8 +123,8 @@ const GsubReverseHandler = {
if (j === doSubAt) {
for (let k = 0; k < st.match[j].length; k++) {
const gFrom = store.glyphs.query(st.match[j][k]);
const gTo = store.glyphs.query(st.to[k]);
const gFrom = store.glyphs.queryByName(st.match[j][k]);
const gTo = store.glyphs.queryByName(st.to[k]);
if (!gFrom) continue;
if (gTo) {
replacement.set(gFrom, gTo);
@ -142,7 +142,7 @@ const GsubReverseHandler = {
function mapGlyphListAll(gl, store) {
const out = [];
for (const item of gl) {
const fg = store.glyphs.query(item);
const fg = store.glyphs.queryByName(item);
if (!fg) return null;
out.push(fg);
}
@ -151,7 +151,7 @@ function mapGlyphListAll(gl, store) {
function mapGlyphListSome(gl, store) {
const out = [];
for (const item of gl) {
const fg = store.glyphs.query(item);
const fg = store.glyphs.queryByName(item);
if (!fg) continue;
out.push(fg);
}
@ -204,7 +204,7 @@ function convertMarkRecords(marks, mm, store) {
const out = new Map();
for (const gn in marks) {
const mark = marks[gn];
const g = store.glyphs.query(gn);
const g = store.glyphs.queryByName(gn);
if (!g) continue;
let markAnchors = [];
markAnchors[mm.get(mark.class)] = { x: mark.x, y: mark.y };
@ -216,7 +216,7 @@ function convertBaseRecords(bases, mm, store) {
const out = new Map();
for (const gn in bases) {
const baseObj = bases[gn];
const g = store.glyphs.query(gn);
const g = store.glyphs.queryByName(gn);
if (!g) continue;
const baseArray = [];
for (const bkStr in baseObj) {
@ -319,7 +319,7 @@ function convertGdef(otdGdef, glyphs) {
const gdef = new Ot.Gdef.Table();
gdef.glyphClassDef = new Map();
for (const gn in otdGdef.glyphClassDef) {
const g = glyphs.query(gn);
const g = glyphs.queryByName(gn);
if (g) gdef.glyphClassDef.set(g, otdGdef.glyphClassDef[gn]);
}
return gdef;