diff options
author | Hans Hagen <pragma@wxs.nl> | 2017-08-06 17:11:19 +0200 |
---|---|---|
committer | Context Git Mirror Bot <phg42.2a@gmail.com> | 2017-08-06 17:11:19 +0200 |
commit | 5c6090af6fb0808017d6f2fe263b90e2efa0ae5e (patch) | |
tree | 84f61dc4994ba9c2376d829b6b71bb3b7e0bb9a5 /tex/context/base/mkiv/font-ots.lua | |
parent | 817e18d3f6969b1b50b4883ec4d5bb05c985db88 (diff) | |
download | context-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.lua | 763 |
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) |