summaryrefslogtreecommitdiff
path: root/tex/context/base/mkiv/font-ots.lua
diff options
context:
space:
mode:
authorHans Hagen <pragma@wxs.nl>2017-07-14 21:22:10 +0200
committerContext Git Mirror Bot <phg42.2a@gmail.com>2017-07-14 21:22:10 +0200
commit23b495f46b4d2e9264d54095f43774ef47d3a656 (patch)
tree1b0131b93d92d4aa7e15b55c50ad1dfa3573a7e1 /tex/context/base/mkiv/font-ots.lua
parent6ae40572e7643edcc29f8d5b071221dd1e04bdf3 (diff)
downloadcontext-23b495f46b4d2e9264d54095f43774ef47d3a656.tar.gz
2017-07-14 19:41:00
Diffstat (limited to 'tex/context/base/mkiv/font-ots.lua')
-rw-r--r--tex/context/base/mkiv/font-ots.lua1170
1 files changed, 821 insertions, 349 deletions
diff --git a/tex/context/base/mkiv/font-ots.lua b/tex/context/base/mkiv/font-ots.lua
index a5a039525..26659721f 100644
--- a/tex/context/base/mkiv/font-ots.lua
+++ b/tex/context/base/mkiv/font-ots.lua
@@ -148,7 +148,6 @@ local trace_compruns = false registertracker("otf.compruns", function
local trace_testruns = false registertracker("otf.testruns", function(v) trace_testruns = v end)
local forcediscretionaries = false
-local optimizekerns = true
directives.register("otf.forcediscretionaries",function(v)
forcediscretionaries = v
@@ -207,7 +206,7 @@ local flush_node_list = nuts.flush_list
local flush_node = nuts.flush_node
local end_of_math = nuts.end_of_math
local traverse_nodes = nuts.traverse
-local traverse_id = nuts.traverse_id
+----- traverse_id = nuts.traverse_id
local set_components = nuts.set_components
local take_components = nuts.take_components
local count_components = nuts.count_components
@@ -271,6 +270,8 @@ local factor = 0
local threshold = 0
local checkmarks = false
+local discs = false
+
local sweepnode = nil
local sweephead = { } -- we don't nil entries but false them (no collection and such)
@@ -305,47 +306,56 @@ local function logwarning(...)
report_direct(...)
end
-local f_unicode = formatters["U+%X"] -- was ["%U"]
-local f_uniname = formatters["U+%X (%s)"] -- was ["%U (%s)"]
-local f_unilist = formatters["% t (% t)"]
+local gref do
-local function gref(n) -- currently the same as in font-otb
- if type(n) == "number" then
- local description = descriptions[n]
- local name = description and description.name
- if name then
- return f_uniname(n,name)
- else
- return f_unicode(n)
- end
- elseif n then
- local num, nam = { }, { }
- for i=1,#n do
- local ni = n[i]
- if tonumber(ni) then -- later we will start at 2
- local di = descriptions[ni]
- num[i] = f_unicode(ni)
- nam[i] = di and di.name or "-"
+ local f_unicode = formatters["U+%X"] -- was ["%U"]
+ local f_uniname = formatters["U+%X (%s)"] -- was ["%U (%s)"]
+ local f_unilist = formatters["% t (% t)"]
+
+ gref = function(n) -- currently the same as in font-otb
+ if type(n) == "number" then
+ local description = descriptions[n]
+ local name = description and description.name
+ if name then
+ return f_uniname(n,name)
+ else
+ return f_unicode(n)
end
+ elseif n then
+ local num, nam = { }, { }
+ for i=1,#n do
+ local ni = n[i]
+ if tonumber(ni) then -- later we will start at 2
+ local di = descriptions[ni]
+ num[i] = f_unicode(ni)
+ nam[i] = di and di.name or "-"
+ end
+ end
+ return f_unilist(num,nam)
+ else
+ return "<error in node mode tracing>"
end
- return f_unilist(num,nam)
- else
- return "<error in node mode tracing>"
end
+
end
local function cref(dataset,sequence,index)
if not dataset then
return "no valid dataset"
- elseif index then
- return formatters["feature %a, type %a, chain lookup %a, index %a"](dataset[4],sequence.type,sequence.name,index)
+ end
+ local merged = sequence.merged and "merged " or ""
+ if index then
+ return formatters["feature %a, type %a, %schain lookup %a, index %a"](
+ dataset[4],sequence.type,merged,sequence.name,index)
else
- return formatters["feature %a, type %a, chain lookup %a"](dataset[4],sequence.type,sequence.name)
+ return formatters["feature %a, type %a, %schain lookup %a"](
+ dataset[4],sequence.type,merged,sequence.name)
end
end
local function pref(dataset,sequence)
- return formatters["feature %a, type %a, lookup %a"](dataset[4],sequence.type,sequence.name)
+ return formatters["feature %a, type %a, %slookup %a"](
+ dataset[4],sequence.type,sequence.merged and "merged " or "",sequence.name)
end
local function mref(rlmode)
@@ -689,7 +699,7 @@ function handlers.gsub_alternate(head,start,dataset,sequence,alternative)
setchar(start,choice)
else
if trace_alternatives then
- logwarning("%s: no variant %a for %s, %s",pref(dataset,sequence),value,gref(getchar(start)),comment)
+ logwarning("%s: no variant %a for %s, %s",pref(dataset,sequence),value,gref(getchar(start)),comment)
end
end
return head, start, true
@@ -850,36 +860,32 @@ function handlers.gpos_pair(head,start,dataset,sequence,kerns,rlmode,step,i,inje
if nextchar then
local krn = kerns[nextchar]
if not krn and marks[nextchar] then
+ -- hm, needs checking i guess
prev = snext
snext = getnext(snext)
elseif not krn then
break
elseif step.format == "pair" then
local a, b = krn[1], krn[2]
- if optimizekerns then
- -- this permits a mixed table, but we could also decide to optimize this
- -- in the loader and use format 'kern'
- if not b and a[1] == 0 and a[2] == 0 and a[4] == 0 then
- local k = setkern(snext,factor,rlmode,a[3],injection)
- if trace_kerns then
- logprocess("%s: shifting single %s by %p",pref(dataset,sequence),gref(nextchar),k)
- end
- return head, start, true
- end
- end
- if a and #a > 0 then
+ if a == true then
+ -- zero
+ elseif a then -- #a > 0
local x, y, w, h = setpair(start,factor,rlmode,sequence.flags[4],a,injection)
if trace_kerns then
local startchar = getchar(start)
logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p) as %s",pref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h,injection or "injections")
end
end
- if b and #b > 0 then
+ if b == true then
+ -- zero
+ start = snext -- cf spec
+ elseif b then -- #b > 0
local x, y, w, h = setpair(snext,factor,rlmode,sequence.flags[4],b,injection)
if trace_kerns then
local startchar = getchar(snext)
logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p) as %s",pref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h,injection or "injections")
end
+ start = snext -- cf spec
end
return head, start, true
elseif krn ~= 0 then
@@ -1073,8 +1079,7 @@ function handlers.gpos_cursive(head,start,dataset,sequence,exitanchors,rlmode,st
if not nextchar then
break
elseif marks[nextchar] then
- -- should not happen (maybe warning)
- nxt = getnext(nxt)
+ nxt = getnext(nxt)
else
local exit = exitanchors[3]
if exit then
@@ -1458,30 +1463,25 @@ function chainprocs.gpos_pair(head,start,stop,dataset,sequence,currentlookup,rlm
break
elseif step.format == "pair" then
local a, b = krn[1], krn[2]
- if optimizekerns then
- -- this permits a mixed table, but we could also decide to optimize this
- -- in the loader and use format 'kern'
- if not b and a[1] == 0 and a[2] == 0 and a[4] == 0 then
- local k = setkern(snext,factor,rlmode,a[3],"injections")
- if trace_kerns then
- logprocess("%s: shifting single %s by %p",cref(dataset,sequence),gref(startchar),k)
- end
- return head, start, true
- end
- end
- if a and #a > 0 then
- local startchar = getchar(start)
+ if a then
+ -- zero
+ elseif a then
local x, y, w, h = setpair(start,factor,rlmode,sequence.flags[4],a,"injections") -- currentlookups flags?
if trace_kerns then
+ local startchar = getchar(start)
logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h)
end
end
- if b and #b > 0 then
- local startchar = getchar(start)
+ if b == true then
+ -- zero
+ start = snext -- cf spec
+ elseif b then -- #b > 0
local x, y, w, h = setpair(snext,factor,rlmode,sequence.flags[4],b,"injections")
if trace_kerns then
+ local startchar = getchar(start)
logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h)
end
+ start = snext -- cf spec
end
return head, start, true
elseif krn ~= 0 then
@@ -1836,20 +1836,21 @@ local noflags = { false, false, false, false }
local function chainrun(head,start,last,dataset,sequence,rlmode,ck,skipped)
local size = ck[5] - ck[4] + 1
- local flags = sequence.flags or noflags
- local done = false
- local skipmark = flags[1]
local chainlookups = ck[6]
+ local done = false
-- current match
if chainlookups then
- local nofchainlookups = #chainlookups
+
-- Lookups can be like { 1, false, 3 } or { false, 2 } or basically anything and
-- #lookups can be less than #current
+
if size == 1 then
+
-- if nofchainlookups > size then
-- -- bad rules
-- end
+
local chainlookup = chainlookups[1]
for j=1,#chainlookup do
local chainstep = chainlookup[j]
@@ -1865,7 +1866,9 @@ local function chainrun(head,start,last,dataset,sequence,rlmode,ck,skipped)
logprocess("%s: %s is not yet supported (1)",cref(dataset,sequence),chainkind)
end
end
+
else
+
-- See LookupType 5: Contextual Substitution Subtable. Now it becomes messy. The
-- easiest case is where #current maps on #lookups i.e. one-to-one. But what if
-- we have a ligature. Cf the spec we then need to advance one character but we
@@ -1876,10 +1879,27 @@ local function chainrun(head,start,last,dataset,sequence,rlmode,ck,skipped)
--
-- Even worse are these family emoji shapes as they can have multiple lookups
-- per slot (probably only for gpos).
+
+ -- It's very unlikely that we will have skip classes here but still ... we seldom
+ -- enter this branch anyway.
+
+ local skipmark
+ local skipligature
+ local skipbase
+ local markclass
+ if skipped then
+ local flags = sequence.flags or noflags
+ skipmark = flags[1]
+ skipligature = flags[2]
+ skipbase = flags[3]
+ markclass = sequence.markclass
+ end
+
local i = 1
local laststart = start
+ local nofchainlookups = #chainlookups -- useful?
while start do
- if skipped then
+ if skipped then -- hm, so we know we skip some
while start do
local char, id = ischar(start,currentfont)
if char then
@@ -1932,6 +1952,7 @@ local function chainrun(head,start,last,dataset,sequence,rlmode,ck,skipped)
if not start then
start = laststart
end
+
end
else
-- todo: needs checking for holes in the replacements
@@ -2762,11 +2783,12 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode)
local checkdisc = sweeptype and getprev(head)
local flags = sequence.flags or noflags
local done = false
+ local markclass = sequence.markclass
local skipmark = flags[1]
local skipligature = flags[2]
local skipbase = flags[3]
- local markclass = sequence.markclass
- local skipsome = skipmark ~= false or skipligature ~= false or skipbase ~= false or markclass
+ -- local skipsome = skipmark ~= false or skipligature ~= false or skipbase ~= false or markclass
+ local skipsome = flags[5]
local skipped = false
local startprev,
startnext = getboth(start)
@@ -2778,7 +2800,6 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode)
local ck = contexts[k]
local seq = ck[3]
local s = #seq
- local size = 1
-- f..l = mid string
if s == 1 then
-- this seldom happens as it makes no sense (bril, ebgaramond, husayni, minion)
@@ -2793,12 +2814,10 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode)
local l = ck[5]
-- current match
-- seq[f][ischar(current,currentfont)] is not nil
- size = l - f + 1
- if size > 1 then
+ if l > f then
-- before/current/after | before/current | current/after
local discfound -- = nil
local n = f + 1
- -- last = getnext(last) -- the second in current (first already matched)
last = startnext -- the second in current (first already matched)
while n <= l do
if not last and (sweeptype == "post" or sweeptype == "replace") then
@@ -2923,13 +2942,10 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode)
end
-- before
if match and f > 1 then
- -- local prev = getprev(start)
- -- if prev then
if startprev then
local prev = startprev
if prev == checkdisc and (sweeptype == "pre" or sweeptype == "replace") then
- prev = getprev(sweepnode)
- -- sweeptype = nil
+ prev = getprev(sweepnode)
end
if prev then
local discfound -- = nil
@@ -3074,8 +3090,7 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode)
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)
- -- sweeptype = nil
+ current = getnext(sweepnode)
end
if current then
local discfound -- = nil
@@ -3232,6 +3247,503 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode)
return head, start, done
end
+-- only a bit faster but probably also a bit cleaner ... so ...
+
+local function optimized_handle_contextchain(head,start,dataset,sequence,contexts,rlmode)
+ -- optimizing for rlmode gains nothing
+ local sweepnode = sweepnode
+ local sweeptype = sweeptype
+ local postreplace
+ local prereplace
+ local checkdisc
+ local diskseen -- = false
+ if sweeptype then
+ if sweeptype == "replace" then
+ postreplace = true
+ prereplace = true
+ else
+ postreplace = sweeptype == "post"
+ prereplace = sweeptype == "pre"
+ end
+ checkdisc = getprev(head)
+ end
+ local currentfont = currentfont
+ local flags = sequence.flags or noflags
+ local skipsome = flags[5]
+ local skipmark
+ local skipligature
+ local skipbase
+ local markclass
+ if skipsome then
+ skipmark = flags[1]
+ skipligature = flags[2]
+ skipbase = flags[3]
+ markclass = sequence.markclass
+ end
+ local skipped -- = false
+ local startprev,
+ startnext = getboth(start)
+ local done -- = false
+
+ for k=1,contexts.n do -- or #contexts do
+ 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 not last and postreplace then
+ last = getnext(sweepnode)
+ sweeptype = nil
+ end
+ if last then
+ local char, id = ischar(last,currentfont)
+ if char then
+ if skipsome then
+ local class = classes[char]
+ -- if class == skipmark or class == skipligature or class == skipbase or (markclass and class == "mark" and not markclass[char]) then
+ if class == skipmark or (markclass and class == "mark" and not markclass[char]) or class == skipligature or class == skipbase then
+ skipped = true
+ if trace_skips then
+ show_skip(dataset,sequence,char,ck,class)
+ end
+ last = getnext(last)
+ elseif 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
+ goto next
+ end
+ else
+ goto next
+ end
+ break
+ end
+ 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
+ goto next
+ end
+ else
+ goto next
+ end
+ break
+ end
+ end
+ elseif char == false then
+ if discfound then
+ notmatchreplace[discfound] = true
+ if notmatchpre[discfound] then
+ goto next
+ end
+ else
+ goto next
+ end
+ break
+ 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
+ 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
+ goto next
+ end
+ break
+ end
+ end
+ -- why here again
+ if notmatchpre[last] then
+ goto next
+ end
+ end
+ -- maybe only if match
+ last = getnext(last)
+ else
+ goto next
+ 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 skipsome then
+ local class = classes[char]
+ -- if class == skipmark or class == skipligature or class == skipbase or (markclass and class == "mark" and not markclass[char]) then
+ if class == skipmark or (markclass and class == "mark" and not markclass[char]) or class == skipligature or class == skipbase then
+ skipped = true
+ if trace_skips then
+ show_skip(dataset,sequence,char,ck,class)
+ end
+ prev = getprev(prev)
+ elseif 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
+ goto next
+ end
+ else
+ goto next
+ end
+ break
+ end
+ 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
+ goto next
+ end
+ else
+ goto next
+ end
+ break
+ end
+ end
+ elseif char == false then
+ if discfound then
+ notmatchreplace[discfound] = true
+ if notmatchpost[discfound] then
+ goto next
+ end
+ else
+ 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 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
+ goto next
+ end
+ break
+ end
+ end
+ end
+ end
+ prev = getprev(prev)
+ elseif id == glue_code and seq[n][32] and isspace(prev,threshold,id) then
+ n = n - 1
+ prev = getprev(prev)
+ else
+ goto next
+ end
+ else
+ goto next
+ end
+ end
+ 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 skipsome then
+ local class = classes[char]
+ -- if class == skipmark or class == skipligature or class == skipbase or (markclass and class == "mark" and not markclass[char]) then
+ if class == skipmark or (markclass and class == "mark" and not markclass[char]) or class == skipligature or class == skipbase then
+ skipped = true
+ if trace_skips then
+ show_skip(dataset,sequence,char,ck,class)
+ 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
+ else
+ if discfound then
+ notmatchreplace[discfound] = true
+ if notmatchpre[discfound] then
+ goto next
+ end
+ else
+ goto next
+ end
+ break
+ end
+ 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
+ goto next
+ end
+ else
+ goto next
+ end
+ break
+ end
+ end
+ elseif char == false then
+ if discfound then
+ notmatchreplace[discfound] = true
+ if notmatchpre[discfound] then
+ goto next
+ 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
+ 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
+ goto next
+ end
+ break
+ end
+ 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)
+ else
+ goto next
+ end
+ else
+ goto next
+ end
+ end
+ else
+ goto next
+ end
+ end
+ end
+ if trace_contexts then
+ chaintrac(head,start,dataset,sequence,rlmode,ck,skipped,true)
+ end
+ if diskseen or sweepnode then
+ head, start, done = chaindisk(head,start,dataset,sequence,rlmode,ck,skipped)
+ else
+ head, start, done = chainrun(head,start,last,dataset,sequence,rlmode,ck,skipped)
+ end
+ if done then
+ break
+ -- else
+ -- next context
+ end
+ ::next::
+ -- if trace_chains then
+ -- chaintrac(head,start,dataset,sequence,rlmode,ck,skipped,match)
+ -- end
+ end
+ if diskseen then
+ notmatchpre = { }
+ notmatchpost = { }
+ notmatchreplace = { }
+ end
+ return head, start, done
+end
+
+directives.register("otf.optimizechains",function(v)
+ if v then
+ report_chain()
+ report_chain("using experimental optimized code")
+ report_chain()
+ end
+ local handle = v and optimized_handle_contextchain or handle_contextchain
+ handlers.gsub_context = handle
+ handlers.gsub_contextchain = handle
+ handlers.gsub_reversecontextchain = handle
+ handlers.gpos_contextchain = handle
+ handlers.gpos_context = handle
+end)
+
------------------------------
handlers.gsub_context = handle_contextchain
@@ -3275,7 +3787,9 @@ chainprocs.gpos_context = chained_contextchain
-- end
-- end
-local missing = setmetatableindex("table")
+local missing = setmetatableindex("table")
+local logwarning = report_process
+local resolved = { } -- we only resolve a font,script,language pair once
local function logprocess(...)
if trace_steps then
@@ -3284,19 +3798,6 @@ local function logprocess(...)
report_process(...)
end
-local logwarning = report_process
-
-local function report_missing_coverage(dataset,sequence)
- local t = missing[currentfont]
- if not t[sequence] then
- t[sequence] = true
- logwarning("missing coverage for feature %a, lookup %a, type %a, font %a, name %a",
- dataset[4],sequence.name,sequence.type,currentfont,tfmdata.properties.fullname)
- end
-end
-
-local resolved = { } -- we only resolve a font,script,language pair once
-
-- todo: pass all these 'locals' in a table
local sequencelists = setmetatableindex(function(t,font)
@@ -3582,12 +4083,11 @@ local function testrun(disc,t_run,c_run,...)
end
local d_post = t_run(post,next,...)
local d_replace = t_run(replace,next,...)
- if (d_post and d_post > 0) or (d_replace and d_replace > 0) then
- local d = d_replace or d_post
- if d_post and d < d_post then
- d = d_post
- end
- local head, tail = getnext(disc), disc
+ if d_post > 0 or d_replace > 0 then
+ local d = d_replace > d_post and d_replace or d_post
+ local head = getnext(disc)
+ -- local tail = disc -- bug
+ local tail = head
for i=1,d do
tail = getnext(tail)
if getid(tail) == disc_code then
@@ -3696,7 +4196,6 @@ end
-- 1{2{\oldstyle\discretionary{3}{4}{5}}6}7\par
-- 1{2\discretionary{3{\oldstyle3}}{{\oldstyle4}4}{5{\oldstyle5}5}6}7\par
-
local nesting = 0
local function c_run_single(head,font,attr,lookupcache,step,dataset,sequence,rlmode,handler)
@@ -3818,6 +4317,7 @@ local function t_run_single(start,stop,font,attr,lookupcache)
break
end
end
+ return 0
end
local function k_run_single(sub,injection,last,font,attr,lookupcache,step,dataset,sequence,rlmode,handler)
@@ -3865,22 +4365,18 @@ local function c_run_multiple(head,font,attr,steps,nofsteps,dataset,sequence,rlm
for i=1,nofsteps do
local step = steps[i]
local lookupcache = step.coverage
- if lookupcache then
- local lookupmatch = lookupcache[char]
- if lookupmatch then
- -- we could move all code inline but that makes things even more unreadable
- local ok
- head, start, ok = handler(head,start,dataset,sequence,lookupmatch,rlmode,step,i)
- if ok then
- done = true
- break
- elseif not start then
- -- don't ask why ... shouldn't happen
- break
- end
+ local lookupmatch = lookupcache[char]
+ if lookupmatch then
+ -- we could move all code inline but that makes things even more unreadable
+ local ok
+ head, start, ok = handler(head,start,dataset,sequence,lookupmatch,rlmode,step,i)
+ if ok then
+ done = true
+ break
+ elseif not start then
+ -- don't ask why ... shouldn't happen
+ break
end
- else
- report_missing_coverage(dataset,sequence)
end
end
if start then
@@ -3918,60 +4414,56 @@ local function t_run_multiple(start,stop,font,attr,steps,nofsteps)
for i=1,nofsteps do
local step = steps[i]
local lookupcache = step.coverage
- if lookupcache then
- local lookupmatch = lookupcache[char]
- if lookupmatch then
- -- if we need more than ligatures we can outline the code and use functions
- local s = startnext
- local ss = nil
- local sstop = s == stop
+ local lookupmatch = lookupcache[char]
+ if lookupmatch then
+ -- if we need more than ligatures we can outline the code and use functions
+ local s = startnext
+ local ss = nil
+ local sstop = s == stop
+ if not s then
+ s = ss
+ ss = nil
+ end
+ while getid(s) == disc_code do
+ ss = getnext(s)
+ s = getfield(s,"replace")
if not s then
s = ss
ss = nil
end
- while getid(s) == disc_code do
- ss = getnext(s)
- s = getfield(s,"replace")
+ end
+ local l = nil
+ local d = 0
+ while s do
+ local lg = lookupmatch[getchar(s)]
+ if lg then
+ if sstop then
+ d = 1
+ elseif d > 0 then
+ d = d + 1
+ end
+ l = lg
+ s = getnext(s)
+ sstop = s == stop
if not s then
s = ss
ss = nil
end
- end
- local l = nil
- local d = 0
- while s do
- local lg = lookupmatch[getchar(s)]
- if lg then
- if sstop then
- d = 1
- elseif d > 0 then
- d = d + 1
- end
- l = lg
- s = getnext(s)
- sstop = s == stop
+ while getid(s) == disc_code do
+ ss = getnext(s)
+ s = getfield(s,"replace")
if not s then
s = ss
ss = nil
end
- while getid(s) == disc_code do
- ss = getnext(s)
- s = getfield(s,"replace")
- if not s then
- s = ss
- ss = nil
- end
- end
- else
- break
end
- end
- if l and l.ligature then
- lastd = d
+ else
+ break
end
end
- else
- report_missing_coverage(dataset,sequence)
+ if l and l.ligature then
+ lastd = d
+ end
end
end
else
@@ -3985,6 +4477,7 @@ local function t_run_multiple(start,stop,font,attr,steps,nofsteps)
break
end
end
+ return 0
end
local function k_run_multiple(sub,injection,last,font,attr,steps,nofsteps,dataset,sequence,rlmode,handler)
@@ -4002,16 +4495,12 @@ local function k_run_multiple(sub,injection,last,font,attr,steps,nofsteps,datase
for i=1,nofsteps do
local step = steps[i]
local lookupcache = step.coverage
- if lookupcache then
- local lookupmatch = lookupcache[char]
- if lookupmatch then
- local h, d, ok = handler(head,n,dataset,sequence,lookupmatch,rlmode,step,i,injection)
- if ok then
- return true
- end
+ local lookupmatch = lookupcache[char]
+ if lookupmatch then
+ local h, d, ok = handler(head,n,dataset,sequence,lookupmatch,rlmode,step,i,injection)
+ if ok then
+ return true
end
- else
- report_missing_coverage(dataset,sequence)
end
end
end
@@ -4074,6 +4563,26 @@ otf.helpers.pardirstate = pardirstate
do
+ -- reference:
+ --
+ -- local a = attr and getattr(start,0)
+ -- if a then
+ -- a = (a == attr) and (not attribute or getprop(start,a_state) == attribute)
+ -- else
+ -- a = not attribute or getprop(start,a_state) == attribute
+ -- end
+ --
+ -- used:
+ --
+ -- local a -- happens often so no assignment is faster
+ -- if attr then
+ -- if getattr(start,0) == attr and (not attribute or getprop(start,a_state) == attribute) then
+ -- a = true
+ -- end
+ -- elseif not attribute or getprop(start,a_state) == attribute then
+ -- a = true
+ -- end
+
-- This is a measurable experimental speedup (only with hyphenated text and multiple
-- fonts per processor call), especially for fonts with lots of contextual lookups.
@@ -4184,19 +4693,15 @@ do
-- for i=1,nofsteps do
-- local step = steps[i]
-- local lookupcache = step.coverage
- -- if lookupcache then
- -- local lookupmatch = lookupcache[char]
- -- if lookupmatch then
- -- -- todo: disc?
- -- local ok
- -- head, start, ok = handler(head,start,dataset,sequence,lookupmatch,rlmode,step,i)
- -- if ok then
- -- done = true
- -- break
- -- end
+ -- local lookupmatch = lookupcache[char]
+ -- if lookupmatch then
+ -- -- todo: disc?
+ -- local ok
+ -- head, start, ok = handler(head,start,dataset,sequence,lookupmatch,rlmode,step,i)
+ -- if ok then
+ -- done = true
+ -- break
-- end
- -- else
- -- report_missing_coverage(dataset,sequence)
-- end
-- end
-- if start then
@@ -4215,72 +4720,62 @@ do
-- if nofsteps == 1 then -- happens often
-- local step = steps[1]
-- local lookupcache = step.coverage
- -- if not lookupcache then
- -- report_missing_coverage(dataset,sequence)
- -- else
- -- while start do
- -- local char, id = ischar(start,font)
- -- if char then
- -- -- local a = attr and getattr(start,0)
- -- -- if a then
- -- -- a = (a == attr) and (not attribute or getprop(start,a_state) == attribute)
- -- -- else
- -- -- a = not attribute or getprop(start,a_state) == attribute
- -- -- end
- -- local a -- happens often so no assignment is faster
- -- if attr then
- -- if getattr(start,0) == attr and (not attribute or getprop(start,a_state) == attribute) then
- -- a = true
- -- end
- -- elseif not attribute or getprop(start,a_state) == attribute then
+ -- while start do
+ -- local char, id = ischar(start,font)
+ -- if char then
+ -- local a -- happens often so no assignment is faster
+ -- if attr then
+ -- if getattr(start,0) == attr and (not attribute or getprop(start,a_state) == attribute) then
-- a = true
-- end
- -- if a then
- -- local lookupmatch = lookupcache[char]
- -- if lookupmatch then
- -- local ok
- -- head, start, ok = handler(head,start,dataset,sequence,lookupmatch,rlmode,step,1)
- -- if ok then
- -- done = true
- -- end
- -- end
- -- if start then
- -- start = getnext(start)
- -- end
- -- else
- -- start = getnext(start)
- -- end
- -- elseif char == false then
- -- -- whatever glyph
- -- start = getnext(start)
- -- elseif id == glue_code then
- -- -- happens often
- -- start = getnext(start)
- -- elseif id == disc_code then
- -- if not discs or discs[start] == true then
+ -- elseif not attribute or getprop(start,a_state) == attribute then
+ -- a = true
+ -- end
+ -- if a then
+ -- local lookupmatch = lookupcache[char]
+ -- if lookupmatch then
-- local ok
- -- if gpossing then
- -- start, ok = kernrun(start,k_run_single, font,attr,lookupcache,step,dataset,sequence,rlmode,handler)
- -- elseif typ == "gsub_ligature" then
- -- start, ok = testrun(start,t_run_single,c_run_single,font,attr,lookupcache,step,dataset,sequence,rlmode,handler)
- -- else
- -- start, ok = comprun(start,c_run_single, font,attr,lookupcache,step,dataset,sequence,rlmode,handler)
- -- end
+ -- head, start, ok = handler(head,start,dataset,sequence,lookupmatch,rlmode,step,1)
-- if ok then
-- done = true
-- end
- -- else
+ -- end
+ -- if start then
-- start = getnext(start)
-- end
- -- elseif id == math_code then
- -- start = getnext(end_of_math(start))
- -- elseif id == dir_code then
- -- start, topstack, rlmode = txtdirstate(start,dirstack,topstack,rlparmode)
- -- elseif id == localpar_code then
- -- start, rlparmode, rlmode = pardirstate(start)
+ -- else
+ -- start = getnext(start)
+ -- end
+ -- elseif char == false then
+ -- -- whatever glyph
+ -- start = getnext(start)
+ -- elseif id == glue_code then
+ -- -- happens often
+ -- start = getnext(start)
+ -- elseif id == disc_code then
+ -- if not discs or discs[start] == true then
+ -- local ok
+ -- if gpossing then
+ -- start, ok = kernrun(start,k_run_single, font,attr,lookupcache,step,dataset,sequence,rlmode,handler)
+ -- elseif typ == "gsub_ligature" then
+ -- start, ok = testrun(start,t_run_single,c_run_single,font,attr,lookupcache,step,dataset,sequence,rlmode,handler)
+ -- else
+ -- start, ok = comprun(start,c_run_single, font,attr,lookupcache,step,dataset,sequence,rlmode,handler)
+ -- end
+ -- if ok then
+ -- done = true
+ -- end
-- else
-- start = getnext(start)
-- end
+ -- elseif id == math_code then
+ -- start = getnext(end_of_math(start))
+ -- elseif id == dir_code then
+ -- start, topstack, rlmode = txtdirstate(start,dirstack,topstack,rlparmode)
+ -- elseif id == localpar_code then
+ -- start, rlparmode, rlmode = pardirstate(start)
+ -- else
+ -- start = getnext(start)
-- end
-- end
--
@@ -4288,12 +4783,6 @@ do
-- while start do
-- local char, id = ischar(start,font)
-- if char then
- -- -- local a = attr and getattr(start,0)
- -- -- if a then
- -- -- a = (a == attr) and (not attribute or getprop(start,a_state) == attribute)
- -- -- else
- -- -- a = not attribute or getprop(start,a_state) == attribute
- -- -- end
-- local a -- happens often so no assignment is faster
-- if attr then
-- if getattr(start,0) == attr and (not attribute or getprop(start,a_state) == attribute) then
@@ -4306,22 +4795,18 @@ do
-- for i=1,nofsteps do
-- local step = steps[i]
-- local lookupcache = step.coverage
- -- if lookupcache then
- -- local lookupmatch = lookupcache[char]
- -- if lookupmatch then
- -- -- we could move all code inline but that makes things even more unreadable
- -- local ok
- -- head, start, ok = handler(head,start,dataset,sequence,lookupmatch,rlmode,step,i)
- -- if ok then
- -- done = true
- -- break
- -- elseif not start then
- -- -- don't ask why ... shouldn't happen
- -- break
- -- end
+ -- local lookupmatch = lookupcache[char]
+ -- if lookupmatch then
+ -- -- we could move all code inline but that makes things even more unreadable
+ -- local ok
+ -- head, start, ok = handler(head,start,dataset,sequence,lookupmatch,rlmode,step,i)
+ -- if ok then
+ -- done = true
+ -- break
+ -- elseif not start then
+ -- -- don't ask why ... shouldn't happen
+ -- break
-- end
- -- else
- -- report_missing_coverage(dataset,sequence)
-- end
-- end
-- if start then
@@ -4381,6 +4866,14 @@ do
-- about 15% on arabtype .. then moving the a test also saves a bit (even when
-- often a is not set at all so that one is a bit debatable
+ local otfdataset = nil -- todo: make an installer
+
+ local getfastdics = function(t,k)
+ local v = usesfont(k,currentfont)
+ t[k] = v
+ return v
+ end
+
function otf.featuresprocessor(head,font,attr,direction,n)
local sequences = sequencelists[font] -- temp hack
@@ -4403,6 +4896,12 @@ do
factor = getthreshold(font)
checkmarks = tfmdata.properties.checkmarks
+ if not otfdataset then
+ otfdataset = otf.dataset
+ end
+
+ discs = fastdisc and n and n > 1 and setmetatableindex(getfastdisc) -- maybe inline
+
elseif currentfont ~= font then
report_warning("nested call with a different font, level %s, quitting",nesting)
@@ -4419,7 +4918,7 @@ do
-- attr = false
-- end
- head = tonut(head)
+ local head = tonut(head)
if trace_steps then
checkstep(head)
@@ -4428,7 +4927,8 @@ do
local initialrl = direction == "TRT" and -1 or 0
local done = false
- local datasets = otf.dataset(tfmdata,font,attr)
+ -- local datasets = otf.dataset(tfmdata,font,attr)
+ local datasets = otfdataset(tfmdata,font,attr)
local dirstack = { } -- could move outside function but we can have local runs
sweephead = { }
@@ -4438,12 +4938,6 @@ do
-- We don't goto the next node when a disc node is created so that we can then treat
-- the pre, post and replace. It's a bit of a hack but works out ok for most cases.
- local discs = fastdisc and n and n > 1 and setmetatableindex(function(t,k)
- local v = usesfont(k,font)
- t[k] = v
- return v
- end)
-
for s=1,#datasets do
local dataset = datasets[s]
----- featurevalue = dataset[1] -- todo: pass to function instead of using a global
@@ -4453,7 +4947,7 @@ do
local topstack = 0
local typ = sequence.type
local gpossing = typ == "gpos_single" or typ == "gpos_pair" -- store in dataset
- local handler = handlers[typ]
+ local handler = handlers[typ] -- store in dataset
local steps = sequence.steps
local nofsteps = sequence.nofsteps
if not steps then
@@ -4489,19 +4983,15 @@ do
-- for i=1,#m do
-- local step = m[i]
local lookupcache = step.coverage
- if lookupcache then
- local lookupmatch = lookupcache[char]
- if lookupmatch then
- -- todo: disc?
- local ok
- head, start, ok = handler(head,start,dataset,sequence,lookupmatch,rlmode,step,i)
- if ok then
- done = true
- break
- end
+ local lookupmatch = lookupcache[char]
+ if lookupmatch then
+ -- todo: disc?
+ local ok
+ head, start, ok = handler(head,start,dataset,sequence,lookupmatch,rlmode,step,i)
+ if ok then
+ done = true
+ break
end
- else
- report_missing_coverage(dataset,sequence)
end
end
if start then
@@ -4523,74 +5013,64 @@ do
if nofsteps == 1 then -- happens often
local step = steps[1]
local lookupcache = step.coverage
- if not lookupcache then
- report_missing_coverage(dataset,sequence)
- else
- while start do
- local char, id = ischar(start,font)
- if char then
- local lookupmatch = lookupcache[char]
- if lookupmatch then
- -- local a = attr and getattr(start,0)
- -- if a then
- -- a = (a == attr) and (not attribute or getprop(start,a_state) == attribute)
- -- else
- -- a = not attribute or getprop(start,a_state) == attribute
- -- end
- local a -- happens often so no assignment is faster
- if attr then
- if getattr(start,0) == attr and (not attribute or getprop(start,a_state) == attribute) then
- a = true
- end
- elseif not attribute or getprop(start,a_state) == attribute then
+ while start do
+ local char, id = ischar(start,font)
+ if char then
+ local lookupmatch = lookupcache[char]
+ if lookupmatch then
+ local a -- happens often so no assignment is faster
+ if attr then
+ if getattr(start,0) == attr and (not attribute or getprop(start,a_state) == attribute) then
a = true
end
- if a then
- local ok
- head, start, ok = handler(head,start,dataset,sequence,lookupmatch,rlmode,step,1)
- if ok then
- done = true
- end
- if start then
- start = getnext(start)
- end
- else
- start = getnext(start)
- end
- else
- start = getnext(start)
+ elseif not attribute or getprop(start,a_state) == attribute then
+ a = true
end
- elseif char == false then
- -- whatever glyph
- start = getnext(start)
- elseif id == glue_code then
- -- happens often
- start = getnext(start)
- elseif id == disc_code then
- if not discs or discs[start] == true then
+ if a then
local ok
- if gpossing then
- start, ok = kernrun(start,k_run_single, font,attr,lookupcache,step,dataset,sequence,rlmode,handler)
- elseif typ == "gsub_ligature" then
- start, ok = testrun(start,t_run_single,c_run_single,font,attr,lookupcache,step,dataset,sequence,rlmode,handler)
- else
- start, ok = comprun(start,c_run_single, font,attr,lookupcache,step,dataset,sequence,rlmode,handler)
- end
+ head, start, ok = handler(head,start,dataset,sequence,lookupmatch,rlmode,step,1)
if ok then
done = true
end
+ if start then
+ start = getnext(start)
+ end
else
start = getnext(start)
end
- elseif id == math_code then
- start = getnext(end_of_math(start))
- elseif id == dir_code then
- start, topstack, rlmode = txtdirstate(start,dirstack,topstack,rlparmode)
- elseif id == localpar_code then
- start, rlparmode, rlmode = pardirstate(start)
+ else
+ start = getnext(start)
+ end
+ elseif char == false then
+ -- whatever glyph
+ start = getnext(start)
+ elseif id == glue_code then
+ -- happens often
+ start = getnext(start)
+ elseif id == disc_code then
+ if not discs or discs[start] == true then
+ local ok
+ if gpossing then
+ start, ok = kernrun(start,k_run_single, font,attr,lookupcache,step,dataset,sequence,rlmode,handler)
+ elseif typ == "gsub_ligature" then
+ start, ok = testrun(start,t_run_single,c_run_single,font,attr,lookupcache,step,dataset,sequence,rlmode,handler)
+ else
+ start, ok = comprun(start,c_run_single, font,attr,lookupcache,step,dataset,sequence,rlmode,handler)
+ end
+ if ok then
+ done = true
+ end
else
start = getnext(start)
end
+ elseif id == math_code then
+ start = getnext(end_of_math(start))
+ elseif id == dir_code then
+ start, topstack, rlmode = txtdirstate(start,dirstack,topstack,rlparmode)
+ elseif id == localpar_code then
+ start, rlparmode, rlmode = pardirstate(start)
+ else
+ start = getnext(start)
end
end
else
@@ -4600,12 +5080,6 @@ do
if char then
local m = merged[char]
if m then
- -- local a = attr and getattr(start,0)
- -- if a then
- -- a = (a == attr) and (not attribute or getprop(start,a_state) == attribute)
- -- else
- -- a = not attribute or getprop(start,a_state) == attribute
- -- end
local a -- happens often so no assignment is faster
if attr then
if getattr(start,0) == attr and (not attribute or getprop(start,a_state) == attribute) then
@@ -4620,22 +5094,18 @@ do
-- for i=1,#m do
-- local step = m[i]
local lookupcache = step.coverage
- if lookupcache then
- local lookupmatch = lookupcache[char]
- if lookupmatch then
- -- we could move all code inline but that makes things even more unreadable
- local ok
- head, start, ok = handler(head,start,dataset,sequence,lookupmatch,rlmode,step,i)
- if ok then
- done = true
- break
- elseif not start then
- -- don't ask why ... shouldn't happen
- break
- end
+ local lookupmatch = lookupcache[char]
+ if lookupmatch then
+ -- we could move all code inline but that makes things even more unreadable
+ local ok
+ head, start, ok = handler(head,start,dataset,sequence,lookupmatch,rlmode,step,i)
+ if ok then
+ done = true
+ break
+ elseif not start then
+ -- don't ask why ... shouldn't happen
+ break
end
- else
- report_missing_coverage(dataset,sequence)
end
end
if start then
@@ -4787,7 +5257,7 @@ local function hasspacekerns(data)
for i=1,#steps do
local coverage = steps[i].coverage
if not coverage then
- -- maybe an issue
+ -- maybe an issue, can't happen
elseif coverage[32] then
return true
else
@@ -4852,7 +5322,7 @@ local function spaceinitializer(tfmdata,value) -- attr
-- not now: analyze (simple) rules
elseif coverage then
-- what to do if we have no [1] but only [2]
- local single = format == gpos_single
+ local single = format == "gpos_single"
local kerns = coverage[32]
if kerns then
for k, v in next, kerns do
@@ -4877,12 +5347,14 @@ local function spaceinitializer(tfmdata,value) -- attr
left[k] = kern[3]
else
local one = kern[1]
- if one then
+ if one and one ~= true then
left[k] = one[3]
end
end
end
end
+ else
+ -- can't happen
end
end
last = i