if not modules then modules = { } end modules ['driv-shp'] = { version = 1.001, 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 marginkern_code = nodecodes.marginkern 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 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 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 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 factor ~= 0 and size_h > 0 then size_h = size_h + size_h * factor / 1000 end if size_h > 0 and size_v > 0 then flushsimplerule(pos_h,pos_v,pos_r,size_h,size_v) pos_h = pos_h + size_h 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 hlist_out(packet[2]) 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 local width, height, depth, naturalwidth if current then width, height, depth, factor = getwhd(current,true) naturalwidth = width if factor ~= 0 then -- width = (1.0 + factor/1000000.0) * width width = width + width * factor/1000000.0 -- width = width + width * 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 end if vfcommands then vfcommands = data.commands end if vfcommands then flush_vf_packet(pos_h,pos_v,pos_r,font,char,data,factor,vfcommands) -- also f ? else 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,naturalwidth,factor,width,f,e) poporientation(orientation,pos_h,pos_v) else flushcharacter(current,pos_h,pos_v,pos_r,font,char,data,naturalwidth,factor,width,f,e) 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 ----- dirstack = { } local dirstack = setmetatableindex(dirstackentry) local function reset_dir_stack() -- dirstack = setmetatableindex(dirstackentry) dirstack = { } end local function flushlatelua(current,h,v) return backends.latelua(current,h,v) end local function flushwriteout(current) if not doing_leaders then backends.writeout(current) end end local function flushopenout(current) if not doing_leaders then backends.openout(current) end end local function flushcloseout(current) if not doing_leaders 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 outer_doing_leaders = false 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, ht, dp = flush_character(current,font,char,false,true,pos_h,pos_v,pos_r) 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) 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 outer_doing_leaders = doing_leaders doing_leaders = true if getid(leader) == vlist_code then vlist_out(leader) else hlist_out(leader) end doing_leaders = outer_doing_leaders cur_h = cur_h + width + lx end 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 boxdir = getdirection(current) or lefttoright_code local width, height, depth = getwhd(current) local list = getlist(current) if list then 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 == 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 == kern_code then local kern, factor = getkern(current,true) if kern ~= 0 then if factor and 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) 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 cur_h = cur_h + width end 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 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 == marginkern_code then cur_h = cur_h + getkern(current) -- elseif id == localpar_code and start_of_par(current) then -- local pardir = getdirection(current) or lefttoright_code -- if pardir == righttoleft_code then -- end -- end 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 outer_doing_leaders = false 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) 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 outer_doing_leaders = doing_leaders doing_leaders = true if getid(leader) == vlist_code then vlist_out(leader) else hlist_out(leader) end doing_leaders = outer_doing_leaders cur_v = cur_v + total + ly end 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 boxdir = getdirection(current) or lefttoright_code local width, height, depth = getwhd(current) local list = getlist(current) if list then local shift, orientation = getshift(current) if not orientation then -- 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 else pos_h = ref_h + shift 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 cur_h = cur_h + left end if right ~= 0 then width = width - right end if pos_r == righttoleft_code then cur_h = cur_h - width xoffset = - xoffset end flushrule(current,pos_h + xoffset,pos_v - total - yoffset,pos_r,width,total,subtype) end cur_v = cur_v + total 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 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 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) else hlist_out(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