summaryrefslogtreecommitdiff
path: root/tex/context/base/mkxl/node-fnt.lmt
diff options
context:
space:
mode:
Diffstat (limited to 'tex/context/base/mkxl/node-fnt.lmt')
-rw-r--r--tex/context/base/mkxl/node-fnt.lmt551
1 files changed, 422 insertions, 129 deletions
diff --git a/tex/context/base/mkxl/node-fnt.lmt b/tex/context/base/mkxl/node-fnt.lmt
index 26e1fc343..61a20c628 100644
--- a/tex/context/base/mkxl/node-fnt.lmt
+++ b/tex/context/base/mkxl/node-fnt.lmt
@@ -73,6 +73,7 @@ local wordboundary_code = boundarycodes.word
local protectglyphs = nuts.protectglyphs
local unprotectglyphs = nuts.unprotectglyphs
+local protectglyphsnone = nuts.protectglyphsnone
local setmetatableindex = table.setmetatableindex
@@ -168,64 +169,428 @@ local function stop_trace(u,usedfonts,d,dynamicfonts,b,basefonts,r,redundant)
report_fonts()
end
+-- This is the original handler and we keep it around as reference. It served us
+-- well for quite a while.
+
+-- do
+--
+-- local usedfonts
+-- local dynamicfonts
+-- local basefonts -- could be reused
+-- local basefont
+-- local prevfont
+-- local prevdynamic
+-- local variants
+-- local redundant -- could be reused
+-- local firstnone
+-- local lastfont
+-- local lastproc
+-- local lastnone
+--
+-- local d, u, b, r
+--
+-- local function protectnone()
+-- protectglyphs(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,dynamic) -- we could use prevfont and prevdynamic when we set then first
+-- if firstnone then
+-- protectnone()
+-- end
+-- if basefont then
+-- basefont[2] = getprev(n)
+-- basefont = false
+-- end
+-- if dynamic > 0 then
+-- local used = dynamicfonts[font]
+-- if not used then
+-- used = { }
+-- dynamicfonts[font] = used
+-- end
+-- if not used[dynamic] then
+-- local fd = setfontdynamics[font]
+-- if fd then
+-- used[dynamic] = fd[dynamic]
+-- d = d + 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
+--
+-- function handlers.characters(head,groupcode,direction)
+-- -- either next or not, but definitely no already processed list
+-- starttiming(nodes)
+--
+-- usedfonts = { }
+-- dynamicfonts = { }
+-- basefonts = { }
+-- basefont = nil
+-- prevfont = nil
+-- prevdynamic = 0
+-- variants = nil
+-- redundant = nil
+-- firstnone = nil
+-- lastfont = nil
+-- lastproc = nil
+-- lastnone = nil
+--
+-- local fontmode = nil -- base none or other
+--
+-- d, u, b, r = 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.
+--
+-- for n, char, font, dynamic in nextchar, head do
+--
+-- if font ~= prevfont then
+-- prevfont = font
+-- fontmode = fontmodes[font]
+-- if fontmode == "none" then
+-- prevdynamic = 0
+-- variants = false
+-- setnone(n)
+-- elseif fontmode == "base" then
+-- prevdynamic = 0
+-- variants = false
+-- setbase(n)
+-- else
+-- -- local dynamic = getglyphdata(n) or 0 -- zero dynamic is reserved for fonts in context
+-- prevdynamic = dynamic
+-- variants = fontvariants[font]
+-- setnode(n,font,dynamic)
+-- end
+-- elseif fontmode == "node" then
+-- local dynamic = getglyphdata(n) or 0 -- zero dynamic is reserved for fonts in context
+-- if dynamic ~= prevdynamic then
+-- prevdynamic = dynamic
+-- variants = fontvariants[font]
+-- setnode(n,font,dynamic)
+-- end
+-- elseif firstnone then
+-- lastnone = n
+-- end
+--
+-- if variants then
+-- if (char >= 0xFE00 and char <= 0xFE0F) or (char >= 0xE0100 and char <= 0xE01EF) then
+-- -- if variants and char >= 0xFE00 then
+-- -- if 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 == wordboundary_code 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
+-- flushnode(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 disc in nextdisc, head do
+-- -- doing only 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 = getreplace(disc)
+-- if r then
+-- local prevfont = nil
+-- local prevdynamic = nil
+-- local none = false
+-- firstnone = nil
+-- basefont = nil
+-- for n, char, font, dynamic in nextchar, r do
+-- -- local dynamic = getglyphdata(n) or 0 -- zero dynamic is reserved for fonts in context
+-- if font ~= prevfont or dynamic ~= prevdynamic then
+-- prevfont = font
+-- prevdynamic = dynamic
+-- local fontmode = fontmodes[font]
+-- if fontmode == "none" then
+-- setnone(n)
+-- elseif fontmode == "base" then
+-- -- so the replace gets an extra treatment ... so be it
+-- setbase(n)
+-- else
+-- setnode(n,font,dynamic)
+-- 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
+-- end
+-- end
+--
+-- end
+--
+-- if trace_fontrun then
+-- stop_trace(u,usedfonts,d,dynamicfonts,b,basefonts,r,redundant)
+-- end
+--
+-- -- in context we always have at least 2 processors
+-- if u == 0 then
+-- -- skip
+-- elseif u == 1 then
+-- for i=1,#lastproc do
+-- head = lastproc[i](head,lastfont,0,direction)
+-- end
+-- else
+-- for font, processors in next, usedfonts do -- unordered
+-- for i=1,#processors do
+-- head = processors[i](head,font,0,direction,u) -- u triggers disc optimizer
+-- end
+-- end
+-- end
+--
+-- if d == 0 then
+-- -- skip
+-- elseif d == 1 then
+-- local font, dynamics = next(dynamicfonts)
+-- for dynamic, processors in next, dynamics do -- unordered, dynamic can switch in between
+-- for i=1,#processors do
+-- head = processors[i](head,font,dynamic,direction)
+-- end
+-- end
+-- else
+-- for font, dynamics in next, dynamicfonts do
+-- for dynamic, processors in next, dynamics do -- unordered, dynamic can switch in between
+-- for i=1,#processors do
+-- head = processors[i](head,font,dynamic,direction,d) -- d triggers disc optimizer
+-- 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
+--
+-- end
+
+
+-- This variant uses less code but relies on the engine checking the textcontrol
+-- flags:
+--
+-- baseligatures : 0x02
+-- basekerns : 0x04
+-- noneprotected : 0x08
+--
+-- This permits one 'base' pass instead of multiple over ranges which is kind of
+-- tricky because we then can have clashes when we process replace fields
+-- independently. We can also protect 'none' in one go. It is actually not that
+-- much faster (and in some cases it might even be slower). We can make the code
+-- a bit leaner (no setbase and setnone).
+
do
local usedfonts
local dynamicfonts
- local basefonts -- could be reused
- local basefont
local prevfont
local prevdynamic
local variants
local redundant -- could be reused
- local firstnone
local lastfont
local lastproc
- local lastnone
+ local basedone
+ local nonedone
local d, u, b, r
- local function protectnone()
- protectglyphs(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
+ nonedone = true
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
+ basedone = true
end
end
local function setnode(n,font,dynamic) -- we could use prevfont and prevdynamic when we set then first
- if firstnone then
- protectnone()
- end
- if basefont then
- basefont[2] = getprev(n)
- basefont = false
- end
if dynamic > 0 then
local used = dynamicfonts[font]
if not used then
@@ -258,24 +623,22 @@ do
usedfonts = { }
dynamicfonts = { }
- basefonts = { }
- basefont = nil
prevfont = nil
prevdynamic = 0
variants = nil
redundant = nil
- firstnone = nil
lastfont = nil
lastproc = nil
- lastnone = nil
+ nonedone = nil
+ basedone = nil
local fontmode = nil -- base none or other
d, u, b, r = 0, 0, 0, 0
- if trace_fontrun then
- start_trace(head)
- end
+-- 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.
@@ -306,8 +669,6 @@ do
variants = fontvariants[font]
setnode(n,font,dynamic)
end
- elseif firstnone then
- lastnone = n
end
if variants then
@@ -348,10 +709,6 @@ do
end
- if firstnone then
- protectnone()
- end
-
if force_boundaryrun then
-- we can inject wordboundaries and then let the hyphenator do its work
@@ -382,31 +739,13 @@ do
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
flushnode(r)
end
end
+ -- todo: make this more clever
+
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 disc in nextdisc, head do
-- doing only replace is good enough because pre and post are normally used
-- for hyphens and these come from fonts that part of the hyphenated word
@@ -415,8 +754,6 @@ do
local prevfont = nil
local prevdynamic = nil
local none = false
- firstnone = nil
- basefont = nil
for n, char, font, dynamic in nextchar, r do
-- local dynamic = getglyphdata(n) or 0 -- zero dynamic is reserved for fonts in context
if font ~= prevfont or dynamic ~= prevdynamic then
@@ -426,29 +763,26 @@ do
if fontmode == "none" then
setnone(n)
elseif fontmode == "base" then
- -- so the replace gets an extra treatment ... so be it
setbase(n)
else
setnode(n,font,dynamic)
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
end
end
end
- if trace_fontrun then
- stop_trace(u,usedfonts,d,dynamicfonts,b,basefonts,r,redundant)
+-- if trace_fontrun then
+-- stop_trace(u,usedfonts,d,dynamicfonts,b,basefonts,r,redundant)
+-- end
+
+ if nonedone then
+ protectglyphsnone(head)
end
-- in context we always have at least 2 processors
@@ -465,6 +799,7 @@ do
end
end
end
+
if d == 0 then
-- skip
elseif d == 1 then
@@ -483,55 +818,13 @@ do
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
+
+ if basedone then
+ local start = head
+ start = ligaturing(start)
+ start = kerning(start)
+ if head ~= start then
+ head = start
end
end