% \iffalse meta-comment
%
%% File: tagpdf-user.dtx
%
% Copyright (C) 2019-2026 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/latex3/tagpdf
%
% for those people who are interested.
%<*driver>
\DocumentMetadata{tagging=on}
\documentclass{l3in2edoc}
\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
% }
%
% \author{^^A
%  Ulrike Fischer\thanks
%    {^^A
%      E-mail:
%        \href{mailto:fischer@troubleshooting-tex.de}
%          {fischer@troubleshooting-tex.de}^^A
%    }^^A
% }
%
% \date{Version 1.0b, released 2026-04-24}
% \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}
%
% \begin{function}{activate (setup-key)}
% And additional setup key which combine the other activate keys
% |activate/mc|, |activate/tree|, |activate/struct| and additionally
% adds a document structure.
% \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}{\tagmcifinTF}
% \begin{syntax}
% \cs{tagmcifinTF}\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 documented 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
% necessarily stops the compilation. The keys and their function are described below.
% \end{function}
%
% \begin{function}{mc-data (show-key)}
%  \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 (show-key)}
%  \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}{mc-marks (show-key)}
%  \begin{syntax}
%    |mc-marks| = |show|\verb+|+|use|
%  \end{syntax}
% This key helps to debug the page marks. It should only be used at shipout in
% header or footer.
% \end{function}
% \begin{function}{struct-stack (show-key)}
%  \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}
%
% \begin{function}{debug/structures (show-key)}
%  \begin{syntax}
%    |debug/structures| = \meta{structure number}
%  \end{syntax}
%  This key is available only if the tagpdf-debug package is loaded
%  and shows all structures starting with the one with the number
%  given by the key.
% \end{function}

% \section{Extension commands}
% The following commands and code parts are not core commands 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 viewed 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{Tagging of paragraphs}
%
% This makes use of the paragraph hooks in 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}{para/tagging (setup-key),paratagging-show (deprecated),paratagging (deprecated)}
%  \begin{syntax}
%    |para/tagging| = |true|\verb+|+|false|\\
%    |debug/show=para|\\
%    |debug/show=paraOff|
%  \end{syntax}
% The |para/tagging| key can be used in |\tagpdfsetup| and enable/disables tagging
% of paragraphics.
% |debug/show=para| puts small colored 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}
%
% \begin{function}{\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}
% \end{function}
%
% \subsection{Header and footer}
% Header and footer are automatically tagged as artifact:
% They are surrounded by an artifact-mc and inside tagging is stopped.
% If some real content is in the header and
% footer, tagging must be restarted there explicitly.
% The behaviour can be changed with the following key.
% The key accepts the values |true| (the default),
% |false| which disables the header tagging code. This can be useful
% if the page style is empty (it then avoids empty mc-chunks) or
% if the head and foot should be tagged in some special way.
% The last value, |pagination|, is like |true| but
% additionally adds an artifact structure with an pagination attribute.
%
% \begin{function}{page/exclude-header-footer (setup-key)}
%  \begin{syntax}
%    |page/exclude-header-footer| = |true|\verb+|+|false|\verb+|+pagination
%  \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 can have an alternative text in the Contents but this disturbs reading,
% so it is not done by default. 
% Another text can be added by changing the dictionary value:
% \begin{verbatim}
% \pdfannot_dict_put:nnn
% { link/GoTo }
% { Contents }
% { (ref) }
% \end{verbatim}
%
% \section{Socket support}
%
% \begin{function}{\tag_socket_use:n,\tag_socket_use:nnn,\UseTaggingSocket}
% \begin{syntax}
%  \cs{tag_socket_use:n} \Arg{socket name}\\
%  \cs{tag_socket_use:nn} \Arg{socket name} \Arg{socket argument}\\
%  \cs{tag_socket_use:nnn} \Arg{socket name} \Arg{socket argument} \Arg{socket argument}\\
%  \cs{tag_socket_use_expandable:n} \Arg{socket name}\\
%  \cs{UseTaggingSocket} \Arg{socket name} \\
%  \cs{UseTaggingSocket} \Arg{socket name} \Arg{socket argument}\\
%  \cs{UseTaggingSocket} \Arg{socket name} \Arg{socket argument} \Arg{socket argument}\\
% \end{syntax}
% \end{function}
%
% Given that we sometimes have to suspend tagging, it would be fairly
% inefficient to put different plugs into these sockets whenever that
% happens. We therefore offer \cs{UseTaggingSocket} which is like
% \cs{UseSocket} except that is expects a socket starting with
% \texttt{tagsupport/} but the socket name is specified without
% this prefix, i.e.,
% \begin{quote}
%   \verb=\UseTaggingSocket{foo}=      $\to$
%   \verb=\UseSocket{tagsupport/foo}=
% \end{quote}.
%
% Beside being slightly shorter, the big advantage is that this way
% we can change \cs{UseTaggingSocket} to do nothing by switching a boolean
% instead of changing the plugs of the tagging support sockets back and forth.
%
% Usually, these sockets have (beside the default plug defined for every socket)
% one additional plug defined and directly assigned. This plug is used when
% tagging is active.
% There may be more plugs, e.g., tagging with special debugging or special behaviour
% depending on the class or PDF version etc., but right now it is usually just on or off.
%
% When tagging is suspended they all have the same predefined behaviour:
% The sockets with zero arguments do nothing. The sockets with one argument
% gobble their argument. The sockets with two arguments
% will drop their first argument and pass the second unchanged.
%
% It is possible to use the tagging support sockets with
% \cs{UseSocket} directly, but in this case the socket remains active
% if e.g. \cs{SuspendTagging} is in force. There may be reasons for doing
% that but in general we expect to always use \cs{UseTaggingSocket}.
%
% For special cases like in some \cs{halign} contexts we need a fully expandable
% version of the commend. For these cases, \cs{UseExpandableTaggingSocket} can be
% used. To allow being expandable, it does not output any debugging information
% if \cs{DebugSocketsOn} is in effect and therefore should be avoided whenever possible.
%
%  The L3 programming layer versions \cs{tag_socket_use_expandable:n}, \cs{tag_socket_use:n}, and
%  \cs{tag_socket_use:nn}, \cs{tag_socket_use:nnn}
%  are slightly more efficient than
%  \cs{UseTaggingSocket} because they do not have to determine how
%  many arguments the socket takes when disabling it.
% \end{documentation}
%
% \begin{implementation}
% \section{User commands and extensions of document commands}
%    \begin{macrocode}
%<@@=tag>
%<*header>
\ProvidesExplPackage {tagpdf-user} {2026-04-24} {1.0b}
  {tagpdf - user commands}
