From 772472f057060460c83828cf7fd1631298165e37 Mon Sep 17 00:00:00 2001
From: Hans Hagen <pragma@wxs.nl>
Date: Fri, 15 Sep 2017 21:00:20 +0200
Subject: 2017-09-15 20:09:00

---
 tex/context/base/mkii/cont-new.mkii                |   2 +-
 tex/context/base/mkii/context.mkii                 |   2 +-
 tex/context/base/mkii/mult-ro.mkii                 |   2 +
 tex/context/base/mkiv/cont-new.mkiv                |   2 +-
 tex/context/base/mkiv/context.mkiv                 |   2 +-
 tex/context/base/mkiv/font-dsp.lua                 |  30 +-
 tex/context/base/mkiv/font-ini.lua                 |   3 +-
 tex/context/base/mkiv/font-otc.lua                 |   4 +-
 tex/context/base/mkiv/font-otj.lua                 | 215 ++++--
 tex/context/base/mkiv/font-otr.lua                 |   6 +-
 tex/context/base/mkiv/font-ots.lua                 | 605 +++++++--------
 tex/context/base/mkiv/font-oup.lua                 |  69 +-
 tex/context/base/mkiv/math-ali.mkiv                |  21 +-
 tex/context/base/mkiv/status-files.pdf             | Bin 25849 -> 25846 bytes
 tex/context/base/mkiv/status-lua.pdf               | Bin 426575 -> 426573 bytes
 tex/context/interface/mkii/keys-ro.xml             |   2 +
 tex/context/interface/mkiv/i-context.pdf           | Bin 818532 -> 818669 bytes
 tex/context/interface/mkiv/i-readme.pdf            | Bin 60775 -> 60774 bytes
 tex/context/modules/mkiv/s-fonts-variable.mkiv     |   6 +-
 tex/context/modules/mkiv/s-present-lines.mkiv      |   8 +-
 tex/generic/context/luatex/luatex-fonts-merged.lua | 836 ++++++++++++---------
 tex/generic/context/luatex/luatex-fonts-mis.lua    |  32 +
 tex/generic/context/luatex/luatex-fonts.lua        |   1 +
 23 files changed, 1076 insertions(+), 772 deletions(-)
 create mode 100644 tex/generic/context/luatex/luatex-fonts-mis.lua

(limited to 'tex')

diff --git a/tex/context/base/mkii/cont-new.mkii b/tex/context/base/mkii/cont-new.mkii
index 805595e50..f31bce976 100644
--- a/tex/context/base/mkii/cont-new.mkii
+++ b/tex/context/base/mkii/cont-new.mkii
@@ -11,7 +11,7 @@
 %C therefore copyrighted by \PRAGMA. See mreadme.pdf for
 %C details.
 
-\newcontextversion{2017.09.08 17:24}
+\newcontextversion{2017.09.15 20:03}
 
 %D This file is loaded at runtime, thereby providing an
 %D excellent place for hacks, patches, extensions and new
diff --git a/tex/context/base/mkii/context.mkii b/tex/context/base/mkii/context.mkii
index cdaac874c..93dd75394 100644
--- a/tex/context/base/mkii/context.mkii
+++ b/tex/context/base/mkii/context.mkii
@@ -20,7 +20,7 @@
 %D your styles an modules.
 
 \edef\contextformat {\jobname}
-\edef\contextversion{2017.09.08 17:24}
+\edef\contextversion{2017.09.15 20:03}
 
 %D For those who want to use this:
 
diff --git a/tex/context/base/mkii/mult-ro.mkii b/tex/context/base/mkii/mult-ro.mkii
index 6ae2fe671..bceff14e4 100644
--- a/tex/context/base/mkii/mult-ro.mkii
+++ b/tex/context/base/mkii/mult-ro.mkii
@@ -753,6 +753,7 @@
 \setinterfaceconstant{direction}{directie}
 \setinterfaceconstant{directory}{director}
 \setinterfaceconstant{display}{display}
+\setinterfaceconstant{displaythreshold}{displaythreshold}
 \setinterfaceconstant{distance}{distanta}
 \setinterfaceconstant{domain}{domain}
 \setinterfaceconstant{dot}{punct}
@@ -862,6 +863,7 @@
 \setinterfaceconstant{index}{index}
 \setinterfaceconstant{indicator}{indicator}
 \setinterfaceconstant{initialsep}{initialsep}
+\setinterfaceconstant{inlinethreshold}{inlinethreshold}
 \setinterfaceconstant{inner}{intern}
 \setinterfaceconstant{innermargin}{innermargin}
 \setinterfaceconstant{inputfile}{inputfile}
diff --git a/tex/context/base/mkiv/cont-new.mkiv b/tex/context/base/mkiv/cont-new.mkiv
index bfb0e6be1..c3305ba66 100644
--- a/tex/context/base/mkiv/cont-new.mkiv
+++ b/tex/context/base/mkiv/cont-new.mkiv
@@ -11,7 +11,7 @@
 %C therefore copyrighted by \PRAGMA. See mreadme.pdf for
 %C details.
 
-\newcontextversion{2017.09.08 17:24}
+\newcontextversion{2017.09.15 20:03}
 
 %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/mkiv/context.mkiv b/tex/context/base/mkiv/context.mkiv
index d7f63e76e..4033f2c7d 100644
--- a/tex/context/base/mkiv/context.mkiv
+++ b/tex/context/base/mkiv/context.mkiv
@@ -41,7 +41,7 @@
 %D up and the dependencies are more consistent.
 
 \edef\contextformat {\jobname}
-\edef\contextversion{2017.09.08 17:24}
+\edef\contextversion{2017.09.15 20:03}
 \edef\contextkind   {beta}
 
 %D For those who want to use this:
diff --git a/tex/context/base/mkiv/font-dsp.lua b/tex/context/base/mkiv/font-dsp.lua
index dee115a6b..34497ece7 100644
--- a/tex/context/base/mkiv/font-dsp.lua
+++ b/tex/context/base/mkiv/font-dsp.lua
@@ -2046,8 +2046,8 @@ do
 
     local function resolvelookups(f,lookupoffset,fontdata,lookups,lookuptypes,lookuphandlers,what,tableoffset)
 
-        local sequences      = fontdata.sequences   or { }
-        local sublookuplist  = fontdata.sublookups  or { }
+        local sequences      = fontdata.sequences  or { }
+        local sublookuplist  = fontdata.sublookups or { }
         fontdata.sequences   = sequences
         fontdata.sublookups  = sublookuplist
         local nofsublookups  = #sublookuplist
@@ -2062,6 +2062,8 @@ do
         local noflookups     = #lookups
         local lookupprefix   = sub(what,2,2) -- g[s|p][ub|os]
         --
+        local usedlookups    = false -- setmetatableindex("number")
+        --
         for lookupid=1,noflookups do
             local lookup     = lookups[lookupid]
             local lookuptype = lookup.type
@@ -2131,12 +2133,26 @@ do
                                                 current[i] = tohash(current[i])
                                             end
                                         end
+                                    else
+                                        -- weird lookup
                                     end
                                     if after then
                                         for i=1,#after do
                                             after[i] = tohash(after[i])
                                         end
                                     end
+                                    if usedlookups then
+                                        local lookups = rule.lookups
+                                        if lookups then
+                                            for k, v in next, lookups do
+                                                if v then
+                                                    for k, v in next, v do
+                                                        usedlookups[v] = usedlookups[v] + 1
+                                                    end
+                                                end
+                                            end
+                                        end
+                                    end
                                 end
                             end
                         end
@@ -2188,6 +2204,10 @@ do
             end
         end
 
+        if usedlookups then
+            report("used %s lookups: % t",what,sortedkeys(usedlookups))
+        end
+
         -- When we have a context, we have sublookups that resolve into lookups for which we need to
         -- know the type. We split the main lookuptable in two parts: sequences (the main lookups)
         -- and subtable lookups (simple specs with no features). We could keep them merged and might do
@@ -2243,7 +2263,7 @@ do
                                                     if d then
                                                         nofsublookups = nofsublookups + 1
                                                      -- report("registering %i as sublookup %i",lookupid,nofsublookups)
