% \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} % % \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.92, released 2021-08-27} % \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{Header and footer} % Header and footer are automatically excluded from tagging. This can for % now to allow debugging be disabled with the following key, but probably % this key will disappear again. If some real content is in the header and % footer, tagging must be restarted there explicitly. % % \begin{function}{exclude-header-footer} % \begin{syntax} % |exclude-header-footer| = |true|\verb+|+|false| % \end{syntax}% % \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-08-27} {0.92} {tagpdf - user commands} % % \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}{mc-marks} % It maps the mc-marks into the sequences and then shows them. % This allows to inspect the first and last mc-Mark on a page. % It should only be used in the shipout (header/footer). % \begin{macrocode} \keys_define:nn { @@ / show } { mc-marks .choice: , mc-marks / show .code:n = { \@@_mc_get_marks: \@@_check_if_mc_in_galley:TF { \iow_term:n {Marks~from~this~page:~} } { \iow_term:n {Marks~from~a~previous~page:~} } \seq_show:N \l_@@_mc_firstmarks_seq \seq_show:N \l_@@_mc_botmarks_seq \@@_check_if_mc_tmb_missing:T { \iow_term:n {BDC~missing~on~this~page!} } \@@_check_if_mc_tme_missing:T { \iow_term:n {EMC~missing~on~this~page!} } }, mc-marks / use .code:n = { \@@_mc_get_marks: \@@_check_if_mc_in_galley:TF { Marks~from~this~page:~} { Marks~from~a~previous~page:~} \seq_use:Nn \l_@@_mc_firstmarks_seq {,~}\quad \seq_use:Nn \l_@@_mc_botmarks_seq {,~}\quad \@@_check_if_mc_tmb_missing:T { BDC~missing~ } \@@_check_if_mc_tme_missing:T { EMC~missing } }, mc-marks .default:n = show } % \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_begin_int \int_new:N \g_@@_para_end_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} { \bool_if:NT \l_@@_para_bool { \int_gincr:N \g_@@_para_begin_int \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_begin_int\ } \tag_mc_end: } \tag_mc_begin:n {tag=P} } } \AddToHook{para/end} { \bool_if:NT \l_@@_para_bool { \int_gincr:N \g_@@_para_end_int \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_end_int} \tag_mc_end: } \tag_struct_end: } } \AddToHook{enddocument/info} { \int_compare:nNnF {\g__tag_para_begin_int}={\g__tag_para_end_int} { \msg_error:nnxx {tag} {para-hook-count-wrong} {\int_use:N\g__tag_para_begin_int} {\int_use:N\g__tag_para_end_int} } } % \end{macrocode} % In generic mode we need the additional code from the ptagging tests. % \begin{macrocode} \AddToHook{begindocument/before} { \bool_if:NF \g_@@_mode_lua_bool { \cs_if_exist:NT \@kernel@before@footins { \tl_put_right:Nn \@kernel@before@footins { \@@_add_missing_mcs_to_stream:Nn \footins {footnote} } \tl_put_right:Nn \@kernel@before@cclv { \@@_check_typeout_v:n {====>~In~\token_to_str:N \@makecol\c_space_tl\the\c@page} \@@_add_missing_mcs_to_stream:Nn \@cclv {main} } \tl_put_right:Nn \@mult@ptagging@hook { \@@_check_typeout_v:n {====>~In~\string\page@sofar} \process@cols\mult@gfirstbox { \@@_add_missing_mcs_to_stream:Nn \count@ {multicol} } \@@_add_missing_mcs_to_stream:Nn \mult@rightbox {multicol} } } } } % \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_@@_para_bool} \newcommand\tagpdfparaOff{\bool_set_false:N \l_@@_para_bool} % \end{macrocode} % \end{macro} % % \begin{macro} % { % \tagpdfsuppressmarks % } % This command allows to suppress the creation of the marks. It takes an argument % which should normally be one of the mc-commands, puts a group around it and % suppress the marks creation in this group. This command should be used if % the begin and end command are at different boxing levels. E.g. % \begin{verbatim} % \@hangfrom % { % \tagstructbegin{tag=H1}% % \tagmcbegin {tag=H1}% % #2 % } % {#3\tagpdfsuppressmarks{\tagmcend}\tagstructend}% % \end{verbatim} % \begin{macrocode} \NewDocumentCommand\tagpdfsuppressmarks{m} {{\use:c{@@_mc_disable_marks:} #1}} % \end{macrocode} % \end{macro} % \subsection{Header and footer} % Header and footer should normally be tagged as artifacts. The following code % requires the new hooks. % For now we allow to disable this function, but probably the code should always there at % the end. % TODO check if Pagination should be changeable. % \begin{macrocode} \cs_new_protected:Npn\@@_hook_kernel_before_head:{} \cs_new_protected:Npn\@@_hook_kernel_after_head:{} \cs_new_protected:Npn\@@_hook_kernel_before_foot:{} \cs_new_protected:Npn\@@_hook_kernel_after_foot:{} \AddToHook{begindocument} { \cs_if_exist:NT \@kernel@before@head { \tl_put_right:Nn \@kernel@before@head {\@@_hook_kernel_before_head:} \tl_put_left:Nn \@kernel@after@head {\@@_hook_kernel_after_head:} \tl_put_right:Nn \@kernel@before@foot {\@@_hook_kernel_before_foot:} \tl_put_left:Nn \@kernel@after@foot {\@@_hook_kernel_after_foot:} } } \bool_new:N \g_@@_saved_in_mc_bool \cs_new_protected:Npn \@@_exclude_headfoot_begin: { \bool_set_false:N \l_@@_para_bool \bool_if:NTF \g_@@_mode_lua_bool { \tag_mc_end_push: } { \bool_gset_eq:NN \g_@@_saved_in_mc_bool \g_@@_in_mc_bool \bool_gset_false:N \g_@@_in_mc_bool } \tag_mc_begin:n {artifact} } \cs_new_protected:Npn \@@_exclude_headfoot_end: { \tag_mc_end: \bool_if:NTF \g_@@_mode_lua_bool { \tag_mc_begin_pop:n{} } { \bool_gset_eq:NN \g_@@_in_mc_bool\g_@@_saved_in_mc_bool } } \keys_define:nn { @@ / setup } { exclude-header-footer .choice:, exclude-header-footer / true .code:n = { \cs_set_eq:NN \@@_hook_kernel_before_head: \@@_exclude_headfoot_begin: \cs_set_eq:NN \@@_hook_kernel_before_foot: \@@_exclude_headfoot_begin: \cs_set_eq:NN \@@_hook_kernel_after_head: \@@_exclude_headfoot_end: \cs_set_eq:NN \@@_hook_kernel_after_foot: \@@_exclude_headfoot_end: }, exclude-header-footer / false .code:n = { \cs_set_eq:NN \@@_hook_kernel_before_head: \prg_do_nothing: \cs_set_eq:NN \@@_hook_kernel_before_foot: \prg_do_nothing: \cs_set_eq:NN \@@_hook_kernel_after_head: \prg_do_nothing: \cs_set_eq:NN \@@_hook_kernel_after_foot: \prg_do_nothing: }, exclude-header-footer .default:n = true, exclude-header-footer .initial:n = true } % \end{macrocode} % \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} % % \end{implementation} % \PrintIndex