summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Master/texmf-dist/doc/luatex/minim-pdf/README31
-rw-r--r--Master/texmf-dist/doc/luatex/minim-pdf/minim-pdf.doc165
-rw-r--r--Master/texmf-dist/doc/luatex/minim-pdf/minim-pdf.pdfbin126824 -> 145084 bytes
-rw-r--r--Master/texmf-dist/tex/luatex/minim-pdf/minim-pdf.lua103
-rw-r--r--Master/texmf-dist/tex/luatex/minim-pdf/minim-pdf.tex80
5 files changed, 311 insertions, 68 deletions
diff --git a/Master/texmf-dist/doc/luatex/minim-pdf/README b/Master/texmf-dist/doc/luatex/minim-pdf/README
index 0626208f2fa..c449a9a2c4e 100644
--- a/Master/texmf-dist/doc/luatex/minim-pdf/README
+++ b/Master/texmf-dist/doc/luatex/minim-pdf/README
@@ -1,4 +1,4 @@
-Version: 2024/1.4
+Version: 2024/1.5
SUMMARY
@@ -27,26 +27,39 @@ In order to obtain the typeset manual of this package, simply say:
HISTORY
+2024/1.5 (in development)
+
+ New features:
+
+ * Add \autotagplainoutput and \sectionstructure.
+ * Allow bookmarks that are not associated to structure elements.
+ * The characters ~#% need no longer be escaped in a \hyperlink url.
+
+ Bug fixes:
+
+ * When writing the document structure is disabled, emit a warning instead
+ of an error for incompatible structure types.
+
2024/1.4 (5/1/2024)
Breaking changes:
- * Table cells and headers now connect automatically in \automarktable
+ * Table cells and headers now connect automatically in \automarktable.
New features:
- * Add support for pdf/ua
- * Re-write \hyperlink, adding many options
- * Add ref and title options to structure elements
- * New helper macros for footnotes
- * Add \withpdfresource
+ * Add support for pdf/ua.
+ * Re-write \hyperlink, adding many options.
+ * Add ref and title options to structure elements.
+ * New helper macros for footnotes.
+ * Add \withpdfresource.
2023/1.3 (20/10/2023)
New features:
- * Add \markcolumnspan and \markrowspan
- * Add \markcolumnhead and \markrowhead
+ * Add \markcolumnspan and \markrowspan.
+ * Add \markcolumnhead and \markrowhead.
2023/1.2 (3/3/2023)
diff --git a/Master/texmf-dist/doc/luatex/minim-pdf/minim-pdf.doc b/Master/texmf-dist/doc/luatex/minim-pdf/minim-pdf.doc
index 111d8c1423b..3dc0349aca8 100644
--- a/Master/texmf-dist/doc/luatex/minim-pdf/minim-pdf.doc
+++ b/Master/texmf-dist/doc/luatex/minim-pdf/minim-pdf.doc
@@ -14,8 +14,8 @@ all other features of the package are described here.
\else \startmetadata
author {Esger Renkema}
title {minim-pdf}
- date {2024-01-05}
- version {2024/1.4}
+ date {2024-02-25}
+ version {2024/1.5}
keywords {LuaTeX; Plain TeX; PDF/A; Tagged PDF; accessibility; a11y;
hypertext; bookmarks; document outline; associated files}
stopmetadata
@@ -40,9 +40,16 @@ Hyperlinks can be made with
With the ⟦name⟧ action, a named destination must be used (see below), while the
⟦user⟧ action will be passed directly to the back-end (as with the pdftex
primitive).
+After the ⟦url⟧ action, the characters \Uchar`\~, \# and \% need not be escaped.
+(Of course, this does nothing for already-tokenised text; be aware of this when
+you wrap ⟦\hyperlink⟧ into another macro.)
+Any spaces after the ⟦<action>⟧ will be ignored.
+
The ⟦*\hyperlinkstyle⟧ token list can be used so set common (pdf) link
attributes; it defaults to ⟦/Border [0 0 0]⟧. The contents of the optional
⟦attr⟧ parameter will be appended to these.
+The ⟦alt⟧ options sets the ⟦/Contents⟧ key that is required by PDF/UA (where it
+has the purpose of an alt text).
A named destination can be created with ⟦*\nameddestination {...}⟧ (also in
horizontal mode, unlike the backend primitive) and if you cannot think of
@@ -53,18 +60,24 @@ generated name.
\section Bookmarks % 1
-Bookmarks (also known as outlines) can be added with ⟦*\outline [open|closed]
-[dest {name}] {title}⟧.
+Bookmarks (also known as outlines) can be added with
+⟦*\outline [level n] [open|closed] [dest {name}] {title}⟧.
Add ⟦open⟧ or ⟦closed⟧ to have the bookmark appear initially open or closed
-(default), and
+(the default), and
say ⟦dest {name}⟧ for having it refer to a specific named destination
(otherwise, a new one will be created where the ⟦\outline⟧ command appears).
-A bookmark is automatically associated with the current structure element and
-the hierarchy of structure elements determines the nesting of bookmarks.
-Therefore, if you want nested bookmarks, you \emph{must} precede the ⟦\outline⟧
-command with a declaration of the current structure element, even if you have
-otherwise disabled tagging. See the next chapter on how to do this.
+In the absence of the ⟦level⟧ option, the bookmark is automatically associated
+with the current structure element and the hierarchy of structure elements
+determines the nesting of bookmarks. This works even if you have otherwise
+disabled tagging and is the recommended way of generating outlines.
+(You can find all relevant macros in next chapter under ‘Document structure’
+and ‘Structure element aliases’.)
+
+As a fallback, outlines specified with the ⟦level n⟧ option will be inserted at
+the end of the current outline list at the specified level (${\tt n}≥1$ and
+need not be contiguous). Both methods can be intertwined, but please use the
+document structure if you can.
\section Page labels % 1
@@ -201,6 +214,46 @@ For a more general introduction to and discussion of tagged pdf, please read
the (excellent) manual of latex’s tagpdf package.
+\section Quick-start guide % 1
+
+The minimal setup for producing tagged pdf from plain tex documents is
+something like the following:
+
+⟦% first update all fonts to TrueType (ttf) or OpenType (otf)
+\input luaotfload.sty
+% ... font redefinitions omitted ...
+\input minim-mp
+\pdfalevel 2a % declare pdf/a conformance, enable tagging
+\autotagplainoutput % update the output routine
+% create section markers and counters
+\sectionstructure { subsection, section, chapter }⟧
+
+You can then update your sectioning macros to look like this:
+
+⟦\def\section#1\par{%
+ % space above
+ \bigskip \goodbreak
+ % structure and outline (this is the new part)
+ \marksection \outline open {#1}
+ % section header
+ \noindent {\bf \the\chapternr.\the\sectionnr. #1}
+ % space below
+ \smallskip \noindent}⟧
+
+Other macros you might have for laying out structural elements, such as tables
+or lists, should of course also be updated. The rest of this chapter describes
+the tools you can use.
+
+Please be advised that producing tagged pdf will likely forever remain
+a fragile and error-prone process.
+You should always validate the resulting pdf.
+An easy-to-use and free validator is \hyperlink alt {The veraPDF website.}
+url {https://verapdf.org/home}veraPDF\endlink.
+For inspecting the document structure, you can use the ⟦pdfinfo⟧ utility that
+comes with the \hyperlink alt {The Poppler website.}
+url {https://poppler.freedesktop.org/}Poppler\endlink\ pdf library.
+
+
\section Purpose, limitations and pitfalls % 1
The main purpose of this package is semi-automatically marking up the
@@ -213,7 +266,7 @@ Furthermore, while the macros in this package are sophisticated enough that
tagging can be done without any manual intervantion, it is quite possible and
rather easy to generate the wrong document structure, or even cause syntax
errors in the resulting pdf code.
-You should always check the result in an external application.
+You should always inspect and validate the result.
This is the full list of limitations, pitfalls and shortcomings:
\startlist
@@ -223,15 +276,13 @@ can mark out-of-order content explicitly if you know what you are doing; see
below).
\item2. The contents of ⟦\localleftbox⟧ and ⟦\localrightbox⟧ must be marked
manually, probably as artifact.
-\item3. You must mark page header, page footer and footnote rule yourself; no
-default is set.
-\item4. There currently is no way of marking xforms or other pdf objects as
+\item3. There currently is no way of marking xforms or other pdf objects as
content items of themselves.
-\item5. The content of xforms (i.e. pdf objects created by ⟦\useboxresource⟧)
+\item4. The content of xforms (i.e. pdf objects created by ⟦\useboxresource⟧)
should not contain tagging commands.
-\item6. Likewise, you should be careful with box reuse: it might work, but you
+\item5. Likewise, you should be careful with box reuse: it might work, but you
should check.
-\item7. This package currently only supports pdf~1.7 tagging and is not yet
+\item6. This package currently only supports pdf~1.7 tagging and is not yet
ready for use with pdf~2.0.
\stoplist
@@ -279,7 +330,7 @@ Use of ⟦ActualText⟧, ⟦Alt⟧ or ⟦Lang⟧ attribute on MCIs, while allowe
pdf standard, is not supported by this package. You should set these on the
structure element instead.
-The begining and ending of a content item can be forced with
+The beginning and ending of a content item can be forced with
⟦*\startcontentitem⟧ and ⟦*\stopcontentitem⟧, while ⟦*\ensurecontentitem⟧ will
only open a new content item if you are currently outside any.
If you need some part to be a single content item, you can use
@@ -336,17 +387,10 @@ All these helpful features can be disabled by setting
will have to be closed by an explicit closing tag, as in xml.
In this case, ⟦\stopelement⟧ and ⟦\ensurestopelement⟧ will be equivalent.
-By default, ⟦P⟧ structure elements are inserted automatically at the start of
-every paragraph. The tag can be changed with ⟦*\nextpartag {Tag}⟧; leaving the
-argument empty will prevent marking the next paragraph.
-Keep in mind that the reassignment is local: if a paragraph marked with
-⟦\nextpartag⟧ starts inside a group, it will not reset.
-Auto-marking paragraphs can be (locally) disabled or enabled by saying
-⟦*\markparagraphsfalse⟧ or ⟦*\markparagraphstrue⟧.
-
You can query the place in the document structure of any point with
⟦*\showdocumentstructure⟧.
+
\section Structure element aliases % 1
New structure element tags can be created with
@@ -360,6 +404,33 @@ Any aliases you declare will be written to the pdf’s ⟦RoleMap⟧ only if the
have actually been used.
+\section Automatic tagging of paragraphs % 1
+
+By default, ⟦P⟧ structure elements are inserted automatically at the start of
+every paragraph. The tag can be changed with ⟦*\nextpartag {Tag}⟧; leaving the
+argument empty will prevent marking the next paragraph.
+Keep in mind that the (internal) reassignment is local: if a paragraph marked
+with ⟦\nextpartag⟧ starts inside a group, it will not reset.
+Hence, to avoid surprises, you should have ⟦\nextpartag⟧ and the start of your
+paragraph at the same grouping level.
+
+Useful structure elements for ⟦\nextpartag⟧ include ⟦H⟧ for headings and ⟦LI⟧
+for list items. Since minim-pdf produces strongly-structured documents, the
+tags ⟦H1⟧, ⟦H2⟧, ⟦H3⟧ etc. should not be used.
+
+Please also note that if you add ⟦\hbox⟧es directly to a vertical list
+(this includes ⟦\line⟧, ⟦\centerline⟧ and the like),
+the ⟦\everypar⟧ token list is not inserted and no new paragraph structure element
+will be opened.
+The contents of the ⟦\hbox⟧ will be added to the current structure element, and
+this may result in an invalid structure hierarchy (and an error messsage
+reading ‘Structure type mismatch’).
+You can make your intentions clear by inserting ⟦\startelement{P}⟧ at the
+appropriate place (see above).
+
+Auto-marking paragraphs can be (locally) disabled or enabled by saying
+⟦*\markparagraphsfalse⟧ or ⟦*\markparagraphstrue⟧.
+
\section Manipulating the logical order % 1
With the process outlined above, the logical order of structure elements has to
@@ -504,7 +575,7 @@ list item. Of course, this only works with two-column tables.
Cells spanning multiple cells or rows can be marked with
⟦*\markcolumnspan {width}⟧ and ⟦*\markrowspan {height}⟧; these statements may not
occur before ⟦\marktablecell⟧. Note that while ⟦\markcolumnspan⟧ properly
-increases the (internal) column number, ⟦\markcolumnrow⟧ does nothing of the
+increases the (internal) column number, ⟦\markrowspan⟧ does nothing of the
sort (and indeed, no general logic can be given in the latter case). Always proceed
with caution when using cells spanning multiple rows, and inspect the resulting
structure carefully.
@@ -529,6 +600,46 @@ For tagging (foot)notes, ⟦*\marknoteref{*}⟧ and ⟦*\marknotelbl{*}⟧, when
around the footnote markers, will insert the proper ⟦Ref⟧, ⟦Note⟧ and ⟦Lbl⟧
tags.
+Helper macros for tagging sections can be setup quickly with
+⟦*\sectionstructure { <section list> }⟧. The ⟦<section list>⟧ should be an
+increasing comma-separated list of section types, e.g.
+⟦{subsection, section, chapter}⟧. This will first reserve the ⟦\count⟧
+registers ⟦\subsectionnr⟧ etc, then create the structure aliases ⟦/Subsection⟧
+etc. and finally define the helper macros ⟦\marksubsection⟧ etc, which will do
+the following:
+\startlist
+\item 1. Call ⟦\ensurestopelement⟧ on all lower section types.
+\item 2. Set all lower section number counts to zero.
+\item 3. Increase the current section type number by one.
+\item 4. Call ⟦\startelement⟧ for the current section type.
+\item 5. Set the ⟦\nextpartag⟧ to ⟦H⟧.
+\stoplist
+The proper place for these helper macros is just before the section heading;
+inbetween those two may come an ⟦\outline⟧ statement (see the previous
+chapter). You can set the ⟦title⟧ option to the internal ⟦\startelement⟧
+statement with an optional argument (e.g.
+⟦\marksection [Section \the\sectionnr]⟧).
+
+\section Tagging the output routine % 1
+
+The command ⟦*\autotagplainoutput⟧ will try and update plain tex’s output routine
+to produce tagged page artifacts and footnotes.
+It redefines ⟦\makeheadline⟧, ⟦\makefootline⟧,
+⟦\footnoterule⟧, ⟦\footnote⟧ and ⟦\vfootnote⟧.
+Headline and footline will not be marked as artifacts if their contents equal
+⟦\hfil⟧; the footnote macros are edited to include the ⟦\marknoteref⟧ and
+⟦\marknotelbl⟧ macros described above.
+Note that the ⟦\topinsert⟧, ⟦\midinsert⟧ and ⟦\pageinsert⟧ macros are left
+untouched; you will have to mark those explicitly.
+
+You can make some changes to the affected macros before calling
+⟦\autotagplainoutput⟧, as it tries to be smart about it.
+Though the redefinitions involve a full expansion,
+most conditionals and common typesetting instructions (⟦\line⟧, ⟦\quad⟧,
+⟦\strut⟧ etc.) are safe-to-use and will not be expanded.
+If you include custom macros of your own, however, it is wise to have those
+⟦\protected⟧.
+
% 
\endmanual
diff --git a/Master/texmf-dist/doc/luatex/minim-pdf/minim-pdf.pdf b/Master/texmf-dist/doc/luatex/minim-pdf/minim-pdf.pdf
index 2b2ea69c428..2056601eec9 100644
--- a/Master/texmf-dist/doc/luatex/minim-pdf/minim-pdf.pdf
+++ b/Master/texmf-dist/doc/luatex/minim-pdf/minim-pdf.pdf
Binary files differ
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 <</S/GoTo /D %s>>', pdf_string(token.scan_argument()))
end
function link_types.url()
- return string.format('/Subtype/Link /A <</S/URI /URI %s>>', pdf_string(token.scan_argument()))
+ local url = scan_escaped_argument ('~#$%^&_')
+ return string.format('/Subtype/Link /A <</S/URI /URI %s>>', 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 <</S/Named /N/LastPage>>' 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()
' <</Type /Outlines /First %s 0 R /Last %s 0 R /Count %s >> ',
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 <args> ... \endlink
% args: alt {...} attr {...} <type>
% 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}