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