From 4d20f8e6557f2ad5321c525679d84b2b5b35ac34 Mon Sep 17 00:00:00 2001 From: be5invis Date: Sun, 9 Aug 2020 18:11:36 -0700 Subject: [PATCH] Refactor: Create a separate class for glyph store --- font-src/gen/build-font.js | 6 +- font-src/gen/build-glyphs.ptl | 21 +-- font-src/gen/finalize/autoref.js | 184 +++++++++++++--------- font-src/gen/finalize/gc.js | 97 +++++------- font-src/gen/finalize/index.js | 82 +++------- font-src/glyphs/autobuild-accents.ptl | 45 +++--- font-src/glyphs/autobuild-composite.ptl | 73 +++++---- font-src/glyphs/autobuild-transformed.ptl | 34 ++-- font-src/glyphs/common-derivatives.ptl | 13 +- font-src/glyphs/letter-latin.ptl | 2 +- font-src/glyphs/overmarks.ptl | 2 +- font-src/glyphs/symbol-math.ptl | 4 +- font-src/index.js | 16 +- font-src/meta/macros.ptl | 2 +- font-src/otl/compat-ligature.ptl | 18 +-- font-src/otl/gpos-mark-mkmk.ptl | 24 +-- font-src/otl/gsub-ccmp.ptl | 8 +- font-src/otl/gsub-cv-ss.ptl | 8 +- font-src/otl/gsub-ligation.ptl | 7 +- font-src/otl/gsub-pairing.ptl | 20 +-- font-src/otl/gsub-thousands.ptl | 2 +- font-src/otl/index.ptl | 40 ++--- font-src/support/glyph-store.js | 109 +++++++++++++ font-src/support/glyph.js | 19 ++- font-src/support/gr.js | 6 +- 25 files changed, 482 insertions(+), 360 deletions(-) create mode 100644 font-src/support/glyph-store.js diff --git a/font-src/gen/build-font.js b/font-src/gen/build-font.js index b85b82104..c5ea118b4 100644 --- a/font-src/gen/build-font.js +++ b/font-src/gen/build-font.js @@ -15,7 +15,7 @@ module.exports = function (para) { assignFontNames(para, gs.metrics, font); setFontMetrics(para, gs.metrics, font); - const otl = buildOtl(para, gs.glyphs, gs.glyphList, gs.unicodeGlyphs); + const otl = buildOtl(para, gs.glyphStore); font.GSUB = otl.GSUB; font.GPOS = otl.GPOS; font.GDEF = otl.GDEF; @@ -28,6 +28,6 @@ module.exports = function (para) { } } - finalizeFont(para, [...gs.glyphList], excludeChars, font); - return font; + finalizeFont(para, gs.glyphStore, excludeChars, font); + return { font, glyphStore: gs.glyphStore }; }; diff --git a/font-src/gen/build-glyphs.ptl b/font-src/gen/build-glyphs.ptl index 98ffdbee6..859140114 100644 --- a/font-src/gen/build-glyphs.ptl +++ b/font-src/gen/build-glyphs.ptl @@ -1,4 +1,5 @@ import '../support/glyph' as Glyph +import '../support/glyph-store' as GlyphStore import '../support/point' as Point import './kits/spiro-kit' as spirokit import './kits/boole-kit' as BooleKit @@ -25,9 +26,7 @@ define [tagged tag component] : begin export all : define [buildGlyphs para recursive recursiveCodes] : begin define variantSelector para.variantSelector - local glyphList {} - local glyphMap {.} - local unicodeGlyphs {} + local glyphStore : new GlyphStore define metrics : calculateMetrics para define [object GlobalTransform UPM Middle CAP XH SB RightSB Contrast Stroke Superness Width TanSlope OverlayPos Descender SymbolMid ParenTop ParenBot OperTop OperBot PlusTop PlusBot TackTop TackBot adviceBlackness MVertStrokeD] metrics @@ -89,11 +88,11 @@ export all : define [buildGlyphs para recursive recursiveCodes] : begin warnAboutBrokenGlyph glyphObject ensuredGlyphName if saveGlyphName : begin - glyphList.push glyphObject - if (saveGlyphName.0 != '.' && glyphMap.(saveGlyphName)) + if (saveGlyphName.0 != '.' && [glyphStore.queryByName saveGlyphName]) throw : new Error "Glyph \(saveGlyphName) already exists" - glyphMap.(saveGlyphName) = glyphObject + glyphStore.addGlyph saveGlyphName glyphObject if unicode : $assignUnicodeImpl$ glyphObject unicode + set dependencyProfile.(saveGlyphName) : getDependencyProfile glyphObject dec nPending @@ -113,8 +112,10 @@ export all : define [buildGlyphs para recursive recursiveCodes] : begin console.log 'Family' para.naming.family para.naming.weight para.naming.width para.naming.slope define [$assignUnicodeImpl$ g unicode] : begin - g.assignUnicode unicode - set unicodeGlyphs.(g.unicode.((g.unicode.length - 1))) g + local u unicode + if ([typeof unicode] === "string") : begin + set u [unicode.codePointAt 0] + glyphStore.encodeGlyph u g ### Spiro constructions # Basic knots @@ -122,7 +123,7 @@ export all : define [buildGlyphs para recursive recursiveCodes] : begin define booleFns : BooleKit.SetupBuilders : object GlobalTransform Glyph # IDKY, but wrapping "metrics" prevents Node.js on Arch modifying it. - define $$Capture$$ : object [metrics : Object.create metrics] $NamedParameterPair$ $donothing$ para recursive recursiveCodes variantSelector glyphMap glyphList unicodeGlyphs $createAndSaveGlyphImpl$ spirofns booleFns MarkSet AS_BASE ALSO_METRICS pickHash dependencyProfile getDependencyProfile buildGlyphs newtemp tagged DivFrame fontMetrics $assignUnicodeImpl$ + define $$Capture$$ : object [metrics : Object.create metrics] $NamedParameterPair$ $donothing$ para recursive recursiveCodes variantSelector glyphStore $createAndSaveGlyphImpl$ spirofns booleFns MarkSet AS_BASE ALSO_METRICS pickHash dependencyProfile getDependencyProfile buildGlyphs newtemp tagged DivFrame fontMetrics $assignUnicodeImpl$ ### HERE WE GO run-glyph-module '../glyphs/common-shapes.js' @@ -153,5 +154,5 @@ export all : define [buildGlyphs para recursive recursiveCodes] : begin run-glyph-module '../glyphs/autobuild-composite.js' run-glyph-module '../glyphs/autobuild-transformed.js' - return : object metrics [glyphs glyphMap] glyphList unicodeGlyphs + return : object metrics glyphStore diff --git a/font-src/gen/finalize/autoref.js b/font-src/gen/finalize/autoref.js index b77c72a40..d1bc2b9b3 100644 --- a/font-src/gen/finalize/autoref.js +++ b/font-src/gen/finalize/autoref.js @@ -1,11 +1,40 @@ "use strict"; const Point = require("../../support/point"); +const { AnyCv } = require("../../support/gr"); -function delta(a, b) { - return Math.round((a - b) * 32); +function autoref(glyphStore) { + suppressNaN(glyphStore); + hashContours(glyphStore); + + const glyphEntryList = getGlyphEntryList(glyphStore); + linkRefl(glyphEntryList); + linkComponent(glyphEntryList); + unlinkHybrid(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; + } + } + } +} + +function hashContours(glyphStore) { + for (const g of glyphStore.glyphs()) { + if (!g.contours) continue; + for (let k = 0; k < g.contours.length; k++) { + const contour = g.contours[k]; + contour.hash = contourHash(contour); + } + } +} function contourHash(c) { if (!c || c.length < 2) return "."; let lx = c[0].x, @@ -18,8 +47,68 @@ function contourHash(c) { } return buf; } +function delta(a, b) { + return Math.round((a - b) * 32); +} -function match(g1, g2, _n) { +function getGlyphEntryList(glyphStore) { + const excludeUnicode = new Set(); + excludeUnicode.add(0x80); + for (let c = 0x2500; c <= 0x259f; c++) excludeUnicode.add(c); + + for (const [j, gn, g] of glyphStore.indexedNamedEntries()) { + if (AnyCv.query(g).length) g.autoRefPriority = -1; + const us = glyphStore.queryUnicodeOf(g); + if (us) { + for (const u of us) if (excludeUnicode.has(u)) g.avoidBeingComposite = true; + } + } + + return Array.from(glyphStore.indexedNamedEntries()).sort(byGlyphPriority); +} + +function byGlyphPriority([ja, gna, a], [jb, gnb, b]) { + const pri1 = a.autoRefPriority || 0; + const pri2 = b.autoRefPriority || 0; + if (pri1 > pri2) return -1; + if (pri1 < pri2) return 1; + if (a.contours && b.contours && a.contours.length < b.contours.length) return 1; + if (a.contours && b.contours && a.contours.length > b.contours.length) return -1; + return 0; +} + +function linkRefl(glyphEntryList) { + for (let j = 0; j < glyphEntryList.length; j++) { + const [, gnj, gj] = glyphEntryList[j]; + if (!gj.contours.length || (gj.references && gj.references.length)) continue; + for (let k = j + 1; k < glyphEntryList.length; k++) { + const [, gnk, gk] = glyphEntryList[k]; + if (gj.contours.length === gk.contours.length) { + match(gnj, gj, gnk, gk); + } + } + } +} +function linkComponent(glyphEntryList) { + for (let j = 0; j < glyphEntryList.length; j++) { + const [, gnj, gj] = glyphEntryList[j]; + if (gj.autoRefPriority < 0) continue; + if (!gj.contours.length) continue; + if (gj.references && gj.references.length) continue; + for (let k = glyphEntryList.length - 1; k >= 0; k--) { + const [, gnk, gk] = glyphEntryList[k]; + if (gj.contours.length > gk.contours.length) continue; + if ( + gj.contours.length === gk.contours.length && + !(gk.references && gk.references.length) + ) { + continue; + } + while (match(gnj, gj, gnk, gk)) "pass"; + } + } +} +function match(gn1, g1, gn2, g2) { for (let j = 0; j + g1.contours.length <= g2.contours.length; j++) { let found = true; for (let k = j; k < g2.contours.length && k - j < g1.contours.length; k++) { @@ -44,13 +133,7 @@ function match(g1, g2, _n) { continue; } if (!g2.references) g2.references = []; - g2.references.push({ - glyph: g1.name, - _n: _n, - x: refX, - y: refY, - roundToGrid: false - }); + g2.references.push({ glyph: gn1, x: refX, y: refY, roundToGrid: false }); g2.contours.splice(j, g1.contours.length); return true; } @@ -58,76 +141,25 @@ function match(g1, g2, _n) { return false; } -function unlinkRef(g, dx, dy, glyf) { +function unlinkHybrid(glyphStore) { + for (const g of glyphStore.glyphs()) { + if (!g.references || g.references.length === 0) continue; + if (!g.avoidBeingComposite && g.contours.length === 0) continue; + g.contours = unlinkRef(g, 0, 0, glyphStore); + g.references = []; + } +} + +function unlinkRef(g, dx, dy, glyphStore) { let contours = g.contours.map(c => c.map(z => new Point(z.x + dx, z.y + dy, z.on, z.cubic))); - if (g.references) + if (g.references) { for (let r of g.references) { - contours = contours.concat(unlinkRef(glyf[r._n], r.x + dx, r.y + dy, glyf)); + contours = contours.concat( + unlinkRef(glyphStore.queryByName(r.glyph), r.x + dx, r.y + dy, glyphStore) + ); } + } return contours; } -function autoref(gs, excludeUnicodeSet) { - suppressNaN(gs); - - for (let j = 0; j < gs.length; j++) { - const g = gs[j]; - if (g.contours) { - for (let k = 0; k < g.contours.length; k++) { - const contour = g.contours[k]; - contour.hash = contourHash(contour); - } - } - } - - // Refl-referencify, forward. - for (let j = 0; j < gs.length; j++) { - if (!gs[j].contours.length || (gs[j].references && gs[j].references.length)) continue; - for (let k = j + 1; k < gs.length; k++) { - if (gs[j].contours.length === gs[k].contours.length) { - match(gs[j], gs[k], j); - } - } - } - - // referencify, backward - for (let j = 0; j < gs.length; j++) { - if (gs[j].autoRefPriority < 0) continue; - if (!gs[j].contours.length) continue; - if (gs[j].references && gs[j].references.length) continue; - for (let k = gs.length - 1; k >= 0; k--) { - if (gs[j].contours.length > gs[k].contours.length) continue; - if ( - gs[j].contours.length === gs[k].contours.length && - !(gs[k].references && gs[k].references.length) - ) { - continue; - } - while (match(gs[j], gs[k], j)) "pass"; - } - } - - // unlink composite - for (let j = 0; j < gs.length; j++) { - if (!gs[j].references || gs[j].references.length === 0) continue; - if (!gs[j].avoidBeingComposite && gs[j].contours.length === 0) continue; - gs[j].contours = unlinkRef(gs[j], 0, 0, gs); - gs[j].references = []; - } -} - -function suppressNaN(glyf) { - for (let j = 0; j < glyf.length; j++) { - let g = glyf[j]; - 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; - } - } - } -} - module.exports = autoref; diff --git a/font-src/gen/finalize/gc.js b/font-src/gen/finalize/gc.js index 57d99b6c3..d004caada 100644 --- a/font-src/gen/finalize/gc.js +++ b/font-src/gen/finalize/gc.js @@ -2,11 +2,11 @@ const { Radical } = require("../../support/gr"); -module.exports = function gcFont(gs, excludedChars, restFont, cfg) { +module.exports = function gcFont(glyphStore, excludedChars, restFont, cfg) { markSweepOtl(restFont.GSUB); markSweepOtl(restFont.GPOS); - const sink = mark(gs, excludedChars, restFont, cfg); - sweep(gs, restFont, sink); + const sink = mark(glyphStore, excludedChars, restFont, cfg); + return sweep(glyphStore, restFont, sink); }; function markSweepOtl(table) { @@ -57,21 +57,22 @@ function markLookups(table, sink) { } while (loop < 0xff && lookupSetChanged); } -function mark(gs, excludedChars, restFont, cfg) { - const sink = markInitial(gs, excludedChars); +function mark(glyphStore, excludedChars, restFont, cfg) { + const sink = markInitial(glyphStore, excludedChars); while (markStep(sink, restFont, cfg)); return sink; } -function markInitial(gs, excludedChars) { +function markInitial(glyphStore, excludedChars) { let sink = new Set(); - for (const g of gs) { + for (const [gName, g] of glyphStore.namedEntries()) { if (!g) continue; - if (g.glyphRank > 0) sink.add(g.name); - if (Radical.get(g)) sink.add(g.name); - if (g.unicode) { - for (const u of g.unicode) { - if (!excludedChars.has(u)) sink.add(g.name); + if (g.glyphRank > 0) sink.add(gName); + if (Radical.get(g)) sink.add(gName); + const unicodeSet = glyphStore.queryUnicodeOf(g); + if (unicodeSet) { + for (const u of unicodeSet) { + if (!excludedChars.has(u)) sink.add(gName); } } } @@ -126,52 +127,52 @@ function markSubtable(sink, type, st, cfg) { } } -function sweep(gs, restFont, sink) { - filterInPlace(gs, g => sink.has(g.name)); - sweepOtl(restFont.GSUB, sink); - sweepOtl(restFont.GPOS, sink); +function sweep(glyphStore, restFont, gnSet) { + sweepOtl(restFont.GSUB, gnSet); + sweepOtl(restFont.GPOS, gnSet); + return glyphStore.filterByName(gnSet); } -function sweepOtl(table, sink) { +function sweepOtl(table, gnSet) { if (!table || !table.lookups) return; for (const lid in table.lookups) { const lookup = table.lookups[lid]; if (!lookup.subtables) continue; const newSubtables = []; for (const st of lookup.subtables) { - const keep = sweepSubtable(st, lookup.type, sink); + const keep = sweepSubtable(st, lookup.type, gnSet); if (keep) newSubtables.push(st); } lookup.subtables = newSubtables; } } -function sweepSubtable(st, type, gs) { +function sweepSubtable(st, type, gnSet) { switch (type) { case "gsub_single": - return sweep_GsubSingle(st, gs); + return sweep_GsubSingle(st, gnSet); case "gsub_multiple": case "gsub_alternate": - return sweep_GsubMultiple(st, gs); + return sweep_GsubMultiple(st, gnSet); case "gsub_ligature": - return sweep_GsubLigature(st, gs); + return sweep_GsubLigature(st, gnSet); case "gsub_chaining": - return sweep_GsubChaining(st, gs); + return sweep_GsubChaining(st, gnSet); case "gsub_reverse": - return sweep_gsubReverse(st, gs); + return sweep_gsubReverse(st, gnSet); case "gpos_mark_to_base": case "gpos_mark_to_mark": - return sweep_gposMark(st, gs); + return sweep_gposMark(st, gnSet); default: return true; } } -function sweep_GsubSingle(st, gs) { +function sweep_GsubSingle(st, gnSet) { let nonEmpty = false; let from = Object.keys(st); for (const gidFrom of from) { - if (!gs.has(gidFrom) || !gs.has(st[gidFrom])) { + if (!gnSet.has(gidFrom) || !gnSet.has(st[gidFrom])) { delete st[gidFrom]; } else { nonEmpty = true; @@ -180,14 +181,14 @@ function sweep_GsubSingle(st, gs) { return nonEmpty; } -function sweep_GsubMultiple(st, gs) { +function sweep_GsubMultiple(st, gnSet) { let nonEmpty = false; let from = Object.keys(st); for (const gidFrom of from) { - let include = gs.has(gidFrom); + let include = gnSet.has(gidFrom); if (st[gidFrom]) { for (const gidTo of st[gidFrom]) { - include = include && gs.has(gidTo); + include = include && gnSet.has(gidTo); } } else { include = false; @@ -201,26 +202,26 @@ function sweep_GsubMultiple(st, gs) { return nonEmpty; } -function sweep_GsubLigature(st, gs) { +function sweep_GsubLigature(st, gnSet) { if (!st.substitutions) return false; let newSubst = []; for (const rule of st.substitutions) { let include = true; - if (!gs.has(rule.to)) include = false; - for (const from of rule.from) if (!gs.has(from)) include = false; + if (!gnSet.has(rule.to)) include = false; + for (const from of rule.from) if (!gnSet.has(from)) include = false; if (include) newSubst.push(rule); } st.substitutions = newSubst; return true; } -function sweep_GsubChaining(st, gs) { +function sweep_GsubChaining(st, gnSet) { const newMatch = []; for (let j = 0; j < st.match.length; j++) { newMatch[j] = []; for (let k = 0; k < st.match[j].length; k++) { const gidFrom = st.match[j][k]; - if (gs.has(gidFrom)) { + if (gnSet.has(gidFrom)) { newMatch[j].push(gidFrom); } } @@ -230,16 +231,16 @@ function sweep_GsubChaining(st, gs) { return true; } -function sweep_gsubReverse(st, gs) { +function sweep_gsubReverse(st, gnSet) { const newMatch = [], newTo = []; for (let j = 0; j < st.match.length; j++) { newMatch[j] = []; for (let k = 0; k < st.match[j].length; k++) { const gidFrom = st.match[j][k]; - let include = gs.has(gidFrom); + let include = gnSet.has(gidFrom); if (j === st.inputIndex) { - include = include && gs.has(st.to[k]); + include = include && gnSet.has(st.to[k]); if (include) { newMatch[j].push(gidFrom); newTo.push(st.to[k]); @@ -255,7 +256,7 @@ function sweep_gsubReverse(st, gs) { return true; } -function sweep_gposMark(st, gs) { +function sweep_gposMark(st, gnSet) { let marks = st.marks || {}, newMarks = {}, hasMarks = false; @@ -264,13 +265,13 @@ function sweep_gposMark(st, gs) { hasBases = true; for (const gid in marks) { - if (gs.has(gid) && marks[gid]) { + if (gnSet.has(gid) && marks[gid]) { newMarks[gid] = marks[gid]; hasMarks = true; } } for (const gid in bases) { - if (gs.has(gid) && bases[gid]) { + if (gnSet.has(gid) && bases[gid]) { newBases[gid] = bases[gid]; hasBases = true; } @@ -279,17 +280,3 @@ function sweep_gposMark(st, gs) { st.bases = newBases; return hasMarks && hasBases; } - -function filterInPlace(a, condition) { - let i = 0, - j = 0; - - while (i < a.length) { - const val = a[i]; - if (condition(val, i, a)) a[j++] = val; - i++; - } - - a.length = j; - return a; -} diff --git a/font-src/gen/finalize/index.js b/font-src/gen/finalize/index.js index a86eab92d..faf0a3ec5 100644 --- a/font-src/gen/finalize/index.js +++ b/font-src/gen/finalize/index.js @@ -5,82 +5,52 @@ const TypoGeom = require("typo-geom"); const Point = require("../../support/point"); const CurveUtil = require("../../support/curve-util"); -const { AnyCv } = require("../../support/gr"); const gcFont = require("./gc"); -module.exports = function finalizeFont(para, glyphList, excludedCodePoints, font) { - forceMonospaceIfNeeded(para, glyphList); - gcFont(glyphList, excludedCodePoints, font, {}); - extractGlyfCmap(regulateGlyphList(para, glyphList), font); +module.exports = function finalizeFont(para, glyphStore, excludedCodePoints, font) { + glyphStore = forceMonospaceIfNeeded(para, glyphStore); + glyphStore = gcFont(glyphStore, excludedCodePoints, font, {}); + extractGlyfCmap(regulateGlyphStore(para, glyphStore), font); }; -function forceMonospaceIfNeeded(para, glyphList) { - if (!para.forceMonospace || para.spacing > 0) return; +function forceMonospaceIfNeeded(para, glyphStore) { const unitWidth = Math.round(para.width); - let i = 0, - j = 0; - for (; i < glyphList.length; i++) { - const g = glyphList[i]; - g.advanceWidth = Math.round(g.advanceWidth || 0); - if (g.advanceWidth === 0 || g.advanceWidth === unitWidth) glyphList[j++] = g; - } - glyphList.length = j; + if (!para.forceMonospace || para.spacing > 0) return glyphStore; + return glyphStore.filterByGlyph({ + has: g => { + const gw = Math.round(g.advanceWidth || 0); + return gw === 0 || gw === unitWidth; + } + }); } -function extractGlyfCmap(glyphList, font) { +function extractGlyfCmap(glyphStore, font) { const glyf = {}; const cmap = {}; - for (let g of glyphList) { - glyf[g.name] = g; - if (!g.unicode) continue; - - for (let u of g.unicode) { - if (isFinite(u - 0)) cmap[u] = g.name; + const sortedEntries = Array.from(glyphStore.indexedNamedEntries()).sort(byRank); + for (const [origIndex, name, g] of sortedEntries) { + glyf[name] = g; + const us = glyphStore.queryUnicodeOf(g); + if (us) { + for (const u of us) if (isFinite(u - 0) && u) cmap[u] = name; } } font.glyf = glyf; font.cmap = cmap; } -function regulateGlyphList(para, gs) { - const skew = Math.tan(((para.slopeAngle || 0) / 180) * Math.PI); - - const excludeUnicode = new Set(); - excludeUnicode.add(0x80); - for (let c = 0x2500; c <= 0x259f; c++) excludeUnicode.add(c); - - // autoref - for (let j = 0; j < gs.length; j++) { - gs[j].glyphOrder = j; - if (AnyCv.query(gs[j]).length) gs[j].autoRefPriority = -1; - if (gs[j].unicode) { - for (const u of gs[j].unicode) { - if (excludeUnicode.has(u)) gs[j].avoidBeingComposite = true; - } - } - } - gs.sort(byGlyphPriority); - autoRef(gs, excludeUnicode); +function regulateGlyphStore(para, glyphStore) { + autoRef(glyphStore); // regulate - for (let g of gs) regulateGlyph(g, skew); + const skew = Math.tan(((para.slopeAngle || 0) / 180) * Math.PI); + for (let g of glyphStore.glyphs()) regulateGlyph(g, skew); - // reorder - return gs.sort(byRank); + return glyphStore; } -function byGlyphPriority(a, b) { - const pri1 = a.autoRefPriority || 0; - const pri2 = b.autoRefPriority || 0; - if (pri1 > pri2) return -1; - if (pri1 < pri2) return 1; - if (a.contours && b.contours && a.contours.length < b.contours.length) return 1; - if (a.contours && b.contours && a.contours.length > b.contours.length) return -1; - return 0; -} - -function byRank(a, b) { - return (b.glyphRank || 0) - (a.glyphRank || 0) || (a.glyphOrder || 0) - (b.glyphOrder || 0); +function byRank([ja, gna, a], [jb, gnb, b]) { + return (b.glyphRank || 0) - (a.glyphRank || 0) || (ja || 0) - (jb || 0); } function regulateGlyph(g, skew) { diff --git a/font-src/glyphs/autobuild-accents.ptl b/font-src/glyphs/autobuild-accents.ptl index 66eede618..172cb4004 100644 --- a/font-src/glyphs/autobuild-accents.ptl +++ b/font-src/glyphs/autobuild-accents.ptl @@ -67,57 +67,66 @@ glyph-block AutoBuild-Accents : begin return s local foundDecompositions {.} - define [decideName namingParts parts code] : begin - local baseName namingParts.0.name + define [decideName namingParts code] : begin + local baseName : glyphStore.queryNameOf namingParts.0 local glyphName baseName - foreach [part : namingParts.slice 1] : if part : glyphName = glyphName + [fallback part.shortName part.name] + foreach [part : namingParts.slice 1] : if part : begin + glyphName = glyphName + [fallback part.shortName : glyphStore.queryNameOf part] + if foundDecompositions.(glyphName) : begin local j 2 while foundDecompositions.(glyphName + j) [inc j] set glyphName (glyphName + j) + if (glyphName.length > 27) : set glyphName ('uni' + [pad [[code.toString 16].toUpperCase] 4]) return glyphName - local [buildForCode code] : if [not unicodeGlyphs.(code)] : begin + local [buildForCode code] : if [not : glyphStore.queryByUnicode code] : begin local str : String.fromCharCode code local nfd : fallback customDecompositions.(str) : unorm.nfd str if (nfd.length > 1) : begin - local parts {} + local parts { } local allFound true foreach j [range 0 nfd.length] : begin - local part unicodeGlyphs.([nfd.charCodeAt j]) - if [not part] : then : set allFound false - : else : set parts.(j) unicodeGlyphs.([nfd.charCodeAt j]) + local part : glyphStore.queryByUnicode [nfd.charCodeAt j] + if [not part] : then + set allFound false + : else + set parts.(j) part + if allFound : begin - local namingParts : parts.slice 0 + local glyphName : decideName parts code set parts : subParts parts - local glyphName : decideName namingParts parts code - set foundDecompositions.(glyphName) {glyphName code parts} + set foundDecompositions.(glyphName) { glyphName code parts } if recursiveCodes : recursiveCodes.forEach buildForCode : else : foreach code [range 0x0000 0xFFFF] : buildForCode code - local s_parts nothing + local s_parts nothing + define construction : glyph-proc include s_parts.0 AS_BASE ALSO_METRICS foreach part [items-of : s_parts.slice 1] : if part : begin include part - if (part.name === 'rtailBR') : eject-contour 'serifRB' + if (part.markAnchors && part.markAnchors.bottomright) : begin + eject-contour 'serifRB' define [RootGlyphProc goalName code parts] : begin set s_parts parts create-glyph goalName code construction foreach [_id : items-of : Object.keys foundDecompositions] : begin - local {glyphName code parts} foundDecompositions.(_id) - RootGlyphProc glyphName code parts + local { glyphName code parts } foundDecompositions.(_id) + + RootGlyphProc glyphName code parts + define part0Name : glyphStore.queryNameOf parts.0 + if(parts.0 != [query-glyph part0Name]) : throw : new Error "Unreachable" - if(parts.0 != [query-glyph parts.0.name]) : throw : new Error "Unreachable" local dstTree {} local targetNameMap {.} - set targetNameMap.(parts.0.name) glyphName - local tree : getGrTree parts.0.name { DotlessOrNot AnyDerivingCv } query-glyph + set targetNameMap.(part0Name) glyphName + local tree : getGrTree part0Name { DotlessOrNot AnyDerivingCv } query-glyph foreach [{gr origBase relBase} : items-of tree] : begin local origGN targetNameMap.(origBase) if [not origGN] : throw : new Error 'Unreachable' diff --git a/font-src/glyphs/autobuild-composite.ptl b/font-src/glyphs/autobuild-composite.ptl index 48cea93e3..64bdec1db 100644 --- a/font-src/glyphs/autobuild-composite.ptl +++ b/font-src/glyphs/autobuild-composite.ptl @@ -95,7 +95,7 @@ glyph-block AutoBuild-Enclosure : begin define gniPart : '.ci.' + gidPart + '@' + [{ prefix finalPlacement dscale xCompress shift }.join '/'] if [not : query-glyph gniPart] : create-glyph gniPart : glyph-proc set-width 0 - include miniatureFont.(gidPart) + include : miniatureFont.queryByName gidPart include : Upright include : Scale (dscale * xCompress) dscale include : Translate 0 (dscale * (-CAP / 2 + shift)) @@ -113,7 +113,7 @@ glyph-block AutoBuild-Enclosure : begin local firstDerivedGyph null local shift 0 foreach [gidPart : items-of parts] : do - local derivedGlyph miniatureFont.(gidPart) + local derivedGlyph : miniatureFont.queryByName gidPart if [not firstDerivedGyph] : set firstDerivedGyph derivedGlyph set totalWidth : totalWidth + derivedGlyph.advanceWidth local xCompress [Math.min 1 (mockInnerWidth / totalWidth)] @@ -128,7 +128,7 @@ glyph-block AutoBuild-Enclosure : begin define gidPart parts.(partIndex) define finalPlacement : accumulatedAdvanceSoFar - width / 2 - totalWidth * dscale / 2 finalParts.push : EnsureComponentGlyphT gidPart : EnsureInnerSubGlyphImpl miniatureFont prefix finalPlacement dscale xCompress shift - set accumulatedAdvanceSoFar : accumulatedAdvanceSoFar + miniatureFont.(gidPart).advanceWidth * dscale * xCompress + set accumulatedAdvanceSoFar : accumulatedAdvanceSoFar + [miniatureFont.queryByName gidPart].advanceWidth * dscale * xCompress return finalParts @@ -375,7 +375,7 @@ glyph-block AutoBuild-Enclosure : begin if [query-glyph gniPart] : return gniPart create-glyph gniPart : glyph-proc set-width 0 - include miniatureFont.(gidPart) + include : miniatureFont.queryByName gidPart include : Upright include : Translate offset 0 include : Scale xCompress 1 @@ -394,7 +394,7 @@ glyph-block AutoBuild-Enclosure : begin local gidPart partsWithDot.(j) if j : set totalWidth : totalWidth - SB set offsets.(j) totalWidth - set totalWidth : totalWidth + miniatureFont.(gidPart).advanceWidth + set totalWidth : totalWidth + [miniatureFont.queryByName gidPart].advanceWidth set totalWidth : totalWidth - SB local xCompress : if (totalWidth > width) (width / totalWidth) 1 local xTranslate : [if (totalWidth > width) 0 (width / 2 - totalWidth / 2)] - width @@ -423,7 +423,7 @@ glyph-block AutoBuild-Enclosure : begin # Circled & Braced define [digitGlyphNames j] : begin - return : [(j+'').split ''].map: c => unicodeGlyphs.(['0'.charCodeAt 0] + (c - 0)).name + return : [(j+'').split ''].map: c => [glyphStore.queryNameOfUnicode (['0'.charCodeAt 0] + (c - 0))] if [not recursive] : do "Single-digit circled" local compositions : list @@ -436,8 +436,8 @@ glyph-block AutoBuild-Enclosure : begin 0x2460 + j - 1 digitGlyphNames j begin WideWidth1 - foreach [j : range 0 26] : compositions.push {(0x24B6 + j) {unicodeGlyphs.(['A'.charCodeAt 0] + j).name} WideWidth1} - foreach [j : range 0 26] : compositions.push {(0x24D0 + j) {unicodeGlyphs.(['a'.charCodeAt 0] + j).name} WideWidth1 0.5 (XH/2)} + foreach [j : range 0 26] : compositions.push {(0x24B6 + j) {[glyphStore.queryNameOfUnicode (['A'.charCodeAt 0] + j)]} WideWidth1} + foreach [j : range 0 26] : compositions.push {(0x24D0 + j) {[glyphStore.queryNameOfUnicode (['a'.charCodeAt 0] + j)]} WideWidth1 0.5 (XH/2)} createCircledGlyphs 1 compositions if [not recursive] : do "Double-digit circled" @@ -467,7 +467,7 @@ glyph-block AutoBuild-Enclosure : begin 0x2776 + j - 1 digitGlyphNames j begin WideWidth1 - foreach [j : range 0 26] : compositions.push {(0x1F150 + j) {unicodeGlyphs.(['A'.charCodeAt 0] + j).name} WideWidth1} + foreach [j : range 0 26] : compositions.push {(0x1F150 + j) {[glyphStore.queryNameOfUnicode (['A'.charCodeAt 0] + j)]} WideWidth1} createInsetCircledGlyphs 1 compositions if [not recursive] : do "Double-digit inset circled" @@ -485,7 +485,7 @@ glyph-block AutoBuild-Enclosure : begin if [not recursive] : do "boxed" local compositions {} compositions.push { null {'markBaseSpace'} WideWidth1 } - foreach [j : range 0 26] : compositions.push {(0x1F130 + j) {unicodeGlyphs.(['A'.charCodeAt 0] + j).name} WideWidth1} + foreach [j : range 0 26] : compositions.push {(0x1F130 + j) {[glyphStore.queryNameOfUnicode (['A'.charCodeAt 0] + j)]} WideWidth1} createBoxedGlyphs 1 compositions if [not recursive] : do "double-digit boxed" @@ -521,7 +521,7 @@ glyph-block AutoBuild-Enclosure : begin if [not recursive] : do "inset boxed" local compositions {} - foreach [j : range 0 26] : compositions.push {(0x1F170 + j) {unicodeGlyphs.(['A'.charCodeAt 0] + j).name} WideWidth1} + foreach [j : range 0 26] : compositions.push {(0x1F170 + j) {[glyphStore.queryNameOfUnicode (['A'.charCodeAt 0] + j)]} WideWidth1} createInsetBoxedGlyphs 1 compositions if [not recursive] : do "double-digit inset boxed" @@ -535,9 +535,9 @@ glyph-block AutoBuild-Enclosure : begin if [not recursive] : do "inset mosaic" local compositions {} - compositions.push { 0x1FBB1 { [unicodeGlyphs.(0x2714).name.replace [regex '.WWID$'] ".NWID"] } WideWidth2 } - compositions.push { 0x1FBB4 { [unicodeGlyphs.(0x21B2).name.replace [regex '.WWID$'] ".NWID"] } WideWidth2 } - compositions.push { 0x1FBC4 { [unicodeGlyphs.(0x003F).name.replace [regex '.WWID$'] ".NWID"] } WideWidth2 } + compositions.push { 0x1FBB1 { [[glyphStore.queryNameOfUnicode (0x2714)].replace [regex '.WWID$'] ".NWID"] } WideWidth2 } + compositions.push { 0x1FBB4 { [[glyphStore.queryNameOfUnicode (0x21B2)].replace [regex '.WWID$'] ".NWID"] } WideWidth2 } + compositions.push { 0x1FBC4 { [[glyphStore.queryNameOfUnicode (0x003F)].replace [regex '.WWID$'] ".NWID"] } WideWidth2 } createInsetMosaicGlyphs 1 compositions if [not recursive] : do "Single-digit double circled" @@ -564,8 +564,8 @@ glyph-block AutoBuild-Enclosure : begin 0x2474 + j - 1 digitGlyphNames j begin WideWidth1 - foreach [j : range 0 26] : compositions.push {(0x249C + j) {unicodeGlyphs.(['a'.charCodeAt 0] + j).name} WideWidth1 0.5 (XH/2)} - foreach [j : range 0 26] : compositions.push {(0x1F110 + j) {unicodeGlyphs.(['A'.charCodeAt 0] + j).name} WideWidth1} + foreach [j : range 0 26] : compositions.push {(0x249C + j) {[glyphStore.queryNameOfUnicode (['a'.charCodeAt 0] + j)]} WideWidth1 0.5 (XH/2)} + foreach [j : range 0 26] : compositions.push {(0x1F110 + j) {[glyphStore.queryNameOfUnicode (['A'.charCodeAt 0] + j)]} WideWidth1} createBracedGlyphs 1 compositions if [not recursive] : do "Double-digit braced" @@ -621,11 +621,12 @@ glyph-block Autobuild-Fractions : begin define [numeratorImpl numid] : begin local gnn ".frac-num-\(prefix){\(numid)}" if [not : query-glyph gnn] : create-glyph gnn : glyph-proc + define mfNumGlyph : miniatureFont.queryByName numid + set-width 0 - if [not miniatureFont.(numid)] : console.log numid - include miniatureFont.(numid) + include mfNumGlyph include : Upright - include : Translate (- miniatureFont.(numid).advanceWidth / 2) 0 + include : Translate (- mfNumGlyph.advanceWidth / 2) 0 include : Scale scaleFactor include : Translate Middle (SymbolMid + dist / 2) include : Italify @@ -635,10 +636,12 @@ glyph-block Autobuild-Fractions : begin define [denumeratorImpl denid] : begin local gnd ".frac-den-\(prefix){\(denid)}" if [not : query-glyph gnd] : create-glyph gnd : glyph-proc + define mfDenGlyph : miniatureFont.queryByName denid + set-width 0 - include miniatureFont.(denid) + include mfDenGlyph include : Upright - include : Translate (- miniatureFont.(denid).advanceWidth / 2) 0 + include : Translate (- mfDenGlyph.advanceWidth / 2) 0 include : Scale scaleFactor include : Translate Middle (SymbolMid - CAP * scaleFactor - dist / 2) include : Italify @@ -721,7 +724,7 @@ glyph-block AutoBuild-Accented-Equal : begin if [query-glyph gni] : return gni create-glyph gni : glyph-proc set-width 0 - include dFont.(gidPart) + include : dFont.queryByName gidPart include : Upright include : Translate (-totalWidth / 2 + offset) 0 include : Scale scale @@ -736,7 +739,7 @@ glyph-block AutoBuild-Accented-Equal : begin foreach [j : range 0 parts.length] : begin local gidPart parts.(j) set offsets.(j) totalWidth - set totalWidth : totalWidth + dFont.(gidPart).advanceWidth + set totalWidth : totalWidth + [dFont.queryByName gidPart].advanceWidth if [not : query-glyph gn] : create-glyph gn unicode : glyph-proc set-width Width @@ -792,7 +795,7 @@ glyph-block Autobuild-Ligatures : begin if [query-glyph gni] : return gni create-glyph gni : glyph-proc set-width aw - include df.(gidPart) + include : df.queryByName gidPart include : Upright include : Translate offset1 0 include : Scale compress 1 @@ -804,8 +807,8 @@ glyph-block Autobuild-Ligatures : begin local { gn unicode { c1 c2 } desiredWidth } job local ps {} - local dfg1 df1.(c1) - local dfg2 df2.(c2) + local dfg1 : df1.queryByName c1 + local dfg2 : df2.queryByName c2 if FMosaicWide : begin local aw : dfg1.advanceWidth + dfg2.advanceWidth @@ -908,21 +911,25 @@ glyph-block Autobuild-Pnonetic-Ligatures : begin local s 0 local step (-OX) local dist (Stroke * 2) + define dfg1 : df1.queryByName c1 + define dfg2 : df2.queryByName c2 while (s < dist) : begin - include df2.(c2) + include dfg2 include : Translate step 0 set s : s + step - include : Translate (df1.(c1).advanceWidth * wadj1 - kern) 0 + include : Translate (dfg1.advanceWidth * wadj1 - kern) 0 create-glyph glyphName unicode : glyph-proc - local sumChildrenWidth : df1.(c1).advanceWidth * wadj1 + df2.(c2).advanceWidth * wadj2 + define dfg1 : df1.queryByName c1 + define dfg2 : df2.queryByName c2 + local sumChildrenWidth : dfg1.advanceWidth * wadj1 + dfg2.advanceWidth * wadj2 local refW : sumChildrenWidth - kern - include df2.(c2) - include : Translate (df1.(c1).advanceWidth * wadj1 - kern) 0 + include dfg2 + include : Translate (dfg1.advanceWidth * wadj1 - kern) 0 include : difference intersection - Rect (CAP * 2) (Descender * 2) (-Width) (df1.(c1).advanceWidth * wadj1 - kern + df2.(c2).advanceWidth * wadj2 / 2) - glyph-proc : include df1.(c1) + Rect (CAP * 2) (Descender * 2) (-Width) (dfg1.advanceWidth * wadj1 - kern + dfg2.advanceWidth * wadj2 / 2) + glyph-proc : include dfg1 maskOut include : Upright include : Translate (-refW / 2) 0 diff --git a/font-src/glyphs/autobuild-transformed.ptl b/font-src/glyphs/autobuild-transformed.ptl index 723b5d8de..336a56982 100644 --- a/font-src/glyphs/autobuild-transformed.ptl +++ b/font-src/glyphs/autobuild-transformed.ptl @@ -9,7 +9,7 @@ glyph-module glyph-block Autobuild-Transformed : begin glyph-block-import CommonShapes glyph-block-import Common-Derivatives - glyph-block-import Recursive-Build : Fork Miniature Widen + glyph-block-import Recursive-Build : Fork Miniature glyph-block-import Overmarks define [suggestName _name] : begin @@ -66,9 +66,10 @@ glyph-block Autobuild-Transformed : begin foreach {unicode glyphid pri} [items-of records] if [not : query-glyph targetNameMap.(glyphid)] create-glyph (targetNameMap.(glyphid)) unicode : glyph-proc - if [not miniatureFont.(glyphid)] : throw : new Error "Cannot find glyph \(glyphid)" - local middle : miniatureFont.(glyphid).advanceWidth / 2 - include miniatureFont.(glyphid) AS_BASE ALSO_METRICS + if [not : miniatureFont.queryByName glyphid] : begin + throw : new Error "Cannot find glyph \(glyphid)" + local middle : [miniatureFont.queryByName glyphid].advanceWidth / 2 + include [miniatureFont.queryByName glyphid] AS_BASE ALSO_METRICS include [Upright] true include [Translate (-middle) (-CAP)] true include [Scale 0.7] true @@ -89,8 +90,8 @@ glyph-block Autobuild-Transformed : begin foreach {unicode glyphid pri} [items-of records] if [not : query-glyph targetNameMap.(glyphid)] create-glyph (targetNameMap.(glyphid)) unicode : glyph-proc - local middle : miniatureFont.(glyphid).advanceWidth / 2 - include miniatureFont.(glyphid) AS_BASE ALSO_METRICS + local middle : [miniatureFont.queryByName glyphid].advanceWidth / 2 + include [miniatureFont.queryByName glyphid] AS_BASE ALSO_METRICS include [Upright] true include [Translate (-middle) 0] true include [Scale 0.7] true @@ -111,11 +112,10 @@ glyph-block Autobuild-Transformed : begin set forkedParams.diversityI 1 set forkedParams.diversityII 1 local sf : Fork pendingGlyphs forkedParams - foreach {unicode glyphid} [items-of records] - if [not : query-glyph targetNameMap.(glyphid)] + foreach {unicode glyphid} [items-of records] : begin + if [not : query-glyph targetNameMap.(glyphid)] : begin create-glyph targetNameMap.(glyphid) unicode : glyph-proc - include sf.(glyphid) AS_BASE - set-width sf.(glyphid).advanceWidth + include [sf.queryByName glyphid] AS_BASE ALSO_METRICS link-relations relSets define [createMedievalCombs defaultLow defaultHigh _records] : begin @@ -131,7 +131,7 @@ glyph-block Autobuild-Transformed : begin foreach {unicode glyphid} [items-of records] : if [not : query-glyph targetNameMap.(glyphid)] create-glyph targetNameMap.(glyphid) unicode : glyph-proc set-width 0 - local derived miniatureFont.(glyphid) + local derived [miniatureFont.queryByName glyphid] local low defaultLow local high defaultHigh if (derived && derived.baseAnchors.above && derived.baseAnchors.below) : begin @@ -163,8 +163,8 @@ glyph-block Autobuild-Transformed : begin foreach {unicode glyphid} [items-of records] : if [not : query-glyph targetNameMap.(glyphid)] create-glyph targetNameMap.(glyphid) unicode : glyph-proc set-width 0 - local middle : miniatureFont.(glyphid).advanceWidth / 2 - include miniatureFont.(glyphid) + local middle : [miniatureFont.queryByName glyphid].advanceWidth / 2 + include [miniatureFont.queryByName glyphid] include : Upright include : Translate (-middle) (-XH) include : Scale 0.4 @@ -305,7 +305,7 @@ glyph-block Autobuild-Transformed : begin if [not recursive] : let [df : Miniature {'a' 'o'} 4 0.7] : begin create-glyph 'ordfeminine' 0xAA : glyph-proc - include df.a + include : df.queryByName 'a' include : HBarBottom SB RightSB Descender include : Upright include : Translate (-Middle) (-XH) @@ -314,7 +314,7 @@ glyph-block Autobuild-Transformed : begin include : Italify create-glyph 'ordmasculine' 0xBA : glyph-proc - include df.o + include : df.queryByName 'o' include : HBarBottom SB RightSB Descender include : Upright include : Translate (-Middle) (-XH) @@ -477,10 +477,10 @@ glyph-block Autobuild-Rhotic : begin if [not recursive] : let [thinfont : Widen {'schwa' 'revLatinEpsilon'} 0.85 1] : begin create-glyph 'er' 0x25A : glyph-proc # er include MarkSet.e - include thinfont.schwa + include : thinfont.queryByName 'schwa' include : ErTail (Width * 0.85 - SB - markFine * HVContrast * 1.25) create-glyph 'revlatinepsiloner' 0x25D : glyph-proc # revlatinepsiloner include MarkSet.e - include thinfont.revLatinEpsilon + include : thinfont.queryByName 'revLatinEpsilon' include : ErTail (Width * 0.85 - SB - markFine * HVContrast * 1.25) diff --git a/font-src/glyphs/common-derivatives.ptl b/font-src/glyphs/common-derivatives.ptl index a7cd2c3d7..a1a95876e 100644 --- a/font-src/glyphs/common-derivatives.ptl +++ b/font-src/glyphs/common-derivatives.ptl @@ -40,14 +40,15 @@ glyph-block Common-Derivatives : begin define [glyph-is-needed name] : [not pickHash] || pickHash.(name) - define [query-glyph id] : return glyphMap.(id) + define [query-glyph id] : return : glyphStore.queryByName id define [refer-glyph id] : lambda [copyAnchors copyWidth] : begin - if [not glyphMap.(id)] : throw : new Error "Cannot find glyph '\(id)'" - this.includeGlyph glyphMap.(id) copyAnchors copyWidth + local goal : query-glyph id + if [not goal] : throw : new Error "Cannot find glyph '\(id)'" + this.includeGlyph goal copyAnchors copyWidth define [with-related-glyphs sourceGid dstGid unicode Fn] : if [glyph-is-needed sourceGid] : begin - local glyphSrc glyphMap.(sourceGid) + local glyphSrc : glyphStore.queryByName sourceGid local glyphDst : create-glyph dstGid unicode : glyph-proc include : Fn sourceGid null @@ -120,14 +121,14 @@ glyph-block Recursive-Build : begin local shouldBuildList : Object.keys sbh :.filter ([x] => [not [not x]]) #console.log shouldBuildList - local shouldBuildUnicodes : shouldBuildList.map ([x] => [if (glyphMap.(x) && glyphMap.(x).unicode) glyphMap.(x).unicode.0 nothing]) + local shouldBuildUnicodes : shouldBuildList.map ([x] => [if ([glyphStore.queryByName x] && [glyphStore.queryUnicodeOfName x]) [glyphStore.queryUnicodeArrayOfName x].0 nothing]) :.filter ([x] => [not [not x]]) local p {.} foreach [{k v} : pairs-of all ps] : set p.(k) v local gs : buildGlyphs p shouldBuildList shouldBuildUnicodes - return gs.glyphs + return gs.glyphStore define [Miniature] : params [glyphs crowd scale [slopeAngle para.slopeAngle] [sbscale (Width / UPM)] [mono false]] : begin local forkedPara : Object.create para diff --git a/font-src/glyphs/letter-latin.ptl b/font-src/glyphs/letter-latin.ptl index b865b1d0b..8cacfd71f 100644 --- a/font-src/glyphs/letter-latin.ptl +++ b/font-src/glyphs/letter-latin.ptl @@ -2386,7 +2386,7 @@ glyph-block Letter-Latin-Lower-D : begin include : refer-glyph "commaAbove" include : Translate (Width + (RightSB - SB) / 2 + markExtend / 2) 0 local f : Widen {src} 0.95 1 - include f.(src) + include : f.queryByName src include MarkSet.b create-glyph 'dcurlytail' 0x221 : glyph-proc diff --git a/font-src/glyphs/overmarks.ptl b/font-src/glyphs/overmarks.ptl index 1261f8611..1fcb7495e 100644 --- a/font-src/glyphs/overmarks.ptl +++ b/font-src/glyphs/overmarks.ptl @@ -1365,7 +1365,7 @@ glyph-block Overmarks : begin define AnchorMap : list list 'above' 'tieAbove' 'aboveBrace' list 'below' 'tieBelow' 'belowBrace' - foreach { gn g } [pairs-of glyphMap] : begin + foreach { gn g } [glyphStore.namedEntries] : begin local handled false foreach { akFrom akTo akBrace } [items-of AnchorMap] : begin if (!handled && g.markAnchors && g.markAnchors.(akFrom)) : begin diff --git a/font-src/glyphs/symbol-math.ptl b/font-src/glyphs/symbol-math.ptl index fc63ffc9e..227db4d62 100644 --- a/font-src/glyphs/symbol-math.ptl +++ b/font-src/glyphs/symbol-math.ptl @@ -90,7 +90,7 @@ glyph-block Symbol-Math-Letter-Like : begin create-glyph [MangleName 'infty'] [MangleUnicode 0x221E] : glyph-proc set-width MosaicWidth - include df.'eight.lnum' + include : df.queryByName 'eight.lnum' include : Translate (-(Width / 2)) (-CAP / 2) include : Rotate (Math.PI / 2) include : Scale s @@ -99,7 +99,7 @@ glyph-block Symbol-Math-Letter-Like : begin create-glyph [MangleName 'propto'] [MangleUnicode 0x221D] : glyph-proc set-width MosaicWidth - include df.rotetedpropto + include : df.queryByName 'rotetedpropto' include : Translate (-(Width / 2)) (-CAP / 2) include : Rotate (Math.PI / 2) include : Scale s diff --git a/font-src/index.js b/font-src/index.js index bde5f2f3e..ad1658293 100644 --- a/font-src/index.js +++ b/font-src/index.js @@ -12,8 +12,8 @@ const Toml = require("@iarna/toml"); module.exports = async function main(argv) { const para = await getParameters(argv); - const font = BuildFont(para); - if (argv.oCharMap) await saveCharMap(argv, font); + const { font, glyphStore } = BuildFont(para); + if (argv.oCharMap) await saveCharMap(argv, glyphStore); if (argv.o) await saveOtd(argv, font); }; @@ -96,12 +96,14 @@ function objHashNonEmpty(obj) { return false; } -async function saveCharMap(argv, font) { +async function saveCharMap(argv, glyphStore) { let charMap = []; - for (const gid in font.glyf) { - const glyph = font.glyf[gid]; - if (!glyph) continue; - charMap.push([glyph.name, glyph.unicode, ...createGrDisplaySheet(font, gid)]); + for (const [gn] of glyphStore.namedEntries()) { + charMap.push([ + gn, + Array.from(glyphStore.queryUnicodeOfName(gn) || []), + ...createGrDisplaySheet(glyphStore, gn) + ]); } await fs.writeFile(argv.oCharMap, JSON.stringify(charMap), "utf8"); } diff --git a/font-src/meta/macros.ptl b/font-src/meta/macros.ptl index 4298504ba..1d958a412 100644 --- a/font-src/meta/macros.ptl +++ b/font-src/meta/macros.ptl @@ -211,7 +211,7 @@ define-macro glyph-block : syntax-rules set externEnv.$glyphBlockVariableUsage$ variableSet define captureImports `[metrics $NamedParameterPair$ $donothing$ para recursive - recursiveCodes variantSelector glyphMap glyphList unicodeGlyphs $createAndSaveGlyphImpl$ + recursiveCodes variantSelector glyphStore $createAndSaveGlyphImpl$ spirofns booleFns MarkSet AS_BASE ALSO_METRICS pickHash dependencyProfile getDependencyProfile buildGlyphs newtemp tagged DivFrame fontMetrics $assignUnicodeImpl$] define metricImports `[UPM HalfUPM Width SB CAP XH Descender Contrast SymbolMid ParenTop diff --git a/font-src/otl/compat-ligature.ptl b/font-src/otl/compat-ligature.ptl index cc705e506..978d2bdef 100644 --- a/font-src/otl/compat-ligature.ptl +++ b/font-src/otl/compat-ligature.ptl @@ -55,7 +55,7 @@ define [interpretLookupAt gs j lut] : match lut.type if subtable.(gs.(j)) : begin set gs.(j) subtable.(gs.(j)) -export : define [BuildCompatLigatures glyphs glyphList unicodeGlyphs GSUB GDEF config] : begin +export : define [BuildCompatLigatures glyphStore GSUB GDEF config] : begin foreach [cldef : items-of config] : do if [not cldef.unicode] : break nothing if [not cldef.featureTag] : break nothing @@ -69,23 +69,23 @@ export : define [BuildCompatLigatures glyphs glyphList unicodeGlyphs GSUB GDEF c local gnames {} for [local j 0] [j < cldef.sequence.length] [inc j] : begin - if [not unicodeGlyphs.[cldef.sequence.charCodeAt j]] : break nothing - gnames.push unicodeGlyphs.[cldef.sequence.charCodeAt j].name + if [not : glyphStore.queryByUnicode : cldef.sequence.charCodeAt j] : break nothing + gnames.push : glyphStore.queryNameOfUnicode : cldef.sequence.charCodeAt j interpretLookups gnames feature GSUB.lookups - local g1 : new Glyph ('$clig.' + cldef.unicode) + define g1Name : '$clig.' + cldef.unicode + local g1 : new Glyph g1Name set g1.advanceWidth 0 set g1.autoRefPriority 1 set g1.unicode {cldef.unicode} foreach [gn : items-of gnames] : begin - local g glyphs.(gn) + local g : glyphStore.queryByName gn g1.applyTransform : new Transform 1 0 0 1 (-g1.advanceWidth) 0 g1.includeGlyph g g1.applyTransform : new Transform 1 0 0 1 (g1.advanceWidth) 0 set g1.advanceWidth : g1.advanceWidth + g.advanceWidth - set glyphs.(g1.name) g1 - set unicodeGlyphs.(cldef.unicode) g1 - glyphList.push g1 - set GDEF.glyphClassDef.(g1.name) GDEF_LIGATURE + glyphStore.addGlyph g1Name g1 + glyphStore.encodeGlyph cldef.unicode g1 + set GDEF.glyphClassDef.(g1Name) GDEF_LIGATURE diff --git a/font-src/otl/gpos-mark-mkmk.ptl b/font-src/otl/gpos-mark-mkmk.ptl index 5f243c94d..f498ddf03 100644 --- a/font-src/otl/gpos-mark-mkmk.ptl +++ b/font-src/otl/gpos-mark-mkmk.ptl @@ -6,7 +6,7 @@ define MarkClasses { 'trailing' 'lf' 'tieAbove' 'tieBelow' 'aboveBrace' 'belowBrace' } -export : define [buildMarkMkmk sink glyphList] : begin +export : define [buildMarkMkmk sink glyphStore] : begin define mark : add-feature sink 'mark' define mkmk : add-feature sink 'mkmk' add-common-feature sink mark @@ -16,7 +16,7 @@ export : define [buildMarkMkmk sink glyphList] : begin local mkmkLookupNames {} foreach markCls [items-of MarkClasses] : begin - local [object markSubtable mkmkSubtable] : createMTSubtables glyphList { markCls } + local [object markSubtable mkmkSubtable] : createMTSubtables glyphStore { markCls } if ([objectIsNotEmpty markSubtable.marks] && [objectIsNotEmpty markSubtable.bases]) : begin local markLookup : add-lookup sink {.type 'gpos_mark_to_base' .subtables { markSubtable }} mark.lookups.push markLookup @@ -30,33 +30,33 @@ export : define [buildMarkMkmk sink glyphList] : begin foreach markLookup [items-of markLookupNames] : foreach mkmkLookup [items-of mkmkLookupNames] sink.lookupDep.push { markLookup mkmkLookup } -define [createMTSubtables glyphList markClasses] : begin +define [createMTSubtables glyphStore markClasses] : begin local markSubtable {.marks {.} .bases {.}} local mkmkSubtable {.marks {.} .bases {.}} local allowMarkClsSet : new Set markClasses - foreach glyph [items-of glyphList] : begin - createMarkInfo markSubtable.marks glyph allowMarkClsSet - createMarkInfo mkmkSubtable.marks glyph allowMarkClsSet + foreach { gn glyph } [glyphStore.namedEntries] : begin + createMarkInfo markSubtable.marks gn glyph allowMarkClsSet + createMarkInfo mkmkSubtable.marks gn glyph allowMarkClsSet local isMark : objectIsNotEmpty glyph.markAnchors if isMark - createBaseInfo mkmkSubtable.bases glyph allowMarkClsSet - createBaseInfo markSubtable.bases glyph allowMarkClsSet + createBaseInfo mkmkSubtable.bases gn glyph allowMarkClsSet + createBaseInfo markSubtable.bases gn glyph allowMarkClsSet return : object markSubtable mkmkSubtable -define [createBaseInfo sink glyph allowMarkClsSet] : begin +define [createBaseInfo sink gn glyph allowMarkClsSet] : begin local res {.} local pushed false foreach { markCls anchor } [pairs-of glyph.baseAnchors] : if [allowMarkClsSet.has markCls] : begin set pushed true set res.(markCls) {.x anchor.x .y anchor.y} - if pushed : set sink.(glyph.name) res + if pushed : set sink.(gn) res return pushed -define [createMarkInfo sink glyph allowMarkClsSet] : begin +define [createMarkInfo sink gn glyph allowMarkClsSet] : begin local m null foreach { markCls anchor } [pairs-of glyph.markAnchors] : if [allowMarkClsSet.has markCls] : begin set m {.class markCls .x anchor.x .y anchor.y} - if m : set sink.(glyph.name) m + if m : set sink.(gn) m return m define [objectIsNotEmpty obj] : obj && [Object.keys obj].length \ No newline at end of file diff --git a/font-src/otl/gsub-ccmp.ptl b/font-src/otl/gsub-ccmp.ptl index 4d0e63eb0..6ebc2089c 100644 --- a/font-src/otl/gsub-ccmp.ptl +++ b/font-src/otl/gsub-ccmp.ptl @@ -5,7 +5,7 @@ extern Set define-operator "~>" 880 'right' : syntax-rules `(@l ~> @r) `{.left @l .right @r} -export : define [buildCCMP sink glyphs markGlyphs] : begin +export : define [buildCCMP sink glyphStore markGlyphs] : begin local rec : BeginLookupBlock sink define ccmp : add-feature sink 'ccmp' @@ -18,7 +18,7 @@ export : define [buildCCMP sink glyphs markGlyphs] : begin define TieMarkFrom {} define TieMarkTo {} define TieGlyphs {} - foreach [{gid g} : pairs-of glyphs] : if (gid.(0) !== ".") : begin + foreach { gid g } [glyphStore.namedEntries] : if (gid.(0) !== ".") : begin if g.baseAnchors.trailing : groupTR.push gid if g.baseAnchors.lf : groupLF.push gid if [Dotless.get g] : begin @@ -214,7 +214,7 @@ export : define [buildCCMP sink glyphs markGlyphs] : begin # CCMP decomposition define decompositions {.} - foreach {gid g} [pairs-of glyphs] : begin + foreach { gid g } [glyphStore.namedEntries] : begin local parts : CcmpDecompose.get g if (parts && parts.length) : set decompositions.(gid) parts @@ -227,4 +227,4 @@ export : define [buildCCMP sink glyphs markGlyphs] : begin add-common-feature sink ccmp EndLookupBlock rec sink -define [objectIsNotEmpty obj] : obj && [Object.keys obj].length \ No newline at end of file +define [objectIsNotEmpty obj] : obj && [Object.keys obj].length diff --git a/font-src/otl/gsub-cv-ss.ptl b/font-src/otl/gsub-cv-ss.ptl index 5b8adf889..039fffa65 100644 --- a/font-src/otl/gsub-cv-ss.ptl +++ b/font-src/otl/gsub-cv-ss.ptl @@ -5,7 +5,7 @@ extern Set define [FeatureName tag] : tag + '_cvss' define [LookupName tag] : 'lookup_cvss_' + tag -export : define [buildCVSS sink para glyphs glyphList] : begin +export : define [buildCVSS sink para glyphStore] : begin if [not para.enableCvSs] : return nothing local rec : BeginLookupBlock sink @@ -13,7 +13,7 @@ export : define [buildCVSS sink para glyphs glyphList] : begin # Decomposition of enclosures define decompositions {.} - foreach {gid g} [pairs-of glyphs] : begin + foreach { gid g } [glyphStore.namedEntries] : begin local parts : CvDecompose.get g if (parts && parts.length) : set decompositions.(gid) parts @@ -22,7 +22,7 @@ export : define [buildCVSS sink para glyphs glyphList] : begin .subtables : list decompositions # cvxx - foreach [glyph : items-of glyphList] + foreach {gn glyph} [glyphStore.namedEntries] foreach [gr : items-of : AnyCv.query glyph] : if gr.tag : begin local lookupName : LookupName gr.tag if [not : cvLookupNameSet.has lookupName] : begin @@ -36,7 +36,7 @@ export : define [buildCVSS sink para glyphs glyphList] : begin sink.lookupDep.push { lookupCvDecompose lookupName } cvLookupNameSet.add lookupName - set [pick-lookup sink lookupName].subtables.0.(glyph.name) [gr.get glyph] + set [pick-lookup sink lookupName].subtables.0.(gn) [gr.get glyph] # ssxx foreach [{name composition} : pairs-of para.variants] : begin diff --git a/font-src/otl/gsub-ligation.ptl b/font-src/otl/gsub-ligation.ptl index cb6e7016e..fef56f49c 100644 --- a/font-src/otl/gsub-ligation.ptl +++ b/font-src/otl/gsub-ligation.ptl @@ -11,13 +11,14 @@ define look-around null define advance : lambda [t] null define ident : lambda [t] : t.map : lambda [x] x -export : define [buildLigations sink para plm glyphs] : begin +export : define [buildLigations sink para plm] : begin local rec : BeginLookupBlock sink local rankedLookups {} - foreach [ {featureName mappedFeature} : pairs-of plm] : buildLigationsImpl sink para glyphs featureName mappedFeature rankedLookups + foreach [ {featureName mappedFeature} : pairs-of plm] : begin + buildLigationsImpl sink para featureName mappedFeature rankedLookups EndLookupBlock rec sink -define [buildLigationsImpl sink para glyphs featureName mappedFeature rankedLookups] : begin +define [buildLigationsImpl sink para featureName mappedFeature rankedLookups] : begin define {chain-rule reverse-rule} : ChainRuleBuilder sink define arrowStick {'hyphen' 'equal'} diff --git a/font-src/otl/gsub-pairing.ptl b/font-src/otl/gsub-pairing.ptl index b08d4ce92..c682feb84 100644 --- a/font-src/otl/gsub-pairing.ptl +++ b/font-src/otl/gsub-pairing.ptl @@ -1,22 +1,22 @@ import [add-common-feature add-feature add-lookup BeginLookupBlock EndLookupBlock] from "./table-util" # Name-driven feature pairs -export : define [buildPairFeature sink tag1 tag2 glyphs glyphList codedOnly] : begin +export : define [buildPairFeature sink tag1 tag2 glyphStore codedOnly] : begin local rec : BeginLookupBlock sink local mapTag2 {.} local mapTag1 {.} define reHidden : regex "^\\." define reTag1 : new RegExp ("\\." + tag1 + "$") - foreach [glyph : items-of glyphList] : begin - if ([reTag1.test glyph.name] && ![reHidden.test glyph.name]) : do - local gnTag2 : glyph.name.replace reTag1 ('.' + tag2) - local glyphTag2 glyphs.(gnTag2) + foreach { glyphName glyph } [glyphStore.namedEntries] : begin + if ([reTag1.test glyphName] && ![reHidden.test glyphName]) : do + local gnTag2 : glyphName.replace reTag1 ('.' + tag2) + local glyphTag2 : glyphStore.queryByName gnTag2 if (glyphTag2) : begin - if(!codedOnly || glyph.unicode && glyph.unicode.length > 0) - set mapTag2.(glyph.name) gnTag2 - if(!codedOnly || glyphTag2.unicode && glyphTag2.unicode.length > 0) - set mapTag1.(gnTag2) glyph.name + if(!codedOnly || [glyphStore.queryUnicodeOf glyph]) + set mapTag2.(glyphName) gnTag2 + if(!codedOnly || [glyphStore.queryUnicodeOf glyphTag2]) + set mapTag1.(gnTag2) glyphName if [objectIsNotEmpty mapTag1] : begin define lookup1 : add-lookup sink {.type 'gsub_single' .subtables {mapTag1}} @@ -32,4 +32,4 @@ export : define [buildPairFeature sink tag1 tag2 glyphs glyphList codedOnly] : b EndLookupBlock rec sink -define [objectIsNotEmpty obj] : obj && [Object.keys obj].length \ No newline at end of file +define [objectIsNotEmpty obj] : obj && [Object.keys obj].length diff --git a/font-src/otl/gsub-thousands.ptl b/font-src/otl/gsub-thousands.ptl index acbd5275d..9d751c7a8 100644 --- a/font-src/otl/gsub-thousands.ptl +++ b/font-src/otl/gsub-thousands.ptl @@ -3,7 +3,7 @@ import [add-common-feature add-feature add-lookup ChainRuleBuilder query-related define-operator "~>" 880 'right' : syntax-rules `(@l ~> @r) `{.left @l .right @r} -export : define [buildGsubThousands sink para glyphs] : begin +export : define [buildGsubThousands sink para] : begin local rec : BeginLookupBlock sink define Thousand : add-feature sink 'THND' diff --git a/font-src/otl/index.ptl b/font-src/otl/index.ptl index be5bbfe78..075daa405 100644 --- a/font-src/otl/index.ptl +++ b/font-src/otl/index.ptl @@ -19,31 +19,31 @@ define GDEF_LIGATURE 2 define GDEF_MARK 3 # GSUB -define [buildGSUB para glyphs glyphList markGlyphs] : begin +define [buildGSUB para glyphStore markGlyphs] : begin define gsub : CreateEmptyTable # lnum / onum - buildPairFeature gsub 'lnum' 'onum' glyphs glyphList true + buildPairFeature gsub 'lnum' 'onum' glyphStore true # NWID / WWID if (!para.forceMonospace || para.spacing > 0) : begin - buildPairFeature gsub 'NWID' 'WWID' glyphs glyphList true + buildPairFeature gsub 'NWID' 'WWID' glyphStore true # ccmp - buildCCMP gsub glyphs markGlyphs + buildCCMP gsub glyphStore markGlyphs # Ligation if para.enableLigation : do define plm : objectAssign {.} para.defaultBuildup if (para.ligation.caltBuildup && para.ligation.caltBuildup.length) : begin set plm.calt para.ligation.caltBuildup - buildLigations gsub para plm glyphs + buildLigations gsub para plm # THND - buildGsubThousands gsub para glyphs + buildGsubThousands gsub para glyphStore # cv##, ss## - buildCVSS gsub para glyphs glyphList + buildCVSS gsub para glyphStore # locl # Builds last, but the lookups are added into the beginning of the lookup list @@ -54,33 +54,33 @@ define [buildGSUB para glyphs glyphList markGlyphs] : begin return gsub # GPOS -define [buildGPOS para glyphs glyphList markGlyphs] : begin +define [buildGPOS para glyphStore markGlyphs] : begin define gpos : CreateEmptyTable - buildMarkMkmk gpos glyphList + buildMarkMkmk gpos glyphStore finalizeTable gpos return gpos # GDEF -define [buildGDEF para glyphs glyphList markGlyphs] : begin +define [buildGDEF para glyphStore markGlyphs] : begin local GDEF {.glyphClassDef {.}} - foreach glyph [items-of glyphList] : begin - set GDEF.glyphClassDef.(glyph.name) : if [[regex '_'].test glyph.name] GDEF_LIGATURE GDEF_SIMPLE + foreach { gn glyph } [glyphStore.namedEntries] : begin + set GDEF.glyphClassDef.(gn) : if [[regex '_'].test gn] GDEF_LIGATURE GDEF_SIMPLE if (glyph.markAnchors && [begin [local anchorKeys : Object.keys glyph.markAnchors] anchorKeys.length]) : begin foreach key [items-of anchorKeys] : begin if [not markGlyphs.(key)] : set markGlyphs.(key) {} - markGlyphs.(key).push glyph.name - markGlyphs.all.push glyph.name - set GDEF.glyphClassDef.(glyph.name) GDEF_MARK + markGlyphs.(key).push gn + markGlyphs.all.push gn + set GDEF.glyphClassDef.(gn) GDEF_MARK return GDEF -export : define [buildOtl para glyphs glyphList unicodeGlyphs] : begin +export : define [buildOtl para glyphStore] : begin local markGlyphs {.all {} } - local GPOS : buildGPOS para glyphs glyphList markGlyphs - local GDEF : buildGDEF para glyphs glyphList markGlyphs - local GSUB : buildGSUB para glyphs glyphList markGlyphs + local GPOS : buildGPOS para glyphStore markGlyphs + local GDEF : buildGDEF para glyphStore markGlyphs + local GSUB : buildGSUB para glyphStore markGlyphs # Build compatibility ligatures if (para.spacing > 0 && para.compLig) : begin - BuildCompatLigatures glyphs glyphList unicodeGlyphs GSUB GDEF para.compLig + BuildCompatLigatures glyphStore GSUB GDEF para.compLig return [object GSUB GPOS GDEF] diff --git a/font-src/support/glyph-store.js b/font-src/support/glyph-store.js new file mode 100644 index 000000000..5529f8287 --- /dev/null +++ b/font-src/support/glyph-store.js @@ -0,0 +1,109 @@ +"use strict"; + +class GlyphStore { + constructor() { + this.nameForward = new Map(); + this.nameBackward = new Map(); + this.encodingForward = new Map(); + this.encodingBackward = new Map(); + } + + glyphs() { + return this.nameForward.values(); + } + namedEntries() { + return this.nameForward.entries(); + } + *indexedNamedEntries() { + let i = 0; + for (const [name, g] of this.nameForward.entries()) { + yield [i, name, g]; + i++; + } + } + + addGlyph(name, g) { + this.nameForward.set(name, g); + this.nameBackward.set(g, name); + } + queryByName(name) { + return this.nameForward.get(name); + } + queryNameOf(g) { + return this.nameBackward.get(g); + } + + deleteGlyph(g) { + const name = this.nameBackward.get(g); + this.nameBackward.delete(g); + if (name) this.nameForward.delete(g); + this.deleteUnicodeAssignmentsOf(g); + } + deleteGlyphByName(name) { + const g = this.nameForward.get(name); + this.nameForward.delete(g); + if (g) { + this.nameBackward.delete(g); + this.deleteUnicodeAssignmentsOf(g); + } + } + + encodeGlyph(u, g) { + this.encodingForward.set(u, g); + let s = this.encodingBackward.get(g); + if (!s) { + s = new Set(); + this.encodingBackward.set(g, s); + } + s.add(u); + } + queryByUnicode(u) { + return this.encodingForward.get(u); + } + queryNameOfUnicode(u) { + const g = this.queryByUnicode(u); + if (!g) return undefined; + return this.queryNameOf(g); + } + queryUnicodeOf(g) { + const s = this.encodingBackward.get(g); + if (!s || !s.size) return null; + return s; + } + queryUnicodeOfName(name) { + const g = this.queryByName(name); + if (!g) return undefined; + return this.queryUnicodeOf(g); + } + queryUnicodeArrayOfName(name) { + return [...this.queryUnicodeOfName(name)]; + } + deleteUnicodeAssignmentsOf(g) { + const s = this.nameBackward.get(g); + if (s) for (const u of s) this.encodingForward.delete(u); + this.encodingBackward.delete(g); + } + + filterByName(nameSet) { + const gs1 = new GlyphStore(); + for (const [name, g] of this.nameForward) { + if (!nameSet.has(name)) continue; + gs1.addGlyph(name, g); + const us = this.encodingBackward.get(g); + if (us) for (const u of us) gs1.encodeGlyph(u, g); + } + return gs1; + } + filterByGlyph(glyphSet) { + const gs1 = new GlyphStore(); + for (const [name, g] of this.nameForward) { + if (!glyphSet.has(g)) continue; + gs1.addGlyph(name, g); + const us = this.encodingBackward.get(g); + if (us) for (const u of us) gs1.encodeGlyph(u, g); + } + return gs1; + } +} + +module.exports = GlyphStore; diff --git a/font-src/support/glyph.js b/font-src/support/glyph.js index 0aa8e562f..f0d70d763 100644 --- a/font-src/support/glyph.js +++ b/font-src/support/glyph.js @@ -6,8 +6,7 @@ const Anchor = require("./anchor"); module.exports = class Glyph { constructor(name) { - Object.defineProperty(this, "name", { value: name, writable: false }); - this.unicode = []; + this._m_dependentName = name; this.contours = []; this.advanceWidth = 500; this.autoRefPriority = 0; @@ -17,6 +16,15 @@ module.exports = class Glyph { this.dependencies = []; this.defaultTag = null; } + get name() { + throw new TypeError("Glyph::name has been deprecated"); + } + get unicode() { + throw new TypeError("Glyph::unicode has been deprecated"); + } + set unicode(x) { + throw new TypeError("Glyph::unicode has been deprecated"); + } // PTL pattern matching static unapply(obj, arity) { if (obj instanceof Glyph) return [obj]; @@ -26,14 +34,9 @@ module.exports = class Glyph { setWidth(w) { this.advanceWidth = w; } - // Encoding - assignUnicode(u) { - if (typeof u === "string") this.unicode.push(u.codePointAt(0)); - else this.unicode.push(u); - } // Dependency dependsOn(glyph) { - if (glyph.name) this.dependencies.push(glyph.name); + if (glyph._m_dependentName) this.dependencies.push(glyph._m_dependentName); if (glyph.dependencies) for (const dep of glyph.dependencies) this.dependencies.push(dep); } // Contour Tagging diff --git a/font-src/support/gr.js b/font-src/support/gr.js index 4fb4e2aa4..46ea858cb 100644 --- a/font-src/support/gr.js +++ b/font-src/support/gr.js @@ -235,8 +235,8 @@ function getGrMesh(gidList, grq, fnGidToGlyph) { return ret; } -function createGrDisplaySheet(font, gid) { - const glyph = font.glyf[gid]; +function createGrDisplaySheet(glyphStore, gid) { + const glyph = glyphStore.queryByName(gid); if (!glyph) return []; // Query selected typographic features -- mostly NWID and WWID @@ -249,7 +249,7 @@ function createGrDisplaySheet(font, gid) { if (decomposition) { const variantFeatureSet = new Set(); for (const componentGn of decomposition) { - const component = font.glyf[componentGn]; + const component = glyphStore.queryByName(componentGn); if (!component) continue; const cvRow = queryCvFeatureTagsOf(componentGn, component, variantFeatureSet); if (cvRow.length) charVariantFeatures.push(cvRow);