diff options
Diffstat (limited to 'tex/context/base/node-ref.lua')
-rw-r--r-- | tex/context/base/node-ref.lua | 191 |
1 files changed, 141 insertions, 50 deletions
diff --git a/tex/context/base/node-ref.lua b/tex/context/base/node-ref.lua index 78ef409bc..4c04e5ea7 100644 --- a/tex/context/base/node-ref.lua +++ b/tex/context/base/node-ref.lua @@ -32,9 +32,9 @@ local colors = attributes.colors local references = structures.references local tasks = nodes.tasks -local trace_backend = false trackers.register("nodes.backend", function(v) trace_backend = v end) 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 trace_areas = false trackers.register("nodes.areas", function(v) trace_areas = v end) local report_reference = logs.reporter("backend","references") local report_destination = logs.reporter("backend","destinations") @@ -57,6 +57,7 @@ local setattr = nuts.setattr local getsubtype = nuts.getsubtype local hpack_list = nuts.hpack +local vpack_list = nuts.vpack local list_dimensions = nuts.dimensions local traverse = nuts.traverse local find_node_tail = nuts.tail @@ -69,6 +70,8 @@ local listcodes = nodes.listcodes local hlist_code = nodecodes.hlist local vlist_code = nodecodes.vlist local glue_code = nodecodes.glue +local glyph_code = nodecodes.glyph +local rule_code = nodecodes.rule local whatsit_code = nodecodes.whatsit local leftskip_code = skipcodes.leftskip @@ -83,68 +86,145 @@ local line_code = listcodes.line local new_rule = nodepool.rule local new_kern = nodepool.kern +local free_node = nuts.free + local tosequence = nodes.tosequence --- local function dimensions(parent,start,stop) --- stop = stop and getnext(stop) --- if parent then --- if stop then --- return list_dimensions(getfield(parent,"glue_set"),getfield(parent,"glue_sign"),getfield(parent,"glue_order"),start,stop) --- else --- return list_dimensions(getfield(parent,"glue_set"),getfield(parent,"glue_sign",getfield(parent,"glue_order"),start) --- end --- else --- if stop then --- return list_dimensions(start,stop) --- else --- return list_dimensions(start) --- end --- end --- end --- --- -- more compact +-- Normally a (destination) area is a box or a simple stretch if nodes but when it is +-- a paragraph we hav ea problem: we cannot calculate the height well. This happens +-- with footnotes or content broken across a page. + +local function vlist_dimensions(start,stop) + local temp + if stop then + temp = getnext(stop) + setfield(stop,"next",nil) + end + local v = vpack_list(start) + local w = getfield(v,"width") + local h = getfield(v,"height") + local d = getfield(v,"depth") + setfield(v,"list",nil) + free_node(v) + if temp then + setfield(stop,"next",temp) + end + return w, h, d +end -local function dimensions(parent,start,stop) +local function hlist_dimensions(start,stop,parent) + local last = stop and getnext(stop) if parent then - return list_dimensions(getfield(parent,"glue_set"),getfield(parent,"glue_sign"),getfield(parent,"glue_order"),start,stop and getnext(stop)) + return list_dimensions(getfield(parent,"glue_set"),getfield(parent,"glue_sign"),getfield(parent,"glue_order"),start,last) + else + return list_dimensions(start,last) + end +end + +local function dimensions(parent,start,stop) -- in principle we could move some to the caller + local id = getid(start) + if start == stop then + if id == hlist_code or id == vlist_code or id == glyph_code or id == rule_code then -- or image + if trace_areas then + report_area("dimensions taken of %a",nodecodes[id]) + end + return getfield(start,"width"), getfield(parent,"height"), getfield(parent,"depth") + else + if trace_areas then + report_area("dimensions calculated of %a",nodecodes[id]) + end + return hlist_dimensions(start,stop) -- one node only so simple + end + end + local last = stop and getnext(stop) + if parent then + -- todo: if no prev and no next and parent + -- todo: we need a a list_dimensions for a vlist + if getid(parent) == vlist_code then + local l = getlist(parent) + local c = l + local ok = false + while c do + if c == start then + ok = true + end + if ok and getid(c) == hlist_code then + break + else + c = getnext(c) + end + end + if ok and c then + if trace_areas then + report_area("dimensions taken of first line in vlist") + end + return getfield(c,"width"), getfield(c,"height"), getfield(c,"depth"), c + else + if trace_areas then + report_area("dimensions taken of vlist (probably wrong)") + end + return hlist_dimensions(start,stop,parent) + end + else + if trace_areas then + report_area("dimensions taken of range starting with %a using parent",nodecodes[id]) + end + return hlist_dimensions(start,stop,parent) + end else - return list_dimensions(start,stop and getnext(stop)) + if trace_areas then + report_area("dimensions taken of range starting with %a",nodecodes[id]) + end + return hlist_dimensions(start,stop) end end -- is pardir important at all? local function inject_range(head,first,last,reference,make,stack,parent,pardir,txtdir) - local width, height, depth = dimensions(parent,first,last) + local width, height, depth, line = dimensions(parent,first,last) if txtdir == "+TRT" or (txtdir == "===" and pardir == "TRT") then -- KH: textdir == "===" test added width = - width end local result, resolved = make(width,height,depth,reference) if result and resolved then - if head == first then - if trace_backend then - report_area("%s: %04i %s %s %s => w=%p, h=%p, d=%p, c=%S","head", - reference,pardir or "---",txtdir or "---",tosequence(first,last,true),width,height,depth,resolved) + if line then + -- special case, we only treat the first line in a vlist + local l = getlist(line) + if trace_areas then + report_area("%s: %04i %s %s %s => w=%p, h=%p, d=%p, c=%S","line", + reference,pardir or "---",txtdir or "---",tosequence(l,nil,true),width,height,depth,resolved) end - setfield(result,"next",first) - setfield(first,"prev",result) - return result, last + setfield(line,"list",result) + setfield(result,"next",l) + setfield(l,"prev",result) + return head, last else - if trace_backend then - report_area("%s: %04i %s %s %s => w=%p, h=%p, d=%p, c=%S","middle", - reference,pardir or "---",txtdir or "---",tosequence(first,last,true),width,height,depth,resolved) - end - local prev = getprev(first) - if prev then - setfield(prev,"next",result) - setfield(result,"prev",prev) + if head == first then + if trace_areas then + report_area("%s: %04i %s %s %s => w=%p, h=%p, d=%p, c=%S","head", + reference,pardir or "---",txtdir or "---",tosequence(first,last,true),width,height,depth,resolved) + end + setfield(result,"next",first) + setfield(first,"prev",result) + return result, last + else + if trace_areas then + report_area("%s: %04i %s %s %s => w=%p, h=%p, d=%p, c=%S","middle", + reference,pardir or "---",txtdir or "---",tosequence(first,last,true),width,height,depth,resolved) + end + local prev = getprev(first) + if prev then + setfield(prev,"next",result) + setfield(result,"prev",prev) + end + setfield(result,"next",first) + setfield(first,"prev",result) + -- if first == getnext(head) then + -- setfield(head,"next",result) -- hm, weird + -- end + return head, last end - setfield(result,"next",first) - setfield(first,"prev",result) --- if first == getnext(head) then --- setfield(head,"next",result) -- hm, weird --- end - return head, last end else return head, last @@ -152,9 +232,12 @@ local function inject_range(head,first,last,reference,make,stack,parent,pardir,t end local function inject_list(id,current,reference,make,stack,pardir,txtdir) - local width, height, depth, correction = getfield(current,"width"), getfield(current,"height"), getfield(current,"depth"), 0 - local moveright = false - local first = getlist(current) + local width = getfield(current,"width") + local height = getfield(current,"height") + local depth = getfield(current,"depth") + local correction = 0 + local moveright = false + local first = getlist(current) 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) @@ -193,7 +276,7 @@ local function inject_list(id,current,reference,make,stack,pardir,txtdir) local result, resolved = make(width,height,depth,reference) -- todo: only when width is ok if result and resolved then - if trace_backend then + if trace_areas then report_area("%s: %04i %s %s %s: w=%p, h=%p, d=%p, c=%S","box", reference,pardir or "---",txtdir or "----","[]",width,height,depth,resolved) end @@ -227,6 +310,11 @@ local function inject_areas(head,attribute,make,stack,done,skip,parent,pardir,tx while current do local id = getid(current) if id == hlist_code or id == vlist_code then + + -- see dimensions: this is tricky with split off boxes like inserts + -- where we can end up with a first and last spanning lines + + local r = getattr(current,attribute) -- test \goto{test}[page(2)] test \gotobox{test}[page(2)] -- test \goto{\TeX}[page(2)] test \gotobox{\hbox {x} \hbox {x}}[page(2)] @@ -432,7 +520,7 @@ local function makereference(width,height,depth,reference) -- height and depth a -- step = 0 local annot = nodeinjections.reference(width,height,depth,set) if annot then -annot = tonut(annot) + annot = tonut(annot) -- todo nofreferences = nofreferences + 1 local result, current if trace_references then @@ -581,12 +669,15 @@ function references.mark(reference,h,d,view) end function references.inject(prefix,reference,h,d,highlight,newwindow,layer) -- todo: use currentreference is possible +-- print(prefix,reference,h,d,highlight,newwindow,layer) 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 -- check - set.highlight, set.newwindow, set.layer = highlight, newwindow, layer + set.highlight = highlight + set.newwindow = newwindow + set.layer = layer setreference(h,d,set) -- sets attribute / todo: for set[*].error end end |