From f4b65fd65868a9f68c17fa969bd5533b8c81af68 Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Fri, 4 Mar 2022 22:04:55 +0000 Subject: minim* (4mar22) git-svn-id: svn://tug.org/texlive/trunk@62419 c570f23f-e606-0410-a88d-b1316a301751 --- .../tex/luatex/minim-math/minim-math-table.lua | 15 +- .../tex/luatex/minim-math/minim-math.lua | 6 +- .../tex/luatex/minim-math/minim-math.tex | 4 + .../texmf-dist/tex/luatex/minim-mp/minim-lamp.ini | 20 ++ Master/texmf-dist/tex/luatex/minim-mp/minim-mp.ini | 1 + Master/texmf-dist/tex/luatex/minim-mp/minim-mp.lua | 390 +++++++++++---------- Master/texmf-dist/tex/luatex/minim-mp/minim-mp.tex | 3 +- .../tex/luatex/minim-pdf/minim-languagecodes.lua | 8 +- .../texmf-dist/tex/luatex/minim-pdf/minim-pdf.lua | 294 +++++++--------- .../texmf-dist/tex/luatex/minim-pdf/minim-pdf.tex | 62 ++-- .../texmf-dist/tex/luatex/minim-xmp/minim-xmp.lua | 7 +- .../texmf-dist/tex/luatex/minim-xmp/minim-xmp.tex | 4 + Master/texmf-dist/tex/luatex/minim/minim-alloc.lua | 183 ++++++++-- Master/texmf-dist/tex/luatex/minim/minim-alloc.tex | 107 +++--- .../tex/luatex/minim/minim-callbacks.lua | 175 ++++++--- Master/texmf-dist/tex/luatex/minim/minim-doc.sty | 64 ++-- Master/texmf-dist/tex/luatex/minim/minim-hooks.lua | 18 +- Master/texmf-dist/tex/luatex/minim/minim-hooks.tex | 8 +- .../texmf-dist/tex/luatex/minim/minim-lmodern.tex | 18 +- .../tex/luatex/minim/minim-pdfresources.lua | 154 ++++++++ .../tex/luatex/minim/minim-pdfresources.tex | 51 +++ Master/texmf-dist/tex/luatex/minim/minim-plain.tex | 14 - 22 files changed, 1021 insertions(+), 585 deletions(-) create mode 100644 Master/texmf-dist/tex/luatex/minim-mp/minim-lamp.ini create mode 100644 Master/texmf-dist/tex/luatex/minim/minim-pdfresources.lua create mode 100644 Master/texmf-dist/tex/luatex/minim/minim-pdfresources.tex (limited to 'Master/texmf-dist/tex/luatex') diff --git a/Master/texmf-dist/tex/luatex/minim-math/minim-math-table.lua b/Master/texmf-dist/tex/luatex/minim-math/minim-math-table.lua index 3a12d1da99f..5e6a70036c5 100644 --- a/Master/texmf-dist/tex/luatex/minim-math/minim-math-table.lua +++ b/Master/texmf-dist/tex/luatex/minim-math/minim-math-table.lua @@ -106,13 +106,22 @@ return , { code = 0x00308, char = ' ̈', class = 'accent', cs = 'ddot' } -- combining diaeresis , { code = 0x00309, char = ' ̉', class = 'accent', cs = 'ovhook' } -- combining hook above , { code = 0x0030A, char = ' ̊', class = 'accent', cs = 'ocirc' } -- combining ring above + , { code = 0x0030B, char = ' ̋', class = 'accent', cs = 'dacute' } -- combining double acute accent , { code = 0x0030C, char = ' ̌', class = 'accent', cs = 'check' } -- combining caron , { code = 0x00310, char = ' ̐', class = 'accent', cs = 'candra' } -- combining candrabindu , { code = 0x00312, char = ' ̒', class = 'accent', cs = 'oturnedcomma' } -- combining turned comma above , { code = 0x00315, char = ' ̕', class = 'accent', cs = 'ocommatopright' } -- combining comma above right , { code = 0x0031A, char = ' ̚', class = 'accent', cs = 'droang' } -- combining left angle above + , { code = 0x00323, char = ' ̣', class = 'botaccent', cs = 'dotbelow' } -- combining dot below + , { code = 0x00324, char = ' ̤', class = 'botaccent', cs = 'ddotbelow' } -- combining diaeresis below + , { code = 0x00325, char = ' ̥', class = 'botaccent', cs = 'ocircbelow' } -- combining ring below + , { code = 0x00326, char = ' ̦', class = 'botaccent', cs = 'commabelow' } -- combining comma below + , { code = 0x00327, char = ' ̧', class = 'botaccent', cs = 'cedilla' } -- combining cedilla + , { code = 0x00328, char = ' ̨', class = 'botaccent', cs = 'ogonek' } -- combining ogonek + , { code = 0x00329, char = ' ̩', class = 'botaccent', cs = 'vlinebelow' } -- combining vertical line below , { code = 0x00330, char = ' ̰', class = 'botaccent', cs = 'wideutilde' } -- combining tilde below , { code = 0x00331, char = ' ̱', class = 'botaccent', cs = 'underbar' } -- combining macron below + , { code = 0x00336, char = ' ̶', class = 'overlay', cs = 'strike' } -- combining long stroke overlay , { code = 0x00338, char = ' ̸', class = 'overlay', cs = 'not' } -- combining long solidus overlay , { code = 0x00391, char = 'Α', class = 'var', cs = 'Alpha', alphabet = 'Greek' } -- greek capital letter alpha , { code = 0x00392, char = 'Β', class = 'var', cs = 'Beta', alphabet = 'Greek' } -- greek capital letter beta @@ -236,7 +245,7 @@ return , { code = 0x02110, char = 'ℐ', class = 'ord', cs = 'mscrI', alphabet = 'script' } -- script capital i , { code = 0x02111, char = 'ℑ', class = 'ord', cs = 'Im' } -- black-letter capital i , { code = 0x02112, char = 'ℒ', class = 'ord', cs = 'mscrL', alphabet = 'script' } -- script capital l - , { code = 0x02113, char = 'ℓ', class = 'ord', cs = 'ell', alphabet = 'script' } -- script small l + , { code = 0x02113, char = 'ℓ', class = 'ord', cs = 'ell' } -- script small l , { code = 0x02115, char = 'ℕ', class = 'ord', cs = 'BbbN', alphabet = 'blackboard' } -- double-struck capital n , { code = 0x02118, char = '℘', class = 'ord', cs = 'wp', } -- weierstrass elliptic function , { code = 0x02119, char = 'ℙ', class = 'ord', cs = 'BbbP', alphabet = 'blackboard' } -- double-struck capital p @@ -402,7 +411,7 @@ return , { code = 0x02213, char = '∓', class = 'bin', cs = 'mp' } -- minus-or-plus sign , { code = 0x02214, char = '∔', class = 'bin', cs = 'dotplus' } -- dot plus , { code = 0x02215, char = '∕', class = 'bin', cs = 'divslash' } -- division slash - , { code = 0x02216, char = '∖', class = 'bin', cs = 'smallsetminus' } -- set minus + , { code = 0x02216, char = '∖', class = 'bin', cs = 'setminus' } -- set minus , { code = 0x02217, char = '∗', class = 'bin', cs = 'ast' } -- asterisk operator , { code = 0x02218, char = '∘', class = 'bin', cs = 'vysmwhtcircle' } -- ring operator , { code = 0x02219, char = '∙', class = 'bin', cs = 'vysmblkcircle' } -- bullet operator @@ -1171,7 +1180,7 @@ return , { code = 0x029F2, char = '⧲', class = 'ord', cs = 'errbarcircle' } -- error-barred white circle , { code = 0x029F3, char = '⧳', class = 'ord', cs = 'errbarblackcircle' } -- error-barred black circle , { code = 0x029F4, char = '⧴', class = 'rel', cs = 'ruledelayed' } -- rule-delayed - , { code = 0x029F5, char = '⧵', class = 'bin', cs = 'setminus' } -- reverse solidus operator + , { code = 0x029F5, char = '⧵', class = 'bin', cs = 'rsolop' } -- reverse solidus operator , { code = 0x029F6, char = '⧶', class = 'bin', cs = 'dsol' } -- solidus with overbar , { code = 0x029F7, char = '⧷', class = 'bin', cs = 'rsolbar' } -- reverse solidus with horizontal stroke , { code = 0x029F8, char = '⧸', class = 'op', cs = 'xsol' } -- big solidus diff --git a/Master/texmf-dist/tex/luatex/minim-math/minim-math.lua b/Master/texmf-dist/tex/luatex/minim-math/minim-math.lua index 194e9388199..6373809e433 100644 --- a/Master/texmf-dist/tex/luatex/minim-math/minim-math.lua +++ b/Master/texmf-dist/tex/luatex/minim-math/minim-math.lua @@ -2,7 +2,7 @@ local M = {} local alloc = require ('minim-alloc') -local callbacks = require ('minim-callbacks') +local cb = require ('minim-callbacks') alloc.remember('minim-math') @@ -312,7 +312,7 @@ local transformcodes = alloc.saved_table ('math:transformcodes') -- set a character as transformable local function set_transform (num, char) - c = alloc.new_count ('math transform '..char) + local c = alloc.new_count ('math transform '..char) transformcodes[num] = c tex.setcount ('global', c, num) end @@ -403,7 +403,7 @@ local function inspect_noads (h,d,n) return true end -callbacks.register ('mlist_to_mlist', inspect_noads) +cb.register ('mlist_to_mlist', inspect_noads) -- 1 Reading the math character table diff --git a/Master/texmf-dist/tex/luatex/minim-math/minim-math.tex b/Master/texmf-dist/tex/luatex/minim-math/minim-math.tex index e05ce17f7cb..06fb632a5c0 100644 --- a/Master/texmf-dist/tex/luatex/minim-math/minim-math.tex +++ b/Master/texmf-dist/tex/luatex/minim-math/minim-math.tex @@ -156,6 +156,10 @@ \mathlet · \cdot \Umathchardef\cdotp "6"0"B7 +% move a macro over +\protected\def\*{\discretionary{\thinspace + \the\textfont\Umathcharfam`\×\Uchar`\×}{}{}} + % some aliases \let\neq = \ne \let\le = \leq diff --git a/Master/texmf-dist/tex/luatex/minim-mp/minim-lamp.ini b/Master/texmf-dist/tex/luatex/minim-mp/minim-lamp.ini new file mode 100644 index 00000000000..7900b3936ae --- /dev/null +++ b/Master/texmf-dist/tex/luatex/minim-mp/minim-lamp.ini @@ -0,0 +1,20 @@ + +\let\DUMP=\dump +\let\dump=\endinput + +\input lualatex.ini + +\toksapp\everyjob{% + \documentclass{article} + \input minim-mp + \message{This is the minim-latex metapost processor.}\relax + \directlua {require('minim-mp').on_line = true}% + \newmetapostinstance[jobname="\jobname", mathmode="scaled"]\MP + \runmetapost\MP{input "\jobname";}% + \directlua {require('minim-mp').shipout(\the\MP)}% + \closemetapostinstance\MP + \csname @fileswfalse\endcsname\end{document}} + +\let\dump=\DUMP +\dump + diff --git a/Master/texmf-dist/tex/luatex/minim-mp/minim-mp.ini b/Master/texmf-dist/tex/luatex/minim-mp/minim-mp.ini index a257f6a18ab..e3312a0cb91 100644 --- a/Master/texmf-dist/tex/luatex/minim-mp/minim-mp.ini +++ b/Master/texmf-dist/tex/luatex/minim-mp/minim-mp.ini @@ -7,6 +7,7 @@ \toksapp\everyjob{% \message{This is the minim metapost processor.}\relax + \directlua {require('minim-mp').on_line = true}% \newmetapostinstance[jobname="\jobname", mathmode="scaled"]\MP \runmetapost\MP{input "\jobname";}% \directlua {require('minim-mp').shipout(\the\MP)}% diff --git a/Master/texmf-dist/tex/luatex/minim-mp/minim-mp.lua b/Master/texmf-dist/tex/luatex/minim-mp/minim-mp.lua index 0f1851eba0d..366313e60ba 100644 --- a/Master/texmf-dist/tex/luatex/minim-mp/minim-mp.lua +++ b/Master/texmf-dist/tex/luatex/minim-mp/minim-mp.lua @@ -1,88 +1,13 @@ local alloc = require ('minim-alloc') local cb = require('minim-callbacks') +local pdfres = require('minim-pdfresources') alloc.remember ('minim-mp') local M = {} -- 1 AUXILIARY FUNCTIONS --- 2 pdf resource management - --- We add /ColorSpace and /Pattern entries to all page and xform resources. --- Each key refers to a central (global) object mapping names to objects. This --- central dictionary will be written to the pdf inside the finish_pdffile --- callback. --- --- In the future, /Shading and /ExtGState may also be added. --- --- Central resource dictionaries and all used resources will be written to the --- pdf inside the finish_pdf callback. --- --- Since a resource dictionary can only contain one entry of each kind, this --- package cannot coëxist with other packages doing their own resource --- management. I am aware of only one other package doing that, however, which --- is pgf. Luckily, pgf users are unlikely to be interested in metapost. Due to --- this incompatibility, however, resource management must be enabled --- explicitly. - --- keys are pdf names (starting with a slash) -local patterns = { }; M.patterns = patterns -local colourspaces = { }; M.colourspaces = colourspaces - -local global_resources, pattern_dict_objnum, colourspace_dict_objnum -function M.enable_resource_management() - if global_resources then return end - -- central dictionary objects - pattern_dict_objnum = pdf.reserveobj() - colourspace_dict_objnum = pdf.reserveobj() - global_resources = string.format('/Pattern %d 0 R /ColorSpace %d 0 R', - pattern_dict_objnum, colourspace_dict_objnum) - -- add to page and xform resources - pdf.setpageresources((pdf.getpageresources() or '')..global_resources) - pdf.setxformresources((pdf.getxformresources() or '')..global_resources) -end - --- Saved patterns should have the following fields: --- objnum the reserved object number for the pattern (optional) --- used true if the pattern is in use (should be set automatically) --- attr the pattern attributes --- stream the pattern drawing statements --- painttype the paint type of the pattern (1 or 2) --- Saved colour spaces should have the following fields: --- objnum the reserved object number for the colour space (optional) --- used true if the pattern is in use (should be set automatically) --- content the colour space contents (a pdf array) - -function M.write_resources() - if not global_resources then return end - -- patterns - local used_patterns = { '<<' } - for name, pat in pairs(patterns) do - if pat.used then - local objnum = pat.objnum or pdf.reserveobj() - pdf.immediateobj(objnum, 'stream', pat.stream, pat.attr) - table.insert(used_patterns, string.format('%s %d 0 R', name, objnum)) - end - end - table.insert(used_patterns, '>>') - pdf.immediateobj(pattern_dict_objnum, table.concat(used_patterns, ' ')) - -- colour spaces - local used_spaces = { '<<' } - for name, space in pairs(colourspaces) do - if space.used then - local objnum = space.objnum or pdf.reserveobj() - pdf.immediateobj(objnum, space.content) - table.insert(used_spaces, string.format('%s %d 0 R', name, objnum)) - end - end - table.insert(used_spaces, '>>') - pdf.immediateobj(colourspace_dict_objnum, table.concat(used_spaces, ' ')) -end - --- Write out resource objects at the end of the run -cb.register('finish_pdffile', M.write_resources) - -- 2 state metatable -- q Q store/restore graphics state @@ -125,6 +50,7 @@ function A.save(append) local st = append.state[#append.state] or { } append.state[#append.state+1] = { + linewidth = st.linewidth, miterlimit = st.miterlimit, linejoin = st.linejoin, linecap = st.linecap, @@ -159,6 +85,7 @@ local debugging = false function M.enable_debugging() debugging = true pdf.setcompresslevel(0) + pdf.setobjcompresslevel(0) end local function print_prop(append, obj, prop) @@ -270,7 +197,7 @@ local function curve_fmt(...) end function A.literal(append, fmt, ...) - local lit = node.new(8,16) + local lit = node.new(8,16) -- pdf_literal lit.data = fmt:format(...) append:node(lit) end @@ -336,14 +263,14 @@ end -- variables ‘stroke’ and ‘fill’ that record the last-used colour settings. -- preload device colour pattern colour spaces -colourspaces['/PsG'] = { content = '[ /Pattern /DeviceGray ]' } -colourspaces['/PsRG'] = { content = '[ /Pattern /DeviceRGB ]' } -colourspaces['/PsK'] = { content = '[ /Pattern /DeviceCMYK ]' } +pdfres.add_resource('ColorSpace', 'PsG', { value = '[ /Pattern /DeviceGray ]' }) +pdfres.add_resource('ColorSpace', 'PsRG', { value = '[ /Pattern /DeviceRGB ]' }) +pdfres.add_resource('ColorSpace', 'PsK', { value = '[ /Pattern /DeviceCMYK ]' }) local colour_template = { '%.3f ', '%.3f %.3f ', '%.3f %.3f %.3f ', '%.3f %.3f %.3f %.3f ' } local colour_stroke_operators = { 'G', nil, 'RG', 'K' } local colour_fill_operators = { 'g', nil, 'rg', 'k' } -local colour_pattern_spaces = { '/PsG', nil, '/PsRG', '/PsK' } +local colour_pattern_spaces = { 'PsG', nil, 'PsRG', 'PsK' } local function get_colour_params(cr) return format_numbers(colour_template[#cr], table.unpack(cr)) @@ -353,16 +280,16 @@ local function get_stroke_colour(cr) return get_colour_params(cr)..colour_stroke_operators[#cr] end -local function get_fill_colour(cr, pattern) +local function get_fill_colour(append, cr) local params = get_colour_params(cr) - if pattern then - local ptype, pname = table.unpack(pattern) + if append.pattern then + local ptype, pname = table.unpack(append.pattern) if ptype == 2 then -- coloured pattern local space = colour_pattern_spaces[#cr] - colourspaces[space].used = true - return string.format('%s cs %s%s scn', space, params, pname) + append:node(pdfres.use_resource_node('ColorSpace', space)) + return string.format('/%s cs %s%s scn', space, params, alloc.pdf_name(pname)) elseif ptype == 1 then -- uncoloured pattern - return string.format('/Pattern cs %s scn', pname) + return string.format('/Pattern cs %s scn', alloc.pdf_name(pname)) else -- should be unreachable alloc.err('Unknown pattern paint type %s', ptype) end @@ -386,7 +313,7 @@ function A.colour(append, cr, otype) end -- fill colour (possibly a pattern) if otype ~= 'outline' then - local fill = get_fill_colour(cr, append.pattern) + local fill = get_fill_colour(append, cr) append.pattern = nil -- patterns only apply to one object if fill ~= append.fill then append.fill = fill @@ -432,7 +359,7 @@ function A.linestate (append, object) end elseif append.dashed then append.dashed = false - table.insert(res, string.format('[] 0 d')) + table.insert(res, '[] 0 d') end append:literal(table.concat(res, ' ')) end @@ -505,16 +432,27 @@ end -- h close the path -- s close and draw the path (equivalent to h S) -- f fill the path (implies h) +-- f* fill the path, use even/odd rule -- b close, fill and draw the path (equivalent to h B) +-- b* close, fill and draw, use even/odd rule -- n do nothing (used for clipping paths) -local function get_path_operator (otype, open) +local function get_path_operator(otype, open) if otype == 'fill' then return 'f' elseif otype == 'outline' then return (open and 'S') or 's' elseif otype == 'both' then return 'b' + elseif otype == 'nofill' then + return '' + elseif otype == 'eofill' then + return 'f*' + elseif otype == 'eofilldraw' then + return 'b*' + else + alloc.err('Unknown path type ‘%s’', otype) + return 'f' end end @@ -557,7 +495,8 @@ local function split_specials(specials) end end -local function parse_object (append, object) +local function parse_object(append, object) + append.object_info = { } append:printobj(object) local processor = nil for sp, instr in split_specials(object.prescript) do @@ -616,29 +555,28 @@ end -- 2 fill and outline -function A.set_pen(append, object, otype, open) +process.fill_or_outline = function(append, object, otype) + append:linestate(object) + local t, appendpath if object.pen and object.pen.type == 'elliptical' then -- metapost includes nonelliptical pens in the outline - local t = mplib.pen_info(object) - append:literal(pdfnum('w', t.width)) - if otype == 'fill' then otype = 'both' end + t = mplib.pen_info(object) + if t.width ~= append.linewidth then + append:literal(pdfnum('w', t.width)) + append.linewidth = t.width + end + if otype == 'fill' then otype = 'both' end -- for in append:colour local transformed = not ( t.sx == 1 and t.rx == 0 and t.ry == 0 and t.sy == 1 and t.tx == 0 and t.ty == 0 ) - return transformed and t, get_path_operator(otype, open), otype - else - return false, get_path_operator(otype, open), otype + t = transformed and t end -end - -process.fill_or_outline = function(append, object, otype) + append:colour(object.color, otype) -- otype is 'fill' 'outline' or 'both' + otype = append.object_info.otype or otype -- 'eofill' etc. local open = object.path and object.path[1].left_type and object.path[#object.path].right_type - local t, operator, otype = append:set_pen(object, otype, open) - append:colour(object.color, otype) - append:linestate(object) - local appendpath + local operator = get_path_operator(otype, open) if t then local d = t.sx * t.sy - t.rx - t.ry local concat = function(px, py) @@ -671,6 +609,9 @@ end -- 2 specials +-- this will be pointed to the right table at the start of each run +local current_instance = false + -- pure specials are already taken care of in parse_object (they only have -- a ‘prescript’ field). process.special = function(append, object) end @@ -692,6 +633,10 @@ prescripts.latelua = function(append, str, object) end postscripts.latelua = prescripts.latelua +prescripts.OTYPE = function(append, str, object) + append.object_info.otype = append.object_info.otype or str +end + specials.BASELINE = function(append, str, object) -- object is a ‘fill’ statement with only a single point in its path (and -- will thus not have to be transformed). @@ -700,15 +645,26 @@ end -- 2 patterns +-- Saved patterns have the following fields: +-- attr the pattern attributes +-- stream the pattern drawing statements +-- painttype the paint type of the pattern (1 or 2) + +local function write_pattern_object(pat) + local objnum = pat.objnum or pdf.reserveobj() + pdf.obj(objnum, 'stream', pat.stream, pat.attr) + pdf.refobj(objnum) + return string.format('%d 0 R', objnum) +end + prescripts.fillpattern = function(append, str, object) - M.enable_resource_management() - local name = '/MnmP'..tonumber(str) - local pat = patterns[name] + local name = 'MnmP'..tonumber(str) + local pat = pdfres.get_resource('Pattern', name) if not pat then alloc.err('Unknown pattern %s', name) else append.pattern = { pat.painttype, name } - pat.used = true + append:node(pdfres.use_resource_node('Pattern', name)) end end @@ -719,9 +675,18 @@ specials.definepattern = function(append, str, object) matrix = { xx = xx, xy = xy, yx = yx, yy = yy, x = 0, y = 0 } } end +local function make_pattern_xform(head, bb) + -- regrettably, pdf.refobj does not work with xforms, so we must + -- write it to the pdf immediately, whether the pattern will be + -- used or not. + local xform = tex.saveboxresource(node.hpack(node.copy_list(head)), + '/Subtype/Form '..bb, nil, true, 4) + return string.format(' /Resources << /XObject << /PTempl %d 0 R >> >>', xform), '/PTempl Do' +end + local function definepattern(head, user, bb) local bb = bbox_fmt(table.unpack(bb)) - local pat, literals, resources = { }, { } + local pat, literals, resources = { write = write_pattern_object }, { } -- pattern content for n in node.traverse(head) do -- try if we can construct the content stream ourselves; otherwise, @@ -735,31 +700,27 @@ local function definepattern(head, user, bb) elseif n.subtype == 31 then -- restore table.insert(literals, 'Q') else - goto fail + resources, pat.stream = make_pattern_xform(head, bb) + goto continue end + else + resources, pat.stream = make_pattern_xform(head, bb) + goto continue end pat.stream = table.concat(literals, '\n') end - ::fail:: do - -- regrettably, pdf.refobj does not work with xforms, so we must - -- write it to the pdf immediately, whether the pattern will be - -- used or not. - local xform = tex.saveboxresource(node.hpack(node.copy_list(head)), - '/Subtype/Form '..bb, resources, true, 4) - resources = string.format(' /Resources << /XObject << /PTempl %d 0 R >> >>', xform) - pat.stream = '/PTempl Do' - end + ::continue:: -- construct the pattern object local i = user.pattern_info local m = i.matrix pat.painttype = tonumber(i.painttype) pat.attr = table.concat({ - string.format(' /PatternType 1 /PaintType %d /TilingType %s /XStep %f /YStep %f\n', + string.format('/PatternType 1 /PaintType %d /TilingType %s /XStep %f /YStep %f\n', i.painttype, i.tilingtype, i.xstep, i.ystep), string.format('%s\n/Matrix [ %s %s %s %s %s %s ]', bb, m.xx, m.xy, m.yx, m.yy, m.x, m.y), resources }, '') -- remember the pattern - patterns['/MnmP'..i.nr] = pat + pdfres.add_resource('Pattern', 'MnmP'..i.nr, pat) end cb.register('finish_mpfigure', function(img) @@ -787,17 +748,16 @@ local function get_transform(rect) return sx, rx, ry, sy, tx, ty end -local function make_surrounding(nd_id, head) +local function make_surrounding_box(nd_id, head) local nd = node.new(nd_id) - nd.dir = 'TLT' - nd.head = head + nd.dir, nd.head = 'TLT', head return nd end -local function apply_translation(box, tx, ty) - local horizontal = make_surrounding(0, box) - local vertical = make_surrounding(1, horizontal) - local outer = make_surrounding(0, vertical) +local function wrap_picture(head, tx, ty) + local horizontal = make_surrounding_box(0, head) + local vertical = make_surrounding_box(1, horizontal) + local outer = make_surrounding_box(0, vertical) vertical.shift = tex.sp('-'..ty..'bp') horizontal.shift = tex.sp(''..tx..'bp') return outer @@ -805,10 +765,10 @@ end local function apply_transform(rect, box) local sx, rx, ry, sy, tx, ty = get_transform(rect) - local transform = node.new(8,29) + local transform = node.new(8,29) -- pdf_setmatrix transform.next, box.prev = box, transform transform.data = string.format('%f %f %f %f', sx, rx, ry, sy) - return apply_translation(transform, tx, ty) + return wrap_picture(transform, tx, ty) end function A.box(append, object, box) @@ -827,7 +787,7 @@ end specials.CHAR = function(append, data, object) local char, font, xo, yo = table.unpack(data:explode(' ')) - local n = node.new(29) + local n = node.new(29) -- glyph n.char, n.font, n.xoffset, n.yoffset = tonumber(char), tonumber(font), tonumber(xo), tonumber(yo) append:box(object, node.hpack(n)) @@ -847,7 +807,7 @@ M.instances = instances -- 2 small instance helper functions -local default_catcodes = alloc.new_catcodetable('minim:mp:catcodes') +local default_catcodes = alloc.registernumber('minim:mp:catcodes') -- parameters: wd, ht+dp, dp local function make_transform(w, h, d) @@ -855,21 +815,27 @@ local function make_transform(w, h, d) w/65536, (h+d)/65536, d/65536) end -local function print_log (nr, res) +local status_names = { [0] = 'good', 'warning', 'error', 'fatal' } +local function print_status(st) + return string.format('status %d (%s)', st, status_names[st]) +end + +M.on_line = false +local function print_log (nr, res, why) local i = instances[nr] - -- only write to term if exit status increases + -- only write to term if on_line or if exit status increases local log, alog - if res.status > i.status then + if M.on_line or res.status > i.status then local nrlines, maxlines = 0, 16 alog = alloc.amsg log = function(...) - if nrlines == maxlines then + if M.on_line or nrlines < maxlines then + nrlines = nrlines + 1 + alloc.msg(...) + else alloc.log(...) alloc.term('╧ [... see log file for full report ...]') log, alog = alloc.log, alloc.alog - else - nrlines = nrlines + 1 - alloc.msg(...) end end else @@ -881,15 +847,11 @@ local function print_log (nr, res) report[#report] = nil end -- write out the log - if #report > 0 then - log('┌ exit status %d', res.status) - for _,line in ipairs(report) do - log('│ '..line) - end - log('└') - else - log('[ no logs for this run; exit status %d ]', res.status) + log('┌ %smetapost instance %s (%d)', why or '', i.jobname, i.nr) + for _,line in ipairs(report) do + log('│ '..line) end + log('└ %s', print_status(res.status)) -- generate error or warning if needed if res.status > i.status then if res.status == 3 then @@ -897,7 +859,7 @@ local function print_log (nr, res) elseif res.status == 2 then alloc.err('Error in metapost code. Further errors will be ignored') elseif res.status == 1 then - alloc.msg('Metapost: code caused warning') + alloc.msg('Metapost code caused warning') end end -- save the exit status for later comparison @@ -915,7 +877,6 @@ end -- 2 processing results local function process_results(nr, res) - print_log(nr, res) local pictures = {} if res.fig then alloc.alog (' (%d figures)', #res.fig) @@ -951,7 +912,7 @@ local function process_results(nr, res) end cb.call_callback('finish_mpfigure', pic) if not pic.discard then - pic.head = apply_translation(append.head, -llx, -bas) + pic.head = wrap_picture(append.head, -llx, -bas) end if debugging then alloc.msg('┌ image %s, with %s objects, %s nodes', @@ -987,8 +948,6 @@ local function default_env() return env end -local current_instance = false - local function runscript(code) local f, msg = load(code, current_instance.jobname, 't', current_instance.env) if f then @@ -1053,22 +1012,22 @@ local function maketext(text, mode) end end -local infont_box = alloc.new_box('infont box') -function M.infont(text, fnt) - local fontid = tonumber(fnt) or font.id(fnt) +local function getfontid(fnt) + return tonumber(fnt) or font.id(fnt) +end + +local typeset_box = alloc.new_box('infont box') + +local function process_typeset(text, fnt, sep, fn) tex.runtoks(function() tex.sprint(default_catcodes, string.format( - '\\setbox%d=\\hbox{\\setfontid%d\\relax', infont_box, fontid)) + '\\setbox%d=\\hbox{\\setfontid%d\\relax', typeset_box, getfontid(fnt))) tex.sprint(-2, text); tex.sprint(default_catcodes, '}') end) local res, x = { }, 0 - for n in node.traverse(tex.box[infont_box].list) do + for n in node.traverse(tex.box[typeset_box].list) do if n.id == 29 then -- glyph - table.insert(res, string.format( - 'draw image ( fill unitsquare shifted (%fpt,0) withprescript "CHAR:%d %d %d %d";' - ..'setbounds currentpicture to unitsquare transformed %s shifted (%fpt,0););', - x/65536, n.char, n.font, n.xoffset, n.yoffset, - make_transform(n.width, n.height, n.depth), x/65536)) + fn(res, n, x) x = x + n.width elseif n.id == 12 then -- glue x = x + n.width @@ -1076,7 +1035,88 @@ function M.infont(text, fnt) x = x + n.kern end end - return table.concat(res, '') + return table.concat(res, sep) +end + +function M.infont(text, fnt) + return process_typeset(text, fnt, '', function(res, n, x) + table.insert(res, string.format( + 'draw image ( fill unitsquare shifted (%fpt,0) withprescript "CHAR:%d %d %d %d";' + ..'setbounds currentpicture to unitsquare transformed %s shifted (%fpt,0););', + x/65536, n.char, n.font, n.xoffset, n.yoffset, + make_transform(n.width, n.height, n.depth), x/65536)) + end) +end + + +-- 2 glyph contours + +function M.make_glyph(glyphname, fnt) + -- gather information + if not luaotfload then + alloc.err('Luaotfload required for glyph of operator') + return { }, 10 + end + local fontid = getfontid(fnt) + local thefont = font.getfont(fontid) + local fontname = thefont.psname + local gid = luaotfload.aux.gid_of_name(fontid, glyphname) + if not gid then + alloc.err('Font %s has no glyph named %s', thefont.psname, glyphname) + return { }, 10 + end + local segments = fonts.hashes.shapes[fontid].glyphs[gid].segments + if #segments == 0 then return { }, 10 end + local q = 1000 / (thefont.units_per_em or 1000) + -- retrieve the contours + local path, paths = { '(' }, { } + for _, s in ipairs(segments) do + local op = s[#s] + if op == 'm' then + if #path > 1 then + table.insert(path, '--cycle)') + table.insert(paths, table.concat(path, '')) + path = { '(' } + end + table.insert(path, string.format('(%f, %f)', q*s[1], q*s[2])) + elseif op == 'l' then + table.insert(path, string.format('--(%f, %f)', q*s[1], q*s[2])) + elseif op == 'c' then + table.insert(path, string.format('..controls (%f, %f) and (%f, %f) .. (%f, %f)', + q*s[1], q*s[2], q*s[3], q*s[4], q*s[5], q*s[6])) + end + end + table.insert(path, '--cycle)') + table.insert(paths, table.concat(path, '')) + return paths, thefont.size +end + +function M.get_named_glyph(name, fnt) + local res, contours, size = {}, M.make_glyph(name, fnt) + for _, c in ipairs(contours) do + table.insert(res, string.format( + '%s scaled %f', c, size/65536000)) + end + return table.concat(res, ', ') +end + +local function get_glyphname(c_id) + return luaotfload.aux.name_of_slot(c_id) +end + +function M.get_glyph(c_id, fnt) + return M.get_named_glyph(get_glyphname(c_id), fnt) +end + +function M.get_contours(text, fnt) + return process_typeset(text, fnt, ', ', function(res, n, x) + local contours, size = M.make_glyph(get_glyphname(n.char), n.font) + for _, c in ipairs(contours) do + table.insert(res, string.format( + '%s scaled %f shifted (%fpt, %fpt)', c, + size/65536/1024, (x + n.xoffset)/65536, n.yoffset/65536)) + end + end) end -- 2 opening, running and and closing instances @@ -1122,27 +1162,21 @@ function M.run (nr, code) return end current_instance = self - alloc.log ('metapost: executing chunk in %s (%d)', self.jobname, nr) - local res = process_results(nr, self.instance:execute(code)) - save_image_list(self, res) + local res = self.instance:execute(code) + print_log(nr, res) + local picts = process_results(nr, res) + save_image_list(self, picts) end -M.init_files = { 'minim.mp' } +M.init_code = { 'let dump=endinput;', 'input INIT;', 'input minim.mp;' } function M.open (t) local nr = #instances + 1 t.jobname = t.jobname or ':metapost:' - alloc.log ('metapost: creating instance %s (%d)', t.jobname, nr) -- creating instance options - local init = "" - for _, f in ipairs(M.init_files) do - init = string.format('%s input %s;', init, f) - end - init = string.format('%s input %s;', init, t.format or 'plain.mp') + local init = string.gsub(table.concat(M.init_code, ''), 'INIT', t.format or 'plain.mp') local opts = apply_default_instance_opts(t) local instance = mplib.new(opts) - instance:execute(init) - local continue -- adding the instance instances[nr] = { nr = nr @@ -1154,15 +1188,15 @@ function M.open (t) , boxes = { } -- allocated by maketext , env = t.env or default_env() } + print_log(nr, instance:execute(init), 'opening ') return nr end function M.close (nr) local i = instances[nr] - alloc.log ('metapost: closing instance %s (%d) ', i.jobname, nr) if i.instance then local res = i.instance:finish() - print_log(nr, res) + print_log(nr, res, 'closing ') end for _, nr in ipairs(i.boxes) do -- remove allocated boxes diff --git a/Master/texmf-dist/tex/luatex/minim-mp/minim-mp.tex b/Master/texmf-dist/tex/luatex/minim-mp/minim-mp.tex index 8e39c7f227a..ad84a4f19df 100644 --- a/Master/texmf-dist/tex/luatex/minim-mp/minim-mp.tex +++ b/Master/texmf-dist/tex/luatex/minim-mp/minim-mp.tex @@ -6,6 +6,7 @@ \catcode`\: = 11 \input minim-alloc +\input minim-pdfresources % a default catcode table \newcatcodetable \minim:mp:catcodes @@ -30,7 +31,7 @@ % \directmetapost [ options ] { code } \protected\def\directmetapost{\withoptions[]\directmetapost:} -\def\directmetapost:[#1]#2{% +\long\def\directmetapost:[#1]#2{% \begingroup \newmetapostinstance[#1]\:mpinst: \runmetapost\:mpinst:{#2}% diff --git a/Master/texmf-dist/tex/luatex/minim-pdf/minim-languagecodes.lua b/Master/texmf-dist/tex/luatex/minim-pdf/minim-languagecodes.lua index df3e95a65e0..6a8b6f3b0b7 100644 --- a/Master/texmf-dist/tex/luatex/minim-pdf/minim-languagecodes.lua +++ b/Master/texmf-dist/tex/luatex/minim-pdf/minim-languagecodes.lua @@ -78,6 +78,7 @@ return { latvian = 'lv', lithuanian = 'lt', liturgicallatin = 'la-x-liturgic', + macedonian = 'mk', malayalam = 'ml', marathi = 'mr', medievalgreek = 'gkm', @@ -94,8 +95,10 @@ return { norwegian = 'nb', nynorsk = 'nn', occitan = 'oc', + oldgerman = 'de', oriya = 'or', pali = 'pi', + panjabi = 'pa', patois = 'fr', persian = 'fa', piedmontese = 'pms', @@ -111,6 +114,7 @@ return { sahidic = 'cop-x-sahidic', samaritan = 'smp', sanskrit = 'sa', + schoolfinnish = 'fi', serbian = 'sr-latn', serbianc = 'sr-cyrl', slovak = 'sk', @@ -129,11 +133,11 @@ return { turkish = 'tr', turkmen = 'tk', ugaritic = 'uga', - uncoded = 'mis', - undetermined = 'und', ukenglish = 'en-UK', UKenglish = 'en-UK', ukrainian = 'uk', + uncoded = 'mis', + undetermined = 'und', uppersorbian = 'hsb', usenglish = 'en-US', USenglish = 'en-US', diff --git a/Master/texmf-dist/tex/luatex/minim-pdf/minim-pdf.lua b/Master/texmf-dist/tex/luatex/minim-pdf/minim-pdf.lua index ffe845061ca..96725523d29 100644 --- a/Master/texmf-dist/tex/luatex/minim-pdf/minim-pdf.lua +++ b/Master/texmf-dist/tex/luatex/minim-pdf/minim-pdf.lua @@ -2,6 +2,7 @@ local M = { } local alloc = require('minim-alloc') local cb = require('minim-callbacks') +alloc.remember('minim-hooks') alloc.remember('minim-pdf') -- 1 helper functions @@ -18,9 +19,27 @@ local function add_to_names(...) pdf.setnames((pdf.getnames() or '') .. string.format(...) .. ' ') end +local pdf_name = alloc.pdf_name +local pdf_string = alloc.pdf_string +local options_scanner = alloc.options_scanner + +-- has this table just one element? +local function singleton(t) + local one = false + for _, _ in pairs(t) do + if one then + return false + else + one = true + end + end + return one +end + -- in-depth node list traversal -- returns current and parent node --- only dives into hbox and vbox nodes +-- only dives into hbox, vbox and ins nodes +-- returns node and enclosing box local function full_traverse(head) return function(stack, last) local next = last.next @@ -36,103 +55,8 @@ local function full_traverse(head) end, { { } }, { next = head } end --- re-encode to utf-16 and surround by <> -local function pdf_hex_string(text) - local str = { [1] = '') - return table.concat(str,'') -end - --- try and produce a () string first, then fall back to <> -function M.pdf_string(text) - local str = { '(' } - for i in text:utfvalues() do - if i > 0x7E then - return pdf_hex_string(text) - elseif i < 0x20 then - insert_formatted(str, '\\%03o', i) - elseif i == 0x28 or i == 0x29 or i == 0x5c then - insert_formatted(str, '\\%c', i) - else - insert_formatted(str, '%c', i) - end - end - table.insert(str, ')') - return table.concat(str,'') - end - --- make available as \pdfstring{...} -alloc.luadef('pdfstring', function() M.pdf_string(token.scan_string()) end) - --- try and produce a date of the format (D:YYYYMMDD) -function M.pdf_date(text) - local y, m, d = string.match(text, '^([12][0-9][0-9][0-9])-([0-9][0-9]?)-([0-9][0-9]?)$') - if not y then d, m, y = string.match(text, '^([0-9][0-9]?)-([0-9][0-9]?)-([12][0-9][0-9][0-9])$') end - if y then - return string.format('(D:%4d%02d%02d)', y, m, d) - else - return string.format('(D:%s)', text) - end -end - -function M.options_scanner() - return { scanners = { }, - add = function(this, name, scanner) - this.scanners[name] = scanner - return this - end, - keyword = function(this, name) - return this:add(name, function() return true end) - end, - int = function(this, name) - return this:add(name, token.scan_int) - end, - glue = function(this, name) - return this:add(name, token.scan_glue) - end, - dimen = function(this, name) - return this:add(name, token.scan_dimen) - end, - string = function(this, name) - return this:add(name, token.scan_string) - end, - argument = function(this, name) - return this:add(name, token.scan_argument) - end, - word = function(this, name) - return this:add(name, token.scan_word) - end, - list = function(this, name) - return this:add(name, token.scan_list) - end, - scan = function(this, defaults) - local res = defaults or { } - repeat - local matched = false - for name, scanner in pairs(this.scanners) do - if token.scan_keyword(name) then - matched, this.scanners[name] = true, nil - res[name] = scanner() - end - end - until not matched - return res - end - } -end - local function pdf_err(n, msg) - local m = node.new(8,16) + local m = node.new(8,16) -- pdf_literal m.mode, m.token = 2, '%% Warning: '..msg node.insert_after(n, n, m) end @@ -158,10 +82,10 @@ local structure = { { local parent_tree = { } -- list of list of structure elements -- Our four helper attributes -local current_struct = alloc.new_attribute('tagging:current:se') -local current_order = alloc.new_attribute('tagging:element:order') -local current_status = alloc.new_attribute('tagging:current:status') -local current_lang = alloc.new_attribute('tagging:current:language') +local current_struct = alloc.registernumber('tagging:current:se') +local current_order = alloc.registernumber('tagging:element:order') +local current_status = alloc.registernumber('tagging:current:status') +local current_lang = alloc.registernumber('tagging:current:language') local function current_structure_element() return structure[tex.attribute[current_struct]] @@ -242,7 +166,7 @@ local structure_types = alloc.saved_table('structure types', { Note = { type = 'inline' }, Reference = { type = 'inline' }, BibEntry = { type = 'inline' }, - Code = { type = 'inline' }, + Code = { type = 'inline', attributes = { ['CSS-2.00'] = { ['white-space'] = '(pre)' } } }, Link = { type = 'inline' }, -- contains link objects Annot = { type = 'inline' }, -- contains other annotations -- ruby/warichu @@ -318,7 +242,6 @@ alloc.luadef('struct:addalias', function() M.add_structure_alias(stype, alias, settings) end, 'protected') - -- 1 writing the document structure local function stable_sort_on_order_field(unsorted) @@ -373,7 +296,7 @@ local function make_rolemap() local aliases = { } for k, v in pairs(structure_types) do if v.aliasof and v.inuse and v.aliasof ~= k then - insert_formatted(aliases, '/%s/%s', k, v.aliasof) + insert_formatted(aliases, '%s%s', pdf_name(k), pdf_name(v.aliasof)) end end if #aliases > 0 then @@ -382,6 +305,33 @@ local function make_rolemap() return '' end +local function make_attributes(res, t) + -- is there just one attribute? + local list = not singleton(t) + if list then table.insert(res, '[') end + for ao, ac in pairs(t) do + insert_formatted(res, '<< /O %s', pdf_name(ao)) + for k,v in pairs(ac) do + insert_formatted(res, '%s %s', pdf_name(k), v) + end + table.insert(res, '>>') + end + if list then table.insert(res, ']') end +end + +local attribute_classes = alloc.saved_table('attribute classes') +local function make_classmap() + local classes = { } + for c, as in pairs(attribute_classes) do + insert_formatted(classes, '\n%s', pdf_name(c)) + make_attributes(classes, as) + end + if #classes > 0 then + return '\n/ClassMap << ' .. table.concat(classes, ' ') .. ' >>' + end + return '' +end + local function write_structure() if #structure == 1 then return end -- reserve object numbers, prepare for writing @@ -395,22 +345,29 @@ local function write_structure() add_to_catalog('/StructTreeRoot %s 0 R', root_obj) -- write the structure tree root pdf.immediateobj(root_obj, string.format( - '<< /Type/StructTreeRoot /K %d 0 R /ParentTree %d 0 R%s >>', - structure[1].objnum, parent_tree_obj, make_rolemap())) + '<< /Type/StructTreeRoot /K %d 0 R /ParentTree %d 0 R%s%s >>', + structure[1].objnum, parent_tree_obj, make_rolemap(), make_classmap())) -- write structure elements for _, se in ipairs(structure) do if not se.hidden then local res = { '<<' } - insert_formatted(res, '/Type/StructElem /S/%s /P %d 0 R', se.struct, se.parent.objnum) + insert_formatted(res, '/Type/StructElem /S%s /P %d 0 R', pdf_name(se.struct), se.parent.objnum) if se.lang and se.lang ~= se.parent.lang then insert_formatted(res, '/Lang (%s)', se.lang) end - if se.alt then insert_formatted(res, '/Alt %s', M.pdf_string(se.alt)) end - if se.actual then insert_formatted(res, '/ActualText %s', M.pdf_string(se.actual)) end + if se.alt then insert_formatted(res, '/Alt %s', pdf_string(se.alt)) end + if se.actual then insert_formatted(res, '/ActualText %s', pdf_string(se.actual)) end if #se.children > 0 then insert_formatted(res, '\n/K %s', format_K_array(se)) end if se.mainpage then insert_formatted(res, '/Pg %d 0 R', se.mainpage) end + if se.class then + table.insert(res, '/C') + if #se.class > 1 then table.insert(res, '[') end + for _, c in ipairs(se.class) do + insert_formatted(res, '%s', pdf_name(c)) + end + if #se.class > 1 then table.insert(res, ']') end + end if se.attributes then - table.insert(res, '/A <<') - for k,v in pairs(se.attributes) do insert_formatted(res, '/%s %s', k, v) end - table.insert(res, '>>') + table.insert(res, '/A') + make_attributes(res, se.attributes) end if se.files then table.insert(res, '/AF [') @@ -487,11 +444,10 @@ end, 'protected') -- \uselanguage patch; provide default document language -- and associate names with numbers -alloc.luadef('minim:apply:language:code', function() - local name = token.scan_string() +cb.register('uselanguage', function(name) local nr = language_codes[name] or alloc.err('No language code known for ‘%s’', name) and 1 if not structure[1].lang then M.set_document_language(language_codes[nr]) end - tex.sprint(nr) + tex.attribute['tagging:current:language'] = nr end) local function write_language() @@ -536,24 +492,20 @@ end, 'protected') function M.open_structure_node(n) local info = structure_types[n.struct] if not info then - alloc.err('Unknown structure type %s replaced by NonStruct', n.struct) + alloc.err('Unknown structure type %s replaced with NonStruct', n.struct) n.struct, info = 'NonStruct', structure_types.NonStruct end info.inuse = true if info.attributes then - n.attributes = n.attributes or { } - for k,v in pairs(info.attributes) do - n.attributes[k] = n.attributes[k] or v + n.attributes = n.attr or { } + for k1,v1 in pairs(info.attributes) do + n.attributes[k1] = n.attributes[k1] or { } + for k2, v2 in pairs(v1) do + n.attributes[k1][k2] = n.attributes[k1][k2] or v2 + end end - end - if n.block then - n.type = 'block' - n.attributes = n.attributes or { } - n.attributes.Placement = '/Block' - elseif n.inline then - n.type = 'inline' - n.attributes = n.attributes or { } - n.attributes.Placement = '/Inline' + else + n.attributes = n.attr end n.index = #structure + 1 n.children = { } @@ -573,13 +525,13 @@ function M.open_structure_node(n) end alloc.luadef('tagging:startelement', function() - local s = M.options_scanner() + local s = options_scanner() :string('type') -- 'section', 'group', 'block' etc. :argument('alt') :argument('actual') :string('lang') - :keyword('block') - :keyword('inline') + :subtable('attr') + :string('class', true) :scan() s.struct = token.scan_string() M.open_structure_node(s) @@ -593,6 +545,11 @@ alloc.luadef('tagging:actual', function() current_structure_element().actual = token.scan_string() end) +alloc.luadef('newattributeclass', function() + local s = options_scanner():subtable('attr') + attribute_classes[token.scan_string()] = s:scan().attr +end, 'protected') + -- 1 marking content items @@ -613,7 +570,7 @@ local function clear_page_tagging_parameters() _open_mci_node_ = function (se_num, order) pageobj = pageobj or pdf.getpageref(status.total_pages + 1) local se = structure[se_num] - pdf.print(string.format('/%s <> BDC ', se.struct, #mcid_list)) + pdf.print(string.format('%s <> BDC ', pdf_name(se.struct), #mcid_list)) table.insert(se.children, { mcid = #mcid_list, order = order, pageobj = pageobj }) table.insert(mcid_list, se) -- unhide hidden parents (done here to preserve the correct order) @@ -631,17 +588,13 @@ local function new_open_mci_node(se, order) return n end -local function new_open_art_node(atype) +local function pdf_literal(token) local n = node.new(8,16) -- pdf_literal - n.mode, n.token = 1, string.format('/Artifact << /Type/%s >> BDC', atype) + n.mode, n.token = 1, token return n end -local function new_emc_node() - local n = node.new(8,16) -- pdf_literal - n.mode, n.token = 1, 'EMC' - return n -end +local open_artifacts = { } cb.register('finish_pdfpage', function(shippingout) if shippingout then @@ -655,17 +608,17 @@ cb.register('finish_pdfpage', function(shippingout) end end) --- 1 content item boundaries and linking +-- 1 content item boundaries and linking (in pre-shipout) function M.mark_content_items(box) - local se, order, open + local se, order, art, open local start_node, end_node, parent_node local pageobj = pdf.getpageref(status.total_pages + 1) - -- inserting mci markers + -- helper functions for inserting mci markers local insert_tags = function(end_parent) if not open then return end parent_node.list = node.insert_before(parent_node.list, start_node, open) - node.insert_after(end_parent.list, end_node, new_emc_node()) + node.insert_after(end_parent.list, end_node, pdf_literal('EMC')) start_node, end_node, parent_node, open = nil, nil, nil, nil end local start_content = function(n, b) @@ -676,18 +629,31 @@ function M.mark_content_items(box) for n, b in full_traverse(box) do local marker = n.id == 8 and n.subtype == 8 and n.user_id == marker_whatsit and n.value - if marker and marker.what == 'art_start' then + local stat = n[current_status] -- first we start with marking artifacts + if marker and marker.what == 'art_start' then insert_tags(b); start_content(n, b) - open = new_open_art_node(marker.it) + local a = string.format('/Artifact << /Type/%s >> BDC', marker.it) + open_artifacts[stat], open, art = a, pdf_literal(a), stat elseif marker and marker.what == 'art_stop' then end_node = n insert_tags(b); - elseif n[current_status] then - -- inside artifact, do nothing - elseif n.id == 8 and n.subtype == 19 then -- pdf_start_link + open_artifacts[art], art = nil, nil + elseif stat and stat >10 and stat ~=art then -- broken artifact + insert_tags(b); + start_content(n, b) + local a = open_artifacts[stat] + if not a then + alloc.err('Encountered tail of unknown artifact (see pdf)') + pdf_err(n, 'unknown artifact (this should not be possible)') + a = '/Artifact << /Type/Unknown >> BDC' + end + open, art = pdf_literal(a), stat + elseif stat then -- inside artifact or tagging disabled + end_node = n -- then attach links to Link elements + elseif n.id == 8 and n.subtype == 19 then -- pdf_start_link local _se, _order = n[current_struct], n[current_order] local link = structure[_se] if link.struct == 'Link' then @@ -698,16 +664,16 @@ function M.mark_content_items(box) alloc.err('Link found outside Link structure element (see pdf)') pdf_err(n, 'unmarked link') end + -- handle explicit start and stop nodes elseif marker and marker.what == 'mci_start' then - -- explicit start and stop nodes insert_tags(b); start_content(n, b) open = new_open_mci_node(se, order) elseif marker and marker.what == 'mci_stop' then end_node = end_node and n; insert_tags(b) + -- finally, see if we need to intervene between content nodes elseif n.id == 2 or n.id == 29 -- rule, glyph or content marker or marker and marker.what == 'content' then - -- now see if we need to intervene between content nodes local _se, _order = n[current_struct], n[current_order] if n.id == 2 and (n.width == 0 or n.height == 0 and n.depth == 0) then -- ignore invisible rules @@ -720,8 +686,7 @@ function M.mark_content_items(box) insert_tags(b); start_content(n, b) open = new_open_mci_node(se, order) - else - -- nothing changed: continue current mci + else -- nothing changed: continue current mci end_node = n end elseif n.id == 12 and n.subtype > 2 and n.subtype < 8 then @@ -730,10 +695,6 @@ function M.mark_content_items(box) end end -- close the last mci - if start_node and start_node.user_id and start_node.value - and start_node.value.what == 'art_start' then - alloc.err('Page %d ends with a broken artifact', status.total_pages+1) - end insert_tags(box) end @@ -786,7 +747,7 @@ local function write_bookmarks() -- write bookmark objects for i=2, #bookmarks do local bm, res = bookmarks[i], { } - insert_formatted(res, '<< /Title %s\n/Parent %s 0 R /Dest (%s)', M.pdf_string(bm.title), + insert_formatted(res, '<< /Title %s\n/Parent %s 0 R /Dest (%s)', pdf_string(bm.title), bm.parent and bm.parent.outline_obj or bookmarks[1].outline_obj, bm.dest) if bm.next then insert_formatted(res, '/Next %s 0 R', bm.next.outline_obj) end if bm.prev then insert_formatted(res, '/Prev %s 0 R', bm.prev.outline_obj) end @@ -827,9 +788,8 @@ function M.add_bookmark(bm) end alloc.luadef('outline', function() - local s = M.options_scanner() - :keyword('open') - :keyword('closed') -- default; ignored + local s = options_scanner() + :keyword('open', 'closed') :string('dest') :scan() s.title = token.scan_string() @@ -866,8 +826,8 @@ function M.embed_file(t) end -- embed the file local attr = { '/Type/EmbeddedFile' } - if t.mimetype then insert_formatted(attr, '/Subtype/%s', string.gsub(t.mimetype, '/', '#2F')) end - if t.moddate then insert_formatted(attr, '/Params << /ModDate %s >>', M.pdf_date(t.moddate)) end + if t.mimetype then insert_formatted(attr, '/Subtype%s', pdf_name(t.mimetype)) end + if t.moddate then insert_formatted(attr, '/Params << /ModDate %s >>', alloc.pdf_date(t.moddate)) end local ef = pdf.obj { immediate = true, compresslevel = t.uncompressed and 0 or nil, @@ -878,7 +838,7 @@ function M.embed_file(t) -- write the filespec local res = { '<< /Type/Filespec' } insert_formatted(res, '/F %s /UF %s /EF << /F %d 0 R /UF %d 0 R >>', t.name, t.name, ef, ef) - if t.desc then insert_formatted(res, '/Desc %s', M.pdf_string(t.desc)) end + if t.desc then insert_formatted(res, '/Desc %s', pdf_string(t.desc)) end if t.relation then insert_formatted(res, '/AFRelationship /%s', t.relation) end table.insert(res, '>>') local fs = pdf.immediateobj(table.concat(res, ' ')) @@ -887,7 +847,7 @@ function M.embed_file(t) end alloc.luadef('embedfile', function() - local t = M.options_scanner() + local t = options_scanner() :string('desc') :string('file') :string('string') @@ -901,7 +861,7 @@ alloc.luadef('embedfile', function() if not t.name then t.name = t.file or aloc.err('No name specified for embedded file stream') end - t.name = M.pdf_string(t.name or '(unnamed)') + t.name = pdf_string(t.name or '(unnamed)') local fs, ef = M.embed_file(t, t.global) -- where to attach? if t.global then @@ -1036,7 +996,7 @@ local function write_pagelabels() end local res = { '/PageLabels << /Nums [' } for _, l in ipairs(pagelabels) do - local s, p = l.s and '/S/'..l.s, l.p and ' /P '..M.pdf_string(l.p) + local s, p = l.s and '/S/'..l.s, l.p and ' /P '..pdf_string(l.p) table.insert(res, string.format('%d << /St %d %s%s >>', l.start, l.st, s or '', p or '')) end table.insert(res, ']') @@ -1083,7 +1043,7 @@ function M.add_default_rgb_output_intent(t) N = 3, path = 'sRGB.icc' } end -function M.add_default_cmyk_output_intents(t) +function M.add_default_cmyk_output_intent(t) t = t or {} M.add_output_intent { subtype = t.subtype or 'GTS_PDFA1', diff --git a/Master/texmf-dist/tex/luatex/minim-pdf/minim-pdf.tex b/Master/texmf-dist/tex/luatex/minim-pdf/minim-pdf.tex index f8075ae6e43..630c374d412 100644 --- a/Master/texmf-dist/tex/luatex/minim-pdf/minim-pdf.tex +++ b/Master/texmf-dist/tex/luatex/minim-pdf/minim-pdf.tex @@ -5,6 +5,9 @@ \chardef\minimpdfloaded = \catcode`\: \catcode`\: = 11 +\input minim-alloc +\input minim-hooks + % Abbreviations used throughout this document: % se structure element % mci marked content item @@ -19,9 +22,6 @@ % 1 the attributes -\input minim-alloc -\input minim-hooks - % By three attributes do we determine the document structure. % % One for marking the current structure element: @@ -37,7 +37,8 @@ % % One for marking the status: % - assignments are generally local -% - if set, disables tagging and content marking +% - if set, disables tagging and content marking in pre_shipout +% - values >10 indicate artifacts \newattribute \tagging:current:status \tagging:current:status = \unset % % A fourth attribute keeps track of the current language @@ -53,7 +54,7 @@ % disables marking structure elements \newif\iftagging:enabled \tagging:enabledtrue \protected\def\starttagging{\tagging:enabledtrue - \ifnum1=\tagging:current:status + \ifnum0<\tagging:current:status \tagging:current:status\unset\fi} \protected\def\stoptagging{\tagging:enabledfalse \ifnum\unset=\tagging:current:status @@ -62,9 +63,12 @@ % \markartifact {Layout} {...} % \startartifact {Pagination /Subtype/Header} ... \stopartifact \long\def\markartifact#1#2{\startartifact{#1}#2\stopartifact} -\protected\def\startartifact{\begingroup\stoptagging +\protected\def\startartifact{\begingroup\tagging:enabledfalse + \tagging:current:status=\tagging:current:artifact + \global\advance\tagging:current:artifact1\relax \tagging:mci:incr\tagging:art:markstart} \protected\def\stopartifact{\tagging:art:markstop\tagging:mci:incr\endgroup} +\newcount\tagging:current:artifact \tagging:current:artifact = 11 % \startcontentitem ... \stopcontentitem \protected\def\startcontentitem{\iftagging:enabled\tagging:mci:incr\tagging:mci:markstart\fi} @@ -223,20 +227,36 @@ \def\tagging:startdisplay\fi\fi\fi#1$${\tagging:makeformula{#1}{$$}} \def\tagging:makeformula#1#2{\fi\fi\fi \global\advance\tagging:formulanr1\relax - \startelement\iftagging:indisplay block\else inline\fi{Formula}% - \setalttext{\tagging:formulasource{#1}}% - \setactualtext{\tagging:formulasource{#1}}% - \ifnum3=\pdfaconformancelevel - \embedfile mimetype text/x-tex - relation Source desc {Equation source} - name {\formulafilename.tex} - string {\tagging:formulasource{#1}}\fi + \startelement attr Layout Placement \iftagging:indisplay/Block\else/Inline + % some html converters ignore Placement attributes + attr CSS-2.00 display (inline)\fi{Formula}% + \formulasource:set{#1}% \scantextokens{#1}#2} \def\tagging:formulasource#1{% $\iftagging:indisplay$\fi \unexpanded{#1}% $\iftagging:indisplay$\fi} +% \includeformulasources {none|actualtext|attachment|both} +\def\includeformulasources#1{% + \expandafter\let + \expandafter\formulasource:set + \csname formulasource:#1\endcsname} +\def\formulasource:none#1{} +\def\formulasource:actualtext#1{% + \setactualtext{\tagging:formulasource{#1}}} +\def\formulasource:attachment#1{% + \ifnum3=\pdfaconformancelevel + \embedfile mimetype text/x-tex + relation Source desc {Equation source} + name {\formulafilename.tex} + string {\tagging:formulasource{#1}}\fi} +\def\formulasource:both#1{% + \formulasource:actualtext{#1}% + \formulasource:attachment{#1}} +\includeformulasources{both} + + % 1 hyperlinks % provided by the lua module: @@ -265,20 +285,6 @@ % provided by the lua module: % \setdocumentlanguage {name or code} % \setlanguagecode {name} {code} -% \minim:apply:language:code{name} → index - -% patch in language codes to \uselanguage -\ifcsname uselanguage@hook\endcsname - \expandafter\let - \expandafter\minim:uselanguagehook - \lastnamedcs \fi -\expandafter\edef\csname uselanguage@hook\endcsname#1{% - % tagging support - \noexpand\tagging:current:language - \noexpand\minim:apply:language:code{#1}% - % previous definitions - \ifdefined\minim:uselanguagehook - \noexpand\minim:uselanguagehook{#1}\fi} % \newnamedlanguage {name} {lhm} {rhm} \def\newnamedlanguage#1#2#3{% diff --git a/Master/texmf-dist/tex/luatex/minim-xmp/minim-xmp.lua b/Master/texmf-dist/tex/luatex/minim-xmp/minim-xmp.lua index ba01344ccd5..95275aef358 100644 --- a/Master/texmf-dist/tex/luatex/minim-xmp/minim-xmp.lua +++ b/Master/texmf-dist/tex/luatex/minim-xmp/minim-xmp.lua @@ -2,6 +2,7 @@ local M = { } local alloc = require('minim-alloc') alloc.remember('minim-xmp') +local cb = require('minim-callbacks') local function sorted_pairs(t) local keys, i = { }, 0 @@ -506,11 +507,13 @@ M.aliases = { version = { 'xmpMM:VersionID' }, } -callback.register('finish_pdffile', function() +cb.register('finish_pdffile', function() + if tex.count['writedocumentmetadata'] == 0 then return end if #XMP > 1 then alloc.err('Not all metadata has been written out.') XMP = { [1] = XMP[1] } - elseif #XMP > 0 then + end + if #XMP > 0 then local metadata_obj = M.write_metadata() local catalog = pdf.getcatalog() or '' pdf.setcatalog(catalog..string.format('/Metadata %s 0 R', metadata_obj)) diff --git a/Master/texmf-dist/tex/luatex/minim-xmp/minim-xmp.tex b/Master/texmf-dist/tex/luatex/minim-xmp/minim-xmp.tex index 2ec4adc8958..2548ad857bf 100644 --- a/Master/texmf-dist/tex/luatex/minim-xmp/minim-xmp.tex +++ b/Master/texmf-dist/tex/luatex/minim-xmp/minim-xmp.tex @@ -19,6 +19,10 @@ \newcount \metadataseparator \metadataseparator = `\; +% \writedocumentmetadata +\newcount \writedocumentmetadata +\writedocumentmetadata = 1 + % Defined from the lua side: % % \getmetadata ns:key diff --git a/Master/texmf-dist/tex/luatex/minim/minim-alloc.lua b/Master/texmf-dist/tex/luatex/minim/minim-alloc.lua index c99ca2c73d1..8f6a69ed0d5 100644 --- a/Master/texmf-dist/tex/luatex/minim/minim-alloc.lua +++ b/Master/texmf-dist/tex/luatex/minim/minim-alloc.lua @@ -27,6 +27,131 @@ function M.err (...) tex.error(string.format(...)) end +-- 1 pdf helpers + +local function insert_formatted(t, ...) + table.insert(t, string.format(...)) +end + +local function hexify(c) + return string.format('#%02x', c:byte()) +end +function M.pdf_name(n) + return '/'..n + :gsub('[][(){}<>#%%/\\]', hexify) + :gsub('%G', hexify) +end + +-- re-encode to utf-16 +local function pdf_hex_string(text) + local str = { [1] = '') + return table.concat(str,'') +end +local function octify(c) + return string.format('\\%03o', c:byte()) +end +function M.pdf_string(text) + -- do note that \ddd is decimal in lua, octal in pdf + if text:match('[^%g\009\010\13 ]') then + return pdf_hex_string(text) + else + return string.format('(%s)', text + :gsub('[()\\]','\\%0') + :gsub('%c', octify)) + end +end + +-- try and produce a date of the format (D:YYYYMMDD) +function M.pdf_date(text) + local y, m, d = string.match(text, '^([12][0-9][0-9][0-9])-([0-9][0-9]?)-([0-9][0-9]?)$') + if not y then d, m, y = string.match(text, '^([0-9][0-9]?)-([0-9][0-9]?)-([12][0-9][0-9][0-9])$') end + if y then + return string.format('(D:%4d%02d%02d)', y, m, d) + else + return string.format('(D:%s)', text) + end +end + +-- 1 scanning helpers + +local function make_scanner(fn) + return function(this, name, multiple) + this.scanners[name] = multiple and function() + this.res[name] = this.res[name] or { } + table.insert(this.res[name], fn()) + end or function() + this.scanners[name] = nil + this.res[name] = fn() + end + return this + end +end + +function M.options_scanner() + return { scanners = { }, res = { }, + int = make_scanner(token.scan_int), + glue = make_scanner(token.scan_glue), + dimen = make_scanner(token.scan_dimen), + string = make_scanner(token.scan_string), + argument = make_scanner(token.scan_argument), + word = make_scanner(token.scan_word), + list = make_scanner(token.scan_list), + keyword = function(this, name, opposite) + this.scanners[name] = function() + this.res[name] = true + if opposite then this.res[opposite] = false end + end + if opposite then + this.scanners[opposite] = function() + this.res[name] = false + this.res[opposite] = true + end + end + return this + end, + table = function(this, name) + this.scanners[name] = function() + this.res[name] = this.res[name] or { } + this.res[name][token.scan_string()] = token.scan_string() + end + return this + end, + subtable = function(this, name) + this.scanners[name] = function() + this.res[name] = this.res[name] or { } + local sub = token.scan_string(); + this.res[name][sub] = this.res[name][sub] or { } + this.res[name][sub][token.scan_string()] = token.scan_string() + end + return this + end, + scan = function(this, defaults) + this.res = defaults or this.res + repeat + local matched = false + for name, scanner in pairs(this.scanners) do + if token.scan_keyword(name) then + matched = true + scanner() + end + end + until not matched + return this.res + end + } +end + -- 1 saving modules and tables local tables = package.loaded['minim-saved-tables'] @@ -70,7 +195,7 @@ function M.table_to_text (tbl) return '{ ' .. table.concat (r,', ') .. ' }' end -require('minim-callbacks') +local cb = require('minim-callbacks') M.remember('minim-callbacks') M.remember('minim-alloc') @@ -79,11 +204,23 @@ M.remember('minim-alloc') -- like \unset M.unset = -0x7FFFFFFF -local allocations = M.saved_table ('minim:allocations') +-- works for both \chardef and the likes of \countdef +function M.registernumber(csname) + if token.is_defined(csname) then + return token.create(csname).index + else + return -- would return 0 otherwise + end +end + +-- we need remember lua-made allocations in the format file, since otherwise, +-- a different register will be reserved when the lua code is seen again in the +-- actual run. +local allocations = M.saved_table('minim lua-side allocations') -local function make_alloc_new (fname, globcount) +local function make_alloc_new(fname, globcount) allocations[fname] = allocations[fname] or { } - M['new_'..fname] = function (id) + M['new_'..fname] = function(id) local nr if id and allocations[fname][id] then nr = allocations[fname][id] @@ -108,7 +245,7 @@ make_alloc_new ('userrule' , 'e@alloc@rule@count' ) -- We need different allocation functions for the older registers, because -- etex’s global allocation macros are off-by-one w.r.t. all other. -- -local function make_alloc_old (fname, globcount, loccount) +local function make_alloc_old(fname, globcount) allocations[fname] = allocations[fname] or { } M['new_'..fname] = function (id) local nr @@ -122,21 +259,16 @@ local function make_alloc_old (fname, globcount, loccount) end return nr end - M['local_'..fname] = function () - local nr = tex.count[loccount] - 1 - tex.setcount(loccount, nr) - return nr - end end -- existing allocation counters -make_alloc_old ('count', 260, 270 ) -make_alloc_old ('dimen', 261, 271 ) -make_alloc_old ('skip', 262, 272 ) -make_alloc_old ('muskip', 263, 273 ) -make_alloc_old ('box', 264, 274 ) -make_alloc_old ('toks', 265, 275 ) -make_alloc_old ('marks', 266, 276 ) +make_alloc_old ('count', 260 ) +make_alloc_old ('dimen', 261 ) +make_alloc_old ('skip', 262 ) +make_alloc_old ('muskip', 263 ) +make_alloc_old ('box', 264 ) +make_alloc_old ('toks', 265 ) +make_alloc_old ('marks', 266 ) function M.luadef (csname, fn, ...) local nr = M.new_function(csname) @@ -144,8 +276,19 @@ function M.luadef (csname, fn, ...) token.set_lua(csname, nr, ...) end -M.luadef ('minim:rememberalloc', function() - allocations[token.scan_string()][token.scan_string()] = tex.count['allocationnumber'] +-- the current file +M.luadef('minim:currentfile', function() + tex.sprint((status.filename:gsub('^.*/', ''))) +end) + +-- make pdf_string() available as \pdfstring{...} +M.luadef('pdfstring', function() M.pdf_string(token.scan_string()) end) + +-- uselanguage hook callback +cb.new_callback('uselanguage', 'simple') +M.luadef('minim:uselanguagecallback', function() + local langname = token.scan_string() + cb.call_callback('uselanguage', langname) end) -- 1 dumping information to the format file @@ -188,7 +331,7 @@ local function dump_saved_tables() lua.bytecode[saved_tables_bytecode] = load(saved_tables) end -callback.register ('pre_dump', dump_saved_tables) +cb.register ('pre_dump', dump_saved_tables) -- diff --git a/Master/texmf-dist/tex/luatex/minim/minim-alloc.tex b/Master/texmf-dist/tex/luatex/minim/minim-alloc.tex index 66f08c90459..8752c2e3362 100644 --- a/Master/texmf-dist/tex/luatex/minim/minim-alloc.tex +++ b/Master/texmf-dist/tex/luatex/minim/minim-alloc.tex @@ -62,58 +62,48 @@ % 1 ltluatex compatibility +% \ProvidesFile identifies most problematic files +\ifdefined \ProvidesFile + \let\minim:providesfile=\ProvidesFile\else + \def\minim:providesfile#1#2[#3]{% + \wlog{Loading file #1 version #3.}}\fi +\def\ProvidesFile#1{\begincsname minim:intercept:#1\endcsname + \minim:providesfile{#1}} + + % repair ltluatex, which, without apparent reason, resets all allocation % counters, even if they already exist -\def\minim:ltltx:file{ltluatex.tex} -\let\ProvidesFile:saved=\ProvidesFile -\def\ProvidesFile#1#2[#3]{% - \ifdefined\ProvidesFile:saved \ProvidesFile:saved{#1}#2[#3]\fi - \def\minim:ltltx:arg{#1}% - \ifx\minim:ltltx:file\minim:ltltx:arg - \let\ProvidesFile=\ProvidesFile:saved - \let\endinput:saved=\endinput - \protected\edef\endinput{% - \minim:ltltx:fix{e@alloc@attribute@count}% - \minim:ltltx:fix{e@alloc@whatsit@count}% - \minim:ltltx:fix{e@alloc@bytecode@count}% - \minim:ltltx:fix{e@alloc@luafunction@count}% - \minim:ltltx:fix{e@alloc@luachunk@count}% - \minim:ltltx:fix{e@alloc@ccodetable@count}% - % also patch in remembering allocations to lua - \alloc:patch \noexpand\attribute - \alloc:patch \noexpand\whatsit - \alloc:patch \noexpand\luabytecode - \alloc:patch \noexpand\luachunkname - \alloc:patch \noexpand\catcodetable - \alloc:patch \noexpand\userrule - % restore register allocation functions - \directlua{ local C = require('minim-callbacks') - callback.register, callback.find, callback.list - = C.register, C.find, C.list }% - \let\noexpand\endinput=\noexpand\endinput:saved - \noexpand\endinput}\fi} +\expandafter\def\csname minim:intercept:ltluatex.tex\endcsname + {\wlog{minim: applying ltluatex patches.}% + \edef\endinput{\let\noexpand\endinput=\noexpand\minim:endinput + \minim:ltltx:fix{e@alloc@attribute@count}% + \minim:ltltx:fix{e@alloc@whatsit@count}% + \minim:ltltx:fix{e@alloc@bytecode@count}% + \minim:ltltx:fix{e@alloc@luafunction@count}% + \minim:ltltx:fix{e@alloc@luachunk@count}% + \minim:ltltx:fix{e@alloc@ccodetable@count}% + % restore register allocation functions + \noexpand\directlua{ callback.register = + require('minim-callbacks').primitiveregister }% + \noexpand\endinput}} +\let\minim:endinput = \endinput \def\minim:ltltx:fix#1{% \ifnum0<\the\csname#1\endcsname \wlog{Restoring \csname#1\endcsname to previous value \the\csname#1\endcsname}% \expandafter\noexpand\csname#1\endcsname =\the\csname#1\endcsname\relax\fi} -\protected\def\alloc:patch#1{% - \expandafter\expandafter\expandafter\let - \expandafter\expandafter\csname\csstring#1:ltluatex:new\endcsname - \csname new\csstring#1\endcsname - \expandafter\edef\csname new\csstring#1\endcsname##1{% - \noexpand\minim:rememberalloc{\csstring#1}{\noexpand\csstring##1}% - \expandafter\noexpand\csname\csstring#1:ltluatex:new\endcsname{##1}}} % 1 allocation % use global allocation (see etex.src) -\let\newcount = \globcount -\let\newdimen = \globdimen -\let\newskip = \globskip -\let\newmuskip = \globmuskip -\let\newbox = \globbox -\let\newtoks = \globtoks -\let\newmarks = \globmarks +\ifdefined \globcount + \let\newcount = \globcount + \let\newdimen = \globdimen + \let\newskip = \globskip + \let\newmuskip = \globmuskip + \let\newbox = \globbox + \let\newtoks = \globtoks + \let\newmarks = \globmarks +\fi % new allocation macros @@ -121,8 +111,7 @@ \unless\ifcsname#3\endcsname \expandafter\newcount \csname#3\endcsname \csname#3\endcsname 0\fi - \ifcsname new\csstring#1\endcsname - \alloc:patch#1\else + \unless\ifcsname new\csstring#1\endcsname \expandafter\edef\csname new\csstring#1\endcsname{% \noexpand\minim:alloc\noexpand#1\noexpand#2% \expandafter\noexpand\csname#3\endcsname}\fi} @@ -131,9 +120,7 @@ \global\advance#31% \allocationnumber#3% \global#2#4\allocationnumber - \wlog{\string#4=\string#1\the\allocationnumber}% - % minim:rememberalloc will be defined from lua side - \minim:rememberalloc{\csstring#1}{\csstring#4}} + \wlog{\string#4=\string#1\the\allocationnumber}} % all names and counters below are identical to those from ltluatex % note: we cannot use \newluafunction, or ltluatex will not load @@ -147,7 +134,10 @@ % initialise new catcode tables \def\catcode:chardef#1#2{\chardef#1#2\initcatcodetable#2} -\csname e@alloc@ccodetable@count\endcsname = 4 % because ltluatex allocates 4... +% ltluatex initialises the catcode tables 1–4, so we make sure not to claim +% those ourselves: +\ifnum\csname e@alloc@ccodetable@count\endcsname = 0 + \csname e@alloc@ccodetable@count\endcsname = 4 \fi % set initial chunk name value \def\chardef:chunk#1#2{\chardef#1#2\directlua{lua.name[\the#2]='\csstring#1'}} @@ -156,17 +146,22 @@ \protected\def\setluachunkname#1#2{\newluachunkname#1% \directlua{lua.name[\the#1]='\luaescapestring{#2}'}} -% patch in remembering box allocations -\def\minim:boxchardef#1{% - \minim:rememberalloc{box}{\csstring#1}% - \mathchardef#1} -\edef\newbox{% - \expandafter\noexpand\csname et@xglob\endcsname - 4\box\noexpand\minim:boxchardef} - % undefine our helper functions \let\alloc:makenew=\undefined +% patch in our callback to \uselanguage +% \minim:uselanguagecallback is defined from Lua +\ifcsname uselanguage@hook\endcsname + \expandafter\let + \expandafter\minim:uselanguagehook + \lastnamedcs \fi +\expandafter\edef\csname uselanguage@hook\endcsname#1{% + % our uselanguage callback + \noexpand\minim:uselanguagecallback{#1}% + % previous definitions + \ifdefined\minim:uselanguagehook + \noexpand\minim:uselanguagehook{#1}\fi} + % 1 format file compatibility % all other work is done at the lua end diff --git a/Master/texmf-dist/tex/luatex/minim/minim-callbacks.lua b/Master/texmf-dist/tex/luatex/minim/minim-callbacks.lua index 3ac075dc01f..af3db59e243 100644 --- a/Master/texmf-dist/tex/luatex/minim/minim-callbacks.lua +++ b/Master/texmf-dist/tex/luatex/minim/minim-callbacks.lua @@ -1,41 +1,51 @@ local M = {} -local function log(msg, ...) +local function log(...) end +local function alog(...) end +local function do_log(msg, ...) texio.write_nl('log', string.format(msg, ...)) end -- 1 capturing the callback mechanism --- if ltluatex is loaded, we must get callback.register back -if luatexbase ~= nil then - local luatex_base = luatexbase - luatexbase.uninstall () - luatexbase = luatex_base -end - local primitives = { } M.primitives = primitives primitives.register = callback.register primitives.find = callback.find primitives.list = callback.list -local own_callbacks = {} -local callback_lists = {} +-- use the ltluatex functions if needed +local primitive_register = primitives.register +if luatexbase then + primitive_register = function(cb, f) + if f == nil then + luatexbase.remove_from_callback(cb, 'minim callback') + elseif f == false then + luatexbase.disable_callback(cb) + else + luatexbase.add_to_callback(cb, f, 'minim callback') + end + end +end + + +local own_callbacks = {} +local callback_lists = {} local callback_stacks = {} -- 1 finding callbacks -function M.find (name) - local f = own_callbacks[name] +function M.find(cb) + local f = own_callbacks[cb] if f == nil then - return primitives.find(name) + return primitives.find(cb) else return f end end -function M.list (name) +function M.list() local t = {} for n,f in pairs(callback_lists) do if f then @@ -44,14 +54,16 @@ function M.list (name) t[n] = false end end - for n,f in pairs(own_callbacks) do + -- no stack callbacks, since the active callback is in one of the two below + for n,f in pairs(primitives.list()) do if f then t[n] = t[n] or true else t[n] = t[n] or false end end - for n,f in pairs(primitives.list()) do + -- this might obscure primitive callbacks (this is intended) + for n,f in pairs(own_callbacks) do if f then t[n] = t[n] or true else @@ -63,42 +75,73 @@ end -- 1 registering callbacks -local function register_simple (cb,f) +local function register_simple(cb,f) -- prefer user-defined callbacks over built-in - local x = own_callbacks[cb] - if x == nil then - return primitives.register (cb, f) + local own = own_callbacks[cb] + log ('callback %s: %s (%s)', f == nil and 'removed' or f and 'set' or 'disabled', + cb, own == nil and 'primitive' or 'user-defined') + if own == nil then -- may be set to ‘false’ + return primitive_register(cb, f) else - -- default to false because nil would delete the callback itself - own_callbacks[cb] = f or false + own_callbacks[cb] = f or false -- ‘nil’ would delete the callback return -1 end end -- will be redefined later -local function announce_callback(cb, f) end -function M.register (cb, f) - announce_callback(cb, f) +function M.register(cb, f) local list = callback_lists[cb] + if list then + if f == nil then + return tex.error('Use ‘deregister’ for removing list callbacks') + else + list[#list+1] = f + log('callback set: %s (#%d on list)', cb, #list) + return -2 + end + end local stack = callback_stacks[cb] if stack then if f == nil then -- pop local p = stack[#stack] stack[#stack] = nil - return register_simple (cb,p) + return register_simple(cb,p) else -- push - stack[#stack+1] = M.find (cb) - return register_simple (cb,f) + stack[#stack+1] = M.find(cb) + return register_simple(cb,f) end - elseif list ~= nil then - list[#list+1] = f - return -2 - else - return register_simple (cb,f) end + return register_simple(cb, f) end +function M.deregister(cb, f) + local list = callback_lists[cb] + if list then + for i,g in ipairs(list) do + if f == g then + log('callback removed: %s (#%d on list)', cb, i) + table.remove(list, i) + return true, -2 + end + end + return false + end + local stack = callback_stacks[cb] + if stack then + for i,g in ipairs(stack) do + if f == g then + log('callback removed: %s (#%d on stack)', cb, i) + table.remove(stack, i) + return true, -3 + end + end + -- no return: fall through to next + end + if f == M.find(cb) then + return true, register_simple(cb, nil) + end +end -- 1 lists of callback functions @@ -169,22 +212,40 @@ function M.call_callback (name, ...) end end +-- 1 replace the primitive registering + +-- TODO: preserve return values +local primitively_registered = { } +function M.primitiveregister(cb, f) + local rv = false + if f == nil then + f = primitively_registered[cb] + if f == nil then + rv = M.register(cb) + else + _, rv = M.deregister(cb, f) + end + else + rv = M.register(cb, f) + end + alog(' through primitive interface') + primitively_registered[cb] = f + return rv +end + + -- 1 initialisation -- save all registered callbacks -local saved = {} -for n,s in pairs(primitives.list()) do - if s then - log('save callback: %s', n) - saved[n] = callback.find(n) +if not luatexbase then + for n,s in pairs(primitives.list()) do + if s then + do_log('save callback: %s', n) + primitively_registered[n] = primitives.find(n) + end end end --- replace the primitive registering -callback.register = M.register -callback.find = M.find -callback.list = M.list - -- string processing callbacks register_list ('process_input_buffer', call_list_data) register_list ('process_output_buffer', call_list_data) @@ -202,7 +263,7 @@ register_list ('pre_output_filter', call_list_node) M.new_callback ('mlist_to_mlist', 'node') M.new_callback ('mlist_to_hlist', 'stack') M.register ('mlist_to_hlist', node.mlist_to_hlist ) -primitives.register ('mlist_to_hlist', function (head, ...) +primitive_register ('mlist_to_hlist', function (head, ...) local newhead = M.call_callback ('mlist_to_mlist', head, ...) if newhead ~= true then head = newhead or head @@ -232,7 +293,7 @@ stack_callback ('build_page_insert') -- process_rule M.new_callback ('process_rule', 'simple') -primitives.register ('process_rule', function (rule, ...) +primitive_register ('process_rule', function (rule, ...) local p = own_callbacks[rule.index] if p then p (rule, ...) @@ -242,23 +303,23 @@ primitives.register ('process_rule', function (rule, ...) end) -- restore all registered callbacks -for n,f in pairs(saved) do - log('restore callback: %s', n) - M.register (n,f) +for n,f in pairs(primitively_registered) do + do_log('restore callback: %s', n) + M.primitiveregister (n,f) end saved = nil +-- -local function announce_callback(cb, f) - if f then - log('callback added: %s', cb) - else - log('callback removed: %s', cb) - end -end - +-- replace primitive callbacks +callback.find = M.find +callback.list = M.list +callback.register = M.primitiveregister --- +log = do_log +local function alog(msg, ...) + texio.write('log', string.format(msg, ...)) +end return M diff --git a/Master/texmf-dist/tex/luatex/minim/minim-doc.sty b/Master/texmf-dist/tex/luatex/minim/minim-doc.sty index 1d3c2d4ceaf..93e770153b4 100644 --- a/Master/texmf-dist/tex/luatex/minim/minim-doc.sty +++ b/Master/texmf-dist/tex/luatex/minim/minim-doc.sty @@ -6,6 +6,7 @@ \expandafter\endinput\fi \input minim +%\decompressedpdf \pdfalevel 3a \overfullrule = 0pt @@ -15,7 +16,6 @@ \pdfvariable horigin 0pt \pdfvariable vorigin 0pt \frenchspacing -\raggedbottom \uselanguage{ukenglish} \hyphenation { @@ -38,27 +38,27 @@ % 1 fonts \input luaotfload.sty -\font\tenrm {Latin Modern Roman:script=latn;protrusion=default} at 10pt -\font\tenbf {Latin Modern Roman/B:script=latn} at 10pt -\font\tenit {Latin Modern Roman/I:script=latn} at 10pt -\font\tentt {Latin Modern Mono:script=latn;+smcp} at 10pt -\font\title {Latin Modern Roman/B:script=latn} at 12pt -\font\Title {Latin Modern Roman/B:script=latn} at 16pt - -\font\tenmath {Latin Modern Math:mode=base;script=math;ssty=0} at 10pt -\font\tenmaths {Latin Modern Math:mode=base;script=math;ssty=1} at 7pt -\font\tenmathss {Latin Modern Math:mode=base;script=math;ssty=2} at 5pt -\textfont 0 = \tenmath -\scriptfont 0 = \tenmaths -\scriptscriptfont 0 = \tenmathss - -\font\altmath {Tex Gyre Pagella Math:mode=base;script=math;ssty=0} at 10pt -\font\altmaths {Tex Gyre Pagella Math:mode=base;script=math;ssty=1} at 7pt -\font\altmathss {Tex Gyre Pagella Math:mode=base;script=math;ssty=2} at 5pt +\font\tenrm {Latin Modern Roman:script=latn;protrusion=default;} at 10pt +\font\tenbf {Latin Modern Roman/B:script=latn;} at 10pt +\font\tenit {Latin Modern Roman/I:script=latn;} at 10pt +\font\tentt {Latin Modern Mono:script=latn;+smcp;} at 10pt +\font\title {Latin Modern Roman/B:script=latn;} at 12pt +\font\Title {Latin Modern Roman/B:script=latn;} at 16pt + +\font\altmath {Tex Gyre Pagella Math:mode=base;script=math;ssty=0;} at 10pt +\font\altmaths {Tex Gyre Pagella Math:mode=base;script=math;ssty=1;} at 7pt +\font\altmathss {Tex Gyre Pagella Math:mode=base;script=math;ssty=2;} at 5pt \textfont 1 = \altmath \scriptfont 1 = \altmaths \scriptscriptfont 1 = \altmathss +\font\tenmath {Latin Modern Math:mode=base;script=math;ssty=0;} at 10pt +\font\tenmaths {Latin Modern Math:mode=base;script=math;ssty=1;} at 7pt +\font\tenmathss {Latin Modern Math:mode=base;script=math;ssty=2;} at 5pt +\textfont 0 = \tenmath +\scriptfont 0 = \tenmaths +\scriptscriptfont 0 = \tenmathss + \expandglyphsinfont \tenrm 40 25 5 \protrudechars=2 \adjustspacing=2 \tenrm @@ -67,21 +67,31 @@ % 1 code typesetting -\def\red#1{\quitvmode\pdfextension - literal{0.75 0 0 rg}{#1}\pdfextension literal{0 g}} +\chardef\thecolourstack = \pdffeedback colorstackinit page {0 g 0 G} +\def\pushcolour#1{\pdfextension colorstack \thecolourstack push {#1}} +\def\popcolour{\pdfextension colorstack \thecolourstack pop\relax} +\def\red#1{\pushcolour{0.75 0 0 rg}{#1}\popcolour} \def\emph#1{{\tenit #1\/}} +\newattributeclass Code + attr Layout Placement /Block + attr CSS-2.00 display (block) + \def\breakablespace{\penalty0~} \catcode`\⟦=\active \def⟦{\quitvmode\begingroup\catcode`\∥=0\relax \markparagraphsfalse \def\do##1{\catcode`##1=12}\dospecials - \catcode`\ =\active - \letcharcode`\ =\breakablespace\obeylines - \parskip0pt\tentt + \catcode`\%=\active \letcharcode`\%=\verbatimcomment + \catcode`\ =\active \letcharcode`\ =\breakablespace + \def\par{\ifhmode\tentt\endgraf\else\vskip\baselineskip\fi}% + \everypar{\stopelement{Code}% + \startelement class Code {Code}}% + \parskip0pt\tentt \obeylines \nextif*{\verbatim\ignore}{\expandafter\ignore\verbatim}} \def\verbatim#1⟧{\red{\markelement{Code}{#1}}\endgroup} +\def\verbatimcomment{\tenit\Uchar`\%} % 1 the minim symbol @@ -109,7 +119,6 @@ endfig;} \setbox\notehead=\hbox{\markartifact{Layout}{\box\notehead}} \closemetapostinstance \mnmMP -% % 1 document structure % page artifacts @@ -134,9 +143,9 @@ endfig;} \ensurestopelement{Section}% \startelement{Chapter}% \outline open {#1}% - \nextpartag{H}\red{\Title#1\hfill\copy\notehead}% \addtotoc{\chapter{#1}{\lastdestinationname}}% - \bigskip} + \nextpartag{H}\quitvmode + \red{\Title#1\hfill\copy\notehead}\bigskip\nobreak} % \section Title \par \addstructuretype Sect Section @@ -144,8 +153,8 @@ endfig;} \bigskip\penalty-50\relax \startelement{Section}% \outline closed {#1}% - \nextpartag{H}\quitvmode \addtotoc{\section{#1}{\lastdestinationname}}% + \nextpartag{H}\quitvmode \red{\title#1}% \par\nobreak} @@ -200,7 +209,6 @@ obtained at {\hyperlink url {https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12}% https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12\endlink}$$\startformulatagging} - % for identifying which file we are typesetting \edef\thejobname{\expandafter\scantextokens\expandafter{\jobname}} \newif \ifchapter diff --git a/Master/texmf-dist/tex/luatex/minim/minim-hooks.lua b/Master/texmf-dist/tex/luatex/minim/minim-hooks.lua index c399547c9e7..f11ce27875e 100644 --- a/Master/texmf-dist/tex/luatex/minim/minim-hooks.lua +++ b/Master/texmf-dist/tex/luatex/minim/minim-hooks.lua @@ -1,13 +1,11 @@ --- Adds a callback just before a box is shipped out, opposite to --- 'finish_pdfpage'. - -local alloc = require('minim-alloc') local cb = require ('minim-callbacks') -alloc.remember('minim-hooks') local M = { } +-- Add a callback just before a box is shipped out, opposite to +-- 'finish_pdfpage'. + cb.new_callback('pre_shipout', 'simple') M.primitive_shipout = tex.shipout @@ -16,15 +14,5 @@ function tex.shipout(nr) M.primitive_shipout(nr) end -local shipout_box = alloc.new_box('minim:shipout:box') - -alloc.luadef('minim:shipout', function() - tex.box[shipout_box] = token.scan_list() - cb.call_callback('pre_shipout', shipout_box) - -- we must let tex do the rest, because some other package may have - -- redefined \shipout before us. - tex.sprint(token.create('minim:shipout:do')) -end, 'protected') - return M diff --git a/Master/texmf-dist/tex/luatex/minim/minim-hooks.tex b/Master/texmf-dist/tex/luatex/minim/minim-hooks.tex index b3b80926541..deef66fc9a6 100644 --- a/Master/texmf-dist/tex/luatex/minim/minim-hooks.tex +++ b/Master/texmf-dist/tex/luatex/minim/minim-hooks.tex @@ -21,13 +21,17 @@ \chardef\minimhooksloaded = \catcode`\: \catcode`\: = 11 -\input minim-alloc +\directlua{ require('minim-hooks') } % 1 the pre_shipout callback \newbox\minim:shipout:box \let\minim:shipout:orig = \shipout \def\minim:shipout:do{\minim:shipout:orig\box\minim:shipout:box} -\directlua{require('minim-hooks')} \let\shipout\minim:shipout +\protected\def\minim:shipout:new{\directlua{ + tex.box[\the\minim:shipout:box] = token.scan_list() + require('minim-callbacks').call_callback('pre_shipout', \the\minim:shipout:box) + token.put_next(token.create('minim:shipout:do'))}} +\let\shipout = \minim:shipout:new % 1 invisibly adding to \everypar diff --git a/Master/texmf-dist/tex/luatex/minim/minim-lmodern.tex b/Master/texmf-dist/tex/luatex/minim/minim-lmodern.tex index 61bc0054e94..e420dd2a1c0 100644 --- a/Master/texmf-dist/tex/luatex/minim/minim-lmodern.tex +++ b/Master/texmf-dist/tex/luatex/minim/minim-lmodern.tex @@ -11,15 +11,15 @@ \def\preloadfont#1#2#3{\def#1{\initfontloader\font#1{#2}at#3#1}} \def\initfontloader{\input luaotfload.sty \let\initfontloader=\relax} -\preloadfont \tenrm {Latin Modern Roman:script=latn;+liga;+kern;+dlig}{10pt} -\preloadfont \tenit {Latin Modern Roman/I:script=latn;+liga;+kern;+dlig}{10pt} -\preloadfont \tenbf {Latin Modern Roman/B:script=latn;+liga;+kern;+dlig}{10pt} -\preloadfont \tensl {Latin Modern Roman Slanted:script=latn;+liga;+kern;+dlig}{10pt} -\preloadfont \tentt {Latin Modern Mono:script=latn;+liga;+kern;+dlig}{10pt} - -\preloadfont\tenmath {Latin Modern Math:mode=base;script=math;ssty=0}{10pt} -\preloadfont\tenmaths {Latin Modern Math:mode=base;script=math;ssty=1}{7pt} -\preloadfont\tenmathss {Latin Modern Math:mode=base;script=math;ssty=2}{5pt} +\preloadfont \tenrm {Latin Modern Roman:script=latn;+liga;+kern;+dlig;}{10pt} +\preloadfont \tenit {Latin Modern Roman/I:script=latn;+liga;+kern;+dlig;}{10pt} +\preloadfont \tenbf {Latin Modern Roman/B:script=latn;+liga;+kern;+dlig;}{10pt} +\preloadfont \tensl {Latin Modern Roman Slanted:script=latn;+liga;+kern;+dlig;}{10pt} +\preloadfont \tentt {Latin Modern Mono:script=latn;+liga;+kern;+dlig;}{10pt} + +\preloadfont\tenmath {Latin Modern Math:mode=base;script=math;ssty=0;}{10pt} +\preloadfont\tenmaths {Latin Modern Math:mode=base;script=math;ssty=1;}{7pt} +\preloadfont\tenmathss {Latin Modern Math:mode=base;script=math;ssty=2;}{5pt} \toksapp\everyjob{\tenmath\tenmaths\tenmathss\tenrm \textfont0=\tenmath\scriptfont0=\tenmaths\scriptscriptfont0=\tenmathss} diff --git a/Master/texmf-dist/tex/luatex/minim/minim-pdfresources.lua b/Master/texmf-dist/tex/luatex/minim/minim-pdfresources.lua new file mode 100644 index 00000000000..bc09aeaf401 --- /dev/null +++ b/Master/texmf-dist/tex/luatex/minim/minim-pdfresources.lua @@ -0,0 +1,154 @@ + +local M = { } + +local alloc = require 'minim-alloc' +local cb = require 'minim-callbacks' + +-- the standard table design +local function init_resources() + return { + ExtGState = { }, + ColorSpace = { }, + Pattern = { }, + Shading = { }, + } +end + +-- the module will use optex’s functions if present +M.self_destruct = pdf.add_page_resource or false + +-- resource_data is a table that can contain any data. only the following keys +-- are used by this module: +-- +-- _entry_ internal value; do not use +-- value value in the resource dictionary +-- write() called for writing the resource to the pdf; returns value +-- +-- of the last two, only one needs be present; if the value is missing it will +-- be set at first use to the result of write(). +-- +local resource_data = init_resources() -- name ↦ { [write = ... | value = ...], ... } +-- +function M.add_resource(kind, name, resource) + resource_data[kind][name] = resource +end +function M.get_resource(kind, name) + return resource_data[kind][name] +end +function M.use_resource(kind, name) + local res = resource_data[kind][name] + if not res then + return alloc.err('Unknown %s resource: %s', kind, name) + end + res.value = res.value or res:write() + if not res._entry_ then -- first-use + res._entry_ = string.format('%s %s', alloc.pdf_name(name), res.value) + if M.self_destruct then + M.self_destruct(kind, name, res.value) + end + end + return res._entry_ +end + +-- global resources are mainly for pgf compatibility: contains adds entries to +-- the resource dictionaries that will be added for every page. +-- +local global_resources = init_resources() -- name ↦ '/Key ' +-- +function M.add_global_resource(kind, name, value) + local r = global_resources[kind] + if M.self_destruct then + M.self_destruct(kind, name, value) + elseif name == nil then -- used for pgf compatibility + if value ~= '' then + r[''] = r[''] and string.format('%s %s', global_resources[kind][''], value) or value + end + else + r[name] = string.format('%s %s', alloc.pdf_name(name), value) + end +end + +-- we can now provide optex’s interface +if not M.self_destruct then + pdf.add_page_resource = M.add_global_resource +end + +-- for nonglobal resources, every use must be markes with a late_lua node. from +-- those, the M.use_resouce() function will be called automatically. +-- +local page_resources = init_resources() -- name ↦ '/Key ' +-- +function _with_pdf_resource_(kind, name) -- global, for use in latelua + page_resources[kind][name] = M.use_resource(kind, name) +end +function M.use_resource_node(kind, name) + local n = node.new('whatsit', 'late_lua') + n.data = string.format('_with_pdf_resource_("%s", "%s")', kind, name) + return n +end + +-- construction and caching of resource dictionaries. +-- +local previous_dicts = init_resources() -- pdf dict ↦ objnum +-- +local function make_resource_entry(kind) + local arr = { } + for _, entry in pairs(page_resources[kind]) do table.insert(arr, entry) end + for _, entry in pairs(global_resources[kind]) do table.insert(arr, entry) end + if #arr == 0 then return false end + table.sort(arr) + arr[0] = '<<'; table.insert(arr, '>>') + local dict = table.concat(arr, ' ', 0) + local objnum = previous_dicts[kind][dict] + if not objnum then + objnum = pdf.obj(dict) + pdf.refobj(objnum) + previous_dicts[kind][dict] = objnum + end + return string.format('/%s %d 0 R', kind, objnum) +end + +local removal_regex = { + ExtGState = ' */ExtGState *%d+ +0 *R', + ColorSpace = ' */ColorSpace *%d+ +0 *R', + Pattern = ' */Pattern *%d+ +0 *R', + Shading = ' */Shading *%d+ +0 *R' } + +local function update_page_resources(shippingout) + if M.self_destruct then return end + local resources = shippingout and pdf.getpageresources() or pdf.getxformresources() or '' + for kind, used in pairs(page_resources) do + resources = string.gsub(resources, removal_regex[kind], '') + local entry = make_resource_entry(kind) + if entry then + resources = resources == '' and entry or string.format('%s %s', resources, entry) + end + end + -- update page resources + if shippingout then + pdf.setpageresources(resources) + else + pdf.setxformresources(resources) + end + page_resources = init_resources() +end + +cb.register('finish_pdfpage', update_page_resources) + +-- for pgf compatibility, reroute the pgf resource registration functions to +-- our global resource pool. +-- +alloc.luadef('minim:pgf:fix:luaside', function() + alloc.luadef('pgf@sys@addpdfresource@extgs@plain', function() + M.add_global_resource('ExtGState', nil, token.scan_string()) + end) + alloc.luadef('pgf@sys@addpdfresource@patterns@plain', function() + M.add_global_resource('Pattern', nil, token.scan_string()) + end) + alloc.luadef('pgf@sys@addpdfresource@colorspaces@plain', function() + M.add_global_resource('ColorSpace', nil, token.scan_string()) + end) +end) + +return M + diff --git a/Master/texmf-dist/tex/luatex/minim/minim-pdfresources.tex b/Master/texmf-dist/tex/luatex/minim/minim-pdfresources.tex new file mode 100644 index 00000000000..6b8dc29577f --- /dev/null +++ b/Master/texmf-dist/tex/luatex/minim/minim-pdfresources.tex @@ -0,0 +1,51 @@ + +\ifdefined \minimpdfresourcesloaded + \message{(skipped)} + \expandafter\endinput\fi +\chardef\minimpdfresourcesloaded=\catcode`\: +\catcode`\:=11 + +% at the moment, this file only deals with pgf compatibility. if you do not use +% pgf, you only need the lua module. + +\directlua{ require 'minim-pdfresources' } + +% 1 pgf compatibility + +% this ballet inserts our fix directly at the end of pgfsys-luatex.def +\expandafter\def\csname minim:intercept:pgfsys-luatex.def\endcsname + {\wlog{minim: applying pgf patches...}\newtoks\minim:pgf:fix:toks + \minim:pgf:fix:toks\csname pgfutil@everybye\endcsname + \let\endinput=\minim:pgf:fix:endinput} +\def\minim:pgf:fix:endinput{% + \begincsname minim:pgf:fix:\minim:currentfile\endcsname + \minim:endinput} +\expandafter\def\csname minim:pgf:fix:pgfsys-luatex.def\endcsname{% + \csname pgfutil@everybye\endcsname\minim:pgf:fix:toks \minim:pgf:fix:common + \let\endinput=\minim:endinput \wlog{minim: done applying pgf patches}} + +\def\minim:pgf:fix:common{\directlua{% + local pdfres = require 'minim-pdfresources' + pdfres.add_global_resource('ExtGState', nil, + '\luaescapestring{\csname pgf@sys@pgf@resource@list@extgs\endcsname}') + pdfres.add_global_resource('Pattern', nil, + '\luaescapestring{\csname pgf@sys@pgf@resource@list@patterns\endcsname}') + pdfres.add_global_resource('ColorSpace', nil, + '\luaescapestring{\csname pgf@sys@pgf@resource@list@colorspaces\endcsname}')} + \expandafter\let\csname pgf@sys@pdf@possible@resources\endcsname = \empty + \minim:pgf:fix:luaside \pdfvariable pageresources{}} + +% if pgf has already been loaded, copy the already-defined resources +\ifcsname pgf@sys@pdf@extgs@objnum\endcsname \minim:pgf:fix:common + % three empty registers will be written at the end. having three unused + % empty objects in the pdf is not ideal, but will not lead to problems. + \expandafter\let\csname pgf@sys@pgf@resource@list@extgs\endcsname = \empty + \expandafter\let\csname pgf@sys@pgf@resource@list@patterns\endcsname = \empty + \expandafter\let\csname pgf@sys@pgf@resource@list@colorspaces\endcsname = \empty +\fi + +%  + +\catcode`\:=\minimpdfresourcesloaded +\endinput + diff --git a/Master/texmf-dist/tex/luatex/minim/minim-plain.tex b/Master/texmf-dist/tex/luatex/minim/minim-plain.tex index 85fd802b8b2..1fc0178ed8d 100644 --- a/Master/texmf-dist/tex/luatex/minim/minim-plain.tex +++ b/Master/texmf-dist/tex/luatex/minim/minim-plain.tex @@ -490,8 +490,6 @@ \def\leavevmode{\unhbox\voidb@x} % begins a paragraph, if necessary \def\_{\leavevmode \kern.06em \vbox{\hrule width.3em}} -\def\AA{\leavevmode\setbox0\hbox{!}\dimen@\ht0\advance\dimen@-1ex% - \rlap{\raise.67\dimen@\hbox{\char'27}}A} \def\mathhexbox#1#2#3{\leavevmode \hbox{$\m@th \mathchar"#1#2#3$}} @@ -512,18 +510,6 @@ \def\dots{\relax\ifmmode\ldots\else$\m@th\ldots\,$\fi} \def\TeX{T\kern-.1667em\lower.5ex\hbox{E}\kern-.125emX} -\def\`#1{{\accent18 #1}} -\def\'#1{{\accent19 #1}} -\def\v#1{{\accent20 #1}} \let\^^_=\v -\def\u#1{{\accent21 #1}} \let\^^S=\u -\def\=#1{{\accent22 #1}} -\def\^#1{{\accent94 #1}} \let\^^D=\^ -\def\.#1{{\accent95 #1}} -\def\H#1{{\accent"7D #1}} -\def\~#1{{\accent"7E #1}} -\def\"#1{{\accent"7F #1}} -\def\t#1{{\edef\next{\the\font}\the\textfont1\accent"7F\next#1}} - \def\hrulefill{\leaders\hrule\hfill} \def\dotfill{\cleaders\hbox{$\m@th \mkern1.5mu.\mkern1.5mu$}\hfill} \def\rightarrowfill{$\m@th\smash-\mkern-7mu% -- cgit v1.2.3