diff options
Diffstat (limited to 'tex/context/base/mkiv/supp-box.lmt')
-rw-r--r-- | tex/context/base/mkiv/supp-box.lmt | 314 |
1 files changed, 201 insertions, 113 deletions
diff --git a/tex/context/base/mkiv/supp-box.lmt b/tex/context/base/mkiv/supp-box.lmt index cee5cf1ad..95af07d9f 100644 --- a/tex/context/base/mkiv/supp-box.lmt +++ b/tex/context/base/mkiv/supp-box.lmt @@ -943,38 +943,62 @@ implement { do - local scaninteger = tokens.scanners.integer - local scanbox = tokens.scanners.box - local scandimen = tokens.scanners.dimen + local scaninteger = tokens.scanners.integer + local scanbox = tokens.scanners.box + local scandimen = tokens.scanners.dimen - local setsubtype = nuts.setsubtype - local removenode = nuts.remove - local getnormalizedline = nuts.getnormalizedline -- we can optimize this + local setsubtype = nuts.setsubtype + local removenode = nuts.remove + local getnormalizedline = nuts.getnormalizedline -- we can optimize this + local getdimensions = nuts.dimensions + local getrangedimensions = nuts.rangedimensions - local line_code = nodes.listcodes.line - local unknown_code = nodes.listcodes.unknown + local setprop = nuts.setprop + local getprop = nuts.getprop - local values = tokens.values - local dimension_value = values.dimension - local cardinal_value = values.cardinal - local list_value = values.list + local line_code = nodes.listcodes.line + local unknown_code = nodes.listcodes.unknown - local function boxlinecount(what) - local box = scaninteger() - local list = getbox(box) - local line = 0 - if list then - list = getlist(list) + local values = tokens.values + local dimension_value = values.dimension + local cardinal_value = values.cardinal + local list_value = values.list + + -- todo: make helper that formats + + local function reporterror(fmt,...) + tex.error(string.formatters[fmt](...)) + end + + -- The first variant did a linear lookup but for large boxes and lots of + -- analysis that is not nice. Okay, in practice performance is quite ok + -- (milliseconds for thousands of access) but still ... the next is nicer + -- and it's part of the experimental fun stuff anyway. + + local function countlines(box) + local prop = getprop(box,"boxlines") + if not prop then + local line = 0 + local list = getlist(box) + prop = { } if list then for n, subtype in nexthlist, list do if subtype == line_code then line = line + 1 + prop[line] = n end end end + setprop(box,"boxlines",prop) end + return prop + end + + local function boxlinecount(what) + local n = scaninteger() + local box = getbox(n) if what == "value" then - return cardinal_value, line + return cardinal_value, box and #countlines(box) or 0 end end @@ -983,32 +1007,62 @@ do local line = scaninteger() local box = getbox(n) if box then - local list = getlist(box) - if list then - for n, subtype in nexthlist, list do - if subtype == line_code then - if line == 1 then - return n, list, box - else - line = line - 1 - end + local prop = getprop(box,"boxlines") + if not prop then + prop = countlines(box) + end + local found = prop[line] + if found then + local props = getprop(found,"lineproperties") + if not props then + props = getnormalizedline(found) + props.width, props.height, props.depth = getwhd(found) + setprop(found,"lineproperties",props) + end + return props, line, found, box + end + end + reporterror("no line %i in box %i",line,n) + end + + local function findrange() + local n = scaninteger() + local first = scaninteger() + local last = scaninteger() + local box = getbox(n) + if box then + local prop = getprop(box,"boxlines") + if not prop then + prop = countlines(box) + end + if first > 0 and last <= #prop then + for i = first, last do + local found = prop[i] + local props = getprop(found,"lineproperties") + if not props then + props = getnormalizedline(found) + props.width, props.height, props.depth = getwhd(found) + setprop(found,"lineproperties",props) end end + return prop, first, last, box end end + reporterror("no lines %i - %i in box %i",first,last,n) end - local function getline(found,list,box,value) + local function getline(props,line,found,box,value) local p, n = getboth(found) local temp = new_hlist() setsubtype(temp,line_code) setwhd(temp,getwhd(found)) - if found == list then + if found == getlist(box) then setlink(temp,n) setlist(box,temp) else setlink(p,temp,n) end + getprop(box,"boxlines")[line] = temp setboth(found) setsubtype(found, unknown_code) found = tonode(found) @@ -1019,9 +1073,8 @@ do end end - local function copyline(found,list,box,value) - local p, n = getboth(found) - found = copy_list(found) + local function copyline(props,line,found,box,value) + found = copy_node(found) setsubtype(found, unknown_code) found = tonode(found) if value then @@ -1031,118 +1084,153 @@ do end end - local function setline(found,list,box) + local function setline(props,line,found,box) local p, n = getboth(found) local temp = scanbox() if temp then temp = tonut(temp) - if found == list then + if found == getlist(box) then setlink(temp,n) setlist(box,temp) else setlink(p,temp,n) end flush_node(found) + getprop(box,"boxlines")[line] = temp + end + end + + local function naturaldimensions(p,l,found) + if not p.naturalwidth then + p.naturalwidth, p.naturalheight, p.naturaldepth = getdimensions(getlist(found)) end + return p + end + + local function rangedimensions(p,f,l,box) + local w, h, d = getrangedimensions(box,p[f],getnext(p[l]),true) + return { width = w, height = h, depth = d } end - local getters = { - ["wd"] = function(found) return dimension_value, getwidth (found) end, - ["ht"] = function(found) return dimension_value, getheight(found) end, - ["dp"] = function(found) return dimension_value, getdepth (found) end, - ["ls"] = function(found) return dimension_value, getnormalizedline(found).leftskip end, - ["rs"] = function(found) return dimension_value, getnormalizedline(found).rightskip end, - ["lh"] = function(found) return dimension_value, getnormalizedline(found).lefthangskip end, - ["rh"] = function(found) return dimension_value, getnormalizedline(found).righthangskip end, - ["lp"] = function(found) return dimension_value, getnormalizedline(found).parfillleftskip end, - ["rp"] = function(found) return dimension_value, getnormalizedline(found).parfillrightskip end, - ["in"] = function(found) return dimension_value, getnormalizedline(found).indent end, - ["get"] = function(found,list,box) return getline(found,list,box,true) end, + + local getters_one = { + + ["wd"] = function(p,l,found) return dimension_value, p.width end, + ["ht"] = function(p,l,found) return dimension_value, p.height end, + ["dp"] = function(p,l,found) return dimension_value, p.depth end, + ["ls"] = function(p,l,found) return dimension_value, p.leftskip end, + ["rs"] = function(p,l,found) return dimension_value, p.rightskip end, + ["lh"] = function(p,l,found) return dimension_value, p.lefthangskip end, + ["rh"] = function(p,l,found) return dimension_value, p.righthangskip end, + ["lp"] = function(p,l,found) return dimension_value, p.parfillleftskip end, + ["rp"] = function(p,l,found) return dimension_value, p.parfillrightskip end, + ["in"] = function(p,l,found) return dimension_value, p.indent end, + + ["nw"] = function(p,l,found) return dimension_value, naturaldimensions(p,l,found).naturalwidth end, + ["nh"] = function(p,l,found) return dimension_value, naturaldimensions(p,l,found).naturalheigth end, + ["nd"] = function(p,l,found) return dimension_value, naturaldimensions(p,l,found).naturaldepth end, + + ["get"] = function(p,l,found,box) return getline(p,l,found,box,true) end, } - local setters = { - ["wd"] = function(found) return setwidth (found,scandimen(false,false,true)) end, - ["ht"] = function(found) return setheight(found,scandimen(false,false,true)) end, - ["dp"] = function(found) return setdepth (found,scandimen(false,false,true)) end, + local getters_two = { + ["wd"] = function(p,f,l,box) return dimension_value, rangedimensions(p,f,l,box).width end, + ["ht"] = function(p,f,l,box) return dimension_value, rangedimensions(p,f,l,box).height end, + ["dp"] = function(p,f,l,box) return dimension_value, rangedimensions(p,f,l,box).depth end, + } + + local setters_one = { + ["wd"] = function(p,l,found) return setwidth (found,scandimen(false,false,true)) end, + ["ht"] = function(p,l,found) return setheight(found,scandimen(false,false,true)) end, + ["dp"] = function(p,l,found) return setdepth (found,scandimen(false,false,true)) end, ["set"] = setline, ["get"] = getline, ["copy"] = copyline, } - local report = logs.reporter("tex", "boxlines") - local function boxline(name,what) - local found, list, box = findline() + local props, line, found, box = findline() if not found then - report("invalid box line specification, pass box number and line number") + -- elseif what == "value" then - local getter = getters[name] + local getter = getters_one[name] if getter then - return getter(found,list,box) + return getter(props,line,found,box) end else - local setter = setters[name] + local setter = setters_one[name] if setter then - return setter(found,list,box) + return setter(props,line,found,box) end end end + -- + + local function boxrange(name,what) + local prop, first, last, box = findrange() + if not prop then + -- + elseif what == "value" then + local getter = getters_two[name] + if getter then + return getter(prop,first,last,box) + end + else + local setter = setters_two[name] + if setter then + return setter(prop,first,last,box) + end + end + end + + local function define_one(name,action) + implement { + name = name, + public = true, + protected = true, + value = true, + actions = function(what) return boxline(action,what) end, + } + end + + local function define_two(name,action) + implement { + name = name, + public = true, + protected = true, + value = true, + actions = function(what) return boxrange(action,what) end, + } + end + implement { - name = "boxlines", public = true, protected = true, value = true, - actions = boxlinecount, - } - implement { - name = "boxline", public = true, protected = true, value = true, - actions = function(what) return boxline("get",what) end, - } - implement { - name = "setboxline", public = true, protected = true, value = true, - actions = function(what) return boxline("set",what) end, - } - implement { - name = "copyboxline", public = true, protected = true, value = true, - actions = function(what) return boxline("copy",what) end, - } - implement { - name = "boxlineht", public = true, protected = true, value = true, - actions = function(what) return boxline("ht",what) end, - } - implement { - name = "boxlinedp", public = true, protected = true, value = true, - actions = function(what) return boxline("dp",what) end, - } - implement { - name = "boxlinewd", public = true, protected = true, value = true, - actions = function(what) return boxline("wd",what) end, - } - implement { - name = "boxlinels", public = true, protected = true, value = true, - actions = function(what) return boxline("ls",what) end, - } - implement { - name = "boxliners", public = true, protected = true, value = true, - actions = function(what) return boxline("rs",what) end, - } - implement { - name = "boxlinelh", public = true, protected = true, value = true, - actions = function(what) return boxline("lh",what) end, - } - implement { - name = "boxlinerh", public = true, protected = true, value = true, - actions = function(what) return boxline("rh",what) end, - } - implement { - name = "boxlinelp", public = true, protected = true, value = true, - actions = function(what) return boxline("lp",what) end, - } - implement { - name = "boxlinerp", public = true, protected = true, value = true, - actions = function(what) return boxline("rp",what) end, - } - implement { - name = "boxlinein", public = true, protected = true, value = true, - actions = function(what) return boxline("in",what) end, + name = "boxlines", + public = true, + protected = true, + value = true, + actions = boxlinecount, } + define_one("boxline", "get") + define_one("setboxline", "set") + define_one("copyboxline", "copy") + define_one("boxlineht", "ht") + define_one("boxlinedp", "dp") + define_one("boxlinewd", "wd") + define_one("boxlinels", "ls") + define_one("boxliners", "rs") + define_one("boxlinelh", "lh") + define_one("boxlinerh", "rh") + define_one("boxlinelp", "lp") + define_one("boxlinerp", "rp") + define_one("boxlinein", "in") + define_one("boxlinenw", "nw") + define_one("boxlinenh", "nh") + define_one("boxlinend", "nd") + + define_two("boxrangewd", "wd") + define_two("boxrangeht", "ht") + define_two("boxrangedp", "dp") + end |