OTL codegen cleanup

This commit is contained in:
be5invis 2020-11-19 18:19:30 -08:00
parent d471e9d948
commit c6dc8c370c
11 changed files with 120 additions and 123 deletions

View file

@ -26,9 +26,9 @@ function markLookups(table, sink) {
let sizeBefore = sink.size;
for (const l of Array.from(sink)) {
const lookup = table.lookups[l];
if (!lookup || !lookup.subtables) continue;
if (!lookup) continue;
if (lookup.type === "gsub_chaining" || lookup.type === "gpos_chaining") {
for (let st of lookup.subtables) {
for (let st of lookup.rules) {
if (!st || !st.apply) continue;
for (const app of st.apply) sink.add(app.lookup);
}
@ -91,56 +91,60 @@ function markGlyphsStep(glyphStore, sink, restFont, cfg) {
if (restFont.GSUB) {
for (const l in restFont.GSUB.lookups) {
const lookup = restFont.GSUB.lookups[l];
if (!lookup || !lookup.subtables) continue;
for (let st of lookup.subtables) {
markGlyphsSubtable(sink, lookup.type, st, cfg);
}
if (!lookup) continue;
markGlyphsLookupImpl(sink, lookup, cfg);
}
}
const glyphCount1 = sink.size;
return glyphCount1 > glyphCount;
}
function markGlyphsSubtable(sink, type, st, cfg) {
switch (type) {
function markGlyphsLookupImpl(sink, lookup, cfg) {
switch (lookup.type) {
case "gsub_single":
return markGlyphsGsubSingle(sink, st, cfg);
return markGlyphsGsubSingle(sink, lookup, cfg);
case "gsub_multiple":
return markGlyphsGsubMultiple(sink, st, cfg);
return markGlyphsGsubMultiple(sink, lookup, cfg);
case "gsub_alternate":
return markGlyphsGsubAlternate(sink, st, cfg);
return markGlyphsGsubAlternate(sink, lookup, cfg);
case "gsub_ligature":
return markGlyphsGsubLigature(sink, st, cfg);
return markGlyphsGsubLigature(sink, lookup, cfg);
case "gsub_chaining":
break;
case "gsub_reverse":
return markGlyphsGsubReverse(sink, st, cfg);
return markGlyphsGsubReverse(sink, lookup, cfg);
}
}
function markGlyphsGsubSingle(sink, st, cfg) {
function markGlyphsGsubSingle(sink, lookup, cfg) {
const st = lookup.substitutions;
for (const k in st) if (sink.has(k) && st[k]) sink.add(st[k]);
}
function markGlyphsGsubMultiple(sink, st, cfg) {
function markGlyphsGsubMultiple(sink, lookup, cfg) {
const st = lookup.substitutions;
for (const k in st) if (sink.has(k) && st[k]) for (const g of st[k]) sink.add(g);
}
function markGlyphsGsubAlternate(sink, st, cfg) {
function markGlyphsGsubAlternate(sink, lookup, cfg) {
const st = lookup.substitutions;
if (!cfg || !cfg.ignoreAltSub) {
for (const k in st) if (sink.has(k) && st[k]) for (const g of st[k]) sink.add(g);
}
}
function markGlyphsGsubLigature(sink, st, cfg) {
for (const sub of st.substitutions) {
function markGlyphsGsubLigature(sink, lookup, cfg) {
const st = lookup.substitutions;
for (const sub of st) {
let check = true;
for (const g of sub.from) if (!sink.has(g)) check = false;
if (check && sub.to) sink.add(sub.to);
}
}
function markGlyphsGsubReverse(sink, st, cfg) {
if (st.match && st.to) {
const matchCoverage = st.match[st.inputIndex];
for (let j = 0; j < matchCoverage.length; j++) {
if (sink.has(matchCoverage[j]) && st.to[j]) sink.add(st.to[j]);
function markGlyphsGsubReverse(sink, lookup, cfg) {
for (const rule of lookup.rules) {
if (rule.match && rule.to) {
const matchCoverage = rule.match[rule.inputIndex];
for (let j = 0; j < matchCoverage.length; j++) {
if (sink.has(matchCoverage[j]) && rule.to[j]) sink.add(rule.to[j]);
}
}
}
}

View file

@ -23,7 +23,7 @@ class LookupStore {
const dst = this.query(id);
const handler = this.m_handlers[otdLookup.type];
if (!dst || !handler) return;
if (otdLookup.subtables) throw new Error("Unreachable.");
handler.fill(dst, otdLookup, this);
}
}
@ -33,12 +33,11 @@ const GsubSingleHandler = {
return new Ot.Gsub.Single();
},
fill(dst, src, store) {
for (const st of src.subtables) {
for (const k in st) {
const from = store.glyphs.query(k);
const to = store.glyphs.query(st[k]);
if (from && to) dst.mapping.set(from, to);
}
const st = src.substitutions;
for (const k in st) {
const from = store.glyphs.query(k);
const to = store.glyphs.query(st[k]);
if (from && to) dst.mapping.set(from, to);
}
}
};
@ -47,13 +46,12 @@ const GsubMultipleHandler = {
return new Ot.Gsub.Multiple();
},
fill(dst, src, store) {
for (const st of src.subtables) {
out: for (const k in st) {
const from = store.glyphs.query(k);
const to = mapGlyphListAll(st[k], store);
if (!from || !to) continue out;
dst.mapping.set(from, to);
}
const st = src.substitutions;
for (const k in st) {
const from = store.glyphs.query(k);
const to = mapGlyphListAll(st[k], store);
if (!from || !to) continue;
dst.mapping.set(from, to);
}
}
};
@ -68,13 +66,12 @@ const GsubLigatureHandler = {
return new Ot.Gsub.Ligature();
},
fill(dst, src, store) {
for (const st of src.subtables) {
for (const { from: _from, to: _to } of st.substitutions) {
const to = store.glyphs.query(_to);
const from = mapGlyphListAll(_from, store);
if (!from || !to) continue;
dst.mapping.push({ from, to });
}
const st = src.substitutions;
for (const { from: _from, to: _to } of st) {
const to = store.glyphs.query(_to);
const from = mapGlyphListAll(_from, store);
if (!from || !to) continue;
dst.mapping.push({ from, to });
}
}
};
@ -84,7 +81,7 @@ const GsubChainingHandler = {
return new Ot.Gsub.Chaining();
},
fill(dst, src, store) {
out: for (const st of src.subtables) {
out: for (const st of src.rules) {
const match = [];
for (const m of st.match) {
const m1 = mapGlyphListSome(m, store);
@ -109,7 +106,7 @@ const GsubReverseHandler = {
return new Ot.Gsub.ReverseSub();
},
fill(dst, src, store) {
out: for (const st of src.subtables) {
out: for (const st of src.rules) {
const match = [];
const doSubAt = st.inputIndex;
const replacement = new Map();
@ -176,10 +173,9 @@ const GposMarkToBaseHandler = {
return new Ot.Gpos.MarkToBase();
},
fill(dst, src, store) {
const st = src.subtables[0];
const mm = collectClassMap(st.marks);
dst.marks = convertMarkRecords(st.marks, mm, store);
dst.bases = convertBaseRecords(st.bases, mm, store);
const mm = collectClassMap(src.marks);
dst.marks = convertMarkRecords(src.marks, mm, store);
dst.bases = convertBaseRecords(src.bases, mm, store);
}
};
const GposMarkToMarkHandler = {
@ -187,10 +183,9 @@ const GposMarkToMarkHandler = {
return new Ot.Gpos.MarkToMark();
},
fill(dst, src, store) {
const st = src.subtables[0];
const mm = collectClassMap(st.marks);
dst.marks = convertMarkRecords(st.marks, mm, store);
dst.baseMarks = convertBaseRecords(st.bases, mm, store);
const mm = collectClassMap(src.marks);
dst.marks = convertMarkRecords(src.marks, mm, store);
dst.baseMarks = convertBaseRecords(src.bases, mm, store);
}
};
function collectClassMap(marks) {

View file

@ -16,44 +16,42 @@ define [interpretLookup gs lut lookups] : match lut.type
local j 0
while (j < gs.length) : begin
local incN 1
do : foreach [subtable : items-of lut.subtables] : begin
local matchT subtable.match
local ib subtable.inputBegins
do : foreach [rule : items-of lut.rules] : begin
local matchT rule.match
local ib rule.inputBegins
local foundMatch true
for [local k 0] (foundMatch && k < matchT.length) [inc k] : begin
if [not gs.(j + k - ib)]
: then : set foundMatch false
: else : if ([matchT.(k).indexOf gs.(j + k - ib)] < 0) : set foundMatch false
if foundMatch : begin
foreach [app : items-of subtable.apply] : do
foreach [app : items-of rule.apply] : do
local aj : j - ib + app.at
local alut lookups.(app.lookup)
interpretLookupAt gs aj alut
set incN : incN + subtable.inputEnds - subtable.inputBegins
set incN : incN + rule.inputEnds - rule.inputBegins
break nothing
set j : j + incN
"gsub_reverse" : begin
local j (gs.length - 1)
while (j >= 0) : begin
do : foreach [subtable : items-of lut.subtables] : begin
local matchT subtable.match
local ib subtable.inputIndex
do : foreach [rule : items-of lut.rules] : begin
local matchT rule.match
local ib rule.inputIndex
local foundMatch true
for [local k 0] (foundMatch && k < matchT.length) [inc k] : begin
if [not gs.(j + k - ib)]
: then : set foundMatch false
: else : if ([matchT.(k).indexOf gs.(j + k - ib)] < 0) : set foundMatch false
if foundMatch : begin
set gs.(j) : subtable.to.[matchT.(ib).indexOf gs.(j)] || gs.(j)
set gs.(j) : rule.to.[matchT.(ib).indexOf gs.(j)] || gs.(j)
set j : j - 1
"gsub_single" : begin
for [local j 0] (j < gs.length) [inc j] : begin
interpretLookupAt gs j lut
define [interpretLookupAt gs j lut] : match lut.type
"gsub_single" : foreach [subtable : items-of lut.subtables] : begin
if subtable.(gs.(j)) : begin
set gs.(j) subtable.(gs.(j))
"gsub_single" : if lut.substitutions.(gs.(j)) : set gs.(j) lut.substitutions.(gs.(j))
export : define [BuildCompatLigatures glyphStore GSUB GDEF config] : begin
foreach [cldef : items-of config] : do

View file

@ -16,32 +16,32 @@ export : define [buildMarkMkmk sink glyphStore] : begin
local mkmkLookupNames {}
foreach markCls [items-of MarkClasses] : begin
local [object markSubtable mkmkSubtable] : createMTSubtables glyphStore { markCls }
if ([objectIsNotEmpty markSubtable.marks] && [objectIsNotEmpty markSubtable.bases]) : begin
local lidMark : add-lookup sink {.type 'gpos_mark_to_base' .subtables { markSubtable }}
local [object markLookup mkmkLookup] : createMTLookups glyphStore { markCls }
if ([objectIsNotEmpty markLookup.marks] && [objectIsNotEmpty markLookup.bases]) : begin
local lidMark : add-lookup sink markLookup
mark.lookups.push lidMark
markLookupNames.push lidMark
if ([objectIsNotEmpty mkmkSubtable.marks] && [objectIsNotEmpty mkmkSubtable.bases]) : begin
local lidMkmk : add-lookup sink {.type 'gpos_mark_to_mark' .subtables { mkmkSubtable }}
if ([objectIsNotEmpty mkmkLookup.marks] && [objectIsNotEmpty mkmkLookup.bases]) : begin
local lidMkmk : add-lookup sink mkmkLookup
mkmk.lookups.push lidMkmk
mkmkLookupNames.push lidMkmk
foreach lidMark [items-of markLookupNames] : foreach lidMkmk [items-of mkmkLookupNames]
sink.lookupDep.push { lidMark lidMkmk }
define [createMTSubtables glyphStore markClasses] : begin
local markSubtable {.marks {.} .bases {.}}
local mkmkSubtable {.marks {.} .bases {.}}
define [createMTLookups glyphStore markClasses] : begin
local markLookup {.type 'gpos_mark_to_base' .marks {.} .bases {.}}
local mkmkLookup {.type 'gpos_mark_to_mark' .marks {.} .bases {.}}
local allowMarkClsSet : new Set markClasses
foreach { gn glyph } [glyphStore.namedEntries] : begin
createMarkInfo markSubtable.marks gn glyph allowMarkClsSet
createMarkInfo mkmkSubtable.marks gn glyph allowMarkClsSet
createMarkInfo markLookup.marks gn glyph allowMarkClsSet
createMarkInfo mkmkLookup.marks gn glyph allowMarkClsSet
local isMark : objectIsNotEmpty glyph.markAnchors
if isMark
createBaseInfo mkmkSubtable.bases gn glyph allowMarkClsSet
createBaseInfo markSubtable.bases gn glyph allowMarkClsSet
return : object markSubtable mkmkSubtable
createBaseInfo mkmkLookup.bases gn glyph allowMarkClsSet
createBaseInfo markLookup.bases gn glyph allowMarkClsSet
return : object markLookup mkmkLookup
define [createBaseInfo sink gn glyph allowMarkClsSet] : begin
local res {.}

View file

@ -99,7 +99,7 @@ export : define [buildCCMP sink glyphStore markGlyphs] : begin
define lookupCcmp1 : add-lookup sink : object
.type 'gsub_chaining'
.subtables : list
.rules : list
# Dot removal (max 6 middle marks are supported)
chain-rule (dotlessFrom ~> dotlessTo) (markGlyphs.above ~> null)
chain-rule (dotlessFrom ~> dotlessTo) markGlyphs.all (markGlyphs.above ~> null)
@ -128,7 +128,7 @@ export : define [buildCCMP sink glyphStore markGlyphs] : begin
define lookupCcmp2 : add-lookup sink : object
.type 'gsub_ligature'
.subtables : list : object : substitutions : list
.substitutions : list
object [from {'commaAbove' 'graveAbove'}] [to 'psilivaria']
object [from {'commaAbove' 'acuteAbove'}] [to 'psilioxia']
object [from {'commaAbove' 'perispomeniAbove'}] [to 'psiliperispomeni']
@ -141,15 +141,15 @@ export : define [buildCCMP sink glyphStore markGlyphs] : begin
define lookupCcmp-TieMarkLigature : add-lookup sink : object
.type 'gsub_ligature'
.subtables : list
object : substitutions : TieMarkFrom.map : lambda [gnFrom idx]
.substitutions : {}.concat
TieMarkFrom.map : lambda [gnFrom idx]
object [from {gnCgjNwid gnFrom}] [to TieMarkTo.(idx)]
object : substitutions : TieMarkFrom.map : lambda [gnFrom idx]
TieMarkFrom.map : lambda [gnFrom idx]
object [from {gnCgjWwid gnFrom}] [to TieMarkTo.(idx)]
define lookupCcmp-TieMarkContextual : add-lookup sink : object
.type 'gsub_chaining'
.subtables : list : object
.rules : list : object
match {[TieGlyphs.concat TieMarkTo] {gnCgjNwid gnCgjWwid} TieMarkFrom}
inputBegins 1
inputEnds 3
@ -157,7 +157,7 @@ export : define [buildCCMP sink glyphStore markGlyphs] : begin
define lookupCcmp-ToneStart : add-lookup sink : object
.type 'gsub_chaining'
.subtables : list
.rules : list
chain-rule [ToneToToneStart 0] {'tone0'}
chain-rule [ToneToToneStart 1] {'tone1'}
chain-rule [ToneToToneStart 2] {'tone2'}
@ -166,7 +166,7 @@ export : define [buildCCMP sink glyphStore markGlyphs] : begin
define lookupCcmp-ToneMid : add-lookup sink : object
.type 'gsub_chaining'
.subtables : list
.rules : list
chain-rule [ToneStartOrMidAt 0] [ToneStartToToneMid 0]
chain-rule [ToneStartOrMidAt 1] [ToneStartToToneMid 1]
chain-rule [ToneStartOrMidAt 2] [ToneStartToToneMid 2]
@ -175,7 +175,7 @@ export : define [buildCCMP sink glyphStore markGlyphs] : begin
define lookupCcmp-ToneEnd : add-lookup sink : object
.type 'gsub_chaining'
.subtables : list
.rules : list
chain-rule [ToneStartOrMidAt 0] [ToneToToneEnd 0]
chain-rule [ToneStartOrMidAt 1] [ToneToToneEnd 1]
chain-rule [ToneStartOrMidAt 2] [ToneToToneEnd 2]
@ -184,7 +184,7 @@ export : define [buildCCMP sink glyphStore markGlyphs] : begin
define lookupCcmp-ToneSandhiStart : add-lookup sink : object
.type 'gsub_chaining'
.subtables : list
.rules : list
chain-rule [ToneSandhiToToneStart 0] {'toneSandhi0'}
chain-rule [ToneSandhiToToneStart 1] {'toneSandhi1'}
chain-rule [ToneSandhiToToneStart 2] {'toneSandhi2'}
@ -193,7 +193,7 @@ export : define [buildCCMP sink glyphStore markGlyphs] : begin
define lookupCcmp-ToneSandhiMid : add-lookup sink : object
.type 'gsub_chaining'
.subtables : list
.rules : list
chain-rule [ToneSandhiStartOrMidAt 0] [ToneSandhiStartToToneMid 0]
chain-rule [ToneSandhiStartOrMidAt 1] [ToneSandhiStartToToneMid 1]
chain-rule [ToneSandhiStartOrMidAt 2] [ToneSandhiStartToToneMid 2]
@ -202,7 +202,7 @@ export : define [buildCCMP sink glyphStore markGlyphs] : begin
define lookupCcmp-ToneSandhiEnd : add-lookup sink : object
.type 'gsub_chaining'
.subtables : list
.rules : list
chain-rule [ToneSandhiStartOrMidAt 0] [ToneSandhiToToneEnd 0]
chain-rule [ToneSandhiStartOrMidAt 1] [ToneSandhiToToneEnd 1]
chain-rule [ToneSandhiStartOrMidAt 2] [ToneSandhiToToneEnd 2]
@ -228,7 +228,7 @@ export : define [buildCCMP sink glyphStore markGlyphs] : begin
ccmp.lookups.push lookupCcmp-Decompose
define lookupCcmp-Decompose : add-lookup sink : object
.type 'gsub_multiple'
.subtables : list decompositions
.substitutions decompositions
add-common-feature sink ccmp
EndLookupBlock rec sink

View file

@ -20,7 +20,7 @@ export : define [buildCVSS sink para glyphStore] : begin
define lookupNameCvDecompose : add-lookup sink : object
.type 'gsub_multiple'
.subtables : list decompositions
.substitutions decompositions
# cvxx
foreach {gn glyph} [glyphStore.namedEntries] : if [not : CvDecompose.get glyph] : do
@ -31,13 +31,13 @@ export : define [buildCVSS sink para glyphStore] : begin
add-common-feature sink feature
local lookup : pick-lookup sink lookupName
begin {.type 'gsub_alternate' .subtables {{.}}}
begin {.type 'gsub_alternate' .substitutions {.}}
add-feature-lookup feature lookupNameCvDecompose
add-feature-lookup feature lookupName
sink.lookupDep.push { lookupNameCvDecompose lookupName }
cvLookupNameSet.add lookupName
local st [pick-lookup sink lookupName].subtables.0
local st [pick-lookup sink lookupName].substitutions
if [not st.(gn)] : set st.(gn) { }
set st.(gn).(gr.rank - 1) : glyphStore.ensureExists : gr.get glyph
@ -46,11 +46,11 @@ export : define [buildCVSS sink para glyphStore] : begin
local feature : pick-feature sink [FeatureName composition.tag]
add-common-feature sink feature
add-feature-lookup feature lookupNameCvDecompose
local lookupNameSub : add-lookup sink {.type 'gsub_single' .subtables {{.}}}
local lookupNameSub : add-lookup sink {.type 'gsub_single' .substitutions {.}}
sink.lookupDep.push { lookupNameCvDecompose lookupNameSub }
add-feature-lookup feature lookupNameSub
define st [pick-lookup sink lookupNameSub].subtables.0
define st [pick-lookup sink lookupNameSub].substitutions
local decomp : composition.decompose para para.variants.selectorTree
foreach { prime pv } [items-of decomp] : if (pv.tag && pv.rank) : begin
local gr : Cv pv.tag pv.rank
@ -60,7 +60,7 @@ export : define [buildCVSS sink para glyphStore] : begin
# If there are holes in the alternates list, fill them
foreach lutn cvLookupNameSet : begin
local st [pick-lookup sink lutn].subtables.0
local st [pick-lookup sink lutn].substitutions
foreach { k v } [pairs-of st] : foreach idx [range 0 v.length] : if [not v.(idx)]
set v.(idx) k

View file

@ -139,14 +139,14 @@ define [buildLigationsImpl sink para featureName mappedFeature rankedLookups] :
define rules : filterNulls _rules
if (rules && rules.length) : AddRankedLookup
.type 'gsub_chaining'
.subtables rules
.rules rules
set lookupRank : lookupRank + 1
define [CreateReverseLigationLookup _rules] : begin
define rules : filterNulls _rules
if (rules && rules.length) : AddRankedLookup
.type 'gsub_reverse'
.subtables rules
.rules rules
set lookupRank : lookupRank + 1
do "Operator centering"

View file

@ -13,7 +13,7 @@ export : define [buildLOCL sink para glyphStore] : begin
cyrlMKD.features.unshift loclSRB.name
loclSRB.lookups.push : add-lookup sink : object
type 'gsub_single'
subtables : list : if para.isItalic
substitutions : if para.isItalic
object
'cyrl/be' : glyphStore.ensureExists 'cyrl/be.SRB'
'cyrl/ghe' : glyphStore.ensureExists 'cyrl/ghe.SRB'
@ -28,7 +28,7 @@ export : define [buildLOCL sink para glyphStore] : begin
cyrlBGR.features.unshift loclBGR.name
loclBGR.lookups.push : add-lookup sink : object
type 'gsub_single'
subtables : list : object
substitutions : object
'cyrl/ve' : glyphStore.ensureExists 'cyrl/ve.BGR'
'cyrl/ghe' : glyphStore.ensureExists 'cyrl/ghe.italic'
'cyrl/de' : glyphStore.ensureExists 'cyrl/de.BGR'

View file

@ -19,13 +19,13 @@ export : define [buildPairFeature sink tag1 tag2 glyphStore codedOnly] : begin
set mapTag1.(gnTag2) glyphName
if [objectIsNotEmpty mapTag1] : begin
define lookup1 : add-lookup sink {.type 'gsub_single' .subtables {mapTag1}}
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' .subtables {mapTag2}}
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

View file

@ -17,7 +17,7 @@ export : define [buildGsubThousands sink para] : begin
define lookupThousand1 : add-lookup sink : object
.type 'gsub_chaining'
.subtables : list
.rules : list
chain-rule ({'period'} ~> null) (numberGlyphIDs ~> [nd 2]) (numberGlyphIDs ~> null) (numberGlyphIDs ~> null)
chain-rule ([nd 2] ~> null) (numberGlyphIDs ~> [nd 1])
chain-rule ([nd 1] ~> null) (numberGlyphIDs ~> [nd 6])
@ -28,13 +28,13 @@ export : define [buildGsubThousands sink para] : begin
define lookupThousand2 : add-lookup sink : object
.type 'gsub_chaining'
.subtables : list
.rules : list
chain-rule (numberGlyphIDs ~> [nd 0]) (numberGlyphIDs ~> null) (numberGlyphIDs ~> null) (numberGlyphIDs ~> null)
chain-rule ([nd 0] ~> null) (numberGlyphIDs ~> [nd 0])
define lookupThousand3 : add-lookup sink : object
.type 'gsub_reverse'
.subtables : list
.rules : list
reverse-rule ([nd 0] ~> [nd 1]) ([nd 0] ~> null)
reverse-rule ([nd 0] ~> [nd 2]) ([nd 1] ~> null)
reverse-rule ([nd 0] ~> [nd 3]) ([nd 2] ~> null)

View file

@ -95,9 +95,9 @@ export : define [MoveBackUtilityLookups sink] : begin
export : define [ChainRuleBuilder sink] : begin
define [createNewLookup f t] : begin
local subtable {.}
foreach [j : range 0 f.length] : set subtable.(f.(j)) t.(j)
return : add-lookup sink {.type 'gsub_single' .subtables {subtable}} UtilityLookupPrefix
local subst {.}
foreach [j : range 0 f.length] : set subst.(f.(j)) t.(j)
return : add-lookup sink {.type 'gsub_single' .substitutions subst} UtilityLookupPrefix
define [getSubLookup left right] : piecewise
[not right] null
@ -108,7 +108,7 @@ export : define [ChainRuleBuilder sink] : begin
local maxMatch 0
local lookupKeys : [Object.keys sink.lookups].reverse
foreach [name : items-of lookupKeys] : begin
local st sink.lookups.(name).subtables.0
local st sink.lookups.(name).substitutions
if [IsUtilityLookupId name] : begin
local compatible true
local matchCount 0
@ -120,7 +120,7 @@ export : define [ChainRuleBuilder sink] : begin
set maxMatch matchCount
if found : begin
local st sink.lookups.(found).subtables.0
local st sink.lookups.(found).substitutions
foreach [j : range 0 left.length] : set st.(left.(j)) right.(j)
return found
@ -128,25 +128,25 @@ export : define [ChainRuleBuilder sink] : begin
define [chain-rule] : begin
local terms : [{}.slice.call arguments 0].map (x -> [if x.left x {.left x .right null}])
local subtable {.match {} .apply {} .inputBegins 0 .inputEnds 0}
local rule {.match {} .apply {} .inputBegins 0 .inputEnds 0}
local foundi false
local founde false
foreach [j : range 0 terms.length] : if (!foundi && terms.(j).right) : begin
set subtable.inputBegins j
set rule.inputBegins j
set foundi true
foreach [j : range (terms.length - 1) downtill 0] : if (!founde && terms.(j).right) : begin
set subtable.inputEnds (j + 1)
set rule.inputEnds (j + 1)
set founde true
foreach [j : range 0 terms.length] : begin
local term terms.(j)
subtable.match.push : Array.from : new Set term.left
rule.match.push : Array.from : new Set term.left
local lutn : getSubLookup term.left term.right
if lutn : subtable.apply.push {.at j .lookup lutn}
return subtable
if lutn : rule.apply.push {.at j .lookup lutn}
return rule
define [reverse-rule] : begin
local terms : [{}.slice.call arguments 0].map (x -> [if x.left x {.left x .right null}])
local subtable {.match {} .to {} .inputIndex 0}
local rule {.match {} .to {} .inputIndex 0}
local foundi false
foreach [j : range 0 terms.length] : begin
@ -157,18 +157,18 @@ export : define [ChainRuleBuilder sink] : begin
if term.right : begin
if foundi : throw : new Error "Duplicate substitutions in one reverse rule"
set foundi true
set subtable.inputIndex j
set rule.inputIndex j
local toGlyphs : piecewise
(term.right <@ Function) [term.right term.left]
true term.right
foreach [k : range 0 term.left.length]
subst.set term.left.(k) (toGlyphs.(k) || term.left.(k))
set subtable.to : Array.from [subst.values]
set rule.to : Array.from [subst.values]
set subtable.match.(j) : Array.from [subst.keys]
set rule.match.(j) : Array.from [subst.keys]
return subtable
return rule
return {chain-rule reverse-rule}