-                                                        h = {
+                                                        local l = {
                                                             index     = nofsublookups, -- handy for tracing
                                                             name      = f_lookupname(lookupprefix,"d",lookupid+lookupidoffset),
                                                             derived   = true,          -- handy for tracing
@@ -2254,7 +2274,7 @@ do
                                                             flags     = d.flags,
                                                          -- chain     = d.chain,
                                                         }
-                                                        sublookuplist[nofsublookups] = copy(h) -- we repack later
+                                                        sublookuplist[nofsublookups] = copy(l) -- we repack later
                                                         sublookuphash[lookupid] = nofsublookups
                                                         sublookupcheck[lookupid] = 1
                                                         h = nofsublookups
@@ -2277,7 +2297,9 @@ do
                                             end
                                         end
                                     end
+-- report("before : % t",rlookups[index])
                                     rlookups[index] = noffound > 0 and found or false
+-- report("after  : % t",rlookups[index])
                                 else
                                     rlookups[index] = false
                                 end
diff --git a/tex/context/base/mkiv/font-ini.lua b/tex/context/base/mkiv/font-ini.lua
index e0ad46cac..3d5dd27a2 100644
--- a/tex/context/base/mkiv/font-ini.lua
+++ b/tex/context/base/mkiv/font-ini.lua
@@ -15,8 +15,7 @@ local allocate   = utilities.storage.allocate
 fonts            = fonts or { }
 local fonts      = fonts
 
-fonts.hashes     = { identifiers = allocate() }
-
+fonts.hashes     = fonts.hashes     or { identifiers = allocate() }
 fonts.tables     = fonts.tables     or { }
 fonts.helpers    = fonts.helpers    or { }
 fonts.tracers    = fonts.tracers    or { } -- for the moment till we have move to moduledata
diff --git a/tex/context/base/mkiv/font-otc.lua b/tex/context/base/mkiv/font-otc.lua
index 7014761f1..1d0db7b81 100644
--- a/tex/context/base/mkiv/font-otc.lua
+++ b/tex/context/base/mkiv/font-otc.lua
@@ -466,10 +466,10 @@ local function addfeature(data,feature,specifications)
                                     subtype = lookup.type
                                 end
                             else
-                                lookups[k] = { false } -- new
+                                lookups[k] = false -- { false } -- new
                             end
                         else
-                            lookups[k] = { false } -- new
+                            lookups[k] = false -- { false } -- new
                         end
                     end
                 end
diff --git a/tex/context/base/mkiv/font-otj.lua b/tex/context/base/mkiv/font-otj.lua
index 74e052408..1f9fd1ac1 100644
--- a/tex/context/base/mkiv/font-otj.lua
+++ b/tex/context/base/mkiv/font-otj.lua
@@ -7,7 +7,7 @@ if not modules then modules = { } end modules ['font-otj'] = {
 }
 
 -- 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
+-- need to use rawget (which is about 4 times slower than a direct access but we cannot
 -- 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.)
 
@@ -49,6 +49,7 @@ local attributes, nodes, node = attributes, nodes, node
 fonts                    = fonts
 local hashes             = fonts.hashes
 local fontdata           = hashes.identifiers
+local fontmarks          = hashes.marks
 ----- parameters         = fonts.hashes.parameters -- not in generic
 ----- resources          = fonts.hashes.resources  -- not in generic
 
@@ -157,9 +158,9 @@ end
 function injections.reset(n)
     local p = rawget(properties,n)
     if p then
-        p.injections = false -- { }
+        p.injections = false -- { } -- nil should work too as we use rawget
     else
-        properties[n] = false -- { injections = { } }
+        properties[n] = false -- { injections = { } } -- nil should work too as we use rawget
     end
 end
 
@@ -192,7 +193,7 @@ function injections.copy(target,source)
     end
 end
 
-function injections.setligaindex(n,index)
+function injections.setligaindex(n,index) -- todo: don't set when 0
     local p = rawget(properties,n)
     if p then
         local i = p.injections
@@ -397,43 +398,43 @@ function injections.setmove(current,factor,rlmode,x,injection)
         if not injection then
             injection = "injections"
         end
-if rlmode and rlmode < 0 then
-        -- we need to swap with a single so then we also need to to it here
-        -- as move is just a simple single
-        if p then
-            local i = p[injection]
-            if i then
-                i.rightkern = dx + (i.rightkern or 0)
+        if rlmode and rlmode < 0 then
+            -- we need to swap with a single so then we also need to to it here
+            -- as move is just a simple single
+            if p then
+                local i = p[injection]
+                if i then
+                    i.rightkern = dx + (i.rightkern or 0)
+                else
+                    p[injection] = {
+                        rightkern = dx,
+                    }
+                end
             else
-                p[injection] = {
-                    rightkern = dx,
+                properties[current] = {
+                    [injection] = {
+                        rightkern = dx,
+                    },
                 }
             end
         else
-            properties[current] = {
-                [injection] = {
-                    rightkern = dx,
-                },
-            }
-        end
-else
-        if p then
-            local i = p[injection]
-            if i then
-                i.leftkern = dx + (i.leftkern or 0)
+            if p then
+                local i = p[injection]
+                if i then
+                    i.leftkern = dx + (i.leftkern or 0)
+                else
+                    p[injection] = {
+                        leftkern = dx,
+                    }
+                end
             else
-                p[injection] = {
-                    leftkern = dx,
+                properties[current] = {
+                    [injection] = {
+                        leftkern = dx,
+                    },
                 }
             end
-        else
-            properties[current] = {
-                [injection] = {
-                    leftkern = dx,
-                },
-            }
         end
-end
         return dx, nofregisteredkerns
     else
         return 0, 0
@@ -454,9 +455,15 @@ function injections.setmark(start,base,factor,rlmode,ba,ma,tfmbase,mkmk,checkmar
             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
+                if dx ~= 0 then
+                    i.markx    = dx
+                end
+                if y ~= 0 then
+                    i.marky    = dy
+                end
+                if rlmode then
+                    i.markdir  = rlmode
+                end
                 i.markbase     = nofregisteredmarks
                 i.markbasenode = base
                 i.markmark     = mkmk
@@ -792,12 +799,12 @@ local function inject_positions_only(head,where)
                     local leftkern  = i.leftkern
                     local rightkern = i.rightkern
                     if leftkern and leftkern ~= 0 then
-if rightkern and leftkern == -rightkern then
-    setoffsets(current,leftkern,false)
-    rightkern = 0
-else
-                        head = insert_node_before(head,current,fontkern(leftkern))
-end
+                        if rightkern and leftkern == -rightkern then
+                            setoffsets(current,leftkern,false)
+                            rightkern = 0
+                        else
+                            head = insert_node_before(head,current,fontkern(leftkern))
+                        end
                     end
                     if rightkern and rightkern ~= 0 then
                         insert_node_after(head,current,fontkern(rightkern))
@@ -1040,16 +1047,16 @@ local function inject_everything(head,where)
                 rightkern = pp.rightkern
             end
         end
+        local markdir = pn.markdir
         if rightkern then -- x and w ~= 0
-            if pn.markdir < 0 then
+            ox = px - (pn.markx or 0) - rightkern
+            if markdir and markdir < 0 then
                 -- kern(w-x) glyph(p) kern(x) mark(n)
-                ox = px - pn.markx - rightkern
                 if not pn.markmark then
                     ox = ox + (pn.leftkern or 0)
                 end
             else
                 -- kern(x) glyph(p) kern(w-x) mark(n)
-             -- ox = px - getwidth(p) + pn.markx - pp.leftkern
                 --
                 -- According to Kai we don't need to handle leftkern here but I'm
                 -- pretty sure I've run into a case where it was needed so maybe
@@ -1057,7 +1064,6 @@ local function inject_everything(head,where)
                 --
                 -- maybe we need to apply both then
                 --
-                ox = px - pn.markx - rightkern -- seguiemj needs the rightkern
                 if false then
                     -- a mark with kerning (maybe husayni needs it )
                     local leftkern = pp.leftkern
@@ -1067,16 +1073,14 @@ local function inject_everything(head,where)
                 end
             end
         else
-            if pn.markdir < 0 then
-                ox = px - pn.markx
+            ox = px - (pn.markx or 0)
+            if markdir and markdir < 0 then
                 if not pn.markmark then
                     local leftkern = pn.leftkern
                     if leftkern then
                         ox = ox + leftkern -- husayni needs it
                     end
                 end
-            else
-                ox = px - pn.markx
             end
             if pn.checkmark then
                 local wn = getwidth(n) -- in arial marks have widths
@@ -1101,7 +1105,7 @@ local function inject_everything(head,where)
                 end
             end
         end
-        local oy = ny + py + pn.marky
+        local oy = ny + py + (pn.marky or 0)
         if not pn.markmark then
             local yoffset = pn.yoffset
             if yoffset then
@@ -1113,15 +1117,72 @@ local function inject_everything(head,where)
             showoffset(n,true)
         end
     end
+    -- begin of temp fix --
+    local base = nil -- bah, some arabic fonts have no mark anchoring
+    -- end of temp fix --
     while current do
         local next = getnext(current)
         local char, id = ischar(current)
         if char then
             local p = rawget(properties,current)
+            -- begin of temp fix --
+            if hascursives then
+                if not p then
+                    local m = fontmarks[getfont(current)]
+                    if m and m[char] then
+                        if base then
+                            p = { injections = { markbasenode = base } }
+                            nofmarks = nofmarks + 1
+                            marks[nofmarks] = current
+                            properties[current] = p
+                            hasmarks = true
+                        end
+                    else
+                        base = current
+                    end
+                end
+            end
+            -- end of temp fix
             if p then
                 local i = p.injections
+                -- begin of temp fix --
+                if hascursives then
+                    if not i then
+                        local m = fontmarks[getfont(current)]
+                        if m and m[char] then
+                            if base then
+                                i = { markbasenode = base }
+                                nofmarks = nofmarks + 1
+                                marks[nofmarks] = current
+                                p.injections = i
+                                hasmarks = true
+                            end
+                        else
+                            base = current
+                        end
+                    end
+                end
+                -- end of temp fix --
                 if i then
                     local pm = i.markbasenode
+                    -- begin of temp fix --
+                    if hascursives then
+                        if not pm then
+                            local m = fontmarks[getfont(current)]
+                            if m and m[char] then
+                                if base then
+                                    pm = base
+                                    i.markbasenode = pm
+                                    hasmarks = true
+                                end
+                            else
+                                base = current
+                            end
+                        else
+                            base = current
+                        end
+                    end
+                    -- end of temp fix --
                     if pm then
                         nofmarks = nofmarks + 1
                         marks[nofmarks] = current
@@ -1185,12 +1246,12 @@ local function inject_everything(head,where)
                         local leftkern  = i.leftkern
                         local rightkern = i.rightkern
                         if leftkern and leftkern ~= 0 then
-if rightkern and leftkern == -rightkern then
-    setoffsets(current,leftkern,false)
-    rightkern = 0
-else
-                            head = insert_node_before(head,current,fontkern(leftkern))
-end
+                            if rightkern and leftkern == -rightkern then
+                                setoffsets(current,leftkern,false)
+                                rightkern = 0
+                            else
+                                head = insert_node_before(head,current,fontkern(leftkern))
+                            end
                         end
                         if rightkern and rightkern ~= 0 then
                             insert_node_after(head,current,fontkern(rightkern))
@@ -1401,6 +1462,7 @@ end
         else
             prevglyph = nil
             prevdisc  = nil
+base = nil
         end
         prev    = current
         current = next
@@ -1532,7 +1594,6 @@ local function injectspaces(head)
     if not triggers then
         return head, false
     end
-
     local lastfont   = nil
     local spacekerns = nil
     local leftkerns  = nil
@@ -1584,23 +1645,25 @@ local function injectspaces(head)
             if old > threshold then
                 if rightkern then
                     if useitalickerns then
-                        local new = old + (leftkern + rightkern) * factor
-                        if trace_spaces then
-                            report_spaces("%C [%p -> %p] %C",prevchar,old,new,nextchar)
-                        end
-                        setwidth(n,new)
-                    else
-                        local new = (leftkern + rightkern) * factor
+                        local lnew = leftkern  * factor
+                        local rnew = rightkern * factor
                         if trace_spaces then
-                            report_spaces("%C [%p + %p] %C",prevchar,old,new,nextchar)
+                            report_spaces("%C [%p + %p + %p] %C",prevchar,lnew,old,rnew,nextchar)
                         end
-                        local h = insert_node_before(nuthead,n,italickern(new))
+                        local h = insert_node_before(nuthead,n,italickern(lnew))
                         if h == nuthead then
                             head = tonode(h)
                             nuthead = h
                         end
+                        insert_node_after(nuthead,n,italickern(rnew))
+                    else
+                        local new = old + (leftkern + rightkern) * factor
+                        if trace_spaces then
+                            report_spaces("%C [%p -> %p] %C",prevchar,old,new,nextchar)
+                        end
+                        setwidth(n,new)
                     end
-                    leftkern = false
+                    rightkern = false
                 else
                     if useitalickerns then
                         local new = leftkern * factor
@@ -1621,11 +1684,19 @@ local function injectspaces(head)
         elseif rightkern then
             local old = getwidth(n)
             if old > threshold then
-                local new = old + rightkern * factor
-                if trace_spaces then
-                    report_spaces("[%p -> %p] %C",nextchar,old,new)
+                if useitalickerns then
+                    local new = rightkern * factor
+                    if trace_spaces then
+                        report_spaces("%C [%p + %p]",nextchar,old,new)
+                    end
+                    insert_node_after(nuthead,n,italickern(new))
+                else
+                    local new = old + rightkern * factor
+                    if trace_spaces then
+                        report_spaces("[%p -> %p] %C",nextchar,old,new)
+                    end
+                    setwidth(n,new)
                 end
-                setwidth(n,new)
             end
             rightkern = false
         end
diff --git a/tex/context/base/mkiv/font-otr.lua b/tex/context/base/mkiv/font-otr.lua
index 8f08dc5eb..8fd84015a 100644
--- a/tex/context/base/mkiv/font-otr.lua
+++ b/tex/context/base/mkiv/font-otr.lua
@@ -2128,9 +2128,9 @@ local function readdata(f,offset,specification)
                 if factors then
                     specification.factors = factors
                     fontdata.factors = factors
-                    report("factors: % t",factors)
-                else
-                    report("bad factors")
+             --     report("factors: % t",factors)
+             -- else
+             --     report("bad factors")
                 end
             else
              -- report("unknown instance")
diff --git a/tex/context/base/mkiv/font-ots.lua b/tex/context/base/mkiv/font-ots.lua
index 031cf3baa..3d0606caf 100644
--- a/tex/context/base/mkiv/font-ots.lua
+++ b/tex/context/base/mkiv/font-ots.lua
@@ -543,12 +543,13 @@ local function toligature(head,start,stop,char,dataset,sequence,skiphash,discfou
             -- we can be more clever here: "not deletemarks or (skiphash and not skiphash[char])"
             -- and such:
             elseif not deletemarks then
+                -- we can get a loop when the font expects otherwise (i.e. unexpected deletemarks)
                 setligaindex(start,baseindex + getligaindex(start,componentindex))
                 if trace_marks then
                     logwarning("%s: keep mark %s, gets index %s",pref(dataset,sequence),gref(char),getligaindex(start))
                 end
                 local n = copy_node(start)
-                copyinjection(n,start)
+                copyinjection(n,start) -- is this ok ? we position later anyway
                 head, current = insert_node_after(head,current,n) -- unlikely that mark has components
             elseif trace_marks then
                 logwarning("%s: delete mark %s",pref(dataset,sequence),gref(char))
@@ -2352,7 +2353,7 @@ end
 -- are real torture tests because they have many steps with one context (having
 -- multiple contexts makes more sense) also because we (can) reduce them. Instead of
 -- a match boolean variable and check for that I decided to use a goto with labels
--- instead. This is one of the cases where it makes th ecode more readable and we
+-- instead. This is one of the cases where it makes the code more readable and we
 -- might even gain a bit performance.
 
 local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode,skiphash)
@@ -2381,254 +2382,134 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode,s
           startnext    = getboth(start)
     local done      -- = false
 
-    -- hm, contexts can also be nested
+    -- we can have multiple hits and as we scan (currently) all we need to check
+    -- if we have a match ... contextchains have no real coverage table (with
+    -- unique entries)
 
-    for k=1,contexts.n do -- or #contexts do
+    -- fonts can have many steps (each doing one check) or many contexts
+
+    -- todo: make a per-char cache so that we have small contexts (when we have a context
+    -- n == 1 and otherwise it can be more so we can even distingish n == 1 or more)
+
+    local nofcontexts = contexts.n -- #contexts
+
+    local startchar = nofcontext == 1 or ischar(start,currentfont) -- only needed in a chain
+
+
+    for k=1,nofcontexts do
+
+        local ck  = contexts[k]
+        local seq = ck[3]
+        local f   = ck[4] -- first current
+        if not startchar or not seq[f][startchar] then
+            -- report("no hit in %a at %i of %i contexts",sequence.type,k,nofcontexts)
+            goto next
+        end
+        local s       = seq.n -- or #seq
+        local l       = ck[5] -- last current
         local current = start
         local last    = start
-        local ck      = contexts[k]
-        local seq     = ck[3]
-     -- local s       = #seq
-        local s       = seq.n -- or #seq
-        -- f..l = mid string
-        if s == 1 then
-            -- this seldom happens as it makes no sense (bril, ebgaramond, husayni, minion)
-            local char = ischar(current,currentfont)
-            if char and not seq[1][char] then
-                goto next
-            end
-        else
-            -- maybe we need a better space check (maybe check for glue or category or combination)
-            local f = ck[4]
-            local l = ck[5]
-            -- current match
-            -- seq[f][ischar(current,currentfont)] is not nil
-            if l > f then
-                -- before/current/after | before/current | current/after
-                local discfound -- = nil
-                local n = f + 1
-                last = startnext -- the second in current (first already matched)
-                while n <= l do
-                    if postreplace and not last then
-                        last      = getnext(sweepnode)
-                        sweeptype = nil
-                    end
-                    if last then
-                        local char, id = ischar(last,currentfont)
-                        if char then
-                            if skiphash and skiphash[char] then
-                                skipped = true
-                                if trace_skips then
-                                    show_skip(dataset,sequence,char,ck,classes[char])
-                                end
+
+        -- current match
+
+        if l > f then
+            -- before/current/after | before/current | current/after
+            local discfound -- = nil
+            local n = f + 1
+            last = startnext -- the second in current (first already matched)
+            while n <= l do
+                if postreplace and not last then
+                    last      = getnext(sweepnode)
+                    sweeptype = nil
+                end
+                if last then
+                    local char, id = ischar(last,currentfont)
+                    if char then
+                        if skiphash and skiphash[char] then
+                            skipped = true
+                            if trace_skips then
+                                show_skip(dataset,sequence,char,ck,classes[char])
+                            end
+                            last = getnext(last)
+                        elseif seq[n][char] then
+                            if n < l then
                                 last = getnext(last)
-                            elseif seq[n][char] then
-                                if n < l then
-                                    last = getnext(last)
-                                end
-                                n = n + 1
-                            elseif discfound then
-                                notmatchreplace[discfound] = true
-                                if notmatchpre[discfound] then
-                                    goto next
-                                else
-                                    break
-                                end
-                            else
-                                goto next
                             end
-                        elseif char == false then
-                            if discfound then
-                                notmatchreplace[discfound] = true
-                                if notmatchpre[discfound] then
-                                    goto next
-                                else
-                                    break
-                                end
+                            n = n + 1
+                        elseif discfound then
+                            notmatchreplace[discfound] = true
+                            if notmatchpre[discfound] then
+                                goto next
                             else
+                                break
+                            end
+                        else
+                            goto next
+                        end
+                    elseif char == false then
+                        if discfound then
+                            notmatchreplace[discfound] = true
+                            if notmatchpre[discfound] then
                                 goto next
+                            else
+                                break
                             end
-                        elseif id == disc_code then
-                     -- elseif id == disc_code and (not discs or discs[last]) then
-                            diskseen              = true
-                            discfound             = last
-                            notmatchpre[last]     = nil
-                            notmatchpost[last]    = true
-                            notmatchreplace[last] = nil
-                            local pre, post, replace = getdisc(last)
-                            if pre then
-                                local n = n
-                                while pre do
-                                    if seq[n][getchar(pre)] then
-                                        n = n + 1
-                                        if n > l then
-                                            break
-                                        end
-                                        pre = getnext(pre)
-                                    else
-                                        notmatchpre[last] = true
+                        else
+                            goto next
+                        end
+                    elseif id == disc_code then
+                 -- elseif id == disc_code and (not discs or discs[last]) then
+                        diskseen              = true
+                        discfound             = last
+                        notmatchpre[last]     = nil
+                        notmatchpost[last]    = true
+                        notmatchreplace[last] = nil
+                        local pre, post, replace = getdisc(last)
+                        if pre then
+                            local n = n
+                            while pre do
+                                if seq[n][getchar(pre)] then
+                                    n = n + 1
+                                    if n > l then
                                         break
                                     end
-                                end
-                                if n <= l then
+                                    pre = getnext(pre)
+                                else
                                     notmatchpre[last] = true
+                                    break
                                 end
-                            else
-                                notmatchpre[last] = true
                             end
-                            if replace then
-                                -- so far we never entered this branch
-                                while replace do
-                                    if seq[n][getchar(replace)] then
-                                        n = n + 1
-                                        if n > l then
-                                            break
-                                        end
-                                        replace = getnext(replace)
-                                    else
-                                        notmatchreplace[last] = true
-                                        if notmatchpre[last] then
-                                            goto next
-                                        else
-                                            break
-                                        end
-                                    end
-                                end
-                                -- why here again
-                                if notmatchpre[last] then
-                                    goto next
-                                end
+                            if n <= l then
+                                notmatchpre[last] = true
                             end
-                            -- maybe only if match
-                            last = getnext(last)
                         else
-                            goto next
+                            notmatchpre[last] = true
                         end
-                    else
-                        goto next
-                    end
-                end
-            end
-            -- before
-            if f > 1 then
-                if startprev then
-                    local prev = startprev
-                    if prereplace and prev == checkdisc then
-                        prev = getprev(sweepnode)
-                    end
-                    if prev then
-                        local discfound -- = nil
-                        local n = f - 1
-                        while n >= 1 do
-                            if prev then
-                                local char, id = ischar(prev,currentfont)
-                                if char then
-                                    if skiphash and skiphash[char] then
-                                        skipped = true
-                                        if trace_skips then
-                                            show_skip(dataset,sequence,char,ck,classes[char])
-                                        end
-                                        prev = getprev(prev)
-                                    elseif seq[n][char] then
-                                        if n > 1 then
-                                            prev = getprev(prev)
-                                        end
-                                        n = n - 1
-                                    elseif discfound then
-                                        notmatchreplace[discfound] = true
-                                        if notmatchpost[discfound] then
-                                            goto next
-                                        else
-                                            break
-                                        end
-                                    else
-                                        goto next
+                        if replace then
+                            -- so far we never entered this branch
+                            while replace do
+                                if seq[n][getchar(replace)] then
+                                    n = n + 1
+                                    if n > l then
+                                        break
                                     end
-                                elseif char == false then
-                                    if discfound then
-                                        notmatchreplace[discfound] = true
-                                        if notmatchpost[discfound] then
-                                            goto next
-                                        end
-                                    else
+                                    replace = getnext(replace)
+                                else
+                                    notmatchreplace[last] = true
+                                    if notmatchpre[last] then
                                         goto next
-                                    end
-                                    break
-                                elseif id == disc_code then
-                             -- elseif id == disc_code and (not discs or discs[prev]) then
-                                    -- the special case: f i where i becomes dottless i ..
-                                    diskseen              = true
-                                    discfound             = prev
-                                    notmatchpre[prev]     = true
-                                    notmatchpost[prev]    = nil
-                                    notmatchreplace[prev] = nil
-                                    local pre, post, replace, pretail, posttail, replacetail = getdisc(prev,true)
-                                    if pre ~= start and post ~= start and replace ~= start then
-                                        if post then
-                                            local n = n
-                                            while posttail do
-                                                if seq[n][getchar(posttail)] then
-                                                    n = n - 1
-                                                    if posttail == post or n < 1 then
-                                                        break
-                                                    else
-                                                        posttail = getprev(posttail)
-                                                    end
-                                                else
-                                                    notmatchpost[prev] = true
-                                                    break
-                                                end
-                                            end
-                                            if n >= 1 then
-                                                notmatchpost[prev] = true
-                                            end
-                                        else
-                                            notmatchpost[prev] = true
-                                        end
-                                        if replace then
-                                            -- we seldom enter this branch (e.g. on brill efficient)
-                                            while replacetail do
-                                                if seq[n][getchar(replacetail)] then
-                                                    n = n - 1
-                                                    if replacetail == replace or n < 1 then
-                                                        break
-                                                    else
-                                                        replacetail = getprev(replacetail)
-                                                    end
-                                                else
-                                                    notmatchreplace[prev] = true
-                                                    if notmatchpost[prev] then
-                                                        goto next
-                                                    else
-                                                        break
-                                                    end
-                                                end
-                                            end
-                                        end
-                                    end
-                                    prev = getprev(prev)
-                             -- elseif id == glue_code and seq[n][32] and isspace(prev,threshold,id) then
-                             -- elseif seq[n][32] and spaces[prev] then
-                             --     n = n - 1
-                             --     prev = getprev(prev)
-                                elseif id == glue_code then
-                                    local sn = seq[n]
-                                    if (sn[32] and spaces[prev]) or sn[0xFFFC] then
-                                        n = n - 1
-                                        prev = getprev(prev)
                                     else
-                                        goto next
+                                        break
                                     end
-                                elseif seq[n][0xFFFC] then
-                                    n = n - 1
-                                    prev = getprev(prev)
-                                else
-                                    goto next
                                 end
-                            else
+                            end
+                            -- why here again
+                            if notmatchpre[last] then
                                 goto next
                             end
                         end
+                        -- maybe only if match
+                        last = getnext(last)
                     else
                         goto next
                     end
@@ -2636,33 +2517,37 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode,s
                     goto next
                 end
             end
-            -- after
-            if s > l then
-                local current = last and getnext(last)
-                if not current and postreplace then
-                    current   = getnext(sweepnode)
+        end
+
+        -- before
+
+        if f > 1 then
+            if startprev then
+                local prev = startprev
+                if prereplace and prev == checkdisc then
+                    prev = getprev(sweepnode)
                 end
-                if current then
+                if prev then
                     local discfound -- = nil
-                    local n = l + 1
-                    while n <= s do
-                        if current then
-                            local char, id = ischar(current,currentfont)
+                    local n = f - 1
+                    while n >= 1 do
+                        if prev then
+                            local char, id = ischar(prev,currentfont)
                             if char then
                                 if skiphash and skiphash[char] then
                                     skipped = true
                                     if trace_skips then
                                         show_skip(dataset,sequence,char,ck,classes[char])
                                     end
-                                    current = getnext(current) -- was absent
+                                    prev = getprev(prev)
                                 elseif seq[n][char] then
-                                    if n < s then -- new test
-                                        current = getnext(current) -- was absent
+                                    if n > 1 then
+                                        prev = getprev(prev)
                                     end
-                                    n = n + 1
+                                    n = n - 1
                                 elseif discfound then
                                     notmatchreplace[discfound] = true
-                                    if notmatchpre[discfound] then
+                                    if notmatchpost[discfound] then
                                         goto next
                                     else
                                         break
@@ -2673,82 +2558,81 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode,s
                             elseif char == false then
                                 if discfound then
                                     notmatchreplace[discfound] = true
-                                    if notmatchpre[discfound] then
+                                    if notmatchpost[discfound] then
                                         goto next
-                                    else
-                                        break
                                     end
                                 else
                                     goto next
                                 end
+                                break
                             elseif id == disc_code then
-                         -- elseif id == disc_code and (not discs or discs[current]) then
-                                diskseen                 = true
-                                discfound                = current
-                                notmatchpre[current]     = nil
-                                notmatchpost[current]    = true
-                                notmatchreplace[current] = nil
-                                local pre, post, replace = getdisc(current)
-                                if pre then
-                                    local n = n
-                                    while pre do
-                                        if seq[n][getchar(pre)] then
-                                            n = n + 1
-                                            if n > s then
-                                                break
+                         -- elseif id == disc_code and (not discs or discs[prev]) then
+                                -- the special case: f i where i becomes dottless i ..
+                                diskseen              = true
+                                discfound             = prev
+                                notmatchpre[prev]     = true
+                                notmatchpost[prev]    = nil
+                                notmatchreplace[prev] = nil
+                                local pre, post, replace, pretail, posttail, replacetail = getdisc(prev,true)
+                                if pre ~= start and post ~= start and replace ~= start then
+                                    if post then
+                                        local n = n
+                                        while posttail do
+                                            if seq[n][getchar(posttail)] then
+                                                n = n - 1
+                                                if posttail == post or n < 1 then
+                                                    break
+                                                else
+                                                    posttail = getprev(posttail)
+                                                end
                                             else
-                                                pre = getnext(pre)
+                                                notmatchpost[prev] = true
+                                                break
                                             end
-                                        else
-                                            notmatchpre[current] = true
-                                            break
                                         end
+                                        if n >= 1 then
+                                            notmatchpost[prev] = true
+                                        end
+                                    else
+                                        notmatchpost[prev] = true
                                     end
-                                    if n <= s then
-                                        notmatchpre[current] = true
-                                    end
-                                else
-                                    notmatchpre[current] = true
-                                end
-                                if replace then
-                                    -- so far we never entered this branch
-                                    while replace do
-                                        if seq[n][getchar(replace)] then
-                                            n = n + 1
-                                            if n > s then
-                                                break
-                                            else
-                                                replace = getnext(replace)
-                                            end
-                                        else
-                                            notmatchreplace[current] = true
-                                            -- different than others, needs checking if "not" is okay
-                                            if not notmatchpre[current] then
-                                                goto next
+                                    if replace then
+                                        -- we seldom enter this branch (e.g. on brill efficient)
+                                        while replacetail do
+                                            if seq[n][getchar(replacetail)] then
+                                                n = n - 1
+                                                if replacetail == replace or n < 1 then
+                                                    break
+                                                else
+                                                    replacetail = getprev(replacetail)
+                                                end
                                             else
-                                                break
+                                                notmatchreplace[prev] = true
+                                                if notmatchpost[prev] then
+                                                    goto next
+                                                else
+                                                    break
+                                                end
                                             end
                                         end
                                     end
-                                else
-                                    -- skip 'm
                                 end
-                                current = getnext(current)
-                         -- elseif id == glue_code and seq[n][32] and isspace(current,threshold,id) then
-                         -- elseif seq[n][32] and spaces[current] then
-                         --     n = n + 1
-                         --     current = getnext(current)
+                                prev = getprev(prev)
+                         -- elseif id == glue_code and seq[n][32] and isspace(prev,threshold,id) then
+                         -- elseif seq[n][32] and spaces[prev] then
+                         --     n = n - 1
+                         --     prev = getprev(prev)
                             elseif id == glue_code then
                                 local sn = seq[n]
-                                if (sn[32] and spaces[current]) or sn[0xFFFC] then
-                                    n = n + 1
-                                    current = getnext(current)
+                                if (sn[32] and spaces[prev]) or sn[0xFFFC] then
+                                    n = n - 1
+                                    prev = getprev(prev)
                                 else
                                     goto next
                                 end
                             elseif seq[n][0xFFFC] then
-                                n = n + 1
-                                current = getnext(current)
+                                n = n - 1
+                                prev = getprev(prev)
                             else
                                 goto next
                             end
@@ -2759,8 +2643,137 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode,s
                 else
                     goto next
                 end
+            else
+                goto next
+            end
+        end
+
+        -- after
+
+        if s > l then
+            local current = last and getnext(last)
+            if not current and postreplace then
+                current   = getnext(sweepnode)
+            end
+            if current then
+                local discfound -- = nil
+                local n = l + 1
+                while n <= s do
+                    if current then
+                        local char, id = ischar(current,currentfont)
+                        if char then
+                            if skiphash and skiphash[char] then
+                                skipped = true
+                                if trace_skips then
+                                    show_skip(dataset,sequence,char,ck,classes[char])
+                                end
+                                current = getnext(current) -- was absent
+                            elseif seq[n][char] then
+                                if n < s then -- new test
+                                    current = getnext(current) -- was absent
+                                end
+                                n = n + 1
+                            elseif discfound then
+                                notmatchreplace[discfound] = true
+                                if notmatchpre[discfound] then
+                                    goto next
+                                else
+                                    break
+                                end
+                            else
+                                goto next
+                            end
+                        elseif char == false then
+                            if discfound then
+                                notmatchreplace[discfound] = true
+                                if notmatchpre[discfound] then
+                                    goto next
+                                else
+                                    break
+                                end
+                            else
+                                goto next
+                            end
+                        elseif id == disc_code then
+                     -- elseif id == disc_code and (not discs or discs[current]) then
+                            diskseen                 = true
+                            discfound                = current
+                            notmatchpre[current]     = nil
+                            notmatchpost[current]    = true
+                            notmatchreplace[current] = nil
+                            local pre, post, replace = getdisc(current)
+                            if pre then
+                                local n = n
+                                while pre do
+                                    if seq[n][getchar(pre)] then
+                                        n = n + 1
+                                        if n > s then
+                                            break
+                                        else
+                                            pre = getnext(pre)
+                                        end
+                                    else
+                                        notmatchpre[current] = true
+                                        break
+                                    end
+                                end
+                                if n <= s then
+                                    notmatchpre[current] = true
+                                end
+                            else
+                                notmatchpre[current] = true
+                            end
+                            if replace then
+                                -- so far we never entered this branch
+                                while replace do
+                                    if seq[n][getchar(replace)] then
+                                        n = n + 1
+                                        if n > s then
+                                            break
+                                        else
+                                            replace = getnext(replace)
+                                        end
+                                    else
+                                        notmatchreplace[current] = true
+                                        -- different than others, needs checking if "not" is okay
+                                        if not notmatchpre[current] then
+                                            goto next
+                                        else
+                                            break
+                                        end
+                                    end
+                                end
+                            else
+                                -- skip 'm
+                            end
+                            current = getnext(current)
+                     -- elseif id == glue_code and seq[n][32] and isspace(current,threshold,id) then
+                     -- elseif seq[n][32] and spaces[current] then
+                     --     n = n + 1
+                     --     current = getnext(current)
+                        elseif id == glue_code then
+                            local sn = seq[n]
+                            if (sn[32] and spaces[current]) or sn[0xFFFC] then
+                                n = n + 1
+                                current = getnext(current)
+                            else
+                                goto next
+                            end
+                        elseif seq[n][0xFFFC] then
+                            n = n + 1
+                            current = getnext(current)
+                        else
+                            goto next
+                        end
+                    else
+                        goto next
+                    end
+                end
+            else
+                goto next
             end
         end
+
         if trace_contexts then
             chaintrac(head,start,dataset,sequence,rlmode,skipped and skiphash,ck,true)
         end
diff --git a/tex/context/base/mkiv/font-oup.lua b/tex/context/base/mkiv/font-oup.lua
index da9ed1a77..79ac76abe 100644
--- a/tex/context/base/mkiv/font-oup.lua
+++ b/tex/context/base/mkiv/font-oup.lua
@@ -2655,10 +2655,6 @@ function readers.expand(data)
                         end
                     end
 
-                    checkmerge(sequence)
-                    checkflags(sequence,resources)
-                    checksteps(sequence)
-
                     for i=1,nofsteps do
                         local step = steps[i]
                         local baseclasses = step.baseclasses
@@ -2675,13 +2671,14 @@ function readers.expand(data)
                         end
                         local rules = step.rules
                         if rules then
-                            local rulehash   = { n = 0 }
+                            local rulehash   = { n = 0 } -- is contexts in font-ots
                             local rulesize   = 0
                             local coverage   = { }
                             local lookuptype = sequence.type
+                            local nofrules   = #rules
                             step.coverage    = coverage -- combined hits
-                            for nofrules=1,#rules do
-                                local rule         = rules[nofrules]
+                            for currentrule=1,nofrules do
+                                local rule         = rules[currentrule]
                                 local current      = rule.current
                                 local before       = rule.before
                                 local after        = rule.after
@@ -2712,7 +2709,7 @@ function readers.expand(data)
                                     for i=1,#lookups do
                                         local lookups = lookups[i]
                                         if lookups then
-                                            for k, v in next, lookups do
+                                            for k, v in next, lookups do -- actually this one is indexed
                                                 local lookup = sublookups[v]
                                                 if lookup then
                                                     lookups[k] = lookup
@@ -2728,9 +2725,8 @@ function readers.expand(data)
                                 end
                                 if sequence[1] then -- we merge coverage into one
                                     sequence.n = #sequence -- tiny speedup
-                                    rulesize = rulesize + 1
-                                    rulehash[rulesize] = {
-                                        nofrules,     -- 1
+                                    local ruledata = {
+                                        currentrule,  -- 1 -- original rule number, only use this for tracing!
                                         lookuptype,   -- 2
                                         sequence,     -- 3
                                         start,        -- 4
@@ -2739,19 +2735,56 @@ function readers.expand(data)
                                         replacements, -- 7
                                         subtype,      -- 8
                                     }
-                                    for unic in next, sequence[start] do
-                                        local cu = coverage[unic]
-                                        if not cu then
-                                            coverage[unic] = rulehash -- can now be done cleaner i think
-                                        else
-                                            -- we can have a problem
+                                    --
+                                    -- possible optimization: per [unic] a rulehash, but beware:
+                                    -- contexts have unique coverage and chains can have multiple
+                                    -- hits (rules) per coverage entry
+                                    --
+                                    -- so: we can combine multiple steps as well as multiple rules
+                                    -- but that takes careful checking, in which case we can go the
+                                    -- step list approach and turn contexts into steps .. in fact,
+                                    -- if we turn multiple contexts into steps we're already ok as
+                                    -- steps gets a coverage hash by metatable
+                                    --
+                                    rulesize = rulesize + 1
+                                    rulehash[rulesize] = ruledata
+                                    rulehash.n = rulesize -- tiny speedup
+                                    --
+                                    if true then -- nofrules > 1
+
+                                        for unic in next, sequence[start] do
+                                            local cu = coverage[unic]
+                                            if cu then
+                                                local n = #cu+1
+                                                cu[n] = ruledata
+                                                cu.n = n
+                                            else
+                                                coverage[unic] = { ruledata, n = 1 }
+                                            end
+                                        end
+
+                                    else
+
+                                        for unic in next, sequence[start] do
+                                            local cu = coverage[unic]
+                                            if cu then
+                                                -- we can have a contextchains with many matches which we
+                                                -- can actually optimize
+                                            else
+                                                coverage[unic] = rulehash
+                                            end
                                         end
+
                                     end
-                                    rulehash.n = rulesize -- tiny speedup
                                 end
                             end
                         end
                     end
+
+                    checkmerge(sequence)
+                    checkflags(sequence,resources)
+                    checksteps(sequence)
+
                 end
             end
         end
diff --git a/tex/context/base/mkiv/math-ali.mkiv b/tex/context/base/mkiv/math-ali.mkiv
index 40da3d4c9..2b0cc0bc1 100644
--- a/tex/context/base/mkiv/math-ali.mkiv
+++ b/tex/context/base/mkiv/math-ali.mkiv
@@ -831,7 +831,8 @@
 
 \unexpanded\def\math_matrix_start_cell
   {\dostarttagged\t!mathtablecell\empty
-   \math_left_of_equalign
+   \hss
+  %\math_left_of_equalign
    \startimath
    \math_matrix_set_style
    \tabskip\zeropoint
@@ -839,7 +840,8 @@
 
 \unexpanded\def\math_matrix_stop_cell
   {\stopimath
-   \math_right_of_eqalign
+  %\math_right_of_eqalign
+   \hss
    \dostoptagged}
 
 % We could construct a preamble with alignment and such embedded but the number
@@ -1187,25 +1189,22 @@
 %D
 %D \typebuffer which gives \getbuffer
 
+% no tagging yet : how is it supposed to be coded?
+
 \unexpanded\def\startsubstack
   {\begingroup
    \vcenter\bgroup
    \baselineskip\mathstacktotal
    \lineskip\mathstackvgap
    \lineskiplimit\lineskip
-   \let\stopmathmode\relax
-   \def\NC{\math_matrix_NC}%
-   \def\MC{\math_matrix_NC\startmathmode}%
-   \global\let\math_matrix_NC\math_matrix_NC_indeed
-   \def\NR
-     {\stopmathmode
-      \global\let\math_matrix_NC\math_matrix_NC_indeed
-      \crcr}%
    \mathsurround\zeropoint
    \everycr\emptytoks
+   \let\NC\relax
+   \let\MC\relax
+   \let\NR\crcr
    \halign\bgroup\hfil\normalstartimath\scriptstyle\alignmark\alignmark\normalstopimath\hfil\crcr}
 
-\def\stopsubstack
+\def\stopsubstack % todo: \unexpanded and delayed
   {\crcr
    \egroup
    \egroup
diff --git a/tex/context/base/mkiv/status-files.pdf b/tex/context/base/mkiv/status-files.pdf
index a91d6f73c..e45d0d6c3 100644
Binary files a/tex/context/base/mkiv/status-files.pdf and b/tex/context/base/mkiv/status-files.pdf differ
diff --git a/tex/context/base/mkiv/status-lua.pdf b/tex/context/base/mkiv/status-lua.pdf
index 89040ffec..59f1db86f 100644
Binary files a/tex/context/base/mkiv/status-lua.pdf and b/tex/context/base/mkiv/status-lua.pdf differ
diff --git a/tex/context/interface/mkii/keys-ro.xml b/tex/context/interface/mkii/keys-ro.xml
index 7f7fc14ad..e0f46ecb5 100644
--- a/tex/context/interface/mkii/keys-ro.xml
+++ b/tex/context/interface/mkii/keys-ro.xml
@@ -759,6 +759,7 @@
 		<cd:constant name='direction' value='directie'/>
 		<cd:constant name='directory' value='director'/>
 		<cd:constant name='display' value='display'/>
+		<cd:constant name='displaythreshold' value='displaythreshold'/>
 		<cd:constant name='distance' value='distanta'/>
 		<cd:constant name='domain' value='domain'/>
 		<cd:constant name='dot' value='punct'/>
@@ -868,6 +869,7 @@
 		<cd:constant name='index' value='index'/>
 		<cd:constant name='indicator' value='indicator'/>
 		<cd:constant name='initialsep' value='initialsep'/>
+		<cd:constant name='inlinethreshold' value='inlinethreshold'/>
 		<cd:constant name='inner' value='intern'/>
 		<cd:constant name='innermargin' value='innermargin'/>
 		<cd:constant name='inputfile' value='inputfile'/>
diff --git a/tex/context/interface/mkiv/i-context.pdf b/tex/context/interface/mkiv/i-context.pdf
index 750f687f2..bf72c9fcc 100644
Binary files a/tex/context/interface/mkiv/i-context.pdf and b/tex/context/interface/mkiv/i-context.pdf differ
diff --git a/tex/context/interface/mkiv/i-readme.pdf b/tex/context/interface/mkiv/i-readme.pdf
index 09ceb5d6c..8f5f4a254 100644
Binary files a/tex/context/interface/mkiv/i-readme.pdf and b/tex/context/interface/mkiv/i-readme.pdf differ
diff --git a/tex/context/modules/mkiv/s-fonts-variable.mkiv b/tex/context/modules/mkiv/s-fonts-variable.mkiv
index 69f4a7843..d024ddc05 100644
--- a/tex/context/modules/mkiv/s-fonts-variable.mkiv
+++ b/tex/context/modules/mkiv/s-fonts-variable.mkiv
@@ -72,9 +72,9 @@
         \char983040\relax\par
     \stopbuffer
 
-%     \showfontvariations
-%       [font=file:VotoSerifGX.ttf,
-%        max=6]
+    \showfontvariations
+      [font=file:VotoSerifGX.ttf,
+      ]% max=6]
 
     \showfontvariations
       [font=file:adobevfprototype.otf]
diff --git a/tex/context/modules/mkiv/s-present-lines.mkiv b/tex/context/modules/mkiv/s-present-lines.mkiv
index 6d4c59a03..3a2fdae53 100644
--- a/tex/context/modules/mkiv/s-present-lines.mkiv
+++ b/tex/context/modules/mkiv/s-present-lines.mkiv
@@ -153,7 +153,13 @@
   [state=start,
    color=maincolor,
    contrastcolor=maincolor,
-   style=bold]
+   style=]
+
+\setuptyping
+  [color=maincolor]
+
+\setuptype
+  [color=maincolor]
 
 \usemodule[abr-04]
 
diff --git a/tex/generic/context/luatex/luatex-fonts-merged.lua b/tex/generic/context/luatex/luatex-fonts-merged.lua
index 4bd3958c8..1952a9819 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 : c:/data/develop/context/sources/luatex-fonts-merged.lua
 -- parent file : c:/data/develop/context/sources/luatex-fonts.lua
--- merge date  : 09/08/17 17:24:08
+-- merge date  : 09/15/17 20:03:34
 
 do -- begin closure to overcome local limits and interference
 
@@ -7550,7 +7550,7 @@ if not modules then modules={} end modules ['font-ini']={
 local allocate=utilities.storage.allocate
 fonts=fonts or {}
 local fonts=fonts
-fonts.hashes={ identifiers=allocate() }
+fonts.hashes=fonts.hashes   or { identifiers=allocate() }
 fonts.tables=fonts.tables   or {}
 fonts.helpers=fonts.helpers  or {}
 fonts.tracers=fonts.tracers  or {} 
@@ -7567,6 +7567,38 @@ end -- closure
 
 do -- begin closure to overcome local limits and interference
 
+if not modules then modules={} end modules ['luatex-font-mis']={
+  version=1.001,
+  comment="companion to luatex-*.tex",
+  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
+  copyright="PRAGMA ADE / ConTeXt Development Team",
+  license="see context related readme files"
+}
+if context then
+  texio.write_nl("fatal error: this module is not for context")
+  os.exit()
+end
+local currentfont=font.current
+local hashes=fonts.hashes
+local identifiers=hashes.identifiers or {}
+local marks=hashes.marks    or {}
+hashes.identifiers=identifiers
+hashes.marks=marks
+table.setmetatableindex(marks,function(t,k)
+  if k==true then
+    return marks[currentfont()]
+  else
+    local resources=identifiers[k].resources or {}
+    local marks=resources.marks or {}
+    t[k]=marks
+    return marks
+  end
+end)
+
+end -- closure
+
+do -- begin closure to overcome local limits and interference
+
 if not modules then modules={} end modules ['font-con']={
   version=1.001,
   comment="companion to font-ini.mkiv",
@@ -11087,9 +11119,6 @@ local function readdata(f,offset,specification)
         if factors then
           specification.factors=factors
           fontdata.factors=factors
-          report("factors: % t",factors)
-        else
-          report("bad factors")
         end
       else
       end
@@ -16029,7 +16058,7 @@ do
   end
   local f_lookupname=formatters["%s_%s_%s"]
   local function resolvelookups(f,lookupoffset,fontdata,lookups,lookuptypes,lookuphandlers,what,tableoffset)
-    local sequences=fontdata.sequences  or {}
+    local sequences=fontdata.sequences or {}
     local sublookuplist=fontdata.sublookups or {}
     fontdata.sequences=sequences
     fontdata.sublookups=sublookuplist
@@ -16044,6 +16073,7 @@ do
     local nofglyphs=fontdata.nofglyphs or #glyphs
     local noflookups=#lookups
     local lookupprefix=sub(what,2,2)
+    local usedlookups=false
     for lookupid=1,noflookups do
       local lookup=lookups[lookupid]
       local lookuptype=lookup.type
@@ -16107,12 +16137,25 @@ do
                         current[i]=tohash(current[i])
                       end
                     end
+                  else
                   end
                   if after then
                     for i=1,#after do
                       after[i]=tohash(after[i])
                     end
                   end
+                  if usedlookups then
+                    local lookups=rule.lookups
+                    if lookups then
+                      for k,v in next,lookups do
+                        if v then
+                          for k,v in next,v do
+                            usedlookups[v]=usedlookups[v]+1
+                          end
+                        end
+                      end
+                    end
+                  end
                 end
               end
             end
@@ -16159,6 +16202,9 @@ do
         report("no handler for lookup %a with type %a",lookupid,lookuptype)
       end
     end
+    if usedlookups then
+      report("used %s lookups: % t",what,sortedkeys(usedlookups))
+    end
     local reported={}
     local function report_issue(i,what,sequence,kind)
       local name=sequence.name
@@ -16200,7 +16246,7 @@ do
                           local d=lookup.done
                           if d then
                             nofsublookups=nofsublookups+1
-                            h={
+                            local l={
                               index=nofsublookups,
                               name=f_lookupname(lookupprefix,"d",lookupid+lookupidoffset),
                               derived=true,
@@ -16210,7 +16256,7 @@ do
                               markclass=d.markclass or nil,
                               flags=d.flags,
                             }
-                            sublookuplist[nofsublookups]=copy(h) 
+                            sublookuplist[nofsublookups]=copy(l) 
                             sublookuphash[lookupid]=nofsublookups
                             sublookupcheck[lookupid]=1
                             h=nofsublookups
@@ -19606,9 +19652,6 @@ function readers.expand(data)
               sequence.markclass=markclasses[markclass]
             end
           end
-          checkmerge(sequence)
-          checkflags(sequence,resources)
-          checksteps(sequence)
           for i=1,nofsteps do
             local step=steps[i]
             local baseclasses=step.baseclasses
@@ -19625,13 +19668,14 @@ function readers.expand(data)
             end
             local rules=step.rules
             if rules then
-              local rulehash={ n=0 }
+              local rulehash={ n=0 } 
               local rulesize=0
               local coverage={}
               local lookuptype=sequence.type
+              local nofrules=#rules
               step.coverage=coverage 
-              for nofrules=1,#rules do
-                local rule=rules[nofrules]
+              for currentrule=1,nofrules do
+                local rule=rules[currentrule]
                 local current=rule.current
                 local before=rule.before
                 local after=rule.after
@@ -19662,7 +19706,7 @@ function readers.expand(data)
                   for i=1,#lookups do
                     local lookups=lookups[i]
                     if lookups then
-                      for k,v in next,lookups do
+                      for k,v in next,lookups do 
                         local lookup=sublookups[v]
                         if lookup then
                           lookups[k]=lookup
@@ -19677,9 +19721,8 @@ function readers.expand(data)
                 end
                 if sequence[1] then 
                   sequence.n=#sequence 
-                  rulesize=rulesize+1
-                  rulehash[rulesize]={
-                    nofrules,
+                  local ruledata={
+                    currentrule,
                     lookuptype,
                     sequence,
                     start,
@@ -19688,18 +19731,36 @@ function readers.expand(data)
                     replacements,
                     subtype,
                   }
-                  for unic in next,sequence[start] do
-                    local cu=coverage[unic]
-                    if not cu then
-                      coverage[unic]=rulehash 
-                    else
+                  rulesize=rulesize+1
+                  rulehash[rulesize]=ruledata
+                  rulehash.n=rulesize
+                  if true then 
+                    for unic in next,sequence[start] do
+                      local cu=coverage[unic]
+                      if cu then
+                        local n=#cu+1
+                        cu[n]=ruledata
+                        cu.n=n
+                      else
+                        coverage[unic]={ ruledata,n=1 }
+                      end
+                    end
+                  else
+                    for unic in next,sequence[start] do
+                      local cu=coverage[unic]
+                      if cu then
+                      else
+                        coverage[unic]=rulehash
+                      end
                     end
                   end
-                  rulehash.n=rulesize 
                 end
               end
             end
           end
+          checkmerge(sequence)
+          checkflags(sequence,resources)
+          checksteps(sequence)
         end
       end
     end
@@ -20875,6 +20936,7 @@ local attributes,nodes,node=attributes,nodes,node
 fonts=fonts
 local hashes=fonts.hashes
 local fontdata=hashes.identifiers
+local fontmarks=hashes.marks
 nodes.injections=nodes.injections or {}
 local injections=nodes.injections
 local tracers=nodes.tracers
@@ -20990,7 +21052,7 @@ function injections.copy(target,source)
     end
   end
 end
-function injections.setligaindex(n,index)
+function injections.setligaindex(n,index) 
   local p=rawget(properties,n)
   if p then
     local i=p.injections
@@ -21170,41 +21232,41 @@ function injections.setmove(current,factor,rlmode,x,injection)
     if not injection then
       injection="injections"
     end
-if rlmode and rlmode<0 then
-    if p then
-      local i=p[injection]
-      if i then
-        i.rightkern=dx+(i.rightkern or 0)
+    if rlmode and rlmode<0 then
+      if p then
+        local i=p[injection]
+        if i then
+          i.rightkern=dx+(i.rightkern or 0)
+        else
+          p[injection]={
+            rightkern=dx,
+          }
+        end
       else
-        p[injection]={
-          rightkern=dx,
+        properties[current]={
+          [injection]={
+            rightkern=dx,
+          },
         }
       end
     else
-      properties[current]={
-        [injection]={
-          rightkern=dx,
-        },
-      }
-    end
-else
-    if p then
-      local i=p[injection]
-      if i then
-        i.leftkern=dx+(i.leftkern or 0)
+      if p then
+        local i=p[injection]
+        if i then
+          i.leftkern=dx+(i.leftkern or 0)
+        else
+          p[injection]={
+            leftkern=dx,
+          }
+        end
       else
-        p[injection]={
-          leftkern=dx,
+        properties[current]={
+          [injection]={
+            leftkern=dx,
+          },
         }
       end
-    else
-      properties[current]={
-        [injection]={
-          leftkern=dx,
-        },
-      }
     end
-end
     return dx,nofregisteredkerns
   else
     return 0,0
@@ -21222,9 +21284,15 @@ function injections.setmark(start,base,factor,rlmode,ba,ma,tfmbase,mkmk,checkmar
     if i then
       if i.markmark then
       else
-        i.markx=dx
-        i.marky=dy
-        i.markdir=rlmode or 0
+        if dx~=0 then
+          i.markx=dx
+        end
+        if y~=0 then
+          i.marky=dy
+        end
+        if rlmode then
+          i.markdir=rlmode
+        end
         i.markbase=nofregisteredmarks
         i.markbasenode=base
         i.markmark=mkmk
@@ -21530,12 +21598,12 @@ local function inject_positions_only(head,where)
           local leftkern=i.leftkern
           local rightkern=i.rightkern
           if leftkern and leftkern~=0 then
-if rightkern and leftkern==-rightkern then
-  setoffsets(current,leftkern,false)
-  rightkern=0
-else
-            head=insert_node_before(head,current,fontkern(leftkern))
-end
+            if rightkern and leftkern==-rightkern then
+              setoffsets(current,leftkern,false)
+              rightkern=0
+            else
+              head=insert_node_before(head,current,fontkern(leftkern))
+            end
           end
           if rightkern and rightkern~=0 then
             insert_node_after(head,current,fontkern(rightkern))
@@ -21762,14 +21830,14 @@ local function inject_everything(head,where)
         rightkern=pp.rightkern
       end
     end
+    local markdir=pn.markdir
     if rightkern then 
-      if pn.markdir<0 then
-        ox=px-pn.markx-rightkern
+      ox=px-(pn.markx or 0)-rightkern
+      if markdir and markdir<0 then
         if not pn.markmark then
           ox=ox+(pn.leftkern or 0)
         end
       else
-        ox=px-pn.markx-rightkern 
         if false then
           local leftkern=pp.leftkern
           if leftkern then
@@ -21778,16 +21846,14 @@ local function inject_everything(head,where)
         end
       end
     else
-      if pn.markdir<0 then
-        ox=px-pn.markx
+      ox=px-(pn.markx or 0)
+      if markdir and markdir<0 then
         if not pn.markmark then
           local leftkern=pn.leftkern
           if leftkern then
             ox=ox+leftkern 
           end
         end
-      else
-        ox=px-pn.markx
       end
       if pn.checkmark then
         local wn=getwidth(n) 
@@ -21801,7 +21867,7 @@ local function inject_everything(head,where)
         end
       end
     end
-    local oy=ny+py+pn.marky
+    local oy=ny+py+(pn.marky or 0)
     if not pn.markmark then
       local yoffset=pn.yoffset
       if yoffset then
@@ -21813,15 +21879,64 @@ local function inject_everything(head,where)
       showoffset(n,true)
     end
   end
+  local base=nil
   while current do
     local next=getnext(current)
     local char,id=ischar(current)
     if char then
       local p=rawget(properties,current)
+      if hascursives then
+        if not p then
+          local m=fontmarks[getfont(current)]
+          if m and m[char] then
+            if base then
+              p={ injections={ markbasenode=base } }
+              nofmarks=nofmarks+1
+              marks[nofmarks]=current
+              properties[current]=p
+              hasmarks=true
+            end
+          else
+            base=current
+          end
+        end
+      end
       if p then
         local i=p.injections
+        if hascursives then
+          if not i then
+            local m=fontmarks[getfont(current)]
+            if m and m[char] then
+              if base then
+                i={ markbasenode=base }
+                nofmarks=nofmarks+1
+                marks[nofmarks]=current
+                p.injections=i
+                hasmarks=true
+              end
+            else
+              base=current
+            end
+          end
+        end
         if i then
           local pm=i.markbasenode
+          if hascursives then
+            if not pm then
+              local m=fontmarks[getfont(current)]
+              if m and m[char] then
+                if base then
+                  pm=base
+                  i.markbasenode=pm
+                  hasmarks=true
+                end
+              else
+                base=current
+              end
+            else
+              base=current
+            end
+          end
           if pm then
             nofmarks=nofmarks+1
             marks[nofmarks]=current
@@ -21884,12 +21999,12 @@ local function inject_everything(head,where)
             local leftkern=i.leftkern
             local rightkern=i.rightkern
             if leftkern and leftkern~=0 then
-if rightkern and leftkern==-rightkern then
-  setoffsets(current,leftkern,false)
-  rightkern=0
-else
-              head=insert_node_before(head,current,fontkern(leftkern))
-end
+              if rightkern and leftkern==-rightkern then
+                setoffsets(current,leftkern,false)
+                rightkern=0
+              else
+                head=insert_node_before(head,current,fontkern(leftkern))
+              end
             end
             if rightkern and rightkern~=0 then
               insert_node_after(head,current,fontkern(rightkern))
@@ -22092,6 +22207,7 @@ end
     else
       prevglyph=nil
       prevdisc=nil
+base=nil
     end
     prev=current
     current=next
@@ -22226,23 +22342,25 @@ local function injectspaces(head)
       if old>threshold then
         if rightkern then
           if useitalickerns then
-            local new=old+(leftkern+rightkern)*factor
+            local lnew=leftkern*factor
+            local rnew=rightkern*factor
             if trace_spaces then
-              report_spaces("%C [%p -> %p] %C",prevchar,old,new,nextchar)
+              report_spaces("%C [%p + %p + %p] %C",prevchar,lnew,old,rnew,nextchar)
             end
-            setwidth(n,new)
-          else
-            local new=(leftkern+rightkern)*factor
-            if trace_spaces then
-              report_spaces("%C [%p + %p] %C",prevchar,old,new,nextchar)
-            end
-            local h=insert_node_before(nuthead,n,italickern(new))
+            local h=insert_node_before(nuthead,n,italickern(lnew))
             if h==nuthead then
               head=tonode(h)
               nuthead=h
             end
+            insert_node_after(nuthead,n,italickern(rnew))
+          else
+            local new=old+(leftkern+rightkern)*factor
+            if trace_spaces then
+              report_spaces("%C [%p -> %p] %C",prevchar,old,new,nextchar)
+            end
+            setwidth(n,new)
           end
-          leftkern=false
+          rightkern=false
         else
           if useitalickerns then
             local new=leftkern*factor
@@ -22263,11 +22381,19 @@ local function injectspaces(head)
     elseif rightkern then
       local old=getwidth(n)
       if old>threshold then
-        local new=old+rightkern*factor
-        if trace_spaces then
-          report_spaces("[%p -> %p] %C",nextchar,old,new)
+        if useitalickerns then
+          local new=rightkern*factor
+          if trace_spaces then
+            report_spaces("%C [%p + %p]",nextchar,old,new)
+          end
+          insert_node_after(nuthead,n,italickern(new))
+        else
+          local new=old+rightkern*factor
+          if trace_spaces then
+            report_spaces("[%p -> %p] %C",nextchar,old,new)
+          end
+          setwidth(n,new)
         end
-        setwidth(n,new)
       end
       rightkern=false
     end
@@ -23037,7 +23163,7 @@ local function toligature(head,start,stop,char,dataset,sequence,skiphash,discfou
           logwarning("%s: keep mark %s, gets index %s",pref(dataset,sequence),gref(char),getligaindex(start))
         end
         local n=copy_node(start)
-        copyinjection(n,start)
+        copyinjection(n,start) 
         head,current=insert_node_after(head,current,n) 
       elseif trace_marks then
         logwarning("%s: delete mark %s",pref(dataset,sequence),gref(char))
@@ -24598,233 +24724,112 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode,s
   local startprev,
      startnext=getboth(start)
   local done
-  for k=1,contexts.n do 
-    local current=start
-    local last=start
+  local nofcontexts=contexts.n 
+  local startchar=nofcontext==1 or ischar(start,currentfont) 
+  for k=1,nofcontexts do
     local ck=contexts[k]
     local seq=ck[3]
-    local s=seq.n
-    if s==1 then
-      local char=ischar(current,currentfont)
-      if char and not seq[1][char] then
-        goto next
-      end
-    else
-      local f=ck[4]
-      local l=ck[5]
-      if l>f then
-        local discfound 
-        local n=f+1
-        last=startnext 
-        while n<=l do
-          if postreplace and not last then
-            last=getnext(sweepnode)
-            sweeptype=nil
-          end
-          if last then
-            local char,id=ischar(last,currentfont)
-            if char then
-              if skiphash and skiphash[char] then
-                skipped=true
-                if trace_skips then
-                  show_skip(dataset,sequence,char,ck,classes[char])
-                end
+    local f=ck[4] 
+    if not startchar or not seq[f][startchar] then
+      goto next
+    end
+    local s=seq.n 
+    local l=ck[5] 
+    local current=start
+    local last=start
+    if l>f then
+      local discfound 
+      local n=f+1
+      last=startnext 
+      while n<=l do
+        if postreplace and not last then
+          last=getnext(sweepnode)
+          sweeptype=nil
+        end
+        if last then
+          local char,id=ischar(last,currentfont)
+          if char then
+            if skiphash and skiphash[char] then
+              skipped=true
+              if trace_skips then
+                show_skip(dataset,sequence,char,ck,classes[char])
+              end
+              last=getnext(last)
+            elseif seq[n][char] then
+              if n<l then
                 last=getnext(last)
-              elseif seq[n][char] then
-                if n<l then
-                  last=getnext(last)
-                end
-                n=n+1
-              elseif discfound then
-                notmatchreplace[discfound]=true
-                if notmatchpre[discfound] then
-                  goto next
-                else
-                  break
-                end
-              else
-                goto next
               end
-            elseif char==false then
-              if discfound then
-                notmatchreplace[discfound]=true
-                if notmatchpre[discfound] then
-                  goto next
-                else
-                  break
-                end
+              n=n+1
+            elseif discfound then
+              notmatchreplace[discfound]=true
+              if notmatchpre[discfound] then
+                goto next
               else
+                break
+              end
+            else
+              goto next
+            end
+          elseif char==false then
+            if discfound then
+              notmatchreplace[discfound]=true
+              if notmatchpre[discfound] then
                 goto next
+              else
+                break
               end
-            elseif id==disc_code then
-              diskseen=true
-              discfound=last
-              notmatchpre[last]=nil
-              notmatchpost[last]=true
-              notmatchreplace[last]=nil
-              local pre,post,replace=getdisc(last)
-              if pre then
-                local n=n
-                while pre do
-                  if seq[n][getchar(pre)] then
-                    n=n+1
-                    if n>l then
-                      break
-                    end
-                    pre=getnext(pre)
-                  else
-                    notmatchpre[last]=true
+            else
+              goto next
+            end
+          elseif id==disc_code then
+            diskseen=true
+            discfound=last
+            notmatchpre[last]=nil
+            notmatchpost[last]=true
+            notmatchreplace[last]=nil
+            local pre,post,replace=getdisc(last)
+            if pre then
+              local n=n
+              while pre do
+                if seq[n][getchar(pre)] then
+                  n=n+1
+                  if n>l then
                     break
                   end
-                end
-                if n<=l then
+                  pre=getnext(pre)
+                else
                   notmatchpre[last]=true
+                  break
                 end
-              else
-                notmatchpre[last]=true
               end
-              if replace then
-                while replace do
-                  if seq[n][getchar(replace)] then
-                    n=n+1
-                    if n>l then
-                      break
-                    end
-                    replace=getnext(replace)
-                  else
-                    notmatchreplace[last]=true
-                    if notmatchpre[last] then
-                      goto next
-                    else
-                      break
-                    end
-                  end
-                end
-                if notmatchpre[last] then
-                  goto next
-                end
+              if n<=l then
+                notmatchpre[last]=true
               end
-              last=getnext(last)
             else
-              goto next
+              notmatchpre[last]=true
             end
-          else
-            goto next
-          end
-        end
-      end
-      if f>1 then
-        if startprev then
-          local prev=startprev
-          if prereplace and prev==checkdisc then
-            prev=getprev(sweepnode)
-          end
-          if prev then
-            local discfound 
-            local n=f-1
-            while n>=1 do
-              if prev then
-                local char,id=ischar(prev,currentfont)
-                if char then
-                  if skiphash and skiphash[char] then
-                    skipped=true
-                    if trace_skips then
-                      show_skip(dataset,sequence,char,ck,classes[char])
-                    end
-                    prev=getprev(prev)
-                  elseif seq[n][char] then
-                    if n>1 then
-                      prev=getprev(prev)
-                    end
-                    n=n-1
-                  elseif discfound then
-                    notmatchreplace[discfound]=true
-                    if notmatchpost[discfound] then
-                      goto next
-                    else
-                      break
-                    end
-                  else
-                    goto next
+            if replace then
+              while replace do
+                if seq[n][getchar(replace)] then
+                  n=n+1
+                  if n>l then
+                    break
                   end
-                elseif char==false then
-                  if discfound then
-                    notmatchreplace[discfound]=true
-                    if notmatchpost[discfound] then
-                      goto next
-                    end
-                  else
+                  replace=getnext(replace)
+                else
+                  notmatchreplace[last]=true
+                  if notmatchpre[last] then
                     goto next
-                  end
-                  break
-                elseif id==disc_code then
-                  diskseen=true
-                  discfound=prev
-                  notmatchpre[prev]=true
-                  notmatchpost[prev]=nil
-                  notmatchreplace[prev]=nil
-                  local pre,post,replace,pretail,posttail,replacetail=getdisc(prev,true)
-                  if pre~=start and post~=start and replace~=start then
-                    if post then
-                      local n=n
-                      while posttail do
-                        if seq[n][getchar(posttail)] then
-                          n=n-1
-                          if posttail==post or n<1 then
-                            break
-                          else
-                            posttail=getprev(posttail)
-                          end
-                        else
-                          notmatchpost[prev]=true
-                          break
-                        end
-                      end
-                      if n>=1 then
-                        notmatchpost[prev]=true
-                      end
-                    else
-                      notmatchpost[prev]=true
-                    end
-                    if replace then
-                      while replacetail do
-                        if seq[n][getchar(replacetail)] then
-                          n=n-1
-                          if replacetail==replace or n<1 then
-                            break
-                          else
-                            replacetail=getprev(replacetail)
-                          end
-                        else
-                          notmatchreplace[prev]=true
-                          if notmatchpost[prev] then
-                            goto next
-                          else
-                            break
-                          end
-                        end
-                      end
-                    end
-                  end
-                  prev=getprev(prev)
-                elseif id==glue_code then
-                  local sn=seq[n]
-                  if (sn[32] and spaces[prev]) or sn[0xFFFC] then
-                    n=n-1
-                    prev=getprev(prev)
                   else
-                    goto next
+                    break
                   end
-                elseif seq[n][0xFFFC] then
-                  n=n-1
-                  prev=getprev(prev)
-                else
-                  goto next
                 end
-              else
+              end
+              if notmatchpre[last] then
                 goto next
               end
             end
+            last=getnext(last)
           else
             goto next
           end
@@ -24832,32 +24837,34 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode,s
           goto next
         end
       end
-      if s>l then
-        local current=last and getnext(last)
-        if not current and postreplace then
-          current=getnext(sweepnode)
+    end
+    if f>1 then
+      if startprev then
+        local prev=startprev
+        if prereplace and prev==checkdisc then
+          prev=getprev(sweepnode)
         end
-        if current then
+        if prev then
           local discfound 
-          local n=l+1
-          while n<=s do
-            if current then
-              local char,id=ischar(current,currentfont)
+          local n=f-1
+          while n>=1 do
+            if prev then
+              local char,id=ischar(prev,currentfont)
               if char then
                 if skiphash and skiphash[char] then
                   skipped=true
                   if trace_skips then
                     show_skip(dataset,sequence,char,ck,classes[char])
                   end
-                  current=getnext(current) 
+                  prev=getprev(prev)
                 elseif seq[n][char] then
-                  if n<s then 
-                    current=getnext(current) 
+                  if n>1 then
+                    prev=getprev(prev)
                   end
-                  n=n+1
+                  n=n-1
                 elseif discfound then
                   notmatchreplace[discfound]=true
-                  if notmatchpre[discfound] then
+                  if notmatchpost[discfound] then
                     goto next
                   else
                     break
@@ -24868,74 +24875,74 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode,s
               elseif char==false then
                 if discfound then
                   notmatchreplace[discfound]=true
-                  if notmatchpre[discfound] then
+                  if notmatchpost[discfound] then
                     goto next
-                  else
-                    break
                   end
                 else
                   goto next
                 end
+                break
               elseif id==disc_code then
                 diskseen=true
-                discfound=current
-                notmatchpre[current]=nil
-                notmatchpost[current]=true
-                notmatchreplace[current]=nil
-                local pre,post,replace=getdisc(current)
-                if pre then
-                  local n=n
-                  while pre do
-                    if seq[n][getchar(pre)] then
-                      n=n+1
-                      if n>s then
-                        break
+                discfound=prev
+                notmatchpre[prev]=true
+                notmatchpost[prev]=nil
+                notmatchreplace[prev]=nil
+                local pre,post,replace,pretail,posttail,replacetail=getdisc(prev,true)
+                if pre~=start and post~=start and replace~=start then
+                  if post then
+                    local n=n
+                    while posttail do
+                      if seq[n][getchar(posttail)] then
+                        n=n-1
+                        if posttail==post or n<1 then
+                          break
+                        else
+                          posttail=getprev(posttail)
+                        end
                       else
-                        pre=getnext(pre)
+                        notmatchpost[prev]=true
+                        break
                       end
-                    else
-                      notmatchpre[current]=true
-                      break
                     end
+                    if n>=1 then
+                      notmatchpost[prev]=true
+                    end
+                  else
+                    notmatchpost[prev]=true
                   end
-                  if n<=s then
-                    notmatchpre[current]=true
-                  end
-                else
-                  notmatchpre[current]=true
-                end
-                if replace then
-                  while replace do
-                    if seq[n][getchar(replace)] then
-                      n=n+1
-                      if n>s then
-                        break
-                      else
-                        replace=getnext(replace)
-                      end
-                    else
-                      notmatchreplace[current]=true
-                      if not notmatchpre[current] then
-                        goto next
+                  if replace then
+                    while replacetail do
+                      if seq[n][getchar(replacetail)] then
+                        n=n-1
+                        if replacetail==replace or n<1 then
+                          break
+                        else
+                          replacetail=getprev(replacetail)
+                        end
                       else
-                        break
+                        notmatchreplace[prev]=true
+                        if notmatchpost[prev] then
+                          goto next
+                        else
+                          break
+                        end
                       end
                     end
                   end
-                else
                 end
-                current=getnext(current)
+                prev=getprev(prev)
               elseif id==glue_code then
                 local sn=seq[n]
-                if (sn[32] and spaces[current]) or sn[0xFFFC] then
-                  n=n+1
-                  current=getnext(current)
+                if (sn[32] and spaces[prev]) or sn[0xFFFC] then
+                  n=n-1
+                  prev=getprev(prev)
                 else
                   goto next
                 end
               elseif seq[n][0xFFFC] then
-                n=n+1
-                current=getnext(current)
+                n=n-1
+                prev=getprev(prev)
               else
                 goto next
               end
@@ -24946,6 +24953,123 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode,s
         else
           goto next
         end
+      else
+        goto next
+      end
+    end
+    if s>l then
+      local current=last and getnext(last)
+      if not current and postreplace then
+        current=getnext(sweepnode)
+      end
+      if current then
+        local discfound 
+        local n=l+1
+        while n<=s do
+          if current then
+            local char,id=ischar(current,currentfont)
+            if char then
+              if skiphash and skiphash[char] then
+                skipped=true
+                if trace_skips then
+                  show_skip(dataset,sequence,char,ck,classes[char])
+                end
+                current=getnext(current) 
+              elseif seq[n][char] then
+                if n<s then 
+                  current=getnext(current) 
+                end
+                n=n+1
+              elseif discfound then
+                notmatchreplace[discfound]=true
+                if notmatchpre[discfound] then
+                  goto next
+                else
+                  break
+                end
+              else
+                goto next
+              end
+            elseif char==false then
+              if discfound then
+                notmatchreplace[discfound]=true
+                if notmatchpre[discfound] then
+                  goto next
+                else
+                  break
+                end
+              else
+                goto next
+              end
+            elseif id==disc_code then
+              diskseen=true
+              discfound=current
+              notmatchpre[current]=nil
+              notmatchpost[current]=true
+              notmatchreplace[current]=nil
+              local pre,post,replace=getdisc(current)
+              if pre then
+                local n=n
+                while pre do
+                  if seq[n][getchar(pre)] then
+                    n=n+1
+                    if n>s then
+                      break
+                    else
+                      pre=getnext(pre)
+                    end
+                  else
+                    notmatchpre[current]=true
+                    break
+                  end
+                end
+                if n<=s then
+                  notmatchpre[current]=true
+                end
+              else
+                notmatchpre[current]=true
+              end
+              if replace then
+                while replace do
+                  if seq[n][getchar(replace)] then
+                    n=n+1
+                    if n>s then
+                      break
+                    else
+                      replace=getnext(replace)
+                    end
+                  else
+                    notmatchreplace[current]=true
+                    if not notmatchpre[current] then
+                      goto next
+                    else
+                      break
+                    end
+                  end
+                end
+              else
+              end
+              current=getnext(current)
+            elseif id==glue_code then
+              local sn=seq[n]
+              if (sn[32] and spaces[current]) or sn[0xFFFC] then
+                n=n+1
+                current=getnext(current)
+              else
+                goto next
+              end
+            elseif seq[n][0xFFFC] then
+              n=n+1
+              current=getnext(current)
+            else
+              goto next
+            end
+          else
+            goto next
+          end
+        end
+      else
+        goto next
       end
     end
     if trace_contexts then
@@ -29051,10 +29175,10 @@ local function addfeature(data,feature,specifications)
                   subtype=lookup.type
                 end
               else
-                lookups[k]={ false } 
+                lookups[k]=false 
               end
             else
-              lookups[k]={ false } 
+              lookups[k]=false 
             end
           end
         end
diff --git a/tex/generic/context/luatex/luatex-fonts-mis.lua b/tex/generic/context/luatex/luatex-fonts-mis.lua
new file mode 100644
index 000000000..02a5b60db
--- /dev/null
+++ b/tex/generic/context/luatex/luatex-fonts-mis.lua
@@ -0,0 +1,32 @@
+if not modules then modules = { } end modules ['luatex-font-mis'] = {
+    version   = 1.001,
+    comment   = "companion to luatex-*.tex",
+    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+    copyright = "PRAGMA ADE / ConTeXt Development Team",
+    license   = "see context related readme files"
+}
+
+if context then
+    texio.write_nl("fatal error: this module is not for context")
+    os.exit()
+end
+
+local currentfont  = font.current
+
+local hashes       = fonts.hashes
+local identifiers  = hashes.identifiers or { }
+local marks        = hashes.marks       or { }
+
+hashes.identifiers = identifiers
+hashes.marks       = marks
+
+table.setmetatableindex(marks,function(t,k)
+    if k == true then
+        return marks[currentfont()]
+    else
+        local resources = identifiers[k].resources or { }
+        local marks = resources.marks or { }
+        t[k] = marks
+        return marks
+    end
+end)
diff --git a/tex/generic/context/luatex/luatex-fonts.lua b/tex/generic/context/luatex/luatex-fonts.lua
index 93ead749e..ef3bb74dc 100644
--- a/tex/generic/context/luatex/luatex-fonts.lua
+++ b/tex/generic/context/luatex/luatex-fonts.lua
@@ -219,6 +219,7 @@ if non_generic_context.luatex_fonts.skip_loading ~= true then
         -- --reload --force --simple option).
 
         loadmodule('font-ini.lua')
+        loadmodule('luatex-fonts-mis.lua')
         loadmodule('font-con.lua')
         loadmodule('luatex-fonts-enc.lua') -- will load font-age on demand
         loadmodule('font-cid.lua')
-- 
cgit v1.2.3