diff options
Diffstat (limited to 'Master/texmf-dist/tex/context/base/node-ref.lua')
-rw-r--r-- | Master/texmf-dist/tex/context/base/node-ref.lua | 257 |
1 files changed, 148 insertions, 109 deletions
diff --git a/Master/texmf-dist/tex/context/base/node-ref.lua b/Master/texmf-dist/tex/context/base/node-ref.lua index 7128b1a6d20..19d602ed673 100644 --- a/Master/texmf-dist/tex/context/base/node-ref.lua +++ b/Master/texmf-dist/tex/context/base/node-ref.lua @@ -14,10 +14,21 @@ if not modules then modules = { } end modules ['node-bck'] = { -- helper, will end up in luatex +-- is grouplevel still used? + +local allocate, mark = utilities.storage.allocate, utilities.storage.mark + local cleanupreferences, cleanupdestinations = false, true -local nodeinjections = backends.nodeinjections -local codeinjections = backends.codeinjections +local attributes, nodes, node = attributes, nodes, node + +local nodeinjections = backends.nodeinjections +local codeinjections = backends.codeinjections + +local transparencies = attributes.transparencies +local colors = attributes.colors +local references = structures.references +local tasks = nodes.tasks local hpack_list = node.hpack local list_dimensions = node.dimensions @@ -28,17 +39,37 @@ local trace_backend = false trackers.register("nodes.backend", functi 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) -local hlist = node.id("hlist") -local vlist = node.id("vlist") -local glue = node.id("glue") -local whatsit = node.id("whatsit") +local report_reference = logs.reporter("backend","references") +local report_destination = logs.reporter("backend","destinations") +local report_area = logs.reporter("backend","areas") + +local nodecodes = nodes.nodecodes +local skipcodes = nodes.skipcodes +local whatcodes = nodes.whatcodes +local listcodes = nodes.listcodes + +local hlist_code = nodecodes.hlist +local vlist_code = nodecodes.vlist +local glue_code = nodecodes.glue +local whatsit_code = nodecodes.whatsit -local new_kern = nodes.kern +local leftskip_code = skipcodes.leftskip +local rightskip_code = skipcodes.rightskip +local parfillskip_code = skipcodes.parfillskip -local has_attribute = node.has_attribute -local traverse = node.traverse -local find_node_tail = node.tail or node.slide -local tosequence = nodes.tosequence +local localpar_code = whatcodes.localpar +local dir_code = whatcodes.dir + +local line_code = listcodes.line + +local nodepool = nodes.pool + +local new_kern = nodepool.kern + +local has_attribute = node.has_attribute +local traverse = node.traverse +local find_node_tail = node.tail or node.slide +local tosequence = nodes.tosequence local function dimensions(parent,start,stop) stop = stop and stop.next @@ -78,14 +109,14 @@ local function inject_range(head,first,last,reference,make,stack,parent,pardir,t if result and resolved then if head == first then if trace_backend then - logs.report("backend","head: %04i %s %s %s => w=%s, h=%s, d=%s, c=%s",reference,pardir or "---",txtdir or "----",tosequence(first,last,true),width,height,depth,resolved) + report_area("head: %04i %s %s %s => w=%s, h=%s, d=%s, c=%s",reference,pardir or "---",txtdir or "----",tosequence(first,last,true),width,height,depth,resolved) end result.next = first first.prev = result return result, last else if trace_backend then - logs.report("backend","middle: %04i %s %s => w=%s, h=%s, d=%s, c=%s",reference,pardir or "---",txtdir or "----",tosequence(first,last,true),width,height,depth,resolved) + report_area("middle: %04i %s %s => w=%s, h=%s, d=%s, c=%s",reference,pardir or "---",txtdir or "----",tosequence(first,last,true),width,height,depth,resolved) end local prev = first.prev if prev then @@ -111,20 +142,17 @@ local function inject_list(id,current,reference,make,stack,pardir,txtdir) local width, height, depth, correction = current.width, current.height, current.depth, 0 local moveright = false local first = current.list - if id == hlist then + if id == hlist_code then -- box_code line_code -- can be either an explicit hbox or a line and there is no way -- to recognize this; anyway only if ht/dp (then inline) - -- - -- to be tested: 0=unknown, 1=linebreak, 2=hbox ---~ if id.subtype == 1 then local sr = stack[reference] if first then if sr and sr[2] then local last = find_node_tail(first) - if last.id == glue and last.subtype == 9 then + if last.id == glue_code and last.subtype == rightskip_code then local prev = last.prev - moveright = first.id == glue and first.subtype == 8 - if prev and prev.id == glue and prev.subtype == 15 then + moveright = first.id == glue_code and first.subtype == leftskip_code + if prev and prev.id == glue_code and prev.subtype == parfillskip_code then width = dimensions(current,first,prev.prev) -- maybe not current as we already take care of it else if moveright and first.writable then @@ -138,10 +166,6 @@ local function inject_list(id,current,reference,make,stack,pardir,txtdir) else -- also weird end ---~ else ---~ print("!!!!!!!!!!!!!!!!!") - -- simple ---~ end else -- ok end @@ -156,7 +180,7 @@ local function inject_list(id,current,reference,make,stack,pardir,txtdir) local result, resolved = make(width,height,depth,reference) if result and resolved then if trace_backend then - logs.report("backend","box: %04i %s %s: w=%s, h=%s, d=%s, c=%s",reference,pardir or "---",txtdir or "----",width,height,depth,resolved) + report_area("box: %04i %s %s: w=%s, h=%s, d=%s, c=%s",reference,pardir or "---",txtdir or "----",width,height,depth,resolved) end if not first then current.list = result @@ -186,15 +210,21 @@ local function inject_areas(head,attribute,make,stack,done,skip,parent,pardir,tx while current do local id = current.id local r = has_attribute(current,attribute) - if id == whatsit then + if id == whatsit_code then local subtype = current.subtype - if subtype == 6 then + if subtype == localpar_code then pardir = current.dir - elseif subtype == 7 then + elseif subtype == dir_code then txtdir = current.dir end - elseif id == hlist or id == vlist then - if not reference and r and (not skip or r > skip) then + elseif id == glue_code and current.subtype == leftskip_code then -- any glue at the left? + -- + elseif id == hlist_code or id == vlist_code then +-- somehow reference is true so teh following fails (second one not done) in +-- test \goto{test}[page(2)] test \gotobox{test}[page(2)] +-- so let's wait till this fails again +-- if not reference and r and (not skip or r > skip) then -- > or ~= + if r and (not skip or r > skip) then -- > or ~= inject_list(id,current,r,make,stack,pardir,txtdir) end if r then @@ -214,8 +244,8 @@ local function inject_areas(head,attribute,make,stack,done,skip,parent,pardir,tx reference, first, last, firstdir = r, current, current, txtdir elseif r == reference then last = current - elseif (done[reference] or 0) == 0 then - if not skip or r > skip then + elseif (done[reference] or 0) == 0 then -- or id == glue_code and current.subtype == right_skip_code + if not skip or r > skip then -- maybe no > test head, current = inject_range(head,first,last,reference,make,stack,parent,pardir,firstdir) reference, first, last, firstdir = nil, nil, nil, nil end @@ -239,14 +269,14 @@ local function inject_area(head,attribute,make,stack,done,parent,pardir,txtdir) while current do local id = current.id local r = has_attribute(current,attribute) - if id == whatsit then + if id == whatsit_code then local subtype = current.subtype - if subtype == 6 then + if subtype == localpar_code then pardir = current.dir - elseif subtype == 7 then + elseif subtype == dir_code then txtdir = current.dir end - elseif id == hlist or id == vlist then + elseif id == hlist_code or id == vlist_code then if r and not done[r] then done[r] = true inject_list(id,current,r,make,stack,pardir,txtdir) @@ -264,8 +294,12 @@ end -- tracing -local new_rule = nodes.rule -local new_kern = nodes.kern + +local nodepool = nodes.pool + +local new_rule = nodepool.rule +local new_kern = nodepool.kern + local set_attribute = node.set_attribute local register_color = colors.register @@ -293,6 +327,15 @@ local function colorize(width,height,depth,n) end u_colors[n] = u_color end + if width == 0 then + report_area("reference %s has no horizontal dimensions: width=%s, height=%s, depth=%s",reference,width,height,depth) + width = 65536 + end + if height + depth <= 0 then + report_area("reference %s has no vertical dimensions: width=%s, height=%s, depth=%s",reference,width,height,depth) + height = 65536/2 + depth = height + end local rule = new_rule(width,height,depth) set_attribute(rule,a_colormodel,1) -- gray color model set_attribute(rule,a_color,u_color) @@ -308,35 +351,51 @@ local function colorize(width,height,depth,n) end end -local new_kern = nodes.kern +local nodepool = nodes.pool + +local new_kern = nodepool.kern + local texattribute = tex.attribute local texcount = tex.count -- references: +local stack = { } +local done = { } +local attribute = attributes.private('reference') +local nofreferences = 0 +local topofstack = 0 + nodes.references = { - attribute = attributes.private('reference'), - stack = { }, - done = { }, + attribute = attribute, + stack = stack, + done = done, } -local stack, done, attribute = nodes.references.stack, nodes.references.done, nodes.references.attribute - -local nofreferences, topofstack = 0, 0 +-- todo: get rid of n (n is just a number, can be used for tracing, obsolete) -local function setreference(n,h,d,r) -- n is just a number, can be used for tracing +local function setreference(n,h,d,r) topofstack = topofstack + 1 - stack[topofstack] = { n, h, d, codeinjections.prerollreference(r) } -- the preroll permits us to determine samepage (but delayed also has some advantages) ---~ texattribute[attribute] = topofstack -- todo -> at tex end + -- the preroll permits us to determine samepage (but delayed also has some advantages) + -- so some part of the backend work is already done here +--~ stack[topofstack] = { n, h, d, codeinjections.prerollreference(r) } + stack[topofstack] = { r, h, d, codeinjections.prerollreference(r) } + -- texattribute[attribute] = topofstack -- todo -> at tex end texcount.lastreferenceattribute = topofstack end -nodes.setreference = setreference +function references.get(n) -- not public so functionality can change + local sn = stack[n] + return sn and sn[1] +end local function makereference(width,height,depth,reference) local sr = stack[reference] if sr then - local resolved, ht, dp, set = sr[1], sr[2], sr[3], sr[4] + if trace_references then + report_reference("resolving attribute %s",reference) + end + local resolved, ht, dp, set, n = sr[1], sr[2], sr[3], sr[4], sr[5] if ht then if height < ht then height = ht end if depth < dp then depth = dp end @@ -347,7 +406,7 @@ local function makereference(width,height,depth,reference) local result, current if trace_references then local step = 65536 - result = hpack_list(colorize(width,height-step,depth-step,2)) -- step subtracted so that we can see seperate links + result = hpack_list(colorize(width,height-step,depth-step,2,reference)) -- step subtracted so that we can see seperate links result.width = 0 current = result end @@ -356,19 +415,20 @@ local function makereference(width,height,depth,reference) else result = annot end + references.registerpage(n) result = hpack_list(result,0) result.width, result.height, result.depth = 0, 0, 0 if cleanupreferences then stack[reference] = nil end return result, resolved - else - logs.report("backends","unable to resolve reference annotation %s",reference) + elseif trace_references then + report_reference("unable to resolve annotation %s",reference) end - else - logs.report("backends","unable to resolve reference attribute %s",reference) + elseif trace_references then + report_reference("unable to resolve attribute %s",reference) end end -function nodes.add_references(head) +function nodes.references.handler(head) if topofstack > 0 then return inject_areas(head,attribute,makereference,stack,done) else @@ -376,29 +436,32 @@ function nodes.add_references(head) end end --- destinations (we can clean up once set!) +-- destinations (we can clean up once set, unless tagging!) + +local stack = { } +local done = { } +local attribute = attributes.private('destination') +local nofdestinations = 0 +local topofstack = 0 nodes.destinations = { - attribute = attributes.private('destination'), - stack = { }, - done = { }, + attribute = attribute, + stack = stack, + done = done, } -local stack, done, attribute = nodes.destinations.stack, nodes.destinations.done, nodes.destinations.attribute - -local nofdestinations, topofstack = 0, 0 - local function setdestination(n,h,d,name,view) -- n = grouplevel, name == table topofstack = topofstack + 1 stack[topofstack] = { n, h, d, name, view } return topofstack end -nodes.setdestination = setdestination - local function makedestination(width,height,depth,reference) local sr = stack[reference] if sr then + if trace_destinations then + report_destination("resolving attribute %s",reference) + end local resolved, ht, dp, name, view = sr[1], sr[2], sr[3], sr[4], sr[5] if ht then if height < ht then height = ht end @@ -412,7 +475,7 @@ local function makedestination(width,height,depth,reference) width, height, depth = 5*step, 5*step, 0 end for n=1,#name do - local rule = hpack_list(colorize(width,height,depth,3)) + local rule = hpack_list(colorize(width,height,depth,3,reference)) rule.width = 0 if not result then result, current = rule, rule @@ -435,16 +498,19 @@ local function makedestination(width,height,depth,reference) current = annot end end - result = hpack_list(result,0) - result.width, result.height, result.depth = 0, 0, 0 + if result then + -- some internal error + result = hpack_list(result,0) + result.width, result.height, result.depth = 0, 0, 0 + end if cleanupdestinations then stack[reference] = nil end return result, resolved - else - logs.report("backends","unable to resolve destination attribute %s",reference) + elseif trace_destinations then + report_destination("unable to resolve attribute %s",reference) end end -function nodes.add_destinations(head) +function nodes.destinations.handler(head) if topofstack > 0 then return inject_area(head,attribute,makedestination,stack,done) -- singular else @@ -454,12 +520,12 @@ end -- will move -function jobreferences.mark(reference,h,d,view) +function references.mark(reference,h,d,view) return setdestination(tex.currentgrouplevel,h,d,reference,view) end -function jobreferences.inject(prefix,reference,h,d,highlight,newwindow,layer) -- todo: use currentreference is possible - local set, bug = jobreferences.identify(prefix,reference) +function references.inject(prefix,reference,h,d,highlight,newwindow,layer) -- todo: use currentreference is possible + local set, bug = references.identify(prefix,reference) if bug or #set == 0 then -- unknown ref, just don't set it and issue an error else @@ -469,8 +535,8 @@ function jobreferences.inject(prefix,reference,h,d,highlight,newwindow,layer) -- end end -function jobreferences.injectcurrentset(h,d) -- used inside doifelse - local currentset = jobreferences.currentset +function references.injectcurrentset(h,d) -- used inside doifelse + local currentset = references.currentset if currentset then setreference(tex.currentgrouplevel,h,d,currentset) -- sets attribute / todo: for set[*].error end @@ -480,43 +546,16 @@ end local function checkboth(open,close) if open and open ~= "" then - local set, bug = jobreferences.identify("",open) + local set, bug = references.identify("",open) open = not bug and #set > 0 and set end if close and close ~= "" then - local set, bug = jobreferences.identify("",close) + local set, bug = references.identify("",close) close = not bug and #set > 0 and set end return open, close end --- expansion is temp hack - -local opendocument, closedocument, openpage, closepage - -local function check(what) - if what and what ~= "" then - local set, bug = jobreferences.identify("",what) - return not bug and #set > 0 and set - end -end - -function jobreferences.checkopendocumentactions (open) opendocument = check(open) end -function jobreferences.checkclosedocumentactions(close) closedocument = check(close) end -function jobreferences.checkopenpageactions (open) openpage = check(open) end -function jobreferences.checkclosepageactions (close) closepage = check(close) end - -function jobreferences.flushdocumentactions() - if opendocument or closedocument then - backends.codeinjections.flushdocumentactions(opendocument,closedocument) -- backend - end -end -function jobreferences.flushpageactions() - if openpage or closepage then - backends.codeinjections.flushpageactions(openpage,closepage) -- backend - end -end - -- end temp hack statistics.register("interactive elements", function() @@ -527,7 +566,7 @@ statistics.register("interactive elements", function() end end) -function jobreferences.enable_interaction() - tasks.enableaction("shipouts","nodes.add_references") - tasks.enableaction("shipouts","nodes.add_destinations") +function references.enableinteraction() + tasks.enableaction("shipouts","nodes.references.handler") + tasks.enableaction("shipouts","nodes.destinations.handler") end |