summaryrefslogtreecommitdiff
path: root/tex/context/base/mkiv/font-ots.lua
diff options
context:
space:
mode:
authorHans Hagen <pragma@wxs.nl>2017-08-06 17:11:19 +0200
committerContext Git Mirror Bot <phg42.2a@gmail.com>2017-08-06 17:11:19 +0200
commit5c6090af6fb0808017d6f2fe263b90e2efa0ae5e (patch)
tree84f61dc4994ba9c2376d829b6b71bb3b7e0bb9a5 /tex/context/base/mkiv/font-ots.lua
parent817e18d3f6969b1b50b4883ec4d5bb05c985db88 (diff)
downloadcontext-5c6090af6fb0808017d6f2fe263b90e2efa0ae5e.tar.gz
2017-08-06 16:19:00
Diffstat (limited to 'tex/context/base/mkiv/font-ots.lua')
-rw-r--r--tex/context/base/mkiv/font-ots.lua763
1 files changed, 157 insertions, 606 deletions
diff --git a/tex/context/base/mkiv/font-ots.lua b/tex/context/base/mkiv/font-ots.lua
index 7194109a1..43585552b 100644
--- a/tex/context/base/mkiv/font-ots.lua
+++ b/tex/context/base/mkiv/font-ots.lua
@@ -169,6 +169,7 @@ registertracker("otf.substitutions", "otf.singles","otf.multiples","otf.alternat
registertracker("otf.positions", "otf.marks","otf.kerns","otf.cursive")
registertracker("otf.actions", "otf.substitutions","otf.positions")
registertracker("otf.sample", "otf.steps","otf.substitutions","otf.positions","otf.analyzing")
+registertracker("otf.sample.silent", "otf.steps=silent","otf.substitutions","otf.positions","otf.analyzing")
local nuts = nodes.nuts
local tonode = nuts.tonode
@@ -305,6 +306,9 @@ local registermessage = (tracers and tracers.steppers.message) or function()
local function logprocess(...)
if trace_steps then
registermessage(...)
+ if trace_steps == "silent" then
+ return
+ end
end
report_direct(...)
end
@@ -490,7 +494,7 @@ local function markstoligature(head,start,stop,char)
end
end
-local function toligature(head,start,stop,char,dataset,sequence,markflag,discfound) -- brr head
+local function toligature(head,start,stop,char,dataset,sequence,skiphash,discfound) -- brr head
if getattr(start,a_noligature) == 1 then
-- so we can do: e\noligature{ff}e e\noligature{f}fie (we only look at the first)
return head, start
@@ -515,7 +519,7 @@ local function toligature(head,start,stop,char,dataset,sequence,markflag,discfou
set_components(base,comp)
setlink(prev,base,next)
if not discfound then
- local deletemarks = markflag ~= "mark"
+ local deletemarks = not skiphash
local components = start
local baseindex = 0
local componentindex = 0
@@ -600,7 +604,7 @@ local function toligature(head,start,stop,char,dataset,sequence,markflag,discfou
return head, base
end
-local function multiple_glyphs(head,start,multiple,ignoremarks,what)
+local function multiple_glyphs(head,start,multiple,skiphash,what) -- what to do with skiphash matches here
local nofmultiples = #multiple
if nofmultiples > 0 then
resetinjection(start)
@@ -693,7 +697,7 @@ function handlers.gsub_single(head,start,dataset,sequence,replacement)
return head, start, true
end
-function handlers.gsub_alternate(head,start,dataset,sequence,alternative,rlmode,skiphash)
+function handlers.gsub_alternate(head,start,dataset,sequence,alternative)
local kind = dataset[4]
local what = dataset[1]
local value = what == true and tfmdata.shared.features[kind] or what
@@ -716,7 +720,7 @@ function handlers.gsub_multiple(head,start,dataset,sequence,multiple,rlmode,skip
if trace_multiples then
logprocess("%s: replacing %s by multiple %s",pref(dataset,sequence),gref(getchar(start)),gref(multiple))
end
- return multiple_glyphs(head,start,multiple,sequence.flags[1],dataset[1])
+ return multiple_glyphs(head,start,multiple,skiphash,dataset[1])
end
-- Don't we deal with disc otherwise now? I need to check if the next one can be
@@ -729,7 +733,7 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature,rlmode,skip
end
local stop = nil
local startchar = getchar(start)
- if marks[startchar] then
+ if skiphash and skiphash[startchar] then
while current do
local char = ischar(current,currentfont)
if char then
@@ -761,13 +765,12 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature,rlmode,skip
end
end
else
- local skipmark = sequence.flags[1]
local discfound = false
local lastdisc = nil
while current do
local char, id = ischar(current,currentfont)
if char then
- if skipmark and marks[char] then
+ if skiphash and skiphash[char] then
current = getnext(current)
else -- ligature is a tree
local lg = ligature[char] -- can there be multiple in a row? maybe in a bad font
@@ -820,10 +823,10 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature,rlmode,skip
if stop then
if trace_ligatures then
local stopchar = getchar(stop)
- head, start = toligature(head,start,stop,lig,dataset,sequence,skipmark,discfound)
+ head, start = toligature(head,start,stop,lig,dataset,sequence,skiphash,discfound)
logprocess("%s: replacing %s upto %s by ligature %s case 2",pref(dataset,sequence),gref(startchar),gref(stopchar),gref(lig))
else
- head, start = toligature(head,start,stop,lig,dataset,sequence,skipmark,discfound)
+ head, start = toligature(head,start,stop,lig,dataset,sequence,skiphash,discfound)
end
else
-- weird but happens (in some arabic font)
@@ -867,12 +870,9 @@ function handlers.gpos_pair(head,start,dataset,sequence,kerns,rlmode,skiphash,st
while snext do
local nextchar = ischar(snext,currentfont)
if nextchar then
- if marks[nextchar] and sequence.flags[1] then
+ if skiphash and skiphash[nextchar] then -- includes marks too when flag
prev = snext
snext = getnext(snext)
--- if skiphash and skiphash[nextchar] then -- includes marks too when flag
--- prev = snext
--- snext = getnext(snext)
else
local krn = kerns[nextchar]
if not krn then
@@ -1129,6 +1129,9 @@ local chainprocs = { }
local function logprocess(...)
if trace_steps then
registermessage(...)
+ if trace_steps == "silent" then
+ return
+ end
end
report_subchain(...)
end
@@ -1138,6 +1141,9 @@ local logwarning = report_subchain
local function logprocess(...)
if trace_steps then
registermessage(...)
+ if trace_steps == "silent" then
+ return
+ end
end
report_chain(...)
end
@@ -1205,17 +1211,31 @@ end
-- logwarning("%s: bad step, no proper return values",cref(dataset,sequence))
-- end
-function chainprocs.gsub_single(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex)
+local function getmapping(dataset,sequence,currentlookup)
local steps = currentlookup.steps
local nofsteps = currentlookup.nofsteps
- if nofsteps > 1 then
- reportmoresteps(dataset,sequence)
- end
if nofsteps == 0 then
reportzerosteps(dataset,sequence)
+ currentlookup.mapping = false
+ return false
else
- local current = start
+ if nofsteps > 1 then
+ reportmoresteps(dataset,sequence)
+ end
local mapping = steps[1].coverage
+ currentlookup.mapping = mapping
+ currentlookup.format = steps[1].format
+ return mapping
+ end
+end
+
+function chainprocs.gsub_single(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex)
+ local mapping = currentlookup.mapping
+ if mapping == nil then
+ mapping = getmapping(dataset,sequence,currentlookup)
+ end
+ if mapping then
+ local current = start
while current do
local currentchar = ischar(current)
if currentchar then
@@ -1246,35 +1266,6 @@ function chainprocs.gsub_single(head,start,stop,dataset,sequence,currentlookup,r
end
--[[ldx--
-<p>Here we replace start by a sequence of new glyphs.</p>
---ldx]]--
-
-function chainprocs.gsub_multiple(head,start,stop,dataset,sequence,currentlookup)
- local steps = currentlookup.steps
- local nofsteps = currentlookup.nofsteps
- if nofsteps > 1 then
- reportmoresteps(dataset,sequence)
- end
- if nofsteps == 0 then
- reportzerosteps(dataset,sequence)
- else
- local startchar = getchar(start)
- local replacement = steps[1].coverage[startchar]
- if not replacement or replacement == "" then
- if trace_bugs then
- logwarning("%s: no multiple for %s",cref(dataset,sequence),gref(startchar))
- end
- else
- if trace_multiples then
- logprocess("%s: replacing %s by multiple characters %s",cref(dataset,sequence),gref(startchar),gref(replacement))
- end
- return multiple_glyphs(head,start,replacement,sequence.flags[1],dataset[1])
- end
- end
- return head, start, false
-end
-
---[[ldx--
<p>Here we replace start by new glyph. First we delete the rest of the match.</p>
--ldx]]--
@@ -1286,20 +1277,16 @@ end
-- marks come last anyway
-- are there cases where we need to delete the mark
-function chainprocs.gsub_alternate(head,start,stop,dataset,sequence,currentlookup)
- local steps = currentlookup.steps
- local nofsteps = currentlookup.nofsteps
- if nofsteps > 1 then
- reportmoresteps(dataset,sequence)
+function chainprocs.gsub_alternate(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex)
+ local mapping = currentlookup.mapping
+ if mapping == nil then
+ mapping = getmapping(dataset,sequence,currentlookup)
end
- if nofsteps == 0 then
- reportzerosteps(dataset,sequence)
- else
+ if mapping then
local kind = dataset[4]
local what = dataset[1]
local value = what == true and tfmdata.shared.features[kind] or what -- todo: optimize in ctx
local current = start
- local mapping = steps[1].coverage
while current do
local currentchar = ischar(current)
if currentchar then
@@ -1333,22 +1320,45 @@ function chainprocs.gsub_alternate(head,start,stop,dataset,sequence,currentlooku
end
--[[ldx--
+<p>Here we replace start by a sequence of new glyphs.</p>
+--ldx]]--
+
+function chainprocs.gsub_multiple(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex)
+ local mapping = currentlookup.mapping
+ if mapping == nil then
+ mapping = getmapping(dataset,sequence,currentlookup)
+ end
+ if mapping then
+ local startchar = getchar(start)
+ local replacement = mapping[startchar]
+ if not replacement or replacement == "" then
+ if trace_bugs then
+ logwarning("%s: no multiple for %s",cref(dataset,sequence),gref(startchar))
+ end
+ else
+ if trace_multiples then
+ logprocess("%s: replacing %s by multiple characters %s",cref(dataset,sequence),gref(startchar),gref(replacement))
+ end
+ return multiple_glyphs(head,start,replacement,skiphash,dataset[1])
+ end
+ end
+ return head, start, false
+end
+
+--[[ldx--
<p>When we replace ligatures we use a helper that handles the marks. I might change
this function (move code inline and handle the marks by a separate function). We
assume rather stupid ligatures (no complex disc nodes).</p>
--ldx]]--
-function chainprocs.gsub_ligature(head,start,stop,dataset,sequence,currentlookup,chainindex)
- local steps = currentlookup.steps
- local nofsteps = currentlookup.nofsteps
- if nofsteps > 1 then
- reportmoresteps(dataset,sequence)
+function chainprocs.gsub_ligature(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex)
+ local mapping = currentlookup.mapping
+ if mapping == nil then
+ mapping = getmapping(dataset,sequence,currentlookup)
end
- if nofsteps == 0 then
- reportzerosteps(dataset,sequence)
- else
+ if mapping then
local startchar = getchar(start)
- local ligatures = steps[1].coverage[startchar]
+ local ligatures = mapping[startchar]
if not ligatures then
if trace_bugs then
logwarning("%s: no ligatures starting with %s",cref(dataset,sequence,chainindex),gref(startchar))
@@ -1358,7 +1368,6 @@ function chainprocs.gsub_ligature(head,start,stop,dataset,sequence,currentlookup
local discfound = false
local last = stop
local nofreplacements = 1
- local skipmark = currentlookup.flags[1] -- sequence.flags?
while current do
-- todo: ischar ... can there really be disc nodes here?
local id = getid(current)
@@ -1373,7 +1382,7 @@ function chainprocs.gsub_ligature(head,start,stop,dataset,sequence,currentlookup
end
else
local schar = getchar(current)
- if skipmark and marks[schar] then -- marks
+ if skiphash and skiphash[schar] then -- marks
-- if current == stop then -- maybe add this
-- break
-- else
@@ -1408,7 +1417,7 @@ function chainprocs.gsub_ligature(head,start,stop,dataset,sequence,currentlookup
logprocess("%s: replacing character %s upto %s by ligature %s case 4",cref(dataset,sequence,chainindex),gref(startchar),gref(getchar(stop)),gref(ligature))
end
end
- head, start = toligature(head,start,stop,ligature,dataset,sequence,skipmark,discfound)
+ head, start = toligature(head,start,stop,ligature,dataset,sequence,skiphash,discfound)
return head, start, true, nofreplacements, discfound
elseif trace_bugs then
if start == stop then
@@ -1423,21 +1432,15 @@ function chainprocs.gsub_ligature(head,start,stop,dataset,sequence,currentlookup
end
function chainprocs.gpos_single(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex)
- local steps = currentlookup.steps
- local nofsteps = currentlookup.nofsteps
- if nofsteps > 1 then
- reportmoresteps(dataset,sequence)
+ local mapping = currentlookup.mapping
+ if mapping == nil then
+ mapping = getmapping(dataset,sequence,currentlookup)
end
- if nofsteps == 0 then
- reportzerosteps(dataset,sequence)
- else
+ if mapping then
local startchar = getchar(start)
- local step = steps[1]
- local kerns = step.coverage[startchar]
- if not kerns then
- -- skip
- else
- local format = step.format
+ local kerns = mapping[startchar]
+ if kerns then
+ local format = currentlookup.format
if format == "single" then
local dx, dy, w, h = setposition(start,factor,rlmode,sequence.flags[4],kerns) -- currentlookup.flags ?
if trace_kerns then
@@ -1455,19 +1458,15 @@ function chainprocs.gpos_single(head,start,stop,dataset,sequence,currentlookup,r
end
function chainprocs.gpos_pair(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex) -- todo: injections ?
- local steps = currentlookup.steps
- local nofsteps = currentlookup.nofsteps
- if nofsteps > 1 then
- reportmoresteps(dataset,sequence)
+ local mapping = currentlookup.mapping
+ if mapping == nil then
+ mapping = getmapping(dataset,sequence,currentlookup)
end
- if nofsteps == 0 then
- reportzerosteps(dataset,sequence)
- else
+ if mapping then
local snext = getnext(start)
if snext then
local startchar = getchar(start)
- local step = steps[1]
- local kerns = step.coverage[startchar] -- always 1 step
+ local kerns = mapping[startchar] -- always 1 step
if kerns then
local prev = start
while snext do
@@ -1475,18 +1474,15 @@ function chainprocs.gpos_pair(head,start,stop,dataset,sequence,currentlookup,rlm
if not nextchar then
break
end
- if marks[nextchar] and sequence.flags[1] then
+ if skiphash and skiphash[nextchar] then
prev = snext
snext = getnext(snext)
--- if skiphash and skiphash[nextchar] then
--- prev = snext
--- snext = getnext(snext)
else
local krn = kerns[nextchar]
if not krn then
break
end
- local format = step.format
+ local format = currentlookup.format
if format == "pair" then
local a, b = krn[1], krn[2]
if a == true then
@@ -1529,18 +1525,15 @@ function chainprocs.gpos_pair(head,start,stop,dataset,sequence,currentlookup,rlm
return head, start, false
end
-function chainprocs.gpos_mark2base(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash)
- local steps = currentlookup.steps
- local nofsteps = currentlookup.nofsteps
- if nofsteps > 1 then
- reportmoresteps(dataset,sequence)
+function chainprocs.gpos_mark2base(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex)
+ local mapping = currentlookup.mapping
+ if mapping == nil then
+ mapping = getmapping(dataset,sequence,currentlookup)
end
- if nofsteps == 0 then
- reportzerosteps(dataset,sequence)
- else
+ if mapping then
local markchar = getchar(start)
if marks[markchar] then
- local markanchors = steps[1].coverage[markchar] -- always 1 step
+ local markanchors = mapping[markchar] -- always 1 step
if markanchors then
local base = getprev(start) -- [glyph] [start=mark]
if base then
@@ -1597,18 +1590,15 @@ function chainprocs.gpos_mark2base(head,start,stop,dataset,sequence,currentlooku
return head, start, false
end
-function chainprocs.gpos_mark2ligature(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash)
- local steps = currentlookup.steps
- local nofsteps = currentlookup.nofsteps
- if nofsteps > 1 then
- reportmoresteps(dataset,sequence)
+function chainprocs.gpos_mark2ligature(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex)
+ local mapping = currentlookup.mapping
+ if mapping == nil then
+ mapping = getmapping(dataset,sequence,currentlookup)
end
- if nofsteps == 0 then
- reportzerosteps(dataset,sequence)
- else
+ if mapping then
local markchar = getchar(start)
if marks[markchar] then
- local markanchors = steps[1].coverage[markchar] -- always 1 step
+ local markanchors = mapping[markchar] -- always 1 step
if markanchors then
local base = getprev(start) -- [glyph] [optional marks] [start=mark]
if base then
@@ -1669,18 +1659,15 @@ function chainprocs.gpos_mark2ligature(head,start,stop,dataset,sequence,currentl
return head, start, false
end
-function chainprocs.gpos_mark2mark(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash)
- local steps = currentlookup.steps
- local nofsteps = currentlookup.nofsteps
- if nofsteps > 1 then
- reportmoresteps(dataset,sequence)
+function chainprocs.gpos_mark2mark(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex)
+ local mapping = currentlookup.mapping
+ if mapping == nil then
+ mapping = getmapping(dataset,sequence,currentlookup)
end
- if nofsteps == 0 then
- reportzerosteps(dataset,sequence)
- else
+ if mapping then
local markchar = getchar(start)
if marks[markchar] then
- local markanchors = steps[1].coverage[markchar] -- always 1 step
+ local markanchors = mapping[markchar] -- always 1 step
if markanchors then
local base = getprev(start) -- [glyph] [basemark] [start=mark]
local slc = getligaindex(start)
@@ -1725,17 +1712,14 @@ function chainprocs.gpos_mark2mark(head,start,stop,dataset,sequence,currentlooku
return head, start, false
end
-function chainprocs.gpos_cursive(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash)
- local steps = currentlookup.steps
- local nofsteps = currentlookup.nofsteps
- if nofsteps > 1 then
- reportmoresteps(dataset,sequence)
+function chainprocs.gpos_cursive(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex)
+ local mapping = currentlookup.mapping
+ if mapping == nil then
+ mapping = getmapping(dataset,sequence,currentlookup)
end
- if nofsteps == 0 then
- reportzerosteps(dataset,sequence)
- else
+ if mapping then
local startchar = getchar(start)
- local exitanchors = steps[1].coverage[startchar] -- always 1 step
+ local exitanchors = mapping[startchar] -- always 1 step
if exitanchors then
if marks[startchar] then
if trace_cursive then
@@ -1789,28 +1773,29 @@ end
-- A previous version had disc collapsing code in the (single sub) handler plus some
-- checking in the main loop, but that left the pre/post sequences undone. The best
-- solution is to add some checking there and backtrack when a replace/post matches
--- but it takes a bit of work to figure out an efficient way (this is what the sweep*
--- names refer to). I might look into that variant one day again as it can replace
--- some other code too. In that approach we can have a special version for gub and pos
--- which gains some speed. This method does the test and passes info to the handlers.
--- Here collapsing is handled in the main loop which also makes code elsewhere simpler
--- (i.e. no need for the other special runners and disc code in ligature building). I
--- also experimented with pushing preceding glyphs sequences in the replace/pre fields
--- beforehand which saves checking afterwards but at the cost of duplicate glyphs
--- (memory) but it's too much overhead (runtime).
+-- but it takes a bit of work to figure out an efficient way (this is what the
+-- sweep* names refer to). I might look into that variant one day again as it can
+-- replace some other code too. In that approach we can have a special version for
+-- gub and pos which gains some speed. This method does the test and passes info to
+-- the handlers. Here collapsing is handled in the main loop which also makes code
+-- elsewhere simpler (i.e. no need for the other special runners and disc code in
+-- ligature building). I also experimented with pushing preceding glyphs sequences
+-- in the replace/pre fields beforehand which saves checking afterwards but at the
+-- cost of duplicate glyphs (memory) but it's too much overhead (runtime).
--
--- In the meantime Kai had moved the code from the single chain into a more general handler
--- and this one (renamed to chaindisk) is used now. I optimized the code a bit and brought
--- it in sycn with the other code. Hopefully I didn't introduce errors. Note: this somewhat
--- complex approach is meant for fonts that implement (for instance) ligatures by character
--- replacement which to some extend is not that suitable for hyphenation. I also use some
--- helpers. This method passes some states but reparses the list. There is room for a bit of
--- speed up but that will be done in the context version. (In fact a partial rewrite of all
--- code can bring some more efficientry.)
+-- In the meantime Kai had moved the code from the single chain into a more general
+-- handler and this one (renamed to chaindisk) is used now. I optimized the code a
+-- bit and brought it in sycn with the other code. Hopefully I didn't introduce
+-- errors. Note: this somewhat complex approach is meant for fonts that implement
+-- (for instance) ligatures by character replacement which to some extend is not
+-- that suitable for hyphenation. I also use some helpers. This method passes some
+-- states but reparses the list. There is room for a bit of speed up but that will
+-- be done in the context version. (In fact a partial rewrite of all code can bring
+-- some more efficiency.)
--
--- I didn't test it with extremes but successive disc nodes still can give issues but in
--- order to handle that we need more complex code which also slows down even more. The main
--- loop variant could deal with that: test, collapse, backtrack.
+-- I didn't test it with extremes but successive disc nodes still can give issues
+-- but in order to handle that we need more complex code which also slows down even
+-- more. The main loop variant could deal with that: test, collapse, backtrack.
local userkern = nuts.pool and nuts.pool.newkern -- context
@@ -1937,7 +1922,7 @@ local function chainrun(head,start,last,dataset,sequence,rlmode,skiphash,ck)
local chainproc = chainprocs[chainkind]
if chainproc then
local ok, n
- head, start, ok, n = chainproc(head,start,last,dataset,sequence,chainstep,rlmode,skiphash)
+ head, start, ok, n = chainproc(head,start,last,dataset,sequence,chainstep,rlmode,skiphash,i)
-- messy since last can be changed !
if ok then
done = true
@@ -2319,452 +2304,16 @@ local function chaintrac(head,start,dataset,sequence,rlmode,skiphash,ck,match)
local last = ck[5]
local char = getchar(start)
logwarning("%s: rule %s %s at char %s for (%s,%s,%s) chars, lookuptype %a",
- cref(dataset,sequence),rule,match and "matches" or "nomatch",gref(char),first-1,last-first+1,nofseq-last,lookuptype)
+ cref(dataset,sequence),rule,match and "matches" or "nomatch",
+ gref(char),first-1,last-first+1,nofseq-last,lookuptype)
end
--- The next one is quite optimized but still somewhat slow, fonts like ebgaramond are real torture
--- tests because they have many steps with one context (having multiple contexts makes more sense)
--- also because we (can) reduce them.
-
--- local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode,skiphash)
--- local sweepnode = sweepnode
--- local sweeptype = sweeptype
--- local currentfont = currentfont
--- local diskseen = false
--- local checkdisc = sweeptype and getprev(head)
--- local flags = sequence.flags or noflags
--- local done = false
--- local skipped = false
--- local startprev,
--- startnext = getboth(start)
---
--- for k=1,#contexts do -- i've only seen ccmp having > 1 (e.g. dejavu)
--- local match = true
--- local current = start
--- local last = start
--- local ck = contexts[k]
--- local seq = ck[3]
--- local s = #seq
--- -- f..l = mid string
--- if s == 1 then
--- -- this seldom happens as it makes no sense (bril, ebgaramond, husayni, minion)
--- local char = ischar(current,currentfont)
--- if char and not seq[1][char] then
--- match = false
--- end
--- else
--- -- maybe we need a better space check (maybe check for glue or category or combination)
--- -- we cannot optimize for n=2 because there can be disc nodes
--- local f = ck[4]
--- local l = ck[5]
--- -- current match
--- -- seq[f][ischar(current,currentfont)] is not nil
--- if l > f then
--- -- before/current/after | before/current | current/after
--- local discfound -- = nil
--- local n = f + 1
--- last = startnext -- the second in current (first already matched)
--- while n <= l do
--- if not last and (sweeptype == "post" or sweeptype == "replace") then
--- last = getnext(sweepnode)
--- sweeptype = nil
--- end
--- if last then
--- local char, id = ischar(last,currentfont)
--- if char then
--- if skiphash and skiphash[char] then
--- skipped = true
--- if trace_skips then
--- show_skip(dataset,sequence,char,ck,classes[char])
--- end
--- last = getnext(last)
--- else
--- if seq[n][char] then
--- if n < l then
--- last = getnext(last)
--- end
--- n = n + 1
--- else
--- if discfound then
--- notmatchreplace[discfound] = true
--- if notmatchpre[discfound] then
--- match = false
--- end
--- else
--- match = false
--- end
--- break
--- end
--- end
--- elseif char == false then
--- if discfound then
--- notmatchreplace[discfound] = true
--- if notmatchpre[discfound] then
--- match = false
--- end
--- else
--- match = false
--- end
--- break
--- elseif id == disc_code then
--- diskseen = true
--- discfound = last
--- notmatchpre[last] = nil
--- notmatchpost[last] = true
--- notmatchreplace[last] = nil
--- local pre, post, replace = getdisc(last)
--- if pre then
--- local n = n
--- while pre do
--- if seq[n][getchar(pre)] then
--- n = n + 1
--- if n > l then
--- break
--- end
--- pre = getnext(pre)
--- else
--- notmatchpre[last] = true
--- break
--- end
--- end
--- if n <= l then
--- notmatchpre[last] = true
--- end
--- else
--- notmatchpre[last] = true
--- end
--- if replace then
--- -- so far we never entered this branch
--- while replace do
--- if seq[n][getchar(replace)] then
--- n = n + 1
--- if n > l then
--- break
--- end
--- replace = getnext(replace)
--- else
--- notmatchreplace[last] = true
--- if notmatchpre[last] then
--- match = false
--- end
--- break
--- end
--- end
--- -- why here again
--- if notmatchpre[last] then
--- match = false
--- end
--- end
--- -- maybe only if match
--- last = getnext(last)
--- else
--- match = false
--- break
--- end
--- else
--- match = false
--- break
--- end
--- end
--- end
--- -- before
--- if match and f > 1 then
--- if startprev then
--- local prev = startprev
--- if prev == checkdisc and (sweeptype == "pre" or sweeptype == "replace") then
--- prev = getprev(sweepnode)
--- end
--- if prev then
--- local discfound -- = nil
--- local n = f - 1
--- while n >= 1 do
--- if prev then
--- local char, id = ischar(prev,currentfont)
--- if char then
--- if skiphash and skiphash[char] then
--- skipped = true
--- if trace_skips then
--- show_skip(dataset,sequence,char,ck,classes[char])
--- end
--- prev = getprev(prev)
--- else
--- if seq[n][char] then
--- if n > 1 then
--- prev = getprev(prev)
--- end
--- n = n - 1
--- else
--- if discfound then
--- notmatchreplace[discfound] = true
--- if notmatchpost[discfound] then
--- match = false
--- end
--- else
--- match = false
--- end
--- break
--- end
--- end
--- elseif char == false then
--- if discfound then
--- notmatchreplace[discfound] = true
--- if notmatchpost[discfound] then
--- match = false
--- end
--- else
--- match = false
--- end
--- break
--- elseif id == disc_code then
--- -- the special case: f i where i becomes dottless i ..
--- diskseen = true
--- discfound = prev
--- notmatchpre[prev] = true
--- notmatchpost[prev] = nil
--- notmatchreplace[prev] = nil
--- local pre, post, replace, pretail, posttail, replacetail = getdisc(prev,true)
--- if pre ~= start and post ~= start and replace ~= start then
--- if post then
--- local n = n
--- while posttail do
--- if seq[n][getchar(posttail)] then
--- n = n - 1
--- if posttail == post then
--- break
--- else
--- if n < 1 then
--- break
--- end
--- posttail = getprev(posttail)
--- end
--- else
--- notmatchpost[prev] = true
--- break
--- end
--- end
--- if n >= 1 then
--- notmatchpost[prev] = true
--- end
--- else
--- notmatchpost[prev] = true
--- end
--- if replace then
--- -- we seldom enter this branch (e.g. on brill efficient)
--- while replacetail do
--- if seq[n][getchar(replacetail)] then
--- n = n - 1
--- if replacetail == replace then
--- break
--- else
--- if n < 1 then
--- break
--- end
--- replacetail = getprev(replacetail)
--- end
--- else
--- notmatchreplace[prev] = true
--- if notmatchpost[prev] then
--- match = false
--- end
--- break
--- end
--- end
--- if not match then
--- break
--- end
--- end
--- end
--- -- maybe only if match
--- prev = getprev(prev)
--- -- elseif id == glue_code and seq[n][32] and isspace(prev,threshold,id) then
--- -- n = n - 1
--- -- prev = getprev(prev)
--- elseif id == glue_code then
--- local sn = seq[n]
--- if (sn[32] and spaces[prev]) or sn[0xFFFC] then
--- n = n - 1
--- prev = getprev(prev)
--- else
--- match = false
--- break
--- end
--- elseif seq[n][0xFFFC] then
--- n = n - 1
--- prev = getprev(prev)
--- else
--- match = false
--- break
--- end
--- else
--- match = false
--- break
--- end
--- end
--- else
--- match = false
--- end
--- else
--- match = false
--- end
--- end
--- -- after
--- if match and s > l then
--- local current = last and getnext(last)
--- if not current and (sweeptype == "post" or sweeptype == "replace") then
--- current = getnext(sweepnode)
--- end
--- if current then
--- local discfound -- = nil
--- -- removed optimization for s-l == 1, we have to deal with marks anyway
--- local n = l + 1
--- while n <= s do
--- if current then
--- local char, id = ischar(current,currentfont)
--- if char then
--- if skiphash and skiphash[char] then
--- skipped = true
--- if trace_skips then
--- show_skip(dataset,sequence,char,ck,classes[char])
--- end
--- current = getnext(current) -- was absent
--- else
--- if seq[n][char] then
--- if n < s then -- new test
--- current = getnext(current) -- was absent
--- end
--- n = n + 1
--- else
--- if discfound then
--- notmatchreplace[discfound] = true
--- if notmatchpre[discfound] then
--- match = false
--- end
--- else
--- match = false
--- end
--- break
--- end
--- end
--- elseif char == false then
--- if discfound then
--- notmatchreplace[discfound] = true
--- if notmatchpre[discfound] then
--- match = false
--- end
--- else
--- match = false
--- end
--- break
--- elseif id == disc_code then
--- diskseen = true
--- discfound = current
--- notmatchpre[current] = nil
--- notmatchpost[current] = true
--- notmatchreplace[current] = nil
--- local pre, post, replace = getdisc(current)
--- if pre then
--- local n = n
--- while pre do
--- if seq[n][getchar(pre)] then
--- n = n + 1
--- if n > s then
--- break
--- end
--- pre = getnext(pre)
--- else
--- notmatchpre[current] = true
--- break
--- end
--- end
--- if n <= s then
--- notmatchpre[current] = true
--- end
--- else
--- notmatchpre[current] = true
--- end
--- if replace then
--- -- so far we never entered this branch
--- while replace do
--- if seq[n][getchar(replace)] then
--- n = n + 1
--- if n > s then
--- break
--- end
--- replace = getnext(replace)
--- else
--- notmatchreplace[current] = true
--- -- different than others, needs checking if "not" is okay
--- if not notmatchpre[current] then
--- match = false
--- end
--- break
--- end
--- end
--- if not match then
--- break
--- end
--- else
--- -- skip 'm
--- end
--- current = getnext(current)
--- -- elseif id == glue_code and seq[n][32] and isspace(current,threshold,id) then
--- -- n = n + 1
--- -- current = getnext(current)
--- elseif id == glue_code then
--- local sn = seq[n]
--- if (sn[32] and spaces[current]) or sn[0xFFFC] then
--- n = n + 1
--- current = getnext(current)
--- else
--- match = false
--- break
--- end
--- elseif seq[n][0xFFFC] then
--- n = n + 1
--- current = getnext(current)
--- else
--- match = false
--- break
--- end
--- else
--- match = false
--- break
--- end
--- end
--- else
--- match = false
--- end
--- end
--- end
--- if match then
--- if trace_contexts then
--- chaintrac(head,start,dataset,sequence,rlmode,skipped and skiphash,ck,true)
--- end
--- if diskseen or sweepnode then
--- head, start, done = chaindisk(head,start,dataset,sequence,rlmode,skipped and skiphash,ck)
--- else
--- head, start, done = chainrun(head,start,last,dataset,sequence,rlmode,skipped and skiphash,ck)
--- end
--- if done then
--- break
--- else
--- -- next context
--- end
--- -- elseif trace_chains then
--- -- chaintrac(head,start,dataset,sequence,rlmode,skipped and skiphash,ck,match)
--- end
--- end
--- if diskseen then
--- notmatchpre = { }
--- notmatchpost = { }
--- notmatchreplace = { }
--- end
--- return head, start, done
--- end
-
--- Instead of a "match" boolean variable and check for that I decided to use a "goto" with
--- "labels" instead. This is one of the cases where it makes th ecode more readable and we might
--- even gain a bit performance.
+-- The next one is quite optimized but still somewhat slow, fonts like ebgaramond
+-- are real torture tests because they have many steps with one context (having
+-- multiple contexts makes more sense) also because we (can) reduce them. Instead of
+-- a match boolean variable and check for that I decided to use a goto with labels
+-- instead. This is one of the cases where it makes th ecode more readable and we
+-- might even gain a bit performance.
local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode,skiphash)
-- optimizing for rlmode gains nothing
@@ -3246,6 +2795,9 @@ local resolved = { } -- we only resolve a font,script,language pair once
local function logprocess(...)
if trace_steps then
registermessage(...)
+ if trace_steps == "silent" then
+ return
+ end
end
report_process(...)
end
@@ -4495,15 +4047,10 @@ registerotffeature {
}
}
--- This can be used for extra handlers, but should be used with care!
-
-otf.handlers = handlers -- used in devanagari
-
--- We implement one here:
-
-local setspacekerns = nodes.injections.setspacekerns if not setspacekerns then os.exit() end
-
--- This pseudo feature has no steps, so it gets called as:
+-- This can be used for extra handlers, but should be used with care! We implement one
+-- here but some more can be found in the osd (script devanagary) file. Now watch out:
+-- when a handlers has steps, it is called as the other ones, but when we have no steps,
+-- we use a different call:
--
-- function(head,dataset,sequence,initialrl,font,attr)
-- return head, done
@@ -4511,6 +4058,10 @@ local setspacekerns = nodes.injections.setspacekerns if not setspacekerns then o
--
-- Also see (!!).
+otf.handlers = handlers
+
+local setspacekerns = nodes.injections.setspacekerns if not setspacekerns then os.exit() end
+
if fontfeatures then
function handlers.trigger_space_kerns(head,dataset,sequence,initialrl,font,attr)