%</header>
%    \end{macrocode}
% \section{Setup and preamble commands}
% \begin{macro}{\tagpdfsetup}
%    \begin{macrocode}
%<base>\NewDocumentCommand \tagpdfsetup { m }{}
%<*package>
\RenewDocumentCommand \tagpdfsetup { m }
  {
    \keys_set:nn { @@ / setup } { #1 }
  }
%</package>
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\tag_tool:n,\tagtool (deprecated)}
% This command is deprecated and will be removed.
%    \begin{macrocode}
%<base>\cs_new_protected:Npn\tag_tool:n #1 {}
%<base>\cs_set_eq:NN\tagtool\tag_tool:n
%<*package>
\cs_set_protected:Npn\tag_tool:n #1
  {
    \tag_if_active:T { \keys_set:nn {tag / tool}{#1} }
  }
\cs_set_eq:NN\tagtool\tag_tool:n
%</package>
%    \end{macrocode}
% \end{macro}

% \section{Commands for the mc-chunks}
% \begin{macro}{\tagmcbegin,\tagmcend,\tagmcuse  }
%    \begin{macrocode}
%<*base>
\NewDocumentCommand \tagmcbegin { m }
  {
    \tag_mc_begin:n {#1}
  }


\NewDocumentCommand \tagmcend {  }
  {
    \tag_mc_end:
  }

\NewDocumentCommand \tagmcuse { m }
  {
    \tag_mc_use:n {#1}
  }
%</base>
%    \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}
%<*package>
\NewDocumentCommand \tagmcifinTF { m m }
  {
    \tag_mc_if_in:TF { #1 } { #2 }
  }
%</package>
%    \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}
%<*base>
\NewDocumentCommand \tagstructbegin { m }
  {
    \tag_struct_begin:n {#1}
  }

\NewDocumentCommand \tagstructend {  }
  {
   \tag_struct_end:
  }

\NewDocumentCommand \tagstructuse { m }
  {
    \tag_struct_use:n {#1}
  }
%</base>
%    \end{macrocode}
% \end{macro}
%
% \section{Tagging Socket support}
%
% \begin{macro}{\tag_socket_use:n,\tag_socket_use:nn,\tag_socket_use:nnn,\UseTaggingSocket,
% \tag_socket_use_expandable:n,\UseExpandableTaggingSocket}
%    \begin{macrocode}
%<*package>
\cs_set_protected:Npn \tag_socket_use:n #1
  {
    \bool_if:NT \l_@@_active_socket_bool
      { \socket_use:n {tagsupport/#1} }
  }
%    \end{macrocode}
%
%    \begin{macrocode}
\cs_set_protected:Npn \tag_socket_use:nn #1#2
  {
    \bool_if:NT \l_@@_active_socket_bool
       { \socket_use:nn {tagsupport/#1} {#2} }
  }
%    \end{macrocode}
%
%    \begin{macrocode}
\cs_set_protected:Npn \tag_socket_use:nnn #1#2#3
  {
    \bool_if:NTF \l_@@_active_socket_bool
      { \socket_use:nnn {tagsupport/#1} {#2} {#3} }
      { #3 }
  }
%    \end{macrocode}
%    \begin{macrocode}
\cs_set:Npn \tag_socket_use_expandable:n #1
  {
    \bool_if:NT \l_@@_active_socket_bool
      { \socket_use_expandable:n {tagsupport/#1} }
  }
%    \end{macrocode}
%    \begin{macrocode}
\cs_set_protected:Npn \UseTaggingSocket #1
  {
    \bool_if:NTF \l_@@_active_socket_bool
      { \socket_use:nw {tagsupport/#1} }
      {
        \int_case:nnF
            { \int_use:c { c__socket_tagsupport/#1_args_int } }
            {
              0 \prg_do_nothing:
              1 \use_none:n
              2 \use_ii:nn
%    \end{macrocode}
%    We do not expect tagging sockets with more than one or two
%    arguments, so for now we only provide those.
%    \begin{macrocode}
            }
            \ERRORusetaggingsocket
      }
  }
%    \end{macrocode}

%    \begin{macrocode}
\cs_set:Npn \UseExpandableTaggingSocket #1
  {
    \bool_if:NTF \l_@@_active_socket_bool
      { \socket_use_expandable:nw {tagsupport/#1} }
      {
        \int_case:nnF
            { \int_use:c { c__socket_tagsupport/#1_args_int } }
            {
              0 \prg_do_nothing:
              1 \use_none:n
              2 \use_ii:nn
%    \end{macrocode}
%    We do not expect tagging sockets with more than one or two
%    arguments, so for now we only provide those.
%    \begin{macrocode}
            }
            \ERRORusetaggingsocket
      }
  }
%</package>
%    \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}
%<*package>
\NewDocumentCommand\ShowTagging { m }
  {
    \keys_set:nn { @@ / show }{ #1}

  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{mc-data (show-key)}
% 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 =
      {
        \bool_if:NT \g_@@_mode_lua_bool
          {
            \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 (show-key)}
% 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
          {
            \int_compare:nNnTF
              { -2147483647 }
               =
              {
                \lua_now:e
                  {
                     tex.print
                      (\int_use:N\c_document_cctab,
                       tex.getattribute
                        (luatexbase.attributes.g_@@_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 (show-key)}
% 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 (show-key)}
%    \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
  }
%</package>
%    \end{macrocode}
% \end{macro}
% \begin{macro}{debug/structures (show-key)}
%  The following key is available only if the tagpdf-debug package is loaded
%  and shows all structures starting with the one with the number
%  given by the key.
%    \begin{macrocode}
%<*debug>
\keys_define:nn { @@ / show }
  {
    ,debug/structures .code:n =
      {
        \int_step_inline:nnn{#1}{\c@g_@@_struct_abs_int}
           {
            \msg_term:nneeee
                   { tag/debug } { show-struct }
                   { ##1 }
                   {
                     \prop_map_function:cN
                       {g_@@_struct_debug_##1_prop}
                       \msg_show_item_unbraced:nn
                   }
                   { } { }
            \msg_term:nneeee
                   { tag/debug } { show-kids }
                   {  ##1 }
                   {
                     \seq_map_function:cN
                       {g_@@_struct_debug_kids_##1_seq}
                       \msg_show_item_unbraced:n
                   }
                   { } { }
          }
      }
    ,debug/structures .default:n = 1
  }
%</debug>
%    \end{macrocode}
% \end{macro}
%
% \section{Commands to extend document commands}
% The following commands and code parts are not core commands of tagpdf.
% They 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.
%
%    \begin{macrocode}
%<*package>
%    \end{macrocode}
% \subsection{Document structure}
% \begin{macro}{\g_@@_root_default_tl,activate (setup-key),activate/socket (setup-key)}
%    \begin{macrocode}
\tl_new:N\g_@@_root_default_tl
\tl_gset:Nn\g_@@_root_default_tl {Document}

\hook_gput_code:nnn{begindocument}{tagpdf}{\tagstructbegin{tag=\g_@@_root_default_tl}}
\hook_gput_code:nnn{tagpdf/finish/before}{tagpdf}{\tagstructend}

\keys_define:nn { @@ / setup}
 {
   activate/socket .bool_set:N  = \l_@@_active_socket_bool,
   activate  .code:n =
    {
      \keys_set:nn { @@ / setup }
        { activate/mc,activate/tree,activate/struct,activate/socket }
      \tl_gset:Nn\g_@@_root_default_tl {#1}
    },
   activate .default:n = Document
 }

%    \end{macrocode}
% \end{macro}
%
% \subsection{Structure destinations}
% Since TeXlive 2022 pdftex and luatex offer support for structure destinations
% and the pdfmanagement has backend support for. We activate them if
% structures are actually created.
% Structure destinations are actually PDF 2.0  only but they don't harm in
% older PDF and can improve html export.
%    \begin{macrocode}
\AddToHook{begindocument/before}
  {
    \bool_lazy_and:nnT
      { \g_@@_active_struct_dest_bool }
      { \g_@@_active_struct_bool }
      {
        \tl_set:Nn \l_pdf_current_structure_destination_tl
           { {@@/struct}{\g_@@_struct_stack_current_tl }}
        \pdf_activate_indexed_structure_destination:
      }
   }
%    \end{macrocode}

% \subsection{Fake space}
% \begin{macro}{\pdffakespace}
% We need a luatex variant for |\pdffakespace|. This should probably go into
% the kernel at some time. We also provide a no-op version for dvi mode
%    \begin{macrocode}
\bool_if:NT \g_@@_mode_lua_bool
  {
    \NewDocumentCommand\pdffakespace { }
     {
       \@@_fakespace:
     }
  }
\providecommand\pdffakespace{}
%    \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_flattened_bool,
%   \l_@@_para_show_bool,
%   \g_@@_para_begin_int,
%   \g_@@_para_end_int,
%   \g_@@_para_main_begin_int,
%   \g_@@_para_main_end_int,
%   \g_@@_para_main_struct_tl,
%   \l_@@_para_tag_default_tl,
%   \l_@@_para_tag_tl,
%   \l_@@_para_main_tag_tl,
%   \l_@@_para_attr_class_tl,
%   \l_@@_para_main_attr_class_tl,
%   }
%  At first some variables.
%    \begin{macrocode}
%</package>
%<base>\bool_new:N \l_@@_para_flattened_bool
%<base>\bool_new:N \l_@@_para_bool
%<*package>
\int_new:N  \g_@@_para_begin_int
\int_new:N  \g_@@_para_end_int
\int_new:N  \g_@@_para_main_begin_int
\int_new:N  \g_@@_para_main_end_int
%    \end{macrocode}
% this will hold the structure number of the current text-unit.
%    \begin{macrocode}
\tl_new:N   \g_@@_para_main_struct_tl
\tl_gset:Nn  \g_@@_para_main_struct_tl {1}
\tl_new:N   \l_@@_para_tag_default_tl
\tl_new:N   \l_@@_para_tag_tl
\tl_set:Nn  \l_@@_para_tag_tl { \l_@@_para_tag_default_tl }
\tl_new:N   \l_@@_para_main_tag_tl
\tl_set:Nn  \l_@@_para_tag_default_tl { \UseStructureName {para/textblock} }
\tl_set:Nn  \l_@@_para_main_tag_tl    { \UseStructureName {para/semantic} }
%\tl_new:N   \l_@@_para_attr_class_tl % defined in lttagging
\tl_new:N   \l_@@_para_main_attr_class_tl
%    \end{macrocode}
% \end{macro}

% \begin{macro}
%   {
%   \@@_gincr_para_main_begin_int:,
%   \@@_gincr_para_main_end_int:,
%   \@@_gincr_para_begin_int:,
%   \@@_gincr_para_end_int:
%   }
% The global para counter should be set through commands so
% that \cs{tag_stop:} can stop them.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_gincr_para_main_begin_int:
 {
   \int_gincr:N \g_@@_para_main_begin_int
 }
\cs_new_protected:Npn \@@_gincr_para_begin_int:
 {
   \int_gincr:N \g_@@_para_begin_int
 }
\cs_new_protected:Npn \@@_gincr_para_main_end_int:
 {
   \int_gincr:N \g_@@_para_main_end_int
 }
\cs_new_protected:Npn \@@_gincr_para_end_int:
 {
   \int_gincr:N \g_@@_para_end_int
 }
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\@@_start_para_ints:,\@@_stop_para_ints:}
%    \begin{macrocode}
\cs_new_protected:Npn \@@_start_para_ints:
 {
   \cs_set_protected:Npn \@@_gincr_para_main_begin_int:
     {
       \int_gincr:N \g_@@_para_main_begin_int
     }
   \cs_set_protected:Npn \@@_gincr_para_begin_int:
    {
      \int_gincr:N \g_@@_para_begin_int
    }
   \cs_set_protected:Npn \@@_gincr_para_main_end_int:
    {
      \int_gincr:N \g_@@_para_main_end_int
    }
   \cs_set_protected:Npn \@@_gincr_para_end_int:
    {
      \int_gincr:N \g_@@_para_end_int
    }
 }
\cs_new_protected:Npn \@@_stop_para_ints:
 {
   \cs_set_eq:NN \@@_gincr_para_main_begin_int:\prg_do_nothing:
   \cs_set_eq:NN \@@_gincr_para_begin_int: \prg_do_nothing:
   \cs_set_eq:NN \@@_gincr_para_main_end_int: \prg_do_nothing:
   \cs_set_eq:NN \@@_gincr_para_end_int: \prg_do_nothing:
 }
%    \end{macrocode}
% \end{macro}
%
% We want to be able to inspect the current para main structure, so
% we need a command to store its structure number
% \begin{macro}{\@@_para_main_store_struct:}
%    \begin{macrocode}
\cs_new:Npn \@@_para_main_store_struct:
  {
    \tl_gset:Ne \g_@@_para_main_struct_tl {\int_use:N \c@g_@@_struct_abs_int }
  }
%    \end{macrocode}
% \end{macro}
%
%\begin{macro}
% {
%  para/tagging (setup-key),
%  para/tag (setup-key),
%  para/maintag (setup-key),
%  para/tagging (tool-key),
%  para/tag (tool-key),
%  para/maintag (tool-key),
%  para/flattened (tool-key),
%  unittag (deprecated),
%  para-flattened (deprecated),
%  paratagging (deprecated),
%  paratagging-show (deprecated),
%  paratag (deprecated),
%  }
% These keys enable/disable locally paratagging.
% Paragraphs are typically tagged with two structure: A main structure
% around the whole paragraph, and inner structures around the various chunks.
% Debugging can be
% activated locally with |debug/show=para|, this can affect the typesetting
% as the small numbers
% are boxes and they have a (small) height. Debugging can be deactivated
% with |debug/show=paraOff|
% The |para/tag| key sets the tag used by
% the inner structure, |para/maintag| the tag of the outer structure,
% both can also be changed with |\tag_tool:n|
%    \begin{macrocode}
\keys_define:nn { @@ / setup }
  {
    para/tagging      .bool_set:N = \l_@@_para_bool,
    debug/show/para   .code:n = {\bool_set_true:N \l_@@_para_show_bool},
    debug/show/paraOff  .code:n = {\bool_set_false:N \l_@@_para_show_bool},
    para/tag          .tl_set:N   = \l_@@_para_tag_tl,
    para/maintag      .tl_set:N   = \l_@@_para_main_tag_tl,
    para/flattened    .bool_set:N = \l_@@_para_flattened_bool
  }
%    \end{macrocode}
% deprecated key definitions:
%    \begin{macrocode}
\keys_define:nn { tag / tool}
  {
    para/tagging   .bool_set:N = \l_@@_para_bool,
    para/tag       .tl_set:N = \l_@@_para_tag_tl,
    para/maintag   .tl_set:N = \l_@@_para_main_tag_tl,
    para/flattened .bool_set:N = \l_@@_para_flattened_bool
  }
%    \end{macrocode}
% the deprecated names
%    \begin{macrocode}
\keys_define:nn { @@ / setup }
  {
    paratagging      .bool_set:N = \l_@@_para_bool,
    paratagging-show .bool_set:N = \l_@@_para_show_bool,
    paratag          .tl_set:N   = \l_@@_para_tag_tl
  }
%    \end{macrocode}
% still needed as used in block code ...
%    \begin{macrocode}
\keys_define:nn { tag / tool}
  {
    para    .bool_set:N = \l_@@_para_bool,
    paratag .tl_set:N = \l_@@_para_tag_tl,
    unittag .tl_set:N = \l_@@_para_main_tag_tl,
    para-flattened .bool_set:N = \l_@@_para_flattened_bool
  }  
%    \end{macrocode}
% \end{macro}
% Helper command for debugging:
%    \begin{macrocode}
\cs_new_protected:Npn \@@_check_para_begin_show:nn #1 #2
 %#1 color, #2 prefix
  {
    \bool_if:NT \l_@@_para_show_bool
      {
        \tag_mc_begin:n{artifact}
        \llap{\color_select:n{#1}\tiny#2\int_use:N\g_@@_para_begin_int\ }
        \tag_mc_end:
      }
  }

\cs_new_protected:Npn \@@_check_para_end_show:nn #1 #2
 %#1  color, #2 prefix
  {
    \bool_if:NT \l_@@_para_show_bool
      {
        \tag_mc_begin:n{artifact}
        \rlap{\color_select:n{#1}\tiny\ #2\int_use:N\g_@@_para_end_int}
        \tag_mc_end:
      }
  }
%    \end{macrocode}
%
%    \begin{macrocode}
\AddToHook{begindocument/before}[tagpdf/para]
  {
    \AddToHook{para/begin}[tagpdf]{ \tag_socket_use:n { para/begin } }
    \AddToHook{para/end}  [tagpdf]  { \tag_socket_use:n { para/end } }
  }
%    \end{macrocode}
%
% We check the para count at the end. If tagging is not active it is not a error,
% but we issue a warning as it perhaps indicates that the code didn't guard
% everything correctly with tagging sockets.
%    \begin{macrocode}
\AddToHook{enddocument/info}
  {
    \tag_if_active:F
      {
        \msg_redirect_name:nnn { tag } { para-hook-count-wrong } { warning }
      }
    \int_compare:nNnF {\g_@@_para_main_begin_int}={\g_@@_para_main_end_int}
         {
           \msg_error:nneee
             {tag}
             {para-hook-count-wrong}
             {\int_use:N\g_@@_para_main_begin_int}
             {\int_use:N\g_@@_para_main_end_int}
             {text-unit}
         }
    \int_compare:nNnF {\g_@@_para_begin_int}={\g_@@_para_end_int}
         {
           \msg_error:nneee
             {tag}
             {para-hook-count-wrong}
             {\int_use:N\g_@@_para_begin_int}
             {\int_use:N\g_@@_para_end_int}
             {text}
         }
  }
%    \end{macrocode}
%</package>
%   
% \begin{macro}
%   {
%    \tagpdfparaOn,
%    \tagpdfparaOff
%   }
%  This two command switch para mode on and off. |\tagpdfsetup| could be used
%  too but is longer. An alternative is |\tag_tool:n{para/tagging=false}|
%    \begin{macrocode}
%<base>\newcommand\tagpdfparaOn {}
%<base>\newcommand\tagpdfparaOff{}
%<*package>
\renewcommand\tagpdfparaOn {\bool_set_true:N \l_@@_para_bool}
\renewcommand\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{Language support}
%
% With the following key the lang variable is set. All structures in the current group will
% then set this lang variable.
% \begin{macro}{test/lang (setup-key)}
%    \begin{macrocode}
\keys_define:nn { @@ / setup }
  {
    text / lang .tl_set:N = \l_@@_struct_lang_tl
  }
%    \end{macrocode}
% \end{macro}
% \subsection{Header and footer}
% Header and footer should normally be tagged as artifacts. The following code
% requires the output tagging sockets.
% 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:{}
%    \end{macrocode}
% We use the page sockets.
%    \begin{macrocode}
\NewTaggingSocketPlug{build/page/header}{tagpdf}
    {
      \@@_hook_kernel_before_head:
      #2
      \@@_hook_kernel_after_head:
    }

\AssignTaggingSocketPlug{build/page/header}{tagpdf}
\NewTaggingSocketPlug{build/page/footer}{tagpdf}
   {
     \@@_hook_kernel_before_foot:
     #2
     \@@_hook_kernel_after_foot:
   }
\AssignTaggingSocketPlug{build/page/footer}{tagpdf}
%    \end{macrocode}
%
%    \begin{macrocode}
\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}
    \tag_suspend:n{headfoot}
 }
\cs_new_protected:Npn \@@_exclude_headfoot_end:
 {
    \tag_resume:n{headfoot}
    \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
     }
 }
%    \end{macrocode}
% This version allows to use an Artifact structure
%    \begin{macrocode}
\@@_attr_new_entry:nn {@@/attr/pagination}{/O/Artifact/Type/Pagination}
\cs_new_protected:Npn \@@_exclude_struct_headfoot_begin:n #1
 {
    \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_struct_begin:n{tag=Artifact,attribute-class=@@/attr/#1}
    \tag_mc_begin:n {artifact=#1}
    \tag_suspend:n{headfoot}
 }

\cs_new_protected:Npn \@@_exclude_struct_headfoot_end:
 {
    \tag_resume:n{headfoot}
    \tag_mc_end:
    \tag_struct_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
     }
 }
%    \end{macrocode}
% And now the keys
% \begin{macro}{page/exclude-header-footer (setup-key),exclude-header-footer (deprecated)}
%    \begin{macrocode}
\keys_define:nn { @@ / setup }
  {
    page/exclude-header-footer .choice:,
    page/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:
     },
    page/exclude-header-footer / pagination .code:n =
     {
       \cs_set:Nn \@@_hook_kernel_before_head: { \@@_exclude_struct_headfoot_begin:n {pagination} }
       \cs_set:Nn \@@_hook_kernel_before_foot: { \@@_exclude_struct_headfoot_begin:n {pagination} }
       \cs_set_eq:NN \@@_hook_kernel_after_head:  \@@_exclude_struct_headfoot_end:
       \cs_set_eq:NN \@@_hook_kernel_after_foot:  \@@_exclude_struct_headfoot_end:
     },
    page/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:
     },
   page/exclude-header-footer .default:n = true,
   page/exclude-header-footer .initial:n = true,
%    \end{macrocode}
% deprecated name
%    \begin{macrocode}
   exclude-header-footer .meta:n = { page/exclude-header-footer = {#1} }
  }
%    \end{macrocode}
% \end{macro}
% 
%  A special, experimental tagged version, which only works with fancyhdr or similar that uses
%  parbox. The sockets aren't in lttagging yet, so until 2026-06-01 we have to declare
%  the plugs at begin document:
%    \begin{macrocode}
\AtBeginDocument
  {
    \NewTaggingSocketPlug{parbox/before}{tag/footer}
      {
       \tag_struct_begin:n{tag=Span}
       \tag_mc_begin:n{}
      }
      
    \NewTaggingSocketPlug{parbox/after}{tag/footer}
      {
       \tag_mc_end:   
       \tag_struct_end:
      } 
  }
\cs_new_protected:Npn \@@_headfoot_tagged_begin:n #1
 { 
   \AssignTaggingSocketPlug{parbox/before}{tag/footer}
   \AssignTaggingSocketPlug{parbox/after}{tag/footer}
    \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_struct_begin:n{tag=Artifact,attribute-class=_@@/attr/#1,parent=\tag_get:n{current_Sect}}
 }

\cs_new_protected:Npn \@@_headfoot_tagged_end:
 {
    \tag_struct_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 }
 { 
   page/tag-header-footer .choice:,   
   page/tag-header-footer/artifact .code:n = 
    {    
      \cs_set:Nn \__tag_hook_kernel_before_head: { \__tag_headfoot_tagged_begin:n {pagination}}
      \cs_set:Nn \__tag_hook_kernel_before_foot: { \__tag_headfoot_tagged_begin:n {pagination}}
      \cs_set_eq:NN \__tag_hook_kernel_after_head:  \__tag_headfoot_tagged_end:
      \cs_set_eq:NN \__tag_hook_kernel_after_foot:  \__tag_headfoot_tagged_end:    
    },
   page/tag-header-footer .default:n = artifact, 
 }   
%    \end{macrocode}
% \subsection{Links}
% We need to close and reopen mc-chunks around links.
% We handle URI, GoTo (internal) links, GoToR, Launch and Named links.
% Links should have an alternative text in the Contents
% key; this is added for normal links by the generic hyperref driver.
% With luatex we make use of the lualinksplit package to get
% OBJR of all annotations into the Link structure, so the hook code
% should not contain the command to insert the OBJR into the structure.
% 
% At first we provide the link name that will be in the next LaTeX release (06/2026)
%    \begin{macrocode}
\AddToHookNext{class/before}
 {
   \cs_if_exist:NF \l_@@_name_link_tl
    {
      \tl_new:N  \l_@@_name_link_tl
      \tl_set:Nn \l_@@_name_link_tl{Link}
    }
 }
%    \end{macrocode}
% Tagging sockets for links
%    \begin{macrocode}
\socket_if_exist:nF {tagsupport/link/before}
 { 
   \NewTaggingSocket{link/before}{1} 
   \NewTaggingSocket{link/after}{1}
 }
\NewTaggingSocketPlug{link/before}{kernel}
 { 
   \mode_leave_vertical:
   \tag_mc_end_push:
   \tag_struct_begin:n { tag=\UseStructureName{link} }
   \tag_mc_begin:n {}
   #1
 }
\AssignTaggingSocketPlug{link/before}{kernel}

\NewTaggingSocketPlug{link/after}{kernel}
 {
   #1
   \tag_mc_end:
   \tag_struct_end:
   \tag_mc_begin_pop:n{}
 }
\AssignTaggingSocketPlug{link/after}{kernel}


\bool_lazy_and:nnTF
 { \sys_if_engine_luatex_p: }
 {
   \tl_if_empty_p:e
    {
      \lua_now:e
       { if~ luatexbase.in_callback('pre_shipout_filter','linksplit')~
         then~else~tex.print('1')~end
       }
    }
 }
 {
   \hook_gput_code:nnn
     {pdfannot/link/URI/before}
     {tagpdf}
     {
       \UseTaggingSocket{link/before}{}
     }

   \hook_gput_code:nnn
     {pdfannot/link/URI/after}
     {tagpdf}
     {
       \UseTaggingSocket{link/after}{}
     }

   \hook_gput_code:nnn
     {pdfannot/link/GoTo/before}
     {tagpdf}
     {
       \UseTaggingSocket{link/before}{}
     }

   \hook_gput_code:nnn
     {pdfannot/link/GoTo/after}
     {tagpdf}
     {
       \UseTaggingSocket{link/after}{}
     }

   \hook_gput_code:nnn
     {pdfannot/link/GoToR/before}
     {tagpdf}
     {
       \UseTaggingSocket{link/before}
     }

   \hook_gput_code:nnn
     {pdfannot/link/GoToR/after}
     {tagpdf}
     {
       \UseTaggingSocket{link/after}{}
     }
   \hook_gput_code:nnn
     {pdfannot/link/Launch/before}
     {tagpdf}
     {
       \UseTaggingSocket{link/before}{}
     }

   \hook_gput_code:nnn
     {pdfannot/link/Launch/after}
     {tagpdf}
     {
       \UseTaggingSocket{link/after}{}
     }
   \hook_gput_code:nnn
     {pdfannot/link/Named/before}
     {tagpdf}
     {
       \UseTaggingSocket{link/before}{}
     }

   \hook_gput_code:nnn
     {pdfannot/link/Named/after}
     {tagpdf}
     {
       \UseTaggingSocket{link/after}{}
     }
 }
 {
   \hook_gput_code:nnn
     {pdfannot/link/URI/before}
     {tagpdf}
     {
       \UseTaggingSocket{link/before}
        {       
         \pdfannot_dict_put:nne
           { link/URI }
           { StructParent }
           { \tag_struct_parent_int: }
        } 
     }

   \hook_gput_code:nnn
     {pdfannot/link/URI/after}
     {tagpdf}
     {
       \UseTaggingSocket{link/after}
        { 
         \tag_struct_insert_annot:ee 
          {\pdfannot_link_ref_last:}{\tag_struct_parent_int:} 
        } 
     }

   \hook_gput_code:nnn
     {pdfannot/link/GoTo/before}
     {tagpdf}
     {
       \UseTaggingSocket{link/before}
        {       
         \pdfannot_dict_put:nne
           { link/GoTo }
           { StructParent }
           { \tag_struct_parent_int: }
        } 
     }

   \hook_gput_code:nnn
     {pdfannot/link/GoTo/after}
     {tagpdf}
     {
       \UseTaggingSocket{link/after}
        { 
         \tag_struct_insert_annot:ee 
          {\pdfannot_link_ref_last:}{\tag_struct_parent_int:} 
        } 
     }

   \hook_gput_code:nnn
     {pdfannot/link/GoToR/before}
     {tagpdf}
     {
        \UseTaggingSocket{link/before}
        {       
         \pdfannot_dict_put:nne
           { link/GoToR }
           { StructParent }
           { \tag_struct_parent_int: }
        } 
     }

   \hook_gput_code:nnn
     {pdfannot/link/GoToR/after}
     {tagpdf}
     {
       \UseTaggingSocket{link/after}
        { 
         \tag_struct_insert_annot:ee 
          {\pdfannot_link_ref_last:}{\tag_struct_parent_int:} 
        } 
     }

   \hook_gput_code:nnn
     {pdfannot/link/Named/before}
     {tagpdf}
     {
       \UseTaggingSocket{link/before}
        {       
         \pdfannot_dict_put:nne
           { link/Named }
           { StructParent }
           { \tag_struct_parent_int: }
        } 
     }

   \hook_gput_code:nnn
     {pdfannot/link/Named/after}
     {tagpdf}
     {
       \UseTaggingSocket{link/after}
        { 
         \tag_struct_insert_annot:ee 
          {\pdfannot_link_ref_last:}{\tag_struct_parent_int:} 
        } 
     }
   \hook_gput_code:nnn
     {pdfannot/link/Launch/before}
     {tagpdf}
     {
        \UseTaggingSocket{link/before}
         {       
           \pdfannot_dict_put:nne
             { link/Launch }
             { StructParent }
             { \tag_struct_parent_int: }
         } 
     }

   \hook_gput_code:nnn
     {pdfannot/link/Launch/after}
     {tagpdf}
     {
       \UseTaggingSocket{link/after}
        { 
         \tag_struct_insert_annot:ee 
          {\pdfannot_link_ref_last:}{\tag_struct_parent_int:} 
        } 
     }
  }
%    \end{macrocode}
%
% \subsection{Attaching css-files for derivation}
%
% Derivation to html (https://pdfa.org/wp-content/uploads/2019/06/Deriving_HTML_from_PDF.pdf,
% implemented by, e.g., ngpdf) can be improved by attaching CSS style definitions
% in associated files with relationship supplement to the Catalog\footnote{Previously they
% suggested the StructTreeRoot, but this is not compatible with pdf/A-3}.
%
% Such CSS style definitions can be given in two ways:
%  \begin{itemize}
%   \item In files with the extension \texttt{.css}. Such files should contain only
%   CSS style definitions. ngpdf will store these files and include them with an
%  \verb+<link rel=stylesheet href=...>+ in the head of the html.
%  \item In files with the extension \texttt{.html}. Such files should contain CSS style
%  definitions inside one (or more) \verb+<style>...</style>+ html tags. The content of these
%  files are copied by ngpdf directly into the head of the derived html.
%  \end{itemize}
%
% By default (if tagging is active) tagpdf embeds now such CSS style definitions.
% Currently the list of files is rather short and consists of two files (with extension
% .html and \verb+<style>...</style>+ html tags) which are provided by the tagpdf package:
% \begin{itemize}
% \item latex-align-css.html which improves the styling of amsmath alignments tagged with MathML.
% \item latex-list-css.html which improves the style of list environments.
% \end{itemize}
%
% It is possible to suppress the embedding of these files by setting the \cs{tagpdfsetup} key
% \texttt{attach-css} to \texttt{false}, \texttt{attach-css=true} or \texttt{attach-css} reverts this again.
%
% For developers, \cs{tagpdfsetup} some keys to manipulate the list exist:
% With \verb+css-list={file1,file2}+ the list can be overwritten. \verb+css-list=+ clears
% the list (and so suppresses the embedding too).
% To remove a file from the list, use \verb+css-list-remove=file+, e.g.
% \verb+css-list-remove=latex-list-css.html+. To add your
% own file use \verb+css-list-add=my-fancy-align-css.html+.
% It is also possible to attach a .css-file in this way.
%
% These keys do not affect files added directly with root-supplemental-file or catalog-supplemental-file.
%
% The files in this list are attached at the end of the compilation 
% but you shouldn't rely on a specific order of the embedding in the html.
%
% We want to avoid to embed files twice, so we use a prop.
%    \begin{macrocode}
\prop_new:N \g_@@_css_prop
\prop_gset_from_keyval:Nn \g_@@_css_prop
 {
   latex-list-css.html=true,
   latex-align-css.html=true
 }


\bool_new:N \g_@@_css_bool
\bool_gset_true:N \g_@@_css_bool
%    \end{macrocode}
% The files for the catalog must be added before the catalog is pushed.
%    \begin{macrocode}
\tl_gput_left:Nn \g__kernel_pdfmanagement_end_run_code_tl
 {
  \bool_lazy_and:nnT  { \g_@@_css_bool }{ \tag_if_active_p: }
   {
    \prop_map_inline:Nn \g_@@_css_prop
     {
       \keys_set:nn { @@ / setup }{ catalog-supplemental-file= {#1} }
     }
   }
 }

\keys_define:nn { @@ / setup }
  {
    attach-css .bool_gset:N = \g_@@_css_bool,
    css-list .code:n =
      {
        \tl_if_empty:nTF{#1}
          {\prop_gclear:N \g_@@_css_prop }
          {\prop_gput:Nnn \g_@@_css_prop { #1 }{true}}
      },
    css-list-add .code:n    = { \prop_gput:Nnn \g_@@_css_prop { #1 }{true} },
    css-list-remove .code:n = { \prop_gremove:Nn \g_@@_css_prop { #1 } },
  }
%    \end{macrocode}
%</package>
% \end{implementation}
% \PrintIndex
