From b14f992ef5f4e868c9959b174278c86516d60dbc Mon Sep 17 00:00:00 2001
From: Hans Hagen This module is a bit more split up that I'd like but since we also want to test
with plain The specification of OpenType is kind of vague. Apart from a lack of a proper
-free specifications there's also the problem that Microsoft and Adobe
-may have their own interpretation of how and in what order to apply features.
-In general the Microsoft website has more detailed specifications and is a
-better reference. There is also some information in the FontForge help files. The specification of OpenType is (or at least a decade ago was) kind of vague.
+Apart from a lack of a proper free specifications there's also the problem that
+Microsoft and Adobe may have their own interpretation of how and in what order to
+apply features. In general the Microsoft website has more detailed specifications
+and is a better reference. There is also some information in the FontForge help
+files. In the end we rely most on the Microsoft specification. Because there is so much possible, fonts might contain bugs and/or be made to
work with certain rederers. These may evolve over time which may have the side
-effect that suddenly fonts behave differently.
After a lot of experiments (mostly by Taco, me and Idris) we're now at yet another
-implementation. Of course all errors are mine and of course the code can be
-improved. There are quite some optimizations going on here and processing speed
-is currently acceptable. Not all functions are implemented yet, often because I
-lack the fonts for testing. Many scripts are not yet supported either, but I will
-look into them as soon as
After a lot of experiments (mostly by Taco, me and Idris) the first implementation
+becaus quite useful. When it did most of what we wanted, a more optimized version
+evolved. Of course all errors are mine and of course the code can be improved. There
+are quite some optimizations going on here and processing speed is currently quite
+acceptable and has been improved over time. Many complex scripts are not yet supported
+yet, but I will look into them as soon as
The specification leaves room for interpretation. In case of doubt the microsoft +
The specification leaves room for interpretation. In case of doubt the Microsoft implementation is the reference as it is the most complete one. As they deal with lots of scripts and fonts, Kai and Ivo did a lot of testing of the generic code and their suggestions help improve the code. I'm aware that not all border cases can be taken care of, unless we accept excessive runtime, and even then the interference with other mechanisms (like hyphenation) are not trivial.
+Especially discretionary handling has been improved much by Kai Eigner who uses complex +(latin) fonts. The current implementation is a compromis between his patches and my code +and in the meantime performance is quite ok. We cannot check all border cases without +compromising speed but so far we're okay. Given good test cases we can probably improve +it here and there. Especially chain lookups are non trivial with discretionaries but +things got much better over time thanks to Kai.
+Glyphs are indexed not by unicode but in their own way. This is because there is no relationship with unicode at all, apart from the fact that a font might cover certain ranges of characters. One character can have multiple shapes. However, at the @@ -84,33 +56,74 @@ then in the output eventually.
that different from the one produced byThis module is sparsely documented because it is a moving target. The table format -of the reader changes and we experiment a lot with different methods for supporting -features.
+unpacked). -As with the
This module is sparsely documented because it is has been a moving target. The +table format of the reader changed a bit over time and we experiment a lot with +different methods for supporting features. By now the structures are quite stable
Incrementing the version number will force a re-cache. We jump the number by one
-when there's a fix in the
This code is also used outside context but in context it has to work with other +mechanisms. Both put some constraints on the code here.
+ --ldx]]-- +-- Remark: We assume that cursives don't cross discretionaries which is okay because it +-- is only used in semitic scripts. +-- +-- Remark: We assume that marks precede base characters. +-- +-- Remark: When complex ligatures extend into discs nodes we can get side effects. Normally +-- this doesn't happen; ff\d{l}{l}{l} in lm works but ff\d{f}{f}{f}. +-- +-- Todo: check if we copy attributes to disc nodes if needed. +-- +-- Todo: it would be nice if we could get rid of components. In other places we can use +-- the unicode properties. +-- +-- Remark: We do some disc juggling where we need to keep in mind that the pre, post and +-- replace fields can have prev pointers to a nesting node ... I wonder if that is still +-- needed. +-- +-- Remark: This is not possible: +-- +-- \discretionary {alpha-} {betagammadelta} +-- {\discretionary {alphabeta-} {gammadelta} +-- {\discretionary {alphabetagamma-} {delta} +-- {alphabetagammadelta}}} +-- +-- Remark: Something is messed up: we have two mark / ligature indices, one at the +-- injection end and one here ... this is based on KE's patches but there is something +-- fishy there as I'm pretty sure that for husayni we need some connection (as it's much +-- more complex than an average font) but I need proper examples of all cases, not of +-- only some. +-- +-- Remark: I wonder if indexed would be faster than unicoded. It would be a major +-- rewrite to have char being unicode + an index field in glyph nodes. Also more +-- assignments have to be made in order to keep things in sync. So, it's a no-go. +-- +-- Remark: We can provide a fast loop when there are no disc nodes (tests show a 1% +-- gain). Smaller functions might perform better cache-wise. But ... memory becomes +-- faster anyway, so ... + local type, next, tonumber = type, next, tonumber local random = math.random local formatters = string.formatters local insert = table.insert -local logs, trackers, nodes, attributes = logs, trackers, nodes, attributes +local registertracker = trackers.register -local registertracker = trackers.register -local registerdirective = directives.register +local logs = logs +local trackers = trackers +local nodes = nodes +local attributes = attributes +local fonts = fonts -local fonts = fonts -local otf = fonts.handlers.otf +local otf = fonts.handlers.otf +local tracers = nodes.tracers local trace_lookups = false registertracker("otf.lookups", function(v) trace_lookups = v end) local trace_singles = false registertracker("otf.singles", function(v) trace_singles = v end) @@ -124,7 +137,6 @@ local trace_cursive = false registertracker("otf.cursive", function(v local trace_preparing = false registertracker("otf.preparing", function(v) trace_preparing = v end) local trace_bugs = false registertracker("otf.bugs", function(v) trace_bugs = v end) local trace_details = false registertracker("otf.details", function(v) trace_details = v end) ------ trace_applied = false registertracker("otf.applied", function(v) trace_applied = v end) local trace_steps = false registertracker("otf.steps", function(v) trace_steps = v end) local trace_skips = false registertracker("otf.skips", function(v) trace_skips = v end) local trace_directions = false registertracker("otf.directions", function(v) trace_directions = v end) @@ -135,23 +147,20 @@ local trace_discruns = false registertracker("otf.discruns", function(v local trace_compruns = false registertracker("otf.compruns", function(v) trace_compruns = v end) local trace_testruns = false registertracker("otf.testruns", function(v) trace_testruns = v end) ------ zwnjruns = true registerdirective("otf.zwnjruns", function(v) zwnjruns = v end) local optimizekerns = true -local alwaysdisc = true registerdirective("otf.alwaysdisc", function(v) alwaysdisc = v end) -local report_direct = logs.reporter("fonts","otf direct") -local report_subchain = logs.reporter("fonts","otf subchain") -local report_chain = logs.reporter("fonts","otf chain") -local report_process = logs.reporter("fonts","otf process") -local report_warning = logs.reporter("fonts","otf warning") -local report_run = logs.reporter("fonts","otf run") +local report_direct = logs.reporter("fonts","otf direct") +local report_subchain = logs.reporter("fonts","otf subchain") +local report_chain = logs.reporter("fonts","otf chain") +local report_process = logs.reporter("fonts","otf process") +local report_warning = logs.reporter("fonts","otf warning") +local report_run = logs.reporter("fonts","otf run") registertracker("otf.replacements", "otf.singles,otf.multiples,otf.alternatives,otf.ligatures") registertracker("otf.positions","otf.marks,otf.kerns,otf.cursive") registertracker("otf.actions","otf.replacements,otf.positions") registertracker("otf.injections","nodes.injections") - -registertracker("*otf.sample","otf.steps,otf.actions,otf.analyzing") +registertracker("otf.sample","otf.steps,otf.actions,otf.analyzing") local nuts = nodes.nuts local tonode = nuts.tonode @@ -178,6 +187,10 @@ local setchar = nuts.setchar local getdisc = nuts.getdisc local setdisc = nuts.setdisc local setlink = nuts.setlink +local getcomponents = nuts.getcomponents -- the original one, not yet node-aux +local setcomponents = nuts.setcomponents -- the original one, not yet node-aux +local getdir = nuts.getdir +local getwidth = nuts.getwidth local ischar = nuts.is_char @@ -190,14 +203,16 @@ local flush_node = nuts.flush_node local end_of_math = nuts.end_of_math local traverse_nodes = nuts.traverse local traverse_id = nuts.traverse_id -local remove_node = nuts.remove +local set_components = nuts.set_components +local take_components = nuts.take_components +local count_components = nuts.count_components +local copy_no_components = nuts.copy_no_components +local copy_only_glyphs = nuts.copy_only_glyphs local setmetatableindex = table.setmetatableindex -local zwnj = 0x200C -local zwj = 0x200D -local wildcard = "*" -local default = "dflt" +----- zwnj = 0x200C +----- zwj = 0x200D local nodecodes = nodes.nodecodes local glyphcodes = nodes.glyphcodes @@ -215,13 +230,8 @@ local ligature_code = glyphcodes.ligature local privateattribute = attributes.private --- Something is messed up: we have two mark / ligature indices, one at the injection --- end and one here ... this is based on KE's patches but there is something fishy --- there as I'm pretty sure that for husayni we need some connection (as it's much --- more complex than an average font) but I need proper examples of all cases, not --- of only some. - local a_state = privateattribute('state') +local a_noligature = privateattribute("noligature") local injections = nodes.injections local setmark = injections.setmark @@ -233,11 +243,8 @@ local copyinjection = injections.copy local setligaindex = injections.setligaindex local getligaindex = injections.getligaindex -local cursonce = true - -local fonthashes = fonts.hashes -local fontdata = fonthashes.identifiers -local fontfeatures = fonthashes.features +local fontdata = fonts.hashes.identifiers +local fontfeatures = fonts.hashes.features local otffeatures = fonts.constructors.features.otf local registerotffeature = otffeatures.register @@ -248,37 +255,36 @@ local getrandom = utilities and utilities.randomizer and utilities.rand otf.defaultnodealternate = "none" -- first last --- We use a few global variables. The handler can be called nested but this assumes that the --- same font is used. Nested calls are normally not needed (only for devanagari). - -local tfmdata = false -local characters = false -local descriptions = false -local marks = false -local currentfont = false -local factor = 0 -local threshold = 0 -local checkmarks = false +-- We use a few semi-global variables. The handler can be called nested but this assumes +-- that the same font is used. -local sweepnode = nil -local sweepprev = nil -local sweepnext = nil -local sweephead = { } +local tfmdata = false +local characters = false +local descriptions = false +local marks = false +local classes = false +local currentfont = false +local factor = 0 +local threshold = 0 +local checkmarks = false -local notmatchpre = { } -local notmatchpost = { } -local notmatchreplace = { } +local sweepnode = nil +local sweepprev = nil +local sweepnext = nil +local sweephead = { } -local handlers = { } +local notmatchpre = { } +local notmatchpost = { } +local notmatchreplace = { } -local isspace = injections.isspace -local getthreshold = injections.getthreshold +local handlers = { } --- we use this for special testing and documentation +local isspace = injections.isspace +local getthreshold = injections.getthreshold -local checkstep = (nodes and nodes.tracers and nodes.tracers.steppers.check) or function() end -local registerstep = (nodes and nodes.tracers and nodes.tracers.steppers.register) or function() end -local registermessage = (nodes and nodes.tracers and nodes.tracers.steppers.message) or function() end +local checkstep = (tracers and tracers.steppers.check) or function() end +local registerstep = (tracers and tracers.steppers.register) or function() end +local registermessage = (tracers and tracers.steppers.message) or function() end local function checkdisccontent(d) local pre, post, replace = getdisc(d) @@ -351,6 +357,13 @@ local function mref(rlmode) end end +-- The next code is somewhat complicated by the fact that some fonts can have ligatures made +-- from ligatures that themselves have marks. This was identified by Kai in for instance +-- arabtype: KAF LAM SHADDA ALEF FATHA (0x0643 0x0644 0x0651 0x0627 0x064E). This becomes +-- KAF LAM-ALEF with a SHADDA on the first and a FATHA op de second component. In a next +-- iteration this becomes a KAF-LAM-ALEF with a SHADDA on the second and a FATHA on the +-- third component. + -- We can assume that languages that use marks are not hyphenated. We can also assume -- that at most one discretionary is present. @@ -360,21 +373,6 @@ end -- However, for arabic we need to keep them around for the sake of mark placement -- and indices. -local function copy_glyph(g) -- next and prev are untouched ! - local components = getfield(g,"components") - if components then - setfield(g,"components") - local n = copy_node(g) - copyinjection(n,g) -- we need to preserve the lig indices - setfield(g,"components",components) - return n - else - local n = copy_node(g) - copyinjection(n,g) -- we need to preserve the lig indices - return n - end -end - local function flattendisk(head,disc) local pre, post, replace, pretail, posttail, replacetail = getdisc(disc,true) local prev, next = getboth(disc) @@ -419,18 +417,40 @@ local function appenddisc(disc,list) if post then setlink(posttail,posthead) else - post = phead + post = posthead end if replace then setlink(replacetail,replacehead) else - replace = rhead + replace = replacehead end setdisc(disc,pre,post,replace) end -- start is a mark and we need to keep that one +local take_components = getcomponents -- we overload here (for now) +local set_components = setcomponents -- we overload here (for now) +----- get_components = getcomponents -- we overload here (for now) + +local function count_components(start,marks) + if getid(start) ~= glyph_code then + return 0 + elseif getsubtype(start) == ligature_code then + local i = 0 + local components = getcomponents(start) + while components do + i = i + count_components(components,marks) + components = getnext(components) + end + return i + elseif not marks[getchar(start)] then + return 1 + else + return 0 + end +end + local function markstoligature(head,start,stop,char) if start == stop and getchar(start) == char then return head, start @@ -439,46 +459,135 @@ local function markstoligature(head,start,stop,char) local next = getnext(stop) setprev(start) setnext(stop) - local base = copy_glyph(start) + local base = copy_no_components(start,copyinjection) if head == start then head = base end resetinjection(base) setchar(base,char) setsubtype(base,ligature_code) - setfield(base,"components",start) - setlink(prev,base) - setlink(base,next) + set_components(base,start) + setlink(prev,base,next) return head, base end end --- The next code is somewhat complicated by the fact that some fonts can have ligatures made --- from ligatures that themselves have marks. This was identified by Kai in for instance --- arabtype: KAF LAM SHADDA ALEF FATHA (0x0643 0x0644 0x0651 0x0627 0x064E). This becomes --- KAF LAM-ALEF with a SHADDA on the first and a FATHA op de second component. In a next --- iteration this becomes a KAF-LAM-ALEF with a SHADDA on the second and a FATHA on the --- third component. - -local function getcomponentindex(start) -- we could store this offset in the glyph (nofcomponents) - if getid(start) ~= glyph_code then -- and then get rid of all components - return 0 - elseif getsubtype(start) == ligature_code then - local i = 0 - local components = getfield(start,"components") - while components do - i = i + getcomponentindex(components) - components = getnext(components) - end - return i - elseif not marks[getchar(start)] then - return 1 - else - return 0 - end -end - -local a_noligature = attributes.private("noligature") +-- local function toligature(head,start,stop,char,dataset,sequence,markflag,discfound) -- brr head +-- if getattr(start,a_noligature) == 1 then +-- -- so we can do: e\noligature{ff}e e\noligature{f}fie (we only look at the first) +-- return head, start +-- end +-- if start == stop and getchar(start) == char then +-- resetinjection(start) +-- setchar(start,char) +-- return head, start +-- end +-- local prev = getprev(start) +-- local next = getnext(stop) +-- local comp = start +-- setprev(start) +-- setnext(stop) +-- local base = copy_no_components(start,copyinjection) +-- if start == head then +-- head = base +-- end +-- resetinjection(base) +-- setchar(base,char) +-- setsubtype(base,ligature_code) +-- set_components(base,comp) +-- setlink(prev,base,next) +-- if not discfound then +-- local deletemarks = markflag ~= "mark" +-- local components = start +-- local baseindex = 0 +-- local componentindex = 0 +-- local head = base +-- local current = base +-- -- first we loop over the glyphs in start .. stop +-- while start do +-- local char = getchar(start) +-- if not marks[char] then +-- baseindex = baseindex + componentindex +-- componentindex = getcomponentindex(start,marks) +-- elseif not deletemarks then -- quite fishy +-- 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) +-- 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)) +-- end +-- start = getnext(start) +-- end +-- -- we can have one accent as part of a lookup and another following +-- -- local start = components -- was wrong (component scanning was introduced when more complex ligs in devanagari was added) +-- local start = getnext(current) +-- while start do +-- local char = ischar(start) +-- if char then +-- if marks[char] then +-- setligaindex(start,baseindex + getligaindex(start,componentindex)) +-- if trace_marks then +-- logwarning("%s: set mark %s, gets index %s",pref(dataset,sequence),gref(char),getligaindex(start)) +-- end +-- start = getnext(start) +-- else +-- break +-- end +-- else +-- break +-- end +-- end +-- else +-- -- discfound ... forget about marks .. probably no scripts that hyphenate and have marks +-- local discprev, discnext = getboth(discfound) +-- if discprev and discnext then +-- -- we assume normalization in context, and don't care about generic ... especially +-- -- \- can give problems as there we can have a negative char but that won't match +-- -- anyway +-- local pre, post, replace, pretail, posttail, replacetail = getdisc(discfound,true) +-- if not replace then -- todo: signal simple hyphen +-- local prev = getprev(base) +-- local current = comp +-- local previous = nil +-- local copied = nil +-- while current do +-- if getid(current) == glyph_code then +-- local n = copy_node(current) +-- if copied then +-- setlink(previous,n) +-- else +-- copied = n +-- end +-- previous = n +-- end +-- current = getnext(current) +-- end +-- setprev(discnext) -- also blocks funny assignments +-- setnext(discprev) -- also blocks funny assignments +-- if pre then +-- setlink(discprev,pre) +-- end +-- pre = comp +-- if post then +-- setlink(posttail,discnext) +-- setprev(post) +-- else +-- post = discnext +-- end +-- setlink(prev,discfound,next) +-- setboth(base) +-- set_components(base,copied) +-- setdisc(discfound,pre,post,base) -- was discretionary_code +-- base = prev -- restart +-- end +-- end +-- end +-- return head, base +-- end local function toligature(head,start,stop,char,dataset,sequence,markflag,discfound) -- brr head if getattr(start,a_noligature) == 1 then @@ -490,33 +599,20 @@ local function toligature(head,start,stop,char,dataset,sequence,markflag,discfou setchar(start,char) return head, start end - -- needs testing (side effects): - local components = getfield(start,"components") - if components then - -- we get a double free .. needs checking - -- flush_node_list(components) - end - -- local prev = getprev(start) local next = getnext(stop) local comp = start setprev(start) setnext(stop) - local base = copy_glyph(start) + local base = copy_no_components(start,copyinjection) if start == head then head = base end resetinjection(base) setchar(base,char) setsubtype(base,ligature_code) - setfield(base,"components",comp) -- start can have components ... do we need to flush? - if prev then - setnext(prev,base) - end - if next then - setprev(next,base) - end - setboth(base,prev,next) + set_components(base,comp) + setlink(prev,base,next) if not discfound then local deletemarks = markflag ~= "mark" local components = start @@ -529,7 +625,7 @@ local function toligature(head,start,stop,char,dataset,sequence,markflag,discfou local char = getchar(start) if not marks[char] then baseindex = baseindex + componentindex - componentindex = getcomponentindex(start) + componentindex = count_components(start,marks) elseif not deletemarks then -- quite fishy setligaindex(start,baseindex + getligaindex(start,componentindex)) if trace_marks then @@ -544,7 +640,6 @@ local function toligature(head,start,stop,char,dataset,sequence,markflag,discfou start = getnext(start) end -- we can have one accent as part of a lookup and another following - -- local start = components -- was wrong (component scanning was introduced when more complex ligs in devanagari was added) local start = getnext(current) while start do local char = ischar(start) @@ -570,27 +665,14 @@ local function toligature(head,start,stop,char,dataset,sequence,markflag,discfou -- \- can give problems as there we can have a negative char but that won't match -- anyway local pre, post, replace, pretail, posttail, replacetail = getdisc(discfound,true) - if not replace then -- todo: signal simple hyphen - local prev = getprev(base) - local current = comp - local previous = nil - local copied = nil - while current do - if getid(current) == glyph_code then - local n = copy_node(current) - if copied then - setlink(previous,n) - else - copied = n - end - previous = n - end - current = getnext(current) - end - setprev(discnext) -- also blocks funny assignments - setnext(discprev) -- also blocks funny assignments + if not replace then + local prev = getprev(base) + local comp = take_components(base) + local copied = copy_only_glyphs(comp) if pre then setlink(discprev,pre) + else + setnext(discprev) -- also blocks funny assignments end pre = comp if post then @@ -598,13 +680,15 @@ local function toligature(head,start,stop,char,dataset,sequence,markflag,discfou setprev(post) else post = discnext + setprev(discnext) -- also blocks funny assignments end - setlink(prev,discfound) - setlink(discfound,next) + setlink(prev,discfound,next) setboth(base) - setfield(base,"components",copied) - setdisc(discfound,pre,post,base) -- was discretionary_code - base = prev -- restart + -- here components have a pointer so we can't free it! + set_components(base,copied) + replace = base + setdisc(discfound,pre,post,replace) -- was discretionary_code + base = prev end end end @@ -868,7 +952,6 @@ function handlers.gpos_pair(head,start,dataset,sequence,kerns,rlmode,step,i,inje return head, start, false else local prev = start - local done = false while snext do local nextchar = ischar(snext,currentfont) if nextchar then @@ -888,8 +971,7 @@ function handlers.gpos_pair(head,start,dataset,sequence,kerns,rlmode,step,i,inje if trace_kerns then logprocess("%s: shifting single %s by %p",pref(dataset,sequence),gref(nextchar),k) end - done = true - break + return head, start, true end end if a and #a > 0 then @@ -906,15 +988,13 @@ function handlers.gpos_pair(head,start,dataset,sequence,kerns,rlmode,step,i,inje logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p) as %s",pref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h,injection or "injections") end end - done = true - break + return head, start, true elseif krn ~= 0 then local k = setkern(snext,factor,rlmode,krn,injection) if trace_kerns then logprocess("%s: inserting kern %p between %s and %s as %s",pref(dataset,sequence),k,gref(getchar(prev)),gref(nextchar),injection or "injections") end - done = true - break + return head, start, true else -- can't happen break end @@ -922,7 +1002,7 @@ function handlers.gpos_pair(head,start,dataset,sequence,kerns,rlmode,step,i,inje break end end - return head, start, done + return head, start, false end end @@ -1085,7 +1165,6 @@ function handlers.gpos_mark2mark(head,start,dataset,sequence,markanchors,rlmode) end function handlers.gpos_cursive(head,start,dataset,sequence,exitanchors,rlmode,step,i) -- to be checked - local done = false local startchar = getchar(start) if marks[startchar] then if trace_cursive then @@ -1093,7 +1172,7 @@ function handlers.gpos_cursive(head,start,dataset,sequence,exitanchors,rlmode,st end else local nxt = getnext(start) - while not done and nxt do + while nxt do local nextchar = ischar(nxt,currentfont) if not nextchar then break @@ -1111,7 +1190,7 @@ function handlers.gpos_cursive(head,start,dataset,sequence,exitanchors,rlmode,st if trace_cursive then logprocess("%s: moving %s to %s cursive (%p,%p) using anchor %s and bound %s in %s mode",pref(dataset,sequence),gref(startchar),gref(nextchar),dx,dy,anchor,bound,mref(rlmode)) end - done = true + return head, start, true end end end @@ -1119,7 +1198,7 @@ function handlers.gpos_cursive(head,start,dataset,sequence,exitanchors,rlmode,st end end end - return head, start, done + return head, start, false end --[[ldx-- @@ -1207,10 +1286,11 @@ function chainprocs.gsub_single(head,start,stop,dataset,sequence,currentlookup,c reportmoresteps(dataset,sequence) end local current = start + local mapping = steps[1].coverage while current do local currentchar = ischar(current) if currentchar then - local replacement = steps[1].coverage[currentchar] + local replacement = mapping[currentchar] if not replacement or replacement == "" then if trace_bugs then logwarning("%s: no single for %s",cref(dataset,sequence,chainindex),gref(currentchar)) @@ -1282,10 +1362,11 @@ function chainprocs.gsub_alternate(head,start,stop,dataset,sequence,currentlooku local what = dataset[1] local value = what == true and tfmdata.shared.features[kind] or what -- todo: optimize in ctx local current = start + local mapping = steps[1].coverage while current do local currentchar = ischar(current) if currentchar then - local alternatives = steps[1].coverage[currentchar] + local alternatives = mapping[currentchar] if alternatives then local choice, comment = get_alternative_glyph(current,alternatives,value) if choice then @@ -1437,7 +1518,6 @@ function chainprocs.gpos_pair(head,start,stop,dataset,sequence,currentlookup,rlm local kerns = step.coverage[startchar] -- always 1 step if kerns then local prev = start - local done = false while snext do local nextchar = ischar(snext,currentfont) if not nextchar then @@ -1459,8 +1539,7 @@ function chainprocs.gpos_pair(head,start,stop,dataset,sequence,currentlookup,rlm if trace_kerns then logprocess("%s: shifting single %s by %p",cref(dataset,sequence),gref(startchar),k) end - done = true - break + return head, start, true end end if a and #a > 0 then @@ -1477,20 +1556,17 @@ function chainprocs.gpos_pair(head,start,stop,dataset,sequence,currentlookup,rlm logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h) end end - done = true - break + return head, start, true elseif krn ~= 0 then local k = setkern(snext,factor,rlmode,krn) if trace_kerns then logprocess("%s: inserting kern %s between %s and %s",cref(dataset,sequence),k,gref(getchar(prev)),gref(nextchar)) end - done = true - break + return head, start, true else break end end - return head, start, done end end return head, start, false @@ -1689,14 +1765,13 @@ function chainprocs.gpos_cursive(head,start,stop,dataset,sequence,currentlookup, local startchar = getchar(start) local exitanchors = steps[1].coverage[startchar] -- always 1 step if exitanchors then - local done = false if marks[startchar] then if trace_cursive then logprocess("%s: ignoring cursive for mark %s",pref(dataset,sequence),gref(startchar)) end else local nxt = getnext(start) - while not done and nxt do + while nxt do local nextchar = ischar(nxt,currentfont) if not nextchar then break @@ -1714,8 +1789,7 @@ function chainprocs.gpos_cursive(head,start,stop,dataset,sequence,currentlookup, if trace_cursive then logprocess("%s: moving %s to %s cursive (%p,%p) using anchor %s and bound %s in %s mode",pref(dataset,sequence),gref(startchar),gref(nextchar),dx,dy,anchor,bound,mref(rlmode)) end - done = true - break + return head, start, true end end elseif trace_bugs then @@ -1725,13 +1799,10 @@ function chainprocs.gpos_cursive(head,start,stop,dataset,sequence,currentlookup, end end end - return head, start, done - else - if trace_cursive and trace_details then - logprocess("%s, cursive %s is already done",pref(dataset,sequence),gref(getchar(start)),alreadydone) - end - return head, start, false + elseif trace_cursive and trace_details then + logprocess("%s, cursive %s is already done",pref(dataset,sequence),gref(getchar(start)),alreadydone) end + return head, start, false end -- what pointer to return, spec says stop @@ -1774,7 +1845,7 @@ local function checked(head) local current = head while current do if getid(current) == glue_code then - local kern = new_kern(getfield(current,"width")) + local kern = new_kern(getwidth(current)) if head == current then local next = getnext(current) if next then @@ -1785,8 +1856,7 @@ local function checked(head) current = next else local prev, next = getboth(current) - setlink(prev,kern) - setlink(kern,next) + setlink(prev,kern,next) flush_node(current) current = next end @@ -1804,7 +1874,107 @@ local function setdiscchecked(d,pre,post,replace) setdisc(d,pre,post,replace) end -local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,ck,chainproc) +local noflags = { false, false, false, false } + +local function chainrun(head,start,last,dataset,sequence,rlmode,ck,skipped) + + local size = ck[5] - ck[4] + 1 + local flags = sequence.flags or noflags + local done = false + local skipmark = flags[1] + local chainlookups = ck[6] + + -- current match + if chainlookups then + local nofchainlookups = #chainlookups + -- Lookups can be like { 1, false, 3 } or { false, 2 } or basically anything and + -- #lookups can be less than #current + if size == 1 then + -- if nofchainlookups > size then + -- -- bad rules + -- end + local chainlookup = chainlookups[1] + local chainkind = chainlookup.type + local chainproc = chainprocs[chainkind] + if chainproc then + local ok + head, start, ok = chainproc(head,start,last,dataset,sequence,chainlookup,rlmode,1) + if ok then + done = true + end + else + logprocess("%s: %s is not yet supported (1)",cref(dataset,sequence),chainkind) + end + else + -- See LookupType 5: Contextual Substitution Subtable. Now it becomes messy. The + -- easiest case is where #current maps on #lookups i.e. one-to-one. But what if + -- we have a ligature. Cf the spec we then need to advance one character but we + -- really need to test it as there are fonts out there that are fuzzy and have + -- too many lookups: + -- + -- U+1105 U+119E U+1105 U+119E : sourcehansansklight: script=hang ccmp=yes + -- + local i = 1 + while start do + if skipped then + while start do + local char = getchar(start) + local class = classes[char] + if class then + if class == skipmark or class == skipligature or class == skipbase or (markclass and class == "mark" and not markclass[char]) then + start = getnext(start) + else + break + end + else + break + end + end + end + local chainlookup = chainlookups[i] + if chainlookup then + local chainkind = chainlookup.type + local chainproc = chainprocs[chainkind] + if chainproc then + local ok, n + head, start, ok, n = chainproc(head,start,last,dataset,sequence,chainlookup,rlmode,i) + -- messy since last can be changed ! + if ok then + done = true + if n and n > 1 and i + n > nofchainlookups then + -- this is a safeguard, we just ignore the rest of the lookups + break + end + end + else + -- actually an error + logprocess("%s: %s is not yet supported (2)",cref(dataset,sequence),chainkind) + end + end + i = i + 1 + if i > size or not start then + break + elseif start then + start = getnext(start) + end + end + end + else + -- todo: needs checking for holes in the replacements + local replacements = ck[7] + if replacements then + head, start, done = reversesub(head,start,last,dataset,sequence,replacements,rlmode) + else + done = true + if trace_contexts then + logprocess("%s: skipping match",cref(dataset,sequence)) + end + end + end + return head, start, done +end + +local function chaindisk(head,start,dataset,sequence,rlmode,ck,skipped) if not start then return head, start, false @@ -1819,7 +1989,6 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c local sweepnode = sweepnode local sweeptype = sweeptype local sweepoverflow = false - local checkdisc = getprev(head) -- hm bad name head local keepdisc = not sweepnode local lookaheaddisc = nil local backtrackdisc = nil @@ -1845,19 +2014,23 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c hasglue = true elseif id == disc_code then if keepdisc then - keepdisc = false - if notmatchpre[current] ~= notmatchreplace[current] then - lookaheaddisc = current - end + keepdisc = false + lookaheaddisc = current local replace = getfield(current,"replace") - while replace and i <= l do - if getid(replace) == glyph_code then - i = i + 1 + if not replace then + sweepoverflow = true + sweepnode = current + current = getnext(current) + else + while replace and i <= l do + if getid(replace) == glyph_code then + i = i + 1 + end + replace = getnext(replace) end - replace = getnext(replace) + current = getnext(replace) end - last = current - current = getnext(c) + last = current else head, current = flattendisk(head,current) end @@ -1919,7 +2092,8 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c if notmatchpre[current] ~= notmatchreplace[current] then lookaheaddisc = current end - local replace = getfield(c,"replace") + -- we assume a simple text only replace (we could use nuts.count) + local replace = getfield(current,"replace") while replace and i < s do if getid(replace) == glyph_code then i = i + 1 @@ -1964,6 +2138,7 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c if notmatchpost[current] ~= notmatchreplace[current] then backtrackdisc = current end + -- we assume a simple text only replace (we could use nuts.count) local replace = getfield(current,"replace") while replace and i > 1 do if getid(replace) == glyph_code then @@ -1982,7 +2157,8 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c end end - local ok = false + local done = false + if lookaheaddisc then local cf = start @@ -2001,11 +2177,7 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c break end end - - setprev(lookaheaddisc,cprev) - if cprev then - setnext(cprev,lookaheaddisc) - end + setlink(cprev,lookaheaddisc) setprev(cf) setnext(cl) if startishead then @@ -2014,25 +2186,35 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c local pre, post, replace = getdisc(lookaheaddisc) local new = copy_node_list(cf) local cnew = new + if pre then + setlink(find_node_tail(cf),pre) + end + if replace then + local tail = find_node_tail(new) + setlink(tail,replace) + end for i=1,insertedmarks do cnew = getnext(cnew) end + cl = start local clast = cnew for i=f,l do + cl = getnext(cl) clast = getnext(clast) end if not notmatchpre[lookaheaddisc] then - cf, start, ok = chainproc(cf,start,last,dataset,sequence,chainlookup,rlmode,k) + local ok = false + cf, start, ok = chainrun(cf,start,cl,dataset,sequence,rlmode,ck,skipped) + if ok then + done = true + end end if not notmatchreplace[lookaheaddisc] then - new, cnew, ok = chainproc(new,cnew,clast,dataset,sequence,chainlookup,rlmode,k) - end - if pre then - setlink(cl,pre) - end - if replace then - local tail = find_node_tail(new) - setlink(tail,replace) + local ok = false + new, cnew, ok = chainrun(new,cnew,clast,dataset,sequence,rlmode,ck,skipped) + if ok then + done = true + end end if hasglue then setdiscchecked(lookaheaddisc,cf,post,new) @@ -2041,7 +2223,7 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c end start = getprev(lookaheaddisc) sweephead[cf] = getnext(clast) - sweephead[new] = getnext(last) + sweephead[new] = getnext(cl) elseif backtrackdisc then @@ -2077,10 +2259,18 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c clast = getnext(clast) end if not notmatchpost[backtrackdisc] then - cf, start, ok = chainproc(cf,start,last,dataset,sequence,chainlookup,rlmode,k) + local ok = false + cf, start, ok = chainrun(cf,start,last,dataset,sequence,rlmode,ck,skipped) + if ok then + done = true + end end if not notmatchreplace[backtrackdisc] then - new, cnew, ok = chainproc(new,cnew,clast,dataset,sequence,chainlookup,rlmode,k) + local ok = false + new, cnew, ok = chainrun(new,cnew,clast,dataset,sequence,rlmode,ck,skipped) + if ok then + done = true + end end if post then setlink(posttail,cf) @@ -2103,21 +2293,34 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c else - head, start, ok = chainproc(head,start,last,dataset,sequence,chainlookup,rlmode,k) + local ok = false + head, start, ok = chainrun(head,start,last,dataset,sequence,rlmode,ck,skipped) + if ok then + done = true + end end - return head, start, ok + return head, start, done end -local noflags = { false, false, false, false } +local function chaintrac(head,start,dataset,sequence,rlmode,ck,skipped) + local rule = ck[1] + local lookuptype = ck[8] or ck[2] + local nofseq = #ck[3] + local first = ck[4] + local last = ck[5] + local char = getchar(start) + logwarning("%s: rule %s matches at char %s for (%s,%s,%s) chars, lookuptype %a", + cref(dataset,sequence),rule,gref(char),first-1,last-first+1,nofseq-last,lookuptype) +end local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) local sweepnode = sweepnode local sweeptype = sweeptype local currentfont = currentfont local diskseen = false - local checkdisc = getprev(head) + local checkdisc = sweeptype and getprev(head) local flags = sequence.flags or noflags local done = false local skipmark = flags[1] @@ -2125,6 +2328,8 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) local skipbase = flags[3] local markclass = sequence.markclass local skipped = false + local startprev, + startnext = getboth(start) for k=1,#contexts do -- i've only seen ccmp having > 1 (e.g. dejavu) local match = true local current = start @@ -2138,7 +2343,9 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) -- this seldom happens as it makes no sense (bril, ebgaramond, husayni, minion) local char = ischar(current,currentfont) if char then - match = seq[1][char] + if not seq[1][char] then + match = false + end end else -- maybe we need a better space check (maybe check for glue or category or combination) @@ -2151,7 +2358,8 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) -- before/current/after | before/current | current/after local discfound = nil local n = f + 1 - last = getnext(last) -- the second in current (first already matched) + -- last = getnext(last) -- the second in current (first already matched) + last = startnext -- the second in current (first already matched) while n <= l do if not last and (sweeptype == "post" or sweeptype == "replace") then last = getnext(sweepnode) @@ -2160,9 +2368,8 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) if last then local char, id = ischar(last,currentfont) if char then - local ccd = descriptions[char] - if ccd then - local class = ccd.class or "base" + local class = classes[char] + if class then if class == skipmark or class == skipligature or class == skipbase or (markclass and class == "mark" and not markclass[char]) then skipped = true if trace_skips then @@ -2177,7 +2384,9 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) else if discfound then notmatchreplace[discfound] = true - match = not notmatchpre[discfound] + if notmatchpre[discfound] then + match = false + end else match = false end @@ -2186,7 +2395,9 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) else if discfound then notmatchreplace[discfound] = true - match = not notmatchpre[discfound] + if notmatchpre[discfound] then + match = false + end else match = false end @@ -2195,7 +2406,9 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) elseif char == false then if discfound then notmatchreplace[discfound] = true - match = not notmatchpre[discfound] + if notmatchpre[discfound] then + match = false + end else match = false end @@ -2238,11 +2451,16 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) end else notmatchreplace[last] = true - match = not notmatchpre[last] + if notmatchpre[last] then + match = false + end break end end - match = not notmatchpre[last] + -- why here again + if notmatchpre[last] then + match = false + end end -- maybe only if match last = getnext(last) @@ -2258,8 +2476,10 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) end -- before if match and f > 1 then - local prev = getprev(start) - if prev then + -- local prev = getprev(start) + -- if prev then + if startprev then + local prev = startprev if prev == checkdisc and (sweeptype == "pre" or sweeptype == "replace") then prev = getprev(sweepnode) -- sweeptype = nil @@ -2271,24 +2491,25 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) if prev then local char, id = ischar(prev,currentfont) if char then - local ccd = descriptions[char] - if ccd then - local class = ccd.class + local class = classes[char] + if class then if class == skipmark or class == skipligature or class == skipbase or (markclass and class == "mark" and not markclass[char]) then skipped = true if trace_skips then show_skip(dataset,sequence,char,ck,class) end - prev = getprev(prev) -- moved here + prev = getprev(prev) elseif seq[n][char] then - if n > 1 then -- new test - prev = getprev(prev) -- moved here + if n > 1 then + prev = getprev(prev) end n = n - 1 else if discfound then notmatchreplace[discfound] = true - match = not notmatchpost[discfound] + if notmatchpost[discfound] then + match = false + end else match = false end @@ -2297,17 +2518,20 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) else if discfound then notmatchreplace[discfound] = true - match = not notmatchpost[discfound] + if notmatchpost[discfound] then + match = false + end else match = false end break end - -- prev = getprev(prev) -- moved up elseif char == false then if discfound then notmatchreplace[discfound] = true - match = not notmatchpost[discfound] + if notmatchpost[discfound] then + match = false + end else match = false end @@ -2360,7 +2584,9 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) end else notmatchreplace[prev] = true - match = not notmatchpost[prev] + if notmatchpost[prev] then + match = false + end break end end @@ -2371,7 +2597,7 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) end -- maybe only if match prev = getprev(prev) - elseif seq[n][32] and isspace(prev,threshold) then + elseif seq[n][32] and id == glue_code and isspace(prev,threshold,id) then n = n - 1 prev = getprev(prev) else @@ -2407,9 +2633,8 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) if current then local char, id = ischar(current,currentfont) if char then - local ccd = descriptions[char] - if ccd then - local class = ccd.class + local class = classes[char] + if class then if class == skipmark or class == skipligature or class == skipbase or (markclass and class == "mark" and not markclass[char]) then skipped = true if trace_skips then @@ -2424,7 +2649,9 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) else if discfound then notmatchreplace[discfound] = true - match = not notmatchpre[discfound] + if notmatchpre[discfound] then + match = false + end else match = false end @@ -2433,7 +2660,9 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) else if discfound then notmatchreplace[discfound] = true - match = not notmatchpre[discfound] + if notmatchpre[discfound] then + match = false + end else match = false end @@ -2442,7 +2671,9 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) elseif char == false then if discfound then notmatchreplace[discfound] = true - match = not notmatchpre[discfound] + if notmatchpre[discfound] then + match = false + end else match = false end @@ -2485,7 +2716,10 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) end else notmatchreplace[current] = true - match = notmatchpre[current] + -- different than others, needs checking if "not" is okay + if not notmatchpre[current] then + match = false + end break end end @@ -2497,7 +2731,7 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) end -- maybe only if match current = getnext(current) - elseif seq[n][32] and isspace(current,threshold) then + elseif seq[n][32] and id == glue_code and isspace(current,threshold,id) then n = n + 1 current = getnext(current) else @@ -2515,112 +2749,13 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) end end if match then - -- Can lookups be of a different type? - local diskchain = diskseen or sweepnode if trace_contexts then - local rule = ck[1] - local lookuptype = ck[8] or ck[2] - local first = ck[4] - local last = ck[5] - local char = getchar(start) - logwarning("%s: rule %s matches at char %s for (%s,%s,%s) chars, lookuptype %a", - cref(dataset,sequence),rule,gref(char),first-1,last-first+1,s-last,lookuptype) - end - local chainlookups = ck[6] - if chainlookups then - local nofchainlookups = #chainlookups - -- Lookups can be like { 1, false, 3 } or { false, 2 } or basically anything and - -- #lookups can be less than #current - if size == 1 then - -- if nofchainlookups > size then - -- -- bad rules - -- end - local chainlookup = chainlookups[1] - local chainkind = chainlookup.type - local chainproc = chainprocs[chainkind] - if chainproc then - local ok - if diskchain then - head, start, ok = chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,1,ck,chainproc) - else - head, start, ok = chainproc(head,start,last,dataset,sequence,chainlookup,rlmode,1) - end - if ok then - done = true - end - else - logprocess("%s: %s is not yet supported (1)",cref(dataset,sequence),chainkind) - end - else - -- See LookupType 5: Contextual Substitution Subtable. Now it becomes messy. The - -- easiest case is where #current maps on #lookups i.e. one-to-one. But what if - -- we have a ligature. Cf the spec we then need to advance one character but we - -- really need to test it as there are fonts out there that are fuzzy and have - -- too many lookups: - -- - -- U+1105 U+119E U+1105 U+119E : sourcehansansklight: script=hang ccmp=yes - -- - local i = 1 - while start do - if skipped then - while start do -- todo: use properties - local char = getchar(start) - local ccd = descriptions[char] - if ccd then - local class = ccd.class or "base" - if class == skipmark or class == skipligature or class == skipbase or (markclass and class == "mark" and not markclass[char]) then - start = getnext(start) - else - break - end - else - break - end - end - end - local chainlookup = chainlookups[i] - if chainlookup then - local chainkind = chainlookup.type - local chainproc = chainprocs[chainkind] - if chainproc then - local ok, n - if diskchain then - head, start, ok = chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,i,ck,chainproc) - else - head, start, ok, n = chainproc(head,start,last,dataset,sequence,chainlookup,rlmode,i) - end - -- messy since last can be changed ! - if ok then - done = true - if n and n > 1 and i + n > nofchainlookups then - -- this is a safeguard, we just ignore the rest of the lookups - break - end - end - else - -- actually an error - logprocess("%s: %s is not yet supported (2)",cref(dataset,sequence),chainkind) - end - end - i = i + 1 - if i > size or not start then - break - elseif start then - start = getnext(start) - end - end - end + chaintrac(head,start,dataset,sequence,rlmode,ck,skipped) + end + if diskseen or sweepnode then + head, start, done = chaindisk(head,start,dataset,sequence,rlmode,ck,skipped) else - -- todo: needs checking for holes in the replacements - local replacements = ck[7] - if replacements then - head, start, done = reversesub(head,start,last,dataset,sequence,replacements,rlmode) - else - done = true - if trace_contexts then - logprocess("%s: skipping match",cref(dataset,sequence)) - end - end + head, start, done = chainrun(head,start,last,dataset,sequence,rlmode,ck,skipped) end if done then break -- out of contexts (new, needs checking) @@ -2693,79 +2828,86 @@ end) -- fonts.hashes.sequences = sequencelists -local autofeatures = fonts.analyzers.features -local featuretypes = otf.tables.featuretypes -local defaultscript = otf.features.checkeddefaultscript -local defaultlanguage = otf.features.checkeddefaultlanguage - -local function initialize(sequence,script,language,enabled,autoscript,autolanguage) - local features = sequence.features - if features then - local order = sequence.order - if order then - local featuretype = featuretypes[sequence.type or "unknown"] - for i=1,#order do - local kind = order[i] - local valid = enabled[kind] - if valid then - local scripts = features[kind] - local languages = scripts and ( - scripts[script] or - scripts[wildcard] or - (autoscript and defaultscript(featuretype,autoscript,scripts)) - ) - local enabled = languages and ( - languages[language] or - languages[wildcard] or - (autolanguage and defaultlanguage(featuretype,autolanguage,languages)) - ) - if enabled then - return { valid, autofeatures[kind] or false, sequence, kind } +do -- overcome local limit + + local autofeatures = fonts.analyzers.features + local featuretypes = otf.tables.featuretypes + local defaultscript = otf.features.checkeddefaultscript + local defaultlanguage = otf.features.checkeddefaultlanguage + + local wildcard = "*" + local default = "dflt" + + local function initialize(sequence,script,language,enabled,autoscript,autolanguage) + local features = sequence.features + if features then + local order = sequence.order + if order then + local featuretype = featuretypes[sequence.type or "unknown"] + for i=1,#order do + local kind = order[i] + local valid = enabled[kind] + if valid then + local scripts = features[kind] + local languages = scripts and ( + scripts[script] or + scripts[wildcard] or + (autoscript and defaultscript(featuretype,autoscript,scripts)) + ) + local enabled = languages and ( + languages[language] or + languages[wildcard] or + (autolanguage and defaultlanguage(featuretype,autolanguage,languages)) + ) + if enabled then + return { valid, autofeatures[kind] or false, sequence, kind } + end end end - end - else - -- can't happen - end - end - return false -end - -function otf.dataset(tfmdata,font) -- generic variant, overloaded in context - local shared = tfmdata.shared - local properties = tfmdata.properties - local language = properties.language or "dflt" - local script = properties.script or "dflt" - local enabled = shared.features - local autoscript = enabled and enabled.autoscript - local autolanguage = enabled and enabled.autolanguage - local res = resolved[font] - if not res then - res = { } - resolved[font] = res - end - local rs = res[script] - if not rs then - rs = { } - res[script] = rs - end - local rl = rs[language] - if not rl then - rl = { - -- indexed but we can also add specific data by key - } - rs[language] = rl - local sequences = tfmdata.resources.sequences - if sequences then - for s=1,#sequences do - local v = enabled and initialize(sequences[s],script,language,enabled,autoscript,autolanguage) - if v then - rl[#rl+1] = v + else + -- can't happen + end + end + return false + end + + function otf.dataset(tfmdata,font) -- generic variant, overloaded in context + local shared = tfmdata.shared + local properties = tfmdata.properties + local language = properties.language or "dflt" + local script = properties.script or "dflt" + local enabled = shared.features + local autoscript = enabled and enabled.autoscript + local autolanguage = enabled and enabled.autolanguage + local res = resolved[font] + if not res then + res = { } + resolved[font] = res + end + local rs = res[script] + if not rs then + rs = { } + res[script] = rs + end + local rl = rs[language] + if not rl then + rl = { + -- indexed but we can also add specific data by key + } + rs[language] = rl + local sequences = tfmdata.resources.sequences + if sequences then + for s=1,#sequences do + local v = enabled and initialize(sequences[s],script,language,enabled,autoscript,autolanguage) + if v then + rl[#rl+1] = v + end end end end + return rl end - return rl + end local function report_disc(what,n) @@ -2851,7 +2993,7 @@ local function kernrun(disc,k_run,font,attr,...) done = true end setprev(replace,nest) --- setprev(replace) + -- setprev(replace) setnext(prev,disc) end if next then @@ -2867,13 +3009,15 @@ local function kernrun(disc,k_run,font,attr,...) if k_run(prevmarks,"emptyinjections",next,font,attr,...) then done = true end - setlink(prev,disc) - setlink(disc,next) + setlink(prev,disc,next) end return nextstart, done end -local function comprun(disc,c_run,...) +-- fonts like ebgaramond do ligatuires this way (less efficient than e.g. dejavu which +-- will do the testrun variant) + +local function comprun(disc,c_run,...) -- vararg faster than the whole list if trace_compruns then report_disc("comp",disc) end @@ -2883,7 +3027,7 @@ local function comprun(disc,c_run,...) -- if pre then sweepnode = disc - sweeptype = "pre" -- in alternative code preinjections is uc_c_sed (also used then for proeprties, saves a variable) + sweeptype = "pre" -- in alternative code preinjections is uc_c_sed (also used then for properties, saves a variable) local new, done = c_run(pre,...) if done then pre = new @@ -2997,41 +3141,6 @@ local function testrun(disc,t_run,c_run,...) end end --- A discrun happens when we have a zwnj. We're gpossing so it is unlikely that --- there has been a match changing the character. Now, as we check again here --- the question is: why do we do this ... needs checking as drun seems useless --- ... maybe that code can go away - --- local function discrun(disc,drun,krun) --- local prev, next = getboth(disc) --- if trace_discruns then --- report_disc("disc",disc) --- end --- if next and prev then --- setnext(prev,next) --- -- setprev(next,prev) --- drun(prev) --- setnext(prev,disc) --- -- setprev(next,disc) --- end --- -- --- if krun then -- currently always false --- local pre = getfield(disc,"pre") --- if not pre then --- -- go on --- elseif prev then --- local nest = getprev(pre) --- setlink(prev,pre) --- krun(prev,"preinjections") --- setprev(pre,nest) --- setnext(prev,disc) --- else --- krun(pre,"preinjections") --- end --- end --- return next --- end - -- We can make some assumptions with respect to discretionaries. First of all it is very -- unlikely that some of the analysis related attributes applies. Then we can also assume -- that the ConTeXt specific dynamic attribute is different, although we do use explicit @@ -3057,6 +3166,7 @@ end -- 1{2{\oldstyle\discretionary{3}{4}{5}}6}7\par -- 1{2\discretionary{3{\oldstyle3}}{{\oldstyle4}4}{5{\oldstyle5}5}6}7\par + local nesting = 0 local function c_run_single(head,font,attr,lookupcache,step,dataset,sequence,rlmode,handler) @@ -3071,7 +3181,10 @@ local function c_run_single(head,font,attr,lookupcache,step,dataset,sequence,rlm while start do local char = ischar(start,font) if char then - local a = attr and getattr(start,0) + local a -- happens often so no assignment is faster + if attr then + a = getattr(start,0) + end if not a or (a == attr) then local lookupmatch = lookupcache[char] if lookupmatch then @@ -3105,12 +3218,16 @@ local function t_run_single(start,stop,font,attr,lookupcache) while start ~= stop do local char = ischar(start,font) if char then - local a = attr and getattr(start,0) + local a -- happens often so no assignment is faster + if attr then + a = getattr(start,0) + end + local startnext = getnext(start) if not a or (a == attr) then local lookupmatch = lookupcache[char] if lookupmatch then -- hm, hyphens can match (tlig) so we need to really check -- if we need more than ligatures we can outline the code and use functions - local s = getnext(start) + local s = startnext local l = nil local d = 0 while s do @@ -3134,32 +3251,18 @@ local function t_run_single(start,stop,font,attr,lookupcache) else -- go on can be a mixed one end - start = getnext(start) + start = starttnext else break end end end --- local function d_run_single(prev,font,attr,lookupcache,step,dataset,sequence,rlmode,handler) --- local a = attr and getattr(prev,0) --- if not a or (a == attr) then --- local char = ischar(prev) -- can be disc --- if char then --- local lookupmatch = lookupcache[char] --- if lookupmatch then --- local h, d, ok = handler(head,start,dataset,sequence,lookupmatch,rlmode,step,1) --- if ok then --- done = true --- success = true --- end --- end --- end --- end --- end - local function k_run_single(sub,injection,last,font,attr,lookupcache,step,dataset,sequence,rlmode,handler) - local a = attr and getattr(sub,0) + local a -- happens often so no assignment is faster + if attr then + a = getattr(sub,0) + end if not a or (a == attr) then for n in traverse_nodes(sub) do -- only gpos if n == last then @@ -3191,7 +3294,10 @@ local function c_run_multiple(head,font,attr,steps,nofsteps,dataset,sequence,rlm while start do local char = ischar(start,font) if char then - local a = attr and getattr(start,0) + local a -- happens often so no assignment is faster + if attr then + a = getattr(start,0) + end if not a or (a == attr) then for i=1,nofsteps do local step = steps[i] @@ -3239,7 +3345,11 @@ local function t_run_multiple(start,stop,font,attr,steps,nofsteps) while start ~= stop do local char = ischar(start,font) if char then - local a = attr and getattr(start,0) + local a -- happens often so no assignment is faster + if attr then + a = getattr(start,0) + end + local startnext = getnext(start) if not a or (a == attr) then for i=1,nofsteps do local step = steps[i] @@ -3248,7 +3358,7 @@ local function t_run_multiple(start,stop,font,attr,steps,nofsteps) local lookupmatch = lookupcache[char] if lookupmatch then -- if we need more than ligatures we can outline the code and use functions - local s = getnext(start) + local s = startnext local l = nil local d = 0 while s do @@ -3276,41 +3386,18 @@ local function t_run_multiple(start,stop,font,attr,steps,nofsteps) else -- go on can be a mixed one end - start = getnext(start) + start = startnext else break end end end --- local function d_run_multiple(prev,attr,steps,nofsteps,dataset,sequence,rlmode,handler) --- local a = attr and getattr(prev,0) --- if not a or (a == attr) then --- local char = ischar(prev) -- can be disc --- if char then --- for i=1,nofsteps do --- local step = steps[i] --- local lookupcache = step.coverage --- if lookupcache then --- local lookupmatch = lookupcache[char] --- if lookupmatch then --- -- we could move all code inline but that makes things even more unreadable --- local h, d, ok = handler(head,prev,dataset,sequence,lookupmatch,rlmode,step,i) --- if ok then --- done = true --- break --- end --- end --- else --- report_missing_coverage(dataset,sequence) --- end --- end --- end --- end --- end - local function k_run_multiple(sub,injection,last,font,attr,steps,nofsteps,dataset,sequence,rlmode,handler) - local a = attr and getattr(sub,0) + local a -- happens often so no assignment is faster + if attr then + a = getattr(sub,0) + end if not a or (a == attr) then for n in traverse_nodes(sub) do -- only gpos if n == last then @@ -3342,7 +3429,7 @@ end -- so maybe we no longer need a stack local function txtdirstate(start,stack,top,rlparmode) - local dir = getfield(start,"dir") + local dir = getdir(start) local new = 1 if dir == "+TRT" then top = top + 1 @@ -3366,7 +3453,7 @@ local function txtdirstate(start,stack,top,rlparmode) end local function pardirstate(start) - local dir = getfield(start,"dir") + local dir = getdir(start) local new = 0 if dir == "TLT" then new = 1 @@ -3394,15 +3481,16 @@ local function featuresprocessor(head,font,attr) nesting = nesting + 1 if nesting == 1 then - - currentfont = font - tfmdata = fontdata[font] - descriptions = tfmdata.descriptions - characters = tfmdata.characters - marks = tfmdata.resources.marks + currentfont = font + tfmdata = fontdata[font] + descriptions = tfmdata.descriptions -- only needed in gref so we could pass node there instead + characters = tfmdata.characters -- but this branch is not entered that often anyway + local resources = tfmdata.resources + marks = resources.marks + classes = resources.classes threshold, - factor = getthreshold(font) - checkmarks = tfmdata.properties.checkmarks + factor = getthreshold(font) + checkmarks = tfmdata.properties.checkmarks elseif currentfont ~= font then @@ -3427,14 +3515,9 @@ local function featuresprocessor(head,font,attr) end local rlmode = 0 - local done = false local datasets = otf.dataset(tfmdata,font,attr) - - local forcedisc = alwaysdisc or not attr - local dirstack = { } -- could move outside function but we can have local runs - sweephead = { } -- We could work on sub start-stop ranges instead but I wonder if there is that @@ -3442,8 +3525,8 @@ local function featuresprocessor(head,font,attr) -- to keep track of directions anyway. Also at some point I want to play with -- font interactions and then we do need the full sweeps. - -- Keeping track of the headnode is needed for devanagari (I generalized it a bit - -- so that multiple cases are also covered.) + -- Keeping track of the headnode is needed for devanagari. (I generalized it a bit + -- so that multiple cases are also covered.) We could prepend a temp node. -- We don't goto the next node when a disc node is created so that we can then treat -- the pre, post and replace. It's a bit of a hack but works out ok for most cases. @@ -3455,7 +3538,6 @@ local function featuresprocessor(head,font,attr) local sequence = dataset[3] -- sequences[s] -- also dataset[5] local rlparmode = 0 local topstack = 0 - local success = false local typ = sequence.type local gpossing = typ == "gpos_single" or typ == "gpos_pair" -- store in dataset local handler = handlers[typ] @@ -3465,7 +3547,7 @@ local function featuresprocessor(head,font,attr) -- this permits injection, watch the different arguments local h, d, ok = handler(head,head,dataset,sequence,nil,nil,nil,0,font,attr) if ok then - success = true + done = true if h then head = h end @@ -3476,7 +3558,10 @@ local function featuresprocessor(head,font,attr) while start do local char = ischar(start,font) if char then - local a = attr and getattr(start,0) + local a -- happens often so no assignment is faster + if attr then + a = getattr(start,0) + end if not a or (a == attr) then for i=1,nofsteps do local step = steps[i] @@ -3488,7 +3573,7 @@ local function featuresprocessor(head,font,attr) local ok head, start, ok = handler(head,start,dataset,sequence,lookupmatch,rlmode,step,i) if ok then - success = true + done = true break end end @@ -3518,11 +3603,19 @@ local function featuresprocessor(head,font,attr) while start do local char, id = ischar(start,font) if char then - local a = attr and getattr(start,0) - if a then - a = (a == attr) and (not attribute or getprop(start,a_state) == attribute) - else - a = not attribute or getprop(start,a_state) == attribute + -- local a = attr and getattr(start,0) + -- if a then + -- a = (a == attr) and (not attribute or getprop(start,a_state) == attribute) + -- else + -- a = not attribute or getprop(start,a_state) == attribute + -- end + local a -- happens often so no assignment is faster + if attr then + if getattr(start,0) == attr and (not attribute or getprop(start,a_state) == attribute) then + a = true + end + elseif not attribute or getprop(start,a_state) == attribute then + a = true end if a then local lookupmatch = lookupcache[char] @@ -3530,12 +3623,8 @@ local function featuresprocessor(head,font,attr) local ok head, start, ok = handler(head,start,dataset,sequence,lookupmatch,rlmode,step,1) if ok then - success = true - -- elseif gpossing and zwnjruns and char == zwnj then - -- discrun(start,d_run,font,attr,lookupcache) + done = true end - -- elseif gpossing and zwnjruns and char == zwnj then - -- discrun(start,d_run,font,attr,lookupcache) end if start then start = getnext(start) @@ -3547,26 +3636,16 @@ local function featuresprocessor(head,font,attr) -- whatever glyph start = getnext(start) elseif id == disc_code then - -- ctx: we could assume the same attr as the surrounding glyphs but then we loose - -- the option to have interesting disc nodes (we gain upto 10% on extreme tests); - -- if a disc would have a font field we could even be more strict (see oldstyle test - -- case) - local a = forcedisc or getsubtype(start) == discretionary_code or getattr(start,0) == attr - if a then - -- local attr = false - local ok - if gpossing then - start, ok = kernrun(start,k_run_single, font,attr,lookupcache,step,dataset,sequence,rlmode,handler) - elseif typ == "gsub_ligature" then - start, ok = testrun(start,t_run_single,c_run_single,font,attr,lookupcache,step,dataset,sequence,rlmode,handler) - else - start, ok = comprun(start,c_run_single, font,attr,lookupcache,step,dataset,sequence,rlmode,handler) - end - if ok then - success = true - end + local ok + if gpossing then + start, ok = kernrun(start,k_run_single, font,attr,lookupcache,step,dataset,sequence,rlmode,handler) + elseif typ == "gsub_ligature" then + start, ok = testrun(start,t_run_single,c_run_single,font,attr,lookupcache,step,dataset,sequence,rlmode,handler) else - start = getnext(start) + start, ok = comprun(start,c_run_single, font,attr,lookupcache,step,dataset,sequence,rlmode,handler) + end + if ok then + done = true end elseif id == math_code then start = getnext(end_of_math(start)) @@ -3581,15 +3660,22 @@ local function featuresprocessor(head,font,attr) end else - while start do local char, id = ischar(start,font) if char then - local a = attr and getattr(start,0) - if a then - a = (a == attr) and (not attribute or getprop(start,a_state) == attribute) - else - a = not attribute or getprop(start,a_state) == attribute + -- local a = attr and getattr(start,0) + -- if a then + -- a = (a == attr) and (not attribute or getprop(start,a_state) == attribute) + -- else + -- a = not attribute or getprop(start,a_state) == attribute + -- end + local a -- happens often so no assignment is faster + if attr then + if getattr(start,0) == attr and (not attribute or getprop(start,a_state) == attribute) then + a = true + end + elseif not attribute or getprop(start,a_state) == attribute then + a = true end if a then for i=1,nofsteps do @@ -3602,16 +3688,12 @@ local function featuresprocessor(head,font,attr) local ok head, start, ok = handler(head,start,dataset,sequence,lookupmatch,rlmode,step,i) if ok then - success = true + done = true break elseif not start then -- don't ask why ... shouldn't happen break - -- elseif gpossing and zwnjruns and char == zwnj then - -- discrun(start,d_run,font,attr,steps,nofsteps) end - -- elseif gpossing and zwnjruns and char == zwnj then - -- discrun(start,d_run,font,attr,steps,nofsteps) end else report_missing_coverage(dataset,sequence) @@ -3626,22 +3708,16 @@ local function featuresprocessor(head,font,attr) elseif char == false then start = getnext(start) elseif id == disc_code then - -- see comment above - local a = forcedisc or getsubtype(start) == discretionary_code or getattr(start,0) == attr - if a then - local ok - if gpossing then - start, ok = kernrun(start,k_run_multiple, font,attr,steps,nofsteps,dataset,sequence,rlmode,handler) - elseif typ == "gsub_ligature" then - start, ok = testrun(start,t_run_multiple,c_run_multiple,font,attr,steps,nofsteps,dataset,sequence,rlmode,handler) - else - start, ok = comprun(start,c_run_multiple, font,attr,steps,nofsteps,dataset,sequence,rlmode,handler) - end - if ok then - success = true - end + local ok + if gpossing then + start, ok = kernrun(start,k_run_multiple, font,attr,steps,nofsteps,dataset,sequence,rlmode,handler) + elseif typ == "gsub_ligature" then + start, ok = testrun(start,t_run_multiple,c_run_multiple,font,attr,steps,nofsteps,dataset,sequence,rlmode,handler) else - start = getnext(start) + start, ok = comprun(start,c_run_multiple, font,attr,steps,nofsteps,dataset,sequence,rlmode,handler) + end + if ok then + done = true end elseif id == math_code then start = getnext(end_of_math(start)) @@ -3656,9 +3732,6 @@ local function featuresprocessor(head,font,attr) end end - if success then - done = true - end if trace_steps then -- ? registerstep(head) end diff --git a/tex/context/base/mkiv/font-pre.mkiv b/tex/context/base/mkiv/font-pre.mkiv index 881a577fb..24bb8de54 100644 --- a/tex/context/base/mkiv/font-pre.mkiv +++ b/tex/context/base/mkiv/font-pre.mkiv @@ -676,16 +676,27 @@ \definefontfeature[f:oldstyle] [onum=yes] \definefontfeature[f:tabular] [tnum=yes] \definefontfeature[f:superiors][sups=yes] +\definefontfeature[f:fractions][frac=yes] \definefontfeature[f:kern] [kern=yes] \definefontfeature[f:kerns] [kern=yes] \definealternativestyle [\v!smallcaps] [\setsmallcaps] [\setsmallcaps] \definealternativestyle [\v!oldstyle] [\setoldstyle ] [\setoldstyle ] +\definealternativestyle [\v!fractions] [\setfractions\resetbreakpoints] [\setfractions\resetbreakpoints] \unexpanded\def\setsmallcaps{\doaddfeature{f:smallcaps}} \unexpanded\def\setoldstyle {\doaddfeature{f:oldstyle}} \unexpanded\def\settabular {\doaddfeature{f:tabular}} \unexpanded\def\setsuperiors{\doaddfeature{f:superiors}} +\unexpanded\def\setfractions{\doaddfeature{f:fractions}} + +% \unexpanded\def\frc#1#2% +% {\dontleavehmode +% \begingroup +% \addff{frac}% +% \resetbreakpoints +% #1/#2% +% \endgroup} %D \macros %D {tinyfont} diff --git a/tex/context/base/mkiv/font-sel.lua b/tex/context/base/mkiv/font-sel.lua index 1bfd41c70..455310e14 100644 --- a/tex/context/base/mkiv/font-sel.lua +++ b/tex/context/base/mkiv/font-sel.lua @@ -18,9 +18,9 @@ local formatters = string.formatters local settings_to_array = utilities.parsers.settings_to_array local settings_to_hash = utilities.parsers.settings_to_hash local allocate = utilities.storage.allocate - + local v_default = interfaces.variables.default - + local implement = interfaces.implement local fonts = fonts @@ -49,7 +49,7 @@ local extras = selectfont.extras local alternatives = selectfont.alternatives local presets = selectfont.presets local defaults = selectfont.defaults - + local ctx_definefontsynonym = context.definefontsynonym local ctx_resetfontfallback = context.resetfontfallback local ctx_startfontclass = context.startfontclass @@ -70,7 +70,6 @@ local report_selectfont = logs.reporter("selectfont") local report_files = logs.reporter("selectfont","files") local report_features = logs.reporter("selectfont","features") local report_goodies = logs.reporter("selectfont","goodies") -local report_alternatives = logs.reporter("selectfont","alternatives") local report_typescript = logs.reporter("selectfont","typescripts") defaults["rm"] = { features = { ["sc"] = "*,f:smallcaps" } } @@ -943,4 +942,4 @@ implement { name = "definefontfamilypreset", actions = selectfont.definefontfamilypreset, arguments = { "string", "string" } -} \ No newline at end of file +} diff --git a/tex/context/base/mkiv/font-set.mkvi b/tex/context/base/mkiv/font-set.mkvi index b29545ace..2c6d065d8 100644 --- a/tex/context/base/mkiv/font-set.mkvi +++ b/tex/context/base/mkiv/font-set.mkvi @@ -137,7 +137,7 @@ \unexpanded\def\font_preloads_fourth_stage {\begingroup %ifzeropt\fontcharwd\font\number`!\relax - \setbox\scratchbox\hbox{c o n t e x t}% + \setbox\scratchbox\hpack{\tf c o n t e x t}% \ifzeropt\wd\scratchbox \writeline \writestatus\m!fonts{!! No bodyfont has been defined and no defaults have been}% diff --git a/tex/context/base/mkiv/font-sol.lua b/tex/context/base/mkiv/font-sol.lua index 44c337dd5..82fc3dc40 100644 --- a/tex/context/base/mkiv/font-sol.lua +++ b/tex/context/base/mkiv/font-sol.lua @@ -65,8 +65,9 @@ local getattr = nuts.getattr local getfont = nuts.getfont local getsubtype = nuts.getsubtype local getlist = nuts.getlist +local getdir = nuts.getdir +local getwidth = nuts.getwidth -local setfield = nuts.setfield local setattr = nuts.setattr local setlink = nuts.setlink local setnext = nuts.setnext @@ -425,7 +426,7 @@ function splitters.split(head) if start then flush() end - rlmode = getfield(current,"dir") + rlmode = getdir(current) else if start then flush() @@ -757,8 +758,8 @@ function splitters.optimize(head) for current in traverse_ids(hlist_code,tonut(head)) do line = line + 1 local sign = getfield(current,"glue_sign") - local dir = getfield(current,"dir") - local width = getfield(current,"width") + local dir = getdir(current) + local width = getwidth(current) local list = getlist(current) if not encapsulate and getid(list) == glyph_code then -- nasty .. we always assume a prev being there .. future luatex will always have a leftskip set diff --git a/tex/context/base/mkiv/font-web.lua b/tex/context/base/mkiv/font-web.lua index 8ea57f301..452a8f59b 100644 --- a/tex/context/base/mkiv/font-web.lua +++ b/tex/context/base/mkiv/font-web.lua @@ -12,6 +12,9 @@ if not modules then modules = { } end modules ['font-otr'] = { -- and in a tex environment one can as well store the ttf/otf files in the tex tree. So, -- eventually we might even remove this code when version 1 is obsolete. +local ioopen = io.open +local replacesuffix = file.replacesuffix + local readers = fonts and fonts.handlers.otf.readers local streamreader = readers and readers.streamreader or utilities.files @@ -44,10 +47,22 @@ local infotags = { local report = logs.reporter("fonts","woff") +local runner = sandbox.registerrunner { + name = "woff2otf", + method = "execute", + program = "woff2_decompress", + template = "%inputfile% %outputfile%", + reporter = report, + checkers = { + inputfile = "readable", + outputfile = "writable", + } +} + local function woff2otf(inpname,outname,infoonly) - local outname = outname or file.replacesuffix(inpname,"otf") - local inp = io.open(inpname,"rb") + local outname = outname or replacesuffix(inpname,"otf") + local inp = ioopen(inpname,"rb") if not inp then report("invalid input file %a",inpname) @@ -73,7 +88,12 @@ local function woff2otf(inpname,outname,infoonly) if signature == "wOF2" then inp:close() if false then - os.execute("woff2_decompress " .. inpname .. " " .. outname) + if runner then + runner { + inputfile = inpname, + outputfile = outname, + } + end return outname, flavor else report("skipping version 2 file %a",inpname) @@ -81,7 +101,7 @@ local function woff2otf(inpname,outname,infoonly) end end - local out = io.open(outname,"wb") + local out = ioopen(outname,"wb") if not out then inp:close() diff --git a/tex/context/base/mkiv/grph-con.lua b/tex/context/base/mkiv/grph-con.lua index 380f56b14..65bb91631 100644 --- a/tex/context/base/mkiv/grph-con.lua +++ b/tex/context/base/mkiv/grph-con.lua @@ -16,7 +16,6 @@ local settings_to_array = utilities.parsers.settings_to_array local settings_to_hash = utilities.parsers.settings_to_hash local allocate = utilities.storage.allocate local setmetatableindex = table.setmetatableindex -local replacetemplate = utilities.templates.replace local codeinjections = backends.codeinjections local nodeinjections = backends.nodeinjections @@ -34,7 +33,6 @@ local converters = figures.converters local programs = figures.programs local runprogram = programs.run -local makeuptions = programs.makeoptions do -- eps | ps @@ -47,15 +45,16 @@ do -- eps | ps local epsconverter = converters.eps converters.ps = epsconverter - local epstopdf = { - resolutions = { - [v_low] = "screen", - [v_medium] = "ebook", - [v_high] = "prepress", - }, - command = os.type == "windows" and { "gswin64c", "gswin32c" } or "gs", - -- -dProcessDSCComments=false - argument = longtostring [[ + local resolutions = { + [v_low] = "screen", + [v_medium] = "ebook", + [v_high] = "prepress", + } + + local runner = sandbox.registerrunner { + name = "eps to pdf", + program = { windows = "gswin64c", unix = "gs" }, + template = longtostring [[ -q -sDEVICE=pdfwrite -dNOPAUSE @@ -70,10 +69,17 @@ do -- eps | ps "%oldname%" -c quit ]], + checkers = { + oldname = "readable", + newname = "writable", + presets = "string", + level = "string", + colorspace = "string", + }, } - programs.epstopdf = epstopdf - programs.gs = epstopdf + programs.epstopdf = { resolutions = epstopdf, runner = runner } + programs.gs = programs.epstopdf local cleanups = { } local cleaners = { } @@ -85,9 +91,9 @@ do -- eps | ps * P("%AI3_Cropmarks:") * quadruple * P("%%CropBox:") * quadruple / function(b,h,m,c) - return formatters["%%%%BoundingBox: %i %i %i %i\n%%%%HiResBoundingBox: %F %F %F %F\n%%%%CropBox: %F %F %F %F\n"]( - m[1],m[2],m[3],m[4], - m[1],m[2],m[3],m[4], + return formatters["%%%%BoundingBox: %r %r %r %r\n%%%%HiResBoundingBox: %F %F %F %F\n%%%%CropBox: %F %F %F %F\n"]( + m[1],m[2],m[3],m[4], -- rounded integer + m[1],m[2],m[3],m[4], -- real number m[1],m[2],m[3],m[4] ) end @@ -108,8 +114,7 @@ do -- eps | ps end function epsconverter.pdf(oldname,newname,resolution,colorspace) -- the resolution interface might change - local epstopdf = programs.epstopdf -- can be changed - local presets = epstopdf.resolutions[resolution or "high"] or epstopdf.resolutions.high + local presets = resolutions[resolution or "high"] or resolutions.high local level = codeinjections.getformatoption("pdf_level") or "1.3" local tmpname = oldname if not tmpname or tmpname == "" or not lfs.isfile(tmpname) then @@ -124,13 +129,13 @@ do -- eps | ps else colorspace = nil end - runprogram(epstopdf.command, epstopdf.argument, { + runner { newname = newname, oldname = tmpname, presets = presets, level = tostring(level), colorspace = colorspace, - } ) + } if tmpname ~= oldname then os.remove(tmpname) end @@ -144,29 +149,36 @@ do -- eps | ps end -do -- pdf - - local pdfconverter = converters.pdf - - -- programs.pdftoeps = { - -- command = "pdftops", - -- argument = [[-eps "%oldname%" "%newname%"]], - -- } - -- - -- pdfconverter.stripped = function(oldname,newname) - -- local pdftoeps = programs.pdftoeps -- can be changed - -- local epstopdf = programs.epstopdf -- can be changed - -- local presets = epstopdf.resolutions[resolution or ""] or epstopdf.resolutions.high - -- local level = codeinjections.getformatoption("pdf_level") or "1.3" - -- local tmpname = newname .. ".tmp" - -- runprogram(pdftoeps.command, pdftoeps.argument, { oldname = oldname, newname = tmpname, presets = presets, level = level }) - -- runprogram(epstopdf.command, epstopdf.argument, { oldname = tmpname, newname = newname, presets = presets, level = level }) - -- os.remove(tmpname) - -- end - -- - -- figures.registersuffix("stripped","pdf") - -end +-- do -- pdf +-- +-- local pdfconverter = converters.pdf +-- +-- programs.pdftoeps = { +-- runner = sandbox.registerrunner { +-- name = "pdf to ps", +-- command = "pdftops", +-- template = [[-eps "%oldname%" "%newname%"]], +-- checkers = { +-- oldname = "readable", +-- newname = "writable", +-- } +-- } +-- } +-- +-- pdfconverter.stripped = function(oldname,newname) +-- local pdftoeps = programs.pdftoeps -- can be changed +-- local epstopdf = programs.epstopdf -- can be changed +-- local presets = epstopdf.resolutions[resolution or ""] or epstopdf.resolutions.high +-- local level = codeinjections.getformatoption("pdf_level") or "1.3" +-- local tmpname = newname .. ".tmp" +-- pdftoeps.runner { oldname = oldname, newname = tmpname, presets = presets, level = level } +-- epstopdf.runner { oldname = tmpname, newname = newname, presets = presets, level = level } +-- os.remove(tmpname) +-- end +-- +-- figures.registersuffix("stripped","pdf") +-- +-- end do -- svg @@ -177,34 +189,46 @@ do -- svg -- arguments change again? Ok, it's weirder, with -A then it's a name only when -- not . (current) - programs.inkscape = { - command = "inkscape", - pdfargument = longtostring [[ + local runner = sandbox.registerrunner { + name = "svg to something", + program = "inkscape", + template = longtostring [[ "%oldname%" - --export-dpi=600 - --export-pdf="%newname%" - ]], - pngargument = longtostring [[ - "%oldname%" - --export-dpi=600 - --export-png="%newname%" + --export-dpi=%resolution% + --export-%format%="%newname%" ]], + checkers = { + oldname = "readable", + newname = "writable", + format = "string", + resolution = "string", + }, + defaults = { + format = "pdf", + resolution = "600", + } + } + + programs.inkscape = { + runner = runner, } function svgconverter.pdf(oldname,newname) - local inkscape = programs.inkscape -- can be changed - runprogram(inkscape.command, inkscape.pdfargument, { - newname = expandfilename(newname), - oldname = expandfilename(oldname), - } ) + runner { + format = "pdf", + resolution = "600", + newname = expandfilename(newname), + oldname = expandfilename(oldname), + } end function svgconverter.png(oldname,newname) - local inkscape = programs.inkscape - runprogram(inkscape.command, inkscape.pngargument, { - newname = expandfilename(newname), - oldname = expandfilename(oldname), - } ) + runner { + format = "png", + resolution = "600", + newname = expandfilename(newname), + oldname = expandfilename(oldname), + } end svgconverter.default = svgconverter.pdf @@ -280,81 +304,115 @@ do -- png | jpg | profiles return rgbprofile, cmykprofile end - programs.pngtocmykpdf = { - command = "gm", - argument = [[convert -compress Zip -strip +profile "*" -profile "%rgbprofile%" -profile "%cmykprofile%" -sampling-factor 1x1 "%oldname%" "%newname%"]], + local checkers = { + oldname = "readable", + newname = "writable", + rgbprofile = "string", + cmykprofile = "string", + resolution = "string", + color = "string", } - programs.jpgtocmykpdf = { - command = "gm", - argument = [[convert -compress JPEG -strip +profile "*" -profile "%rgbprofile%" -profile "%cmykprofile%" -sampling-factor 1x1 "%oldname%" "%newname%"]], + local defaults = { + resolution = "600", } - programs.pngtograypdf = { - command = "gm", - argument = [[convert -colorspace gray -compress Zip -sampling-factor 1x1 "%oldname%" "%newname%"]], + local pngtocmykpdf = sandbox.registerrunner { + name = "png to cmyk pdf", + program = "gm", + template = [[convert -compress Zip -strip +profile "*" -profile "%rgbprofile%" -profile "%cmykprofile%" -sampling-factor 1x1 "%oldname%" "%newname%"]], + checkers = checkers, + defaults = defaults, } - programs.jpgtograypdf = { - command = "gm", - argument = [[convert -colorspace gray -compress Zip -sampling-factor 1x1 "%oldname%" "%newname%"]], + local jpgtocmykpdf = sandbox.registerrunner { + name = "jpg to cmyk pdf", + program = "gm", + template = [[convert -compress JPEG -strip +profile "*" -profile "%rgbprofile%" -profile "%cmykprofile%" -sampling-factor 1x1 "%oldname%" "%newname%"]], + checkers = checkers, + defaults = defaults, } + local pngtograypdf = sandbox.registerrunner { + name = "png to gray pdf", + program = "gm", + template = [[convert -colorspace gray -compress Zip -sampling-factor 1x1 "%oldname%" "%newname%"]], + checkers = checkers, + defaults = defaults, + } + + local jpgtograypdf = sandbox.registerrunner { + name = "jpg to gray pdf", + program = "gm", + template = [[convert -colorspace gray -compress Zip -sampling-factor 1x1 "%oldname%" "%newname%"]], + checkers = checkers, + defaults = defaults, + } + + programs.pngtocmykpdf = { runner = pngtocmykpdf } + programs.jpgtocmykpdf = { runner = jpgtocmykpdf } + programs.pngtograypdf = { runner = pngtograypdf } + programs.jpgtograypdf = { runner = jpgtograypdf } + pngconverters["cmyk.pdf"] = function(oldname,newname,resolution) local rgbprofile, cmykprofile = profiles() - runprogram(programs.pngtocmykpdf.command, programs.pngtocmykpdf.argument, { - -- runprogram(programs.pngtocmykpdf, { - rgbprofile = rgbprofile, - cmykprofile = cmykprofile, + pngtocmykpdf { oldname = oldname, newname = newname, - } ) + rgbprofile = rgbprofile, + cmykprofile = cmykprofile, + resolution = resolution, + } end pngconverters["gray.pdf"] = function(oldname,newname,resolution) - runprogram(programs.pngtograypdf.command, programs.pngtograypdf.argument, { - -- runprogram(programs.pngtograypdf, { - oldname = oldname, - newname = newname, - } ) + pngtograypdf { + oldname = oldname, + newname = newname, + resolution = resolution, + } end jpgconverters["cmyk.pdf"] = function(oldname,newname,resolution) local rgbprofile, cmykprofile = profiles() - runprogram(programs.jpgtocmykpdf.command, programs.jpgtocmykpdf.argument, { - -- runprogram(programs.jpgtocmykpdf, { - rgbprofile = rgbprofile, - cmykprofile = cmykprofile, + jpgtocmykpdf { oldname = oldname, newname = newname, - } ) + rgbprofile = rgbprofile, + cmykprofile = cmykprofile, + resolution = resolution, + } end jpgconverters["gray.pdf"] = function(oldname,newname,resolution) - runprogram(programs.jpgtograypdf.command, programs.jpgtograypdf.argument, { - -- runprogram(programs.jpgtograypdf, { - oldname = oldname, - newname = newname, - } ) + jpgtograypdf { + oldname = oldname, + newname = newname, + resolution = resolution, + } end -- recolor - programs.recolor = { - command = "gm", - argument = [[convert -recolor "%color%" "%oldname%" "%newname%"]], + local recolorpng = sandbox.registerrunner { + name = "recolor png", + program = "gm", + template = [[convert -recolor "%color%" "%oldname%" "%newname%"]], + checkers = checkers, + defaults = defaults, } + -- this is now built in so not really needed any more + + programs.recolor = { runner = recolorpng } + pngconverters["recolor.png"] = function(oldname,newname,resolution,arguments) - runprogram ( - programs.recolor.command, - programs.recolor.argument, - { - oldname = oldname, - newname = newname, - color = arguments or ".5 0 0 .7 0 0 .9 0 0", - } - ) + recolorpng { + oldname = oldname, + newname = newname, + resolution = resolution, + color = arguments or ".5 0 0 .7 0 0 .9 0 0", + } end end diff --git a/tex/context/base/mkiv/grph-fil.lua b/tex/context/base/mkiv/grph-fil.lua index e774d097e..3c069da37 100644 --- a/tex/context/base/mkiv/grph-fil.lua +++ b/tex/context/base/mkiv/grph-fil.lua @@ -42,6 +42,16 @@ end job.register('job.files.collected', tobesaved, initializer) +local runner = sandbox.registerrunner { + name = "hashed context run", + program = "context", + template = [[%options% "%filename%"]], + checkers = { + options = "string", + filename = "readable", + } +} + function jobfiles.run(name,action) local usedname = addsuffix(name,inputsuffix) -- we assume tex if not set local oldchecksum = collected[usedname] @@ -55,7 +65,10 @@ function jobfiles.run(name,action) if ta == "function" then action(name) elseif ta == "string" and action ~= "" then + -- can be anything but we assume it gets checked by the sandbox os.execute(action) + elseif ta == "table" then + runner(action) else report_run("processing file, no action given for processing %a",name) end @@ -79,7 +92,7 @@ function jobfiles.context(name,options) else local result = replacesuffix(name,resultsuffix) if not done[result] then - jobfiles.run(name,"context ".. (options or "") .. " " .. name) + jobfiles.run(name, { options = options, filename = name }) done[result] = true end return result diff --git a/tex/context/base/mkiv/grph-inc.lua b/tex/context/base/mkiv/grph-inc.lua index 901d31827..b5e74b4c1 100644 --- a/tex/context/base/mkiv/grph-inc.lua +++ b/tex/context/base/mkiv/grph-inc.lua @@ -47,7 +47,6 @@ local concat, insert, remove = table.concat, table.insert, table.remove local todimen = string.todimen local collapsepath = file.collapsepath local formatters = string.formatters -local expandfilename = dir.expandname local formatcolumns = utilities.formatters.formatcolumns local P, R, S, Cc, C, Cs, Ct, lpegmatch = lpeg.P, lpeg.R, lpeg.S, lpeg.Cc, lpeg.C, lpeg.Cs, lpeg.Ct, lpeg.match @@ -97,16 +96,12 @@ end local report_inclusion = logs.reporter("graphics","inclusion") local report_figures = logs.reporter("system","graphics") local report_figure = logs.reporter("used graphic") -local report_status = logs.reporter("graphics","status") local report_newline = logs.newline local f_hash_part = formatters["%s->%s->%s->%s"] local f_hash_full = formatters["%s->%s->%s->%s->%s->%s->%s->%s"] local v_yes = variables.yes -local v_low = variables.low -local v_medium = variables.medium -local v_high = variables.high local v_global = variables["global"] local v_local = variables["local"] local v_default = variables.default @@ -1636,13 +1631,15 @@ includers.cld = includers.nongeneric setmetatableindex(converters,"table") +-- We keep this helper because it has been around for a while and therefore it can +-- be a depedency in an existing workflow. + function programs.makeoptions(options) local to = type(options) return (to == "table" and concat(options," ")) or (to == "string" and options) or "" end function programs.run(binary,argument,variables) - -- move this check to the runner code local found = nil if type(binary) == "table" then for i=1,#binary do diff --git a/tex/context/base/mkiv/grph-inc.mkiv b/tex/context/base/mkiv/grph-inc.mkiv index 90453b8ed..881bf9713 100644 --- a/tex/context/base/mkiv/grph-inc.mkiv +++ b/tex/context/base/mkiv/grph-inc.mkiv @@ -316,7 +316,7 @@ \edef\p_reference{\externalfigureparameter\c!reference}% % \dostarttagged\t!image\empty - \clf_figure_push + \clf_figure_push { name {\p_grph_include_name}% label {\ifx\p_label\empty\p_grph_include_label\else\p_label\fi}% page {\externalfigureparameter\c!page}% @@ -343,7 +343,7 @@ \ifx\p_height\empty \else height \dimexpr\p_height\relax \fi - \relax + }%\relax \clf_figure_identify \relax \ifconditional\c_grph_include_test_only diff --git a/tex/context/base/mkiv/grph-rul.lua b/tex/context/base/mkiv/grph-rul.lua index 4ac73b6ae..e3d1d8963 100644 --- a/tex/context/base/mkiv/grph-rul.lua +++ b/tex/context/base/mkiv/grph-rul.lua @@ -175,6 +175,7 @@ interfaces.implement { { "name", "string" }, } } , actions = function(t) + -- no nuts ! local rule = userrule(t) local ma = getattribute(a_colormodel) or 1 local ca = getattribute(a_color) diff --git a/tex/context/base/mkiv/l-lpeg.lua b/tex/context/base/mkiv/l-lpeg.lua index 959ca553e..877dae644 100644 --- a/tex/context/base/mkiv/l-lpeg.lua +++ b/tex/context/base/mkiv/l-lpeg.lua @@ -839,28 +839,48 @@ end local p_false = P(false) local p_true = P(true) -local function make(t) - local function making(t) - local p = p_false - local keys = sortedkeys(t) - for i=1,#keys do - local k = keys[i] - if k ~= "" then - local v = t[k] - if v == true then - p = p + P(k) * p_true - elseif v == false then - -- can't happen - else - p = p + P(k) * making(v) - end - end - end - if t[""] then - p = p + p_true - end - return p - end +-- local function making(t) +-- local p = p_false +-- local keys = sortedkeys(t) +-- for i=1,#keys do +-- local k = keys[i] +-- if k ~= "" then +-- local v = t[k] +-- if v == true then +-- p = p + P(k) * p_true +-- elseif v == false then +-- -- can't happen +-- else +-- p = p + P(k) * making(v) +-- end +-- end +-- end +-- if t[""] then +-- p = p + p_true +-- end +-- return p +-- end + +-- local function make(t) +-- local p = p_false +-- local keys = sortedkeys(t) +-- for i=1,#keys do +-- local k = keys[i] +-- if k ~= "" then +-- local v = t[k] +-- if v == true then +-- p = p + P(k) * p_true +-- elseif v == false then +-- -- can't happen +-- else +-- p = p + P(k) * making(v) +-- end +-- end +-- end +-- return p +-- end + +local function make(t,rest) local p = p_false local keys = sortedkeys(t) for i=1,#keys do @@ -872,10 +892,13 @@ local function make(t) elseif v == false then -- can't happen else - p = p + P(k) * making(v) + p = p + P(k) * make(v,v[""]) end end end + if rest then + p = p + p_true + end return p end @@ -990,21 +1013,21 @@ end -- local t = { "a", "abc", "ac", "abe", "abxyz", "xy", "bef","aa" } -- local p = lpeg.Cs((lpeg.utfchartabletopattern(t)/string.upper + 1)^1) --- inspect(lpegmatch(p,"a")) --- inspect(lpegmatch(p,"aa")) --- inspect(lpegmatch(p,"aaaa")) --- inspect(lpegmatch(p,"ac")) --- inspect(lpegmatch(p,"bc")) --- inspect(lpegmatch(p,"zzbczz")) --- inspect(lpegmatch(p,"zzabezz")) --- inspect(lpegmatch(p,"ab")) --- inspect(lpegmatch(p,"abc")) --- inspect(lpegmatch(p,"abe")) --- inspect(lpegmatch(p,"xa")) --- inspect(lpegmatch(p,"bx")) --- inspect(lpegmatch(p,"bax")) --- inspect(lpegmatch(p,"abxyz")) --- inspect(lpegmatch(p,"foobarbefcrap")) +-- inspect(lpegmatch(p,"a")=="A") +-- inspect(lpegmatch(p,"aa")=="AA") +-- inspect(lpegmatch(p,"aaaa")=="AAAA") +-- inspect(lpegmatch(p,"ac")=="AC") +-- inspect(lpegmatch(p,"bc")=="bc") +-- inspect(lpegmatch(p,"zzbczz")=="zzbczz") +-- inspect(lpegmatch(p,"zzabezz")=="zzABEzz") +-- inspect(lpegmatch(p,"ab")=="Ab") +-- inspect(lpegmatch(p,"abc")=="ABC") +-- inspect(lpegmatch(p,"abe")=="ABE") +-- inspect(lpegmatch(p,"xa")=="xA") +-- inspect(lpegmatch(p,"bx")=="bx") +-- inspect(lpegmatch(p,"bax")=="bAx") +-- inspect(lpegmatch(p,"abxyz")=="ABXYZ") +-- inspect(lpegmatch(p,"foobarbefcrap")=="foobArBEFcrAp") -- local t = { ["^"] = 1, ["^^"] = 2, ["^^^"] = 3, ["^^^^"] = 4 } -- local p = lpeg.Cs((lpeg.utfchartabletopattern(t)/t + 1)^1) diff --git a/tex/context/base/mkiv/l-lua.lua b/tex/context/base/mkiv/l-lua.lua index 357153836..adc2c97a8 100644 --- a/tex/context/base/mkiv/l-lua.lua +++ b/tex/context/base/mkiv/l-lua.lua @@ -188,7 +188,7 @@ if lua then lua.mask = load([[τεχ = 1]]) and "utf" or "ascii" end -local flush = io.flush +local flush = io.flush if flush then @@ -199,3 +199,85 @@ if flush then end +-- new + +if ffi and ffi.number then + -- already loaded +else + local okay + + okay, ffi = pcall(require,"ffi") + + if not ffi then + -- an old version + elseif ffi.os == "" or ffi.arch == "" then + -- no ffi support + ffi = nil + elseif ffi.number then + -- luatex + else + -- luajittex + ffi.number = tonumber + end +end + +-- done differently in context +-- +-- if ffi then +-- local load = ffi.load +-- local select = select +-- local type = type +-- local next = next +-- local sort = table.sort +-- local gmatch = string.gmatch +-- local okay = true +-- local control = { } +-- function ffi.load(name,...) +-- if okay == true or okay[name] then +-- return load(name,...) +-- else +-- return nil +-- end +-- end +-- function control.permit(...) +-- if okay == true then +-- okay = { } +-- end +-- for i=1,select("#",...) do +-- local n = select(i,...) +-- local t = type(n) +-- if t == "table" then +-- for i=1,#n do +-- control.permit(n[i]) +-- end +-- elseif t == "string" then +-- for s in gmatch(n,"[^,%s]+") do +-- okay[n] = true +-- end +-- end +-- end +-- end +-- function control.freeze(none) +-- control.permit = function() end +-- control.freeze = function() end +-- if none then +-- okay = { } +-- end +-- end +-- function control.permitted(name) +-- if okay == true then +-- return true +-- elseif type(name) == "string" then +-- return okay[name] or false +-- else +-- -- no helpers yet +-- local t = { } +-- for k, v in next, okay do +-- t[#t+1] = k +-- end +-- sort(t) +-- return t +-- end +-- end +-- ffi.control = control +-- end diff --git a/tex/context/base/mkiv/l-os.lua b/tex/context/base/mkiv/l-os.lua index 0a86ea6d6..5108faeef 100644 --- a/tex/context/base/mkiv/l-os.lua +++ b/tex/context/base/mkiv/l-os.lua @@ -119,7 +119,7 @@ end local execute = os.execute local iopopen = io.popen -function os.resultof(command) +local function resultof(command) local handle = iopopen(command,"r") -- already has flush if handle then local result = handle:read("*all") or "" @@ -130,9 +130,15 @@ function os.resultof(command) end end +os.resultof = resultof + +function os.pipeto(command) + return iopopen(command,"w") -- already has flush +end + if not io.fileseparator then if find(os.getenv("PATH"),";",1,true) then - io.fileseparator, io.pathseparator, os.type = "\\", ";", os.type or "mswin" + io.fileseparator, io.pathseparator, os.type = "\\", ";", os.type or "windows" else io.fileseparator, io.pathseparator, os.type = "/" , ":", os.type or "unix" end @@ -203,17 +209,17 @@ end }) local name, platform = os.name or "linux", os.getenv("MTX_PLATFORM") or "" -local function guess() - local architecture = os.resultof("uname -m") or "" - if architecture ~= "" then - return architecture - end - architecture = os.getenv("HOSTTYPE") or "" - if architecture ~= "" then - return architecture - end - return os.resultof("echo $HOSTTYPE") or "" -end +-- local function guess() +-- local architecture = resultof("uname -m") or "" +-- if architecture ~= "" then +-- return architecture +-- end +-- architecture = os.getenv("HOSTTYPE") or "" +-- if architecture ~= "" then +-- return architecture +-- end +-- return resultof("echo $HOSTTYPE") or "" +-- end -- os.bits = 32 | 64 @@ -245,7 +251,7 @@ elseif name == "linux" then function resolvers.platform(t,k) -- we sometimes have HOSTTYPE set so let's check that first - local platform, architecture = "", os.getenv("HOSTTYPE") or os.resultof("uname -m") or "" + local platform, architecture = "", os.getenv("HOSTTYPE") or resultof("uname -m") or "" if find(architecture,"x86_64",1,true) then platform = "linux-64" elseif find(architecture,"ppc",1,true) then @@ -273,9 +279,9 @@ elseif name == "macosx" then function resolvers.platform(t,k) -- local platform, architecture = "", os.getenv("HOSTTYPE") or "" -- if architecture == "" then - -- architecture = os.resultof("echo $HOSTTYPE") or "" + -- architecture = resultof("echo $HOSTTYPE") or "" -- end - local platform, architecture = "", os.resultof("echo $HOSTTYPE") or "" + local platform, architecture = "", resultof("echo $HOSTTYPE") or "" if architecture == "" then -- print("\nI have no clue what kind of OSX you're running so let's assume an 32 bit intel.\n") platform = "osx-intel" @@ -294,7 +300,7 @@ elseif name == "macosx" then elseif name == "sunos" then function resolvers.platform(t,k) - local platform, architecture = "", os.resultof("uname -m") or "" + local platform, architecture = "", resultof("uname -m") or "" if find(architecture,"sparc",1,true) then platform = "solaris-sparc" else -- if architecture == 'i86pc' @@ -308,7 +314,7 @@ elseif name == "sunos" then elseif name == "freebsd" then function resolvers.platform(t,k) - local platform, architecture = "", os.resultof("uname -m") or "" + local platform, architecture = "", resultof("uname -m") or "" if find(architecture,"amd64",1,true) then platform = "freebsd-amd64" else @@ -323,7 +329,7 @@ elseif name == "kfreebsd" then function resolvers.platform(t,k) -- we sometimes have HOSTTYPE set so let's check that first - local platform, architecture = "", os.getenv("HOSTTYPE") or os.resultof("uname -m") or "" + local platform, architecture = "", os.getenv("HOSTTYPE") or resultof("uname -m") or "" if find(architecture,"x86_64",1,true) then platform = "kfreebsd-amd64" else diff --git a/tex/context/base/mkiv/l-sandbox.lua b/tex/context/base/mkiv/l-sandbox.lua index f7901379c..a95e70395 100644 --- a/tex/context/base/mkiv/l-sandbox.lua +++ b/tex/context/base/mkiv/l-sandbox.lua @@ -8,8 +8,8 @@ if not modules then modules = { } end modules ['l-sandbox'] = { -- We use string instead of function variables, so 'io.open' instead of io.open. That -- way we can still intercept repetetive overloads. One complication is that when we use --- sandboxed function sin helpers in the sanbox checkers, we can get a recursion loop --- so for that vreason we need to keep originals around till we enable the sandbox. +-- sandboxed functions in helpers in the sanbox checkers, we can get a recursion loop +-- so for that reason we need to keep originals around till we enable the sandbox. -- if sandbox then return end @@ -23,6 +23,8 @@ local format = string.format -- no formatters yet local concat = table.concat local sort = table.sort local gmatch = string.gmatch +local gsub = string.gsub +local requiem = require sandbox = { } local sandboxed = false @@ -34,6 +36,7 @@ local originals = { } local comments = { } local trace = false local logger = false +local blocked = { } -- this comes real early, so that we can still alias @@ -139,29 +142,62 @@ function sandbox.overload(func,overload,comment) return func end -function sandbox.initializer(f) - if not sandboxed then - initializers[#initializers+1] = f +local function whatever(specification,what,target) + if type(specification) ~= "table" then + report("%s needs a specification",what) + elseif type(specification.category) ~= "string" or type(specification.action) ~= "function" then + report("%s needs a category and action",what) + elseif not sandboxed then + target[#target+1] = specification elseif trace then - report("already enabled, discarding initializer") + report("already enabled, discarding %s",what) end end -function sandbox.finalizer(f) - if not sandboxed then - finalizers[#finalizers+1] = f - elseif trace then - report("already enabled, discarding finalizer") +function sandbox.initializer(specification) + whatever(specification,"initializer",initializers) +end + +function sandbox.finalizer(specification) + whatever(specification,"finalizer",finalizers) +end + +function require(name) + local n = gsub(name,"^.*[\\/]","") + local n = gsub(n,"[%.].*$","") + local b = blocked[n] + if b then + if trace then + report("using blocked: %s",n) + end + return b + else + if trace then + report("requiring: %s",name) + end + return requiem(name) + end +end + +function blockrequire(name,lib) + if trace then + report("preventing reload of: %s",name) end + blocked[name] = lib or _G[name] +end + +if TEXENGINE == "luajittex" or not ffi then + local ok + ok, ffi = pcall(require,"ffi") end function sandbox.enable() if not sandboxed then for i=1,#initializers do - initializers[i]() + initializers[i].action() end for i=1,#finalizers do - finalizers[i]() + finalizers[i].action() end local nnot = 0 local nyes = 0 @@ -189,22 +225,48 @@ function sandbox.enable() end if #cyes > 0 then sort(cyes) - report(" overloaded known : %s",concat(cyes," | ")) + report("overloaded known: %s",concat(cyes," | ")) end if nyes > 0 then - report(" overloaded unknown : %s",nyes) + report("overloaded unknown: %s",nyes) end if #cnot > 0 then sort(cnot) - report("not overloaded known : %s",concat(cnot," | ")) + report("not overloaded known: %s",concat(cnot," | ")) end if nnot > 0 then - report("not overloaded unknown : %s",nnot) + report("not overloaded unknown: %s",nnot) end if #skip > 0 then sort(skip) - report("not overloaded redefined : %s",concat(skip," | ")) + report("not overloaded redefined: %s",concat(skip," | ")) end + -- + -- if ffi then + -- report("disabling ffi") + -- -- for k, v in next, ffi do + -- -- if k ~= "gc" then + -- -- local t = type(v) + -- -- if t == "function" then + -- -- ffi[k] = function() report("accessing ffi.%s",k) end + -- -- elseif t == "number" then + -- -- ffi[k] = 0 + -- -- elseif t == "string" then + -- -- ffi[k] = "" + -- -- elseif t == "table" then + -- -- ffi[k] = { } + -- -- else + -- -- ffi[k] = false + -- -- end + -- -- end + -- -- end + -- for k, v in next, ffi do + -- if k ~= "gc" then + -- ffi[k] = nil + -- end + -- end + -- end + -- initializers = nil finalizers = nil originals = nil @@ -212,6 +274,13 @@ function sandbox.enable() end end +blockrequire("lfs",lfs) +blockrequire("io",io) +blockrequire("os",os) +blockrequire("ffi",ffi) + +-- require = register(require,"require") + -- we sandbox some of the built-in functions now: -- todo: require diff --git a/tex/context/base/mkiv/l-unicode.lua b/tex/context/base/mkiv/l-unicode.lua index 3dec80013..b913d0cfc 100644 --- a/tex/context/base/mkiv/l-unicode.lua +++ b/tex/context/base/mkiv/l-unicode.lua @@ -1270,3 +1270,35 @@ function utf.chrlen(u) -- u is number (u < 0xFC and 5) or (u < 0xFE and 6) or 0 end + +-- hashing saves a little but not that much in practice +-- +-- local utf32 = table.setmetatableindex(function(t,k) local v = toutf32(k) t[k] = v return v end) + +local extract = bit32.extract +local char = string.char + +function unicode.toutf32string(n) + if n <= 0xFF then + return + char(n) .. + "\000\000\000" + elseif n <= 0xFFFF then + return + char(extract(n, 0,8)) .. + char(extract(n, 8,8)) .. + "\000\000" + elseif n <= 0xFFFFFF then + return + char(extract(n, 0,8)) .. + char(extract(n, 8,8)) .. + char(extract(n,16,8)) .. + "\000" + else + return + char(extract(n, 0,8)) .. + char(extract(n, 8,8)) .. + char(extract(n,16,8)) .. + char(extract(n,24,8)) + end +end diff --git a/tex/context/base/mkiv/lang-dis.lua b/tex/context/base/mkiv/lang-dis.lua index e6ea180b0..34d7ec000 100644 --- a/tex/context/base/mkiv/lang-dis.lua +++ b/tex/context/base/mkiv/lang-dis.lua @@ -13,6 +13,9 @@ local nodes = nodes local tasks = nodes.tasks local nuts = nodes.nuts +local enableaction = tasks.enableaction +local setaction = tasks.setaction + local tonode = nuts.tonode local tonut = nuts.tonut @@ -29,12 +32,17 @@ local getchar = nuts.getchar local setchar = nuts.setchar local getdisc = nuts.getdisc local setdisc = nuts.setdisc +local getlang = nuts.setlang +local getboth = nuts.getboth +local setlist = nuts.setlist +local setlink = nuts.setlink local isglyph = nuts.isglyph local copy_node = nuts.copy local remove_node = nuts.remove local traverse_id = nuts.traverse_id local flush_list = nuts.flush_list +local flush_node = nuts.flush_node local nodecodes = nodes.nodecodes local disccodes = nodes.disccodes @@ -83,7 +91,7 @@ local expanders = { -- todo: take existing penalty setdisc(d,pre,post,replace,explicit_code,tex.exhyphenpenalty) else - setfield(d,"subtype",explicit_code) + setsubtype(d,explicit_code) end return template end, @@ -141,7 +149,7 @@ local expanders = { end end if template then - local language = template and getfield(template,"lang") + local language = template and getlang(template) local data = getlanguagedata(language) local prechar = data.prehyphenchar local postchar = data.posthyphenchar @@ -214,7 +222,7 @@ function languages.showdiscretionaries(v) setattribute(a_visualize,unsetvalue) else -- also nil if not enabled then - nodes.tasks.enableaction("processors","languages.visualizediscretionaries") + enableaction("processors","languages.visualizediscretionaries") enabled = true end setattribute(a_visualize,1) @@ -237,3 +245,71 @@ function languages.serializediscretionary(d) -- will move to tracer ) end +-- -- + +local wiped = 0 + +local function wipe(head,delayed) + local p, n = getboth(delayed) + local _, _, h, _, _, t = getdisc(delayed,true) + if p or n then + if h then + setlink(p,h) + setlink(t,n) + setfield(delayed,"replace") + else + setlink(p,n) + end + end + if head == delayed then + head = h + end + wiped = wiped + 1 + flush_node(delayed) + return head +end + +function languages.flatten(head) + local nuthead = tonut(head) + local delayed = nil + for d in traverse_id(disc_code,nuthead) do + if delayed then + nuthead = wipe(nuthead,delayed) + end + delayed = d + end + if delayed then + return tonode(wipe(nuthead,delayed)), true + else + return head, false + end +end + +function languages.nofflattened() + return wiped -- handy for testing +end + +-- experiment + +local flatten = languages.flatten +local getlist = nodes.getlist + +function nodes.handlers.flattenline(head) + local list = getlist(head) + if list then + flatten(list) + end + return head +end + +function nodes.handlers.flatten(head,where) + if head and (where == "box" or where == "adjusted_hbox") then + return flatten(head) + end + return true +end + +directives.register("hyphenator.flatten",function(v) + setaction("processors","nodes.handlers.flatten",v) + setaction("contributers","nodes.handlers.flattenline",v) +end) diff --git a/tex/context/base/mkiv/lang-hyp.lua b/tex/context/base/mkiv/lang-hyp.lua index b80bb003b..50132bfe1 100644 --- a/tex/context/base/mkiv/lang-hyp.lua +++ b/tex/context/base/mkiv/lang-hyp.lua @@ -78,6 +78,8 @@ if not modules then modules = { } end modules ['lang-hyp'] = { -- ins : when hyphenationbounds 2 or 3 -- adjust : when hyphenationbounds 2 or 3 +-- todo: maybe subtypes (because they have subtle meanings in the line breaking) + local type, rawset, tonumber, next = type, rawset, tonumber, next local P, R, S, Cg, Cf, Ct, Cc, C, Carg, Cs = lpeg.P, lpeg.R, lpeg.S, lpeg.Cg, lpeg.Cf, lpeg.Ct, lpeg.Cc, lpeg.C, lpeg.Carg, lpeg.Cs @@ -652,9 +654,11 @@ if context then local getprev = nuts.getprev local getsubtype = nuts.getsubtype local getlist = nuts.getlist + local getlang = nuts.getlang + local getattrlist = nuts.getattrlist + local setattrlist = nuts.setattrlist local isglyph = nuts.isglyph - local setfield = nuts.setfield local setchar = nuts.setchar local setdisc = nuts.setdisc @@ -993,6 +997,8 @@ if context then [nodecodes.math] = true, } + -- local gf = getfield local gt = setmetatableindex("number") getfield = function(n,f) gt[f] = gt[f] + 1 return gf(n,f) end languages.GETFIELD = gt + function traditional.hyphenate(head) local first = tonut(head) @@ -1045,7 +1051,7 @@ if context then local function insertpenalty() local p = new_penalty(interwordpenalty) - setfield(p,"attr",getfield(last,"attr")) + setattrlist(p,last) if trace_visualize then nuts.setvisual(p,"penalty") end @@ -1233,7 +1239,7 @@ if context then local current = start - local attributes = getfield(start,"attr") -- todo: just copy the last disc .. faster + local attrnode = start -- will be different, just the first char for i=1,rsize do local r = result[i] @@ -1248,8 +1254,8 @@ if context then post = serialize(true,leftchar) end setdisc(disc,pre,post,nil,discretionary_code,hyphenpenalty) - if attributes then - setfield(disc,"attr",attributes) + if attrnode then + setattrlist(disc,attrnode) end -- could be a replace as well insert_before(first,current,disc) @@ -1282,8 +1288,8 @@ if context then end end setdisc(disc,pre,post,replace,discretionary_code,hyphenpenalty) - if attributes then - setfield(disc,"attr",attributes) + if attrnode then + setattrlist(disc,attrnode) end insert_before(first,current,disc) else @@ -1303,7 +1309,7 @@ if context then end - local function inject(leftchar,rightchar,code,attributes) + local function inject(leftchar,rightchar,code,attrnode) if first ~= current then local disc = new_disc() first, current, glyph = remove_node(first,current) @@ -1322,8 +1328,8 @@ if context then pre = copy_node(glyph) setchar(pre,rightchar and rightchar > 0 and rightchar or code) setdisc(disc,pre,post,replace,discretionary_code,hyphenpenalty) - if attributes then - setfield(disc,"attr",attributes) + if attrnode then + setattrlist(disc,attrnode) end end return current @@ -1343,9 +1349,10 @@ if context then while current and current ~= last do -- and current local code, id = isglyph(current) if code then - local lang = getfield(current,"lang") + local lang = getlang(current) if lang ~= language then if dictionary and size > charmin and leftmin + rightmin <= size then + -- only german has many words starting with an uppercase character if categories[word[1]] == "lu" and getfield(start,"uchyph") < 0 then -- skip else @@ -1411,9 +1418,9 @@ if context then -- maybe also a strict mode here: no hyphenation before hyphenchars and skip -- the next set (but then, strict is an option) if code == exhyphenchar then - current = inject(leftexchar,rightexchar,code,getfield(current,"attr")) + current = inject(leftexchar,rightexchar,code,current) elseif hyphenchars and hyphenchars[code] then - current = inject(leftchar,rightchar,code,getfield(current,"attr")) + current = inject(leftchar,rightchar,code,current) end end else @@ -1557,11 +1564,13 @@ if context then local getcount = tex.getcount hyphenators.methods = methods - hyphenators.optimize = false + local optimize = false + + directives.register("hyphenator.optimize", function(v) optimize = v end) function hyphenators.handler(head,groupcode) if usedmethod then - if groupcode == "hbox" and hyphenators.optimize then + if optimize and (groupcode == "hbox" or groupcode == "adjusted_hbox") then if getcount("hyphenstate") > 0 then forced = false return usedmethod(head) diff --git a/tex/context/base/mkiv/lang-rep.lua b/tex/context/base/mkiv/lang-rep.lua index 2e998b7fb..6fde353f7 100644 --- a/tex/context/base/mkiv/lang-rep.lua +++ b/tex/context/base/mkiv/lang-rep.lua @@ -52,11 +52,13 @@ local getchar = nuts.getchar local isglyph = nuts.isglyph local setfield = nuts.setfield +local getfield = nuts.getfield local setattr = nuts.setattr local setlink = nuts.setlink local setnext = nuts.setnext local setprev = nuts.setprev local setchar = nuts.setchar +local setattrlist = nuts.setattrlist local insert_node_before = nuts.insert_before local remove_node = nuts.remove @@ -70,6 +72,8 @@ local new_disc = nodepool.disc local texsetattribute = tex.setattribute local unsetvalue = attributes.unsetvalue +local enableaction = nodes.tasks.enableaction + local v_reset = interfaces.variables.reset local implement = interfaces.implement @@ -222,34 +226,35 @@ function replacements.handler(head) local i = 1 while i <= newlength do local codes = newcodes[i] - local new = nil if type(codes) == "table" then local method = codes[1] if method == "discretionary" then local pre, post, replace = codes[2], codes[3], codes[4] - new = new_disc() if pre then - setfield(new,"pre",tonodes(pre,last)) + pre = tonodes(pre,last) end if post then - setfield(new,"post",tonodes(post,last)) + post = tonodes(post,last) end if replace then - setfield(new,"replace",tonodes(replace,last)) + replace = tonodes(replace,last) end + -- todo: also set attr + local new = new_disc(pre,post,replace) + setattrlist(new,last) head, current = insert_after(head,current,new) elseif method == "noligature" then -- not that efficient to copy but ok for testing local list = codes[2] if list then for i=1,#list do - new = copy_node(last) + local new = copy_node(last) setchar(new,list[i]) setattr(new,a_noligature,1) head, current = insert_after(head,current,new) end else - new = copy_node(last) + local new = copy_node(last) setchar(new,zwnj) head, current = insert_after(head,current,new) end @@ -257,7 +262,7 @@ function replacements.handler(head) -- todo end else - new = copy_node(last) + local new = copy_node(last) setchar(new,codes) head, current = insert_after(head,current,new) end @@ -310,7 +315,7 @@ function replacements.set(n) else n = lists[n].attribute if not enabled then - nodes.tasks.enableaction("processors","languages.replacements.handler") + enableaction("processors","languages.replacements.handler") if trace_replacements then report_replacement("enabling replacement handler") end diff --git a/tex/context/base/mkiv/lang-wrd.lua b/tex/context/base/mkiv/lang-wrd.lua index 38e6187af..8b6e48401 100644 --- a/tex/context/base/mkiv/lang-wrd.lua +++ b/tex/context/base/mkiv/lang-wrd.lua @@ -38,6 +38,7 @@ local getid = nuts.getid local getsubtype = nuts.getsubtype local getchar = nuts.getchar local setattr = nuts.setattr +local getlang = nuts.getlang local isglyph = nuts.isglyph local traverse_nodes = nuts.traverse @@ -45,7 +46,7 @@ local traverse_ids = nuts.traverse_id local wordsdata = words.data local chardata = characters.data -local tasks = nodes.tasks +local enableaction = nodes.tasks.enableaction local unsetvalue = attributes.unsetvalue @@ -161,7 +162,7 @@ local function mark_words(head,whenfound) -- can be optimized and shared while current do local code, id = isglyph(current) if code then - local a = getfield(current,"lang") + local a = getlang(current) if a then if a ~= language then if s > 0 then @@ -234,7 +235,7 @@ function words.enable(settings) if e then e(settings) end - tasks.enableaction("processors","languages.words.check") + enableaction("processors","languages.words.check") enabled = true end diff --git a/tex/context/base/mkiv/lpdf-ano.lua b/tex/context/base/mkiv/lpdf-ano.lua index 138388c7c..e89bda12b 100644 --- a/tex/context/base/mkiv/lpdf-ano.lua +++ b/tex/context/base/mkiv/lpdf-ano.lua @@ -229,7 +229,6 @@ luatex.registerstopactions(function() end end) - local function pdfnametree(destinations) local slices = { } local sorted = table.sortedkeys(destinations) diff --git a/tex/context/base/mkiv/lpdf-mis.lua b/tex/context/base/mkiv/lpdf-mis.lua index 8d2e85ad2..dc3f8560a 100644 --- a/tex/context/base/mkiv/lpdf-mis.lua +++ b/tex/context/base/mkiv/lpdf-mis.lua @@ -442,10 +442,10 @@ local function documentspecification() addtocatalog("Version", pdfconstant(format("1.%s",pdf.getminorversion()))) end --- temp hack: the mediabox is not under our control and has a precision of 4 digits +-- temp hack: the mediabox is not under our control and has a precision of 5 digits local factor = number.dimenfactors.bp -local f_value = formatters["%0.4F"] +local f_value = formatters["%0.5F"] local function boxvalue(n) -- we could share them return pdfverbose(f_value(factor * n)) diff --git a/tex/context/base/mkiv/lpdf-res.lua b/tex/context/base/mkiv/lpdf-res.lua index ca092c772..ac9478488 100644 --- a/tex/context/base/mkiv/lpdf-res.lua +++ b/tex/context/base/mkiv/lpdf-res.lua @@ -12,7 +12,7 @@ local implement = interfaces.implement local nuts = nodes.nuts local tonut = nodes.tonut -local setfield = nuts.setfield +local setwhd = nuts.setwhd local setlist = nuts.setlist local new_hlist = nuts.pool.hlist @@ -29,9 +29,7 @@ function codeinjections.restoreboxresource(index) local hbox = new_hlist() local list, wd, ht, dp = useboxresource(index) setlist(hbox,tonut(list)) - setfield(hbox,"width", wd) - setfield(hbox,"height", ht) - setfield(hbox,"depth", dp) + setwhd(hbox,wd,ht,dp) return hbox -- so we return a nut ! end diff --git a/tex/context/base/mkiv/lpdf-tag.lua b/tex/context/base/mkiv/lpdf-tag.lua index 3167aeb5c..e33c8a811 100644 --- a/tex/context/base/mkiv/lpdf-tag.lua +++ b/tex/context/base/mkiv/lpdf-tag.lua @@ -24,7 +24,7 @@ local nodes = nodes local nodeinjections = backends.pdf.nodeinjections local codeinjections = backends.pdf.codeinjections -local tasks = nodes.tasks +local enableaction = nodes.tasks.enableaction local pdfdictionary = lpdf.dictionary local pdfarray = lpdf.array @@ -602,9 +602,9 @@ end function codeinjections.enabletags(tg,lb) structures.tags.handler = nodeinjections.addtags - tasks.enableaction("shipouts","structures.tags.handler") - tasks.enableaction("shipouts","nodes.handlers.accessibility") - tasks.enableaction("math","noads.handlers.tags") + enableaction("shipouts","structures.tags.handler") + enableaction("shipouts","nodes.handlers.accessibility") + enableaction("math","noads.handlers.tags") -- maybe also textblock if trace_tags then report_tags("enabling structure tags") diff --git a/tex/context/base/mkiv/luat-cbk.lua b/tex/context/base/mkiv/luat-cbk.lua index 2c3bede72..7b28b3be4 100644 --- a/tex/context/base/mkiv/luat-cbk.lua +++ b/tex/context/base/mkiv/luat-cbk.lua @@ -70,9 +70,12 @@ directives.register("system.callbacks.permitoverloads", function(v) end end) -sandbox.initializer(function() - block_overloads = true -end) +sandbox.initializer { + category = "functions", + action = function() + block_overloads = true + end +} if not list then -- otherwise counters get reset diff --git a/tex/context/base/mkiv/luat-cod.lua b/tex/context/base/mkiv/luat-cod.lua index f62396a8e..31860db78 100644 --- a/tex/context/base/mkiv/luat-cod.lua +++ b/tex/context/base/mkiv/luat-cod.lua @@ -6,7 +6,7 @@ if not modules then modules = { } end modules ['luat-cod'] = { license = "see context related readme files" } -local type, loadfile = type, loadfile +local type, loadfile, tonumber = type, loadfile, tonumber local match, gsub, find, format = string.match, string.gsub, string.find, string.format local texconfig, lua = texconfig, lua @@ -96,7 +96,29 @@ local targetpath = "." -- environment.jobname = tex.jobname -- environment.version = tostring(tex.toks.contextversiontoks) -environment.initex = tex.formatname == "" +if LUATEXVERION == nil then + LUATEXVERSION = status.luatex_version/100 + + tonumber(status.luatex_revision)/1000 +end + +if LUATEXENGINE == nil then + LUATEXENGINE = status.luatex_engine and string.lower(status.luatex_engine) + or (find(status.banner,"LuajitTeX") and "luajittex" or "luatex") +end + +if JITSUPPORTED == nil then + JITSUPPORTED = LUATEXENGINE == "luajittex" or jit +end + +if INITEXMODE == nil then + INITEXMODE = status.ini_version +end + +environment.initex = INITEXMODE +environment.initexmode = INITEXMODE +environment.luatexversion = LUATEXVERSION +environment.luatexengine = LUATEXENGINE +environment.jitsupported = JITSUPPORTED if not environment.luafilechunk then diff --git a/tex/context/base/mkiv/luat-exe.lua b/tex/context/base/mkiv/luat-exe.lua index d8d954a30..1e9811218 100644 --- a/tex/context/base/mkiv/luat-exe.lua +++ b/tex/context/base/mkiv/luat-exe.lua @@ -8,66 +8,118 @@ if not modules then modules = { } end modules ['luat-exe'] = { if not sandbox then require("l-sandbox") require("util-sbx") end -- for testing +-- Ok, as usual, after finishing some code, I rewarded myself with searching youtube for +-- new music ... this time I ran into the swedisch group 'wintergatan' (search for: marble +-- machine) ... mechanical computers are so much more fun than the ones needed for running +-- the code below. Nice videos (and shows) too ... + local type = type -local executers = resolvers.executers or { } -resolvers.executers = executers +local executers = resolvers.executers or { } +resolvers.executers = executers -local disablerunners = sandbox.disablerunners -local registerbinary = sandbox.registerbinary -local registerroot = sandbox.registerroot +local disablerunners = sandbox.disablerunners +local disablelibraries = sandbox.disablelibraries +local registerbinary = sandbox.registerbinary +local registerlibrary = sandbox.registerlibrary +local registerroot = sandbox.registerroot -local lpegmatch = lpeg.match +local lpegmatch = lpeg.match -local sc_splitter = lpeg.tsplitat(";") -local cm_splitter = lpeg.tsplitat(",") +local sc_splitter = lpeg.tsplitat(";") +local cm_splitter = lpeg.tsplitat(",") local execution_mode directives.register("system.executionmode", function(v) execution_mode = v end) local execution_list directives.register("system.executionlist", function(v) execution_list = v end) local root_list directives.register("system.rootlist", function(v) root_list = v end) +local library_mode directives.register("system.librarymode", function(v) library_mode = v end) +local library_list directives.register("system.librarylist", function(v) library_list = v end) -sandbox.initializer(function() - if execution_mode == "none" then - -- will be done later - elseif execution_mode == "list" then - if type(execution_list) == "string" then - execution_list = lpegmatch(cm_splitter,execution_list) - end - if type(execution_list) == "table" then - for i=1,#execution_list do - registerbinary(execution_list[i]) +sandbox.initializer { + category = "binaries", + action = function() + if execution_mode == "none" then + -- will be done later + elseif execution_mode == "list" then + if type(execution_list) == "string" then + execution_list = lpegmatch(cm_splitter,execution_list) + end + if type(execution_list) == "table" then + for i=1,#execution_list do + registerbinary(execution_list[i]) + end end + else + registerbinary(true) -- all end - else - -- whatever else we have configured end -end) +} -sandbox.initializer(function() - if type(root_list) == "string" then - root_list = lpegmatch(sc_splitter,root_list) +sandbox.finalizer { + category = "binaries", + action = function() + if execution_mode == "none" then + disablerunners() + end end - if type(root_list) == "table" then - for i=1,#root_list do - local entry = root_list[i] - if entry ~= "" then - registerroot(entry) +} + +sandbox.initializer { + category = "libraries", + action = function() + if library_mode == "none" then + -- will be done later + elseif library_mode == "list" then + if type(library_list) == "string" then + library_list = lpegmatch(cm_splitter,library_list) + end + if type(library_list) == "table" then + for i=1,#library_list do + registerlibrary(library_list[i]) + end end + else + registerlibrary(true) -- all + end + end +} + +sandbox.finalizer { + category = "libraries", + action = function() + if library_mode == "none" then + disablelibraries() end end -end) +} -sandbox.finalizer(function() - if execution_mode == "none" then - disablerunners() +-- A bit of file system protection. + +sandbox.initializer{ + category = "files", + action = function () + if type(root_list) == "string" then + root_list = lpegmatch(sc_splitter,root_list) + end + if type(root_list) == "table" then + for i=1,#root_list do + local entry = root_list[i] + if entry ~= "" then + registerroot(entry) + end + end + end end -end) +} -- Let's prevent abuse of these libraries (built-in support still works). -sandbox.finalizer(function() - mplib = nil - epdf = nil - zip = nil - fontloader = nil -end) +sandbox.finalizer { + category = "functions", + action = function() + mplib = nil + epdf = nil + zip = nil + fontloader = nil + end +} diff --git a/tex/context/base/mkiv/luat-fmt.lua b/tex/context/base/mkiv/luat-fmt.lua index b5ea5685a..fe3c1042c 100644 --- a/tex/context/base/mkiv/luat-fmt.lua +++ b/tex/context/base/mkiv/luat-fmt.lua @@ -51,6 +51,33 @@ end -- The silent option is Taco. It's a bit of a hack because we cannot yet mess -- with directives. In fact, I could probably clean up the maker a bit by now. +local template = [[--ini %primaryflags% --lua="%luafile%" "%texfile%" %secondaryflags% %dump% %redirect%]] +local checkers = { + primaryflags = "string", + secondaryflags = "string", + luafile = "readable", -- "cache" + texfile = "readable", -- "cache" + redirect = "string", + dump = "string", +} + +local runners = { + luatex = sandbox.registerrunner { + name = "make luatex format", + program = "luatex", + template = template, + checkers = checkers, + reporter = report_format, + }, + luajittex = sandbox.registerrunner { + name = "make luajittex format", + program = "luajittex", + template = template, + checkers = checkers, + reporter = report_format, + }, +} + function environment.make_format(name,arguments) local engine = environment.ownmain or "luatex" local silent = environment.arguments.silent @@ -116,13 +143,20 @@ function environment.make_format(name,arguments) return end -- generate format - local dump = os.platform=="unix" and "\\\\dump" or "\\dump" - local command = format("%s --ini %s --lua=%s %s %s %s", - engine,primaryflags(),quoted(usedluastub),quoted(fulltexsourcename),secondaryflags(),dump) - if silent then + local specification = { + primaryflags = primaryflags(), + secondaryflags = secondaryflags(), + luafile = usedluastub, + texfile = fulltexsourcename, + dump = os.platform == "unix" and "\\\\dump" or "\\dump", + } + local runner = runners[engine] + if not runner then + report_format("format %a cannot be generated, no runner available for engine %a",name,engine) + elseif silent then statistics.starttiming() - local command = format("%s > temp.log",command) - local result = os.execute(command) + specification.redirect = "> temp.log" + local result = makeformat(specification) local runtime = statistics.stoptiming() if result ~= 0 then print(format("%s silent make > fatal error when making format %q",engine,name)) -- we use a basic print @@ -131,8 +165,7 @@ function environment.make_format(name,arguments) end os.remove("temp.log") else - report_format("running command: %s\n",command) - os.execute(command) + makeformat(specification) end -- remove related mem files local pattern = file.removesuffix(file.basename(usedluastub)).."-*.mem" diff --git a/tex/context/base/mkiv/luat-ini.lua b/tex/context/base/mkiv/luat-ini.lua index cd1f45692..3ea8551c8 100644 --- a/tex/context/base/mkiv/luat-ini.lua +++ b/tex/context/base/mkiv/luat-ini.lua @@ -25,4 +25,12 @@ if not global then global = _G end -LUATEXVERSION = status.luatex_version/100 + tonumber(status.luatex_revision)/1000 +LUATEXVERSION = status.luatex_version/100 + + tonumber(status.luatex_revision)/1000 + +LUATEXENGINE = status.luatex_engine and string.lower(status.luatex_engine) + or (string.find(status.banner,"LuajitTeX") and "luajittex" or "luatex") + +JITSUPPORTED = LUATEXENGINE == "luajittex" or jit + +INITEXMODE = status.ini_version diff --git a/tex/context/base/mkiv/luat-iop.lua b/tex/context/base/mkiv/luat-iop.lua index e1772af4e..34cc74e3e 100644 --- a/tex/context/base/mkiv/luat-iop.lua +++ b/tex/context/base/mkiv/luat-iop.lua @@ -9,16 +9,19 @@ if not modules then modules = { } end modules ['luat-iop'] = { local cleanedpathlist = resolvers.cleanedpathlist local registerroot = sandbox.registerroot -sandbox.initializer(function() - local function register(str,mode) - local trees = cleanedpathlist(str) - for i=1,#trees do - registerroot(trees[i],mode) +sandbox.initializer { + category = "files", + action = function() + local function register(str,mode) + local trees = cleanedpathlist(str) + for i=1,#trees do + registerroot(trees[i],mode) + end end + register("TEXMF","read") + register("TEXINPUTS","read") + register("MPINPUTS","read") + -- register("TEXMFCACHE","write") + registerroot(".","write") end - register("TEXMF","read") - register("TEXINPUTS","read") - register("MPINPUTS","read") - -- register("TEXMFCACHE","write") - registerroot(".","write") -end) +} diff --git a/tex/context/base/mkiv/lxml-ini.lua b/tex/context/base/mkiv/lxml-ini.lua index 6026b1090..11f634739 100644 --- a/tex/context/base/mkiv/lxml-ini.lua +++ b/tex/context/base/mkiv/lxml-ini.lua @@ -41,6 +41,8 @@ implement { name = "xmldoifelseselfempty", actions = lxml.doifelseempty, arg --------- { name = "xmlflushstripped", actions = lxml.strip, arguments = { "string", true } } implement { name = "xmlall", actions = lxml.all, arguments = { "string", "string" } } implement { name = "xmllastmatch", actions = lxml.lastmatch } +implement { name = "xmlpushmatch", actions = lxml.pushmatch } +implement { name = "xmlpopmatch", actions = lxml.popmatch } implement { name = "xmlatt", actions = lxml.att, arguments = { "string", "string" } } implement { name = "xmllastatt", actions = lxml.lastatt } implement { name = "xmlattdef", actions = lxml.att, arguments = { "string", "string", "string" } } diff --git a/tex/context/base/mkiv/lxml-ini.mkiv b/tex/context/base/mkiv/lxml-ini.mkiv index bf641f10b..6ba6bc8d4 100644 --- a/tex/context/base/mkiv/lxml-ini.mkiv +++ b/tex/context/base/mkiv/lxml-ini.mkiv @@ -82,6 +82,8 @@ \let\xmllast \clf_xmllast \let\xmllastatt \clf_xmllastatt \let\xmllastmatch \clf_xmllastmatch +\let\xmlpushmatch \clf_xmlpushmatch +\let\xmlpopmatch \clf_xmlpopmatch \let\xmlloaddirectives \clf_xmlloaddirectives \let\xmlmain \clf_xmlmain \let\xmlmatch \clf_xmlmatch diff --git a/tex/context/base/mkiv/lxml-lpt.lua b/tex/context/base/mkiv/lxml-lpt.lua index 19d69076a..939a737ab 100644 --- a/tex/context/base/mkiv/lxml-lpt.lua +++ b/tex/context/base/mkiv/lxml-lpt.lua @@ -820,36 +820,38 @@ local pathparser = Ct { "patterns", -- can be made a bit faster by moving some p + V("s_parent") + V("s_self") + V("s_root") - + V("s_ancestor"), + + V("s_ancestor") + + V("s_lastmatch"), shortcuts = V("shortcuts_a") * (spaces * "/" * spaces * V("shortcuts_a"))^0, s_descendant_or_self = (P("***/") + P("/")) * Cc(register_descendant_or_self), --- *** is a bonus s_descendant = P("**") * Cc(register_descendant), - s_child = P("*") * no_nextcolon * Cc(register_child ), - s_parent = P("..") * Cc(register_parent ), - s_self = P("." ) * Cc(register_self ), - s_root = P("^^") * Cc(register_root ), - s_ancestor = P("^") * Cc(register_ancestor ), + s_child = P("*") * no_nextcolon * Cc(register_child), + s_parent = P("..") * Cc(register_parent), + s_self = P("." ) * Cc(register_self), + s_root = P("^^") * Cc(register_root), + s_ancestor = P("^") * Cc(register_ancestor), + s_lastmatch = P("=") * Cc(register_last_match), -- we can speed this up when needed but we cache anyway so ... - descendant = P("descendant::") * Cc(register_descendant ), - child = P("child::") * Cc(register_child ), - parent = P("parent::") * Cc(register_parent ), - self = P("self::") * Cc(register_self ), - root = P('root::') * Cc(register_root ), - ancestor = P('ancestor::') * Cc(register_ancestor ), - descendant_or_self = P('descendant-or-self::') * Cc(register_descendant_or_self ), - ancestor_or_self = P('ancestor-or-self::') * Cc(register_ancestor_or_self ), - -- attribute = P('attribute::') * Cc(register_attribute ), - -- namespace = P('namespace::') * Cc(register_namespace ), - following = P('following::') * Cc(register_following ), - following_sibling = P('following-sibling::') * Cc(register_following_sibling ), - preceding = P('preceding::') * Cc(register_preceding ), - preceding_sibling = P('preceding-sibling::') * Cc(register_preceding_sibling ), - reverse_sibling = P('reverse-sibling::') * Cc(register_reverse_sibling ), - last_match = P('last-match::') * Cc(register_last_match ), + descendant = P("descendant::") * Cc(register_descendant), + child = P("child::") * Cc(register_child), + parent = P("parent::") * Cc(register_parent), + self = P("self::") * Cc(register_self), + root = P('root::') * Cc(register_root), + ancestor = P('ancestor::') * Cc(register_ancestor), + descendant_or_self = P('descendant-or-self::') * Cc(register_descendant_or_self), + ancestor_or_self = P('ancestor-or-self::') * Cc(register_ancestor_or_self), + -- attribute = P('attribute::') * Cc(register_attribute), + -- namespace = P('namespace::') * Cc(register_namespace), + following = P('following::') * Cc(register_following), + following_sibling = P('following-sibling::') * Cc(register_following_sibling), + preceding = P('preceding::') * Cc(register_preceding), + preceding_sibling = P('preceding-sibling::') * Cc(register_preceding_sibling), + reverse_sibling = P('reverse-sibling::') * Cc(register_reverse_sibling), + last_match = P('last-match::') * Cc(register_last_match), selector = P("{") * C((1-P("}"))^1) * P("}") / register_selector, @@ -1197,6 +1199,16 @@ do return lastmatch end + local stack = { } + + function xml.pushmatch() + insert(stack,lastmatch) + end + + function xml.popmatch() + lastmatch = remove(stack) + end + end local applylpath = xml.applylpath diff --git a/tex/context/base/mkiv/lxml-tex.lua b/tex/context/base/mkiv/lxml-tex.lua index fc86b9460..582185ba8 100644 --- a/tex/context/base/mkiv/lxml-tex.lua +++ b/tex/context/base/mkiv/lxml-tex.lua @@ -53,7 +53,8 @@ local xmlinclusions = xml.inclusions local xmlbadinclusions = xml.badinclusions local xmlcontent = xml.content local xmllastmatch = xml.lastmatch - +local xmlpushmatch = xml.pushmatch +local xmlpopmatch = xml.popmatch directives.enable("xml.path.keeplastmatch") @@ -1943,6 +1944,9 @@ function lxml.lastmatch() end end +lxml.pushmatch = xmlpushmatch +lxml.popmatch = xmlpopmatch + function lxml.snippet(id,i) local e = getid(id) if e then diff --git a/tex/context/base/mkiv/math-dir.lua b/tex/context/base/mkiv/math-dir.lua index 6978ba3b5..cba991b84 100644 --- a/tex/context/base/mkiv/math-dir.lua +++ b/tex/context/base/mkiv/math-dir.lua @@ -41,7 +41,7 @@ local insert_node_before = nuts.insert_before local insert_node_after = nuts.insert_after local nodecodes = nodes.nodecodes -local tasks = nodes.tasks +local enableaction = nodes.tasks.enableaction local glyph_code = nodecodes.glyph local hlist_code = nodecodes.hlist @@ -160,7 +160,7 @@ function directions.setmath(n) if trace_directions then report_directions("enabling directions handler") end - tasks.enableaction("math","typesetters.directions.processmath") + enableaction("math","typesetters.directions.processmath") enabled = true end end diff --git a/tex/context/base/mkiv/math-ini.lua b/tex/context/base/mkiv/math-ini.lua index de7592c87..321014d94 100644 --- a/tex/context/base/mkiv/math-ini.lua +++ b/tex/context/base/mkiv/math-ini.lua @@ -189,32 +189,16 @@ local escapes = characters.filters.utf.private.escapes -- not that many so no need to reuse tables -local setmathcharacter - -if LUATEXVERSION > 0.98 then - setmathcharacter = function(class,family,slot,unicode,mset,dset) - if mset and codes[class] then -- regular codes < 7 - setmathcode("global",slot,class,family,unicode) - mset = false - end - if dset and class == open_class or class == close_class or class == middle_class then - setdelcode("global",slot,family,unicode,0,0) - dset = false - end - return mset, dset +local setmathcharacter = function(class,family,slot,unicode,mset,dset) + if mset and codes[class] then -- regular codes < 7 + setmathcode("global",slot,class,family,unicode) + mset = false end -else - setmathcharacter = function(class,family,slot,unicode,mset,dset) - if mset and codes[class] then -- regular codes < 7 - setmathcode("global",slot,{class,family,unicode}) - mset = false - end - if dset and class == open_class or class == close_class or class == middle_class then - setdelcode("global",slot,{family,unicode,0,0}) - dset = false - end - return mset, dset + if dset and class == open_class or class == close_class or class == middle_class then + setdelcode("global",slot,family,unicode,0,0) + dset = false end + return mset, dset end local f_accent = formatters[ [[\ugdef\%s{\Umathaccent 0 "%X "%X }]] ] diff --git a/tex/context/base/mkiv/math-ini.mkiv b/tex/context/base/mkiv/math-ini.mkiv index 90478771e..3b57c56da 100644 --- a/tex/context/base/mkiv/math-ini.mkiv +++ b/tex/context/base/mkiv/math-ini.mkiv @@ -118,6 +118,7 @@ \definesystemattribute[mathcategory] [public] \definesystemattribute[mathmode] [public] \definesystemattribute[mathitalics] [public] +\definesystemattribute[mathkernpairs] [public] \definesystemattribute[mathbidi] [public] \definesystemattribute[mathdomain] [public] @@ -237,7 +238,9 @@ \def\math_m_yes_text[#1]% {\begingroup - \edef\currentmathematics{#1}% check for valid + \doifassignmentelse{#1}% + {\setupcurrentmathematics[#1]}% + {\edef\currentmathematics{#1}}% check for valid \edef\p_openup{\mathematicsparameter\c!openup}% \ifx\p_openup\v!yes \expandafter\math_m_yes_text_openedup @@ -1357,6 +1360,31 @@ % \csname\??mathitalics\mathematicsparameter\s!italics\endcsname % \to \everyswitchmathematics % only in mathematics +%D Math kerns (experiment) + +\installcorenamespace{mathkernpairs} + +\setnewconstant\c_math_kernpairs_attribute\attributeunsetvalue % no real need for an extra constant + +\def\math_kernpairs_initialize + {\ifnum\c_math_kernpairs_attribute=\attributeunsetvalue \else + \clf_initializemathkernpairs % one time + \global\let\math_kernpairs_initialize\relax + \fi} + +\appendtoks + \edef\p_kernpairs{\mathematicsparameter\s!kernpairs}% + \c_math_kernpairs_attribute\ifx\p_kernpairs\v!yes\plusone\else\attributeunsetvalue\fi\relax +\to \everyswitchmathematics % only in mathematics + +\appendtoks + \math_kernpairs_initialize + \attribute\mathkernpairsattribute\c_math_kernpairs_attribute +\to \everymathematics + +\setupmathematics + [\s!kernpairs=\v!no] + %D \macros %D {enablemathpunctuation,disablemathpunctuation} %D diff --git a/tex/context/base/mkiv/math-noa.lua b/tex/context/base/mkiv/math-noa.lua index 2b0d7b73f..fb08c4ef4 100644 --- a/tex/context/base/mkiv/math-noa.lua +++ b/tex/context/base/mkiv/math-noa.lua @@ -56,6 +56,7 @@ local trace_goodies = false registertracker("math.goodies", function local trace_variants = false registertracker("math.variants", function(v) trace_variants = v end) local trace_alternates = false registertracker("math.alternates", function(v) trace_alternates = v end) local trace_italics = false registertracker("math.italics", function(v) trace_italics = v end) +local trace_kernpairs = false registertracker("math.kernpairs", function(v) trace_kernpairs = v end) local trace_domains = false registertracker("math.domains", function(v) trace_domains = v end) local trace_families = false registertracker("math.families", function(v) trace_families = v end) local trace_fences = false registertracker("math.fences", function(v) trace_fences = v end) @@ -71,6 +72,7 @@ local report_goodies = logreporter("mathematics","goodies") local report_variants = logreporter("mathematics","variants") local report_alternates = logreporter("mathematics","alternates") local report_italics = logreporter("mathematics","italics") +local report_kernpairs = logreporter("mathematics","kernpairs") local report_domains = logreporter("mathematics","domains") local report_families = logreporter("mathematics","families") local report_fences = logreporter("mathematics","fences") @@ -86,6 +88,7 @@ local nutstring = nuts.tostring local setfield = nuts.setfield local setlink = nuts.setlink +local setlist = nuts.setlist local setnext = nuts.setnext local setprev = nuts.setprev local setchar = nuts.setchar @@ -101,6 +104,15 @@ local getsubtype = nuts.getsubtype local getchar = nuts.getchar local getfont = nuts.getfont local getattr = nuts.getattr +local getlist = nuts.getlist + +local getnucleus = nuts.getnucleus +local getsub = nuts.getsub +local getsup = nuts.getsup + +local setnucleus = nuts.setnucleus +local setsub = nuts.setsub +local setsup = nuts.setsup local flush_node = nuts.flush local new_node = nuts.new -- todo: pool: math_noad math_sub @@ -139,6 +151,8 @@ noads.handlers = noads.handlers or { } local handlers = noads.handlers local tasks = nodes.tasks +local enableaction = tasks.enableaction +local setaction = tasks.setaction local nodecodes = nodes.nodecodes local noadcodes = nodes.noadcodes @@ -175,6 +189,9 @@ local right_fence_code = fencecodes.right -- this initial stuff is tricky as we can have removed and new nodes with the same address -- the only way out is a free-per-page list of nodes (not bad anyway) +-- local gf = getfield local gt = setmetatableindex("number") getfield = function(n,f) gt[f] = gt[f] + 1 return gf(n,f) end mathematics.GETFIELD = gt +-- local sf = setfield local st = setmetatableindex("number") setfield = function(n,f,v) st[f] = st[f] + 1 sf(n,f,v) end mathematics.SETFIELD = st + local function process(start,what,n,parent) if n then n = n + 1 @@ -223,13 +240,13 @@ local function process(start,what,n,parent) end elseif id == math_noad then -- single characters are like this - local noad = getfield(start,"nucleus") if noad then process(noad,what,n,start) end -- list - noad = getfield(start,"sup") if noad then process(noad,what,n,start) end -- list - noad = getfield(start,"sub") if noad then process(noad,what,n,start) end -- list + local noad = getnucleus(start) if noad then process(noad,what,n,start) end -- list + noad = getsup (start) if noad then process(noad,what,n,start) end -- list + noad = getsub (start) if noad then process(noad,what,n,start) end -- list elseif id == math_char or id == math_textchar or id == math_delim then break elseif id == math_box or id == math_sub then - local noad = getfield(start,"list") if noad then process(noad,what,n,start) end -- list (not getlist !) + local noad = getlist(start) if noad then process(noad,what,n,start) end -- list (not getlist !) elseif id == math_fraction then local noad = getfield(start,"num") if noad then process(noad,what,n,start) end -- list noad = getfield(start,"denom") if noad then process(noad,what,n,start) end -- list @@ -243,15 +260,15 @@ local function process(start,what,n,parent) elseif id == math_fence then local noad = getfield(start,"delim") if noad then process(noad,what,n,start) end -- delimiter elseif id == math_radical then - local noad = getfield(start,"nucleus") if noad then process(noad,what,n,start) end -- list - noad = getfield(start,"sup") if noad then process(noad,what,n,start) end -- list - noad = getfield(start,"sub") if noad then process(noad,what,n,start) end -- list + local noad = getnucleus(start) if noad then process(noad,what,n,start) end -- list + noad = getsup (start) if noad then process(noad,what,n,start) end -- list + noad = getsub (start) if noad then process(noad,what,n,start) end -- list noad = getfield(start,"left") if noad then process(noad,what,n,start) end -- delimiter noad = getfield(start,"degree") if noad then process(noad,what,n,start) end -- list elseif id == math_accent then - local noad = getfield(start,"nucleus") if noad then process(noad,what,n,start) end -- list - noad = getfield(start,"sup") if noad then process(noad,what,n,start) end -- list - noad = getfield(start,"sub") if noad then process(noad,what,n,start) end -- list + local noad = getnucleus(start) if noad then process(noad,what,n,start) end -- list + noad = getsup (start) if noad then process(noad,what,n,start) end -- list + noad = getsub (start) if noad then process(noad,what,n,start) end -- list noad = getfield(start,"accent") if noad then process(noad,what,n,start) end -- list noad = getfield(start,"bot_accent") if noad then process(noad,what,n,start) end -- list -- elseif id == math_style then @@ -270,11 +287,11 @@ local function processnested(current,what,n) local noad = nil local id = getid(current) if id == math_noad then - noad = getfield(current,"nucleus") if noad then process(noad,what,n,current) end -- list - noad = getfield(current,"sup") if noad then process(noad,what,n,current) end -- list - noad = getfield(current,"sub") if noad then process(noad,what,n,current) end -- list + noad = getnucleus(current) if noad then process(noad,what,n,current) end -- list + noad = getsup (current) if noad then process(noad,what,n,current) end -- list + noad = getsub (current) if noad then process(noad,what,n,current) end -- list elseif id == math_box or id == math_sub then - noad = getfield(current,"list") if noad then process(noad,what,n,current) end -- list (not getlist !) + noad = getlist(current) if noad then process(noad,what,n,current) end -- list (not getlist !) elseif id == math_fraction then noad = getfield(current,"num") if noad then process(noad,what,n,current) end -- list noad = getfield(current,"denom") if noad then process(noad,what,n,current) end -- list @@ -288,15 +305,15 @@ local function processnested(current,what,n) elseif id == math_fence then noad = getfield(current,"delim") if noad then process(noad,what,n,current) end -- delimiter elseif id == math_radical then - noad = getfield(current,"nucleus") if noad then process(noad,what,n,current) end -- list - noad = getfield(current,"sup") if noad then process(noad,what,n,current) end -- list - noad = getfield(current,"sub") if noad then process(noad,what,n,current) end -- list + noad = getnucleus(current) if noad then process(noad,what,n,current) end -- list + noad = getsup (current) if noad then process(noad,what,n,current) end -- list + noad = getsub (current) if noad then process(noad,what,n,current) end -- list noad = getfield(current,"left") if noad then process(noad,what,n,current) end -- delimiter noad = getfield(current,"degree") if noad then process(noad,what,n,current) end -- list elseif id == math_accent then - noad = getfield(current,"nucleus") if noad then process(noad,what,n,current) end -- list - noad = getfield(current,"sup") if noad then process(noad,what,n,current) end -- list - noad = getfield(current,"sub") if noad then process(noad,what,n,current) end -- list + noad = getnucleus(current) if noad then process(noad,what,n,current) end -- list + noad = getsup (current) if noad then process(noad,what,n,current) end -- list + noad = getsub (current) if noad then process(noad,what,n,current) end -- list noad = getfield(current,"accent") if noad then process(noad,what,n,current) end -- list noad = getfield(current,"bot_accent") if noad then process(noad,what,n,current) end -- list end @@ -306,11 +323,11 @@ local function processstep(current,process,n,id) local noad = nil local id = id or getid(current) if id == math_noad then - noad = getfield(current,"nucleus") if noad then process(noad,n,current) end -- list - noad = getfield(current,"sup") if noad then process(noad,n,current) end -- list - noad = getfield(current,"sub") if noad then process(noad,n,current) end -- list + noad = getnucleus(current) if noad then process(noad,n,current) end -- list + noad = getsup (current) if noad then process(noad,n,current) end -- list + noad = getsub (current) if noad then process(noad,n,current) end -- list elseif id == math_box or id == math_sub then - noad = getfield(current,"list") if noad then process(noad,n,current) end -- list (not getlist !) + noad = getlist(current) if noad then process(noad,n,current) end -- list (not getlist !) elseif id == math_fraction then noad = getfield(current,"num") if noad then process(noad,n,current) end -- list noad = getfield(current,"denom") if noad then process(noad,n,current) end -- list @@ -324,15 +341,15 @@ local function processstep(current,process,n,id) elseif id == math_fence then noad = getfield(current,"delim") if noad then process(noad,n,current) end -- delimiter elseif id == math_radical then - noad = getfield(current,"nucleus") if noad then process(noad,n,current) end -- list - noad = getfield(current,"sup") if noad then process(noad,n,current) end -- list - noad = getfield(current,"sub") if noad then process(noad,n,current) end -- list + noad = getnucleus(current) if noad then process(noad,n,current) end -- list + noad = getsup (current) if noad then process(noad,n,current) end -- list + noad = getsub (current) if noad then process(noad,n,current) end -- list noad = getfield(current,"left") if noad then process(noad,n,current) end -- delimiter noad = getfield(current,"degree") if noad then process(noad,n,current) end -- list elseif id == math_accent then - noad = getfield(current,"nucleus") if noad then process(noad,n,current) end -- list - noad = getfield(current,"sup") if noad then process(noad,n,current) end -- list - noad = getfield(current,"sub") if noad then process(noad,n,current) end -- list + noad = getnucleus(current) if noad then process(noad,n,current) end -- list + noad = getsup (current) if noad then process(noad,n,current) end -- list + noad = getsub (current) if noad then process(noad,n,current) end -- list noad = getfield(current,"accent") if noad then process(noad,n,current) end -- list noad = getfield(current,"bot_accent") if noad then process(noad,n,current) end -- list end @@ -703,8 +720,8 @@ local function makefence(what,char) local d = new_node(math_delim) local f = new_node(math_fence) if char then - local sym = getfield(char,"nucleus") - local chr = getfield(sym,"char") + local sym = getnucleus(char) + local chr = getchar(sym) local fam = getfield(sym,"fam") if chr == dummyfencechar then chr = 0 @@ -720,9 +737,9 @@ end local function makelist(noad,f_o,o_next,c_prev,f_c,middle) local list = new_node(math_sub) - setfield(list,"head",f_o) + setlist(list,f_o) setsubtype(noad,noad_inner) - setfield(noad,"nucleus",list) + setnucleus(noad,list) setlink(f_o,o_next) setlink(c_prev,f_c) if middle and next(middle) then @@ -733,12 +750,11 @@ local function makelist(noad,f_o,o_next,c_prev,f_c,middle) if m then local next = getnext(current) local fence = makefence(middle_fence_code,current) - setfield(current,"nucleus",nil) + setnucleus(current) flush_node(current) middle[current] = nil -- replace_node - setlink(prev,fence) - setlink(fence,next) + setlink(prev,fence,next) prev = fence current = next else @@ -758,7 +774,7 @@ local function convert_both(open,close,middle) local f_o = makefence(left_fence_code,open) local f_c = makefence(right_fence_code,close) makelist(open,f_o,o_next,c_prev,f_c,middle) - setfield(close,"nucleus",nil) + setnucleus(close) flush_node(close) if c_next then setprev(c_next,open) @@ -877,7 +893,7 @@ implement { name = "enableautofences", onlyonce = true, actions = function() - tasks.enableaction("math","noads.handlers.autofences") + enableaction("math","noads.handlers.autofences") enabled = true end } @@ -904,8 +920,8 @@ local function replace(pointer,what,n,parent) local start_super, stop_super, start_sub, stop_sub local mode = "unset" while next and getid(next) == math_noad do - local nextnucleus = getfield(next,"nucleus") - if nextnucleus and getid(nextnucleus) == math_char and not getfield(next,"sub") and not getfield(next,"sup") then + local nextnucleus = getnucleus(next) + if nextnucleus and getid(nextnucleus) == math_char and not getsub(next) and not getsup(next) then local char = getchar(nextnucleus) local s = superscripts[char] if s then @@ -948,11 +964,11 @@ local function replace(pointer,what,n,parent) end if start_super then if start_super == stop_super then - setfield(pointer,"sup",getfield(start_super,"nucleus")) + setsup(pointer,getnucleus(start_super)) else local list = new_node(math_sub) -- todo attr - setfield(list,"list",start_super) - setfield(pointer,"sup",list) + setlist(list,start_super) + setsup(pointer,list) end if mode == "super" then setnext(pointer,getnext(stop_super)) @@ -961,11 +977,11 @@ local function replace(pointer,what,n,parent) end if start_sub then if start_sub == stop_sub then - setfield(pointer,"sub",getfield(start_sub,"nucleus")) + setsub(pointer,getnucleus(start_sub)) else local list = new_node(math_sub) -- todo attr - setfield(list,"list",start_sub) - setfield(pointer,"sub",list) + setlist(list,start_sub) + setsub(pointer,list) end if mode == "sub" then setnext(pointer,getnext(stop_sub)) @@ -1237,9 +1253,9 @@ local c_negative_d = "trace:dr" local function insert_kern(current,kern) local sub = new_node(math_sub) -- todo: pool local noad = new_node(math_noad) -- todo: pool - setfield(sub,"list",kern) + setlist(sub,kern) setnext(kern,noad) - setfield(noad,"nucleus",current) + setnucleus(noad,current) return sub end @@ -1341,7 +1357,7 @@ end local enable enable = function() - tasks.enableaction("math", "noads.handlers.italics") + enableaction("math", "noads.handlers.italics") if trace_italics then report_italics("enabling math italics") end @@ -1393,6 +1409,80 @@ implement { actions = mathematics.resetitalics } +do + + -- math kerns (experiment) in goodies: + -- + -- mathematics = { + -- kernpairs = { + -- [0x1D44E] = { + -- [0x1D44F] = 400, -- 𝑎𝑏 + -- } + -- }, + -- } + + local a_kernpairs = privateattribute("mathkernpairs") + local kernpairs = { } + + local function enable() + enableaction("math", "noads.handlers.kernpairs") + if trace_kernpairs then + report_kernpairs("enabling math kern pairs") + end + enable = false + end + + implement { + name = "initializemathkernpairs", + actions = enable, + onlyonce = true, + } + + local hash = setmetatableindex(function(t,font) + local g = fontdata[font].goodies + local m = g and g[1].mathematics + local k = m and m.kernpairs + t[font] = k + return k + end) + + kernpairs[math_char] = function(pointer,what,n,parent) + if getattr(pointer,a_kernpairs) == 1 then + local font = getfont(pointer) + local list = hash[font] + if list then + local first = getchar(pointer) + local found = list[first] + if found then + local next = getnext(parent) + if next and getid(next) == math_noad then + pointer = getnucleus(next) + if pointer then + if getfont(pointer) == font then + local second = getchar(pointer) + local kern = found[second] + if kern then + kern = kern * fonts.hashes.parameters[font].hfactor + if trace_kernpairs then + report_kernpairs("adding %p kerning between %C and %C",kern,first,second) + end + setlink(parent,new_kern(kern),getnext(parent)) + end + end + end + end + end + end + end + end + + function handlers.kernpairs(head,style,penalties) + processnoads(head,kernpairs,"kernpairs") + return true + end + +end + -- primes and such local collapse = { } processors.collapse = collapse @@ -1437,30 +1527,30 @@ local validpair = { local function movesubscript(parent,current_nucleus,current_char) local prev = getprev(parent) if prev and getid(prev) == math_noad then - if not getfield(prev,"sup") and not getfield(prev,"sub") then + if not getsup(prev) and not getsub(prev) then -- {f} {'}_n => f_n^' setchar(current_nucleus,movesub[current_char or getchar(current_nucleus)]) - local nucleus = getfield(parent,"nucleus") - local sub = getfield(parent,"sub") - local sup = getfield(parent,"sup") - setfield(prev,"sup",nucleus) - setfield(prev,"sub",sub) + local nucleus = getnucleus(parent) + local sub = getsub(parent) + local sup = getsup(parent) + setsup(prev,nucleus) + setsub(prev,sub) local dummy = copy_node(nucleus) setchar(dummy,0) - setfield(parent,"nucleus",dummy) - setfield(parent,"sub",nil) + setnucleus(parent,dummy) + setsub(parent) if trace_collapsing then report_collapsing("fixing subscript") end - elseif not getfield(prev,"sup") then + elseif not getsup(prev) then -- {f} {'}_n => f_n^' setchar(current_nucleus,movesub[current_char or getchar(current_nucleus)]) - local nucleus = getfield(parent,"nucleus") - local sup = getfield(parent,"sup") - setfield(prev,"sup",nucleus) + local nucleus = getnucleus(parent) + local sup = getsup(parent) + setsup(prev,nucleus) local dummy = copy_node(nucleus) setchar(dummy,0) - setfield(parent,"nucleus",dummy) + setnucleus(parent,dummy) if trace_collapsing then report_collapsing("fixing subscript") end @@ -1471,16 +1561,16 @@ end local function collapsepair(pointer,what,n,parent,nested) -- todo: switch to turn in on and off if parent then if validpair[getsubtype(parent)] then - local current_nucleus = getfield(parent,"nucleus") + local current_nucleus = getnucleus(parent) if getid(current_nucleus) == math_char then local current_char = getchar(current_nucleus) - if not getfield(parent,"sub") and not getfield(parent,"sup") then + if not getsub(parent) and not getsup(parent) then local mathpair = mathpairs[current_char] if mathpair then local next_noad = getnext(parent) if next_noad and getid(next_noad) == math_noad then if validpair[getsubtype(next_noad)] then - local next_nucleus = getfield(next_noad,"nucleus") + local next_nucleus = getnucleus(next_noad) local next_char = getchar(next_nucleus) if getid(next_nucleus) == math_char then local newchar = mathpair[next_char] @@ -1498,10 +1588,10 @@ local function collapsepair(pointer,what,n,parent,nested) -- todo: switch to tur else setnext(parent) end - setfield(parent,"sup",getfield(next_noad,"sup")) - setfield(parent,"sub",getfield(next_noad,"sub")) - setfield(next_noad,"sup",nil) - setfield(next_noad,"sub",nil) + setsup(parent,getsup(next_noad)) + setsub(parent,getsub(next_noad)) + setsup(next_noad) + setsub(next_noad) flush_node(next_noad) collapsepair(pointer,what,n,parent,true) -- if not nested and movesub[current_char] then @@ -1560,7 +1650,7 @@ variants[math_char] = function(pointer,what,n,parent) -- also set export value if selector then local next = getnext(parent) if next and getid(next) == math_noad then - local nucleus = getfield(next,"nucleus") + local nucleus = getnucleus(next) if nucleus and getid(nucleus) == math_char and getchar(nucleus) == selector then local variant local tfmdata = fontdata[getfont(pointer)] @@ -1630,7 +1720,7 @@ function handlers.classes(head,style,penalties) end registertracker("math.classes",function(v) - tasks.setaction("math","noads.handlers.classes",v) + setaction("math","noads.handlers.classes",v) end) -- experimental @@ -1676,7 +1766,7 @@ do local enable enable = function() - tasks.enableaction("math", "noads.handlers.domains") + enableaction("math", "noads.handlers.domains") if trace_domains then report_domains("enabling math domains") end @@ -1799,7 +1889,7 @@ function handlers.showtree(head,style,penalties) end registertracker("math.showtree",function(v) - tasks.setaction("math","noads.handlers.showtree",v) + setaction("math","noads.handlers.showtree",v) end) -- also for me @@ -1813,7 +1903,7 @@ end registertracker("math.makeup",function(v) visual = v - tasks.setaction("math","noads.handlers.makeup",v) + setaction("math","noads.handlers.makeup",v) end) -- the normal builder diff --git a/tex/context/base/mkiv/math-tag.lua b/tex/context/base/mkiv/math-tag.lua index 975b894ec..13c8fffc7 100644 --- a/tex/context/base/mkiv/math-tag.lua +++ b/tex/context/base/mkiv/math-tag.lua @@ -30,6 +30,8 @@ local getdisc = nuts.getdisc local getsubtype = nuts.getsubtype local getattr = nuts.getattr local setattr = nuts.setattr +local getcomponents = nuts.getcomponents +local getwidth = nuts.getwidth local set_attributes = nuts.setattributes local traverse_nodes = nuts.traverse @@ -250,7 +252,7 @@ process = function(start) -- we cannot use the processor as we have no finalizer if tag == "formulacaption" then -- skip elseif tag == "mstacker" then - local list = getfield(start,"list") + local list = getlist(start) if list then process(list) end @@ -260,7 +262,7 @@ process = function(start) -- we cannot use the processor as we have no finalizer end local text = start_tagged(tag) setattr(start,a_tagged,text) - local list = getfield(start,"list") + local list = getlist(start) if not list then -- empty list elseif not attr then @@ -315,7 +317,7 @@ process = function(start) -- we cannot use the processor as we have no finalizer if id == hlist_code or id == vlist_code then runner(getlist(n),depth+1) elseif id == glyph_code then - runner(getfield(n,"components"),depth+1) -- this should not be needed + runner(getcomponents(n),depth+1) -- this should not be needed elseif id == disc_code then local pre, post, replace = getdisc(n) runner(pre,depth+1) -- idem @@ -335,7 +337,7 @@ process = function(start) -- we cannot use the processor as we have no finalizer stop_tagged() end elseif id == math_sub_code then -- normally a hbox - local list = getfield(start,"list") + local list = getlist(start) if list then local attr = getattr(start,a_tagged) local last = attr and taglist[attr] @@ -526,7 +528,7 @@ process = function(start) -- we cannot use the processor as we have no finalizer processsubsup(start) end elseif id == glue_code then - -- setattr(start,a_tagged,start_tagged("mspace",{ width = getfield(start,"width") })) + -- setattr(start,a_tagged,start_tagged("mspace",{ width = getwidth(start) })) setattr(start,a_tagged,start_tagged("mspace")) stop_tagged() else diff --git a/tex/context/base/mkiv/meta-imp-txt.mkiv b/tex/context/base/mkiv/meta-imp-txt.mkiv index c6ecc6f03..b2a6d6d1d 100644 --- a/tex/context/base/mkiv/meta-imp-txt.mkiv +++ b/tex/context/base/mkiv/meta-imp-txt.mkiv @@ -289,6 +289,9 @@ fi ; fi ; endfor ; + if TraceRot : + draw boundingbox currentpicture withpen pencircle scaled .25pt withcolor blue ; + fi ; enddef ; \stopMPdefinitions diff --git a/tex/context/base/mkiv/meta-tex.lua b/tex/context/base/mkiv/meta-tex.lua index 205024fae..71207975d 100644 --- a/tex/context/base/mkiv/meta-tex.lua +++ b/tex/context/base/mkiv/meta-tex.lua @@ -241,7 +241,7 @@ local f_exptext = formatters[ [[textext("\mathematics{%s\times10^{%s}}")]] ] local mpprint = mp.print -function mp.format(fmt,str) +function mp.format(fmt,str) -- bah, this overloads mp.format in mlib-lua.lua fmt = lpegmatch(cleaner,fmt) mpprint(f_textext(formatters[fmt](metapost.untagvariable(str,false)))) end diff --git a/tex/context/base/mkiv/mlib-lua.lua b/tex/context/base/mkiv/mlib-lua.lua index 8f24124b9..4198a7339 100644 --- a/tex/context/base/mkiv/mlib-lua.lua +++ b/tex/context/base/mkiv/mlib-lua.lua @@ -202,7 +202,7 @@ end local replacer = lpeg.replacer("@","%%") -function mp.format(fmt,...) +function mp.fprint(fmt,...) n = n + 1 if not find(fmt,"%%") then fmt = lpegmatch(replacer,fmt) @@ -539,3 +539,95 @@ mp._get_toks_ = mp.gettoks mp._set_dimen_ = mp.setdimen mp._set_count_ = mp.setcount mp._set_toks_ = mp.settoks + +-- position fun + +do + + local mprint = mp.print + local fprint = mp.fprint + local qprint = mp.quoted + local getwhd = job.positions.whd + local getxy = job.positions.xy + local getposition = job.positions.position + local getpage = job.positions.page + local getregion = job.positions.region + local getmacro = tokens.getters.macro + + function mp.positionpath(name) + local w, h, d = getwhd(name) + if w then + fprint("((%p,%p)--(%p,%p)--(%p,%p)--(%p,%p)--cycle)",0,-d,w,-d,w,h,0,h) + else + mprint("(origin--cycle)") + end + end + + function mp.positioncurve(name) + local w, h, d = getwhd(name) + if w then + fprint("((%p,%p)..(%p,%p)..(%p,%p)..(%p,%p)..cycle)",0,-d,w,-d,w,h,0,h) + else + mprint("(origin--cycle)") + end + end + + function mp.positionbox(name) + local p, x, y, w, h, d = getposition(name) + if p then + fprint("((%p,%p)--(%p,%p)--(%p,%p)--(%p,%p)--cycle)",x,y-d,x+w,y-d,x+w,y+h,x,y+h) + else + mprint("(%p,%p)",x,y) + end + end + + function mp.positionxy(name) + local x, y = getxy(name) + if x then + fprint("(%p,%p)",x,y) + else + mprint("origin") + end + end + + function mp.positionpage(name) + local p = getpage(name) + if p then + fprint("%p",p) + else + mprint("0") + end + end + + function mp.positionregion(name) + local r = getregion(name) + if r then + qprint(r) + else + qprint("unknown") + end + end + + function mp.positionwhd(name) + local w, h, d = getwhd(name) + if w then + fprint("(%p,%p,%p)",w,h,d) + else + mprint("(0,0,0)") + end + end + + function mp.positionpxy(name) + local p, x, y = getposition(name) + if p then + fprint("(%p,%p,%p)",p,x,y) + else + mprint("(0,0,0)") + end + end + + function mp.positionanchor() + qprint(getmacro("MPanchorid")) + end + +end diff --git a/tex/context/base/mkiv/mlib-pps.lua b/tex/context/base/mkiv/mlib-pps.lua index d08d5ddb7..8c7910d16 100644 --- a/tex/context/base/mkiv/mlib-pps.lua +++ b/tex/context/base/mkiv/mlib-pps.lua @@ -13,9 +13,11 @@ local insert, remove, concat = table.insert, table.remove, table.concat local Cs, Cf, C, Cg, Ct, P, S, V, Carg = lpeg.Cs, lpeg.Cf, lpeg.C, lpeg.Cg, lpeg.Ct, lpeg.P, lpeg.S, lpeg.V, lpeg.Carg local lpegmatch, tsplitat, tsplitter = lpeg.match, lpeg.tsplitat, lpeg.tsplitter local formatters = string.formatters +local exists, savedata = io.exists, io.savedata -local mplib, metapost, lpdf, context = mplib, metapost, lpdf, context - +local mplib = mplib +local metapost = metapost +local lpdf = lpdf local context = context local implement = interfaces.implement @@ -761,11 +763,33 @@ implement { arguments = "string" } +local pdftompy = sandbox.registerrunner { + name = "mpy:pstoedit", + program = "pstoedit", + template = "-ssp -dt -f mpost %pdffile% %mpyfile%", + checkers = { + pdffile = "writable", + mpyfile = "readable", + }, + reporter = report_metapost, +} + +local textopdf = sandbox.registerrunner { + name = "mpy:context", + program = "context", + template = "--once %runmode% %texfile%", + checkers = { + runmode = "string", + texfile = "readable", + }, + reporter = report_metapost, +} + function makempy.processgraphics(graphics) if #graphics == 0 then return end - if mpyfilename and io.exists(mpyfilename) then + if mpyfilename and exists(mpyfilename) then report_metapost("using file: %s",mpyfilename) return end @@ -775,16 +799,17 @@ function makempy.processgraphics(graphics) local mpyfile = file.replacesuffix(mpofile,"mpy") local pdffile = file.replacesuffix(mpofile,"pdf") local texfile = file.replacesuffix(mpofile,"tex") - io.savedata(texfile, { start, preamble, metapost.tex.get(), concat(graphics,"\n"), stop }, "\n") - local command = format("context --once %s %s", (tex.interactionmode == 0 and "--batchmode") or "", texfile) - os.execute(command) - if io.exists(pdffile) then - command = format("pstoedit -ssp -dt -f mpost %s %s", pdffile, mpyfile) - logs.newline() - report_metapost("running: %s",command) - logs.newline() - os.execute(command) - if io.exists(mpyfile) then + savedata(texfile, { start, preamble, metapost.tex.get(), concat(graphics,"\n"), stop }, "\n") + textopdf { + runmode = tex.interactionmode == 0 and "--batchmode" or "", + texfile = texfile, + } + if exists(pdffile) then + pdftompy { + pdffile = pdffile, + mpyfile = mpyfile, + } + if exists(mpyfile) then local result, r = { }, 0 local data = io.loaddata(mpyfile) if data and #data > 0 then @@ -792,7 +817,7 @@ function makempy.processgraphics(graphics) r = r + 1 result[r] = formatters["begingraphictextfig%sendgraphictextfig ;\n"](figure) end - io.savedata(mpyfile,concat(result,"")) + savedata(mpyfile,concat(result,"")) end end end diff --git a/tex/context/base/mkiv/mult-def.lua b/tex/context/base/mkiv/mult-def.lua index 69484a90f..7cee595cd 100644 --- a/tex/context/base/mkiv/mult-def.lua +++ b/tex/context/base/mkiv/mult-def.lua @@ -15238,6 +15238,9 @@ return { ["oldstyle"]={ ["en"]="oldstyle", }, + ["fractions"]={ + ["en"]="fractions", + }, ["on"]={ ["cs"]="zap", ["de"]="an", diff --git a/tex/context/base/mkiv/mult-low.lua b/tex/context/base/mkiv/mult-low.lua index ea1c169ea..23ee8688f 100644 --- a/tex/context/base/mkiv/mult-low.lua +++ b/tex/context/base/mkiv/mult-low.lua @@ -401,6 +401,7 @@ return { "cldprocessfile", "cldloadfile", "cldcontext", "cldcommand", -- "carryoverpar", + "lastlinewidth", -- "assumelongusagecs", -- diff --git a/tex/context/base/mkiv/mult-prm.lua b/tex/context/base/mkiv/mult-prm.lua index 4f01b66b6..ef6a5a0ad 100644 --- a/tex/context/base/mkiv/mult-prm.lua +++ b/tex/context/base/mkiv/mult-prm.lua @@ -315,6 +315,7 @@ return { "pdfvariable", "postexhyphenchar", "posthyphenchar", + "predisplaygapfactor", "preexhyphenchar", "prehyphenchar", "primitive", @@ -1139,6 +1140,7 @@ return { "postexhyphenchar", "posthyphenchar", "predisplaydirection", + "predisplaygapfactor", "predisplaypenalty", "predisplaysize", "preexhyphenchar", diff --git a/tex/context/base/mkiv/mult-sys.mkiv b/tex/context/base/mkiv/mult-sys.mkiv index 914929ab1..bd3ff9b3d 100644 --- a/tex/context/base/mkiv/mult-sys.mkiv +++ b/tex/context/base/mkiv/mult-sys.mkiv @@ -149,6 +149,7 @@ \definesystemconstant {sans} \definesystemconstant {mono} \definesystemconstant {math} +\definesystemconstant {nomath} \definesystemconstant {handwriting} \definesystemconstant {calligraphy} \definesystemconstant {casual} @@ -358,7 +359,7 @@ \definesystemconstant {integral} \definesystemconstant {insert} % maybe insertclass \definesystemconstant {marker} - +\definesystemconstant {kernpairs} \definesystemconstant {mixedcolumn} %definesystemconstant {property} diff --git a/tex/context/base/mkiv/node-acc.lua b/tex/context/base/mkiv/node-acc.lua index a63aef646..dccd7b7c0 100644 --- a/tex/context/base/mkiv/node-acc.lua +++ b/tex/context/base/mkiv/node-acc.lua @@ -8,92 +8,72 @@ if not modules then modules = { } end modules ['node-acc'] = { local nodes, node = nodes, node -local nodecodes = nodes.nodecodes -local tasks = nodes.tasks - -local nuts = nodes.nuts -local tonut = nodes.tonut -local tonode = nodes.tonode - -local getid = nuts.getid -local getfield = nuts.getfield -local getattr = nuts.getattr -local getlist = nuts.getlist -local getchar = nuts.getchar -local getnext = nuts.getnext - -local setfield = nuts.setfield -local setattr = nuts.setattr -local setlink = nuts.setlink -local setchar = nuts.setchar -local setsubtype = nuts.setsubtype - ------ traverse_nodes = nuts.traverse -local traverse_id = nuts.traverse_id -local copy_node = nuts.copy -local flush_node_list = nuts.flush_list -local insert_after = nuts.insert_after - -local glue_code = nodecodes.glue ------ kern_code = nodecodes.kern -local glyph_code = nodecodes.glyph -local hlist_code = nodecodes.hlist -local vlist_code = nodecodes.vlist - -local a_characters = attributes.private("characters") - -local threshold = 65536 -- not used -local nofreplaced = 0 +local nodecodes = nodes.nodecodes +local tasks = nodes.tasks + +local nuts = nodes.nuts +local tonut = nodes.tonut +local tonode = nodes.tonode + +local getid = nuts.getid +local getfield = nuts.getfield +local getattr = nuts.getattr +local getlist = nuts.getlist +local getchar = nuts.getchar +local getnext = nuts.getnext + +local setfield = nuts.setfield +local setattr = nuts.setattr +local setlink = nuts.setlink +local setchar = nuts.setchar +local setsubtype = nuts.setsubtype +local getwidth = nuts.getwidth +local setwidth = nuts.setwidth + +----- traverse_nodes = nuts.traverse +local traverse_id = nuts.traverse_id +----- copy_node = nuts.copy +local insert_after = nuts.insert_after +local copy_no_components = nuts.copy_no_components + +local glue_code = nodecodes.glue +----- kern_code = nodecodes.kern +local glyph_code = nodecodes.glyph +local hlist_code = nodecodes.hlist +local vlist_code = nodecodes.vlist + +local a_characters = attributes.private("characters") + +local threshold = 65536 -- not used +local nofreplaced = 0 -- todo: nbsp etc --- todo: collapse kerns - --- p_id +-- todo: collapse kerns (not needed, backend does this) +-- todo: maybe cache as we now create many nodes +-- todo: check for subtype related to spacing (13/14 but most seems to be user anyway) local function injectspaces(head) local p, p_id local n = head while n do local id = getid(n) - if id == glue_code then -- todo: check for subtype related to spacing (13/14 but most seems to be 0) - -- if getfield(n,."width") > 0 then -- threshold - -- if p and p_id == glyph_code then + if id == glue_code then if p and getid(p) == glyph_code then - local g = copy_node(p) - local c = getfield(g,"components") - if c then -- it happens that we copied a ligature - flush_node_list(c) - setfield(g,"components",nil) - setsubtype(g,256) - end + -- unless we don't care about the little bit of overhead + -- we can just: local g = copy_node(g) + local g = copy_no_components(p) local a = getattr(n,a_characters) setchar(g,32) - setlink(p,g) - setlink(g,n) --- we could cache as we now create many nodes - setfield(n,"width",getfield(n,"width") - getfield(g,"width")) + setlink(p,g,n) + setwidth(n,getwidth(n) - getwidth(g)) if a then setattr(g,a_characters,a) end setattr(n,a_characters,0) nofreplaced = nofreplaced + 1 end - -- end elseif id == hlist_code or id == vlist_code then injectspaces(getlist(n),attribute) - -- elseif id == kern_code then -- the backend already collapses - -- local first = n - -- while true do - -- local nn = getnext(n) - -- if nn and getid(nn) == kern_code then - -- -- maybe we should delete kerns but who cares at this stage - -- setfield(first,"kern",getfield(first,"kern") + getfield(nn,"kern") - -- setfield(nn,"kern",0) - -- n = nn - -- else - -- break - -- end - -- end end p_id = id p = n diff --git a/tex/context/base/mkiv/node-aux.lua b/tex/context/base/mkiv/node-aux.lua index 7f2360276..c6b276337 100644 --- a/tex/context/base/mkiv/node-aux.lua +++ b/tex/context/base/mkiv/node-aux.lua @@ -35,6 +35,10 @@ local getfont = nuts.getfont local getchar = nuts.getchar local getattr = nuts.getattr local getfield = nuts.getfield +local getboth = nuts.getboth +local getcomponents = nuts.getcomponents +local getwidth = nuts.getwidth +local setwidth = nuts.setwidth local setfield = nuts.setfield local setattr = nuts.setattr @@ -42,18 +46,21 @@ local setlink = nuts.setlink local setlist = nuts.setlist local setnext = nuts.setnext local setprev = nuts.setprev +local setcomponents = nuts.setcomponents +local setattrlist = nuts.setattrlist local traverse_nodes = nuts.traverse local traverse_id = nuts.traverse_id local flush_node = nuts.flush +local flush_list = nuts.flush_list local hpack_nodes = nuts.hpack local unset_attribute = nuts.unset_attribute local first_glyph = nuts.first_glyph local copy_node = nuts.copy ----- copy_node_list = nuts.copy_list local find_tail = nuts.tail -local insert_node_after = nuts.insert_after local getbox = nuts.getbox +local count = nuts.count local nodepool = nuts.pool local new_glue = nodepool.glue @@ -341,11 +348,10 @@ local function tonodes(str,fnt,attr) -- (str,template_glyph) -- moved from blob- n = new_glyph(fnt,s) end if attr then -- normally false when template - -- setfield(n,"attr",copy_node_list(attr)) - setfield(n,"attr",attr) + setattrlist(n,attr) end if head then - insert_node_after(head,tail,n) + setlink(tail,n) else head = n end @@ -447,9 +453,9 @@ end local function rehpack(n,width) local head = getlist(n) - local size = width or getfield(n,"width") + local size = width or getwidth(n) local temp = hpack_nodes(head,size,"exactly") - setfield(n,"width", size) + setwidth(n,size) setfield(n,"glue_set", getfield(temp,"glue_set")) setfield(n,"glue_sign", getfield(temp,"glue_sign")) setfield(n,"glue_order",getfield(temp,"glue_order")) @@ -482,3 +488,177 @@ end -- return 0 -- end -- end + +-- these component helpers might move to another module + +-- nodemode helper: here we also flatten components, no check for disc here + +function nuts.set_components(target,start,stop) + local head = getcomponents(target) + if head then + flush_list(head) + head = nil + end + if start then + setprev(start) + else + return nil + end + if stop then + setnext(stop) + end + local tail = nil + while start do + local c = getcomponents(start) + local n = getnext(start) + if c then + if head then + setlink(tail,c) + else + head = c + end + tail = find_tail(c) + setcomponents(start) + flush_node(start) + else + if head then + setlink(tail,start) + else + head = start + end + tail = start + end + start = n + end + setcomponents(target,head) + -- maybe also upgrade the subtype but we don't use it anyway + return head +end + +function nuts.get_components(target) + return getcomponents(target) +end + +nuts.get_components = getcomponents + +function nuts.take_components(target) + local c = getcomponents(target) + setcomponents(target) + -- maybe also upgrade the subtype but we don't use it anyway + return c +end + +-- nodemode helper: we assume a glyph and a flat components list (basemode can +-- have nested components) + +function nuts.count_components(n,marks) + local components = getcomponents(n) + if components then + if marks then + local i = 0 + for g in traverse_id(glyph_code,components) do + if not marks[getchar(g)] then + i = i + 1 + end + end + return i + else + return count(glyph_code,components) + end + else + return 0 + end +end + +-- nodemode helper: the next and prev pointers are untouched + +function nuts.copy_no_components(g,copyinjection) + local components = getcomponents(g) + if components then + setcomponents(g) + local n = copy_node(g) + if copyinjection then + copyinjection(n,g) + end + setcomponents(g,components) + -- maybe also upgrade the subtype but we don't use it anyway + return n + else + local n = copy_node(g) + if copyinjection then + copyinjection(n,g) + end + return n + end +end + +function nuts.copy_only_glyphs(current) + local head = nil + local previous = nil + for n in traverse_id(glyph_code,current) do + n = copy_node(n) + if head then + setlink(previous,n) + else + head = n + end + previous = n + end + return head +end + +-- node- and basemode helper + +function nuts.use_components(head,current) + local components = getcomponents(current) + if not components then + return head, current, current + end + local prev, next = getboth(current) + local first = current + local last = next + while components do + local gone = current + local tail = find_tail(components) + if prev then + setlink(prev,components) + end + if next then + setlink(tail,next) + end + if first == current then + first = components + end + if head == current then + head = components + end + current = components + setcomponents(gone) + flush_node(gone) + while true do + components = getcomponents(current) + if components then + next = getnext(current) + break -- current is composed + end + if next == last then + last = current + break -- components is false + end + prev = current + current = next + next = getnext(current) + end + end + return head, first, last +end + +-- function nuts.current_tail() +-- local whatever = texnest[texnest.ptr] +-- if whatever then +-- local tail = whatever.tail +-- if tail then +-- return tonut(tail) +-- end +-- end +-- end diff --git a/tex/context/base/mkiv/node-bck.lua b/tex/context/base/mkiv/node-bck.lua index 9ecc62170..abb025b74 100644 --- a/tex/context/base/mkiv/node-bck.lua +++ b/tex/context/base/mkiv/node-bck.lua @@ -11,7 +11,7 @@ if not modules then modules = { } end modules ['node-bck'] = { local attributes, nodes, node = attributes, nodes, node -local tasks = nodes.tasks +local enableaction = nodes.tasks.enableaction local nodecodes = nodes.nodecodes local listcodes = nodes.listcodes @@ -35,7 +35,6 @@ local getattr = nuts.getattr local getsubtype = nuts.getsubtype local getwhd = nuts.getwhd -local setfield = nuts.setfield local setattr = nuts.setattr local setlink = nuts.setlink local setlist = nuts.setlist @@ -85,11 +84,12 @@ local function add_backgrounds(head) -- rather old code .. to be redone if transparency then setattr(rule,a_transparency,transparency) end - setlink(rule,glue) - if list then - setlink(glue,list) - end - setlist(current,rule) +-- setlink(rule,glue) +-- if list then +-- setlink(glue,list) +-- end +-- setlist(current,rule) + setlist(current,rule,glue,list) end end end @@ -172,21 +172,16 @@ end nodes.handlers.backgrounds = function(head) local head, done = add_backgrounds (tonut(head)) return tonode(head), done end nodes.handlers.alignbackgrounds = function(head) local head, done = add_alignbackgrounds(tonut(head)) return tonode(head), done end --- elsewhere: needs checking - --- tasks.appendaction("shipouts","normalizers","nodes.handlers.backgrounds") --- tasks.appendaction("shipouts","normalizers","nodes.handlers.alignbackgrounds") - interfaces.implement { name = "enablebackgroundboxes", onlyonce = true, - actions = nodes.tasks.enableaction, + actions = enableaction, arguments = { "'shipouts'", "'nodes.handlers.backgrounds'" } } interfaces.implement { name = "enablebackgroundalign", onlyonce = true, - actions = nodes.tasks.enableaction, + actions = enableaction, arguments = { "'shipouts'", "'nodes.handlers.alignbackgrounds'" } } diff --git a/tex/context/base/mkiv/node-fin.lua b/tex/context/base/mkiv/node-fin.lua index 25a2d2f44..03c8a7607 100644 --- a/tex/context/base/mkiv/node-fin.lua +++ b/tex/context/base/mkiv/node-fin.lua @@ -26,6 +26,7 @@ local getid = nuts.getid local getlist = nuts.getlist local getleader = nuts.getleader local getattr = nuts.getattr +local getwidth = nuts.getwidth local setlist = nuts.setlist local setleader = nuts.setleader @@ -204,25 +205,31 @@ local function process(namespace,attribute,head,inheritance,default) -- one attr if content ~= list then setlist(stack,list) end - done = done or ok + if ok then + done = true + end else local list, ok = process(namespace,attribute,content,inheritance,default) if content ~= list then setlist(stack,list) end - done = done or ok + if ok then + done = true + end end else local list, ok = process(namespace,attribute,content,inheritance,default) if content ~= list then setlist(stack,list) end - done = done or ok + if ok then + done = true + end end -- end nested -- end elseif id == rule_code then - check = getfield(stack,"width") ~= 0 + check = getwidth(stack) ~= 0 end -- much faster this way than using a check() and nested() function if check then @@ -230,14 +237,14 @@ local function process(namespace,attribute,head,inheritance,default) -- one attr if c then if default and c == inheritance then if current ~= default then - head = insert_node_before(head,stack,copied(nsdata[default])) + head = insert_node_before(head,stack,copied(nsdata[default])) current = default - done = true + done = true end elseif current ~= c then - head = insert_node_before(head,stack,copied(nsdata[c])) + head = insert_node_before(head,stack,copied(nsdata[c])) current = c - done = true + done = true end if leader then local savedcurrent = current @@ -256,20 +263,26 @@ local function process(namespace,attribute,head,inheritance,default) -- one attr if leader ~= list then setleader(stack,list) end - done = done or ok + if ok then + done = true + end else local list, ok = process(namespace,attribute,leader,inheritance,default) if leader ~= list then setleader(stack,list) end - done = done or ok + if ok then + done = true + end end else local list, ok = process(namespace,attribute,leader,inheritance,default) if leader ~= list then setleader(stack,list) end - done = done or ok + if ok then + done = true + end end -- end nested -- current = savedcurrent @@ -277,14 +290,14 @@ local function process(namespace,attribute,head,inheritance,default) -- one attr end elseif default and inheritance then if current ~= default then - head = insert_node_before(head,stack,copied(nsdata[default])) + head = insert_node_before(head,stack,copied(nsdata[default])) current = default - done = true + done = true end elseif current > 0 then - head = insert_node_before(head,stack,copied(nsnone)) + head = insert_node_before(head,stack,copied(nsnone)) current = 0 - done = true + done = true end check = false end @@ -331,25 +344,31 @@ local function selective(namespace,attribute,head,inheritance,default) -- two at if content ~= list then setlist(stack,list) end - done = done or ok + if ok then + done = true + end else local list, ok = selective(namespace,attribute,content,inheritance,default) if content ~= list then setlist(stack,list) end - done = done or ok + if ok then + done = true + end end else local list, ok = selective(namespace,attribute,content,inheritance,default) if content ~= list then setlist(stack,list) end - done = done or ok + if ok then + done = true + end end -- end nested end elseif id == rule_code then - check = getfield(stack,"width") ~= 0 + check = getwidth(stack) ~= 0 end if check then @@ -360,7 +379,9 @@ local function selective(namespace,attribute,head,inheritance,default) -- two at local data = nsdata[default] head = insert_node_before(head,stack,copied(data[nsforced or getattr(stack,nsselector) or nsselector])) current = default - done = true + if ok then + done = true + end end else local s = getattr(stack,nsselector) @@ -369,7 +390,9 @@ local function selective(namespace,attribute,head,inheritance,default) -- two at head = insert_node_before(head,stack,copied(data[nsforced or getattr(stack,nsselector) or nsselector])) current = c current_selector = s - done = true + if ok then + done = true + end end end if leader then @@ -381,20 +404,26 @@ local function selective(namespace,attribute,head,inheritance,default) -- two at if leader ~= list then setleader(stack,list) end - done = done or ok + if ok then + done = true + end else local list, ok = selective(namespace,attribute,leader,inheritance,default) if leader ~= list then setleader(stack,list) end - done = done or ok + if ok then + done = true + end end else local list, ok = selective(namespace,attribute,leader,inheritance,default) if leader ~= list then setleader(stack,list) end - done = done or ok + if ok then + done = true + end end -- end nested leader = false @@ -402,9 +431,9 @@ local function selective(namespace,attribute,head,inheritance,default) -- two at elseif default and inheritance then if current ~= default then local data = nsdata[default] - head = insert_node_before(head,stack,copied(data[nsforced or getattr(stack,nsselector) or nsselector])) + head = insert_node_before(head,stack,copied(data[nsforced or getattr(stack,nsselector) or nsselector])) current = default - done = true + done = true end elseif current > 0 then head = insert_node_before(head,stack,copied(nsnone)) @@ -456,55 +485,63 @@ local function stacked(namespace,attribute,head,default) -- no triggering, no in if a and current ~= a and nslistwise[a] then -- viewerlayer / needs checking, see below local p = current current = a - head = insert_node_before(head,stack,copied(nsdata[a])) + head = insert_node_before(head,stack,copied(nsdata[a])) local list = stacked(namespace,attribute,content,current) -- two return values if content ~= list then setlist(stack,list) end - done = true head, stack = insert_node_after(head,stack,copied(nsnone)) current = p + done = true else local list, ok = stacked(namespace,attribute,content,current) if content ~= list then setlist(stack,list) -- only if ok end - done = done or ok + if ok then + done = true + end end else local list, ok = stacked(namespace,attribute,content,current) if content ~= list then setlist(stack,list) -- only if ok end - done = done or ok + if ok then + done = true + end end end elseif id == rule_code then - check = getfield(stack,"width") ~= 0 + check = getwidth(stack) ~= 0 end if check then local a = getattr(stack,attribute) if a then if current ~= a then - head = insert_node_before(head,stack,copied(nsdata[a])) - depth = depth + 1 - current, done = a, true + head = insert_node_before(head,stack,copied(nsdata[a])) + depth = depth + 1 + current = a + done = true end if leader then local list, ok = stacked(namespace,attribute,content,current) if leader ~= list then setleader(stack,list) -- only if ok end - done = done or ok + if ok then + done = true + end leader = false end elseif default > 0 then -- elseif current > 0 then - head = insert_node_before(head,stack,copied(nsnone)) - depth = depth - 1 - current, done = 0, true + head = insert_node_before(head,stack,copied(nsnone)) + depth = depth - 1 + current = 0 + done = true end check = false end @@ -564,17 +601,21 @@ local function stacker(namespace,attribute,head,default) -- no triggering, no in if content ~= list then setlist(current,list) end - done = done or ok + if ok then + done = true + end end else local list, ok = stacker(namespace,attribute,content,default) if list ~= content then setlist(current,list) end - done = done or ok + if ok then + done = true + end end elseif id == rule_code then - check = getfield(current,"width") ~= 0 + check = getwidth(current) ~= 0 end if check then @@ -588,11 +629,14 @@ local function stacker(namespace,attribute,head,default) -- no triggering, no in if n then head = insert_node_before(head,current,tonut(n)) -- a end - attrib, done = a, true + attrib = a + done = true if leader then -- tricky as a leader has to be a list so we cannot inject before local list, ok = stacker(namespace,attribute,leader,attrib) - done = done or ok + if ok then + done = true + end leader = false end end diff --git a/tex/context/base/mkiv/node-fnt.lua b/tex/context/base/mkiv/node-fnt.lua index 60b1f8332..85525cac2 100644 --- a/tex/context/base/mkiv/node-fnt.lua +++ b/tex/context/base/mkiv/node-fnt.lua @@ -157,56 +157,75 @@ end fonts.setdiscexpansion(true) +local function start_trace(head) + run = run + 1 + report_fonts() + report_fonts("checking node list, run %s",run) + report_fonts() + local n = tonut(head) + while n do + local char, id = isglyph(n) + if char then + local font = getfont(n) + local attr = getattr(n,0) or 0 + report_fonts("font %03i, dynamic %03i, glyph %C",font,attr,char) + elseif id == disc_code then + report_fonts("[disc] %s",nodes.listtoutf(n,true,false,n)) + elseif id == boundary_code then + report_fonts("[boundary] %i:%i",getsubtype(n),getfield(n,"value")) + else + report_fonts("[%s]",nodecodes[id]) + end + n = getnext(n) + end +end + +local function stop_trace(u,usedfonts,a,attrfonts,b,basefonts,r,redundant,e,expanders) + report_fonts() + report_fonts("statics : %s",u > 0 and concat(keys(usedfonts)," ") or "none") + report_fonts("dynamics: %s",a > 0 and concat(keys(attrfonts)," ") or "none") + report_fonts("built-in: %s",b > 0 and b or "none") + report_fonts("removed : %s",r > 0 and r or "none") +if expanders then + report_fonts("expanded: %s",e > 0 and e or "none") +end + report_fonts() +end + function handlers.characters(head) -- either next or not, but definitely no already processed list starttiming(nodes) - local usedfonts = { } - local attrfonts = { } - local basefonts = { } - local a, u, b, r = 0, 0, 0, 0 - local basefont = nil - local prevfont = nil - local prevattr = 0 - local mode = nil - local done = false - local variants = nil - local redundant = nil + local usedfonts = { } + local attrfonts = { } + local basefonts = { } + local basefont = nil + local prevfont = nil + local prevattr = 0 + local done = false + local variants = nil + local redundant = nil + local none = false + local nuthead = tonut(head) + + local a, u, b, r, e = 0, 0, 0, 0, 0 if trace_fontrun then - run = run + 1 - report_fonts() - report_fonts("checking node list, run %s",run) - report_fonts() - local n = tonut(head) - while n do - local char, id = isglyph(n) - if char then - local font = getfont(n) - local attr = getattr(n,0) or 0 - report_fonts("font %03i, dynamic %03i, glyph %C",font,attr,char) - elseif id == disc_code then - report_fonts("[disc] %s",nodes.listtoutf(n,true,false,n)) - elseif id == boundary_code then - report_fonts("[boundary] %i:%i",getsubtype(n),getfield(n,"value")) - else - report_fonts("[%s]",nodecodes[id]) - end - n = getnext(n) - end + start_trace(head) end - local nuthead = tonut(head) + -- 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 in traverse_char(nuthead) do local font = getfont(n) - local attr = getattr(n,0) or 0 -- zero attribute is reserved for fonts in context + local attr = (none and prevattr) or getattr(n,0) or 0 -- zero attribute is reserved for fonts in context if font ~= prevfont or attr ~= prevattr then prevfont = font prevattr = attr - mode = fontmodes[font] -- we can also avoid the attr check variants = fontvariants[font] - if mode == "none" then + none = fontmodes[font] == "none" + if none then -- skip -- variants = false protect_glyph(n) @@ -316,11 +335,17 @@ function handlers.characters(head) if b > 0 then for i=1,b do local bi = basefonts[i] - if r == bi[1] then + 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 - end - if r == bi[2] then - bi[2] = n + elseif b2 == r then + bi[2] = p end end end @@ -328,26 +353,31 @@ function handlers.characters(head) end end - local e = 0 - 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 - -- local prevfont = nil - -- local prevattr = 0 - for d in traverse_id(disc_code,nuthead) do -- we could use first_glyph, only doing replace is good enough local _, _, r = getdisc(d) if r then + local prevfont = nil + local prevattr = nil + local none = false for n in traverse_char(r) do local font = getfont(n) - local attr = getattr(n,0) or 0 -- zero attribute is reserved for fonts in context + local attr = (none and prevattr) or getattr(n,0) or 0 -- zero attribute is reserved for fonts in context if font ~= prevfont or attr ~= prevattr then - if attr > 0 then + prevfont = font + prevattr = attr + none = fontmodes[font] == "none" -- very unlikely that we run into disc nodes in none mode + if none then + -- skip + -- variants = false + protect_glyph(n) + elseif attr > 0 then local used = attrfonts[font] if not used then used = { } @@ -370,11 +400,11 @@ function handlers.characters(head) end end end - prevfont = font - prevattr = attr 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 - break elseif expanders then local subtype = getsubtype(d) if subtype == discretionary_code then @@ -389,36 +419,35 @@ function handlers.characters(head) end if trace_fontrun then - report_fonts() - report_fonts("statics : %s",u > 0 and concat(keys(usedfonts)," ") or "none") - report_fonts("dynamics: %s",a > 0 and concat(keys(attrfonts)," ") or "none") - report_fonts("built-in: %s",b > 0 and b or "none") - report_fonts("removed : %s",redundant and #redundant > 0 and #redundant or "none") - if expanders then - report_fonts("expanded: %s",e > 0 and e or "none") - end - report_fonts() + 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 font, processors = next(usedfonts) - local attr = a == 0 and false or 0 -- 0 is the savest way + -- 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 i=1,#processors do local h, d = processors[i](head,font,attr) if d then - head = h or head + if h then + head = h + end done = true end end else - local attr = a == 0 and false or 0 -- 0 is the savest way - for font, processors in next, usedfonts do + -- 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) if d then - head = h or head + if h then + head = h + end done = true end end @@ -428,22 +457,26 @@ function handlers.characters(head) -- skip elseif a == 1 then local font, dynamics = next(attrfonts) - for attribute, processors in next, dynamics do -- attr can switch in between + 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) if d then - head = h or head + if h then + head = h + end done = true end end end else for font, dynamics in next, attrfonts do - for attribute, processors in next, dynamics do -- attr can switch in between + 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) if d then - head = h or head + if h then + head = h + end done = true end end @@ -460,14 +493,15 @@ function handlers.characters(head) if (start or stop) and (start ~= stop) then local front = nuthead == start if stop then - start, stop = ligaturing(start,stop) - start, stop = kerning(start,stop) + start = ligaturing(start,stop) + start = kerning(start,stop) elseif start then -- safeguard start = ligaturing(start) start = kerning(start) end - if front then - head = tonode(start) + if front and nuthead ~= start then + -- nuthead = start + head = tonode(start) end end else @@ -476,26 +510,28 @@ function handlers.characters(head) local range = basefonts[i] local start = range[1] local stop = range[2] - if start then + if start then -- and start ~= stop but that seldom happens local front = nuthead == start - local prev, next + local prev = getprev(start) + local next = getnext(stop) if stop then - next = getnext(stop) start, stop = ligaturing(start,stop) start, stop = kerning(start,stop) else - prev = getprev(start) 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 nuthead ~= start then - head = tonode(nuthead) + nuthead = start + head = tonode(start) end end end diff --git a/tex/context/base/mkiv/node-ltp.lua b/tex/context/base/mkiv/node-ltp.lua index 32b11267b..22a4799ad 100644 --- a/tex/context/base/mkiv/node-ltp.lua +++ b/tex/context/base/mkiv/node-ltp.lua @@ -21,6 +21,7 @@ if not modules then modules = { } end modules ['node-par'] = { -- todo: check and improve protrusion -- todo: arabic etc (we could use pretty large scales there) .. marks and cursive -- todo: see: we need to check this with the latest patches to the tex kernel +-- todo: adapt math glue spacing to new model (left/right) -- todo: optimize a bit more (less par.*) @@ -139,14 +140,13 @@ local sub, formatters = string.sub, string.formatters local round, floor = math.round, math.floor local insert, remove = table.insert, table.remove -local fonts, nodes, node = fonts, nodes, node +-- local fonts, nodes, node = fonts, nodes, node -- too many locals local trace_basic = false trackers.register("builders.paragraphs.basic", function(v) trace_basic = v end) local trace_lastlinefit = false trackers.register("builders.paragraphs.lastlinefit", function(v) trace_lastlinefit = v end) local trace_adjusting = false trackers.register("builders.paragraphs.adjusting", function(v) trace_adjusting = v end) local trace_protruding = false trackers.register("builders.paragraphs.protruding", function(v) trace_protruding = v end) local trace_expansion = false trackers.register("builders.paragraphs.expansion", function(v) trace_expansion = v end) -local trace_quality = false trackers.register("builders.paragraphs.quality", function(v) trace_quality = v end) local report_parbuilders = logs.reporter("nodes","parbuilders") ----- report_hpackers = logs.reporter("nodes","hpackers") @@ -207,7 +207,14 @@ local getattr = nuts.getattr local getdisc = nuts.getdisc local getglue = nuts.getglue local getwhd = nuts.getwhd -local setwhd = nuts.setwhd +local getcomponents = nuts.getcomponents +local getkern = nuts.getkern +local getpenalty = nuts.getpenalty +local getdir = nuts.getdir +local getshift = nuts.getshift +local getwidth = nuts.getwidth +local getheight = nuts.getheight +local getdepth = nuts.getdepth local isglyph = nuts.isglyph @@ -220,6 +227,13 @@ local setprev = nuts.setprev local setdisc = nuts.setdisc local setsubtype = nuts.setsubtype local setglue = nuts.setglue +local setwhd = nuts.setwhd +local setkern = nuts.setkern +local setdir = nuts.setdir +local setshift = nuts.setshift +local setwidth = nuts.setwidth +----- getheight = nuts.getheight +----- getdepth = nuts.getdepth local slide_node_list = nuts.slide -- get rid of this, probably ok > 78.2 local find_tail = nuts.tail @@ -233,8 +247,6 @@ local insert_node_after = nuts.insert_after local insert_node_before = nuts.insert_before local is_zero_glue = nuts.is_zero_glue -local setnodecolor = nodes.tracers.colors.set - local nodepool = nuts.pool local nodecodes = nodes.nodecodes @@ -352,12 +364,12 @@ local function checked_line_dir(stack,current) local n = stack.n + 1 stack.n = n stack[n] = current - return getfield(current,"dir") + return getdir(current) elseif n > 0 then local n = stack.n local dirnode = stack[n] dirstack.n = n - 1 - return getfield(dirnode,"dir") + return getdir(dirnode) else report_parbuilders("warning: missing pop node (%a)",1) -- in line ... end @@ -374,7 +386,7 @@ local function inject_dirs_at_end_of_line(stack,current,start,stop) while start and start ~= stop do local id = getid(start) if id == dir_code then - if not dir_pops[getfield(start,"dir")] then -- weird, what is this # + if not dir_pops[getdir(start)] then -- weird, what is this # n = n + 1 stack[n] = start elseif n > 0 then @@ -386,7 +398,7 @@ local function inject_dirs_at_end_of_line(stack,current,start,stop) start = getnext(start) end for i=n,1,-1 do - h, current = insert_node_after(current,current,new_dir(dir_negations[getfield(stack[i],"dir")])) + h, current = insert_node_after(current,current,new_dir(dir_negations[getdir(stack[i])])) end stack.n = n return current @@ -754,13 +766,13 @@ local function add_to_width(line_break_dir,checked_expansion,s) -- split into tw end elseif id == hlist_code or id == vlist_code then local wd, ht, dp = getwhd(s) - if is_parallel[getfield(s,"dir")][line_break_dir] then + if is_parallel[getdir(s)][line_break_dir] then size = size + wd else size = size + ht + dp end elseif id == kern_code then - local kern = getfield(s,"kern") + local kern = getkern(s) if kern ~= 0 then if checked_expansion and expand_kerns and (getsubtype(s) == kerning_code or getattr(a_fontkern)) then local stretch, shrink = kern_stretch_shrink(s,kern) @@ -776,7 +788,7 @@ local function add_to_width(line_break_dir,checked_expansion,s) -- split into tw size = size + kern end elseif id == rule_code then - size = size + getfield(s,"width") + size = size + getwidth(s) elseif trace_unsupported then report_parbuilders("unsupported node at location %a",6) end @@ -831,12 +843,12 @@ local function compute_break_width(par,break_type,p) -- split in two elseif id == kern_code then local s = getsubtype(p) if s == userkern_code or s == italickern_code then - break_width.size = break_width.size - getfield(p,"kern") + break_width.size = break_width.size - getkern(p) else return end elseif id == math_code then - break_width.size = break_width.size - getfield(p,"surround") + break_width.size = break_width.size - getkern(p) -- surround -- new in luatex local wd, stretch, shrink, stretch_order = getglue(p) local order = stretch_orders[stretch_order] @@ -859,7 +871,7 @@ local function append_to_vlist(par, b) if prev_depth > ignore_depth then if is_hlist then local width, stretch, shrink, stretch_order, shrink_order = getglue(par.baseline_skip) - local delta = width - prev_depth - getfield(b,"height") -- deficiency of space between baselines + local delta = width - prev_depth - getheight(b) -- deficiency of space between baselines local skip = nil if delta < par.line_skip_limit then width, stretch, shrink, stretch_order, shrink_order = getglue(par.lineskip) @@ -882,7 +894,7 @@ local function append_to_vlist(par, b) par.head_field = b end if is_hlist then - local pd = getfield(b,"depth") + local pd = getdepth(b) par.prev_depth = pd texnest[texnest.ptr].prevdepth = pd end @@ -1303,9 +1315,9 @@ local function post_line_break(par) setdisc(lastnode) -- nil, nil, nil disc_break = true elseif id == kern_code then - setfield(lastnode,"kern",0) + setkern(lastnode,0) elseif getid(lastnode) == math_code then - setfield(lastnode,"surround",0) + setkern(lastnode,0) -- surround -- new in luatex setglue(lastnode) -- zeros end @@ -1398,21 +1410,21 @@ local function post_line_break(par) local adjust_head = texlists.adjust_head local pre_adjust_head = texlists.pre_adjust_head -- - setfield(finished_line,"shift",cur_indent) + setshift(finished_line,cur_indent) -- -- -- this is gone: -- -- if par.each_line_height ~= ignored_dimen then - -- setfield(finished_line,"height",par.each_line_height) + -- setheight(finished_line,par.each_line_height) -- end -- if par.each_line_depth ~= ignored_dimen then - -- setfield(finished_line,"depth",par.each_line_depth) + -- setdepth(finished_line,par.each_line_depth) -- end -- if par.first_line_height ~= ignored_dimen and (current_line == par.first_line + 1) then - -- setfield(finished_line,"height",par.first_line_height) + -- setheight(finished_line,par.first_line_height) -- end -- if par.last_line_depth ~= ignored_dimen and current_line + 1 == par.best_line then - -- setfield(finished_line,"depth",par.last_line_depth) + -- setdepth(finished_line,par.last_line_depth) -- end -- if texlists.pre_adjust_head ~= pre_adjust_head then @@ -1473,7 +1485,7 @@ local function post_line_break(par) break elseif id == math_code then -- keep the math node - setfield(next,"surround",0) + setkern(next,0) -- surround -- new in luatex setglue(lastnode) -- zeros break @@ -1519,7 +1531,7 @@ local function wrap_up(par) par.do_last_line_fit = false else local glue = par.final_par_glue - setfield(glue,"width",getfield(glue,"width") + active_short - active_glue) + setwidth(glue,getwidth(glue) + active_short - active_glue) setfield(glue,"stretch",0) if trace_lastlinefit then report_parbuilders("applying last line fit, short %a, glue %p",active_short,active_glue) @@ -2263,7 +2275,7 @@ function constructors.methods.basic(head,d) end elseif id == hlist_code or id == vlist_code then local wd, ht, dp = getwhd(current) - if is_parallel[getfield(current,"dir")][par.line_break_dir] then + if is_parallel[getdir(current)][par.line_break_dir] then active_width.size = active_width.size + wd else active_width.size = active_width.size + ht + dp @@ -2298,7 +2310,7 @@ function constructors.methods.basic(head,d) if second_pass or subtype <= automatic_disc_code then local actual_pen = subtype == automatic_disc_code and par.ex_hyphen_penalty or par.hyphen_penalty -- 0.81 : - -- local actual_pen = getfield(current,"penalty") + -- local actual_pen = getpenalty(current) -- local pre, post, replace = getdisc(current) if not pre then -- trivial pre-break @@ -2377,9 +2389,9 @@ function constructors.methods.basic(head,d) p_active, n_active = try_break(0, unhyphenated_code, par, first_p, current, checked_expansion) end local active_width = par.active_width - active_width.size = active_width.size + getfield(current,"kern") + active_width.size = active_width.size + getkern(current) else - local kern = getfield(current,"kern") + local kern = getkern(current) if kern ~= 0 then active_width.size = active_width.size + kern if checked_expansion and expand_kerns and (getsubtype(current) == kerning_code or getattr(current,a_fontkern)) then @@ -2404,13 +2416,13 @@ function constructors.methods.basic(head,d) p_active, n_active = try_break(0, unhyphenated_code, par, first_p, current, checked_expansion) end local active_width = par.active_width - active_width.size = active_width.size + getfield(current,"surround") + active_width.size = active_width.size + getkern(current) -- surround -- new in luatex - + getfield(current,"width") + + getwidth(current) elseif id == rule_code then - active_width.size = active_width.size + getfield(current,"width") + active_width.size = active_width.size + getwidth(current) elseif id == penalty_code then - p_active, n_active = try_break(getfield(current,"penalty"), unhyphenated_code, par, first_p, current, checked_expansion) + p_active, n_active = try_break(getpenalty(current), unhyphenated_code, par, first_p, current, checked_expansion) elseif id == dir_code then par.line_break_dir = checked_line_dir(dirstack) or par.line_break_dir elseif id == localpar_code then @@ -2492,144 +2504,190 @@ end -- standard tex logging .. will be adapted .. -local function write_esc(cs) - local esc = tex.escapechar - if esc then - write("log",utfchar(esc),cs) - else - write("log",cs) +do + + local function write_esc(cs) + local esc = tex.escapechar + if esc then + write("log",utfchar(esc),cs) + else + write("log",cs) + end end -end -function diagnostics.start() -end + function diagnostics.start() + end -function diagnostics.stop() - write_nl("log",'') -end + function diagnostics.stop() + write_nl("log",'') + end -function diagnostics.current_pass(par,what) - write_nl("log",formatters["@%s"](what)) -end + function diagnostics.current_pass(par,what) + write_nl("log",formatters["@%s"](what)) + end -local verbose = false -- true + local verbose = false -- true -local function short_display(target,a,font_in_short_display) - while a do - local char, id = isglyph(a) - if char then - local font = getfont(a) - if font ~= font_in_short_display then - write(target,tex.fontidentifier(font) .. ' ') - font_in_short_display = font - end - if getsubtype(a) == ligature_code then - font_in_short_display = short_display(target,getfield(a,"components"),font_in_short_display) - else - write(target,utfchar(char)) - end - elseif id == disc_code then - local pre, post, replace = getdisc(a) - font_in_short_display = short_display(target,pre,font_in_short_display) - font_in_short_display = short_display(target,post,font_in_short_display) - elseif verbose then - write(target,formatters["[%s]"](nodecodes[id])) - elseif id == rule_code then - write(target,"|") - elseif id == glue_code then - write(target," ") - elseif id == kern_code then - local s = getsubtype(a) - if s == userkern_code or s == italickern_code or getattr(a,a_fontkern) then - if verbose then - write(target,"[|]") - -- else - -- write(target,"") + local function short_display(target,a,font_in_short_display) + while a do + local char, id = isglyph(a) + if char then + local font = getfont(a) + if font ~= font_in_short_display then + write(target,tex.fontidentifier(font) .. ' ') + font_in_short_display = font + end + -- todo: instead of components the split tounicode string + if getsubtype(a) == ligature_code then + font_in_short_display = short_display(target,getcomponents(a),font_in_short_display) + else + write(target,utfchar(char)) + end + elseif id == disc_code then + local pre, post, replace = getdisc(a) + font_in_short_display = short_display(target,pre,font_in_short_display) + font_in_short_display = short_display(target,post,font_in_short_display) + elseif verbose then + write(target,formatters["[%s]"](nodecodes[id])) + elseif id == rule_code then + write(target,"|") + elseif id == glue_code then + write(target," ") + elseif id == kern_code then + local s = getsubtype(a) + if s == userkern_code or s == italickern_code or getattr(a,a_fontkern) then + if verbose then + write(target,"[|]") + -- else + -- write(target,"") + end + else + write(target,"[]") end + elseif id == math_code then + write(target,"$") else write(target,"[]") end - elseif id == math_code then - write(target,"$") - else - write(target,"[]") + a = getnext(a) end - a = getnext(a) + return font_in_short_display end - return font_in_short_display -end -diagnostics.short_display = short_display + diagnostics.short_display = short_display -function diagnostics.break_node(par, q, fit_class, break_type, current) -- %d ? - local passive = par.passive - local typ_ind = break_type == hyphenated_code and '-' or "" - if par.do_last_line_fit then - local s = number.toscaled(q.active_short) - local g = number.toscaled(q.active_glue) - if current then - write_nl("log",formatters["@@%d: line %d.%d%s t=%s s=%s g=%s"]( - passive.serial or 0,q.line_number-1,fit_class,typ_ind,q.total_demerits,s,g)) + function diagnostics.break_node(par, q, fit_class, break_type, current) -- %d ? + local passive = par.passive + local typ_ind = break_type == hyphenated_code and '-' or "" + if par.do_last_line_fit then + local s = number.toscaled(q.active_short) + local g = number.toscaled(q.active_glue) + if current then + write_nl("log",formatters["@@%d: line %d.%d%s t=%s s=%s g=%s"]( + passive.serial or 0,q.line_number-1,fit_class,typ_ind,q.total_demerits,s,g)) + else + write_nl("log",formatters["@@%d: line %d.%d%s t=%s s=%s a=%s"]( + passive.serial or 0,q.line_number-1,fit_class,typ_ind,q.total_demerits,s,g)) + end else - write_nl("log",formatters["@@%d: line %d.%d%s t=%s s=%s a=%s"]( - passive.serial or 0,q.line_number-1,fit_class,typ_ind,q.total_demerits,s,g)) + write_nl("log",formatters["@@%d: line %d.%d%s t=%s"]( + passive.serial or 0,q.line_number-1,fit_class,typ_ind,q.total_demerits)) + end + if not passive.prev_break then + write("log"," -> @0") + else + write("log",formatters[" -> @%d"](passive.prev_break.serial or 0)) end - else - write_nl("log",formatters["@@%d: line %d.%d%s t=%s"]( - passive.serial or 0,q.line_number-1,fit_class,typ_ind,q.total_demerits)) - end - if not passive.prev_break then - write("log"," -> @0") - else - write("log",formatters[" -> @%d"](passive.prev_break.serial or 0)) end -end -function diagnostics.feasible_break(par, current, r, b, pi, d, artificial_demerits) - local printed_node = par.printed_node - if printed_node ~= current then - write_nl("log","") + function diagnostics.feasible_break(par, current, r, b, pi, d, artificial_demerits) + local printed_node = par.printed_node + if printed_node ~= current then + write_nl("log","") + if not current then + par.font_in_short_display = short_display("log",getnext(printed_node),par.font_in_short_display) + else + local save_link = getnext(current) + setnext(current) + write_nl("log","") + par.font_in_short_display = short_display("log",getnext(printed_node),par.font_in_short_display) + setnext(current,save_link) + end + par.printed_node = current + end + write_nl("log","@") if not current then - par.font_in_short_display = short_display("log",getnext(printed_node),par.font_in_short_display) + write_esc("par") else - local save_link = getnext(current) - setnext(current) - write_nl("log","") - par.font_in_short_display = short_display("log",getnext(printed_node),par.font_in_short_display) - setnext(current,save_link) + local id = getid(current) + if id == glue_code then + -- print nothing + elseif id == penalty_code then + write_esc("penalty") + elseif id == disc_code then + write_esc("discretionary") + elseif id == kern_code then + write_esc("kern") + elseif id == math_code then + write_esc("math") + else + write_esc("unknown") + end + end + local via, badness, demerits = 0, '*', '*' + if r.break_node then + via = r.break_node.serial or 0 + end + if b <= infinite_badness then + badness = tonumber(d) + end + if not artificial_demerits then + demerits = tonumber(d) end - par.printed_node = current + write("log",formatters[" via @%d b=%s p=%s d=%s"](via,badness,pi,demerits)) end - write_nl("log","@") - if not current then - write_esc("par") - else - local id = getid(current) - if id == glue_code then - -- print nothing - elseif id == penalty_code then - write_esc("penalty") - elseif id == disc_code then - write_esc("discretionary") - elseif id == kern_code then - write_esc("kern") - elseif id == math_code then - write_esc("math") + + -- + + local function common_message(hlist,line,str) + write_nl("") + if status.output_active then -- unset + write(str," has occurred while \\output is active") + else + write(str) + end + local fileline = status.linenumber + if line > 0 then + write(formatters[" in paragraph at lines %s--%s"](fileline,"--",fileline+line-1)) + elseif line < 0 then + write(formatters[" in alignment at lines "](fileline,"--",fileline-line-1)) else - write_esc("unknown") + write(formatters[" detected at line %s"](fileline)) end + write_nl("") + diagnostics.short_display(getlist(hlist),false) + write_nl("") + -- diagnostics.start() + -- show_box(getlist(hlist)) + -- diagnostics.stop() + end + + function diagnostics.overfull_hbox(hlist,line,d) + common_message(hlist,line,formatters["Overfull \\hbox (%spt too wide)"](number.toscaled(d))) end - local via, badness, demerits = 0, '*', '*' - if r.break_node then - via = r.break_node.serial or 0 + + function diagnostics.bad_hbox(hlist,line,b) + common_message(hlist,line,formatters["Tight \\hbox (badness %i)"](b)) end - if b <= infinite_badness then - badness = tonumber(d) + + function diagnostics.underfull_hbox(hlist,line,b) + common_message(hlist,line,formatters["Underfull \\hbox (badness %i)"](b)) end - if not artificial_demerits then - demerits = tonumber(d) + + function diagnostics.loose_hbox(hlist,line,b) + common_message(hlist,line,formatters["Loose \\hbox (badness %i)"](b)) end - write("log",formatters[" via @%d b=%s p=%s d=%s"](via,badness,pi,demerits)) + end -- reporting -- @@ -2640,574 +2698,536 @@ statistics.register("alternative parbuilders", function() end end) --- actually scaling kerns is not such a good idea and it will become --- configureable - --- This is no way a replacement for the built in (fast) packer --- it's just an alternative for special (testing) purposes. --- --- We could use two hpacks: one to be used in the par builder --- and one to be used for other purposes. The one in the par --- builder is much more simple as it does not need the expansion --- code but only need to register the effective expansion factor --- with the glyph. - -local function glyph_width_height_depth(curdir,pdir,p) - local wd, ht, dp = getwhd(p) - if is_rotated[curdir] then - if is_parallel[curdir][pdir] then - local half = (ht + dp) / 2 - return wd, half, half - else - local half = wd / 2 - return ht + dp, half, half - end - elseif is_rotated[pdir] then - if is_parallel[curdir][pdir] then - local half = (ht + dp) / 2 - return wd, half, half +do + + -- actually scaling kerns is not such a good idea and it will become + -- configureable + + -- This is no way a replacement for the built in (fast) packer + -- it's just an alternative for special (testing) purposes. + -- + -- We could use two hpacks: one to be used in the par builder + -- and one to be used for other purposes. The one in the par + -- builder is much more simple as it does not need the expansion + -- code but only need to register the effective expansion factor + -- with the glyph. + + local setnodecolor = nodes.tracers.colors.set + + local function glyph_width_height_depth(curdir,pdir,p) + local wd, ht, dp = getwhd(p) + if is_rotated[curdir] then + if is_parallel[curdir][pdir] then + local half = (ht + dp) / 2 + return wd, half, half + else + local half = wd / 2 + return ht + dp, half, half + end + elseif is_rotated[pdir] then + if is_parallel[curdir][pdir] then + local half = (ht + dp) / 2 + return wd, half, half + else + return ht + dp, wd, 0 -- weird + end else - return ht + dp, wd, 0 -- weird - end - else - if glyphdir_is_equal[curdir][pdir] then - return wd, ht, dp - elseif is_opposite[curdir][pdir] then - return wd, dp, ht - else -- can this happen? - return ht + dp, wd, 0 + if glyphdir_is_equal[curdir][pdir] then + return wd, ht, dp + elseif is_opposite[curdir][pdir] then + return wd, dp, ht + else -- can this happen? + return ht + dp, wd, 0 + end end end -end -local function pack_width_height_depth(curdir,pdir,p) - local wd, ht, dp = getwhd(p) - if is_rotated[curdir] then - if is_parallel[curdir][pdir] then - local half = (ht + dp) / 2 - return wd, half, half - else -- can this happen? - local half = wd / 2 - return ht + dp, half, half - end - else - if pardir_is_equal[curdir][pdir] then - return wd, ht, dp - elseif is_opposite[curdir][pdir] then - return wd, dp, ht - else -- weird dimensions, can this happen? - return ht + dp, wd, 0 + local function pack_width_height_depth(curdir,pdir,p) + local wd, ht, dp = getwhd(p) + if is_rotated[curdir] then + if is_parallel[curdir][pdir] then + local half = (ht + dp) / 2 + return wd, half, half + else -- can this happen? + local half = wd / 2 + return ht + dp, half, half + end + else + if pardir_is_equal[curdir][pdir] then + return wd, ht, dp + elseif is_opposite[curdir][pdir] then + return wd, dp, ht + else -- weird dimensions, can this happen? + return ht + dp, wd, 0 + end end end -end --- local function xpack(head,width,method,direction,analysis) --- --- -- inspect(analysis) --- --- local expansion = method == "cal_expand_ratio" --- local natural = analysis.size --- local font_stretch = analysis.adjust_stretch --- local font_shrink = analysis.adjust_shrink --- local font_expand_ratio = 0 --- local delta = width - natural --- --- local hlist = new_hlist() --- --- setlist(hlist,head) --- setfield(hlist,"dir",direction or tex.textdir) --- setfield(hlist,"width",width) --- setfield(hlist,"height",height) --- setfield(hlist,"depth",depth) --- --- if delta == 0 then --- --- setfield(hlist,"glue_sign",0) --- setfield(hlist,"glue_order",0) --- setfield(hlist,"glue_set",0) --- --- else --- --- local order = analysis.filll ~= 0 and fillcodes.filll or --- analysis.fill ~= 0 and fillcodes.fill or --- analysis.fil ~= 0 and fillcodes.fil or --- analysis.fi ~= 0 and fillcodes.fi or 0 --- --- if delta > 0 then --- --- if expansion and order == 0 and font_stretch > 0 then --- font_expand_ratio = (delta/font_stretch) * 1000 --- else --- local stretch = analysis.stretch --- if stretch ~= 0 then --- setfield(hlist,"glue_sign",1) -- stretch --- setfield(hlist,"glue_order",order) --- setfield(hlist,"glue_set",delta/stretch) --- else --- setfield(hlist,"glue_sign",0) -- nothing --- setfield(hlist,"glue_order",order) --- setfield(hlist,"glue_set",0) --- end --- end --- --- else --- --- if expansion and order == 0 and font_shrink > 0 then --- font_expand_ratio = (delta/font_shrink) * 1000 --- else --- local shrink = analysis.shrink --- if shrink ~= 0 then --- setfield(hlist,"glue_sign",2) -- shrink --- setfield(hlist,"glue_order",order) --- setfield(hlist,"glue_set",-delta/stretch) --- else --- setfield(hlist,"glue_sign",0) -- nothing --- setfield(hlist,"glue_order",order) --- setfield(hlist,"glue_set",0) --- end --- end --- --- end --- --- end --- --- if not expansion or font_expand_ratio == 0 then --- -- nothing --- elseif font_expand_ratio > 0 then --- if font_expand_ratio > 1000 then --- font_expand_ratio = 1000 --- end --- local current = head --- while current do --- local id = getid(current) --- if id == glyph_code then --- local stretch, shrink = char_stretch_shrink(current) -- get only one --- if stretch then --- if trace_expansion then --- setnodecolor(g,"hz:positive") --- end --- current.expansion_factor = font_expand_ratio * stretch --- end --- elseif id == kern_code then --- local kern = getfield(current,"kern") --- if kern ~= 0 and getsubtype(current) == kerning_code then --- setfield(current,"kern",font_expand_ratio * kern) --- end --- end --- current = getnext(current) --- end --- elseif font_expand_ratio < 0 then --- if font_expand_ratio < -1000 then --- font_expand_ratio = -1000 --- end --- local current = head --- while current do --- local id = getid(current) --- if id == glyph_code then --- local stretch, shrink = char_stretch_shrink(current) -- get only one --- if shrink then --- if trace_expansion then --- setnodecolor(g,"hz:negative") --- end --- current.expansion_factor = font_expand_ratio * shrink --- end --- elseif id == kern_code then --- local kern = getfield(current,"kern") --- if kern ~= 0 and getsubtype(current) == kerning_code then --- setfield(current,"kern",font_expand_ratio * kern) --- end --- end --- current = getnext(current) --- end --- end --- return hlist, 0 --- end - -local function hpack(head,width,method,direction,firstline,line) -- fast version when head = nil - - -- we can pass the adjust_width and adjust_height so that we don't need to recalculate them but - -- with the glue mess it's less trivial as we lack detail .. challenge - - local hlist = new_hlist() - - setfield(hlist,"dir",direction) - - if head == nil then - setfield(hlist,"width",width) - return hlist, 0 - else - setlist(hlist,head) - end + -- local function xpack(head,width,method,direction,analysis) + -- + -- -- inspect(analysis) + -- + -- local expansion = method == "cal_expand_ratio" + -- local natural = analysis.size + -- local font_stretch = analysis.adjust_stretch + -- local font_shrink = analysis.adjust_shrink + -- local font_expand_ratio = 0 + -- local delta = width - natural + -- + -- local hlist = new_hlist() + -- + -- setlist(hlist,head) + -- setdir(hlist,direction or tex.textdir) + -- setwhd(hlist,width,height,depth) + -- + -- if delta == 0 then + -- + -- setfield(hlist,"glue_sign",0) + -- setfield(hlist,"glue_order",0) + -- setfield(hlist,"glue_set",0) + -- + -- else + -- + -- local order = analysis.filll ~= 0 and fillcodes.filll or + -- analysis.fill ~= 0 and fillcodes.fill or + -- analysis.fil ~= 0 and fillcodes.fil or + -- analysis.fi ~= 0 and fillcodes.fi or 0 + -- + -- if delta > 0 then + -- + -- if expansion and order == 0 and font_stretch > 0 then + -- font_expand_ratio = (delta/font_stretch) * 1000 + -- else + -- local stretch = analysis.stretch + -- if stretch ~= 0 then + -- setfield(hlist,"glue_sign",1) -- stretch + -- setfield(hlist,"glue_order",order) + -- setfield(hlist,"glue_set",delta/stretch) + -- else + -- setfield(hlist,"glue_sign",0) -- nothing + -- setfield(hlist,"glue_order",order) + -- setfield(hlist,"glue_set",0) + -- end + -- end + -- + -- else + -- + -- if expansion and order == 0 and font_shrink > 0 then + -- font_expand_ratio = (delta/font_shrink) * 1000 + -- else + -- local shrink = analysis.shrink + -- if shrink ~= 0 then + -- setfield(hlist,"glue_sign",2) -- shrink + -- setfield(hlist,"glue_order",order) + -- setfield(hlist,"glue_set",-delta/stretch) + -- else + -- setfield(hlist,"glue_sign",0) -- nothing + -- setfield(hlist,"glue_order",order) + -- setfield(hlist,"glue_set",0) + -- end + -- end + -- + -- end + -- + -- end + -- + -- if not expansion or font_expand_ratio == 0 then + -- -- nothing + -- elseif font_expand_ratio > 0 then + -- if font_expand_ratio > 1000 then + -- font_expand_ratio = 1000 + -- end + -- local current = head + -- while current do + -- local id = getid(current) + -- if id == glyph_code then + -- local stretch, shrink = char_stretch_shrink(current) -- get only one + -- if stretch then + -- if trace_expansion then + -- setnodecolor(g,"hz:positive") + -- end + -- current.expansion_factor = font_expand_ratio * stretch + -- end + -- elseif id == kern_code then + -- local kern = getkern(current) + -- if kern ~= 0 and getsubtype(current) == kerning_code then + -- setkern(current,font_expand_ratio * kern) + -- end + -- end + -- current = getnext(current) + -- end + -- elseif font_expand_ratio < 0 then + -- if font_expand_ratio < -1000 then + -- font_expand_ratio = -1000 + -- end + -- local current = head + -- while current do + -- local id = getid(current) + -- if id == glyph_code then + -- local stretch, shrink = char_stretch_shrink(current) -- get only one + -- if shrink then + -- if trace_expansion then + -- setnodecolor(g,"hz:negative") + -- end + -- current.expansion_factor = font_expand_ratio * shrink + -- end + -- elseif id == kern_code then + -- local kern = getkern(current) + -- if kern ~= 0 and getsubtype(current) == kerning_code then + -- setkern(current,font_expand_ratio * kern) + -- end + -- end + -- current = getnext(current) + -- end + -- end + -- return hlist, 0 + -- end + + local function hpack(head,width,method,direction,firstline,line) -- fast version when head = nil + + -- we can pass the adjust_width and adjust_height so that we don't need to recalculate them but + -- with the glue mess it's less trivial as we lack detail .. challenge + + local hlist = new_hlist() + + setdir(hlist,direction) + + if head == nil then + setwidth(hlist,width) + return hlist, 0 + else + setlist(hlist,head) + end - local cal_expand_ratio = method == "cal_expand_ratio" or method == "subst_ex_font" + local cal_expand_ratio = method == "cal_expand_ratio" or method == "subst_ex_font" - direction = direction or tex.textdir + direction = direction or tex.textdir - local line = 0 + local line = 0 - local height = 0 - local depth = 0 - local natural = 0 - local font_stretch = 0 - local font_shrink = 0 - local font_expand_ratio = 0 - local last_badness = 0 - local expansion_stack = cal_expand_ratio and { } -- todo: optionally pass this - local expansion_index = 0 - local total_stretch = { [0] = 0, 0, 0, 0, 0 } - local total_shrink = { [0] = 0, 0, 0, 0, 0 } + local height = 0 + local depth = 0 + local natural = 0 + local font_stretch = 0 + local font_shrink = 0 + local font_expand_ratio = 0 + local last_badness = 0 + local expansion_stack = cal_expand_ratio and { } -- todo: optionally pass this + local expansion_index = 0 + local total_stretch = { [0] = 0, 0, 0, 0, 0 } + local total_shrink = { [0] = 0, 0, 0, 0, 0 } - local hpack_dir = direction + local hpack_dir = direction - local adjust_head = texlists.adjust_head - local pre_adjust_head = texlists.pre_adjust_head - local adjust_tail = adjust_head and slide_node_list(adjust_head) -- todo: find_tail - local pre_adjust_tail = pre_adjust_head and slide_node_list(pre_adjust_head) -- todo: find_tail + local adjust_head = texlists.adjust_head + local pre_adjust_head = texlists.pre_adjust_head + local adjust_tail = adjust_head and slide_node_list(adjust_head) -- todo: find_tail + local pre_adjust_tail = pre_adjust_head and slide_node_list(pre_adjust_head) -- todo: find_tail - new_dir_stack(hpack_dir) + new_dir_stack(hpack_dir) - local checked_expansion = false + local checked_expansion = false - if cal_expand_ratio then - checked_expansion = { } - setmetatableindex(checked_expansion,check_expand_lines) - end + if cal_expand_ratio then + checked_expansion = { } + setmetatableindex(checked_expansion,check_expand_lines) + end - -- this one also needs to check the font, so in the end indeed we might end up with two variants + -- this one also needs to check the font, so in the end indeed we might end up with two variants - local fontexps, lastfont + local fontexps, lastfont - local function process(current) -- called nested in disc replace + local function process(current) -- called nested in disc replace - while current do - local char, id = isglyph(current) - if char then - if cal_expand_ratio then - local currentfont = getfont(current) - if currentfont ~= lastfont then - fontexps = checked_expansion[currentfont] -- a bit redundant for the par line packer - lastfont = currentfont + while current do + local char, id = isglyph(current) + if char then + if cal_expand_ratio then + local currentfont = getfont(current) + if currentfont ~= lastfont then + fontexps = checked_expansion[currentfont] -- a bit redundant for the par line packer + lastfont = currentfont + end + if fontexps then + local expansion = fontexps[char] + if expansion then + font_stretch = font_stretch + expansion.glyphstretch + font_shrink = font_shrink + expansion.glyphshrink + expansion_index = expansion_index + 1 + expansion_stack[expansion_index] = current + end + end + end + -- use inline + local wd, ht, dp = glyph_width_height_depth(hpack_dir,"TLT",current) -- was TRT ? + natural = natural + wd + if ht > height then + height = ht + end + if dp > depth then + depth = dp end - if fontexps then - local expansion = fontexps[char] - if expansion then - font_stretch = font_stretch + expansion.glyphstretch - font_shrink = font_shrink + expansion.glyphshrink + elseif id == kern_code then + local kern = getkern(current) + if kern == 0 then + -- no kern + elseif getsubtype(current) == kerning_code then -- check getkern(p) + if cal_expand_ratio then + local stretch, shrink = kern_stretch_shrink(current,kern) + font_stretch = font_stretch + stretch + font_shrink = font_shrink + shrink expansion_index = expansion_index + 1 expansion_stack[expansion_index] = current end + natural = natural + kern + else + natural = natural + kern end - end - -- use inline - local wd, ht, dp = glyph_width_height_depth(hpack_dir,"TLT",current) -- was TRT ? - natural = natural + wd - if ht > height then - height = ht - end - if dp > depth then - depth = dp - end - elseif id == kern_code then - local kern = getfield(current,"kern") - if kern == 0 then - -- no kern - elseif getsubtype(current) == kerning_code then -- check getfield(p,"kern") - if cal_expand_ratio then - local stretch, shrink = kern_stretch_shrink(current,kern) - font_stretch = font_stretch + stretch - font_shrink = font_shrink + shrink - expansion_index = expansion_index + 1 - expansion_stack[expansion_index] = current + elseif id == disc_code then + local subtype = getsubtype(current) + if subtype ~= second_disc_code then + -- todo : local stretch, shrink = char_stretch_shrink(s) + local replace = getfield(current,"replace") + if replace then + process(replace) + end end - natural = natural + kern - else - natural = natural + kern - end - elseif id == disc_code then - local subtype = getsubtype(current) - if subtype ~= second_disc_code then - -- todo : local stretch, shrink = char_stretch_shrink(s) - local replace = getfield(current,"replace") - if replace then - process(replace) + elseif id == glue_code then + local wd, stretch, shrink, stretch_order, shrink_order = getglue(current) + natural = natural + wd + total_stretch[stretch_order] = total_stretch[stretch_order] + stretch + total_shrink [shrink_order] = total_shrink[shrink_order] + shrink + if getsubtype(current) >= leaders_code then + local leader = getleader(current) + local wd, ht, dp = getwhd(leader) -- can become getwhd(current) after 1.003 + if ht > height then + height = ht + end + if dp > depth then + depth = dp + end end - end - elseif id == glue_code then - local wd, stretch, shrink, stretch_order, shrink_order = getglue(current) - natural = natural + wd - total_stretch[stretch_order] = total_stretch[stretch_order] + stretch - total_shrink [shrink_order] = total_shrink[shrink_order] + shrink - if getsubtype(current) >= leaders_code then - local leader = getleader(current) - local ht = getfield(leader,"height") - local dp = getfield(leader,"depth") + elseif id == hlist_code or id == vlist_code then + local sh = getshift(current) + local wd, ht, dp = pack_width_height_depth(hpack_dir,getdir(current) or hpack_dir,current) -- added: or pack_dir + local hs, ds = ht - sh, dp + sh + natural = natural + wd + if hs > height then + height = hs + end + if ds > depth then + depth = ds + end + elseif id == rule_code then + local wd, ht, dp = getwhd(current) + natural = natural + wd if ht > height then height = ht end if dp > depth then depth = dp end + elseif id == math_code then + natural = natural + getkern(current) -- surround + -- new in luatex + + getwidth(current) + elseif id == unset_code then + local wd, ht, dp = getwhd(current) + local sh = getshift(current) + local hs = ht - sh + local ds = dp + sh + natural = natural + wd + if hs > height then + height = hs + end + if ds > depth then + depth = ds + end + elseif id == ins_code or id == mark_code then + local prev, next = getboth(current) + if adjust_tail then -- todo + setlink(prev,next) + setlink(adjust_tail,current) + setnext(current) + adjust_tail = current + else + adjust_head = current + adjust_tail = current + setboth(current) + end + elseif id == adjust_code then + local list = getlist(current) + if adjust_tail then + setnext(adjust_tail,list) + else + adjust_head = list + end + adjust_tail = slide_node_list(list) -- find_tail(list) + elseif id == dir_code then + hpack_dir = checked_line_dir(stack,current) or hpack_dir + elseif id == marginkern_code then + local width = getwidth(current) + if cal_expand_ratio then + -- is this ok? + local glyph = getfield(current,"glyph") + local char_pw = getsubtype(current) == leftmargin_code and left_pw or right_pw + font_stretch = font_stretch - width - char_pw(glyph) + font_shrink = font_shrink - width - char_pw(glyph) + expansion_index = expansion_index + 1 + expansion_stack[expansion_index] = glyph + end + natural = natural + width end - elseif id == hlist_code or id == vlist_code then - local sh = getfield(current,"shift") - local wd, ht, dp = pack_width_height_depth(hpack_dir,getfield(current,"dir") or hpack_dir,current) -- added: or pack_dir - local hs, ds = ht - sh, dp + sh - natural = natural + wd - if hs > height then - height = hs - end - if ds > depth then - depth = ds - end - elseif id == rule_code then - local wd, ht, dp = getwhd(current) - natural = natural + wd - if ht > height then - height = ht - end - if dp > depth then - depth = dp - end - elseif id == math_code then - natural = natural + getfield(current,"surround") - -- new in luatex - + getfield(current,"width") - elseif id == unset_code then - local wd = getfield(current,"width") - local ht = getfield(current,"height") - local dp = getfield(current,"depth") - local sh = getfield(current,"shift") - local hs = ht - sh - local ds = dp + sh - natural = natural + wd - if hs > height then - height = hs - end - if ds > depth then - depth = ds - end - elseif id == ins_code or id == mark_code then - local prev, next = getboth(current) - if adjust_tail then -- todo - setlink(prev,next) - setlink(adjust_tail,current) - setnext(current) - adjust_tail = current - else - adjust_head = current - adjust_tail = current - setboth(current) - end - elseif id == adjust_code then - local list = getlist(current) - if adjust_tail then - setnext(adjust_tail,list) - else - adjust_head = list - end - adjust_tail = slide_node_list(list) -- find_tail(list) - elseif id == dir_code then - hpack_dir = checked_line_dir(stack,current) or hpack_dir - elseif id == marginkern_code then - local width = getfield(current,"width") - if cal_expand_ratio then - -- is this ok? - local glyph = getfield(current,"glyph") - local char_pw = getsubtype(current) == leftmargin_code and left_pw or right_pw - font_stretch = font_stretch - width - char_pw(glyph) - font_shrink = font_shrink - width - char_pw(glyph) - expansion_index = expansion_index + 1 - expansion_stack[expansion_index] = glyph - end - natural = natural + width + current = getnext(current) end - current = getnext(current) - end - end - - process(head) - - if adjust_tail then - adjust_tail.next = nil -- todo - end - if pre_adjust_tail then - pre_adjust_tail.next = nil -- todo - end - if method == "additional" then - width = width + natural - end + end - setwhd(hlist,width,height,depth) + process(head) - local delta = width - natural - if delta == 0 then - setfield(hlist,"glue_sign",0) - setfield(hlist,"glue_order",0) - setfield(hlist,"glue_set",0) - elseif delta > 0 then - -- natural width smaller than requested width - local order = (total_stretch[4] ~= 0 and 4 or total_stretch[3] ~= 0 and 3) or - (total_stretch[2] ~= 0 and 2 or total_stretch[1] ~= 0 and 1) or 0 - if cal_expand_ratio and order == 0 and font_stretch > 0 then -- check sign of font_stretch - font_expand_ratio = delta/font_stretch + if adjust_tail then + adjust_tail.next = nil -- todo + end + if pre_adjust_tail then + pre_adjust_tail.next = nil -- todo + end + if method == "additional" then + width = width + natural + end - if font_expand_ratio > 1 then - font_expand_ratio = 1 - end + setwhd(hlist,width,height,depth) - local fontexps, lastfont - for i=1,expansion_index do - local g = expansion_stack[i] - local e = 0 - local char = isglyph(g) - if char then - local currentfont = getfont(g) - if currentfont ~= lastfont then - fontexps = expansions[currentfont] - lastfont = currentfont - end - local data = fontexps[char] - if trace_expansion then - setnodecolor(g,"hz:positive") - end - e = font_expand_ratio * data.glyphstretch / 1000 - else - local kern = getfield(g,"kern") - local stretch, shrink = kern_stretch_shrink(g,kern) - e = font_expand_ratio * stretch / 1000 - end - setfield(g,"expansion_factor",e) - end - end - local tso = total_stretch[order] - if tso ~= 0 then - setfield(hlist,"glue_sign",1) - setfield(hlist,"glue_order",order) - setfield(hlist,"glue_set",delta/tso) - else + local delta = width - natural + if delta == 0 then setfield(hlist,"glue_sign",0) - setfield(hlist,"glue_order",order) + setfield(hlist,"glue_order",0) setfield(hlist,"glue_set",0) - end - if font_expand_ratio ~= 0 then - -- todo - elseif order == 0 then -- and getlist(hlist) then - last_badness = calculate_badness(delta,total_stretch[0]) - if last_badness > tex.hbadness then - if last_badness > 100 then - diagnostics.underfull_hbox(hlist,line,last_badness) - else - diagnostics.loose_hbox(hlist,line,last_badness) + elseif delta > 0 then + -- natural width smaller than requested width + local order = (total_stretch[4] ~= 0 and 4 or total_stretch[3] ~= 0 and 3) or + (total_stretch[2] ~= 0 and 2 or total_stretch[1] ~= 0 and 1) or 0 + if cal_expand_ratio and order == 0 and font_stretch > 0 then -- check sign of font_stretch + font_expand_ratio = delta/font_stretch + + if font_expand_ratio > 1 then + font_expand_ratio = 1 + end + + local fontexps, lastfont + for i=1,expansion_index do + local g = expansion_stack[i] + local e = 0 + local char = isglyph(g) + if char then + local currentfont = getfont(g) + if currentfont ~= lastfont then + fontexps = expansions[currentfont] + lastfont = currentfont + end + local data = fontexps[char] + if trace_expansion then + setnodecolor(g,"hz:positive") + end + e = font_expand_ratio * data.glyphstretch / 1000 + else + local kern = getkern(g) + local stretch, shrink = kern_stretch_shrink(g,kern) + e = font_expand_ratio * stretch / 1000 + end + setfield(g,"expansion_factor",e) end end - end - else - -- natural width larger than requested width - local order = total_shrink[4] ~= 0 and 4 or total_shrink[3] ~= 0 and 3 - or total_shrink[2] ~= 0 and 2 or total_shrink[1] ~= 0 and 1 or 0 - if cal_expand_ratio and order == 0 and font_shrink > 0 then -- check sign of font_shrink - font_expand_ratio = delta/font_shrink - - if font_expand_ratio < 1 then - font_expand_ratio = -1 + local tso = total_stretch[order] + if tso ~= 0 then + setfield(hlist,"glue_sign",1) + setfield(hlist,"glue_order",order) + setfield(hlist,"glue_set",delta/tso) + else + setfield(hlist,"glue_sign",0) + setfield(hlist,"glue_order",order) + setfield(hlist,"glue_set",0) end - - local fontexps, lastfont - for i=1,expansion_index do - local g = expansion_stack[i] - local e = 0 - local char = isglyph(g) - if char then - local currentfont = getfont(g) - if currentfont ~= lastfont then - fontexps = expansions[currentfont] - lastfont = currentfont - end - local data = fontexps[char] - if trace_expansion then - setnodecolor(g,"hz:negative") + if font_expand_ratio ~= 0 then + -- todo + elseif order == 0 then -- and getlist(hlist) then + last_badness = calculate_badness(delta,total_stretch[0]) + if last_badness > tex.hbadness then + if last_badness > 100 then + diagnostics.underfull_hbox(hlist,line,last_badness) + else + diagnostics.loose_hbox(hlist,line,last_badness) end - e = font_expand_ratio * data.glyphshrink / 1000 - else - local kern = getfield(g,"kern") - local stretch, shrink = kern_stretch_shrink(g,kern) - e = font_expand_ratio * shrink / 1000 end - setfield(g,"expansion_factor",e) end - end - local tso = total_shrink[order] - if tso ~= 0 then - setfield(hlist,"glue_sign",2) - setfield(hlist,"glue_order",order) - setfield(hlist,"glue_set",-delta/tso) else - setfield(hlist,"glue_sign",0) - setfield(hlist,"glue_order",order) - setfield(hlist,"glue_set",0) - end - if font_expand_ratio ~= 0 then - -- todo - elseif tso < -delta and order == 0 then -- and getlist(hlist) then - last_badness = 1000000 - setfield(hlist,"glue_set",1) - local fuzz = - delta - total_shrink[0] - local hfuzz = tex.hfuzz - if fuzz > hfuzz or tex.hbadness < 100 then - local overfullrule = tex.overfullrule - if fuzz > hfuzz and overfullrule > 0 then - -- weird, is always called and no rules shows up - setfield(slide_node_list(list),"next",new_rule(overfullrule,nil,nil,getfield(hlist,"dir"))) -- todo: find_tail + -- natural width larger than requested width + local order = total_shrink[4] ~= 0 and 4 or total_shrink[3] ~= 0 and 3 + or total_shrink[2] ~= 0 and 2 or total_shrink[1] ~= 0 and 1 or 0 + if cal_expand_ratio and order == 0 and font_shrink > 0 then -- check sign of font_shrink + font_expand_ratio = delta/font_shrink + + if font_expand_ratio < 1 then + font_expand_ratio = -1 + end + + local fontexps, lastfont + for i=1,expansion_index do + local g = expansion_stack[i] + local e = 0 + local char = isglyph(g) + if char then + local currentfont = getfont(g) + if currentfont ~= lastfont then + fontexps = expansions[currentfont] + lastfont = currentfont + end + local data = fontexps[char] + if trace_expansion then + setnodecolor(g,"hz:negative") + end + e = font_expand_ratio * data.glyphshrink / 1000 + else + local kern = getkern(g) + local stretch, shrink = kern_stretch_shrink(g,kern) + e = font_expand_ratio * shrink / 1000 + end + setfield(g,"expansion_factor",e) end - diagnostics.overfull_hbox(hlist,line,-delta) end - elseif order == 0 and getlist(hlist) and last_badness > tex.hbadness then - diagnostics.bad_hbox(hlist,line,last_badness) + local tso = total_shrink[order] + if tso ~= 0 then + setfield(hlist,"glue_sign",2) + setfield(hlist,"glue_order",order) + setfield(hlist,"glue_set",-delta/tso) + else + setfield(hlist,"glue_sign",0) + setfield(hlist,"glue_order",order) + setfield(hlist,"glue_set",0) + end + if font_expand_ratio ~= 0 then + -- todo + elseif tso < -delta and order == 0 then -- and getlist(hlist) then + last_badness = 1000000 + setfield(hlist,"glue_set",1) + local fuzz = - delta - total_shrink[0] + local hfuzz = tex.hfuzz + if fuzz > hfuzz or tex.hbadness < 100 then + local overfullrule = tex.overfullrule + if fuzz > hfuzz and overfullrule > 0 then + -- weird, is always called and no rules shows up + setnext(slide_node_list(list),new_rule(overfullrule,nil,nil,getdir(hlist))) -- todo: find_tail + end + diagnostics.overfull_hbox(hlist,line,-delta) + end + elseif order == 0 and getlist(hlist) and last_badness > tex.hbadness then + diagnostics.bad_hbox(hlist,line,last_badness) + end end + return hlist, last_badness end - return hlist, last_badness -end -xpack_nodes = hpack -- comment this for old fashioned expansion (we need to fix float mess) + xpack_nodes = hpack -- comment this for old fashioned expansion (we need to fix float mess) -constructors.methods.hpack = hpack - -local function common_message(hlist,line,str) - write_nl("") - if status.output_active then -- unset - write(str," has occurred while \\output is active") - else - write(str) - end - local fileline = status.linenumber - if line > 0 then - write(formatters[" in paragraph at lines %s--%s"](fileline,"--",fileline+line-1)) - elseif line < 0 then - write(formatters[" in alignment at lines "](fileline,"--",fileline-line-1)) - else - write(formatters[" detected at line %s"](fileline)) - end - write_nl("") - diagnostics.short_display(getlist(hlist),false) - write_nl("") - -- diagnostics.start() - -- show_box(getlist(hlist)) - -- diagnostics.stop() -end - -function diagnostics.overfull_hbox(hlist,line,d) - common_message(hlist,line,formatters["Overfull \\hbox (%spt too wide)"](number.toscaled(d))) -end - -function diagnostics.bad_hbox(hlist,line,b) - common_message(hlist,line,formatters["Tight \\hbox (badness %i)"](b)) -end - -function diagnostics.underfull_hbox(hlist,line,b) - common_message(hlist,line,formatters["Underfull \\hbox (badness %i)"](b)) -end + constructors.methods.hpack = hpack -function diagnostics.loose_hbox(hlist,line,b) - common_message(hlist,line,formatters["Loose \\hbox (badness %i)"](b)) end diff --git a/tex/context/base/mkiv/node-met.lua b/tex/context/base/mkiv/node-met.lua index ea6ce6aca..acdb1286e 100644 --- a/tex/context/base/mkiv/node-met.lua +++ b/tex/context/base/mkiv/node-met.lua @@ -63,12 +63,7 @@ end nodes = nodes or { } local nodes = nodes ------ gonuts = type(node.direct) == "table" ------.gonuts = gonuts - local nodecodes = nodes.nodecodes -local hlist_code = nodecodes.hlist -local vlist_code = nodecodes.vlist nodes.tostring = node.tostring or tostring nodes.copy = node.copy @@ -107,8 +102,12 @@ nodes.protrusion_skippable = node.protrusion_skippable nodes.check_discretionaries = node.check_discretionaries nodes.write = node.write +nodes.count = node.count +nodes.length = node.length + nodes.has_attribute = node.has_attribute nodes.set_attribute = node.set_attribute +nodes.find_attribute = node.find_attribute nodes.unset_attribute = node.unset_attribute nodes.protect_glyphs = node.protect_glyphs @@ -118,34 +117,6 @@ nodes.kerning = node.kerning nodes.ligaturing = node.ligaturing nodes.mlist_to_hlist = node.mlist_to_hlist -if LUATEXVERSION < 0.97 then - - local getglue = node.getglue - - function node.is_zero_glue(n) - local width, stretch, shrink = getglue(n) - return width == 0 and stretch == 0 and shrink == 0 - end - -end - -if not node.rangedimensions then -- LUATEXVERSION < 0.99 - - local dimensions = node.dimensions - local getfield = node.getfield - local find_tail = node.tail - - function node.rangedimensions(parent,first,last) - return dimensions( - getfield(parent,"glue_set"), getfield(parent,"glue_sign"), getfield(parent,"glue_order"), - first, last or find_tail(first), getfield(parent,"dir") - ) - end - - nodes.rangedimensions = node.rangedimensions - -end - if not node.getwhd then local getfield = node.getfield function node.getwhd(n) @@ -196,69 +167,82 @@ local n_getfield = node.getfield local n_setattr = node.setattr local n_getattr = node.getattr local n_getdisc = node.getdisc -local n_getwhd = node.getwhd local n_getleader = node.getleader -local n_setnext = node.setnext or +local n_setnext = node.setnext or -- always function(c,next) setfield(c,"next",n) end -local n_setprev = node.setprev or +local n_setprev = node.setprev or -- always function(c,prev) setfield(c,"prev",p) end -local n_setlink = node.setlink or - function(c1,c2) - if c1 then setfield(c1,"next",c2) end - if c2 then setfield(c2,"prev",c1) end +local n_setlink = node.setlink or -- always +-- function(c1,c2) +-- if c1 then setfield(c1,"next",c2) end +-- if c2 then setfield(c2,"prev",c1) end +-- end + function(...) + -- not that fast but not used often anyway + local h = nil + for i=1,select("#",...) do + local n = (select(i,...)) + if not n then + -- go on + elseif h then + setfield(h,"next",n) + setfield(n,"prev",h) + else + h = n + end + end + return h end -local n_setboth = node.setboth or +local n_setboth = node.setboth or -- always function(c,p,n) setfield(c,"prev",p) setfield(c,"next",n) end -node.setnext = n_setnext -node.setprev = n_setprev -node.setlink = n_setlink -node.setboth = n_setboth - -nodes.getfield = n_getfield -nodes.setfield = n_setfield -nodes.getattr = n_getattr -nodes.setattr = n_setattr - -nodes.getnext = n_getnext -nodes.getprev = n_getprev -nodes.getid = n_getid -nodes.getchar = n_getchar -nodes.getfont = n_getfont -nodes.getsubtype = n_getsubtype -nodes.getlist = n_getlist -nodes.getleader = n_getleader -nodes.getdisc = n_getdisc ------.getpre = node.getpre or function(n) local h, _, _, t = n_getdisc(n,true) return h, t end ------.getpost = node.getpost or function(n) local _, h, _, _, t = n_getdisc(n,true) return h, t end ------.getreplace = node.getreplace or function(n) local _, _, h, _, _, t = n_getdisc(n,true) return h, t end - -nodes.is_char = node.is_char -nodes.ischar = node.is_char - -nodes.is_glyph = node.is_glyph -nodes.isglyph = node.is_glyph - -nodes.getbox = node.getbox or tex.getbox -nodes.setbox = node.setbox or tex.setbox - -local n_flush_node = nodes.flush -local n_copy_node = nodes.copy -local n_copy_list = nodes.copy_list -local n_find_tail = nodes.tail -local n_insert_after = nodes.insert_after -local n_insert_before = nodes.insert_before -local n_slide = nodes.slide - -local n_remove_node = node.remove -- not yet nodes.remove +node.setnext = n_setnext +node.setprev = n_setprev +node.setlink = n_setlink +node.setboth = n_setboth + +nodes.getfield = n_getfield +nodes.setfield = n_setfield +nodes.getattr = n_getattr +nodes.setattr = n_setattr +nodes.takeattr = nodes.unset_attribute + +nodes.getnext = n_getnext +nodes.getprev = n_getprev +nodes.getid = n_getid +nodes.getchar = n_getchar +nodes.getfont = n_getfont +nodes.getsubtype = n_getsubtype +nodes.getlist = n_getlist +nodes.getleader = n_getleader +nodes.getdisc = n_getdisc + +nodes.is_char = node.is_char +nodes.ischar = node.is_char + +nodes.is_glyph = node.is_glyph +nodes.isglyph = node.is_glyph + +nodes.getbox = node.getbox or tex.getbox +nodes.setbox = node.setbox or tex.setbox + +local n_flush_node = nodes.flush +local n_copy_node = nodes.copy +local n_copy_list = nodes.copy_list +local n_find_tail = nodes.tail +local n_insert_after = nodes.insert_after +local n_insert_before = nodes.insert_before +local n_slide = nodes.slide + +local n_remove_node = node.remove -- not yet nodes.remove local function remove(head,current,free_too) local t = current @@ -311,26 +295,7 @@ function nodes.replace(head,current,new) -- no head returned if false end end -local function count(stack,flat) - local n = 0 - while stack do - local id = n_getid(stack) - if not flat and id == hlist_code or id == vlist_code then - local list = n_getlist(stack) - if list then - n = n + 1 + count(list) -- self counts too - else - n = n + 1 - end - else - n = n + 1 - end - stack = n_getnext(stack) - end - return n -end - -nodes.count = count +-- nodes.countall : see node-nut.lua function nodes.append(head,current,...) for i=1,select("#",...) do @@ -662,7 +627,7 @@ local messyhack = table.tohash { -- temporary solution } table.setmetatableindex(keys,function(t,k) - v = (k == "attributelist" or k == nodecodes.attributelist) and { } or getfields(k) + local v = (k == "attributelist" or k == nodecodes.attributelist) and { } or getfields(k) if messyhack[k] then for i=1,#v do if v[i] == "subtype" then diff --git a/tex/context/base/mkiv/node-mig.lua b/tex/context/base/mkiv/node-mig.lua index 24bebb0cc..b3820a7d8 100644 --- a/tex/context/base/mkiv/node-mig.lua +++ b/tex/context/base/mkiv/node-mig.lua @@ -16,7 +16,7 @@ local report_nodes = logs.reporter("nodes","migrations") local attributes = attributes local nodes = nodes -local tasks = nodes.tasks +local enableaction = nodes.tasks.enableaction local nuts = nodes.nuts local tonut = nuts.tonut @@ -26,7 +26,6 @@ local getid = nuts.getid local getlist = nuts.getlist local getattr = nuts.getattr -local setfield = nuts.setfield local setattr = nuts.setattr local setlink = nuts.setlink local setlist = nuts.setlist @@ -139,21 +138,21 @@ end experiments.register("marks.migrate", function(v) if v then - tasks.enableaction("mvlbuilders", "nodes.handlers.migrate") + enableaction("mvlbuilders", "nodes.handlers.migrate") end migrate_marks = v end) experiments.register("inserts.migrate", function(v) if v then - tasks.enableaction("mvlbuilders", "nodes.handlers.migrate") + enableaction("mvlbuilders", "nodes.handlers.migrate") end migrate_inserts = v end) experiments.register("inserts.migrate.nested", function(v) if v then - tasks.enableaction("mvlbuilders", "nodes.handlers.migrate") + enableaction("mvlbuilders", "nodes.handlers.migrate") end inserts_too = v end) diff --git a/tex/context/base/mkiv/node-nut.lua b/tex/context/base/mkiv/node-nut.lua index cec272bcf..0c6714667 100644 --- a/tex/context/base/mkiv/node-nut.lua +++ b/tex/context/base/mkiv/node-nut.lua @@ -133,19 +133,90 @@ if not direct.setwhd then end end -nuts.getwhd = direct.getwhd -nuts.setwhd = direct.setwhd - -nuts.getfield = direct.getfield -nuts.getnext = direct.getnext -nuts.getprev = direct.getprev -nuts.getid = direct.getid -nuts.getattr = direct.get_attribute or direct.has_attribute or direct.getfield -nuts.getchar = direct.getchar -nuts.getfont = direct.getfont -nuts.getsubtype = direct.getsubtype -nuts.getlist = direct.getlist -- only hlist and vlist ! -nuts.getleader = direct.getleader +if not direct.getcomponents then + + local getfield = direct.getfield + local setfield = direct.setfield + local setsubtype = direct.setsubtype + + local attributelist_code = nodecodes.attributelist + + function direct.getcomponents(n) return getfield(n,"components") end + function direct.setcomponents(n,c) setfield(n,"components",c) end + function direct.getkern(n) return getfield(n,"kern") end + function direct.getwidth(n) return getfield(n,"width") end + function direct.setwidth(n,w) return setfield(n,"width",w) end + function direct.getheight(n) return getfield(n,"height") end + function direct.setheight(n,h) return setfield(n,"height",h) end + function direct.getdepth(n) return getfield(n,"depth") end + function direct.setdepth(n,d) return setfield(n,"depth",d) end + function direct.getshift(n) return getfield(n,"shift") end + function direct.setshift(n,s) return setfield(n,"shift",s) end + function direct.getpenalty(n) return getfield(n,"penalty") end + function direct.setpenalty(n,p) setfield(n,"penalty",p) end + function direct.getdir(n) return getfield(n,"dir") end + function direct.setdir(n,p) setfield(n,"dir",p) end + function direct.getlanguage(n) return getfield(n,"lang") end + function direct.setlanguage(n,l) return setfield(n,"lang",l) end + function direct.getattributelist(n) getfield(n,"attr") end + + function direct.getnucleus(n) return getfield(n,"nucleus") end + function direct.setnucleus(n,p) return setfield(n,"nucleus",p) end + function direct.getsup(n) return getfield(n,"sup") end + function direct.setsup(n,p) return setfield(n,"sup",p) end + function direct.getsub(n) return getfield(n,"sub") end + function direct.setsub(n,p) return setfield(n,"sub",p) end + + function direct.setattributelist(n,a) + if a and type(a) ~= attributelist_code then + a = getfield(a,"attr") + end + setfield(n,"attr",a) + end + + function direct.setkern(n,k,s) + setfield(n,"kern",k) + if s then + setsubtype(n,s) + end + end + + function direct.setfont(n,f,c) + setfield(n,"font",f) + if c then + setfield(n,"char",f) + end + end + + function direct.getoffsets(n) + return getfield(n,"xoffset"), getfield(n,"yoffset") + end + + function direct.setoffsets(n,x,y) + if x then + setfield(n,"xoffset",x) + end + if y then + setfield(n,"yoffset",y) + end + end + +end + +-- if LUATEXVERSION < 1.004 then +-- local gc = direct.getcomponents +-- getcomponents = function(n) local c = gc(n) return c ~= 0 and c or nil end +-- end + +-- local hash = table.setmetatableindex("number") +-- local ga = direct.get_attribute +-- function direct.get_attribute(n,a) +-- hash[a] = hash[a] + 1 +-- return ga(n,a) +-- end +-- function nuts.reportattr() +-- inspect(hash) +-- end -- local function track(name) -- local n = 0 @@ -163,12 +234,6 @@ nuts.getleader = direct.getleader -- setters -nuts.setfield = direct.setfield -nuts.setattr = direct.set_attribute or setfield - -nuts.getbox = direct.getbox -nuts.setbox = direct.setbox - -- helpers nuts.tostring = direct.tostring @@ -199,6 +264,10 @@ nuts.is_direct = direct.is_direct nuts.is_nut = direct.is_direct nuts.first_glyph = direct.first_glyph nuts.has_glyph = direct.has_glyph or direct.first_glyph +nuts.count = direct.count +nuts.length = direct.length +nuts.find_attribute = direct.find_attribute +nuts.unset_attribute = direct.unset_attribute nuts.current_attr = direct.current_attr nuts.has_field = direct.has_field @@ -228,56 +297,95 @@ if not direct.mlist_to_hlist then -- needed end -if LUATEXVERSION < 0.97 then - - local getglue = direct.getglue - - function direct.is_zero_glue(n) - local width, stretch, shrink = getglue(n) - return width == 0 and stretch == 0 and shrink == 0 - end - -end - -if not direct.rangedimensions then -- LUATEXVERSION < 0.99 - - local dimensions = direct.dimensions - local getfield = direct.getfield - local find_tail = direct.tail +nuts.getfield = direct.getfield +nuts.setfield = direct.setfield - function direct.rangedimensions(parent,first,last) - return dimensions( - getfield(parent,"glue_set"), getfield(parent,"glue_sign"), getfield(parent,"glue_order"), - first, last or find_tail(first), getfield(parent,"dir") - ) - end +nuts.getnext = direct.getnext +nuts.setnext = direct.setnext - nuts.rangedimensions = direct.rangedimensions +nuts.getid = direct.getid -end +nuts.getprev = direct.getprev +nuts.setprev = direct.setprev -local getglue = direct.getglue -local setglue = direct.setglue -local is_zero_glue = direct.is_zero_glue +nuts.getattr = direct.get_attribute +nuts.setattr = direct.set_attribute +nuts.takeattr = direct.unset_attribute -- ? +nuts.is_zero_glue = direct.is_zero_glue nuts.effective_glue = direct.effective_glue -nuts.getglue = getglue -nuts.setglue = setglue -nuts.is_zero_glue = is_zero_glue + +nuts.getglue = direct.getglue +nuts.setglue = direct.setglue nuts.getdisc = direct.getdisc -nuts.getwhd = direct.getwhd nuts.setdisc = direct.setdisc +nuts.getdiscretionary = direct.getdisc +nuts.setdiscretionary = direct.setdisc + +nuts.getwhd = direct.getwhd +nuts.setwhd = direct.setwhd +nuts.getwidth = direct.getwidth +nuts.setwidth = direct.setwidth +nuts.getheight = direct.getheight +nuts.setheight = direct.setheight +nuts.getdepth = direct.getdepth +nuts.setdepth = direct.setdepth +nuts.getshift = direct.getshift +nuts.setshift = direct.setshift + +nuts.getnucleus = direct.getnucleus +nuts.setnucleus = direct.setnucleus +nuts.getsup = direct.getsup +nuts.setsup = direct.setsup +nuts.getsub = direct.getsub +nuts.setsub = direct.setsub + +nuts.getchar = direct.getchar nuts.setchar = direct.setchar -nuts.setnext = direct.setnext -nuts.setprev = direct.setprev -nuts.setboth = direct.setboth +nuts.getfont = direct.getfont +nuts.setfont = direct.setfont + nuts.getboth = direct.getboth +nuts.setboth = direct.setboth nuts.setlink = direct.setlink +nuts.setsplit = direct.setsplit + +nuts.getlist = direct.getlist -- only hlist and vlist ! nuts.setlist = direct.setlist +nuts.getleader = direct.getleader nuts.setleader = direct.setleader +nuts.getcomponents = direct.getcomponents +nuts.setcomponents = direct.setcomponents + +nuts.getsubtype = direct.getsubtype nuts.setsubtype = direct.setsubtype +nuts.getlang = direct.getlang +nuts.setlang = direct.setlang +nuts.getlanguage = direct.getlang +nuts.setlanguage = direct.setlang + +nuts.getattrlist = direct.getattributelist +nuts.setattrlist = direct.setattributelist +nuts.getattributelist = direct.getattributelist +nuts.setattributelist = direct.setattributelist + +nuts.getoffsets = direct.getoffsets +nuts.setoffsets = direct.setoffsets + +nuts.getkern = direct.getkern +nuts.setkern = direct.setkern + +nuts.getdir = direct.getdir +nuts.setdir = direct.setdir + +nuts.getpenalty = direct.getpenalty +nuts.setpenalty = direct.setpenalty + +nuts.getbox = direct.getbox +nuts.setbox = direct.setbox + nuts.is_char = direct.is_char nuts.ischar = direct.is_char nuts.is_glyph = direct.is_glyph @@ -313,6 +421,11 @@ local function remove(head,current,free_too) return head, current, t end +-- alias + +nuts.getsurround = nuts.getkern +nuts.setsurround = nuts.setkern + -- bad: we can have prev's being glue_spec nuts.remove = remove @@ -326,11 +439,14 @@ function nuts.replace(head,current,new) -- no head returned if false head, current, new = false, head, current end local prev, next = d_getboth(current) - if next then - d_setlink(new,next) - end - if prev then - d_setlink(prev,new) +-- if next then +-- d_setlink(new,next) +-- end +-- if prev then +-- d_setlink(prev,new) +-- end + if prev or next then + d_setlink(prev,new,next) end if head then if head == current then @@ -344,14 +460,14 @@ function nuts.replace(head,current,new) -- no head returned if false end end -local function count(stack,flat) +local function countall(stack,flat) local n = 0 while stack do local id = d_getid(stack) if not flat and id == hlist_code or id == vlist_code then local list = d_getlist(stack) if list then - n = n + 1 + count(list) -- self counts too + n = n + 1 + countall(list) -- self counts too else n = n + 1 end @@ -363,7 +479,11 @@ local function count(stack,flat) return n end -nuts.count = count +nuts.countall = countall + +function nodes.countall(stack,flat) + return countall(tonut(stack),flat) +end function nuts.append(head,current,...) for i=1,select("#",...) do @@ -379,7 +499,7 @@ function nuts.prepend(head,current,...) return head, current end -function nuts.linked(...) +function nuts.linked(...) -- slides ! local head, last for i=1,select("#",...) do local next = select(i,...) diff --git a/tex/context/base/mkiv/node-ppt.lua b/tex/context/base/mkiv/node-ppt.lua index 82acf2ff4..5ebfca87d 100644 --- a/tex/context/base/mkiv/node-ppt.lua +++ b/tex/context/base/mkiv/node-ppt.lua @@ -27,7 +27,6 @@ local getnext = nuts.getnext local getprev = nuts.getprev local getsubtype = nuts.getsubtype local getfield = nuts.getfield -local setfield = nuts.setfield local getlist = nuts.getlist local setlist = nuts.setlist local removenode = nuts.remove @@ -102,8 +101,7 @@ local actions = { } properties.actions = actions table.setmetatableindex(actions,function(t,k) report("unknown property action %a",k) - local v = function() end - return v + return function() end end) local f_delayed = formatters["return function(target,head,where,propdata,parent) %s end"] @@ -314,7 +312,7 @@ local anchored = { } table.setmetatableindex(anchored,function(t,k) - v = anchored[v_after] + local v = anchored[v_after] t[k] = v return v end) diff --git a/tex/context/base/mkiv/node-pro.lua b/tex/context/base/mkiv/node-pro.lua index 713d78f07..8a501a590 100644 --- a/tex/context/base/mkiv/node-pro.lua +++ b/tex/context/base/mkiv/node-pro.lua @@ -6,23 +6,17 @@ if not modules then modules = { } end modules ['node-pro'] = { license = "see context related readme files" } -local utfchar = utf.char -local format, concat = string.format, table.concat - local trace_callbacks = false trackers .register("nodes.callbacks", function(v) trace_callbacks = v end) local force_processors = false directives.register("nodes.processors.force", function(v) force_processors = v end) local report_nodes = logs.reporter("nodes","processors") -local nodes = nodes -local tasks = nodes.tasks -local nuts = nodes.nuts - -local first_glyph = nodes.first_glyph -local has_glyph = nodes.has_glyph +local nodes = nodes +local tasks = nodes.tasks +local nuts = nodes.nuts -nodes.processors = nodes.processors or { } -local processors = nodes.processors +nodes.processors = nodes.processors or { } +local processors = nodes.processors -- vbox: grouptype: vbox vtop output split_off split_keep | box_type: exactly|aditional -- hbox: grouptype: hbox adjusted_hbox(=hbox_in_vmode) | box_type: exactly|aditional @@ -35,6 +29,9 @@ do local isglyph = nuts.isglyph local getnext = nuts.getnext + local utfchar = utf.char + local concat = table.concat + local n = 0 local function reconstruct(head) -- we probably have a better one @@ -72,125 +69,164 @@ local tracer = processors.tracer processors.enabled = true -- this will become a proper state (like trackers) -function processors.pre_linebreak_filter(head,groupcode) -- ,size,packtype,direction - -- local first, found = first_glyph(head) -- they really need to be glyphs - local found = force_processors or has_glyph(head) - if found then - if trace_callbacks then - local before = nodes.count(head,true) - local head, done = actions(head,groupcode) -- ,size,packtype,direction - local after = nodes.count(head,true) - if done then - tracer("pre_linebreak","changed",head,groupcode,before,after,true) +do + + local has_glyph = nodes.has_glyph + + function processors.pre_linebreak_filter(head,groupcode) -- ,size,packtype,direction + local found = force_processors or has_glyph(head) + if found then + if trace_callbacks then + local before = nodes.count(head,true) + local head, done = actions(head,groupcode) -- ,size,packtype,direction + local after = nodes.count(head,true) + if done then + tracer("pre_linebreak","changed",head,groupcode,before,after,true) + else + tracer("pre_linebreak","unchanged",head,groupcode,before,after,true) + end + return done and head or true else - tracer("pre_linebreak","unchanged",head,groupcode,before,after,true) + local head, done = actions(head,groupcode) -- ,size,packtype,direction + return done and head or true end - return done and head or true - else - local head, done = actions(head,groupcode) -- ,size,packtype,direction - return done and head or true + elseif trace_callbacks then + local n = nodes.count(head,false) + tracer("pre_linebreak","no chars",head,groupcode,n,n) end - elseif trace_callbacks then - local n = nodes.count(head,false) - tracer("pre_linebreak","no chars",head,groupcode,n,n) + return true end - return true -end -local function hpack_filter(head,groupcode,size,packtype,direction,attributes) - -- local first, found = first_glyph(head) -- they really need to be glyphs - local found = force_processors or has_glyph(head) - if found then - if trace_callbacks then - local before = nodes.count(head,true) - local head, done = actions(head,groupcode,size,packtype,direction,attributes) - local after = nodes.count(head,true) - if done then - tracer("hpack","changed",head,groupcode,before,after,true) + local function hpack_filter(head,groupcode,size,packtype,direction,attributes) + local found = force_processors or has_glyph(head) + if found then + if trace_callbacks then + local before = nodes.count(head,true) + local head, done = actions(head,groupcode,size,packtype,direction,attributes) + local after = nodes.count(head,true) + if done then + tracer("hpack","changed",head,groupcode,before,after,true) + else + tracer("hpack","unchanged",head,groupcode,before,after,true) + end + return done and head or true else - tracer("hpack","unchanged",head,groupcode,before,after,true) + local head, done = actions(head,groupcode,size,packtype,direction,attributes) + return done and head or true end - return done and head or true - else - local head, done = actions(head,groupcode,size,packtype,direction,attributes) - return done and head or true + elseif trace_callbacks then + local n = nodes.count(head,false) + tracer("hpack","no chars",head,groupcode,n,n) end - elseif trace_callbacks then - local n = nodes.count(head,false) - tracer("hpack","no chars",head,groupcode,n,n) + return true end - return true -end -processors.hpack_filter = hpack_filter + processors.hpack_filter = hpack_filter -do + do + + local setfield = nodes.setfield + local hpack = nodes.hpack + + function nodes.fullhpack(head,...) + local ok = hpack_filter(head) + if not done or done == true then + ok = head + end + local hp, b = hpack(ok,...) + setfield(hp,"prev",nil) + setfield(hp,"next",nil) + return hp, b + end + + end + + do - local setfield = nodes.setfield - local hpack = nodes.hpack + local setboth = nuts.setboth + local hpack = nuts.hpack - function nodes.fullhpack(head,...) - local ok = hpack_filter(head) - if not done or done == true then - ok = head + function nuts.fullhpack(head,...) + local ok = hpack_filter(tonode(head)) + if not done or done == true then + ok = head + else + ok = tonut(ok) + end + local hp, b = hpack(...) + setboth(hp) + return hp, b end - local hp, b = hpack(ok,...) - setfield(hp,"prev",nil) - setfield(hp,"next",nil) - return hp, b + end + callbacks.register('pre_linebreak_filter', processors.pre_linebreak_filter, "all kind of horizontal manipulations (before par break)") + callbacks.register('hpack_filter' , processors.hpack_filter, "all kind of horizontal manipulations (before hbox creation)") + end do - local setboth = nuts.setboth - local hpack = nuts.hpack + local actions = tasks.actions("finalizers") -- head, where + + -- beware, these are packaged boxes so no first_glyph test + -- maybe some day a hash with valid groupcodes + -- + -- beware, much can pass twice, for instance vadjust passes two times + -- + -- something weird here .. group mvl when making a vbox - function nuts.fullhpack(head,...) - local ok = hpack_filter(tonode(head)) - if not done or done == true then - ok = head + function processors.post_linebreak_filter(head,groupcode) + if trace_callbacks then + local before = nodes.count(head,true) + local head, done = actions(head,groupcode) + local after = nodes.count(head,true) + if done then + tracer("post_linebreak","changed",head,groupcode,before,after,true) + else + tracer("post_linebreak","unchanged",head,groupcode,before,after,true) + end + return done and head or true else - ok = tonut(ok) + local head, done = actions(head,groupcode) + return done and head or true end - local hp, b = hpack(...) - setboth(hp) - return hp, b end + callbacks.register('post_linebreak_filter', processors.post_linebreak_filter,"all kind of horizontal manipulations (after par break)") + end -callbacks.register('pre_linebreak_filter', processors.pre_linebreak_filter, "all kind of horizontal manipulations (before par break)") -callbacks.register('hpack_filter' , processors.hpack_filter, "all kind of horizontal manipulations (before hbox creation)") - -local actions = tasks.actions("finalizers") -- head, where - --- beware, these are packaged boxes so no first_glyph test --- maybe some day a hash with valid groupcodes --- --- beware, much can pass twice, for instance vadjust passes two times --- --- something weird here .. group mvl when making a vbox - -function processors.post_linebreak_filter(head,groupcode) - if trace_callbacks then - local before = nodes.count(head,true) - local head, done = actions(head,groupcode) - local after = nodes.count(head,true) - if done then - tracer("post_linebreak","changed",head,groupcode,before,after,true) - else - tracer("post_linebreak","unchanged",head,groupcode,before,after,true) +do + + local texnest = tex.nest + + local getlist = nodes.getlist + local getsubtype = nodes.getsubtype + local setlist = nodes.setlist + + local line_code = nodes.listcodes.line + + local actions = tasks.actions("contributers") + + function processors.contribute_filter(groupcode) + if groupcode == "box" then -- "pre_box" + local whatever = texnest[texnest.ptr] + if whatever then + local tail = whatever.tail + if tail and getsubtype(tail) == line_code then + local okay, done = actions(tail,groupcode) + if okay and okay ~= tail then + setlist(tail,okay) + end + end + end end - return done and head or true - else - local head, done = actions(head,groupcode) - return done and head or true end -end -callbacks.register('post_linebreak_filter', processors.post_linebreak_filter,"all kind of horizontal manipulations (after par break)") + callbacks.register('contribute_filter', processors.contribute_filter,"things done with lines") + +end statistics.register("h-node processing time", function() return statistics.elapsedseconds(nodes,"including kernel") -- hm, ok here? diff --git a/tex/context/base/mkiv/node-ref.lua b/tex/context/base/mkiv/node-ref.lua index c082ac817..b313a00b6 100644 --- a/tex/context/base/mkiv/node-ref.lua +++ b/tex/context/base/mkiv/node-ref.lua @@ -32,7 +32,7 @@ local cleanupdestinations = true local transparencies = attributes.transparencies local colors = attributes.colors local references = structures.references -local tasks = nodes.tasks +local enableaction = nodes.tasks.enableaction local trace_references = false trackers.register("nodes.references", function(v) trace_references = v end) local trace_destinations = false trackers.register("nodes.destinations", function(v) trace_destinations = v end) @@ -60,10 +60,15 @@ local getprev = nuts.getprev local getid = nuts.getid local getlist = nuts.getlist local setlist = nuts.setlist +local getwidth = nuts.getwidth +local setwidth = nuts.setwidth +local getheight = nuts.getheight local getattr = nuts.getattr local setattr = nuts.setattr local getsubtype = nuts.getsubtype local getwhd = nuts.getwhd +local getdir = nuts.getdir +local setshift = nuts.setshift local hpack_list = nuts.hpack local vpack_list = nuts.vpack @@ -212,7 +217,7 @@ local function dimensions(parent,start,stop) -- in principle we could move some report_area("dimensions taken of vlist") end local w, h, d = vlist_dimensions(first,last,parent) - local ht = getfield(first,"height") + local ht = getheight(first) return w, ht, d + h - ht, first else -- return hlist_dimensions(start,stop,parent) @@ -286,8 +291,9 @@ if first == last and getid(parent) == vlist_code and getid(first) == hlist_code setlink(result,getlist(first)) setlist(first,result) else - setlink(getprev(first),result) - setlink(result,first) + -- setlink(getprev(first),result) + -- setlink(result,first) + setlink(getprev(first),result,first) end return head, last end @@ -345,8 +351,9 @@ local function inject_list(id,current,reference,make,stack,pardir,txtdir) setlist(current,result) elseif moveright then -- brr no prevs done -- result after first - setlink(result,getnext(first)) - setlink(first,result) + -- setlink(result,getnext(first)) + -- setlink(first,result) + setlink(first,result,getnext(first)) else -- first after result setlink(result,first) @@ -405,9 +412,9 @@ local function inject_areas(head,attribute,make,stack,done,skip,parent,pardir,tx done[r] = done[r] - 1 end elseif id == dir_code then - txtdir = getfield(current,"dir") + txtdir = getdir(current) elseif id == localpar_code then - pardir = getfield(current,"dir") + pardir = getdir(current) elseif id == glue_code and getsubtype(current) == leftskip_code then -- any glue at the left? -- else @@ -457,9 +464,9 @@ local function inject_area(head,attribute,make,stack,done,parent,pardir,txtdir) end end elseif id == dir_code then - txtdir = getfield(current,"dir") + txtdir = getdir(current) elseif id == localpar_code then - pardir = getfield(current,"dir") + pardir = getdir(current) else local r = getattr(current,attribute) if r and not done[r] then @@ -501,8 +508,8 @@ local function addstring(what,str,shift) --todo make a pluggable helper (in font end local text = typesetters.tohpack(str,infofont) local rule = new_rule(emwidth/5,4*exheight,3*exheight) - setfield(text,"shift",shift) - return hpack_list(nuts.linked(text,rule)) + setshift(text,shift) + return hpack_list(setlink(text,rule)) end end end @@ -540,30 +547,30 @@ local function colorize(width,height,depth,n,reference,what,sr,offset) setattr(rule,a_transparency,u_transparency) if width < 0 then local kern = new_kern(width) - setfield(rule,"width",-width) + setwidth(rule,-width) setnext(kern,rule) setprev(rule,kern) return kern elseif sr and sr ~= "" then local text = addstring(what,sr,shift) if text then - local kern = new_kern(-getfield(text,"width")) - setlink(kern,text) - setlink(text,rule) + local kern = new_kern(-getwidth(text)) + -- setlink(kern,text) + -- setlink(text,rule) + setlink(kern,text,rule) return kern end end return rule end -local function justadd(what,sr,shift) +local function justadd(what,sr,shift,current) -- needs testing if sr and sr ~= "" then local text = addstring(what,sr,shift) if text then - local kern = new_kern(-getfield(text,"width")) - setlink(kern,text) - setlink(text,rule) - return kern + local kern = new_kern(-getwidth(text)) + setlink(kern,text,current) + return new_hlist(kern) end end end @@ -637,17 +644,12 @@ local function makereference(width,height,depth,reference) -- height and depth a end if trace_references then local step = 65536 --- result = hpack_list(colorize(width,height-step,depth-step,2,reference,"reference",texts,show_references)) -- step subtracted so that we can see seperate links --- setfield(result,"width",0) -result = new_hlist(colorize(width,height-step,depth-step,2,reference,"reference",texts,show_references)) -- step subtracted so that we can see seperate links + result = new_hlist(colorize(width,height-step,depth-step,2,reference,"reference",texts,show_references)) -- step subtracted so that we can see seperate links current = result elseif texts then - texts = justadd("reference",texts,show_references) + texts = justadd("reference",texts,show_references,current) if texts then --- result = hpack_list(texts) --- setfield(result,"width",0) -result = new_hlist(texts) - current = result + current = texts end end if current then @@ -656,11 +658,7 @@ result = new_hlist(texts) result = annot end references.registerpage(n) --- result = hpack_list(result,0) --- setfield(result,"width",0) --- setfield(result,"height",0) --- setfield(result,"depth",0) -result = new_hlist(result) + result = new_hlist(result) if cleanupreferences then stack[reference] = nil end return result, resolved elseif trace_references then @@ -757,9 +755,7 @@ local function makedestination(width,height,depth,reference) step = 4*65536 width, height, depth = 5*step, 5*step, 0 end --- local rule = hpack_list(colorize(width,height,depth,3,reference,"destination",texts,show_destinations)) --- setfield(rule,"width",0) -local rule = new_list(colorize(width,height,depth,3,reference,"destination",texts,show_destinations)) + local rule = new_hlist(colorize(width,height,depth,3,reference,"destination",texts,show_destinations)) if not result then result, current = rule, rule else @@ -768,15 +764,9 @@ local rule = new_list(colorize(width,height,depth,3,reference,"destination",text end width, height = width - step, height - step elseif texts then - texts = justadd("destination",texts,show_destinations) + texts = justadd("destination",texts,show_destinations,current) if texts then --- result = hpack_list(texts) --- if result then --- setfield(result,"width",0) --- current = result --- end -result = new_list(texts) -current = result + current = texts end end nofdestinations = nofdestinations + 1 @@ -791,12 +781,7 @@ current = result current = find_node_tail(annot) end if result then - -- some internal error --- result = hpack_list(result,0) --- setfield(result,"width",0) --- setfield(result,"height",0) --- setfield(result,"depth",0) -result = new_hlist(result) + result = new_hlist(result) end if cleanupdestinations then stack[reference] = nil end return result, resolved @@ -932,8 +917,8 @@ statistics.register("interactive elements", function() end) function references.enableinteraction() - tasks.enableaction("shipouts","nodes.references.handler") - tasks.enableaction("shipouts","nodes.destinations.handler") + enableaction("shipouts","nodes.references.handler") + enableaction("shipouts","nodes.destinations.handler") function references.enableinteraction() end end diff --git a/tex/context/base/mkiv/node-res.lua b/tex/context/base/mkiv/node-res.lua index cb06ae488..8b7ec1a62 100644 --- a/tex/context/base/mkiv/node-res.lua +++ b/tex/context/base/mkiv/node-res.lua @@ -79,14 +79,18 @@ local setchar = nuts.setchar local setlist = nuts.setlist local setwhd = nuts.setwhd local setglue = nuts.setglue +local setdisc = nuts.setdisc +local setfont = nuts.setfont +local setkern = nuts.setkern +local setpenalty = nuts.setpenalty +local setdir = nuts.setdir +local setshift = nuts.setshift +local setwidth = nuts.setwidth local copy_nut = nuts.copy local new_nut = nuts.new local flush_nut = nuts.flush -local copy_node = nodes.copy -local new_node = nodes.new - -- at some point we could have a dual set (the overhead of tonut is not much larger than -- metatable associations at the lua/c end esp if we also take assignments into account @@ -181,23 +185,26 @@ local wordboundary = register_nut(new_nut("boundary",boundarycodes.word)) -- the dir field needs to be set otherwise crash: -local rule = register_nut(new_nut("rule")) setfield(rule, "dir","TLT") -local emptyrule = register_nut(new_nut("rule",rulecodes.empty)) setfield(rule, "dir","TLT") -local userrule = register_nut(new_nut("rule",rulecodes.user)) setfield(rule, "dir","TLT") -local hlist = register_nut(new_nut("hlist")) setfield(hlist,"dir","TLT") -local vlist = register_nut(new_nut("vlist")) setfield(vlist,"dir","TLT") +local rule = register_nut(new_nut("rule")) setdir(rule, "TLT") +local emptyrule = register_nut(new_nut("rule",rulecodes.empty)) setdir(rule, "TLT") +local userrule = register_nut(new_nut("rule",rulecodes.user)) setdir(rule, "TLT") +local hlist = register_nut(new_nut("hlist")) setdir(hlist,"TLT") +local vlist = register_nut(new_nut("vlist")) setdir(vlist,"TLT") function nutpool.glyph(fnt,chr) local n = copy_nut(glyph) - if fnt then setfield(n,"font",fnt) end - if chr then setchar(n,chr) end + if fnt then + setfont(n,fnt,chr) + elseif chr then + setchar(n,chr) + end return n end function nutpool.penalty(p) local n = copy_nut(penalty) if p and p ~= 0 then - setfield(n,"penalty",p) + setpenalty(n,p) end return n end @@ -205,7 +212,7 @@ end function nutpool.kern(k) local n = copy_nut(kern) if k and k ~= 0 then - setfield(n,"kern",k) + setkern(n,k) end return n end @@ -228,39 +235,20 @@ end function nutpool.fontkern(k) local n = copy_nut(fontkern) - setfield(n,"kern",k) + if k and k ~= 0 then + setkern(n,k) + end return n end function nutpool.italickern(k) local n = copy_nut(italickern) if k and k ~= 0 then - setfield(n,"kern",k) + setkern(n,k) end return n end --- function nutpool.gluespec(width,stretch,shrink,stretch_order,shrink_order) --- -- maybe setglue --- local s = copy_nut(glue_spec) --- if width and width ~= 0 then --- setfield(s,"width",width) --- end --- if stretch and stretch ~= 0 then --- setfield(s,"stretch",stretch) --- end --- if shrink and shrink ~= 0 then --- setfield(s,"shrink",shrink) --- end --- if stretch_order and stretch_order ~= 0 then --- setfield(s,"stretch_order",stretch_order) --- end --- if shrink_order and shrink_order ~= 0 then --- setfield(s,"shrink_order",shrink_order) --- end --- return s --- end - function nutpool.gluespec(width,stretch,shrink,stretch_order,shrink_order) -- maybe setglue local s = copy_nut(glue_spec) @@ -270,27 +258,6 @@ function nutpool.gluespec(width,stretch,shrink,stretch_order,shrink_order) return s end --- local function someskip(skip,width,stretch,shrink,stretch_order,shrink_order) --- -- maybe setglue --- local n = copy_nut(skip) --- if width and width ~= 0 then --- setfield(n,"width",width) --- end --- if stretch and stretch ~= 0 then --- setfield(n,"stretch",stretch) --- end --- if shrink and shrink ~= 0 then --- setfield(n,"shrink",shrink) --- end --- if stretch_order and stretch_order ~= 0 then --- setfield(n,"stretch_order",stretch_order) --- end --- if shrink_order and shrink_order ~= 0 then --- setfield(n,"shrink_order",shrink_order) --- end --- return n --- end - local function someskip(skip,width,stretch,shrink,stretch_order,shrink_order) -- maybe setglue local n = copy_nut(skip) @@ -300,18 +267,6 @@ local function someskip(skip,width,stretch,shrink,stretch_order,shrink_order) return n end --- function nutpool.stretch(a,b) --- local n = copy_nut(glue) --- if b then --- setfield(n,"stretch",a) --- setfield(n,"stretch_order",b) --- else --- setfield(n,"stretch",1) --- setfield(n,"stretch_order",a or 1) --- end --- return n --- end - function nutpool.stretch(a,b) -- width stretch shrink stretch_order shrink_order local n = copy_nut(glue) @@ -322,18 +277,6 @@ function nutpool.stretch(a,b) return n end --- function nutpool.shrink(a,b) --- local n = copy_nut(glue) --- if b then --- setfield(n,"shrink",a) --- setfield(n,"shrink_order",b) --- else --- setfield(n,"shrink",1) --- setfield(n,"shrink_order",a or 1) --- end --- return n --- end - function nutpool.shrink(a,b) local n = copy_nut(glue) if not b then @@ -347,23 +290,6 @@ function nutpool.glue(width,stretch,shrink,stretch_order,shrink_order) return someskip(glue,width,stretch,shrink,stretch_order,shrink_order) end --- function nutpool.negatedglue(glue) --- local n = copy_nut(glue) --- local width = getfield(n,"width") --- local stretch = getfield(n,"stretch") --- local shrink = getfield(n,"shrink") --- if width and width ~= 0 then --- setfield(n,"width", -width) --- end --- if stretch and stretch ~= 0 then --- setfield(n,"stretch",-stretch) --- end --- if shrink and shrink ~= 0 then --- setfield(n,"shrink", -shrink) --- end --- return n --- end - function nutpool.negatedglue(glue) local n = copy_nut(glue) local width, stretch, shrink = getglue(n) @@ -387,13 +313,19 @@ function nutpool.baselineskip(width,stretch,shrink) return someskip(baselineskip,width,stretch,shrink) end -function nutpool.disc() - return copy_nut(disc) +function nutpool.disc(pre,post,replace) + local d = copy_nut(disc) + if pre or post or replace then + setdisc(d,pre,post,replace) + end + return d end function nutpool.textdir(dir) local t = copy_nut(textdir) - setfield(t,"dir",dir) + if dir then + setdir(t,dir) + end return t end @@ -403,7 +335,7 @@ function nutpool.rule(width,height,depth,dir) -- w/h/d == nil will let them adap setwhd(n,width,height,depth) end if dir then - setfield(n,"dir",dir) + setdir(n,dir) end return n end @@ -414,7 +346,7 @@ function nutpool.emptyrule(width,height,depth,dir) -- w/h/d == nil will let them setwhd(n,width,height,depth) end if dir then - setfield(n,"dir",dir) + setdir(n,dir) end return n end @@ -425,7 +357,7 @@ function nutpool.userrule(width,height,depth,dir) -- w/h/d == nil will let them setwhd(n,width,height,depth) end if dir then - setfield(n,"dir",dir) + setdir(n,dir) end return n end @@ -448,7 +380,7 @@ function nutpool.leftmarginkern(glyph,width) setfield(n,"glyph",glyph) end if width and width ~= 0 then - setfield(n,"width",width) + setwidth(n,width) end return n end @@ -463,7 +395,7 @@ function nutpool.rightmarginkern(glyph,width) setfield(n,"glyph",glyph) end if width and width ~= 0 then - setfield(n,"width",width) + setwidth(n,width) end return n end @@ -485,7 +417,7 @@ local function new_hlist(list,width,height,depth,shift) setwhd(n,width,height,depth) end if shift and shift ~= 0 then - setfield(n,"shift",shift) + setshift(n,shift) end return n end @@ -499,7 +431,7 @@ local function new_vlist(list,width,height,depth,shift) setwhd(n,width,height,depth) end if shift and shift ~= 0 then - setfield(n,"shift",shift) + setshift(n,shift) end return n end diff --git a/tex/context/base/mkiv/node-rul.lua b/tex/context/base/mkiv/node-rul.lua index 97100c896..8646fe447 100644 --- a/tex/context/base/mkiv/node-rul.lua +++ b/tex/context/base/mkiv/node-rul.lua @@ -19,9 +19,10 @@ if not modules then modules = { } end modules ['node-rul'] = { local attributes = attributes local nodes = nodes -local tasks = nodes.tasks local properties = nodes.properties +local enableaction = nodes.tasks.enableaction + local nuts = nodes.nuts local tonode = nuts.tonode local tonut = nuts.tonut @@ -39,6 +40,12 @@ local setattr = nuts.setattr local getfont = nuts.getfont local getsubtype = nuts.getsubtype local getlist = nuts.getlist +local setwhd = nuts.setwhd +local setdir = nuts.setdir +local setattrlist = nuts.setattrlist +local setshift = nuts.setshift +local getwidth = nuts.getwidth +local setwidth = nuts.setwidth local flushlist = nuts.flush_list local effective_glue = nuts.effective_glue @@ -58,15 +65,9 @@ local listcodes = nodes.listcodes local kerncodes = nodes.kerncodes local glyph_code = nodecodes.glyph -local disc_code = nodecodes.disc -local rule_code = nodecodes.rule -local boundary_code = nodecodes.boundary local localpar_code = nodecodes.localpar local dir_code = nodecodes.dir -local math_code = nodecodes.math local glue_code = nodecodes.glue -local penalty_code = nodecodes.penalty -local kern_code = nodecodes.kern local hlist_code = nodecodes.hlist local indent_code = listcodes.indent @@ -103,13 +104,10 @@ local v_left = variables.left local v_right = variables.right local v_local = variables["local"] local v_yes = variables.yes -local v_all = variables.all local v_foreground = variables.foreground local fonthashes = fonts.hashes local fontdata = fonthashes.identifiers -local fontunicodes = fonthashes.unicodes -local fontcharacters = fonthashes.characters local fontresources = fonthashes.resources local dimenfactor = fonts.helpers.dimenfactor @@ -139,7 +137,7 @@ local function userrule(t,noattributes) if noattributes == false or noattributes == nil then -- avoid fuzzy ones else - setfield(r,"attr",current_attr()) + setattrlist(r,current_attr()) end properties[r] = t return tonode(r) @@ -349,14 +347,9 @@ rules.handler = function(head) end function rules.enable() - tasks.enableaction("shipouts","nodes.rules.handler") + enableaction("shipouts","nodes.rules.handler") end --- elsewhere: --- --- tasks.appendaction ("shipouts", "normalizers", "nodes.rules.handler") --- tasks.disableaction("shipouts", "nodes.rules.handler") -- only kick in when used - local trace_shifted = false trackers.register("nodes.shifting", function(v) trace_shifted = v end) local report_shifted = logs.reporter("nodes","shifting") @@ -384,7 +377,7 @@ local function flush_shifted(head,first,last,data,level,parent,strip) -- not tha setprev(first) setnext(last) local width, height, depth = list_dimensions(parent,first,next) - local list = hpack_nodes(first,width,"exactly") + local list = hpack_nodes(first,width,"exactly") -- we can use a simple pack if first == head then head = list end @@ -395,9 +388,8 @@ local function flush_shifted(head,first,last,data,level,parent,strip) -- not tha setlink(list,next) end local raise = data.dy * dimenfactor(data.unit,fontdata[getfont(first)]) - setfield(list,"shift",raise) - setfield(list,"height",height) - setfield(list,"depth",depth) + setshift(list,raise) + setwhd(list,width,height,depth) if trace_shifted then report_shifted("width %p, nodes %a, text %a",width,n_tostring(first,last),n_tosequence(first,last,true)) end @@ -409,7 +401,7 @@ local process = nodes.processwords nodes.shifts.handler = function(head) return process(a_shifted,data,flush_shifted,head) end function nodes.shifts.enable() - tasks.enableaction("shipouts","nodes.shifts.handler") + enableaction("shipouts","nodes.shifts.handler") end -- linefillers @@ -445,7 +437,7 @@ local function linefiller(current,data,width,location) ca = ca, ta = ta, option = location, - direction = getfield(current,"dir"), + direction = getdir(current), }) else local linefiller = new_rule(width,height,depth) @@ -471,6 +463,7 @@ local function find_attr(head,attr) end function nodes.linefillers.handler(head) +-- local current = tonut(head) -- when we hook into the contributers for current in traverse_id(hlist_code,tonut(head)) do if getsubtype(current) == line_code then local list = getlist(current) @@ -523,16 +516,16 @@ function nodes.linefillers.handler(head) head = getnext(head) end if head then - local indentation = iskip and getfield(iskip,"width") or 0 - local leftfixed = lskip and getfield(lskip,"width") or 0 + local indentation = iskip and getwidth(iskip) or 0 + local leftfixed = lskip and getwidth(lskip) or 0 local lefttotal = lskip and effective_glue(lskip,current) or 0 local width = lefttotal - (leftlocal and leftfixed or 0) + indentation - distance if width > threshold then if iskip then - setfield(iskip,"width",0) + setwidth(iskip,0) end if lskip then - setglue(lskip,leftlocal and getfield(lskip,"width") or nil) + setglue(lskip,leftlocal and getwidth(lskip) or nil) if distance > 0 then insert_node_after(list,lskip,new_kern(distance)) end @@ -563,9 +556,9 @@ function nodes.linefillers.handler(head) tail = getprev(tail) end if tail then - local rightfixed = rskip and getfield(rskip,"width") or 0 + local rightfixed = rskip and getwidth(rskip) or 0 local righttotal = rskip and effective_glue(rskip,current) or 0 - local parfixed = pskip and getfield(pskip,"width") or 0 + local parfixed = pskip and getwidth(pskip) or 0 local partotal = pskip and effective_glue(pskip,current) or 0 local width = righttotal - (rightlocal and rightfixed or 0) + partotal - distance if width > threshold then @@ -573,7 +566,7 @@ function nodes.linefillers.handler(head) setglue(pskip) end if rskip then - setglue(rskip,rightlocal and getfield(rskip,"width") or nil) + setglue(rskip,rightlocal and getwidth(rskip) or nil) if distance > 0 then insert_node_before(list,rskip,new_kern(distance)) end @@ -600,7 +593,7 @@ local enable = false function nodes.linefillers.enable() if not enable then -- we could now nil it - tasks.enableaction("finalizers","nodes.linefillers.handler") + enableaction("finalizers","nodes.linefillers.handler") enable = true end end diff --git a/tex/context/base/mkiv/node-ser.lua b/tex/context/base/mkiv/node-ser.lua index 847db7a15..f1be21f84 100644 --- a/tex/context/base/mkiv/node-ser.lua +++ b/tex/context/base/mkiv/node-ser.lua @@ -26,7 +26,6 @@ local nodecodes = nodes.nodecodes local subtcodes = nodes.codes local noadcodes = nodes.noadcodes local getfields = nodes.fields -local nodekeys = nodes.keys local tonode = nodes.tonode diff --git a/tex/context/base/mkiv/node-tra.lua b/tex/context/base/mkiv/node-tra.lua index b3b4311e7..0d3192559 100644 --- a/tex/context/base/mkiv/node-tra.lua +++ b/tex/context/base/mkiv/node-tra.lua @@ -47,10 +47,14 @@ local getsubtype = nuts.getsubtype local getlist = nuts.getlist local getdisc = nuts.getdisc local setattr = nuts.setattr +local getglue = nuts.getglue local isglyph = nuts.isglyph +local getcomponents = nuts.getcomponents +local getdir = nuts.getdir +local getwidth = nuts.getwidth local flush_list = nuts.flush_list -local count_nodes = nuts.count +local count_nodes = nuts.countall local used_nodes = nuts.usedlist local traverse_by_id = nuts.traverse_id @@ -121,6 +125,7 @@ function nodes.handlers.checkforleaks(sparse) end local f_sequence = formatters["U+%04X:%s"] +local f_subrange = formatters["[[ %s ][ %s ][ %s ]]"] local function tosequence(start,stop,compact) if start then @@ -131,7 +136,7 @@ local function tosequence(start,stop,compact) local c, id = isglyph(start) if c then if compact then - local components = getfield(start,"components") + local components = getcomponents(start) if components then t[#t+1] = tosequence(components,nil,compact) else @@ -140,6 +145,9 @@ local function tosequence(start,stop,compact) else t[#t+1] = f_sequence(c,utfchar(c)) end + elseif id == disc_code then + local pre, post, replace = getdisc(start) + t[#t+1] = f_subrange(pre and tosequence(pre),post and tosequence(post),replace and tosequence(replace)) elseif id == rule_code then if compact then t[#t+1] = "|" @@ -147,7 +155,7 @@ local function tosequence(start,stop,compact) t[#t+1] = nodecodes[id] end elseif id == dir_code or id == localpar_code then - t[#t+1] = "[" .. getfield(start,"dir") .. "]" + t[#t+1] = "[" .. getdir(start) .. "]" elseif compact then t[#t+1] = "[]" else @@ -310,7 +318,7 @@ local function listtoutf(h,joiner,textonly,last,nodisc) end elseif textonly then if id == glue_code then - if getfield(h,"width") > 0 then + if getwidth(h) > 0 then w[#w+1] = " " end elseif id == hlist_code or id == vlist_code then @@ -375,7 +383,7 @@ local function nodetodimen(n) n = tonut(n) local id = getid(n) if id == kern_code then - local width = getfield(n,"width") + local width = getwidth(n) if width == 0 then return "0pt" else @@ -384,11 +392,10 @@ local function nodetodimen(n) elseif id ~= glue_code then return "0pt" end - local stretch_order = getfield(n,"stretch_order") - local shrink_order = getfield(n,"shrink_order") - local stretch = getfield(n,"stretch") / 65536 - local shrink = getfield(n,"shrink") / 65536 - local width = getfield(n,"width") / 65536 + local width, stretch, shrink, stretch_order, shrink_order = getglue(n) + stretch = stretch / 65536 + shrink = shrink / 65536 + width = width / 65536 if stretch_order ~= 0 then if shrink_order ~= 0 then return f_f_f(width,stretch,fillorders[stretch_order],shrink,fillorders[shrink_order]) diff --git a/tex/context/base/mkiv/node-tsk.lua b/tex/context/base/mkiv/node-tsk.lua index 56a4b18ef..4dcbb27bd 100644 --- a/tex/context/base/mkiv/node-tsk.lua +++ b/tex/context/base/mkiv/node-tsk.lua @@ -30,6 +30,20 @@ local sequencers = utilities.sequencers local compile = sequencers.compile local nodeprocessor = sequencers.nodeprocessor +local newsequencer = sequencers.new + +local appendgroup = sequencers.appendgroup +----- prependgroup = sequencers.prependgroup +----- replacegroup = sequencers.replacegroup +local enablegroup = sequencers.enablegroup +local disablegroup = sequencers.disablegroup + +local appendaction = sequencers.appendaction +local prependaction = sequencers.prependaction +local replaceaction = sequencers.replaceaction +local enableaction = sequencers.enableaction +local disableaction = sequencers.disableaction + local frozengroups = "no" function tasks.freeze(kind) @@ -41,7 +55,7 @@ function tasks.new(specification) -- was: name,arguments,list local arguments = specification.arguments or 0 local sequence = specification.sequence if name and sequence then - local tasklist = sequencers.new { + local tasklist = newsequencer { -- we can move more to the sequencer now .. todo } tasksdata[name] = { @@ -53,7 +67,7 @@ function tasks.new(specification) -- was: name,arguments,list processor = specification.processor or nodeprocessor } for l=1,#sequence do - sequencers.appendgroup(tasklist,sequence[l]) + appendgroup(tasklist,sequence[l]) end end end @@ -104,7 +118,7 @@ end function tasks.enableaction(name,action) local data = valid(name) if data then - sequencers.enableaction(data.list,action) + enableaction(data.list,action) data.runner = false end end @@ -112,7 +126,7 @@ end function tasks.disableaction(name,action) local data = valid(name) if data then - sequencers.disableaction(data.list,action) + disableaction(data.list,action) data.runner = false end end @@ -120,23 +134,30 @@ end function tasks.replaceaction(name,group,oldaction,newaction) local data = valid(name) if data then - sequencers.replaceaction(data.list,group,oldaction,newaction) + replaceaction(data.list,group,oldaction,newaction) data.runner = false end end -function tasks.setaction(name,action,value) - if value then - tasks.enableaction(name,action) - else - tasks.disableaction(name,action) +do + + local enableaction = tasks.enableaction + local disableaction = tasks.disableaction + + function tasks.setaction(name,action,value) + if value then + enableaction(name,action) + else + disableaction(name,action) + end end + end function tasks.enablegroup(name,group) local data = validgroup(name,"enable group") if data then - sequencers.enablegroup(data.list,group) + enablegroup(data.list,group) data.runner = false end end @@ -144,7 +165,7 @@ end function tasks.disablegroup(name,group) local data = validgroup(name,"disable group") if data then - sequencers.disablegroup(data.list,group) + disablegroup(data.list,group) data.runner = false end end @@ -152,7 +173,7 @@ end function tasks.appendaction(name,group,action,where,kind) local data = validgroup(name,"append action") if data then - sequencers.appendaction(data.list,group,action,where,kind) + appendaction(data.list,group,action,where,kind) data.runner = false end end @@ -160,7 +181,7 @@ end function tasks.prependaction(name,group,action,where,kind) local data = validgroup(name,"prepend action") if data then - sequencers.prependaction(data.list,group,action,where,kind) + prependaction(data.list,group,action,where,kind) data.runner = false end end @@ -168,7 +189,7 @@ end function tasks.removeaction(name,group,action) local data = validgroup(name,"remove action") if data then - sequencers.removeaction(data.list,group,action) + removeaction(data.list,group,action) data.runner = false end end @@ -366,6 +387,7 @@ tasks.new { tasks.new { name = "shipouts", arguments = 0, + -- nostate = true, -- maybe but only for main ones so little gain processor = nodeprocessor, sequence = { "before", -- for users @@ -418,3 +440,15 @@ tasks.new { -- "after", -- for users -- } -- } + +tasks.new { + name = "contributers", + arguments = 1, + processor = nodeprocessor, + sequence = { + "before", -- for users + "normalizers", + "after", -- for users + } +} + diff --git a/tex/context/base/mkiv/node-tst.lua b/tex/context/base/mkiv/node-tst.lua index 4832c048c..1109f28a3 100644 --- a/tex/context/base/mkiv/node-tst.lua +++ b/tex/context/base/mkiv/node-tst.lua @@ -32,6 +32,9 @@ local getprev = nuts.getprev local getid = nuts.getid local getchar = nuts.getchar local getsubtype = nuts.getsubtype +local getkern = nuts.getkern +local getpenalty = nuts.getpenalty +local getwidth = nuts.getwidth local find_node_tail = nuts.tail @@ -39,11 +42,11 @@ function nuts.leftmarginwidth(n) -- todo: three values while n do local id = getid(n) if id == glue_code then - return getsubtype(n) == leftskip_code and getfield(n,"width") or 0 + return getsubtype(n) == leftskip_code and getwidth(n) or 0 elseif id == whatsit_code then n = getnext(n) elseif id == hlist_code then - return getfield(n,"width") + return getwidth(n) else break end @@ -57,7 +60,7 @@ function nuts.rightmarginwidth(n) while n do local id = getid(n) if id == glue_code then - return getsubtype(n) == rightskip_code and getfield(n,"width") or 0 + return getsubtype(n) == rightskip_code and getwidth(n) or 0 elseif id == whatsit_code then n = getprev(n) else @@ -72,10 +75,9 @@ function nuts.somespace(n,all) if n then local id = getid(n) if id == glue_code then - return (all or ((getfield(n,"width") or 0) ~= 0)) and glue_code -- temp: or 0 - -- return (all or (getfield(n,"width") ~= 0)) and glue_code + return (all or (getwidth(n) ~= 0)) and glue_code -- temp: or 0 elseif id == kern_code then - return (all or (getfield(n,"kern") ~= 0)) and kern + return (all or (getkern(n) ~= 0)) and kern elseif id == glyph_code then local category = chardata[getchar(n)].category -- maybe more category checks are needed @@ -90,7 +92,7 @@ function nuts.somepenalty(n,value) local id = getid(n) if id == penalty_code then if value then - return getfield(n,"penalty") == value + return getpenalty(n) == value else return true end diff --git a/tex/context/base/mkiv/node-typ.lua b/tex/context/base/mkiv/node-typ.lua index efabe657b..06d0f13c2 100644 --- a/tex/context/base/mkiv/node-typ.lua +++ b/tex/context/base/mkiv/node-typ.lua @@ -18,6 +18,7 @@ local tonut = nuts.tonut local setfield = nuts.setfield local setlink = nuts.setlink local setchar = nuts.setchar +----- setattrlist = nuts.setattrlist local getfield = nuts.getfield local getfont = nuts.getfont @@ -42,7 +43,7 @@ local function tonodes(str,fontid,spacing,templateglyph) -- quick and dirty if not fontid then if templateglyph then fontid = getfont(templateglyph) - -- attrid = getfield(templateglyph,"attr") + -- attrid = setattrlist(templateglyph) else fontid = currentfont() -- attrid = current_attr() @@ -74,10 +75,10 @@ local function tonodes(str,fontid,spacing,templateglyph) -- quick and dirty if not next then -- nothing elseif not head then --- setfield(next,"attr",attrid) + -- setattrlist(next,attrid) head = next else --- setfield(next,"attr",attrid) + -- setattrlist(next,attrid) setlink(prev,next) end prev = next diff --git a/tex/context/base/mkiv/pack-rul.lua b/tex/context/base/mkiv/pack-rul.lua index 3279dca51..30eda7dd2 100644 --- a/tex/context/base/mkiv/pack-rul.lua +++ b/tex/context/base/mkiv/pack-rul.lua @@ -11,8 +11,6 @@ if not modules then modules = { } end modules ['pack-rul'] = { --ldx]]-- -- we need to be careful with display math as it uses shifts --- challenge: adapt glue_set --- setfield(h,"glue_set", getfield(h,"glue_set") * getfield(h,"width")/maxwidth -- interesting ... doesn't matter much -- \framed[align={lohi,middle}]{$x$} -- \framed[align={lohi,middle}]{$ $} @@ -45,6 +43,10 @@ local getwhd = nuts.getwhd local getid = nuts.getid local getsubtype = nuts.getsubtype local getbox = nuts.getbox +local getdir = nuts.getdir +local setshift = nuts.setshift +local setwidth = nuts.setwidth +local getwidth = nuts.getwidth local hpack = nuts.hpack local traverse_id = nuts.traverse_id @@ -68,7 +70,7 @@ local function doreshapeframedbox(n) local maxwidth = 0 local totalwidth = 0 local averagewidth = 0 - local boxwidth = getfield(box,"width") + local boxwidth = getwidth(box) if boxwidth ~= 0 then -- and h.subtype == vlist_code local list = getlist(box) if list then @@ -84,7 +86,7 @@ local function doreshapeframedbox(n) if repack then local subtype = getsubtype(n) if subtype == box_code or subtype == line_code then - lastlinelength = list_dimensions(l,getfield(n,"dir")) + lastlinelength = list_dimensions(l,getdir(n)) else lastlinelength = width end @@ -122,7 +124,7 @@ local function doreshapeframedbox(n) if l then local subtype = getsubtype(h) if subtype == box_code or subtype == line_code then - local p = hpack(l,maxwidth,'exactly',getfield(h,"dir")) -- multiple return value + local p = hpack(l,maxwidth,'exactly',getdir(h)) -- multiple return value setfield(h,"glue_set",getfield(p,"glue_set")) setfield(h,"glue_order",getfield(p,"glue_order")) setfield(h,"glue_sign",getfield(p,"glue_sign")) @@ -131,25 +133,25 @@ local function doreshapeframedbox(n) elseif checkformath and subtype == equation_code then -- display formulas use a shift if nofnonzero == 1 then - setfield(h,"shift",0) + setshift(h,0) end end - setfield(h,"width",maxwidth) + setwidth(h,maxwidth) end end end -- if vdone then -- for v in traverse_id(vlist_code,list) do - -- local width = getfield(n,"width") + -- local width = getwidth(n) -- if width > maxwidth then - -- setfield(v,"width",maxwidth) + -- setwidth(v,maxwidth) -- end -- end -- end - setfield(box,"width",maxwidth) + setwidth(box,maxwidth) averagewidth = noflines > 0 and totalwidth/noflines or 0 else -- e.g. empty math {$ $} or \hbox{} or ... - setfield(box,"width",0) + setwidth(box,0) end end end @@ -166,7 +168,7 @@ local function doanalyzeframedbox(n) local noflines = 0 local firstheight = nil local lastdepth = nil - if getfield(box,"width") ~= 0 then + if getwidth(box) ~= 0 then local list = getlist(box) if list then local function check(n) @@ -194,7 +196,7 @@ implement { name = "doreshapeframedbox", actions = doreshapeframedbox, arguments implement { name = "doanalyzeframedbox", actions = doanalyzeframedbox, arguments = "integer" } local function maxboxwidth(box) - local boxwidth = getfield(box,"width") + local boxwidth = getwidth(box) if boxwidth == 0 then return 0 end @@ -213,12 +215,12 @@ local function maxboxwidth(box) if repack then local subtype = getsubtype(n) if subtype == box_code or subtype == line_code then - lastlinelength = list_dimensions(l,getfield(n,"dir")) + lastlinelength = list_dimensions(l,getdir(n)) else - lastlinelength = getfield(n,"width") + lastlinelength = getwidth(n) end else - lastlinelength = getfield(n,"width") + lastlinelength = getwidth(n) end if lastlinelength > maxwidth then maxwidth = lastlinelength @@ -238,6 +240,6 @@ nodes.maxboxwidth = maxboxwidth implement { name = "themaxboxwidth", - actions = function(n) context("%isp",maxboxwidth(getbox(n))) end, + actions = function(n) context("%rsp",maxboxwidth(getbox(n))) end, -- r = rounded arguments = "integer" } diff --git a/tex/context/base/mkiv/page-cst.lua b/tex/context/base/mkiv/page-cst.lua index cd3b63c5d..03707a312 100644 --- a/tex/context/base/mkiv/page-cst.lua +++ b/tex/context/base/mkiv/page-cst.lua @@ -52,6 +52,10 @@ local setsubtype = nuts.setsubtype local setbox = nuts.setbox local getwhd = nuts.getwhd local setwhd = nuts.setwhd +local getkern = nuts.getkern +local getpenalty = nuts.getpenalty +local getwidth = nuts.getwidth +local getheight = nuts.getheight local getnext = nuts.getnext local getprev = nuts.getprev @@ -337,11 +341,7 @@ function columnsets.prepareflush(name) for r=1,nofrows-1 do setlink(column[r],column[r+1]) end - local v = new_vlist(column[1]) - setfield(v,"height",height) - -- setfield(v,"depth",linedepth) - setfield(v,"width",widths[c]) - columns[c] = v + columns[c] = new_vlist(column[1],widths[c],height,0) -- linedepth end -- texsetcount("c_page_grid_first_column",firstcolumn) @@ -774,9 +774,9 @@ end -- if line then -- break -- end --- used = used + getfield(head,"width") +-- used = used + getwidth(head) -- elseif id == kern_code then --- used = used + getfield(head,"kern") +-- used = used + getkern(head) -- elseif id == penalty_code then -- end -- if used > available then @@ -813,18 +813,18 @@ local function checkroom(head,available,row) if line then break end - used = used + getfield(head,"width") + used = used + getwidth(head) if used > available then break end elseif id == kern_code then - used = used + getfield(head,"kern") + used = used + getkern(head) if used > available then break end elseif id == penalty_code then -- not good enough ... we need to look bakck too - if getfield(head,"penalty") >= 10000 then + if getpenalty(head) >= 10000 then line = false else break @@ -862,9 +862,9 @@ end -- if id == hlist_code or id == vlist_code or id == rule_code then -- <= rule_code -- hd = getfield(head,"height") + getfield(head,"depth") -- elseif id == glue_code then --- hd = getfield(head,"width") +-- hd = getwidth(head) -- elseif id == kern_code then --- hd = getfield(head,"kern") +-- hd = getkern(head) -- elseif id == penalty_code then -- end -- if used + hd > available then @@ -919,7 +919,7 @@ local function findslice(dataset,head,available,column,row) attempts = attempts + 1 texsetbox("scratchbox",tonode(new_vlist(copy))) local done = splitbox("scratchbox",usedsize,"additional") - local used = getfield(done,"height") + local used = getheight(done) local rest = takebox("scratchbox") if used > (usedsize+slack) then if trace_detail then @@ -943,7 +943,7 @@ local function findslice(dataset,head,available,column,row) texsetbox("scratchbox",tonode(new_vlist(head))) done = splitbox("scratchbox",usedsize,"additional") rest = takebox("scratchbox") - used = getfield(done,"height") + used = getheight(done) if attempts > 1 then used = available end @@ -1237,9 +1237,7 @@ function columnsets.setarea(t) local column = t.c local row = t.r if column and row then - setfield(box,"height",dataset.lineheight) - setfield(box,"depth",dataset.linedepth) - setfield(box,"width",dataset.widths[column]) + setwhd(box,dataset.widths[column],dataset.lineheight,dataset.linedepth) cells[column][row] = box end end diff --git a/tex/context/base/mkiv/page-ins.mkiv b/tex/context/base/mkiv/page-ins.mkiv index c91073a14..51f2a3c1c 100644 --- a/tex/context/base/mkiv/page-ins.mkiv +++ b/tex/context/base/mkiv/page-ins.mkiv @@ -55,7 +55,7 @@ \unexpanded\def\page_inserts_synchronize_registers {\currentinsertionnumber\csname\??insertionnumber\currentinsertion\endcsname} -% for practical reasone we still set these elsewhere but that might chaneg in the future +% for practical reasons we still set these elsewhere but that might change in the future % % \global\count\currentinsertionnumber\numexpr\insertionparameter\c!factor/\insertionparameter\c!n\relax % \global\skip \currentinsertionnumber\insertionparameter\c!distance \relax @@ -65,7 +65,7 @@ \page_inserts_synchronize_registers \to \everysetupinsertion -\unexpanded\def\page_inserts_process#1% beware, this addapts currentinsertion ! +\unexpanded\def\page_inserts_process#1% beware, this adapts currentinsertion ! {\edef\currentinsertion{#1}% \currentinsertionnumber\csname\??insertionnumber\currentinsertion\endcsname \doprocessinsert\currentinsertionnumber} % old method diff --git a/tex/context/base/mkiv/page-lin.lua b/tex/context/base/mkiv/page-lin.lua index 011418063..8ec4ba5df 100644 --- a/tex/context/base/mkiv/page-lin.lua +++ b/tex/context/base/mkiv/page-lin.lua @@ -56,7 +56,7 @@ local line_code = listcodes.line local a_displaymath = attributes.private('displaymath') local a_linenumber = attributes.private('linenumber') local a_linereference = attributes.private('linereference') -local a_verbatimline = attributes.private('verbatimline') +----- a_verbatimline = attributes.private('verbatimline') local current_list = { } local cross_references = { } @@ -72,6 +72,10 @@ local setattr = nuts.setattr local getlist = nuts.getlist local getbox = nuts.getbox local getfield = nuts.getfield +----- getdir = nuts.getdir +----- getwidth = nuts.getwidth +local getheight = nuts.getheight +local getdepth = nuts.getdepth local setprop = nuts.setprop local getprop = nuts.getprop @@ -386,7 +390,7 @@ function boxed.stage_one(n,nested) local subtype = getsubtype(n) if subtype ~= line_code then -- go on - elseif getfield(n,"height") == 0 and getfield(n,"depth") == 0 then + elseif getheight(n) == 0 and getdepth(n) == 0 then -- skip funny hlists -- todo: check line subtype else local a = lineisnumbered(n) @@ -410,14 +414,14 @@ function boxed.stage_one(n,nested) check_number(n,a,skip) end else --- -- we now prevent nesting anyway .. maybe later we need to check again --- local v = getattr(list,a_verbatimline) --- if not v or v ~= last_v then --- last_v = v + -- -- we now prevent nesting anyway .. maybe later we need to check again + -- local v = getattr(list,a_verbatimline) + -- if not v or v ~= last_v then + -- last_v = v check_number(n,a,skip) --- else --- check_number(n,a,skip,true) --- end + -- else + -- check_number(n,a,skip,true) + -- end end skip = false end @@ -480,10 +484,10 @@ function boxed.stage_two(n,m) local li = current_list[i] local n, m, ti = li[1], li[2], t[i] if ti then - -- local d = getfield(n,"dir") + -- local d = getdir(n) -- local l = getlist(n) -- if d == "TRT" then - -- local w = getfield(n,"width") + -- local w = getwidth(n) -- ti = hpack_nodes(linked_nodes(new_kern(-w),ti,new_kern(w))) -- end -- setnext(ti,l) diff --git a/tex/context/base/mkiv/page-mix.lua b/tex/context/base/mkiv/page-mix.lua index 6bbc434dd..524181c8e 100644 --- a/tex/context/base/mkiv/page-mix.lua +++ b/tex/context/base/mkiv/page-mix.lua @@ -47,14 +47,17 @@ local flushnode = nuts.flush local concatnodes = nuts.concat local slidenodes = nuts.slide -- ok here as we mess with prev links intermediately -local getfield = nuts.getfield local setfield = nuts.setfield local setlink = nuts.setlink local setlist = nuts.setlist local setnext = nuts.setnext local setprev = nuts.setprev local setbox = nuts.setbox +local setwhd = nuts.setwhd +local setheight = nuts.setheight +local setdepth = nuts.setdepth +local getfield = nuts.getfield local getnext = nuts.getnext local getprev = nuts.getprev local getid = nuts.getid @@ -63,10 +66,11 @@ local getsubtype = nuts.getsubtype local getbox = nuts.getbox local getattribute = nuts.getattribute local getwhd = nuts.getwhd -local setwhd = nuts.setwhd - -local texgetcount = tex.getcount -local texgetglue = tex.getglue +local getkern = nuts.getkern +local getpenalty = nuts.getpenalty +local getwidth = nuts.getwidth +local getheight = nuts.getheight +local getdepth = nuts.getdepth local theprop = nuts.theprop @@ -119,7 +123,7 @@ local function collectinserts(result,nxt,nxtid) if nxtid == insert_code then i = i + 1 result.i = i - inserttotal = inserttotal + getfield(nxt,"height") -- height includes depth + inserttotal = inserttotal + getheight(nxt) -- height includes depth local s = getsubtype(nxt) local c = inserts[s] if trace_detail then @@ -172,15 +176,15 @@ local function discardtopglue(current,discarded) while current do local id = getid(current) if id == glue_code then - size = size + getfield(current,"width") + size = size + getwidth(current) discarded[#discarded+1] = current current = getnext(current) elseif id == penalty_code then - if getfield(current,"penalty") == forcedbreak then + if getpenalty(current) == forcedbreak then discarded[#discarded+1] = current current = getnext(current) while current and getid(current) == glue_code do - size = size + getfield(current,"width") + size = size + getwidth(current) discarded[#discarded+1] = current current = getnext(current) end @@ -210,7 +214,7 @@ local function stripbottomglue(results,discarded) end local id = getid(t) if id == penalty_code then - if getfield(t,"penalty") == forcedbreak then + if getpenalty(t) == forcedbreak then break else discarded[#discarded+1] = t @@ -219,7 +223,7 @@ local function stripbottomglue(results,discarded) end elseif id == glue_code then discarded[#discarded+1] = t - local width = getfield(t,"width") + local width = getwidth(t) if trace_state then report_state("columns %s, discarded bottom glue %p",i,width) end @@ -256,8 +260,8 @@ local function preparesplit(specification) -- a rather large function slidenodes(head) -- we can have set prev's to nil to prevent backtracking local discarded = { } local originalhead = head - local originalwidth = specification.originalwidth or getfield(list,"width") - local originalheight = specification.originalheight or getfield(list,"height") + local originalwidth = specification.originalwidth or getwidth(list) + local originalheight = specification.originalheight or getheight(list) local current = head local skipped = 0 local height = 0 @@ -480,7 +484,7 @@ local function preparesplit(specification) -- a rather large function head = current local function process_skip(current,nxt) - local advance = getfield(current,"width") + local advance = getwidth(current) if advance ~= 0 then local state, skipped = checked(advance,"glue") if trace_state then @@ -515,7 +519,7 @@ local function preparesplit(specification) -- a rather large function end local function process_kern(current,nxt) - local advance = getfield(current,"kern") + local advance = getkern(current) if advance ~= 0 then local state, skipped = checked(advance,"kern") if trace_state then @@ -538,7 +542,7 @@ local function preparesplit(specification) -- a rather large function local function process_rule(current,nxt) -- simple variant of h|vlist - local advance = getfield(current,"height") -- + getfield(current,"depth") + local advance = getheight(current) -- + getdepth(current) if advance ~= 0 then local state, skipped = checked(advance,"rule") if trace_state then @@ -556,7 +560,7 @@ local function preparesplit(specification) -- a rather large function -- else -- height = height + currentskips -- end - depth = getfield(current,"depth") + depth = getdepth(current) skip = 0 end lastcontent = current @@ -569,7 +573,7 @@ local function preparesplit(specification) -- a rather large function -- [chapter] [penalty] [section] [penalty] [first line] local function process_penalty(current,nxt) - local penalty = getfield(current,"penalty") + local penalty = getpenalty(current) if penalty == 0 then unlock(penalty) elseif penalty == forcedbreak then @@ -783,11 +787,11 @@ local function finalize(result) local l = list[i] local h = new_hlist() t[i] = h - setlist(h,getfield(l,"head")) + setlist(h,getlist(l)) local wd, ht, dp = getwhd(l) -- here ht is still ht + dp ! - setwhd(h,getfield(h,"width"),ht,dp) - setfield(l,"head",nil) + setwhd(h,getwidth(h),ht,dp) + setlist(l) end setprev(t[1]) -- needs checking setnext(t[#t]) -- needs checking @@ -946,9 +950,7 @@ local function getsplit(result,n) dp = result.depth end - setfield(v,"width",wd) - setfield(v,"height",ht) - setfield(v,"depth",dp) + setwhd(v,wd,ht,dp) if trace_state then local id = getid(h) @@ -962,9 +964,9 @@ local function getsplit(result,n) for c, list in next, r.inserts do local l = concatnodes(list) -for i=1,#list-1 do - setfield(list[i],"depth",0) -end + for i=1,#list-1 do + setdepth(list[i],0) + end local b = vpack(l) -- multiple arguments, todo: fastvpack -- setbox("global",c,b) diff --git a/tex/context/base/mkiv/page-str.lua b/tex/context/base/mkiv/page-str.lua index a254e9d7d..4aeffffd8 100644 --- a/tex/context/base/mkiv/page-str.lua +++ b/tex/context/base/mkiv/page-str.lua @@ -28,6 +28,8 @@ local vpack_node_list = nodes.vpack local settings_to_array = utilities.parsers.settings_to_array +local enableaction = nodes.tasks.enableaction + local texgetdimen = tex.getdimen local texgetbox = tex.getbox @@ -233,7 +235,7 @@ tasks.appendaction("mvlbuilders", "normalizers", "streams.collect") tasks.disableaction("mvlbuilders", "streams.collect") function streams.initialize() - tasks.enableaction ("mvlbuilders", "streams.collect") + enableaction("mvlbuilders","streams.collect") function streams.initialize() end end @@ -241,8 +243,8 @@ end -- todo: better names, enable etc implement { - name = "initializestream", - actions = streams.initialize, + name = "initializestream", + actions = streams.initialize, onlyonce = true, } diff --git a/tex/context/base/mkiv/publ-sor.lua b/tex/context/base/mkiv/publ-sor.lua index 218d11093..30a0d9bdd 100644 --- a/tex/context/base/mkiv/publ-sor.lua +++ b/tex/context/base/mkiv/publ-sor.lua @@ -217,6 +217,7 @@ local function sortsequence(dataset,list,sorttype) if type(action) == "function" then local valid = action(dataset,list,method) if valid and #valid > 0 then +-- sorters.setlanguage(options.language,options.method) sorters.sort(valid,compare) return valid else diff --git a/tex/context/base/mkiv/scrn-fld.mkvi b/tex/context/base/mkiv/scrn-fld.mkvi index a92abebc5..d69e7beb9 100644 --- a/tex/context/base/mkiv/scrn-fld.mkvi +++ b/tex/context/base/mkiv/scrn-fld.mkvi @@ -246,7 +246,6 @@ \fi layer {\fieldbodyparameter\c!fieldlayer}% option {\fieldbodyparameter\c!option}% - align {\fieldbodyparameter\c!align}% clickin {\fieldbodyparameter\c!clickin}% clickout {\fieldbodyparameter\c!clickout}% regionin {\fieldbodyparameter\c!regionin}% diff --git a/tex/context/base/mkiv/scrp-cjk.lua b/tex/context/base/mkiv/scrp-cjk.lua index b919098f1..d2ec201ca 100644 --- a/tex/context/base/mkiv/scrp-cjk.lua +++ b/tex/context/base/mkiv/scrp-cjk.lua @@ -31,6 +31,7 @@ local getchar = nuts.getchar local getid = nuts.getid local getattr = nuts.getattr local getsubtype = nuts.getsubtype +local getwidth = nuts.getwidth local getfield = nuts.getfield local setchar = nuts.setchar @@ -958,7 +959,7 @@ local function process(head,first,last) local subtype = getsubtype(first) if subtype == userskip_code or subtype == spaceskip_code or subtype == xspaceskip_code then -- for the moment no distinction possible between space and userskip - local w = getfield(first,"width") + local w = getwidth(first) local s = spacedata[getfont(p)] if w == s then -- could be option if trace_details then diff --git a/tex/context/base/mkiv/spac-adj.lua b/tex/context/base/mkiv/spac-adj.lua index bebc15b88..3db59881b 100644 --- a/tex/context/base/mkiv/spac-adj.lua +++ b/tex/context/base/mkiv/spac-adj.lua @@ -8,15 +8,17 @@ if not modules then modules = { } end modules ['spac-adj'] = { -- sort of obsolete code -local a_vadjust = attributes.private('graphicvadjust') +local a_vadjust = attributes.private('graphicvadjust') -local nodecodes = nodes.nodecodes +local nodecodes = nodes.nodecodes -local hlist_code = nodecodes.hlist -local vlist_code = nodecodes.vlist +local hlist_code = nodecodes.hlist +local vlist_code = nodecodes.vlist -local remove_node = nodes.remove -local hpack_node = node.hpack +local remove_node = nodes.remove +local hpack_node = node.hpack + +local enableaction = nodes.tasks.enableaction function nodes.handlers.graphicvadjust(head,groupcode) -- we can make an actionchain for mvl only if groupcode == "" then -- mvl only @@ -60,6 +62,6 @@ interfaces.implement { name = "enablegraphicvadjust", onlyonce = true, actions = function() - nodes.tasks.enableaction("finalizers","nodes.handlers.graphicvadjust") + enableaction("finalizers","nodes.handlers.graphicvadjust") end } diff --git a/tex/context/base/mkiv/spac-ali.lua b/tex/context/base/mkiv/spac-ali.lua index dc206a2a2..bc77090cf 100644 --- a/tex/context/base/mkiv/spac-ali.lua +++ b/tex/context/base/mkiv/spac-ali.lua @@ -19,18 +19,18 @@ local tonode = nuts.tonode local tonut = nuts.tonut local getfield = nuts.getfield -local setfield = nuts.setfield local getnext = nuts.getnext local getprev = nuts.getprev local getid = nuts.getid local getlist = nuts.getlist local setlist = nuts.setlist -local getattr = nuts.getattr -local setattr = nuts.setattr +local setlink = nuts.setlink +local takeattr = nuts.takeattr local getsubtype = nuts.getsubtype +local getwidth = nuts.getwidth +local findtail = nuts.tail local hpack_nodes = nuts.hpack -local linked_nodes = nuts.linked local unsetvalue = attributes.unsetvalue @@ -71,7 +71,7 @@ local function handler(head,leftpage,realpageno) local id = getid(current) if id == hlist_code then if getsubtype(current) == line_code then - local a = getattr(current,a_realign) + local a = takeattr(current,a_realign) if not a or a == 0 then -- skip else @@ -87,12 +87,16 @@ local function handler(head,leftpage,realpageno) action = leftpage and 2 or 1 end if action == 1 then - setlist(current,hpack_nodes(linked_nodes(getlist(current),new_stretch(3)),getfield(current,"width"),"exactly")) + local head = getlist(current) + setlink(findtail(head),new_stretch(3)) -- append + setlist(current,hpack_nodes(head,getwidth(current),"exactly")) if trace_realign then report_realign("flushing left, align %a, page %a, realpage %a",align,pageno,realpageno) end elseif action == 2 then - setlist(current,hpack_nodes(linked_nodes(new_stretch(3),getlist(current)),getfield(current,"width"),"exactly")) + local list = getlist(current) + local head = setlink(new_stretch(3),list) -- prepend + setlist(current,hpack_nodes(head,getwidth(current),"exactly")) if trace_realign then report_realign("flushing right. align %a, page %a, realpage %a",align,pageno,realpageno) end @@ -102,7 +106,6 @@ local function handler(head,leftpage,realpageno) done = true nofrealigned = nofrealigned + 1 end - setattr(current,a_realign,unsetvalue) end end handler(getlist(current),leftpage,realpageno) diff --git a/tex/context/base/mkiv/spac-chr.lua b/tex/context/base/mkiv/spac-chr.lua index 2ea53b89e..fe402ed87 100644 --- a/tex/context/base/mkiv/spac-chr.lua +++ b/tex/context/base/mkiv/spac-chr.lua @@ -36,6 +36,7 @@ local getnext = nuts.getnext local getprev = nuts.getprev local getattr = nuts.getattr local setattr = nuts.setattr +local setattrlist = nuts.setattrlist local getfont = nuts.getfont local getchar = nuts.getchar local setsubtype = nuts.setsubtype @@ -86,36 +87,33 @@ local c_zero = byte('0') local c_period = byte('.') local function inject_quad_space(unicode,head,current,fraction) - local attr = getfield(current,"attr") if fraction ~= 0 then fraction = fraction * fontquads[getfont(current)] end local glue = new_glue(fraction) - setfield(glue,"attr",attr) - setfield(current,"attr",nil) + setattrlist(glue,current) + setattrlist(current) -- why reset all setattr(glue,a_character,unicode) head, current = insert_node_after(head,current,glue) return head, current end local function inject_char_space(unicode,head,current,parent) - local attr = getfield(current,"attr") local font = getfont(current) local char = fontcharacters[font][parent] local glue = new_glue(char and char.width or fontparameters[font].space) - setfield(glue,"attr",attr) - setfield(current,"attr",nil) + setattrlist(glue,current) + setattrlist(current) -- why reset all setattr(glue,a_character,unicode) head, current = insert_node_after(head,current,glue) return head, current end local function inject_nobreak_space(unicode,head,current,space,spacestretch,spaceshrink) - local attr = getfield(current,"attr") local glue = new_glue(space,spacestretch,spaceshrink) local penalty = new_penalty(10000) - setfield(glue,"attr",attr) - setfield(current,"attr",nil) + setattrlist(glue,current) + setattrlist(current) -- why reset all setattr(glue,a_character,unicode) -- bombs head, current = insert_node_after(head,current,penalty) if trace_nbsp then diff --git a/tex/context/base/mkiv/spac-prf.lua b/tex/context/base/mkiv/spac-prf.lua index f89d836d8..841e5d271 100644 --- a/tex/context/base/mkiv/spac-prf.lua +++ b/tex/context/base/mkiv/spac-prf.lua @@ -51,12 +51,22 @@ local getsubtype = nuts.getsubtype local getlist = nuts.getlist local gettexbox = nuts.getbox local getwhd = nuts.getwhd +local getglue = nuts.getglue +local getkern = nuts.getkern +local getshift = nuts.getshift +local getwidth = nuts.getwidth +local getheight = nuts.getheight +local getdepth = nuts.getdepth local setfield = nuts.setfield local setlink = nuts.setlink local setlist = nuts.setlist local setattr = nuts.setattr local setwhd = nuts.setwhd +local setshift = nuts.setshift +local setwidth = nuts.setwidth +local setheight = nuts.setheight +local setdepth = nuts.setdepth local properties = nodes.properties.data local setprop = nuts.setprop @@ -86,6 +96,8 @@ local v_strict = variables.strict local setcolor = nodes.tracers.colors.set local settransparency = nodes.tracers.transparencies.set +local enableaction = nodes.tasks.enableaction + local profiling = { } builders.profiling = profiling @@ -117,7 +129,7 @@ local function getprofile(line,step) local step = step or 65536 -- * 2 -- 2pt local margin = step / 4 local min = 0 - local max = ceiling(getfield(line,"width")/step) + 1 + local max = ceiling(getwidth(line)/step) + 1 for i=min,max do heights[i] = 0 @@ -166,7 +178,7 @@ local function getprofile(line,step) wd, ht, dp = getwhd(current) progress() elseif id == kern_code then - wd = getfield(current,"kern") + wd = getkern(current) ht = 0 dp = 0 progress() @@ -176,20 +188,26 @@ local function getprofile(line,step) process(replace) end elseif id == glue_code then - wd = getfield(current,"width") + local width, stretch, shrink, stretch_order, shrink_order = getglue(current) if glue_sign == 1 then - if getfield(current,"stretch_order") == glue_order then - wd = wd + getfield(current,"stretch") * glue_set + if stretch_order == glue_order then + wd = width + stretch * glue_set + else + wd = width end elseif glue_sign == 2 then - if getfield(current,"shrink_order") == glue_order then - wd = wd - getfield(current,"shrink") * glue_set + if shrink_order == glue_order then + wd = width - shrink * glue_set + else + wd = width end + else + wd = width end if getsubtype(current) >= leaders_code then local leader = getleader(current) - ht = getfield(leader,"height") - dp = getfield(leader,"depth") + local w + w, ht, dp = getwhd(leader) -- can become getwhd(current) after 1.003 else ht = 0 dp = 0 @@ -197,7 +215,7 @@ local function getprofile(line,step) progress() elseif id == hlist_code then -- we could do a nested check .. but then we need to push / pop glue - local shift = getfield(current,"shift") + local shift = getshift(current) local w, h, d = getwhd(current) -- if getattr(current,a_specialcontent) then if getprop(current,"specialcontent") then @@ -212,19 +230,19 @@ local function getprofile(line,step) end progress() elseif id == vlist_code or id == unset_code then - local shift = getfield(current,"shift") -- todo + local shift = getshift(current) -- todo wd, ht, dp = getwhd(current) progress() elseif id == rule_code then wd, ht, dp = getwhd(current) progress() elseif id == math_code then - wd = getfield(current,"surround") + getfield(current,"width") + wd = getkern(current) + getwidth(current) -- surround ht = 0 dp = 0 progress() elseif id == marginkern_code then - wd = getfield(current,"width") + wd = getwidth(current) ht = 0 dp = 0 progress() @@ -293,16 +311,14 @@ local function addstring(height,depth) local dptext = depth local httext = typesetters.tohpack(height,infofont) local dptext = typesetters.tohpack(depth,infofont) - setfield(httext,"shift",- 1.2 * exheight) - setfield(dptext,"shift", 0.6 * exheight) - local text = nuts.hpack( - nuts.linked( - new_kern(-getfield(httext,"width")-emwidth), - httext, - new_kern(-getfield(dptext,"width")), - dptext - ) - ) + setshift(httext,- 1.2 * exheight) + setshift(dptext, 0.6 * exheight) + local text = hpack_nodes(setlink( + new_kern(-getwidth(httext)-emwidth), + httext, + new_kern(-getwidth(dptext)), + dptext + )) setwhd(text,0,0,0) return text end @@ -385,8 +401,8 @@ local function addprofile(node,profile,step) -- if texttoo then -- -- local text = addstring( - -- formatters["%0.4f"](getfield(rule,"height")/65536), - -- formatters["%0.4f"](getfield(rule,"depth") /65536) + -- formatters["%0.4f"](getheight(rule)/65536), + -- formatters["%0.4f"](getdepth(rule) /65536) -- ) -- -- setlink(text,rule) @@ -475,8 +491,8 @@ methods[v_strict] = function(top,bot,t_profile,b_profile,specification) local strutdp = specification.depth or texdimen.strutdp local lineheight = strutht + strutdp - local depth = getfield(top,"depth") - local height = getfield(bot,"height") + local depth = getdepth(top) + local height = getheight(bot) local total = depth + height local distance = specification.distance or 0 local delta = lineheight - total @@ -511,8 +527,8 @@ methods[v_fixed] = function(top,bot,t_profile,b_profile,specification) local strutdp = specification.depth or texdimen.strutdp local lineheight = strutht + strutdp - local depth = getfield(top,"depth") - local height = getfield(bot,"height") + local depth = getdepth(top) + local height = getheight(bot) local total = depth + height local distance = specification.distance or 0 local delta = lineheight - total @@ -524,8 +540,8 @@ methods[v_fixed] = function(top,bot,t_profile,b_profile,specification) -- no distance (yet) if delta < lineheight then - setfield(top,"depth",strutdp) - setfield(bot,"height",strutht) + setdepth(top,strutdp) + setheight(bot,strutht) return true end @@ -536,13 +552,13 @@ methods[v_fixed] = function(top,bot,t_profile,b_profile,specification) depth = depth - lineheight dp = dp + lineheight end - setfield(top,"depth",dp) + setdepth(top,dp) local ht = strutht while height > lineheight - strutht do height = height - lineheight ht = ht + lineheight end - setfield(bot,"height",ht) + setheight(bot,ht) local lines = floor(delta/lineheight) if lines > 0 then inject(top,bot,-lines * lineheight) @@ -553,17 +569,17 @@ methods[v_fixed] = function(top,bot,t_profile,b_profile,specification) end if total < lineheight then - setfield(top,"depth",strutdp) - setfield(bot,"height",strutht) + setdepth(top,strutdp) + setheight(bot,strutht) return true end if depth < strutdp then - setfield(top,"depth",strutdp) + setdepth(top,strutdp) total = total - depth + strutdp end if height < strutht then - setfield(bot,"height",strutht) + setheight(bot,strutht) total = total - height + strutht end @@ -663,7 +679,7 @@ local function profilelist(line,mvl) end break elseif id == glue_code then - local wd = getfield(current,"width") + local wd = getwidth(current) if not wd or wd == 0 then -- go on else @@ -737,7 +753,7 @@ local function profilelist(line,mvl) if top then local subtype = getsubtype(current) -- if subtype == lineskip_code or subtype == baselineskip_code then - local wd = getfield(current,"width") + local wd = getwidth(current) if wd > 0 then distance = wd lastglue = current @@ -781,9 +797,9 @@ local enabled = false function profiling.set(specification) if not enabled then - nodes.tasks.enableaction("mvlbuilders", "builders.profiling.pagehandler") + enableaction("mvlbuilders", "builders.profiling.pagehandler") -- too expensive so we expect that this happens explicitly, we keep for reference: - -- nodes.tasks.enableaction("vboxbuilders","builders.profiling.vboxhandler") + -- enableaction("vboxbuilders","builders.profiling.vboxhandler") enabled = true end local n = #specifications + 1 @@ -842,7 +858,7 @@ function profiling.profilebox(specification) local subtype = getsubtype(current) if subtype == lineskip_code or subtype == baselineskip_code then if top then - local wd = getfield(current,"width") + local wd = getwidth(current) if wd > 0 then distance = wd lastglue = current diff --git a/tex/context/base/mkiv/spac-ver.lua b/tex/context/base/mkiv/spac-ver.lua index 37f99e760..c7eec18ee 100644 --- a/tex/context/base/mkiv/spac-ver.lua +++ b/tex/context/base/mkiv/spac-ver.lua @@ -30,6 +30,8 @@ if not modules then modules = { } end modules ['spac-ver'] = { -- todo: strip baselineskip around display math +-- todo: getglue(n,false) instead of getfield + local next, type, tonumber = next, type, tonumber local gmatch, concat = string.gmatch, table.concat local ceil, floor = math.ceil, math.floor @@ -39,8 +41,6 @@ local allocate = utilities.storage.allocate local todimen = string.todimen local formatters = string.formatters -local P, C, R, S, Cc, Carg = lpeg.P, lpeg.C, lpeg.R, lpeg.S, lpeg.Cc, lpeg.Carg - local nodes = nodes local node = node local trackers = trackers @@ -62,7 +62,7 @@ local implement = interfaces.implement local v_local = variables["local"] local v_global = variables["global"] local v_box = variables.box -local v_page = variables.page -- reserved for future use +----- v_page = variables.page -- reserved for future use local v_split = variables.split local v_min = variables.min local v_max = variables.max @@ -136,15 +136,23 @@ local getprop = nuts.getprop local setprop = nuts.setprop local getglue = nuts.getglue local setglue = nuts.setglue +local getkern = nuts.getkern +local getpenalty = nuts.getpenalty +local setshift = nuts.setshift +local setwidth = nuts.setwidth +local getwidth = nuts.getwidth +local setheight = nuts.setheight +local getheight = nuts.getheight +local setdepth = nuts.setdepth +local getdepth = nuts.getdepth local find_node_tail = nuts.tail local flush_node = nuts.flush_node local traverse_nodes = nuts.traverse local traverse_nodes_id = nuts.traverse_id local insert_node_before = nuts.insert_before -local insert_node_after = nuts.insert_after local remove_node = nuts.remove -local count_nodes = nuts.count +local count_nodes = nuts.countall local hpack_node = nuts.hpack local vpack_node = nuts.vpack ----- writable_spec = nuts.writable_spec @@ -266,17 +274,6 @@ function vspacing.definesnapmethod(name,method) context(n) end --- local rule_id = nodecodes.rule --- local vlist_id = nodecodes.vlist --- function nodes.makevtop(n) --- if getid(n) == vlist_id then --- local list = getlist(n) --- local height = (list and getid(list) <= rule_id and getfield(list,"height")) or 0 --- setfield(n,"depth",getfield(n,"depth") - height + getfield(n,"height") --- setfield(n,"height",height --- end --- end - local function validvbox(parentid,list) if parentid == hlist_code then local id = getid(list) @@ -326,16 +323,16 @@ local function already_done(parentid,list,a_snapmethod) -- todo: done when only for n in traverse_nodes(list) do local id = getid(n) if id == hlist_code or id == vlist_code then --- local a = getattr(n,a_snapmethod) --- if not a then --- -- return true -- not snapped at all --- elseif a == 0 then --- return true -- already snapped --- end -local p = getprop(n,"snapper") -if p then - return p -end + -- local a = getattr(n,a_snapmethod) + -- if not a then + -- -- return true -- not snapped at all + -- elseif a == 0 then + -- return true -- already snapped + -- end + local p = getprop(n,"snapper") + if p then + return p + end elseif id == glue_code or id == penalty_code then -- or id == kern_code then -- go on else @@ -517,7 +514,7 @@ local function snap_hlist(where,current,method,height,depth) -- method[v_strut] ch, cd = lh, delta + d h, d = ch, cd local shifted = hpack_node(getlist(current)) - setfield(shifted,"shift",delta) + setshift(shifted,delta) setlist(current,shifted) done = true if t then @@ -552,7 +549,7 @@ local function snap_hlist(where,current,method,height,depth) -- method[v_strut] cd, ch = ld, delta + h h, d = ch, cd local shifted = hpack_node(getlist(current)) - setfield(shifted,"shift",delta) + setshift(shifted,delta) setlist(current,shifted) done = true if t then @@ -618,7 +615,7 @@ local function snap_hlist(where,current,method,height,depth) -- method[v_strut] t[#t+1] = formatters["before offset: %p (width %p height %p depth %p)"](offset,wd,ht,dp) end local shifted = hpack_node(getlist(current)) - setfield(shifted,"shift",offset) + setshift(shifted,offset) setlist(current,shifted) if t then local wd, ht, dp = getwhd(current) @@ -628,13 +625,13 @@ local function snap_hlist(where,current,method,height,depth) -- method[v_strut] setattr(current,a_snapmethod,0) end if not height then - setfield(current,"height",ch) + setheight(current,ch) if t then t[#t+1] = formatters["forced height: %p"](ch) end end if not depth then - setfield(current,"depth",cd) + setdepth(current,cd) if t then t[#t+1] = formatters["forced depth: %p"](cd) end @@ -664,8 +661,8 @@ local function snap_hlist(where,current,method,height,depth) -- method[v_strut] end local function snap_topskip(current,method) - local w = getfield(current,"width") or 0 - setfield(current,"width",0) + local w = getwidth(current) + setwidth(current,0) return w, 0 end @@ -714,6 +711,8 @@ storage.register("builders/vspacing/data/skip", vspacingdata.skip, "builders.vsp do -- todo: interface.variables and properties + local P, C, R, S, Cc = lpeg.P, lpeg.C, lpeg.R, lpeg.S, lpeg.Cc + vspacing.fixed = false local map = vspacingdata.map @@ -834,11 +833,11 @@ local function nodes_to_string(head) local id = getid(current) local ty = nodecodes[id] if id == penalty_code then - t[#t+1] = formatters["%s:%s"](ty,getfield(current,"penalty")) + t[#t+1] = formatters["%s:%s"](ty,getpenalty(current)) elseif id == glue_code then - t[#t+1] = formatters["%s:%s:%p"](ty,skipcodes[getsubtype(current)],getfield(current,"width")) + t[#t+1] = formatters["%s:%s:%p"](ty,skipcodes[getsubtype(current)],getwidth(current)) elseif id == kern_code then - t[#t+1] = formatters["%s:%p"](ty,getfield(current,"kern")) + t[#t+1] = formatters["%s:%p"](ty,getkern(current)) else t[#t+1] = ty end @@ -852,12 +851,12 @@ local function reset_tracing(head) end local function trace_skip(str,sc,so,sp,data) - trace_list[#trace_list+1] = { "skip", formatters["%s | %p | category %s | order %s | penalty %s"](str, getfield(data,"width"), sc or "-", so or "-", sp or "-") } + trace_list[#trace_list+1] = { "skip", formatters["%s | %p | category %s | order %s | penalty %s"](str, getwidth(data), sc or "-", so or "-", sp or "-") } tracing_info = true end local function trace_natural(str,data) - trace_list[#trace_list+1] = { "skip", formatters["%s | %p"](str, getfield(data,"width")) } + trace_list[#trace_list+1] = { "skip", formatters["%s | %p"](str, getwidth(data)) } tracing_info = true end @@ -877,9 +876,9 @@ end local function trace_done(str,data) if getid(data) == penalty_code then - trace_list[#trace_list+1] = { "penalty", formatters["%s | %s"](str,getfield(data,"penalty")) } + trace_list[#trace_list+1] = { "penalty", formatters["%s | %s"](str,getpenalty(data)) } else - trace_list[#trace_list+1] = { "glue", formatters["%s | %p"](str,getfield(data,"width")) } + trace_list[#trace_list+1] = { "glue", formatters["%s | %p"](str,getwidth(data)) } end tracing_info = true end @@ -958,10 +957,10 @@ end local w, h, d = 0, 0, 0 ----- w, h, d = 100*65536, 65536, 65536 -local function forced_skip(head,current,width,where,trace) +local function forced_skip(head,current,width,where,trace) -- looks old ... we have other tricks now if head == current then if getsubtype(head) == baselineskip_code then - width = width - (getfield(head,"width") or 0) + width = width - getwidth(head) end end if width == 0 then @@ -1057,7 +1056,7 @@ specialmethods[1] = function(pagehead,pagetail,start,penalty) report_specials(" context penalty %a, higher level, continue",p) end else - local p = getfield(current,"penalty") + local p = getpenalty(current) if p < 10000 then -- assume some other mechanism kicks in so we seem to have content if trace_specials then @@ -1101,15 +1100,15 @@ local function check_experimental_overlay(head,current) local skips = 0 -- -- We deal with this at the tex end .. we don't see spacing .. enabling this code - -- is probably harmless btu then we need to test it. + -- is probably harmless but then we need to test it. -- local c = getnext(p) while c and c ~= n do local id = getid(c) if id == glue_code then - skips = skips + (getfield(c,"width") or 0) + skips = skips + getwidth(c) elseif id == kern_code then - skips = skips + getfield(c,"kern") + skips = skips + getkern(c) end c = getnext(c) end @@ -1119,7 +1118,7 @@ local function check_experimental_overlay(head,current) local k = new_kern(-delta) if n_ht > p_ht then -- we should adapt pagetotal ! (need a hook for that) .. now we have the wrong pagebreak - setfield(p,"height",n_ht) + setheight(p,n_ht) end insert_node_before(head,n,k) if p == head then @@ -1230,18 +1229,18 @@ local function collapser(head,where,what,trace,snap,a_snapmethod) -- maybe also local function compensate(n) local g = 0 while n and getid(n) == glue_code do - g = g + getfield(n,"width") + g = g + getwidth(n) n = getnext(n) end if n then local p = getprop(n,"snapper") if p then local extra = p.extra - if extra < 0 then - local h = p.ch -- getfield(n,"height") + if extra and extra < 0 then -- hm, extra can be unset ... needs checking + local h = p.ch -- getheight(n) -- maybe an extra check -- if h - extra < g then - setfield(n,"height",h-2*extra) + setheight(n,h-2*extra) p.extra = 0 if trace_vsnapping then report_snapper("removed extra space at top: %p",extra) @@ -1326,16 +1325,16 @@ local function collapser(head,where,what,trace,snap,a_snapmethod) -- maybe also if trace then trace_done("flushed due to forced " .. why,glue_data) end - head = forced_skip(head,current,getfield(glue_data,"width") or 0,"before",trace) + head = forced_skip(head,current,getwidth(glue_data,width),"before",trace) flush_node(glue_data) else - local w = getfield(glue_data,"width") - if w ~= 0 then + local width, stretch, shrink = getglue(glue_data) + if width ~= 0 then if trace then trace_done("flushed due to non zero " .. why,glue_data) end head = insert_node_before(head,current,glue_data) - elseif getfield(glue_data,"stretch") ~= 0 or getfield(glue_data,"shrink") ~= 0 then + elseif stretch ~= 0 or shrink ~= 0 then if trace then trace_done("flushed due to stretch/shrink in" .. why,glue_data) end @@ -1398,16 +1397,15 @@ local function collapser(head,where,what,trace,snap,a_snapmethod) -- maybe also end else local h, d, ch, cd, lines, extra = snap_hlist("mvl",current,sv,false,false) -lastsnap = { - ht = h, - dp = d, - ch = ch, - cd = cd, - extra = extra, - current = current, -} -setprop(current,"snapper",lastsnap) - + lastsnap = { + ht = h, + dp = d, + ch = ch, + cd = cd, + extra = extra, + current = current, + } + setprop(current,"snapper",lastsnap) if trace_vsnapping then report_snapper("mvl %a snapped from (%p,%p) to (%p,%p) using method %a (%s) for %a (%s lines): %s", nodecodes[id],h,d,ch,cd,sv.name,sv.specification,where,lines,listtoutf(list)) @@ -1425,15 +1423,15 @@ setprop(current,"snapper",lastsnap) flush("list") current = getnext(current) elseif id == penalty_code then - -- natural_penalty = getfield(current,"penalty") + -- natural_penalty = getpenalty(current) -- if trace then -- trace_done("removed penalty",current) -- end -- head, current = remove_node(head, current, true) current = getnext(current) elseif id == kern_code then - if snap and trace_vsnapping and getfield(current,"kern") ~= 0 then - report_snapper("kern of %p kept",getfield(current,"kern")) + if snap and trace_vsnapping and getkern(current) ~= 0 then + report_snapper("kern of %p kept",getkern(current)) end flush("kern") current = getnext(current) @@ -1572,8 +1570,8 @@ setprop(current,"snapper",lastsnap) elseif glue_order == so then -- is now exclusive, maybe support goback as combi, else why a set if sc == largest then - local cw = getfield(current,"width") or 0 - local gw = getfield(glue_data,"width") or 0 + local cw = getwidth(current) + local gw = getwidth(glue_data) if cw > gw then if trace then trace_skip("largest",sc,so,sp,current) @@ -1636,7 +1634,7 @@ setprop(current,"snapper",lastsnap) local s = getattr(current,a_snapmethod) if s and s ~= 0 then setattr(current,a_snapmethod,0) - setfield(current,"width",0) + setwidth(current,0) if trace_vsnapping then report_snapper("lineskip set to zero") end @@ -1658,7 +1656,7 @@ setprop(current,"snapper",lastsnap) local s = getattr(current,a_snapmethod) if s and s ~= 0 then setattr(current,a_snapmethod,0) - setfield(current,"width",0) + setwidth(current,0) if trace_vsnapping then report_snapper("baselineskip set to zero") end @@ -1683,8 +1681,8 @@ setprop(current,"snapper",lastsnap) end head, current = remove_node(head, current, true) elseif glue_data then - local w = getfield(current,"width") or 0 - if ((w ~= 0) and (w > (getfield(glue_data,"width") or 0))) then + local w = getwidth(current) + if (w ~= 0) and (w > getwidth(glue_data)) then glue_data = current if trace then trace_natural("taking parskip",current) @@ -1763,7 +1761,7 @@ setprop(current,"snapper",lastsnap) -- else -- other glue if snap and trace_vsnapping then - local w = getfield(current,"width") or 0 + local w = getwidth(current) if w ~= 0 then report_snapper("glue %p of type %a kept",w,skipcodes[subtype]) end @@ -1795,7 +1793,7 @@ setprop(current,"snapper",lastsnap) if trace then trace_done("result",p) end - head, tail = insert_node_after(head,tail,p) + setlink(tail,p) -- if penalty_data > special_penalty_min and penalty_data < special_penalty_max then local props = properties[p] if props then @@ -1813,11 +1811,13 @@ setprop(current,"snapper",lastsnap) trace_done("result",glue_data) end if force_glue then - head, tail = forced_skip(head,tail,getfield(glue_data,"width") or 0,"after",trace) + head, tail = forced_skip(head,tail,getwidth(glue_data),"after",trace) flush_node(glue_data) glue_data = nil + elseif tail then + setlink(tail,glue_data) else - head, tail = insert_node_after(head,tail,glue_data) + head = glue_data end texnest[texnest.ptr].prevdepth = 0 -- appending to the list bypasses tex's prevdepth handler end @@ -1911,36 +1911,40 @@ function vspacing.pagehandler(newhead,where) return nil end -local ignore = table.tohash { - "split_keep", - "split_off", - -- "vbox", -} +do -function vspacing.vboxhandler(head,where) - if head and not ignore[where] then - local h = tonut(head) - if getnext(h) then -- what if a one liner and snapping? - h = collapser(h,"vbox",where,trace_vbox_vspacing,true,a_snapvbox) -- todo: local snapper - return tonode(h) + local ignore = table.tohash { + "split_keep", + "split_off", + -- "vbox", + } + + function vspacing.vboxhandler(head,where) + if head and not ignore[where] then + local h = tonut(head) + if getnext(h) then -- what if a one liner and snapping? + h = collapser(h,"vbox",where,trace_vbox_vspacing,true,a_snapvbox) -- todo: local snapper + return tonode(h) + end end + return head end - return head -end -function vspacing.collapsevbox(n,aslist) -- for boxes but using global a_snapmethod - local box = getbox(n) - if box then - local list = getlist(box) - if list then - list = collapser(list,"snapper","vbox",trace_vbox_vspacing,true,a_snapmethod) - if aslist then - setlist(box,list) -- beware, dimensions of box are wrong now - else - setlist(box,vpack_node(list)) + function vspacing.collapsevbox(n,aslist) -- for boxes but using global a_snapmethod + local box = getbox(n) + if box then + local list = getlist(box) + if list then + list = collapser(list,"snapper","vbox",trace_vbox_vspacing,true,a_snapmethod) + if aslist then + setlist(box,list) -- beware, dimensions of box are wrong now + else + setlist(box,vpack_node(list)) + end end end end + end -- This one is needed to prevent bleeding of prevdepth to the next page @@ -1979,71 +1983,75 @@ end -- interface -implement { - name = "vspacing", - actions = vspacing.analyze, - scope = "private", - arguments = "string" -} - -implement { - name = "resetprevdepth", - actions = vspacing.resetprevdepth, - scope = "private" -} - -implement { - name = "vspacingsetamount", - actions = vspacing.setskip, - scope = "private", - arguments = "string", -} - -implement { - name = "vspacingdefine", - actions = vspacing.setmap, - scope = "private", - arguments = { "string", "string" } -} - -implement { - name = "vspacingcollapse", - actions = vspacing.collapsevbox, - scope = "private", - arguments = "integer" -} - -implement { - name = "vspacingcollapseonly", - actions = vspacing.collapsevbox, - scope = "private", - arguments = { "integer", true } -} - -implement { - name = "vspacingsnap", - actions = vspacing.snapbox, - scope = "private", - arguments = { "integer", "integer" } -} - -implement { - name = "definesnapmethod", - actions = vspacing.definesnapmethod, - scope = "private", - arguments = { "string", "string" } -} - -local remove_node = nodes.remove -local find_node_tail = nodes.tail +do -interfaces.implement { - name = "fakenextstrutline", - actions = function() - local head = texlists.page_head - if head then - local head = remove_node(head,find_node_tail(head),true) - texlists.page_head = head + implement { + name = "vspacing", + actions = vspacing.analyze, + scope = "private", + arguments = "string" + } + + implement { + name = "resetprevdepth", + actions = vspacing.resetprevdepth, + scope = "private" + } + + implement { + name = "vspacingsetamount", + actions = vspacing.setskip, + scope = "private", + arguments = "string", + } + + implement { + name = "vspacingdefine", + actions = vspacing.setmap, + scope = "private", + arguments = { "string", "string" } + } + + implement { + name = "vspacingcollapse", + actions = vspacing.collapsevbox, + scope = "private", + arguments = "integer" + } + + implement { + name = "vspacingcollapseonly", + actions = vspacing.collapsevbox, + scope = "private", + arguments = { "integer", true } + } + + implement { + name = "vspacingsnap", + actions = vspacing.snapbox, + scope = "private", + arguments = { "integer", "integer" } + } + + implement { + name = "definesnapmethod", + actions = vspacing.definesnapmethod, + scope = "private", + arguments = { "string", "string" } + } + + local remove_node = nodes.remove + local find_node_tail = nodes.tail + + interfaces.implement { + name = "fakenextstrutline", + actions = function() + local head = texlists.page_head + if head then + local head = remove_node(head,find_node_tail(head),true) + texlists.page_head = head + end end - end -} + } + +end diff --git a/tex/context/base/mkiv/status-files.pdf b/tex/context/base/mkiv/status-files.pdf index ed9a82192..c01ed7449 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 c6c5939bb..d9528aa62 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/base/mkiv/strc-con.mkvi b/tex/context/base/mkiv/strc-con.mkvi index 396869608..18ce17355 100644 --- a/tex/context/base/mkiv/strc-con.mkvi +++ b/tex/context/base/mkiv/strc-con.mkvi @@ -971,8 +971,8 @@ catcodes \catcodetable } references { - internal \nextinternalreference - order \nextinternalorderreference + internal \locationcount + order \locationorder reference {\currentconstructionreference} prefix {\currentconstructionreferenceprefix} % block {\currentsectionblock} @@ -1016,7 +1016,7 @@ \clf_setinternalreference prefix {\referenceprefix}% reference {\currentconstructionreference}% - internal \nextinternalreference + internal \locationcount view {\interactionparameter\c!focus}% \relax \normalexpanded{% diff --git a/tex/context/base/mkiv/strc-doc.lua b/tex/context/base/mkiv/strc-doc.lua index 105e5ad8d..57fff5a21 100644 --- a/tex/context/base/mkiv/strc-doc.lua +++ b/tex/context/base/mkiv/strc-doc.lua @@ -16,7 +16,7 @@ if not modules then modules = { } end modules ['strc-doc'] = { -- in lists however zero's are ignored, so there numbersegments=2:4 gives result local next, type, tonumber, select = next, type, tonumber, select -local format, gsub, find, gmatch, match = string.format, string.gsub, string.find, string.gmatch, string.match +local find, match = string.find, string.match local concat, fastcopy, insert, remove = table.concat, table.fastcopy, table.insert, table.remove local max, min = math.max, math.min local allocate, mark, accesstable = utilities.storage.allocate, utilities.storage.mark, utilities.tables.accesstable @@ -411,16 +411,17 @@ function sections.setentry(given) v[2](k) end end - local n = { } - for i=1,newdepth do - n[i] = numbers[i] - end - numberdata.numbers = n +-- local n = { } +-- for i=1,newdepth do +-- n[i] = numbers[i] +-- end +-- numberdata.numbers = n + numberdata.numbers = { unpack(numbers,1,newdepth) } if not numberdata.block then numberdata.block = getcurrentblock() -- also in references end if #ownnumbers > 0 then - numberdata.ownnumbers = fastcopy(ownnumbers) + numberdata.ownnumbers = fastcopy(ownnumbers) -- { unpack(ownnumbers) } end if trace_detail then report_structure("name %a, numbers % a, own numbers % a",givenname,numberdata.numbers,numberdata.ownnumbers) diff --git a/tex/context/base/mkiv/strc-doc.mkiv b/tex/context/base/mkiv/strc-doc.mkiv index c453f199e..5f40521fa 100644 --- a/tex/context/base/mkiv/strc-doc.mkiv +++ b/tex/context/base/mkiv/strc-doc.mkiv @@ -23,10 +23,10 @@ {\clf_setinternalreference prefix {\currentstructurereferenceprefix}% reference {\currentstructurereference} - internal \nextinternalreference + internal \locationcount view {\interactionparameter\c!focus}% \relax \xdef\currentstructureattribute {\the\lastdestinationattribute}% - \xdef\currentstructuresynchronize{\strc_lists_inject_enhance{#1}{\nextinternalreference}}} + \xdef\currentstructuresynchronize{\strc_lists_inject_enhance{#1}{\the\locationcount}}} \protect \endinput diff --git a/tex/context/base/mkiv/strc-enu.mkvi b/tex/context/base/mkiv/strc-enu.mkvi index aaf735918..8eff706bb 100644 --- a/tex/context/base/mkiv/strc-enu.mkvi +++ b/tex/context/base/mkiv/strc-enu.mkvi @@ -366,7 +366,7 @@ \strc_enumerations_full_number_yes \edef\p_coupling{\constructionparameter\c!coupling}% \ifx\p_coupling\empty \else - \symbolreference[order(construction:\p_coupling:\nextinternalorderreference)]% + \symbolreference[order(construction:\p_coupling:\the\locationorder)]% \fi \fi} diff --git a/tex/context/base/mkiv/strc-itm.mkvi b/tex/context/base/mkiv/strc-itm.mkvi index e622318c3..a28193415 100644 --- a/tex/context/base/mkiv/strc-itm.mkvi +++ b/tex/context/base/mkiv/strc-itm.mkvi @@ -274,7 +274,7 @@ catcodes \catcodetable }% references {% - internal \nextinternalreference % no: this spoils references + internal \locationcount % no: this spoils references % block {\currentsectionblock}% view {\interactionparameter\c!focus}% prefix {\referenceprefix}% diff --git a/tex/context/base/mkiv/strc-lst.mkvi b/tex/context/base/mkiv/strc-lst.mkvi index 4309ae93a..a3718af18 100644 --- a/tex/context/base/mkiv/strc-lst.mkvi +++ b/tex/context/base/mkiv/strc-lst.mkvi @@ -145,7 +145,7 @@ {\endgroup} \unexpanded\def\strc_lists_inject_enhance#listindex#internal% - {\normalexpanded{\ctxlatecommand{enhancelist(#listindex)}}} + {\normalexpanded{\ctxlatecommand{enhancelist(\number#listindex)}}} \unexpanded\def\strc_lists_inject_yes[#settings][#userdata]% can be used directly {\setupcurrentlist[\c!type=userdata,\c!location=\v!none,#settings]% grouped (use \let... @@ -153,7 +153,7 @@ \setnextinternalreference \scratchcounter\clf_addtolist references { - internal \nextinternalreference + internal \locationcount % block {\currentsectionblock} % section structures.sections.currentid() % location {\p_location} @@ -167,12 +167,12 @@ userdata {\detokenize\expandafter{\normalexpanded{#userdata}}} \relax \edef\currentlistnumber{\the\scratchcounter}% -\setxvalue{\??listlocations\currentlist}{\nextinternalreference}% +\setxvalue{\??listlocations\currentlist}{\the\locationcount}% \ifx\p_location\v!here % this branch injects nodes ! - \strc_lists_inject_enhance{\currentlistnumber}{\nextinternalreference}% + \strc_lists_inject_enhance{\currentlistnumber}{\the\locationcount}% \clf_setinternalreference - internal \nextinternalreference + internal \locationcount view {\interactionparameter\c!focus}% \relax % this will change \xdef\currentstructurelistattribute{\the\lastdestinationattribute}% diff --git a/tex/context/base/mkiv/strc-mar.lua b/tex/context/base/mkiv/strc-mar.lua index 8b30e8514..624972af4 100644 --- a/tex/context/base/mkiv/strc-mar.lua +++ b/tex/context/base/mkiv/strc-mar.lua @@ -31,7 +31,8 @@ local getlist = nuts.getlist local getattr = nuts.getattr local getbox = nuts.getbox -local traverse_nodes = nuts.traverse +local traverse = nuts.traverse +local traverse_id = nuts.traverse_id local nodecodes = nodes.nodecodes local glyph_code = nodecodes.glyph @@ -117,7 +118,7 @@ end -- identify range local function sweep(head,first,last) - for n in traverse_nodes(head) do + for n in traverse(head) do local id = getid(n) if id == glyph_code then local a = getattr(n,a_marks) diff --git a/tex/context/base/mkiv/strc-mat.mkiv b/tex/context/base/mkiv/strc-mat.mkiv index 4c6b88c8a..4308666f3 100644 --- a/tex/context/base/mkiv/strc-mat.mkiv +++ b/tex/context/base/mkiv/strc-mat.mkiv @@ -518,8 +518,6 @@ %D Tricky stuff: -\newdimen\lastlinewidth - \abovedisplayskip \zeropoint \abovedisplayshortskip \zeropoint % evt. 0pt minus 3pt \belowdisplayskip \zeropoint @@ -529,6 +527,8 @@ \postdisplaypenalty \zerocount % -5000 goes wrong, see penalty at \section \mathdisplayskipmode \plusthree % because align also adds +% \predisplaygapfactor \zerocount % default is 2000 + \unexpanded\def\strc_formulas_forget_display_skips {\mathdisplayskipmode \plusthree \abovedisplayskip \zeropoint diff --git a/tex/context/base/mkiv/strc-not.lua b/tex/context/base/mkiv/strc-not.lua index c54cd442e..1464c7f73 100644 --- a/tex/context/base/mkiv/strc-not.lua +++ b/tex/context/base/mkiv/strc-not.lua @@ -26,8 +26,11 @@ local counterspecials = counters.specials local texgetcount = tex.getcount local texgetbox = tex.getbox +-- todo: allocate + notes.states = notes.states or { } lists.enhancers = lists.enhancers or { } +notes.numbers = notes.numbers or { } storage.register("structures/notes/states", notes.states, "structures.notes.states") @@ -143,6 +146,8 @@ end notes.setstate = setstate notes.getstate = getstate + + implement { name = "setnotestate", actions = setstate, @@ -157,6 +162,7 @@ implement { function notes.define(tag,kind,number) local state = setstate(tag,kind) + notes.numbers[number] = state state.number = number end @@ -451,23 +457,39 @@ end -- for the moment here but better in some builder modules +-- gets register "n" and location "i" (where 1 is before) + +-- this is an experiment, we will make a more general handler instead +-- of the current note one + local report_insert = logs.reporter("pagebuilder","insert") local trace_insert = false trackers.register("pagebuilder.insert",function(v) trace_insert = v end) local texgetglue = tex.getglue ------ texsetglue = tex.setglue +local texsetglue = tex.setglue -function notes.check_spacing(n,i) +local function check_spacing(n,i) local gn, pn, mn = texgetglue(n) local gi, pi, mi = texgetglue(i > 1 and "s_strc_notes_inbetween" or "s_strc_notes_before") - local gt, pt, mt = gn+gi, pn+pi, mn+mi + local gi, pi, mi = gn+gi, pn+pi, mn+mi if trace_insert then report_insert("%s %i: %p plus %p minus %p","always ",n,gn,pn,mn) report_insert("%s %i: %p plus %p minus %p",i > 1 and "inbetween" or "before ",n,gi,pi,mi) report_insert("%s %i: %p plus %p minus %p","effective",n,gt,pt,mt) end - -- texsetglue(0,gt,pt,mt) -- for the moment we use skip register 0 return gt, pt, mt end -callback.register("build_page_insert", notes.check_spacing) +notes.check_spacing = check_spacing + +callback.register("build_page_insert", function(n,i) + local state = notes.numbers[n] + if state then + -- only notes, kind of hardcoded .. bah + local gt, pt, mt = check_spacing(n,i) + texsetglue(0,gt,pt,mt) -- for the moment we use skip register 0 + return 0 + else + return n + end +end) diff --git a/tex/context/base/mkiv/strc-not.mkvi b/tex/context/base/mkiv/strc-not.mkvi index d2626d2ab..f1a51c5ad 100644 --- a/tex/context/base/mkiv/strc-not.mkvi +++ b/tex/context/base/mkiv/strc-not.mkvi @@ -404,7 +404,11 @@ \setexpandednoteparameter\s!insert{\namednoteparameter\currentnoteparent\s!insert}% \definenotation[\currentnote][\currentnoteparent][\c!type=\v!note]% \fi - \clf_definenote{\currentnote}{insert}\currentnoteinsertionnumber\relax + \clf_definenote + {\currentnote}% + {insert}% + \currentnoteinsertionnumber + \relax \to \everydefinenote % maybe we will share this at some point: diff --git a/tex/context/base/mkiv/strc-num.mkiv b/tex/context/base/mkiv/strc-num.mkiv index 2418130f9..4b222801a 100644 --- a/tex/context/base/mkiv/strc-num.mkiv +++ b/tex/context/base/mkiv/strc-num.mkiv @@ -545,7 +545,7 @@ \clf_setdestinationattribute {% references {% - internal \nextinternalreference + internal \locationcount % block {\currentsectionblock}% move to lua view {\interactionparameter\c!focus}% prefix {\currentstructurecomponentreferenceprefix}% @@ -621,7 +621,7 @@ \fi } references { - internal \nextinternalreference + internal \locationcount % block {\currentsectionblock} reference {\currentstructurecomponentreference} prefix {\currentstructurecomponentreferenceprefix} @@ -670,10 +670,10 @@ \relax \xdef\m_strc_counters_last_registered_index{\the\scratchcounter}% \clf_setinternalreference - internal \nextinternalreference + internal \locationcount \relax \xdef\m_strc_counters_last_registered_attribute {\the\lastdestinationattribute}% - \xdef\m_strc_counters_last_registered_synchronize{\strc_lists_inject_enhance{\m_strc_counters_last_registered_index}{\nextinternalreference}}} + \xdef\m_strc_counters_last_registered_synchronize{\strc_lists_inject_enhance{\m_strc_counters_last_registered_index}{\the\locationcount}}} \let\m_strc_counters_last_registered_index \relax \let\m_strc_counters_last_registered_attribute \relax diff --git a/tex/context/base/mkiv/strc-ref.mkvi b/tex/context/base/mkiv/strc-ref.mkvi index 96cb61b4a..9f2a7b91c 100644 --- a/tex/context/base/mkiv/strc-ref.mkvi +++ b/tex/context/base/mkiv/strc-ref.mkvi @@ -219,7 +219,7 @@ \clf_setdestinationattribute {% references {% - internal \nextinternalreference + internal \locationcount % block {\currentsectionblock}% view {\interactionparameter\c!focus}% \ifx\referenceprefix\empty\else @@ -281,7 +281,7 @@ \clf_setdestinationattribute {% references {% - internal \nextinternalreference + internal \locationcount % block {\currentsectionblock}% view {\interactionparameter\c!focus}% \ifx\referenceprefix\empty\else @@ -310,7 +310,7 @@ \clf_setdestinationattribute {% references {% - internal \nextinternalreference + internal \locationcount % block {\currentsectionblock}% view {\interactionparameter\c!focus}% \ifx\referenceprefix\empty\else @@ -401,7 +401,7 @@ prefix {\referenceprefix}% \fi reference {#label}% - internal \nextinternalreference + internal \locationcount }% metadata {% kind {\s!page}% @@ -424,7 +424,7 @@ references {% view {\interactionparameter\c!focus}% reference {#label}% - internal \nextinternalreference + internal \locationcount }% metadata {% kind {\s!page}% @@ -847,7 +847,7 @@ \letvalue{\??savedinternalreference\s!default}\!!zerocount \unexpanded\def\storeinternalreference#1#2% - {\setxvalue{\??savedinternalreference\currentstructurename}{#2}} + {\setxvalue{\??savedinternalreference\currentstructurename}{\number#2}} \newconditional\preferpagereferences diff --git a/tex/context/base/mkiv/strc-reg.mkiv b/tex/context/base/mkiv/strc-reg.mkiv index 5b32c6fc8..380cc9f22 100644 --- a/tex/context/base/mkiv/strc-reg.mkiv +++ b/tex/context/base/mkiv/strc-reg.mkiv @@ -298,7 +298,7 @@ userdata {\detokenize\expandafter{\normalexpanded{#3}}} }% \clf_setinternalreference - internal \nextinternalreference + internal \locationcount view {\interactionparameter\c!focus}% \relax % this will change \ifx\currentregisterownnumber\v!yes @@ -337,7 +337,7 @@ }% % overlap with the above % \clf_setinternalreference - % internal \nextinternalreference + % internal \locationcount % view {\interactionparameter\c!focus}% \relax % this will change \xdef\currentregistersynchronize{\ctxlatecommand{enhanceregister("\currentregister",\currentregisternumber)}}% @@ -524,7 +524,7 @@ }% }}% \clf_setinternalreference - internal \nextinternalreference + internal \locationcount view {\interactionparameter\c!focus}% \relax % this will change \dostarttagged\t!registerlocation\currentregister diff --git a/tex/context/base/mkiv/strc-ren.mkiv b/tex/context/base/mkiv/strc-ren.mkiv index b5fc9e11d..b3b9f04d9 100644 --- a/tex/context/base/mkiv/strc-ren.mkiv +++ b/tex/context/base/mkiv/strc-ren.mkiv @@ -82,24 +82,24 @@ \def\headreferenceattributes {\iflocation - % \ctxlua{structures.lists.taglocation(\nextinternalreference)}% maybe ... tags entry as used + % \ctxlua{structures.lists.taglocation(\the\locationcount)}% maybe ... tags entry as used attr \destinationattribute \currentstructureattribute attr \referenceattribute \currentstructurereferenceattribute - % attr \internalattribute \nextinternalreference + % attr \internalattribute \locationcount \fi} \def\setinlineheadreferenceattributes {\ifconditional\headisdisplay \else \iflocation \attribute\destinationattribute\currentstructureattribute \attribute\referenceattribute \currentstructurereferenceattribute - % \attribute\internalattribute \nextinternalreference + % \attribute\internalattribute \locationcount \fi \fi} \def\docheckheadreference {\edef\currentheadinteraction{\headparameter\c!interaction}% \ifx\currentheadinteraction\v!list % setuphead[