LaTeX format for LuaMetaTeX
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

106 lines
3.9 KiB

local writer -- = require'luametalatex-nodewriter' -- This would introduce some cyclic dependency
local pdfvariable = pdf.variable
-- XForms currently have the form {width, height, depth, objnum, attributes, list, margin}
local xforms = {}
local utils = require'luametalatex-pdf-utils'
local strip_floats = utils.strip_floats
local to_bp = utils.to_bp
local function shipout(pfile, xform, fontdirs, usedglyphs)
local list, margin = xform.list, xform.margin
if not list then return xform.objnum end -- Already shipped out
local last_page = cur_page cur_page = nil
local out, resources, annots = writer(pfile, list, fontdirs, usedglyphs)
cur_page = last_page
assert(annots == '')
if pdfvariable.xformattr ~= '' or pdfvariable.xformresources ~= '' then
texio.write_nl('term and log', 'WARNING (savedboxresource shipout): Ignoring unsupported PDF variables xformattr and xformresources. Specify resources and attributes for specific XForms instead.')
local bbox = strip_floats(string.format('/BBox[%f %f %f %f]', -to_bp(margin), -to_bp(list.depth+margin), to_bp(list.width+margin), to_bp(list.height+margin)))
local dict = string.format('/Subtype/Form%s/Resources%s%s', bbox, resources(xform.resources), xform.attributes or '')
xform.list = nil
local objnum = pfile:stream(xform.objnum, dict, out)
xform.objnum = objnum
return objnum
local function save(pfile, n, attr, resources, immediate, type, margin, fontdirs, usedglyphs)
local index = #xforms+1
local xform = {
list = assert(n, 'List required for saveboxresource'),
width = n.width,
height = n.height,
depth = n.depth,
attributes = attr,
resources = resources,
margin = margin,
-- type = type, -- TODO: Not yet used. Do we need this at all?
xforms[index] = xform
if immediate then
shipout(pfile, xform, fontdirs, usedglyphs)
return index
local function adjust_sizes(width, height, depth, real_width, real_height, real_depth)
if not depth then
if height then
local scale = height/real_height
depth = (real_depth*scale + .5)//1
width = width or (real_width*scale + .5)//1
elseif width then
local scale = width/real_width
depth = (real_depth*scale + .5)//1
height = (real_height*scale + .5)//1
width, height, depth = real_width, real_height, real_depth
elseif height then
width = width or (real_width*(height+depth)/(real_height+real_depth) + .5)//1
width = width or real_width
local scale = width/real_width
height = ((real_depth+real_height)*scale + .5)//1 - depth
return width, height, depth
local ruleid ='rule'
local ruletypes = node.subtypes'rule'
local boxrule
for n, name in next, ruletypes do
if name == 'box' then boxrule = n break end
local function use(index, width, height, depth)
local xform = xforms[index]
if not xform then return nil, nil, nil, nil end
width, height, depth = adjust_sizes(width, height, depth, xform.width, xform.height, xform.depth)
local n =, boxrule), index), width, height, depth)
return, width, height, depth
local function do_box(data, p, n, x, y)
local xform = assert(xforms[data], 'Invalid XForm')
local objnum = shipout(p.file, xform, p.fontdirs, p.usedglyphs)
local width, height, depth =
local xscale, yscale = width / xform.width, (height+depth) / (xform.height+xform.depth)
p.resources.XObject['Fm' .. tostring(data)] = objnum
pdf.write('page', strip_floats(string.format('q %f 0 0 %f %f %f cm /Fm%i Do Q',
xscale, yscale,
to_bp(x), to_bp(y-depth+yscale*xform.depth),
data)), nil, nil, p)
return {
save = save,
use = use,
ship = do_box,
init_nodewriter = function(t, nodewriter) writer, t.init_nodewriter = nodewriter, nil end,