summaryrefslogtreecommitdiff
path: root/tex/context/base/mkiv/font-ots.lua
diff options
context:
space:
mode:
Diffstat (limited to 'tex/context/base/mkiv/font-ots.lua')
-rw-r--r--tex/context/base/mkiv/font-ots.lua605
1 files changed, 309 insertions, 296 deletions
diff --git a/tex/context/base/mkiv/font-ots.lua b/tex/context/base/mkiv/font-ots.lua
index 031cf3baa..3d0606caf 100644
--- a/tex/context/base/mkiv/font-ots.lua
+++ b/tex/context/base/mkiv/font-ots.lua
@@ -543,12 +543,13 @@ local function toligature(head,start,stop,char,dataset,sequence,skiphash,discfou
-- we can be more clever here: "not deletemarks or (skiphash and not skiphash[char])"
-- and such:
elseif not deletemarks then
+ -- we can get a loop when the font expects otherwise (i.e. unexpected deletemarks)
setligaindex(start,baseindex + getligaindex(start,componentindex))
if trace_marks then
logwarning("%s: keep mark %s, gets index %s",pref(dataset,sequence),gref(char),getligaindex(start))
end
local n = copy_node(start)
- copyinjection(n,start)
+ copyinjection(n,start) -- is this ok ? we position later anyway
head, current = insert_node_after(head,current,n) -- unlikely that mark has components
elseif trace_marks then
logwarning("%s: delete mark %s",pref(dataset,sequence),gref(char))
@@ -2352,7 +2353,7 @@ end
-- 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
+-- instead. This is one of the cases where it makes the code more readable and we
-- might even gain a bit performance.
local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode,skiphash)
@@ -2381,254 +2382,134 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode,s
startnext = getboth(start)
local done -- = false
- -- hm, contexts can also be nested
+ -- we can have multiple hits and as we scan (currently) all we need to check
+ -- if we have a match ... contextchains have no real coverage table (with
+ -- unique entries)
- for k=1,contexts.n do -- or #contexts do
+ -- fonts can have many steps (each doing one check) or many contexts
+
+ -- todo: make a per-char cache so that we have small contexts (when we have a context
+ -- n == 1 and otherwise it can be more so we can even distingish n == 1 or more)
+
+ local nofcontexts = contexts.n -- #contexts
+
+ local startchar = nofcontext == 1 or ischar(start,currentfont) -- only needed in a chain
+
+
+ for k=1,nofcontexts do
+
+ local ck = contexts[k]
+ local seq = ck[3]
+ local f = ck[4] -- first current
+ if not startchar or not seq[f][startchar] then
+ -- report("no hit in %a at %i of %i contexts",sequence.type,k,nofcontexts)
+ goto next
+ end
+ local s = seq.n -- or #seq
+ local l = ck[5] -- last current
local current = start
local last = start
- local ck = contexts[k]
- local seq = ck[3]
- -- local s = #seq
- local s = seq.n -- or #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
- goto next
- end
- else
- -- maybe we need a better space check (maybe check for glue or category or combination)
- 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 postreplace and not last 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
+
+ -- current match
+
+ 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 postreplace and not last 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)
+ elseif seq[n][char] then
+ if n < l then
last = getnext(last)
- elseif seq[n][char] then
- if n < l then
- last = getnext(last)
- end
- n = n + 1
- elseif discfound then
- notmatchreplace[discfound] = true
- if notmatchpre[discfound] then
- goto next
- else
- break
- end
- else
- goto next
end
- elseif char == false then
- if discfound then
- notmatchreplace[discfound] = true
- if notmatchpre[discfound] then
- goto next
- else
- break
- end
+ n = n + 1
+ elseif discfound then
+ notmatchreplace[discfound] = true
+ if notmatchpre[discfound] then
+ goto next
else
+ break
+ end
+ else
+ goto next
+ end
+ elseif char == false then
+ if discfound then
+ notmatchreplace[discfound] = true
+ if notmatchpre[discfound] then
goto next
+ else
+ break
end
- elseif id == disc_code then
- -- elseif id == disc_code and (not discs or discs[last]) 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
+ else
+ goto next
+ end
+ elseif id == disc_code then
+ -- elseif id == disc_code and (not discs or discs[last]) 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
- end
- if n <= l then
+ pre = getnext(pre)
+ else
notmatchpre[last] = true
+ break
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
- goto next
- else
- break
- end
- end
- end
- -- why here again
- if notmatchpre[last] then
- goto next
- end
+ if n <= l then
+ notmatchpre[last] = true
end
- -- maybe only if match
- last = getnext(last)
else
- goto next
+ notmatchpre[last] = true
end
- else
- goto next
- end
- end
- end
- -- before
- if f > 1 then
- if startprev then
- local prev = startprev
- if prereplace and prev == checkdisc 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)
- elseif seq[n][char] then
- if n > 1 then
- prev = getprev(prev)
- end
- n = n - 1
- elseif discfound then
- notmatchreplace[discfound] = true
- if notmatchpost[discfound] then
- goto next
- else
- break
- end
- else
- goto next
+ 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
- elseif char == false then
- if discfound then
- notmatchreplace[discfound] = true
- if notmatchpost[discfound] then
- goto next
- end
- else
+ replace = getnext(replace)
+ else
+ notmatchreplace[last] = true
+ if notmatchpre[last] then
goto next
- end
- break
- elseif id == disc_code then
- -- elseif id == disc_code and (not discs or discs[prev]) 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 or n < 1 then
- break
- else
- 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 or n < 1 then
- break
- else
- replacetail = getprev(replacetail)
- end
- else
- notmatchreplace[prev] = true
- if notmatchpost[prev] then
- goto next
- else
- break
- end
- end
- end
- end
- end
- prev = getprev(prev)
- -- elseif id == glue_code and seq[n][32] and isspace(prev,threshold,id) then
- -- elseif seq[n][32] and spaces[prev] 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
- goto next
+ break
end
- elseif seq[n][0xFFFC] then
- n = n - 1
- prev = getprev(prev)
- else
- goto next
end
- else
+ end
+ -- why here again
+ if notmatchpre[last] then
goto next
end
end
+ -- maybe only if match
+ last = getnext(last)
else
goto next
end
@@ -2636,33 +2517,37 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode,s
goto next
end
end
- -- after
- if s > l then
- local current = last and getnext(last)
- if not current and postreplace then
- current = getnext(sweepnode)
+ end
+
+ -- before
+
+ if f > 1 then
+ if startprev then
+ local prev = startprev
+ if prereplace and prev == checkdisc then
+ prev = getprev(sweepnode)
end
- if current then
+ if prev then
local discfound -- = nil
- local n = l + 1
- while n <= s do
- if current then
- local char, id = ischar(current,currentfont)
+ 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
- current = getnext(current) -- was absent
+ prev = getprev(prev)
elseif seq[n][char] then
- if n < s then -- new test
- current = getnext(current) -- was absent
+ if n > 1 then
+ prev = getprev(prev)
end
- n = n + 1
+ n = n - 1
elseif discfound then
notmatchreplace[discfound] = true
- if notmatchpre[discfound] then
+ if notmatchpost[discfound] then
goto next
else
break
@@ -2673,82 +2558,81 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode,s
elseif char == false then
if discfound then
notmatchreplace[discfound] = true
- if notmatchpre[discfound] then
+ if notmatchpost[discfound] then
goto next
- else
- break
end
else
goto next
end
+ break
elseif id == disc_code then
- -- elseif id == disc_code and (not discs or discs[current]) 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
+ -- elseif id == disc_code and (not discs or discs[prev]) 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 or n < 1 then
+ break
+ else
+ posttail = getprev(posttail)
+ end
else
- pre = getnext(pre)
+ notmatchpost[prev] = true
+ break
end
- else
- notmatchpre[current] = true
- break
end
+ if n >= 1 then
+ notmatchpost[prev] = true
+ end
+ else
+ notmatchpost[prev] = true
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
- else
- replace = getnext(replace)
- end
- else
- notmatchreplace[current] = true
- -- different than others, needs checking if "not" is okay
- if not notmatchpre[current] then
- goto next
+ 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 or n < 1 then
+ break
+ else
+ replacetail = getprev(replacetail)
+ end
else
- break
+ notmatchreplace[prev] = true
+ if notmatchpost[prev] then
+ goto next
+ else
+ break
+ end
end
end
end
- else
- -- skip 'm
end
- current = getnext(current)
- -- elseif id == glue_code and seq[n][32] and isspace(current,threshold,id) then
- -- elseif seq[n][32] and spaces[current] then
- -- n = n + 1
- -- current = getnext(current)
+ prev = getprev(prev)
+ -- elseif id == glue_code and seq[n][32] and isspace(prev,threshold,id) then
+ -- elseif seq[n][32] and spaces[prev] then
+ -- n = n - 1
+ -- prev = getprev(prev)
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)
+ if (sn[32] and spaces[prev]) or sn[0xFFFC] then
+ n = n - 1
+ prev = getprev(prev)
else
goto next
end
elseif seq[n][0xFFFC] then
- n = n + 1
- current = getnext(current)
+ n = n - 1
+ prev = getprev(prev)
else
goto next
end
@@ -2759,8 +2643,137 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode,s
else
goto next
end
+ else
+ goto next
+ end
+ end
+
+ -- after
+
+ if s > l then
+ local current = last and getnext(last)
+ if not current and postreplace then
+ current = getnext(sweepnode)
+ end
+ if current then
+ local discfound -- = nil
+ 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
+ elseif seq[n][char] then
+ if n < s then -- new test
+ current = getnext(current) -- was absent
+ end
+ n = n + 1
+ elseif discfound then
+ notmatchreplace[discfound] = true
+ if notmatchpre[discfound] then
+ goto next
+ else
+ break
+ end
+ else
+ goto next
+ end
+ elseif char == false then
+ if discfound then
+ notmatchreplace[discfound] = true
+ if notmatchpre[discfound] then
+ goto next
+ else
+ break
+ end
+ else
+ goto next
+ end
+ elseif id == disc_code then
+ -- elseif id == disc_code and (not discs or discs[current]) 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
+ else
+ pre = getnext(pre)
+ end
+ 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
+ else
+ replace = getnext(replace)
+ end
+ else
+ notmatchreplace[current] = true
+ -- different than others, needs checking if "not" is okay
+ if not notmatchpre[current] then
+ goto next
+ else
+ break
+ end
+ end
+ end
+ else
+ -- skip 'm
+ end
+ current = getnext(current)
+ -- elseif id == glue_code and seq[n][32] and isspace(current,threshold,id) then
+ -- elseif seq[n][32] and spaces[current] 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
+ goto next
+ end
+ elseif seq[n][0xFFFC] then
+ n = n + 1
+ current = getnext(current)
+ else
+ goto next
+ end
+ else
+ goto next
+ end
+ end
+ else
+ goto next
end
end
+
if trace_contexts then
chaintrac(head,start,dataset,sequence,rlmode,skipped and skiphash,ck,true)
end