% \iffalse meta-comment
%
%% File: latex-lab-tikz.dtx (C) Copyright 2025 LaTeX Project
%
% 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
%
%
% The latex-lab bundle is developed in the LaTeX2e GitHub.
% Issues may be reported at
%
%    https://github.com/latex3/latex2e/issues
%
\def\ltlabtikzdate{2026-05-12}
\def\ltlabtikzversion{0.80i}
%<*driver>
\DocumentMetadata{tagging=on,pdfstandard=ua-2}
\documentclass[kernel]{l3in2edoc}

\EnableCrossrefs
\CodelineIndex
\begin{document}
  \DocInput{latex-lab-tikz.dtx}
\end{document}
%</driver>
%
% \fi
%
% \providecommand\tikzname{Ti\textit{k}Z}
% \title{The \textsf{latex-lab-tikz} package\\
% Support for the tagging of \tikzname\ pictures }
% \author{\LaTeX{} Project\thanks{Initial implementation done by Ulrike Fischer}}
% \date{v\ltlabtikzversion\ \ltlabtikzdate}
%
% \maketitle
%
% \newcommand{\xt}[1]{\textsl{\textsf{#1}}}
% \newcommand{\TODO}[1]{\textbf{[TODO:} #1\textbf{]}}
% \newcommand{\docclass}{document class \marginpar{\raggedright document class
% customizations}}
%
%
% \begin{abstract}
% \end{abstract}
%
% \section{Introduction}
%
% This implements the tagging of \tikzname\ picture along the ideas
% described in latex-lab-graphic, please check its documentation for the
% background!
%
% Resulting structures and contents should be checked!
%
% The code doesn't use the generic sockets documented in \texttt{latex-lab-graphic}
% but instead sets up sockets and keys that are \tikzname-specific. One reason for
% this approach is to avoid that the tagging \tikzname\ pictures has side effect on pictures
% but more importantly because as this implementation patches into
% tikz internals special code in the plugs is required.
%
% The module is automatically loaded if \texttt{tagging=on} or \texttt{testphase=latest}
% is used. The patches of \tikzname\ commands can be suppressed by removing the
% code with the label \texttt{latex-lab-testphase-tikz} from the hook
% \texttt{package/tikz/after} before loading \tikzname.
%
% The module implements a number of keys that can be used both in \cs{tikzset} and in the
% optional argument of \texttt{tikzpicture} and \cs{tikz}.
%
% \begin{description}
%  \item[\texttt{alt}] This key switches to the illustrative mode. Its value is the
%  alternative text. If no value is given the alternative text variable is not changed,
%  \texttt{alt=} will empty the text variable.
%  \item[\texttt{actualtext}] This switches to the actualtext mode.
%  This is useful for small graphics that represent single chars or a short word like a
%  logo. If \texttt{actualtext} is used, the graphics is not enclosed in a \texttt{Figure}
%  structure but in a \texttt{Span} structure and no \texttt{/BBox} attribute is added.%
%  \footnote{This is in accordance with PDF/UA-2 but violates perhaps PDF/UA-1.}
%  \item[\texttt{artifact}] This tags the graphic as an artifact.
%  \item[\texttt{tagging-setup}] This key takes as argument a key-list,
%  which can contain the following keys:
%   \begin{description}
%    \item[\texttt{alt=\meta{text}}] This is a second way to tag the graphic as a figure with
%    alternative text. \texttt{alt} without value will tag as a figure but not change
%    the text variable, \texttt{alt=} will empty the text variable.
%    \item[\texttt{actualtext=\meta{text}}] This is a second way to tag the graphic as a
%    symbol with actualtext.
%    \item[\texttt{artifact}] This is a second way to tag the graphic as artifact.
%    \item[\texttt{text}] This switches to text mode.
%    \item[\texttt{off}] When used tagging will be stopped completely. It is then the
%   responsibility of the surrounding code to add appropriate tagging commands.
%   \item[\texttt{tag=\meta{name}}] This switches to the illustrative mode but uses
%   \meta{name} as tag name in the structure instead of the default \texttt{Figure}.
%   This can for example be used to tag an image of a formula with \texttt{Formula}.
%   The key typically should be combined with a suitable alt key:
%   \begin{verbatim}
%   \begin{tikzpicture}[tagging-setup={alt=math,tag=Formula}]
%   \end{verbatim}
%   \end{description}
%  \end{description}
%
%  It is possible to define new keys to change the tagging setup.
%  As they should be processed earlier than normal tikz keys,
%  they must be part of a special family:
%
%  \begin{verbatim}
%  \tikzset
%   {
%     my alt/.style 2 args={alt=`#1' is for #2,},
%     my alt/.belongs to family=/tikz/tagging-setup,
%   }
%   \begin{tikzpicture}[my alt={A}{ardvaark}]
%   ...
%   \end{tikzpicture}
%   \end{verbatim}
%
%  \changes{v0.80f}{2026-02-27}{Use \texttt{pgfkeys} for setup.}
%  \changes{v0.80f}{2026-02-27}{Use symbolic names.}
% \begin{implementation}
% \section{Implementation}
%    \begin{macrocode}
%<*package>
%<@@=tag>
%    \end{macrocode}
%    \begin{macrocode}
\ProvidesExplPackage {latex-lab-testphase-tikz} {\ltlabtikzdate} {\ltlabtikzversion}
  {Code related to the tagging of tikz pictures}
%    \end{macrocode}
%
% \subsection{Sockets}
%
% \begin{socketdecl}{
%   tagsupport/tikz/picture/init,
%   tagsupport/tikz/picture/begin,
%   tagsupport/tikz/picture/end}
% Sockets at the begin and the end of a tikzpicture.
% The argument in the \texttt{init}
% should process the keys of the picture and switch
% the plugs if needed. Unlike the generic sockets the
% begin and end sockets here do not need arguments.
%    \begin{macrocode}
\NewTaggingSocket{tikz/picture/init}{1}
\NewTaggingSocket{tikz/picture/begin}{0}
\NewTaggingSocket{tikz/picture/end}{0}
%    \end{macrocode}
% \end{socketdecl}
%
% \begin{socketdecl}{tagsupport/tikz/picture/text/begin,tagsupport/tikz/picture/text/end}
% Sockets at the end and begin of text parts.
%    \begin{macrocode}
\NewSocket{tagsupport/tikz/picture/text/begin}{0}
\NewSocket{tagsupport/tikz/picture/text/end}{0}
%    \end{macrocode}
% \end{socketdecl}
%%
%
% \subsection{Plugs}
%
% \begin{plugdecl}{default (tagsupport/tikz/picture/init)}
% The init socket takes a list of keys, processes the known keys to setup tagging options
% and then assigns the plugs.
% \changes{0.80i}{2026-05-12}{Change key filter to support keys not in the tikz path, tagging/1344}
%    \begin{macrocode}
\NewTaggingSocketPlug{tikz/picture/init}{default}
  {
    \pgfkeyssavekeyfilterstateto\tikz@temp@tagging@saved@filterstate
    \pgfkeysinstallkeyfilter{/pgf/key~filters/active~families~or~no~family}
      {{/pgf/key~filters/false}{/pgf/key~filters/false}}
    \pgfqkeysactivatesinglefamilyandfilteroptions{/tikz/tagging-setup}{/tikz}{#1}
    \tikz@temp@tagging@saved@filterstate
  }
\AssignTaggingSocketPlug{tikz/picture/init}{default}
%    \end{macrocode}
% \end{plugdecl}
%
% \begin{plugdecl}{text (tagsupport/tikz/picture/begin),text (tagsupport/tikz/picture/end)}
% This plug handles the \tikzname\ picture as a text object. So the graphical parts
% are tagged as artifact, but when we encounter a node we activate tagging there.
% There is no BBox. A \tikzname\ picture does not necessarly starts with a \cs{leavevmode}
% so we test for vmode.
%    \begin{macrocode}
\NewTaggingSocketPlug{tikz/picture/begin}{text}
  {
   \mode_if_vertical:T
    {
     \legacy_if:nTF {@inlabel} {\leavevmode} {\tag_socket_use:n{para/begin}}
    }
   \tag_mc_end_push:
   \tagmcbegin{artifact}
%    \end{macrocode}
% We hook into two pgf commands to add the tagging code.
% They are only used for postscript and svg so it should be
% safe inside a tagging socket for now.
% TODO: ask for an interface.
%    \begin{macrocode}
   \def\pgfsys@begin@text
    {
      \tag_resume:n{\pgfpicture}
      \tag_socket_use:n{tikz/picture/text/begin}
    }
   \def\pgfsys@end@text
    {
      \tag_socket_use:n{tikz/picture/text/end}
      \tag_suspend:n{\pgfpicture}
    }
  }
\NewTaggingSocketPlug{tikz/picture/end}{text}
  {
   \tagmcend
   \tag_mc_begin_pop:n{}
  }
%    \end{macrocode}
% \end{plugdecl}
%
% \begin{plugdecl}{figure (tagsupport/tikz/picture/begin),figure (tagsupport/tikz/picture/end)}
% This plug handles the \tikzname\ picture as a figure.
% Around the graphic is a \texttt{Figure} environment which will
% use an alt text given in the optional argument and internally tagging is suspended.
% The Bbox will be set (after the second compilation) to the size of the bounding box.
%    \begin{macrocode}
\NewTaggingSocketPlug{tikz/picture/begin}{alt}
  {
   \mode_if_vertical:T
    {
     \legacy_if:nTF {@inlabel} {\leavevmode} {\tag_socket_use:n{para/begin}}
    }
    \tag_mc_end_push:
    \tag_struct_begin:n
     {
      tag=\UseStructureName{graphic},
      alt=\l__tikz_tagging_alt_tl
     }
    \pgfrememberpicturepositiononpagetrue
    \tag_mc_begin:n{tag=Figure}
  }

\NewTaggingSocketPlug{tikz/picture/end}{alt}
  {
   \tag_mc_end:
%    \end{macrocode}
% this is the code that calculates and sets the BBox attribute
% \changes{0.80d}{2025-09-27}{Support also pgfplots. Tagging issue 924}
%    \begin{macrocode}
   \cs_set:Npn\pgfqpoint##1##2
    {
      \tl_set:Ne\l_tmpa_tl
       {
         \dim_to_decimal_in_bp:n {##1+ \pgf@picminx}
         \c_space_tl
         \dim_to_decimal_in_bp:n {##2+ \pgf@picminy}
         \c_space_tl
         \dim_to_decimal_in_bp:n {##1+ \pgf@picmaxx}
         \c_space_tl
         \dim_to_decimal_in_bp:n {##2+ \pgf@picmaxx}
       }
    }
%    \end{macrocode}
% The following command executes a \cs{pgfqpoint} command with the origin coordinates,
% and so set the \cs{l_tmpa_tl} used then in the BBox command. With pgfplots
% the command is not expandable. So we execute it before the structure command.
%    \begin{macrocode}
   \cs_if_exist:cT { pgf@sys@pdf@mark@pos@pgfid\the\pgf@picture@serial@count }
    {
      \use:c { pgf@sys@pdf@mark@pos@pgfid\the\pgf@picture@serial@count }
      \tag_struct_gput:ene
        {\tag_get:n{struct_num}}
        {attribute}
        {
          /O /Layout /BBox~
          [
            \l_tmpa_tl
          ]
        }
     }
   \tag_struct_end:
   \tag_mc_begin_pop:n{}
  }
%    \end{macrocode}
% \end{plugdecl}
%
% \begin{plugdecl}{actualtext (tagsupport/tikz/picture/begin),actualtext (tagsupport/tikz/picture/end)}
% This plug handles the \tikzname\ picture as a symbol with an actualtext.
% It tags the content as a Span and expects an actualtext.
% Internally tagging is suspended.
%    \begin{macrocode}
\NewTaggingSocketPlug{tikz/picture/begin}{actualtext}
  {
   \mode_if_vertical:T
    {
     \legacy_if:nTF {@inlabel} {\leavevmode} {\tag_socket_use:n{para/begin}}
    }
   \tag_mc_end_push:
   \tag_struct_begin:n
     {tag=\UseStructureName{graphic/symbol},
      actualtext=\l__tikz_tagging_actualtext_tl}
   \tag_mc_begin:n{}
  }

\NewTaggingSocketPlug{tikz/picture/end}{actualtext}
  {
   \tag_mc_end:
   \tag_struct_end:
   \tag_mc_begin_pop:n{}
  }
%    \end{macrocode}
% \end{plugdecl}
%
% \begin{plugdecl}{artifact (tagsupport/tikz/picture/begin),artifact (tagsupport/tikz/picture/end)}
% This plug handles the \tikzname\ picture as an artifact, as decoration.
% So it is surrounded by an artifact MC and internal text does not restart tagging.
%    \begin{macrocode}
\NewTaggingSocketPlug{tikz/picture/begin}{artifact}
  {
    \mode_if_vertical:T
     {
      \legacy_if:nTF {@inlabel} {\leavevmode} {\tag_socket_use:n{para/begin}}
     }
    \tag_mc_end_push:
    \tag_mc_begin:n {artifact}
  }

\NewTaggingSocketPlug{tikz/picture/end}{artifact}
  {
    \tag_mc_end:
    \tag_mc_begin_pop:n{}
  }
%    \end{macrocode}
% \end{plugdecl}
%
%  By default we use the text plugs. This allow packages like todonotes to
%  get a sensible tagging without changes.
%    \begin{macrocode}
\AssignTaggingSocketPlug{tikz/picture/begin}{text}
\AssignTaggingSocketPlug{tikz/picture/end}{text}
%    \end{macrocode}
%
% \begin{plugdecl}{default (tagsupport/tikz/picture/text/begin),
%  default (tagsupport/tikz/picture/text/end)}
% These sockets are used inside the text
% plugs and ends the previous mc and restarts it after the text.
%    \begin{macrocode}
\NewTaggingSocketPlug{tikz/picture/text/begin}{default}
  {
   \tag_mc_end:
   \tag_mc_begin:n{}
  }
\NewTaggingSocketPlug{tikz/picture/text/end}{default}
  {
   \tag_mc_end:
   \tag_mc_begin:n {artifact}
  }
\AssignTaggingSocketPlug{tikz/picture/text/begin}{default}
\AssignTaggingSocketPlug{tikz/picture/text/end}{default}
%    \end{macrocode}
% \end{plugdecl}
%
% \subsection{Patching tagging into tikz}
% We add the begin socket to the \cs{tikz@picture} command (it is also used
% by \cs{tikz}).
% This allows us to process the keys of the picture, assign the plugs
% and then to suspend tagging.
%    \begin{macrocode}
\AddToHook{package/tikz/after}
 {
   \AddToHookWithArguments{cmd/tikz@picture/before}
     {
       \tag_socket_use:nn {tikz/picture/init} {#1}
       \tag_socket_use:n {tikz/picture/begin}
     }
%    \end{macrocode}
%  The suspend command is in the \texttt{cmd/pgfpicture/before} hook so that it works
%  also if pgfpicture is used internally, e.g. by the forest package.
%  \changes{0.80e}{2026-01-19}{Moved suspend command into another hook for symmetry}
%    \begin{macrocode}
  \AddToHookWithArguments{cmd/pgfpicture/before}
     {
       \tag_suspend:n {\pgfpicture}
     }
%    \end{macrocode}
% The end socket is in the \cs{endpgfpicture} command.
%    \begin{macrocode}
   \AddToHook{cmd/endpgfpicture/after}
     {
       \tag_resume:n {\pgfpicture}
       \tag_socket_use:n {tikz/picture/end}
     }
  }
%    \end{macrocode}
%
%
% \subsection{User interface: Keys to change the tagging behaviour}
% These keys will be processed directly at the begin of the picture commands
% to change the tagging behaviour.
% They are specific to tikz and so are implemented with pgfkeys.
% \begin{variable}{\l__tikz_tagging_alt_tl,\l__tikz_tagging_actualtext_tl}
% The variables that hold the text alternatives.
%    \begin{macrocode}
\tl_new:N  \l__tikz_tagging_alt_tl
\tl_set:Nn \l__tikz_tagging_alt_tl {Alternative~text~missing!}
\tl_new:N  \l__tikz_tagging_actualtext_tl
%    \end{macrocode}
% \end{variable}
%
%    \begin{macrocode}
\AddToHook{package/tikz/after}
  {
%    \end{macrocode}
% The tagging keys must be set earlier than the normal processing
% of \tikzname\ keys. We implement that with a family and filter the
% relevant keys in the init socket, this means that the keys will be processed
% again when tikz does its normal processing but there is no good way to avoid that
% without changing various tikz internals.
% \changes{v0.80h}{2026-04-28}{Use \cs{pdf_purify:nN} for the alt and actualtext.}
%    \begin{macrocode}
    \pgfqkeys{/tikz}
     {
      tagging-setup/.is~family,
%    \end{macrocode}
% The short versions are forwarded to the longer one
%    \begin{macrocode}
      alt/.forward~to=/tikz/tagging-setup/alt,
      alt/.belongs~to~family=/tikz/tagging-setup,
      actualtext/.forward~to=/tikz/tagging-setup/actualtext,
      actualtext/.belongs~to~family=/tikz/tagging-setup,
      artifact/.forward~to=/tikz/tagging-setup/artifact,
      artifact/.belongs~to~family=/tikz/tagging-setup,
%    \end{macrocode}
% The tagging-setup key.
%    \begin{macrocode}
      tagging-setup/.code=\pgfqkeys{/tikz/tagging-setup}{#1},
      tagging-setup/.belongs~to~family=/tikz/tagging-setup,
      tagging-setup/text/.code =
       {
         \AssignTaggingSocketPlug{tikz/picture/begin}{text}
         \AssignTaggingSocketPlug{tikz/picture/end}{text}
       },
      tagging-setup/text/.belongs~to~family=/tikz/tagging-setup,
      tagging-setup/alt/.code =
       {
         \tl_if_eq:nnF{#1}{\pgfkeysnovalue}
          { \pdf_purify:nN {#1}\l__tikz_tagging_alt_tl }
         \AssignTaggingSocketPlug{tikz/picture/begin}{alt}
         \AssignTaggingSocketPlug{tikz/picture/end}{alt}
         \def\pgfsys@begin@text{}
         \def\pgfsys@end@text{}
       },
      tagging-setup/alt/.belongs~to~family=/tikz/tagging-setup,
      tagging-setup/tag/.code =
       {
         \AssignStructureRole{graphic}{#1}
         \AssignTaggingSocketPlug{tikz/picture/begin}{alt}
         \AssignTaggingSocketPlug{tikz/picture/end}{alt}
         \def\pgfsys@begin@text{}
         \def\pgfsys@end@text{}
       },
      tagging-setup/tag/.belongs~to~family=/tikz/tagging-setup,
      tagging-setup/actualtext/.code =
       {
          \tl_if_eq:nnF{#1}{\pgfkeysnovalue}
           { \pdf_purify:nN {#1} \l__tikz_tagging_actualtext_tl }
          \AssignTaggingSocketPlug{tikz/picture/begin}{actualtext}
          \AssignTaggingSocketPlug{tikz/picture/end}{actualtext}
          \def\pgfsys@begin@text{}
          \def\pgfsys@end@text{}
       },
      tagging-setup/actualtext/.belongs~to~family=/tikz/tagging-setup,
      tagging-setup/artifact/.code =
       {
         \AssignTaggingSocketPlug{tikz/picture/begin}{artifact}
         \AssignTaggingSocketPlug{tikz/picture/end}{artifact}
         \def\pgfsys@begin@text{}
         \def\pgfsys@end@text{}
       },
      tagging-setup/artifact/.belongs~to~family=/tikz/tagging-setup,
      tagging-setup/off/.code =
        {
          \AssignTaggingSocketPlug{tikz/picture/begin}{noop}
          \AssignTaggingSocketPlug{tikz/picture/end}{noop}
          \def\pgfsys@begin@text{}
          \def\pgfsys@end@text{}
        },
      tagging-setup/off/.belongs~to~family=/tikz/tagging-setup,
     }
 }
%    \end{macrocode}
%
% Todonotes works with the default text recipe quite ok, details can
% be handled later.
%    \begin{macrocode}
%</package>
%    \end{macrocode}
% \end{implementation}
