summaryrefslogtreecommitdiff
path: root/tex/context/base/mkiv/driv-shp.lmt
diff options
context:
space:
mode:
Diffstat (limited to 'tex/context/base/mkiv/driv-shp.lmt')
-rw-r--r--tex/context/base/mkiv/driv-shp.lmt1361
1 files changed, 1361 insertions, 0 deletions
diff --git a/tex/context/base/mkiv/driv-shp.lmt b/tex/context/base/mkiv/driv-shp.lmt
new file mode 100644
index 000000000..2e9751b9c
--- /dev/null
+++ b/tex/context/base/mkiv/driv-shp.lmt
@@ -0,0 +1,1361 @@
+if not modules then modules = { } end modules ['driv-shp'] = {
+ version = 1.001,
+ optimize = true,
+ comment = "companion to driv-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local type, next = type, next
+local round = math.round
+
+local setmetatableindex = table.setmetatableindex
+local formatters = string.formatters
+local concat = table.concat
+local keys = table.keys
+local sortedhash = table.sortedhash
+local splitstring = string.split
+local idiv = number.idiv
+local extract = bit32.extract
+local nuts = nodes.nuts
+
+local tonut = nodes.tonut
+local tonode = nodes.tonode
+
+local getdirection = nuts.getdirection
+local getlist = nuts.getlist
+local getoffsets = nuts.getoffsets
+local getorientation = nuts.getorientation
+local getfield = nuts.getfield
+local getwhd = nuts.getwhd
+local getkern = nuts.getkern
+local getheight = nuts.getheight
+local getdepth = nuts.getdepth
+----- getwidth = nuts.getwidth
+local getnext = nuts.getnext
+local getsubtype = nuts.getsubtype
+local getid = nuts.getid
+local getleader = nuts.getleader
+----- getglue = nuts.getglue
+local getshift = nuts.getshift
+local getdata = nuts.getdata
+----- getexpansion = nuts.getexpansion
+local getreplace = nuts.getreplace
+local setreplace = nuts.setreplace
+local getfont = nuts.getfont
+
+local setdirection = nuts.setdirection
+local setfield = nuts.setfield
+local setlink = nuts.setlink
+
+local isglyph = nuts.isglyph
+local findtail = nuts.tail
+local nextdir = nuts.traversers.dir
+local nextnode = nuts.traversers.node
+
+local rangedimensions = node.direct.rangedimensions -- nuts ?
+local effectiveglue = nuts.effective_glue
+local start_of_par = nuts.start_of_par
+local dirdimensions = nuts.dirdimensions
+
+local texget = tex.get
+
+local fonthashes = fonts.hashes
+local fontdata = fonthashes.identifiers
+local characters = fonthashes.characters
+local parameters = fonthashes.parameters
+
+local nodecodes = nodes.nodecodes
+local whatsitcodes = nodes.whatsitcodes
+local leadercodes = nodes.leadercodes
+local gluecodes = nodes.gluecodes
+local dircodes = nodes.dircodes
+local dirvalues = nodes.dirvalues
+local subtypes = nodes.subtypes
+
+local normaldir_code = dircodes.normal
+
+local lefttoright_code = dirvalues.lefttoright
+local righttoleft_code = dirvalues.righttoleft
+
+local glyph_code = nodecodes.glyph
+local kern_code = nodecodes.kern
+local glue_code = nodecodes.glue
+local hlist_code = nodecodes.hlist
+local vlist_code = nodecodes.vlist
+local dir_code = nodecodes.dir
+local disc_code = nodecodes.disc
+local math_code = nodecodes.math
+local rule_code = nodecodes.rule
+local whatsit_code = nodecodes.whatsit
+----- penalty_code = nodecodes.penalty
+----- boundary_code = nodecodes.boundary
+
+local leaders_code = leadercodes.leaders
+local cleaders_code = leadercodes.cleaders
+local xleaders_code = leadercodes.xleaders
+local gleaders_code = leadercodes.gleaders
+
+local spaceskip_code = gluecodes.spaceskip
+
+local saveposwhatsit_code = whatsitcodes.savepos
+local userdefinedwhatsit_code = whatsitcodes.userdefined
+local openwhatsit_code = whatsitcodes.open
+local writewhatsit_code = whatsitcodes.write
+local closewhatsit_code = whatsitcodes.close
+local lateluawhatsit_code = whatsitcodes.latelua
+local literalwhatsit_code = whatsitcodes.literal
+local setmatrixwhatsit_code = whatsitcodes.setmatrix
+local savewhatsit_code = whatsitcodes.save
+local restorewhatsit_code = whatsitcodes.restore
+
+local getpagedimensions getpagedimensions = function()
+ getpagedimensions = backends.codeinjections.getpagedimensions
+ return getpagedimensions()
+end
+
+local drivers = drivers
+local instances = drivers.instances
+
+local report = logs.reporter("drivers")
+
+---------------------------------------------------------------------------------------
+
+local lastfont = nil
+local fontcharacters = nil
+
+local magicconstants = tex.magicconstants
+local trueinch = magicconstants.trueinch
+local maxdimen = magicconstants.maxdimen
+local running = magicconstants.running
+
+local pos_h = 0
+local pos_v = 0
+local pos_r = lefttoright_code
+local shippingmode = "none"
+
+local abs_max_v = 0
+local abs_max_h = 0
+
+local shipbox_h = 0
+local shipbox_v = 0
+local page_size_h = 0
+local page_size_v = 0
+----- page_h_origin = 0 -- trueinch
+----- page_v_origin = 0 -- trueinch
+
+local initialize
+local finalize
+local updatefontstate
+local pushorientation
+local poporientation
+local flushcharacter
+local flushfontchar
+local flushrule
+local flushliteral
+local flushsetmatrix
+local flushsave
+local flushrestore
+local flushspecial
+----- flushimage
+
+-- make local
+
+function drivers.getpos () return round(pos_h), round(pos_v) end
+function drivers.getrpos() return round(pos_h), round(pos_v), pos_r end
+function drivers.gethpos() return round(pos_h) end
+function drivers.getvpos() return round(pos_v) end
+
+-- characters
+
+local flush_character
+
+local stack = setmetatableindex("table")
+local level = 0
+local nesting = 0
+local main = 0
+
+-- experiment (smaller page stream but might be fragile)
+
+local tospace = false directives.register("backends.spaces", function(v) tospace = v end)
+
+-- todo: cache streams
+
+local default = 16384 * number.dimenfactors.bp -- 65536 // 4
+
+local function flush_vf_packet(pos_h,pos_v,pos_r,font,char,data,factor,vfcommands)
+
+ if nesting > 100 then
+ return
+ elseif nesting == 0 then
+ main = font
+ end
+
+ nesting = nesting + 1
+
+ local saved_h = pos_h
+ local saved_v = pos_v
+ local saved_r = pos_r
+ pos_r = lefttoright_code
+
+ local data = fontdata[font]
+ local fnt = font
+ local fonts = data.fonts
+ local siz = (data.parameters.factor or 1)/65536
+
+ local function flushchar(font,char,fnt,chr,f,e)
+ if fnt then
+ local nest = char ~= chr or font ~= fnt
+ if fnt == 0 then
+ fnt = main
+ end
+ return flush_character(false,fnt,chr,factor,nest,pos_h,pos_v,pos_r,f,e)
+ else
+ return 0
+ end
+ end
+
+ -- we assume resolved fonts: id mandate but maybe also size
+
+ for i=1,#vfcommands do
+ local packet = vfcommands[i]
+ local command = packet[1]
+ if command == "char" then
+ local chr = packet[2]
+ local f = packet[3]
+ local e = packet[4]
+ pos_h = pos_h + flushchar(font,char,fnt,chr,f,e)
+ elseif command == "slot" then
+ local index = packet[2]
+ local chr = packet[3]
+ local f = packet[4]
+ local e = packet[5]
+ if index == 0 then
+ pos_h = pos_h + flushchar(font,char,font,chr,f,e)
+ else
+ local okay = fonts and fonts[index]
+ if okay then
+ local fnt = okay.id
+ if fnt then
+ pos_h = pos_h + flushchar(font,char,fnt,chr,f,e)
+ end
+ else
+ -- safeguard, we assume the font itself (often index 1)
+ pos_h = pos_h + flushchar(font,char,font,chr,f,e)
+ end
+ end
+ elseif command == "use" then
+ local index = packet[2]
+ if index then
+ local fnt
+ if index == 0 then
+ fnt = font
+ else
+ local okay = fonts and fonts[index]
+ if okay then
+ fnt = okay.id
+ end
+ end
+ if fnt then
+ -- not efficient but ok for now as experiment
+ local d = characters[fnt]
+ if d then
+ for i=3,#packet do
+ local chr = packet[i]
+ local dat = d[chr]
+ if dat then
+ flushfontchar(fnt,chr,dat)
+ end
+ end
+ end
+ end
+ end
+ elseif command == "right" then
+ local h = packet[2] * siz -- * siz is really needed for boldening
+ if factor ~= 0 and h ~= 0 then
+ h = h + h * factor / 1000 -- expansion
+ end
+ pos_h = pos_h + h
+ elseif command == "down" then
+ local v = packet[2] * siz -- * siz is really needed for boldening
+ pos_v = pos_v - v
+ elseif command == "push" then
+ level = level + 1
+ local s = stack[level]
+ s[1] = pos_h
+ s[2] = pos_v
+ elseif command == "pop" then
+ if level > 0 then
+ local s = stack[level]
+ pos_h = s[1]
+ pos_v = s[2]
+ level = level - 1
+ end
+ elseif command == "pdf" then
+ flushliteral(false,pos_h,pos_v,packet[2],packet[3])
+ elseif command == "rule" then
+ local size_v = packet[2]
+ local size_h = packet[3]
+ if size_h > 0 and size_v > 0 then
+ if factor ~= 0 then
+ size_h = size_h + size_h * factor / 1000
+ end
+ if size_h > 0 then
+ flushsimplerule(pos_h,pos_v,pos_r,size_h,size_v)
+ pos_h = pos_h + size_h
+ end
+ end
+ elseif command == "frame" then
+ local width = packet[2]
+ if width > 0 then
+ local height = packet[3] or 0
+ local depth = packet[4] or 0
+ local total = height + depth
+ if total > 0 then
+ if factor ~= 0 then
+ width = width + width * factor / 1000
+ end
+ if width > 0 then
+ local line = packet[5] or default
+ local outline = not packet[6]
+ local advance = not packet[7]
+ flushspecialrule(pos_h,pos_v,pos_r,width,height,depth,line,outline)
+ if advance then
+ pos_h = pos_h + width
+ end
+ end
+ end
+ end
+ elseif command == "font" then
+ local index = packet[2]
+ local okay = fonts and fonts[index]
+ if okay then
+ fnt = okay.id or fnt -- or maybe just return
+ end
+ elseif command == "lua" then
+ local code = packet[2]
+ if type(code) ~= "function" then
+ code = loadstring(code)
+ end
+ if type(code) == "function" then
+ code(font,char,pos_h,pos_v)
+ end
+ elseif command == "node" then
+ local h = packet[2]
+ hlist_out(h,getlist(h))
+ elseif command == "image" then
+ -- doesn't work because intercepted by engine so we use a different
+ -- mechanism (for now)
+ local image = packet[2]
+ -- to do
+ elseif command == "pdfmode" then
+ -- doesn't happen
+ -- elseif command == "special" then
+ -- -- not supported
+ -- elseif command == "nop" then
+ -- -- nothing to do|
+ -- elseif command == "scale" then
+ -- -- not supported
+ end
+ end
+
+ pos_h = saved_h
+ pos_v = saved_v
+ pos_r = saved_r
+
+ nesting = nesting - 1
+end
+
+local onetimemessage -- could be defined later (todo: make plug for this)
+
+flush_character = function(current,font,char,factor,vfcommands,pos_h,pos_v,pos_r,f,e)
+
+ if font ~= lastfont then
+ lastfont = font
+ fontcharacters = characters[font]
+ updatefontstate(font)
+ end
+
+ local data = fontcharacters[char]
+ if not data then
+ if char > 0 then
+ if not onetimemessage then
+ onetimemessage = fonts.loggers.onetimemessage
+ end
+ onetimemessage(font,char,"missing")
+ end
+ return 0, 0, 0
+ end
+ if vfcommands then
+ vfcommands = data.commands
+ end
+ local width, height, depth, naturalwidth
+ if current then
+ naturalwidth, height, depth, factor = getwhd(current,true) -- also get corrected width
+ if factor == 0 then
+ width = naturalwidth
+ else
+ -- width = (1.0 + factor/1000000.0) * naturalwidth
+ width = naturalwidth + naturalwidth * factor/1000000.0
+ -- width = naturalwidth + naturalwidth * 0.000001 * factor
+ end
+ else
+ width = data.width or 0
+ height = data.height or 0
+ depth = data.depth or 0
+ naturalwidth = width
+ if not factor then
+ factor = 0
+ end
+ end
+ if pos_r == righttoleft_code then
+ pos_h = pos_h - width -- here ?
+ end
+ if vfcommands then
+ flush_vf_packet(pos_h,pos_v,pos_r,font,char,data,factor,vfcommands) -- also f ?
+ else
+ -- kind of messy that we do orientation here and offsets elsewhere
+ local orientation = data.orientation
+ if orientation and (orientation == 1 or orientation == 3) then
+ local x = data.xoffset
+ local y = data.yoffset
+ if x then
+ pos_h = pos_h + x
+ end
+ if y then
+ pos_v = pos_v + y
+ end
+ pushorientation(orientation,pos_h,pos_v)
+ flushcharacter(current,pos_h,pos_v,pos_r,font,char,data,f,e,factor) -- ,naturalwidth,width)
+ poporientation(orientation,pos_h,pos_v)
+ else
+ flushcharacter(current,pos_h,pos_v,pos_r,font,char,data,f,e,factor) -- ,naturalwidth,width)
+ end
+ end
+ return width, height, depth
+end
+
+-- end of characters
+
+local function reset_state()
+ pos_h = 0
+ pos_v = 0
+ pos_r = lefttoright_code
+ shipbox_h = 0
+ shipbox_v = 0
+ shippingmode = "none"
+ page_size_h = 0
+ page_size_v = 0
+ -- page_h_origin = 0 -- trueinch
+ -- page_v_origin = 0 -- trueinch
+end
+
+-- local function dirstackentry(t,k)
+-- local v = {
+-- cur_h = 0,
+-- cur_v = 0,
+-- ref_h = 0,
+-- ref_v = 0,
+-- }
+-- t[k] = v
+-- return v
+-- end
+--
+-- local dirstack = setmetatableindex(dirstackentry)
+--
+-- local function reset_dir_stack()
+-- dirstack = setmetatableindex(dirstackentry)
+-- end
+
+local dirstack = { }
+
+local function reset_dir_stack()
+ dirstack = { }
+end
+
+local leaderlevel = 0
+
+local function flushlatelua(current,h,v)
+ -- Here we assume maganement by the lua function so currently we don't
+ -- check for leaderlevel.
+ return backends.latelua(current,h,v)
+end
+
+local function flushwriteout(current)
+ if leaderlevel == 0 then
+ backends.writeout(current)
+ end
+end
+
+local function flushopenout(current)
+ if leaderlevel == 0 then
+ backends.openout(current)
+ end
+end
+
+local function flushcloseout(current)
+ if leaderlevel == 0 then
+ backends.closeout(current)
+ end
+end
+
+local hlist_out, vlist_out do
+
+ local function applyanchor(orientation,x,y,width,height,depth,woffset,hoffset,doffset,xoffset,yoffset)
+ local ot = extract(orientation, 0,4)
+ local ay = extract(orientation, 4,4)
+ local ax = extract(orientation, 8,4)
+ local of = extract(orientation,12,4)
+ if ot == 4 then
+ ot, ay = 0, 1
+ elseif ot == 5 then
+ ot, ay = 0, 2
+ end
+ if ot == 0 or ot == 2 then
+ if ax == 1 then x = x - width
+ elseif ax == 2 then x = x + width
+ elseif ax == 3 then x = x - width/2
+ elseif ax == 4 then x = x + width/2
+ end
+ if ot == 2 then
+ doffset, hoffset = hoffset, doffset
+ end
+ if ay == 1 then y = y - doffset
+ elseif ay == 2 then y = y + hoffset
+ elseif ay == 3 then y = y + (doffset + hoffset)/2 - doffset
+ end
+ elseif ot == 1 or ot == 3 then
+ if ay == 1 then y = y - height
+ elseif ay == 2 then y = y + height
+ elseif ay == 3 then y = y - height/2
+ end
+ if ot == 1 then
+ doffset, hoffset = hoffset, doffset
+ end
+ if ax == 1 then x = x - width
+ elseif ax == 2 then x = x + width
+ elseif ax == 3 then x = x - width/2
+ elseif ax == 4 then x = x + width/2
+ elseif ax == 5 then x = x - hoffset
+ elseif ax == 6 then x = x + doffset
+ end
+ end
+ return ot, x + xoffset, y - yoffset
+ end
+
+ -- to be checked: begin- or enddir kan nil zijn, weird
+
+ -- local function calculate_width_to_enddir(this_box,begindir) -- can be a helper
+ -- local dir_nest = 1
+ -- local enddir = begindir
+ -- for current, subtype in nextdir, getnext(begindir) do
+ -- if subtype == normaldir_code then -- todo
+ -- dir_nest = dir_nest + 1
+ -- else
+ -- dir_nest = dir_nest - 1
+ -- end
+ -- if dir_nest == 0 then -- does the type matter
+ -- enddir = current
+ -- local width = rangedimensions(this_box,begindir,enddir)
+ -- return enddir, width
+ -- end
+ -- end
+ -- if enddir == begindir then
+ -- local width = rangedimensions(this_box,begindir) -- ,enddir)
+ -- return enddir, width
+ -- end
+ -- return enddir, 0
+ -- end
+
+ -- check frequencies of nodes
+
+ hlist_out = function(this_box,current)
+ local ref_h = pos_h
+ local ref_v = pos_v
+ local ref_r = pos_r
+ pos_r = getdirection(this_box)
+ local boxwidth,
+ boxheight,
+ boxdepth = getwhd(this_box)
+
+ local cur_h = 0
+ local cur_v = 0
+
+ -- if not current then
+ -- current = getlist(this_box)
+ -- end
+
+ -- we can encounter localpar, boundary and penalty nodes but a special
+ -- iterator over content nodes won't save much
+
+ for current, id, subtype in nextnode, current do
+ if id == glyph_code then
+ local char, font = isglyph(current)
+ local x_offset, y_offset = getoffsets(current)
+ if x_offset ~= 0 or y_offset ~= 0 then
+ if pos_r == righttoleft_code then
+ pos_h = ref_h - (cur_h + x_offset)
+ else
+ pos_h = ref_h + (cur_h + x_offset)
+ end
+ pos_v = ref_v - (cur_v - y_offset)
+ -- synced
+ end
+ local wd = flush_character(current,font,char,false,true,pos_h,pos_v,pos_r)
+ cur_h = cur_h + wd
+ elseif id == glue_code then
+ local gluewidth = effectiveglue(current,this_box)
+ if gluewidth ~= 0 then
+ if subtype >= leaders_code then
+ local leader = getleader(current)
+ if leader then
+ local width, height, depth = getwhd(leader)
+ if getid(leader) == rule_code then
+ if gluewidth > 0 then
+ if height == running then
+ height = boxheight
+ end
+ if depth == running then
+ depth = boxdepth
+ end
+ local total = height + depth
+ if total > 0 then
+ if pos_r == righttoleft_code then
+ pos_h = pos_h - gluewidth
+ end
+ pos_v = pos_v - depth
+ flushrule(leader,pos_h,pos_v,pos_r,gluewidth,total,getsubtype(leader))
+ end
+ cur_h = cur_h + gluewidth
+ end
+ elseif width > 0 and gluewidth > 0 then
+ local boxdir = getdirection(leader) or lefttoright_code
+ gluewidth = gluewidth + 10
+ local edge = cur_h + gluewidth
+ local lx = 0
+ if subtype == gleaders_code then
+ local save_h = cur_h
+ if pos_r == righttoleft_code then
+ cur_h = ref_h - shipbox_h - cur_h
+ cur_h = width * (cur_h / width)
+ cur_h = ref_h - shipbox_h - cur_h
+ else
+ cur_h = cur_h + ref_h - shipbox_h
+ cur_h = width * (cur_h / width)
+ cur_h = cur_h - ref_h - shipbox_h
+ end
+ if cur_h < save_h then
+ cur_h = cur_h + width
+ end
+ elseif subtype == leaders_code then
+ local save_h = cur_h
+ cur_h = width * (cur_h / width)
+ if cur_h < save_h then
+ cur_h = cur_h + width
+ end
+ else
+ lq = gluewidth / width
+ lr = gluewidth % width
+ if subtype == cleaders_code then
+ cur_h = cur_h + lr / 2
+ else
+ lx = lr / (lq + 1)
+ cur_h = cur_h + (lr - (lq - 1) * lx) / 2
+ end
+ end
+ local shift = getshift(leader)
+ leaderlevel = leaderlevel + 1
+ while cur_h + width <= edge do
+ local basepoint_h = 0
+ -- local basepoint_v = shift
+ if boxdir ~= pos_r then
+ basepoint_h = boxwidth
+ end
+ -- synch_pos_with_cur(ref_h,ref_v,cur_h + basepoint_h,shift)
+ if pos_r == righttoleft_code then
+ pos_h = ref_h - (cur_h + basepoint_h)
+ else
+ pos_h = ref_h + (cur_h + basepoint_h)
+ end
+ pos_v = ref_v - shift
+ -- synced
+ if getid(leader) == vlist_code then
+ vlist_out(leader,getlist(leader))
+ else
+ hlist_out(leader,getlist(leader))
+ end
+ cur_h = cur_h + width + lx
+ end
+ leaderlevel = leaderlevel - 1
+ cur_h = edge - 10
+ else
+ cur_h = cur_h + gluewidth
+ end
+ else
+ cur_h = cur_h + gluewidth
+ end
+ else
+ if tospace and subtype == spaceskip_code then
+ -- todo: flush_space
+ flush_character(false,getfont(current),32,false,true,pos_h,pos_v,pos_r)
+ end
+ cur_h = cur_h + gluewidth
+ end
+ end
+ elseif id == hlist_code or id == vlist_code then
+ local width, height, depth = getwhd(current)
+ local list = getlist(current)
+ if list then
+ local boxdir = getdirection(current) or lefttoright_code
+ local shift, orientation = getshift(current)
+ if not orientation then
+ local basepoint_h = boxdir ~= pos_r and width or 0
+ -- local basepoint_v = shift
+ if pos_r == righttoleft_code then
+ pos_h = ref_h - (cur_h + basepoint_h)
+ else
+ pos_h = ref_h + (cur_h + basepoint_h)
+ end
+ pos_v = ref_v - shift
+ -- synced
+ if id == vlist_code then
+ vlist_out(current,list)
+ else
+ hlist_out(current,list)
+ end
+ elseif orientation == 0x1000 then
+ local orientation, xoffset, yoffset = getorientation(current)
+ local basepoint_h = boxdir ~= pos_r and width or 0
+ -- local basepoint_v = shift
+ if pos_r == righttoleft_code then
+ pos_h = ref_h - (cur_h + basepoint_h + xoffset)
+ else
+ pos_h = ref_h + (cur_h + basepoint_h + xoffset)
+ end
+ pos_v = ref_v - (shift - yoffset)
+ -- synced
+ if id == vlist_code then
+ vlist_out(current,list)
+ else
+ hlist_out(current,list)
+ end
+ else
+ local orientation, xoffset, yoffset, woffset, hoffset, doffset = getorientation(current)
+ local orientation, basepoint_h, basepoint_v = applyanchor(orientation,0,shift,width,height,depth,woffset,hoffset,doffset,xoffset,yoffset)
+ if orientation == 1 then
+ basepoint_h = basepoint_h + doffset
+ if boxdir == pos_r then
+ basepoint_v = basepoint_v - height
+ end
+ elseif orientation == 2 then
+ if boxdir == pos_r then
+ basepoint_h = basepoint_h + width
+ end
+ elseif orientation == 3 then
+ basepoint_h = basepoint_h + hoffset
+ if boxdir ~= pos_r then
+ basepoint_v = basepoint_v - height
+ end
+ end
+ if pos_r == righttoleft_code then
+ pos_h = ref_h - (cur_h + basepoint_h)
+ else
+ pos_h = ref_h + (cur_h + basepoint_h)
+ end
+ pos_v = ref_v - (cur_v + basepoint_v)
+ -- synced
+ pushorientation(orientation,pos_h,pos_v,pos_r)
+ if id == vlist_code then
+ vlist_out(current,list)
+ else
+ hlist_out(current,list)
+ end
+ poporientation(orientation,pos_h,pos_v,pos_r)
+ end
+ end
+ cur_h = cur_h + width
+ elseif id == kern_code then
+ local kern, factor = getkern(current,true)
+ if kern ~= 0 then
+ if factor ~= 0 then
+ cur_h = cur_h + (1.0 + factor/1000000.0) * kern
+ else
+ cur_h = cur_h + kern
+ end
+ end
+ elseif id == rule_code then
+ local width, height, depth = getwhd(current)
+ if width > 0 then
+ if height == running then
+ height = boxheight
+ end
+ if depth == running then
+ depth = boxdepth
+ end
+ local total = height + depth
+ if total > 0 then
+ local xoffset, yoffset, left, right = getoffsets(current) -- top bottom
+ if left ~= 0 then
+ pos_v = pos_v + left
+ total = total - left
+ end
+ if right ~= 0 then
+ depth = depth - right
+ total = total - right
+ end
+ if pos_r == righttoleft_code then
+ pos_h = pos_h - width
+ xoffset = - xoffset
+ end
+ pos_v = pos_v - depth
+ flushrule(current,pos_h + xoffset,pos_v + yoffset,pos_r,width,total,subtype)
+ end
+ end
+ cur_h = cur_h + width
+ elseif id == math_code then
+ -- local kern = getkern(current)
+ -- if kern ~= 0 then
+ -- cur_h = cur_h + kern
+ -- else
+ cur_h = cur_h + effectiveglue(current,this_box)
+ -- end
+ elseif id == dir_code then
+ -- We normally have proper begin-end pairs. A begin without end is (silently) handled
+ -- and an end without a begin will be (silently) skipped we only need to move forward
+ -- so we then have a faster calculation.
+ local dir, cancel = getdirection(current)
+ if cancel then
+ local ds = dirstack[current]
+ if ds then
+ ref_h = ds.ref_h
+ ref_v = ds.ref_v
+ cur_h = ds.cur_h
+ cur_v = ds.cur_v
+ else
+ -- pardir
+ end
+ pos_r = dir
+ else
+ local width, enddir = dirdimensions(this_box,current)
+ local new_h = cur_h + width
+ if dir ~= pos_r then
+ cur_h = new_h
+ end
+ if enddir ~= current then
+ dirstack[enddir] = {
+ cur_h = new_h,
+ cur_v = cur_v,
+ ref_h = ref_h,
+ ref_v = ref_v,
+ }
+ setdirection(enddir,pos_r)
+ end
+ if pos_r == righttoleft_code then
+ pos_h = ref_h - cur_h
+ else
+ pos_h = ref_h + cur_h
+ end
+ pos_v = ref_v - cur_v
+ -- synced
+ ref_h = pos_h
+ ref_v = pos_v
+ cur_h = 0
+ cur_v = 0
+ pos_r = dir
+ goto synced
+ end
+ elseif id == whatsit_code then
+ if subtype == literalwhatsit_code then
+ flushliteral(current,pos_h,pos_v)
+ elseif subtype == lateluawhatsit_code then
+ flushlatelua(current,pos_h,pos_v)
+ elseif subtype == setmatrixwhatsit_code then
+ flushsetmatrix(current,pos_h,pos_v)
+ elseif subtype == savewhatsit_code then
+ flushsave(current,pos_h,pos_v)
+ elseif subtype == restorewhatsit_code then
+ flushrestore(current,pos_h,pos_v)
+ elseif subtype == saveposwhatsit_code then
+ last_position_x = pos_h
+ last_position_y = pos_v
+ elseif subtype == writewhatsit_code then
+ flushwriteout(current)
+ elseif subtype == closewhatsit_code then
+ flushcloseout(current)
+ elseif subtype == openwhatsit_code then
+ flushopenout(current)
+ end
+ elseif id == disc_code then
+ local replace, tail = getreplace(current)
+ if replace and subtype ~= select_disc then
+ -- we could flatten .. no gain
+ setlink(tail,getnext(current))
+ setlink(current,replace)
+ setreplace(current)
+ end
+ -- elseif id == localpar_code and start_of_par(current) then
+ -- local pardir = getdirection(current) or lefttoright_code
+ -- if pardir == righttoleft_code then
+ -- end
+ -- end
+ else
+ -- penalty, boundary ... no dimensions
+ goto synced
+ end
+ -- There is no gain in skipping over this when we have zero progression
+ -- and such.
+ if pos_r == righttoleft_code then
+ pos_h = ref_h - cur_h
+ else
+ pos_h = ref_h + cur_h
+ end
+ pos_v = ref_v - cur_v
+ ::synced::
+ end
+ pos_h = ref_h
+ pos_v = ref_v
+ pos_r = ref_r
+ end
+
+ vlist_out = function(this_box,current)
+ local ref_h = pos_h
+ local ref_v = pos_v
+ local ref_r = pos_r
+ pos_r = getdirection(this_box)
+
+ local boxwidth,
+ boxheight,
+ boxdepth = getwhd(this_box)
+
+ local cur_h = 0
+ local cur_v = - boxheight
+ local top_edge = cur_v
+
+ if pos_r == righttoleft_code then
+ pos_h = ref_h - cur_h
+ else
+ pos_h = ref_h + cur_h
+ end
+ pos_v = ref_v - cur_v
+ -- synced
+
+ -- if not current then
+ -- current = getlist(this_box)
+ -- end
+
+ -- while current do
+ -- local id = getid(current)
+ for current, id, subtype in nextnode, current do
+ if id == glue_code then
+ local glueheight = effectiveglue(current,this_box)
+ if glueheight ~= 0 then
+ if subtype >= leaders_code then
+ local leader = getleader(current)
+ if leader then
+ local width, height, depth = getwhd(leader)
+ local total = height + depth
+ if getid(leader) == rule_code then
+ depth = 0 -- hm
+ if total > 0 then
+ if width == running then
+ width = boxwidth
+ end
+ if width > 0 then
+ if pos_r == righttoleft_code then
+ cur_h = cur_h - width
+ end
+ flushrule(leader,pos_h,pos_v - total,pos_r,width,total,getsubtype(leader))
+ end
+ cur_v = cur_v + total
+ end
+ elseif total > 0 and glueheight > 0 then
+ glueheight = glueheight + 10
+ local edge = cur_v + glueheight
+ local ly = 0
+ if subtype == gleaders_code then
+ save_v = cur_v
+ cur_v = ref_v - shipbox_v - cur_v
+ cur_v = total * (cur_v / total)
+ cur_v = ref_v - shipbox_v - cur_v
+ if cur_v < save_v then
+ cur_v = cur_v + total
+ end
+ elseif subtype == leaders_code then -- aleader
+ save_v = cur_v
+ cur_v = top_edge + total * ((cur_v - top_edge) / total)
+ if cur_v < save_v then
+ cur_v = cur_v + total
+ end
+ else
+ lq = glueheight / total
+ lr = glueheight % total
+ if subtype == cleaders_code then
+ cur_v = cur_v + lr / 2
+ else
+ ly = lr / (lq + 1)
+ cur_v = cur_v + (lr - (lq - 1) * ly) / 2
+ end
+ end
+ local shift = getshift(leader)
+ leaderlevel = leaderlevel + 1
+ while cur_v + total <= edge do -- todo: <= edge - total
+ -- synch_pos_with_cur(ref_h, ref_v, getshift(leader), cur_v + height)
+ if pos_r == righttoleft_code then
+ pos_h = ref_h - shift
+ else
+ pos_h = ref_h + shift
+ end
+ pos_v = ref_v - (cur_v + height)
+ -- synced
+ if getid(leader) == vlist_code then
+ vlist_out(leader,getlist(leader))
+ else
+ hlist_out(leader,getlist(leader))
+ end
+ cur_v = cur_v + total + ly
+ end
+ leaderlevel = leaderlevel - 1
+ cur_v = edge - 10
+ else
+ cur_v = cur_v + glueheight
+ end
+ end
+ else
+ cur_v = cur_v + glueheight
+ end
+ end
+ elseif id == hlist_code or id == vlist_code then
+ local width, height, depth = getwhd(current)
+ local list = getlist(current)
+ if list then
+ local boxdir = getdirection(current) or lefttoright_code
+ local shift, orientation = getshift(current)
+ if not orientation then
+ -- local basepoint_h = shift
+ -- local basepoint_v = height
+ if shift == 0 then
+ pos_h = ref_h
+ else
+ if boxdir ~= pos_r then
+ shift = shift + width
+ end
+ if pos_r == righttoleft_code then
+ pos_h = ref_h - shift
+ else
+ pos_h = ref_h + shift
+ end
+ end
+ pos_v = ref_v - (cur_v + height)
+ -- synced
+ if id == vlist_code then
+ vlist_out(current,list)
+ else
+ hlist_out(current,list)
+ end
+ elseif orientation == 0x1000 then
+ local orientation, xoffset, yoffset = getorientation(current)
+ -- local basepoint_h = shift
+ -- local basepoint_v = height
+ if boxdir ~= pos_r then
+ shift = shift + width
+ end
+ if pos_r == righttoleft_code then
+ pos_h = ref_h - (shift + xoffset)
+ else
+ pos_h = ref_h + (shift + xoffset)
+ end
+ pos_v = ref_v - (cur_v + height - yoffset)
+ -- synced
+ if id == vlist_code then
+ vlist_out(current,list)
+ else
+ hlist_out(current,list)
+ end
+ else
+ local orientation, xoffset, yoffset, woffset, hoffset, doffset = getorientation(current)
+ local orientation, basepoint_h, basepoint_v = applyanchor(orientation,shift,height,width,height,depth,woffset,hoffset,doffset,xoffset,yoffset)
+ if orientation == 1 then
+ basepoint_h = basepoint_h + width - height
+ basepoint_v = basepoint_v - height
+ elseif orientation == 2 then
+ basepoint_h = basepoint_h + width
+ basepoint_v = basepoint_v + depth - height
+ elseif orientation == 3 then -- weird
+ basepoint_h = basepoint_h + height
+ end
+ if pos_r == righttoleft_code then
+ pos_h = ref_h - basepoint_h
+ else
+ pos_h = ref_h + basepoint_h
+ end
+ pos_v = ref_v - (cur_v + basepoint_v)
+ -- synced
+ pushorientation(orientation,pos_h,pos_v,pos_r)
+ if id == vlist_code then
+ vlist_out(current,list)
+ else
+ hlist_out(current,list)
+ end
+ poporientation(orientation,pos_h,pos_v,pos_r)
+ end
+ end
+ cur_v = cur_v + height + depth
+ elseif id == kern_code then
+ cur_v = cur_v + getkern(current)
+ elseif id == rule_code then
+ local width, height, depth = getwhd(current)
+ local total = height + depth
+ if total > 0 then
+ if width == running then
+ width = boxwidth
+ end
+ if width > 0 then
+ local xoffset, yoffset, left, right = getoffsets(current)
+ if left ~= 0 then
+ width = width - left
+ xoffset = left
+ end
+ if right ~= 0 then
+ width = width - right
+ end
+ if pos_r == righttoleft_code then
+ xoffset = - xoffset - width
+ end
+ flushrule(current,pos_h + xoffset,pos_v - total - yoffset,pos_r,width,total,subtype)
+ end
+ end
+ cur_v = cur_v + total
+ elseif id == whatsit_code then
+ if subtype == literalwhatsit_code then
+ flushliteral(current,pos_h,pos_v)
+ elseif subtype == lateluawhatsit_code then
+ flushlatelua(current,pos_h,pos_v)
+ elseif subtype == setmatrixwhatsit_code then
+ flushsetmatrix(current,pos_h,pos_v)
+ elseif subtype == savewhatsit_code then
+ flushsave(current,pos_h,pos_v)
+ elseif subtype == restorewhatsit_code then
+ flushrestore(current,pos_h,pos_v)
+ elseif subtype == saveposwhatsit_code then
+ last_position_x = pos_h
+ last_position_y = pos_v
+ elseif subtype == writewhatsit_code then
+ flushwriteout(current)
+ elseif subtype == closewhatsit_code then
+ flushcloseout(current)
+ elseif subtype == openwhatsit_code then
+ flushopenout(current)
+ end
+ else
+ -- penalty
+ goto synced
+ end
+ if pos_r == righttoleft_code then
+ pos_h = ref_h - cur_h
+ else
+ pos_h = ref_h + cur_h
+ end
+ pos_v = ref_v - cur_v
+ ::synced::
+ end
+ pos_h = ref_h
+ pos_v = ref_v
+ pos_r = ref_r
+ end
+
+end
+
+function drivers.converters.lmtx(driver,box,smode,objnum,specification)
+
+ if not driver then
+ report("error in converter, no driver")
+ return
+ end
+
+ if box then
+ box = tonut(box)
+ else
+ report("error in converter, no box")
+ return
+ end
+
+ local actions = driver.actions
+ local flushers = driver.flushers
+
+ initialize = actions.initialize
+ finalize = actions.finalize
+
+ updatefontstate = flushers.updatefontstate
+
+ pushorientation = flushers.pushorientation
+ poporientation = flushers.poporientation
+
+ flushcharacter = flushers.character
+ flushfontchar = flushers.fontchar
+ flushrule = flushers.rule
+ flushsimplerule = flushers.simplerule
+ flushspecialrule = flushers.specialrule
+ flushspecial = flushers.special
+ flushliteral = flushers.literal
+ flushsetmatrix = flushers.setmatrix
+ flushsave = flushers.save
+ flushrestore = flushers.restore
+ -- flushimage = flushers.image
+
+ reset_dir_stack()
+ reset_state()
+
+ shippingmode = smode
+
+ local details = nil -- must be outside labels
+
+ local width, height, depth = getwhd(box)
+
+ local total = height + depth
+
+ ----- v_offset_par = 0
+ ----- h_offset_par = 0
+
+ local max_v = total -- + v_offset_par
+ local max_h = width -- + h_offset_par
+
+ if height > maxdimen or depth > maxdimen or width > maxdimen then
+ goto DONE
+ end
+
+ if max_v > maxdimen then
+ goto DONE
+ elseif max_v > abs_max_v then
+ abs_max_v = max_v
+ end
+
+ if max_h > maxdimen then
+ goto DONE
+ elseif max_h > abs_max_h then
+ abs_max_h = max_h
+ end
+
+ if shippingmode == "page" then
+
+ -- We have zero offsets in ConTeXt.
+
+ local pagewidth, pageheight = getpagedimensions()
+
+ -- local h_offset_par = texget("hoffset")
+ -- local v_offset_par = texget("voffset")
+
+ -- page_h_origin = trueinch
+ -- page_v_origin = trueinch
+
+ pos_r = lefttoright_code
+
+ if pagewidth > 0 then
+ page_size_h = pagewidth
+ else
+ page_size_h = width
+ end
+
+ if page_size_h == 0 then
+ page_size_h = width
+ end
+
+ if pageheight > 0 then
+ page_size_v = pageheight
+ else
+ page_size_v = total
+ end
+
+ if page_size_v == 0 then
+ page_size_v = total
+ end
+
+ local refpoint_h = 0 -- + page_h_origin + h_offset_par
+ local refpoint_v = page_size_v -- - page_v_origin - v_offset_par
+
+ pos_h = refpoint_h
+ pos_v = refpoint_v - height
+ -- synced
+
+ else
+
+ -- page_h_origin = 0
+ -- page_v_origin = 0
+ page_size_h = width
+ page_size_v = total
+ pos_r = getdirection(box)
+ pos_v = depth
+ pos_h = pos_r == righttoleft_code and width or 0
+
+ end
+
+ shipbox_ref_h = pos_h
+ shipbox_ref_v = pos_v
+
+ details = {
+ shippingmode = smode, -- target
+ boundingbox = { 0, 0, page_size_h, page_size_v },
+ objectnumber = smode ~= "page" and objnum or nil,
+ pagenumber = smode == "page" and objnum or nil,
+ specification = specification,
+ }
+
+ initialize(driver,details)
+
+ lastfont = nil -- this forces a sync each page / object
+
+ if getid(box) == vlist_code then
+ vlist_out(box,getlist(box))
+ else
+ hlist_out(box,getlist(box))
+ end
+
+ ::DONE::
+
+ finalize(driver,details)
+
+ shippingmode = "none"
+end
+
+-- This will move to back-out.lua eventually.
+
+do
+
+ ----- sortedhash = table.sortedhash
+
+ ----- tonut = nodes.tonut
+ local properties = nodes.properties.data
+ local flush = texio.write_nl
+
+ local periods = utilities.strings.newrepeater(".")
+
+ local function showdetails(n,l)
+ local p = properties[tonut(n)]
+ if p then
+ local done = false
+ for k, v in sortedhash(p) do
+ if done then
+ flush("\n")
+ else
+ done = true
+ end
+ flush(periods[l+1] .. " " .. k .. " = " .. tostring(v))
+ end
+ end
+ end
+
+ local whatsittracers = {
+ latelua = showdetails,
+ literal = showdetails,
+ }
+
+ callback.register("show_whatsit",function(n,l)
+ local s = nodes.whatsitcodes[n.subtype]
+ texio.write(" [" .. s .. "]")
+ local w = whatsittracers[s]
+ if w then
+ w(n,l)
+ end
+ end)
+
+end