diff options
author | Hans Hagen <pragma@wxs.nl> | 2018-05-12 01:19:03 +0200 |
---|---|---|
committer | Context Git Mirror Bot <phg42.2a@gmail.com> | 2018-05-12 01:19:03 +0200 |
commit | 77e216e323271fb85d508b7206b13c980540b74b (patch) | |
tree | 5b4053c2bbe5190e28c0dce89653c7b13aea0642 /tex/context/base/mkiv/node-fnt.lua | |
parent | d817aef76ab8b606c02bd0636661b634b43a68a6 (diff) | |
download | context-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.lua | 432 |
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 |