From 1195e0f20177c1441944508e8d6ac2f5cc8c36b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20Fabian=20Kr=C3=BCger?= Date: Wed, 8 Jul 2020 22:20:08 +0200 Subject: [PATCH] Fix bugs and add node fonts --- luametalatex-back-pdf.lua | 43 +++++++++++++++++++++++---- luametalatex-font-resolve.lua | 4 +-- luametalatex-nodewriter.lua | 30 +++++++------------ luametalatex-pdf-font-deduplicate.lua | 2 +- luametalatex-pdf-font.lua | 21 ++++++++----- luametalatex-pdf-savedbox.lua | 2 +- 6 files changed, 66 insertions(+), 36 deletions(-) diff --git a/luametalatex-back-pdf.lua b/luametalatex-back-pdf.lua index 8e2a902..ba70d4f 100644 --- a/luametalatex-back-pdf.lua +++ b/luametalatex-back-pdf.lua @@ -5,6 +5,7 @@ local writer = require'luametalatex-nodewriter' local newpdf = require'luametalatex-pdf' local nametree = require'luametalatex-pdf-nametree' local build_fontdir = require'luametalatex-pdf-font' +local prepare_node_font = require'luametalatex-pdf-font-node'.prepare local fontmap = require'luametalatex-pdf-font-map' local utils = require'luametalatex-pdf-utils' @@ -13,7 +14,17 @@ local to_bp = utils.to_bp local pdfname, pfile local fontdirs = setmetatable({}, {__index=function(t, k)t[k] = pfile:getobj() return t[k] end}) -local usedglyphs = {} +local nodefont_meta = {} +local usedglyphs = setmetatable({}, {__index=function(t, fid) + local v + if font.fonts[fid].format == 'type3node' then + v = setmetatable({generation = 0, next_generation = 0}, nodefont_meta) + else + v = {} + end + t[fid] = v + return v +end}) local dests = {} local cur_page local declare_whatsit = require'luametalatex-whatsits'.new @@ -69,7 +80,7 @@ token.luacmd("shipout", function() local out, resources, annots = writer(pfile, list, fontdirs, usedglyphs, colorstacks) cur_page = nil local content = pfile:stream(nil, '', out) - pfile:indirect(page, string.format([[<>%s%s>>]], parent, content, -math.ceil(to_bp(list.depth)), math.ceil(to_bp(list.width)), math.ceil(to_bp(list.height)), resources, pdfvariable.pageresources, annots, pdfvariable.pageattr)) + pfile:indirect(page, string.format([[<>]], parent, content, -math.ceil(to_bp(list.depth)), math.ceil(to_bp(list.width)), math.ceil(to_bp(list.height)), resources(pdfvariable.pageresources), annots, pdfvariable.pageattr)) node.flush_list(list) token.put_next(reset_deadcycles) token.scan_token() @@ -104,14 +115,36 @@ local pdf_escape = require'luametalatex-pdf-escape' local pdf_bytestring = pdf_escape.escape_bytes local pdf_text = pdf_escape.escape_text +local function nodefont_newindex(t, k, v) + t.generation = t.next_generation + return rawset(t, k, v) +end + callback.register("stop_run", function() if not pfile then return end + do + nodefont_meta.__newindex = nodefont_newindex -- Start recording generations + local need_new_run = true + while need_new_run do + need_new_run = nil + for fid, glyphs in pairs(usedglyphs) do + local next_gen = glyphs.next_generation + if next_gen and next_gen == glyphs.generation then + glyphs.next_generation = next_gen+1 + need_new_run = true + local f = font.getfont(fid) or font.fonts[fid] + prepare_node_font(f, glyphs, pfile, fontdirs, usedglyphs) -- Might become fid, glyphs + end + end + end + end for fid, id in pairs(fontdirs) do local f = font.getfont(fid) or font.fonts[fid] - local psname = f.psname or f.fullname local sorted = {} + local used = usedglyphs[fid] + used.generation, used.next_generation = nil, nil for k,v in pairs(usedglyphs[fid]) do sorted[#sorted+1] = v end @@ -438,8 +471,8 @@ local refobj_whatsit = declare_whatsit('pdf_refobj', function(prop, p, n, x, y) end) local literal_whatsit = declare_whatsit('pdf_literal', function(prop, p, n, x, y) if not prop then - tex.error('Invalid pdf_literal whatsit', {"A pdf_literal whatsit did not contain a literal to be inserted. \z - Maybe your code hasn't been adapted to LuaMetaLaTeX yet?"}) + tex.error('Invalid pdf_literal whatsit', "A pdf_literal whatsit did not contain a literal to be inserted. \z + Maybe your code hasn't been adapted to LuaMetaLaTeX yet?") return end pdf.write(prop.mode, prop.data, x, y, p) diff --git a/luametalatex-font-resolve.lua b/luametalatex-font-resolve.lua index 48aeb83..d12be9e 100644 --- a/luametalatex-font-resolve.lua +++ b/luametalatex-font-resolve.lua @@ -55,7 +55,7 @@ function font.define(f) local format = f.format or "unknown" local encodingbytes = f.encodingbytes or (f.format:sub(5) == "type" and 2 or 1) f.encodingbytes = encodingbytes - if encodingbytes == 1 and f.type ~= 'virtual' then + if encodingbytes == 1 and f.type ~= 'virtual' and f.format ~= 'type3node' then -- map file lookup local entry = fontmap[f.name] if entry then @@ -145,7 +145,7 @@ function font.addcharacters(fid, newdir) local existing = fontdir[cp] if existing ~= glyph then if existing then - texio.write_nl'Overwriting existing character. Here be dragons' + -- texio.write_nl'Overwriting existing character. Here be dragons' end end if glyph.commands then diff --git a/luametalatex-nodewriter.lua b/luametalatex-nodewriter.lua index 1ce3e93..c5cabc7 100644 --- a/luametalatex-nodewriter.lua +++ b/luametalatex-nodewriter.lua @@ -35,6 +35,7 @@ local utils = require'luametalatex-pdf-utils' local strip_floats = utils.strip_floats local to_bp = utils.to_bp +local make_resources = require'luametalatex-pdf-resources' local pdf_font_map = require'luametalatex-pdf-font-deduplicate' local get_whatsit_handler = require'luametalatex-whatsits'.handler @@ -382,6 +383,8 @@ local function do_commands(p, c, f, fid, x, y, outer, ...) for _, cmd in ipairs(c.commands) do if cmd[1] == "node" then local cmd = cmd[2] + assert(node.type(cmd)) + cmd = todirect(cmd) nodehandler[getid(cmd)](p, cmd, x, y, nil, ...) x = x + getwidth(cmd) elseif cmd[1] == "font" then @@ -397,17 +400,17 @@ local function do_commands(p, c, f, fid, x, y, outer, ...) current_font = assert(fonts[cmd[2]], "invalid font requested") local n = direct.new'glyph' setsubtype(n, 256) - setfont(n, current_font.id, cmd[2]) + setfont(n, current_font.id, cmd[3]) nodehandler.glyph(p, n, x, y, outer, ...) - direct.free(n) x = x + getwidth(n) + direct.free(n) elseif cmd[1] == "rule" then local n = direct.new'rule' setheight(n, cmd[2]) setwidth(n, cmd[3]) nodehandler.rule(p, n, x, y, outer, ...) - direct.free(n) x = x + getwidth(n) + direct.free(n) elseif cmd[1] == "left" then x = x + cmd[2] elseif cmd[1] == "down" then @@ -533,22 +536,9 @@ local ondemandmeta = { return t[k] end } -local function writeresources(p) - local resources = p.resources - local result = {} - for kind, t in pairs(resources) do if next(t) then - result[#result+1] = format("/%s<<", kind) - for name, value in pairs(t) do - result[#result+1] = format("/%s %i 0 R", name, value) - t[name] = nil - end - result[#result+1] = ">>" - end end - return concat(result) -end -local function nodewriter(file, n, fontdirs, usedglyphs, colorstacks) +local function nodewriter(file, n, fontdirs, usedglyphs, colorstacks, resources) n = todirect(n) - setmetatable(usedglyphs, ondemandmeta) + resources = resources or make_resources() local p = { is_page = not not colorstacks, file = file, @@ -560,7 +550,7 @@ local function nodewriter(file, n, fontdirs, usedglyphs, colorstacks) vfont = {}, matrix = {1, 0, 0, 1, 0, 0}, pending_matrix = {}, - resources = setmetatable({}, ondemandmeta), + resources = resources, annots = {}, linkcontext = file.linkcontext, fontdirs = fontdirs, @@ -580,7 +570,7 @@ local function nodewriter(file, n, fontdirs, usedglyphs, colorstacks) nodehandler[getid(n)](p, n, 0, 0, n, nil, 0) -- nodehandler[getid(n)](p, n, 0, getdepth(n), n) topage(p) - return concat(p.strings, '\n'), writeresources(p), (p.annots[1] and string.format("/Annots[%s]", table.concat(p.annots, ' ')) or "") + return concat(p.strings, '\n'), resources, (p.annots[1] and string.format("/Annots[%s]", table.concat(p.annots, ' ')) or "") end require'luametalatex-pdf-savedbox':init_nodewriter(nodewriter) return nodewriter diff --git a/luametalatex-pdf-font-deduplicate.lua b/luametalatex-pdf-font-deduplicate.lua index 2542fed..f0a9813 100644 --- a/luametalatex-pdf-font-deduplicate.lua +++ b/luametalatex-pdf-font-deduplicate.lua @@ -17,7 +17,7 @@ local function build_sharekey(fontdir) local encodingbytes = assert(fontdir.encodingbytes) local key = string.format("%i:%s:", fontdir.encodingbytes, fontdir.format) if encodingbytes == 1 then - if fontdir.format == "type3" then + if fontdir.format:sub(1,5) == "type3" then return string.format("%s%i:%s", key, fontdir.size, fontdir.name) end key = string.format("%s%s:", key, fontdir.encoding or '') diff --git a/luametalatex-pdf-font.lua b/luametalatex-pdf-font.lua index a047301..32312fe 100644 --- a/luametalatex-pdf-font.lua +++ b/luametalatex-pdf-font.lua @@ -250,27 +250,34 @@ local function buildfont0(pdf, fontdir, usedcids) cidfont) end local buildfontpk = require'luametalatex-pdf-font-pk' +local buildfontnode = require'luametalatex-pdf-font-node'.buildfont local function buildfont3(pdf, fontdir, usedcids) + local buildfont = fontdir.format == 'type3' and buildfontpk + or fontdir.format == 'type3node' and buildfontnode + or error[[Unsupported Type3 based font format]] usedcids = usedcids or allcids(fontdir) table.sort(usedcids, function(a,b) return a[1]>", - -- "<>", + local matrices = strip_floats(string.format( + "/FontBBox[%f %f %f %f]/FontMatrix[%f %f %f %f %f %f]", bbox[1], bbox[2], bbox[3], bbox[4], - matrix[1], matrix[2], matrix[3], matrix[4], matrix[5], matrix[6], + matrix[1], matrix[2], matrix[3], matrix[4], matrix[5], matrix[6])) + return string.format( + "<>", + -- "<>", + matrices, charprocs, encodingtype3(pdf), usedcids[1][1], usedcids[#usedcids][1], widths, touni - )) -- , descriptor) -- TODO + ) -- , descriptor) -- TODO end return function(pdf, fontdir, usedcids) - if fontdir.format == "type3" then + if fontdir.format:sub(1,5) == "type3" then return buildfont3(pdf, fontdir, usedcids) else return buildfont0(pdf, fontdir, usedcids) diff --git a/luametalatex-pdf-savedbox.lua b/luametalatex-pdf-savedbox.lua index 15d3ecd..d10fa0b 100644 --- a/luametalatex-pdf-savedbox.lua +++ b/luametalatex-pdf-savedbox.lua @@ -19,7 +19,7 @@ local function shipout(pfile, xform, fontdirs, usedglyphs) texio.write_nl('term and log', 'WARNING (savedboxresource shipout): Ignoring unsupported PDF variables xformattr and xformresources. Specify resources and attributes for specific XForms instead.') end 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>>%s', bbox, resources, xform.resources or '', xform.attributes or '') + local dict = string.format('/Subtype/Form%s/Resources%s%s', bbox, resources(xform.resources), xform.attributes or '') node.flush_list(list) xform.list = nil local objnum = pfile:stream(xform.objnum, dict, out)