summaryrefslogtreecommitdiff
path: root/tex
diff options
context:
space:
mode:
Diffstat (limited to 'tex')
-rw-r--r--tex/context/base/cont-new.mkiv2
-rw-r--r--tex/context/base/context-version.pdfbin4205 -> 4181 bytes
-rw-r--r--tex/context/base/context.mkiv2
-rw-r--r--tex/context/base/font-dsp.lua6
-rw-r--r--tex/context/base/font-otd.lua2
-rw-r--r--tex/context/base/font-otn.lua1404
-rw-r--r--tex/context/base/font-ots.lua1243
-rw-r--r--tex/context/base/lang-dis.lua152
-rw-r--r--tex/context/base/m-newotf.mkiv2
-rw-r--r--tex/context/base/node-nut.lua103
-rw-r--r--tex/context/base/status-files.pdfbin24455 -> 24498 bytes
-rw-r--r--tex/context/base/status-lua.pdfbin255169 -> 255952 bytes
-rw-r--r--tex/context/base/util-fil.lua4
-rw-r--r--tex/generic/context/luatex/luatex-fonts-inj.lua291
-rw-r--r--tex/generic/context/luatex/luatex-fonts-merged.lua1234
-rw-r--r--tex/generic/context/luatex/luatex-fonts-otn.lua1225
-rw-r--r--tex/generic/context/luatex/luatex-fonts.lua2
17 files changed, 4159 insertions, 1513 deletions
diff --git a/tex/context/base/cont-new.mkiv b/tex/context/base/cont-new.mkiv
index 86f9d7473..fb713cf57 100644
--- a/tex/context/base/cont-new.mkiv
+++ b/tex/context/base/cont-new.mkiv
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\newcontextversion{2015.08.30 23:03}
+\newcontextversion{2015.09.01 11:10}
%D This file is loaded at runtime, thereby providing an excellent place for
%D hacks, patches, extensions and new features.
diff --git a/tex/context/base/context-version.pdf b/tex/context/base/context-version.pdf
index 6625867b0..b2d52084f 100644
--- a/tex/context/base/context-version.pdf
+++ b/tex/context/base/context-version.pdf
Binary files differ
diff --git a/tex/context/base/context.mkiv b/tex/context/base/context.mkiv
index f013626e6..31e02d6e5 100644
--- a/tex/context/base/context.mkiv
+++ b/tex/context/base/context.mkiv
@@ -39,7 +39,7 @@
%D up and the dependencies are more consistent.
\edef\contextformat {\jobname}
-\edef\contextversion{2015.08.30 23:03}
+\edef\contextversion{2015.09.01 11:10}
\edef\contextkind {beta}
%D For those who want to use this:
diff --git a/tex/context/base/font-dsp.lua b/tex/context/base/font-dsp.lua
index a1a89dd3b..8cdd645c8 100644
--- a/tex/context/base/font-dsp.lua
+++ b/tex/context/base/font-dsp.lua
@@ -1419,7 +1419,7 @@ do
end
lookups[lookupid] = {
type = lookuptype,
- chain = chaindirections[lookuptype] or nil,
+ -- chain = chaindirections[lookuptype] or nil,
flags = lookupflags,
name = lookupid,
subtables = subtables,
@@ -1475,6 +1475,7 @@ do
local nofsubtables = #subtables
local order = lookup.order
local flags = lookup.flags
+ -- local chain = lookup.chain
local markclass = lookup.markclass
if nofsubtables > 0 then
local steps = { }
@@ -1537,6 +1538,7 @@ do
type = lookuptype,
markclass = markclass or nil,
flags = flags,
+ -- chain = chain,
order = order,
features = features,
}
@@ -1553,6 +1555,7 @@ do
type = lookuptype,
markclass = markclass or nil,
flags = flags,
+ -- chain = chain,
}
sublookuplist[nofsublookups] = l
sublookuphash[lookupid] = nofsublookups
@@ -1616,6 +1619,7 @@ do
type = d.lookuptype,
markclass = d.markclass or nil,
flags = d.flags,
+ -- chain = d.chain,
}
sublookuplist[nofsublookups] = h
sublookuphash[lookupid] = nofsublookups
diff --git a/tex/context/base/font-otd.lua b/tex/context/base/font-otd.lua
index ff1b471fc..a2354a0cc 100644
--- a/tex/context/base/font-otd.lua
+++ b/tex/context/base/font-otd.lua
@@ -178,7 +178,7 @@ local function initialize(sequence,script,language,s_enabled,a_enabled,font,attr
"font %s, dynamic %a (%a), feature %a, script %a, language %a, lookup %a, value %a",
font,attr or 0,dynamic,kind,script,language,sequence.name,valid)
end
- ra[#ra+1] = { valid, attribute, sequence.chain or 0, kind, sequence }
+ ra[#ra+1] = { valid, attribute, sequence, kind }
end
end
end
diff --git a/tex/context/base/font-otn.lua b/tex/context/base/font-otn.lua
index 99e52a3b0..9a85dcf96 100644
--- a/tex/context/base/font-otn.lua
+++ b/tex/context/base/font-otn.lua
@@ -1,4 +1,4 @@
-if not modules then modules = { } end modules ['font-otn'] = {
+if not modules then modules = { } end modules ['font-ots'] = { -- sequences
version = 1.001,
comment = "companion to font-ini.mkiv",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
@@ -6,9 +6,6 @@ if not modules then modules = { } end modules ['font-otn'] = {
license = "see context related readme files",
}
--- todo: looks like we have a leak somewhere (probably in ligatures)
--- todo: copy attributes to disc
-
-- this is a context version which can contain experimental code, but when we
-- have serious patches we also need to change the other two font-otn files
@@ -83,9 +80,12 @@ is currently acceptable. Not all functions are implemented yet, often because I
lack the fonts for testing. Many scripts are not yet supported either, but I will
look into them as soon as <l n='context'/> users ask for it.</p>
-<p>Because there are different interpretations possible, I will extend the code
-with more (configureable) variants. I can also add hooks for users so that they can
-write their own extensions.</p>
+<p>The specification leaves room for interpretation. In case of doubt the microsoft
+implementation is the reference as it is the most complete one. As they deal with
+lots of scripts and fonts, Kai and Ivo did a lot of testing of the generic code and
+their suggestions help improve the code. I'm aware that not all border cases can be
+taken care of, unless we accept excessive runtime, and even then the interference
+with other mechanisms (like hyphenation) are not trivial.</p>
<p>Glyphs are indexed not by unicode but in their own way. This is because there is no
relationship with unicode at all, apart from the fact that a font might cover certain
@@ -112,12 +112,12 @@ when there's a fix in the <l n='fontforge'/> library or <l n='lua'/> code that
results in different tables.</p>
--ldx]]--
--- action handler chainproc chainmore comment
+-- action handler chainproc
--
--- gsub_single ok ok ok
--- gsub_multiple ok ok not implemented yet
--- gsub_alternate ok ok not implemented yet
--- gsub_ligature ok ok ok
+-- gsub_single ok ok
+-- gsub_multiple ok ok
+-- gsub_alternate ok ok
+-- gsub_ligature ok ok
-- gsub_context ok --
-- gsub_contextchain ok --
-- gsub_reversecontextchain ok --
@@ -182,13 +182,11 @@ local trace_discruns = false registertracker("otf.discruns", function(v
local trace_compruns = false registertracker("otf.compruns", function(v) trace_compruns = v end)
local quit_on_no_replacement = true -- maybe per font
-local check_discretionaries = true -- "trace"
local zwnjruns = true
registerdirective("otf.zwnjruns", function(v) zwnjruns = v end)
registerdirective("otf.chain.quitonnoreplacement",function(value) quit_on_no_replacement = value end)
-
local report_direct = logs.reporter("fonts","otf direct")
local report_subchain = logs.reporter("fonts","otf subchain")
local report_chain = logs.reporter("fonts","otf chain")
@@ -260,7 +258,7 @@ local localpar_code = whatcodes.localpar
local discretionary_code = disccodes.discretionary
local regular_code = disccodes.regular
-local automatic_code = disccodes.automatic
+----- automatic_code = disccodes.automatic
local ligature_code = glyphcodes.ligature
@@ -313,6 +311,15 @@ local handlers = { }
local rlmode = 0
local featurevalue = false
+local sweephead = { }
+local sweepnode = nil
+local sweepprev = nil
+local sweepnext = nil
+
+local notmatchpre = { }
+local notmatchpost = { }
+local notmatchreplace = { }
+
-- head is always a whatsit so we can safely assume that head is not changed
-- we use this for special testing and documentation
@@ -403,50 +410,64 @@ local function copy_glyph(g) -- next and prev are untouched !
end
end
--- temp here (context)
-
-local function collapse_disc(start,next)
- local replace1 = getfield(start,"replace")
- local replace2 = getfield(next,"replace")
- if replace1 and replace2 then
- local pre2 = getfield(next,"pre")
- local post2 = getfield(next,"post")
- setfield(replace1,"prev",nil)
- if pre2 then
- local pre1 = getfield(start,"pre")
- if pre1 then
- flush_node_list(pre1)
+local function flattendisk(head,disc)
+ local replace = getfield(disc,"replace")
+ setfield(disc,"replace",nil)
+ free_node(disc)
+ if head == disc then
+ local next = getnext(disc)
+ if replace then
+ if next then
+ local tail = find_node_tail(replace)
+ setfield(tail,"next",next)
+ setfield(next,"prev",tail)
end
- local pre1 = copy_node_list(replace1)
- local tail1 = find_node_tail(pre1)
- setfield(tail1,"next",pre2)
- setfield(pre2,"prev",tail1)
- setfield(start,"pre",pre1)
- setfield(next,"pre",nil)
+ return replace, replace
+ elseif next then
+ return next, next
else
- setfield(start,"pre",nil)
+ return -- maybe warning
end
- if post2 then
- local post1 = getfield(start,"post")
- if post1 then
- flush_node_list(post1)
+ else
+ local next = getnext(disc)
+ local prev = getprev(disc)
+ if replace then
+ local tail = find_node_tail(replace)
+ if next then
+ setfield(tail,"next",next)
+ setfield(next,"prev",tail)
end
- setfield(start,"post",post2)
+ setfield(prev,"next",replace)
+ setfield(replace,"prev",prev)
+ return head, replace
else
- setfield(start,"post",nil)
- end
- local tail1 = find_node_tail(replace1)
- setfield(tail1,"next",replace2)
- setfield(replace2,"prev",tail1)
- setfield(start,"replace",replace1)
- setfield(next,"replace",nil)
- --
- local nextnext = getnext(next)
- setfield(nextnext,"prev",start)
- setfield(start,"next",nextnext)
- free_node(next)
+ if next then
+ setfield(next,"prev",prev)
+ end
+ setfield(prev,"next",next)
+ return head, next
+ end
+ end
+end
+
+local function appenddisc(disc,list)
+ local post = getfield(disc,"post")
+ local replace = getfield(disc,"replace")
+ local phead = list
+ local rhead = copy_node_list(list)
+ local ptail = find_node_tail(post)
+ local rtail = find_node_tail(replace)
+ if post then
+ setfield(ptail,"next",phead)
+ setfield(phead,"prev",ptail)
else
- -- maybe remove it
+ setfield(disc,"post",phead)
+ end
+ if replace then
+ setfield(rtail,"next",rhead)
+ setfield(rhead,"prev",rtail)
+ else
+ setfield(disc,"replace",rhead)
end
end
@@ -716,13 +737,38 @@ local function toligature(kind,lookupname,head,start,stop,char,markflag,discfoun
return head, base
end
-function handlers.gsub_single(head,start,kind,lookupname,replacement)
- if trace_singles then
- logprocess("%s: replacing %s by single %s",pref(kind,lookupname),gref(getchar(start)),gref(replacement))
+local function multiple_glyphs(head,start,multiple,ignoremarks)
+ local nofmultiples = #multiple
+ if nofmultiples > 0 then
+ resetinjection(start)
+ setfield(start,"char",multiple[1])
+ if nofmultiples > 1 then
+ local sn = getnext(start)
+ for k=2,nofmultiples do -- todo: use insert_node
+-- untested:
+--
+-- while ignoremarks and marks[getchar(sn)] then
+-- local sn = getnext(sn)
+-- end
+ local n = copy_node(start) -- ignore components
+ resetinjection(n)
+ setfield(n,"char",multiple[k])
+ setfield(n,"next",sn)
+ setfield(n,"prev",start)
+ if sn then
+ setfield(sn,"prev",n)
+ end
+ setfield(start,"next",n)
+ start = n
+ end
+ end
+ return head, start, true
+ else
+ if trace_multiples then
+ logprocess("no multiple for %s",gref(getchar(start)))
+ end
+ return head, start, false
end
- resetinjection(start)
- setfield(start,"char",replacement)
- return head, start, true
end
local function get_alternative_glyph(start,alternatives,value,trace_alternatives)
@@ -757,38 +803,15 @@ local function get_alternative_glyph(start,alternatives,value,trace_alternatives
end
end
-local function multiple_glyphs(head,start,multiple,ignoremarks)
- local nofmultiples = #multiple
- if nofmultiples > 0 then
- resetinjection(start)
- setfield(start,"char",multiple[1])
- if nofmultiples > 1 then
- local sn = getnext(start)
- for k=2,nofmultiples do -- todo: use insert_node
--- untested:
---
--- while ignoremarks and marks[getchar(sn)] then
--- local sn = getnext(sn)
--- end
- local n = copy_node(start) -- ignore components
- resetinjection(n)
- setfield(n,"char",multiple[k])
- setfield(n,"next",sn)
- setfield(n,"prev",start)
- if sn then
- setfield(sn,"prev",n)
- end
- setfield(start,"next",n)
- start = n
- end
- end
- return head, start, true
- else
- if trace_multiples then
- logprocess("no multiple for %s",gref(getchar(start)))
- end
- return head, start, false
+-- handlers
+
+function handlers.gsub_single(head,start,kind,lookupname,replacement)
+ if trace_singles then
+ logprocess("%s: replacing %s by single %s",pref(kind,lookupname),gref(getchar(start)),gref(replacement))
end
+ resetinjection(start)
+ setfield(start,"char",replacement)
+ return head, start, true
end
function handlers.gsub_alternate(head,start,kind,lookupname,alternative,sequence)
@@ -910,19 +933,78 @@ function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence)
return head, start, false, discfound
end
--- function is_gsub_ligature(start,ligature) -- limited case: in disc nodes, only latin, always glyphs
--- local s = getnext(start)
--- while s do
--- local lg = ligature[getchar(s)]
--- if lg then
--- ligature = lg
--- s = getnext(s)
--- else
--- return
--- end
--- end
--- return ligature and ligature.ligature
--- end
+function handlers.gpos_single(head,start,kind,lookupname,kerns,sequence,injection)
+ local startchar = getchar(start)
+ local dx, dy, w, h = setpair(start,tfmdata.parameters.factor,rlmode,sequence.flags[4],kerns,injection) -- ,characters[startchar])
+ if trace_kerns then
+ logprocess("%s: shifting single %s by (%p,%p) and correction (%p,%p)",pref(kind,lookupname),gref(startchar),dx,dy,w,h)
+ end
+ return head, start, false
+end
+
+function handlers.gpos_pair(head,start,kind,lookupname,kerns,sequence,lookuphash,i,injection)
+ -- todo: kerns in disc nodes: pre, post, replace -> loop over disc too
+ -- todo: kerns in components of ligatures
+ local snext = getnext(start)
+ if not snext then
+ return head, start, false
+ else
+ local prev, done = start, false
+ local factor = tfmdata.parameters.factor
+ local lookuptype = lookuptypes[lookupname]
+ while snext and getid(snext) == glyph_code and getfont(snext) == currentfont and getsubtype(snext)<256 do
+ local nextchar = getchar(snext)
+ local krn = kerns[nextchar]
+ if not krn and marks[nextchar] then
+ prev = snext
+ snext = getnext(snext)
+ else
+ if not krn then
+ -- skip
+ elseif type(krn) == "table" then
+ if lookuptype == "pair" then -- probably not needed
+ local a, b = krn[2], krn[3]
+ if a and #a > 0 then
+ local x, y, w, h = setpair(start,factor,rlmode,sequence.flags[4],a,injection) -- characters[startchar])
+ if trace_kerns then
+ local startchar = getchar(start)
+ logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p)",pref(kind,lookupname),gref(startchar),gref(nextchar),x,y,w,h)
+ end
+ end
+ if b and #b > 0 then
+ local x, y, w, h = setpair(snext,factor,rlmode,sequence.flags[4],b,injection) -- characters[nextchar])
+ if trace_kerns then
+ local startchar = getchar(start)
+ logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p)",pref(kind,lookupname),gref(startchar),gref(nextchar),x,y,w,h)
+ end
+ end
+ else -- wrong ... position has different entries
+ report_process("%s: check this out (old kern stuff)",pref(kind,lookupname))
+ -- local a, b = krn[2], krn[6]
+ -- if a and a ~= 0 then
+ -- local k = setkern(snext,factor,rlmode,a)
+ -- if trace_kerns then
+ -- logprocess("%s: inserting first kern %s between %s and %s",pref(kind,lookupname),k,gref(getchar(prev)),gref(nextchar))
+ -- end
+ -- end
+ -- if b and b ~= 0 then
+ -- logwarning("%s: ignoring second kern xoff %s",pref(kind,lookupname),b*factor)
+ -- end
+ end
+ done = true
+ elseif krn ~= 0 then
+ local k = setkern(snext,factor,rlmode,krn,injection)
+ if trace_kerns then
+ logprocess("%s: inserting kern %s between %s and %s",pref(kind,lookupname),k,gref(getchar(prev)),gref(nextchar)) -- prev?
+ end
+ done = true
+ end
+ break
+ end
+ end
+ return head, start, done
+ end
+end
--[[ldx--
<p>We get hits on a mark, but we're not sure if the it has to be applied so
@@ -1169,85 +1251,11 @@ function handlers.gpos_cursive(head,start,kind,lookupname,exitanchors,sequence)
end
end
-function handlers.gpos_single(head,start,kind,lookupname,kerns,sequence,injection)
- local startchar = getchar(start)
- local dx, dy, w, h = setpair(start,tfmdata.parameters.factor,rlmode,sequence.flags[4],kerns,injection) -- ,characters[startchar])
- if trace_kerns then
- logprocess("%s: shifting single %s by (%p,%p) and correction (%p,%p)",pref(kind,lookupname),gref(startchar),dx,dy,w,h)
- end
- return head, start, false
-end
-
-function handlers.gpos_pair(head,start,kind,lookupname,kerns,sequence,lookuphash,i,injection)
- -- todo: kerns in disc nodes: pre, post, replace -> loop over disc too
- -- todo: kerns in components of ligatures
- local snext = getnext(start)
- if not snext then
- return head, start, false
- else
- local prev, done = start, false
- local factor = tfmdata.parameters.factor
- local lookuptype = lookuptypes[lookupname]
- while snext and getid(snext) == glyph_code and getfont(snext) == currentfont and getsubtype(snext)<256 do
- local nextchar = getchar(snext)
- local krn = kerns[nextchar]
- if not krn and marks[nextchar] then
- prev = snext
- snext = getnext(snext)
- else
- if not krn then
- -- skip
- elseif type(krn) == "table" then
- if lookuptype == "pair" then -- probably not needed
- local a, b = krn[2], krn[3]
- if a and #a > 0 then
- local startchar = getchar(start)
- local x, y, w, h = setpair(start,factor,rlmode,sequence.flags[4],a,injection) -- characters[startchar])
- if trace_kerns then
- logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p)",pref(kind,lookupname),gref(startchar),gref(nextchar),x,y,w,h)
- end
- end
- if b and #b > 0 then
- local startchar = getchar(start)
- local x, y, w, h = setpair(snext,factor,rlmode,sequence.flags[4],b,injection) -- characters[nextchar])
- if trace_kerns then
- logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p)",pref(kind,lookupname),gref(startchar),gref(nextchar),x,y,w,h)
- end
- end
- else -- wrong ... position has different entries
- report_process("%s: check this out (old kern stuff)",pref(kind,lookupname))
- -- local a, b = krn[2], krn[6]
- -- if a and a ~= 0 then
- -- local k = setkern(snext,factor,rlmode,a)
- -- if trace_kerns then
- -- logprocess("%s: inserting first kern %s between %s and %s",pref(kind,lookupname),k,gref(getchar(prev)),gref(nextchar))
- -- end
- -- end
- -- if b and b ~= 0 then
- -- logwarning("%s: ignoring second kern xoff %s",pref(kind,lookupname),b*factor)
- -- end
- end
- done = true
- elseif krn ~= 0 then
- local k = setkern(snext,factor,rlmode,krn,injection)
- if trace_kerns then
- logprocess("%s: inserting kern %s between %s and %s",pref(kind,lookupname),k,gref(getchar(prev)),gref(nextchar))
- end
- done = true
- end
- break
- end
- end
- return head, start, done
- end
-end
-
--[[ldx--
<p>I will implement multiple chain replacements once I run into a font that uses
it. It's not that complex to handle.</p>
--ldx]]--
-local chainmores = { }
local chainprocs = { }
local function logprocess(...)
@@ -1276,11 +1284,6 @@ function chainprocs.chainsub(head,start,stop,kind,chainname,currentcontext,looku
return head, start, false
end
-function chainmores.chainsub(head,start,stop,kind,chainname,currentcontext,lookuphash,lookuplist,chainlookupname,n)
- logprocess("%s: a direct call to chainsub cannot happen",cref(kind,chainname,chainlookupname))
- return head, start, false
-end
-
-- The reversesub is a special case, which is why we need to store the replacements
-- in a bit weird way. There is no lookup and the replacement comes from the lookup
-- itself. It is meant mostly for dealing with Urdu.
@@ -1377,83 +1380,7 @@ function chainprocs.gsub_single(head,start,stop,kind,chainname,currentcontext,lo
logprocess("%s: replacing single %s by %s",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(currentchar),gref(replacement))
end
resetinjection(current)
- if check_discretionaries then
- -- some fonts use a chain lookup to replace e.g. an f in a fi ligature
- -- and there can be a disc node in between ... the next code tries to catch
- -- this
- local next = getnext(current)
- local prev = getprev(current) -- todo: just remember it above
- local done = false
- if next then
- if getid(next) == disc_code then
- local subtype = getsubtype(next)
- if subtype == discretionary_code then
- setfield(next,"prev",prev)
- setfield(prev,"next",next)
- setfield(current,"prev",nil)
- setfield(current,"next",nil)
- local replace = getfield(next,"replace")
- local pre = getfield(next,"pre")
- local new = copy_node(current)
- setfield(new,"char",replacement)
- if replace then
- setfield(new,"next",replace)
- setfield(replace,"prev",new)
- end
- if pre then
- setfield(current,"next",pre)
- setfield(pre,"prev",current)
- end
- setfield(next,"replace",new) -- also updates tail
- setfield(next,"pre",current) -- also updates tail
- end
- start = next
- done = true
- local next = getnext(start)
- if next and getid(next) == disc_code then
- collapse_disc(start,next)
- end
- end
- end
- if not done and prev then
- if getid(prev) == disc_code then
- local subtype = getsubtype(prev)
- if subtype == discretionary_code then
- setfield(next,"prev",prev)
- setfield(prev,"next",next)
- setfield(current,"prev",nil)
- setfield(current,"next",nil)
- local replace = getfield(prev,"replace")
- local post = getfield(prev,"post")
- local new = copy_node(current)
- setfield(new,"char",replacement)
- if replace then
- local tail = find_node_tail(replace)
- setfield(tail,"next",new)
- setfield(new,"prev",tail)
- else
- replace = new
- end
- if post then
- local tail = find_node_tail(post)
- setfield(tail,"next",current)
- setfield(current,"prev",tail)
- else
- post = current
- end
- setfield(prev,"replace",replace) -- also updates tail
- setfield(prev,"post",post) -- also updates tail
- start = prev
- done = true
- end
- end
- end
- if not done then
- setfield(current,"char",replacement)
- end
- else
- setfield(current,"char",replacement)
- end
+ setfield(current,"char",replacement)
end
end
return head, start, true
@@ -1466,8 +1393,6 @@ function chainprocs.gsub_single(head,start,stop,kind,chainname,currentcontext,lo
return head, start, false
end
-chainmores.gsub_single = chainprocs.gsub_single
-
--[[ldx--
<p>Here we replace start by a sequence of new glyphs.</p>
--ldx]]--
@@ -1498,8 +1423,6 @@ function chainprocs.gsub_multiple(head,start,stop,kind,chainname,currentcontext,
return head, start, false
end
-chainmores.gsub_multiple = chainprocs.gsub_multiple
-
--[[ldx--
<p>Here we replace start by new glyph. First we delete the rest of the match.</p>
--ldx]]--
@@ -1554,8 +1477,6 @@ function chainprocs.gsub_alternate(head,start,stop,kind,chainname,currentcontext
return head, start, false
end
-chainmores.gsub_alternate = chainprocs.gsub_alternate
-
--[[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
@@ -1643,7 +1564,93 @@ function chainprocs.gsub_ligature(head,start,stop,kind,chainname,currentcontext,
return head, start, false, 0, false
end
-chainmores.gsub_ligature = chainprocs.gsub_ligature
+function chainprocs.gpos_single(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex,sequence)
+ -- untested .. needs checking for the new model
+ local startchar = getchar(start)
+ local subtables = currentlookup.subtables
+ local lookupname = subtables[1]
+ local kerns = lookuphash[lookupname]
+ if kerns then
+ kerns = kerns[startchar] -- needed ?
+ if kerns then
+ local dx, dy, w, h = setpair(start,tfmdata.parameters.factor,rlmode,sequence.flags[4],kerns) -- ,characters[startchar])
+ if trace_kerns then
+ logprocess("%s: shifting single %s by (%p,%p) and correction (%p,%p)",cref(kind,chainname,chainlookupname),gref(startchar),dx,dy,w,h)
+ end
+ end
+ end
+ return head, start, false
+end
+
+function chainprocs.gpos_pair(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex,sequence)
+ local snext = getnext(start)
+ if snext then
+ local startchar = getchar(start)
+ local subtables = currentlookup.subtables
+ local lookupname = subtables[1]
+ local kerns = lookuphash[lookupname]
+ if kerns then
+ kerns = kerns[startchar]
+ if kerns then
+ local lookuptype = lookuptypes[lookupname]
+ local prev, done = start, false
+ local factor = tfmdata.parameters.factor
+ while snext and getid(snext) == glyph_code and getfont(snext) == currentfont and getsubtype(snext)<256 do
+ local nextchar = getchar(snext)
+ local krn = kerns[nextchar]
+ if not krn and marks[nextchar] then
+ prev = snext
+ snext = getnext(snext)
+ else
+ if not krn then
+ -- skip
+ elseif type(krn) == "table" then
+ if lookuptype == "pair" then
+ local a, b = krn[2], krn[3]
+ if a and #a > 0 then
+ local startchar = getchar(start)
+ local x, y, w, h = setpair(start,factor,rlmode,sequence.flags[4],a) -- ,characters[startchar])
+ if trace_kerns then
+ logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(kind,chainname,chainlookupname),gref(startchar),gref(nextchar),x,y,w,h)
+ end
+ end
+ if b and #b > 0 then
+ local startchar = getchar(start)
+ local x, y, w, h = setpair(snext,factor,rlmode,sequence.flags[4],b) -- ,characters[nextchar])
+ if trace_kerns then
+ logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(kind,chainname,chainlookupname),gref(startchar),gref(nextchar),x,y,w,h)
+ end
+ end
+ else
+ report_process("%s: check this out (old kern stuff)",cref(kind,chainname,chainlookupname))
+ -- local a, b = krn[2], krn[6]
+ -- if a and a ~= 0 then
+ -- local k = setkern(snext,factor,rlmode,a)
+ -- if trace_kerns then
+ -- logprocess("%s: inserting first kern %s between %s and %s",cref(kind,chainname,chainlookupname),k,gref(getchar(prev)),gref(nextchar))
+ -- end
+ -- end
+ -- if b and b ~= 0 then
+ -- logwarning("%s: ignoring second kern xoff %s",cref(kind,chainname,chainlookupname),b*factor)
+ -- end
+ end
+ done = true
+ elseif krn ~= 0 then
+ local k = setkern(snext,factor,rlmode,krn)
+ if trace_kerns then
+ logprocess("%s: inserting kern %s between %s and %s",cref(kind,chainname,chainlookupname),k,gref(getchar(prev)),gref(nextchar))
+ end
+ done = true
+ end
+ break
+ end
+ end
+ return head, start, done
+ end
+ end
+ end
+ return head, start, false
+end
function chainprocs.gpos_mark2base(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname)
local markchar = getchar(start)
@@ -1903,129 +1910,345 @@ function chainprocs.gpos_cursive(head,start,stop,kind,chainname,currentcontext,l
return head, start, false
end
-function chainprocs.gpos_single(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex,sequence)
- -- untested .. needs checking for the new model
- local startchar = getchar(start)
- local subtables = currentlookup.subtables
- local lookupname = subtables[1]
- local kerns = lookuphash[lookupname]
- if kerns then
- kerns = kerns[startchar] -- needed ?
- if kerns then
- local dx, dy, w, h = setpair(start,tfmdata.parameters.factor,rlmode,sequence.flags[4],kerns) -- ,characters[startchar])
- if trace_kerns then
- logprocess("%s: shifting single %s by (%p,%p) and correction (%p,%p)",cref(kind,chainname,chainlookupname),gref(startchar),dx,dy,w,h)
+-- what pointer to return, spec says stop
+-- to be discussed ... is bidi changer a space?
+-- elseif char == zwnj and sequence[n][32] then -- brrr
+
+-- somehow l or f is global
+-- we don't need to pass the currentcontext, saves a bit
+-- make a slow variant then can be activated but with more tracing
+
+local function show_skip(kind,chainname,char,ck,class)
+ if ck[9] then
+ logwarning("%s: skipping char %s, class %a, rule %a, lookuptype %a, %a => %a",cref(kind,chainname),gref(char),class,ck[1],ck[2],ck[9],ck[10])
+ else
+ logwarning("%s: skipping char %s, class %a, rule %a, lookuptype %a",cref(kind,chainname),gref(char),class,ck[1],ck[2])
+ end
+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
+-- (sweepnode, sweepmode, sweepprev, sweepnext, etc). 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.)
+--
+-- 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 function chaindisk(head,start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,chainindex,sequence,chainproc)
+
+ if not start then
+ return -- safeguard
+ end
+
+ local startishead = start == head
+ local seq = ck[3]
+ local f = ck[4]
+ local l = ck[5]
+ local s = #seq
+ local done = false
+ local sweepnode = sweepnode
+ local sweeptype = sweeptype
+ local sweepoverflow = false
+ local checkdisc = getprev(head) -- hm bad name head
+ local keepdisc = not sweepnode
+ local lookaheaddisc = nil
+ local backtrackdisc = nil
+ local current = start
+ local last = start
+ local prev = getprev(start)
+
+ -- fishy: so we can overflow and then go on in the sweep?
+
+ local i = f
+ while i <= l do
+ local id = getid(current)
+ if id == glyph_code then
+ i = i + 1
+ last = current
+ current = getnext(current)
+ elseif id == disc_code then
+ if keepdisc then
+ keepdisc = false
+ if notmatchpre[current] ~= notmatchreplace[current] then
+ lookaheaddisc = current
+ end
+ local replace = getfield(current,"replace")
+ while replace and i <= l do
+ if getid(replace) == glyph_code then
+ i = i + 1
+ end
+ replace = getnext(replace)
+ end
+ last = current
+ current = getnext(c)
+ else
+ head, current = flattendisk(head,current)
+ end
+ else
+ last = current
+ current = getnext(current)
+ end
+ if current then
+ -- go on
+ elseif sweepoverflow then
+ -- we already are folling up on sweepnode
+ break
+ elseif sweeptype == "post" or sweeptype == "replace" then
+ current = getnext(sweepnode)
+ if current then
+ sweeptype = nil
+ sweepoverflow = true
+ else
+ break
end
end
end
- return head, start, false
-end
-chainmores.gpos_single = chainprocs.gpos_single -- okay?
+ if sweepoverflow then
+ local prev = current and getprev(current)
+ if not current or prev ~= sweepnode then
+ local head = getnext(sweepnode)
+ local tail = nil
+ if prev then
+ tail = prev
+ setfield(current,"prev",sweepnode)
+ else
+ tail = find_node_tail(head)
+ end
+ setfield(sweepnode,"next",current)
+ setfield(head,"prev",nil)
+ setfield(tail,"next",nil)
+ appenddisc(sweepnode,head)
+ end
+ end
--- when machines become faster i will make a shared function
+ if l < s then
+ local i = l
+ local t = sweeptype == "post" or sweeptype == "replace"
+ while current and i < s do
+ local id = getid(current)
+ if id == glyph_code then
+ i = i + 1
+ current = getnext(current)
+ elseif id == disc_code then
+ if keepdisc then
+ keepdisc = false
+ if notmatchpre[current] ~= notmatchreplace[current] then
+ lookaheaddisc = current
+ end
+ local replace = getfield(c,"replace")
+ while replace and i < s do
+ if getid(replace) == glyph_code then
+ i = i + 1
+ end
+ replace = getnext(replace)
+ end
+ current = getnext(current)
+ elseif notmatchpre[current] ~= notmatchreplace[current] then
+ head, current = flattendisk(head,current)
+ else
+ current = getnext(current) -- HH
+ end
+ else
+ current = getnext(current)
+ end
+ if not current and t then
+ current = getnext(sweepnode)
+ if current then
+ sweeptype = nil
+ end
+ end
+ end
+ end
-function chainprocs.gpos_pair(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex,sequence)
- local snext = getnext(start)
- if snext then
- local startchar = getchar(start)
- local subtables = currentlookup.subtables
- local lookupname = subtables[1]
- local kerns = lookuphash[lookupname]
- if kerns then
- kerns = kerns[startchar]
- if kerns then
- local lookuptype = lookuptypes[lookupname]
- local prev, done = start, false
- local factor = tfmdata.parameters.factor
- while snext and getid(snext) == glyph_code and getfont(snext) == currentfont and getsubtype(snext)<256 do
- local nextchar = getchar(snext)
- local krn = kerns[nextchar]
- if not krn and marks[nextchar] then
- prev = snext
- snext = getnext(snext)
- else
- if not krn then
- -- skip
- elseif type(krn) == "table" then
- if lookuptype == "pair" then
- local a, b = krn[2], krn[3]
- if a and #a > 0 then
- local startchar = getchar(start)
- local x, y, w, h = setpair(start,factor,rlmode,sequence.flags[4],a) -- ,characters[startchar])
- if trace_kerns then
- logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(kind,chainname,chainlookupname),gref(startchar),gref(nextchar),x,y,w,h)
- end
- end
- if b and #b > 0 then
- local startchar = getchar(start)
- local x, y, w, h = setpair(snext,factor,rlmode,sequence.flags[4],b) -- ,characters[nextchar])
- if trace_kerns then
- logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(kind,chainname,chainlookupname),gref(startchar),gref(nextchar),x,y,w,h)
- end
- end
- else
- report_process("%s: check this out (old kern stuff)",cref(kind,chainname,chainlookupname))
- -- local a, b = krn[2], krn[6]
- -- if a and a ~= 0 then
- -- local k = setkern(snext,factor,rlmode,a)
- -- if trace_kerns then
- -- logprocess("%s: inserting first kern %s between %s and %s",cref(kind,chainname,chainlookupname),k,gref(getchar(prev)),gref(nextchar))
- -- end
- -- end
- -- if b and b ~= 0 then
- -- logwarning("%s: ignoring second kern xoff %s",cref(kind,chainname,chainlookupname),b*factor)
- -- end
- end
- done = true
- elseif krn ~= 0 then
- local k = setkern(snext,factor,rlmode,krn)
- if trace_kerns then
- logprocess("%s: inserting kern %s between %s and %s",cref(kind,chainname,chainlookupname),k,gref(getchar(prev)),gref(nextchar))
- end
- done = true
+ if f > 1 then
+ local current = prev
+ local i = f
+ local t = sweeptype == "pre" or sweeptype == "replace"
+ if not current and t and current == checkdisk then
+ current = getprev(sweepnode)
+ end
+ while current and i > 1 do -- missing getprev added / moved outside
+ local id = getid(current)
+ if id == glyph_code then
+ i = i - 1
+ elseif id == disc_code then
+ if keepdisc then
+ keepdisc = false
+ if notmatchpost[current] ~= notmatchreplace[current] then
+ backtrackdisc = current
+ end
+ local replace = getfield(current,"replace")
+ while replace and i > 1 do
+ if getid(replace) == glyph_code then
+ i = i - 1
end
- break
+ replace = getnext(replace)
end
+ elseif notmatchpost[current] ~= notmatchreplace[current] then
+ head, current = flattendisk(head,current)
end
- return head, start, done
+ end
+ current = getprev(current)
+ if t and current == checkdisk then
+ current = getprev(sweepnode)
end
end
end
- return head, start, false
-end
-chainmores.gpos_pair = chainprocs.gpos_pair -- okay?
+ local ok = false
+ if lookaheaddisc then
--- what pointer to return, spec says stop
--- to be discussed ... is bidi changer a space?
--- elseif char == zwnj and sequence[n][32] then -- brrr
+ local cf = start
+ local cl = getprev(lookaheaddisc)
+ local cprev = getprev(start)
+ local insertedmarks = 0
--- somehow l or f is global
--- we don't need to pass the currentcontext, saves a bit
--- make a slow variant then can be activated but with more tracing
+ while cprev and getid(cf) == glyph_code and getfont(cf) == currentfont and getsubtype(cf) < 256 and marks[getchar(cf)] do
+ insertedmarks = insertedmarks + 1
+ cf = cprev
+ startishead = cf == head
+ cprev = getprev(cprev)
+ end
+
+ setfield(lookaheaddisc,"prev",cprev)
+ if cprev then
+ setfield(cprev,"next",lookaheaddisc)
+ end
+ setfield(cf,"prev",nil)
+ setfield(cl,"next",nil)
+ if startishead then
+ head = lookaheaddisc
+ end
+
+ local replace = getfield(lookaheaddisc,"replace")
+ local pre = getfield(lookaheaddisc,"pre")
+ local new = copy_node_list(cf)
+ local cnew = new
+ for i=1,insertedmarks do
+ cnew = getnext(cnew)
+ end
+ local clast = cnew
+ for i=f,l do
+ clast = getnext(clast)
+ end
+ if not notmatchpre[lookaheaddisc] then
+ cf, start, ok = chainproc(cf,start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,nil,sequence)
+ end
+ if not notmatchreplace[lookaheaddisc] then
+ new, cnew, ok = chainproc(new,cnew,clast,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,nil,sequence)
+ end
+ if pre then
+ setfield(cl,"next",pre)
+ setfield(pre,"prev",cl)
+ end
+ if replace then
+ local tail = find_node_tail(new)
+ setfield(tail,"next",replace)
+ setfield(replace,"prev",tail)
+ end
+ setfield(lookaheaddisc,"pre",cf) -- also updates tail
+ setfield(lookaheaddisc,"replace",new) -- also updates tail
+
+ start = getprev(lookaheaddisc)
+ sweephead[cf] = getnext(clast)
+ sweephead[new] = getnext(last)
+
+ elseif backtrackdisc then
+
+ local cf = getnext(backtrackdisc)
+ local cl = start
+ local cnext = getnext(start)
+ local insertedmarks = 0
+
+ while cnext and getid(cnext) == glyph_code and getfont(cnext) == currentfont and getsubtype(cnext) < 256 and marks[getchar(cnext)] do
+ insertedmarks = insertedmarks + 1
+ cl = cnext
+ cnext = getnext(cnext)
+ end
+ if cnext then
+ setfield(cnext,"prev",backtrackdisc)
+ end
+ setfield(backtrackdisc,"next",cnext)
+ setfield(cf,"prev",nil)
+ setfield(cl,"next",nil)
+ local replace = getfield(backtrackdisc,"replace")
+ local post = getfield(backtrackdisc,"post")
+ local new = copy_node_list(cf)
+ local cnew = find_node_tail(new)
+ for i=1,insertedmarks do
+ cnew = getprev(cnew)
+ end
+ local clast = cnew
+ for i=f,l do
+ clast = getnext(clast)
+ end
+ if not notmatchpost[backtrackdisc] then
+ cf, start, ok = chainproc(cf,start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,nil,sequence)
+ end
+ if not notmatchreplace[backtrackdisc] then
+ new, cnew, ok = chainproc(new,cnew,clast,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,nil,sequence)
+ end
+ if post then
+ local tail = find_node_tail(post)
+ setfield(tail,"next",cf)
+ setfield(cf,"prev",tail)
+ else
+ post = cf
+ end
+ if replace then
+ local tail = find_node_tail(replace)
+ setfield(tail,"next",new)
+ setfield(new,"prev",tail)
+ else
+ replace = new
+ end
+ setfield(backtrackdisc,"post",post) -- also updates tail
+ setfield(backtrackdisc,"replace",replace) -- also updates tail
+ start = getprev(backtrackdisc)
+ sweephead[post] = getnext(clast)
+ sweephead[replace] = getnext(last)
-local function show_skip(kind,chainname,char,ck,class)
- if ck[9] then
- logwarning("%s: skipping char %s, class %a, rule %a, lookuptype %a, %a => %a",cref(kind,chainname),gref(char),class,ck[1],ck[2],ck[9],ck[10])
else
- logwarning("%s: skipping char %s, class %a, rule %a, lookuptype %a",cref(kind,chainname),gref(char),class,ck[1],ck[2])
+
+ head, start, ok = chainproc(head,start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,nil,sequence)
+
end
-end
---hm, do i need to deal with disc here ?
+ return head, start, ok
+end
local function normal_handle_contextchain(head,start,kind,chainname,contexts,sequence,lookuphash)
- -- local rule, lookuptype, sequence, f, l, lookups = ck[1], ck[2] ,ck[3], ck[4], ck[5], ck[6]
+ local sweepnode = sweepnode
+ local sweeptype = sweeptype
+ local diskseen = false
+ local checkdisc = getprev(head)
local flags = sequence.flags
local done = false
local skipmark = flags[1]
local skipligature = flags[2]
local skipbase = flags[3]
- local someskip = skipmark or skipligature or skipbase -- could be stored in flags for a fast test (hm, flags could be false !)
- local markclass = sequence.markclass -- todo, first we need a proper test
+ local markclass = sequence.markclass
local skipped = false
- for k=1,#contexts do
+ for k=1,#contexts do -- i've only seen ccmp having > 1 (e.g. dejavu)
local match = true
local current = start
local last = start
@@ -2039,7 +2262,8 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
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, l = ck[4], ck[5]
+ local f = ck[4]
+ local l = ck[5]
-- current match
if f == 1 and f == l then -- current only
-- already a hit
@@ -2052,6 +2276,10 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
local n = f + 1
last = getnext(last)
while n <= l do
+ if not last and (sweeptype == "post" or sweeptype == "replace") then
+ last = getnext(sweepnode)
+ sweeptype = nil
+ end
if last then
local id = getid(last)
if id == glyph_code then
@@ -2059,7 +2287,7 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
local char = getchar(last)
local ccd = descriptions[char]
if ccd then
- local class = ccd.class
+ local class = ccd.class or "base"
if class == skipmark or class == skipligature or class == skipbase or (markclass and class == "mark" and not markclass[char]) then
skipped = true
if trace_skips then
@@ -2084,39 +2312,59 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
break
end
elseif id == disc_code then
- if check_discretionaries then
- local replace = getfield(last,"replace")
- if replace then
- -- so far we never entered this branch
- while replace do
- if seq[n][getchar(replace)] then
- n = n + 1
- replace = getnext(replace)
- if not replace then
- break
- elseif n > l then
- -- match = false
- break
- end
- else
- match = false
+ diskseen = true
+ notmatchpre[last] = nil
+ notmatchpost[last] = true
+ notmatchreplace[last] = nil
+ local pre = getfield(last,"pre")
+ if pre then
+ local n = n
+ while pre do
+ if seq[n][getchar(pre)] then
+ n = n + 1
+ pre = getnext(pre)
+ if not pre then
+ break
+ elseif n > l then
break
end
+ else
+ notmatchpre[last] = true
+ break
end
- if not match then
+ end
+ else
+ notmatchpre[last] = true
+ end
+ local replace = getfield(last,"replace")
+ if replace then
+ -- so far we never entered this branch
+ while replace do
+ if seq[n][getchar(replace)] then
+ n = n + 1
+ replace = getnext(replace)
+ if not replace then
+ break
+ elseif n > l then
+ -- match = false
+ break
+ end
+ else
+ notmatchreplace[last] = true
+ if notmatchpre[last] then
+ match = false
+ end
break
- elseif check_discretionaries == "trace" then
- report_chain("check disc action in current")
end
- else
- last = getnext(last) -- no skipping here
+ end
+ if not match then
+ break
end
else
last = getnext(last) -- no skipping here
end
else
- match = false
- break
+ last = getnext(last) -- no skipping here
end
else
match = false
@@ -2129,23 +2377,32 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
if match and f > 1 then
local prev = getprev(start)
if prev then
- local n = f-1
- while n >= 1 do
- if prev then
- local id = getid(prev)
- if id == glyph_code then
- if getfont(prev) == currentfont and getsubtype(prev)<256 then -- normal char
- local char = getchar(prev)
- local ccd = descriptions[char]
- if ccd then
- local class = ccd.class
- if class == skipmark or class == skipligature or class == skipbase or (markclass and class == "mark" and not markclass[char]) then
- skipped = true
- if trace_skips then
- show_skip(kind,chainname,char,ck,class)
+ if prev == checkdisc and (sweeptype == "pre" or sweeptype == "replace") then
+ prev = getprev(sweepnode)
+ -- sweeptype = nil
+ end
+ if prev then
+ local n = f-1
+ while n >= 1 do
+ if prev then
+ local id = getid(prev)
+ if id == glyph_code then
+ if getfont(prev) == currentfont and getsubtype(prev)<256 then -- normal char
+ local char = getchar(prev)
+ local ccd = descriptions[char]
+ if ccd then
+ local class = ccd.class
+ if class == skipmark or class == skipligature or class == skipbase or (markclass and class == "mark" and not markclass[char]) then
+ skipped = true
+ if trace_skips then
+ show_skip(kind,chainname,char,ck,class)
+ end
+ elseif seq[n][char] then
+ n = n -1
+ else
+ match = false
+ break
end
- elseif seq[n][char] then
- n = n -1
else
match = false
break
@@ -2154,57 +2411,84 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
match = false
break
end
- else
- match = false
- break
- end
- elseif id == disc_code then
- -- the special case: f i where i becomes dottless i ..
- if check_discretionaries then
+ elseif id == disc_code then
+ -- the special case: f i where i becomes dottless i ..
+ diskseen = true
+ notmatchpre[prev] = true
+ notmatchpost[prev] = nil
+ notmatchreplace[prev] = nil
+ local pre = getfield(prev,"pre")
+ local post = getfield(prev,"post")
local replace = getfield(prev,"replace")
- if replace then
- -- we seldom enter this branch (e.g. on brill efficient)
- replace = find_node_tail(replace)
- local finish = getprev(replace)
- while replace do
- if seq[n][getchar(replace)] then
- n = n - 1
- replace = getprev(replace)
- if not replace or replace == finish then
+ if pre ~= start and post ~= start and replace ~= start then
+ if post then
+ local n = n
+ post = find_node_tail(post)
+ local finish = getprev(post)
+ while post do
+ if seq[n][getchar(post)] then
+ n = n - 1
+ post = getprev(post)
+ if not post or post == finish then
+ break
+ elseif n < 1 then
+ break
+ end
+ else
+ notmatchpost[prev] = true
break
- elseif n < 1 then
- -- match = false
+ end
+ end
+ else
+ notmatchpost[prev] = true
+ end
+ if replace then
+ -- we seldom enter this branch (e.g. on brill efficient)
+ replace = find_node_tail(replace)
+ local finish = getprev(replace)
+ while replace do
+ if seq[n][getchar(replace)] then
+ n = n - 1
+ replace = getprev(replace)
+ if not replace or replace == finish then
+ break
+ elseif n < 1 then
+ -- match = false
+ break
+ end
+ else
+ notmatchreplace[prev] = true
+ if notmatchpost[prev] then
+ match = false
+ end
break
end
- else
- match = false
+ end
+ if not match then
break
end
- end
- if not match then
- break
- elseif check_discretionaries == "trace" then
- report_chain("check disc action in before")
+ else
+ -- skip 'm
end
else
-- skip 'm
end
+ elseif seq[n][32] then
+ n = n -1
else
- -- skip 'm
+ match = false
+ break
end
- elseif seq[n][32] then
- n = n -1
+ prev = getprev(prev)
+ elseif seq[n][32] then -- somewhat special, as zapfino can have many preceding spaces
+ n = n - 1
else
match = false
break
end
- prev = getprev(prev)
- elseif seq[n][32] then -- somewhat special, as zapfino can have many preceding spaces
- n = n - 1
- else
- match = false
- break
end
+ else
+ match = false
end
else
match = false
@@ -2213,6 +2497,12 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
-- after
if match and s > l then
local current = last and getnext(last)
+ if not current then
+ if sweeptype == "post" or sweeptype == "replace" then
+ current = getnext(sweepnode)
+ -- sweeptype = nil
+ end
+ end
if current then
-- removed optimization for s-l == 1, we have to deal with marks anyway
local n = l + 1
@@ -2245,31 +2535,52 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
break
end
elseif id == disc_code then
- if check_discretionaries then
- local replace = getfield(current,"replace")
- if replace then
- -- so far we never entered this branch
- while replace do
- if seq[n][getchar(replace)] then
- n = n + 1
- replace = getnext(replace)
- if not replace then
- break
- elseif n > s then
- break
- end
- else
- match = false
+ diskseen = true
+ notmatchpre[current] = nil
+ notmatchpost[current] = true
+ notmatchreplace[current] = nil
+ local pre = getfield(current,"pre")
+ local replace = getfield(current,"replace")
+ if pre then
+ local n = n
+ while pre do
+ if seq[n][getchar(pre)] then
+ n = n + 1
+ pre = getnext(pre)
+ if not pre then
+ break
+ elseif n > s then
break
end
+ else
+ notmatchpre[current] = true
+ break
end
- if not match then
+ 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
+ replace = getnext(replace)
+ if not replace then
+ break
+ elseif n > s then
+ break
+ end
+ else
+ notmatchreplace[current] = true
+ if notmatchpre[current] then
+ match = false
+ end
break
- elseif check_discretionaries == "trace" then
- report_chain("check disc action in after")
end
- else
- -- skip 'm
+ end
+ if not match then
+ break
end
else
-- skip 'm
@@ -2294,7 +2605,8 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
end
end
if match then
- -- ck == currentcontext
+ -- can lookups be of a different type ?
+ local diskchain = diskseen or sweepnode
if trace_contexts then
local rule, lookuptype, f, l = ck[1], ck[2], ck[4], ck[5]
local char = getchar(start)
@@ -2314,10 +2626,14 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
local chainlookupname = chainlookups[1]
local chainlookup = lookuptable[chainlookupname]
if chainlookup then
- local cp = chainprocs[chainlookup.type]
- if cp then
+ local chainproc = chainprocs[chainlookup.type]
+ if chainproc then
local ok
- head, start, ok = cp(head,start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,nil,sequence)
+ if diskchain then
+ head, start, ok = chaindisk(head,start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,nil,sequence,chainproc)
+ else
+ head, start, ok = chainproc(head,start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,nil,sequence)
+ end
if ok then
done = true
end
@@ -2335,7 +2651,7 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
local char = getchar(start)
local ccd = descriptions[char]
if ccd then
- local class = ccd.class
+ local class = ccd.class or "base"
if class == skipmark or class == skipligature or class == skipbase or (markclass and class == "mark" and not markclass[char]) then
start = getnext(start)
else
@@ -2353,14 +2669,18 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
-- we just advance
i = i + 1
else
- local cp = chainmores[chainlookup.type]
- if not cp then
+ local chainproc = chainprocs[chainlookup.type]
+ if not chainproc then
-- actually an error
logprocess("%s: %s is not yet supported",cref(kind,chainname,chainlookupname),chainlookup.type)
i = i + 1
else
local ok, n
- head, start, ok, n = cp(head,start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,i,sequence)
+ if diskchain then
+ head, start, ok = chaindisk(head,start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,nil,sequence,chainproc)
+ else
+ head, start, ok, n = chainproc(head,start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,i,sequence)
+ end
-- messy since last can be changed !
if ok then
done = true
@@ -2401,8 +2721,16 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
end
end
end
+ if done then
+ break -- out of contexts (new, needs checking)
+ end
end
end
+ if diskchain then -- maybe move up so that we can turn checking on/off
+ notmatchpre = { }
+ notmatchpost = { }
+ notmatchreplace = { }
+ end
return head, start, done
end
@@ -2493,7 +2821,7 @@ local function initialize(sequence,script,language,enabled)
local scripts = features[kind] --
local languages = scripts[script] or scripts[wildcard]
if languages and (languages[language] or languages[wildcard]) then
- return { valid, autofeatures[kind] or false, sequence.chain or 0, kind, sequence }
+ return { valid, autofeatures[kind] or false, sequence, kind }
end
end
end
@@ -2537,33 +2865,6 @@ function otf.dataset(tfmdata,font) -- generic variant, overloaded in context
return rl
end
--- elseif id == glue_code then
--- if p[5] then -- chain
--- local pc = pp[32]
--- if pc then
--- start, ok = start, false -- p[1](start,kind,p[2],pc,p[3],p[4])
--- if ok then
--- done = true
--- end
--- if start then start = getnext(start) end
--- else
--- start = getnext(start)
--- end
--- else
--- start = getnext(start)
--- end
-
--- there will be a new direction parser (pre-parsed etc)
-
--- less bytecode: 290 -> 254
---
--- attr = attr or false
---
--- local a = getattr(start,0)
--- if (a == attr and (not attribute or getprop(start,a_state) == attribute)) or (not attribute or getprop(start,a_state) == attribute) then
--- -- the action
--- end
-
-- assumptions:
--
-- * languages that use complex disc nodes
@@ -2576,20 +2877,29 @@ local function kernrun(disc,run) -- we can assume that prev and next are glyphs
report_run("kern") -- will be more detailed
end
--
- local prev = getprev(disc) -- todo, keep these in the main loop
- local next = getnext(disc) -- todo, keep these in the main loop
+ local prev = getprev(disc) -- todo, keep these in the main loop
+ local next = getnext(disc) -- todo, keep these in the main loop
--
- local pre = getfield(disc,"pre")
- local post = getfield(disc,"post")
- local replace = getfield(disc,"replace")
+ local pre = getfield(disc,"pre")
+ local post = getfield(disc,"post")
+ local replace = getfield(disc,"replace")
+ --
+ local prevmarks = prev
--
- if pre or replace then
- if not (prev and getid(prev) == glyph_code and getfont(prev) == currentfont and getsubtype(prev)<256) then
+ -- can be optional:
+ --
+ -- while prevmarks and getid(prevmarks) == glyph_code and getfont(prevmarks) == currentfont and marks[getchar(prevmarks)] and getsubtype(prevmarks) < 256 do
+ while prevmarks and getid(prevmarks) == glyph_code and marks[getchar(prevmarks)] and getfont(prevmarks) == currentfont and getsubtype(prevmarks) < 256 do
+ prevmarks = getprev(prevmarks)
+ end
+ --
+ if prev and (pre or replace) then
+ if not (getid(prev) == glyph_code and getfont(prev) == currentfont and getsubtype(prev)<256) then
prev = false
end
end
- if post or replace then
- if not (next and getid(next) == glyph_code and getfont(next) == currentfont and getsubtype(next)<256) then
+ if next and (post or replace) then
+ if not (getid(next) == glyph_code and getfont(next) == currentfont and getsubtype(next)<256) then
next = false
end
end
@@ -2600,7 +2910,7 @@ local function kernrun(disc,run) -- we can assume that prev and next are glyphs
local nest = getprev(pre)
setfield(pre,"prev",prev)
setfield(prev,"next",pre)
- run(prev,"preinjections")
+ run(prevmarks,"preinjections")
setfield(pre,"prev",nest)
setfield(prev,"next",disc)
else
@@ -2613,7 +2923,7 @@ local function kernrun(disc,run) -- we can assume that prev and next are glyphs
local tail = find_node_tail(post)
setfield(tail,"next",next)
setfield(next,"prev",tail)
- run(post,"postinjections",tail)
+ run(post,"postinjections",next)
setfield(tail,"next",nil)
setfield(next,"prev",disc)
else
@@ -2622,6 +2932,11 @@ local function kernrun(disc,run) -- we can assume that prev and next are glyphs
--
if not replace and prev and next then
-- this should be already done by discfound
+ setfield(prev,"next",next)
+ setfield(next,"prev",prev)
+ run(prevmarks,"injections",next)
+ setfield(prev,"next",disc)
+ setfield(next,"prev",disc)
elseif prev and next then
local tail = find_node_tail(replace)
local nest = getprev(replace)
@@ -2629,7 +2944,7 @@ local function kernrun(disc,run) -- we can assume that prev and next are glyphs
setfield(prev,"next",replace)
setfield(tail,"next",next)
setfield(next,"prev",tail)
- run(prev,"replaceinjections",tail)
+ run(prevmarks,"replaceinjections",next)
setfield(replace,"prev",nest)
setfield(prev,"next",disc)
setfield(tail,"next",nil)
@@ -2638,14 +2953,14 @@ local function kernrun(disc,run) -- we can assume that prev and next are glyphs
local nest = getprev(replace)
setfield(replace,"prev",prev)
setfield(prev,"next",replace)
- run(prev,"replaceinjections")
+ run(prevmarks,"replaceinjections")
setfield(replace,"prev",nest)
setfield(prev,"next",disc)
elseif next then
local tail = find_node_tail(replace)
setfield(tail,"next",next)
setfield(next,"prev",tail)
- run(replace,"replaceinjections",tail)
+ run(replace,"replaceinjections",next)
setfield(tail,"next",nil)
setfield(next,"prev",disc)
else
@@ -2663,6 +2978,8 @@ local function comprun(disc,run)
--
local pre = getfield(disc,"pre")
if pre then
+ sweepnode = disc
+ sweeptype = "pre" -- in alternative code preinjections is used (also used then for proeprties, saves a variable)
local new, done = run(pre)
if done then
setfield(disc,"pre",new)
@@ -2671,6 +2988,8 @@ local function comprun(disc,run)
--
local post = getfield(disc,"post")
if post then
+ sweepnode = disc
+ sweeptype = "post"
local new, done = run(post)
if done then
setfield(disc,"post",new)
@@ -2679,14 +2998,18 @@ local function comprun(disc,run)
--
local replace = getfield(disc,"replace")
if replace then
+ sweepnode = disc
+ sweeptype = "replace"
local new, done = run(replace)
if done then
setfield(disc,"replace",new)
end
end
+ sweepnode = nil
+ sweeptype = nil
end
-local function testrun(disc,trun,crun)
+local function testrun(disc,trun,crun) -- use helper
local next = getnext(disc)
if next then
local replace = getfield(disc,"replace")
@@ -2784,6 +3107,7 @@ local function featuresprocessor(head,font,attr)
currentfont = font
rlmode = 0
+ sweephead = { }
local sequences = resources.sequences
local done = false
@@ -2810,18 +3134,18 @@ local function featuresprocessor(head,font,attr)
local dataset = datasets[s]
featurevalue = dataset[1] -- todo: pass to function instead of using a global
local attribute = dataset[2]
- local chain = dataset[3] -- sequence.chain or 0
+ local sequence = dataset[3] -- sequences[s] -- also dataset[5]
local kind = dataset[4]
- local sequence = dataset[5] -- sequences[s] -- also dataset[5]
+ ----- chain = dataset[5] -- sequence.chain or 0
local rlparmode = 0
local topstack = 0
local success = false
local typ = sequence.type
- local gpossing = typ == "gpos_single" or typ == "gpos_pair"
+ local gpossing = typ == "gpos_single" or typ == "gpos_pair" -- maybe all of them
local subtables = sequence.subtables
local handler = handlers[typ]
- if chain < 0 then
+ if typ == "gsub_reversecontextchain" then -- chain < 0
-- this is a limited case, no special treatments like 'init' etc
-- we need to get rid of this slide! probably no longer needed in latest luatex
local start = find_node_tail(head) -- slow (we can store tail because there's always a skip at the end): todo
@@ -2876,9 +3200,14 @@ local function featuresprocessor(head,font,attr)
report_missing_cache(typ,lookupname)
else
- local function c_run(start) -- no need to check for 256 and attr probably also the same
- local head = start
- local done = false
+ local function c_run(head) -- no need to check for 256 and attr probably also the same
+ local done = false
+ local start = sweephead[head]
+ if start then
+ sweephead[head] = nil
+ else
+ start = head
+ end
while start do
local id = getid(start)
if id ~= glyph_code then
@@ -3057,17 +3386,17 @@ local function featuresprocessor(head,font,attr)
local subtype = getsubtype(start)
if subtype == dir_code then
local dir = getfield(start,"dir")
- if dir == "+TRT" or dir == "+TLT" then
+ if dir == "+TLT" then
topstack = topstack + 1
dirstack[topstack] = dir
- elseif dir == "-TRT" or dir == "-TLT" then
- topstack = topstack - 1
- end
- local newdir = dirstack[topstack]
- if newdir == "+TRT" then
- rlmode = -1
- elseif newdir == "+TLT" then
rlmode = 1
+ elseif dir == "+TRT" then
+ topstack = topstack + 1
+ dirstack[topstack] = dir
+ rlmode = -1
+ elseif dir == "-TLT" or dir == "-TRT" then
+ topstack = topstack - 1
+ rlmode = dirstack[topstack] == "+TLT" and 1 or -1
else
rlmode = rlparmode
end
@@ -3100,9 +3429,14 @@ local function featuresprocessor(head,font,attr)
else
- local function c_run(start)
- local head = start
- local done = false
+ local function c_run(head)
+ local done = false
+ local start = sweephead[head]
+ if start then
+ sweephead[head] = nil
+ else
+ start = head
+ end
while start do
local id = getid(start)
if id ~= glyph_code then
@@ -3121,7 +3455,6 @@ local function featuresprocessor(head,font,attr)
local lookupname = subtables[i]
local lookupcache = lookuphash[lookupname]
if lookupcache then
- -- local lookupmatch = lookupcache[getchar(start)]
local lookupmatch = lookupcache[char]
if lookupmatch then
-- we could move all code inline but that makes things even more unreadable
@@ -3333,18 +3666,17 @@ local function featuresprocessor(head,font,attr)
elseif id == whatsit_code then
local subtype = getsubtype(start)
if subtype == dir_code then
- local dir = getfield(start,"dir")
- if dir == "+TRT" or dir == "+TLT" then
+ if dir == "+TLT" then
topstack = topstack + 1
dirstack[topstack] = dir
- elseif dir == "-TRT" or dir == "-TLT" then
- topstack = topstack - 1
- end
- local newdir = dirstack[topstack]
- if newdir == "+TRT" then
- rlmode = -1
- elseif newdir == "+TLT" then
rlmode = 1
+ elseif dir == "+TRT" then
+ topstack = topstack + 1
+ dirstack[topstack] = dir
+ rlmode = -1
+ elseif dir == "-TLT" or dir == "-TRT" then
+ topstack = topstack - 1
+ rlmode = dirstack[topstack] == "+TLT" and 1 or -1
else
rlmode = rlparmode
end
diff --git a/tex/context/base/font-ots.lua b/tex/context/base/font-ots.lua
index 74d7ac60b..27e0f161e 100644
--- a/tex/context/base/font-ots.lua
+++ b/tex/context/base/font-ots.lua
@@ -11,6 +11,10 @@ if not modules then modules = { } end modules ['font-ots'] = { -- sequences
-- cursives don't cross discretionaries
-- marks precede bases
+-- pitfalls:
+--
+-- when we append to a dics field we need to set the field in order to update tail
+
-- This is a version of font-otn.lua adapted to the new font loader code. It
-- is a context version which can contain experimental code, but when we
-- have serious patches we will backport to the font-otn files. There will
@@ -121,7 +125,6 @@ local trace_discruns = false registertracker("otf.discruns", function(v
local trace_compruns = false registertracker("otf.compruns", function(v) trace_compruns = v end)
local quit_on_no_replacement = true -- maybe per font
-local check_discretionaries = true -- "trace"
local zwnjruns = true
registerdirective("otf.zwnjruns", function(v) zwnjruns = v end)
@@ -131,9 +134,10 @@ local report_direct = logs.reporter("fonts","otf direct")
local report_subchain = logs.reporter("fonts","otf subchain")
local report_chain = logs.reporter("fonts","otf chain")
local report_process = logs.reporter("fonts","otf process")
-local report_prepare = logs.reporter("fonts","otf prepare")
+----- report_prepare = logs.reporter("fonts","otf prepare")
local report_warning = logs.reporter("fonts","otf warning")
local report_run = logs.reporter("fonts","otf run")
+local report_check = logs.reporter("fonts","otf check")
registertracker("otf.replacements", "otf.singles,otf.multiples,otf.alternatives,otf.ligatures")
registertracker("otf.positions","otf.marks,otf.kerns,otf.cursive")
@@ -244,6 +248,15 @@ local marks = false
local currentfont = false
local factor = 0
+local sweepnode = nil
+local sweepprev = nil
+local sweepnext = nil
+local sweephead = { }
+
+local notmatchpre = { }
+local notmatchpost = { }
+local notmatchreplace = { }
+
-- head is always a whatsit so we can safely assume that head is not changed
-- handlers .whatever(head,start, dataset,sequence,kerns, step,i,injection)
@@ -341,50 +354,157 @@ local function copy_glyph(g) -- next and prev are untouched !
end
end
--- temp here (context)
-
-local function collapse_disc(start,next)
- local replace1 = getfield(start,"replace")
- local replace2 = getfield(next,"replace")
- if replace1 and replace2 then
- local pre2 = getfield(next,"pre")
- local post2 = getfield(next,"post")
- setfield(replace1,"prev",nil)
- if pre2 then
- local pre1 = getfield(start,"pre")
- if pre1 then
- flush_node_list(pre1)
+-- temp here (context) - watch out: we need to set post/pre/replace in order to update its tail
+
+-- local function collapsedisc(start,next)
+-- local replace1 = getfield(start,"replace")
+-- local replace2 = getfield(next,"replace")
+-- if replace1 and replace2 then
+-- local pre2 = getfield(next,"pre")
+-- local post2 = getfield(next,"post")
+-- setfield(replace1,"prev",nil)
+-- if pre2 then
+-- local pre1 = getfield(start,"pre")
+-- if pre1 then
+-- flush_node_list(pre1)
+-- end
+-- local pre1 = copy_node_list(replace1)
+-- local tail1 = find_node_tail(pre1)
+-- setfield(tail1,"next",pre2)
+-- setfield(pre2,"prev",tail1)
+-- setfield(start,"pre",pre1)
+-- setfield(next,"pre",nil)
+-- else
+-- setfield(start,"pre",nil)
+-- end
+-- if post2 then
+-- local post1 = getfield(start,"post")
+-- if post1 then
+-- flush_node_list(post1)
+-- end
+-- setfield(start,"post",post2)
+-- else
+-- setfield(start,"post",nil)
+-- end
+-- local tail1 = find_node_tail(replace1)
+-- setfield(tail1,"next",replace2)
+-- setfield(replace2,"prev",tail1)
+-- setfield(start,"replace",replace1)
+-- setfield(next,"replace",nil)
+-- --
+-- local nextnext = getnext(next)
+-- setfield(nextnext,"prev",start)
+-- setfield(start,"next",nextnext)
+-- free_node(next)
+-- else
+-- -- maybe remove it
+-- end
+-- end
+
+-- local function prependdisc(first,last,prev)
+-- local prev = prev or getprev(first)
+-- local pre = getfield(last,"pre")
+-- local replace = getfield(last,"replace")
+-- local rs = getfield(first,"replace")
+-- local ps = copy_node_list(rs)
+-- local rt = ps and find_node_tail(rs)
+-- local pt = rs and find_node_tail(ps)
+-- if pre then
+-- setfield(pre,"prev",pt)
+-- setfield(pt,"next",pre)
+-- end
+-- if replace then
+-- setfield(replace,"prev",rt)
+-- setfield(rt,"next",replace)
+-- end
+-- setfield(last,"pre",ps)
+-- setfield(last,"replace",rs)
+-- setfield(first,"replace",nil)
+-- free_node(first)
+-- setfield(last,"prev",prev)
+-- setfield(prev,"next",last)
+-- return prev -- if nil then last is head
+-- end
+
+-- local function prependglyph(first,last,prev)
+-- local prev = prev or getprev(first)
+-- local pre = getfield(last,"pre")
+-- local replace = getfield(last,"replace")
+-- local rs = first
+-- local ps = copy_node(first)
+-- if pre then
+-- setfield(pre,"prev",ps)
+-- setfield(ps,"next",pre)
+-- end
+-- if replace then
+-- setfield(replace,"prev",rs)
+-- setfield(rs,"next",replace)
+-- end
+-- setfield(last,"pre",ps)
+-- setfield(last,"replace",rs)
+-- setfield(last,"prev",prev)
+-- setfield(prev,"next",last)
+-- return prev -- if nil then last is head
+-- end
+
+local function flattendisk(head,disc)
+ local replace = getfield(disc,"replace")
+ setfield(disc,"replace",nil)
+ free_node(disc)
+ if head == disc then
+ local next = getnext(disc)
+ if replace then
+ if next then
+ local tail = find_node_tail(replace)
+ setfield(tail,"next",next)
+ setfield(next,"prev",tail)
end
- local pre1 = copy_node_list(replace1)
- local tail1 = find_node_tail(pre1)
- setfield(tail1,"next",pre2)
- setfield(pre2,"prev",tail1)
- setfield(start,"pre",pre1)
- setfield(next,"pre",nil)
+ return replace, replace
+ elseif next then
+ return next, next
else
- setfield(start,"pre",nil)
+ return -- maybe warning
end
- if post2 then
- local post1 = getfield(start,"post")
- if post1 then
- flush_node_list(post1)
+ else
+ local next = getnext(disc)
+ local prev = getprev(disc)
+ if replace then
+ local tail = find_node_tail(replace)
+ if next then
+ setfield(tail,"next",next)
+ setfield(next,"prev",tail)
end
- setfield(start,"post",post2)
+ setfield(prev,"next",replace)
+ setfield(replace,"prev",prev)
+ return head, replace
else
- setfield(start,"post",nil)
- end
- local tail1 = find_node_tail(replace1)
- setfield(tail1,"next",replace2)
- setfield(replace2,"prev",tail1)
- setfield(start,"replace",replace1)
- setfield(next,"replace",nil)
- --
- local nextnext = getnext(next)
- setfield(nextnext,"prev",start)
- setfield(start,"next",nextnext)
- free_node(next)
+ if next then
+ setfield(next,"prev",prev)
+ end
+ setfield(prev,"next",next)
+ return head, next
+ end
+ end
+end
+
+local function appenddisc(disc,list)
+ local post = getfield(disc,"post")
+ local replace = getfield(disc,"replace")
+ local phead = list
+ local rhead = copy_node_list(list)
+ local ptail = find_node_tail(post)
+ local rtail = find_node_tail(replace)
+ if post then
+ setfield(ptail,"next",phead)
+ setfield(phead,"prev",ptail)
+ else
+ setfield(disc,"post",phead)
+ end
+ if replace then
+ setfield(rtail,"next",rhead)
+ setfield(rhead,"prev",rtail)
else
- -- maybe remove it
+ setfield(disc,"replace",rhead)
end
end
@@ -425,8 +545,8 @@ end
-- iteration this becomes a KAF-LAM-ALEF with a SHADDA on the second and a FATHA on the
-- third component.
-local function getcomponentindex(start)
- if getid(start) ~= glyph_code then
+local function getcomponentindex(start) -- we could store this offset in the glyph (nofcomponents)
+ if getid(start) ~= glyph_code then -- and then get rid of all components
return 0
elseif getsubtype(start) == ligature_code then
local i = 0
@@ -899,7 +1019,7 @@ function handlers.gpos_pair(head,start,dataset,sequence,kerns,rlmode,step,i,inje
if b and #b > 0 then
local x, y, w, h = setpair(snext,factor,rlmode,sequence.flags[4],b,injection) -- characters[nextchar])
if trace_kerns then
- local startchar = getchar(start)
+ local startchar = getchar(snext)
logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p)",pref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h)
end
end
@@ -1225,83 +1345,7 @@ function chainprocs.gsub_single(head,start,stop,dataset,sequence,currentlookup,c
logprocess("%s: replacing single %s by %s",cref(dataset,sequence,chainindex),gref(currentchar),gref(replacement))
end
resetinjection(current)
- if check_discretionaries then
- -- some fonts use a chain lookup to replace e.g. an f in a fi ligature
- -- and there can be a disc node in between ... the next code tries to catch
- -- this
- local next = getnext(current)
- local prev = getprev(current) -- todo: just remember it above
- local done = false
- if next then
- if getid(next) == disc_code then
- local subtype = getsubtype(next)
- if subtype == discretionary_code then
- setfield(next,"prev",prev)
- setfield(prev,"next",next)
- setfield(current,"prev",nil)
- setfield(current,"next",nil)
- local replace = getfield(next,"replace")
- local pre = getfield(next,"pre")
- local new = copy_node(current)
- setfield(new,"char",replacement)
- if replace then
- setfield(new,"next",replace)
- setfield(replace,"prev",new)
- end
- if pre then
- setfield(current,"next",pre)
- setfield(pre,"prev",current)
- end
- setfield(next,"replace",new) -- also updates tail
- setfield(next,"pre",current) -- also updates tail
- end
- start = next
- done = true
- local next = getnext(start)
- if next and getid(next) == disc_code then
- collapse_disc(start,next)
- end
- end
- end
- if not done and prev then
- if getid(prev) == disc_code then
- local subtype = getsubtype(prev)
- if subtype == discretionary_code then
- setfield(next,"prev",prev)
- setfield(prev,"next",next)
- setfield(current,"prev",nil)
- setfield(current,"next",nil)
- local replace = getfield(prev,"replace")
- local post = getfield(prev,"post")
- local new = copy_node(current)
- setfield(new,"char",replacement)
- if replace then
- local tail = find_node_tail(replace)
- setfield(tail,"next",new)
- setfield(new,"prev",tail)
- else
- replace = new
- end
- if post then
- local tail = find_node_tail(post)
- setfield(tail,"next",current)
- setfield(current,"prev",tail)
- else
- post = current
- end
- setfield(prev,"replace",replace) -- also updates tail
- setfield(prev,"post",post) -- also updates tail
- start = prev
- done = true
- end
- end
- end
- if not done then
- setfield(current,"char",replacement)
- end
- else
- setfield(current,"char",replacement)
- end
+ setfield(current,"char",replacement)
end
return head, start, true
elseif current == stop then
@@ -1317,8 +1361,6 @@ end
<p>Here we replace start by a sequence of new glyphs.</p>
--ldx]]--
--- disc?
-
function chainprocs.gsub_multiple(head,start,stop,dataset,sequence,currentlookup)
local steps = currentlookup.steps
local nofsteps = currentlookup.nofsteps
@@ -1352,10 +1394,6 @@ end
-- marks come last anyway
-- are there cases where we need to delete the mark
--- maybe we can share them ...
-
--- disc ?
-
function chainprocs.gsub_alternate(head,start,stop,dataset,sequence,currentlookup)
local steps = currentlookup.steps
local nofsteps = currentlookup.nofsteps
@@ -1504,8 +1542,6 @@ function chainprocs.gpos_single(head,start,stop,dataset,sequence,currentlookup,r
return head, start, false
end
--- when machines become faster i will make a shared function
-
function chainprocs.gpos_pair(head,start,stop,dataset,sequence,currentlookup,rlmode,chainindex)
local steps = currentlookup.steps
local nofsteps = currentlookup.nofsteps
@@ -1783,7 +1819,382 @@ local function show_skip(dataset,sequence,char,ck,class)
logwarning("%s: skipping char %s, class %a, rule %a, lookuptype %a",cref(dataset,sequence),gref(char),class,ck[1],ck[8])
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
+-- (sweepnode, sweepmode, sweepprev, sweepnext, etc). 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.)
+--
+-- 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 function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,ck,chainproc)
+
+ if not start then
+ return -- safeguard
+ end
+
+ local startishead = start == head
+ local seq = ck[3]
+ local f = ck[4]
+ local l = ck[5]
+ local s = #seq
+ local done = false
+ local sweepnode = sweepnode
+ local sweeptype = sweeptype
+ local sweepoverflow = false
+ local checkdisc = getprev(head) -- hm bad name head
+ local keepdisc = not sweepnode
+ local lookaheaddisc = nil
+ local backtrackdisc = nil
+ local current = start
+ local last = start
+ local prev = getprev(start)
+
+ -- fishy: so we can overflow and then go on in the sweep?
+
+ local i = f
+ while i <= l do
+ local id = getid(current)
+ if id == glyph_code then
+ i = i + 1
+ last = current
+ current = getnext(current)
+ elseif id == disc_code then
+ if keepdisc then
+ keepdisc = false
+ if notmatchpre[current] ~= notmatchreplace[current] then
+ lookaheaddisc = current
+ end
+ local replace = getfield(current,"replace")
+ while replace and i <= l do
+ if getid(replace) == glyph_code then
+ i = i + 1
+ end
+ replace = getnext(replace)
+ end
+ last = current
+ current = getnext(c)
+ else
+ head, current = flattendisk(head,current)
+ end
+ else
+ last = current
+ current = getnext(current)
+ end
+ if current then
+ -- go on
+ elseif sweepoverflow then
+ -- we already are folling up on sweepnode
+ break
+ elseif sweeptype == "post" or sweeptype == "replace" then
+ current = getnext(sweepnode)
+ if current then
+ sweeptype = nil
+ sweepoverflow = true
+ else
+ break
+ end
+ end
+ end
+
+ if sweepoverflow then
+ local prev = current and getprev(current)
+ if not current or prev ~= sweepnode then
+ local head = getnext(sweepnode)
+ local tail = nil
+ if prev then
+ tail = prev
+ setfield(current,"prev",sweepnode)
+ else
+ tail = find_node_tail(head)
+ end
+ setfield(sweepnode,"next",current)
+ setfield(head,"prev",nil)
+ setfield(tail,"next",nil)
+ appenddisc(sweepnode,head)
+ end
+ end
+
+ if l < s then
+ local i = l
+ local t = sweeptype == "post" or sweeptype == "replace"
+ while current and i < s do
+ local id = getid(current)
+ if id == glyph_code then
+ i = i + 1
+ current = getnext(current)
+ elseif id == disc_code then
+ if keepdisc then
+ keepdisc = false
+ if notmatchpre[current] ~= notmatchreplace[current] then
+ lookaheaddisc = current
+ end
+ local replace = getfield(c,"replace")
+ while replace and i < s do
+ if getid(replace) == glyph_code then
+ i = i + 1
+ end
+ replace = getnext(replace)
+ end
+ current = getnext(current)
+ elseif notmatchpre[current] ~= notmatchreplace[current] then
+ head, current = flattendisk(head,current)
+ else
+ current = getnext(current) -- HH
+ end
+ else
+ current = getnext(current)
+ end
+ if not current and t then
+ current = getnext(sweepnode)
+ if current then
+ sweeptype = nil
+ end
+ end
+ end
+ end
+
+ if f > 1 then
+ local current = prev
+ local i = f
+ local t = sweeptype == "pre" or sweeptype == "replace"
+ if not current and t and current == checkdisk then
+ current = getprev(sweepnode)
+ end
+ while current and i > 1 do -- missing getprev added / moved outside
+ local id = getid(current)
+ if id == glyph_code then
+ i = i - 1
+ elseif id == disc_code then
+ if keepdisc then
+ keepdisc = false
+ if notmatchpost[current] ~= notmatchreplace[current] then
+ backtrackdisc = current
+ end
+ local replace = getfield(current,"replace")
+ while replace and i > 1 do
+ if getid(replace) == glyph_code then
+ i = i - 1
+ end
+ replace = getnext(replace)
+ end
+ elseif notmatchpost[current] ~= notmatchreplace[current] then
+ head, current = flattendisk(head,current)
+ end
+ end
+ current = getprev(current)
+ if t and current == checkdisk then
+ current = getprev(sweepnode)
+ end
+ end
+ end
+
+ local ok = false
+ if lookaheaddisc then
+
+ local cf = start
+ local cl = getprev(lookaheaddisc)
+ local cprev = getprev(start)
+ local insertedmarks = 0
+
+ while cprev and getid(cf) == glyph_code and getfont(cf) == currentfont and marks[getchar(cf)] and getsubtype(cf) < 256 do
+ insertedmarks = insertedmarks + 1
+ cf = cprev
+ startishead = cf == head
+ cprev = getprev(cprev)
+ end
+
+ setfield(lookaheaddisc,"prev",cprev)
+ if cprev then
+ setfield(cprev,"next",lookaheaddisc)
+ end
+ setfield(cf,"prev",nil)
+ setfield(cl,"next",nil)
+ if startishead then
+ head = lookaheaddisc
+ end
+
+ local replace = getfield(lookaheaddisc,"replace")
+ local pre = getfield(lookaheaddisc,"pre")
+ local new = copy_node_list(cf)
+ local cnew = new
+ for i=1,insertedmarks do
+ cnew = getnext(cnew)
+ end
+ local clast = cnew
+ for i=f,l do
+ clast = getnext(clast)
+ end
+ if not notmatchpre[lookaheaddisc] then
+ cf, start, ok = chainproc(cf,start,last,dataset,sequence,chainlookup,rlmode,k)
+ end
+ if not notmatchreplace[lookaheaddisc] then
+ new, cnew, ok = chainproc(new,cnew,clast,dataset,sequence,chainlookup,rlmode,k)
+ end
+ if pre then
+ setfield(cl,"next",pre)
+ setfield(pre,"prev",cl)
+ end
+ if replace then
+ local tail = find_node_tail(new)
+ setfield(tail,"next",replace)
+ setfield(replace,"prev",tail)
+ end
+ setfield(lookaheaddisc,"pre",cf) -- also updates pre-tail
+ setfield(lookaheaddisc,"replace",new) -- also updates replace-tail
+
+ start = getprev(lookaheaddisc)
+ sweephead[cf] = getnext(clast)
+ sweephead[new] = getnext(last)
+
+ elseif backtrackdisc then
+
+ local cf = getnext(backtrackdisc)
+ local cl = start
+ local cnext = getnext(start)
+ local insertedmarks = 0
+
+ while cnext and getid(cnext) == glyph_code and getfont(cnext) == currentfont and marks[getchar(cnext)] and getsubtype(cnext) < 256 do
+ insertedmarks = insertedmarks + 1
+ cl = cnext
+ cnext = getnext(cnext)
+ end
+ if cnext then
+ setfield(cnext,"prev",backtrackdisc)
+ end
+ setfield(backtrackdisc,"next",cnext)
+ setfield(cf,"prev",nil)
+ setfield(cl,"next",nil)
+ local replace = getfield(backtrackdisc,"replace")
+ local post = getfield(backtrackdisc,"post")
+ local new = copy_node_list(cf)
+ local cnew = find_node_tail(new)
+ for i=1,insertedmarks do
+ cnew = getprev(cnew)
+ end
+ local clast = cnew
+ for i=f,l do
+ clast = getnext(clast)
+ end
+ if not notmatchpost[backtrackdisc] then
+ cf, start, ok = chainproc(cf,start,last,dataset,sequence,chainlookup,rlmode,k)
+ end
+ if not notmatchreplace[backtrackdisc] then
+ new, cnew, ok = chainproc(new,cnew,clast,dataset,sequence,chainlookup,rlmode,k)
+ end
+ if post then
+ local tail = find_node_tail(post)
+ setfield(tail,"next",cf)
+ setfield(cf,"prev",tail)
+ else
+ post = cf
+ end
+ if replace then
+ local tail = find_node_tail(replace)
+ setfield(tail,"next",new)
+ setfield(new,"prev",tail)
+ else
+ replace = new
+ end
+ setfield(backtrackdisc,"post",post) -- also updates post-tail
+ setfield(backtrackdisc,"replace",replace) -- also updates replace-tail
+ start = getprev(backtrackdisc)
+ sweephead[post] = getnext(clast)
+ sweephead[replace] = getnext(last)
+
+ else
+
+ head, start, ok = chainproc(head,start,last,dataset,sequence,chainlookup,rlmode,k)
+
+ end
+
+ return head, start, ok
+end
+
+-- helpers from elsewhere
+
+-- local function currentmatch(current,n,l)
+-- while current do
+-- if getid(current) ~= glyph_code then
+-- return false
+-- elseif seq[n][getchar(current)] then
+-- n = n + 1
+-- current = getnext(current)
+-- if not current then
+-- return true, n, current
+-- elseif n > l then
+-- -- match = false
+-- return true, n, current
+-- end
+-- else
+-- return false
+-- end
+-- end
+-- end
+--
+-- local function aftermatch(current,n,l)
+-- while current do
+-- if getid(current) ~= glyph_code then
+-- return false
+-- elseif seq[n][getchar(current)] then
+-- n = n + 1
+-- current = getnext(current)
+-- if not current then
+-- return true, n, current
+-- elseif n > l then
+-- -- match = false
+-- return true, n, current
+-- end
+-- else
+-- return false
+-- end
+-- end
+-- end
+--
+-- local function beforematch(current,n)
+-- local finish = getprev(current)
+-- local current = find_node_tail(current)
+-- while current do
+-- if getid(current) ~= glyph_code then
+-- return false
+-- elseif seq[n][getchar(current)] then
+-- n = n - 1
+-- current = getprev(current)
+-- if not current or current == finish then
+-- return true, n, current
+-- elseif n < 1 then
+-- -- match = false
+-- return true, n, current
+-- end
+-- else
+-- return false
+-- end
+-- end
+-- end
+
local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode)
+ local sweepnode = sweepnode
+ local sweeptype = sweeptype
+ local diskseen = false
+ local checkdisc = getprev(head)
local flags = sequence.flags
local done = false
local skipmark = flags[1]
@@ -1791,7 +2202,7 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode)
local skipbase = flags[3]
local markclass = sequence.markclass
local skipped = false
- for k=1,#contexts do
+ for k=1,#contexts do -- i've only seen ccmp having > 1 (e.g. dejavu)
local match = true
local current = start
local last = start
@@ -1809,7 +2220,7 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode)
local l = ck[5]
-- current match
if f == 1 and f == l then -- current only
- -- already a hit -- do we need to check for mark?
+ -- already a hit
-- match = true
else -- before/current/after | before/current | current/after
-- no need to test first hit (to be optimized)
@@ -1819,6 +2230,10 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode)
local n = f + 1
last = getnext(last)
while n <= l do
+ if not last and (sweeptype == "post" or sweeptype == "replace") then
+ last = getnext(sweepnode)
+ sweeptype = nil
+ end
if last then
local id = getid(last)
if id == glyph_code then
@@ -1851,39 +2266,59 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode)
break
end
elseif id == disc_code then
- if check_discretionaries then
- local replace = getfield(last,"replace")
- if replace then
- -- so far we never entered this branch
- while replace do
- if seq[n][getchar(replace)] then
- n = n + 1
- replace = getnext(replace)
- if not replace then
- break
- elseif n > l then
- -- match = false
- break
- end
- else
- match = false
+ diskseen = true
+ notmatchpre[last] = nil
+ notmatchpost[last] = true
+ notmatchreplace[last] = nil
+ local pre = getfield(last,"pre")
+ if pre then
+ local n = n
+ while pre do
+ if seq[n][getchar(pre)] then
+ n = n + 1
+ pre = getnext(pre)
+ if not pre then
+ break
+ elseif n > l then
break
end
+ else
+ notmatchpre[last] = true
+ break
end
- if not match then
+ end
+ else
+ notmatchpre[last] = true
+ end
+ local replace = getfield(last,"replace")
+ if replace then
+ -- so far we never entered this branch
+ while replace do
+ if seq[n][getchar(replace)] then
+ n = n + 1
+ replace = getnext(replace)
+ if not replace then
+ break
+ elseif n > l then
+ -- match = false
+ break
+ end
+ else
+ notmatchreplace[last] = true
+ if notmatchpre[last] then
+ match = false
+ end
break
- elseif check_discretionaries == "trace" then
- report_chain("check disc action in current")
end
- else
- last = getnext(last) -- no skipping here
+ end
+ if not match then
+ break
end
else
last = getnext(last) -- no skipping here
end
else
- match = false
- break
+ last = getnext(last) -- no skipping here
end
else
match = false
@@ -1896,23 +2331,32 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode)
if match and f > 1 then
local prev = getprev(start)
if prev then
- local n = f-1
- while n >= 1 do
- if prev then
- local id = getid(prev)
- if id == glyph_code then
- if getfont(prev) == currentfont and getsubtype(prev)<256 then -- normal char
- local char = getchar(prev)
- local ccd = descriptions[char]
- if ccd then
- local class = ccd.class or "base"
- if class == skipmark or class == skipligature or class == skipbase or (markclass and class == "mark" and not markclass[char]) then
- skipped = true
- if trace_skips then
- show_skip(dataset,sequence,char,ck,class)
+ if prev == checkdisc and (sweeptype == "pre" or sweeptype == "replace") then
+ prev = getprev(sweepnode)
+ -- sweeptype = nil
+ end
+ if prev then
+ local n = f-1
+ while n >= 1 do
+ if prev then
+ local id = getid(prev)
+ if id == glyph_code then
+ if getfont(prev) == currentfont and getsubtype(prev)<256 then -- normal char
+ local char = getchar(prev)
+ local ccd = descriptions[char]
+ if ccd then
+ local class = ccd.class
+ if class == skipmark or class == skipligature or class == skipbase or (markclass and class == "mark" and not markclass[char]) then
+ skipped = true
+ if trace_skips then
+ show_skip(kind,chainname,char,ck,class)
+ end
+ elseif seq[n][char] then
+ n = n -1
+ else
+ match = false
+ break
end
- elseif seq[n][char] then
- n = n -1
else
match = false
break
@@ -1921,57 +2365,84 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode)
match = false
break
end
- else
- match = false
- break
- end
- elseif id == disc_code then
- -- the special case: f i where i becomes dottless i ..
- if check_discretionaries then
+ elseif id == disc_code then
+ -- the special case: f i where i becomes dottless i ..
+ diskseen = true
+ notmatchpre[prev] = true
+ notmatchpost[prev] = nil
+ notmatchreplace[prev] = nil
+ local pre = getfield(prev,"pre")
+ local post = getfield(prev,"post")
local replace = getfield(prev,"replace")
- if replace then
- -- we seldom enter this branch (e.g. on brill efficient)
- replace = find_node_tail(replace)
- local finish = getprev(replace)
- while replace do
- if seq[n][getchar(replace)] then
- n = n - 1
- replace = getprev(replace)
- if not replace or replace == finish then
+ if pre ~= start and post ~= start and replace ~= start then
+ if post then
+ local n = n
+ post = find_node_tail(post)
+ local finish = getprev(post)
+ while post do
+ if seq[n][getchar(post)] then
+ n = n - 1
+ post = getprev(post)
+ if not post or post == finish then
+ break
+ elseif n < 1 then
+ break
+ end
+ else
+ notmatchpost[prev] = true
break
- elseif n < 1 then
- -- match = false
+ end
+ end
+ else
+ notmatchpost[prev] = true
+ end
+ if replace then
+ -- we seldom enter this branch (e.g. on brill efficient)
+ replace = find_node_tail(replace)
+ local finish = getprev(replace)
+ while replace do
+ if seq[n][getchar(replace)] then
+ n = n - 1
+ replace = getprev(replace)
+ if not replace or replace == finish then
+ break
+ elseif n < 1 then
+ -- match = false
+ break
+ end
+ else
+ notmatchreplace[prev] = true
+ if notmatchpost[prev] then
+ match = false
+ end
break
end
- else
- match = false
+ end
+ if not match then
break
end
- end
- if not match then
- break
- elseif check_discretionaries == "trace" then
- report_chain("check disc action in before")
+ else
+ -- skip 'm
end
else
-- skip 'm
end
+ elseif seq[n][32] then
+ n = n -1
else
- -- skip 'm
+ match = false
+ break
end
- elseif seq[n][32] then
- n = n -1
+ prev = getprev(prev)
+ elseif seq[n][32] then -- somewhat special, as zapfino can have many preceding spaces
+ n = n - 1
else
match = false
break
end
- prev = getprev(prev)
- elseif seq[n][32] then -- somewhat special, as zapfino can have many preceding spaces
- n = n - 1
- else
- match = false
- break
end
+ else
+ match = false
end
else
match = false
@@ -1980,6 +2451,12 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode)
-- after
if match and s > l then
local current = last and getnext(last)
+ if not current then
+ if sweeptype == "post" or sweeptype == "replace" then
+ current = getnext(sweepnode)
+ -- sweeptype = nil
+ end
+ end
if current then
-- removed optimization for s-l == 1, we have to deal with marks anyway
local n = l + 1
@@ -1989,13 +2466,13 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode)
if id == glyph_code then
if getfont(current) == currentfont and getsubtype(current)<256 then -- normal char
local char = getchar(current)
- local ccd = descriptions[char] -- TODO: we have a marks array !
+ local ccd = descriptions[char]
if ccd then
- local class = ccd.class or "base"
+ local class = ccd.class
if class == skipmark or class == skipligature or class == skipbase or (markclass and class == "mark" and not markclass[char]) then
skipped = true
if trace_skips then
- show_skip(dataset,sequence,char,ck,class)
+ show_skip(kind,chainname,char,ck,class)
end
elseif seq[n][char] then
n = n + 1
@@ -2012,31 +2489,52 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode)
break
end
elseif id == disc_code then
- if check_discretionaries then
- local replace = getfield(current,"replace")
- if replace then
- -- so far we never entered this branch
- while replace do
- if seq[n][getchar(replace)] then
- n = n + 1
- replace = getnext(replace)
- if not replace then
- break
- elseif n > s then
- break
- end
- else
- match = false
+ diskseen = true
+ notmatchpre[current] = nil
+ notmatchpost[current] = true
+ notmatchreplace[current] = nil
+ local pre = getfield(current,"pre")
+ local replace = getfield(current,"replace")
+ if pre then
+ local n = n
+ while pre do
+ if seq[n][getchar(pre)] then
+ n = n + 1
+ pre = getnext(pre)
+ if not pre then
+ break
+ elseif n > s then
break
end
+ else
+ notmatchpre[current] = true
+ break
end
- if not match then
+ 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
+ replace = getnext(replace)
+ if not replace then
+ break
+ elseif n > s then
+ break
+ end
+ else
+ notmatchreplace[current] = true
+ if notmatchpre[current] then
+ match = false
+ end
break
- elseif check_discretionaries == "trace" then
- report_chain("check disc action in after")
end
- else
- -- skip 'm
+ end
+ if not match then
+ break
end
else
-- skip 'm
@@ -2062,6 +2560,7 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode)
end
if match then
-- can lookups be of a different type ?
+ local diskchain = diskseen or sweepnode
if trace_contexts then
local rule = ck[1]
local lookuptype = ck[8]
@@ -2081,7 +2580,11 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode)
local chainproc = chainprocs[chainkind]
if chainproc then
local ok
- head, start, ok = chainproc(head,start,last,dataset,sequence,chainlookup,rlmode,1)
+ if diskchain then
+ head, start, ok = chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,1,ck,chainproc)
+ else
+ head, start, ok = chainproc(head,start,last,dataset,sequence,chainlookup,rlmode,1)
+ end
if ok then
done = true
end
@@ -2117,7 +2620,11 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode)
local chainproc = chainprocs[chainkind]
if chainproc then
local ok, n
- head, start, ok, n = chainproc(head,start,last,dataset,sequence,chainlookup,rlmode,i)
+ if diskchain then
+ head, start, ok = chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,i,ck,chainproc)
+ else
+ head, start, ok, n = chainproc(head,start,last,dataset,sequence,chainlookup,rlmode,i)
+ end
-- messy since last can be changed !
if ok then
done = true
@@ -2161,8 +2668,16 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode)
end
end
end
+ if done then
+ break -- out of contexts (new, needs checking)
+ end
end
end
+ if diskseen then
+ notmatchpre = { }
+ notmatchpost = { }
+ notmatchreplace = { }
+ end
return head, start, done
end
@@ -2221,13 +2736,7 @@ local function initialize(sequence,script,language,enabled)
local scripts = features[kind] --
local languages = scripts[script] or scripts[wildcard]
if languages and (languages[language] or languages[wildcard]) then
- return {
- valid,
- autofeatures[kind] or false,
- sequence.chain or 0,
- kind,
- sequence,
- }
+ return { valid, autofeatures[kind] or false, sequence, kind }
end
end
end
@@ -2283,20 +2792,29 @@ local function kernrun(disc,run)
report_run("kern") -- will be more detailed
end
--
- local prev = getprev(disc) -- todo, keep these in the main loop
- local next = getnext(disc) -- todo, keep these in the main loop
+ local prev = getprev(disc) -- todo, keep these in the main loop
+ local next = getnext(disc) -- todo, keep these in the main loop
--
- local pre = getfield(disc,"pre")
- local post = getfield(disc,"post")
- local replace = getfield(disc,"replace")
+ local pre = getfield(disc,"pre")
+ local post = getfield(disc,"post")
+ local replace = getfield(disc,"replace")
--
- if pre or replace then
- if not (prev and getid(prev) == glyph_code and getfont(prev) == currentfont and getsubtype(prev)<256) then
+ local prevmarks = prev
+ --
+ -- can be optional, because why on earth do we get a disc after a mark (okay, maybe when a ccmp
+ -- has happened but then it should be in the disc so basically this test indicates an error)
+ --
+ while prevmarks and getid(prevmarks) == glyph_code and marks[getchar(prevmarks)] and getfont(prevmarks) == currentfont and getsubtype(prevmarks) < 256 do
+ prevmarks = getprev(prevmarks)
+ end
+ --
+ if prev and (pre or replace) then
+ if not (getid(prev) == glyph_code and getfont(prev) == currentfont and getsubtype(prev)<256) then
prev = false
end
end
- if post or replace then
- if not (next and getid(next) == glyph_code and getfont(next) == currentfont and getsubtype(next)<256) then
+ if next and (post or replace) then
+ if not (getid(next) == glyph_code and getfont(next) == currentfont and getsubtype(next)<256) then
next = false
end
end
@@ -2307,7 +2825,7 @@ local function kernrun(disc,run)
local nest = getprev(pre)
setfield(pre,"prev",prev)
setfield(prev,"next",pre)
- run(prev,"preinjections")
+ run(prevmarks,"preinjections")
setfield(pre,"prev",nest)
setfield(prev,"next",disc)
else
@@ -2320,7 +2838,7 @@ local function kernrun(disc,run)
local tail = find_node_tail(post)
setfield(tail,"next",next)
setfield(next,"prev",tail)
- run(post,"postinjections",tail)
+ run(post,"postinjections",next)
setfield(tail,"next",nil)
setfield(next,"prev",disc)
else
@@ -2329,6 +2847,11 @@ local function kernrun(disc,run)
--
if not replace and prev and next then
-- this should be already done by discfound
+ setfield(prev,"next",next)
+ setfield(next,"prev",prev)
+ run(prevmarks,"injections",next)
+ setfield(prev,"next",disc)
+ setfield(next,"prev",disc)
elseif prev and next then
local tail = find_node_tail(replace)
local nest = getprev(replace)
@@ -2336,7 +2859,7 @@ local function kernrun(disc,run)
setfield(prev,"next",replace)
setfield(tail,"next",next)
setfield(next,"prev",tail)
- run(prev,"replaceinjections",tail)
+ run(prevmarks,"replaceinjections",next)
setfield(replace,"prev",nest)
setfield(prev,"next",disc)
setfield(tail,"next",nil)
@@ -2345,14 +2868,14 @@ local function kernrun(disc,run)
local nest = getprev(replace)
setfield(replace,"prev",prev)
setfield(prev,"next",replace)
- run(prev,"replaceinjections")
+ run(prevmarks,"replaceinjections")
setfield(replace,"prev",nest)
setfield(prev,"next",disc)
- elseif next then
+ elseif next then
local tail = find_node_tail(replace)
setfield(tail,"next",next)
setfield(next,"prev",tail)
- run(replace,"replaceinjections",tail)
+ run(replace,"replaceinjections",next)
setfield(tail,"next",nil)
setfield(next,"prev",disc)
else
@@ -2363,6 +2886,15 @@ end
-- the if new test might be dangerous as luatex will check / set some tail stuff
-- in a temp node
+local function checkdisc(str,d) -- only used when debugging
+ report_check("%s : [%s][%s][%s]",
+ str,
+ nodes.toutf(getfield(d,"pre")),
+ nodes.toutf(getfield(d,"post")),
+ nodes.toutf(getfield(d,"replace"))
+ )
+end
+
local function comprun(disc,run)
if trace_compruns then
report_run("comp: %s",languages.serializediscretionary(disc))
@@ -2370,6 +2902,8 @@ local function comprun(disc,run)
--
local pre = getfield(disc,"pre")
if pre then
+ sweepnode = disc
+ sweeptype = "pre" -- in alternative code preinjections is used (also used then for proeprties, saves a variable)
local new, done = run(pre)
if done then
setfield(disc,"pre",new)
@@ -2378,6 +2912,8 @@ local function comprun(disc,run)
--
local post = getfield(disc,"post")
if post then
+ sweepnode = disc
+ sweeptype = "post"
local new, done = run(post)
if done then
setfield(disc,"post",new)
@@ -2386,14 +2922,18 @@ local function comprun(disc,run)
--
local replace = getfield(disc,"replace")
if replace then
+ sweepnode = disc
+ sweeptype = "replace"
local new, done = run(replace)
if done then
setfield(disc,"replace",new)
end
end
+ sweepnode = nil
+ sweeptype = nil
end
-local function testrun(disc,trun,crun)
+local function testrun(disc,trun,crun) -- use helper
local next = getnext(disc)
if next then
local replace = getfield(disc,"replace")
@@ -2464,6 +3004,28 @@ end
-- todo: maybe run lr and rl stretches
+local function txtdirstate(start,stack,top,rlparmode)
+ local dir = getfield(start,"dir")
+ if dir == "+TRT" then
+ top = top + 1
+ stack[top] = dir
+ return top, -1
+ elseif dir == "+TLT" then
+ top = top + 1
+ stack[top] = dir
+ return top, 1
+ end
+ if dir == "-TRT" or dir == "-TLT" then
+ top = top - 1
+ if dir == "+TRT" then
+ return top, -1
+ else
+ return top, 1
+ end
+ end
+ return top, rlparmode
+end
+
local nesting = 0
local function featuresprocessor(head,font,attr)
@@ -2500,11 +3062,14 @@ local function featuresprocessor(head,font,attr)
end
local rlmode = 0
+
local done = false
local datasets = otf.dataset(tfmdata,font,attr)
local dirstack = { } -- could move outside function
+ sweephead = { }
+
-- We could work on sub start-stop ranges instead but I wonder if there is that
-- much speed gain (experiments showed that it made not much sense) and we need
-- to keep track of directions anyway. Also at some point I want to play with
@@ -2514,7 +3079,7 @@ local function featuresprocessor(head,font,attr)
-- so that multiple cases are also covered.)
-- We don't goto the next node of a disc node is created so that we can then treat
- -- the pre, post and replace. It's abit of a hack but works out ok for most cases.
+ -- the pre, post and replace. It's a bit of a hack but works out ok for most cases.
-- there can be less subtype and attr checking in the comprun etc helpers
@@ -2522,18 +3087,17 @@ local function featuresprocessor(head,font,attr)
local dataset = datasets[s]
----- featurevalue = dataset[1] -- todo: pass to function instead of using a global
local attribute = dataset[2]
- local chain = dataset[3] -- sequence.chain or 0
- ----- kind = dataset[4]
- local sequence = dataset[5] -- sequences[s] -- also dataset[5]
+ local sequence = dataset[3] -- sequences[s] -- also dataset[5]
local rlparmode = 0
local topstack = 0
local success = false
local typ = sequence.type
- local gpossing = typ == "gpos_single" or typ == "gpos_pair"
+ local gpossing = typ == "gpos_single" or typ == "gpos_pair" -- store in dataset
local handler = handlers[typ]
local steps = sequence.steps
local nofsteps = sequence.nofsteps
- if chain < 0 then
+
+ if typ == "gsub_reversecontextchain" then -- chain < 0
-- this is a limited case, no special treatments like 'init' etc
-- we need to get rid of this slide! probably no longer needed in latest luatex
local start = find_node_tail(head) -- slow (we can store tail because there's always a skip at the end): todo
@@ -2586,9 +3150,14 @@ local function featuresprocessor(head,font,attr)
report_missing_cache(dataset,sequence)
else
- local function c_run(start) -- no need to check for 256 and attr probably also the same
- local head = start
- local done = false
+ local function c_run(head) -- no need to check for 256 and attr probably also the same
+ local done = false
+ local start = sweephead[head]
+ if start then
+ sweephead[head] = nil
+ else
+ start = head
+ end
while start do
local id = getid(start)
if id ~= glyph_code then
@@ -2596,12 +3165,13 @@ local function featuresprocessor(head,font,attr)
start = getnext(start)
elseif getfont(start) == font and getsubtype(start) < 256 then
local a = 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
- if a then
+-- 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
+-- if a then
+if not a or (a == attr) then
local lookupmatch = lookupcache[getchar(start)]
if lookupmatch then
-- sequence kan weg
@@ -2630,12 +3200,13 @@ local function featuresprocessor(head,font,attr)
local id = getid(start)
if id == glyph_code and getfont(start) == font and getsubtype(start) < 256 then
local a = 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
- if a then
+-- 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
+-- if a then
+if not a or (a == attr) then
local lookupmatch = lookupcache[getchar(start)]
if lookupmatch then -- hm, hyphens can match (tlig) so we need to really check
-- if we need more than ligatures we can outline the code and use functions
@@ -2664,12 +3235,13 @@ local function featuresprocessor(head,font,attr)
local function d_run(prev) -- we can assume that prev and next are glyphs
local a = getattr(prev,0)
- if a then
- a = (a == attr) and (not attribute or getprop(prev,a_state) == attribute)
- else
- a = not attribute or getprop(prev,a_state) == attribute
- end
- if a then
+-- if a then
+-- a = (a == attr) and (not attribute or getprop(prev,a_state) == attribute)
+-- else
+-- a = not attribute or getprop(prev,a_state) == attribute
+-- end
+-- if a then
+if not a or (a == attr) then
local lookupmatch = lookupcache[getchar(prev)]
if lookupmatch then
-- sequence kan weg
@@ -2684,12 +3256,13 @@ local function featuresprocessor(head,font,attr)
local function k_run(sub,injection,last)
local a = getattr(sub,0)
- if a then
- a = (a == attr) and (not attribute or getprop(sub,a_state) == attribute)
- else
- a = not attribute or getprop(sub,a_state) == attribute
- end
- if a then
+-- if a then
+-- a = (a == attr) and (not attribute or getprop(sub,a_state) == attribute)
+-- else
+-- a = not attribute or getprop(sub,a_state) == attribute
+-- end
+-- if a then
+if not a or (a == attr) then
-- sequence kan weg
for n in traverse_nodes(sub) do -- only gpos
if n == last then
@@ -2767,17 +3340,17 @@ local function featuresprocessor(head,font,attr)
local subtype = getsubtype(start)
if subtype == dir_code then
local dir = getfield(start,"dir")
- if dir == "+TRT" or dir == "+TLT" then
+ if dir == "+TLT" then
topstack = topstack + 1
dirstack[topstack] = dir
- elseif dir == "-TRT" or dir == "-TLT" then
- topstack = topstack - 1
- end
- local newdir = dirstack[topstack]
- if newdir == "+TRT" then
- rlmode = -1
- elseif newdir == "+TLT" then
rlmode = 1
+ elseif dir == "+TRT" then
+ topstack = topstack + 1
+ dirstack[topstack] = dir
+ rlmode = -1
+ elseif dir == "-TLT" or dir == "-TRT" then
+ topstack = topstack - 1
+ rlmode = dirstack[topstack] == "+TLT" and 1 or -1
else
rlmode = rlparmode
end
@@ -2810,9 +3383,14 @@ local function featuresprocessor(head,font,attr)
else
- local function c_run(start)
- local head = start
- local done = false
+ local function c_run(head)
+ local done = false
+ local start = sweephead[head]
+ if start then
+ sweephead[head] = nil
+ else
+ start = head
+ end
while start do
local id = getid(start)
if id ~= glyph_code then
@@ -2820,15 +3398,16 @@ local function featuresprocessor(head,font,attr)
start = getnext(start)
elseif getfont(start) == font and getsubtype(start) < 256 then
local a = 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
- if a then
+-- 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
+-- if a then
+if not a or (a == attr) then
local char = getchar(start)
for i=1,nofsteps do
- local step = steps[i]
+ local step = steps[i]
local lookupcache = step.coverage
if lookupcache then
local lookupmatch = lookupcache[char]
@@ -2864,12 +3443,13 @@ local function featuresprocessor(head,font,attr)
local function d_run(prev)
local a = getattr(prev,0)
- if a then
- a = (a == attr) and (not attribute or getprop(prev,a_state) == attribute)
- else
- a = not attribute or getprop(prev,a_state) == attribute
- end
- if a then
+-- if a then
+-- a = (a == attr) and (not attribute or getprop(prev,a_state) == attribute)
+-- else
+-- a = not attribute or getprop(prev,a_state) == attribute
+-- end
+-- if a then
+if not a or (a == attr) then
-- brr prev can be disc
local char = getchar(prev)
for i=1,nofsteps do
@@ -2894,12 +3474,13 @@ local function featuresprocessor(head,font,attr)
local function k_run(sub,injection,last)
local a = getattr(sub,0)
- if a then
- a = (a == attr) and (not attribute or getprop(sub,a_state) == attribute)
- else
- a = not attribute or getprop(sub,a_state) == attribute
- end
- if a then
+-- if a then
+-- a = (a == attr) and (not attribute or getprop(sub,a_state) == attribute)
+-- else
+-- a = not attribute or getprop(sub,a_state) == attribute
+-- end
+-- if a then
+if not a or (a == attr) then
for n in traverse_nodes(sub) do -- only gpos
if n == last then
break
@@ -2908,7 +3489,7 @@ local function featuresprocessor(head,font,attr)
if id == glyph_code then
local char = getchar(n)
for i=1,nofsteps do
- local step = steps[i]
+ local step = steps[i]
local lookupcache = step.coverage
if lookupcache then
local lookupmatch = lookupcache[char]
@@ -2935,12 +3516,13 @@ local function featuresprocessor(head,font,attr)
local id = getid(start)
if id == glyph_code and getfont(start) == font and getsubtype(start) < 256 then
local a = 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
- if a then
+-- 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
+-- if a then
+if not a or (a == attr) then
local char = getchar(start)
for i=1,nofsteps do
local step = steps[i]
@@ -2988,7 +3570,7 @@ local function featuresprocessor(head,font,attr)
end
if a then
for i=1,nofsteps do
- local step = steps[i]
+ local step = steps[i]
local lookupcache = step.coverage
if lookupcache then
local char = getchar(start)
@@ -3042,18 +3624,17 @@ local function featuresprocessor(head,font,attr)
elseif id == whatsit_code then
local subtype = getsubtype(start)
if subtype == dir_code then
- local dir = getfield(start,"dir")
- if dir == "+TRT" or dir == "+TLT" then
+ if dir == "+TLT" then
topstack = topstack + 1
dirstack[topstack] = dir
- elseif dir == "-TRT" or dir == "-TLT" then
- topstack = topstack - 1
- end
- local newdir = dirstack[topstack]
- if newdir == "+TRT" then
- rlmode = -1
- elseif newdir == "+TLT" then
rlmode = 1
+ elseif dir == "+TRT" then
+ topstack = topstack + 1
+ dirstack[topstack] = dir
+ rlmode = -1
+ elseif dir == "-TLT" or dir == "-TRT" then
+ topstack = topstack - 1
+ rlmode = dirstack[topstack] == "+TLT" and 1 or -1
else
rlmode = rlparmode
end
diff --git a/tex/context/base/lang-dis.lua b/tex/context/base/lang-dis.lua
index bacd7f04b..91b0e9460 100644
--- a/tex/context/base/lang-dis.lua
+++ b/tex/context/base/lang-dis.lua
@@ -26,6 +26,8 @@ local getfont = nuts.getfont
local getattr = nuts.getattr
local getsubtype = nuts.getsubtype
local getchar = nuts.getchar
+local getdisc = nuts.getdisc
+local setdisc = nuts.setdisc
local copy_node = nuts.copy
local free_node = nuts.free
@@ -45,6 +47,103 @@ local setattribute = tex.setattribute
local getlanguagedata = languages.getdata
+-- local expanders = {
+-- [disccodes.discretionary] = function(d,template)
+-- -- \discretionary
+-- return template
+-- end,
+-- [disccodes.explicit] = function(d,template)
+-- -- \-
+-- local pre = getfield(d,"pre")
+-- if pre and getid(pre) == glyph_code and getchar(pre) <= 0 then
+-- setfield(d,"pre",nil)
+-- end
+-- local post = getfield(d,"post")
+-- if post and getid(post) == glyph_code and getchar(post) <= 0 then
+-- setfield(d,"post",nil)
+-- end
+-- setfield(d,"subtype",discretionary_code) -- to be checked
+-- return template
+-- end,
+-- [disccodes.automatic] = function(d,template)
+-- -- following a - : the pre and post chars are already appended and set
+-- -- so we have pre=preex and post=postex .. however, the previous
+-- -- hyphen is already injected ... downside: the font handler sees this
+-- -- so this is another argument for doing a hyphenation pass in context
+-- if getfield(d,"pre") then
+-- -- we have a preex characters and want that one to replace the
+-- -- character in front which is the trigger
+-- if not template then
+-- -- can there be font kerns already?
+-- template = getprev(d)
+-- if template and getid(template) ~= glyph_code then
+-- template = getnext(d)
+-- if template and getid(template) ~= glyph_code then
+-- template = nil
+-- end
+-- end
+-- end
+-- if template then
+-- local pseudohead = getprev(template)
+-- if pseudohead then
+-- while template ~= d do
+-- pseudohead, template, removed = remove_node(pseudohead,template)
+-- setfield(d,"replace",removed)
+-- -- break ?
+-- end
+-- else
+-- -- can't happen
+-- end
+-- setfield(d,"subtype",discretionary_code)
+-- else
+-- -- print("lone regular discretionary ignored")
+-- end
+-- else
+-- setfield(d,"subtype",discretionary_code)
+-- end
+-- return template
+-- end,
+-- [disccodes.regular] = function(d,template)
+-- -- simple
+-- if not template then
+-- -- can there be font kerns already?
+-- template = getprev(d)
+-- if template and getid(template) ~= glyph_code then
+-- template = getnext(d)
+-- if template and getid(template) ~= glyph_code then
+-- template = nil
+-- end
+-- end
+-- end
+-- if template then
+-- local language = template and getfield(template,"lang")
+-- local data = getlanguagedata(language)
+-- local prechar = data.prehyphenchar
+-- local postchar = data.posthyphenchar
+-- if prechar and prechar > 0 then
+-- local c = copy_node(template)
+-- setfield(c,"char",prechar)
+-- setfield(d,"pre",c)
+-- end
+-- if postchar and postchar > 0 then
+-- local c = copy_node(template)
+-- setfield(c,"char",postchar)
+-- setfield(d,"post",c)
+-- end
+-- setfield(d,"subtype",discretionary_code)
+-- else
+-- -- print("lone regular discretionary ignored")
+-- end
+-- return template
+-- end,
+-- [disccodes.first] = function()
+-- -- forget about them
+-- end,
+-- [disccodes.second] = function()
+-- -- forget about them
+-- end,
+-- }
+
local expanders = {
[disccodes.discretionary] = function(d,template)
-- \discretionary
@@ -52,15 +151,19 @@ local expanders = {
end,
[disccodes.explicit] = function(d,template)
-- \-
- local pre = getfield(d,"pre")
+ local pre, post, replace = getdisc(d)
+ local done = false
if pre and getid(pre) == glyph_code and getchar(pre) <= 0 then
- setfield(d,"pre",nil)
+ done = true
+ pre = nil
end
- local post = getfield(d,"post")
if post and getid(post) == glyph_code and getchar(post) <= 0 then
- setfield(d,"post",nil)
+ done = true
+ post = nil
+ end
+ if done then
+ setdisc(d,pre,post,replace,discretionary_code)
end
- setfield(d,"subtype",discretionary_code) -- to be checked
return template
end,
[disccodes.automatic] = function(d,template)
@@ -68,7 +171,8 @@ local expanders = {
-- so we have pre=preex and post=postex .. however, the previous
-- hyphen is already injected ... downside: the font handler sees this
-- so this is another argument for doing a hyphenation pass in context
- if getfield(d,"pre") then
+ local pre, post, replace = getdisc(d)
+ if pre then
-- we have a preex characters and want that one to replace the
-- character in front which is the trigger
if not template then
@@ -86,18 +190,19 @@ local expanders = {
if pseudohead then
while template ~= d do
pseudohead, template, removed = remove_node(pseudohead,template)
- setfield(d,"replace",removed)
+ -- free old replace ?
+ replace = removed
-- break ?
end
else
-- can't happen
end
- setfield(d,"subtype",discretionary_code)
+ setdisc(d,pre,post,replace,discretionary_code)
else
-- print("lone regular discretionary ignored")
end
else
- setfield(d,"subtype",discretionary_code)
+ setdisc(d,pre,post,replace,discretionary_code)
end
return template
end,
@@ -118,17 +223,21 @@ local expanders = {
local data = getlanguagedata(language)
local prechar = data.prehyphenchar
local postchar = data.posthyphenchar
+ local pre, post, replace = getdisc(d) -- pre can be set
+ local done = false
if prechar and prechar > 0 then
- local c = copy_node(template)
- setfield(c,"char",prechar)
- setfield(d,"pre",c)
+ done = true
+ pre = copy_node(template)
+ setfield(pre,"char",prechar)
end
if postchar and postchar > 0 then
- local c = copy_node(template)
- setfield(c,"char",postchar)
- setfield(d,"post",c)
+ done = true
+ post = copy_node(template)
+ setfield(post,"char",postchar)
+ end
+ if done then
+ setdisc(d,pre,post,replace,discretionary_code)
end
- setfield(d,"subtype",discretionary_code)
else
-- print("lone regular discretionary ignored")
end
@@ -158,9 +267,7 @@ local setlistcolor = nodes.tracers.colors.setlist
function languages.visualizediscretionaries(head)
for d in traverse_id(disc_code,tonut(head)) do
if getattr(d,a_visualize) then
- local pre = getfield(d,"pre")
- local post = getfield(d,"post")
- local replace = getfield(d,"replace")
+ local pre, post, replace = getdisc(d)
if pre then
setlistcolor(pre,"darkred")
end
@@ -196,10 +303,11 @@ interfaces.implement {
local toutf = nodes.listtoutf
function languages.serializediscretionary(d) -- will move to tracer
+ local pre, post, replace = getdisc(d)
return string.formatters["{%s}{%s}{%s}"](
- toutf(getfield(d,"pre")) or "",
- toutf(getfield(d,"post")) or "",
- toutf(getfield(d,"replace")) or ""
+ pre and toutf(pre) or "",
+ post and toutf(post) or "",
+ replace and toutf(replace) or ""
)
end
diff --git a/tex/context/base/m-newotf.mkiv b/tex/context/base/m-newotf.mkiv
index 0bdd6ec8e..df91cbe02 100644
--- a/tex/context/base/m-newotf.mkiv
+++ b/tex/context/base/m-newotf.mkiv
@@ -26,7 +26,7 @@
"font-oup",
"font-otl",
"font-ots",
-"font-ots-xxx", -- for me, testing
+"font-ots-new", -- for testing (15% faster variant, but luatex update needed)
"font-oto",
"font-otd",
"font-otc",
diff --git a/tex/context/base/node-nut.lua b/tex/context/base/node-nut.lua
index 554d74ec5..de03fd433 100644
--- a/tex/context/base/node-nut.lua
+++ b/tex/context/base/node-nut.lua
@@ -240,6 +240,109 @@ if not direct.mlist_to_hlist then
end
+-- new, a few experimental extra helpers that can speed up font handling 15%
+-- especially a mix of complex (latin) features and discretionaries or complex
+-- scripts with lots of contextual chains (for other use there is not that
+-- much gain)
+
+if not direct.getdisc then
+
+ local getid = nuts.getid
+ local getsubtype = nuts.getsubtype
+ local getfont = nuts.getfont
+ local getfield = nuts.getfield
+ local setfield = nuts.setfield
+ local findtail = nuts.tail
+
+ local glyph_code = nodecodes.glyph
+
+ -- this one saves finding tails (i.e. extra calls and passes)
+
+ function direct.getdisc(n,tailtoo)
+ local pre = getfield(n,"pre")
+ local post = getfield(n,"post")
+ local replace = getfield(n,"replace")
+ if tailtoo then
+ return pre, post, replace,
+ pre and findtail(pre),
+ post and findtail(post),
+ replace and findtail(replace)
+
+ else
+ return pre, post, replace
+ end
+ end
+
+ -- this one is more efficient than three assignments and we need to
+ -- do it in order to updat ethe internal tail data (will change)
+
+ function direct.setdisc(n,pre,post,replace,subtype)
+ setfield(n,"pre",pre)
+ setfield(n,"post",post)
+ setfield(n,"replace",replace)
+ if subtype then
+ setfield(n,"subtype",subtype)
+ end
+ end
+
+ -- very small speedup but more convenient
+
+ function direct.setchar(n,chr)
+ setfield(n,"char",chr)
+ end
+
+ function direct.setnext(n,next)
+ setfield(n,"next",next)
+ end
+
+ function direct.setprev(g,prev)
+ setfield(n,"prev",prev)
+ end
+
+ function direct.setboth(n,prev,next)
+ if n then
+ setfield(n,"next",next)
+ setfield(n,"prev",prev)
+ end
+ end
+
+ function direct.getboth(n)
+ if n then
+ return getfield(n,"prev"), getfield(n,"prev")
+ end
+ end
+
+ function direct.setlink(a,b)
+ if a then
+ if b then
+ setfield(a,"next",b)
+ setfield(b,"prev",a)
+ else
+ setfield(a,"next",nil)
+ end
+ elseif b then
+ setfield(b,"prev",nil)
+ end
+ end
+
+ -- this one saves a lot (one call instead of 3)
+
+ function direct.is_char(g,font)
+ return getid(g) == glyph_code and getsubtype(g) < 256 and (not font or getfont(g) == font)
+ end
+
+end
+
+nuts.getdisc = direct.getdisc
+nuts.setdisc = direct.setdisc
+nuts.setchar = direct.setchar
+nuts.setnext = direct.setnext
+nuts.setprev = direct.setprev
+nuts.setboth = direct.setboth
+nuts.getboth = direct.getboth
+nuts.setlink = direct.setlink
+nuts.is_char = direct.is_char
+
--
local d_remove_node = direct.remove
diff --git a/tex/context/base/status-files.pdf b/tex/context/base/status-files.pdf
index 4d56f3d84..7ccbf6cdc 100644
--- a/tex/context/base/status-files.pdf
+++ b/tex/context/base/status-files.pdf
Binary files differ
diff --git a/tex/context/base/status-lua.pdf b/tex/context/base/status-lua.pdf
index c12c6a530..c8718cfe4 100644
--- a/tex/context/base/status-lua.pdf
+++ b/tex/context/base/status-lua.pdf
Binary files differ
diff --git a/tex/context/base/util-fil.lua b/tex/context/base/util-fil.lua
index 3e8c8ea23..42bbe37b3 100644
--- a/tex/context/base/util-fil.lua
+++ b/tex/context/base/util-fil.lua
@@ -21,7 +21,9 @@ local zerobased = { }
function files.open(filename,zb)
local f = io.open(filename,"rb")
- zerobased[f] = zb or false
+ if f then
+ zerobased[f] = zb or false
+ end
return f
end
diff --git a/tex/generic/context/luatex/luatex-fonts-inj.lua b/tex/generic/context/luatex/luatex-fonts-inj.lua
index 332e92033..cdf14b935 100644
--- a/tex/generic/context/luatex/luatex-fonts-inj.lua
+++ b/tex/generic/context/luatex/luatex-fonts-inj.lua
@@ -8,7 +8,16 @@ if not modules then modules = { } end modules ['font-inj'] = {
-- This property based variant is not faster but looks nicer than the attribute one. We
-- need to use rawget (which is apbout 4 times slower than a direct access but we cannot
--- get/set that one for our purpose!
+-- get/set that one for our purpose! This version does a bit more with discretionaries
+-- (and Kai has tested it with his collection of weird fonts.)
+
+-- There is some duplicate code here (especially in the the pre/post/replace branches) but
+-- we go for speed. We could store a list of glyph and mark nodes when registering but it's
+-- cleaner to have an identification pass here. Also, I need to keep tracing in mind so
+-- being too clever here is dangerous.
+
+-- The subtype test is not needed as there will be no (new) properties set, given that we
+-- reset the properties.
if not nodes.properties then return end
@@ -80,8 +89,7 @@ function injections.resetcounts()
keepregisteredcounts = false
end
--- We need to make sure that a possible metatable will not kick in
--- unexpectedly.
+-- We need to make sure that a possible metatable will not kick in unexpectedly.
function injections.reset(n)
local p = rawget(properties,n)
@@ -146,7 +154,8 @@ end
function injections.setcursive(start,nxt,factor,rlmode,exit,entry,tfmstart,tfmnext) -- hm: nuts or nodes
local dx = factor*(exit[1]-entry[1])
local dy = -factor*(exit[2]-entry[2])
- local ws, wn = tfmstart.width, tfmnext.width
+ local ws = tfmstart.width
+ local wn = tfmnext.width
nofregisteredcursives = nofregisteredcursives + 1
if rlmode < 0 then
dx = -(dx + wn)
@@ -205,9 +214,12 @@ function injections.setpair(current,factor,rlmode,r2lflag,spec,injection) -- r2l
if rlmode and rlmode < 0 then
leftkern, rightkern = rightkern, leftkern
end
+ if not injection then
+ injection = "injections"
+ end
local p = rawget(properties,current)
if p then
- local i = rawget(p,"injections")
+ local i = rawget(p,injection)
if i then
if leftkern ~= 0 then
i.leftkern = (i.leftkern or 0) + leftkern
@@ -219,19 +231,19 @@ function injections.setpair(current,factor,rlmode,r2lflag,spec,injection) -- r2l
i.yoffset = (i.yoffset or 0) + yoffset
end
elseif leftkern ~= 0 or rightkern ~= 0 then
- p.injections = {
+ p[injection] = {
leftkern = leftkern,
rightkern = rightkern,
yoffset = yoffset,
}
else
- p.injections = {
+ p[injection] = {
yoffset = yoffset,
}
end
elseif leftkern ~= 0 or rightkern ~= 0 then
properties[current] = {
- injections = {
+ [injection] = {
leftkern = leftkern,
rightkern = rightkern,
yoffset = yoffset,
@@ -239,7 +251,7 @@ function injections.setpair(current,factor,rlmode,r2lflag,spec,injection) -- r2l
}
else
properties[current] = {
- injections = {
+ [injection] = {
yoffset = yoffset,
},
}
@@ -250,10 +262,9 @@ function injections.setpair(current,factor,rlmode,r2lflag,spec,injection) -- r2l
return x, y, w, h -- no bound
end
--- this needs checking for rl < 0 but it is unlikely that a r2l script
--- uses kernclasses between glyphs so we're probably safe (KE has a
--- problematic font where marks interfere with rl < 0 in the previous
--- case)
+-- This needs checking for rl < 0 but it is unlikely that a r2l script uses kernclasses between
+-- glyphs so we're probably safe (KE has a problematic font where marks interfere with rl < 0 in
+-- the previous case)
function injections.setkern(current,factor,rlmode,x,injection)
local dx = factor * x
@@ -285,7 +296,7 @@ function injections.setkern(current,factor,rlmode,x,injection)
end
end
-function injections.setmark(start,base,factor,rlmode,ba,ma,tfmbase) -- ba=baseanchor, ma=markanchor
+function injections.setmark(start,base,factor,rlmode,ba,ma,tfmbase,mkmk) -- ba=baseanchor, ma=markanchor
local dx, dy = factor*(ba[1]-ma[1]), factor*(ba[2]-ma[2])
nofregisteredmarks = nofregisteredmarks + 1
-- markanchors[nofregisteredmarks] = base
@@ -293,14 +304,20 @@ function injections.setmark(start,base,factor,rlmode,ba,ma,tfmbase) -- ba=basean
dx = tfmbase.width - dx -- see later commented ox
end
local p = rawget(properties,start)
+ -- hm, dejavu serif does a sloppy mark2mark before mark2base
if p then
local i = rawget(p,"injections")
if i then
- i.markx = dx
- i.marky = dy
- i.markdir = rlmode or 0
- i.markbase = nofregisteredmarks
- i.markbasenode = base
+ if i.markmark then
+ -- out of order mkmk: yes or no or option
+ else
+ i.markx = dx
+ i.marky = dy
+ i.markdir = rlmode or 0
+ i.markbase = nofregisteredmarks
+ i.markbasenode = base
+ i.markmark = mkmk
+ end
else
p.injections = {
markx = dx,
@@ -308,6 +325,7 @@ function injections.setmark(start,base,factor,rlmode,ba,ma,tfmbase) -- ba=basean
markdir = rlmode or 0,
markbase = nofregisteredmarks,
markbasenode = base,
+ markmark = mkmk,
}
end
else
@@ -318,6 +336,7 @@ function injections.setmark(start,base,factor,rlmode,ba,ma,tfmbase) -- ba=basean
markdir = rlmode or 0,
markbase = nofregisteredmarks,
markbasenode = base,
+ markmark = mkmk,
},
}
end
@@ -430,30 +449,32 @@ local function show_result(head)
end
end
--- we could also check for marks here but maybe not all are registered (needs checking)
-
-local function collect_glyphs_1(head)
- local glyphs, nofglyphs = { }, 0
- local marks, nofmarks = { }, 0
+local function collect_glyphs(head,offsets)
+ local glyphs, glyphi, nofglyphs = { }, { }, 0
+ local marks, marki, nofmarks = { }, { }, 0
local nf, tm = nil, nil
- for n in traverse_id(glyph_code,head) do -- only needed for relevant fonts
- if getsubtype(n) < 256 then
- local f = getfont(n)
- if f ~= nf then
- nf = f
- tm = fontdata[nf].resources.marks -- other hash in ctx
- end
- if tm and tm[getchar(n)] then
- nofmarks = nofmarks + 1
- marks[nofmarks] = n
- else
- nofglyphs = nofglyphs + 1
- glyphs[nofglyphs] = n
- end
+ local n = head
+
+ local function identify(n,what)
+ local f = getfont(n)
+ if f ~= nf then
+ nf = f
+ tm = fontdata[nf].resources.marks -- other hash in ctx
+ end
+ if tm and tm[getchar(n)] then
+ nofmarks = nofmarks + 1
+ marks[nofmarks] = n
+ marki[nofmarks] = "injections"
+ else
+ nofglyphs = nofglyphs + 1
+ glyphs[nofglyphs] = n
+ glyphi[nofglyphs] = what
+ end
+ if offsets then
-- yoffsets can influence curs steps
local p = rawget(properties,n)
if p then
- local i = rawget(p,"injections")
+ local i = rawget(p,what)
if i then
local yoffset = i.yoffset
if yoffset and yoffset ~= 0 then
@@ -463,38 +484,50 @@ local function collect_glyphs_1(head)
end
end
end
- return glyphs, nofglyphs, marks, nofmarks
-end
-local function collect_glyphs_2(head)
- local glyphs, nofglyphs = { }, 0
- local marks, nofmarks = { }, 0
- local nf, tm = nil, nil
- for n in traverse_id(glyph_code,head) do
- if getsubtype(n) < 256 then
- local f = getfont(n)
- if f ~= nf then
- nf = f
- tm = fontdata[nf].resources.marks -- other hash in ctx
- end
- if tm and tm[getchar(n)] then
- nofmarks = nofmarks + 1
- marks[nofmarks] = n
- else
- nofglyphs = nofglyphs + 1
- glyphs[nofglyphs] = n
- end
+ while n do -- only needed for relevant fonts
+ local id = getid(n)
+ if id == glyph_code then
+ identify(n,"injections")
+ elseif id == disc_code then
+ local d = getfield(n,"pre")
+ if d then
+ for n in traverse_id(glyph_code,d) do
+ if getsubtype(n) < 256 then
+ identify(n,"preinjections")
+ end
+ end
+ end
+ local d = getfield(n,"post")
+ if d then
+ for n in traverse_id(glyph_code,d) do
+ if getsubtype(n) < 256 then
+ identify(n,"postinjections")
+ end
+ end
+ end
+ local d = getfield(n,"replace")
+ if d then
+ for n in traverse_id(glyph_code,d) do
+ if getsubtype(n) < 256 then
+ identify(n,"replaceinjections")
+ end
+ end
+ end
end
+ n = getnext(n)
end
- return glyphs, nofglyphs, marks, nofmarks
+
+ return glyphs, glyphi, nofglyphs, marks, marki, nofmarks
end
-local function inject_marks(marks,nofmarks)
+local function inject_marks(marks,marki,nofmarks)
for i=1,nofmarks do
- local n = marks[i]
+ local n = marks[i]
local pn = rawget(properties,n)
if pn then
- pn = rawget(pn,"injections")
+ local ni = marki[i]
+ local pn = rawget(pn,ni)
if pn then
local p = pn.markbasenode
if p then
@@ -503,7 +536,7 @@ local function inject_marks(marks,nofmarks)
local rightkern = nil
local pp = rawget(properties,p)
if pp then
- pp = rawget(pp,"injections")
+ pp = rawget(pp,ni)
if pp then
rightkern = pp.rightkern
end
@@ -518,11 +551,10 @@ local function inject_marks(marks,nofmarks)
-- ox = px - getfield(p,"width") + pn.markx - pp.leftkern
local leftkern = pp.leftkern
if leftkern then
- ox = px - pn.markx
- else
ox = px - pn.markx - leftkern
+ else
+ ox = px - pn.markx
end
--- report_injections("l2r case 1: %p",ox)
end
else
-- we need to deal with fonts that have marks with width
@@ -548,12 +580,13 @@ local function inject_marks(marks,nofmarks)
setfield(n,"xoffset",ox)
--
local py = getfield(p,"yoffset")
- local oy = 0
- if marks[p] then
- oy = py + pn.marky
- else
- oy = getfield(n,"yoffset") + py + pn.marky
- end
+-- local oy = 0
+-- if marks[p] then
+-- oy = py + pn.marky
+-- else
+-- oy = getfield(n,"yoffset") + py + pn.marky
+-- end
+ local oy = getfield(n,"yoffset") + py + pn.marky
setfield(n,"yoffset",oy)
else
-- normally this can't happen (only when in trace mode which is a special case anyway)
@@ -564,14 +597,14 @@ local function inject_marks(marks,nofmarks)
end
end
-local function inject_cursives(glyphs,nofglyphs)
+local function inject_cursives(glyphs,glyphi,nofglyphs)
local cursiveanchor, lastanchor = nil, nil
local minc, maxc, last = 0, 0, nil
for i=1,nofglyphs do
- local n = glyphs[i]
+ local n = glyphs[i]
local pn = rawget(properties,n)
if pn then
- pn = rawget(pn,"injections")
+ pn = rawget(pn,glyphi[i])
end
if pn then
local cursivex = pn.cursivex
@@ -630,7 +663,7 @@ local function inject_cursives(glyphs,nofglyphs)
-- if maxc > 0 and not cursiveanchor then
-- local ny = getfield(n,"yoffset")
-- for i=maxc,minc,-1 do
- -- local ti = glyphs[i]
+ -- local ti = glyphs[i][1]
-- ny = ny + properties[ti].cursivedy
-- setfield(ti,"yoffset",ny) -- why not add ?
-- end
@@ -647,23 +680,67 @@ local function inject_cursives(glyphs,nofglyphs)
end
end
-local function inject_kerns(head,list,length)
- -- todo: pre/post/replace
+-- G +D-pre G
+-- D-post+
+-- +D-replace+
+--
+-- G +D-pre +D-pre
+-- D-post +D-post
+-- +D-replace +D-replace
+
+local function inject_kerns(head,glist,ilist,length) -- not complete ! compare with inject_kerns_only (but unlikely disc here)
for i=1,length do
- local n = list[i]
+ local n = glist[i]
local pn = rawget(properties,n)
if pn then
- local i = rawget(pn,"injections")
- if i then
- local leftkern = i.leftkern
- if leftkern and leftkern ~= 0 then
- insert_node_before(head,n,newkern(leftkern)) -- type 0/2
- end
- local rightkern = i.rightkern
- if rightkern and rightkern ~= 0 then
- insert_node_after(head,n,newkern(rightkern)) -- type 0/2
- end
- end
+ local dp = nil
+ local dr = nil
+ local ni = ilist[i]
+ local p = nil
+ if ni == "injections" then
+ p = getprev(n)
+ if p then
+ local id = getid(p)
+ if id == disc_code then
+ dp = getfield(p,"post")
+ dr = getfield(p,"replace")
+ end
+ end
+ end
+ if dp then
+ local i = rawget(pn,"postinjections")
+ if i then
+ local leftkern = i.leftkern
+ if leftkern and leftkern ~= 0 then
+ local t = find_tail(dp)
+ insert_node_after(dp,t,newkern(leftkern))
+setfield(p,"post",dp) -- currently we need to force a tail refresh
+ end
+ end
+ end
+ if dr then
+ local i = rawget(pn,"replaceinjections")
+ if i then
+ local leftkern = i.leftkern
+ if leftkern and leftkern ~= 0 then
+ local t = find_tail(dr)
+ insert_node_after(dr,t,newkern(leftkern))
+setfield(p,"replace",dr) -- currently we need to force a tail refresh
+ end
+ end
+ else
+ local i = rawget(pn,ni)
+ if i then
+ local leftkern = i.leftkern
+ if leftkern and leftkern ~= 0 then
+ insert_node_before(head,n,newkern(leftkern)) -- type 0/2
+ end
+ local rightkern = i.rightkern
+ if rightkern and rightkern ~= 0 then
+ insert_node_after(head,n,newkern(rightkern)) -- type 0/2
+ end
+ end
+ end
end
end
end
@@ -673,23 +750,18 @@ local function inject_everything(head,where)
if trace_injections then
trace(head,"everything")
end
- local glyphs, nofglyphs, marks, nofmarks
- if nofregisteredpairs > 0 then
- glyphs, nofglyphs, marks, nofmarks = collect_glyphs_1(head)
- else
- glyphs, nofglyphs, marks, nofmarks = collect_glyphs_2(head)
- end
+ local glyphs, glyphi, nofglyphs, marks, marki, nofmarks = collect_glyphs(head,nofregisteredpairs > 0)
if nofglyphs > 0 then
if nofregisteredcursives > 0 then
- inject_cursives(glyphs,nofglyphs)
+ inject_cursives(glyphs,glyphi,nofglyphs)
end
if nofregisteredmarks > 0 then -- and nofmarks > 0
- inject_marks(marks,nofmarks)
+ inject_marks(marks,marki,nofmarks)
end
- inject_kerns(head,glyphs,nofglyphs)
+ inject_kerns(head,glyphs,glyphi,nofglyphs)
end
if nofmarks > 0 then
- inject_kerns(head,marks,nofmarks)
+ inject_kerns(head,marks,marki,nofmarks)
end
if keepregisteredcounts then
keepregisteredcounts = false
@@ -702,6 +774,14 @@ local function inject_everything(head,where)
return tonode(head), true
end
+-- G +D-pre G
+-- D-post+
+-- +D-replace+
+--
+-- G +D-pre +D-pre
+-- D-post +D-post
+-- +D-replace +D-replace
+
local function inject_kerns_only(head,where)
head = tonut(head)
if trace_injections then
@@ -724,6 +804,7 @@ local function inject_kerns_only(head,where)
if leftkern and leftkern ~= 0 then
local t = find_tail(d)
insert_node_after(d,t,newkern(leftkern))
+setfield(p,"post",d) -- currently we need to force a tail refresh
end
end
end
@@ -735,6 +816,7 @@ local function inject_kerns_only(head,where)
if leftkern and leftkern ~= 0 then
local t = find_tail(d)
insert_node_after(d,t,newkern(leftkern))
+setfield(p,"replace",d) -- currently we need to force a tail refresh
end
end
else
@@ -784,6 +866,7 @@ local function inject_kerns_only(head,where)
setfield(n,"pre",h)
end
end
+ -- weird
local d = getfield(n,"post")
if d then
local h = d
@@ -852,7 +935,7 @@ local function inject_pairs_only(head,where)
end
--
local n = head
- local p = nil
+ local p = nil -- disc node when non-nil
while n do
local id = getid(n)
if id == glyph_code then
@@ -868,6 +951,7 @@ local function inject_pairs_only(head,where)
if leftkern and leftkern ~= 0 then
local t = find_tail(d)
insert_node_after(d,t,newkern(leftkern))
+setfield(p,"post",d) -- currently we need to force a tail refresh
end
-- local rightkern = i.rightkern
-- if rightkern and rightkern ~= 0 then
@@ -884,6 +968,7 @@ local function inject_pairs_only(head,where)
if leftkern and leftkern ~= 0 then
local t = find_tail(d)
insert_node_after(d,t,newkern(leftkern))
+setfield(p,"replace",d) -- currently we need to force a tail refresh
end
-- local rightkern = i.rightkern
-- if rightkern and rightkern ~= 0 then
@@ -1042,7 +1127,7 @@ local function inject_pairs_only(head,where)
return tonode(head), true
end
-function injections.handler(head,where) -- optimize for n=1 ?
+function injections.handler(head,where)
if nofregisteredmarks > 0 or nofregisteredcursives > 0 then
return inject_everything(head,where)
elseif nofregisteredpairs > 0 then
diff --git a/tex/generic/context/luatex/luatex-fonts-merged.lua b/tex/generic/context/luatex/luatex-fonts-merged.lua
index 97222c733..da21fa6d8 100644
--- a/tex/generic/context/luatex/luatex-fonts-merged.lua
+++ b/tex/generic/context/luatex/luatex-fonts-merged.lua
@@ -1,6 +1,6 @@
-- merged file : luatex-fonts-merged.lua
-- parent file : luatex-fonts.lua
--- merge date : 08/30/15 23:03:00
+-- merge date : 09/01/15 11:10:11
do -- begin closure to overcome local limits and interference
@@ -10205,7 +10205,8 @@ end
function injections.setcursive(start,nxt,factor,rlmode,exit,entry,tfmstart,tfmnext)
local dx=factor*(exit[1]-entry[1])
local dy=-factor*(exit[2]-entry[2])
- local ws,wn=tfmstart.width,tfmnext.width
+ local ws=tfmstart.width
+ local wn=tfmnext.width
nofregisteredcursives=nofregisteredcursives+1
if rlmode<0 then
dx=-(dx+wn)
@@ -10262,9 +10263,12 @@ function injections.setpair(current,factor,rlmode,r2lflag,spec,injection)
if rlmode and rlmode<0 then
leftkern,rightkern=rightkern,leftkern
end
+ if not injection then
+ injection="injections"
+ end
local p=rawget(properties,current)
if p then
- local i=rawget(p,"injections")
+ local i=rawget(p,injection)
if i then
if leftkern~=0 then
i.leftkern=(i.leftkern or 0)+leftkern
@@ -10276,19 +10280,19 @@ function injections.setpair(current,factor,rlmode,r2lflag,spec,injection)
i.yoffset=(i.yoffset or 0)+yoffset
end
elseif leftkern~=0 or rightkern~=0 then
- p.injections={
+ p[injection]={
leftkern=leftkern,
rightkern=rightkern,
yoffset=yoffset,
}
else
- p.injections={
+ p[injection]={
yoffset=yoffset,
}
end
elseif leftkern~=0 or rightkern~=0 then
properties[current]={
- injections={
+ [injection]={
leftkern=leftkern,
rightkern=rightkern,
yoffset=yoffset,
@@ -10296,7 +10300,7 @@ function injections.setpair(current,factor,rlmode,r2lflag,spec,injection)
}
else
properties[current]={
- injections={
+ [injection]={
yoffset=yoffset,
},
}
@@ -10335,7 +10339,7 @@ function injections.setkern(current,factor,rlmode,x,injection)
return 0,0
end
end
-function injections.setmark(start,base,factor,rlmode,ba,ma,tfmbase)
+function injections.setmark(start,base,factor,rlmode,ba,ma,tfmbase,mkmk)
local dx,dy=factor*(ba[1]-ma[1]),factor*(ba[2]-ma[2])
nofregisteredmarks=nofregisteredmarks+1
if rlmode>=0 then
@@ -10345,11 +10349,15 @@ function injections.setmark(start,base,factor,rlmode,ba,ma,tfmbase)
if p then
local i=rawget(p,"injections")
if i then
- i.markx=dx
- i.marky=dy
- i.markdir=rlmode or 0
- i.markbase=nofregisteredmarks
- i.markbasenode=base
+ if i.markmark then
+ else
+ i.markx=dx
+ i.marky=dy
+ i.markdir=rlmode or 0
+ i.markbase=nofregisteredmarks
+ i.markbasenode=base
+ i.markmark=mkmk
+ end
else
p.injections={
markx=dx,
@@ -10357,6 +10365,7 @@ function injections.setmark(start,base,factor,rlmode,ba,ma,tfmbase)
markdir=rlmode or 0,
markbase=nofregisteredmarks,
markbasenode=base,
+ markmark=mkmk,
}
end
else
@@ -10367,6 +10376,7 @@ function injections.setmark(start,base,factor,rlmode,ba,ma,tfmbase)
markdir=rlmode or 0,
markbase=nofregisteredmarks,
markbasenode=base,
+ markmark=mkmk,
},
}
end
@@ -10471,27 +10481,30 @@ local function show_result(head)
current=getnext(current)
end
end
-local function collect_glyphs_1(head)
- local glyphs,nofglyphs={},0
- local marks,nofmarks={},0
+local function collect_glyphs(head,offsets)
+ local glyphs,glyphi,nofglyphs={},{},0
+ local marks,marki,nofmarks={},{},0
local nf,tm=nil,nil
- for n in traverse_id(glyph_code,head) do
- if getsubtype(n)<256 then
- local f=getfont(n)
- if f~=nf then
- nf=f
- tm=fontdata[nf].resources.marks
- end
- if tm and tm[getchar(n)] then
- nofmarks=nofmarks+1
- marks[nofmarks]=n
- else
- nofglyphs=nofglyphs+1
- glyphs[nofglyphs]=n
- end
+ local n=head
+ local function identify(n,what)
+ local f=getfont(n)
+ if f~=nf then
+ nf=f
+ tm=fontdata[nf].resources.marks
+ end
+ if tm and tm[getchar(n)] then
+ nofmarks=nofmarks+1
+ marks[nofmarks]=n
+ marki[nofmarks]="injections"
+ else
+ nofglyphs=nofglyphs+1
+ glyphs[nofglyphs]=n
+ glyphi[nofglyphs]=what
+ end
+ if offsets then
local p=rawget(properties,n)
if p then
- local i=rawget(p,"injections")
+ local i=rawget(p,what)
if i then
local yoffset=i.yoffset
if yoffset and yoffset~=0 then
@@ -10501,36 +10514,47 @@ local function collect_glyphs_1(head)
end
end
end
- return glyphs,nofglyphs,marks,nofmarks
-end
-local function collect_glyphs_2(head)
- local glyphs,nofglyphs={},0
- local marks,nofmarks={},0
- local nf,tm=nil,nil
- for n in traverse_id(glyph_code,head) do
- if getsubtype(n)<256 then
- local f=getfont(n)
- if f~=nf then
- nf=f
- tm=fontdata[nf].resources.marks
- end
- if tm and tm[getchar(n)] then
- nofmarks=nofmarks+1
- marks[nofmarks]=n
- else
- nofglyphs=nofglyphs+1
- glyphs[nofglyphs]=n
- end
+ while n do
+ local id=getid(n)
+ if id==glyph_code then
+ identify(n,"injections")
+ elseif id==disc_code then
+ local d=getfield(n,"pre")
+ if d then
+ for n in traverse_id(glyph_code,d) do
+ if getsubtype(n)<256 then
+ identify(n,"preinjections")
+ end
+ end
+ end
+ local d=getfield(n,"post")
+ if d then
+ for n in traverse_id(glyph_code,d) do
+ if getsubtype(n)<256 then
+ identify(n,"postinjections")
+ end
+ end
+ end
+ local d=getfield(n,"replace")
+ if d then
+ for n in traverse_id(glyph_code,d) do
+ if getsubtype(n)<256 then
+ identify(n,"replaceinjections")
+ end
+ end
+ end
end
+ n=getnext(n)
end
- return glyphs,nofglyphs,marks,nofmarks
+ return glyphs,glyphi,nofglyphs,marks,marki,nofmarks
end
-local function inject_marks(marks,nofmarks)
+local function inject_marks(marks,marki,nofmarks)
for i=1,nofmarks do
local n=marks[i]
local pn=rawget(properties,n)
if pn then
- pn=rawget(pn,"injections")
+ local ni=marki[i]
+ local pn=rawget(pn,ni)
if pn then
local p=pn.markbasenode
if p then
@@ -10539,7 +10563,7 @@ local function inject_marks(marks,nofmarks)
local rightkern=nil
local pp=rawget(properties,p)
if pp then
- pp=rawget(pp,"injections")
+ pp=rawget(pp,ni)
if pp then
rightkern=pp.rightkern
end
@@ -10550,9 +10574,9 @@ local function inject_marks(marks,nofmarks)
else
local leftkern=pp.leftkern
if leftkern then
- ox=px-pn.markx
- else
ox=px-pn.markx-leftkern
+ else
+ ox=px-pn.markx
end
end
else
@@ -10565,12 +10589,7 @@ local function inject_marks(marks,nofmarks)
end
setfield(n,"xoffset",ox)
local py=getfield(p,"yoffset")
- local oy=0
- if marks[p] then
- oy=py+pn.marky
- else
- oy=getfield(n,"yoffset")+py+pn.marky
- end
+ local oy=getfield(n,"yoffset")+py+pn.marky
setfield(n,"yoffset",oy)
else
end
@@ -10578,14 +10597,14 @@ local function inject_marks(marks,nofmarks)
end
end
end
-local function inject_cursives(glyphs,nofglyphs)
+local function inject_cursives(glyphs,glyphi,nofglyphs)
local cursiveanchor,lastanchor=nil,nil
local minc,maxc,last=0,0,nil
for i=1,nofglyphs do
local n=glyphs[i]
local pn=rawget(properties,n)
if pn then
- pn=rawget(pn,"injections")
+ pn=rawget(pn,glyphi[i])
end
if pn then
local cursivex=pn.cursivex
@@ -10651,22 +10670,59 @@ local function inject_cursives(glyphs,nofglyphs)
end
end
end
-local function inject_kerns(head,list,length)
+local function inject_kerns(head,glist,ilist,length)
for i=1,length do
- local n=list[i]
+ local n=glist[i]
local pn=rawget(properties,n)
if pn then
- local i=rawget(pn,"injections")
- if i then
- local leftkern=i.leftkern
- if leftkern and leftkern~=0 then
- insert_node_before(head,n,newkern(leftkern))
- end
- local rightkern=i.rightkern
- if rightkern and rightkern~=0 then
- insert_node_after(head,n,newkern(rightkern))
- end
- end
+ local dp=nil
+ local dr=nil
+ local ni=ilist[i]
+ local p=nil
+ if ni=="injections" then
+ p=getprev(n)
+ if p then
+ local id=getid(p)
+ if id==disc_code then
+ dp=getfield(p,"post")
+ dr=getfield(p,"replace")
+ end
+ end
+ end
+ if dp then
+ local i=rawget(pn,"postinjections")
+ if i then
+ local leftkern=i.leftkern
+ if leftkern and leftkern~=0 then
+ local t=find_tail(dp)
+ insert_node_after(dp,t,newkern(leftkern))
+setfield(p,"post",dp)
+ end
+ end
+ end
+ if dr then
+ local i=rawget(pn,"replaceinjections")
+ if i then
+ local leftkern=i.leftkern
+ if leftkern and leftkern~=0 then
+ local t=find_tail(dr)
+ insert_node_after(dr,t,newkern(leftkern))
+setfield(p,"replace",dr)
+ end
+ end
+ else
+ local i=rawget(pn,ni)
+ if i then
+ local leftkern=i.leftkern
+ if leftkern and leftkern~=0 then
+ insert_node_before(head,n,newkern(leftkern))
+ end
+ local rightkern=i.rightkern
+ if rightkern and rightkern~=0 then
+ insert_node_after(head,n,newkern(rightkern))
+ end
+ end
+ end
end
end
end
@@ -10675,23 +10731,18 @@ local function inject_everything(head,where)
if trace_injections then
trace(head,"everything")
end
- local glyphs,nofglyphs,marks,nofmarks
- if nofregisteredpairs>0 then
- glyphs,nofglyphs,marks,nofmarks=collect_glyphs_1(head)
- else
- glyphs,nofglyphs,marks,nofmarks=collect_glyphs_2(head)
- end
+ local glyphs,glyphi,nofglyphs,marks,marki,nofmarks=collect_glyphs(head,nofregisteredpairs>0)
if nofglyphs>0 then
if nofregisteredcursives>0 then
- inject_cursives(glyphs,nofglyphs)
+ inject_cursives(glyphs,glyphi,nofglyphs)
end
if nofregisteredmarks>0 then
- inject_marks(marks,nofmarks)
+ inject_marks(marks,marki,nofmarks)
end
- inject_kerns(head,glyphs,nofglyphs)
+ inject_kerns(head,glyphs,glyphi,nofglyphs)
end
if nofmarks>0 then
- inject_kerns(head,marks,nofmarks)
+ inject_kerns(head,marks,marki,nofmarks)
end
if keepregisteredcounts then
keepregisteredcounts=false
@@ -10725,6 +10776,7 @@ local function inject_kerns_only(head,where)
if leftkern and leftkern~=0 then
local t=find_tail(d)
insert_node_after(d,t,newkern(leftkern))
+setfield(p,"post",d)
end
end
end
@@ -10736,6 +10788,7 @@ local function inject_kerns_only(head,where)
if leftkern and leftkern~=0 then
local t=find_tail(d)
insert_node_after(d,t,newkern(leftkern))
+setfield(p,"replace",d)
end
end
else
@@ -10850,7 +10903,7 @@ local function inject_pairs_only(head,where)
trace(head,"pairs")
end
local n=head
- local p=nil
+ local p=nil
while n do
local id=getid(n)
if id==glyph_code then
@@ -10866,6 +10919,7 @@ local function inject_pairs_only(head,where)
if leftkern and leftkern~=0 then
local t=find_tail(d)
insert_node_after(d,t,newkern(leftkern))
+setfield(p,"post",d)
end
end
end
@@ -10877,6 +10931,7 @@ local function inject_pairs_only(head,where)
if leftkern and leftkern~=0 then
local t=find_tail(d)
insert_node_after(d,t,newkern(leftkern))
+setfield(p,"replace",d)
end
end
else
@@ -11022,7 +11077,7 @@ local function inject_pairs_only(head,where)
end
return tonode(head),true
end
-function injections.handler(head,where)
+function injections.handler(head,where)
if nofregisteredmarks>0 or nofregisteredcursives>0 then
return inject_everything(head,where)
elseif nofregisteredpairs>0 then
@@ -11422,14 +11477,12 @@ if not modules then modules={} end modules ['font-otn']={
copyright="PRAGMA ADE / ConTeXt Development Team",
license="see context related readme files",
}
-local concat,insert,remove=table.concat,table.insert,table.remove
-local gmatch,gsub,find,match,lower,strip=string.gmatch,string.gsub,string.find,string.match,string.lower,string.strip
-local type,next,tonumber,tostring=type,next,tonumber,tostring
-local lpegmatch=lpeg.match
+local type,next,tonumber=type,next,tonumber
local random=math.random
local formatters=string.formatters
local logs,trackers,nodes,attributes=logs,trackers,nodes,attributes
local registertracker=trackers.register
+local registerdirective=directives.register
local fonts=fonts
local otf=fonts.handlers.otf
local trace_lookups=false registertracker("otf.lookups",function(v) trace_lookups=v end)
@@ -11448,6 +11501,14 @@ local trace_applied=false registertracker("otf.applied",function(v) trace_applie
local trace_steps=false registertracker("otf.steps",function(v) trace_steps=v end)
local trace_skips=false registertracker("otf.skips",function(v) trace_skips=v end)
local trace_directions=false registertracker("otf.directions",function(v) trace_directions=v end)
+local trace_kernruns=false registertracker("otf.kernruns",function(v) trace_kernruns=v end)
+local trace_discruns=false registertracker("otf.discruns",function(v) trace_discruns=v end)
+local trace_compruns=false registertracker("otf.compruns",function(v) trace_compruns=v end)
+local quit_on_no_replacement=true
+local check_discretionaries=true
+local zwnjruns=true
+registerdirective("otf.zwnjruns",function(v) zwnjruns=v end)
+registerdirective("otf.chain.quitonnoreplacement",function(value) quit_on_no_replacement=value end)
local report_direct=logs.reporter("fonts","otf direct")
local report_subchain=logs.reporter("fonts","otf subchain")
local report_chain=logs.reporter("fonts","otf chain")
@@ -11610,6 +11671,48 @@ local function copy_glyph(g)
return n
end
end
+local function collapse_disc(start,next)
+ local replace1=getfield(start,"replace")
+ local replace2=getfield(next,"replace")
+ if replace1 and replace2 then
+ local pre2=getfield(next,"pre")
+ local post2=getfield(next,"post")
+ setfield(replace1,"prev",nil)
+ if pre2 then
+ local pre1=getfield(start,"pre")
+ if pre1 then
+ flush_node_list(pre1)
+ end
+ local pre1=copy_node_list(replace1)
+ local tail1=find_node_tail(pre1)
+ setfield(tail1,"next",pre2)
+ setfield(pre2,"prev",tail1)
+ setfield(start,"pre",pre1)
+ setfield(next,"pre",nil)
+ else
+ setfield(start,"pre",nil)
+ end
+ if post2 then
+ local post1=getfield(start,"post")
+ if post1 then
+ flush_node_list(post1)
+ end
+ setfield(start,"post",post2)
+ else
+ setfield(start,"post",nil)
+ end
+ local tail1=find_node_tail(replace1)
+ setfield(tail1,"next",replace2)
+ setfield(replace2,"prev",tail1)
+ setfield(start,"replace",replace1)
+ setfield(next,"replace",nil)
+ local nextnext=getnext(next)
+ setfield(nextnext,"prev",start)
+ setfield(start,"next",nextnext)
+ free_node(next)
+ else
+ end
+end
local function markstoligature(kind,lookupname,head,start,stop,char)
if start==stop and getchar(start)==char then
return head,start
@@ -11654,14 +11757,66 @@ local function getcomponentindex(start)
return 0
end
end
+local a_noligature=attributes.private("noligature")
+local prehyphenchar=languages and languages.prehyphenchar
+local posthyphenchar=languages and languages.posthyphenchar
+if prehyphenchar then
+elseif context then
+ report_warning("no language support") os.exit()
+else
+ local newlang=lang.new
+ local getpre=lang.prehyphenchar
+ local getpost=lang.posthyphenchar
+ prehyphenchar=function(l) local l=newlang(l) return l and getpre (l) or -1 end
+ posthyphenchar=function(l) local l=newlang(l) return l and getpost (l) or -1 end
+end
+local function addhyphens(template,pre,post)
+ local l=getfield(template,"lang")
+ local p=prehyphenchar(l)
+ if p and p>0 then
+ local c=copy_node(template)
+ setfield(c,"char",p)
+ if pre then
+ local t=find_node_tail(pre)
+ setfield(t,"next",c)
+ setfield(c,"prev",t)
+ else
+ pre=c
+ end
+ end
+ local p=posthyphenchar(l)
+ if p and p>0 then
+ local c=copy_node(template)
+ setfield(c,"char",p)
+ if post then
+ local prev=getprev(post)
+ setfield(c,"next",post)
+ setfield(post,"prev",c)
+ if prev then
+ setfield(prev,"next",c)
+ setfield(c,"prev",prev)
+ end
+ else
+ post=c
+ end
+ end
+ return pre,post
+end
local function toligature(kind,lookupname,head,start,stop,char,markflag,discfound)
+ if getattr(start,a_noligature)==1 then
+ return head,start
+ end
if start==stop and getchar(start)==char then
resetinjection(start)
setfield(start,"char",char)
return head,start
end
+ local components=getfield(start,"components")
+ if components then
+ end
local prev=getprev(start)
local next=getnext(stop)
+ local comp=start
setfield(start,"prev",nil)
setfield(stop,"next",nil)
local base=copy_glyph(start)
@@ -11671,7 +11826,7 @@ local function toligature(kind,lookupname,head,start,stop,char,markflag,discfoun
resetinjection(base)
setfield(base,"char",char)
setfield(base,"subtype",ligature_code)
- setfield(base,"components",start)
+ setfield(base,"components",comp)
if prev then
setfield(prev,"next",base)
end
@@ -11697,7 +11852,9 @@ local function toligature(kind,lookupname,head,start,stop,char,markflag,discfoun
if trace_marks then
logwarning("%s: keep mark %s, gets index %s",pref(kind,lookupname),gref(char),getligaindex(start))
end
- head,current=insert_node_after(head,current,copy_node(start))
+ local n=copy_node(start)
+ copyinjection(n,start)
+ head,current=insert_node_after(head,current,n)
elseif trace_marks then
logwarning("%s: delete mark %s",pref(kind,lookupname),gref(char))
end
@@ -11716,6 +11873,66 @@ local function toligature(kind,lookupname,head,start,stop,char,markflag,discfoun
end
start=getnext(start)
end
+ else
+ local discprev=getfield(discfound,"prev")
+ local discnext=getfield(discfound,"next")
+ if discprev and discnext then
+ local subtype=getsubtype(discfound)
+ if subtype==discretionary_code then
+ local pre=getfield(discfound,"pre")
+ local post=getfield(discfound,"post")
+ local replace=getfield(discfound,"replace")
+ if not replace then
+ local prev=getfield(base,"prev")
+ local copied=copy_node_list(comp)
+ setfield(discnext,"prev",nil)
+ setfield(discprev,"next",nil)
+ if pre then
+ setfield(discprev,"next",pre)
+ setfield(pre,"prev",discprev)
+ end
+ pre=comp
+ if post then
+ local tail=find_node_tail(post)
+ setfield(tail,"next",discnext)
+ setfield(discnext,"prev",tail)
+ setfield(post,"prev",nil)
+ else
+ post=discnext
+ end
+ setfield(prev,"next",discfound)
+ setfield(next,"prev",discfound)
+ setfield(discfound,"next",next)
+ setfield(discfound,"prev",prev)
+ setfield(base,"next",nil)
+ setfield(base,"prev",nil)
+ setfield(base,"components",copied)
+ setfield(discfound,"pre",pre)
+ setfield(discfound,"post",post)
+ setfield(discfound,"replace",base)
+ setfield(discfound,"subtype",discretionary_code)
+ base=prev
+ end
+ elseif subtype==regular_code then
+ local copied=copy_node_list(comp)
+ setfield(discnext,"prev",nil)
+ setfield(discprev,"next",nil)
+ local pre,post=addhyphens(comp,comp,discnext,subtype)
+ setfield(prev,"next",discfound)
+ setfield(next,"prev",discfound)
+ setfield(discfound,"next",next)
+ setfield(discfound,"prev",prev)
+ setfield(base,"next",nil)
+ setfield(base,"prev",nil)
+ setfield(base,"components",copied)
+ setfield(discfound,"pre",pre)
+ setfield(discfound,"post",post)
+ setfield(discfound,"replace",base)
+ setfield(discfound,"subtype",discretionary_code)
+ base=next
+ else
+ end
+ end
end
return head,base
end
@@ -11809,7 +12026,7 @@ function handlers.gsub_multiple(head,start,kind,lookupname,multiple,sequence)
return multiple_glyphs(head,start,multiple,sequence.flags[1])
end
function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence)
- local s,stop,discfound=getnext(start),nil,false
+ local s,stop=getnext(start),nil
local startchar=getchar(start)
if marks[startchar] then
while s do
@@ -11837,23 +12054,29 @@ function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence)
else
head,start=markstoligature(kind,lookupname,head,start,stop,lig)
end
- return head,start,true
+ return head,start,true,false
else
end
end
else
local skipmark=sequence.flags[1]
+ local discfound=false
+ local lastdisc=nil
while s do
local id=getid(s)
- if id==glyph_code and getsubtype(s)<256 then
- if getfont(s)==currentfont then
+ if id==glyph_code and getsubtype(s)<256 then
+ if getfont(s)==currentfont then
local char=getchar(s)
if skipmark and marks[char] then
s=getnext(s)
- else
- local lg=ligature[char]
+ else
+ local lg=ligature[char]
if lg then
- stop=s
+ if not discfound and lastdisc then
+ discfound=lastdisc
+ lastdisc=nil
+ end
+ stop=s
ligature=lg
s=getnext(s)
else
@@ -11864,13 +12087,13 @@ function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence)
break
end
elseif id==disc_code then
- discfound=true
+ lastdisc=s
s=getnext(s)
else
break
end
end
- local lig=ligature.ligature
+ local lig=ligature.ligature
if lig then
if stop then
if trace_ligatures then
@@ -11887,11 +12110,11 @@ function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence)
logprocess("%s: replacing %s by (no real) ligature %s case 3",pref(kind,lookupname),gref(startchar),gref(lig))
end
end
- return head,start,true
+ return head,start,true,discfound
else
end
end
- return head,start,false
+ return head,start,false,discfound
end
function handlers.gpos_mark2base(head,start,kind,lookupname,markanchors,sequence)
local markchar=getchar(start)
@@ -12045,7 +12268,7 @@ function handlers.gpos_mark2mark(head,start,kind,lookupname,markanchors,sequence
if al[anchor] then
local ma=markanchors[anchor]
if ma then
- local dx,dy,bound=setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma,characters[basechar])
+ local dx,dy,bound=setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma,characters[basechar],true)
if trace_marks then
logprocess("%s, anchor %s, bound %s: anchoring mark %s to basemark %s => (%p,%p)",
pref(kind,lookupname),anchor,bound,gref(markchar),gref(basechar),dx,dy)
@@ -12123,15 +12346,15 @@ function handlers.gpos_cursive(head,start,kind,lookupname,exitanchors,sequence)
return head,start,false
end
end
-function handlers.gpos_single(head,start,kind,lookupname,kerns,sequence)
+function handlers.gpos_single(head,start,kind,lookupname,kerns,sequence,injection)
local startchar=getchar(start)
- local dx,dy,w,h=setpair(start,tfmdata.parameters.factor,rlmode,sequence.flags[4],kerns,characters[startchar])
+ local dx,dy,w,h=setpair(start,tfmdata.parameters.factor,rlmode,sequence.flags[4],kerns,injection)
if trace_kerns then
logprocess("%s: shifting single %s by (%p,%p) and correction (%p,%p)",pref(kind,lookupname),gref(startchar),dx,dy,w,h)
end
return head,start,false
end
-function handlers.gpos_pair(head,start,kind,lookupname,kerns,sequence)
+function handlers.gpos_pair(head,start,kind,lookupname,kerns,sequence,lookuphash,i,injection)
local snext=getnext(start)
if not snext then
return head,start,false
@@ -12149,17 +12372,17 @@ function handlers.gpos_pair(head,start,kind,lookupname,kerns,sequence)
if not krn then
elseif type(krn)=="table" then
if lookuptype=="pair" then
- local a,b=krn[2],krn[3]
+ local a,b=krn[2],krn[3]
if a and #a>0 then
local startchar=getchar(start)
- local x,y,w,h=setpair(start,factor,rlmode,sequence.flags[4],a,characters[startchar])
+ local x,y,w,h=setpair(start,factor,rlmode,sequence.flags[4],a,injection)
if trace_kerns then
logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p)",pref(kind,lookupname),gref(startchar),gref(nextchar),x,y,w,h)
end
end
if b and #b>0 then
local startchar=getchar(start)
- local x,y,w,h=setpair(snext,factor,rlmode,sequence.flags[4],b,characters[nextchar])
+ local x,y,w,h=setpair(snext,factor,rlmode,sequence.flags[4],b,injection)
if trace_kerns then
logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p)",pref(kind,lookupname),gref(startchar),gref(nextchar),x,y,w,h)
end
@@ -12169,7 +12392,7 @@ function handlers.gpos_pair(head,start,kind,lookupname,kerns,sequence)
end
done=true
elseif krn~=0 then
- local k=setkern(snext,factor,rlmode,krn)
+ local k=setkern(snext,factor,rlmode,krn,injection)
if trace_kerns then
logprocess("%s: inserting kern %s between %s and %s",pref(kind,lookupname),k,gref(getchar(prev)),gref(nextchar))
end
@@ -12223,7 +12446,7 @@ function chainprocs.gsub_single(head,start,stop,kind,chainname,currentcontext,lo
local current=start
local subtables=currentlookup.subtables
if #subtables>1 then
- logwarning("todo: check if we need to loop over the replacements: %s",concat(subtables," "))
+ logwarning("todo: check if we need to loop over the replacements: % t",subtables)
end
while current do
if getid(current)==glyph_code then
@@ -12245,7 +12468,80 @@ function chainprocs.gsub_single(head,start,stop,kind,chainname,currentcontext,lo
logprocess("%s: replacing single %s by %s",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(currentchar),gref(replacement))
end
resetinjection(current)
- setfield(current,"char",replacement)
+ if check_discretionaries then
+ local next=getnext(current)
+ local prev=getprev(current)
+ local done=false
+ if next then
+ if getid(next)==disc_code then
+ local subtype=getsubtype(next)
+ if subtype==discretionary_code then
+ setfield(next,"prev",prev)
+ setfield(prev,"next",next)
+ setfield(current,"prev",nil)
+ setfield(current,"next",nil)
+ local replace=getfield(next,"replace")
+ local pre=getfield(next,"pre")
+ local new=copy_node(current)
+ setfield(new,"char",replacement)
+ if replace then
+ setfield(new,"next",replace)
+ setfield(replace,"prev",new)
+ end
+ if pre then
+ setfield(current,"next",pre)
+ setfield(pre,"prev",current)
+ end
+ setfield(next,"replace",new)
+ setfield(next,"pre",current)
+ end
+ start=next
+ done=true
+ local next=getnext(start)
+ if next and getid(next)==disc_code then
+ collapse_disc(start,next)
+ end
+ end
+ end
+ if not done and prev then
+ if getid(prev)==disc_code then
+ local subtype=getsubtype(prev)
+ if subtype==discretionary_code then
+ setfield(next,"prev",prev)
+ setfield(prev,"next",next)
+ setfield(current,"prev",nil)
+ setfield(current,"next",nil)
+ local replace=getfield(prev,"replace")
+ local post=getfield(prev,"post")
+ local new=copy_node(current)
+ setfield(new,"char",replacement)
+ if replace then
+ local tail=find_node_tail(replace)
+ setfield(tail,"next",new)
+ setfield(new,"prev",tail)
+ else
+ replace=new
+ end
+ if post then
+ local tail=find_node_tail(post)
+ setfield(tail,"next",current)
+ setfield(current,"prev",tail)
+ else
+ post=current
+ end
+ setfield(prev,"replace",replace)
+ setfield(prev,"post",post)
+ start=prev
+ done=true
+ end
+ end
+ end
+ if not done then
+ setfield(current,"char",replacement)
+ end
+ else
+ setfield(current,"char",replacement)
+ end
end
end
return head,start,true
@@ -12349,11 +12645,17 @@ function chainprocs.gsub_ligature(head,start,stop,kind,chainname,currentcontext,
while s do
local id=getid(s)
if id==disc_code then
- s=getnext(s)
- discfound=true
+ if not discfound then
+ discfound=s
+ end
+ if s==stop then
+ break
+ else
+ s=getnext(s)
+ end
else
local schar=getchar(s)
- if skipmark and marks[schar] then
+ if skipmark and marks[schar] then
s=getnext(s)
else
local lg=ligatures[schar]
@@ -12383,7 +12685,7 @@ function chainprocs.gsub_ligature(head,start,stop,kind,chainname,currentcontext,
end
end
head,start=toligature(kind,lookupname,head,start,stop,l2,currentlookup.flags[1],discfound)
- return head,start,true,nofreplacements
+ return head,start,true,nofreplacements,discfound
elseif trace_bugs then
if start==stop then
logwarning("%s: replacing character %s by ligature fails",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar))
@@ -12393,7 +12695,7 @@ function chainprocs.gsub_ligature(head,start,stop,kind,chainname,currentcontext,
end
end
end
- return head,start,false,0
+ return head,start,false,0,false
end
chainmores.gsub_ligature=chainprocs.gsub_ligature
function chainprocs.gpos_mark2base(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname)
@@ -12559,7 +12861,7 @@ function chainprocs.gpos_mark2mark(head,start,stop,kind,chainname,currentcontext
if al[anchor] then
local ma=markanchors[anchor]
if ma then
- local dx,dy,bound=setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma,characters[basechar])
+ local dx,dy,bound=setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma,characters[basechar],true)
if trace_marks then
logprocess("%s, anchor %s, bound %s: anchoring mark %s to basemark %s => (%p,%p)",
cref(kind,chainname,chainlookupname,lookupname),anchor,bound,gref(markchar),gref(basechar),dx,dy)
@@ -12654,7 +12956,7 @@ function chainprocs.gpos_single(head,start,stop,kind,chainname,currentcontext,lo
if kerns then
kerns=kerns[startchar]
if kerns then
- local dx,dy,w,h=setpair(start,tfmdata.parameters.factor,rlmode,sequence.flags[4],kerns,characters[startchar])
+ local dx,dy,w,h=setpair(start,tfmdata.parameters.factor,rlmode,sequence.flags[4],kerns)
if trace_kerns then
logprocess("%s: shifting single %s by (%p,%p) and correction (%p,%p)",cref(kind,chainname,chainlookupname),gref(startchar),dx,dy,w,h)
end
@@ -12689,30 +12991,20 @@ function chainprocs.gpos_pair(head,start,stop,kind,chainname,currentcontext,look
local a,b=krn[2],krn[3]
if a and #a>0 then
local startchar=getchar(start)
- local x,y,w,h=setpair(start,factor,rlmode,sequence.flags[4],a,characters[startchar])
+ local x,y,w,h=setpair(start,factor,rlmode,sequence.flags[4],a)
if trace_kerns then
logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(kind,chainname,chainlookupname),gref(startchar),gref(nextchar),x,y,w,h)
end
end
if b and #b>0 then
local startchar=getchar(start)
- local x,y,w,h=setpair(snext,factor,rlmode,sequence.flags[4],b,characters[nextchar])
+ local x,y,w,h=setpair(snext,factor,rlmode,sequence.flags[4],b)
if trace_kerns then
logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(kind,chainname,chainlookupname),gref(startchar),gref(nextchar),x,y,w,h)
end
end
else
report_process("%s: check this out (old kern stuff)",cref(kind,chainname,chainlookupname))
- local a,b=krn[2],krn[6]
- if a and a~=0 then
- local k=setkern(snext,factor,rlmode,a)
- if trace_kerns then
- logprocess("%s: inserting first kern %s between %s and %s",cref(kind,chainname,chainlookupname),k,gref(getchar(prev)),gref(nextchar))
- end
- end
- if b and b~=0 then
- logwarning("%s: ignoring second kern xoff %s",cref(kind,chainname,chainlookupname),b*factor)
- end
end
done=true
elseif krn~=0 then
@@ -12739,10 +13031,6 @@ local function show_skip(kind,chainname,char,ck,class)
logwarning("%s: skipping char %s, class %a, rule %a, lookuptype %a",cref(kind,chainname),gref(char),class,ck[1],ck[2])
end
end
-local quit_on_no_replacement=true
-directives.register("otf.chain.quitonnoreplacement",function(value)
- quit_on_no_replacement=value
-end)
local function normal_handle_contextchain(head,start,kind,chainname,contexts,sequence,lookuphash)
local flags=sequence.flags
local done=false
@@ -12802,7 +13090,34 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
break
end
elseif id==disc_code then
- last=getnext(last)
+ if check_discretionaries then
+ local replace=getfield(last,"replace")
+ if replace then
+ while replace do
+ if seq[n][getchar(replace)] then
+ n=n+1
+ replace=getnext(replace)
+ if not replace then
+ break
+ elseif n>l then
+ break
+ end
+ else
+ match=false
+ break
+ end
+ end
+ if not match then
+ break
+ elseif check_discretionaries=="trace" then
+ report_chain("check disc action in current")
+ end
+ else
+ last=getnext(last)
+ end
+ else
+ last=getnext(last)
+ end
else
match=false
break
@@ -12847,6 +13162,34 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
break
end
elseif id==disc_code then
+ if check_discretionaries then
+ local replace=getfield(prev,"replace")
+ if replace then
+ replace=find_node_tail(replace)
+ local finish=getprev(replace)
+ while replace do
+ if seq[n][getchar(replace)] then
+ n=n-1
+ replace=getprev(replace)
+ if not replace or replace==finish then
+ break
+ elseif n<1 then
+ break
+ end
+ else
+ match=false
+ break
+ end
+ end
+ if not match then
+ break
+ elseif check_discretionaries=="trace" then
+ report_chain("check disc action in before")
+ end
+ else
+ end
+ else
+ end
elseif seq[n][32] then
n=n -1
else
@@ -12855,7 +13198,7 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
end
prev=getprev(prev)
elseif seq[n][32] then
- n=n -1
+ n=n-1
else
match=false
break
@@ -12898,6 +13241,32 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
break
end
elseif id==disc_code then
+ if check_discretionaries then
+ local replace=getfield(current,"replace")
+ if replace then
+ while replace do
+ if seq[n][getchar(replace)] then
+ n=n+1
+ replace=getnext(replace)
+ if not replace then
+ break
+ elseif n>s then
+ break
+ end
+ else
+ match=false
+ break
+ end
+ end
+ if not match then
+ break
+ elseif check_discretionaries=="trace" then
+ report_chain("check disc action in after")
+ end
+ else
+ end
+ else
+ end
elseif seq[n][32] then
n=n+1
else
@@ -13082,7 +13451,7 @@ local function initialize(sequence,script,language,enabled)
local scripts=features[kind]
local languages=scripts[script] or scripts[wildcard]
if languages and (languages[language] or languages[wildcard]) then
- return { valid,autofeatures[kind] or false,sequence.chain or 0,kind,sequence }
+ return { valid,autofeatures[kind] or false,sequence,kind }
end
end
end
@@ -13122,6 +13491,162 @@ function otf.dataset(tfmdata,font)
end
return rl
end
+local function kernrun(disc,run)
+ if trace_kernruns then
+ report_run("kern")
+ end
+ local prev=getprev(disc)
+ local next=getnext(disc)
+ local pre=getfield(disc,"pre")
+ local post=getfield(disc,"post")
+ local replace=getfield(disc,"replace")
+ if pre or replace then
+ if not (prev and getid(prev)==glyph_code and getfont(prev)==currentfont and getsubtype(prev)<256) then
+ prev=false
+ end
+ end
+ if post or replace then
+ if not (next and getid(next)==glyph_code and getfont(next)==currentfont and getsubtype(next)<256) then
+ next=false
+ end
+ end
+ if not pre then
+ elseif prev then
+ local nest=getprev(pre)
+ setfield(pre,"prev",prev)
+ setfield(prev,"next",pre)
+ run(prev,"preinjections")
+ setfield(pre,"prev",nest)
+ setfield(prev,"next",disc)
+ else
+ run(pre,"preinjections")
+ end
+ if not post then
+ elseif next then
+ local tail=find_node_tail(post)
+ setfield(tail,"next",next)
+ setfield(next,"prev",tail)
+ run(post,"postinjections",tail)
+ setfield(tail,"next",nil)
+ setfield(next,"prev",disc)
+ else
+ run(post,"postinjections")
+ end
+ if not replace and prev and next then
+ elseif prev and next then
+ local tail=find_node_tail(replace)
+ local nest=getprev(replace)
+ setfield(replace,"prev",prev)
+ setfield(prev,"next",replace)
+ setfield(tail,"next",next)
+ setfield(next,"prev",tail)
+ run(prev,"replaceinjections",tail)
+ setfield(replace,"prev",nest)
+ setfield(prev,"next",disc)
+ setfield(tail,"next",nil)
+ setfield(next,"prev",disc)
+ elseif prev then
+ local nest=getprev(replace)
+ setfield(replace,"prev",prev)
+ setfield(prev,"next",replace)
+ run(prev,"replaceinjections")
+ setfield(replace,"prev",nest)
+ setfield(prev,"next",disc)
+ elseif next then
+ local tail=find_node_tail(replace)
+ setfield(tail,"next",next)
+ setfield(next,"prev",tail)
+ run(replace,"replaceinjections",tail)
+ setfield(tail,"next",nil)
+ setfield(next,"prev",disc)
+ else
+ run(replace,"replaceinjections")
+ end
+end
+local function comprun(disc,run)
+ if trace_compruns then
+ report_run("comp: %s",languages.serializediscretionary(disc))
+ end
+ local pre=getfield(disc,"pre")
+ if pre then
+ local new,done=run(pre)
+ if done then
+ setfield(disc,"pre",new)
+ end
+ end
+ local post=getfield(disc,"post")
+ if post then
+ local new,done=run(post)
+ if done then
+ setfield(disc,"post",new)
+ end
+ end
+ local replace=getfield(disc,"replace")
+ if replace then
+ local new,done=run(replace)
+ if done then
+ setfield(disc,"replace",new)
+ end
+ end
+end
+local function testrun(disc,trun,crun)
+ local next=getnext(disc)
+ if next then
+ local replace=getfield(disc,"replace")
+ if replace then
+ local prev=getprev(disc)
+ if prev then
+ local tail=find_node_tail(replace)
+ setfield(tail,"next",next)
+ setfield(next,"prev",tail)
+ if trun(replace,next) then
+ setfield(disc,"replace",nil)
+ setfield(prev,"next",replace)
+ setfield(replace,"prev",prev)
+ setfield(next,"prev",tail)
+ setfield(tail,"next",next)
+ setfield(disc,"prev",nil)
+ setfield(disc,"next",nil)
+ flush_node_list(disc)
+ return replace
+ else
+ setfield(tail,"next",nil)
+ setfield(next,"prev",disc)
+ end
+ else
+ end
+ else
+ end
+ else
+ end
+ comprun(disc,crun)
+ return next
+end
+local function discrun(disc,drun,krun)
+ local next=getnext(disc)
+ local prev=getprev(disc)
+ if trace_discruns then
+ report_run("disc")
+ end
+ if next and prev then
+ setfield(prev,"next",next)
+ drun(prev)
+ setfield(prev,"next",disc)
+ end
+ local pre=getfield(disc,"pre")
+ if not pre then
+ elseif prev then
+ local nest=getprev(pre)
+ setfield(pre,"prev",prev)
+ setfield(prev,"next",pre)
+ krun(prev,"preinjections")
+ setfield(pre,"prev",nest)
+ setfield(prev,"next",disc)
+ else
+ krun(pre,"preinjections")
+ end
+ return next
+end
local function featuresprocessor(head,font,attr)
local lookuphash=lookuphashes[font]
if not lookuphash then
@@ -13148,17 +13673,18 @@ local function featuresprocessor(head,font,attr)
local dirstack={}
for s=1,#datasets do
local dataset=datasets[s]
- featurevalue=dataset[1]
- local sequence=dataset[5]
+ featurevalue=dataset[1]
+ local attribute=dataset[2]
+ local sequence=dataset[3]
+ local kind=dataset[4]
local rlparmode=0
local topstack=0
local success=false
- local attribute=dataset[2]
- local chain=dataset[3]
local typ=sequence.type
+ local gpossing=typ=="gpos_single" or typ=="gpos_pair"
local subtables=sequence.subtables
- if chain<0 then
- local handler=handlers[typ]
+ local handler=handlers[typ]
+ if typ=="gsub_reversecontextchain" then
local start=find_node_tail(head)
while start do
local id=getid(start)
@@ -13171,13 +13697,14 @@ local function featuresprocessor(head,font,attr)
a=true
end
if a then
+ local char=getchar(start)
for i=1,#subtables do
local lookupname=subtables[i]
local lookupcache=lookuphash[lookupname]
if lookupcache then
- local lookupmatch=lookupcache[getchar(start)]
+ local lookupmatch=lookupcache[start]
if lookupmatch then
- head,start,success=handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i)
+ head,start,success=handler(head,start,kind,lookupname,lookupmatch,sequence,lookuphash,i)
if success then
break
end
@@ -13198,7 +13725,6 @@ local function featuresprocessor(head,font,attr)
end
end
else
- local handler=handlers[typ]
local ns=#subtables
local start=head
rlmode=0
@@ -13208,12 +13734,14 @@ local function featuresprocessor(head,font,attr)
if not lookupcache then
report_missing_cache(typ,lookupname)
else
- local function subrun(start)
+ local function c_run(start)
local head=start
local done=false
while start do
local id=getid(start)
- if id==glyph_code and getfont(start)==font and getsubtype(start)<256 then
+ if id~=glyph_code then
+ start=getnext(start)
+ elseif getfont(start)==font and getsubtype(start)<256 then
local a=getattr(start,0)
if a then
a=(a==attr) and (not attribute or getprop(start,a_state)==attribute)
@@ -13224,7 +13752,7 @@ local function featuresprocessor(head,font,attr)
local lookupmatch=lookupcache[getchar(start)]
if lookupmatch then
local ok
- head,start,ok=handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,1)
+ head,start,ok=handler(head,start,kind,lookupname,lookupmatch,sequence,lookuphash,1)
if ok then
done=true
end
@@ -13234,43 +13762,98 @@ local function featuresprocessor(head,font,attr)
start=getnext(start)
end
else
- start=getnext(start)
+ return head,false
end
end
if done then
- success=true
- return head
+ success=true
end
+ return head,done
end
- local function kerndisc(disc)
- local prev=getprev(disc)
- local next=getnext(disc)
- if prev and next then
- setfield(prev,"next",next)
- local a=getattr(prev,0)
- if a then
- a=(a==attr) and (not attribute or getprop(prev,a_state)==attribute)
+ local function t_run(start,stop)
+ while start~=stop do
+ local id=getid(start)
+ if id==glyph_code and getfont(start)==font and getsubtype(start)<256 then
+ local a=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
+ if a then
+ local lookupmatch=lookupcache[getchar(start)]
+ if lookupmatch then
+ local s=getnext(start)
+ local l=nil
+ while s do
+ local lg=lookupmatch[getchar(s)]
+ if lg then
+ l=lg
+ s=getnext(s)
+ else
+ break
+ end
+ end
+ if l and l.ligature then
+ return true
+ end
+ end
+ end
+ start=getnext(start)
else
- a=not attribute or getprop(prev,a_state)==attribute
+ break
end
- if a then
- local lookupmatch=lookupcache[getchar(prev)]
- if lookupmatch then
- local h,d,ok=handler(head,prev,dataset[4],lookupname,lookupmatch,sequence,lookuphash,1)
- if ok then
- done=true
- success=true
+ end
+ end
+ local function d_run(prev)
+ local a=getattr(prev,0)
+ if a then
+ a=(a==attr) and (not attribute or getprop(prev,a_state)==attribute)
+ else
+ a=not attribute or getprop(prev,a_state)==attribute
+ end
+ if a then
+ local lookupmatch=lookupcache[getchar(prev)]
+ if lookupmatch then
+ local h,d,ok=handler(head,prev,kind,lookupname,lookupmatch,sequence,lookuphash,1)
+ if ok then
+ done=true
+ success=true
+ end
+ end
+ end
+ end
+ local function k_run(sub,injection,last)
+ local a=getattr(sub,0)
+ if a then
+ a=(a==attr) and (not attribute or getprop(sub,a_state)==attribute)
+ else
+ a=not attribute or getprop(sub,a_state)==attribute
+ end
+ if a then
+ for n in traverse_nodes(sub) do
+ if n==last then
+ break
+ end
+ local id=getid(n)
+ if id==glyph_code then
+ local lookupmatch=lookupcache[getchar(n)]
+ if lookupmatch then
+ local h,d,ok=handler(sub,n,kind,lookupname,lookupmatch,sequence,lookuphash,1,injection)
+ if ok then
+ done=true
+ success=true
+ end
end
+ else
end
end
- setfield(prev,"next",disc)
end
- return next
end
while start do
local id=getid(start)
if id==glyph_code then
- if getfont(start)==font and getsubtype(start)<256 then
+ if getfont(start)==font and getsubtype(start)<256 then
local a=getattr(start,0)
if a then
a=(a==attr) and (not attribute or getprop(start,a_state)==attribute)
@@ -13278,13 +13861,18 @@ local function featuresprocessor(head,font,attr)
a=not attribute or getprop(start,a_state)==attribute
end
if a then
- local lookupmatch=lookupcache[getchar(start)]
+ local char=getchar(start)
+ local lookupmatch=lookupcache[char]
if lookupmatch then
local ok
- head,start,ok=handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,1)
+ head,start,ok=handler(head,start,kind,lookupname,lookupmatch,sequence,lookuphash,1)
if ok then
success=true
+ elseif gpossing and zwnjruns and char==zwnj then
+ discrun(start,d_run)
end
+ elseif gpossing and zwnjruns and char==zwnj then
+ discrun(start,d_run)
end
if start then start=getnext(start) end
else
@@ -13294,26 +13882,24 @@ local function featuresprocessor(head,font,attr)
start=getnext(start)
end
elseif id==disc_code then
- if getsubtype(start)==discretionary_code then
- local pre=getfield(start,"pre")
- if pre then
- local new=subrun(pre)
- if new then setfield(start,"pre",new) end
- end
- local post=getfield(start,"post")
- if post then
- local new=subrun(post)
- if new then setfield(start,"post",new) end
+ local discretionary=getsubtype(start)==discretionary_code
+ if gpossing then
+ if discretionary then
+ kernrun(start,k_run)
+ else
+ discrun(start,d_run,k_run)
end
- local replace=getfield(start,"replace")
- if replace then
- local new=subrun(replace)
- if new then setfield(start,"replace",new) end
+ start=getnext(start)
+ elseif discretionary then
+ if typ=="gsub_ligature" then
+ start=testrun(start,t_run,c_run)
+ else
+ comprun(start,c_run)
+ start=getnext(start)
end
-elseif typ=="gpos_single" or typ=="gpos_pair" then
- kerndisc(start)
+ else
+ start=getnext(start)
end
- start=getnext(start)
elseif id==whatsit_code then
local subtype=getsubtype(start)
if subtype==dir_code then
@@ -13358,12 +13944,14 @@ elseif typ=="gpos_single" or typ=="gpos_pair" then
end
end
else
- local function subrun(start)
+ local function c_run(start)
local head=start
local done=false
while start do
local id=getid(start)
- if id==glyph_code and getfont(start)==font and getsubtype(start)<256 then
+ if id~=glyph_code then
+ start=getnext(start)
+ elseif getfont(start)==font and getsubtype(start)<256 then
local a=getattr(start,0)
if a then
a=(a==attr) and (not attribute or getprop(start,a_state)==attribute)
@@ -13371,14 +13959,15 @@ elseif typ=="gpos_single" or typ=="gpos_pair" then
a=not attribute or getprop(start,a_state)==attribute
end
if a then
+ local char=getchar(start)
for i=1,ns do
local lookupname=subtables[i]
local lookupcache=lookuphash[lookupname]
if lookupcache then
- local lookupmatch=lookupcache[getchar(start)]
+ local lookupmatch=lookupcache[char]
if lookupmatch then
local ok
- head,start,ok=handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i)
+ head,start,ok=handler(head,start,kind,lookupname,lookupmatch,sequence,lookuphash,i)
if ok then
done=true
break
@@ -13395,46 +13984,120 @@ elseif typ=="gpos_single" or typ=="gpos_pair" then
start=getnext(start)
end
else
- start=getnext(start)
+ return head,false
end
end
if done then
success=true
- return head
end
+ return head,done
end
- local function kerndisc(disc)
- local prev=getprev(disc)
- local next=getnext(disc)
- if prev and next then
- setfield(prev,"next",next)
- local a=getattr(prev,0)
- if a then
- a=(a==attr) and (not attribute or getprop(prev,a_state)==attribute)
- else
- a=not attribute or getprop(prev,a_state)==attribute
+ local function d_run(prev)
+ local a=getattr(prev,0)
+ if a then
+ a=(a==attr) and (not attribute or getprop(prev,a_state)==attribute)
+ else
+ a=not attribute or getprop(prev,a_state)==attribute
+ end
+ if a then
+ local char=getchar(prev)
+ for i=1,ns do
+ local lookupname=subtables[i]
+ local lookupcache=lookuphash[lookupname]
+ if lookupcache then
+ local lookupmatch=lookupcache[char]
+ if lookupmatch then
+ local h,d,ok=handler(head,prev,kind,lookupname,lookupmatch,sequence,lookuphash,i)
+ if ok then
+ done=true
+ break
+ end
+ end
+ else
+ report_missing_cache(typ,lookupname)
+ end
end
- if a then
- for i=1,ns do
- local lookupname=subtables[i]
- local lookupcache=lookuphash[lookupname]
- if lookupcache then
- local lookupmatch=lookupcache[getchar(prev)]
- if lookupmatch then
- local h,d,ok=handler(head,prev,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i)
- if ok then
- done=true
- break
+ end
+ end
+ local function k_run(sub,injection,last)
+ local a=getattr(sub,0)
+ if a then
+ a=(a==attr) and (not attribute or getprop(sub,a_state)==attribute)
+ else
+ a=not attribute or getprop(sub,a_state)==attribute
+ end
+ if a then
+ for n in traverse_nodes(sub) do
+ if n==last then
+ break
+ end
+ local id=getid(n)
+ if id==glyph_code then
+ local char=getchar(n)
+ for i=1,ns do
+ local lookupname=subtables[i]
+ local lookupcache=lookuphash[lookupname]
+ if lookupcache then
+ local lookupmatch=lookupcache[char]
+ if lookupmatch then
+ local h,d,ok=handler(head,n,kind,lookupname,lookupmatch,sequence,lookuphash,i,injection)
+ if ok then
+ done=true
+ break
+ end
end
+ else
+ report_missing_cache(typ,lookupname)
+ end
+ end
+ else
+ end
+ end
+ end
+ end
+ local function t_run(start,stop)
+ while start~=stop do
+ local id=getid(start)
+ if id==glyph_code and getfont(start)==font and getsubtype(start)<256 then
+ local a=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
+ if a then
+ local char=getchar(start)
+ for i=1,ns do
+ local lookupname=subtables[i]
+ local lookupcache=lookuphash[lookupname]
+ if lookupcache then
+ local lookupmatch=lookupcache[char]
+ if lookupmatch then
+ local s=getnext(start)
+ local l=nil
+ while s do
+ local lg=lookupmatch[getchar(s)]
+ if lg then
+ l=lg
+ s=getnext(s)
+ else
+ break
+ end
+ end
+ if l and l.ligature then
+ return true
+ end
+ end
+ else
+ report_missing_cache(typ,lookupname)
end
- else
- report_missing_cache(typ,lookupname)
end
end
+ start=getnext(start)
+ else
+ break
end
- setfield(prev,"next",disc)
end
- return next
end
while start do
local id=getid(start)
@@ -13451,16 +14114,21 @@ elseif typ=="gpos_single" or typ=="gpos_pair" then
local lookupname=subtables[i]
local lookupcache=lookuphash[lookupname]
if lookupcache then
- local lookupmatch=lookupcache[getchar(start)]
+ local char=getchar(start)
+ local lookupmatch=lookupcache[char]
if lookupmatch then
local ok
- head,start,ok=handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i)
+ head,start,ok=handler(head,start,kind,lookupname,lookupmatch,sequence,lookuphash,i)
if ok then
success=true
break
elseif not start then
break
+ elseif gpossing and zwnjruns and char==zwnj then
+ discrun(start,d_run)
end
+ elseif gpossing and zwnjruns and char==zwnj then
+ discrun(start,d_run)
end
else
report_missing_cache(typ,lookupname)
@@ -13474,26 +14142,24 @@ elseif typ=="gpos_single" or typ=="gpos_pair" then
start=getnext(start)
end
elseif id==disc_code then
- if getsubtype(start)==discretionary_code then
- local pre=getfield(start,"pre")
- if pre then
- local new=subrun(pre)
- if new then setfield(start,"pre",new) end
- end
- local post=getfield(start,"post")
- if post then
- local new=subrun(post)
- if new then setfield(start,"post",new) end
+ local discretionary=getsubtype(start)==discretionary_code
+ if gpossing then
+ if discretionary then
+ kernrun(start,k_run)
+ else
+ discrun(start,d_run,k_run)
end
- local replace=getfield(start,"replace")
- if replace then
- local new=subrun(replace)
- if new then setfield(start,"replace",new) end
+ start=getnext(start)
+ elseif discretionary then
+ if typ=="gsub_ligature" then
+ start=testrun(start,t_run,c_run)
+ else
+ comprun(start,c_run)
+ start=getnext(start)
end
-elseif typ=="gpos_single" or typ=="gpos_pair" then
- kerndisc(start)
+ else
+ start=getnext(start)
end
- start=getnext(start)
elseif id==whatsit_code then
local subtype=getsubtype(start)
if subtype==dir_code then
@@ -13556,43 +14222,46 @@ local function generic(lookupdata,lookupname,unicode,lookuphash)
lookuphash[lookupname]={ [unicode]=lookupdata }
end
end
+local function ligature(lookupdata,lookupname,unicode,lookuphash)
+ local target=lookuphash[lookupname]
+ if not target then
+ target={}
+ lookuphash[lookupname]=target
+ end
+ for i=1,#lookupdata do
+ local li=lookupdata[i]
+ local tu=target[li]
+ if not tu then
+ tu={}
+ target[li]=tu
+ end
+ target=tu
+ end
+ target.ligature=unicode
+end
+local function pair(lookupdata,lookupname,unicode,lookuphash)
+ local target=lookuphash[lookupname]
+ if not target then
+ target={}
+ lookuphash[lookupname]=target
+ end
+ local others=target[unicode]
+ local paired=lookupdata[1]
+ if others then
+ others[paired]=lookupdata
+ else
+ others={ [paired]=lookupdata }
+ target[unicode]=others
+ end
+end
local action={
substitution=generic,
multiple=generic,
alternate=generic,
position=generic,
- ligature=function(lookupdata,lookupname,unicode,lookuphash)
- local target=lookuphash[lookupname]
- if not target then
- target={}
- lookuphash[lookupname]=target
- end
- for i=1,#lookupdata do
- local li=lookupdata[i]
- local tu=target[li]
- if not tu then
- tu={}
- target[li]=tu
- end
- target=tu
- end
- target.ligature=unicode
- end,
- pair=function(lookupdata,lookupname,unicode,lookuphash)
- local target=lookuphash[lookupname]
- if not target then
- target={}
- lookuphash[lookupname]=target
- end
- local others=target[unicode]
- local paired=lookupdata[1]
- if others then
- others[paired]=lookupdata
- else
- others={ [paired]=lookupdata }
- target[unicode]=others
- end
- end,
+ ligature=ligature,
+ pair=pair,
+ kern=pair,
}
local function prepare_lookups(tfmdata)
local rawdata=tfmdata.shared.rawdata
@@ -13603,13 +14272,14 @@ local function prepare_lookups(tfmdata)
local lookuptypes=resources.lookuptypes
local characters=tfmdata.characters
local descriptions=tfmdata.descriptions
+ local duplicates=resources.duplicates
for unicode,character in next,characters do
local description=descriptions[unicode]
if description then
local lookups=description.slookups
if lookups then
for lookupname,lookupdata in next,lookups do
- action[lookuptypes[lookupname]](lookupdata,lookupname,unicode,lookuphash)
+ action[lookuptypes[lookupname]](lookupdata,lookupname,unicode,lookuphash,duplicates)
end
end
local lookups=description.mlookups
@@ -13618,7 +14288,7 @@ local function prepare_lookups(tfmdata)
local lookuptype=lookuptypes[lookupname]
for l=1,#lookuplist do
local lookupdata=lookuplist[l]
- action[lookuptype](lookupdata,lookupname,unicode,lookuphash)
+ action[lookuptype](lookupdata,lookupname,unicode,lookuphash,duplicates)
end
end
end
@@ -13640,7 +14310,7 @@ local function prepare_lookups(tfmdata)
for name,anchor in next,anchors do
local lookups=anchor_to_lookup[name]
if lookups then
- for lookup,_ in next,lookups do
+ for lookup in next,lookups do
local target=lookuphash[lookup]
if target then
target[unicode]=anchors
@@ -13722,7 +14392,7 @@ local function prepare_contextchains(tfmdata)
if sequence[1] then
nt=nt+1
t[nt]={ nofrules,lookuptype,sequence,start,stop,rule.lookups,replacements }
- for unic,_ in next,sequence[start] do
+ for unic in next,sequence[start] do
local cu=contexts[unic]
if not cu then
contexts[unic]=t
diff --git a/tex/generic/context/luatex/luatex-fonts-otn.lua b/tex/generic/context/luatex/luatex-fonts-otn.lua
index 0bf231fff..be2c48a09 100644
--- a/tex/generic/context/luatex/luatex-fonts-otn.lua
+++ b/tex/generic/context/luatex/luatex-fonts-otn.lua
@@ -12,6 +12,13 @@ if not modules then modules = { } end modules ['font-otn'] = {
-- this is a context version which can contain experimental code, but when we
-- have serious patches we also need to change the other two font-otn files
+-- at some point i might decide to convert the whole list into a table and then
+-- run over that instead (but it has some drawbacks as we also need to deal with
+-- attributes and such so we need to keep a lot of track - which is why i rejected
+-- that method - although it has become a bit easier in the meantime so it might
+-- become an alternative (by that time i probably have gone completely lua) .. the
+-- usual chicken-egg issues ... maybe mkix as it's no real tex any more then
+
-- preprocessors = { "nodes" }
-- anchor class : mark, mkmk, curs, mklg (todo)
@@ -40,7 +47,18 @@ if not modules then modules = { } end modules ['font-otn'] = {
-- mark (to mark) code is still not what it should be (too messy but we need some more extreem husayni tests)
-- remove some optimizations (when I have a faster machine)
--
--- maybe redo the lot some way (more context specific)
+-- beware:
+--
+-- we do some disc jugling where we need to keep in mind that the
+-- pre, post and replace fields can have prev pointers to a nesting
+-- node ... i wonder if that is still needed
+--
+-- not possible:
+--
+-- \discretionary {alpha-} {betagammadelta}
+-- {\discretionary {alphabeta-} {gammadelta}
+-- {\discretionary {alphabetagamma-} {delta}
+-- {alphabetagammadelta}}}
--[[ldx--
<p>This module is a bit more split up that I'd like but since we also want to test
@@ -123,7 +141,6 @@ results in different tables.</p>
-- chainmore : multiple substitutions triggered by contextual lookup (e.g. fij -> f + ij)
--
-- remark: the 'not implemented yet' variants will be done when we have fonts that use them
--- remark: we need to check what to do with discretionaries
-- We used to have independent hashes for lookups but as the tags are unique
-- we now use only one hash. If needed we can have multiple again but in that
@@ -131,16 +148,14 @@ results in different tables.</p>
-- Todo: make plugin feature that operates on char/glyphnode arrays
-local concat, insert, remove = table.concat, table.insert, table.remove
-local gmatch, gsub, find, match, lower, strip = string.gmatch, string.gsub, string.find, string.match, string.lower, string.strip
-local type, next, tonumber, tostring = type, next, tonumber, tostring
-local lpegmatch = lpeg.match
+local type, next, tonumber = type, next, tonumber
local random = math.random
local formatters = string.formatters
local logs, trackers, nodes, attributes = logs, trackers, nodes, attributes
-local registertracker = trackers.register
+local registertracker = trackers.register
+local registerdirective = directives.register
local fonts = fonts
local otf = fonts.handlers.otf
@@ -162,6 +177,18 @@ local trace_steps = false registertracker("otf.steps", function(v
local trace_skips = false registertracker("otf.skips", function(v) trace_skips = v end)
local trace_directions = false registertracker("otf.directions", function(v) trace_directions = v end)
+local trace_kernruns = false registertracker("otf.kernruns", function(v) trace_kernruns = v end)
+local trace_discruns = false registertracker("otf.discruns", function(v) trace_discruns = v end)
+local trace_compruns = false registertracker("otf.compruns", function(v) trace_compruns = v end)
+
+local quit_on_no_replacement = true -- maybe per font
+local check_discretionaries = true -- "trace"
+local zwnjruns = true
+
+registerdirective("otf.zwnjruns", function(v) zwnjruns = v end)
+registerdirective("otf.chain.quitonnoreplacement",function(value) quit_on_no_replacement = value end)
+
+
local report_direct = logs.reporter("fonts","otf direct")
local report_subchain = logs.reporter("fonts","otf subchain")
local report_chain = logs.reporter("fonts","otf chain")
@@ -376,8 +403,52 @@ local function copy_glyph(g) -- next and prev are untouched !
end
end
---
-
+-- temp here (context)
+
+local function collapse_disc(start,next)
+ local replace1 = getfield(start,"replace")
+ local replace2 = getfield(next,"replace")
+ if replace1 and replace2 then
+ local pre2 = getfield(next,"pre")
+ local post2 = getfield(next,"post")
+ setfield(replace1,"prev",nil)
+ if pre2 then
+ local pre1 = getfield(start,"pre")
+ if pre1 then
+ flush_node_list(pre1)
+ end
+ local pre1 = copy_node_list(replace1)
+ local tail1 = find_node_tail(pre1)
+ setfield(tail1,"next",pre2)
+ setfield(pre2,"prev",tail1)
+ setfield(start,"pre",pre1)
+ setfield(next,"pre",nil)
+ else
+ setfield(start,"pre",nil)
+ end
+ if post2 then
+ local post1 = getfield(start,"post")
+ if post1 then
+ flush_node_list(post1)
+ end
+ setfield(start,"post",post2)
+ else
+ setfield(start,"post",nil)
+ end
+ local tail1 = find_node_tail(replace1)
+ setfield(tail1,"next",replace2)
+ setfield(replace2,"prev",tail1)
+ setfield(start,"replace",replace1)
+ setfield(next,"replace",nil)
+ --
+ local nextnext = getnext(next)
+ setfield(nextnext,"prev",start)
+ setfield(start,"next",nextnext)
+ free_node(next)
+ else
+ -- maybe remove it
+ end
+end
-- start is a mark and we need to keep that one
@@ -434,16 +505,90 @@ local function getcomponentindex(start)
end
end
--- eventually we will do positioning in an other way (needs addional w/h/d fields)
+local a_noligature = attributes.private("noligature")
+local prehyphenchar = languages and languages.prehyphenchar
+local posthyphenchar = languages and languages.posthyphenchar
+----- preexhyphenchar = languages and languages.preexhyphenchar
+----- postexhyphenchar = languages and languages.postexhyphenchar
+
+if prehyphenchar then
+
+ -- okay
+
+elseif context then
+
+ report_warning("no language support") os.exit()
+
+else
+
+ local newlang = lang.new
+ local getpre = lang.prehyphenchar
+ local getpost = lang.posthyphenchar
+ -- local getpreex = lang.preexhyphenchar
+ -- local getpostex = lang.postexhyphenchar
+
+ prehyphenchar = function(l) local l = newlang(l) return l and getpre (l) or -1 end
+ posthyphenchar = function(l) local l = newlang(l) return l and getpost (l) or -1 end
+ -- preexhyphenchar = function(l) local l = newlang(l) return l and getpreex (l) or -1 end
+ -- postexhyphenchar = function(l) local l = newlang(l) return l and getpostex(l) or -1 end
+
+end
+
+local function addhyphens(template,pre,post)
+ -- inserted by hyphenation algorithm
+ local l = getfield(template,"lang")
+ local p = prehyphenchar(l)
+ if p and p > 0 then
+ local c = copy_node(template)
+ setfield(c,"char",p)
+ if pre then
+ local t = find_node_tail(pre)
+ setfield(t,"next",c)
+ setfield(c,"prev",t)
+ else
+ pre = c
+ end
+ end
+ local p = posthyphenchar(l)
+ if p and p > 0 then
+ local c = copy_node(template)
+ setfield(c,"char",p)
+ if post then
+ -- post has a prev nesting node .. alternatively we could
+ local prev = getprev(post)
+ setfield(c,"next",post)
+ setfield(post,"prev",c)
+ if prev then
+ setfield(prev,"next",c)
+ setfield(c,"prev",prev)
+ end
+ else
+ post = c
+ end
+ end
+ return pre, post
+end
local function toligature(kind,lookupname,head,start,stop,char,markflag,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
+ end
if start == stop and getchar(start) == char then
resetinjection(start)
setfield(start,"char",char)
return head, start
end
+ -- needs testing (side effects):
+ local components = getfield(start,"components")
+ if components then
+-- we get a double free .. needs checking
+-- flush_node_list(components)
+ end
+ --
local prev = getprev(start)
local next = getnext(stop)
+ local comp = start
setfield(start,"prev",nil)
setfield(stop,"next",nil)
local base = copy_glyph(start)
@@ -453,7 +598,7 @@ local function toligature(kind,lookupname,head,start,stop,char,markflag,discfoun
resetinjection(base)
setfield(base,"char",char)
setfield(base,"subtype",ligature_code)
- setfield(base,"components",start) -- start can have components
+ setfield(base,"components",comp) -- start can have components .. do we need to flush?
if prev then
setfield(prev,"next",base)
end
@@ -480,7 +625,9 @@ local function toligature(kind,lookupname,head,start,stop,char,markflag,discfoun
if trace_marks then
logwarning("%s: keep mark %s, gets index %s",pref(kind,lookupname),gref(char),getligaindex(start))
end
- head, current = insert_node_after(head,current,copy_node(start)) -- unlikely that mark has components
+ local n = copy_node(start)
+ copyinjection(n,start)
+ head, current = insert_node_after(head,current,n) -- unlikely that mark has components
elseif trace_marks then
logwarning("%s: delete mark %s",pref(kind,lookupname),gref(char))
end
@@ -501,6 +648,70 @@ local function toligature(kind,lookupname,head,start,stop,char,markflag,discfoun
end
start = getnext(start)
end
+ else
+ -- discfound ... forget about marks .. probably no scripts that hyphenate and have marks
+ local discprev = getfield(discfound,"prev")
+ local discnext = getfield(discfound,"next")
+ if discprev and discnext then
+ local subtype = getsubtype(discfound)
+ if subtype == discretionary_code then
+ local pre = getfield(discfound,"pre")
+ local post = getfield(discfound,"post")
+ local replace = getfield(discfound,"replace")
+ if not replace then -- todo: signal simple hyphen
+ local prev = getfield(base,"prev")
+ local copied = copy_node_list(comp)
+ setfield(discnext,"prev",nil) -- also blocks funny assignments
+ setfield(discprev,"next",nil) -- also blocks funny assignments
+ if pre then
+ setfield(discprev,"next",pre)
+ setfield(pre,"prev",discprev)
+ end
+ pre = comp
+ if post then
+ local tail = find_node_tail(post)
+ setfield(tail,"next",discnext)
+ setfield(discnext,"prev",tail)
+ setfield(post,"prev",nil)
+ else
+ post = discnext
+ end
+ setfield(prev,"next",discfound)
+ setfield(next,"prev",discfound)
+ setfield(discfound,"next",next)
+ setfield(discfound,"prev",prev)
+ setfield(base,"next",nil)
+ setfield(base,"prev",nil)
+ setfield(base,"components",copied)
+ setfield(discfound,"pre",pre)
+ setfield(discfound,"post",post)
+ setfield(discfound,"replace",base)
+ setfield(discfound,"subtype",discretionary_code)
+ base = prev -- restart
+ end
+ elseif subtype == regular_code then
+ -- local prev = getfield(base,"prev")
+ -- local next = getfield(base,"next")
+ local copied = copy_node_list(comp)
+ setfield(discnext,"prev",nil) -- also blocks funny assignments
+ setfield(discprev,"next",nil) -- also blocks funny assignments
+ local pre, post = addhyphens(comp,comp,discnext,subtype) -- takes from components
+ setfield(prev,"next",discfound)
+ setfield(next,"prev",discfound)
+ setfield(discfound,"next",next)
+ setfield(discfound,"prev",prev)
+ setfield(base,"next",nil)
+ setfield(base,"prev",nil)
+ setfield(base,"components",copied)
+ setfield(discfound,"pre",pre)
+ setfield(discfound,"post",post)
+ setfield(discfound,"replace",base)
+ setfield(discfound,"subtype",discretionary_code)
+ base = next -- or restart
+ else
+ -- forget about it in generic usage
+ end
+ end
end
return head, base
end
@@ -605,7 +816,7 @@ function handlers.gsub_multiple(head,start,kind,lookupname,multiple,sequence)
end
function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence)
- local s, stop, discfound = getnext(start), nil, false
+ local s, stop = getnext(start), nil
local startchar = getchar(start)
if marks[startchar] then
while s do
@@ -633,24 +844,30 @@ function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence)
else
head, start = markstoligature(kind,lookupname,head,start,stop,lig)
end
- return head, start, true
+ return head, start, true, false
else
-- ok, goto next lookup
end
end
else
- local skipmark = sequence.flags[1]
+ local skipmark = sequence.flags[1]
+ local discfound = false
+ local lastdisc = nil
while s do
local id = getid(s)
- if id == glyph_code and getsubtype(s)<256 then
- if getfont(s) == currentfont then
+ if id == glyph_code and getsubtype(s)<256 then -- not needed
+ if getfont(s) == currentfont then -- also not needed only when mark
local char = getchar(s)
if skipmark and marks[char] then
s = getnext(s)
- else
- local lg = ligature[char]
+ else -- ligature is a tree
+ local lg = ligature[char] -- can there be multiple in a row? maybe in a bad font
if lg then
- stop = s
+ if not discfound and lastdisc then
+ discfound = lastdisc
+ lastdisc = nil
+ end
+ stop = s -- needed for fake so outside then
ligature = lg
s = getnext(s)
else
@@ -661,13 +878,13 @@ function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence)
break
end
elseif id == disc_code then
- discfound = true
+ lastdisc = s
s = getnext(s)
else
break
end
end
- local lig = ligature.ligature
+ local lig = ligature.ligature -- can't we get rid of this .ligature?
if lig then
if stop then
if trace_ligatures then
@@ -685,14 +902,28 @@ function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence)
logprocess("%s: replacing %s by (no real) ligature %s case 3",pref(kind,lookupname),gref(startchar),gref(lig))
end
end
- return head, start, true
+ return head, start, true, discfound
else
- -- weird but happens
+ -- weird but happens, pseudo ligatures ... just the components
end
end
- return head, start, false
+ return head, start, false, discfound
end
+-- function is_gsub_ligature(start,ligature) -- limited case: in disc nodes, only latin, always glyphs
+-- local s = getnext(start)
+-- while s do
+-- local lg = ligature[getchar(s)]
+-- if lg then
+-- ligature = lg
+-- s = getnext(s)
+-- else
+-- return
+-- end
+-- end
+-- return ligature and ligature.ligature
+-- end
+
--[[ldx--
<p>We get hits on a mark, but we're not sure if the it has to be applied so
we need to explicitly test for basechar, baselig and basemark entries.</p>
@@ -855,7 +1086,7 @@ function handlers.gpos_mark2mark(head,start,kind,lookupname,markanchors,sequence
if al[anchor] then
local ma = markanchors[anchor]
if ma then
- local dx, dy, bound = setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma,characters[basechar])
+ local dx, dy, bound = setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma,characters[basechar],true)
if trace_marks then
logprocess("%s, anchor %s, bound %s: anchoring mark %s to basemark %s => (%p,%p)",
pref(kind,lookupname),anchor,bound,gref(markchar),gref(basechar),dx,dy)
@@ -938,16 +1169,16 @@ function handlers.gpos_cursive(head,start,kind,lookupname,exitanchors,sequence)
end
end
-function handlers.gpos_single(head,start,kind,lookupname,kerns,sequence)
+function handlers.gpos_single(head,start,kind,lookupname,kerns,sequence,injection)
local startchar = getchar(start)
- local dx, dy, w, h = setpair(start,tfmdata.parameters.factor,rlmode,sequence.flags[4],kerns,characters[startchar])
+ local dx, dy, w, h = setpair(start,tfmdata.parameters.factor,rlmode,sequence.flags[4],kerns,injection) -- ,characters[startchar])
if trace_kerns then
logprocess("%s: shifting single %s by (%p,%p) and correction (%p,%p)",pref(kind,lookupname),gref(startchar),dx,dy,w,h)
end
return head, start, false
end
-function handlers.gpos_pair(head,start,kind,lookupname,kerns,sequence)
+function handlers.gpos_pair(head,start,kind,lookupname,kerns,sequence,lookuphash,i,injection)
-- todo: kerns in disc nodes: pre, post, replace -> loop over disc too
-- todo: kerns in components of ligatures
local snext = getnext(start)
@@ -968,17 +1199,17 @@ function handlers.gpos_pair(head,start,kind,lookupname,kerns,sequence)
-- skip
elseif type(krn) == "table" then
if lookuptype == "pair" then -- probably not needed
- local a, b = krn[2], krn[3]
+ local a, b = krn[2], krn[3]
if a and #a > 0 then
local startchar = getchar(start)
- local x, y, w, h = setpair(start,factor,rlmode,sequence.flags[4],a,characters[startchar])
+ local x, y, w, h = setpair(start,factor,rlmode,sequence.flags[4],a,injection) -- characters[startchar])
if trace_kerns then
logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p)",pref(kind,lookupname),gref(startchar),gref(nextchar),x,y,w,h)
end
end
if b and #b > 0 then
local startchar = getchar(start)
- local x, y, w, h = setpair(snext,factor,rlmode,sequence.flags[4],b,characters[nextchar])
+ local x, y, w, h = setpair(snext,factor,rlmode,sequence.flags[4],b,injection) -- characters[nextchar])
if trace_kerns then
logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p)",pref(kind,lookupname),gref(startchar),gref(nextchar),x,y,w,h)
end
@@ -998,7 +1229,7 @@ function handlers.gpos_pair(head,start,kind,lookupname,kerns,sequence)
end
done = true
elseif krn ~= 0 then
- local k = setkern(snext,factor,rlmode,krn)
+ local k = setkern(snext,factor,rlmode,krn,injection)
if trace_kerns then
logprocess("%s: inserting kern %s between %s and %s",pref(kind,lookupname),k,gref(getchar(prev)),gref(nextchar))
end
@@ -1116,8 +1347,7 @@ as less as needed but that would also make the code even more messy.</p>
-- end
--[[ldx--
-<p>Here we replace start by a single variant, First we delete the rest of the
-match.</p>
+<p>Here we replace start by a single variant.</p>
--ldx]]--
function chainprocs.gsub_single(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex)
@@ -1125,7 +1355,7 @@ function chainprocs.gsub_single(head,start,stop,kind,chainname,currentcontext,lo
local current = start
local subtables = currentlookup.subtables
if #subtables > 1 then
- logwarning("todo: check if we need to loop over the replacements: %s",concat(subtables," "))
+ logwarning("todo: check if we need to loop over the replacements: % t",subtables)
end
while current do
if getid(current) == glyph_code then
@@ -1147,7 +1377,83 @@ function chainprocs.gsub_single(head,start,stop,kind,chainname,currentcontext,lo
logprocess("%s: replacing single %s by %s",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(currentchar),gref(replacement))
end
resetinjection(current)
- setfield(current,"char",replacement)
+ if check_discretionaries then
+ -- some fonts use a chain lookup to replace e.g. an f in a fi ligature
+ -- and there can be a disc node in between ... the next code tries to catch
+ -- this
+ local next = getnext(current)
+ local prev = getprev(current) -- todo: just remember it above
+ local done = false
+ if next then
+ if getid(next) == disc_code then
+ local subtype = getsubtype(next)
+ if subtype == discretionary_code then
+ setfield(next,"prev",prev)
+ setfield(prev,"next",next)
+ setfield(current,"prev",nil)
+ setfield(current,"next",nil)
+ local replace = getfield(next,"replace")
+ local pre = getfield(next,"pre")
+ local new = copy_node(current)
+ setfield(new,"char",replacement)
+ if replace then
+ setfield(new,"next",replace)
+ setfield(replace,"prev",new)
+ end
+ if pre then
+ setfield(current,"next",pre)
+ setfield(pre,"prev",current)
+ end
+ setfield(next,"replace",new) -- also updates tail
+ setfield(next,"pre",current) -- also updates tail
+ end
+ start = next
+ done = true
+ local next = getnext(start)
+ if next and getid(next) == disc_code then
+ collapse_disc(start,next)
+ end
+ end
+ end
+ if not done and prev then
+ if getid(prev) == disc_code then
+ local subtype = getsubtype(prev)
+ if subtype == discretionary_code then
+ setfield(next,"prev",prev)
+ setfield(prev,"next",next)
+ setfield(current,"prev",nil)
+ setfield(current,"next",nil)
+ local replace = getfield(prev,"replace")
+ local post = getfield(prev,"post")
+ local new = copy_node(current)
+ setfield(new,"char",replacement)
+ if replace then
+ local tail = find_node_tail(replace)
+ setfield(tail,"next",new)
+ setfield(new,"prev",tail)
+ else
+ replace = new
+ end
+ if post then
+ local tail = find_node_tail(post)
+ setfield(tail,"next",current)
+ setfield(current,"prev",tail)
+ else
+ post = current
+ end
+ setfield(prev,"replace",replace) -- also updates tail
+ setfield(prev,"post",post) -- also updates tail
+ start = prev
+ done = true
+ end
+ end
+ end
+ if not done then
+ setfield(current,"char",replacement)
+ end
+ else
+ setfield(current,"char",replacement)
+ end
end
end
return head, start, true
@@ -1163,8 +1469,7 @@ end
chainmores.gsub_single = chainprocs.gsub_single
--[[ldx--
-<p>Here we replace start by a sequence of new glyphs. First we delete the rest of
-the match.</p>
+<p>Here we replace start by a sequence of new glyphs.</p>
--ldx]]--
function chainprocs.gsub_multiple(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname)
@@ -1281,12 +1586,22 @@ function chainprocs.gsub_ligature(head,start,stop,kind,chainname,currentcontext,
while s do
local id = getid(s)
if id == disc_code then
- s = getnext(s)
- discfound = true
+ if not discfound then
+ discfound = s
+ end
+ if s == stop then
+ break -- okay? or before the disc
+ else
+ s = getnext(s)
+ end
else
local schar = getchar(s)
if skipmark and marks[schar] then -- marks
+-- if s == stop then -- maybe add this
+-- break
+-- else
s = getnext(s)
+-- end
else
local lg = ligatures[schar]
if lg then
@@ -1315,7 +1630,7 @@ function chainprocs.gsub_ligature(head,start,stop,kind,chainname,currentcontext,
end
end
head, start = toligature(kind,lookupname,head,start,stop,l2,currentlookup.flags[1],discfound)
- return head, start, true, nofreplacements
+ return head, start, true, nofreplacements, discfound
elseif trace_bugs then
if start == stop then
logwarning("%s: replacing character %s by ligature fails",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar))
@@ -1325,7 +1640,7 @@ function chainprocs.gsub_ligature(head,start,stop,kind,chainname,currentcontext,
end
end
end
- return head, start, false, 0
+ return head, start, false, 0, false
end
chainmores.gsub_ligature = chainprocs.gsub_ligature
@@ -1497,7 +1812,7 @@ function chainprocs.gpos_mark2mark(head,start,stop,kind,chainname,currentcontext
if al[anchor] then
local ma = markanchors[anchor]
if ma then
- local dx, dy, bound = setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma,characters[basechar])
+ local dx, dy, bound = setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma,characters[basechar],true)
if trace_marks then
logprocess("%s, anchor %s, bound %s: anchoring mark %s to basemark %s => (%p,%p)",
cref(kind,chainname,chainlookupname,lookupname),anchor,bound,gref(markchar),gref(basechar),dx,dy)
@@ -1597,7 +1912,7 @@ function chainprocs.gpos_single(head,start,stop,kind,chainname,currentcontext,lo
if kerns then
kerns = kerns[startchar] -- needed ?
if kerns then
- local dx, dy, w, h = setpair(start,tfmdata.parameters.factor,rlmode,sequence.flags[4],kerns,characters[startchar])
+ local dx, dy, w, h = setpair(start,tfmdata.parameters.factor,rlmode,sequence.flags[4],kerns) -- ,characters[startchar])
if trace_kerns then
logprocess("%s: shifting single %s by (%p,%p) and correction (%p,%p)",cref(kind,chainname,chainlookupname),gref(startchar),dx,dy,w,h)
end
@@ -1637,30 +1952,30 @@ function chainprocs.gpos_pair(head,start,stop,kind,chainname,currentcontext,look
local a, b = krn[2], krn[3]
if a and #a > 0 then
local startchar = getchar(start)
- local x, y, w, h = setpair(start,factor,rlmode,sequence.flags[4],a,characters[startchar])
+ local x, y, w, h = setpair(start,factor,rlmode,sequence.flags[4],a) -- ,characters[startchar])
if trace_kerns then
logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(kind,chainname,chainlookupname),gref(startchar),gref(nextchar),x,y,w,h)
end
end
if b and #b > 0 then
local startchar = getchar(start)
- local x, y, w, h = setpair(snext,factor,rlmode,sequence.flags[4],b,characters[nextchar])
+ local x, y, w, h = setpair(snext,factor,rlmode,sequence.flags[4],b) -- ,characters[nextchar])
if trace_kerns then
logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(kind,chainname,chainlookupname),gref(startchar),gref(nextchar),x,y,w,h)
end
end
else
report_process("%s: check this out (old kern stuff)",cref(kind,chainname,chainlookupname))
- local a, b = krn[2], krn[6]
- if a and a ~= 0 then
- local k = setkern(snext,factor,rlmode,a)
- if trace_kerns then
- logprocess("%s: inserting first kern %s between %s and %s",cref(kind,chainname,chainlookupname),k,gref(getchar(prev)),gref(nextchar))
- end
- end
- if b and b ~= 0 then
- logwarning("%s: ignoring second kern xoff %s",cref(kind,chainname,chainlookupname),b*factor)
- end
+ -- local a, b = krn[2], krn[6]
+ -- if a and a ~= 0 then
+ -- local k = setkern(snext,factor,rlmode,a)
+ -- if trace_kerns then
+ -- logprocess("%s: inserting first kern %s between %s and %s",cref(kind,chainname,chainlookupname),k,gref(getchar(prev)),gref(nextchar))
+ -- end
+ -- end
+ -- if b and b ~= 0 then
+ -- logwarning("%s: ignoring second kern xoff %s",cref(kind,chainname,chainlookupname),b*factor)
+ -- end
end
done = true
elseif krn ~= 0 then
@@ -1698,11 +2013,7 @@ local function show_skip(kind,chainname,char,ck,class)
end
end
-local quit_on_no_replacement = true
-
-directives.register("otf.chain.quitonnoreplacement",function(value) -- maybe per font
- quit_on_no_replacement = value
-end)
+--hm, do i need to deal with disc here ?
local function normal_handle_contextchain(head,start,kind,chainname,contexts,sequence,lookuphash)
-- local rule, lookuptype, sequence, f, l, lookups = ck[1], ck[2] ,ck[3], ck[4], ck[5], ck[6]
@@ -1773,7 +2084,36 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
break
end
elseif id == disc_code then
- last = getnext(last)
+ if check_discretionaries then
+ local replace = getfield(last,"replace")
+ if replace then
+ -- so far we never entered this branch
+ while replace do
+ if seq[n][getchar(replace)] then
+ n = n + 1
+ replace = getnext(replace)
+ if not replace then
+ break
+ elseif n > l then
+ -- match = false
+ break
+ end
+ else
+ match = false
+ break
+ end
+ end
+ if not match then
+ break
+ elseif check_discretionaries == "trace" then
+ report_chain("check disc action in current")
+ end
+ else
+ last = getnext(last) -- no skipping here
+ end
+ else
+ last = getnext(last) -- no skipping here
+ end
else
match = false
break
@@ -1819,7 +2159,39 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
break
end
elseif id == disc_code then
- -- skip 'm
+ -- the special case: f i where i becomes dottless i ..
+ if check_discretionaries then
+ local replace = getfield(prev,"replace")
+ if replace then
+ -- we seldom enter this branch (e.g. on brill efficient)
+ replace = find_node_tail(replace)
+ local finish = getprev(replace)
+ while replace do
+ if seq[n][getchar(replace)] then
+ n = n - 1
+ replace = getprev(replace)
+ if not replace or replace == finish then
+ break
+ elseif n < 1 then
+ -- match = false
+ break
+ end
+ else
+ match = false
+ break
+ end
+ end
+ if not match then
+ break
+ elseif check_discretionaries == "trace" then
+ report_chain("check disc action in before")
+ end
+ else
+ -- skip 'm
+ end
+ else
+ -- skip 'm
+ end
elseif seq[n][32] then
n = n -1
else
@@ -1828,7 +2200,7 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
end
prev = getprev(prev)
elseif seq[n][32] then -- somewhat special, as zapfino can have many preceding spaces
- n = n -1
+ n = n - 1
else
match = false
break
@@ -1873,7 +2245,35 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
break
end
elseif id == disc_code then
- -- skip 'm
+ if check_discretionaries then
+ local replace = getfield(current,"replace")
+ if replace then
+ -- so far we never entered this branch
+ while replace do
+ if seq[n][getchar(replace)] then
+ n = n + 1
+ replace = getnext(replace)
+ if not replace then
+ break
+ elseif n > s then
+ break
+ end
+ else
+ match = false
+ break
+ end
+ end
+ if not match then
+ break
+ elseif check_discretionaries == "trace" then
+ report_chain("check disc action in after")
+ end
+ else
+ -- skip 'm
+ end
+ else
+ -- skip 'm
+ end
elseif seq[n][32] then -- brrr
n = n + 1
else
@@ -1966,7 +2366,10 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
done = true
if n and n > 1 then
-- we have a ligature (cf the spec we advance one but we really need to test it
- -- as there are fonts out there that are fuzzy and have too many lookups
+ -- as there are fonts out there that are fuzzy and have too many lookups:
+ --
+ -- U+1105 U+119E U+1105 U+119E : sourcehansansklight: script=hang ccmp=yes
+ --
if i + n > nofchainlookups then
-- if trace_contexts then
-- logprocess("%s: quitting lookups",cref(kind,chainname))
@@ -2090,7 +2493,7 @@ local function initialize(sequence,script,language,enabled)
local scripts = features[kind] --
local languages = scripts[script] or scripts[wildcard]
if languages and (languages[language] or languages[wildcard]) then
- return { valid, autofeatures[kind] or false, sequence.chain or 0, kind, sequence }
+ return { valid, autofeatures[kind] or false, sequence, kind }
end
end
end
@@ -2161,6 +2564,199 @@ end
-- -- the action
-- end
+-- assumptions:
+--
+-- * languages that use complex disc nodes
+
+local function kernrun(disc,run) -- we can assume that prev and next are glyphs
+ --
+ -- we catch <font 1><disc font 2>
+ --
+ if trace_kernruns then
+ report_run("kern") -- will be more detailed
+ end
+ --
+ local prev = getprev(disc) -- todo, keep these in the main loop
+ local next = getnext(disc) -- todo, keep these in the main loop
+ --
+ local pre = getfield(disc,"pre")
+ local post = getfield(disc,"post")
+ local replace = getfield(disc,"replace")
+ --
+ if pre or replace then
+ if not (prev and getid(prev) == glyph_code and getfont(prev) == currentfont and getsubtype(prev)<256) then
+ prev = false
+ end
+ end
+ if post or replace then
+ if not (next and getid(next) == glyph_code and getfont(next) == currentfont and getsubtype(next)<256) then
+ next = false
+ end
+ end
+ --
+ if not pre then
+ -- go on
+ elseif prev then
+ local nest = getprev(pre)
+ setfield(pre,"prev",prev)
+ setfield(prev,"next",pre)
+ run(prev,"preinjections")
+ setfield(pre,"prev",nest)
+ setfield(prev,"next",disc)
+ else
+ run(pre,"preinjections")
+ end
+ --
+ if not post then
+ -- go on
+ elseif next then
+ local tail = find_node_tail(post)
+ setfield(tail,"next",next)
+ setfield(next,"prev",tail)
+ run(post,"postinjections",tail)
+ setfield(tail,"next",nil)
+ setfield(next,"prev",disc)
+ else
+ run(post,"postinjections")
+ end
+ --
+ if not replace and prev and next then
+ -- this should be already done by discfound
+ elseif prev and next then
+ local tail = find_node_tail(replace)
+ local nest = getprev(replace)
+ setfield(replace,"prev",prev)
+ setfield(prev,"next",replace)
+ setfield(tail,"next",next)
+ setfield(next,"prev",tail)
+ run(prev,"replaceinjections",tail)
+ setfield(replace,"prev",nest)
+ setfield(prev,"next",disc)
+ setfield(tail,"next",nil)
+ setfield(next,"prev",disc)
+ elseif prev then
+ local nest = getprev(replace)
+ setfield(replace,"prev",prev)
+ setfield(prev,"next",replace)
+ run(prev,"replaceinjections")
+ setfield(replace,"prev",nest)
+ setfield(prev,"next",disc)
+ elseif next then
+ local tail = find_node_tail(replace)
+ setfield(tail,"next",next)
+ setfield(next,"prev",tail)
+ run(replace,"replaceinjections",tail)
+ setfield(tail,"next",nil)
+ setfield(next,"prev",disc)
+ else
+ run(replace,"replaceinjections")
+ end
+end
+
+-- the if new test might be dangerous as luatex will check / set some tail stuff
+-- in a temp node
+
+local function comprun(disc,run)
+ if trace_compruns then
+ report_run("comp: %s",languages.serializediscretionary(disc))
+ end
+ --
+ local pre = getfield(disc,"pre")
+ if pre then
+ local new, done = run(pre)
+ if done then
+ setfield(disc,"pre",new)
+ end
+ end
+ --
+ local post = getfield(disc,"post")
+ if post then
+ local new, done = run(post)
+ if done then
+ setfield(disc,"post",new)
+ end
+ end
+ --
+ local replace = getfield(disc,"replace")
+ if replace then
+ local new, done = run(replace)
+ if done then
+ setfield(disc,"replace",new)
+ end
+ end
+end
+
+local function testrun(disc,trun,crun)
+ local next = getnext(disc)
+ if next then
+ local replace = getfield(disc,"replace")
+ if replace then
+ local prev = getprev(disc)
+ if prev then
+ -- only look ahead
+ local tail = find_node_tail(replace)
+ -- local nest = getprev(replace)
+ setfield(tail,"next",next)
+ setfield(next,"prev",tail)
+ if trun(replace,next) then
+ setfield(disc,"replace",nil) -- beware, side effects of nest so first
+ setfield(prev,"next",replace)
+ setfield(replace,"prev",prev)
+ setfield(next,"prev",tail)
+ setfield(tail,"next",next)
+ setfield(disc,"prev",nil)
+ setfield(disc,"next",nil)
+ flush_node_list(disc)
+ return replace -- restart
+ else
+ setfield(tail,"next",nil)
+ setfield(next,"prev",disc)
+ end
+ else
+ -- weird case
+ end
+ else
+ -- no need
+ end
+ else
+ -- weird case
+ end
+ comprun(disc,crun)
+ return next
+end
+
+local function discrun(disc,drun,krun)
+ local next = getnext(disc)
+ local prev = getprev(disc)
+ if trace_discruns then
+ report_run("disc") -- will be more detailed
+ end
+ if next and prev then
+ setfield(prev,"next",next)
+ -- setfield(next,"prev",prev)
+ drun(prev)
+ setfield(prev,"next",disc)
+ -- setfield(next,"prev",disc)
+ end
+ --
+ local pre = getfield(disc,"pre")
+ if not pre then
+ -- go on
+ elseif prev then
+ local nest = getprev(pre)
+ setfield(pre,"prev",prev)
+ setfield(prev,"next",pre)
+ krun(prev,"preinjections")
+ setfield(pre,"prev",nest)
+ setfield(prev,"next",disc)
+ else
+ krun(pre,"preinjections")
+ end
+ return next
+end
+
+-- todo: maybe run lr and rl stretches
+
local function featuresprocessor(head,font,attr)
local lookuphash = lookuphashes[font] -- we can also check sequences here
@@ -2205,21 +2801,28 @@ local function featuresprocessor(head,font,attr)
-- todo: retain prev
+ -- We don't goto the next node of 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.
+
+ -- there can be less subtype and attr checking in the comprun etc helpers
+
for s=1,#datasets do
- local dataset = datasets[s]
- featurevalue = dataset[1] -- todo: pass to function instead of using a global
-
- local sequence = dataset[5] -- sequences[s] -- also dataset[5]
- local rlparmode = 0
- local topstack = 0
- local success = false
- local attribute = dataset[2]
- local chain = dataset[3] -- sequence.chain or 0
- local typ = sequence.type
- local subtables = sequence.subtables
- if chain < 0 then
+ local dataset = datasets[s]
+ featurevalue = dataset[1] -- todo: pass to function instead of using a global
+ local attribute = dataset[2]
+ local sequence = dataset[3] -- sequences[s] -- also dataset[5]
+ local kind = dataset[4]
+ ----- chain = dataset[5] -- sequence.chain or 0
+ local rlparmode = 0
+ local topstack = 0
+ local success = false
+ local typ = sequence.type
+ local gpossing = typ == "gpos_single" or typ == "gpos_pair"
+ local subtables = sequence.subtables
+ local handler = handlers[typ]
+
+ if typ == "gsub_reversecontextchain" then -- chain < 0
-- this is a limited case, no special treatments like 'init' etc
- local handler = handlers[typ]
-- we need to get rid of this slide! probably no longer needed in latest luatex
local start = find_node_tail(head) -- slow (we can store tail because there's always a skip at the end): todo
while start do
@@ -2233,13 +2836,16 @@ local function featuresprocessor(head,font,attr)
a = true
end
if a then
+ local char = getchar(start)
for i=1,#subtables do
local lookupname = subtables[i]
local lookupcache = lookuphash[lookupname]
if lookupcache then
- local lookupmatch = lookupcache[getchar(start)]
+ -- local lookupmatch = lookupcache[getchar(start)]
+ local lookupmatch = lookupcache[start]
if lookupmatch then
- head, start, success = handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i)
+ -- todo: disc?
+ head, start, success = handler(head,start,kind,lookupname,lookupmatch,sequence,lookuphash,i)
if success then
break
end
@@ -2260,7 +2866,6 @@ local function featuresprocessor(head,font,attr)
end
end
else
- local handler = handlers[typ]
local ns = #subtables
local start = head -- local ?
rlmode = 0 -- to be checked ?
@@ -2271,13 +2876,15 @@ local function featuresprocessor(head,font,attr)
report_missing_cache(typ,lookupname)
else
- local function subrun(start)
- -- mostly for gsub, gpos would demand a more clever approach
+ local function c_run(start) -- no need to check for 256 and attr probably also the same
local head = start
local done = false
while start do
local id = getid(start)
- if id == glyph_code and getfont(start) == font and getsubtype(start) < 256 then
+ if id ~= glyph_code then
+ -- very unlikely
+ start = getnext(start)
+ elseif getfont(start) == font and getsubtype(start) < 256 then
local a = getattr(start,0)
if a then
a = (a == attr) and (not attribute or getprop(start,a_state) == attribute)
@@ -2289,7 +2896,7 @@ local function featuresprocessor(head,font,attr)
if lookupmatch then
-- sequence kan weg
local ok
- head, start, ok = handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,1)
+ head, start, ok = handler(head,start,kind,lookupname,lookupmatch,sequence,lookuphash,1)
if ok then
done = true
end
@@ -2299,48 +2906,106 @@ local function featuresprocessor(head,font,attr)
start = getnext(start)
end
else
- start = getnext(start)
+ return head, false
end
end
if done then
- success = true
- return head
+ success = true -- needed in this subrun?
end
+ return head, done
end
- local function kerndisc(disc) -- we can assume that prev and next are glyphs
- local prev = getprev(disc)
- local next = getnext(disc)
- if prev and next then
- setfield(prev,"next",next)
- -- setfield(next,"prev",prev)
- local a = getattr(prev,0)
- if a then
- a = (a == attr) and (not attribute or getprop(prev,a_state) == attribute)
+ local function t_run(start,stop)
+ while start ~= stop do
+ local id = getid(start)
+ if id == glyph_code and getfont(start) == font and getsubtype(start) < 256 then
+ local a = 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
+ if a then
+ local lookupmatch = lookupcache[getchar(start)]
+ if lookupmatch then -- hm, hyphens can match (tlig) so we need to really check
+ -- if we need more than ligatures we can outline the code and use functions
+ local s = getnext(start)
+ local l = nil
+ while s do
+ local lg = lookupmatch[getchar(s)]
+ if lg then
+ l = lg
+ s = getnext(s)
+ else
+ break
+ end
+ end
+ if l and l.ligature then
+ return true
+ end
+ end
+ end
+ start = getnext(start)
else
- a = not attribute or getprop(prev,a_state) == attribute
+ break
end
- if a then
- local lookupmatch = lookupcache[getchar(prev)]
- if lookupmatch then
- -- sequence kan weg
- local h, d, ok = handler(head,prev,dataset[4],lookupname,lookupmatch,sequence,lookuphash,1)
- if ok then
- done = true
- success = true
+ end
+ end
+
+ local function d_run(prev) -- we can assume that prev and next are glyphs
+ local a = getattr(prev,0)
+ if a then
+ a = (a == attr) and (not attribute or getprop(prev,a_state) == attribute)
+ else
+ a = not attribute or getprop(prev,a_state) == attribute
+ end
+ if a then
+ local lookupmatch = lookupcache[getchar(prev)]
+ if lookupmatch then
+ -- sequence kan weg
+ local h, d, ok = handler(head,prev,kind,lookupname,lookupmatch,sequence,lookuphash,1)
+ if ok then
+ done = true
+ success = true
+ end
+ end
+ end
+ end
+
+ local function k_run(sub,injection,last)
+ local a = getattr(sub,0)
+ if a then
+ a = (a == attr) and (not attribute or getprop(sub,a_state) == attribute)
+ else
+ a = not attribute or getprop(sub,a_state) == attribute
+ end
+ if a then
+ -- sequence kan weg
+ for n in traverse_nodes(sub) do -- only gpos
+ if n == last then
+ break
+ end
+ local id = getid(n)
+ if id == glyph_code then
+ local lookupmatch = lookupcache[getchar(n)]
+ if lookupmatch then
+ local h, d, ok = handler(sub,n,kind,lookupname,lookupmatch,sequence,lookuphash,1,injection)
+ if ok then
+ done = true
+ success = true
+ end
end
+ else
+ -- message
end
end
- setfield(prev,"next",disc)
- -- setfield(next,"prev",disc)
end
- return next
end
while start do
local id = getid(start)
if id == glyph_code then
- if getfont(start) == font and getsubtype(start) < 256 then
+ if getfont(start) == font and getsubtype(start) < 256 then -- why a 256 test ...
local a = getattr(start,0)
if a then
a = (a == attr) and (not attribute or getprop(start,a_state) == attribute)
@@ -2348,44 +3013,46 @@ local function featuresprocessor(head,font,attr)
a = not attribute or getprop(start,a_state) == attribute
end
if a then
- local lookupmatch = lookupcache[getchar(start)]
+ local char = getchar(start)
+ local lookupmatch = lookupcache[char]
if lookupmatch then
-- sequence kan weg
local ok
- head, start, ok = handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,1)
+ head, start, ok = handler(head,start,kind,lookupname,lookupmatch,sequence,lookuphash,1)
if ok then
success = true
+ elseif gpossing and zwnjruns and char == zwnj then
+ discrun(start,d_run)
end
+ elseif gpossing and zwnjruns and char == zwnj then
+ discrun(start,d_run)
end
if start then start = getnext(start) end
else
- start = getnext(start)
+ start = getnext(start)
end
else
start = getnext(start)
end
elseif id == disc_code then
- -- mostly for gsub
- if getsubtype(start) == discretionary_code then
- local pre = getfield(start,"pre")
- if pre then
- local new = subrun(pre)
- if new then setfield(start,"pre",new) end
- end
- local post = getfield(start,"post")
- if post then
- local new = subrun(post)
- if new then setfield(start,"post",new) end
- end
- local replace = getfield(start,"replace")
- if replace then
- local new = subrun(replace)
- if new then setfield(start,"replace",new) end
- end
-elseif typ == "gpos_single" or typ == "gpos_pair" then
- kerndisc(start)
- end
- start = getnext(start)
+ local discretionary = getsubtype(start) == discretionary_code
+ if gpossing then
+ if discretionary then
+ kernrun(start,k_run)
+ else
+ discrun(start,d_run,k_run)
+ end
+ start = getnext(start)
+ elseif discretionary then
+ if typ == "gsub_ligature" then
+ start = testrun(start,t_run,c_run)
+ else
+ comprun(start,c_run)
+ start = getnext(start)
+ end
+ else
+ start = getnext(start)
+ end
elseif id == whatsit_code then -- will be function
local subtype = getsubtype(start)
if subtype == dir_code then
@@ -2430,15 +3097,18 @@ elseif typ == "gpos_single" or typ == "gpos_pair" then
end
end
end
+
else
- local function subrun(start)
- -- mostly for gsub, gpos would demand a more clever approach
+ local function c_run(start)
local head = start
local done = false
while start do
local id = getid(start)
- if id == glyph_code and getfont(start) == font and getsubtype(start) < 256 then
+ if id ~= glyph_code then
+ -- very unlikely
+ start = getnext(start)
+ elseif getfont(start) == font and getsubtype(start) < 256 then
local a = getattr(start,0)
if a then
a = (a == attr) and (not attribute or getprop(start,a_state) == attribute)
@@ -2446,15 +3116,17 @@ elseif typ == "gpos_single" or typ == "gpos_pair" then
a = not attribute or getprop(start,a_state) == attribute
end
if a then
+ local char = getchar(start)
for i=1,ns do
local lookupname = subtables[i]
local lookupcache = lookuphash[lookupname]
if lookupcache then
- local lookupmatch = lookupcache[getchar(start)]
+ -- local lookupmatch = lookupcache[getchar(start)]
+ 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[4],lookupname,lookupmatch,sequence,lookuphash,i)
+ head, start, ok = handler(head,start,kind,lookupname,lookupmatch,sequence,lookuphash,i)
if ok then
done = true
break
@@ -2472,50 +3144,127 @@ elseif typ == "gpos_single" or typ == "gpos_pair" then
start = getnext(start)
end
else
- start = getnext(start)
+ return head, false
end
end
if done then
success = true
- return head
end
+ return head, done
end
- local function kerndisc(disc) -- we can assume that prev and next are glyphs
- local prev = getprev(disc)
- local next = getnext(disc)
- if prev and next then
- setfield(prev,"next",next)
- -- setfield(next,"prev",prev)
- local a = getattr(prev,0)
- if a then
- a = (a == attr) and (not attribute or getprop(prev,a_state) == attribute)
- else
- a = not attribute or getprop(prev,a_state) == attribute
+ local function d_run(prev)
+ local a = getattr(prev,0)
+ if a then
+ a = (a == attr) and (not attribute or getprop(prev,a_state) == attribute)
+ else
+ a = not attribute or getprop(prev,a_state) == attribute
+ end
+ if a then
+ -- brr prev can be disc
+ local char = getchar(prev)
+ for i=1,ns do
+ local lookupname = subtables[i]
+ local lookupcache = lookuphash[lookupname]
+ if lookupcache then
+ local lookupmatch = lookupcache[char]
+ if lookupmatch then
+ -- we could move all code inline but that makes things even more unreadable
+ local h, d, ok = handler(head,prev,kind,lookupname,lookupmatch,sequence,lookuphash,i)
+ if ok then
+ done = true
+ break
+ end
+ end
+ else
+ report_missing_cache(typ,lookupname)
+ end
end
- if a then
- for i=1,ns do
- local lookupname = subtables[i]
- local lookupcache = lookuphash[lookupname]
- if lookupcache then
- local lookupmatch = lookupcache[getchar(prev)]
- if lookupmatch then
- -- we could move all code inline but that makes things even more unreadable
- local h, d, ok = handler(head,prev,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i)
- if ok then
- done = true
- break
+ end
+ end
+
+ local function k_run(sub,injection,last)
+ local a = getattr(sub,0)
+ if a then
+ a = (a == attr) and (not attribute or getprop(sub,a_state) == attribute)
+ else
+ a = not attribute or getprop(sub,a_state) == attribute
+ end
+ if a then
+ for n in traverse_nodes(sub) do -- only gpos
+ if n == last then
+ break
+ end
+ local id = getid(n)
+ if id == glyph_code then
+ local char = getchar(n)
+ for i=1,ns do
+ local lookupname = subtables[i]
+ local lookupcache = lookuphash[lookupname]
+ if lookupcache then
+ local lookupmatch = lookupcache[char]
+ if lookupmatch then
+ local h, d, ok = handler(head,n,kind,lookupname,lookupmatch,sequence,lookuphash,i,injection)
+ if ok then
+ done = true
+ break
+ end
end
+ else
+ report_missing_cache(typ,lookupname)
end
- else
- report_missing_cache(typ,lookupname)
end
+ else
+ -- message
end
end
- setfield(prev,"next",disc)
- -- setfield(next,"prev",disc)
end
- return next
+ end
+
+ local function t_run(start,stop)
+ while start ~= stop do
+ local id = getid(start)
+ if id == glyph_code and getfont(start) == font and getsubtype(start) < 256 then
+ local a = 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
+ if a then
+ local char = getchar(start)
+ for i=1,ns do
+ local lookupname = subtables[i]
+ local lookupcache = lookuphash[lookupname]
+ 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 = getnext(start)
+ local l = nil
+ while s do
+ local lg = lookupmatch[getchar(s)]
+ if lg then
+ l = lg
+ s = getnext(s)
+ else
+ break
+ end
+ end
+ if l and l.ligature then
+ return true
+ end
+ end
+ else
+ report_missing_cache(typ,lookupname)
+ end
+ end
+ end
+ start = getnext(start)
+ else
+ break
+ end
+ end
end
while start do
@@ -2533,18 +3282,23 @@ elseif typ == "gpos_single" or typ == "gpos_pair" then
local lookupname = subtables[i]
local lookupcache = lookuphash[lookupname]
if lookupcache then
- local lookupmatch = lookupcache[getchar(start)]
+ local char = getchar(start)
+ 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[4],lookupname,lookupmatch,sequence,lookuphash,i)
+ head, start, ok = handler(head,start,kind,lookupname,lookupmatch,sequence,lookuphash,i)
if ok then
success = true
break
elseif not start then
-- don't ask why ... shouldn't happen
break
+ elseif gpossing and zwnjruns and char == zwnj then
+ discrun(start,d_run)
end
+ elseif gpossing and zwnjruns and char == zwnj then
+ discrun(start,d_run)
end
else
report_missing_cache(typ,lookupname)
@@ -2558,27 +3312,24 @@ elseif typ == "gpos_single" or typ == "gpos_pair" then
start = getnext(start)
end
elseif id == disc_code then
- -- mostly for gsub
- if getsubtype(start) == discretionary_code then
- local pre = getfield(start,"pre")
- if pre then
- local new = subrun(pre)
- if new then setfield(start,"pre",new) end
- end
- local post = getfield(start,"post")
- if post then
- local new = subrun(post)
- if new then setfield(start,"post",new) end
+ local discretionary = getsubtype(start) == discretionary_code
+ if gpossing then
+ if discretionary then
+ kernrun(start,k_run)
+ else
+ discrun(start,d_run,k_run)
end
- local replace = getfield(start,"replace")
- if replace then
- local new = subrun(replace)
- if new then setfield(start,"replace",new) end
+ start = getnext(start)
+ elseif discretionary then
+ if typ == "gsub_ligature" then
+ start = testrun(start,t_run,c_run)
+ else
+ comprun(start,c_run)
+ start = getnext(start)
end
-elseif typ == "gpos_single" or typ == "gpos_pair" then
- kerndisc(start)
+ else
+ start = getnext(start)
end
- start = getnext(start)
elseif id == whatsit_code then
local subtype = getsubtype(start)
if subtype == dir_code then
@@ -2637,6 +3388,8 @@ elseif typ == "gpos_single" or typ == "gpos_pair" then
return head, done
end
+-- this might move to the loader
+
local function generic(lookupdata,lookupname,unicode,lookuphash)
local target = lookuphash[lookupname]
if target then
@@ -2646,47 +3399,48 @@ local function generic(lookupdata,lookupname,unicode,lookuphash)
end
end
-local action = {
+local function ligature(lookupdata,lookupname,unicode,lookuphash)
+ local target = lookuphash[lookupname]
+ if not target then
+ target = { }
+ lookuphash[lookupname] = target
+ end
+ for i=1,#lookupdata do
+ local li = lookupdata[i]
+ local tu = target[li]
+ if not tu then
+ tu = { }
+ target[li] = tu
+ end
+ target = tu
+ end
+ target.ligature = unicode
+end
+local function pair(lookupdata,lookupname,unicode,lookuphash)
+ local target = lookuphash[lookupname]
+ if not target then
+ target = { }
+ lookuphash[lookupname] = target
+ end
+ local others = target[unicode]
+ local paired = lookupdata[1]
+ if others then
+ others[paired] = lookupdata
+ else
+ others = { [paired] = lookupdata }
+ target[unicode] = others
+ end
+end
+
+local action = {
substitution = generic,
multiple = generic,
alternate = generic,
position = generic,
-
- ligature = function(lookupdata,lookupname,unicode,lookuphash)
- local target = lookuphash[lookupname]
- if not target then
- target = { }
- lookuphash[lookupname] = target
- end
- for i=1,#lookupdata do
- local li = lookupdata[i]
- local tu = target[li]
- if not tu then
- tu = { }
- target[li] = tu
- end
- target = tu
- end
- target.ligature = unicode
- end,
-
- pair = function(lookupdata,lookupname,unicode,lookuphash)
- local target = lookuphash[lookupname]
- if not target then
- target = { }
- lookuphash[lookupname] = target
- end
- local others = target[unicode]
- local paired = lookupdata[1]
- if others then
- others[paired] = lookupdata
- else
- others = { [paired] = lookupdata }
- target[unicode] = others
- end
- end,
-
+ ligature = ligature,
+ pair = pair,
+ kern = pair,
}
local function prepare_lookups(tfmdata)
@@ -2699,12 +3453,17 @@ local function prepare_lookups(tfmdata)
local lookuptypes = resources.lookuptypes
local characters = tfmdata.characters
local descriptions = tfmdata.descriptions
+ local duplicates = resources.duplicates
-- we cannot free the entries in the descriptions as sometimes we access
-- then directly (for instance anchors) ... selectively freeing does save
-- much memory as it's only a reference to a table and the slot in the
-- description hash is not freed anyway
+ -- we can delay this using metatables so that we don't make the hashes for
+ -- features we don't use but then we need to loop over the characters
+ -- many times so we gain nothing
+
for unicode, character in next, characters do -- we cannot loop over descriptions !
local description = descriptions[unicode]
@@ -2714,7 +3473,7 @@ local function prepare_lookups(tfmdata)
local lookups = description.slookups
if lookups then
for lookupname, lookupdata in next, lookups do
- action[lookuptypes[lookupname]](lookupdata,lookupname,unicode,lookuphash)
+ action[lookuptypes[lookupname]](lookupdata,lookupname,unicode,lookuphash,duplicates)
end
end
@@ -2724,7 +3483,7 @@ local function prepare_lookups(tfmdata)
local lookuptype = lookuptypes[lookupname]
for l=1,#lookuplist do
local lookupdata = lookuplist[l]
- action[lookuptype](lookupdata,lookupname,unicode,lookuphash)
+ action[lookuptype](lookupdata,lookupname,unicode,lookuphash,duplicates)
end
end
end
@@ -2748,7 +3507,7 @@ local function prepare_lookups(tfmdata)
for name, anchor in next, anchors do
local lookups = anchor_to_lookup[name]
if lookups then
- for lookup, _ in next, lookups do
+ for lookup in next, lookups do
local target = lookuphash[lookup]
if target then
target[unicode] = anchors
@@ -2768,6 +3527,8 @@ local function prepare_lookups(tfmdata)
end
+-- so far
+
local function split(replacement,original)
local result = { }
for i=1,#replacement do
@@ -2843,7 +3604,7 @@ local function prepare_contextchains(tfmdata)
-- use sequence[start] instead but it's somewhat ugly.
nt = nt + 1
t[nt] = { nofrules, lookuptype, sequence, start, stop, rule.lookups, replacements }
- for unic, _ in next, sequence[start] do
+ for unic in next, sequence[start] do
local cu = contexts[unic]
if not cu then
contexts[unic] = t
diff --git a/tex/generic/context/luatex/luatex-fonts.lua b/tex/generic/context/luatex/luatex-fonts.lua
index fe0e9de77..738118945 100644
--- a/tex/generic/context/luatex/luatex-fonts.lua
+++ b/tex/generic/context/luatex/luatex-fonts.lua
@@ -29,7 +29,7 @@ if not modules then modules = { } end modules ['luatex-fonts'] = {
-- texio.write_nl("")
-- texio.write_nl("--------------------------------------------------------------------------------")
--- texio.write_nl("The font code has been brought in sync with the context version of 2014.12.21 so")
+-- texio.write_nl("The font code has been brought in sync with the context version of 2015.08.31 so")
-- texio.write_nl("if things don't work out as expected the interfacing needs to be checked. When")
-- texio.write_nl("this works as expected a second upgrade will happen that gives a more complete")
-- texio.write_nl("support and another sync with the context code (that new code is currently being")