From edfd6ab3ed7259f3284e48f303725e60a2b96cbe Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Fri, 1 Mar 2024 21:45:43 +0000 Subject: minim-pdf (1mar24) git-svn-id: svn://tug.org/texlive/trunk@70311 c570f23f-e606-0410-a88d-b1316a301751 --- .../texmf-dist/tex/luatex/minim-pdf/minim-pdf.lua | 103 ++++++++++++++------- .../texmf-dist/tex/luatex/minim-pdf/minim-pdf.tex | 80 +++++++++++++++- 2 files changed, 151 insertions(+), 32 deletions(-) (limited to 'Master/texmf-dist/tex/luatex') 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 875fd896592..101a548e4b5 100644 --- a/Master/texmf-dist/tex/luatex/minim-pdf/minim-pdf.lua +++ b/Master/texmf-dist/tex/luatex/minim-pdf/minim-pdf.lua @@ -229,7 +229,13 @@ local function determine_parent_node(current, se) end end if not c then - alloc.err('Structure type mismatch: %s in %s', se.struct, current.struct) + if tagging_enabled() then + alloc.err('Structure type mismatch: %s in %s', + pdf_name(se.struct), pdf_name(current.struct)) + else + alloc.msg('Warning (minim-pdf): Structure type mismatch (%s in %s)', + pdf_name(se.struct), pdf_name(current.struct)) + end end return c or current end @@ -820,6 +826,13 @@ alloc.luadef('lastdestinationname', function() tex.sprint(last_dest_name()) end) -- provide the arguments to \pdfextension startlink local link_types = { } +local function make_link_attr(s) + local attr = { 'attr {\\csname minim:linkattr\\endcsname' } + if s.attr then table.insert(attr, s.attr) end + if s.alt or s.contents then insert_formatted(attr, '/Contents %s', pdf_string(s.alt or s.contents)) end + table.insert(attr, '}') + return attr +end alloc.luadef('hyper:makelink', function() local s = options_scanner() :argument('alt'):argument('contents') -- same thing @@ -832,18 +845,32 @@ alloc.luadef('hyper:makelink', function() userf = link_types.first end local user = userf() - attr = { 'attr {\\csname minim:linkattr\\endcsname' } - if s.attr then table.insert(attr, s.attr) end - if s.alt or s.contents then insert_formatted(attr, '/Contents %s', pdf_string(s.alt or s.contents)) end - insert_formatted(attr, '} user {%s}', user) + local attr = make_link_attr(s) tex.sprint(table.concat(attr, ' ')) + tex.sprint('user {') + tex.write(user) + tex.sprint('}\\ignorespaces') end) +local function scan_escaped_argument(chars_to_escape) + local stored = { } + for char in string.utfvalues(chars_to_escape) do + stored[char] = tex.getcatcode(char) + tex.setcatcode(char, 12) + end + local res = token.scan_argument() + for char, code in pairs(stored) do + tex.setcatcode(char, code) + end + return res +end + function link_types.dest() return string.format('/Subtype/Link /A <>', pdf_string(token.scan_argument())) end function link_types.url() - return string.format('/Subtype/Link /A <>', pdf_string(token.scan_argument())) + local url = scan_escaped_argument ('~#$%^&_') + return string.format('/Subtype/Link /A <>', pdf_string(url)) end function link_types.user() return token.scan_argument() end @@ -855,7 +882,7 @@ function link_types.last() return '/Subtype/Link /A <>' en -- 1 bookmarks (outlines) -- start with a dummy top-level bookmark -local bookmarks = { { count = 0 } } +local bookmarks = { { count = 0, level = 0 } } structure[1].bookmark = bookmarks[1] local function write_bookmarks() @@ -870,13 +897,13 @@ local function write_bookmarks() ' <> ', bookmarks[2].outline_obj, bookmarks[1].last.outline_obj, #bookmarks - 1)) -- write bookmark objects - for i=2, #bookmarks do + for i=2, #bookmarks do -- skip the root (i=1) local bm, res = bookmarks[i], { } 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, pdf_string(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 - if bm.struct and bm.struct.objnum then + if bm.struct and bm.struct.objnum then -- false if no structures are written out insert_formatted(res, '/SE %s 0 R', bm.struct.objnum) end if bm.count > 0 then @@ -888,37 +915,51 @@ local function write_bookmarks() end function M.add_bookmark(bm) - local se = current_structure_element() - bm.parent, bm.count = false, 0 - bm.dest = bm.dest or write_new_dest() - se.bookmark, bm.struct = bm, se - -- find and update the parent bookmarks - local p = se.parent - while p do - local pbm = p.bookmark - if pbm then - if not bm.parent then - if pbm.last then pbm.last.next = bm end - bm.parent, bm.prev = pbm, pbm.last - pbm.first, pbm.last = pbm.first or bm, bm + local pbm + if bm.level then + for i = #bookmarks, 1, -1 do + pbm = bookmarks[i] + if pbm.level < bm.level then + break end - -- update the count until the first closed bookmark - pbm.count = pbm.count + 1 - p = pbm.open and pbm.parent - else - p = p.parent end + else + local se = current_structure_element() + if se.bookmark then + return alloc.err('Structure element %s already has a bookmark', pdf_name(se.struct)) + end + se.bookmark, bm.struct = bm, se + -- derive parent from strucrure + pbm = se.parent + while not pbm.bookmark do + pbm = pbm.parent + end + pbm = pbm.bookmark end + -- initial values; links to other bookmarks + bm.parent, bm.count = false, 0 + bm.dest = bm.dest or write_new_dest() + if pbm.last then pbm.last.next = bm end + bm.parent, bm.prev = pbm, pbm.last + pbm.first, pbm.last = pbm.first or bm, bm + bm.level = bm.level or (pbm.level + 1) + -- update the count until the first closed bookmarks + repeat + pbm.count = pbm.count + 1 + pbm = pbm.open and pbm.parent + until not pbm + -- append to the list table.insert(bookmarks, bm) end alloc.luadef('outline', function() - local s = options_scanner() + local bm = options_scanner() :keyword('open', 'closed') :string('dest') + :int('level') :scan() - s.title = token.scan_string() - M.add_bookmark(s) + bm.title = token.scan_string() + M.add_bookmark(bm) end, 'protected') @@ -987,7 +1028,7 @@ alloc.luadef('embedfile', function() t.name = t.file or alloc.err('No name specified for embedded file stream') end t.name = pdf_string(t.name or '(unnamed)') - local fs, ef = M.embed_file(t, t.global) + local fs, _ = M.embed_file(t, t.global) -- where to attach? if t.global then table.insert(attached_files, { name = t.name, objnum = fs } ) 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 8a5f738063f..d5300fd58f5 100644 --- a/Master/texmf-dist/tex/luatex/minim-pdf/minim-pdf.tex +++ b/Master/texmf-dist/tex/luatex/minim-pdf/minim-pdf.tex @@ -323,6 +323,84 @@ \markelement{Lbl}{{\stopformulatagging#1}}} \def\tagging:ensurestopNote{\ensurestopelement{Note}} +% \sectionstructure { subsection, section, chapter } +\def\sectionstructure{% + \newtoks\tag:sect:resets \tag:sect:resets{}% + \splitcommalist\tag:sect:a} +\def\tag:sect:a#1{\expandafter\tag:sect:b + \expandafter{\Uchar\uccode`#1}{#1}} +\def\tag:sect:b#1#2{% Section section + \addstructuretype Sect #1\relax + \expandafter\newcount\csname #2nr\endcsname + \expandafter\edef\csname mark#2\endcsname{% + \noexpand\withoptions[]% + \expandafter\noexpand\csname #2:domark\endcsname}% + \expandafter\edef\csname #2:domark\endcsname[##1]{% + \unexpanded{\ifhmode\errhelp{You should place section markers + in the vertical list, before the header.}\errmessage + {Section marker in horizontal list}\fi}% + \global\advance\expandafter\noexpand + \csname #2nr\endcsname1 + \noexpand\the\expandafter\noexpand + \csname #2:resets\endcsname + \startelement\noexpand\ifx=##1=\noexpand\else + title{##1}\noexpand\fi{#1}% + \nextpartag{H}\ignorespaces}% + \expandafter\newtoks\csname #2:resets\endcsname + \csname #2:resets\endcsname \tag:sect:resets + \etoksapp\tag:sect:resets{% + \noexpand\ensurestopelement{#1}% + \global\expandafter\noexpand\csname#2nr\endcsname0 }} + +% tagging the plain output routine +\begingroup\catcode`\@=11 +\gdef\autotagplainoutput{% + \let \vfootnot = \tag:vfootnote + \begingroup + % these should not be expanded + \tag:mkrelax + \ifhmode \ifvmode \ifnum \ifdim \ifodd \ifeven + \ifcondition \unless \else \fi \next \tmp + \strut \strutbox \footstrut + \the \number \empty \folio + \line \leftline \rightline \centerline + \nointerlineskip \offinterlineskip + \textindent \narrower \hang \llap \rlap + \enspace \thinspace \hidewidth + \quad \qquad \enskip + \@sf \fo@t \footins + \tag:mkrelax + % redefine head- and footlines + \def\footline{\taggedfootline}% + \def\headline{\taggedheadline}% + \xdef\makeheadline{\makeheadline}% + \xdef\makefootline{\makefootline}% + \xdef\footnoterule{\markartifact{Layout}\footnoterule} + % redefine vfootnote + \def\textindent##1{\noexpand\nextpartag{}% + \noexpand\marknotelbl{\noexpand\textindent{##1}}% + \noexpand\startelement{P}}% + \xdef\vfootnote##1{\vfootnote{##1}}% + % redefine footnote + \let\vfootnote=\relax \let\textindent=\relax + \def\fi##1\@sf{\noexpand\fi\noexpand\marknoteref{##1}\@sf} + \xdef\footnote##1{\footnote{##1}}% + \endgroup} +\endgroup +\def\tag:mkrelax#1{\ifx\tag:mkrelax#1\tag:else + \let#1=\relax\expandafter\tag:mkrelax\tag:fi} +\let\tag:else=\else \let\tag:fi=\fi +\newtoks \taggedheadline \newtoks \taggedfootline +\taggedheadline{\tagtoks:nonempty{Pagination /Subtype/Header}\headline} +\taggedfootline{\tagtoks:nonempty{Pagination /Subtype/Footer}\footline} +\def\tagtoks:nonempty#1#2{% + \edef\tagtoks:tmp{\the#2}% + \ifx\tagtoks:tmp\tagtoks:hfil + \the#2\else + \markartifact{#1}{\the#2}\fi} +\def\tagtoks:hfil{\hfil} + + % 1 tagging formulas % \autotagformulas @@ -408,7 +486,7 @@ % \hyperlink ... \endlink % args: alt {...} attr {...} % type: dest {name} | url {url} | next | prev | first | last -\protected\def\endlink{\pdfextension endlink\stopelement{Link}\relax} +\protected\def\endlink{\pdfextension endlink\ensurestopelement{Link}\relax} \protected\def\startlink{\startelement{Link}\pdfextension startlink} \protected\def\hyperlink{\quitvmode\startlink\hyper:makelink} -- cgit v1.2.3