summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2021-06-30 21:14:14 +0000
committerKarl Berry <karl@freefriends.org>2021-06-30 21:14:14 +0000
commitc604c653358384d71cfbdad75147fe6b3ef448d3 (patch)
treeaaa2eb4dac429b5bb9bdde1d867e88d75612e65d /Master/texmf-dist/source
parentf52cb629a5dd055df1ae60054f89cc718a5ce58e (diff)
tagpdf (30jun21)
git-svn-id: svn://tug.org/texlive/trunk@59769 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/source')
-rw-r--r--Master/texmf-dist/source/latex/tagpdf/tagpdf-backend.dtx1059
-rw-r--r--Master/texmf-dist/source/latex/tagpdf/tagpdf-checks.dtx643
-rw-r--r--Master/texmf-dist/source/latex/tagpdf/tagpdf-mc-generic.dtx389
-rw-r--r--Master/texmf-dist/source/latex/tagpdf/tagpdf-mc-luacode.dtx490
-rw-r--r--Master/texmf-dist/source/latex/tagpdf/tagpdf-mc-shared.dtx442
-rw-r--r--Master/texmf-dist/source/latex/tagpdf/tagpdf-mc.dtx818
-rw-r--r--Master/texmf-dist/source/latex/tagpdf/tagpdf-roles.dtx165
-rw-r--r--Master/texmf-dist/source/latex/tagpdf/tagpdf-space.dtx130
-rw-r--r--Master/texmf-dist/source/latex/tagpdf/tagpdf-struct.dtx1024
-rw-r--r--Master/texmf-dist/source/latex/tagpdf/tagpdf-tree.dtx343
-rw-r--r--Master/texmf-dist/source/latex/tagpdf/tagpdf-user.dtx585
-rw-r--r--Master/texmf-dist/source/latex/tagpdf/tagpdf.dtx865
-rw-r--r--Master/texmf-dist/source/latex/tagpdf/tagpdf.ins47
13 files changed, 4591 insertions, 2409 deletions
diff --git a/Master/texmf-dist/source/latex/tagpdf/tagpdf-backend.dtx b/Master/texmf-dist/source/latex/tagpdf/tagpdf-backend.dtx
index 1010c79b7a5..f643e3dbdea 100644
--- a/Master/texmf-dist/source/latex/tagpdf/tagpdf-backend.dtx
+++ b/Master/texmf-dist/source/latex/tagpdf/tagpdf-backend.dtx
@@ -22,31 +22,57 @@
%
% for those people who are interested.
%
+%<*driver>
+\RequirePackage{pdfmanagement-testphase}
+\DeclareDocumentMetadata{}
+\makeatletter
+\declare@file@substitution{doc.sty}{doc-v3beta.sty}
+\makeatother
+\documentclass{l3doc}
+\usepackage{array,booktabs,caption}
+\hypersetup{pdfauthor=Ulrike Fischer,
+ pdftitle=tagpdf-mc module (tagpdf)}
+\begin{document}
+ \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
% \fi
+% \title{^^A
+% The \pkg{tagpdf-luatex.def} \\ Driver for luatex ^^A
+% \\ Part of the tagpdf package
+% }
%
+% \author{^^A
+% Ulrike Fischer\thanks
+% {^^A
+% E-mail:
+% \href{mailto:fischer@troubleshooting-tex.de}
+% {fischer@troubleshooting-tex.de}^^A
+% }^^A
+% }
+%
+% \date{Version 0.9, released 2021-06-29}
+% \maketitle
+% \begin{implementation}
% \begin{macrocode}
%<@@=tag>
%<*luatex>
-\ProvidesExplFile {tagpdf-luatex.def} {2021-06-14} {0.82}
+\ProvidesExplFile {tagpdf-luatex.def} {2021-06-29} {0.9}
{tagpdf~driver~for~luatex}
-
-\newattribute \l_@@_mc_type_attr %the value represent the type
-\newattribute \l_@@_mc_cnt_attr %will hold the \c@g_@@_MCID_abs_int value
-
-\newattribute \g_@@_interwordspace_attr
-\newattribute \g_@@_interwordfont_attr
-
-% The lua code
-% ensure that 10pt font has been loaded:
+% \end{macrocode}
+% \section{Loading the lua}
+% The space code requires that the fall back font has been loaded and initialized,
+% so we force that first. But perhaps this could be done in the kernel.
+%
+% \begin{macrocode}
{
\fontencoding{TU}\fontfamily{lmr}\fontseries{m}\fontshape{n}\fontsize{10pt}{10pt}\selectfont
}
-\directlua { tagpdf=require('tagpdf.lua') }
-
-%%%% driver (lualatex) commands
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-
+\lua_now:e { tagpdf=require('tagpdf.lua') }
+% \end{macrocode}
+%
+% The following defines wrappers around prop and seq commands to store the
+% data also in lua tables.
% I probably want also lua tables
% I put them in the ltx.@@.tables namespaces
% The tables will be named like the variables but without backslash
@@ -54,94 +80,80 @@
% ltx.@@.tables[string]
% Old code, I'm not quite sure if this was a good idea. Now I have mix of table in
% ltx.@@.tables and ltx.@@.mc/struct. And a lot is probably not needed.
-
-
-\cs_new_protected:Nn \@@_prop_new:N
+% TODO: this should be cleaned up, but at least roles are currently using
+% the table!
+%
+% \begin{macro}
+% {
+% \@@_prop_new:N,
+% \@@_seq_new:N,
+% \@@_prop_gput:Nnn,
+% \@@_seq_gput_right:Nn,
+% \@@_seq_item:cn,
+% \@@_prop_item:cn,
+% \@@_seq_show:N,
+% \@@_prop_show:N
+% }
+% \begin{macrocode}
+\cs_set_protected:Npn \@@_prop_new:N #1
{
\prop_new:N #1
- \directlua { ltx.@@.tables.\cs_to_str:N#1 = {} }
+ \lua_now:e { ltx.@@.tables.\cs_to_str:N#1 = {} }
}
-\cs_new_protected:Nn \@@_seq_new:N
+\cs_set_protected:Npn \@@_seq_new:N #1
{
\seq_new:N #1
- \directlua { ltx.@@.tables.\cs_to_str:N#1 = {} }
+ \lua_now:e { ltx.@@.tables.\cs_to_str:N#1 = {} }
}
-\cs_new_protected:Nn \@@_prop_gput:Nnn
+\cs_set_protected:Npn \@@_prop_gput:Nnn #1 #2 #3
{
\prop_gput:Nnn #1 { #2 } { #3 }
- \directlua { ltx.@@.tables.\cs_to_str:N#1 ["#2"] = "#3" }
+ \lua_now:e { ltx.@@.tables.\cs_to_str:N#1 ["#2"] = "#3" }
}
-\cs_new_protected:Nn \@@_seq_gput_right:Nn
+\cs_set_protected:Npn \@@_seq_gput_right:Nn #1 #2
{
\seq_gput_right:Nn #1 { #2 }
- \directlua { table.insert(ltx.@@.tables.\cs_to_str:N#1, "#2") }
+ \lua_now:e { table.insert(ltx.@@.tables.\cs_to_str:N#1, "#2") }
}
%Hm not quite sure about the naming
-\cs_new:Npn \@@_seq_item:cn #1 #2
+\cs_set:Npn \@@_seq_item:cn #1 #2
{
- \directlua { tex.print(ltx.@@.tables.#1[#2]) }
+ \lua_now:e { tex.print(ltx.@@.tables.#1[#2]) }
}
-\cs_new:Npn \@@_prop_item:cn #1 #2
+\cs_set:Npn \@@_prop_item:cn #1 #2
{
- \directlua { tex.print(ltx.@@.tables.#1["#2"]) }
+ \lua_now:e { tex.print(ltx.@@.tables.#1["#2"]) }
}
%for debugging commands that show both the seq/prop and the lua tables
-\cs_new_protected:Nn \@@_seq_show:N
+\cs_set_protected:Npn \@@_seq_show:N #1
{
\seq_show:N #1
- \directlua { ltx.@@.trace.log ("lua~sequence~array~\cs_to_str:N#1",1) }
- \directlua { ltx.@@.trace.show_seq (ltx.@@.tables.\cs_to_str:N#1) }
+ \lua_now:e { ltx.@@.trace.log ("lua~sequence~array~\cs_to_str:N#1",1) }
+ \lua_now:e { ltx.@@.trace.show_seq (ltx.@@.tables.\cs_to_str:N#1) }
}
-\cs_new_protected:Nn \@@_prop_show:N
+\cs_set_protected:Npn \@@_prop_show:N #1
{
\prop_show:N #1
- \directlua {ltx.@@.trace.log ("lua~property~table~\cs_to_str:N#1",1) }
- \directlua {ltx.@@.trace.show_prop (ltx.@@.tables.\cs_to_str:N#1) }
+ \lua_now:e {ltx.@@.trace.log ("lua~property~table~\cs_to_str:N#1",1) }
+ \lua_now:e {ltx.@@.trace.show_prop (ltx.@@.tables.\cs_to_str:N#1) }
}
-%</luatex>
% \end{macrocode}
-%
+% \end{macro}
% \begin{macrocode}
-%<*pdftex>
-\ProvidesExplFile {tagpdf-pdftex.def} {2021-06-14} {0.82}
- {tagpdf~driver~for~pdftex}
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%%% driver (pdflatex) commands
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-
-% These commands are only aliases for pdflatex but are defined differently with luatex
-% to get also lua tables.
-\cs_set_eq:NN \@@_prop_new:N \prop_new:N
-
-\cs_set_eq:NN \@@_seq_new:N \seq_new:N
-
-\cs_set_eq:NN \@@_prop_gput:Nnn \prop_gput:Nnn
-
-\cs_set_eq:NN \@@_seq_gput_right:Nn \seq_gput_right:Nn
-
-\cs_set_eq:NN \@@_seq_item:cn \seq_item:cn
-
-\cs_set_eq:NN \@@_prop_item:cn \prop_item:cn
-
-\cs_set_eq:NN \@@_seq_show:N \seq_show:N
-
-\cs_set_eq:NN \@@_prop_show:N \prop_show:N
-
-%</pdftex>
+%</luatex>
% \end{macrocode}
+% The module declaration
% \begin{macrocode}
%<*lua>
-- tagpdf.lua
@@ -149,8 +161,8 @@
local ProvidesLuaModule = {
name = "tagpdf",
- version = "0.82", --TAGVERSION
- date = "2021-06-14", --TAGDATE
+ version = "0.9", --TAGVERSION
+ date = "2021-06-29", --TAGDATE
description = "tagpdf lua code",
license = "The LATEX Project Public License 1.3c"
}
@@ -168,8 +180,9 @@ The code has quite probably a number of problems
-
--]]
-
-
+% \end{macrocode}
+% Some comments about the lua structure.
+% \begin{macrocode}
--[[
the main table is named ltx.@@. It contains the functions and also the data
collected during the compilation.
@@ -199,9 +212,10 @@ functions
ltx.@@.func.mark_shipout (): a wrapper around the core function which inserts the last EMC
ltx.@@.func.fill_parent_tree_line (page): outputs the entries of the parenttree for this page
ltx.@@.func.output_parenttree(): outputs the content of the parenttree
+ ltx.@@.func.pdf_object_ref(name): outputs the object reference for the object name
ltx.@@.func.markspaceon(), ltx.@@.func.markspaceoff(): (de)activates the marking of positions for space chars
- ltx.@@.trace.show_mc_data (num): shows ltx.@@.mc[num]
- ltx.@@.trace.show_all_mc_data (max): shows a maximum about mc's
+ ltx.@@.trace.show_mc_data (num,loglevel): shows ltx.@@.mc[num] is the current log level is >= loglevel
+ ltx.@@.trace.show_all_mc_data (max,loglevel): shows a maximum about mc's if the current log level is >= loglevel
ltx.@@.trace.show_seq: shows a sequence (array)
ltx.@@.trace.show_struct_data (num): shows data of structure num
ltx.@@.trace.show_prop: shows a prop
@@ -209,19 +223,34 @@ functions
ltx.@@.trace.showspaces : boolean
--]]
-local mctypeattributeid = luatexbase.registernumber ("l_@@_mc_type_attr")
-local mccntattributeid = luatexbase.registernumber ("l_@@_mc_cnt_attr")
-local iwspaceattributeid = luatexbase.registernumber ("g_@@_interwordspace_attr")
-local iwfontattributeid = luatexbase.registernumber ("g_@@_interwordfont_attr")
-
-
-local catlatex = luatexbase.registernumber("catcodetable@latex")
+% \end{macrocode}
+% This set-ups the main attribute registers.
+% The mc_type attribute stores the type (P, Span etc) encoded as a num,
+% The mc_cnt attribute stores the absolute number and allows so to see
+% if a node belongs to the same mc-chunk.
+%
+% The interwordspace attr is set by the function |@@_mark_spaces|, and marks
+% the place where spaces should be inserted.
+% The interwordfont attr is set by the function |@@_mark_spaces| too and
+% stores the font, so that we can decide which font
+% to use for the real space char.
+% \begin{macrocode}
+local mctypeattributeid = luatexbase.new_attribute ("g_@@_mc_type_attr")
+local mccntattributeid = luatexbase.new_attribute ("g_@@_mc_cnt_attr")
+local iwspaceattributeid = luatexbase.new_attribute ("g_@@_interwordspace_attr")
+local iwfontattributeid = luatexbase.new_attribute ("g_@@_interwordfont_attr")
+% \end{macrocode}
+% with this token we can query the state of the boolean
+% and so detect if unmarked nodes should be marked as attributes
+% \begin{macrocode}
local tagunmarkedbool= token.create("g_@@_tagunmarked_bool")
local truebool = token.create("c_true_bool")
-
+% \end{macrocode}
+% Now a number of local versions from global tables.
+% Not all is perhaps needed, most node variants were copied from lua-debug.
+% \begin{macrocode}
+local catlatex = luatexbase.registernumber("catcodetable@latex")
local tableinsert = table.insert
-
--- not all needed, copied from lua-visual-debug.
local nodeid = node.id
local nodecopy = node.copy
local nodegetattribute = node.get_attribute
@@ -247,29 +276,29 @@ local KERN = node.id("kern")
local PENALTY = node.id("penalty")
local LOCAL_PAR = node.id("local_par")
local MATH = node.id("math")
-
-local function @@_get_mathsubtype (mathnode)
- if mathnode.subtype == 0 then
- subtype = "beginmath"
- else
- subtype = "endmath"
- end
- return subtype
-end
-
-
-
+% \end{macrocode}
+% Now we setup the main table structure. ltx is used by other latex code too!
+% \begin{macrocode}
ltx = ltx or { }
ltx.@@ = ltx.@@ or { }
-ltx.@@.mc = ltx.@@.mc or { } -- mc data
-ltx.@@.struct = ltx.@@.struct or { } -- struct data
-ltx.@@.tables = ltx.@@.tables or { } -- tables created with new prop and new seq.
- -- wasn't a so great idea ...
-ltx.@@.page = ltx.@@.page or { } -- page data, currently only i->{0->mcnum,1->mcnum,...}
-ltx.@@.trace = ltx.@@.trace or { } -- show commands
-ltx.@@.func = ltx.@@.func or { } -- functions
-ltx.@@.conf = ltx.@@.conf or { } -- configuration variables
-
+ltx.@@.mc = ltx.@@.mc or { } -- mc data
+ltx.@@.struct = ltx.@@.struct or { } -- struct data
+ltx.@@.tables = ltx.@@.tables or { } -- tables created with new prop and new seq.
+ -- wasn't a so great idea ...
+ -- g_@@_role_tags_seq used by tag<-> is in this tables!
+ltx.@@.page = ltx.@@.page or { } -- page data, currently only i->{0->mcnum,1->mcnum,...}
+ltx.@@.trace = ltx.@@.trace or { } -- show commands
+ltx.@@.func = ltx.@@.func or { } -- functions
+ltx.@@.conf = ltx.@@.conf or { } -- configuration variables
+% \end{macrocode}
+% \section{Logging functions}
+%
+% \begin{macro}{@@_log,ltx.@@.trace.log}
+% This rather simple log function takes as argument a
+% message (string) and a number and
+% will output the message to the log/terminal if the current loglevel
+% is greater or equal than num.
+% \begin{macrocode}
local @@_log =
function (message,loglevel)
if (loglevel or 3) <= tex.count["l_@@_loglevel_int"] then
@@ -278,16 +307,267 @@ local @@_log =
end
ltx.@@.trace.log = @@_log
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{ltx.@@.trace.show_seq}
+% This shows the content of a seq as stored in the tables table.
+% It is used by the |\@@_seq_show:N| function. It is not used
+% in user commands, only for debugging, and so requires log level >0.
+% \begin{macrocode}
+function ltx.@@.trace.show_seq (seq)
+ if (type(seq) == "table") then
+ for i,v in ipairs(seq) do
+ @@_log ("[" .. i .. "] => " .. tostring(v),1)
+ end
+ else
+ @@_log ("sequence " .. tostring(seq) .. " not found",1)
+ end
+end
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{ @@_pairs_prop,ltx.@@.trace.show_prop}
+% This shows the content of a prop as stored in the tables table.
+% It is used by the |\@@_prop_show:N| function.
+% \begin{macrocode}
+local @@_pairs_prop =
+ function (prop)
+ local a = {}
+ for n in pairs(prop) do tableinsert(a, n) end
+ table.sort(a)
+ local i = 0 -- iterator variable
+ local iter = function () -- iterator function
+ i = i + 1
+ if a[i] == nil then return nil
+ else return a[i], prop[a[i]]
+ end
+ end
+ return iter
+ end
+function ltx.@@.trace.show_prop (prop)
+ if (type(prop) == "table") then
+ for i,v in @@_pairs_prop (prop) do
+ @@_log ("[" .. i .. "] => " .. tostring(v),1)
+ end
+ else
+ @@_log ("prop " .. tostring(prop) .. " not found or not a table",1)
+ end
+ end
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{ltx.@@.trace.show_mc_data}
+% This shows some data for a mc given by |num|.
+% If something is shown depends on the log level.
+% The function is used by the following function and then in
+% |\ShowTagging|
+% \begin{macrocode}
+function ltx.@@.trace.show_mc_data (num,loglevel)
+ if ltx.@@ and ltx.@@.mc and ltx.@@.mc[num] then
+ for k,v in pairs(ltx.@@.mc[num]) do
+ @@_log ("mc"..num..": "..tostring(k).."=>"..tostring(v),loglevel)
+ end
+ if ltx.@@.mc[num]["kids"] then
+ @@_log ("mc" .. num .. " has " .. #ltx.@@.mc[num]["kids"] .. " kids",loglevel)
+ for k,v in ipairs(ltx.@@.mc[num]["kids"]) do
+ @@_log ("mc ".. num .. " kid "..k.." =>" .. v.kid.." on page " ..v.page,loglevel)
+ end
+ end
+ else
+ @@_log ("mc"..num.." not found",loglevel)
+ end
+end
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{ltx.@@.trace.show_all_mc_data}
+% This shows data for the mc's between |min| and |max| (numbers).
+% It is used by the |\ShowTagging| function.
+% \begin{macrocode}
+function ltx.@@.trace.show_all_mc_data (min,max,loglevel)
+ for i = min, max do
+ ltx.@@.trace.show_mc_data (i,loglevel)
+ end
+ texio.write_nl("")
+end
+% \end{macrocode}
+% \end{macro}
+
+% \begin{macro}
+% {
+% ltx.@@.trace.show_struct_data
+% }
+% This function shows some struct data.
+% Unused but kept for debugging.
+% \begin{macrocode}
+function ltx.@@.trace.show_struct_data (num)
+ if ltx.@@ and ltx.@@.struct and ltx.@@.struct[num] then
+ for k,v in ipairs(ltx.@@.struct[num]) do
+ @@_log ("struct "..num..": "..tostring(k).."=>"..tostring(v),1)
+ end
+ else
+ @@_log ("struct "..num.." not found ",1)
+ end
+end
+% \end{macrocode}
+% \end{macro}
+
+%
+% \section{Helper functions}
+% \subsection{Retrieve data functions}
+% \begin{macro}{@@_get_mc_cnt_type_tag}
+% This takes a node as argument and returns the mc-cnt, the mc-type and
+% and the tag (calculated from the mc-cnt.
+% \begin{macrocode}
local @@_get_mc_cnt_type_tag = function (n)
local mccnt = nodegetattribute(n,mccntattributeid) or -1
local mctype = nodegetattribute(n,mctypeattributeid) or -1
local tag = ltx.@@.func.get_tag_from(mctype)
return mccnt,mctype,tag
end
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{@@_get_mathsubtype}
+% This function allows to detect if we are at the begin or the end of math.
+% It takes as argument a mathnode.
+% \begin{macrocode}
+local function @@_get_mathsubtype (mathnode)
+ if mathnode.subtype == 0 then
+ subtype = "beginmath"
+ else
+ subtype = "endmath"
+ end
+ return subtype
+end
+% \end{macrocode}
+% \end{macro}
+
+% \begin{macro}
+% {
+% @@_get_num_from,
+% ltx.@@.func.get_num_from,
+% ltx.@@.func.output_num_from
+% }
+% These functions take as argument a string |tag|, and return the number
+% under which is it recorded (and so the attribute value).
+% The first function outputs the number for lua, while the |output| function
+% outputs to tex.
+% \begin{macrocode}
+local @@_get_num_from =
+ function (tag)
+ if ltx.@@.tables["g_@@_role_tags_prop"][tag] then
+ a= ltx.@@.tables["g_@@_role_tags_prop"][tag]
+ else
+ a= -1
+ end
+ return a
+ end
+
+ltx.@@.func.get_num_from = @@_get_num_from
+
+function ltx.@@.func.output_num_from (tag)
+ local num = @@_get_num_from (tag)
+ tex.sprint(catlatex,num)
+ if num == -1 then
+ @@_log ("Unknown tag "..tag.." used")
+ end
+end
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}
+% {
+% @@_get_tag_from ,
+% ltx.@@.func.get_tag_from,
+% ltx.@@.func.output_tag_from
+% }
+% These functions are the opposites to the previous function:
+% they take as argument a number (the attribute value) and return the string |tag|.
+% The first function outputs the number for lua, while the |output| function
+% outputs to tex.
+% \begin{macrocode}
+local @@_get_tag_from =
+ function (num)
+ if ltx.@@.tables["g_@@_role_tags_seq"][num] then
+ a = ltx.@@.tables["g_@@_role_tags_seq"][num]
+ else
+ a= "UNKNOWN"
+ end
+ return a
+end
+ltx.@@.func.get_tag_from = @@_get_tag_from
+function ltx.@@.func.output_tag_from (num)
+ tex.sprint(catlatex,@@_get_tag_from (num))
+end
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}
+% {
+% ltx.@@.func.store_mc_data
+% }
+% This function stores for |key|=|data| for mc-chunk |num|. It is used in the
+% tagpdf-mc code, to store for example the tag string, and the raw options.
+% \begin{macrocode}
+function ltx.@@.func.store_mc_data (num,key,data)
+ ltx.@@.mc[num] = ltx.@@.mc[num] or { }
+ ltx.@@.mc[num][key] = data
+ @@_log ("INFO TEX-STORE-MC-DATA: "..num.." => "..tostring(key).." => "..tostring(data),3)
+end
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}
+% {
+% ltx.@@.func.store_mc_label
+% }
+% This function stores the |label|=|num| relationship in the |labels| subtable.
+% TODO: this is probably unused and can go.
+% \begin{macrocode}
+function ltx.@@.func.store_mc_label (label,num)
+ ltx.@@.mc["labels"] = ltx.@@.mc["labels"] or { }
+ ltx.@@.mc.labels[label] = num
+end
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}
+% {
+% ltx.@@.func.store_mc_kid
+% }
+% This function is used in the traversing code. It stores
+% a sub-chunk of a mc |mcnum| into the |kids| table.
+% \begin{macrocode}
+function ltx.@@.func.store_mc_kid (mcnum,kid,page)
+ ltx.@@.trace.log("INFO TAG-STORE-MC-KID: "..mcnum.." => " .. kid.." on page " .. page,3)
+ ltx.@@.mc[mcnum]["kids"] = ltx.@@.mc[mcnum]["kids"] or { }
+ local kidtable = {kid=kid,page=page}
+ tableinsert(ltx.@@.mc[mcnum]["kids"], kidtable )
+end
+% \end{macrocode}
+% \end{macro}
+
+% \begin{macro}
+% {
+% ltx.@@.func.mc_num_of_kids
+% }
+% This function returns the number of kids a mc |mcnum| has. We need to account for
+% the case that a mc can have no kids.
+% \begin{macrocode}
+function ltx.@@.func.mc_num_of_kids (mcnum)
+ local num = 0
+ if ltx.@@.mc[mcnum] and ltx.@@.mc[mcnum]["kids"] then
+ num = #ltx.@@.mc[mcnum]["kids"]
+ end
+ ltx.@@.trace.log ("INFO MC-KID-NUMBERS: " .. mcnum .. "has " .. num .. "KIDS",4)
+ return num
+end
+% \end{macrocode}
+% \end{macro}
+% \subsection{Functions to insert the pdf literals}
+% \begin{macro}{@@_insert_emc_node}
+% This insert the emc node.
+% \begin{macrocode}
local function @@_insert_emc_node (head,current)
local emcnode = nodenew("whatsit","pdf_literal")
emcnode.data = "EMC"
@@ -295,8 +575,11 @@ local function @@_insert_emc_node (head,current)
head = node.insert_before(head,current,emcnode)
return head
end
-
-
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{@@_insert_bmc_node}
+% This inserts a simple bmc node
+% \begin{macrocode}
local function @@_insert_bmc_node (head,current,tag)
local bmcnode = nodenew("whatsit","pdf_literal")
bmcnode.data = "/"..tag.." BMC"
@@ -304,7 +587,12 @@ local function @@_insert_bmc_node (head,current,tag)
head = node.insert_before(head,current,bmcnode)
return head
end
-
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{@@_insert_bdc_node}
+% This inserts a bcd node with a fix dict.
+% TODO: check if this is still used, now that we create properties.
+% \begin{macrocode}
local function @@_insert_bdc_node (head,current,tag,dict)
local bdcnode = nodenew("whatsit","pdf_literal")
bdcnode.data = "/"..tag.."<<"..dict..">> BDC"
@@ -312,8 +600,28 @@ local function @@_insert_bdc_node (head,current,tag,dict)
head = node.insert_before(head,current,bdcnode)
return head
end
-
--- this is for debugging the space chars
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{@@_pdf_object_ref,ltx.@@.func.pdf_object_ref}
+% This allows to reference a pdf object reserved with the l3pdf command by name.
+% The return value is |n 0 R|, if the object doesn't exist, n is 0.
+% TODO: is uses internal l3pdf commands, this should be properly supported by l3pdf
+% \begin{macrocode}
+local function @@_pdf_object_ref (name)
+ local tokenname = 'c__pdf_backend_object_'..name..'_int'
+ local object = token.create(tokenname).index..' 0 R'
+ return object
+end
+ltx.@@.func.pdf_object_ref=@@_pdf_object_ref
+% \end{macrocode}
+% \end{macro}
+%
+% \section{Function for the real space chars}
+% \begin{macro}{@@_show_spacemark}
+% A debugging function, it is used to
+% inserts red color markers in the places where space chars can go, it can have
+% side effects so not always reliable, but ok.
+% \begin{macrocode}
local function @@_show_spacemark (head,current,color,height)
local markcolor = color or "1 0 0"
local markheight = height or 10
@@ -323,7 +631,24 @@ local function @@_show_spacemark (head,current,color,height)
head = node.insert_after(head,current,pdfstring)
return head
end
-
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{@@_fakespace,ltx.@@.func.fakespace}
+% This is used to define a lua version of |\pdffakespace|
+% \begin{macrocode}
+local function @@_fakespace()
+ tex.setattribute(iwspaceattributeid,1)
+ tex.setattribute(iwfontattributeid,font.current())
+end
+ltx.@@.func.fakespace = @@_fakespace
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{@@_mark_spaces}
+% a function to mark up places where real space chars should be inserted.
+% It only sets attributes, these are then be used in a later traversing
+% which inserts the actual spaces.
+% When space handling is activated this function is inserted in some callbacks.
+% \begin{macrocode}
--[[ a function to mark up places where real space chars should be inserted
it only sets an attribute.
--]]
@@ -353,13 +678,15 @@ local function @@_mark_spaces (head)
end
-- look also back
if glyph.prev and (glyph.prev.id == GLUE)
- and not inside_math and (glyph.prev.width >0) and not nodehasattribute(glyph.prev,iwspaceattributeid)
+ and not inside_math
+ and (glyph.prev.width >0)
+ and not nodehasattribute(glyph.prev,iwspaceattributeid)
then
nodesetattribute(glyph.prev,iwspaceattributeid,1)
nodesetattribute(glyph.prev,iwfontattributeid,glyph.font)
-- for debugging
- if ltx.__tag.trace.showspaces then
- __tag_show_spacemark (head,glyph)
+ if ltx.@@.trace.showspaces then
+ @@_show_spacemark (head,glyph)
end
end
elseif id == PENALTY then
@@ -381,7 +708,18 @@ local function @@_mark_spaces (head)
end
return head
end
-
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}
+% {
+% @@_activate_mark_space,
+% ltx.@@.func.markspaceon,
+% @@_activate_mark_space,
+% ltx.@@.func.markspaceoff
+% }
+% Theses functions add/remove the function which marks the spaces to the callbacks
+% |pre_linebreak_filter| and |hpack_filter|
+% \begin{macrocode}
local function @@_activate_mark_space ()
if not luatexbase.in_callback ("pre_linebreak_filter","markspaces") then
luatexbase.add_to_callback("pre_linebreak_filter",@@_mark_spaces,"markspaces")
@@ -397,23 +735,150 @@ local function @@_deactivate_mark_space ()
luatexbase.remove_from_callback("hpack_filter","markspaces")
end
end
---
-ltx.@@.func.markspaceoff=@@_deactivate_mark_space
+ltx.@@.func.markspaceoff=@@_deactivate_mark_space
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}
+% {
+% default_space_char,
+% default_fontid,
+% }
+% We need two local variable to setup a default space char.
+% \begin{macrocode}
local default_space_char = node.new(GLYPH)
local default_fontid = font.id("TU/lmr/m/n/10")
default_space_char.char = 32
default_space_char.font = default_fontid
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}
+% {
+% @@_space_chars_shipout,
+% ltx.@@.func.space_chars_shipout,
+% }
+% These is the main function to insert real space chars. It inserts a
+% glyph before every glue which has been marked previously. The attributes
+% are copied from the glue, so if the tagging is done later,
+% it will be tagged like it.
+% \begin{macrocode}
+local function @@_space_chars_shipout (box)
+ local head = box.head
+ if head then
+ for n in node.traverse(head) do
+ local spaceattr = nodegetattribute(n,iwspaceattributeid) or -1
+ if n.id == HLIST then -- enter the hlist
+ @@_space_chars_shipout (n)
+ elseif n.id == VLIST then -- enter the vlist
+ @@_space_chars_shipout (n)
+ elseif n.id == GLUE then
+ if ltx.@@.trace.showspaces and spaceattr==1 then
+ @@_show_spacemark (head,n,"0 1 0")
+ end
+ if spaceattr==1 then
+ local space
+ local space_char = node.copy(default_space_char)
+ local curfont = nodegetattribute(n,iwfontattributeid)
+ ltx.@@.trace.log ("INFO SPACE-FUNCTION-FONT: ".. tostring(curfont),3)
+ if curfont and luaotfload.aux.slot_of_name(curfont,"space") then
+ space_char.font=curfont
+ end
+ head, space = node.insert_before(head, n, space_char) --
+ n.width = n.width - space.width
+ space.attr = n.attr
+ end
+ end
+ end
+ end
+end
-local function @@_insert_space_char (head,n,fontid)
- if luaotfload.aux.slot_of_name(fontid,"space") then
- local space
- -- head, space = node.insert_before(head, n, ) -- Set the right font
- -- n.width = n.width - space.width
- -- space.attr = n.attr
- end
+function ltx.@@.func.space_chars_shipout (box)
+ @@_space_chars_shipout (box)
+end
+% \end{macrocode}
+% \end{macro}
+%
+% \section{Function for the tagging}
+% \begin{macro}
+% {
+% ltx.@@.func.mc_insert_kids
+% }
+% This is the main function to insert the
+% K entry into a StructElem object. It is used in tagpdf-mc-luacode module.
+% The |single| attribute allows to handle the case that a single
+% mc on the tex side can have more than one kid after the processing here,
+% and so we get the correct array/non array setup.
+% \begin{macrocode}
+function ltx.@@.func.mc_insert_kids (mcnum,single)
+ if ltx.@@.mc[mcnum] then
+ ltx.@@.trace.log("INFO TEX-MC-INSERT-KID-TEST: " .. mcnum,4)
+ if ltx.@@.mc[mcnum]["kids"] then
+ if #ltx.@@.mc[mcnum]["kids"] > 1 and single==1 then
+ tex.sprint("[")
+ end
+ for i,kidstable in ipairs( ltx.@@.mc[mcnum]["kids"] ) do
+ local kidnum = kidstable["kid"]
+ local kidpage = kidstable["page"]
+ local kidpageobjnum = pdfpageref(kidpage)
+ ltx.@@.trace.log("INFO TEX-MC-INSERT-KID: " .. mcnum ..
+ " insert KID " ..i..
+ " with num " .. kidnum ..
+ " on page " .. kidpage.."/"..kidpageobjnum,3)
+ tex.sprint(catlatex,"<</Type /MCR /Pg "..kidpageobjnum .. " 0 R /MCID "..kidnum.. ">> " )
+ end
+ if #ltx.@@.mc[mcnum]["kids"] > 1 and single==1 then
+ tex.sprint("]")
+ end
+ else
+ -- this is typically not a problem, e.g. empty hbox in footer/header can
+ -- trigger this warning.
+ ltx.@@.trace.log("WARN TEX-MC-INSERT-NO-KIDS: "..mcnum.." has no kids",2)
+ if single==1 then
+ tex.sprint("null")
+ end
+ end
+ else
+ ltx.@@.trace.log("WARN TEX-MC-INSERT-MISSING: "..mcnum.." doesn't exist",0)
+ end
+end
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{ltx.@@.func.store_struct_mcabs}
+% This function is used in the tagpdf-mc-luacode. It store the absolute count
+% of the mc into the current structure. This must be done ordered.
+% \begin{macrocode}
+function ltx.@@.func.store_struct_mcabs (structnum,mcnum)
+ ltx.@@.struct[structnum]=ltx.@@.struct[structnum] or { }
+ ltx.@@.struct[structnum]["mc"]=ltx.@@.struct[structnum]["mc"] or { }
+ -- a structure can contain more than on mc chunk, the content should be ordered
+ tableinsert(ltx.@@.struct[structnum]["mc"],mcnum)
+ ltx.@@.trace.log("INFO TEX-MC-INTO-STRUCT: "..
+ mcnum.." inserted in struct "..structnum,3)
+ -- but every mc can only be in one structure
+ ltx.@@.mc[mcnum]= ltx.@@.mc[mcnum] or { }
+ ltx.@@.mc[mcnum]["parent"] = structnum
end
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{ltx.@@.func.store_mc_in_page}
+% This is used in the traversing code and stores the relation between
+% abs count and page count.
+% \begin{macrocode}
+-- pay attention: lua counts arrays from 1, tex pages from one
+-- mcid and arrays in pdf count from 0.
+function ltx.@@.func.store_mc_in_page (mcnum,mcpagecnt,page)
+ ltx.@@.page[page] = ltx.@@.page[page] or {}
+ ltx.@@.page[page][mcpagecnt] = mcnum
+ ltx.@@.trace.log("INFO TAG-MC-INTO-PAGE: page " .. page ..
+ ": inserting MCID " .. mcpagecnt .. " => " .. mcnum,3)
+end
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{ltx.@@.func.mark_page_elements}
+% This is the main traversing function. See the lua comment for more details.
+% \begin{macrocode}
--[[
Now follows the core function
It wades through the shipout box and checks the attributes
@@ -433,22 +898,35 @@ end
function ltx.@@.func.mark_page_elements (box,mcpagecnt,mccntprev,mcopen,name,mctypeprev)
local name = name or ("SOMEBOX")
local mctypeprev = mctypeprev or -1
- local abspage = status.total_pages + 1 -- the real counter is increased inside the box so one off
- -- if the callback is not used.
- ltx.@@.trace.log ("PAGE " .. abspage,3)
- ltx.@@.trace.log ("FUNC ARGS: pagecnt".. mcpagecnt.." prev "..mccntprev .. " type prev "..mctypeprev,4)
- ltx.@@.trace.log ("TRAVERSING BOX ".. tostring(name).." TYPE ".. node.type(node.getid(box)),3)
+ local abspage = status.total_pages + 1 -- the real counter is increased
+ -- inside the box so one off
+ -- if the callback is not used. (???)
+ ltx.@@.trace.log ("INFO TAG-ABSPAGE: " .. abspage,3)
+ ltx.@@.trace.log ("INFO TAG-ARGS: pagecnt".. mcpagecnt..
+ " prev "..mccntprev ..
+ " type prev "..mctypeprev,4)
+ ltx.@@.trace.log ("INFO TAG-TRAVERSING-BOX: ".. tostring(name)..
+ " TYPE ".. node.type(node.getid(box)),3)
local head = box.head -- ShipoutBox is a vlist?
if head then
mccnthead, mctypehead,taghead = @@_get_mc_cnt_type_tag (head)
- ltx.@@.trace.log ("HEAD " .. node.type(node.getid(head)).. " MC"..tostring(mccnthead).." => TAG "..tostring(mctypehead).." => "..tostring(taghead),3)
+ ltx.@@.trace.log ("INFO TAG-HEAD: " ..
+ node.type(node.getid(head))..
+ " MC"..tostring(mccnthead)..
+ " => TAG " .. tostring(mctypehead)..
+ " => ".. tostring(taghead),3)
else
- ltx.@@.trace.log ("HEAD is ".. tostring(head),3)
+ ltx.@@.trace.log ("INFO TAG-NO-HEAD: head is "..
+ tostring(head),3)
end
for n in node.traverse(head) do
local mccnt, mctype, tag = @@_get_mc_cnt_type_tag (n)
local spaceattr = nodegetattribute(n,iwspaceattributeid) or -1
- ltx.@@.trace.log ("NODE ".. node.type(node.getid(n)).." MC"..tostring(mccnt).." => TAG "..tostring(mctype).." => " .. tostring(tag),3)
+ ltx.@@.trace.log ("INFO TAG-NODE: "..
+ node.type(node.getid(n))..
+ " MC".. tostring(mccnt)..
+ " => TAG ".. tostring(mctype)..
+ " => " .. tostring(tag),3)
if n.id == HLIST
then -- enter the hlist
mcopen,mcpagecnt,mccntprev,mctypeprev=
@@ -456,83 +934,81 @@ function ltx.@@.func.mark_page_elements (box,mcpagecnt,mccntprev,mcopen,name,mct
elseif n.id == VLIST then -- enter the vlist
mcopen,mcpagecnt,mccntprev,mctypeprev=
ltx.@@.func.mark_page_elements (n,mcpagecnt,mccntprev,mcopen,"INTERNAL VLIST",mctypeprev)
- elseif n.id == GLUE then -- at glue real space chars are inserted, for the rest it is ignored
- -- for debugging
- if ltx.@@.trace.showspaces and spaceattr==1 then
- @@_show_spacemark (head,n,"0 1 0")
- end
- if spaceattr==1 then
- local space
- local space_char = node.copy(default_space_char)
- local curfont = nodegetattribute(n,iwfontattributeid)
- ltx.@@.trace.log ("FONT ".. tostring(curfont),3)
- if curfont and luaotfload.aux.slot_of_name(curfont,"space") then
- space_char.font=curfont
- end
- head, space = node.insert_before(head, n, space_char) --
- n.width = n.width - space.width
- space.attr = n.attr
- end
+ elseif n.id == GLUE then -- at glue real space chars are inserted, but this has
+ -- been done if the previous shipout wandering, so here it is ignored
elseif n.id == LOCAL_PAR then -- local_par is ignored
elseif n.id == PENALTY then -- penalty is ignored
elseif n.id == KERN then -- kern is ignored
- ltx.@@.trace.log ("SUBTYPE KERN ".. n.subtype,3)
+ ltx.@@.trace.log ("INFO TAG-KERN-SUBTYPE: "..
+ node.type(node.getid(n)).." "..n.subtype,4)
else
-- math is currently only logged.
-- we could mark the whole as math
-- for inner processing the mlist_to_hlist callback is probably needed.
if n.id == MATH then
- ltx.@@.trace.log("NODE "..node.type(node.getid(n)).." "..@@_get_mathsubtype(n),3)
+ ltx.@@.trace.log("INFO TAG-MATH-SUBTYPE: "..
+ node.type(node.getid(n)).." "..@@_get_mathsubtype(n),4)
end
-- endmath
- ltx.@@.trace.log("CURRENT "..mccnt.." PREV "..mccntprev,3)
+ ltx.@@.trace.log("INFO TAG-MC-COMPARE: current "..
+ mccnt.." prev "..mccntprev,4)
if mccnt~=mccntprev then -- a new mc chunk
- ltx.@@.trace.log ("NODE ".. node.type(node.getid(n)).." MC"..tostring(mccnt).." <=> PREVIOUS "..tostring(mccntprev),3)
+ ltx.@@.trace.log ("INFO TAG-NEW-MC-NODE: "..
+ node.type(node.getid(n))..
+ " MC"..tostring(mccnt)..
+ " <=> PREVIOUS "..tostring(mccntprev),4)
if mcopen~=0 then -- there is a chunk open, close it (hope there is only one ...
box.list=@@_insert_emc_node (box.list,n)
mcopen = mcopen - 1
- ltx.@@.trace.log ("INSERT EMC " .. mcpagecnt .. " MCOPEN = " .. mcopen,2)
+ ltx.@@.trace.log ("INFO TAG-INSERT-EMC: " ..
+ mcpagecnt .. " MCOPEN = " .. mcopen,3)
if mcopen ~=0 then
- ltx.@@.trace.log ("!WARNING! open mc" .. " MCOPEN = " .. mcopen,1)
+ ltx.@@.trace.log ("WARN TAG-OPEN-MC: " .. mcopen,1)
end
end
if ltx.@@.mc[mccnt] then
if ltx.@@.mc[mccnt]["artifact"] then
- ltx.@@.trace.log("THIS IS AN ARTIFACT of type "..tostring(ltx.@@.mc[mccnt]["artifact"]),3)
+ ltx.@@.trace.log("INFO TAG-INSERT-ARTIFACT: "..
+ tostring(ltx.@@.mc[mccnt]["artifact"]),3)
if ltx.@@.mc[mccnt]["artifact"] == "" then
box.list = @@_insert_bmc_node (box.list,n,"Artifact")
else
box.list = @@_insert_bdc_node (box.list,n,"Artifact", "/Type /"..ltx.@@.mc[mccnt]["artifact"])
end
else
- ltx.@@.trace.log("THIS IS A TAG "..tostring(tag),3)
+ ltx.@@.trace.log("INFO TAG-INSERT-TAG: "..
+ tostring(tag),3)
mcpagecnt = mcpagecnt +1
- ltx.@@.trace.log ("INSERT BDC "..mcpagecnt,2)
+ ltx.@@.trace.log ("INFO TAG-INSERT-BDC: "..mcpagecnt,3)
local dict= "/MCID "..mcpagecnt
if ltx.@@.mc[mccnt]["raw"] then
- ltx.@@.trace.log("RAW CONTENT"..tostring(ltx.@@.mc[mccnt]["raw"]),3)
+ ltx.@@.trace.log("INFO TAG-USE-RAW: "..
+ tostring(ltx.@@.mc[mccnt]["raw"]),3)
dict= dict .. " " .. ltx.@@.mc[mccnt]["raw"]
end
if ltx.@@.mc[mccnt]["alt"] then
- ltx.@@.trace.log("RAW CONTENT"..tostring(ltx.@@.mc[mccnt]["alt"]),3)
+ ltx.@@.trace.log("INFO TAG-USE-ALT: "..
+ tostring(ltx.@@.mc[mccnt]["alt"]),3)
dict= dict .. " " .. ltx.@@.mc[mccnt]["alt"]
end
if ltx.@@.mc[mccnt]["actualtext"] then
- ltx.@@.trace.log("RAW CONTENT"..tostring(ltx.@@.mc[mccnt]["actualtext"]),3)
+ ltx.@@.trace.log("INFO TAG-USE-ACTUALTEXT: "..
+ tostring(ltx.@@.mc[mccnt]["actualtext"]),3)
dict= dict .. " " .. ltx.@@.mc[mccnt]["actualtext"]
end
box.list = @@_insert_bdc_node (box.list,n,tag, dict)
ltx.@@.func.store_mc_kid (mccnt,mcpagecnt,abspage)
ltx.@@.func.store_mc_in_page(mccnt,mcpagecnt,abspage)
- ltx.@@.trace.show_mc_data (mccnt)
+ ltx.@@.trace.show_mc_data (mccnt,3)
end
mcopen = mcopen + 1
else
- ltx.@@.trace.log("THIS HAS NOT BEEN TAGGED",1)
- -- perhaps code that tag a artifact can be added ...
if tagunmarkedbool.mode == truebool.mode then
+ ltx.@@.trace.log("INFO TAG-NOT-TAGGED: this has not been tagged, using artifact",2)
box.list = @@_insert_bmc_node (box.list,n,"Artifact")
mcopen = mcopen + 1
+ else
+ ltx.@@.trace.log("WARN TAG-NOT-TAGGED: this has not been tagged",1)
end
end
mccntprev = mccnt
@@ -541,18 +1017,29 @@ function ltx.@@.func.mark_page_elements (box,mcpagecnt,mccntprev,mcopen,name,mct
end -- end for
if head then
mccnthead, mctypehead,taghead = @@_get_mc_cnt_type_tag (head)
- ltx.@@.trace.log ("ENDHEAD " .. node.type(node.getid(head)).. " MC"..tostring(mccnthead).." => TAG "..tostring(mctypehead).." => "..tostring(taghead),3)
+ ltx.@@.trace.log ("INFO TAG-ENDHEAD: " ..
+ node.type(node.getid(head))..
+ " MC"..tostring(mccnthead)..
+ " => TAG "..tostring(mctypehead)..
+ " => "..tostring(taghead),4)
else
- ltx.@@.trace.log ("ENDHEAD is ".. tostring(head),3)
+ ltx.@@.trace.log ("INFO TAG-ENDHEAD: ".. tostring(head),4)
end
- ltx.@@.trace.log ("QUITTING TRAVERSING BOX ".. tostring(name).." TYPE ".. node.type(node.getid(box)),3)
+ ltx.@@.trace.log ("INFO TAG-QUITTING-BOX "..
+ tostring(name)..
+ " TYPE ".. node.type(node.getid(box)),4)
return mcopen,mcpagecnt,mccntprev,mctypeprev
end
-
-
-function ltx.__tag.func.mark_shipout (box)
- mcopen = ltx.__tag.func.mark_page_elements (box,-1,-100,0,"Shipout",-1)
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{ltx.@@.func.mark_shipout}
+% This is the function used in the callback. Beside calling the traversing
+% function it also checks if there is an open MC-chunk from a page
+% break and insert the needed EMC literal.
+% \begin{macrocode}
+function ltx.@@.func.mark_shipout (box)
+ mcopen = ltx.@@.func.mark_page_elements (box,-1,-100,0,"Shipout",-1)
if mcopen~=0 then -- there is a chunk open, close it (hope there is only one ...
local emcnode = nodenew("whatsit","pdf_literal")
local list = box.list
@@ -561,199 +1048,28 @@ function ltx.__tag.func.mark_shipout (box)
if list then
list = node.insert_after (list,node.tail(list),emcnode)
mcopen = mcopen - 1
- ltx.__tag.trace.log ("INSERT LAST EMC, MCOPEN = " .. mcopen,2)
+ ltx.@@.trace.log ("INFO SHIPOUT-INSERT-LAST-EMC: MCOPEN " .. mcopen,3)
else
- ltx.__tag.trace.log ("UPS ",1)
+ ltx.@@.trace.log ("WARN SHIPOUT-UPS: this shouldn't happen",0)
end
if mcopen ~=0 then
- ltx.__tag.trace.log ("!WARNING! open mc" .. " MCOPEN = " .. mcopen,1)
+ ltx.@@.trace.log ("WARN SHIPOUT-MC-OPEN: " .. mcopen,1)
end
end
end
-
-
-function ltx.@@.trace.show_seq (seq)
- if (type(seq) == "table") then
- for i,v in ipairs(seq) do
- @@_log ("[" .. i .. "] => " .. tostring(v),1)
- end
- else
- @@_log ("sequence " .. tostring(seq) .. " not found",1)
- end
-end
-
-local @@_pairs_prop =
- function (prop)
- local a = {}
- for n in pairs(prop) do tableinsert(a, n) end
- table.sort(a)
- local i = 0 -- iterator variable
- local iter = function () -- iterator function
- i = i + 1
- if a[i] == nil then return nil
- else return a[i], prop[a[i]]
- end
- end
- return iter
- end
-
-
-function ltx.@@.trace.show_prop (prop)
- if (type(prop) == "table") then
- for i,v in @@_pairs_prop (prop) do
- @@_log ("[" .. i .. "] => " .. tostring(v),1)
- end
- else
- @@_log ("prop " .. tostring(prop) .. " not found or not a table",1)
- end
- end
-
-
-local @@_get_num_from =
- function (tag)
- if ltx.@@.tables["g_@@_role_tags_prop"][tag] then
- a= ltx.@@.tables["g_@@_role_tags_prop"][tag]
- else
- a= -1
- end
- return a
- end
-
-ltx.@@.func.get_num_from = @@_get_num_from
-
-function ltx.@@.func.output_num_from (tag)
- local num = @@_get_num_from (tag)
- tex.sprint(catlatex,num)
- if num == -1 then
- @@_log ("Unknown tag "..tag.." used")
- end
-end
-
-local @@_get_tag_from =
- function (num)
- if ltx.@@.tables["g_@@_role_tags_seq"][num] then
- a = ltx.@@.tables["g_@@_role_tags_seq"][num]
- else
- a= "UNKNOWN"
- end
- return a
-end
-
-ltx.@@.func.get_tag_from = @@_get_tag_from
-
-function ltx.@@.func.output_tag_from (num)
- tex.sprint(catlatex,@@_get_tag_from (num))
-end
-
-function ltx.@@.func.store_mc_data (num,key,data)
- ltx.@@.mc[num] = ltx.@@.mc[num] or { }
- ltx.@@.mc[num][key] = data
- @@_log ("storing mc"..num..": "..tostring(key).."=>"..tostring(data))
-end
-
-function ltx.@@.trace.show_mc_data (num)
- if ltx.@@ and ltx.@@.mc and ltx.@@.mc[num] then
- for k,v in pairs(ltx.@@.mc[num]) do
- @@_log ("mc"..num..": "..tostring(k).."=>"..tostring(v),3)
- end
- if ltx.@@.mc[num]["kids"] then
- @@_log ("mc" .. num .. " has " .. #ltx.@@.mc[num]["kids"] .. " kids",3)
- for k,v in ipairs(ltx.@@.mc[num]["kids"]) do
- @@_log ("mc ".. num .. " kid "..k.." =>" .. v.kid.." on page " ..v.page,3)
- end
- end
- else
- @@_log ("mc"..num.." not found",3)
- end
-end
-
-function ltx.@@.trace.show_all_mc_data (max)
- for i = 1, max do
- ltx.@@.trace.show_mc_data (i)
- end
-end
-
-
-function ltx.@@.func.store_mc_label (label,num)
- ltx.@@.mc["labels"] = ltx.@@.mc["labels"] or { }
- ltx.@@.mc.labels[label] = num
-end
-
-function ltx.@@.func.store_mc_kid (mcnum,kid,page)
- ltx.@@.trace.log("MC"..mcnum.." STORING KID" .. kid.." on page " .. page,3)
- ltx.@@.mc[mcnum]["kids"] = ltx.@@.mc[mcnum]["kids"] or { }
- local kidtable = {kid=kid,page=page}
- tableinsert(ltx.@@.mc[mcnum]["kids"], kidtable )
-end
-
-
-function ltx.@@.func.mc_num_of_kids (mcnum)
- local num = 0
- if ltx.@@.mc[mcnum] and ltx.@@.mc[mcnum]["kids"] then
- num = #ltx.@@.mc[mcnum]["kids"]
- end
- ltx.@@.trace.log ("MC" .. mcnum .. "has " .. num .. "KIDS",4)
- return num
-end
-
-function ltx.@@.func.mc_insert_kids (mcnum,single)
- if ltx.@@.mc[mcnum] then
- ltx.@@.trace.log("MC-KIDS test " .. mcnum,4)
- if ltx.@@.mc[mcnum]["kids"] then
- if #ltx.@@.mc[mcnum]["kids"] > 1 and single==1 then
- tex.sprint("[")
- end
- for i,kidstable in ipairs( ltx.@@.mc[mcnum]["kids"] ) do
- local kidnum = kidstable["kid"]
- local kidpage = kidstable["page"]
- local kidpageobjnum = pdfpageref(kidpage)
- ltx.@@.trace.log("MC" .. mcnum .. " insert KID " ..i.. " with num " .. kidnum .. " on page " .. kidpage.."/"..kidpageobjnum,3)
- tex.sprint(catlatex,"<</Type /MCR /Pg "..kidpageobjnum .. " 0 R /MCID "..kidnum.. ">> " )
- end
- if #ltx.@@.mc[mcnum]["kids"] > 1 and single==1 then
- tex.sprint("]")
- end
- else
- ltx.@@.trace.log("WARN! MC"..mcnum.." has no kids",0)
- if single==1 then
- tex.sprint("null")
- end
- end
- else
- ltx.@@.trace.log("WARN! MC"..mcnum.." doesn't exist",0)
- end
-end
-
-
-function ltx.@@.func.store_struct_mcabs (structnum,mcnum)
- ltx.@@.struct[structnum]=ltx.@@.struct[structnum] or { }
- ltx.@@.struct[structnum]["mc"]=ltx.@@.struct[structnum]["mc"] or { }
- -- a structure can contain more than on mc chunk, the content should be ordered
- tableinsert(ltx.@@.struct[structnum]["mc"],mcnum)
- ltx.@@.trace.log("MCNUM "..mcnum.." insert in struct "..structnum,3)
- -- but every mc can only be in one structure
- ltx.@@.mc[mcnum]= ltx.@@.mc[mcnum] or { }
- ltx.@@.mc[mcnum]["parent"] = structnum
-end
-
-function ltx.@@.trace.show_struct_data (num)
- if ltx.@@ and ltx.@@.struct and ltx.@@.struct[num] then
- for k,v in ipairs(ltx.@@.struct[num]) do
- @@_log ("struct "..num..": "..tostring(k).."=>"..tostring(v))
- end
- else
- @@_log ("struct "..num.." not found ")
- end
-end
-
--- pay attention: lua counts arrays from 1, tex pages from one
--- mcid and arrays in pdf count from 0.
-function ltx.@@.func.store_mc_in_page (mcnum,mcpagecnt,page)
- ltx.@@.page[page] = ltx.@@.page[page] or {}
- ltx.@@.page[page][mcpagecnt] = mcnum
- ltx.@@.trace.log("PAGE " .. page .. ": inserting MCID " .. mcpagecnt .. " => " .. mcnum,3)
-end
-
+% \end{macrocode}
+% \end{macro}
+
+% \section{Parenttree}
+% \begin{macro}
+% {
+% ltx.@@.func.fill_parent_tree_line,
+% ltx.@@.func.output_parenttree
+% }
+% These functions create the parent tree. The second, main function
+% is used in the tagpdf-tree code.
+% TODO check if the tree code can move into the backend code.
+% \begin{macrocode}
function ltx.@@.func.fill_parent_tree_line (page)
-- we need to get page-> i=kid -> mcnum -> structnum
-- pay attention: the kid numbers and the page number in the parent tree start with 0!
@@ -761,33 +1077,41 @@ function ltx.@@.func.fill_parent_tree_line (page)
local pdfpage = page-1
if ltx.@@.page[page] and ltx.@@.page[page][0] then
mcchunks=#ltx.@@.page[page]
- ltx.@@.trace.log("PAGETREE PAGE "..page.." has "..mcchunks.."+1 Elements ",3)
+ ltx.@@.trace.log("INFO PARENTTREE-NUM: page "..
+ page.." has "..mcchunks.."+1 Elements ",4)
for i=0,mcchunks do
- ltx.@@.trace.log("PAGETREE CHUNKS "..ltx.@@.page[page][i],3)
+ -- what does this log??
+ ltx.@@.trace.log("INFO PARENTTREE-CHUNKS: "..
+ ltx.@@.page[page][i],4)
end
if mcchunks == 0 then
-- only one chunk so no need for an array
local mcnum = ltx.@@.page[page][0]
local structnum = ltx.@@.mc[mcnum]["parent"]
local propname = "g_@@_struct_"..structnum.."_prop"
- local objref = ltx.@@.tables[propname]["objref"] or "XXXX"
- ltx.@@.trace.log("=====>"..tostring(objref),5)
+ --local objref = ltx.@@.tables[propname]["objref"] or "XXXX"
+ local objref = @@_pdf_object_ref('@@/struct/'..structnum)
+ ltx.@@.trace.log("INFO PARENTTREE-STRUCT-OBJREF: =====>"..
+ tostring(objref),5)
numsentry = pdfpage .. " [".. objref .. "]"
- ltx.@@.trace.log("PAGETREE PAGE" .. page.. " NUM ENTRY = ".. numsentry,3)
+ ltx.@@.trace.log("INFO PARENTTREE-NUMENTRY: page " ..
+ page.. " num entry = ".. numsentry,3)
else
numsentry = pdfpage .. " ["
for i=0,mcchunks do
local mcnum = ltx.@@.page[page][i]
local structnum = ltx.@@.mc[mcnum]["parent"] or 0
local propname = "g_@@_struct_"..structnum.."_prop"
- local objref = ltx.@@.tables[propname]["objref"] or "XXXX"
+ --local objref = ltx.@@.tables[propname]["objref"] or "XXXX"
+ local objref = @@_pdf_object_ref('@@/struct/'..structnum)
numsentry = numsentry .. " ".. objref
end
numsentry = numsentry .. "] "
- ltx.@@.trace.log("PAGETREE PAGE" .. page.. " NUM ENTRY = ".. numsentry,3)
+ ltx.@@.trace.log("INFO PARENTTREE-NUMENTRY: page " ..
+ page.. " num entry = ".. numsentry,3)
end
else
- ltx.@@.trace.log ("PAGETREE: NO DATA FOR PAGE "..page,3)
+ ltx.@@.trace.log ("INFO PARENTTREE-NO-DATA: page "..page,3)
end
return numsentry
end
@@ -798,7 +1122,10 @@ function ltx.@@.func.output_parenttree (abspage)
tex.sprint(catlatex,line)
end
end
-
-
+% \end{macrocode}
+% \end{macro}
+% \begin{macrocode}
%</lua>
% \end{macrocode}
+% \end{implementation}
+% \PrintIndex
diff --git a/Master/texmf-dist/source/latex/tagpdf/tagpdf-checks.dtx b/Master/texmf-dist/source/latex/tagpdf/tagpdf-checks.dtx
index 87f493d0d82..e0a1c013d7f 100644
--- a/Master/texmf-dist/source/latex/tagpdf/tagpdf-checks.dtx
+++ b/Master/texmf-dist/source/latex/tagpdf/tagpdf-checks.dtx
@@ -22,59 +22,442 @@
%
% for those people who are interested.
%
+%
+%<*driver>
+\RequirePackage{pdfmanagement-testphase}
+\DeclareDocumentMetadata{}
+\makeatletter
+\declare@file@substitution{doc.sty}{doc-v3beta.sty}
+\makeatother
+\documentclass{l3doc}
+\usepackage{array,booktabs,caption}
+\hypersetup{pdfauthor=Ulrike Fischer,
+ pdftitle=tagpdf-checks module (tagpdf)}
+\begin{document}
+ \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
% \fi
+% \title{^^A
+% The \pkg{tagpdf-checks} module\\ Messages and check code ^^A
+% \\ Part of the tagpdf package
+% }
+%
+% \author{^^A
+% Ulrike Fischer\thanks
+% {^^A
+% E-mail:
+% \href{mailto:fischer@troubleshooting-tex.de}
+% {fischer@troubleshooting-tex.de}^^A
+% }^^A
+% }
+%
+% \date{Version 0.9, released 2021-06-29}
+% \maketitle
+% \begin{documentation}
+% \section{Commands}
+% \begin{function}[pTF,EXP]{\tag_if_active:}
+% This command tests if tagging is active. It only gives true if all tagging has
+% been activated, \emph{and} if tagging hasn't been stopped locally.
+% \end{function}
+% \begin{function}[EXP]{\tag_get:n}
+% \begin{syntax}
+% \cs{tag_get:n}\Arg{keyword}
+% \end{syntax}
+% This is a generic command to retrieve data. Currently
+% the only sensible values for the argument \meta{keyword}
+% are |mc_tag| and |struct_tag|.
+% \end{function}
+%
+% \section{Description of log messages}
+% \subsection{\cs{ShowTagging} command}
+% \begin{tabular}{lll}
+% Argument & type & note\\
+% \cs{ShowTagging}{mc-data = num} & log+term & lua-only\\
+% \cs{ShowTagging}{mc-current} & log+term & \\
+% \cs{ShowTagging}{struck-stack= [log\verb+|+show]} & log or term+stop \\
+% \end{tabular}
+%
+% \subsection{Messages in checks and commands}
+% \scriptsize
+% \begin{tabular}{llll}
+% command & message & action & remark\\
+% |\@@_check_structure_has_tag:n|
+% & |struct-missing-tag|
+% & error
+% \\
+% |\@@_check_structure_tag:N|
+% & |role-unknown-tag|
+% & warning
+% \\
+% |\@@_check_info_closing_struct:n|
+% & |struct-show-closing|
+% & info
+% & log-level>0
+% \\
+% |\@@_check_no_open_struct:|
+% & struct-faulty-nesting
+% & error
+% & TODO: error only with 1?
+% \\
+% |\@@_check_struct_used:n|
+% & |struct-used-twice|
+% & warning
+% \\
+% |\@@_check_add_tag_role:nn|
+% & |role-missing|, |role-tag|, |role-unknown|
+% & warning, info (>0), warning
+% \\
+% |\@@_check_mc_if_nested:|,
+% & |mc-nested|
+% & warning
+% \\
+% |\@@_check_mc_if_open:|
+% & |mc-not-open|
+% & warning
+% & only generic (?)
+% \\
+% |\@@_check_mc_pushed_popped:nn|
+% & |mc-pushed|, |mc-popped|
+% & info (2), info+|seq_log| (>2)
+% \\
+% |\@@_check_mc_tag:N|
+% & |mc-tag-missing|, |role-unknown-tag|
+% & error (missing), warning (unknown).
+% \\
+% |\@@_check_mc_used:n|
+% & |mc-used-twice|
+% & warning
+% & TODO: review the sense of this test!
+% \\
+% |\@@_check_show_MCID_by_page:|
+% &
+% &
+% & currently unused
+% \\
+% |\tag_mc_use:n|
+% & |mc-label-unknown|, |mc-used-twice|
+% & warning
+% & in mc-shared
+% \\
+% |\role_add_tag:nn|
+% & |new-tag|
+% & info (>0)
+% & in roles
+% \\
+% & |sys-no-interwordspace|
+% & warning
+% & space module, only xetex/dvi
+% \\
+% |\@@_struct_write_obj:n|
+% & |struct-no-objnum|
+% & error
+% & in struct module
+% \\
+% |\tag_struct_begin:n|
+% & |struct-faulty-nesting|
+% & error
+% \\
+% |\@@_struct_insert_annot:nn|
+% & |struct-faulty-nesting|
+% & error
+% \\
+% |tag_struct_use:n|
+% & |struct-label-unknown|
+% & warning
+% \\
+% |attribute-class|, |attribute|
+% & |attr-unknown|
+% & error
+% \\
+% |\@@_tree_fill_parenttree:|
+% & |tree-mcid-index-wrong|
+% & warning
+% TODO: should trigger a standard rerun message.
+% \end{tabular}
%
+% \normalsize
+% \subsection{Warning messages from the lua-code}
+% The messages are triggered if the log-level is at least equal to the number.
+%
+% \begin{tabular}[t]{>{\ttfamily}lll}
+% message & log-level & remark \\\hline
+% WARN TAG-NOT-TAGGED: &1 \\
+% WARN TAG-OPEN-MC: &1 \\
+% WARN SHIPOUT-MC-OPEN: &1 \\
+% WARN SHIPOUT-UPS: &0 & shouldn't happen \\
+% WARN TEX-MC-INSERT-MISSING:&0 & shouldn't happen \\
+% WARN TEX-MC-INSERT-NO-KIDS:&2 & e.g. from empty hbox
+% \end{tabular}
+%
+% \subsection{Info messages from the lua-code}
+% The messages are triggered if the log-level is at least equal to the number.
+% |TAG| messages are from the traversing function, |TEX| from code used in the tagpdf-mc module.
+% |PARENTREE| is the code building the parenttree.
+%
+% \begin{longtable}{>{\ttfamily}lll}
+% message & log-level & remark \\\hline\endhead
+% INFO SHIPOUT-INSERT-LAST-EMC & 3 & finish of shipout code \\
+% INFO SPACE-FUNCTION-FONT & 3 & interwordspace code \\
+% INFO TAG-ABSPAGE & 3 \\
+% INFO TAG-ARGS & 4 \\
+% INFO TAG-ENDHEAD & 4 \\
+% INFO TAG-ENDHEAD & 4 \\
+% INFO TAG-HEAD & 3 \\
+% INFO TAG-INSERT-ARTIFACT & 3 \\
+% INFO TAG-INSERT-BDC & 3 \\
+% INFO TAG-INSERT-EMC & 3 \\
+% INFO TAG-INSERT-TAG & 3 \\
+% INFO TAG-KERN-SUBTYPE & 4\\
+% INFO TAG-MATH-SUBTYPE & 4 \\
+% INFO TAG-MC-COMPARE & 4 \\
+% INFO TAG-MC-INTO-PAGE & 3 \\
+% INFO TAG-NEW-MC-NODE & 4 \\
+% INFO TAG-NODE & 3 \\
+% INFO TAG-NO-HEAD & 3 \\
+% INFO TAG-NOT-TAGGED & 2 & replaced by artifact\\
+% INFO TAG-QUITTING-BOX & 4 \\
+% INFO TAG-STORE-MC-KID & 4 \\
+% INFO TAG-TRAVERSING-BOX 3 \\
+% INFO TAG-USE-ACTUALTEXT & 3 \\
+% INFO TAG-USE-ALT & 3 \\
+% INFO TAG-USE-RAW & 3 \\
+% INFO TEX-MC-INSERT-KID & 3 \\
+% INFO TEX-MC-INSERT-KID-TEST & 4 \\
+% INFO TEX-MC-INTO-STRUCT & 3 \\
+% INFO TEX-STORE-MC-DATA & 3 \\
+% INFO TEX-STORE-MC-KID & 3 \\
+% INFO PARENTTREE-CHUNKS & 3 \\
+% INFO PARENTTREE-NO-DATA & 3\\
+% INFO PARENTTREE-NUM & 3 \\
+% INFO PARENTTREE-NUMENTRY & 3 \\
+% INFO PARENTTREE-STRUCT-OBJREF & 4
+% \end{longtable}
+
+% \end{documentation}
+% \begin{implementation}
% \begin{macrocode}
%<@@=tag>
-%<*checks>
-\ProvidesExplPackage {tagpdf-checks-code} {2021-06-14} {0.82}
- {part of tagpdf - code related to checks and messages}
-
-
-%messages
-
-% mc
-\msg_new:nnn { tag } {mc-nested} { nested~marked~content~found~-~mcid~#1 }
-\msg_new:nnn { tag } {mc-tag-missing} { required~tag~missing~-~mcid~#1 }
-\msg_new:nnn { tag } {mc-label-unknown} { label~#1~unknown~-~rerun }
-\msg_new:nnn { tag } {mc-used-twice} { mc~#1~has~been~already~used }
-\msg_new:nnn { tag } {mc-not-open} { there~is~no~mc~to~end~at~#1 }
-\msg_new:nnn { tag } {mc-pushed} { #1~has~been~pushed~to~the~mc~stack}
-\msg_new:nnn { tag } {mc-popped} { #1~has~been~removed~from~the~mc~stack }
-
-% structures
-\msg_new:nnn { tag } {struct-no-objnum} { objnum~missing~for~structure~#1 }
-\msg_new:nnn { tag } {struct-faulty-nesting} { there~is~no~open~structure~on~the~stack }
-\msg_new:nnn { tag } {struct-missing-tag} { a~structure~must~have~a~tag! }
-\msg_new:nnn { tag } {struct-show-closing} { closing~structure~#1~tagged~\prop_item:cn{g_@@_struct_#1_prop}{S} }
-\msg_new:nnn { tag } {struct-used-twice} { structure~with~label~#1~has~already~been~used}
-\msg_new:nnn { tag } {struct-label-unknown} { structure~with~label~#1~is~unknown~rerun}
-
-% attributes
+%<*header>
+\ProvidesExplPackage {tagpdf-checks-code} {2021-06-29} {0.9}
+ {part of tagpdf - code related to checks, conditionals, debugging and messages}
+%</header>
+% \end{macrocode}
+% \section{Messages}
+% \subsection{Messages related to mc-chunks}
+% \begin{macro}{mc-nested}
+% This message is issue is a mc is opened before the previous has been closed.
+% This is not relevant for luamode, as the attributes don't care about this.
+% It is used in the |\@@_check_mc_if_nested:| test.
+% \begin{macrocode}
+%<*package>
+\msg_new:nnn { tag } {mc-nested} { nested~marked~content~found~-~mcid~#1 }
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{mc-tag-missing}
+% If the tag is missing
+% \begin{macrocode}
+\msg_new:nnn { tag } {mc-tag-missing} { required~tag~missing~-~mcid~#1 }
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{mc-label-unknown}
+% If the label of a mc that is used in another place is not known (yet)
+% or has been undefined as the mc was already used.
+% \begin{macrocode}
+\msg_new:nnn { tag } {mc-label-unknown}
+ { label~#1~unknown~or~has~been~already~used.\\
+ Either~rerun~or~remove~one~of~the~uses. }
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{mc-used-twice}
+% An mc-chunk can be inserted only in one structure. This indicates wrong coding
+% and so should at least give a warning.
+% \begin{macrocode}
+\msg_new:nnn { tag } {mc-used-twice} { mc~#1~has~been~already~used }
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{mc-not-open}
+% This is issued if a |\tag_mc_end:| is issued wrongly, wrong coding.
+% \begin{macrocode}
+\msg_new:nnn { tag } {mc-not-open} { there~is~no~mc~to~end~at~#1 }
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{mc-pushed,mc-popped}
+% Informational messages about mc-pushing.
+% \begin{macrocode}
+\msg_new:nnn { tag } {mc-pushed} { #1~has~been~pushed~to~the~mc~stack}
+\msg_new:nnn { tag } {mc-popped} { #1~has~been~removed~from~the~mc~stack }
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{mc-current}
+% Informational messages about current mc state.
+% \begin{macrocode}
+\msg_new:nnn { tag } {mc-current}
+ { current~MC:~
+ \bool_if:NTF\g_@@_in_mc_bool
+ {abscnt=\@@_get_mc_abs_cnt:,~tag=\g_@@_mc_key_tag_tl}
+ {no~MC~open,~current~abscnt=\@@_get_mc_abs_cnt:"}
+ }
+% \end{macrocode}
+% \end{macro}
+% \subsection{Messages related to mc-chunks}
+% \begin{macro}{struct-no-objnum}
+% Should not happen \ldots
+% \begin{macrocode}
+\msg_new:nnn { tag } {struct-no-objnum} { objnum~missing~for~structure~#1 }
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{struct-faulty-nesting}
+% This indicates that there is somewhere one |\tag_struct_end:| too much.
+% This should be normally an error.
+% \begin{macrocode}
+\msg_new:nnn { tag }
+ {struct-faulty-nesting}
+ { there~is~no~open~structure~on~the~stack }
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{struct-missing-tag}
+% A structure must have a tag.
+% \begin{macrocode}
+\msg_new:nnn { tag } {struct-missing-tag} { a~structure~must~have~a~tag! }
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{struct-used-twice}
+% \begin{macrocode}
+\msg_new:nnn { tag } {struct-used-twice}
+ { structure~with~label~#1~has~already~been~used}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{struct-label-unknown}
+% label is unknown, typically needs a rerun.
+% \begin{macrocode}
+\msg_new:nnn { tag } {struct-label-unknown}
+ { structure~with~label~#1~is~unknown~rerun}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{struct-show-closing}
+% Informational message shown if log-mode is high enough
+% \begin{macrocode}
+\msg_new:nnn { tag } {struct-show-closing}
+ { closing~structure~#1~tagged~\prop_item:cn{g_@@_struct_#1_prop}{S} }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Attributes}
+% Not much yet, as attributes aren't used so much.
+% \begin{macro}{attr-unknown}
+% \begin{macrocode}
\msg_new:nnn { tag } {attr-unknown} { attribute~#1~is~unknown}
-
-
-%Roles
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Roles}
+% \begin{macro}{role-missing,role-unknown,role-unknown-tag}
+% Warning message if either the tag or the role is missing
+% \begin{macrocode}
\msg_new:nnn { tag } {role-missing} { tag~#1~has~no~role~assigned }
\msg_new:nnn { tag } {role-unknown} { role~#1~is~not~known }
\msg_new:nnn { tag } {role-unknown-tag} { tag~#1~is~not~known }
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{role-tag,new-tag}
+% Info messages.
+% \begin{macrocode}
\msg_new:nnn { tag } {role-tag} { mapping~tag~#1~to~role~#2 }
\msg_new:nnn { tag } {new-tag} { adding~new~tag~#1 }
-
-
-% trees
-\msg_new:nnn { tag } {tree-mcid-index-wrong} {something~is~wrong~with~the~mcid}
-
-% obj
-\msg_new:nnn { tag } {obj-write-num} {write~obj~#1~to~pdf}
-
-% engine problem
-\msg_new:nnn { tag } {sys-no-interwordspace} {engine~#1~doesn't~support~the~interword~spaces}
-
-%checks
-%structures
-
-\cs_new:Nn \@@_check_structure_has_tag:n %#1 struct num %_protected?
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Miscellaneous}
+% \begin{macro}{tree-mcid-index-wrong}
+% Used in the tree code, typically indicates the document must be rerun.
+% \begin{macrocode}
+\msg_new:nnn { tag } {tree-mcid-index-wrong}
+ {something~is~wrong~with~the~mcid--rerun}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{sys-no-interwordspace}
+% Currently only pdflatex and lualatex have some support for real spaces.
+% \begin{macrocode}
+\msg_new:nnn { tag } {sys-no-interwordspace}
+ {engine/output~mode~#1~doesn't~support~the~interword~spaces}
+% \end{macrocode}
+% \end{macro}
+% \section{Retrieving data}
+% \begin{macro}[EXP]{\tag_get:n}
+% This retrieves some data.
+% This is a generic command to retrieve data. Currently
+% the only sensible values for the argument are |mc_tag| and |struct_tag|.
+% \begin{macrocode}
+\cs_new:Npn \tag_get:n #1 { \use:c {@@_get_data_#1: } }
+% \end{macrocode}
+% \end{macro}
+%
+% \section{User conditionals}
+% \begin{macro}[pTF]{\tag_if_active:}
+% This is a test it tagging is active. This allows packages
+% to add conditional code.
+% The test is true if all booleans, the global and the two local one are true.
+%
+% \begin{macrocode}
+\prg_new_conditional:Npnn \tag_if_active: { p , T , TF, F }
+ {
+ \bool_lazy_all:nTF
+ {
+ {\g_@@_active_struct_bool}
+ {\g_@@_active_mc_bool}
+ {\g_@@_active_tree_bool}
+ {\l_@@_active_struct_bool}
+ {\l_@@_active_mc_bool}
+ }
+ {
+ \prg_return_true:
+ }
+ {
+ \prg_return_false:
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \section{Internal checks}
+% These are checks used in various places in the code.
+%
+% \subsection{checks for active tagging}
+% \begin{macro}[TF]{\@@_check_if_active_mc:,\@@_check_if_active_struct:}
+% Structures must have a tag, so we check if the S entry is in the property.
+% It is an error if this is missing. The argument is a number.
+% \begin{macrocode}
+\prg_new_conditional:Npnn \@@_check_if_active_mc: {T,F,TF}
+ {
+ \bool_lazy_and:nnTF { \g_@@_active_mc_bool } { \l_@@_active_mc_bool }
+ {
+ \prg_return_true:
+ }
+ {
+ \prg_return_false:
+ }
+ }
+\prg_new_conditional:Npnn \@@_check_if_active_struct: {T,F,TF}
+ {
+ \bool_lazy_and:nnTF { \g_@@_active_struct_bool } { \l_@@_active_struct_bool }
+ {
+ \prg_return_true:
+ }
+ {
+ \prg_return_false:
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \subsection{Checks related to stuctures}
+% \begin{macro}{\@@_check_structure_has_tag:n}
+% Structures must have a tag, so we check if the S entry is in the property.
+% It is an error if this is missing. The argument is a number.
+% The tests for existence and type is split in structures,
+% as the tags are stored differently to the mc case.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_check_structure_has_tag:n #1 %#1 struct num
{
\prop_if_in:cnF { g_@@_struct_#1_prop }
{S}
@@ -82,37 +465,50 @@
\msg_error:nn { tag } {struct-missing-tag}
}
}
-
-\cs_new:Nn \@@_check_structure_tag:N %_protected?
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\@@_check_structure_tag:N}
+% This checks if the name of the tag is known,
+% either because it is a standard type or has been rolemapped.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_check_structure_tag:N #1
{
\prop_if_in:NoF \g_@@_role_tags_prop {#1}
{
\msg_warning:nnx { tag } {role-unknown-tag} {#1}
}
}
-
-\cs_new:Nn \@@_check_structure_tag:NN %_protected?
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\@@_check_info_closing_struct:n}
+% This info message is issued at a closing structure, the use should be guarded by
+% log-level.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_check_info_closing_struct:n #1 %#1 struct num
{
- \exp_args:NNx
- \prop_if_in:NnF \g_@@_role_tags_prop {#1/#2}
+ \int_compare:nNnT {\l_@@_loglevel_int} > { 0 }
{
- \msg_warning:nnx { tag } {role-unknown-tag} {#1}
+ \msg_info:nnn { tag } {struct-show-closing} {#1}
}
}
-\cs_new_protected:Nn \@@_check_info_closing_struct:n %#1 struct num
- {
- \msg_info:nnn { tag } {struct-show-closing} {#1}
- }
-
\cs_generate_variant:Nn \@@_check_info_closing_struct:n {o,x}
-
-\cs_new_protected:Nn \@@_check_no_open_struck:
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\@@_check_no_open_struct:}
+% This checks if there is an open structure. It should be used when trying to
+% close a structure. It errors if false.%
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_check_no_open_struct:
{
\msg_error:nn { tag } {struct-faulty-nesting}
}
-
-\cs_new_protected:Nn \@@_check_struct_used:n %#1 label
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\@@_check_struct_used:n}
+% This checks if a stashed structure has already been used.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_check_struct_used:n #1 %#1 label
{
\prop_get:cnNT
{g_@@_struct_\@@_ref_value:enn{tagpdfstruct-#1}{tagstruct}{unknown}_prop}
@@ -122,10 +518,14 @@
\msg_warning:nnn { tag } {struct-used-twice} {#1}
}
}
-
-%roles
-
-\cs_new_protected:Nn \@@_check_add_tag_role:nn %#1 tag, #2 role
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Checks related to roles}
+% \begin{macro}{\@@_check_add_tag_role:nn}
+% This check is used when defining a new role mapping.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_check_add_tag_role:nn #1 #2 %#1 tag, #2 role
{
\tl_if_empty:nTF {#2}
{
@@ -134,16 +534,26 @@
{
\prop_get:NnNTF \g_@@_role_tags_prop {#2} \l_tmpa_tl
{
- \msg_info:nnnn { tag } {role-tag} {#1} {#2}
+ \int_compare:nNnT {\l_@@_loglevel_int} > { 0 }
+ {
+ \msg_info:nnnn { tag } {role-tag} {#1} {#2}
+ }
}
{
\msg_warning:nnn { tag } {role-unknown} {#2}
}
}
}
-
-%mc
-\cs_new_protected:Nn \@@_check_mc_if_nested:
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Check related to mc-chunks}
+%
+% \begin{macro}{\@@_check_mc_if_nested:,\@@_check_mc_if_open:}
+% Two tests if a mc is currently open. One for the true (for begin
+% code), one for the false part (for end code).
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_check_mc_if_nested:
{
\@@_mc_if_in:T
{
@@ -151,15 +561,21 @@
}
}
-\cs_new_protected:Nn \@@_check_mc_if_open:
+\cs_new_protected:Npn \@@_check_mc_if_open:
{
\@@_mc_if_in:F
{
\msg_warning:nnx { tag } {mc-not-open} { \@@_get_mc_abs_cnt: }
}
}
-
-\cs_new_protected:Nn \@@_check_mc_pushed_popped:nn
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\@@_check_mc_pushed_popped:nn}
+% This creates an information message if mc's are pushed or popped.
+% The first argument is a word (pushed or popped), the second the tag name.
+% With larger log-level the stack is shown too.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_check_mc_pushed_popped:nn #1 #2
{
\int_compare:nNnT
{ \l_@@_loglevel_int } ={ 2 }
@@ -167,13 +583,16 @@
\int_compare:nNnT
{ \l_@@_loglevel_int } > { 2 }
{
- \msg_warning:nnx {tag}{mc-#1}{#2}
- \seq_log:N \g_@@_mc_stack_seq
+ \msg_info:nnx {tag}{mc-#1}{#2}
+ \seq_log:N \g_@@_mc_stack_seq
}
}
-
-
-\cs_new:Nn \@@_check_mc_tag:N %protected??
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\@@_check_mc_tag:N}
+% This checks if the mc has a (known) tag.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_check_mc_tag:N #1 %#1 is var with a tag name in it
{
\tl_if_empty:NT #1
{
@@ -184,22 +603,56 @@
\msg_warning:nnx { tag } {role-unknown-tag} {#1}
}
}
-
-\seq_new:N \g_@@_check_mc_used_seq
-\cs_new_protected:Nn \@@_check_mc_used:n
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{variable}{\g_@@_check_mc_used_intarray, \@@_check_init_mc_used:}
+% This variable holds the list of used mc numbers.
+% Everytime we store a mc-number we will add one the relevant array index
+% If everything is right at the end there should be only 1 until the max count
+% of the mcid. 2 indicates that one mcid was used twice, 0 that we lost one.
+% In engines other than luatex the total number of all intarray entries
+% are restricted so we use only a rather small value of 65536, and we initialize
+% the array only at first used, guarded by the log-level.
+% This check is probably only needed for debugging.
+% TODO does this really make sense to check? When can it happen??
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_check_init_mc_used:
{
- \seq_if_in:NnTF \g_@@_check_mc_used_seq {#1}
- {
- \msg_warning:nnn { tag } {mc-used-twice} {#1}
- }
+ \intarray_new:Nn \g_@@_check_mc_used_intarray { 65536 }
+ \cs_gset_eq:NN \@@_check_init_mc_used: \prg_do_nothing:
+ }
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}{\@@_check_mc_used:n}
+% This checks if a mc is used twice.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_check_mc_used:n #1 %#1 mcid abscnt
+ {
+ \int_compare:nNnT {\l_@@_loglevel_int} > { 2 }
{
- \seq_gput_right:Nx \g_@@_check_mc_used_seq {#1}
+ \@@_check_init_mc_used:
+ \intarray_gset:Nnn \g_@@_check_mc_used_intarray
+ {#1}
+ { \intarray_item:Nn \g_@@_check_mc_used_intarray {#1} + 1 }
+ \int_compare:nNnT
+ {
+ \intarray_item:Nn \g_@@_check_mc_used_intarray {#1}
+ }
+ >
+ { 1 }
+ {
+ \msg_warning:nnn { tag } {mc-used-twice} {#1}
+ }
}
}
-
-
-
-\cs_new_protected:Nn \@@_check_show_MCID_by_page:
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\@@_check_show_MCID_by_page:}
+% This allows to show the mc on a page. Currently unused.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_check_show_MCID_by_page:
{
\tl_set:Nx \l_@@_tmpa_tl
{
@@ -245,14 +698,10 @@
\seq_show:N \l_tmpa_seq
}
}
-
-\cs_new:Nn \@@_check_record_pdfobj_num:n %protected?
- {
- \int_compare:nT { \l_@@_loglevel_int >= 3 }
- {
- \msg_info:nnx { tag } {obj-write-num} {#1}
- }
- }
-
-%</checks>
% \end{macrocode}
+% \end{macro}
+% \begin{macrocode}
+%</package>
+% \end{macrocode}
+% \end{implementation}
+% \PrintIndex
diff --git a/Master/texmf-dist/source/latex/tagpdf/tagpdf-mc-generic.dtx b/Master/texmf-dist/source/latex/tagpdf/tagpdf-mc-generic.dtx
new file mode 100644
index 00000000000..956e3e91cbf
--- /dev/null
+++ b/Master/texmf-dist/source/latex/tagpdf/tagpdf-mc-generic.dtx
@@ -0,0 +1,389 @@
+% \iffalse meta-comment
+%
+%% File: tagpdf-mc.dtx
+%
+% Copyright (C) 2019-2021 Ulrike Fischer
+%
+% It may be distributed and/or modified under the conditions of the
+% LaTeX Project Public License (LPPL), either version 1.3c of this
+% license or (at your option) any later version. The latest version
+% of this license is in the file
+%
+% https://www.latex-project.org/lppl.txt
+%
+% This file is part of the "tagpdf bundle" (The Work in LPPL)
+% and all files in that bundle must be distributed together.
+%
+% -----------------------------------------------------------------------
+%
+% The development version of the bundle can be found at
+%
+% https://github.com/u-fischer/tagpdf
+%
+% for those people who are interested.
+%<*driver>
+\RequirePackage{pdfmanagement-testphase}
+\DeclareDocumentMetadata{}
+\makeatletter
+\declare@file@substitution{doc.sty}{doc-v3beta.sty}
+\makeatother
+\documentclass{l3doc}
+\usepackage{array,booktabs,caption}
+\hypersetup{pdfauthor=Ulrike Fischer,
+ pdftitle=tagpdf-mc module (tagpdf)}
+\begin{document}
+ \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
+% \fi
+% \title{^^A
+% The \pkg{tagpdf-mc-generic} module\\ Code related to Marked Content (mc-chunks), generic mode ^^A
+% \\ Part of the tagpdf package
+% }
+%
+% \author{^^A
+% Ulrike Fischer\thanks
+% {^^A
+% E-mail:
+% \href{mailto:fischer@troubleshooting-tex.de}
+% {fischer@troubleshooting-tex.de}^^A
+% }^^A
+% }
+%
+% \date{Version 0.9, released 2021-06-29}
+% \maketitle
+% \begin{implementation}
+% \section{Marked content code -- generic mode}
+% \begin{macrocode}
+%<@@=tag>
+%<*generic>
+\ProvidesExplPackage {tagpdf-mc-code-generic} {2021-06-29} {0.9}
+ {part of tagpdf - code related to marking chunks - generic mode}
+%</generic>
+% \end{macrocode}
+% \subsection{Variables}
+% \begin{variable}{\g_@@_in_mc_bool}
+% This booleans records if a mc is open, to test nesting.
+% \begin{macrocode}
+%<*generic>
+\bool_new:N \g_@@_in_mc_bool
+% \end{macrocode}
+% \end{variable}
+
+% \begin{variable}{\g_@@_MCID_byabspage_prop}
+% This property will hold the current maximum on a page
+% it will contain key-value of type \meta{abspagenum}=\meta{max mcid}
+%
+% \begin{macrocode}
+\@@_prop_new:N \g_@@_MCID_byabspage_prop
+% \end{macrocode}
+% \end{variable}
+
+% \begin{variable}{\l_@@_mc_ref_abspage_tl}
+% We need a ref-label system to ensure that the MCID cnt
+% restarts at 0 on a new page
+% This will be used to store the tagabspage attribute retrieved from
+% a label.
+% \begin{macrocode}
+\tl_new:N \l_@@_mc_ref_abspage_tl
+% \end{macrocode}
+% \end{variable}
+
+% \begin{variable}{\l_@@_mc_tmpa_tl}
+% temporary variable
+% \begin{macrocode}
+\tl_new:N \l_@@_mc_tmpa_tl
+% \end{macrocode}
+% \end{variable}
+
+% \subsection{Functions}
+
+% \begin{macro}[pTF]{\@@_mc_if_in:,\tag_mc_if_in:}
+% This is a test if a mc is open or not. It depends simply on a global boolean:
+% mc-chunks are added linearly so nesting should not be relevant.
+% \begin{macrocode}
+\prg_new_conditional:Nnn \@@_mc_if_in: {p,T,F,TF}
+ {
+ \bool_if:NTF \g_@@_in_mc_bool
+ { \prg_return_true: }
+ { \prg_return_false: }
+ }
+
+\prg_new_eq_conditional:NNn \tag_mc_if_in: \@@_mc_if_in: {p,T,F,TF}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{ \@@_mc_bmc:n,\@@_mc_emc:,\@@_mc_bdc:nn,\@@_mc_bdc:nx}
+% These are the low-level commands. There are now equal to the
+% pdfmanagement commands generic mode, but we use an indirection
+% in case luamode need something else.
+% change 04.08.2018: the commands do not check the validity of the arguments or try
+% to escape them, this should be done before using them.
+% \begin{macrocode}
+% #1 tag, #2 properties
+\cs_set_eq:NN \@@_mc_bmc:n \pdf_bmc:n
+\cs_set_eq:NN \@@_mc_emc: \pdf_emc:
+\cs_set_eq:NN \@@_mc_bdc:nn \pdf_bdc:nn
+\cs_generate_variant:Nn \@@_mc_bdc:nn {nx}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}
+% {
+% \@@_mc_bdc_mcid:nn,\@@_mc_bdc_mcid:n,
+% \@@_mc_handle_mcid:nn,\@@_mc_handle_mcid:VV
+% }
+%
+% This create a BDC mark with an |/MCID| key. Most of the work here is to get
+% the current number value for the MCID: they must be numbered by page
+% starting with 0 and then successively.
+% The first argument is the tag, e.g. |P| or |Span|, the second is used to pass
+% more properties.
+% We also define a wrapper around the low-level command as luamode will need
+% something different.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_mc_bdc_mcid:nn #1 #2
+ {
+ \int_gincr:N \c@g_@@_MCID_abs_int
+ \tl_set:Nx \l_@@_mc_ref_abspage_tl
+ {
+ \@@_ref_value:enn %3 args
+ {
+ mcid-\int_use:N \c@g_@@_MCID_abs_int
+ }
+ { tagabspage }
+ {-1}
+ }
+ \prop_get:NoNTF
+ \g_@@_MCID_byabspage_prop
+ {
+ \l_@@_mc_ref_abspage_tl
+ }
+ \l_@@_mc_tmpa_tl
+ {
+ %key already present, use value for MCID and add 1 for the next
+ \int_gset:Nn \g_@@_MCID_tmp_bypage_int { \l_@@_mc_tmpa_tl }
+ \@@_prop_gput:Nxx
+ \g_@@_MCID_byabspage_prop
+ { \l_@@_mc_ref_abspage_tl }
+ { \int_eval:n {\l_@@_mc_tmpa_tl +1} }
+ }
+ {
+ %key not present, set MCID to 0 and insert 1
+ \int_gzero:N \g_@@_MCID_tmp_bypage_int
+ \@@_prop_gput:Nxx
+ \g_@@_MCID_byabspage_prop
+ { \l_@@_mc_ref_abspage_tl }
+ {1}
+ }
+ \@@_ref_label:en
+ {
+ mcid-\int_use:N \c@g_@@_MCID_abs_int
+ }
+ { mc }
+ \@@_mc_bdc:nx
+ {#1}
+ { /MCID~\int_eval:n { \g_@@_MCID_tmp_bypage_int }~ \exp_not:n { #2 } }
+ }
+\cs_new_protected:Npn \@@_mc_bdc_mcid:n #1
+ {
+ \@@_mc_bdc_mcid:nn {#1} {}
+ }
+
+\cs_new_protected:Npn \@@_mc_handle_mcid:nn #1 #2 %#1 tag, #2 properties
+ {
+ \@@_mc_bdc_mcid:nn {#1} {#2}
+ }
+
+\cs_generate_variant:Nn \@@_mc_handle_mcid:nn {VV}
+% \end{macrocode}
+% \end{macro}
+
+% \begin{macro}{\@@_mc_handle_stash:n,\@@_mc_handle_stash:x}
+% This is the handler which puts a mc into the
+% the current structure. The argument is the number of the mc.
+% Beside storing the mc into the structure, it also has to record the
+% structure for the parent tree.
+% The name is a bit confusing, it does \emph{not} handle mc with the stash key
+% \ldots.
+% TODO: why does luamode use it for begin + use, but generic mode only for begin?
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_mc_handle_stash:n #1 %1 mcidnum
+ {
+ \@@_check_mc_used:n {#1}
+ \@@_struct_kid_mc_gput_right:nn
+ { \g_@@_struct_stack_current_tl }
+ {#1}
+ \prop_gput:Nxx \g_@@_mc_parenttree_prop
+ {#1}
+ { \g_@@_struct_stack_current_tl }
+ }
+\cs_generate_variant:Nn \@@_mc_handle_stash:n { x }
+% \end{macrocode}
+% \end{macro}
+
+% \begin{macro}
+% {
+% \@@_mc_bmc_artifact:,
+% \@@_mc_bmc_artifact:n,
+% \@@_mc_handle_artifact:N
+% }
+% Two commands to create artifacts, one without type, and one with.
+% We define also a wrapper handler as luamode will need a different definition.
+% TODO: perhaps later: more properties for artifacts
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_mc_bmc_artifact:
+ {
+ \@@_mc_bmc:n {Artifact}
+ }
+\cs_new_protected:Npn \@@_mc_bmc_artifact:n #1
+ {
+ \@@_mc_bdc:nn {Artifact}{/Type/#1}
+ }
+\cs_new_protected:Npn \@@_mc_handle_artifact:N #1
+ % #1 is a var containing the artifact type
+ {
+ \tl_if_empty:NTF #1
+ { \@@_mc_bmc_artifact: }
+ { \exp_args:NV\@@_mc_bmc_artifact:n #1 }
+ }
+% \end{macrocode}
+% \end{macro}
+
+% \begin{macro}{ \@@_get_data_mc_tag: }
+% This allows to retrieve the active mc-tag.
+% It is use by the get command.
+% \begin{macrocode}
+\cs_new:Nn \@@_get_data_mc_tag: { \g_@@_mc_key_tag_tl }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\tag_mc_begin:n,\tag_mc_end:}
+% These are the core public commands to open and close an mc.
+% They don't need to be in the same group or grouping level,
+% but the code expect that they are issued linearly. The tag and
+% the state is passed to the end command through a global var and
+% a global boolean.
+% \begin{macrocode}
+\cs_new_protected:Npn \tag_mc_begin:n #1 %#1 keyval
+ {
+ \@@_check_if_active_mc:T
+ {
+ \group_begin: %hm
+ \@@_check_mc_if_nested:
+ \bool_gset_true:N \g_@@_in_mc_bool
+ \keys_set:nn { @@ / mc } {#1}
+ \bool_if:NTF \l_@@_mc_artifact_bool
+ { %handle artifact
+ \@@_mc_handle_artifact:N \l_@@_mc_artifact_type_tl
+ }
+ { %handle mcid type
+ \@@_check_mc_tag:N \l_@@_mc_key_tag_tl
+ \@@_mc_handle_mcid:VV
+ \l_@@_mc_key_tag_tl
+ \l_@@_mc_key_properties_tl
+ \tl_if_empty:NF {\l_@@_mc_key_label_tl}
+ {
+ \exp_args:NV
+ \@@_mc_handle_mc_label:n \l_@@_mc_key_label_tl
+ }
+ \bool_if:NF \l_@@_mc_key_stash_bool
+ {
+ \@@_mc_handle_stash:x { \int_use:N \c@g_@@_MCID_abs_int }
+ }
+ }
+ \group_end:
+ }
+ }
+\cs_new_protected:Nn \tag_mc_end:
+ {
+ \@@_check_if_active_mc:T
+ {
+ \@@_check_mc_if_open:
+ \bool_gset_false:N \g_@@_in_mc_bool
+ \tl_gset:Nn \g_@@_mc_key_tag_tl { }
+ \@@_mc_emc:
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+
+%
+% \subsection{Keys}
+% Definitions are different in luamode.
+% |tag| and |raw| are expanded as |\lua_now:e| in lua does it too and
+% we assume that their values are safe.
+% \begin{macro}
+% {
+% tag,raw,
+% alttext,alttext-o,
+% actualtext,actualtext-o,
+% label,artifact
+% }
+% \begin{macrocode}
+\keys_define:nn { @@ / mc }
+ {
+ tag .code:n = % the name (H,P,Span) etc
+ {
+ \tl_set:Nx \l_@@_mc_key_tag_tl { #1 }
+ \tl_gset:Nx \g_@@_mc_key_tag_tl { #1 }
+ },
+ raw .code:n =
+ {
+ \tl_put_right:Nx \l_@@_mc_key_properties_tl { #1 }
+ },
+ alttext .code:n = % Alt property
+ {
+ \str_set_convert:Nnon
+ \l_@@_tmpa_str
+ { #1 }
+ { default }
+ { utf16/hex }
+ \tl_put_right:Nn \l_@@_mc_key_properties_tl { /Alt~< }
+ \tl_put_right:No \l_@@_mc_key_properties_tl { \l_@@_tmpa_str>~ }
+ },
+ alttext-o .code:n = % Alt property
+ {
+ \str_set_convert:Noon
+ \l_@@_tmpa_str
+ { #1 }
+ { default }
+ { utf16/hex }
+ \tl_put_right:Nn \l_@@_mc_key_properties_tl { /Alt~< }
+ \tl_put_right:No \l_@@_mc_key_properties_tl { \l_@@_tmpa_str>~ }
+ },
+ actualtext .code:n = % ActualText property
+ {
+ \str_set_convert:Nnon
+ \l_@@_tmpa_str
+ { #1 }
+ { default }
+ { utf16/hex }
+ \tl_put_right:Nn \l_@@_mc_key_properties_tl { /ActualText~< }
+ \tl_put_right:No \l_@@_mc_key_properties_tl { \l_@@_tmpa_str>~ }
+ },
+ actualtext-o .code:n = % ActualText property
+ {
+ \str_set_convert:Noon
+ \l_@@_tmpa_str
+ { #1 }
+ { default }
+ { utf16/hex }
+ \tl_put_right:Nn \l_@@_mc_key_properties_tl { /ActualText~< }
+ \tl_put_right:No \l_@@_mc_key_properties_tl { \l_@@_tmpa_str>~ }
+ },
+ label .tl_set:N = \l_@@_mc_key_label_tl,
+ artifact .code:n =
+ {
+ \exp_args:Nnx
+ \keys_set:nn
+ { @@ / mc }
+ { __artifact-bool, __artifact-type=#1 }
+ },
+ artifact .default:n = {notype}
+ }
+%</generic>
+% \end{macrocode}
+% \end{macro}
+% \end{implementation}
+% \PrintIndex
diff --git a/Master/texmf-dist/source/latex/tagpdf/tagpdf-mc-luacode.dtx b/Master/texmf-dist/source/latex/tagpdf/tagpdf-mc-luacode.dtx
new file mode 100644
index 00000000000..aae817c9eb9
--- /dev/null
+++ b/Master/texmf-dist/source/latex/tagpdf/tagpdf-mc-luacode.dtx
@@ -0,0 +1,490 @@
+% \iffalse meta-comment
+%
+%% File: tagpdf-mc.dtx
+%
+% Copyright (C) 2019-2021 Ulrike Fischer
+%
+% It may be distributed and/or modified under the conditions of the
+% LaTeX Project Public License (LPPL), either version 1.3c of this
+% license or (at your option) any later version. The latest version
+% of this license is in the file
+%
+% https://www.latex-project.org/lppl.txt
+%
+% This file is part of the "tagpdf bundle" (The Work in LPPL)
+% and all files in that bundle must be distributed together.
+%
+% -----------------------------------------------------------------------
+%
+% The development version of the bundle can be found at
+%
+% https://github.com/u-fischer/tagpdf
+%
+% for those people who are interested.
+%<*driver>
+\RequirePackage{pdfmanagement-testphase}
+\DeclareDocumentMetadata{}
+\makeatletter
+\declare@file@substitution{doc.sty}{doc-v3beta.sty}
+\makeatother
+\documentclass{l3doc}
+\usepackage{array,booktabs,caption}
+\hypersetup{pdfauthor=Ulrike Fischer,
+ pdftitle=tagpdf-mc module (tagpdf)}
+\begin{document}
+ \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
+% \fi
+% \title{^^A
+% The \pkg{tagpdf-mc-luacode} module\\ Code related to Marked Content (mc-chunks), luamode-specific ^^A
+% \\ Part of the tagpdf package
+% }
+%
+% \author{^^A
+% Ulrike Fischer\thanks
+% {^^A
+% E-mail:
+% \href{mailto:fischer@troubleshooting-tex.de}
+% {fischer@troubleshooting-tex.de}^^A
+% }^^A
+% }
+%
+% \date{Version 0.9, released 2021-06-29}
+% \maketitle
+
+% \begin{implementation}
+% The code is splitted into three parts: code shared by all engines,
+% code specific to luamode and code not used by luamode.
+%
+% \section{Marked content code -- luamode code}
+% luamode uses attributes to mark mc-chunks. The two attributes used are
+% defined in the backend file. The backend also load the lua file, as it can contain
+% functions needed elsewhere.
+% The attributes for mc are global (between 0.6 and 0.81 they were local but this
+% was reverted). The attributes are setup only in lua, and one should use
+% the lua functions to set and get them.\\
+% |g_@@_mc_type_attr|: the value represent the type\\
+% |g_@@_mc_cnt_attr|: will hold the |\c@g_@@_MCID_abs_int value|
+%
+% Handling attribute needs a different system to number the page wise mcid's:
+% a |\tagmcbegin ... \tagmcend| pair no longer surrounds exactly one mc chunk:
+% it can be split at page breaks.
+% We know the included mcid(s) only after the ship out.
+% So for the |struct -> mcid| mapping we
+% need to record |struct -> mc-cnt| (in |\g_@@_mc_parenttree_prop| and/or a lua table
+% and at shipout |mc-cnt-> {mcid, mcid, ...}|
+% and when building the trees connect both.
+%
+% Key definitions are overwritten for luatex to store that data in lua-tables.
+% The data for the mc are in |ltx.@@.mc[absnum]|.
+% The fields of the table are:\\
+% tag : the type (a string)\\
+% raw : more properties (string)\\
+% label: a string. \\
+% artifact: the presence indicates an artifact, the value (string) is the type.\\
+% kids: a array of tables\\
+% |{1={kid=num2,page=pagenum1}, 2={kid=num2,page=pagenum2},...}|,\\
+% this describes the chunks the mc has been split to by the traversing code\\
+% parent: the number of the structure it is in. Needed to build the parent tree.
+%
+% \begin{macrocode}
+%<@@=tag>
+%<*luamode>
+\ProvidesExplPackage {tagpdf-mc-code-lua} {2021-06-29} {0.9}
+ {tagpdf - mc code only for the luamode }
+%</luamode>
+% \end{macrocode}
+% The main function which wanders through the shipout box to inject the literals.
+% if the new callback is there, it is used.
+% \begin{macrocode}
+%<*luamode>
+\hook_gput_code:nnn{begindocument}{tagpdf/mc}
+ {
+ \bool_if:NT\g__tag_active_space_bool
+ {
+ \lua_now:e
+ {
+ if~luatexbase.callbacktypes.pre_shipout_filter~then~
+ luatexbase.add_to_callback("pre_shipout_filter", function(TAGBOX)~
+ ltx.@@.func.space_chars_shipout(TAGBOX)~return~true~
+ end, "tagpdf")~
+ end
+ }
+ \lua_now:e
+ {
+ if~luatexbase.callbacktypes.pre_shipout_filter~then~
+ token.get_next()~
+ end
+ }\@secondoftwo\@gobble
+ {
+ \hook_gput_code:nnn{shipout/before}{tagpdf/lua}
+ {
+ \lua_now:e
+ { ltx.@@.func.space_chars_shipout (tex.box["ShipoutBox"]) }
+ }
+ }
+ }
+ \bool_if:NT\g__tag_active_mc_bool
+ {
+ \lua_now:e
+ {
+ if~luatexbase.callbacktypes.pre_shipout_filter~then~
+ luatexbase.add_to_callback("pre_shipout_filter", function(TAGBOX)~
+ ltx.@@.func.mark_shipout(TAGBOX)~return~true~
+ end, "tagpdf")~
+ end
+ }
+ \lua_now:e
+ {
+ if~luatexbase.callbacktypes.pre_shipout_filter~then~
+ token.get_next()~
+ end
+ }\@secondoftwo\@gobble
+ {
+ \hook_gput_code:nnn{shipout/before}{tagpdf/lua}
+ {
+ \lua_now:e
+ { ltx.@@.func.mark_shipout (tex.box["ShipoutBox"]) }
+ }
+ }
+ }
+ }
+% \end{macrocode}
+% \subsection{Commands}
+% \begin{macro}{\@@_mc_if_in:,\tag_mc_if_in:}
+% This tests, if we are in an mc, for attributes
+% this means to check against a number.
+% \begin{macrocode}
+\prg_new_conditional:Nnn \@@_mc_if_in: {p,T,F,TF}
+ {
+ \int_compare:nNnTF
+ { -2147483647 }
+ =
+ {\lua_now:e
+ {
+ tex.print(tex.getattribute(luatexbase.attributes.g__tag_mc_type_attr))
+ }
+ }
+ { \prg_return_false: }
+ { \prg_return_true: }
+ }
+
+\prg_new_eq_conditional:NNn \tag_mc_if_in: \@@_mc_if_in: {p,T,F,TF}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}
+% {
+% \@@_mc_lua_set_mc_type_attr:n
+% ,\@@_mc_lua_set_mc_type_attr:o
+% ,\@@_mc_lua_unset_mc_type_attr:
+% }
+% This takes a tag name, and sets the attributes to the related number.
+% It is not decided yet if this will be global or local, see the global-mc option.
+% \begin{macrocode}
+\cs_new:Nn \@@_mc_lua_set_mc_type_attr:n % #1 is a tag name
+ {
+ %TODO ltx.@@.func.get_num_from("#1") seems not to return a suitable number??
+ \tl_set:Nx\l_@@_tmpa_tl{\lua_now:e{ltx.@@.func.output_num_from ("#1")} }
+ \lua_now:e
+ {
+ tex.setattribute
+ (
+ "global",
+ luatexbase.attributes.g_@@_mc_type_attr,
+ \l_@@_tmpa_tl
+ )
+ }
+ \lua_now:e
+ {
+ tex.setattribute
+ (
+ "global",
+ luatexbase.attributes.g_@@_mc_cnt_attr,
+ \@@_get_mc_abs_cnt:
+ )
+ }
+ }
+
+\cs_generate_variant:Nn\@@_mc_lua_set_mc_type_attr:n { o }
+
+\cs_new:Nn \@@_mc_lua_unset_mc_type_attr:
+ {
+ \lua_now:e
+ {
+ tex.setattribute
+ (
+ "global",
+ luatexbase.attributes.g_@@_mc_type_attr,
+ -2147483647
+ )
+ }
+ \lua_now:e
+ {
+ tex.setattribute
+ (
+ "global",
+ luatexbase.attributes.g_@@_mc_cnt_attr,
+ -2147483647
+ )
+ }
+ }
+
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}
+% {
+% \@@_mc_insert_mcid_kids:n
+% ,\@@_mc_insert_mcid_single_kids:n
+% }
+% These commands will in the finish code replace the dummy for a mc by the real mcid kids
+% we need a variant for the case that it is the only kid, to get the array right
+% \begin{macrocode}
+\cs_new:Nn \@@_mc_insert_mcid_kids:n
+ {
+ \lua_now:e { ltx.@@.func.mc_insert_kids (#1,0) }
+ }
+
+\cs_new:Nn \@@_mc_insert_mcid_single_kids:n
+ {
+ \lua_now:e {ltx.@@.func.mc_insert_kids (#1,1) }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%\begin{macro}{\@@_mc_handle_stash:n,\@@_mc_handle_stash:x}
+% This is the lua variant for the command to
+% put an mcid absolute number in the current structure.
+% \begin{macrocode}
+\cs_new:Nn \@@_mc_handle_stash:n %1 mcidnum
+ {
+ \@@_check_mc_used:n { #1 }
+ \seq_gput_right:cn % Don't fill a lua table due to the command in the item,
+ % so use the kernel command
+ { g_@@_struct_kids_\g_@@_struct_stack_current_tl _seq }
+ {
+ \@@_mc_insert_mcid_kids:n {#1}%
+ }
+ \lua_now:e
+ {
+ ltx.@@.func.store_struct_mcabs
+ (
+ \g_@@_struct_stack_current_tl,#1
+ )
+ }
+ \prop_gput:Nxx
+ \g_@@_mc_parenttree_prop
+ { #1 }
+ { \g_@@_struct_stack_current_tl }
+ }
+
+\cs_generate_variant:Nn \@@_mc_handle_stash:n { x }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\tag_mc_begin:n}
+% This is the lua version of the user command.
+% We currently don't check if there is nesting as it doesn't matter so
+% much in lua.
+% \begin{macrocode}
+\cs_new_protected:Nn \tag_mc_begin:n
+ {
+ \@@_check_if_active_mc:T
+ {
+ \group_begin:
+ %\@@_check_mc_if_nested:
+ \bool_gset_true:N \g_@@_in_mc_bool
+ \bool_set_false:N\l_@@_mc_artifact_bool
+ \tl_clear:N \l_@@_mc_key_properties_tl
+ \int_gincr:N \c@g_@@_MCID_abs_int
+ \keys_set:nn { @@ / mc }{ label={}, #1 }
+ %check that a tag or artifact has been used
+ \@@_check_mc_tag:N \l_@@_mc_key_tag_tl
+ %set the attributes:
+ \@@_mc_lua_set_mc_type_attr:o { \l_@@_mc_key_tag_tl }
+ \bool_if:NF \l_@@_mc_artifact_bool
+ { % store the absolute num name in a label:
+ \tl_if_empty:NF {\l_@@_mc_key_label_tl}
+ {
+ \exp_args:NV
+ \@@_mc_handle_mc_label:n \l_@@_mc_key_label_tl
+ }
+ % if not stashed record the absolute number
+ \bool_if:NF \l_@@_mc_key_stash_bool
+ {
+ \@@_mc_handle_stash:x { \@@_get_mc_abs_cnt: }
+ }
+ }
+ \group_end:
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\tag_mc_end:}
+%
+% TODO: check how the use command must be guarded.
+% \begin{macrocode}
+\cs_new_protected:Nn \tag_mc_end:
+ {
+ \@@_check_if_active_mc:T
+ {
+ %\@@_check_mc_if_open:
+ \bool_gset_false:N \g_@@_in_mc_bool
+ \bool_set_false:N\l_@@_mc_artifact_bool
+ \@@_mc_lua_unset_mc_type_attr:
+ \tl_set:Nn \l_@@_mc_key_tag_tl { }
+ \tl_gset:Nn \g_@@_mc_key_tag_tl { }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{ \@@_get_data_mc_tag: }
+% The command to retrieve the current mc tag.
+% TODO: Perhaps this should use the attribute instead.
+% \begin{macrocode}
+\cs_new:Npn \@@_get_data_mc_tag: { \g_@@_mc_key_tag_tl }
+% \end{macrocode}
+% \end{macro}
+
+% \subsection{Key definitions}
+% \begin{macro}
+% {
+% tag,raw,
+% alttext,alttext-o,
+% actualtext,actualtext-o,
+% label,artifact
+% }
+% TODO: check conversion, check if local/global setting is right.
+% \begin{macrocode}
+\keys_define:nn { @@ / mc }
+ {
+ tag .code:n = %
+ {
+ \tl_set:Nx \l_@@_mc_key_tag_tl { #1 }
+ \tl_gset:Nx \g_@@_mc_key_tag_tl { #1 }
+ \lua_now:e
+ {
+ ltx.@@.func.store_mc_data(\@@_get_mc_abs_cnt:,"tag","#1")
+ }
+ },
+ raw .code:n =
+ {
+ \tl_put_right:Nx \l_@@_mc_key_properties_tl { #1 }
+ \lua_now:e
+ {
+ ltx.@@.func.store_mc_data(\@@_get_mc_abs_cnt:,"raw","#1")
+ }
+ },
+ alttext .code:n = % Alt property
+ {
+ \str_set_convert:Nnon
+ \l_@@_tmpa_str
+ { #1 }
+ { default }
+ { utf16/hex }
+ \tl_put_right:Nn \l_@@_mc_key_properties_tl { /Alt~< }
+ \tl_put_right:No \l_@@_mc_key_properties_tl { \l_@@_tmpa_str>~ }
+ \lua_now:e
+ {
+ ltx.@@.func.store_mc_data
+ (
+ \@@_get_mc_abs_cnt:,"alt","/Alt~<\str_use:N \l_@@_tmpa_str>"
+ )
+ }
+ },
+ alttext-o .code:n = % Alt property
+ {
+ \str_set_convert:Noon
+ \l_@@_tmpa_str
+ { #1 }
+ { default }
+ { utf16/hex }
+ \tl_put_right:Nn \l_@@_mc_key_properties_tl { /Alt~< }
+ \tl_put_right:No \l_@@_mc_key_properties_tl { \l_@@_tmpa_str>~ }
+ \lua_now:e
+ {
+ ltx.@@.func.store_mc_data
+ (
+ \@@_get_mc_abs_cnt:,"alt","/Alt~<\str_use:N \l_@@_tmpa_str>"
+ )
+ }
+ },
+ actualtext .code:n = % Alt property
+ {
+ \str_set_convert:Nnon
+ \l_@@_tmpa_str
+ { #1 }
+ { default }
+ { utf16/hex }
+ \tl_put_right:Nn \l_@@_mc_key_properties_tl { /Alt~< }
+ \tl_put_right:No \l_@@_mc_key_properties_tl { \l_@@_tmpa_str>~ }
+ \lua_now:e
+ {
+ ltx.@@.func.store_mc_data
+ (
+ \@@_get_mc_abs_cnt:,"actualtext","/ActualText~<\str_use:N \l_@@_tmpa_str>"
+ )
+ }
+ },
+ actualtext-o .code:n = % Alt property
+ {
+ \str_set_convert:Noon
+ \l_@@_tmpa_str
+ { #1 }
+ { default }
+ { utf16/hex }
+ \tl_put_right:Nn \l_@@_mc_key_properties_tl { /Alt~< }
+ \tl_put_right:No \l_@@_mc_key_properties_tl { \l_@@_tmpa_str>~ }
+ \lua_now:e
+ {
+ ltx.@@.func.store_mc_data
+ (
+ \@@_get_mc_abs_cnt:,
+ "actualtext",
+ "/ActualText~<\str_use:N \l_@@_tmpa_str>"
+ )
+ }
+ },
+ label .code:n =
+ {
+ \tl_set:Nn\l_@@_mc_key_label_tl { #1 }
+ \lua_now:e
+ {
+ ltx.@@.func.store_mc_data
+ (
+ \@@_get_mc_abs_cnt:,"label","#1"
+ )
+ }
+ },
+ __artifact-store .code:n =
+ {
+ \lua_now:e
+ {
+ ltx.@@.func.store_mc_data
+ (
+ \@@_get_mc_abs_cnt:,"artifact","#1"
+ )
+ }
+ },
+ artifact .code:n =
+ {
+ \exp_args:Nnx
+ \keys_set:nn
+ { @@ / mc}
+ { __artifact-bool, __artifact-type=#1, tag=Artifact }
+ \exp_args:Nnx
+ \keys_set:nn
+ { @@ / mc }
+ { __artifact-store=\l_@@_mc_artifact_type_tl }
+ },
+ artifact .default:n = { notype }
+ }
+
+%</luamode>
+% \end{macrocode}
+% \end{macro}
+%
+% \end{implementation}
+% \PrintIndex
diff --git a/Master/texmf-dist/source/latex/tagpdf/tagpdf-mc-shared.dtx b/Master/texmf-dist/source/latex/tagpdf/tagpdf-mc-shared.dtx
new file mode 100644
index 00000000000..12680109a05
--- /dev/null
+++ b/Master/texmf-dist/source/latex/tagpdf/tagpdf-mc-shared.dtx
@@ -0,0 +1,442 @@
+% \iffalse meta-comment
+%
+%% File: tagpdf-mc.dtx
+%
+% Copyright (C) 2019-2021 Ulrike Fischer
+%
+% It may be distributed and/or modified under the conditions of the
+% LaTeX Project Public License (LPPL), either version 1.3c of this
+% license or (at your option) any later version. The latest version
+% of this license is in the file
+%
+% https://www.latex-project.org/lppl.txt
+%
+% This file is part of the "tagpdf bundle" (The Work in LPPL)
+% and all files in that bundle must be distributed together.
+%
+% -----------------------------------------------------------------------
+%
+% The development version of the bundle can be found at
+%
+% https://github.com/u-fischer/tagpdf
+%
+% for those people who are interested.
+%<*driver>
+\RequirePackage{pdfmanagement-testphase}
+\DeclareDocumentMetadata{}
+\makeatletter
+\declare@file@substitution{doc.sty}{doc-v3beta.sty}
+\makeatother
+\documentclass{l3doc}
+\usepackage{array,booktabs,caption}
+\hypersetup{pdfauthor=Ulrike Fischer,
+ pdftitle=tagpdf-mc module (tagpdf)}
+\begin{document}
+ \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
+% \fi
+% \title{^^A
+% The \pkg{tagpdf-mc-shared} module\\ Code related to Marked Content (mc-chunks), code shared by all modes ^^A
+% \\ Part of the tagpdf package
+% }
+%
+% \author{^^A
+% Ulrike Fischer\thanks
+% {^^A
+% E-mail:
+% \href{mailto:fischer@troubleshooting-tex.de}
+% {fischer@troubleshooting-tex.de}^^A
+% }^^A
+% }
+%
+% \date{Version 0.9, released 2021-06-29}
+% \maketitle
+% \begin{documentation}
+% \section{Public Commands}
+% \begin{function}{\tag_mc_begin:n,\tag_mc_end:}
+% \begin{syntax}
+% \cs{tag_mc_begin:n}\Arg{key-values}\\
+% \cs{tag_mc_end:}
+% \end{syntax}
+% These commands insert the end code of the marked content.
+% They don't end a group and in generic mode it doesn't matter
+% if they are in another group as the starting commands.
+% In generic mode both commands check if they are correctly nested
+% and issue a warning if not.
+% \end{function}
+%
+% \begin{function}{\tag_mc_use:n}
+% \begin{syntax}
+% \cs{tag_mc_use:n}\Arg{label}
+% \end{syntax}
+% These command allow to record a marked content that was stashed away before
+% into the current structure. A marked content can be used only once --
+% the command will issue a warning if an mc is use a second time.
+% \end{function}
+%
+% \begin{function}[added = 2019-11-20]
+% {
+% \tag_mc_artifact_group_begin:n, \tag_mc_artifact_group_end:
+% }
+% \begin{syntax}
+% \cs{tag_mc_artifact_group_begin:n} \Arg{name}\\
+% \cs{tag_mc_artifact_group_end:}
+% \end{syntax}
+% This command pair creates a group with an artifact marker at the begin
+% and the end. Inside the group the tagging commands are disabled.
+% It allows to mark a complete region as artifact without having to worry
+% about user commands with tagging commands.
+% \meta{name} should be a value allowed also for the |artifact| key.
+% It pushes and pops mc-chunks at the begin and end.
+% TODO: document is in tagpdf.tex
+% \end{function}
+%
+% \begin{function}[added = 2021-04-22]
+% {
+% \tag_mc_end_push:, \tag_mc_begin_pop:n
+% }
+% \begin{syntax}
+% \cs{tag_mc_end_push:} \\
+% \cs{tag_mc_begin_pop:n}\Arg{key-values}
+% \end{syntax}
+% If there is an open mc chunk,
+% \cs{tag_mc_end_push:} ends it and pushes its tag of the (global) stack.
+% If there is no open chunk, it puts $-1$ on the stack (for debugging)
+% \cs{tag_mc_begin_pop:n} removes a value from the stack. If it is different from
+% $-1$ it opens a tag with it.
+% The reopened mc chunk looses info like the alttext for now.
+% \end{function}
+%
+% \begin{function}[pTF, EXP]{\tag_mc_if_in:}
+% \begin{syntax}
+% \cs{tag_mc_if_in:TF} \Arg{true code} \Arg{false code}
+% \end{syntax}
+% Determines if a mc-chunk is open.
+% \end{function}
+
+%
+% \section{Public keys}
+% The following keys can be used with |\tag_mc_begin:n|, |\tagmcbegin|,
+% |\tag_mc_begin_pop:n|,
+%
+% \begin{function}{tag}
+% This key is required, unless artifact is used.
+% The value is a tag like |P| or |H1| without a slash at the begin,
+% this is added by the code.
+% It is possible to setup new tags.
+% The value of the key is expanded, so it can be a command.
+% The expansion is passed unchanged to the PDF,
+% so it should with a starting slash give a valid PDF name
+% (some ascii with numbers like \texttt{H4} is fine).
+% \end{function}
+%
+% \begin{function}{artifact}
+% This will setup the marked content as an artifact. The key should be used
+% for content that should be ignored.
+% The key can take one of the values |pagination|,
+% |layout|, |page|, |background| and |notype|
+% (this is the default).
+% \end{function}
+%
+% \begin{function}{raw}
+% This key allows to add more entries to the properties dictionary.
+% The value must be correct, low-level PDF. E.g.
+% \verb+raw=/Alt (Hello)+ will insert an alternative Text.
+% \end{function}
+%
+% \begin{function}{alttext,alttext-o}
+% This key inserts an \texttt{/Alt} value in the property dictionary of the BDC operator.
+% The value is handled as verbatim string, commands are not expanded. With |alttext-o|
+% the value is expanded once.
+% \end{function}
+%
+% \begin{function}{actualtext,actualtext-o}
+% This key inserts an \texttt{/ActualText} value in the property dictionary
+% of the BDC operator. The value is handled as verbatim string,
+% commands are not expanded.With |actualtext-o|
+% the value is expanded once.
+% \end{function}
+%
+% \begin{function}{label}
+% This key sets a label by which one can call the marked content
+% later in another structure
+% (if it has been stashed with the |stash| key).
+% Internally the label name will start with \texttt{tagpdf-}.
+% \end{function}
+%
+% \begin{function}{stash}
+% This \enquote{stashes} an mc-chunk: it is not inserted into the current structure.
+% It should be normally be used along with a label to be able to use the mc-chunk
+% in another place.
+% \end{function}
+% \end{documentation}
+% \begin{implementation}
+% The code is splitted into three parts: code shared by all engines,
+% code specific to luamode and code not used by luamode.
+% \section{Marked content code -- shared}
+% \begin{macrocode}
+%<@@=tag>
+%<*header>
+\ProvidesExplPackage {tagpdf-mc-code-shared} {2021-06-29} {0.9}
+ {part of tagpdf - code related to marking chunks -
+ code shared by generic and luamode }
+%</header>
+% \end{macrocode}
+%
+% \subsection{Variables and counters}
+% MC chunks must be counted.
+% I use a latex counter for the absolute count, so that it is added to
+% |\cl@@ckpt| and restored e.g. in tabulars and align.
+% |\int_new:N \c@g_@@_MCID_int| and
+% |\tl_put_right:Nn\cl@@ckpt{\@elt{g_uf_test_int}}|
+% would work too, but as the name is not expl3 then too, why bother?
+% The absolute counter can be used to label and to check if the page
+% counter needs a reset.
+%
+% \begin{variable}{g_@@_MCID_abs_int}
+% \begin{macrocode}
+%<*shared>
+\newcounter { g_@@_MCID_abs_int }
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}{\_@@_get_mc_abs_cnt:}
+% A (expandable) function to get the current value of the cnt.
+% \begin{macrocode}
+\cs_new:Npn \_@@_get_mc_abs_cnt: { \int_use:N \c@g_@@_MCID_abs_int }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{variable}{\g_@@_MCID_tmp_bypage_int}
+% The following hold the temporary by page number assigned to a mc.
+% It must be defined in the shared code to avoid problems with labels.
+% \begin{macrocode}
+\int_new:N \g_@@_MCID_tmp_bypage_int
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\g_@@_mc_parenttree_prop}
+% For every chunk we need to know the structure it is in, to
+% record this in the parent tree. We store this in a property.\\
+% key: absolute number of the mc (tagmcabs)\\
+% value: the structure number the mc is in
+% \begin{macrocode}
+\@@_prop_new:N \g_@@_mc_parenttree_prop
+% \end{macrocode}
+% \end{variable}
+%
+%\begin{variable}{\g_@@_mc_parenttree_prop}
+% Some commands (e.g. links) want to close a previous mc and reopen it after
+% they did their work. For this we create a stack:
+% \begin{macrocode}
+\seq_new:N \g_@@_mc_stack_seq
+% \end{macrocode}
+% \end{variable}
+%
+%\begin{variable}{\l_@@_mc_artifact_type_tl}
+% Artifacts can have various types like Pagination or Layout. This stored
+% in this variable.
+% \begin{macrocode}
+\tl_new:N \l_@@_mc_artifact_type_tl
+% \end{macrocode}
+% \end{variable}
+%
+%\begin{variable}{\l_@@_mc_key_stash_bool,\l_@@_mc_artifact_bool}
+%This booleans store the stash and artifact status of the mc-chunk.
+% \begin{macrocode}
+\bool_new:N \l_@@_mc_key_stash_bool
+\bool_new:N \l_@@_mc_artifact_bool
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}
+% {
+% \l_@@_mc_key_tag_tl,
+% \g_@@_mc_key_tag_tl,
+% \l_@@_mc_key_label_tl,
+% \l_@@_mc_key_properties_tl
+% }
+% Variables used by the keys. |\l_@@_mc_key_properties_tl|
+% will collect a number of values. TODO: should this be a pdfdict now?
+% \begin{macrocode}
+\tl_new:N \l_@@_mc_key_tag_tl
+\tl_new:N \g_@@_mc_key_tag_tl
+\tl_new:N \l_@@_mc_key_label_tl
+\tl_new:N \l_@@_mc_key_properties_tl
+% \end{macrocode}
+% \end{variable}
+%
+% \subsection{Functions}
+% \begin{macro}{\_@@_mc_handle_mc_label:n}
+% The commands labels a mc-chunk. It is used if the user explicitly
+% labels the mc-chunk with the |label| key. The argument is the
+% value provided by the user. It stores the attributes\\
+% |tagabspage|: the absolute page, |\g_shipout_readonly_int|,\\
+% |tagmcabs|: the absolute mc-counter |\c@g_@@_MCID_abs_int|,\\
+% |tagmcid|: the ID of the chunk on the page |\g_@@_MCID_tmp_bypage_int|, this
+% typically settles down after a second compilation.
+% The reference command is defined in tagpdf.dtx and is based on l3ref.
+% \begin{macrocode}
+\cs_new:Nn \_@@_mc_handle_mc_label:n
+ {
+ \@@_ref_label:en{tagpdf-#1}{mc}
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_mc_set_label_used:n}
+% Unlike with structures we can't check if a labeled mc has been used by
+% looking at the P key, so we use a dedicated csname for the test
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_mc_set_label_used:n #1 %#1 labelname
+ {
+ \tl_new:c { g_@@_mc_label_\tl_to_str:n{#1}_used_tl }
+ }
+% \end{macrocode}
+%
+% \end{macro}
+% \begin{macro}{\tag_mc_use:n}
+% These command allow to record a marked content that was stashed away before
+% into the current structure. A marked content can be used only once --
+% the command will issue a warning if an mc is use a second time.
+% The argument is a label name set with the |label| key.
+%
+% TODO: is testing for struct the right test?
+% \begin{macrocode}
+\cs_new_protected:Npn \tag_mc_use:n #1 %#1: label name
+ {
+ \@@_check_if_active_struct:T
+ {
+ \tl_set:Nx \l_@@_tmpa_tl { \@@_ref_value:nnn{tagpdf-#1}{tagmcabs}{} }
+ \tl_if_empty:NTF\l_@@_tmpa_tl
+ {
+ \msg_warning:nnn {tag} {mc-label-unknown} {#1}
+ }
+ {
+ \cs_if_free:cTF { g_@@_mc_label_\tl_to_str:n{#1}_used_tl }
+ {
+ \@@_mc_handle_stash:x { \l_@@_tmpa_tl }
+ \@@_mc_set_label_used:n {#1}
+ }
+ {
+ \msg_warning:nnn {tag}{mc-used-twice}{#1}
+ }
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}
+% {
+% \tag_mc_artifact_group_begin:n,
+% \tag_mc_artifact_group_end:
+% }
+% This opens an artifact of the type given in the argument,
+% and then stops all tagging. It creates a group.
+% It pushes and pops mc-chunks at the begin and end.
+% \begin{macrocode}
+\cs_new_protected:Npn \tag_mc_artifact_group_begin:n #1
+ {
+ \tag_mc_end_push:
+ \tag_mc_begin:n {artifact=#1}
+ \tag_stop_group_begin:
+ }
+
+\cs_new_protected:Npn \tag_mc_artifact_group_end:
+ {
+ \tag_stop_group_end:
+ \tag_mc_end:
+ \tag_mc_begin_pop:n{}
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\tag_mc_end_push:, \tag_mc_begin_pop:n}
+%
+% \begin{macrocode}
+\cs_new_protected:Npn \tag_mc_end_push:
+ {
+ \@@_check_if_active_mc:T
+ {
+ \@@_mc_if_in:TF
+ {
+ \seq_gpush:Nx \g_@@_mc_stack_seq { \tag_get:n {mc_tag} }
+ \@@_check_mc_pushed_popped:nn
+ { pushed }
+ { \tag_get:n {mc_tag} }
+ \tag_mc_end:
+ }
+ {
+ \seq_gpush:Nn \g_@@_mc_stack_seq {-1}
+ \@@_check_mc_pushed_popped:nn { pushed }{-1}
+ }
+ }
+ }
+
+\cs_new_protected:Npn \tag_mc_begin_pop:n #1
+ {
+ \@@_check_if_active_mc:T
+ {
+ \seq_gpop:NNTF \g_@@_mc_stack_seq \l_@@_tmpa_tl
+ {
+ \tl_if_eq:NnTF \l_@@_tmpa_tl {-1}
+ {
+ \@@_check_mc_pushed_popped:nn {popped}{-1}
+ }
+ {
+ \@@_check_mc_pushed_popped:nn {popped}{\l_@@_tmpa_tl}
+ \tag_mc_begin:n {tag=\l_@@_tmpa_tl,#1}
+ }
+ }
+ {
+ \@@_check_mc_pushed_popped:nn {popped}{empty~stack,~nothing}
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Keys}
+% This are the keys where the code can be shared between the modes.
+%
+% \begin{macro}{stash,__artifact-bool,__artifact-type}
+% the two internal artifact keys are use to define the public |artifact|.
+% \begin{macrocode}
+\keys_define:nn { @@ / mc }
+ {
+ stash .bool_set:N = \l_@@_mc_key_stash_bool,
+ __artifact-bool .bool_set:N = \l_@@_mc_artifact_bool,
+ __artifact-type .choice:,
+ __artifact-type / pagination .code:n =
+ {
+ \tl_set:Nn \l_@@_mc_artifact_type_tl { Pagination }
+ },
+ __artifact-type / layout .code:n =
+ {
+ \tl_set:Nn \l_@@_mc_artifact_type_tl { Layout }
+ },
+ __artifact-type / page .code:n =
+ {
+ \tl_set:Nn \l_@@_mc_artifact_type_tl { Page }
+ },
+ __artifact-type / background .code:n =
+ {
+ \tl_set:Nn \l_@@_mc_artifact_type_tl { Background }
+ },
+ __artifact-type / notype .code:n =
+ {
+ \tl_set:Nn \l_@@_mc_artifact_type_tl {}
+ },
+ __artifact-type / .code:n =
+ {
+ \tl_set:Nn \l_@@_mc_artifact_type_tl {}
+ },
+ }
+% \end{macrocode}
+% \end{macro}
+% \begin{macrocode}
+%</shared>
+% \end{macrocode}
+% \end{implementation}
+% \PrintIndex
diff --git a/Master/texmf-dist/source/latex/tagpdf/tagpdf-mc.dtx b/Master/texmf-dist/source/latex/tagpdf/tagpdf-mc.dtx
deleted file mode 100644
index 4842c8b9931..00000000000
--- a/Master/texmf-dist/source/latex/tagpdf/tagpdf-mc.dtx
+++ /dev/null
@@ -1,818 +0,0 @@
-% \iffalse meta-comment
-%
-%% File: tagpdf-mc.dtx
-%
-% Copyright (C) 2019-2020 Ulrike Fischer
-%
-% It may be distributed and/or modified under the conditions of the
-% LaTeX Project Public License (LPPL), either version 1.3c of this
-% license or (at your option) any later version. The latest version
-% of this license is in the file
-%
-% https://www.latex-project.org/lppl.txt
-%
-% This file is part of the "tagpdf bundle" (The Work in LPPL)
-% and all files in that bundle must be distributed together.
-%
-% -----------------------------------------------------------------------
-%
-% The development version of the bundle can be found at
-%
-% https://github.com/u-fischer/tagpdf
-%
-% for those people who are interested.
-%
-% \fi
-%
-% \begin{macrocode}
-%<@@=tag>
-%<*shared>
-\ProvidesExplPackage {tagpdf-mc-code-shared} {2021-06-14} {0.82}
- {part of tagpdf - code related to marking chunks -
- code shared by generic and luamode }
-% I use a latex counter for the absolute count, so that it is added to
-% \cl@@ckpt and restored e.g. in tabulars and align
-% \int_new:N \c@g_@@_MCID_int and
-% \tl_put_right:Nn\cl@@ckpt{\@elt{g_uf_test_int}}
-% would work too, but as the name is not expl3 then too, why bother?
-% the absolute counter can be used to label and to check if the page
-% counter needs a reset.
-
-\newcounter { g_@@_MCID_abs_int }
-\cs_new:Nn \_@@_get_mc_abs_cnt: { \int_use:N \c@g_@@_MCID_abs_int }
-
-% tagmcabs is the label name of the absolute count which is used
-% to identify the chunk
-% the ref code is now in tagpdf.dtx
-
-%stores labels of mcid.
-\cs_new:Nn \_@@_mc_handle_mc_label:n
- {
- \@@_ref_label:en{tagpdf-#1}{mc}
- }
-
-% will hold the structure numbers for the parenttree
-% key: absolute number of the mc (tagmcabs)
-% value: the structure number the mc is in
-\_@@_prop_new:N \g_@@_mc_parenttree_prop
-
-% some commands (e.g. links) want to close a previous mc and reopen it after
-% there work. For this we create a stack:
-\seq_new:N \g_@@_mc_stack_seq
-% shared keys
-% the rest are in the splitted code
-\tl_new:N \l_@@_mc_artifact_type_tl
-
-\keys_define:nn { @@ / mc }
- {
- stash .bool_set:N = \l_@@_mc_key_stash_bool,
- artifact-bool .bool_set:N = \l_@@_mc_artifact_bool,
- artifact-type .choice:,
- artifact-type / pagination .code:n =
- {
- \tl_set:Nn \l_@@_mc_artifact_type_tl { Pagination }
- },
- artifact-type / layout .code:n =
- {
- \tl_set:Nn \l_@@_mc_artifact_type_tl { Layout }
- },
- artifact-type / page .code:n =
- {
- \tl_set:Nn \l_@@_mc_artifact_type_tl { Page }
- },
- artifact-type / background .code:n =
- {
- \tl_set:Nn \l_@@_mc_artifact_type_tl { Background }
- },
- artifact-type / notype .code:n =
- {
- \tl_set:Nn \l_@@_mc_artifact_type_tl {}
- },
- artifact-type / .code:n =
- {
- \tl_set:Nn \l_@@_mc_artifact_type_tl {}
- },
- }
-% \end{macrocode}
-% \begin{function}[added = 2019-11-20]
-% {
-% \tag_mc_artifact_group_begin:n, \tag_mc_artifact_group_end:
-% }
-% \begin{syntax}
-% \cs{tag_mc_artifact_group_begin:n} \Arg{name}
-% \end{syntax}
-% This command pair create a group with an artifact marker at the begin
-% and the end. Inside the group the tagging commands are disabled.
-% \end{function}
-% \begin{macrocode}
-
-
-\cs_new_protected:Npn \tag_mc_artifact_group_begin:n #1
- {
- \tag_mc_begin:n {artifact=#1}
- \tag_stop_group_begin:
- }
-
-\cs_new_protected:Npn \tag_mc_artifact_group_end:
- {
- \tag_stop_group_end:
- \tag_mc_end:
- }
-
-% we need to define it for both modes to avoid a problem with the label
-\int_new:N \g_@@_MCID_tmp_bypage_int
-
-% \end{macrocode}
-
-% \begin{function}[added = 2021-04-22]
-% {
-% \tag_mc_end_push:, \tag_mc_begin_pop:n
-% }
-% \begin{syntax}
-% \cs{tag_mc_end_push:} \\
-% \cs{tag_mc_begin_pop:n}\Arg{key-values}
-% \end{syntax}
-% If there is an open mc chunk,
-% \cs{tag_mc_end_push:} ends it and pushes its tag of the stack. If there is no
-% open chunk, it puts -1 on the stack (for debugging)
-% \cs{tag_mc_begin_pop:n} removes a value from the stack. If it is different from
-% -1 it opens a tag with it.
-% The reopened mc chunk looses info like the alttext for now.
-%
-% \begin{macrocode}
-\cs_new_protected:Npn \tag_mc_end_push:
- {
- \@@_mc_if_in:TF
- {
- \seq_gpush:Nx \g_@@_mc_stack_seq { \tag_get:n {mc_tag} }
- \@@_check_mc_pushed_popped:nn {pushed}{\tag_get:n {mc_tag}}
- \tag_mc_end:
- }
- {
- \@@_check_mc_pushed_popped:nn {pushed}{-1}
- \seq_gpush:Nn \g_@@_mc_stack_seq{ -1 }
- }
- }
-\cs_new_protected:Npn \tag_mc_begin_pop:n #1
- {
- \seq_gpop:NNTF \g_@@_mc_stack_seq \l_@@_tmpa_tl
- {
- \tl_if_eq:NnTF \l_@@_tmpa_tl {-1}
- {
- \@@_check_mc_pushed_popped:nn {popped}{-1}
- }
- {
- \@@_check_mc_pushed_popped:nn {popped}{\l_@@_tmpa_tl}
- \tag_mc_begin:n {tag=\l_@@_tmpa_tl,#1}
- }
- }
- { \@@_check_mc_pushed_popped:nn {popped}{empty~stack,~nothing} } %message?
- }
-
-%</shared>
-% \end{macrocode}
-% \begin{macrocode}
-%<*generic>
-\ProvidesExplPackage {tagpdf-mc-code-generic} {2021-06-14} {0.82}
- {part of tagpdf - code related to marking chunks - generic mode}
-
-% for the label system
-% tagmcid is the id which should be also in the pdf
-% it will be (hopefully) reset by page
-
-% ref code is in tagpdf.dtx now
-%
-% will hold the current maximum on a page
-% it will contain key-value of type "abspagenum=max mcid on this page"
-\@@_prop_new:N \g_@@_MCID_byabspage_prop
-
-%to test nesting mc:
-\bool_new:N \g_@@_in_mc_bool
-
-\prg_new_conditional:Nnn \@@_mc_if_in: {p,T,F,TF}
- {
- \bool_if:NTF \g_@@_in_mc_bool
- { \prg_return_true: }
- { \prg_return_false: }
- }
-
-\prg_new_eq_conditional:NNn \tag_mc_if_in: \@@_mc_if_in: {p,T,F,TF}
-
-
-
-% this are the low level mc command.
-% they insert literals and so a are specific to generic mode
-% checking if the type is defined will done somewhere else
-% #1 is the type/tag
-% change 04.08.2018: I don't try to escape the name, but assume that it is valid.
-% Checks/conversions should perhaps be done on a higher level
-\cs_new_protected:Nn \@@_mc_bmc:n
- {
- \pdf_bmc:n {#1}
-% \@@_pdfliteral_page:n
-% {
-% /#1\c_space_tl BMC
-% }
- }
-
-\cs_new_protected:Nn \@@_mc_emc:
- {
- \pdf_emc:
- %\@@_pdfliteral_page:n
-% {
-% EMC
-% }
- }
-
-% #1 tag, #2 properties
-% change 04.08.2018: I don't escape the name. Also the dictionary content
-% must imho be done at a higher level
-\cs_new_protected:Nn \@@_mc_bdc:nn
- {
- \pdf_bdc:nn { #1 } { #2 }
- }
-
-\cs_generate_variant:Nn \@@_mc_bdc:nn {nx}
-% bdc with /MCID + more properties
-% we need a ref-label system to ensure that the cnt restarts at 0 on a new page
-
-\tl_new:N \l_@@_mc_ref_abspage_tl %will store the abspage value of label
-\tl_new:N \l_@@_mc_tmp_tl
-
-\cs_new:Nn \@@_mc_bdc_mcid:nn
- {
- \int_gincr:N \c@g_@@_MCID_abs_int
- \tl_set:Nx \l_@@_mc_ref_abspage_tl
- {
- \@@_ref_value:enn %3 args
- {
- mcid-\int_use:N \c@g_@@_MCID_abs_int
- }
- { tagabspage }
- {-1}
- }
- \prop_get:NoNTF
- \g_@@_MCID_byabspage_prop
- {
- \l_@@_mc_ref_abspage_tl
- }
- \l_@@_mc_tmp_tl
- {
- %key already present, use value for MCID and add 1 for the next
- \int_gset:Nn \g_@@_MCID_tmp_bypage_int { \l_@@_mc_tmp_tl }
- \@@_prop_gput:Nxx
- \g_@@_MCID_byabspage_prop
- { \l_@@_mc_ref_abspage_tl }
- { \int_eval:n {\l_@@_mc_tmp_tl +1} }
- }
- {
- %key not present, set MCID to 0 and insert 1
- \int_gzero:N \g_@@_MCID_tmp_bypage_int
- \@@_prop_gput:Nxx
- \g_@@_MCID_byabspage_prop
- { \l_@@_mc_ref_abspage_tl }
- {1}
- }
- \@@_ref_label:en
- {
- mcid-\int_use:N \c@g_@@_MCID_abs_int
- }
- { mc }
- %\exp_args:Nnx
- \@@_mc_bdc:nx
- {#1}
- { /MCID~\int_eval:n { \g_@@_MCID_tmp_bypage_int }~ \exp_not:n { #2 } }
- }
-
-% only /MCID
-\cs_new:Nn \@@_mc_bdc_mcid:n
- {
- \@@_mc_bdc_mcid:nn {#1} {}
- }
-
-%artifact without type
-\cs_new:Nn \@@_mc_bmc_artifact:
- {
- \@@_mc_bmc:n {Artifact}
- }
-
-%artifact with a type:
-\cs_new:Nn \@@_mc_bmc_artifact:n
- {
- \@@_mc_bdc:nn {Artifact}{/Type/#1}
- }
-
-% perhaps later: more properties for artifacts
-
-
-% keyval definitions for the user commands:
-
-\tl_new:N \l_@@_mc_key_tag_tl
-\tl_new:N \g_@@_mc_key_tag_tl %for "outside" queries
-\tl_new:N \l_@@_mc_key_properties_tl
-
-% Attention! definitions are different in luamode.
-% tag and raw are expanded as \directlua in lua does it too.
-\keys_define:nn { @@ / mc }
- {
- tag .code:n = % the name (H,P,Spa) etc
- {
- %%????????? \pdfescapename??
- \tl_set:Nx \l_@@_mc_key_tag_tl { #1 }
- \tl_gset:Nx \g_@@_mc_key_tag_tl { #1 }
- },
- raw .code:n =
- {
- \tl_put_right:Nx \l_@@_mc_key_properties_tl { #1 }
- },
- alttext .code:n = % Alt property
- {
- \str_set_convert:Nnon
- \l_@@_tmpa_str
- { #1 }
- { default }
- { utf16/hex }
- \tl_put_right:Nn \l_@@_mc_key_properties_tl { /Alt~< }
- \tl_put_right:No \l_@@_mc_key_properties_tl { \l_@@_tmpa_str>~ }
- },
- alttext-o .code:n = % Alt property
- {
- \str_set_convert:Noon
- \l_@@_tmpa_str
- { #1 }
- { default }
- { utf16/hex }
- \tl_put_right:Nn \l_@@_mc_key_properties_tl { /Alt~< }
- \tl_put_right:No \l_@@_mc_key_properties_tl { \l_@@_tmpa_str>~ }
- },
- actualtext .code:n = % ActualText property
- {
- \str_set_convert:Nnon
- \l_@@_tmpa_str
- { #1 }
- { default }
- { utf16/hex }
- \tl_put_right:Nn \l_@@_mc_key_properties_tl { /ActualText~< }
- \tl_put_right:No \l_@@_mc_key_properties_tl { \l_@@_tmpa_str>~ }
- },
- actualtext-o .code:n = % ActualText property
- {
- \str_set_convert:Noon
- \l_@@_tmpa_str
- { #1 }
- { default }
- { utf16/hex }
- \tl_put_right:Nn \l_@@_mc_key_properties_tl { /ActualText~< }
- \tl_put_right:No \l_@@_mc_key_properties_tl { \l_@@_tmpa_str>~ }
- },
- label .tl_set:N = \l_@@_mc_key_label_tl,
- artifact .code:n =
- {
- \exp_args:Nnx
- \keys_set:nn
- { @@ / mc }
- { artifact-bool, artifact-type=#1 }
- },
- artifact .default:n = {notype}
- }
-
-\cs_new:Nn \@@_mc_handle_artifact:N %#1 contains the artifact type
- {
- \tl_if_empty:NTF #1
- { \@@_mc_bmc_artifact: }
- { \exp_args:No\@@_mc_bmc_artifact:n {#1} }
- }
-
-\cs_new:Nn \@@_mc_handle_mcid:nn %#1 tag, #2 properties
- {
- \@@_mc_bdc_mcid:nn {#1} {#2}
- }
-
-\cs_generate_variant:Nn \@@_mc_handle_mcid:nn {VV}
-
-% puts the absolute number of an mcid in the current structure
-\cs_new:Nn \@@_mc_handle_stash:n %1 mcidnum
- {
- \@@_check_mc_used:n {#1}
- \@@_struct_kid_mc_gput_right:nn
- { \g_@@_struct_stack_current_tl }
- {#1}
- \prop_gput:Nxx \g_@@_mc_parenttree_prop
- {#1}
- { \g_@@_struct_stack_current_tl }
- }
-
-\cs_new_protected:Nn \tag_mc_begin:n
- {
- \group_begin: %hm
- \@@_check_mc_if_nested:
- \bool_gset_true:N \g_@@_in_mc_bool
- \keys_set:nn { @@ / mc } {#1}
- \bool_if:NTF \l_@@_mc_artifact_bool
- { %handle artifact
- \@@_mc_handle_artifact:N \l_@@_mc_artifact_type_tl
- }
- { %handle mcid type
- \@@_check_mc_tag:N \l_@@_mc_key_tag_tl
- \@@_mc_handle_mcid:VV
- \l_@@_mc_key_tag_tl
- \l_@@_mc_key_properties_tl
- \tl_if_empty:NF {\l_@@_mc_key_label_tl}
- {
- \@@_mc_handle_mc_label:n { \l_@@_mc_key_label_tl }
- }
- \bool_if:NF \l_@@_mc_key_stash_bool
- {
- \@@_mc_handle_stash:n { \int_use:N \c@g_@@_MCID_abs_int }
- }
- }
- \group_end:
- }
-
-
-\cs_new_protected:Nn \tag_mc_end:
- {
- \@@_check_mc_if_open:
- \bool_gset_false:N \g_@@_in_mc_bool
- \tl_gset:Nn \g_@@_mc_key_tag_tl { }
- \@@_mc_emc:
- }
-
-
-
-\cs_new_protected:Nn \tag_mc_use:n %#1: label name
- {
- \tl_set:Nx \l_tmpa_tl { \@@_ref_value:enn{tagpdf-#1}{tagmcabs}{} }
- \tl_if_empty:NTF\l_tmpa_tl
- {
- \msg_warning:nnn {tag} {mc-label-unknown} {#1}
- }
- {
- \prop_gput:Nxx
- \g_@@_mc_parenttree_prop
- {
- \@@_ref_value:enn {tagpdf-#1} {tagmcabs} {}
- }
- {
- \g_@@_struct_stack_current_tl
- }
- \@@_struct_kid_mc_gput_right:nn
- {
- \g_@@_struct_stack_current_tl
- }
- {
- \@@_ref_value:enn {tagpdf-#1} {tagmcabs} {}
- }
- }
- }
-
-
-\cs_new:Nn \@@_get_data_mc_tag: { \g_@@_mc_key_tag_tl }
-%</generic>
-% \end{macrocode}
-% \begin{macrocode}
-%<*luamode>
-\ProvidesExplPackage {tagpdf-mc-code-lua} {2021-06-14} {0.82}
- {tagpdf - mc code only for the luamode }
-
-% the two attibutes are defined in the driver file.
-% it also load the lua (as it can also contain functions needed by generic mode.
-% (new) attributes for mc are local:
-% \newattribute \l_@@_mc_type_attr %the value represent the type
-% \newattribute \l_@@_mc_cnt_attr %will hold the \c@g_@@_MCID_abs_int value
-
-
-% An attribute for the current structure probably doesn't make sense as mc chunks can be used later.
-% \newattribute \g_@@_struct_type_attr %represent the current structure type. Not sure if needed
-% \newattribute \g_@@_struct_cnt_attr %will hold \c@g_@@_struct_abs_int a cnt
-
-% handling attribute needs a different system to number the page wise mcid's:
-% a tagmcbegin ... tagmcend pair no longer surrounds exactly one mc chunk: it can be split
-% at page breaks. We know the included mcid(s) only after the ship out. So for the struct-> mcid mapping we
-% need to record struct -> mc-cnt (in \g_@@_mc_parenttree_prop and/or a lua table
-% and at shipout mc-cnt-> {mcid, mcid, ...} (in a table?)
-% and when building the trees connect both
-
-% key definitions are overwritten for luatex to store that data in tables
-% the data for the mc are in ltx.@@.mc[absnum]
-% the fields of the table are
-% tag : the type (a string)
-% raw : more properties (string)
-% label: a string. Do we need a way to retrieve the num from the label from lua??
-% artifact: the presence indicates an artifact, the value (string) is the type.
-% kids: a array of tables {1={kid=num2,page=pagenum1}, 2={kid=num2,page=pagenum2},...},
-% this describes the chunks the mc has been split to by the traversing code
-% parent: the number of the structure it is in. Needed to build the parent tree.
-
-% The main function which wanders through the shipout box to inject the literals.
-% if the new callback is there, it is used.
-\hook_gput_code:nnn{begindocument}{tagpdf/mc}
- {
- \bool_if:NT\g__tag_active_mc_bool
- {
- \directlua
- {
- if~luatexbase.callbacktypes.pre_shipout_filter~then~
- luatexbase.add_to_callback("pre_shipout_filter", function(TAGBOX)~
- ltx.__tag.func.mark_shipout(TAGBOX)~return~true~
- end, "tagpdf")~
- end
- }
- \directlua
- {
- if~luatexbase.callbacktypes.pre_shipout_filter~then~
- token.get_next()~
- end
- }\@secondoftwo\@gobble
- {
- \hook_gput_code:nnn{shipout/before}{tagpdf/lua}
- {
- \directlua
- { ltx.__tag.func.mark_shipout (tex.box["ShipoutBox"]) }
- }
- }
- }
- }
-
-\prg_new_conditional:Nnn \@@_mc_if_in: {p,T,F,TF}
- {
- \int_compare:nNnTF { -2147483647 }={ \l_@@_mc_type_attr }
- { \prg_return_false: }
- { \prg_return_true: }
- }
-
-\prg_new_eq_conditional:NNn \tag_mc_if_in: \@@_mc_if_in: {p,T,F,TF}
-
-
-% the keys
-\tl_new:N \l_@@_mc_key_tag_tl
-\tl_new:N \l_@@_mc_key_label_tl
-\tl_new:N \l_@@_mc_key_properties_tl
-
-\keys_define:nn { @@ / mc }
- {
- tag .code:n = %
- {%%????????? \pdfescapename??
- \tl_set:Nx \l_@@_mc_key_tag_tl { #1 }
- \directlua
- {
- ltx.@@.func.store_mc_data(\@@_get_mc_abs_cnt:,"tag","#1")
- }
- },
- raw .code:n =
- {
- \tl_put_right:Nx \l_@@_mc_key_properties_tl { #1 }
- \directlua
- {
- ltx.@@.func.store_mc_data(\@@_get_mc_abs_cnt:,"raw","#1")
- }
- },
- alttext .code:n = % Alt property
- {
- \str_set_convert:Nnon
- \l_@@_tmpa_str
- { #1 }
- { default }
- { utf16/hex }
- \tl_put_right:Nn \l_@@_mc_key_properties_tl { /Alt~< }
- \tl_put_right:No \l_@@_mc_key_properties_tl { \l_@@_tmpa_str>~ }
- \directlua
- {
- ltx.@@.func.store_mc_data
- (
- \@@_get_mc_abs_cnt:,"alt","/Alt~<\str_use:N \l_@@_tmpa_str>"
- )
- }
- },
- alttext-o .code:n = % Alt property
- {
- \str_set_convert:Noon
- \l_@@_tmpa_str
- { #1 }
- { default }
- { utf16/hex }
- \tl_put_right:Nn \l_@@_mc_key_properties_tl { /Alt~< }
- \tl_put_right:No \l_@@_mc_key_properties_tl { \l_@@_tmpa_str>~ }
- \directlua
- {
- ltx.@@.func.store_mc_data
- (
- \@@_get_mc_abs_cnt:,"alt","/Alt~<\str_use:N \l_@@_tmpa_str>"
- )
- }
- },
- actualtext .code:n = % Alt property
- {
- \str_set_convert:Nnon
- \l_@@_tmpa_str
- { #1 }
- { default }
- { utf16/hex }
- \tl_put_right:Nn \l_@@_mc_key_properties_tl { /Alt~< }
- \tl_put_right:No \l_@@_mc_key_properties_tl { \l_@@_tmpa_str>~ }
- \directlua
- {
- ltx.@@.func.store_mc_data
- (
- \@@_get_mc_abs_cnt:,"actualtext","/ActualText~<\str_use:N \l_@@_tmpa_str>"
- )
- }
- },
- actualtext-o .code:n = % Alt property
- {
- \str_set_convert:Noon
- \l_@@_tmpa_str
- { #1 }
- { default }
- { utf16/hex }
- \tl_put_right:Nn \l_@@_mc_key_properties_tl { /Alt~< }
- \tl_put_right:No \l_@@_mc_key_properties_tl { \l_@@_tmpa_str>~ }
- \directlua
- {
- ltx.@@.func.store_mc_data
- (
- \@@_get_mc_abs_cnt:,
- "actualtext",
- "/ActualText~<\str_use:N \l_@@_tmpa_str>"
- )
- }
- },
- label .code:n =
- {
- \tl_set:Nn\l_@@_mc_key_label_tl { #1 }
- \directlua
- {
- ltx.@@.func.store_mc_data
- (
- \@@_get_mc_abs_cnt:,"label","#1"
- )
- }
- },
- __artifact-store .code:n =
- {
- \directlua
- {
- ltx.@@.func.store_mc_data
- (
- \@@_get_mc_abs_cnt:,"artifact","#1"
- )
- }
- },
- artifact .code:n =
- {
- \exp_args:Nnx
- \keys_set:nn
- { @@ / mc}
- { artifact-bool, artifact-type=#1, tag=Artifact }
- \exp_args:Nnx
- \keys_set:nn
- { @@ / mc }
- { __artifact-store=\l_@@_mc_artifact_type_tl }
- },
- artifact .default:n = { notype }
- }
-
-
-% attributes
-% set the mc from a tag name
-
-\cs_set_protected:Npn \@@_attribute_gset:Nn #1 #2
- {
- \tex_global:D \setattribute #1 #2
- }
-
-\cs_set_protected:Npn \@@_attribute_set:Nn #1 #2
- {
- \setattribute #1 #2
- }
-
-\cs_set_protected:Npn \@@_attribute_gunset:N #1
- {
- \tex_global:D \unsetattribute #1
- }
-
-\cs_set_protected:Npn \@@_attribute_unset:N #1
- {
- \unsetattribute #1
- }
-
-
-\cs_new:Nn \@@_mc_lua_set_mc_type_attr:n % #1 is a tag name
- {
- \@@_attribute_set:Nn \l_@@_mc_type_attr
- {
- \directlua { ltx.@@.func.output_num_from ("#1") }
- }
- \@@_attribute_set:Nn \l_@@_mc_cnt_attr { \@@_get_mc_abs_cnt: }
- }
-
-\cs_generate_variant:Nn\@@_mc_lua_set_mc_type_attr:n { o }
-
-\cs_new:Nn \@@_mc_lua_unset_mc_type_attr:
- {
- \@@_attribute_unset:N \l_@@_mc_type_attr
- \@@_attribute_unset:N \l_@@_mc_cnt_attr
- }
-
-
-
-%This command will in the finish code replace the dummy for a mc by the real mcid kids
-%we need a variant for the case that it is the only kid, to get the array right
-\cs_new:Nn \@@_mc_insert_mcid_kids:n
- {
- \directlua { ltx.@@.func.mc_insert_kids (#1,0) }
- }
-
-\cs_new:Nn \@@_mc_insert_mcid_single_kids:n
- {
- \directlua {ltx.@@.func.mc_insert_kids (#1,1) }
- }
-
-
-% we need to pass the info if the kids are alone or already in an array
-% so we add a second argument, which should == 1 if the kids are single
-
-
-% puts an mcid absolute number in the current structure
-\cs_new:Nn \@@_mc_handle_stash:n %1 mcidnum
- {
- \@@_check_mc_used:n { #1 }
- \seq_gput_right:cn % Don't fill a lua table due to the command in the item,
- % so use the kernel command
- { g_@@_struct_kids_\g_@@_struct_stack_current_tl _seq }
- {
- \@@_mc_insert_mcid_kids:n {#1}%
- }
- \directlua
- {
- ltx.@@.func.store_struct_mcabs
- (
- \g_@@_struct_stack_current_tl,#1
- )
- }
- \prop_gput:Nxx
- \g_@@_mc_parenttree_prop
- { #1 }
- { \g_@@_struct_stack_current_tl }
- }
-
-\cs_generate_variant:Nn \@@_mc_handle_stash:n { o }
-
-\cs_new_protected:Nn \tag_mc_begin:n
- {
- %\group_begin:
- %\@@_check_mc_if_nested:
- %\bool_gset_true:N \g_@@_in_mc_bool
- \bool_set_false:N\l_@@_mc_artifact_bool
- \int_gincr:N \c@g_@@_MCID_abs_int
- \tl_clear:N \l_@@_mc_key_properties_tl
- \keys_set:nn { @@ / mc }{ label={}, #1 }
- %check that a tag or artifact has been used
- \@@_check_mc_tag:N \l_@@_mc_key_tag_tl
- %set the attributes:
- \@@_mc_lua_set_mc_type_attr:o { \l_@@_mc_key_tag_tl }
- \bool_if:NF \l_@@_mc_artifact_bool
- { % store the absolute num name in a label:
- \tl_if_empty:NF {\l_@@_mc_key_label_tl}
- {
- \@@_mc_handle_mc_label:n { \l_@@_mc_key_label_tl }
- }
- % if not stashed record the absolute number
- \bool_if:NF \l_@@_mc_key_stash_bool
- {
- \exp_args:Nx \@@_mc_handle_stash:n { \@@_get_mc_abs_cnt: }
- }
- }
- %\bool_set_false:N\l_@@_mc_artifact_bool
- %\group_end:
- }
-
-
-\cs_new_protected:Nn \tag_mc_end:
- {
- %\@@_check_mc_if_open:
- %\bool_gset_false:N \g_@@_in_mc_bool
- \bool_set_false:N\l_@@_mc_artifact_bool
- \@@_mc_lua_unset_mc_type_attr:
- \tl_set:Nn \l_@@_mc_key_tag_tl { }
- }
-
-
-
-\cs_new_protected:Nn \tag_mc_use:n %#1: label name
- {
- \tl_set:Nx \l_tmpa_tl { \@@_ref_value:enn{tagpdf-#1}{tagmcabs}{} }
- \tl_if_empty:NTF\l_tmpa_tl
- {
- \msg_warning:nnn {tag} {mc-label-unknown} { #1 }
- }
- {
- \@@_mc_handle_stash:o { \l_tmpa_tl }
- }
- }
-
-
-
-\cs_new:Nn \@@_get_data_mc_tag: { \l_@@_mc_key_tag_tl }
-%</luamode>
-% \end{macrocode}
diff --git a/Master/texmf-dist/source/latex/tagpdf/tagpdf-roles.dtx b/Master/texmf-dist/source/latex/tagpdf/tagpdf-roles.dtx
index 7955226573f..f8a11bc4649 100644
--- a/Master/texmf-dist/source/latex/tagpdf/tagpdf-roles.dtx
+++ b/Master/texmf-dist/source/latex/tagpdf/tagpdf-roles.dtx
@@ -21,28 +21,60 @@
% https://github.com/u-fischer/tagpdf
%
% for those people who are interested.
-%
+%<*driver>
+\RequirePackage{pdfmanagement-testphase}
+\DeclareDocumentMetadata{}
+\makeatletter
+\declare@file@substitution{doc.sty}{doc-v3beta.sty}
+\makeatother
+\documentclass{l3doc}
+\usepackage{array,booktabs,caption}
+\hypersetup{pdfauthor=Ulrike Fischer,
+ pdftitle=tagpdf-checks module (tagpdf)}
+\begin{document}
+ \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
% \fi
+% \title{^^A
+% The \pkg{tagpdf-roles} module\\ Tags, roles and namesspace code ^^A
+% \\ Part of the tagpdf package
+% }
+%
+% \author{^^A
+% Ulrike Fischer\thanks
+% {^^A
+% E-mail:
+% \href{mailto:fischer@troubleshooting-tex.de}
+% {fischer@troubleshooting-tex.de}^^A
+% }^^A
+% }
%
+% \date{Version 0.9, released 2021-06-29}
+% \maketitle
+% \begin{implementation}
% \begin{macrocode}
%<@@=tag>
-%<*roles>
-\ProvidesExplPackage {tagpdf-roles-code} {2021-06-14} {0.82}
+%<*header>
+\ProvidesExplPackage {tagpdf-roles-code} {2021-06-29} {0.9}
{part of tagpdf - code related to roles and structure names}
+%</header>
% \end{macrocode}
-% \section{Variables}
+% \section{Code related to roles and structure names}
+% \subsection{Variables}
% Tags have both a name (a string) and a number (for the lua attribute).
% Testing a name is easier with a prop, while accessing with a number is
% better done with a seq. So both are used and must be kept in sync if a new
% tag is added. The number is only relevant for the MC type, tags with the same
% name from different names spaces can have the same number.
-% \begin{macro}{\g_@@_role_tags_seq,\g_@@_role_tags_prop}
+% \begin{variable}{\g_@@_role_tags_seq,\g_@@_role_tags_prop}
% \begin{macrocode}
+%<*package>
\@@_seq_new:N \g_@@_role_tags_seq %to get names (type/NS) from numbers
\@@_prop_new:N \g_@@_role_tags_prop %to get numbers from names (type/NS)
% \end{macrocode}
-% \end{macro}
-% \begin{macro}{\g_@@_role_tags_NS_prop}
+% \end{variable}
+% \begin{variable}{\g_@@_role_tags_NS_prop}
% in pdf 2.0 tags belong to a name space. For every tag we store a default
% name space.
% The keys are the tags, the value shorthands like pdf2, or mathml.
@@ -50,8 +82,8 @@
% \begin{macrocode}
\prop_new:N \g_@@_role_tags_NS_prop %to namespace info
% \end{macrocode}
-% \end{macro}
-% \begin{macro}{\g_@@_role_NS_prop}
+% \end{variable}
+% \begin{variable}{\g_@@_role_NS_prop}
% The standard names spaces are the following. The keys are the name
% tagpdf will use, the urls are the identifier in the namespace object.
% \begin{description}
@@ -68,13 +100,28 @@
% \begin{macrocode}
\prop_new:N \g_@@_role_NS_prop % collect namespaces
% \end{macrocode}
-% \end{macro}
-% \section{Namesspaces}
+% \end{variable}
+%
+% We need also a bunch of temporary variables:
+% \begin{variable}
+% {
+% \l_@@_role_tag_tmpa_tl
+% ,\l_@@_role_tag_namespace_tmpa_tl
+% ,\l_@@_role_role_tmpa_tl
+% ,\l_@@_role_role_namespace_tmpa_tl
+% }
+% \begin{macrocode}
+\tl_new:N \l_@@_role_tag_tmpa_tl
+\tl_new:N \l_@@_role_tag_namespace_tmpa_tl
+\tl_new:N \l_@@_role_role_tmpa_tl
+\tl_new:N \l_@@_role_role_namespace_tmpa_tl
+% \end{macrocode}
+% \end{variable}
+% \subsection{Namesspaces}
% The following commands setups a names space. Namespace dictionaries can
% contain an optional |/Schema| and |/RoleMapNS| entry. We only reserve the
% objects but delay the writing to the finish code, where we can test if the
% keys and the name spaces are actually needed
-% \begin{macro}{\@@_role_NS_new:nn}
% This commands setups objects for the name space and its rolemap. It also
% initialize a prop to collect the rolemaps if needed.
% \begin{function}{\@@_role_NS_new:nnn}
@@ -85,7 +132,7 @@
% \begin{macro}{\@@_role_NS_new:nnn}
% \begin{macrocode}
\cs_new_protected:Npn \@@_role_NS_new:nnn #1 #2 #3
- { \msg_redirect_name:nnn { pdfdict } { empty-value } { none }
+ {
\pdf_object_new:nn {tag/NS/#1}{dict}
\pdfdict_new:n {g_@@_role/Namespace_#1_dict}
\pdf_object_new:nn {@@/RoleMapNS/#1}{dict}
@@ -95,15 +142,20 @@
{Type}
{/Namespace}
\pdf_string_from_unicode:nnN{utf8/string}{#2}\l_tmpa_str
- \pdfdict_gput:nnx
- {g_@@_role/Namespace_#1_dict}
- {NS}
- {\l_tmpa_str}
+ \tl_if_empty:NF \l_tmpa_str
+ {
+ \pdfdict_gput:nnx
+ {g_@@_role/Namespace_#1_dict}
+ {NS}
+ {\l_tmpa_str}
+ }
%RoleMapNS is added in tree
- \pdfdict_gput:nnx{g_@@_role/Namespace_#1_dict}
- {Schema}{#3}
+ \tl_if_empty:nF {#3}
+ {
+ \pdfdict_gput:nnx{g_@@_role/Namespace_#1_dict}
+ {Schema}{#3}
+ }
\prop_gput:Nnx \g_@@_role_NS_prop {#1}{\pdf_object_ref:n{tag/NS/#1}~}
- \msg_redirect_name:nnn { pdfdict } { empty-value } { warning }
}
% \end{macrocode}
% \end{macro}
@@ -112,6 +164,7 @@
% be fixed by setting a seed. We fake a sort of
% GUID but not try to be really exact as it doesn't matter ...
%
+% \begin{variable}{\c_@@_role_userNS_id_str}
% \begin{macrocode}
\str_const:Nx \c_@@_role_userNS_id_str
{ data:,
@@ -128,6 +181,7 @@
\int_to_Hex:n{\int_rand:n {16777215}}
}
% \end{macrocode}
+% \end{variable}
% Now we setup the standard names spaces. Currently only if we detect pdf2.0 but
% this will perhaps have to change if the structure code gets to messy.
% \begin{macrocode}
@@ -141,14 +195,14 @@
}
% \end{macrocode}
%
-% \section{Data}
+% \subsection{Data}
% In this section we setup the standard data.
% At first the list of structure types. We split them in three lists,
% the tags with which are both in the pdf and pdf2 namespace,
% the one only in pdf and the one with the tags only in pdf2.
% We also define a rolemap for the pdfII only type to pdf so that
% they can always be used.
-% \begin{macro}
+% \begin{variable}
% {
% \c_@@_role_sttags_pdf_pdfII_clist,
% \c_@@_role_sttags_only_pdf_clist,
@@ -160,7 +214,8 @@
%
\clist_const:Nn \c_@@_role_sttags_pdf_pdfII_clist
{
- Document, %A complete document. This is the root element of any structure tree containing
+ Document, %A complete document. This is the root element
+ %of any structure tree containing
%multiple parts or multiple articles.
Part, %A large-scale division of a document.
Sect, %A container for grouping related content elements.
@@ -205,13 +260,16 @@
\clist_const:Nn \c_@@_role_sttags_only_pdf_clist
{
- Art,%A relatively self-contained body of text constituting a single narrative or exposition
- BlockQuote, %A portion of text consisting of one or more paragraphs attributed to someone other
- %than the author of the surrounding text.
- TOC, %A list made up of table of contents item entries (structure tag TOCI; see below)
- %and/or other nested table of contents entries
- TOCI, %An individual member of a table of contents. This entry's children can be any of
- %the following structure tags:
+ Art, %A relatively self-contained body of text
+ %constituting a single narrative or exposition
+ BlockQuote, %A portion of text consisting of one or more paragraphs
+ %attributed to someone other than the author of the
+ %surrounding text.
+ TOC, %A list made up of table of contents item entries
+ %(structure tag TOCI; see below) and/or other
+ %nested table of contents entries
+ TOCI, %An individual member of a table of contents.
+ %This entry's children can be any of the following structure tags:
%Lbl,Reference,NonStruct,P,TOC
Index,
Private,
@@ -448,7 +506,7 @@
Strong= Span,
}
% \end{macrocode}
-% \end{macro}
+% \end{variable}
% We fill the structure tags in to the seq. We allow all pdf1.7 and pdf2.0,
% and role map if needed the 2.0 tags.
% \begin{macrocode}
@@ -482,7 +540,6 @@
% For luatex and the MC we need a name/number relation.
% The name space is not relevant.
% \begin{macrocode}
-
\int_step_inline:nnnn { 1 }{ 1 }{ \seq_count:N \g_@@_role_tags_seq }
{
\@@_prop_gput:Nxn \g_@@_role_tags_prop
@@ -493,24 +550,29 @@
}
% \end{macrocode}
%
-% \section{Adding new tags and rolemapping}
+% \subsection{Adding new tags and rolemapping}
%
-% \subsection{pdf 1.7 and earlier}
+% \subsubsection{pdf 1.7 and earlier}
% With this versions only RoleMap is filled.
% At first the dictionary:
+% \begin{variable}{g_@@_role/RoleMap_dict}
% \begin{macrocode}
\pdfdict_new:n {g_@@_role/RoleMap_dict}
% \end{macrocode}
+% \end{variable}
% \begin{macro}{\@@_role_add_tag:nn}
% The pdf 1.7 version has only two arguments: new and rolemap name.
% To make pdf 2.0 types usable we directly define a rolemapping for them.
-% TODO: add checks
+%
% \begin{macrocode}
\cs_new_protected:Nn \@@_role_add_tag:nn %(new) name, reference to old
{
\prop_if_in:NnF \g_@@_role_tags_prop {#1}
{
- \msg_info:nnn { tag }{new-tag}{#1}
+ \int_compare:nNnT {\l_@@_loglevel_int} > { 0 }
+ {
+ \msg_info:nnn { tag }{new-tag}{#1}
+ }
\@@_seq_gput_right:Nn \g_@@_role_tags_seq { #1 }
\@@_prop_gput:Nnx \g_@@_role_tags_prop { #1 }
{
@@ -518,7 +580,7 @@
}
\prop_gput:Nnn \g_@@_role_tags_NS_prop { #1 }{ user }
}
- %\@@_check_add_tag_role:nn {#1}{#2} %%!TODO
+ \@@_check_add_tag_role:nn {#1}{#2}
\tl_if_empty:nF { #2 }
{
\pdfdict_gput:nnx {g_@@_role/RoleMap_dict}
@@ -538,22 +600,24 @@
% \end{macrocode}
% \end{macro}
-%
+% \subsubsection{The pdf 2.0 version}
% \begin{macro}{\@@_role_add_tag:nnnn}
-% The pdf 2.0 version takes for arguments:
+% The pdf 2.0 version takes four arguments:
% tag/namespace/role/namespace
-% TODO: add checks
% \begin{macrocode}
\cs_new_protected:Nn \@@_role_add_tag:nnnn %tag/namespace/role/namespace
{
- \msg_info:nnn { tag }{new-tag}{#1}
+ \int_compare:nNnT {\l_@@_loglevel_int} > { 0 }
+ {
+ \msg_info:nnn { tag }{new-tag}{#1}
+ }
\@@_seq_gput_right:Nn \g_@@_role_tags_seq { #1 }
\@@_prop_gput:Nnx \g_@@_role_tags_prop { #1 }
{
\seq_count:N \g_@@_role_tags_seq
}
\prop_gput:Nnn \g_@@_role_tags_NS_prop { #1 }{ #2 }
- %\@@_check_add_tag_role:nn {#1}{#3} %TODO
+ \@@_check_add_tag_role:nn {#1}{#3}
\pdfdict_gput:nnx {g_@@_role/RoleMapNS_#2_dict}{#1}
{
[
@@ -566,15 +630,11 @@
\cs_generate_variant:Nn \@@_role_add_tag:nnnn {VVVV}
% \end{macrocode}
% \end{macro}
-% The user interface use the key add-new-tag, which takes either a
+% \subsection{Key-val user interface}
+% The user interface use the key |add-new-tag|, which takes either a
% keyval list as argument, or a tag/role.
+% \begin{macro}{tag,tag-namespace,role,role-namespace,add-new-tag}
% \begin{macrocode}
-
-\tl_new:N \l_@@_role_tag_tmpa_tl
-\tl_new:N \l_@@_role_tag_namespace_tmpa_tl
-\tl_new:N \l_@@_role_role_tmpa_tl
-\tl_new:N \l_@@_role_role_namespace_tmpa_tl
-
\keys_define:nn { @@ / tag-role }
{
,tag .tl_set:N = \l_@@_role_tag_tmpa_tl
@@ -632,7 +692,8 @@
}
}
}
-
-
-%</roles>
+%</package>
% \end{macrocode}
+% \end{macro}
+% \end{implementation}
+% \PrintIndex
diff --git a/Master/texmf-dist/source/latex/tagpdf/tagpdf-space.dtx b/Master/texmf-dist/source/latex/tagpdf/tagpdf-space.dtx
index 55021a74d2b..9ccee62c6f0 100644
--- a/Master/texmf-dist/source/latex/tagpdf/tagpdf-space.dtx
+++ b/Master/texmf-dist/source/latex/tagpdf/tagpdf-space.dtx
@@ -2,7 +2,7 @@
%
%% File: tagpdf-space.dtx
%
-% Copyright (C) 2019 Ulrike Fischer
+% Copyright (C) 2019-2021 Ulrike Fischer
%
% It may be distributed and/or modified under the conditions of the
% LaTeX Project Public License (LPPL), either version 1.3c of this
@@ -21,25 +21,74 @@
% https://github.com/u-fischer/tagpdf
%
% for those people who are interested.
-%
+%<*driver>
+\RequirePackage{pdfmanagement-testphase}
+\DeclareDocumentMetadata{}
+\makeatletter
+\declare@file@substitution{doc.sty}{doc-v3beta.sty}
+\makeatother
+\documentclass{l3doc}
+\usepackage{array,booktabs,caption}
+\hypersetup{pdfauthor=Ulrike Fischer,
+ pdftitle=tagpdf-space module (tagpdf)}
+\begin{document}
+ \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
% \fi
+% \title{^^A
+% The \pkg{tagpdf-space} module\\ Code related to real space chars ^^A
+% \\ Part of the tagpdf package
+% }
+%
+% \author{^^A
+% Ulrike Fischer\thanks
+% {^^A
+% E-mail:
+% \href{mailto:fischer@troubleshooting-tex.de}
+% {fischer@troubleshooting-tex.de}^^A
+% }^^A
+% }
%
+% \date{Version 0.9, released 2021-06-29}
+% \maketitle
+% \begin{implementation}
% \begin{macrocode}
%<@@=tag>
-%<*space>
-\ProvidesExplPackage {tagpdf-space-code} {2021-06-14} {0.82}
+%<*header>
+\ProvidesExplPackage {tagpdf-space-code} {2021-06-29} {0.9}
{part of tagpdf - code related to real space chars}
-% luatex uses an attribute (declared in the driver file) and some luacode in tagpdf.lua
-% perhaps I will split the code by engine in the future
-
+%</header>
+% \end{macrocode}
+% \section{Code for interword spaces}
+% The code is engine/backend dependant. Basically only pdftex and luatex
+% support real space chars. Most of the code for luatex which uses attributes
+% is in the lua code, here are only the keys.
+%
+% \begin{macro}{interwordspace,show-spaces}
+% \begin{macrocode}
+%<*package>
\sys_if_engine_pdftex:T
{
- \pdfglyphtounicode{space}{0020}
- \keys_define:nn { @@ / setup }
+ \sys_if_output_pdf:TF
{
- interwordspace .choices:nn = { true, on } { \pdfinterwordspaceon },
- interwordspace .choices:nn = { false, off }{ \pdfinterwordspaceon },
- show-spaces .bool_set:N = \l_@@_showspaces_bool
+ \pdfglyphtounicode{space}{0020}
+ \keys_define:nn { @@ / setup }
+ {
+ interwordspace .choices:nn = { true, on } { \pdfinterwordspaceon },
+ interwordspace .choices:nn = { false, off }{ \pdfinterwordspaceon },
+ interwordspace .default:n = true,
+ show-spaces .bool_set:N = \l_@@_showspaces_bool
+ }
+ }
+ {
+ \keys_define:nn { @@ / setup }
+ {
+ interwordspace .choices:nn = { true, on, false, off }
+ { \msg_warning:nnn {tag}{sys-no-interwordspace}{dvi} },
+ interwordspace .default:n = true,
+ show-spaces .bool_set:N = \l_@@_showspaces_bool
+ }
}
}
@@ -50,40 +99,57 @@
{
interwordspace .choices:nn =
{ true, on }
- { \directlua{ltx.@@.func.markspaceon()} },
+ {
+ \bool_gset_true:N \g_@@_active_space_bool
+ \lua_now:e{ltx.@@.func.markspaceon()}
+ },
interwordspace .choices:nn =
{ false, off }
- {\directlua{ltx.@@.func.markspaceoff()} },
+ {
+ \bool_gset_false:N \g_@@_active_space_bool
+ \lua_now:e{ltx.@@.func.markspaceoff()}
+ },
+ interwordspace .default:n = true,
show-spaces .choice:,
show-spaces / true .code:n =
- {\directlua{ltx.@@.trace.showspaces=true}},
+ {\lua_now:e{ltx.@@.trace.showspaces=true}},
show-spaces / false .code:n =
- {\directlua{ltx.@@.trace.showspaces=nil}},
+ {\lua_now:e{ltx.@@.trace.showspaces=nil}},
show-spaces .default:n = true
}
-
- \cs_new_protected:Nn \@@_fakespace:
- {
- \group_begin:
- \setattribute\g_@@_interwordspace_attr{1}
- \setattribute\g_@@_interwordfont_attr
- {
- \directlua{tex.print(\the\catcodetable@latex, font.current())}
- }
- \skip_horizontal:n{\c_zero_skip}
- \group_end:
- }
}
\sys_if_engine_xetex:T
{
\keys_define:nn { @@ / setup }
{
- interwordspace .choices:nn = { true, on } { \msg_warning:nnn {tag}{sys-no-interwordspace}{xetex} },
- interwordspace .choices:nn = { false, off }{ \msg_warning:nnn {tag}{sys-no-interwordspace}{xetex} },
+ interwordspace .choices:nn = { true, on }
+ { \msg_warning:nnn {tag}{sys-no-interwordspace}{xetex} },
+ interwordspace .choices:nn = { false, off }
+ { \msg_warning:nnn {tag}{sys-no-interwordspace}{xetex} },
+ interwordspace .default:n = true,
show-spaces .bool_set:N = \l_@@_showspaces_bool
}
}
-
-%</space>
% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_fakespace:}
+% For luatex we need a command for the fake space as equivalent of the pdftex
+% primitive.
+% \begin{macrocode}
+\sys_if_engine_luatex:T
+ {
+ \cs_new_protected:Nn \@@_fakespace:
+ {
+ \group_begin:
+ \lua_now:e{ltx.@@.func.fakespace()}
+ \skip_horizontal:n{\c_zero_skip}
+ \group_end:
+ }
+ }
+%</package>
+% \end{macrocode}
+% \end{macro}
+% \end{implementation}
+% \PrintIndex
diff --git a/Master/texmf-dist/source/latex/tagpdf/tagpdf-struct.dtx b/Master/texmf-dist/source/latex/tagpdf/tagpdf-struct.dtx
index e385fea951d..4c342f921c9 100644
--- a/Master/texmf-dist/source/latex/tagpdf/tagpdf-struct.dtx
+++ b/Master/texmf-dist/source/latex/tagpdf/tagpdf-struct.dtx
@@ -21,57 +21,278 @@
% https://github.com/u-fischer/tagpdf
%
% for those people who are interested.
-%
+%<*driver>
+\RequirePackage{pdfmanagement-testphase}
+\DeclareDocumentMetadata{}
+\makeatletter
+\declare@file@substitution{doc.sty}{doc-v3beta.sty}
+\makeatother
+\documentclass{l3doc}
+\usepackage{array,booktabs,caption}
+\hypersetup{pdfauthor=Ulrike Fischer,
+ pdftitle=tagpdf-tree module (tagpdf)}
+\begin{document}
+ \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
% \fi
+% \title{^^A
+% The \pkg{tagpdf-struct} module\\ Commands to create the structure ^^A
+% \\ Part of the tagpdf package
+% }
+%
+% \author{^^A
+% Ulrike Fischer\thanks
+% {^^A
+% E-mail:
+% \href{mailto:fischer@troubleshooting-tex.de}
+% {fischer@troubleshooting-tex.de}^^A
+% }^^A
+% }
+%
+% \date{Version 0.9, released 2021-06-29}
+% \maketitle
+% \begin{documentation}
+% \section{Public Commands}
+% \begin{function}{\tag_struct_begin:n,\tag_struct_end:}
+% \begin{syntax}
+% \cs{tag_struct_begin:n}\Arg{key-values}\\
+% \cs{tag_struct_end:}
+% \end{syntax}
+% These commands start and end a new structure.
+% They don't start a group. They set all their values globally.
+% \end{function}
+% \begin{function}{\tag_struct_use:n}
+% \begin{syntax}
+% \cs{tag_struct_use:n}\Arg{label}
+% \end{syntax}
+% These commands insert a structure previously stashed away as kid
+% into the currently active structure.
+% A structure should be used only once,
+% if the structure already has a parent a warning is issued.
+% \end{function}
+% The following two functions are used to add annotations. They must be used
+% together and with care to get the same numbers. Perhaps some improvements are needed
+% here.
+% \begin{function}{\tag_struct_insert_annot:nn}
+% \begin{syntax}
+% \cs{tag_struct_insert_annot:nn}\Arg{object reference}\Arg{struct parent number}
+% \end{syntax}
+% This inserts an annotation in the structure. \meta{object reference}
+% is there reference to the annotation. \meta{struct parent number}
+% should be the same number as had been inserted with \cs{tag_struct_parent_int:}
+% as |StructParent| value to the dictionary of the annotion.
+% The command will increase the value of the counter
+% used by \cs{tag_struct_parent_int:}.
+% \end{function}
+% \begin{function}{\tag_struct_parent_int:}
+% \begin{syntax}
+% \cs{tag_struct_parent_int:}
+% \end{syntax}
+% This gives back the next free /StructParent number (assuming that it is
+% together with \cs{tag_struct_insert_annot:nn} which will increase the number.
+% \end{function}
+% \section{Public keys}
+% \subsection{Keys for the structure commands}
+% \begin{function}{tag}
+% This is required. The value of the key is normally one of the
+% standard types listed in section \ref{sec:new-tag}.
+% It is possible to setup new tags/types.
+% The value can also be of the form |type/NS|, where |NS| is the
+% shorthand of a declared name space.
+% Currently the names spaces |pdf|, |pdf2|, |mathml| and |user| are defined.
+% This allows to use a different name space than
+% the one connected by default to the tag. But normally this should not be needed.
+% \end{function}
+% \begin{function}{stash}
+% Normally a new structure inserts itself as a kid
+% into the currently active structure. This key prohibits this.
+% The structure is nevertheless from now on
+% \enquote{the current active structure}
+% and parent for following marked content and structures.
+% \end{function}
+% \begin{function}{label}
+% This key sets a label by which
+% one can use the structure later in another structure.
+% Internally the label name will start with \texttt{tagpdfstruct-}.
+% \end{function}
+% \begin{function}{title,title-o}
+% This keys allows to set the dictionary entry
+% \texttt{/Title} in the structure object.
+% The value is handled as verbatim string and hex encoded.
+% Commands are not expanded. |title-o| will expand the value once.
+% \end{function}
+%
+% \begin{function}{alttext,alttext-o}
+% This key inserts an \texttt{/Alt} value in the dictionary of structure object.
+% The value is handled as verbatim string and hex encoded.
+% |alttext-o| will expand the value once.
+% \end{function}
+% \begin{function}{actualtext,actualtext-o}
+% This key inserts an \texttt{/ActualText} value in the dictionary of structure object.
+% The value is handled as verbatim string and hex encoded.
+% |actualtext-o| will expand the value once.
+% \end{function}
+% \begin{function}{lang}
+% This key allows to set the language for a structure element. The value should be a bcp-identifier,
+% e.g. |de-De|.
+% \end{function}
+% \begin{function}{ref}
+% This key allows to add references to other structure elements,
+% it adds the |/Ref| array to the structure.
+% The value should be a comma separated list of structure labels
+% set with the |label| key. e.g. |ref={label1,label2}|.
+% \end{function}
+% \begin{function}{E}
+% This key sets the |/E| key, the expanded form of an
+% abbreviation or an acronym
+% (I couldn't think of a better name, so I sticked to E).
+% \end{function}
+% \begin{function}{AF,AFinline,AFinline-o}
+% \begin{syntax}
+% AF = \meta{object name}\\
+% AF-inline = \meta{text content}
+% \end{syntax}
+% These keys allows to reference an associated file in the structure element.
+% The value \meta{object name} should be the name of an object pointing
+% to the \texttt{/Filespec} dictionary as expected by
+% |\pdf_object_ref:n| from a current \texttt{l3kernel}.
+%
+% The value |AF-inline| is some text,
+% which is embedded in the PDF as a text file with mime type text/plain.
+% |AF-inline-o| is like |AF-inline| but expands the value once.
+%
+% Future versions will perhaps extend this to more mime types, but it is
+% still a research task to find out what is really needed.
+%
+% \end{function}
+%
+% \begin{function}{attribute}
+% This key takes as argument a comma list of attribute names
+% (use braces to protect the commas from the external key-val parser)
+% and allows to add one or more attribute dictionary entries in
+% the structure object. As an example
+% \begin{verbatim}
+% \tagstructbegin{tag=TH,attribute= TH-row}
+% \end{verbatim}
+% Attribute names and their content must be declared first in \cs{tagpdfsetup}.
+%
+% \end{function}
%
+% \begin{function}{attribute-class}
+% This key takes as argument a comma list of attribute class names
+% (use braces to protect the commas from the external key-val parser)
+% and allows to add one or more attribute classes to the structure object.
+%
+% Attribute class names and their content
+% must be declared first in \cs{tagpdfsetup}.
+% \end{function}
+% \subsection{Setup keys}
+% \begin{function}{newattribute}
+% \begin{syntax}
+% newattribute = \Arg{name}\Arg{Content}
+% \end{syntax}
+% This key can be used in the setup command \cs{tagpdfsetup} and allow to declare a
+% new attribute, which can be used as attribute or attribute class.
+% The value are two brace groups, the first contains the name, the second the content.
+% \begin{verbatim}
+% \tagpdfsetup
+% {
+% newattribute =
+% {TH-col}{/O /Table /Scope /Column},
+% newattribute =
+% {TH-row}{/O /Table /Scope /Row},
+% }
+% \end{verbatim}
+%
+% \end{function}
+% \end{documentation}
+% \begin{implementation}
% \begin{macrocode}
%<@@=tag>
-%<*struct>
-\ProvidesExplPackage {tagpdf-struct-code} {2021-06-14} {0.82}
+%<*header>
+\ProvidesExplPackage {tagpdf-struct-code} {2021-06-29} {0.9}
{part of tagpdf - code related to storing structure}
+%</header>
% \end{macrocode}
+% \section{Variables}
+% \begin{variable}{\c@g_@@_struct_abs_int}
+% Every structure will have a unique, absolute number.
% I will use a latex counter for the structure count
-% to have a chance to avoid double structures in align etc
+% to have a chance to avoid double structures in align etc.
+%
% \begin{macrocode}
+%<*package>
\newcounter { g_@@_struct_abs_int }
\int_gzero:N \c@g_@@_struct_abs_int
% \end{macrocode}
-% a sequence to store structnum -> the obj numbers
-% to allow easy mapping over the structures
+% \end{variable}
+%
+% \begin{variable}{\g_@@_struct_objR_seq}
+% a sequence to store mapping between the
+% structure number and the object number.
+% We assume that structure numbers are assign
+% consecutively and so the index of the seq can be used.
+% A seq allows easy mapping over the structures.
% \begin{macrocode}
\@@_seq_new:N \g_@@_struct_objR_seq
% \end{macrocode}
-% a sequence for the structure stack.
+% \end{variable}
+%
+% \begin{variable}{\g_@@_struct_stack_seq}
+% A stack sequence for the structure stack.
% When a sequence is opened it's number is put on the stack.
% \begin{macrocode}
\seq_new:N \g_@@_struct_stack_seq
\seq_gpush:Nn \g_@@_struct_stack_seq {0}
% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\g_@@_struct_tag_stack_seq}
% We will perhaps also need the tags. While it is possible to get them from the
% numbered stack, lets build a tag stack too.
% \begin{macrocode}
\seq_new:N \g_@@_struct_tag_stack_seq
\seq_gpush:Nn \g_@@_struct_tag_stack_seq {Root}
% \end{macrocode}
-%this variables will hold the number of top entry and the parent on the stack
+% \end{variable}
+%
+% \begin{variable}{\g_@@_struct_stack_current_tl,\l_@@_struct_stack_parent_tmpa_tl}
+% The global variable will hold the current structure number.
+% The local temporary variable will hold the parent when we fetch it from the stack.
% \begin{macrocode}
-\tl_new:N \l_@@_struct_stack_parent_tmp_tl
\tl_new:N \g_@@_struct_stack_current_tl
+\tl_new:N \l_@@_struct_stack_parent_tmpa_tl
% \end{macrocode}
-% I need at least one structure: the StructTreeRoot
+% \end{variable}
+%
+% I will need at least one structure: the StructTreeRoot
% normally it should have only one kid, e.g. the document element.
% The data of the StructTreeRoot and the StructElem are in properties:
-% \g_@@_struct_0_prop for the root
-% \g_@@_struct_N_prop, N >=1
-% they have all the keys
-% objnum - number,
-% Type - StructTreeRoot or StructElem
-% num - number (identical to the num in the name, or 0 for the root)
+% |\g_@@_struct_0_prop| for the root and
+% |\g_@@_struct_N_prop|, $N \geq =1$ for the other.
+%
+% This creates quite a number of properties, so perhaps we will have to
+% do this more efficiently in the future.
+%
+% All properties have at least the keys
+% \begin{description}
+% \item[Type] StructTreeRoot or StructElem
+% \end{description}
% and the keys from the two following lists
% (the root has a special set of properties).
% the values of the prop should be already escaped properly
% when the entries are created (title,lange,alt,E,actualtext)
+% \begin{variable}
+% {
+% \c_@@_struct_StructTreeRoot_entries_seq,
+% \c_@@_struct_StructElem_entries_seq
+% }
+% These seq contain the keys we support in the two object types.
+% They are currently no longer used, but are provided as documentation and
+% for potential future checks.
+% They should be adapted if there are changes in the PDF format.
% \begin{macrocode}
\seq_const_from_clist:Nn \c_@@_struct_StructTreeRoot_entries_seq
{%p. 857/858
@@ -79,7 +300,7 @@
K, % kid, dictionary or array of dictionaries
IDTree, % currently unused
ParentTree, % required,obj ref to the parent tree
- ParentTreeNextKey, %optional
+ ParentTreeNextKey, % optional
RoleMap,
ClassMap,
Namespaces
@@ -96,22 +317,55 @@
K, %kids
A, %attributes, probably unused
C, %class ""
- %R,
+ %R, %attribute revision number, irrelevant for us as we
+ % don't update/change existing PDF and (probably)
+ % deprecated in PDF 2.0
T, %title, value in () or <>
Lang, %language
Alt, % value in () or <>
- E, %abreviation
+ E, % abreviation
ActualText,
AF, %pdf 2.0, array of dict, associated files
NS, %pdf 2.0, dict, namespace
PhoneticAlphabet, %pdf 2.0
Phoneme %pdf 2.0
}
-
-% I need an output handler for each prop, to get expandable output
-% see https://tex.stackexchange.com/questions/424208/expandable-version-of-a-expl3-command/424213#424213
-
-\cs_new:Nn \@@_struct_output_prop_aux:nn %#1 num, #2 key
+% \end{macrocode}
+% \end{variable}
+%
+% \subsection{Variables used by the keys}
+% \begin{variable}{\g_@@_struct_tag_tl,\g_@@_struct_tag_NS_tl}
+% Use by the tag key to store the tag and the namespace.
+% \begin{macrocode}
+\tl_new:N \g_@@_struct_tag_tl
+\tl_new:N \g_@@_struct_tag_NS_tl
+% \end{macrocode}
+% \end{variable}
+% \begin{variable}{\l_@@_struct_key_label_tl}
+% This will hold the label value.
+% \begin{macrocode}
+\tl_new:N \l_@@_struct_key_label_tl
+% \end{macrocode}
+% \end{variable}
+% \begin{variable}{\l_@@_struct_elem_stash_bool}
+% This will keep track of the stash status
+% \begin{macrocode}
+\bool_new:N \l_@@_struct_elem_stash_bool
+% \end{macrocode}
+% \end{variable}
+% \section{Commands}
+%
+% The properties must be in some places handled expandably.
+% So I need an output handler for each prop, to get expandable output
+% see \url{https://tex.stackexchange.com/questions/424208}.
+% There is probably room here for a more efficient implementation.
+% TODO check if this can now be implemented with the pdfdict commands.
+% The property contains currently non pdf keys, but e.g. object numbers are
+% perhaps no longer needed as we have named object anyway.
+%
+% \begin{macro}{\@@_struct_output_prop_aux:nn,\@@_new_output_prop_handler:n}
+% \begin{macrocode}
+\cs_new:Npn \@@_struct_output_prop_aux:nn #1 #2 %#1 num, #2 key
{
\prop_if_in:cnT
{ g_@@_struct_#1_prop }
@@ -121,99 +375,113 @@
}
}
-\cs_new:Nn \@@_new_output_prop_handler:n
+\cs_new_protected:Npn \@@_new_output_prop_handler:n #1
{
\cs_new:cn { @@_struct_output_prop_#1:n }
{
\@@_struct_output_prop_aux:nn {#1}{##1}
}
}
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Initialization of the StructTreeRoot}
+% The first structure element, the StructTreeRoot is special, so
+% created manually. The underlying object is |@@/struct/0| which is currently
+% created in the tree code (TODO move it here).
+% The |ParentTree| and |RoleMap| entries are added at begin document
+% in the tree code as they refer to object which are setup in other parts of the
+% code. This avoid timing issues.
+%
+% \begin{macrocode}
+\tl_gset:Nn \g_@@_struct_stack_current_tl {0}
+% \end{macrocode}
-
-% the first one, the StructTreeRoot is special, so
-% created manually:
+%
+% \begin{variable}{g_@@_struct_0_prop,g_@@_struct_kids_0_seq}
+% \begin{macrocode}
\@@_prop_new:c { g_@@_struct_0_prop }
\@@_new_output_prop_handler:n {0}
-\tl_gset:Nn \g_@@_struct_stack_current_tl {0}
-
\@@_seq_new:c { g_@@_struct_kids_0_seq }
-% new
-\@@_prop_gput:cnx
- { g_@@_struct_0_prop }
- { objref}
- { \pdf_object_ref:n { @@/struct/0 } }
-
\@@_prop_gput:cnn
{ g_@@_struct_0_prop }
{ Type }
{ /StructTreeRoot }
-% the constants are defined in the tree code.
-\@@_prop_gput:cnx
- { g_@@_struct_0_prop }
- { ParentTree }
- { \pdf_object_ref:n { @@/tree/parenttree } }
-\@@_prop_gput:cnx
- { g_@@_struct_0_prop }
- { RoleMap }
- { \pdf_object_ref:n { @@/tree/rolemap } }
-
-\@@_prop_gput:cnn
- { g_@@_struct_0_prop }
- { entries }
- { StructTreeRoot }
-
-\@@_prop_gput:cnn
- { g_@@_struct_0_prop }
- { num }
- { 0 }
-%Namespaces are pdf 2.0 but it doesn't harm to have an empty entry
+% \end{macrocode}
+% Namespaces are pdf 2.0 but it doesn't harm
+% to have an empty entry. We could add a test, but if the code moves into
+% the kernel, timing could get tricky.
+% \begin{macrocode}
\@@_prop_gput:cnx
{ g_@@_struct_0_prop }
{ Namespaces }
{ \pdf_object_ref:n { @@/tree/namespaces } }
-
-
-% commands to store the kids
-% I don't compare the page objects number yet, but always add the /Pg key, perhaps later
-
-\cs_new:Nn \@@_struct_kid_mc_gput_right:nn %#1 structure num, #2 MCID absnum%
+% \end{macrocode}
+% \end{variable}
+% \subsection{Handlings kids}
+% Commands to store the kids. Kids in a structure can be a reference to a mc-chunk,
+% an object reference to another structure element, or a object reference to an
+% annotation (through an OBJR object).
+% \begin{macro}{\@@_struct_kid_mc_gput_right:nn}
+% The command to store an mc-chunk, this is a dictionary of type MCR.
+% It would be possible to write out the content directly as unnamed object
+% and to store only the object reference, but probably this would be slower,
+% and the PDF is more readable like this.
+% The code doesn't try to avoid the use of the /Pg key by checking page numbers.
+% That imho only slows down without much gain.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_struct_kid_mc_gput_right:nn #1 #2 %#1 structure num, #2 MCID absnum%
{
- %\@@_store_pdfpageref:Nn \l_tmpa_tl { \@@_ref_value:enn{mcid-#2}{tagabspage}{1} }
\@@_seq_gput_right:cx
{ g_@@_struct_kids_#1_seq }
{
<<
/Type \c_space_tl /MCR \c_space_tl
- /Pg %\c_space_tl \l_tmpa_tl \c_space_tl 0 \c_space_tl R \c_space_tl
+ /Pg
\c_space_tl
\pdf_pageobject_ref:n { \@@_ref_value:enn{mcid-#2}{tagabspage}{1} }
/MCID \c_space_tl \@@_ref_value:enn{mcid-#2}{tagmcid}{1}
>>
}
}
-
-\cs_new:Nn\@@_struct_kid_struct_gput_right:nn %#1 num of parent struct, #2 kid struct
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}
+% {
+% \@@_struct_kid_struct_gput_right:nn,\@@_struct_kid_struct_gput_right:xx
+% }
+% This commands adds a structure as kid. We only need to record the object
+% reference in the sequence.
+% \begin{macrocode}
+\cs_new_protected:Npn\@@_struct_kid_struct_gput_right:nn #1 #2 %#1 num of parent struct, #2 kid struct
{
\@@_seq_gput_right:cx
{ g_@@_struct_kids_#1_seq }
{
- \prop_item:cn
- { g_@@_struct_#2_prop }
- { objref }
+ \pdf_object_ref:n { @@/struct/#2 }
}
}
-\cs_new:Nn\@@_struct_kid_OBJR_gput_right:nn %#1 num of parent struct, #2 obj reference
+\cs_generate_variant:Nn \@@_struct_kid_struct_gput_right:nn {xx}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}
+% {\@@_struct_kid_OBJR_gput_right:nn,\@@_struct_kid_OBJR_gput_right:xx}
+% At last the command to add an OBJR object. This has to write an object first.
+% The first argument is the number of the parent structure, the second the
+% (expanded) object reference of the annotation.
+% \begin{macrocode}
+\cs_new_protected:Npn\@@_struct_kid_OBJR_gput_right:nn #1 #2 %#1 num of parent struct,
+ %#2 obj reference
{
- \pdf_object_unnamed_write:nx
+ \pdf_object_unnamed_write:nn
{ dict }
{
- /Type \c_space_tl /OBJR \c_space_tl
- /Obj~#2
+ /Type/OBJR/Obj~#2
}
\@@_seq_gput_right:cx
{ g_@@_struct_kids_#1_seq }
@@ -222,27 +490,43 @@
}
}
-\cs_generate_variant:Nn\@@_struct_kid_OBJR_gput_right:nn { nx }
+\cs_generate_variant:Nn\@@_struct_kid_OBJR_gput_right:nn { xx }
-\cs_new:Nn\@@_struct_exchange_kid_command:N %N= seq
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}
+% {\@@_struct_exchange_kid_command:N, \@@_struct_exchange_kid_command:c}
+% In luamode it can happen that a single kid in a structure is split at a page
+% break into two or more mcid. In this case the lua code has to convert
+% put the dictionary of the kid into an array. See issue 13 at tagpdf repo.
+% We exchange the dummy command for the kids to mark this case.
+% \begin{macrocode}
+\cs_new_protected:Npn\@@_struct_exchange_kid_command:N #1 %#1 = seq var
{
- \seq_gpop_left:NN #1 \l_tmpa_tl
+ \seq_gpop_left:NN #1 \l_@@_tmpa_tl
\regex_replace_once:nnN
{ \c{\@@_mc_insert_mcid_kids:n} }
{ \c{\@@_mc_insert_mcid_single_kids:n} }
- \l_tmpa_tl
- \seq_gput_left:NV #1 \l_tmpa_tl
+ \l_@@_tmpa_tl
+ \seq_gput_left:NV #1 \l_@@_tmpa_tl
}
\cs_generate_variant:Nn\@@_struct_exchange_kid_command:N { c }
-
-\cs_new:Nn \@@_struct_fill_kid_key:n %#1 is the struct num
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{ \@@_struct_fill_kid_key:n }
+% This command adds the kid info to the K entry. In lua mode the
+% content contains commands which are expanded later. The argument is the structure
+% number.
+%
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_struct_fill_kid_key:n #1 %#1 is the struct num
{
\int_case:nnF
{
\seq_count:c
{
- g_@@_struct_kids_\prop_item:cn{ g_@@_struct_#1_prop }{num}_seq
+ g_@@_struct_kids_#1_seq
}
}
{
@@ -251,17 +535,17 @@
{ 1 } % 1 kid, insert
{
% in this case we need a special command in
- %luamode to get the array right. See issue #13
+ % luamode to get the array right. See issue #13
\bool_if:NT\g_@@_mode_lua_bool
{
\@@_struct_exchange_kid_command:c
- {g_@@_struct_kids_\prop_item:cn{ g_@@_struct_#1_prop }{num}_seq}
+ {g_@@_struct_kids_#1_seq}
}
\@@_prop_gput:cnx { g_@@_struct_#1_prop } {K}
{
\seq_item:cn
{
- g_@@_struct_kids_\prop_item:cn{ g_@@_struct_#1_prop }{num}_seq
+ g_@@_struct_kids_#1_seq
}
{1}
}
@@ -273,7 +557,7 @@
[
\seq_use:cn
{
- g_@@_struct_kids_\prop_item:cn{ g_@@_struct_#1_prop }{num}_seq
+ g_@@_struct_kids_#1_seq
}
{
\c_space_tl
@@ -283,22 +567,25 @@
}
}
-% this command can be used for roots and structure elements
-% #1 is a num
-
-\tl_new:N \l_@@_struct_dict_content_tl
-
-\cs_new:Nn \@@_struct_get_dict_content:n
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\@@_struct_get_dict_content:nN}
+% This maps the dictionary content of a structure into a tl-var.
+% Basically it does what |\pdfdict_use:n| does.
+% TODO!! this looks over-complicated. Check if it can be done with pdfdict now.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_struct_get_dict_content:nN #1 #2 %#1: stucture num
{
- %\tl_set:Nn \l_@@_struct_dict_content_tl {<<}
- \tl_clear:N \l_@@_struct_dict_content_tl
+ \tl_clear:N #2
\seq_map_inline:cn
{
- c_@@_struct_\prop_item:cn{ g_@@_struct_#1_prop }{entries}_entries_seq
+ c_@@_struct_
+ \int_compare:nNnTF{#1}={0}{StructTreeRoot}{StructElem}
+ _entries_seq
}
{
\tl_put_right:Nx
- \l_@@_struct_dict_content_tl
+ #2
{
\prop_if_in:cnT
{ g_@@_struct_#1_prop }
@@ -308,35 +595,99 @@
}
}
}
- %\tl_put_right:Nn \l_@@_struct_dict_content_tl { >> }
}
-
-
-% #1 is the struct num
-\cs_new:Nn \@@_struct_write_obj:n
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\@@_struct_write_obj:n}
+% This writes out the structure object.
+% This is done in the finish code, in the tree module and
+% guarded by the tree boolean.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_struct_write_obj:n #1 % #1 is the struct num
{
- \prop_if_in:cnTF
- { g_@@_struct_#1_prop }
- { objref }
+ \pdf_object_if_exist:nTF { @@/struct/#1 }
{
\@@_struct_fill_kid_key:n { #1 }
- %\prop_show:c { g_@@_struct_#1_prop }
- \@@_struct_get_dict_content:n { #1 }
+ \@@_struct_get_dict_content:nN { #1 } \l_@@_tmpa_tl
\exp_args:Nx
\pdf_object_write:nx
{ @@/struct/#1 }
{
- \l_@@_struct_dict_content_tl
+ \l_@@_tmpa_tl
}
}
{
\msg_error:nnn { tag } { struct-no-objnum } { #1}
}
}
-
-% this command allows to get the current structure tag. We will need to handle nesting
-% P
-\cs_new:Nn \@@_get_data_struct_tag:
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\@@_struct_insert_annot:nn}
+% This is the command to insert an annotation into the structure.
+% It can probably be used for xform too.
+%
+% Annotations used as structure content must
+% \begin{enumerate}
+% \item add a StructParent integer to their dictionary
+% \item push the object reference as OBJR object in the structure
+% \item Add a Structparent/obj-nr reference to the parent tree.
+% \end{enumerate}
+% For a link this looks like this
+% \begin{verbatim}
+% \tag_struct_begin:n { tag=Link }
+% \tag_mc_begin:n { tag=Link }
+% (1) \pdfannot_dict_put:nnx
+% { link/URI }
+% { StructParent }
+% { \int_use:N\c@g_@@_parenttree_obj_int }
+% <start link> link text <stop link>
+% (2+3) \@@_struct_insert_annot:nn {obj ref}{parent num}
+% \tag_mc_end:
+% \tag_struct_end:
+% \end{verbatim}
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_struct_insert_annot:nn #1 #2 %#1 object reference to the annotation/xform
+ %#2 structparent number
+ {
+ \bool_if:NT \g_@@_active_struct_bool
+ {
+ %get the number of the parent structure:
+ \seq_get:NNF
+ \g_@@_struct_stack_seq
+ \l_@@_struct_stack_parent_tmpa_tl
+ {
+ \msg_error:nn { tag } { struct-faulty-nesting }
+ }
+ %put the obj number of the annot in the kid entry, this also creates
+ %the OBJR object
+ \@@_struct_kid_OBJR_gput_right:xx
+ {
+ \l_@@_struct_stack_parent_tmpa_tl
+ }
+ {
+ #1 %
+ }
+ % add the parent obj number to the parent tree:
+ \exp_args:Nnx
+ \@@_parenttree_add_objr:nn
+ {
+ #2
+ }
+ {
+ \pdf_object_ref:e { @@/struct/\l_@@_struct_stack_parent_tmpa_tl }
+ }
+ % increase the int:
+ \stepcounter{ g_@@_parenttree_obj_int }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_get_data_struct_tag:}
+% this command allows \cs{tag_get:n} to get the current
+% structure tag with the keyword |struct_tag|. We will need to handle nesting
+% \begin{macrocode}
+\cs_new:Npn \@@_get_data_struct_tag:
{
\exp_args:Ne
\tl_tail:n
@@ -344,28 +695,33 @@
\prop_item:cn {g_@@_struct_\g__tag_struct_stack_current_tl _prop}{S}
}
}
-
-% keys for the user commands
-% should I pass the values (e.g. the tag) through an escape command?
+% \end{macrocode}
+% \end{macro}
+%
+% \section{Keys}
+% This are the keys for the user commands.
% we store the tag in a variable. But we should be careful, it is only reliable
-% at the begin
-\tl_new:N \g_@@_struct_tag_tl
-\tl_new:N \g_@@_struct_tag_NS_tl
-\cs_generate_variant:Nn \seq_set_split:Nnn{Nne}
+% at the begin.
+% \begin{macro}
+% {
+% label,stash,tag,
+% title,title-o,
+% alttext,alttext-o,
+% actualtext,actualtext-o
+% lang,ref,E
+% }
+% \begin{macrocode}
\keys_define:nn { @@ / struct }
{
label .tl_set:N = \l_@@_struct_key_label_tl,
stash .bool_set:N = \l_@@_struct_elem_stash_bool,
tag .code:n = % S property
- {%%????????? \pdfescapename?? slash/not slash is here the question ...
- \seq_set_split:Nne \l_tmpa_seq { / } {#1/\prop_item:Nn\g__tag_role_tags_NS_prop{#1}}
- \tl_gset:Nx \g_@@_struct_tag_tl { \seq_item:Nn\l_tmpa_seq {1} }
- \tl_gset:Nx \g_@@_struct_tag_NS_tl { \seq_item:Nn\l_tmpa_seq {2} }
- \bool_if:NT \g_@@_check_tags_bool
- {
- \@@_check_structure_tag:N \g_@@_struct_tag_tl
- }
- \@@_prop_gput:cnx
+ {
+ \seq_set_split:Nne \l_@@_tmpa_seq { / } {#1/\prop_item:Nn\g__tag_role_tags_NS_prop{#1}}
+ \tl_gset:Nx \g_@@_struct_tag_tl { \seq_item:Nn\l_@@_tmpa_seq {1} }
+ \tl_gset:Nx \g_@@_struct_tag_NS_tl { \seq_item:Nn\l_@@_tmpa_seq {2} }
+ \@@_check_structure_tag:N \g_@@_struct_tag_tl
+ \@@_prop_gput:cnx
{ g_@@_struct_\int_eval:n {\c@g_@@_struct_abs_int}_prop }
{ S }
{ \pdf_name_from_unicode_e:n{ \g_@@_struct_tag_tl} } %
@@ -482,12 +838,17 @@
{ <\l_@@_tmpa_str> }
},
}
-
-% keys for AF keys, they rely on l3pdffile!
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{AF,AFinline,AFinline-o}
+% keys for the AF keys (associated files). They use commands from l3pdffile!
% The stream variants use txt as extension to get the mimetype.
+% TODO: check if this should be configurable. For math we will perhaps need another
+% extension.
+% \begin{macrocode}
\keys_define:nn { @@ / struct }
{
- AF .code:n = % T property
+ AF .code:n = % AF property
{
\pdf_object_if_exist:nTF {#1}
{
@@ -503,8 +864,7 @@
,AFinline .code:n =
{
\group_begin:
- \exp_args:Ne
- \pdf_object_if_exist:nF {@@/fileobj\int_use:N\c@g_@@_struct_abs_int}
+ \pdf_object_if_exist:eF {@@/fileobj\int_use:N\c@g_@@_struct_abs_int}
{
\pdffile_embed_stream:nxx
{#1}
@@ -520,8 +880,7 @@
,AFinline-o .code:n =
{
\group_begin:
- \exp_args:Ne
- \pdf_object_if_exist:nF {@@/fileobj\int_use:N\c@g_@@_struct_abs_int}
+ \pdf_object_if_exist:eF {@@/fileobj\int_use:N\c@g_@@_struct_abs_int}
{
\pdffile_embed_stream:oxx
{#1}
@@ -535,81 +894,70 @@
\group_end:
}
}
-
-\cs_new_protected:Nn \tag_struct_begin:n
+% \end{macrocode}
+% \end{macro}
+%
+% \section{User commands}
+%
+% \begin{macro}{\tag_struct_begin:n,\tag_struct_end:}
+% \begin{macrocode}
+\cs_new_protected:Npn \tag_struct_begin:n #1 %#1 key-val
{
- \group_begin:
- \int_gincr:N \c@g_@@_struct_abs_int
- \@@_prop_new:c { g_@@_struct_\int_eval:n { \c@g_@@_struct_abs_int }_prop }
- \@@_new_output_prop_handler:n {\int_eval:n { \c@g_@@_struct_abs_int }}
- \@@_seq_new:c { g_@@_struct_kids_\int_eval:n { \c@g_@@_struct_abs_int }_seq}
- %\@@_pdfreserveobjnum:N \l_tmpa_tl
- \exp_args:Ne
- \pdf_object_new:nn
- { @@/struct/\int_eval:n { \c@g_@@_struct_abs_int } }
- { dict }
- \@@_prop_gput:cnx
- { g_@@_struct_\int_eval:n { \c@g_@@_struct_abs_int }_prop }
- { objref}
+ \@@_check_if_active_struct:T
{
+ \group_begin:
+ \int_gincr:N \c@g_@@_struct_abs_int
+ \@@_prop_new:c { g_@@_struct_\int_eval:n { \c@g_@@_struct_abs_int }_prop }
+ \@@_new_output_prop_handler:n {\int_eval:n { \c@g_@@_struct_abs_int }}
+ \@@_seq_new:c { g_@@_struct_kids_\int_eval:n { \c@g_@@_struct_abs_int }_seq}
\exp_args:Ne
- \pdf_object_ref:n
- {@@/struct/\int_eval:n { \c@g_@@_struct_abs_int }}
- }
-% \prop_show:c { g_@@_struct_\int_eval:n { \c@g_@@_struct_abs_int }_prop }
- \@@_prop_gput:cnx
- { g_@@_struct_\int_eval:n { \c@g_@@_struct_abs_int }_prop }
- { num}
- { \int_eval:n { \c@g_@@_struct_abs_int } }
- \@@_prop_gput:cno
- { g_@@_struct_\int_eval:n { \c@g_@@_struct_abs_int }_prop }
- { Type }
- { /StructElem }
- \@@_prop_gput:cno
- { g_@@_struct_\int_eval:n { \c@g_@@_struct_abs_int }_prop }
- { entries }
- { StructElem }
- \keys_set:nn { @@ / struct} { #1 }
- \@@_check_structure_has_tag:n { \int_eval:n {\c@g_@@_struct_abs_int} }
- \tl_if_empty:NF
- \l_@@_struct_key_label_tl
- {
- \@@_ref_label:en{tagpdfstruct-\l_@@_struct_key_label_tl}{struct}
- }
- %get the potential parent from the stack:
- \seq_get:NNF
- \g_@@_struct_stack_seq
- \l_@@_struct_stack_parent_tmp_tl
- {
- \msg_error:nn { tag } { struct-faulty-nesting }
- }
- \seq_gpush:NV \g_@@_struct_stack_seq \c@g_@@_struct_abs_int
- \seq_gpush:NV \g_@@_struct_tag_stack_seq \g_@@_struct_tag_tl
- \tl_gset:NV \g_@@_struct_stack_current_tl \c@g_@@_struct_abs_int
- %\seq_show:N \g_@@_struct_stack_seq
- \bool_if:NF
- \l_@@_struct_elem_stash_bool
- {%set the parent
- \@@_prop_gput:cnx
- { g_@@_struct_\int_eval:n {\c@g_@@_struct_abs_int}_prop }
- { P }
+ \pdf_object_new:nn
+ { @@/struct/\int_eval:n { \c@g_@@_struct_abs_int } }
+ { dict }
+ \@@_prop_gput:cno
+ { g_@@_struct_\int_eval:n { \c@g_@@_struct_abs_int }_prop }
+ { Type }
+ { /StructElem }
+ \keys_set:nn { @@ / struct} { #1 }
+ \@@_check_structure_has_tag:n { \int_eval:n {\c@g_@@_struct_abs_int} }
+ \tl_if_empty:NF
+ \l_@@_struct_key_label_tl
+ {
+ \@@_ref_label:en{tagpdfstruct-\l_@@_struct_key_label_tl}{struct}
+ }
+ %get the potential parent from the stack:
+ \seq_get:NNF
+ \g_@@_struct_stack_seq
+ \l_@@_struct_stack_parent_tmpa_tl
{
- \prop_item:cn
- { g_@@_struct_\l_@@_struct_stack_parent_tmp_tl _prop}
- { objref }
+ \msg_error:nn { tag } { struct-faulty-nesting }
+ }
+ \seq_gpush:NV \g_@@_struct_stack_seq \c@g_@@_struct_abs_int
+ \seq_gpush:NV \g_@@_struct_tag_stack_seq \g_@@_struct_tag_tl
+ \tl_gset:NV \g_@@_struct_stack_current_tl \c@g_@@_struct_abs_int
+ %\seq_show:N \g_@@_struct_stack_seq
+ \bool_if:NF
+ \l_@@_struct_elem_stash_bool
+ {%set the parent
+ \@@_prop_gput:cnx
+ { g_@@_struct_\int_eval:n {\c@g_@@_struct_abs_int}_prop }
+ { P }
+ {
+ \pdf_object_ref:e { @@/struct/\l_@@_struct_stack_parent_tmpa_tl }
+ }
+ %record this structure as kid:
+ %\tl_show:N \g_@@_struct_stack_current_tl
+ %\tl_show:N \l_@@_struct_stack_parent_tmpa_tl
+ \@@_struct_kid_struct_gput_right:xx
+ { \l_@@_struct_stack_parent_tmpa_tl }
+ { \g_@@_struct_stack_current_tl }
+ %\prop_show:c { g_@@_struct_\g_@@_struct_stack_current_tl _prop }
+ %\seq_show:c {g_@@_struct_kids_\l_@@_struct_stack_parent_tmpa_tl _seq}
}
- %record this structure as kid:
- %\tl_show:N \g_@@_struct_stack_current_tl
- %\tl_show:N \l_@@_struct_stack_parent_tmp_tl
- \@@_struct_kid_struct_gput_right:nn
- { \l_@@_struct_stack_parent_tmp_tl }
- { \g_@@_struct_stack_current_tl }
%\prop_show:c { g_@@_struct_\g_@@_struct_stack_current_tl _prop }
- %\seq_show:c {g_@@_struct_kids_\l_@@_struct_stack_parent_tmp_tl _seq}
- }
- %\prop_show:c { g_@@_struct_\g_@@_struct_stack_current_tl _prop }
- %\seq_show:c {g_@@_struct_kids_\l_@@_struct_stack_parent_tmp_tl _seq}
- \group_end:
+ %\seq_show:c {g_@@_struct_kids_\l_@@_struct_stack_parent_tmpa_tl _seq}
+ \group_end:
+ }
}
@@ -617,149 +965,145 @@
{ %take the current structure num from the stack:
%the objects are written later, lua mode hasn't all needed info yet
%\seq_show:N \g_@@_struct_stack_seq
- \seq_gpop:NN \g_@@_struct_tag_stack_seq \l_tmpa_tl
- \seq_gpop:NNTF \g_@@_struct_stack_seq \l_tmpa_tl
+ \@@_check_if_active_struct:T
{
- \int_compare:nNnT {\l_@@_loglevel_int} > { 0 }
+ \seq_gpop:NN \g_@@_struct_tag_stack_seq \l_@@_tmpa_tl
+ \seq_gpop:NNTF \g_@@_struct_stack_seq \l_@@_tmpa_tl
{
\@@_check_info_closing_struct:o { \g_@@_struct_stack_current_tl }
}
- }
- { \@@_check_no_open_struck: }
- % get the previous one, shouldn't be empty as the root should be there
- \seq_get:NNTF \g_@@_struct_stack_seq \l_tmpa_tl
- {
- \tl_gset:NV \g_@@_struct_stack_current_tl \l_tmpa_tl
- }
- {
- \@@_check_no_open_struck:
- }
- \seq_get:NNT \g_@@_struct_tag_stack_seq \l_tmpa_tl
- {
- \tl_gset:NV \g_@@_struct_tag_tl \l_tmpa_tl
- }
- }
-
-
-
-\cs_new_protected:Nn \tag_struct_use:n %#1 is the label
- {
- \prop_if_exist:cTF
- { g_@@_struct_\@@_ref_value:enn{tagpdfstruct-#1}{tagstruct}{unknown}_prop } %??????????
- {
- \@@_check_struct_used:n {#1}
- %add the label structure as kid to the current structure (can be the root)
- \@@_struct_kid_struct_gput_right:nn
- { \g_@@_struct_stack_current_tl }
- { \@@_ref_value:enn{tagpdfstruct-#1}{tagstruct}{0} }
- %add the current structure to the labeled one as parents
- \@@_prop_gput:cnx
- { g_@@_struct_\@@_ref_value:enn{tagpdfstruct-#1}{tagstruct}{0}_prop }
- { P }
+ { \@@_check_no_open_struct: }
+ % get the previous one, shouldn't be empty as the root should be there
+ \seq_get:NNTF \g_@@_struct_stack_seq \l_@@_tmpa_tl
{
- \prop_item:cn
- { g_@@_struct_\g_@@_struct_stack_current_tl _prop}
- { objref }
+ \tl_gset:NV \g_@@_struct_stack_current_tl \l_@@_tmpa_tl
}
- }
- {
- \msg_warning:nnn{ tag }{struct-label-unknown}{#1}
- }
- }
-
-
-%%%% Code to tag annotations like links.
-% Annotations used as structure content must
-% (1) add a StructParent integer to their dictionary
-% (2) push the object reference as OBJR object in the structure
-% (3) Add a Stuctparent/obj-nr reference to the parent three.
-% For a link this looks like this
-% \tag_struct_begin:n { tag=Link }
-% \tag_mc_begin:n { tag=Link }
-% (1) \pdfannot_dict_put:nnx
-% { link/URI }
-% { StructParent }
-% { \int_use:N\c@g_@@_parenttree_obj_int }
-% <start link> link text <stop link>
-% (2+3) \@@_struct_insert_annot:nn {obj ref}{parent num}
-% \tag_mc_end:
-% \tag_struct_end:
-%
-%%%% this works for url, see exp-link.pdf.
-%%%% it must be checked for other links
-
-
-% this will probably be used for xform too, but then we can rename it.
-\cs_new_protected:Npn \@@_struct_insert_annot:nn #1 #2 %#1 object reference to the annotation/xform
- %#2 structparent number
- {
- \bool_if:NT \g_@@_active_struct_bool
- {
- %get the number of the parent link structure:
- \seq_get:NNF
- \g_@@_struct_stack_seq
- \l_@@_struct_stack_parent_tmp_tl
{
- \msg_error:nn { tag } { struct-faulty-nesting }
+ \@@_check_no_open_struct:
}
- %put the obj number of link annot in the kid entry:
- \@@_struct_kid_OBJR_gput_right:nx
+ \seq_get:NNT \g_@@_struct_tag_stack_seq \l_@@_tmpa_tl
{
- \l_@@_struct_stack_parent_tmp_tl
+ \tl_gset:NV \g_@@_struct_tag_tl \l_@@_tmpa_tl
}
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\tag_struct_use:n}
+% This command allows to use a stashed structure in another place.
+% TODO: decide how it should be guarded. Probably by the struct-check.
+% \begin{macrocode}
+\cs_new_protected:Nn \tag_struct_use:n %#1 is the label
+ {
+ \@@_check_if_active_struct:T
+ {
+ \prop_if_exist:cTF
+ { g_@@_struct_\@@_ref_value:enn{tagpdfstruct-#1}{tagstruct}{unknown}_prop } %
{
- #1 %
- }
- % add the parent obj number to the parent tree:
- \exp_args:Nnx
- \@@_parenttree_add_objr:nn
- {
- #2
+ \@@_check_struct_used:n {#1}
+ %add the label structure as kid to the current structure (can be the root)
+ \@@_struct_kid_struct_gput_right:xx
+ { \g_@@_struct_stack_current_tl }
+ { \@@_ref_value:enn{tagpdfstruct-#1}{tagstruct}{0} }
+ %add the current structure to the labeled one as parents
+ \@@_prop_gput:cnx
+ { g_@@_struct_\@@_ref_value:enn{tagpdfstruct-#1}{tagstruct}{0}_prop }
+ { P }
+ {
+ \pdf_object_ref:e { @@/struct/\g_@@_struct_stack_current_tl }
+ }
}
{
- \prop_item:cn
- { g_@@_struct_\l_@@_struct_stack_parent_tmp_tl _prop }
- { objref }
+ \msg_warning:nnn{ tag }{struct-label-unknown}{#1}
}
- % increase the int:
- \stepcounter{ g_@@_parenttree_obj_int }
}
}
-
-
-
-% Code to add an annot to the structure.
-% This is for example needed for widget annotations and form field
-% It reuses the command used by links
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}
+% {
+% \tag_struct_insert_annot:nn,
+% \tag_struct_insert_annot:xx
+% }
+% \begin{macro}[EXP]
+% {
+% \tag_struct_parent_int:
+% }
+% This are the user command to insert annotations. They must be used
+% together to get the numbers right. They use a counter to the
+% |StructParent| and \cs{tag_struct_insert_annot:nn} increases the
+% counter given back by \cs{tag_struct_parent_int:}.
+%
+% It must be used together with |\tag_struct_parent_int:| to insert an
+% annotation.
+% TODO: decide how it should be guarded if tagging is deactivated.
+% \begin{macrocode}
\cs_new_protected:Npn \tag_struct_insert_annot:nn #1 #2 %#1 should be an object reference
%#2 struct parent num
{
- \@@_struct_insert_annot:nn {#1}{#2}
+ \@@_check_if_active_struct:T
+ {
+ \@@_struct_insert_annot:nn {#1}{#2}
+ }
}
\cs_generate_variant:Nn \tag_struct_insert_annot:nn {xx}
\cs_new:Npn \tag_struct_parent_int: {\int_use:c { c@g_@@_parenttree_obj_int }}
-%</struct>
+%</package>
% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \section{Attributes and attribute classes}
% \begin{macrocode}
-%<*attr>
-\ProvidesExplPackage {tagpdf-attr-code} {2021-06-14} {0.82}
+%<*header>
+\ProvidesExplPackage {tagpdf-attr-code} {2021-06-29} {0.9}
{part of tagpdf - code related to attributes and attribute classes}
-
-% the obj is written in tagpdf-tree-code.
-
-\seq_new:N \g_@@_attr_class_used_seq
-\prop_new:N \g_@@_attr_objref_prop %will contain obj num of used attributes
-
+%</header>
+% \end{macrocode}
+% \subsection{Variables}
+% \begin{variable}
+% {
+% ,\g_@@_attr_entries_prop
+% ,\g_@@_attr_class_used_seq
+% ,\g_@@_attr_objref_prop
+% ,\l_@@_attr_value_tl
+% }
+% |\g_@@_attr_entries_prop| will store attribute names and their dictionary content.\\
+% |\g_@@_attr_class_used_seq| will hold the attributes which have been used as
+% class name.
+% |\l_@@_attr_value_tl| is used to build the attribute array or key.
+% Everytime an attribute is used for the first time, and object is created
+% with its content, the name-object reference relation is stored in
+% |\g_@@_attr_objref_prop|
+% \begin{macrocode}
+%<*package>
\prop_new:N \g_@@_attr_entries_prop
-\tl_new:N \g_@@_attr_class_content_tl
-\tl_new:N \l_@@_attr_objtmp_tl
+\seq_new:N \g_@@_attr_class_used_seq
\tl_new:N \l_@@_attr_value_tl
-
-
-\cs_new_protected:Nn \@@_attr_new_entry:nn %#1:name, #2: content
+\prop_new:N \g_@@_attr_objref_prop %will contain obj num of used attributes
+% \end{macrocode}
+% \end{variable}
+% \subsection{Commands and keys}
+% \begin{macro}{\@@_attr_new_entry:nn,newattribute}
+% This allows to define attributes. Defined attributes
+% are stored in a global property. |newattribute| expects
+% two brace group, the name and the content. The content typically
+% needs an |/O| key for the owner. An example look like
+% this.
+% \begin{verbatim}
+% \tagpdfsetup
+% {
+% newattribute =
+% {TH-col}{/O /Table /Scope /Column},
+% newattribute =
+% {TH-row}{/O /Table /Scope /Row},
+% }
+% \end{verbatim}
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_attr_new_entry:nn #1 #2 %#1:name, #2: content
{
\prop_gput:Nnn \g_@@_attr_entries_prop
{#1}{#2}
@@ -772,16 +1116,19 @@
\@@_attr_new_entry:nn #1
}
}
-
-
-% the key for the structure:
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{attribute-class}
+% attribute-class has to store the used attribute names so that
+% they can be added to the ClassMap later.
+% \begin{macrocode}
\keys_define:nn { @@ / struct }
{
attribute-class .code:n =
{
- \clist_set:No \l_tmpa_clist { #1 }
- \seq_set_from_clist:NN \l_tmpa_seq \l_tmpa_clist
- \seq_map_inline:Nn \l_tmpa_seq
+ \clist_set:No \l_@@_tmpa_clist { #1 }
+ \seq_set_from_clist:NN \l_@@_tmpa_seq \l_@@_tmpa_clist
+ \seq_map_inline:Nn \l_@@_tmpa_seq
{
\prop_if_in:NnF \g_@@_attr_entries_prop {##1}
{
@@ -789,38 +1136,41 @@
}
\seq_gput_left:Nn\g_@@_attr_class_used_seq { ##1}
}
- \seq_set_map:NNn \l_tmpb_seq \l_tmpa_seq
+ \seq_set_map:NNn \l_@@_tmpb_seq \l_@@_tmpa_seq
{
/##1
}
- \tl_set:Nx \l_tmpa_tl
+ \tl_set:Nx \l_@@_tmpa_tl
{
- \int_compare:nT { \seq_count:N \l_tmpa_seq > 1 }{[}
- \seq_use:Nn \l_tmpb_seq { \c_space_tl }
- \int_compare:nT { \seq_count:N \l_tmpa_seq > 1 }{]}
+ \int_compare:nT { \seq_count:N \l_@@_tmpa_seq > 1 }{[}
+ \seq_use:Nn \l_@@_tmpb_seq { \c_space_tl }
+ \int_compare:nT { \seq_count:N \l_@@_tmpa_seq > 1 }{]}
}
- \int_compare:nT { \seq_count:N \l_tmpa_seq > 0 }
+ \int_compare:nT { \seq_count:N \l_@@_tmpa_seq > 0 }
{
\@@_prop_gput:cnx
{ g_@@_struct_\int_eval:n {\c@g_@@_struct_abs_int}_prop }
{ C }
- { \l_tmpa_tl }
+ { \l_@@_tmpa_tl }
%\prop_show:c { g_@@_struct_\int_eval:n {\c@g_@@_struct_abs_int}_prop }
}
- }
+ }
}
-
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{attribute}
+% \begin{macrocode}
\keys_define:nn { @@ / struct }
{
attribute .code:n = % A property (attribute, value currently a dictionary)
{
- \clist_set:No \l_tmpa_clist { #1 }
- \seq_set_from_clist:NN \l_tmpa_seq \l_tmpa_clist
+ \clist_set:No \l_@@_tmpa_clist { #1 }
+ \seq_set_from_clist:NN \l_@@_tmpa_seq \l_@@_tmpa_clist
\tl_set:Nx \l_@@_attr_value_tl
{
- \int_compare:nT { \seq_count:N \l_tmpa_seq > 1 }{[}%]
+ \int_compare:nT { \seq_count:N \l_@@_tmpa_seq > 1 }{[}%]
}
- \seq_map_inline:Nn \l_tmpa_seq
+ \seq_map_inline:Nn \l_@@_tmpa_seq
{
\prop_if_in:NnF \g_@@_attr_entries_prop {##1}
{
@@ -844,7 +1194,7 @@
}
\tl_put_right:Nx \l_@@_attr_value_tl
{ %[
- \int_compare:nT { \seq_count:N \l_tmpa_seq > 1 }{]}%
+ \int_compare:nT { \seq_count:N \l_@@_tmpa_seq > 1 }{]}%
}
% \tl_show:N \l_@@_attr_value_tl
\@@_prop_gput:cnx
@@ -853,5 +1203,7 @@
{ \l_@@_attr_value_tl }
},
}
-%</attr>
+%</package>
% \end{macrocode}
+% \end{macro}
+% \end{implementation}
diff --git a/Master/texmf-dist/source/latex/tagpdf/tagpdf-tree.dtx b/Master/texmf-dist/source/latex/tagpdf/tagpdf-tree.dtx
index c3e5d6d71b2..6a1d3e95622 100644
--- a/Master/texmf-dist/source/latex/tagpdf/tagpdf-tree.dtx
+++ b/Master/texmf-dist/source/latex/tagpdf/tagpdf-tree.dtx
@@ -22,80 +22,144 @@
%
% for those people who are interested.
%
+%<*driver>
+\RequirePackage{pdfmanagement-testphase}
+\DeclareDocumentMetadata{}
+\makeatletter
+\declare@file@substitution{doc.sty}{doc-v3beta.sty}
+\makeatother
+\documentclass{l3doc}
+\usepackage{array,booktabs,caption}
+\hypersetup{pdfauthor=Ulrike Fischer,
+ pdftitle=tagpdf-tree module (tagpdf)}
+\begin{document}
+ \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
% \fi
+% \title{^^A
+% The \pkg{tagpdf-tree} module\\ Commands trees and main dictionaries ^^A
+% \\ Part of the tagpdf package
+% }
%
+% \author{^^A
+% Ulrike Fischer\thanks
+% {^^A
+% E-mail:
+% \href{mailto:fischer@troubleshooting-tex.de}
+% {fischer@troubleshooting-tex.de}^^A
+% }^^A
+% }
+%
+% \date{Version 0.9, released 2021-06-29}
+% \maketitle
+% \begin{implementation}
% \begin{macrocode}
%<@@=tag>
-%<*tree>
-\ProvidesExplPackage {tagpdf-tree-code} {2021-06-14} {0.82}
+%<*header>
+\ProvidesExplPackage {tagpdf-tree-code} {2021-06-29} {0.9}
{part of tagpdf - code related to writing trees and dictionaries to the pdf}
-
-%this does the actual finishing:
-%Is \AddToHook{enddocument/end} the best places??
+%</header>
+% \end{macrocode}
+% \section{Trees, pdfmanagement and finalization code}
+%
+% The code to finish the structure is in a hook.
+% This will perhaps at the end be a kernel hook.
+% TODO check right place for the code
+% The pdfmanagement code is the kernel hook after
+% shipout/lastpage so all code affecting it should be before.
+% Objects can be written later, at least in pdf mode.
+% \begin{macrocode}
+%<*package>
\hook_gput_code:nnn{begindocument}{tagpdf}
{
\bool_if:NT \g_@@_active_tree_bool
{
\sys_if_output_pdf:TF
{
- \AddToHook{enddocument/end} { \tag_finish_structure: }
+ \AddToHook{enddocument/end} { \@@_finish_structure: }
}
{
- \AddToHook{shipout/lastpage} { \tag_finish_structure: }
+ \AddToHook{shipout/lastpage} { \@@_finish_structure: }
}
}
}
-
-
-% the StructTreeRoot
-% we better get the object number in any case:
-% deprecated
-%\@@_pdfreserveobjnum:N \l_tmpa_tl
-%\tl_const:Nx \c_@@_tree_obj_structtreeroot_tl { \l_tmpa_tl }
-
-%new
+% \end{macrocode}
+% \subsection{Catalog: MarkInfo and StructTreeRoot}
+% The StructTreeRoot and the MarkInfo entry must be added to the catalog.
+% We do it late so that we can win, but before the pdfmanagement hook.
+% \begin{macro}{@@/struct/0}
+% This is the object for the root object, the StructTreeRoot
+% \begin{macrocode}
\pdf_object_new:nn { @@/struct/0 }{ dict }
-
- %need to think about the best place ...
-\hook_gput_code:nnn{begindocument}{tagpdf}
+% \end{macrocode}
+% \end{macro}
+% \begin{macrocode}
+\hook_gput_code:nnn{shipout/lastpage}{tagpdf}
{
- \bool_if:NT \g_@@_active_struct_bool
+ \bool_if:NT \g_@@_active_tree_bool
{
+ \pdfmanagement_add:nnn { Catalog / MarkInfo } { Marked } { true }
\pdfmanagement_add:nnx
{ Catalog }
{ StructTreeRoot }
{ \pdf_object_ref:n { @@/struct/0 } }
}
}
-\cs_new_protected:Nn \@@_tree_write_structtreeroot:
+% \end{macrocode}
+%
+% \subsection{Writing structure elements}
+% The following commands are needed to write out the structure.
+% \begin{macro}{\@@_tree_write_structtreeroot:}
+% This writes out the root object.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_tree_write_structtreeroot:
{
- \@@_struct_write_obj:n { 0 }
+ \@@_prop_gput:cnx
+ { g_@@_struct_0_prop }
+ { ParentTree }
+ { \pdf_object_ref:n { @@/tree/parenttree } }
+ \@@_prop_gput:cnx
+ { g_@@_struct_0_prop }
+ { RoleMap }
+ { \pdf_object_ref:n { @@/tree/rolemap } }
+ \@@_struct_write_obj:n { 0 }
}
-
-\cs_new_protected:Nn \@@_tree_write_structelements:
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_tree_write_structelements:}
+% This writes out the other struct elems, the absolute number is in the counter
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_tree_write_structelements:
{
\int_step_inline:nnnn {1}{1}{\c@g_@@_struct_abs_int}
{
- %\prop_show:c {g_@@_struct_##1_prop}
- \@@_struct_write_obj:n { ##1 } %write the object
+ \@@_struct_write_obj:n { ##1 }
}
}
-
-
-%the ParentTree
-% deprecated
-%\@@_pdfreserveobjnum:N \l_tmpa_tl
-%\tl_const:Nx \c_@@_tree_obj_parenttree_tl { \l_tmpa_tl }
-
-%new
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{ParentTree}
+% \begin{macro}{@@/tree/parenttree}
+% The object which will hold the parenttree
+% \begin{macrocode}
\pdf_object_new:nn { @@/tree/parenttree }{ dict }
-
-% we have two sets of entries in the parent tree:
-% page streams and real objects.
-% The numbers must be distinct and ordered
-% So we rely on abspage and put the real objects at the end
-% I use a counter to have a chance to get the correct number
-% if code is process twice.
+% \end{macrocode}
+% \end{macro}
+% The ParentTree maps numbers to objects or (if the number represents a page)
+% to arrays of objects. The numbers refer to two dictinct types of entries:
+% page streams and real objects like annotations.
+% The numbers must be distinct and ordered.
+% So we rely on abspage for the pages and put the real objects at the end.
+% We use a counter to have a chance to get the correct number
+% if code is processed twice.
+%
+% \begin{macro}{\c@g_@@_parenttree_obj_int}
+% This is a counter for the real objects. It starts at the absolute last page
+% value. It relies on l3ref.
+% \begin{macrocode}
\newcounter { g_@@_parenttree_obj_int }
\hook_gput_code:nnn{begindocument}{tagpdf}
{
@@ -103,39 +167,59 @@
\c@g_@@_parenttree_obj_int
{ \@@_ref_value_lastpage:nn{abspage}{100} }
}
-
-% we need to record the obj references:
-
+% \end{macrocode}
+% \end{macro}
+% We store the number/object references in a tl-var. If more structure is needed
+% one could switch to a seq.
+% \begin{variable}{ \g_@@_parenttree_objr_tl }
+% \begin{macrocode}
\tl_new:N \g_@@_parenttree_objr_tl
-
-\cs_new_protected:Nn \@@_parenttree_add_objr:nn %#1 Structparent number, #2 objref
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}{ \@@_parenttree_add_objr:nn }
+% This command stores a StructParent number and a objref into the tl var.
+% This is only for objects like annotations, pages are handled elsewhere.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_parenttree_add_objr:nn #1 #2 %#1 StructParent number, #2 objref
{
\tl_gput_right:Nx \g_@@_parenttree_objr_tl
{
#1 \c_space_tl #2 ^^J
}
}
-
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{variable}{\l_@@_parenttree_content_tl}
+% A tl-var which will get the page related parenttree content.
+% \begin{macrocode}
\tl_new:N \l_@@_parenttree_content_tl
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}{\@@_tree_fill_parenttree:}
+% This is the main command to assemble the page related entries of the parent tree.
+% It wanders through the pages and the mcid numbers and collects all mcid of one page.
+% \begin{macrocode}
-\cs_new_protected:Nn \@@_tree_fill_parenttree:
+\cs_new_protected:Npn \@@_tree_fill_parenttree:
{
\int_step_inline:nnnn{1}{1}{\@@_ref_value_lastpage:nn{abspage}{-1}} %not quite clear if labels are needed. See lua code
- { %page ##1\par
- \prop_clear:N \l_tmpa_prop
+ { %page ##1
+ \prop_clear:N \l_@@_tmpa_prop
\int_step_inline:nnnn{1}{1}{\@@_ref_value_lastpage:nn{tagmcabs}{-1}}
{
%mcid####1
- \int_compare:nT%F
+ \int_compare:nT
{\@@_ref_value:enn{mcid-####1}{tagabspage}{-1}=##1} %mcid is on current page
- {% yes\par
+ {% yes
\prop_put:Nxx
- \l_tmpa_prop
+ \l_@@_tmpa_prop
{\@@_ref_value:enn{mcid-####1}{tagmcid}{-1}}
{\prop_item:Nn \g_@@_mc_parenttree_prop {####1}}
}
}
- %\prop_show:N \l_tmpa_prop
\tl_put_right:Nx\l_@@_parenttree_content_tl
{
\int_eval:n {##1-1}\c_space_tl
@@ -144,16 +228,18 @@
\int_step_inline:nnnn
{0}
{1}
- { \prop_map_function:NN \l_tmpa_prop\@@_prop_count:nn -1 }
+ { \prop_count:N \l_@@_tmpa_prop -1 }
{
- \prop_get:NnNTF \l_tmpa_prop {####1} \l_tmpb_tl
- {% page#1:mcid##1:\l_tmpb_tl :content
+ \prop_get:NnNTF \l_@@_tmpa_prop {####1} \l_@@_tmpa_tl
+ {% page#1:mcid##1:\l_@@_tmpa_tl :content
\tl_put_right:Nx \l_@@_parenttree_content_tl
{
- \prop_item:cn { g_@@_struct_\l_tmpb_tl _prop } {objref}
+ \pdf_object_if_exist:eT { @@/struct/\l_@@_tmpa_tl }
+ {
+ \pdf_object_ref:e { @@/struct/\l_@@_tmpa_tl }
+ }
\c_space_tl
}
- %\tl_show:N \l_@@_parenttree_content_tl
}
{
\msg_warning:nn { tag } {tree-mcid-index-wrong}
@@ -166,13 +252,18 @@
}
}
}
-
-%lua mode must/can do it differently
-\cs_new_protected:Nn \@@_tree_lua_fill_parenttree:
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_tree_lua_fill_parenttree:}
+% This is a special variant for luatex.
+% lua mode must/can do it differently.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_tree_lua_fill_parenttree:
{
\tl_set:Nn \l_@@_parenttree_content_tl
{
- \directlua
+ \lua_now:e
{
ltx.@@.func.output_parenttree
(
@@ -181,10 +272,14 @@
}
}
}
-
-
-
-\cs_new_protected:Nn \@@_tree_write_parenttree:
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_tree_write_parenttree:}
+% This combines the two parts and writes out the object.
+% TODO should the check for lua be moved into the backend code?
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_tree_write_parenttree:
{
\bool_if:NTF \g_@@_mode_lua_bool
{
@@ -199,26 +294,44 @@
/Nums\c_space_tl [\l_@@_parenttree_content_tl]
}
}
-
-%the Rolemap tree
-
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Rolemap dictionary}
+% The Rolemap dictionary describes relations between new tags and standard types.
+% The main part here is handled in the role module, here we only define the
+% command which writes it to the PDF.
+% \begin{variable}{@@/tree/rolemap}
+% At first we reserve again an object.
+% \begin{macrocode}
\pdf_object_new:nn { @@/tree/rolemap }{ dict }
-
-\cs_new_protected:Nn \@@_tree_write_rolemap:
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}{\@@_tree_write_rolemap:}
+% This writes out the rolemap, basically it simply pushes out
+% the dictionary which has been filled in the role module.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_tree_write_rolemap:
{
\pdf_object_write:nx { @@/tree/rolemap }
{
\pdfdict_use:n{g_@@_role/RoleMap_dict}
}
}
-
-%classmap, should only be written, if values has been used
-
-\cs_new_protected:Nn \@@_tree_write_classmap:
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Classmap dictionary}
+% Classmap and attributes are setup in the struct module, here is only the
+% code to write it out. It should only done if values have been used.
+% \begin{macro}{\@@_tree_write_classmap:}
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_tree_write_classmap:
{
- \tl_gclear:N \g_@@_attr_class_content_tl
+ \tl_clear:N \l_@@_tmpa_tl
\seq_gremove_duplicates:N \g_@@_attr_class_used_seq
- \seq_set_map:NNn \l_tmpa_seq \g_@@_attr_class_used_seq
+ \seq_set_map:NNn \l_@@_tmpa_seq \g_@@_attr_class_used_seq
{
/##1\c_space_tl
<<
@@ -227,30 +340,37 @@
{##1}
>>
}
- \tl_gset:Nx \g_@@_attr_class_content_tl
+ \tl_set:Nx \l_@@_tmpa_tl
{
\seq_use:Nn
- \l_tmpa_seq
+ \l_@@_tmpa_seq
{ \iow_newline: }
}
\tl_if_empty:NF
- \g_@@_attr_class_content_tl
+ \l_@@_tmpa_tl
{
\pdf_object_new:nn { @@/tree/classmap }{ dict }
- % \@@_pdfreserveobjnum:N \l_tmpa_tl
- % \tl_const:Nx \c_@@_tree_obj_classmap_tl { \l_tmpa_tl }
\pdf_object_write:nx
{ @@/tree/classmap }
- { \g_@@_attr_class_content_tl }
+ { \l_@@_tmpa_tl }
\@@_prop_gput:cnx
{ g_@@_struct_0_prop }
{ ClassMap }
{ \pdf_object_ref:n { @@/tree/classmap } }
}
}
-
-% namespaces are only relevant for pdf2.0 but we don't care
+% \end{macrocode}
+% \end{macro}
+% \subsection{Namespaces}
+% Namespaces are handle in the role module, here is the code to write them out.
+% Namespaces are only relevant for pdf2.0 but we don't care, it doesn't harm.
+% \begin{variable}{@@/tree/namespaces}
+% \begin{macrocode}
\pdf_object_new:nn{ @@/tree/namespaces }{array}
+% \end{macrocode}
+% \end{variable}
+% \begin{macro}{\@@_tree_write_namespaces:}
+% \begin{macrocode}
\cs_new_protected:Npn \@@_tree_write_namespaces:
{
\prop_map_inline:Nn \g_@@_role_NS_prop
@@ -274,34 +394,47 @@
\prop_map_tokens:Nn \g_@@_role_NS_prop{\use_ii:nn}
}
}
-
-
-\cs_new_protected:Nn \tag_finish_structure:
+% \end{macrocode}
+% \end{macro}
+% \subsection{Finishing the structure}
+% This assembles the various parts.
+% TODO (when tabular are done or if someone requests it): IDTree
+% \begin{macro}{ \@@_finish_structure: }
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_finish_structure:
{
- \@@_tree_write_parenttree:
- \@@_tree_write_rolemap:
- \@@_tree_write_classmap:
- \@@_tree_write_namespaces:
- \@@_tree_write_structelements: %this is rather slow!!
- \@@_tree_write_structtreeroot:
+ \bool_if:NT\g_@@_active_tree_bool
+ {
+ \hook_use:n {tagpdf/finish/before}
+ \@@_tree_write_parenttree:
+ \@@_tree_write_rolemap:
+ \@@_tree_write_classmap:
+ \@@_tree_write_namespaces:
+ \@@_tree_write_structelements: %this is rather slow!!
+ \@@_tree_write_structtreeroot:
+ }
}
-
-
-%StructParents !!! we need a better hook for \g__pdf_BACKEND_thispage_shipout_tl!!
-% No actually
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{StructParents entry for Page}
+% We need to add to the Page resources the |StructParents| entry, this is simply the
+% absolute page number.
+% \begin{macrocode}
\hook_gput_code:nnn{begindocument}{tagpdf}
{
\bool_if:NT\g_@@_active_tree_bool
{
\hook_gput_code:nnn{shipout/before} { tagpdf/structparents }
{
- \pdfmanagement_add:nnx
- { Page }
- {StructParents}
- {\int_eval:n { \g_shipout_readonly_int}}
+ \pdfmanagement_add:nnx
+ { Page }
+ { StructParents }
+ { \int_eval:n { \g_shipout_readonly_int} }
}
}
}
-
-%</tree>
+%</package>
% \end{macrocode}
+% \end{implementation}
+% \PrintIndex
diff --git a/Master/texmf-dist/source/latex/tagpdf/tagpdf-user.dtx b/Master/texmf-dist/source/latex/tagpdf/tagpdf-user.dtx
new file mode 100644
index 00000000000..cbc6b79c334
--- /dev/null
+++ b/Master/texmf-dist/source/latex/tagpdf/tagpdf-user.dtx
@@ -0,0 +1,585 @@
+% \iffalse meta-comment
+%
+%% File: tagpdf-user.dtx
+%
+% Copyright (C) 2019-2021 Ulrike Fischer
+%
+% It may be distributed and/or modified under the conditions of the
+% LaTeX Project Public License (LPPL), either version 1.3c of this
+% license or (at your option) any later version. The latest version
+% of this license is in the file
+%
+% https://www.latex-project.org/lppl.txt
+%
+% This file is part of the "tagpdf bundle" (The Work in LPPL)
+% and all files in that bundle must be distributed together.
+%
+% -----------------------------------------------------------------------
+%
+% The development version of the bundle can be found at
+%
+% https://github.com/u-fischer/tagpdf
+%
+% for those people who are interested.
+%<*driver>
+\RequirePackage{pdfmanagement-testphase}
+\DeclareDocumentMetadata{}
+\makeatletter
+\declare@file@substitution{doc.sty}{doc-v3beta.sty}
+\makeatother
+\documentclass{l3doc}
+\usepackage{array,booktabs,caption}
+\hypersetup{pdfauthor=Ulrike Fischer,
+ pdftitle=tagpdf-user module (tagpdf)}
+\begin{document}
+ \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
+% \fi
+% \title{^^A
+% The \pkg{tagpdf-user} module\\ Code related to \LaTeX2e user commands and document commands ^^A
+% \\ Part of the tagpdf package
+% }
+%
+% \author{^^A
+% Ulrike Fischer\thanks
+% {^^A
+% E-mail:
+% \href{mailto:fischer@troubleshooting-tex.de}
+% {fischer@troubleshooting-tex.de}^^A
+% }^^A
+% }
+%
+% \date{Version 0.9, released 2021-06-29}
+% \maketitle
+% \begin{documentation}
+% \section{Setup commands}
+% \begin{function}{\tagpdfsetup}
+% \begin{syntax}
+% \cs{tagpdfsetup}\Arg{key val list}
+% \end{syntax}
+% This is the main setup command to adapt the behaviour of tagpdf.
+% It can be used in the preamble and in the document (but not all keys make sense there).
+%
+% \end{function}
+%
+% \section{Commands related to mc-chunks}
+% \begin{function}{\tagmcbegin, \tagmcend,\tagmcuse}
+% \begin{syntax}
+% \cs{tagmcbegin} \Arg{key-val}\\
+% \cs{tagmcend}\\
+% \cs{tagmcuse}\Arg{label}
+% \end{syntax}
+% These are wrappers around |\tag_mc_begin:n|, |\tag_mc_end:| and |\tag_mc_use:n|.
+% The commands and their argument are documentated in the \pkg{tagpdf-mc} module.
+% In difference to the expl3 commands, \cs{tagmcbegin} issues also an \cs{ignorespaces},
+% and \cs{tagmcend} will issue in horizontal mode an \cs{unskip}.
+% \end{function}
+%
+% \begin{function}{\tagmcifin}
+% \begin{syntax}
+% \cs{tagmcifin} \Arg{true code}\Arg{false code}
+% \end{syntax}
+% This is a wrapper around |\tag_mc_if_in:TF|.
+% and tests if an mc is open or not. It is mostly of
+% importance for pdflatex as lualatex doesn't mind much if a mc tag is not
+% correctly closed. Unlike the expl3 command it is not expandable.
+%
+% The command is probably not of much use and will perhaps disappear in future
+% versions. It normally makes more sense to push/pop an mc-chunk.
+% \end{function}
+%
+% \section{Commands related to structures}
+% \begin{function}{\tagstructbegin, \tagstructend,\tagstructuse}
+% \begin{syntax}
+% \cs{tagstructbegin} \Arg{key-val}\\
+% \cs{tagstructend}\\
+% \cs{tagstructuse}\Arg{label}
+% \end{syntax}
+% These are direct wrappers around |\tag_struct_begin:n|,
+% |\tag_struct_end:| and |\tag_struct_use:n|.
+% The commands and their argument are documentated in the \pkg{tagpdf-struct} module.
+% \end{function}
+
+
+
+% \section{Debugging}
+% \begin{function}{\ShowTagging}
+% \begin{syntax}
+% \cs{ShowTagging} \Arg{key-val}
+% \end{syntax}
+% This is a generic function to output various debugging helps. It not
+% necessarly stops the compilation. The keys and their function are described below.
+% \end{function}
+%
+% \begin{function}{mc-data}
+% \begin{syntax}
+% |mc-data| = \meta{number}
+% \end{syntax}
+% This key is (currently?) relevant for lua mode only.
+% It shows the data of all mc-chunks created so far.
+% It is accurate only after shipout (and perhaps a second compilation),
+% so typically should be issued after a
+% newpage. The value is a positive integer and sets the first mc-shown. If no value
+% is given, 1 is used and so all mc-chunks created so far are shown.
+% \end{function}
+% \begin{function}{mc-current}
+% \begin{syntax}
+% |mc-current|
+% \end{syntax}
+% This key shows the number and the tag of the currently open mc-chunk. If no
+% chunk is open it shows only the state of the abs count. It works in all mode,
+% but the output in luamode looks different.
+% \end{function}
+% \begin{function}{struct-stack}
+% \begin{syntax}
+% |struct-stack| = |log|\verb+|+|show|
+% \end{syntax}
+% This key shows the current structure stack. With |log| the info is only
+% written to the log-file, |show| stops the compilation and shows on the terminal.
+% If no value is used, then the default is |show|.
+% \end{function}
+%
+% \section{Extension commands}
+% The following commands and code parts are not core command of tagpdf.
+% They either provide work-arounds for missing functionality elsewhere,
+% or do a first step to apply tagpdf commands to document commands.
+%
+% The commands and keys should be view as experimental!
+%
+% This part will be regularly revisited to check if the code should go to a
+% better place or can be improved and so can change easily.
+%
+% \subsection{Fake space}
+% \begin{function}{\pdffakespace}
+% (lua-only) This provides a lua-version of the |\pdffakespace| primitive of
+% pdftex.
+% \end{function}
+%
+% \subsection{Paratagging}
+%
+% This is a first try to make use of the new paragraph hooks in a current LaTeX to
+% automate the tagging of paragraph. It requires sane paragraph nesting,
+% faulty code, e.g. a missing |\par| at the end of a low-level vbox can highly
+% confuse the tagging. The tags should be carefully checked if this is used.
+%
+% \begin{function}{paratagging,paratagging-show}
+% \begin{syntax}
+% |paratagging| = |true|\verb+|+|false|\\
+% |paratagging-show| = |true|\verb+|+|false|\\
+% \end{syntax}
+% This keys can be used in |\tagpdfsetup| and enable/disable paratagging.
+% |paratagging-show| puts small red numbers at the begin and end of a paragraph.
+% This is meant as a debugging help. The number are boxes and have a (tiny) height,
+% so they can affect typesetting.
+% \end{function}
+%
+% \begin{function}{\tagpdfparaOn,\tagpdfparaOff}
+% These commands allow to enable/disable para tagging too and are a bit
+% faster then |\tagpdfsetup|. But I'm not sure if the names are good.
+% \end{function}
+%
+% \subsection{Link tagging}
+% Links need a special structure and cross reference system.
+% This is added through hooks of the l3pdfannot module and will work
+% automatically if tagging is activated.
+%
+% Links should (probably) have an alternative text in the Contents
+% key. It is unclear which text this should be and
+% how to get it. Currently the code simply adds the fix texts |url| and |ref|.
+% Another text can be added by changing the dictionary value:
+% \begin{verbatim}
+% \pdfannot_dict_put:nnn
+% { link/GoTo }
+% { Contents }
+% { (ref) }
+% \end{verbatim}
+% \end{documentation}
+%
+% \begin{implementation}
+% \section{User commands and extensions of document commands}
+% \begin{macrocode}
+%<@@=tag>
+%<*header>
+\ProvidesExplPackage {tagpdf-user} {2021-06-29} {0.9}
+ {tagpdf - user commands}
+%</header>
+% \end{macrocode}
+% \section{Setup and preamble commands}
+% \begin{macro}{\tagpdfsetup}
+% \begin{macrocode}
+%<*package>
+\NewDocumentCommand \tagpdfsetup { m }
+ {
+ \keys_set:nn { @@ / setup } { #1 }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+
+% \section{Commands for the mc-chunks}
+% \begin{macro}{\tagmcbegin,\tagmcend,\tagmcuse }
+% \begin{macrocode}
+\NewDocumentCommand \tagmcbegin { m }
+ {
+ \tag_mc_begin:n {#1}%\ignorespaces
+ }
+
+
+\NewDocumentCommand \tagmcend { }
+ {
+ %\if_mode_horizontal: \unskip \fi: %
+ \tag_mc_end:
+ }
+
+\NewDocumentCommand \tagmcuse { m }
+ {
+ \tag_mc_use:n {#1}
+ }
+
+% \end{macrocode}
+% \end{macro}
+
+% \begin{macro}{\tagmcifinTF}
+% This is a wrapper around |\tag_mc_if_in:| and tests if an mc is open or not. It is mostly of
+% importance for pdflatex as lualatex doesn't mind much if a mc tag is not
+% correctly closed. Unlike the expl3 command it is not expandable.
+% \begin{macrocode}
+\NewDocumentCommand \tagmcifinTF { m m }
+ {
+ \tag_mc_if_in:TF { #1 } { #2 }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \section{Commands for the structure}
+% \begin{macro}{\tagstructbegin,\tagstructend,\tagstructuse }
+%
+% These are structure related user commands. There are direct wrapper around the
+% expl3 variants.
+% \begin{macrocode}
+\NewDocumentCommand \tagstructbegin { m }
+ {
+ \tag_struct_begin:n {#1}
+ }
+
+\NewDocumentCommand \tagstructend { }
+ {
+ \tag_struct_end:
+ }
+
+\NewDocumentCommand \tagstructuse { m }
+ {
+ \tag_struct_use:n {#1}
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}{\tagpdfifluatexTF,\tagpdfifluatexT,\tagpdfifpdftexTF}
+% I should deprecate them ...
+% \begin{macrocode}
+\cs_set_eq:NN\tagpdfifluatexTF \sys_if_engine_luatex:TF
+\cs_set_eq:NN\tagpdfifluatexT \sys_if_engine_luatex:T
+\cs_set_eq:NN\tagpdfifpdftexT \sys_if_engine_pdftex:T
+% \end{macrocode}
+% \end{macro}
+%
+% \section{Debugging}
+% \begin{macro}{\ShowTagging}
+% This is a generic command for various show commands.
+% It takes a keyval list, the various keys are implemented below.
+% \begin{macrocode}
+\NewDocumentCommand\ShowTagging { m }
+ {
+ \keys_set:nn { @@ / show }{ #1}
+
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{mc-data}
+% This key is (currently?) relevant for lua mode only.
+% It shows the data of all mc-chunks created so far.
+% It is accurate only after shipout, so typically should be issued after a
+% newpage. With the optional argument the minimal number can be set.
+% \begin{macrocode}
+\keys_define:nn { @@ / show }
+ {
+ mc-data .code:n =
+ {
+ \sys_if_engine_luatex:T
+ {
+ \lua_now:e{ltx.@@.trace.show_all_mc_data(#1,\@@_get_mc_abs_cnt:,0)}
+ }
+ }
+ ,mc-data .default:n = 1
+ }
+
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{mc-current}
+% This shows some info about the current mc-chunk. It works in generic and lua-mode.
+% \begin{macrocode}
+\keys_define:nn { @@ / show }
+ { mc-current .code:n =
+ {
+ \bool_if:NTF \g_@@_mode_lua_bool
+ {
+ \sys_if_engine_luatex:T
+ {
+ \int_compare:nNnTF
+ { -2147483647 }
+ =
+ {
+ \lua_now:e
+ {
+ tex.print
+ (tex.getattribute
+ (luatexbase.attributes.g__tag_mc_cnt_attr))
+ }
+ }
+ {
+ \lua_now:e
+ {
+ ltx.@@.trace.log
+ (
+ "mc-current:~no~MC~open,~current~abscnt
+ =\@@_get_mc_abs_cnt:"
+ ,0
+ )
+ texio.write_nl("")
+ }
+ }
+ {
+ \lua_now:e
+ {
+ ltx.@@.trace.log
+ (
+ "mc-current:~abscnt=\@@_get_mc_abs_cnt:=="
+ ..
+ tex.getattribute(luatexbase.attributes.g_@@_mc_cnt_attr)
+ ..
+ "~=>tag="
+ ..
+ tostring
+ (ltx.@@.func.get_tag_from
+ (tex.getattribute
+ (luatexbase.attributes.g_@@_mc_type_attr)))
+ ..
+ "="
+ ..
+ tex.getattribute
+ (luatexbase.attributes.g_@@_mc_type_attr)
+ ,0
+ )
+ texio.write_nl("")
+ }
+ }
+ }
+ }
+ {
+ \msg_note:nn{ tag }{ mc-current }
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{struct-stack}
+% \begin{macrocode}
+\keys_define:nn { @@ / show }
+ {
+ struct-stack .choice:
+ ,struct-stack / log .code:n = \seq_log:N \g_@@_struct_tag_stack_seq
+ ,struct-stack / show .code:n = \seq_show:N \g_@@_struct_tag_stack_seq
+ ,struct-stack .default:n = show
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \section{Commands to extend document commands}
+% The following commands and code parts are not core command of tagpdf.
+% The either provide work arounds for missing functionality elsewhere,
+% or do a first step to apply tagpdf commands to document commands.
+% This part should be regularly revisited to check if the code should go to a
+% better place or can be improved.
+% \subsection{Document structure}
+% \begin{macro}{\@@_add_document_structure:n,activate}
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_add_document_structure:n #1
+ {
+ \hook_gput_code:nnn{begindocument}{tagpdf}{\tagstructbegin{tag=#1}}
+ \hook_gput_code:nnn{tagpdf/finish/before}{tagpdf}{\tagstructend}
+ }
+\keys_define:nn { @@ / setup}
+ {
+ activate .code:n =
+ {
+ \keys_set:nn { @@ / setup }
+ { activate-mc,activate-tree,activate-struct }
+ \@@_add_document_structure:n {#1}
+ },
+ activate .default:n = Document
+ }
+% \end{macrocode}
+% \end{macro}
+% \subsection{Fake space}
+% \begin{macro}{\pdffakespace}
+% We need a luatex variant for |\pdffakespace|. This should probably go into
+% the kernel at some time.
+% \begin{macrocode}
+\sys_if_engine_luatex:T
+ {
+ \NewDocumentCommand\pdffakespace { }
+ {
+ \@@_fakespace:
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Paratagging}
+% The following are some simple commands to enable/disable paratagging.
+% Probably one should add some checks if we are already in a paragraph.
+%
+%
+% \begin{macro}{\l_@@_para_bool,\l_@@_para_show_bool,\g_@@_para_int}
+% At first some variables.
+% \begin{macrocode}
+\bool_new:N \l_@@_para_bool
+\bool_new:N \l_@@_para_show_bool
+\int_new:N \g_@@_para_int
+% \end{macrocode}
+% \end{macro}
+%
+%
+%\begin{macro}
+% {
+% paratagging,
+% paratagging-show,
+% }
+% These keys enable/disable locally paratagging, and the debug modus.
+% It can affect the typesetting if |paratagging-show| is used. The small numbers
+% are boxes and they have a (small) height.
+% \begin{macrocode}
+\keys_define:nn { @@ / setup }
+ {
+ paratagging .bool_set:N = \l_@@_para_bool,
+ paratagging-show .bool_set:N = \l_@@_para_show_bool,
+ }
+
+% \end{macrocode}
+% \end{macro}
+% This fills the para hooks with the needed code.
+% \begin{macrocode}
+\AddToHook{para/begin}
+ {
+ \int_gincr:N \g_@@_para_int
+ \bool_if:NT \l__tag_para_bool
+ {
+ \tag_struct_begin:n {tag=P}
+ \bool_if:NT \l_@@_para_show_bool
+ { \tag_mc_begin:n{artifact}
+ \llap{\color_select:n{red}\tiny\int_use:N\g_@@_para_int\ }
+ \tag_mc_end:
+ }
+ \tag_mc_begin:n {tag=P}
+ }
+ }
+\AddToHook{para/end}
+ {
+ \bool_if:NT \l__tag_para_bool
+ {
+ \tag_mc_end:
+ \bool_if:NT \l_@@_para_show_bool
+ { \tag_mc_begin:n{artifact}
+ \rlap{\color_select:n{red}\tiny\ \int_use:N\g_@@_para_int}
+ \tag_mc_end:
+ }
+ \tag_struct_end:
+ }
+ }
+% \end{macrocode}
+% \begin{macro}
+% {
+% \tagpdfparaOn,
+% \tagpdfparaOff
+% }
+% This two command switch para mode on and off. |\tagpdfsetup| could be used
+% too but is longer.
+% \begin{macrocode}
+\newcommand\tagpdfparaOn {\bool_set_true:N \l__tag_para_bool}
+\newcommand\tagpdfparaOff{\bool_set_false:N \l__tag_para_bool}
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Links}
+% We need to close and reopen mc-chunks around links.
+% Currently we handle URI and GoTo (internal) links.
+% Links should have an alternative text in the Contents
+% key. It is unclear which text this should be and
+% how to get it.
+% \begin{macrocode}
+\hook_gput_code:nnn
+ {pdfannot/link/URI/before}
+ {tagpdf}
+ {
+ \tag_mc_end_push:
+ \tag_struct_begin:n { tag=Link }
+ \tag_mc_begin:n { tag=Link }
+ \pdfannot_dict_put:nnx
+ { link/URI }
+ { StructParent }
+ { \tag_struct_parent_int: }
+ }
+
+\hook_gput_code:nnn
+ {pdfannot/link/URI/after}
+ {tagpdf}
+ {
+ \tag_struct_insert_annot:xx {\pdfannot_link_ref_last:}{\tag_struct_parent_int:}
+ \tag_mc_end:
+ \tag_struct_end:
+ \tag_mc_begin_pop:n{}
+ }
+
+\hook_gput_code:nnn
+ {pdfannot/link/GoTo/before}
+ {tagpdf}
+ {
+ \tag_mc_end_push:
+ \tag_struct_begin:n{tag=Link}
+ \tag_mc_begin:n{tag=Link}
+ \pdfannot_dict_put:nnx
+ { link/GoTo }
+ { StructParent }
+ { \tag_struct_parent_int: }
+ }
+
+\hook_gput_code:nnn
+ {pdfannot/link/GoTo/after}
+ {tagpdf}
+ {
+ \tag_struct_insert_annot:xx {\pdfannot_link_ref_last:}{\tag_struct_parent_int:}
+ \tag_mc_end:
+ \tag_struct_end:
+ \tag_mc_begin_pop:n{}
+
+ }
+
+% "alternative descriptions " for PAX3. How to get better text here??
+\pdfannot_dict_put:nnn
+ { link/URI }
+ { Contents }
+ { (url) }
+
+\pdfannot_dict_put:nnn
+ { link/GoTo }
+ { Contents }
+ { (ref) }
+
+% \end{macrocode}
+%</package>
+% \end{implementation}
+% \PrintIndex
diff --git a/Master/texmf-dist/source/latex/tagpdf/tagpdf.dtx b/Master/texmf-dist/source/latex/tagpdf/tagpdf.dtx
index 959e7c0097b..6b79f8e7aaf 100644
--- a/Master/texmf-dist/source/latex/tagpdf/tagpdf.dtx
+++ b/Master/texmf-dist/source/latex/tagpdf/tagpdf.dtx
@@ -2,7 +2,7 @@
%
%% File: tagpdf.dtx
%
-% Copyright (C) 2019-2020 Ulrike Fischer
+% Copyright (C) 2019-2021 Ulrike Fischer
%
% It may be distributed and/or modified under the conditions of the
% LaTeX Project Public License (LPPL), either version 1.3c of this
@@ -24,10 +24,12 @@
%
% \fi
%
+% \begin{implementation}
+% \section{Initialization and test if pdfmanagement is active.}
% \begin{macrocode}
%<@@=tag>
%<*package>
-\ProvidesExplPackage {tagpdf} {2021-06-14} {0.82}
+\ProvidesExplPackage {tagpdf} {2021-06-29} {0.9}
{ A package to experiment with pdf tagging }
\bool_if:nF
@@ -49,33 +51,36 @@
before~\string\documentclass
}
}
-
-%\debug_on:n{check-declarations,check-expressions,deprecation}
-
-%map internal tag to package name
+% \end{macrocode}
+% We map the internal module name \enquote{tag} to \enquote{tagpdf} in messages.
+% \begin{macrocode}
\prop_if_exist:NT \g_msg_module_name_prop
{
\prop_gput:Nnn \g_msg_module_name_prop { tag }{ tagpdf }
}
-
-% storing internal names to my name space:
-\cs_set_eq:NN \@@_tex_global:D \tex_global:D
-
-%%% package options
+% \end{macrocode}
+%\section{Package options}
+% There are only two options to switch for luatex between generic and luamode,
+% TODO try to get rid of them.
+% \begin{macrocode}
\bool_new:N\g_@@_mode_lua_bool
-
\DeclareOption {luamode} { \sys_if_engine_luatex:T { \bool_gset_true:N \g_@@_mode_lua_bool } }
\DeclareOption {genericmode}{ \bool_gset_false:N\g_@@_mode_lua_bool }
\ExecuteOptions{luamode}
\ProcessOptions
-
-%%% some packages
-%references use l3ref-tmp
+% \end{macrocode}
+% \section{Packages}
+% We need the temporary version of l3ref until this is in the kernel.
+% \begin{macrocode}
\RequirePackage{l3ref-tmp}
- %================
- % temporary code
- % ===============
- % faking the LastPage label:
+% \end{macrocode}
+%
+% \section{Temporary code}
+% This is code which will be removed when proper support exists in LaTeX
+% \subsection{a LastPage label}
+% See also issue \#2 in Accessible-xref
+% \begin{macro}{\@@_lastpagelabel:}
+% \begin{macrocode}
\cs_new_protected:Npn \@@_lastpagelabel:
{
\legacy_if:nT { @filesw }
@@ -94,8 +99,17 @@
\AddToHook{enddocument/afterlastpage}
{\@@_lastpagelabel:}
-
- % a command to override the general default. See issue in ref
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ref_value:nnn}
+% This allows to locally set a default value if the label or the attribute
+% doesn't exist.
+% See issue \#4 in Accessible-xref.
+% \begin{syntax}
+% \cs{ref_value:nnn}\Arg{label}\Arg{attribute}\Arg{Fallback default}
+% \end{syntax}
+% \begin{macrocode}
\cs_if_exist:NF \ref_value:nnn
{
\cs_new:Npn \ref_value:nnn #1#2#3
@@ -109,182 +123,216 @@
\tl_if_exist:cTF { g__ref_label_ #1 _ #2 _tl }
{ \tl_use:c { g__ref_label_ #1 _ #2 _tl } }
{
- % test if attribute exist at all?
#3
}
}
}
+% \end{macrocode}
+% \end{macro}
- %=============
- % attributes
- %=============
-\ref_attribute_gset:nnnn {tagstruct} {0}{now} { \int_use:N \c@g_@@_struct_abs_int }
-\ref_attribute_gset:nnnn {tagstructobj} {}{now}
- {
- \exp_args:Ne
- \pdf_object_if_exist:nT {@@/struct/\int_use:N \c@g__tag_struct_abs_int}
- {
- \pdf_object_ref:e{@@/struct/\int_use:N \c@g_@@_struct_abs_int}
- }
- }
- % replace by abspage??
-\ref_attribute_gset:nnnn {tagabspage}{0}{shipout}{ \int_use:N \g_shipout_readonly_int }
-\ref_attribute_gset:nnnn {tagmcabs } {0}{now} { \int_use:N \c@g_@@_MCID_abs_int }
-\ref_attribute_gset:nnnn {tagmcid } {0}{now} { \int_use:N \g_@@_MCID_tmp_bypage_int }
-%============
-% lists
-%============
-\clist_const:Nn \c_@@_refmc_clist {tagabspage,tagmcabs,tagmcid} %mc is new!!
+% \section{Variables}
+% \begin{variable}
+% {
+% \l_@@_tmpa_tl,
+% \l_@@_tmpa_str,
+% \l_@@_tmpa_prop,
+% \l_@@_tmpa_seq,
+% \l_@@_tmpb_seq,
+% \l_@@_tmpa_clist,
+% \l_@@_tmpa_int
+% }
+% A few temporary variables
+% \begin{macrocode}
+\tl_new:N \l_@@_tmpa_tl
+\str_new:N \l_@@_tmpa_str
+\prop_new:N \l_@@_tmpa_prop
+\seq_new:N \l_@@_tmpa_seq
+\seq_new:N \l_@@_tmpb_seq
+\clist_new:N \l_@@_tmpa_clist
+\int_new:N \l_@@_tmpa_int
+% \end{macrocode}
+% \end{variable}
+% Attribute lists for the label command. We have a list for
+% mc-related labels, and one for structures.
+% \begin{macro}{\c_@@_refmc_clist,\c_@@_refstruct_clist}
+% \begin{macrocode}
+\clist_const:Nn \c_@@_refmc_clist {tagabspage,tagmcabs,tagmcid}
\clist_const:Nn \c_@@_refstruct_clist {tagstruct,tagstructobj}
-%=================
-% command to set a label
-%================
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{variable}{\l_@@_loglevel_int}
+% This integer hold the log-level and so allows to
+% control the messages.
+% TODO: a list which log-level shows what is needed. The current behaviour
+% is quite ad-hoc.
+% \begin{macrocode}
+\int_new:N \l_@@_loglevel_int
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}
+% {
+% \g_@@_active_space_bool,
+% \g_@@_active_mc_bool,
+% \g_@@_active_tree_bool,
+% \g_@@_active_struct_bool
+% }
+% These booleans should help to control the global behaviour of tagpdf.
+% Ideally it should more or less do nothing if all are false.
+% The space-boolean controles the interword space code,
+% the mc-boolean activates \cs{tag_mc_begin:n},
+% the tree-boolean activates writing the finish code and the pdfmanagement related
+% commands, the struct-boolean activates the storing of the structure data.
+% In a normal document all should be active, the split is only there for
+% debugging purpose.
+% Also we assume currently that they are set only at begin document. But
+% if some control passing over groups are needed they could be perhaps
+% used in a document too.
+% TODO: check if they are used everywhere as needed and as wanted.
+% \begin{macrocode}
+\bool_new:N \g_@@_active_space_bool
+\bool_new:N \g_@@_active_mc_bool
+\bool_new:N \g_@@_active_tree_bool
+\bool_new:N \g_@@_active_struct_bool
+% \end{macrocode}
+% \end{variable}
+
+% \begin{variable}
+% {
+% \l_@@_active_mc_bool,
+% \l_@@_active_struct_bool
+% }
+% These booleans should help to control the \emph{local} behaviour of tagpdf.
+% In some cases it could e.g. be necessary to stop tagging completely.
+% As local booleans they respect groups.
+% TODO: check if they are used everywhere as needed and as wanted.
+% \begin{macrocode}
+\bool_new:N \l_@@_active_mc_bool
+\bool_set_true:N \l_@@_active_mc_bool
+\bool_new:N \l_@@_active_struct_bool
+\bool_set_true:N \l_@@_active_struct_bool
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\g_@@_tagunmarked_bool}
+% This boolean controls if the code should try to automatically
+% tag parts not in mc-chunk. It is currently only used in luamode.
+% It would be possible to used it in generic mode, but this would create
+% quite a lot empty artifact mc-chunks.
+% \begin{macrocode}
+\bool_new:N \g_@@_tagunmarked_bool
+% \end{macrocode}
+% \end{variable}
+%
+% \section{Variants of l3 commands}
+% \begin{macrocode}
+\prg_generate_conditional_variant:Nnn \pdf_object_if_exist:n {e}{T,F}
+\cs_generate_variant:Nn \pdf_object_ref:n {e}
+\cs_generate_variant:Nn \pdfannot_dict_put:nnn {nnx}
+\cs_generate_variant:Nn \pdffile_embed_stream:nnn {nxx,oxx}
+\cs_generate_variant:Nn \prop_gput:Nnn {Nxx}
+\cs_generate_variant:Nn \prop_put:Nnn {Nxx}
\cs_generate_variant:Nn \ref_label:nn { nv }
+\cs_generate_variant:Nn \seq_set_split:Nnn{Nne}
+\cs_generate_variant:Nn \str_set_convert:Nnnn {Nonn, Noon, Nnon }
+% \end{macrocode}
+
+% \section{Setup label attributes}
+% \begin{macro}{tagstruct,tagstructobj,tagabspage,tagmcabs,tagmcid}
+% This are attributes used by the label/ref system.
+% With structures we store the structure number |tagstruct|
+% and the object reference |tagstructobj|.
+% The second is needed to be able to reference a structure which hasn't been
+% created yet. The alternative would be to create the object in such cases,
+% but then we would have to check the object existence all the time.
+%
+% With mc-chunks we store the absolute page number |tagabspage|,
+% the absolute id |tagmcabc|, and the id on the page |tagmcid|.
+% \begin{macrocode}
+\ref_attribute_gset:nnnn { tagstruct } {0} { now }
+ { \int_use:N \c@g_@@_struct_abs_int }
+\ref_attribute_gset:nnnn { tagstructobj } {} { now }
+ {
+ \pdf_object_if_exist:eT {@@/struct/\int_use:N \c@g__tag_struct_abs_int}
+ {
+ \pdf_object_ref:e{@@/struct/\int_use:N \c@g_@@_struct_abs_int}
+ }
+ }
+\ref_attribute_gset:nnnn { tagabspage } {0} { shipout }
+ { \int_use:N \g_shipout_readonly_int }
+\ref_attribute_gset:nnnn { tagmcabs } {0} { now }
+ { \int_use:N \c@g_@@_MCID_abs_int }
+\ref_attribute_gset:nnnn {tagmcid } {0} { now }
+ { \int_use:N \g_@@_MCID_tmp_bypage_int }
+% \end{macrocode}
+% \end{macro}
+%
+% \section{Label commands}
+% \begin{macro}{\@@_ref_label:nn}
+% A version of |\ref_label:nn| to set a label
+% which takes a keyword |mc| or |struct| to
+% call the relevant lists.
+% TODO: check if |\@bsphack| and |\@esphack| make sense here.
+% \begin{macrocode}
\cs_new_protected:Npn \@@_ref_label:nn #1 #2 %#1 label, #2 name of list mc or struct
{
\@bsphack
\ref_label:nv {#1}{c_@@_ref#2_clist}
\@esphack
}
-%==============
-% command to retrieve the value
-%===============
+\cs_generate_variant:Nn \@@_ref_label:nn {en}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\@@_ref_value:nnn}
+% A local version to retrieve the value. It is a direct wrapper,
+% but to keep naming consistent \ldots. It uses the variant defined temporarly
+% above.
+% \begin{macrocode}
\cs_new:Npn \@@_ref_value:nnn #1 #2 #3 %#1 label, #2 attribute, #3 default
{
\ref_value:nnn {#1}{#2}{#3}
}
-%===============
-% the LastPage label has a different name, so we need a special command for now
-% =============
+\cs_generate_variant:Nn \@@_ref_value:nnn {enn}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_ref_value_lastpage:nn}
+% A command to retrieve the lastpage label, this will be adapted when there
+% is a proper, kernel lastpage label.
+% \begin{macrocode}
\cs_new:Npn \@@_ref_value_lastpage:nn #1 #2
{
\ref_value:nnn {@@_LastPage}{#1}{#2}
}
-
-% as ref doesn't expand label names we need variants:
-\cs_generate_variant:Nn \@@_ref_label:nn {en}
-\cs_generate_variant:Nn \@@_ref_value:nnn {enn}
-
-\RequirePackage{etoolbox}
-%\RequirePackage{l3pdf}
-%\RequirePackage{pdfescape} %check if needed
-%\RequirePackage{pdftexcmds}%check if needed (expandable commands!)
-
-%\RequirePackage{l3str-convert}
-\cs_generate_variant:Nn \str_set_convert:Nnnn {Nonn, Noon, Nnon }
-
-
-
-
-%%% tagpdfsetup,
-%%% TODO: checks need to be improved
-\int_new:N \l_@@_loglevel_int
-\tl_new:N \l_@@_tree_tabs_order_tl
-
-\keys_define:nn { @@ / setup }
- {
- activate-mc .bool_gset:N = \g_@@_active_mc_bool,
- activate-tree .bool_gset:N = \g_@@_active_tree_bool,
- activate-struct .bool_gset:N = \g_@@_active_struct_bool,
- activate-all .meta:n ={activate-mc,activate-tree,activate-struct},
- check-tags .bool_gset:N = \g_@@_check_tags_bool,
- check-tags .initial:n = true,
- log .choice:,
- log / none .code:n = {\int_set:Nn \l_@@_loglevel_int { 0 }},
- log / v .code:n = {\int_set:Nn \l_@@_loglevel_int { 1 }},
- log / vv .code:n = {\int_set:Nn \l_@@_loglevel_int { 2 }},
- log / vvv .code:n = {\int_set:Nn \l_@@_loglevel_int { 3 }},
- log / all .code:n = {\int_set:Nn \l_@@_loglevel_int { 10 }},
- tagunmarked .bool_gset:N = \g_@@_tagunmarked_bool,
- tagunmarked .initial:n = true,
- tabsorder .choice:,
- tabsorder / row .code:n = %{\tl_set:Nn \l_@@_tree_tabs_order_tl {/Tabs/R}},
- \pdfmanagement_add:nnn { Page } {Tabs}{/R},
- tabsorder / column .code:n = %{\tl_set:Nn \l_@@_tree_tabs_order_tl {/Tabs/C}},
- \pdfmanagement_add:nnn { Page } {Tabs}{/C},
- tabsorder / structure .code:n = %{\tl_set:Nn \l_@@_tree_tabs_order_tl {/Tabs/S}},
- \pdfmanagement_add:nnn { Page } {Tabs}{/S},
- tabsorder / none .code:n = %{\tl_set:Nn \l_@@_tree_tabs_order_tl {}},
- \pdfmanagement_remove:nn {Page} {Tabs},
- tabsorder .initial:n = structure,
- uncompress .code:n = {\pdf_uncompress: },
- global-mc .code:n =
- {
- \cs_set_eq:NN\@@_attribute_set:Nn \@@_attribute_gset:Nn
- \cs_set_eq:NN\@@_attribute_unset:N\@@_attribute_gunset:N
- }
- }
-%need to think about the right place ...
-%\AtBeginDocument
-\hook_gput_code:nnn{begindocument}{tagpdf}
- {
- \bool_if:NT \g_@@_active_struct_bool
- {
- \pdfmanagement_add:nnn { Catalog / MarkInfo } { Marked } { true }
- }
- \keys_define:nn { @@ / setup }
- {
- global-mc .code:n={}
- }
- }
-% escape commands are a bit engine specific so have been moved to the backend files.
-% commands to escape strings so that they can be safely used in pdf
-% currently not much used. But will be needed later, when alt and actualtext are added.
-% we probably need the equivalent \pdfescapestring, \pdfescapename \pdfescapehex
-% the commands of pdfescape adds an additional layout to allow for babel shorthands
-%\cs_set_eq:NN \@@_pdf_escape_string:Nn \EdefEscapeString
-%\cs_set_eq:NN \@@_pdf_escape_name:Nn \EdefEscapeName
-%\cs_set_eq:NN \@@_pdf_escape_hex:Nn \EdefEscapeHex
-
-%\cs_set_eq:NN \@@_pdf_escape_string:n \EdefEscapeString
-%\cs_set_eq:NN \@@_pdf_escape_name:Nn \EdefEscapeName
-
-%escape command. They are backend specific as \pdf@escapehex would ignore most chars
-%outside the "pdflatex" range
-
-
-
-
-
-% a hook for later code and an absolute page counter
-% should be executed before counters are resetted.
-% is it used?
-\cs_new:Nn \@@_finish_page_hook: { }
-
-%\AtBeginShipout
-
-\hook_gput_code:nnn
- { shipout/before }
- { tagpdf/cnt }
- {
- \@@_finish_page_hook:
- %\int_gincr:N \g_@@_abspage_int
- }
-
-
-%testing the engines and loading the backend files
-\sys_if_engine_xetex:T
- { %lets try with xelatex ...
- %\PackageError { tagpdf } { xelatex~is~not~supported~-~aborting } {}
- %\tex_endinput:D
- \file_input:n {tagpdf-pdftex.def}
- }
-
-\sys_if_engine_luatex:T
- {
- \file_input:n {tagpdf-luatex.def}
- }
-
-\sys_if_engine_pdftex:T
- {
- \file_input:n {tagpdf-pdftex.def}
- }
-
-\sys_if_output_dvi:T
- {
- %\PackageError { tagpdf } { dvi~output~is~not~supported~-~aborting }{}
- %\tex_endinput:D
- }
+% \end{macrocode}
+%\end{macro}
+
+
+
+%\section{Commands to fill seq and prop}
+% With most engines these are simply copies of the expl3 commands,
+% but luatex will overwrite them, to store the data also in lua tables.
+% \begin{macro}
+% {
+% \@@_prop_new:N
+% ,\@@_seq_new:N
+% ,\@@_prop_gput:Nnn
+% ,\@@_seq_gput_right:Nn
+% ,\@@_seq_item:cn
+% ,\@@_prop_item:cn
+% ,\@@_seq_show:N
+% ,\@@_prop_show:N
+% }
+% \begin{macrocode}
+\cs_set_eq:NN \@@_prop_new:N \prop_new:N
+\cs_set_eq:NN \@@_seq_new:N \seq_new:N
+\cs_set_eq:NN \@@_prop_gput:Nnn \prop_gput:Nnn
+\cs_set_eq:NN \@@_seq_gput_right:Nn \seq_gput_right:Nn
+\cs_set_eq:NN \@@_seq_item:cn \seq_item:cn
+\cs_set_eq:NN \@@_prop_item:cn \prop_item:cn
+\cs_set_eq:NN \@@_seq_show:N \seq_show:N
+\cs_set_eq:NN \@@_prop_show:N \prop_show:N
\cs_generate_variant:Nn \@@_prop_gput:Nnn { Nxn , Nxx, Nnx , cnn, cxn, cnx, cno}
\cs_generate_variant:Nn \@@_seq_gput_right:Nn { Nx , No, cn, cx }
@@ -292,439 +340,110 @@
\cs_generate_variant:Nn \@@_seq_new:N { c }
\cs_generate_variant:Nn \@@_seq_show:N { c }
\cs_generate_variant:Nn \@@_prop_show:N { c }
-\cs_generate_variant:Nn \prop_gput:Nnn {Nxx}
-\cs_generate_variant:Nn \prop_put:Nnn {Nxx}
-
-\cs_generate_variant:Nn \pdffile_embed_stream:nnn {nxx,oxx}
-\cs_generate_variant:Nn \pdf_object_ref:n {e}
-
-
-% few temp tl
-\tl_new:N \g_@@_tmpa_tl
-\tl_new:N \l_@@_tmpa_tl
-\tl_new:N \l_@@_tmpb_tl
-\tl_new:N \l_@@_tmpc_tl
-\tl_new:N \l_@@_tmpd_tl
-\tl_new:N \l_@@_tmpe_tl
-\str_new:N \l_@@_tmpa_str
-
-% helper function to get the propcount.
-% use as \prop_map_function:NN PROP { \@@_prop_count:nn -1 }
-\cs_new:Nn\@@_prop_count:nn { + 1 }
-
-%% Loading the tagpdf sub packages
-\RequirePackage { tagpdf-checks-code }
-\RequirePackage { tagpdf-user }
-\RequirePackage { tagpdf-tree-code }
-\RequirePackage { tagpdf-roles-code }
-\RequirePackage { tagpdf-attr-code }
-% mc-code is split:
-\RequirePackage { tagpdf-mc-code-shared }
-\bool_if:NTF \g_@@_mode_lua_bool
- {
- \RequirePackage {tagpdf-mc-code-lua}
- }
- {
- \RequirePackage { tagpdf-mc-code-generic } %
- }
-
-\RequirePackage { tagpdf-struct-code }
-\RequirePackage { tagpdf-space-code }
-%</package>
-% \end{macrocode}
-%
-% \begin{macrocode}
-%<*user>
-\ProvidesExplPackage {tagpdf-user} {2021-06-14} {0.82}
- {tagpdf - user commands}
-% \end{macrocode}
-
-% \begin{macro}{\tagpdfsetup}
-% \begin{macrocode}
-\NewDocumentCommand \tagpdfsetup { m }
- {
- \keys_set:nn { @@ / setup } { #1 }
- }
-
-\cs_set_eq:NN\tagpdfifluatexTF \sys_if_engine_luatex:TF
-\cs_set_eq:NN\tagpdfifluatexT \sys_if_engine_luatex:T
-\cs_set_eq:NN\tagpdfifpdftexT \sys_if_engine_pdftex:T
% \end{macrocode}
% \end{macro}
-% \begin{macro}{\tag_if_active:}
-% This is a test it tagging is active. This allows packages
-% to add conditional code. We probably will need a better
-% test in the end, but for now it should be ok.
-% \begin{macrocode}
-\prg_new_conditional:Npnn \tag_if_active: { p , T , TF, F }
- {
- \bool_if:NTF\g_@@_active_struct_bool
- {
- \prg_return_true:
- }
- {
- \prg_return_false:
- }
- }
-% \end{macrocode}
-% \end{macro}
-%
-% We need a command to stop tagging in some places.
%
+% \section{General tagging commands}
+
% \begin{macro}{ \tag_stop_group_begin:, \tag_stop_group_end: }
+% We need a command to stop tagging in some places.
+% This simply switches the two local booleans.
% \begin{macrocode}
-\bool_new:N \l_@@_stop_bool
-
-\prg_new_conditional:Nnn \@@_if_stop: {p,T,F,TF}
- {
- \bool_if:NTF \l_@@_stop_bool
- { \prg_return_true: }
- { \prg_return_false: }
- }
-
-\prg_new_eq_conditional:NNn \tag_if_stop: \@@_if_stop: {p,T,F,TF}
-
-\cs_new_protected:Npn \@@_stop:
- {
- \bool_set_true:N \l_@@_stop_bool
- \cs_set_eq:NN \tag_mc_begin:n \use_none:n
- \cs_set_eq:NN \tag_mc_end: \prg_do_nothing:
- \cs_set_eq:NN \tag_mc_use:n \use_none:n
- \cs_set_eq:NN \tag_struct_begin:n \use_none:n
- \cs_set_eq:NN \tag_struct_end: \prg_do_nothing:
- \cs_set_eq:NN \tag_struct_use:n \use_none:n
- }
-
\cs_new_protected:Npn \tag_stop_group_begin:
{
\group_begin:
- \@@_stop:
+ \bool_set_false:N \l_@@_active_struct_bool
+ \bool_set_false:N \l_@@_active_mc_bool
}
-
\cs_set_eq:NN \tag_stop_group_end: \group_end:
% \end{macrocode}
% \end{macro}
-% We need a command to stop tagging in some places.
%
-% \begin{macro}{ \tagpdfget, \tag_get:n }
-% This is a generic command to retrieve data. Currently
-% the only sensible value for the argument is |mc_tag|
-% \begin{macrocode}
-\cs_new:Npn \tagpdfget #1 { \use:c {@@_get_data_#1: } }
-\cs_new:Npn \tag_get:n #1 { \use:c {@@_get_data_#1: } }
+% \section{Keys for tagpdfsetup}
-% \end{macrocode}
-% \end{macro}
+% TODO: the log-levels must be sorted
%
-% \begin{macro}{\tagmcifinTF}
-% This is a test if an mc is open or not. It is mostly of
-% importance for pdflatex as lualatex doesn't mind much if a mc tag is not
-% correctly closed.
+% \begin{macro}
+% {
+% activate-space,
+% activate-mc,
+% activate-tree,
+% activate-struct,
+% activate-all,
+% }
+% Keys to (globally) activate tagging.
+% |activate-space| activates the additional parsing needed for
+% interword spaces. It is not documented, the parsing is currently
+% implicitly activated by the known key |interwordspace|, as the code will
+% perhaps move to some other place, now that it is better separated.
% \begin{macrocode}
-\NewDocumentCommand \tagmcifinTF { m m }
+\keys_define:nn { @@ / setup }
{
- \@@_mc_if_in:TF { #1 } { #2 }
- }
-% \end{macrocode}
+ activate-space .bool_gset:N = \g_@@_active_space_bool,
+ activate-mc .bool_gset:N = \g_@@_active_mc_bool,
+ activate-tree .bool_gset:N = \g_@@_active_tree_bool,
+ activate-struct .bool_gset:N = \g_@@_active_struct_bool,
+ activate-all .meta:n =
+ {activate-mc,activate-tree,activate-struct},
+ % \end{macrocode}
% \end{macro}
-%
-% \begin{macro}{tagmcartifact}
+% \begin{macro}{log}
+% The |log| takes currently the values |none|, |v|, |vv|, |vvv|, |all|.
+% The description of the log levels is in tagpdf-checks.
% \begin{macrocode}
-\NewDocumentEnvironment{tagmcartifact}{m}
- {
- \tag_mc_artifact_group_begin:n { #1}\ignorespaces
- }
- {
- \tag_mc_artifact_group_end:
- }
-
+ log .choice:,
+ log / none .code:n = {\int_set:Nn \l_@@_loglevel_int { 0 }},
+ log / v .code:n = {\int_set:Nn \l_@@_loglevel_int { 1 }},
+ log / vv .code:n = {\int_set:Nn \l_@@_loglevel_int { 2 }},
+ log / vvv .code:n = {\int_set:Nn \l_@@_loglevel_int { 3 }},
+ log / all .code:n = {\int_set:Nn \l_@@_loglevel_int { 10 }},
% \end{macrocode}
% \end{macro}
-%
-% \begin{macro}{\tagmcbegin,\tagmcend,\tagmcuse }
+% \begin{macro}{tagunmarked}
+% This key allows to set if (in luamode) unmarked text should be
+% marked up as artifact. The initial value is true.
% \begin{macrocode}
-\NewDocumentCommand \tagmcbegin { m }
- {
- \tag_mc_begin:n {#1}\ignorespaces
- }
-
-
-\NewDocumentCommand \tagmcend { }
- {
- \if_mode_horizontal: \unskip \fi: %
- \tag_mc_end:
- }
-
-\NewDocumentCommand \tagmcuse { m }
- {
- \tag_mc_use:n {#1}
- }
-
+ tagunmarked .bool_gset:N = \g_@@_tagunmarked_bool,
+ tagunmarked .initial:n = true,
% \end{macrocode}
% \end{macro}
-%
-% \begin{macro}{\tagstructbegin,\tagstructend,\tagstructuse }
-%
-% These are structure related user commands
+% \begin{macro}{tabsorder}
+% This sets the tabsorder one a page. The values are |row|, |column|, |structure| (default)
+% or |none|. Currently this is set more or less globally. More finer controll can be
+% added if needed.
% \begin{macrocode}
-\NewDocumentCommand \tagstructbegin { m }
- {
- \tag_struct_begin:n {#1}
- }
-
-\NewDocumentCommand \tagstructend { }
- {
- \tag_struct_end:
- }
-
-\NewDocumentCommand \tagstructuse { m }
- {
- \tag_struct_use:n {#1}
- }
-
-% \end{macrocode}
-% \end{macro}
-%
-% \section{Debugging}
-%
-% \begin{macro}{\showtagpdfmcdata,\showtagpdfattributes }
-% This commands are lua only
-% \begin{macrocode}
-\NewDocumentCommand\showtagpdfmcdata { O {\@@_tag_get_mc_abs_cnt:} }
- {
- \bool_if:NT \g_@@_mode_lua_bool
- {
- \sys_if_engine_luatex:T
- {
- \directlua{ltx.@@.trace.show_all_mc_data(#1)}
- }
- }
- }
-
-\NewDocumentCommand\showtagpdfattributes { }
- {
- \bool_if:NT \g_@@_mode_lua_bool
- {
- \sys_if_engine_luatex:T
- {
- \directlua
- {
- ltx.@@.trace.log
- (
- "showtagpdfattributes:
- MC=>abscnt=\@@_get_mc_abs_cnt:
- =>attr=\the\l_@@_mc_cnt_attr=>tag="
- ..
- tostring(ltx.@@.func.get_tag_from (\the\l_@@_mc_type_attr))
- ..
- "=\the\l_@@_mc_type_attr",0
- )
- }
- \ignorespaces
- }
- }
- }
-
-\NewDocumentCommand\showtagstack {}
- {
- \seq_show:N \g_@@_struct_tag_stack_seq
+ tabsorder .choice:,
+ tabsorder / row .code:n =
+ \pdfmanagement_add:nnn { Page } {Tabs}{/R},
+ tabsorder / column .code:n =
+ \pdfmanagement_add:nnn { Page } {Tabs}{/C},
+ tabsorder / structure .code:n =
+ \pdfmanagement_add:nnn { Page } {Tabs}{/S},
+ tabsorder / none .code:n =
+ \pdfmanagement_remove:nn {Page} {Tabs},
+ tabsorder .initial:n = structure,
+ uncompress .code:n = { \pdf_uncompress: },
}
% \end{macrocode}
% \end{macro}
-%
-% \begin{macro}{ }
+% \section{loading of engine/more dependent code}
% \begin{macrocode}
\sys_if_engine_luatex:T
{
- \NewDocumentCommand\pdffakespace { }
- {
- \@@_fakespace:
- }
- }
-% \end{macrocode}
-% \end{macro}
-% \section{Paratagging}
-% The following are some simple commands to enable/disable paratagging.
-% Probably one should add some checks if we are already in a paragraph.
-% \begin{macrocode}
-\bool_new:N \l_@@_para_bool
-\bool_new:N \l_@@_para_show_bool
-\int_new:N \g_@@_para_int
-
-\keys_define:nn { @@ / setup }
- {
- paratagging .bool_set:N = \l_@@_para_bool,
- paratagging-show .bool_set:N = \l_@@_para_show_bool,
- }
-
-\AddToHook{para/begin}
- {
- \int_gincr:N \g_@@_para_int
- \bool_if:NT \l__tag_para_bool
- {
- \tag_struct_begin:n {tag=P}
- \bool_if:NT \l_@@_para_show_bool
- { \tag_mc_begin:n{artifact}
- \llap{\color_select:n{red}\tiny\int_use:N\g_@@_para_int\ }
- \tag_mc_end:
- }
- \tag_mc_begin:n {tag=P}
- }
- }
-\AddToHook{para/end}
- {
- \bool_if:NT \l__tag_para_bool
- {
- \tag_mc_end:
- \bool_if:NT \l_@@_para_show_bool
- { \tag_mc_begin:n{artifact}
- \rlap{\color_select:n{red}\tiny\ \int_use:N\g_@@_para_int}
- \tag_mc_end:
- }
- \tag_struct_end:
- }
+ \file_input:n {tagpdf-luatex.def}
}
-
-
-\newcommand\tagpdfparaOn {\bool_set_true:N \l__tag_para_bool}
-\newcommand\tagpdfparaOff{\bool_set_false:N \l__tag_para_bool}
-
+%</package>
% \end{macrocode}
-% \section{Links}
-% We need to close and reopen mc-chunks around links.
-% With luatex the push/pop command must be outside groups,
-% so we add also code to the generic commands in the hyperref driver.
% \begin{macrocode}
-\cs_generate_variant:Nn \pdfannot_dict_put:nnn {nnx}
-\hook_gput_code:nnn
- {pdfannot/link/URI/before}
- {tagpdf}
- {
- \bool_if:NT \g_@@_active_struct_bool
- {
- \tag_mc_end_push:
- \tag_struct_begin:n { tag=Link }
- \tag_mc_begin:n { tag=Link }
- \pdfannot_dict_put:nnx
- { link/URI }
- { StructParent }
- { \tag_struct_parent_int: }
- }
- }
-
-\hook_gput_code:nnn
- {pdfannot/link/URI/after}
- {tagpdf}
+%<*mcloading>
+\bool_if:NTF \g_@@_mode_lua_bool
{
- \bool_if:NT \g_@@_active_struct_bool
- {
- \tag_struct_insert_annot:xx {\pdfannot_link_ref_last:}{\tag_struct_parent_int:}
- \tag_mc_end:
- \tag_struct_end:
- \tag_mc_begin_pop:n{}
- }
+ \RequirePackage {tagpdf-mc-code-lua}
}
-
-\hook_gput_code:nnn
- {pdfannot/link/GoTo/before}
- {tagpdf}
{
- \bool_if:NT \g_@@_active_struct_bool
- {
- \tag_mc_end_push:
- \tag_struct_begin:n{tag=Link}
- \tag_mc_begin:n{tag=Link}
- \pdfannot_dict_put:nnx
- { link/GoTo }
- { StructParent }
- { \tag_struct_parent_int: }
- }
+ \RequirePackage {tagpdf-mc-code-generic} %
}
-
-\hook_gput_code:nnn
- {pdfannot/link/GoTo/after}
- {tagpdf}
- {
- \bool_if:NT \g_@@_active_struct_bool
- {
- \tag_struct_insert_annot:xx {\pdfannot_link_ref_last:}{\tag_struct_parent_int:}
- \tag_mc_end:
- \tag_struct_end:
- \tag_mc_begin_pop:n{}
- }
- }
-
-\hook_gput_code:nnn
- {cmd/url/before}
- {tagpdf}
- {\tag_mc_end_push:}
-
-\hook_gput_code:nnn
- {cmd/url/after}
- {tagpdf}
- {\tag_mc_begin_pop:n{}}
-
-\hook_gput_code:nnn
- {cmd/href/before}
- {tagpdf}
- {\tag_mc_end_push:}
-
-\hook_gput_code:nnn
- {cmd/href/after}
- {tagpdf}
- {\tag_mc_begin_pop:n{}}
-
-\hook_gput_code:nnn
- {cmd/hrefurl/before}
- {tagpdf}
- {\tag_mc_end_push:}
-
-\hook_gput_code:nnn
- {cmd/hrefurl/after}
- {tagpdf}
- {\tag_mc_begin_pop:n{}}
-
-%this will go when references are improved
-\hook_gput_code:nnn
- {cmd/T@ref/before}
- {tagpdf}
- {\tag_mc_end_push:}
-
-\hook_gput_code:nnn
- {cmd/T@ref/after}
- {tagpdf}
- {\tag_mc_begin_pop:n{}}
-
-\hook_gput_code:nnn
- {cmd/T@pageref/before}
- {tagpdf}
- {\tag_mc_end_push:}
-
-\hook_gput_code:nnn
- {cmd/T@pageref/after}
- {tagpdf}
- {\tag_mc_begin_pop:n{}}
-
-\hook_gput_code:nnn
- {cmd/T@nameref/before}
- {tagpdf}
- {\tag_mc_end_push:}
-
-\hook_gput_code:nnn
- {cmd/T@nameref/after}
- {tagpdf}
- {\tag_mc_begin_pop:n{}}
-% "alternative descriptions " for PAX3. How to get better text here??
-\pdfannot_dict_put:nnn
- { link/URI }
- { Contents }
- { (url) }
-
-\pdfannot_dict_put:nnn
- { link/GoTo }
- { Contents }
- { (ref) }
-
+%</mcloading>
% \end{macrocode}
-%</user>
-%
+% \end{implementation}
+% \PrintIndex
diff --git a/Master/texmf-dist/source/latex/tagpdf/tagpdf.ins b/Master/texmf-dist/source/latex/tagpdf/tagpdf.ins
index c94a1808ded..583509d4a24 100644
--- a/Master/texmf-dist/source/latex/tagpdf/tagpdf.ins
+++ b/Master/texmf-dist/source/latex/tagpdf/tagpdf.ins
@@ -2,7 +2,7 @@
File: tagpdf.ins
-Copyright (C) 2019 Ulrike Fischer
+Copyright (C) 2019-2021 Ulrike Fischer
It may be distributed and/or modified under the conditions of the
LaTeX Project Public License (LPPL), either version 1.3c of this
@@ -34,7 +34,7 @@ for those people who are interested.
\let\MetaPrefix\relax
\preamble
-Copyright (C) 2019 Ulrike Fischer
+Copyright (C) 2019-2021 Ulrike Fischer
It may be distributed and/or modified under the conditions of
the LaTeX Project Public License (LPPL), either version 1.3c of
@@ -55,41 +55,28 @@ and all files in that bundle must be distributed together.
\keepsilent
\generate
- {\file{tagpdf.sty} {\from{tagpdf.dtx}{package}}}
-\generate
- {\file{tagpdf-user.sty} {\from{tagpdf.dtx}{user}}}
-\generate
- {\file{tagpdf-deprecated.def}{\from{tagpdf.dtx}{deprecated}}}
+ {\file{tagpdf.sty}
+ {
+ \from{tagpdf.dtx}{package}
+ \from{tagpdf-checks.dtx}{package}
+ \from{tagpdf-user.dtx}{package}
+ \from{tagpdf-mc-shared.dtx}{shared}
+ \from{tagpdf.dtx}{mcloading}
+ \from{tagpdf-tree.dtx}{package}
+ \from{tagpdf-roles.dtx}{package}
+ \from{tagpdf-struct.dtx}{package}%contains also the attr code.
+ \from{tagpdf-space.dtx}{package}
+ }
+ }
\generate
{\file{tagpdf-luatex.def}{\from{tagpdf-backend.dtx}{luatex}}}
\generate
- {\file{tagpdf-pdftex.def}{\from{tagpdf-backend.dtx}{pdftex}}}
-
-\generate
- {\file{tagpdf-mc-code-shared.sty}{\from{tagpdf-mc.dtx}{shared}}}
-\generate
- {\file{tagpdf-mc-code-generic.sty}{\from{tagpdf-mc.dtx}{generic}}}
-\generate
- {\file{tagpdf-mc-code-lua.sty}{\from{tagpdf-mc.dtx}{luamode}}}
-
-\generate
- {\file{tagpdf-struct-code.sty}{\from{tagpdf-struct.dtx}{struct}}}
-\generate
- {\file{tagpdf-attr-code.sty}{\from{tagpdf-struct.dtx}{attr}}}
-
+ {\file{tagpdf-mc-code-generic.sty}{\from{tagpdf-mc-generic.dtx}{generic}}}
\generate
- {\file{tagpdf-checks-code.sty}{\from{tagpdf-checks.dtx}{checks}}}
+ {\file{tagpdf-mc-code-lua.sty}{\from{tagpdf-mc-luacode.dtx}{luamode}}}
-\generate
- {\file{tagpdf-roles-code.sty}{\from{tagpdf-roles.dtx}{roles}}}
-\generate
- {\file{tagpdf-space-code.sty}{\from{tagpdf-space.dtx}{space}}}
-
-\generate
- {\file{tagpdf-tree-code.sty}{\from{tagpdf-tree.dtx}{tree}}}
-
\def\MetaPrefix{-- }
\def\defaultpostamble{%
\MetaPrefix^^J%