Refactor geometry system
This commit is contained in:
parent
855a812758
commit
3fd1ebfec3
11 changed files with 208 additions and 159 deletions
|
@ -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);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -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 };
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue