Optimize the footprint of TTCs and Super-TTCs by 1/3.
This commit is contained in:
parent
ededbbc703
commit
6135354a30
28 changed files with 252 additions and 169 deletions
|
@ -88,6 +88,7 @@ function markGlyphsInitial(glyphStore, excludedChars) {
|
||||||
}
|
}
|
||||||
function markGlyphsStep(glyphStore, sink, otl, cfg) {
|
function markGlyphsStep(glyphStore, sink, otl, cfg) {
|
||||||
const glyphCount = sink.size;
|
const glyphCount = sink.size;
|
||||||
|
|
||||||
if (otl.GSUB) {
|
if (otl.GSUB) {
|
||||||
for (const l in otl.GSUB.lookups) {
|
for (const l in otl.GSUB.lookups) {
|
||||||
const lookup = otl.GSUB.lookups[l];
|
const lookup = otl.GSUB.lookups[l];
|
||||||
|
|
|
@ -42,7 +42,7 @@ function regulateCompositeGlyph(glyphStore, memo, g) {
|
||||||
|
|
||||||
for (const sr of refs) {
|
for (const sr of refs) {
|
||||||
const gn = glyphStore.queryNameOf(sr.glyph);
|
const gn = glyphStore.queryNameOf(sr.glyph);
|
||||||
if (!gn || sr.glyph.autoRefPriority < 0) return memoSet(memo, g, false);
|
if (!gn) return memoSet(memo, g, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// De-doppelganger
|
// De-doppelganger
|
||||||
|
|
|
@ -2,21 +2,38 @@
|
||||||
|
|
||||||
const finalizeGlyphs = require("./glyphs");
|
const finalizeGlyphs = require("./glyphs");
|
||||||
const gcFont = require("./gc");
|
const gcFont = require("./gc");
|
||||||
|
const { Nwid, Wwid } = require("../../support/gr");
|
||||||
|
|
||||||
module.exports = function finalizeFont(cache, para, glyphStore, excludedCodePoints, restFont) {
|
module.exports = function finalizeFont(cache, para, glyphStore, excludedCodePoints, restFont) {
|
||||||
|
assignGrAndCodeRank(glyphStore, Nwid, Wwid);
|
||||||
|
assignSubRank(glyphStore);
|
||||||
glyphStore = gcFont(glyphStore, excludedCodePoints, restFont, {});
|
glyphStore = gcFont(glyphStore, excludedCodePoints, restFont, {});
|
||||||
glyphStore = finalizeGlyphs(cache, para, glyphStore);
|
glyphStore = finalizeGlyphs(cache, para, glyphStore);
|
||||||
validateMonospace(para, glyphStore);
|
validateMonospace(para, glyphStore);
|
||||||
return glyphStore;
|
return glyphStore;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function assignGrAndCodeRank(glyphStore, ...flatteners) {
|
||||||
|
for (const g of glyphStore.glyphs()) {
|
||||||
|
g.codeRank = 0xffffffff;
|
||||||
|
for (const c of glyphStore.flattenCodes(g, flatteners)) if (c < g.codeRank) g.codeRank = c;
|
||||||
|
|
||||||
|
g.grRank = 0;
|
||||||
|
for (let i = 0; i < flatteners.length; i++) if (flatteners[i].get(g)) g.grRank |= 1 << i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function assignSubRank(glyphStore) {
|
||||||
|
let sr = 0;
|
||||||
|
for (const g of glyphStore.glyphs()) g.subRank = sr++;
|
||||||
|
}
|
||||||
|
|
||||||
// In FontConfig, a font is considered "monospace" if and only if all non-combining characters
|
// In FontConfig, a font is considered "monospace" if and only if all non-combining characters
|
||||||
// (AW > 0) have the same width. We use this method to validate whether our "Fixed" subfamilies
|
// (AW > 0) have the same width. We use this method to validate whether our "Fixed" subfamilies
|
||||||
// are properly built.
|
// are properly built.
|
||||||
function validateMonospace(para, glyphStore) {
|
function validateMonospace(para, glyphStore) {
|
||||||
if (!para.forceMonospace) return;
|
if (!para.forceMonospace) return;
|
||||||
let awSet = new Set();
|
let awSet = new Set();
|
||||||
for (const g of glyphStore.glyphs()) {
|
for (const [u, g] of glyphStore.encodedEntries()) {
|
||||||
const aw = Math.round(g.advanceWidth || 0);
|
const aw = Math.round(g.advanceWidth || 0);
|
||||||
if (aw > 0) awSet.add(aw);
|
if (aw > 0) awSet.add(aw);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
const { Joining, AnyCv, TieMark } = require("../../support/gr");
|
const { Joining, AnyCv, TieMark, Nwid, Wwid } = require("../../support/gr");
|
||||||
|
|
||||||
const ApplePostNames = new Map([
|
const ApplePostNames = new Map([
|
||||||
/* spell-checker: disable */
|
/* spell-checker: disable */
|
||||||
|
@ -261,9 +261,9 @@ const ApplePostNames = new Map([
|
||||||
/* spell-checker: enable */
|
/* spell-checker: enable */
|
||||||
]);
|
]);
|
||||||
|
|
||||||
function nameSingleGlyph1(gid, gSrc, primaryUnicode, conflictSet) {
|
function byCode(gSrc, primaryUnicode, conflictSet) {
|
||||||
if (gid === 0) return ".notdef";
|
if (gSrc.glyphRank === 9999) return ".notdef";
|
||||||
if (gid === 1) return ".null";
|
if (gSrc.glyphRank === 9998) return ".null";
|
||||||
|
|
||||||
let preferredName = null;
|
let preferredName = null;
|
||||||
if (primaryUnicode) {
|
if (primaryUnicode) {
|
||||||
|
@ -279,32 +279,61 @@ function nameSingleGlyph1(gid, gSrc, primaryUnicode, conflictSet) {
|
||||||
function formatCodePointHex(u) {
|
function formatCodePointHex(u) {
|
||||||
return u.toString(16).padStart(4, "0").toUpperCase();
|
return u.toString(16).padStart(4, "0").toUpperCase();
|
||||||
}
|
}
|
||||||
|
function bySpacing(gSrcBase, gOtBase, internalNameMap, conflictSet) {
|
||||||
function nameSingleGlyph2(gSrcBase, baseName, internalNameMap, conflictSet) {
|
if (!gOtBase.name) return 0;
|
||||||
if (!baseName) return;
|
let n = 0;
|
||||||
|
n += nameByPairGr(Nwid, Wwid, "NWID", "WWID", gSrcBase, gOtBase, internalNameMap, conflictSet);
|
||||||
|
n += nameByPairGr(Wwid, Nwid, "WWID", "NWID", gSrcBase, gOtBase, internalNameMap, conflictSet);
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
function byGr(gSrcBase, gOtBase, internalNameMap, conflictSet) {
|
||||||
|
if (!gOtBase.name) return 0;
|
||||||
|
let n = 0;
|
||||||
for (const cv of AnyCv.query(gSrcBase)) {
|
for (const cv of AnyCv.query(gSrcBase)) {
|
||||||
nameByGr(cv, gSrcBase, baseName, internalNameMap, conflictSet);
|
n += nameByGr(cv, gSrcBase, gOtBase, internalNameMap, conflictSet);
|
||||||
}
|
}
|
||||||
if (TieMark.get(gSrcBase)) {
|
if (TieMark.get(gSrcBase)) {
|
||||||
nameByGr(TieMark, gSrcBase, baseName, internalNameMap, conflictSet);
|
n += nameByGr(TieMark, gSrcBase, gOtBase, internalNameMap, conflictSet);
|
||||||
}
|
}
|
||||||
|
return n;
|
||||||
}
|
}
|
||||||
function nameByGr(gr, gSrcBase, baseName, internalNameMap, conflictSet) {
|
function nameByPairGr(grCis, grTrans, tagCis, tagTrans, gSrcBase, gOtBase, nm, conflictSet) {
|
||||||
|
const gnDst = grCis.get(gSrcBase);
|
||||||
|
if (!gnDst) return 0;
|
||||||
|
const gOtDst = nm.get(gnDst);
|
||||||
|
if (!gOtDst || gOtDst.name) return 0;
|
||||||
|
const nameS = gOtBase.name + "." + tagTrans;
|
||||||
|
const nameT = gOtBase.name + "." + tagCis;
|
||||||
|
if (!conflictSet.has(nameS) && !conflictSet.has(nameT)) {
|
||||||
|
conflictSet.add(nameS);
|
||||||
|
conflictSet.add(nameT);
|
||||||
|
gOtBase.name = nameS;
|
||||||
|
gOtDst.name = nameT;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
function nameByGr(gr, gSrcBase, gOtBase, internalNameMap, conflictSet) {
|
||||||
const gnDst = gr.get(gSrcBase);
|
const gnDst = gr.get(gSrcBase);
|
||||||
|
if (!gnDst) return 0;
|
||||||
const gOtDst = internalNameMap.get(gnDst);
|
const gOtDst = internalNameMap.get(gnDst);
|
||||||
const nameT = gr.amendOtName(baseName);
|
if (!gOtDst || gOtDst.name) return 0;
|
||||||
if (gOtDst && !gOtDst.name && !conflictSet.has(nameT)) {
|
const nameT = gr.amendOtName(gOtBase.name);
|
||||||
|
if (!conflictSet.has(nameT)) {
|
||||||
conflictSet.add(nameT);
|
conflictSet.add(nameT);
|
||||||
gOtDst.name = nameT;
|
gOtDst.name = nameT;
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function nameSingleGlyph3(gid, gSrc, gnOrig) {
|
function byBuildOrder(rank, gSrc, gnOrig) {
|
||||||
if (!gnOrig) gnOrig = `.gid${gid}`;
|
if (!gnOrig) gnOrig = `.g${rank}`;
|
||||||
gnOrig = Joining.amendOtName(gnOrig, Joining.get(gSrc));
|
gnOrig = Joining.amendOtName(gnOrig, Joining.get(gSrc));
|
||||||
return gnOrig;
|
return gnOrig;
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.nameSingleGlyph1 = nameSingleGlyph1;
|
exports.byCode = byCode;
|
||||||
exports.nameSingleGlyph2 = nameSingleGlyph2;
|
exports.bySpacing = bySpacing;
|
||||||
exports.nameSingleGlyph3 = nameSingleGlyph3;
|
exports.byGr = byGr;
|
||||||
|
exports.byBuildOrder = byBuildOrder;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
const { Ot } = require("ot-builder");
|
const { Ot } = require("ot-builder");
|
||||||
const Point = require("../../support/point");
|
const Point = require("../../support/point");
|
||||||
const { nameSingleGlyph1, nameSingleGlyph2, nameSingleGlyph3 } = require("./glyph-name");
|
const Gr = require("../../support/gr");
|
||||||
|
const { byCode, bySpacing, byGr, byBuildOrder } = require("./glyph-name");
|
||||||
|
|
||||||
class MappedGlyphStore {
|
class MappedGlyphStore {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
@ -16,6 +17,7 @@ class MappedGlyphStore {
|
||||||
setPrimaryUnicode(source, u) {
|
setPrimaryUnicode(source, u) {
|
||||||
this.m_primaryUnicodeMapping.set(u, source);
|
this.m_primaryUnicodeMapping.set(u, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
queryBySourceGlyph(source) {
|
queryBySourceGlyph(source) {
|
||||||
return this.m_mapping.get(source);
|
return this.m_mapping.get(source);
|
||||||
}
|
}
|
||||||
|
@ -48,23 +50,44 @@ class MappedGlyphStore {
|
||||||
let conflictSet = new Set();
|
let conflictSet = new Set();
|
||||||
let rev = new Map();
|
let rev = new Map();
|
||||||
for (const [u, g] of this.m_primaryUnicodeMapping) rev.set(g, u);
|
for (const [u, g] of this.m_primaryUnicodeMapping) rev.set(g, u);
|
||||||
for (const [gSrc, gOt] of this.m_mapping) gOt.name = undefined;
|
|
||||||
|
const glyphsInBuildOrder = Array.from(this.m_mapping).sort(
|
||||||
|
([a], [b]) => a.subRank - b.subRank
|
||||||
|
);
|
||||||
|
|
||||||
|
for (const [gSrc, gOt] of glyphsInBuildOrder) gOt.name = undefined;
|
||||||
|
|
||||||
// Name by Unicode
|
// Name by Unicode
|
||||||
gid = 0;
|
for (const [gSrc, gOt] of glyphsInBuildOrder) {
|
||||||
for (const [gSrc, gOt] of this.m_mapping) {
|
gOt.name = byCode(gSrc, rev.get(gSrc), conflictSet);
|
||||||
gOt.name = nameSingleGlyph1(gid, gSrc, rev.get(gSrc), conflictSet);
|
|
||||||
gid++;
|
|
||||||
}
|
|
||||||
// Name by CV
|
|
||||||
for (const [gSrcBase, gOtBase] of this.m_mapping) {
|
|
||||||
nameSingleGlyph2(gSrcBase, gOtBase.name, this.m_nameMapping, conflictSet);
|
|
||||||
}
|
}
|
||||||
|
// Name by NWID/WWID
|
||||||
|
let nNewNames = 0;
|
||||||
|
do {
|
||||||
|
nNewNames = 0;
|
||||||
|
for (const [gSrcBase, gOtBase] of glyphsInBuildOrder) {
|
||||||
|
nNewNames += bySpacing(gSrcBase, gOtBase, this.m_nameMapping, conflictSet);
|
||||||
|
}
|
||||||
|
} while (nNewNames > 0);
|
||||||
|
// Name by Gr
|
||||||
|
do {
|
||||||
|
nNewNames = 0;
|
||||||
|
for (const [gSrcBase, gOtBase] of glyphsInBuildOrder) {
|
||||||
|
nNewNames += byGr(gSrcBase, gOtBase, this.m_nameMapping, conflictSet);
|
||||||
|
}
|
||||||
|
} while (nNewNames > 0);
|
||||||
// Name rest
|
// Name rest
|
||||||
gid = 0;
|
for (const [gSrc, gOt] of glyphsInBuildOrder) {
|
||||||
for (const [gSrc, gOt] of this.m_mapping) {
|
gOt.name = byBuildOrder(gSrc.subRank, gSrc, gOt.name);
|
||||||
gOt.name = nameSingleGlyph3(gid, gSrc, gOt.name);
|
}
|
||||||
gid++;
|
|
||||||
|
// validate
|
||||||
|
{
|
||||||
|
let gnSet = new Set();
|
||||||
|
for (const [gSrc, gOt] of this.m_mapping) {
|
||||||
|
if (gnSet.has(gOt.name)) throw new Error("Unreachable! duplicate name " + gOt.name);
|
||||||
|
gnSet.add(gOt.name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,14 +124,12 @@ class MappedGlyphStore {
|
||||||
|
|
||||||
module.exports = convertGlyphs;
|
module.exports = convertGlyphs;
|
||||||
function convertGlyphs(gsOrig) {
|
function convertGlyphs(gsOrig) {
|
||||||
const sortedEntries = Array.from(gsOrig.indexedNamedEntries())
|
const sortedEntries = Array.from(gsOrig.namedEntries(Gr.Nwid, Gr.Wwid)).sort(byRank);
|
||||||
.map(([j, gn, g]) => [j, gn, queryOrderingUnicode(gsOrig, g), g])
|
|
||||||
.sort(byRank);
|
|
||||||
|
|
||||||
const gs = new MappedGlyphStore();
|
const gs = new MappedGlyphStore();
|
||||||
const cmap = new Ot.Cmap.Table();
|
const cmap = new Ot.Cmap.Table();
|
||||||
|
|
||||||
for (const [origIndex, name, uOrd, gSrc] of sortedEntries) {
|
for (const [name, gSrc] of sortedEntries) {
|
||||||
gs.declare(name, gSrc);
|
gs.declare(name, gSrc);
|
||||||
const us = gsOrig.queryUnicodeOf(gSrc);
|
const us = gsOrig.queryUnicodeOf(gSrc);
|
||||||
if (us) {
|
if (us) {
|
||||||
|
@ -119,17 +140,16 @@ function convertGlyphs(gsOrig) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const [origIndex, name, uOrd, gSrc] of sortedEntries) gs.fill(name, gSrc);
|
for (const [name, gSrc] of sortedEntries) gs.fill(name, gSrc);
|
||||||
gs.fillOtGlyphNames();
|
gs.fillOtGlyphNames();
|
||||||
return { glyphs: gs, cmap };
|
return { glyphs: gs, cmap };
|
||||||
}
|
}
|
||||||
function queryOrderingUnicode(gs, g) {
|
|
||||||
const us = gs.queryUnicodeOf(g);
|
function byRank([gna, a], [gnb, b]) {
|
||||||
if (us && us.size) return Array.from(us).sort((a, b) => a - b)[0];
|
|
||||||
else return 0xffffff;
|
|
||||||
}
|
|
||||||
function byRank([ja, gna, ua, a], [jb, gnb, ub, b]) {
|
|
||||||
return (
|
return (
|
||||||
(b.glyphRank || 0) - (a.glyphRank || 0) || (ua || 0) - (ub || 0) || (ja || 0) - (jb || 0)
|
b.glyphRank - a.glyphRank ||
|
||||||
|
a.grRank - b.grRank ||
|
||||||
|
a.codeRank - b.codeRank ||
|
||||||
|
a.subRank - b.subRank
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -569,8 +569,6 @@ glyph-block AutoBuild-Enclosure : begin
|
||||||
ps.push p
|
ps.push p
|
||||||
include : Translate width 0
|
include : Translate width 0
|
||||||
if jobDecomposable : CvDecompose.set currentGlyph ps
|
if jobDecomposable : CvDecompose.set currentGlyph ps
|
||||||
set currentGlyph.autoRefPriority 11
|
|
||||||
|
|
||||||
|
|
||||||
define gnSpace : '.dotted-space.' + [{ digits suffix }.join '/']
|
define gnSpace : '.dotted-space.' + [{ digits suffix }.join '/']
|
||||||
if [not : query-glyph gnSpace] : create-glyph gnSpace : glyph-proc
|
if [not : query-glyph gnSpace] : create-glyph gnSpace : glyph-proc
|
||||||
|
|
|
@ -80,7 +80,7 @@ glyph-block Autobuild-Transformed : begin
|
||||||
scale -- 0.7
|
scale -- 0.7
|
||||||
mono -- true
|
mono -- true
|
||||||
sbscale -- 1
|
sbscale -- 1
|
||||||
foreach {unicode glyphid pri} [items-of records]
|
foreach {unicode glyphid} [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.queryByName glyphid] : begin
|
if [not : miniatureFont.queryByName glyphid] : begin
|
||||||
|
@ -92,7 +92,6 @@ glyph-block Autobuild-Transformed : begin
|
||||||
include [Scale 0.7] true
|
include [Scale 0.7] true
|
||||||
include [Translate middle (CAP + Accent / 2)] true
|
include [Translate middle (CAP + Accent / 2)] true
|
||||||
include [Italify] true
|
include [Italify] true
|
||||||
if pri : set currentGlyph.autoRefPriority pri
|
|
||||||
link-relations relSets
|
link-relations relSets
|
||||||
return { targetNameMap records }
|
return { targetNameMap records }
|
||||||
|
|
||||||
|
@ -104,7 +103,7 @@ glyph-block Autobuild-Transformed : begin
|
||||||
scale -- 0.7
|
scale -- 0.7
|
||||||
mono -- true
|
mono -- true
|
||||||
sbscale -- 1
|
sbscale -- 1
|
||||||
foreach {unicode glyphid pri} [items-of records]
|
foreach {unicode glyphid} [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.queryByName glyphid].advanceWidth / 2
|
local middle : [miniatureFont.queryByName glyphid].advanceWidth / 2
|
||||||
|
@ -114,7 +113,6 @@ glyph-block Autobuild-Transformed : begin
|
||||||
include [Scale 0.7] true
|
include [Scale 0.7] true
|
||||||
include [Translate middle (Descender / 2)] true
|
include [Translate middle (Descender / 2)] true
|
||||||
include [Italify] true
|
include [Italify] true
|
||||||
if pri : set currentGlyph.autoRefPriority pri
|
|
||||||
link-relations relSets
|
link-relations relSets
|
||||||
|
|
||||||
# Not used today -- may be used in the future
|
# Not used today -- may be used in the future
|
||||||
|
@ -314,11 +312,11 @@ glyph-block Autobuild-Transformed : begin
|
||||||
list 0x1D41 'U'
|
list 0x1D41 'U'
|
||||||
list 0x1D42 'W'
|
list 0x1D42 'W'
|
||||||
list 0x2C7D 'V'
|
list 0x2C7D 'V'
|
||||||
list 0x207A 'plus' (-11)
|
list 0x207A 'plus'
|
||||||
list 0x207B 'minus' (-11)
|
list 0x207B 'minus'
|
||||||
list 0x207C 'equal' (-11)
|
list 0x207C 'equal'
|
||||||
list 0x207D 'parenLeft' (-11)
|
list 0x207D 'parenLeft'
|
||||||
list 0x207E 'parenRight' (-11)
|
list 0x207E 'parenRight'
|
||||||
list 0xA7F8 'smcpHbar'
|
list 0xA7F8 'smcpHbar'
|
||||||
list 0xA7F9 'oe'
|
list 0xA7F9 'oe'
|
||||||
|
|
||||||
|
@ -364,11 +362,11 @@ glyph-block Autobuild-Transformed : begin
|
||||||
list 0x1D69 'grek/phi'
|
list 0x1D69 'grek/phi'
|
||||||
list 0x1D6A 'grek/chi'
|
list 0x1D6A 'grek/chi'
|
||||||
list 0x2C7C 'j'
|
list 0x2C7C 'j'
|
||||||
list 0x208A 'plus' (-11)
|
list 0x208A 'plus'
|
||||||
list 0x208B 'minus' (-11)
|
list 0x208B 'minus'
|
||||||
list 0x208C 'equal' (-11)
|
list 0x208C 'equal'
|
||||||
list 0x208D 'parenLeft' (-11)
|
list 0x208D 'parenLeft'
|
||||||
list 0x208E 'parenRight' (-11)
|
list 0x208E 'parenRight'
|
||||||
|
|
||||||
createMedievalCombs 0 XH : list
|
createMedievalCombs 0 XH : list
|
||||||
list 0x363 'a'
|
list 0x363 'a'
|
||||||
|
|
|
@ -102,7 +102,6 @@ glyph-block Common-Derivatives : begin
|
||||||
define x : if (_x <@ Function) [_x.call currentGlyph] _x
|
define x : if (_x <@ Function) [_x.call currentGlyph] _x
|
||||||
define y : if (_y <@ Function) [_y.call currentGlyph] _y
|
define y : if (_y <@ Function) [_y.call currentGlyph] _y
|
||||||
include : FlipAround x y
|
include : FlipAround x y
|
||||||
set currentGlyph.autoRefPriority [query-glyph src].autoRefPriority
|
|
||||||
|
|
||||||
define [link-reduced-variant] : params [dstGid srcGid gr follow] : begin
|
define [link-reduced-variant] : params [dstGid srcGid gr follow] : begin
|
||||||
if [not : query-glyph dstGid] : select-variant dstGid (shapeFrom -- srcGid) (follow -- [fallback follow dstGid])
|
if [not : query-glyph dstGid] : select-variant dstGid (shapeFrom -- srcGid) (follow -- [fallback follow dstGid])
|
||||||
|
|
|
@ -3,6 +3,7 @@ import '../support/glyph-store' as GlyphStore
|
||||||
import '../support/glyph-block' as GlyphBlock
|
import '../support/glyph-block' as GlyphBlock
|
||||||
import '../support/point' as Point
|
import '../support/point' as Point
|
||||||
import '../support/anchor' as Anchor
|
import '../support/anchor' as Anchor
|
||||||
|
import '../support/gr' as Gr
|
||||||
import '../kits/spiro-kit' as spirokit
|
import '../kits/spiro-kit' as spirokit
|
||||||
import '../kits/boole-kit' as BooleKit
|
import '../kits/boole-kit' as BooleKit
|
||||||
import [ DesignParameters ] from "../meta/aesthetics"
|
import [ DesignParameters ] from "../meta/aesthetics"
|
||||||
|
@ -155,5 +156,7 @@ export all : define [buildGlyphs para recursive recursiveCodes] : begin
|
||||||
|
|
||||||
foreach [gb : items-of $$Capture$$.$pendingGlyphBlocks$] : gb.resolve
|
foreach [gb : items-of $$Capture$$.$pendingGlyphBlocks$] : gb.resolve
|
||||||
|
|
||||||
return : object glyphStore fontMetrics
|
Gr.linkSuffixPairGr glyphStore 'NWID' 'WWID' Gr.Nwid Gr.Wwid
|
||||||
|
Gr.linkSuffixPairGr glyphStore 'lnum' 'onum' Gr.Lnum Gr.Onum
|
||||||
|
|
||||||
|
return : object glyphStore fontMetrics
|
||||||
|
|
|
@ -43,7 +43,6 @@ glyph-block Letter-Latin-Lower-L : begin
|
||||||
|
|
||||||
define [SeriflessBody df xMiddle] : glyph-proc
|
define [SeriflessBody df xMiddle] : glyph-proc
|
||||||
include : VBar xMiddle 0 CAP
|
include : VBar xMiddle 0 CAP
|
||||||
set currentGlyph.autoRefPriority (-2)
|
|
||||||
|
|
||||||
define [SerifedBody df xMiddle] : glyph-proc
|
define [SerifedBody df xMiddle] : glyph-proc
|
||||||
include : VBar xMiddle 0 CAP
|
include : VBar xMiddle 0 CAP
|
||||||
|
|
|
@ -1197,7 +1197,6 @@ glyph-block Marks : begin
|
||||||
flat 0 (-O) [heading Downward]
|
flat 0 (-O) [heading Downward]
|
||||||
curl 0 0 [heading Downward]
|
curl 0 0 [heading Downward]
|
||||||
straight.right.end (HookX - HalfStroke * HVContrast) (-Hook + HalfStroke)
|
straight.right.end (HookX - HalfStroke * HVContrast) (-Hook + HalfStroke)
|
||||||
set currentGlyph.autoRefPriority (-2)
|
|
||||||
|
|
||||||
create-glyph 'rRetroflexTailBR' : glyph-proc
|
create-glyph 'rRetroflexTailBR' : glyph-proc
|
||||||
set-width 0
|
set-width 0
|
||||||
|
@ -1209,7 +1208,6 @@ glyph-block Marks : begin
|
||||||
flat (SideJut) Stroke [heading Downward]
|
flat (SideJut) Stroke [heading Downward]
|
||||||
curl (SideJut) 0 [heading Downward]
|
curl (SideJut) 0 [heading Downward]
|
||||||
straight.right.end (HookX - HalfStroke * HVContrast) (-Hook + HalfStroke)
|
straight.right.end (HookX - HalfStroke * HVContrast) (-Hook + HalfStroke)
|
||||||
set currentGlyph.autoRefPriority (-2)
|
|
||||||
|
|
||||||
create-glyph 'ltailBR' 0x321 : glyph-proc
|
create-glyph 'ltailBR' 0x321 : glyph-proc
|
||||||
set-width 0
|
set-width 0
|
||||||
|
@ -1220,7 +1218,6 @@ glyph-block Marks : begin
|
||||||
flat 0 (-O) [heading Downward]
|
flat 0 (-O) [heading Downward]
|
||||||
curl 0 0 [heading Downward]
|
curl 0 0 [heading Downward]
|
||||||
straight.left.end (-HookX - HalfStroke * HVContrast) (-Hook - HalfStroke)
|
straight.left.end (-HookX - HalfStroke * HVContrast) (-Hook - HalfStroke)
|
||||||
set currentGlyph.autoRefPriority (-2)
|
|
||||||
|
|
||||||
# Overlay Marks
|
# Overlay Marks
|
||||||
create-glyph 'tildeOver' 0x334 : glyph-proc
|
create-glyph 'tildeOver' 0x334 : glyph-proc
|
||||||
|
@ -1424,7 +1421,6 @@ glyph-block Marks : begin
|
||||||
include : Translate (0 - k) 0
|
include : Translate (0 - k) 0
|
||||||
|
|
||||||
set-mark-anchor 'above' markMiddle XH markMiddle aboveMarkTop
|
set-mark-anchor 'above' markMiddle XH markMiddle aboveMarkTop
|
||||||
set currentGlyph.autoRefPriority 50
|
|
||||||
|
|
||||||
create-glyph "\(id)GrekUpperTonos" : glyph-proc
|
create-glyph "\(id)GrekUpperTonos" : glyph-proc
|
||||||
set-width 0
|
set-width 0
|
||||||
|
@ -1455,7 +1451,6 @@ glyph-block Marks : begin
|
||||||
archv
|
archv
|
||||||
g4.down.end (markMiddle + radius) yc [heading Downward]
|
g4.down.end (markMiddle + radius) yc [heading Downward]
|
||||||
set-mark-anchor 'above' markMiddle XH markMiddle (aboveMarkTop + markHalfStroke * 2)
|
set-mark-anchor 'above' markMiddle XH markMiddle (aboveMarkTop + markHalfStroke * 2)
|
||||||
set currentGlyph.autoRefPriority 50
|
|
||||||
|
|
||||||
create-glyph 'psiliPerispomeniGrekUpperTonos' : glyph-proc
|
create-glyph 'psiliPerispomeniGrekUpperTonos' : glyph-proc
|
||||||
set-width 0
|
set-width 0
|
||||||
|
@ -1479,7 +1474,6 @@ glyph-block Marks : begin
|
||||||
archv
|
archv
|
||||||
g4.down.end (markMiddle + radius) yc [heading Downward]
|
g4.down.end (markMiddle + radius) yc [heading Downward]
|
||||||
set-mark-anchor 'above' markMiddle XH markMiddle (aboveMarkTop + markHalfStroke * 2)
|
set-mark-anchor 'above' markMiddle XH markMiddle (aboveMarkTop + markHalfStroke * 2)
|
||||||
set currentGlyph.autoRefPriority 50
|
|
||||||
|
|
||||||
create-glyph 'dasiaPerispomeniGrekUpperTonos' : glyph-proc
|
create-glyph 'dasiaPerispomeniGrekUpperTonos' : glyph-proc
|
||||||
set-width 0
|
set-width 0
|
||||||
|
@ -1499,7 +1493,6 @@ glyph-block Marks : begin
|
||||||
alsoThru.g2 0.5 0.5
|
alsoThru.g2 0.5 0.5
|
||||||
g2.right.end (markMiddle + [Math.max radius (markExtend * 2)]) yc [heading Rightward]
|
g2.right.end (markMiddle + [Math.max radius (markExtend * 2)]) yc [heading Rightward]
|
||||||
set-mark-anchor 'above' markMiddle XH markMiddle (aboveMarkTop + markHalfStroke * 2)
|
set-mark-anchor 'above' markMiddle XH markMiddle (aboveMarkTop + markHalfStroke * 2)
|
||||||
set currentGlyph.autoRefPriority 50
|
|
||||||
|
|
||||||
create-glyph 'spaced_dasiaPerispomeni' 0x1FDF : glyph-proc
|
create-glyph 'spaced_dasiaPerispomeni' 0x1FDF : glyph-proc
|
||||||
include [refer-glyph 'markBaseSpace'] AS_BASE
|
include [refer-glyph 'markBaseSpace'] AS_BASE
|
||||||
|
|
|
@ -53,7 +53,6 @@ glyph-block Digits-One : begin
|
||||||
create-glyph 'one.lnum.line' : glyph-proc
|
create-glyph 'one.lnum.line' : glyph-proc
|
||||||
include : MarkSet.capital
|
include : MarkSet.capital
|
||||||
include : VBar Middle 0 CAP
|
include : VBar Middle 0 CAP
|
||||||
set currentGlyph.autoRefPriority (-2)
|
|
||||||
|
|
||||||
create-glyph 'one.onum.nobase' : glyph-proc
|
create-glyph 'one.onum.nobase' : glyph-proc
|
||||||
include : OnumMarks.e
|
include : OnumMarks.e
|
||||||
|
@ -85,7 +84,6 @@ glyph-block Digits-One : begin
|
||||||
create-glyph 'one.onum.line' : glyph-proc
|
create-glyph 'one.onum.line' : glyph-proc
|
||||||
include : OnumMarks.e
|
include : OnumMarks.e
|
||||||
include : VBar Middle 0 OnumHeight
|
include : VBar Middle 0 OnumHeight
|
||||||
set currentGlyph.autoRefPriority (-2)
|
|
||||||
|
|
||||||
select-variant 'one.lnum' [CodeLnum '1'] (follow -- 'one')
|
select-variant 'one.lnum' [CodeLnum '1'] (follow -- 'one')
|
||||||
select-variant 'one.onum' [CodeOnum '1'] (follow -- 'one')
|
select-variant 'one.onum' [CodeOnum '1'] (follow -- 'one')
|
||||||
|
|
|
@ -10,11 +10,9 @@ glyph-block Symbol-Mosaic-NotDef : begin
|
||||||
|
|
||||||
create-glyph '.null' : glyph-proc
|
create-glyph '.null' : glyph-proc
|
||||||
set-width 0
|
set-width 0
|
||||||
set currentGlyph.autoRefPriority (-9998)
|
|
||||||
set currentGlyph.glyphRank (9998)
|
set currentGlyph.glyphRank (9998)
|
||||||
|
|
||||||
create-glyph 'space' ' ' : glyph-proc
|
create-glyph 'space' ' ' : glyph-proc
|
||||||
set currentGlyph.autoRefPriority (-100)
|
|
||||||
local df : DivFrame para.diversityI
|
local df : DivFrame para.diversityI
|
||||||
set-width df.width
|
set-width df.width
|
||||||
|
|
||||||
|
@ -38,7 +36,6 @@ glyph-block Symbol-Mosaic-NotDef : begin
|
||||||
|
|
||||||
create-glyph 'zwsp' 0x200B : glyph-proc
|
create-glyph 'zwsp' 0x200B : glyph-proc
|
||||||
set-width 0
|
set-width 0
|
||||||
set currentGlyph.autoRefPriority (-9999)
|
|
||||||
|
|
||||||
alias 'nonmarkingreturn' 0x000D 'zwsp'
|
alias 'nonmarkingreturn' 0x000D 'zwsp'
|
||||||
alias 'cgj' 0x34F 'zwsp'
|
alias 'cgj' 0x34F 'zwsp'
|
||||||
|
|
|
@ -288,6 +288,10 @@ glyph-block Symbol-Arrow : for-width-kinds WideWidth1
|
||||||
MkArrow ArrowShape [MangleName 'arrowDownRight'] [MangleUnicode 0x2198] arrowDiagSB arrowDiagTop arrowDiagRSB arrowDiagBot
|
MkArrow ArrowShape [MangleName 'arrowDownRight'] [MangleUnicode 0x2198] arrowDiagSB arrowDiagTop arrowDiagRSB arrowDiagBot
|
||||||
MkArrow ArrowShape [MangleName 'arrowDownLeft'] [MangleUnicode 0x2199] arrowDiagRSB arrowDiagTop arrowDiagSB arrowDiagBot
|
MkArrow ArrowShape [MangleName 'arrowDownLeft'] [MangleUnicode 0x2199] arrowDiagRSB arrowDiagTop arrowDiagSB arrowDiagBot
|
||||||
|
|
||||||
|
define kLong 0.5
|
||||||
|
MkArrow ArrowShape [MangleName 'longArrowLeft'] [MangleUnicode 0x27F5] [mix MosaicWidth arrowRSB kLong] SymbolMid [mix 0 arrowSB kLong] SymbolMid
|
||||||
|
MkArrow ArrowShape [MangleName 'longArrowRight'] [MangleUnicode 0x27F6] [mix 0 arrowSB kLong] SymbolMid [mix MosaicWidth arrowRSB kLong] SymbolMid
|
||||||
|
|
||||||
do "Dash Straight Arrow"
|
do "Dash Straight Arrow"
|
||||||
MkArrow DashArrowShape [MangleName 'dashArrowLeft'] [MangleUnicode 0x21E0] arrowRSB SymbolMid arrowSB SymbolMid
|
MkArrow DashArrowShape [MangleName 'dashArrowLeft'] [MangleUnicode 0x21E0] arrowRSB SymbolMid arrowSB SymbolMid
|
||||||
MkArrow DashArrowShape [MangleName 'dashArrowUp'] [MangleUnicode 0x21E1] arrowMidX arrowBot arrowMidX arrowTop
|
MkArrow DashArrowShape [MangleName 'dashArrowUp'] [MangleUnicode 0x21E1] arrowMidX arrowBot arrowMidX arrowTop
|
||||||
|
@ -687,7 +691,3 @@ glyph-block Symbol-Arrow : for-width-kinds WideWidth1
|
||||||
|
|
||||||
if (MosaicWidthScalar == 1) : begin
|
if (MosaicWidthScalar == 1) : begin
|
||||||
glyph-block-export ArrowShape
|
glyph-block-export ArrowShape
|
||||||
|
|
||||||
if (!para.forceMonospace && MosaicNameSuffix === '.WWID') : begin
|
|
||||||
alias 'longArrowLeft' 0x27F5 'arrowLeft.WWID'
|
|
||||||
alias 'longArrowRight' 0x27F6 'arrowRight.WWID'
|
|
||||||
|
|
|
@ -68,7 +68,6 @@ glyph-block Symbol-Ligation : begin
|
||||||
create-glyph "hyphen.lig.\(lS)\(rS)" : glyph-proc
|
create-glyph "hyphen.lig.\(lS)\(rS)" : glyph-proc
|
||||||
include : SetJoiningKind lS rS
|
include : SetJoiningKind lS rS
|
||||||
include : HBar left right SymbolMid OperatorStroke
|
include : HBar left right SymbolMid OperatorStroke
|
||||||
set currentGlyph.autoRefPriority (-3)
|
|
||||||
create-glyph "hyphen.lig.\(lS)\(rS).notched" : glyph-proc
|
create-glyph "hyphen.lig.\(lS)\(rS).notched" : glyph-proc
|
||||||
include : SetJoiningKind lS rS
|
include : SetJoiningKind lS rS
|
||||||
include : difference
|
include : difference
|
||||||
|
@ -87,7 +86,6 @@ glyph-block Symbol-Ligation : begin
|
||||||
include : SetJoiningKind lS rS
|
include : SetJoiningKind lS rS
|
||||||
include : HBarTop left right (SymbolMid + dblArrowD) dblArrowSw
|
include : HBarTop left right (SymbolMid + dblArrowD) dblArrowSw
|
||||||
include : HBarBottom left right (SymbolMid - dblArrowD) dblArrowSw
|
include : HBarBottom left right (SymbolMid - dblArrowD) dblArrowSw
|
||||||
set currentGlyph.autoRefPriority (-3)
|
|
||||||
|
|
||||||
do "Waves"
|
do "Waves"
|
||||||
glyph-block-import Shared-Symbol-Shapes : CreateWaveShape
|
glyph-block-import Shared-Symbol-Shapes : CreateWaveShape
|
||||||
|
|
|
@ -49,7 +49,7 @@ glyph-block Symbol-Math-Integrals : begin
|
||||||
include [shape]
|
include [shape]
|
||||||
include : Translate (Width * 0.275) 0
|
include : Translate (Width * 0.275) 0
|
||||||
|
|
||||||
define [IntegrateRingMask kx] : OShapeOutline (SymbolMid + (RightSB - SB) / 2) (SymbolMid - (RightSB - SB) / 2) [mix 0 SB kx] [mix Width RightSB kx]
|
define [IntegrateRingMask kx] : OShapeOutline.NoOvershoot (SymbolMid + (RightSB - SB) / 2) (SymbolMid - (RightSB - SB) / 2) [mix 0 SB kx] [mix Width RightSB kx]
|
||||||
define [IntegrateRing kx sw] : OShape (SymbolMid + (RightSB - SB) / 2) (SymbolMid - (RightSB - SB) / 2) [mix 0 SB kx] [mix Width RightSB kx] sw
|
define [IntegrateRing kx sw] : OShape (SymbolMid + (RightSB - SB) / 2) (SymbolMid - (RightSB - SB) / 2) [mix 0 SB kx] [mix Width RightSB kx] sw
|
||||||
|
|
||||||
define RingIntFine : AdviceStroke 4
|
define RingIntFine : AdviceStroke 4
|
||||||
|
|
|
@ -872,5 +872,4 @@ glyph-block Symbol-Mosaic-NotDef : begin
|
||||||
difference
|
difference
|
||||||
Rect CAP 0 SB RightSB
|
Rect CAP 0 SB RightSB
|
||||||
Rect (CAP - sw) (0 + sw) (SB + sw) (RightSB - sw)
|
Rect (CAP - sw) (0 + sw) (SB + sw) (RightSB - sw)
|
||||||
set currentGlyph.autoRefPriority (-9999)
|
|
||||||
set currentGlyph.glyphRank (9999)
|
set currentGlyph.glyphRank (9999)
|
||||||
|
|
|
@ -105,7 +105,7 @@ glyph-block Symbol-Pictograph-IEC-Power-And-Playback : for-width-kinds WideWidth
|
||||||
corner (df.middle + trigRad / 2) (SymbolMid + trigRad)
|
corner (df.middle + trigRad / 2) (SymbolMid + trigRad)
|
||||||
corner (df.middle - trigRad / 2) (SymbolMid)
|
corner (df.middle - trigRad / 2) (SymbolMid)
|
||||||
|
|
||||||
create-glyph [MangleUnicode 'playback/eject'] [MangleUnicode 0x23CF] : glyph-proc
|
create-glyph [MangleName 'playback/eject'] [MangleUnicode 0x23CF] : glyph-proc
|
||||||
set-width df.width
|
set-width df.width
|
||||||
include : Rect (SymbolMid - squareRadiusFW / 3) (SymbolMid - squareRadiusFW) (df.middle - squareRadiusFW) (df.middle + squareRadiusFW)
|
include : Rect (SymbolMid - squareRadiusFW / 3) (SymbolMid - squareRadiusFW) (df.middle - squareRadiusFW) (df.middle + squareRadiusFW)
|
||||||
include : spiro-outline
|
include : spiro-outline
|
||||||
|
|
|
@ -66,7 +66,3 @@ glyph-block Symbol-Punctuation-Dashes : begin
|
||||||
include : HBar 0 emDashWidth SymbolMid
|
include : HBar 0 emDashWidth SymbolMid
|
||||||
|
|
||||||
alias [MangleName 'horizontalBar'] [MangleUnicode 0x2015] [MangleName 'emDash']
|
alias [MangleName 'horizontalBar'] [MangleUnicode 0x2015] [MangleName 'emDash']
|
||||||
|
|
||||||
create-glyph [MangleName 'doubleEmDash'] : glyph-proc
|
|
||||||
set-width (emDashWidth * 2)
|
|
||||||
include : HBar 0 (emDashWidth * 2) SymbolMid
|
|
||||||
|
|
|
@ -11,12 +11,12 @@ glyph-block Symbol-Punctuation-Interpuncts : begin
|
||||||
glyph-block-import Common-Derivatives
|
glyph-block-import Common-Derivatives
|
||||||
glyph-block-import Symbol-Punctuation-Small
|
glyph-block-import Symbol-Punctuation-Small
|
||||||
|
|
||||||
create-glyph 'period.mid' : glyph-proc
|
create-glyph 'interpunct' 0xB7 : glyph-proc
|
||||||
local df : DivFrame para.diversityF
|
local df : DivFrame para.diversityF
|
||||||
set-width df.width
|
set-width df.width
|
||||||
include : DotAt df.middle SymbolMid (PeriodRadius - O)
|
include : DotAt df.middle SymbolMid (PeriodRadius - O)
|
||||||
|
|
||||||
alias 'interpunct' 0xB7 'period.mid'
|
alias 'period.mid' 0xB7 'interpunct'
|
||||||
alias 'greekbullet' 0x387 'period.mid'
|
alias 'greekbullet' 0x387 'interpunct'
|
||||||
alias 'hyphenpoint' 0x2027 'period.mid'
|
alias 'hyphenpoint' 0x2027 'interpunct'
|
||||||
alias 'mathCDot' 0x22C5 'period.mid'
|
alias 'mathCDot' 0x22C5 'interpunct'
|
||||||
|
|
|
@ -75,7 +75,6 @@ export : define [BuildCompatLigatures para glyphStore GSUB GDEF config] : begin
|
||||||
define g1Name : '$clig.' + cldef.unicode
|
define g1Name : '$clig.' + cldef.unicode
|
||||||
local g1 : new Glyph g1Name
|
local g1 : new Glyph g1Name
|
||||||
set g1.advanceWidth 0
|
set g1.advanceWidth 0
|
||||||
set g1.autoRefPriority 1
|
|
||||||
foreach [gn : items-of gnames] : begin
|
foreach [gn : items-of gnames] : begin
|
||||||
local g : glyphStore.queryByName 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
|
||||||
|
|
22
font-src/otl/gsub-gr.ptl
Normal file
22
font-src/otl/gsub-gr.ptl
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
import [add-common-feature add-feature add-lookup BeginLookupBlock EndLookupBlock] from "./table-util"
|
||||||
|
|
||||||
|
# Name-driven feature pairs
|
||||||
|
export : define [buildGrFeature sink glyphStore tag gr] : begin
|
||||||
|
local rec : BeginLookupBlock sink
|
||||||
|
|
||||||
|
local mapping {.}
|
||||||
|
foreach { gnSrc glyph } [glyphStore.namedEntries] : begin
|
||||||
|
local gnDst : gr.get glyph
|
||||||
|
local glyphDst : glyphStore.queryByName gnDst
|
||||||
|
if (glyphDst && ([glyphStore.queryUnicodeOf glyph] || [glyphStore.queryUnicodeOf glyphDst]))
|
||||||
|
set mapping.(gnSrc) gnDst
|
||||||
|
|
||||||
|
if [objectIsNotEmpty mapping] : begin
|
||||||
|
define lookup1 : add-lookup sink {.type 'gsub_single' .substitutions mapping}
|
||||||
|
define feature1 : add-feature sink tag
|
||||||
|
feature1.lookups.push lookup1
|
||||||
|
add-common-feature sink feature1
|
||||||
|
|
||||||
|
EndLookupBlock rec sink
|
||||||
|
|
||||||
|
define [objectIsNotEmpty obj] : obj && [Object.keys obj].length
|
|
@ -1,35 +0,0 @@
|
||||||
import [add-common-feature add-feature add-lookup BeginLookupBlock EndLookupBlock] from "./table-util"
|
|
||||||
|
|
||||||
# Name-driven feature pairs
|
|
||||||
export : define [buildPairFeature sink tag1 tag2 glyphStore codedOnly] : begin
|
|
||||||
local rec : BeginLookupBlock sink
|
|
||||||
|
|
||||||
local mapTag2 {.}
|
|
||||||
local mapTag1 {.}
|
|
||||||
define reHidden : regex "^\\."
|
|
||||||
define reTag1 : new RegExp ("\\." + tag1 + "$")
|
|
||||||
foreach { glyphName glyph } [glyphStore.namedEntries] : begin
|
|
||||||
if ([reTag1.test glyphName] && ![reHidden.test glyphName]) : do
|
|
||||||
local gnTag2 : glyphName.replace reTag1 ('.' + tag2)
|
|
||||||
local glyphTag2 : glyphStore.queryByName gnTag2
|
|
||||||
if (glyphTag2) : begin
|
|
||||||
if(!codedOnly || [glyphStore.queryUnicodeOf glyph])
|
|
||||||
set mapTag2.(glyphName) gnTag2
|
|
||||||
if(!codedOnly || [glyphStore.queryUnicodeOf glyphTag2])
|
|
||||||
set mapTag1.(gnTag2) glyphName
|
|
||||||
|
|
||||||
if [objectIsNotEmpty mapTag1] : begin
|
|
||||||
define lookup1 : add-lookup sink {.type 'gsub_single' .substitutions mapTag1}
|
|
||||||
define feature1 : add-feature sink tag1
|
|
||||||
feature1.lookups.push lookup1
|
|
||||||
add-common-feature sink feature1
|
|
||||||
|
|
||||||
if [objectIsNotEmpty mapTag2] : begin
|
|
||||||
define lookup2 : add-lookup sink {.type 'gsub_single' .substitutions mapTag2}
|
|
||||||
define feature2 : add-feature sink tag2
|
|
||||||
feature2.lookups.push lookup2
|
|
||||||
add-common-feature sink feature2
|
|
||||||
|
|
||||||
EndLookupBlock rec sink
|
|
||||||
|
|
||||||
define [objectIsNotEmpty obj] : obj && [Object.keys obj].length
|
|
|
@ -1,12 +1,13 @@
|
||||||
import 'toposort' as toposort
|
import 'toposort' as toposort
|
||||||
import '../support/glyph' as Glyph
|
import '../support/glyph' as Glyph
|
||||||
import '../support/transform' as Transform
|
import '../support/transform' as Transform
|
||||||
|
import '../support/gr' as Gr
|
||||||
|
|
||||||
import [CreateEmptyTable finalizeTable MoveBackUtilityLookups] from "./table-util"
|
import [CreateEmptyTable finalizeTable MoveBackUtilityLookups] from "./table-util"
|
||||||
|
|
||||||
import [buildLigations] from './gsub-ligation'
|
import [buildLigations] from './gsub-ligation'
|
||||||
import [buildCCMP] from './gsub-ccmp'
|
import [buildCCMP] from './gsub-ccmp'
|
||||||
import [buildPairFeature] from './gsub-pairing'
|
import [buildGrFeature] from './gsub-gr'
|
||||||
import [buildCVSS] from './gsub-cv-ss'
|
import [buildCVSS] from './gsub-cv-ss'
|
||||||
import [buildLOCL] from './gsub-locl'
|
import [buildLOCL] from './gsub-locl'
|
||||||
import [buildGsubThousands] from './gsub-thousands'
|
import [buildGsubThousands] from './gsub-thousands'
|
||||||
|
@ -22,11 +23,13 @@ define [buildGSUB para glyphStore markGlyphs] : begin
|
||||||
define gsub : CreateEmptyTable
|
define gsub : CreateEmptyTable
|
||||||
|
|
||||||
# lnum / onum
|
# lnum / onum
|
||||||
buildPairFeature gsub 'lnum' 'onum' glyphStore true
|
buildGrFeature gsub glyphStore 'lnum' Gr.Lnum
|
||||||
|
buildGrFeature gsub glyphStore 'onum' Gr.Onum
|
||||||
|
|
||||||
# NWID / WWID
|
# NWID / WWID
|
||||||
if (!para.forceMonospace || para.spacing > 0) : begin
|
if (!para.forceMonospace || para.spacing > 0) : begin
|
||||||
buildPairFeature gsub 'NWID' 'WWID' glyphStore true
|
buildGrFeature gsub glyphStore 'NWID' Gr.Nwid
|
||||||
|
buildGrFeature gsub glyphStore 'WWID' Gr.Wwid
|
||||||
|
|
||||||
# ccmp
|
# ccmp
|
||||||
buildCCMP gsub glyphStore markGlyphs
|
buildCCMP gsub glyphStore markGlyphs
|
||||||
|
|
|
@ -14,11 +14,23 @@ class GlyphStore {
|
||||||
namedEntries() {
|
namedEntries() {
|
||||||
return this.nameForward.entries();
|
return this.nameForward.entries();
|
||||||
}
|
}
|
||||||
*indexedNamedEntries() {
|
encodedEntries() {
|
||||||
let i = 0;
|
return this.encodingForward.entries();
|
||||||
for (const [name, g] of this.nameForward.entries()) {
|
}
|
||||||
yield [i, name, g];
|
|
||||||
i++;
|
*flattenCodes(g, flatteners) {
|
||||||
|
{
|
||||||
|
const codes = this.encodingBackward.get(g);
|
||||||
|
if (codes) for (const c of codes) yield c;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const gr of flatteners) {
|
||||||
|
const gn = gr.get(g);
|
||||||
|
if (!gn) continue;
|
||||||
|
const g2 = this.nameForward.get(gn);
|
||||||
|
if (!g2) continue;
|
||||||
|
const codes2 = this.encodingBackward.get(g2);
|
||||||
|
if (codes2) for (const c of codes2) yield c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,16 +116,6 @@ class GlyphStore {
|
||||||
}
|
}
|
||||||
return gs1;
|
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;
|
module.exports = GlyphStore;
|
||||||
|
|
|
@ -8,12 +8,23 @@ const Geom = require("./geometry");
|
||||||
module.exports = class Glyph {
|
module.exports = class Glyph {
|
||||||
constructor(_identifier) {
|
constructor(_identifier) {
|
||||||
this._m_identifier = _identifier;
|
this._m_identifier = _identifier;
|
||||||
|
|
||||||
|
// Ranks
|
||||||
|
this.glyphRank = 0;
|
||||||
|
this.grRank = 0;
|
||||||
|
this.codeRank = 0xffffffff;
|
||||||
|
this.subRank = 0xffffffff;
|
||||||
|
|
||||||
|
// Geometry
|
||||||
this.geometry = new Geom.CombineGeometry();
|
this.geometry = new Geom.CombineGeometry();
|
||||||
|
this.gizmo = Transform.Id();
|
||||||
|
|
||||||
|
// Metrics
|
||||||
this.advanceWidth = 500;
|
this.advanceWidth = 500;
|
||||||
this.autoRefPriority = 0;
|
|
||||||
this.markAnchors = {};
|
this.markAnchors = {};
|
||||||
this.baseAnchors = {};
|
this.baseAnchors = {};
|
||||||
this.gizmo = Transform.Id();
|
|
||||||
|
// Tracking
|
||||||
this.dependencies = [];
|
this.dependencies = [];
|
||||||
this.ctxTag = null;
|
this.ctxTag = null;
|
||||||
}
|
}
|
||||||
|
@ -69,11 +80,7 @@ module.exports = class Glyph {
|
||||||
|
|
||||||
// Combine anchors and get offset
|
// Combine anchors and get offset
|
||||||
let shift = { x: 0, y: 0 };
|
let shift = { x: 0, y: 0 };
|
||||||
if (g.markAnchors) {
|
this.combineMarks(g, shift);
|
||||||
for (const m in this.baseAnchors) {
|
|
||||||
this.combineAnchor(shift, this.baseAnchors[m], g.markAnchors[m], g.baseAnchors);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.includeGlyphImpl(g, shift.x, shift.y);
|
this.includeGlyphImpl(g, shift.x, shift.y);
|
||||||
if (copyAnchors || g.isMarkSet) this.copyAnchors(g);
|
if (copyAnchors || g.isMarkSet) this.copyAnchors(g);
|
||||||
|
@ -90,7 +97,6 @@ module.exports = class Glyph {
|
||||||
this.related = g.related;
|
this.related = g.related;
|
||||||
}
|
}
|
||||||
cloneRankFromGlyph(g) {
|
cloneRankFromGlyph(g) {
|
||||||
this.autoRefPriority = g.autoRefPriority;
|
|
||||||
this.glyphRank = g.glyphRank;
|
this.glyphRank = g.glyphRank;
|
||||||
this.avoidBeingComposite = g.avoidBeingComposite;
|
this.avoidBeingComposite = g.avoidBeingComposite;
|
||||||
}
|
}
|
||||||
|
@ -147,17 +153,26 @@ module.exports = class Glyph {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Anchors
|
// Anchors
|
||||||
combineAnchor(shift, baseThis, markThat, basesThat) {
|
combineMarks(g, shift) {
|
||||||
if (!baseThis || !markThat) return;
|
if (!g.markAnchors) return;
|
||||||
shift.x = baseThis.x - markThat.x;
|
for (const m in g.markAnchors) {
|
||||||
shift.y = baseThis.y - markThat.y;
|
const markThat = g.markAnchors[m];
|
||||||
if (basesThat) {
|
const baseThis = this.baseAnchors[m];
|
||||||
for (const bk in basesThat) {
|
if (!baseThis) continue;
|
||||||
this.baseAnchors[bk] = new Anchor(
|
shift.x = baseThis.x - markThat.x;
|
||||||
shift.x + basesThat[bk].x,
|
shift.y = baseThis.y - markThat.y;
|
||||||
shift.y + basesThat[bk].y
|
let fSuppress = true;
|
||||||
);
|
if (g.baseAnchors) {
|
||||||
|
for (const m2 in g.baseAnchors) {
|
||||||
|
if (m2 === m) fSuppress = false;
|
||||||
|
const baseDerived = g.baseAnchors[m2];
|
||||||
|
this.baseAnchors[m2] = new Anchor(
|
||||||
|
shift.x + baseDerived.x,
|
||||||
|
shift.y + baseDerived.y
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if (fSuppress) delete this.baseAnchors[m];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
copyAnchors(g) {
|
copyAnchors(g) {
|
||||||
|
|
|
@ -35,6 +35,11 @@ const DollarShrinkKernel = SimpleProp("DollarShrinkKernel");
|
||||||
const DollarShorterBar = SimpleProp("DollarShorterBar");
|
const DollarShorterBar = SimpleProp("DollarShorterBar");
|
||||||
const MathSansSerif = SimpleProp("MathSansSerif");
|
const MathSansSerif = SimpleProp("MathSansSerif");
|
||||||
|
|
||||||
|
const Nwid = SimpleProp("Nwid");
|
||||||
|
const Wwid = SimpleProp("Wwid");
|
||||||
|
const Lnum = SimpleProp("Lnum");
|
||||||
|
const Onum = SimpleProp("Onum");
|
||||||
|
|
||||||
const CvDecompose = {
|
const CvDecompose = {
|
||||||
get(glyph) {
|
get(glyph) {
|
||||||
if (glyph && glyph.related) return glyph.related.CvDecompose;
|
if (glyph && glyph.related) return glyph.related.CvDecompose;
|
||||||
|
@ -386,6 +391,19 @@ function queryCvFeatureTagsOf(sink, gid, glyph, variantAssignmentSet) {
|
||||||
for (const g of m.values()) if (g.length) sink.push(g);
|
for (const g of m.values()) if (g.length) sink.push(g);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function linkSuffixPairGr(gs, tagCis, tagTrans, grCis, grTrans) {
|
||||||
|
const reTagCis = new RegExp("\\." + tagCis + "$");
|
||||||
|
for (const [gnCis, gCis] of gs.namedEntries()) {
|
||||||
|
if (reTagCis.test(gnCis) && !/^\./.test(gnCis)) {
|
||||||
|
const gnTrans = gnCis.replace(reTagCis, "." + tagTrans);
|
||||||
|
const gTrans = gs.queryByName(gnTrans);
|
||||||
|
if (!gTrans) continue;
|
||||||
|
grTrans.set(gCis, gnTrans);
|
||||||
|
grCis.set(gTrans, gnCis);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
exports.Dotless = Dotless;
|
exports.Dotless = Dotless;
|
||||||
exports.LowerYDotAtBelow = LowerYDotAtBelow;
|
exports.LowerYDotAtBelow = LowerYDotAtBelow;
|
||||||
exports.Cv = Cv;
|
exports.Cv = Cv;
|
||||||
|
@ -401,8 +419,15 @@ exports.Joining = Joining;
|
||||||
exports.AnyDerivingCv = AnyDerivingCv;
|
exports.AnyDerivingCv = AnyDerivingCv;
|
||||||
exports.CcmpDecompose = CcmpDecompose;
|
exports.CcmpDecompose = CcmpDecompose;
|
||||||
exports.CvDecompose = CvDecompose;
|
exports.CvDecompose = CvDecompose;
|
||||||
exports.createGrDisplaySheet = createGrDisplaySheet;
|
|
||||||
exports.DollarShrinkKernel = DollarShrinkKernel;
|
exports.DollarShrinkKernel = DollarShrinkKernel;
|
||||||
exports.DollarShorterBar = DollarShorterBar;
|
exports.DollarShorterBar = DollarShorterBar;
|
||||||
exports.MathSansSerif = MathSansSerif;
|
exports.MathSansSerif = MathSansSerif;
|
||||||
|
exports.Nwid = Nwid;
|
||||||
|
exports.Wwid = Wwid;
|
||||||
|
exports.Lnum = Lnum;
|
||||||
|
exports.Onum = Onum;
|
||||||
|
|
||||||
|
exports.createGrDisplaySheet = createGrDisplaySheet;
|
||||||
|
exports.linkSuffixPairGr = linkSuffixPairGr;
|
||||||
|
|
||||||
exports.SvInheritableRelations = [DollarShrinkKernel, DollarShorterBar, Joining];
|
exports.SvInheritableRelations = [DollarShrinkKernel, DollarShorterBar, Joining];
|
||||||
|
|
11
verdafile.js
11
verdafile.js
|
@ -36,6 +36,7 @@ const webfontFormatsPages = [["woff2", "woff2"]];
|
||||||
const WIDTH_NORMAL = "normal";
|
const WIDTH_NORMAL = "normal";
|
||||||
const WEIGHT_NORMAL = "regular";
|
const WEIGHT_NORMAL = "regular";
|
||||||
const SLOPE_NORMAL = "upright";
|
const SLOPE_NORMAL = "upright";
|
||||||
|
const SLOPE_OBLIQUE = "oblique";
|
||||||
const DEFAULT_SUBFAMILY = "regular";
|
const DEFAULT_SUBFAMILY = "regular";
|
||||||
|
|
||||||
const BUILD_PLANS = "build-plans.toml";
|
const BUILD_PLANS = "build-plans.toml";
|
||||||
|
@ -409,7 +410,7 @@ async function getCollectPlans(target, rawCollectPlans, config, fnFileName) {
|
||||||
sfi.slope
|
sfi.slope
|
||||||
);
|
);
|
||||||
const glyfTtcFileName = fnFileName(
|
const glyfTtcFileName = fnFileName(
|
||||||
{ ...config, distinguishWidths: true },
|
{ ...config, distinguishWidths: true, distinguishWhetherUpright: true },
|
||||||
collectPrefix,
|
collectPrefix,
|
||||||
sfi.weight,
|
sfi.weight,
|
||||||
sfi.width,
|
sfi.width,
|
||||||
|
@ -440,7 +441,13 @@ function fnStandardTtc(collectConfig, prefix, w, wd, s) {
|
||||||
const ttcSuffix = makeSuffix(
|
const ttcSuffix = makeSuffix(
|
||||||
collectConfig.distinguishWeights ? w : WEIGHT_NORMAL,
|
collectConfig.distinguishWeights ? w : WEIGHT_NORMAL,
|
||||||
collectConfig.distinguishWidths ? wd : WIDTH_NORMAL,
|
collectConfig.distinguishWidths ? wd : WIDTH_NORMAL,
|
||||||
collectConfig.distinguishSlope ? s : SLOPE_NORMAL,
|
collectConfig.distinguishSlope
|
||||||
|
? s
|
||||||
|
: collectConfig.distinguishWhetherUpright
|
||||||
|
? s === SLOPE_NORMAL
|
||||||
|
? SLOPE_NORMAL
|
||||||
|
: SLOPE_OBLIQUE
|
||||||
|
: SLOPE_NORMAL,
|
||||||
DEFAULT_SUBFAMILY
|
DEFAULT_SUBFAMILY
|
||||||
);
|
);
|
||||||
return `${prefix}-${ttcSuffix}`;
|
return `${prefix}-${ttcSuffix}`;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue