summaryrefslogtreecommitdiff
path: root/tex/context/base/mkiv/node-fnt.lua
diff options
context:
space:
mode:
authorHans Hagen <pragma@wxs.nl>2018-05-12 01:19:03 +0200
committerContext Git Mirror Bot <phg42.2a@gmail.com>2018-05-12 01:19:03 +0200
commit77e216e323271fb85d508b7206b13c980540b74b (patch)
tree5b4053c2bbe5190e28c0dce89653c7b13aea0642 /tex/context/base/mkiv/node-fnt.lua
parentd817aef76ab8b606c02bd0636661b634b43a68a6 (diff)
downloadcontext-77e216e323271fb85d508b7206b13c980540b74b.tar.gz
2018-05-12 00:16:00
Diffstat (limited to 'tex/context/base/mkiv/node-fnt.lua')
-rw-r--r--tex/context/base/mkiv/node-fnt.lua432
1 files changed, 378 insertions, 54 deletions
diff --git a/tex/context/base/mkiv/node-fnt.lua b/tex/context/base/mkiv/node-fnt.lua
index f846f996d..044be8ca8 100644
--- a/tex/context/base/mkiv/node-fnt.lua
+++ b/tex/context/base/mkiv/node-fnt.lua
@@ -40,8 +40,6 @@ local nodecodes = nodes.nodecodes
local handlers = nodes.handlers
local nuts = nodes.nuts
-local tonut = nuts.tonut
-local tonode = nuts.tonode
local getattr = nuts.getattr
local getid = nuts.getid
@@ -62,9 +60,12 @@ local setprev = nuts.setprev
local isglyph = nuts.isglyph -- unchecked
local ischar = nuts.ischar -- checked
-local traverse_id = nuts.traverse_id
-local traverse_char = nuts.traverse_char
-local protect_glyph = nuts.protect_glyph
+----- traverse_id = nuts.traverse_id
+----- traverse_char = nuts.traverse_char
+local nextboundary = nuts.traversers.boundary
+local nextdisc = nuts.traversers.disc
+local nextchar = nuts.traversers.char
+
local flush_node = nuts.flush
local disc_code = nodecodes.disc
@@ -172,7 +173,7 @@ local function start_trace(head)
report_fonts()
report_fonts("checking node list, run %s",run)
report_fonts()
- local n = tonut(head)
+ local n = head
while n do
local char, id = isglyph(n)
if char then
@@ -212,10 +213,8 @@ function handlers.characters(head,groupcode,size,packtype,direction)
local basefont = nil
local prevfont = nil
local prevattr = 0
- local done = false
local variants = nil
local redundant = nil
- local nuthead = tonut(head)
local lastfont = nil
local lastproc = nil
local lastnone = nil
@@ -296,7 +295,7 @@ function handlers.characters(head,groupcode,size,packtype,direction)
end
end
- for n in traverse_char(nuthead) do
+ for n in nextchar, head do
local font = getfont(n)
-- local attr = (none and prevattr) or getattr(n,0) or 0 -- zero attribute is reserved for fonts in context
local attr = getattr(n,0) or 0 -- zero attribute is reserved for fonts in context
@@ -361,7 +360,7 @@ function handlers.characters(head,groupcode,size,packtype,direction)
-- but we need to get rid of those nodes in order to build ligatures
-- and kern (a rather context thing)
- for b in traverse_id(boundary_code,nuthead) do
+ for b in nextboundary, head do
if getsubtype(b) == word_boundary then
if redundant then
r = r + 1
@@ -379,8 +378,8 @@ function handlers.characters(head,groupcode,size,packtype,direction)
for i=1,r do
local r = redundant[i]
local p, n = getboth(r)
- if r == nuthead then
- nuthead = n
+ if r == head then
+ head = n
setprev(n)
else
setlink(p,n)
@@ -411,7 +410,7 @@ function handlers.characters(head,groupcode,size,packtype,direction)
-- basefont is not supported in disc only runs ... it would mean a lot of
-- ranges .. we could try to run basemode as a separate processor run but
-- not for now (we can consider it when the new node code is tested
- for d in traverse_id(disc_code,nuthead) do
+ for d in nextdisc, head do
-- we could use first_glyph, only doing replace is good enough because
-- pre and post are normally used for hyphens and these come from fonts
-- that part of the hyphenated word
@@ -420,7 +419,7 @@ function handlers.characters(head,groupcode,size,packtype,direction)
local prevfont = nil
local prevattr = nil
local none = false
- for n in traverse_char(r) do
+ for n in nextchar, r do
local font = getfont(n)
local attr = getattr(n,0) or 0 -- zero attribute is reserved for fonts in context
if font ~= prevfont or attr ~= prevattr then
@@ -466,26 +465,14 @@ function handlers.characters(head,groupcode,size,packtype,direction)
elseif u == 1 then
local attr = a > 0 and 0 or false -- 0 is the savest way
for i=1,#lastproc do
- local h, d = lastproc[i](head,lastfont,attr,direction)
- if d then
- if h then
- head = h
- end
- done = true
- end
+ head = lastproc[i](head,lastfont,attr,direction)
end
else
-- local attr = a == 0 and false or 0 -- 0 is the savest way
local attr = a > 0 and 0 or false -- 0 is the savest way
for font, processors in next, usedfonts do -- unordered
for i=1,#processors do
- local h, d = processors[i](head,font,attr,direction,u)
- if d then
- if h then
- head = h
- end
- done = true
- end
+ head = processors[i](head,font,attr,direction,u)
end
end
end
@@ -495,26 +482,14 @@ function handlers.characters(head,groupcode,size,packtype,direction)
local font, dynamics = next(attrfonts)
for attribute, processors in next, dynamics do -- unordered, attr can switch in between
for i=1,#processors do
- local h, d = processors[i](head,font,attribute,direction)
- if d then
- if h then
- head = h
- end
- done = true
- end
+ head = processors[i](head,font,attribute,direction)
end
end
else
for font, dynamics in next, attrfonts do
for attribute, processors in next, dynamics do -- unordered, attr can switch in between
for i=1,#processors do
- local h, d = processors[i](head,font,attribute,direction,a)
- if d then
- if h then
- head = h
- end
- done = true
- end
+ head = processors[i](head,font,attribute,direction,a)
end
end
end
@@ -527,7 +502,7 @@ function handlers.characters(head,groupcode,size,packtype,direction)
local start = range[1]
local stop = range[2]
if (start or stop) and (start ~= stop) then
- local front = nuthead == start
+ local front = head == start
if stop then
start = ligaturing(start,stop)
start = kerning(start,stop)
@@ -535,9 +510,8 @@ function handlers.characters(head,groupcode,size,packtype,direction)
start = ligaturing(start)
start = kerning(start)
end
- if front and nuthead ~= start then
- -- nuthead = start
- head = tonode(start)
+ if front and head ~= start then
+ head = start
end
end
else
@@ -547,7 +521,7 @@ function handlers.characters(head,groupcode,size,packtype,direction)
local start = range[1]
local stop = range[2]
if start then -- and start ~= stop but that seldom happens
- local front = nuthead == start
+ local front = head == start
local prev = getprev(start)
local next = getnext(stop)
if stop then
@@ -565,19 +539,369 @@ function handlers.characters(head,groupcode,size,packtype,direction)
setlink(stop,next)
end
-- till here
- if front and nuthead ~= start then
- nuthead = start
- head = tonode(start)
+ if front and head ~= start then
+ head = start
end
end
end
end
stoptiming(nodes)
if trace_characters then
- nodes.report(head,done)
+ nodes.report(head)
+ end
+ return head
+end
+
+if LUATEXVERSION >= 1.090 then
+
+ function handlers.characters(head,groupcode,size,packtype,direction)
+ -- either next or not, but definitely no already processed list
+ starttiming(nodes)
+
+ local usedfonts = { }
+ local attrfonts = { }
+ local basefonts = { }
+ local basefont = nil
+ local prevfont = nil
+ local prevattr = 0
+ local variants = nil
+ local redundant = nil
+ local lastfont = nil
+ local lastproc = nil
+ local lastnone = nil
+
+ local a, u, b, r, e = 0, 0, 0, 0, 0
+
+ if trace_fontrun then
+ start_trace(head)
+ end
+
+ -- There is no gain in checking for a single glyph and then having a fast path. On the
+ -- metafun manual (with some 2500 single char lists) the difference is just noise.
+
+ local function protectnone()
+ protect_glyphs(firstnone,lastnone)
+ firstnone = nil
+ end
+
+ local function setnone(n)
+ if firstnone then
+ protectnone()
+ end
+ if basefont then
+ basefont[2] = getprev(n)
+ basefont = false
+ end
+ if not firstnone then
+ firstnone = n
+ end
+ lastnone = n
+ end
+
+ local function setbase(n)
+ if firstnone then
+ protectnone()
+ end
+ if force_basepass then
+ if basefont then
+ basefont[2] = getprev(n)
+ end
+ b = b + 1
+ basefont = { n, false }
+ basefonts[b] = basefont
+ end
+ end
+
+ local function setnode(n,font,attr) -- we could use prevfont and prevattr when we set then first
+ if firstnone then
+ protectnone()
+ end
+ if basefont then
+ basefont[2] = getprev(n)
+ basefont = false
+ end
+ if attr > 0 then
+ local used = attrfonts[font]
+ if not used then
+ used = { }
+ attrfonts[font] = used
+ end
+ if not used[attr] then
+ local fd = setfontdynamics[font]
+ if fd then
+ used[attr] = fd[attr]
+ a = a + 1
+ end
+ end
+ else
+ local used = usedfonts[font]
+ if not used then
+ lastfont = font
+ lastproc = fontprocesses[font]
+ if lastproc then
+ usedfonts[font] = lastproc
+ u = u + 1
+ end
+ end
+ end
+ end
+
+ for n, char, font in nextchar, head do
+ -- local attr = (none and prevattr) or getattr(n,0) or 0 -- zero attribute is reserved for fonts in context
+ local attr = getattr(n,0) or 0 -- zero attribute is reserved for fonts in context
+ if font ~= prevfont or attr ~= prevattr then
+ prevfont = font
+ prevattr = attr
+ variants = fontvariants[font]
+ local fontmode = fontmodes[font]
+ if fontmode == "none" then
+ setnone(n)
+ elseif fontmode == "base" then
+ setbase(n)
+ else
+ setnode(n,font,attr)
+ end
+ elseif firstnone then
+ lastnone = n
+ end
+ if variants then
+ if char >= 0xFE00 and (char <= 0xFE0F or (char >= 0xE0100 and char <= 0xE01EF)) then
+ local hash = variants[char]
+ if hash then
+ local p = getprev(n)
+ if p then
+ local char = ischar(p) -- checked
+ local variant = hash[char]
+ if variant then
+ if trace_variants then
+ report_fonts("replacing %C by %C",char,variant)
+ end
+ setchar(p,variant)
+ if redundant then
+ r = r + 1
+ redundant[r] = n
+ else
+ r = 1
+ redundant = { n }
+ end
+ end
+ end
+ elseif keep_redundant then
+ -- go on, can be used for tracing
+ elseif redundant then
+ r = r + 1
+ redundant[r] = n
+ else
+ r = 1
+ redundant = { n }
+ end
+ end
+ end
+ end
+
+ if firstnone then
+ protectnone()
+ end
+
+ if force_boundaryrun then
+
+ -- we can inject wordboundaries and then let the hyphenator do its work
+ -- but we need to get rid of those nodes in order to build ligatures
+ -- and kern (a rather context thing)
+
+ for b, subtype in nextboundary, head do
+ if subtype == word_boundary then
+ if redundant then
+ r = r + 1
+ redundant[r] = b
+ else
+ r = 1
+ redundant = { b }
+ end
+ end
+ end
+
+ end
+
+ if redundant then
+ for i=1,r do
+ local r = redundant[i]
+ local p, n = getboth(r)
+ if r == head then
+ head = n
+ setprev(n)
+ else
+ setlink(p,n)
+ end
+ if b > 0 then
+ for i=1,b do
+ local bi = basefonts[i]
+ local b1 = bi[1]
+ local b2 = bi[2]
+ if b1 == b2 then
+ if b1 == r then
+ bi[1] = false
+ bi[2] = false
+ end
+ elseif b1 == r then
+ bi[1] = n
+ elseif b2 == r then
+ bi[2] = p
+ end
+ end
+ end
+ flush_node(r)
+ end
+ end
+
+ if force_discrun then
+
+ -- basefont is not supported in disc only runs ... it would mean a lot of
+ -- ranges .. we could try to run basemode as a separate processor run but
+ -- not for now (we can consider it when the new node code is tested
+ for d in nextdisc, head do
+ -- we could use first_glyph, only doing replace is good enough because
+ -- pre and post are normally used for hyphens and these come from fonts
+ -- that part of the hyphenated word
+ local _, _, r = getdisc(d)
+ if r then
+ local prevfont = nil
+ local prevattr = nil
+ local none = false
+ for n, char, font in nextchar, r do
+ local attr = getattr(n,0) or 0 -- zero attribute is reserved for fonts in context
+ if font ~= prevfont or attr ~= prevattr then
+ prevfont = font
+ prevattr = attr
+ local fontmode = fontmodes[font]
+ if fontmode == "none" then
+ setnone(n)
+ elseif fontmode == "base" then
+ setbase(n)
+ else
+ setnode(n,font,attr)
+ end
+ elseif firstnone then
+ -- lastnone = n
+ lastnone = nil
+ end
+ -- we assume one font for now (and if there are more and we get into issues then
+ -- we can always remove the break)
+ break
+ end
+ if firstnone then
+ protectnone()
+ end
+ -- elseif expanders then
+ -- local subtype = getsubtype(d)
+ -- if subtype == automatic_code or subtype == explicit_code then
+ -- expanders[subtype](d)
+ -- e = e + 1
+ -- end
+ end
+ end
+
+ end
+
+ if trace_fontrun then
+ stop_trace(u,usedfonts,a,attrfonts,b,basefonts,r,redundant,e,expanders)
+ end
+
+ -- in context we always have at least 2 processors
+ if u == 0 then
+ -- skip
+ elseif u == 1 then
+ local attr = a > 0 and 0 or false -- 0 is the savest way
+ for i=1,#lastproc do
+ head = lastproc[i](head,lastfont,attr,direction)
+ end
+ else
+ -- local attr = a == 0 and false or 0 -- 0 is the savest way
+ local attr = a > 0 and 0 or false -- 0 is the savest way
+ for font, processors in next, usedfonts do -- unordered
+ for i=1,#processors do
+ head = processors[i](head,font,attr,direction,u)
+ end
+ end
+ end
+ if a == 0 then
+ -- skip
+ elseif a == 1 then
+ local font, dynamics = next(attrfonts)
+ for attribute, processors in next, dynamics do -- unordered, attr can switch in between
+ for i=1,#processors do
+ head = processors[i](head,font,attribute,direction)
+ end
+ end
+ else
+ for font, dynamics in next, attrfonts do
+ for attribute, processors in next, dynamics do -- unordered, attr can switch in between
+ for i=1,#processors do
+ head = processors[i](head,font,attribute,direction,a)
+ end
+ end
+ end
+ end
+ if b == 0 then
+ -- skip
+ elseif b == 1 then
+ -- only one font
+ local range = basefonts[1]
+ local start = range[1]
+ local stop = range[2]
+ if (start or stop) and (start ~= stop) then
+ local front = head == start
+ if stop then
+ start = ligaturing(start,stop)
+ start = kerning(start,stop)
+ elseif start then -- safeguard
+ start = ligaturing(start)
+ start = kerning(start)
+ end
+ if front and head ~= start then
+ head = start
+ end
+ end
+ else
+ -- multiple fonts
+ for i=1,b do
+ local range = basefonts[i]
+ local start = range[1]
+ local stop = range[2]
+ if start then -- and start ~= stop but that seldom happens
+ local front = head == start
+ local prev = getprev(start)
+ local next = getnext(stop)
+ if stop then
+ start, stop = ligaturing(start,stop)
+ start, stop = kerning(start,stop)
+ else
+ start = ligaturing(start)
+ start = kerning(start)
+ end
+ -- is done automatically
+ if prev then
+ setlink(prev,start)
+ end
+ if next then
+ setlink(stop,next)
+ end
+ -- till here
+ if front and head ~= start then
+ head = start
+ end
+ end
+ end
+ end
+ stoptiming(nodes)
+ if trace_characters then
+ nodes.report(head)
+ end
+ return head
end
- return head, true
+
end
-handlers.protectglyphs = function(n) protect_glyphs (tonut(n)) return n, true end
-handlers.unprotectglyphs = function(n) unprotect_glyphs(tonut(n)) return n, true end
+
+handlers.protectglyphs = protect_glyphs
+handlers.unprotectglyphs = unprotect_glyphs