% \iffalse meta-comment
%
%% File: latex-lab-float.dtx (C) Copyright 2023-2026 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\ltlabfloatdate{2026-04-24}
\def\ltlabfloatversion{0.81n}
%<*driver>
\DocumentMetadata{tagging=on,pdfstandard=ua-2}
\documentclass{l3in2edoc}

\EnableCrossrefs
\CodelineIndex
\begin{document}
  \DocInput{latex-lab-float.dtx}
\end{document}
%</driver>
%
% \fi
%
%
% \title{The \textsf{latex-lab-floats} package\\
% Tagging of floats }
% \author{\LaTeX{} Project\thanks{Initial implementation done by Ulrike Fischer}}
% \date{v\ltlabfloatversion\ \ltlabfloatdate}
%
% \maketitle
%
% \newcommand{\xt}[1]{\textsl{\textsf{#1}}}
% \newcommand{\TODO}[1]{\textbf{[TODO:} #1\textbf{]}}
% \newcommand{\docclass}{document class \marginpar{\raggedright document class
% customizations}}
%
%
% \begin{documentation}
% \begin{abstract}
% The following code implements a first draft for the tagging of float
% environments
% \end{abstract}
%
%
% \section{Introduction}
%
% The code here handles the tagging of float environments.
%
% Figures (and tables) are in \LaTeX{} typically typeset in float environments.
% These are boxes which can \enquote{float} away to special float areas on the pages,
% e.g., to the top or the bottom of a page or to special float pages.
% If the rules allow it they can also be placed in the main text stream (\enquote{here}).
% Floats can also be collected at the end of the document.
% In either case  the order within each type of floats
% (e.g., figures, tables, algorithms, etc.) is preserved.
%
% A special type, called a H-float, (provided by the float package)
% is always placed in the main text stream and does not
% necessarily preserve the order with normal floats of the same type: It is basically
% a minipage with a caption.
%
% Floats typically contain a figure (or a table, etc.) and a caption,
% but more complex constructions with subfigures,
% copyright statements, sources or additional description are possible too.
%
% In the \LaTeX{} source a float is normally more or less at the place of
% the first call-out, but when preparing a document for print the code
% is sometimes moved around to place floats in a more visually pleasing way.
%
% \section{Tagging}
%
% Floats (with the exception of H-floats) do not belong into the text stream, they
% are \enquote{consultation objects}: Readers must be able to choose if and when they read the float.
% Floats can have captions: the PDF rules require that if a \texttt{Caption} structure element is used,
% it is the first or last structure in its parent structure.
% This poses some challenges on a good tagging.
%
% In PDF~2.0 there is the suitable \texttt{Aside} tag which hopefully will
% be handled correctly regarding the reading order once processor actually support
% PDF~2.0. But in PDF~1.7 we rolemap it to \texttt{Note} and this doesn't lead to
% a good reading order. The code therefore defers the output of float:
% it collects the float structures and moves
% them to a \texttt{Sect} structure which is flushed out at the end of the document
% or earlier if the author requests it. (H-floats once they are handled will not be moved).
%
% To fulfill the requirement that a \texttt{Caption} should be at the begin or end, we always
% move it to the begin of the structure. If a float has two captions the author
% has to insert a command which splits the float in two.
%
% Subfigures and subcaptions are currently not handled, but will be implemented
% as simple \texttt{Part} with their own \texttt{Caption}.
%
% Unknown float types are put into a generic structure when they are encountered in the
% source. To add support for a new float type the \texttt{float/new} key described below can
% be used.
%
% \section{Links}
% \pkg{hyperref} doesn't patch the caption commands anymore if \cs{DocumentMetadata} is used.
% The code here has to add a target for links. To improve the linking behavior,
% it add this target at the begin of the float (and at the begin of split if the float is splitted)
% and changes \cs{caption} so that a link to a caption label will go to this target.
%
% \section{Keys}
%
% The code adds the following keys for the \cs{tagpdfsetup} command:
%
% \begin{function}{float/new,float/flush,float/split,float/container}
% \begin{description}
% \item[float/new] This sets up the needed code for a new float type. The value
% is the \meta{captype} which should be the same name as
% the name stored in \cs{\@captype}. The code defines symbolic
% structure names \texttt{float/\meta{captype}s} (for the container),
% \texttt{float/\meta{captype}} (for a single float), \texttt{float/\meta{captype}/caption}
% and \texttt{float/\meta{captype}/label} (for the caption and its label) and
% assigns standard roles to them. The roles can be changed with \cs{AssignStructureRole}.
%
% \item[float/flush]  This will flush out all so far deferred floats (currently
% table and figure) into a container. The value is a sectioning level for which
% \cs{toclevel@}\meta{name} exists, e.g., \texttt{section} or \texttt{chapter},
% or an integer number describing the level, like $1$ for
% the section level. The container will then behave like a sectioning command
% of this level and create a \texttt{Sect} structure element containing the floats.
% The default value is the current sectioning level.
% The command should typically be used directly before a sectioning of the same
% or higher level. E.g. this here is wrong as following text \enquote{some text}
% would no longer be inside subsection A:
% \begin{verbatim}
% \DocumentMetadata{tagging=on}
% \documentclass{article}
%
% \begin{document}
% \section{section A}
% \subsection{subsection A}
% \begin{figure}
% \caption{hallo}
% \end{figure}
% \tagpdfsetup{float/flush}
% some text
% \section{section B}
% \end{document}
% \end{verbatim}
%
% Correct would be to put it directly before \verb+\subsection{section B}+.
% The key issues a \cs{par} to end the current paragraph.
%
% The floats will then be inserted as a \texttt{Sect} of this level (all \texttt{Sect} of smaller or equal
% level are closed). The key then creates a new container for following floats.
% At the end of the document all remaining floats will be flushed automatically.
%
% \item[float/split] This can be used inside a float if there are two captions.
% It will only work reasonably well if the content of the float parts are in a sensible order
% and can be separated by this command. More complex setups with tabulars will need more
% thoughts.
%
% \item[float/defer] The value \texttt{false} disables
% the deferring of floats in a container: the float structure is then inserted directly
% where it appears in the source. The key sets a global boolean. It can be used
% in the document to switch the collection on and off. The default value is \texttt{true}.
%
% \item[float/here] This is the inverse of the \texttt{defer} key and so a shorter
% way to disable the deferring. The default value is \texttt{true}.
% \end{description}
% \end{function}
%
% \section{Kernel commands}
% \begin{function}{\@current@float@struct}
% This variable holds the number of the current float structure. With tagging
% this is the structure number, without tagging a unique counter. A float
% can contain more than one float structure (e.g., if there is more than one
% caption).
% \end{function}
%
% \begin{function}{\@makecaption}
% \cs{@makecaption} is defined by the classes so we overwrite it for now
% at begin document.
% \end{function}
%
%
%    \begin{macrocode}
%<@@=tag>
%<*package>
%    \end{macrocode}
% \end{documentation}
% \begin{implementation}
% \section{Implementation}
%    \begin{macrocode}
\ProvidesExplPackage {latex-lab-testphase-float} {\ltlabfloatdate} {\ltlabfloatversion}
  {Code related to the tagging of floats}
%    \end{macrocode}
% \changes{0.81m}{2025-12-04}{Use symbolic names}
% \changes{0.81m}{2025-12-04}{Deprecate \cs{tagtool}}
% \changes{0.81m}{2025-12-04}{Interface for new float types}
% \changes{0.81m}{2025-12-04}{Interface to disable deferring of float into a container}
%
% \subsection{Variables}
% We rolemap floats to Aside, and float sections to Sect.
%
% \begin{variable}{
%  \g_@@_float_sect_prop,
%  \g_@@_float_types_seq,
%  \@current@float@struct,
%  \g_@@_float_int
%   }
% These variables will hold the structure number for the float container
% and the list of float types. Currently only figure and table are supported
% TODO: interface to declare new float types.
% To set the target for links we need also a unique counter.
% With tagging we could use the structure number, but
% the structure commands now are hidden inside tagging sockets
% so we use a dedicated counter.
%    \begin{macrocode}
\prop_new:N \g_@@_float_sect_prop
\seq_new:N  \g_@@_float_types_seq
\seq_gput_right:Nn \g_@@_float_types_seq {figure}
\seq_gput_right:Nn \g_@@_float_types_seq {table}
\tl_new:N\@current@float@struct
\int_new:N\g_@@_float_int
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\g_@@_float_sect_bool}
% With this boolean float collection is switched on and off.
% Currently it is always on and set globally.
% TODO: think if an interface is needed.
% TODO: would a local variable make more sense?
%    \begin{macrocode}
\bool_new:N       \g_@@_float_sect_bool
\bool_gset_true:N  \g_@@_float_sect_bool
%    \end{macrocode}
% \end{variable}
% \begin{variable}{\l_@@_float_tmpa_tl,\l_@@_float_tmpb_tl}
%    \begin{macrocode}
\tl_new:N\l_@@_float_tmpa_tl
\tl_new:N\l_@@_float_tmpb_tl
%    \end{macrocode}
% \end{variable}
% \begin{macro}{\@@_float_init:}
% To be able to set unique targets for links, we
% need a counter outside the tagging sockets.
% TODO: check if this command should be public or
% a socket or a hook.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_float_init:
 {
   \int_gincr:N \g_@@_float_int
   \tl_set:Ne \@current@float@struct { \int_use:N \g_@@_float_int}
 }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Setup for a new float type}
% A new float type needs
% \begin{itemize}
% \item symbolic names for the float, the caption and the label
% \item symbolic name for the container
% \item and it must be recorded in the sequence.
% \end{itemize}
%
% This is all done with the following key. The value is the captype.
%
%    \begin{macrocode}
\keys_define:nn {__tag/setup}
 {
   float/new .code:n =
    {
      \NewStructureName{float/#1s}
      \AssignStructureRole{float/#1s}{Sect}
      \NewStructureName{float/#1}
      \AssignStructureRole{float/#1}{float}
      \NewStructureName{float/#1/caption}
      \AssignStructureRole{float/#1/caption}{Caption}
      \NewStructureName{float/#1/label}
      \AssignStructureRole{float/#1/label}{Lbl}
      \seq_gput_right:Nn \g_@@_float_types_seq {#1}
    }
 }
%    \end{macrocode}
%
%\subsection{Moving float structures}
%
% Currently it is for all float types or none.
% Probably we will need some more options here to select some float types.
%
% \begin{macro}{float/defer,float/here}
%    \begin{macrocode}
\keys_define:nn{__tag/setup}
  {
    float/defer .bool_gset:N = \g_@@_float_sect_bool
    ,float/here .bool_gset_inverse:N = \g_@@_float_sect_bool
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_float_container_new:n}
% This creates a new container and then stashes it.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_float_container_new:nN #1 #2 % #1 captype #2 tl-var to return number
  {
    \tag_struct_begin:n{tag=\UseStructureName{float/#1s},stash}
    \tl_set:Ne #2 {\int_use:N\c@g__tag_struct_abs_int}
    \prop_gput:Nne\g_@@_float_sect_prop {#1-struct}{\int_use:N\c@g__tag_struct_abs_int}
    \tag_struct_end:
  }
\cs_generate_variant:Nn \@@_float_container_new:nN {eN}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\@@_float_init_collect:}
% This initializes a container structure for every float type.
% It can be used more than once in a document, this allows to have e.g.
% chapter wise containers.
%    \begin{macrocode}
\cs_new_protected:Npn\@@_float_init_collect:
  {
    \bool_if:NT\g_@@_float_sect_bool
      {
        \seq_map_inline:Nn\g_@@_float_types_seq
          {
            \@@_float_container_new:nN {##1}\l_@@_tmpa_tl
          }
      }
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_float_stop_sect:}
% This pushes out the floats. For every type is checks if there is actually
% a float of this type and then writes out the container structure.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_float_stop_sect:
  {
    \seq_map_inline:Nn\g_@@_float_types_seq
      {
        \prop_get:NnNT\g_@@_float_sect_prop{##1-used}\l_@@_float_tmpa_tl
          {
            \prop_get:NnNF\g_@@_float_sect_prop{##1-struct}\l_@@_float_tmpb_tl
             {
               \@@_float_container_new:eN {##1}\l_@@_float_tmpb_tl
             }
            \exp_args:Ne
            \tag_struct_use_num:n{\l_@@_float_tmpb_tl}
            \prop_gremove:Nn \g_@@_float_sect_prop{##1-used}
          }
      }
  }
%    \end{macrocode}
% \end{macro}
% \begin{macro}{flush/float}
% This is a key for \cs{tagpdfsetup} to flush out the collected floats.
% The value allows to set to which level the create Sect belongs.
% So \texttt{section} will close all previous Sect until the section level
% and create a new section structure.
%    \begin{macrocode}
\keys_define:nn { __tag / setup }
 {
   float/flush .code:n =
     {
       \par
       \cs_if_exist:cTF{toclevel@#1}
        { \UseTaggingSocket{sec/end}{\int_eval:n{\use:c{toclevel@#1}}}}
        { \UseTaggingSocket{sec/end}{\int_eval:n{#1}}}
       \@@_float_stop_sect:
       \@@_float_init_collect:
     },
   float/flush .default:n = \@currentseclevel
 }
%    \end{macrocode}
% \end{macro}

% \begin{macro}{flush-floats (deprecated)}
% This is the same key for the deprecated command
% \cs{tagtool} to flush out the collected floats.
% Kept for compatibility for now but will be removed at some time.
% The value allows to set to which level the create Sect contains.
% So \texttt{section} will close all previous Sect until the section level
% and create a new section.
%    \begin{macrocode}
\keys_define:nn { tag / tool}
 {
   flush-floats .meta:nn = {__tag/setup}{float/flush=#1},
   flush-floats .default:n = \@currentseclevel
 }
%    \end{macrocode}
% \end{macro}
%
% We need at least one pair
%    \begin{macrocode}
\AddToHook{begindocument/end}[latex-lab/float]
  {\@@_float_init_collect:}
\AddToHook{tagpdf/finish/before}[latex-lab/float]
  {\par\__tag_sec_end:n{-10}\@@_float_stop_sect:}
\DeclareHookRule{tagpdf/finish/before}{latex-lab/float}{before}{tagpdf}
%    \end{macrocode}
%
% \subsection{Splitting floats}
% \begin{macro}{float/split}
% TODO: check if the target affect spacing!!
%    \begin{macrocode}
\keys_define:nn { __tag / setup}
  {
   float/split .code:n =
    {
      \UseTaggingSocket{float/end}
      \@@_float_init:
      \UseTaggingSocket{float/begin}
      \MakeLinkTarget*{floatstructure.\@current@float@struct}
    }
 }
%    \end{macrocode}
% \end{macro}
% \begin{macro}{split-float (deprecated)}
% This is the same key for the deprecated command
% \cs{tagtool} to split a float.
% Kept for compatibility for now but will be removed at some time.
%    \begin{macrocode}
\keys_define:nn { tag / tool}
  {
   split-float .meta:nn = {__tag/setup}{float/split}
  }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Tagging sockets}
% The tagging sockets are declared in lttagging.
% Currently we have the tagging sockets \texttt{float/hmode/begin}, \texttt{float/hmode/end},
% \texttt{float/begin} and \texttt{float/end}. All sockets have no argument.
%
% \begin{plugdecl}{default  (tagsupport/float/hmode/begin)}
% This plug should be used if a float is called in hmode.
% It then closes the MC-chunks and starts the structure.
%    \begin{macrocode}
\NewTaggingSocketPlug{float/hmode/begin}{kernel}
  {
    \@@_float_stop_par:
  }
\AssignTaggingSocketPlug{float/hmode/begin}{kernel}
%    \end{macrocode}
% \end{plugdecl}
%
% \begin{plugdecl}{default  (tagsupport/float/hmode/end)}
% This plug should be used if a float is called in hmode;
% at the end of the float it then restarts the MC.
%    \begin{macrocode}
\NewTaggingSocketPlug{float/hmode/end}{kernel}
  {
    \@@_float_start_par:
  }
\AssignTaggingSocketPlug{float/hmode/end}{kernel}
%    \end{macrocode}
% \end{plugdecl}
%
% \begin{plugdecl}{default  (tagsupport/float/begin)}
%    \begin{macrocode}
\NewTaggingSocketPlug{float/begin}{kernel}
  {
    \@@_float_begin:
  }
\AssignTaggingSocketPlug{float/begin}{kernel}
%    \end{macrocode}
% \end{plugdecl}
%
% \begin{plugdecl}{default  (tagsupport/float/end)}
%    \begin{macrocode}
\NewTaggingSocketPlug{float/end}{kernel}
  {
    \@@_float_end:
  }
\AssignTaggingSocketPlug{float/end}{kernel}
%    \end{macrocode}
% \end{plugdecl}
%
% \begin{macro}{\@@_float_stop_par:,\@@_float_start_par:}
% if a float is in a par, we need commands to stop and restart the P-mc
%    \begin{macrocode}
\cs_new_protected:Npn \@@_float_stop_par:
  {
    \tag_mc_end:
    \bool_if:NF \g_@@_float_sect_bool
     {
      \tag_struct_end:
     }
  }
\cs_new_protected:Npn \@@_float_start_par:
  {
    \bool_if:NF \g_@@_float_sect_bool
     {
      \tag_struct_begin:n{tag=\UseStructureName{para/textblock}}%
     }
   \tag_mc_begin:n{tag=P}
  }
%    \end{macrocode}
% \end{macro}
% These commands are the main commands to start and end the float tagging.
%
%    \begin{macrocode}
\cs_new_protected:Npn \@@_float_begin:
 {%
%    \end{macrocode}
% We test if the float structure should be included directly or move to a dedicated section.
%    \begin{macrocode}
  \seq_if_in:NoTF\g_@@_float_types_seq{\@captype}
    {
     \bool_if:NTF\g_@@_float_sect_bool
      {
        \prop_get:NoNF \g_@@_float_sect_prop{\@captype-struct}\l_@@_float_tmpa_tl
         {
           \@@_float_container_new:eN {\@captype}\l_@@_float_tmpa_tl
         }
       \tag_struct_begin:e
          {
            tag=\UseStructureName{float/\@captype},
            parent=\l_@@_float_tmpa_tl
          }%
       \prop_gput:Nee \g_@@_float_sect_prop {\@captype-used}{true}
      }
      {
        \tag_struct_begin:n{tag=\UseStructureName{float/\@captype}}
      }
    }
    {
      \tag_struct_begin:n{tag=\UseStructureName{float/generic}}
    }
     \tl_set:Ne\@current@float@struct{\tag_get:n{struct_num}}%
     \typeout{Float structure: \@current@float@struct}
 }

\cs_new_protected:Npn\@@_float_end:{\tag_struct_end:} %end Aside

%    \end{macrocode}
% \subsection{Patching}
% This patches the main command \cs{@xfloat}.
% There is a : in the code, so we disable expl3 syntax
%    \begin{macrocode}
\ExplSyntaxOff
\def\@xfloat #1[#2]{%
  \@nodocument
  \def \@captype {#1}%
   \def \@fps {#2}%
   \@onelevel@sanitize \@fps
   \def \reserved@b {!}%
   \ifx \reserved@b \@fps
     \@fpsadddefault
   \else
     \ifx \@fps \@empty
       \@fpsadddefault
     \fi
   \fi
   \ifhmode
     \@bsphack
%    \end{macrocode}
% If the float is in hmode we have to interrupt the P
%    \begin{macrocode}
     \UseTaggingSocket{float/hmode/begin}%
     \@floatpenalty -\@Mii
   \else
     \@floatpenalty-\@Miii
   \fi
  \ifinner
     \@parmoderr\@floatpenalty\z@
  \else
    \@next\@currbox\@freelist
      {%
       \@tempcnta \sixt@@@@n
       \expandafter \@tfor \expandafter \reserved@a
         \expandafter :\expandafter =\@fps
         \do
          {%
           \if \reserved@a h%
             \ifodd \@tempcnta
             \else
               \advance \@tempcnta \@ne
             \fi
           \else\if \reserved@a t%
             \@setfpsbit \tw@
           \else\if \reserved@a b%
             \@setfpsbit 4%
           \else\if \reserved@a p%
             \@setfpsbit 8%
           \else\if \reserved@a !%
             \ifnum \@tempcnta>15
               \advance\@tempcnta -\sixt@@@@n\relax
             \fi
           \else
             \@latex@error{Unknown float option `\reserved@a'}%
             {Option `\reserved@a' ignored and `p' used.}%
             \@setfpsbit 8%
           \fi\fi\fi\fi\fi
           }%
       \@tempcntb \csname ftype@\@captype \endcsname
       \multiply \@tempcntb \@xxxii
       \advance \@tempcnta \@tempcntb
       \global \count\@currbox \@tempcnta
       }%
    \@fltovf
  \fi
%    \end{macrocode}
% This starts the structure for the float.
%    \begin{macrocode}
  \csname @@_float_init:\endcsname
  \UseTaggingSocket{float/begin}%
  \global \setbox\@currbox
    \color@vbox
      \normalcolor
      \vbox \bgroup
        \hsize\columnwidth
        \@parboxrestore
        \@floatboxreset
%    \end{macrocode}
% We add a target for links. TODO: check that it doesn't affect spacing!!
%    \begin{macrocode}
        \MakeLinkTarget*{\@captype.struct.\@current@float@struct}%
}%
%    \end{macrocode}
%  The end code of the float ...
%    \begin{macrocode}
\def\end@float{%
  \@endfloatbox
  \UseTaggingSocket{float/end}%
  \ifnum\@floatpenalty <\z@
    \@largefloatcheck
    \@cons\@currlist\@currbox
    \ifnum\@floatpenalty <-\@Mii
      \penalty -\@Miv
      \@tempdima\prevdepth
      \vbox{}%
      \prevdepth\@tempdima
      \penalty\@floatpenalty
    \else
      \vadjust{\penalty -\@Miv \vbox{}\penalty\@floatpenalty}\@Esphack
      \UseTaggingSocket{float/hmode/end}%
    \fi
  \fi
}
%    \end{macrocode}
%  and similar for double floats:
%    \begin{macrocode}
\def\end@dblfloat{%
  \if@twocolumn
    \@endfloatbox
    \UseTaggingSocket{float/end}%
    \ifnum\@floatpenalty <\z@
      \@largefloatcheck
      \global\dp\@currbox1sp %
      \@cons\@currlist\@currbox
      \ifnum\@floatpenalty <-\@Mii
        \penalty -\@Miv
        \@tempdima\prevdepth
        \vbox{}%
        \prevdepth\@tempdima
        \penalty\@floatpenalty
      \else
        \vadjust{\penalty -\@Miv \vbox{}\penalty\@floatpenalty}\@Esphack
        \UseTaggingSocket{float/hmode/end}%
      \fi
    \fi
  \else
    \end@float
  \fi
}%
\ExplSyntaxOn
%    \end{macrocode}
%
% \subsection{Handling captions}
%
% \subsubsection{(Tagging) sockets}
%
% These sockets are in lttagging: \texttt{caption/begin} (1 argument),
% \texttt{caption/end}, \texttt{caption/label/begin}, \texttt{caption/label/end}.
%
% \begin{socketdecl}{caption/label}
% This socket is a lightweight start for
% some interface to format the label or add a font command.
% The argument is the label text.
% The default plug \texttt{kernel} adds a colon
% and a space.
% TODO: revisit after checking float and caption packages
% to identify which sockets and hooks are needed.
%    \begin{macrocode}
\NewSocket{caption/label}{1}
%    \end{macrocode}
% \end{socketdecl}
%
% \begin{plugdecl}{kernel (caption/label)}
% The standard label formatting from the kernel.
%    \begin{macrocode}
\NewSocketPlug{caption/label}{kernel}
 {
   #1:~
 }
\AssignSocketPlug{caption/label}{kernel}
%    \end{macrocode}
% \end{plugdecl}
% \begin{plugdecl}{default}
% The caption begin socket takes an argument: the structure number of
% the parent float. If the argument is empty, the current structure is used.
% TODO: a tagpdf key that moves a structure to the begin of the parent.
% The caption is moved to the first position with the firstkid option.
%    \begin{macrocode}
\NewTaggingSocketPlug{caption/begin}{default}
  {
     \tl_if_empty:eTF {#1}
      {
        \tag_struct_begin:n{tag=\UseStructureName{float/\@captype/caption},firstkid}
      }
      {
        \tag_struct_begin:n{tag=\UseStructureName{float/\@captype/caption},parent=#1,firstkid}
      }
     \bool_set_true:N \l__tag_para_flattened_bool
  }
\AssignTaggingSocketPlug{caption/begin}{default}
%    \end{macrocode}
% \end{plugdecl}
% \begin{plugdecl}{default}
%    \begin{macrocode}
\NewTaggingSocketPlug{caption/end}{default}
  {
    \tag_struct_end:
  }
\AssignTaggingSocketPlug{caption/end}{default}
%    \end{macrocode}
% \end{plugdecl}
%
% \begin{plugdecl}{default (tagsupport/caption/label/begin)}
%    \begin{macrocode}
\NewTaggingSocketPlug{caption/label/begin}{default}
  {
%    \end{macrocode}
% suppress para tagging at the begin.
%    \begin{macrocode}
     \tagpdfparaOff
     \tag_struct_begin:n{tag=\UseStructureName{float/\@captype/label}}
     \tag_mc_begin:n{}
  }
\AssignTaggingSocketPlug{caption/label/begin}{default}
%    \end{macrocode}
% \end{plugdecl}
%
% \begin{plugdecl}{default (tagsupport/caption/label/end)}
%    \begin{macrocode}
\NewTaggingSocketPlug{caption/label/end}{default}
  {
    \tag_mc_end:
    \tag_struct_end:
    \tagpdfparaOn
  }
\AssignTaggingSocketPlug{caption/label/end}{default}
%    \end{macrocode}
% \end{plugdecl}
%
% \subsubsection{Redefinitions}
%
% With hyperref that means that the \cs{refstepcounter} now can affect spacing so we
% change that to the kernel refstepcounter:
%    \begin{macrocode}
\def\caption{%
   \ifx\@captype\@undefined
     \@latex@error{\noexpand\caption\c_space_tl outside~float}\@ehd
     \expandafter\@gobble
   \else
%    \end{macrocode}
% if a caption is used outside a float no
% target has been set and \cs{@current@float@struct} is empty
%    \begin{macrocode}
     \tl_if_empty:NTF\@current@float@struct
      {
        \refstepcounter\@captype
      }
      {
        \@kernel@refstepcounter\@captype
%    \end{macrocode}
% we need to reset the target for \cs{addcontentsline}.
% We use \cs{@captype} to support autoref.
%    \begin{macrocode}
        \xdef\@currentHref{\@captype.struct.\@current@float@struct}%
      }
     \expandafter\@firstofone
   \fi
   {\@dblarg{\@caption\@captype}}%
}
%    \end{macrocode}
%
% \begin{macro}{\@makecaption}
% \cs{@makecaption} is defined by the classes so we overwrite it for now
% at begin document.
% \changes{0.81k}{2025-10-11}{Add command hook explicitly to avoid patching error, tagging issue 998}
%    \begin{macrocode}
\NewHookWithArguments{cmd/@makecaption/before}{2}
\AddToHook{begindocument}
  {
    \long\def\@makecaption#1#2{%
      \UseHookWithArguments{cmd/@makecaption/before}{2}{#1}{#2}%
      \vskip\abovecaptionskip
%    \end{macrocode}
% We don't want tagging when storing the caption for the singleline check.
% \changes{0.81l}{2025-10-17}{Measure \texttt{caption/label} socket instead of hard-coded colon and space, tagging issue 935}
%    \begin{macrocode}
      \SuspendTagging{\@makecaption}
      \sbox\@tempboxa{\UseSocket{caption/label}{#1}#2}%
      \ResumeTagging{\@makecaption}
%    \end{macrocode}
% We pass \cs{@current@float@struct} as parent structure
% number. If that is empty the socket will use the parent structure and hope ...
%    \begin{macrocode}
      \UseTaggingSocket{caption/begin}{\@current@float@struct}
      \ifdim \wd\@tempboxa >\hsize
      \UseTaggingSocket{caption/label/begin}
      \UseSocket{caption/label}{#1}
      \UseTaggingSocket{caption/label/end}
      \UseTaggingSocket{para/begin}
          #2
      \par
      \else
%    \end{macrocode}
% we don't reuse the box as it doesn't contain tagging, but set the text explicitly.
%    \begin{macrocode}
          \global \@minipagefalse
        \hb@xt@\hsize{\hfil
         \UseTaggingSocket{caption/label/begin}
         \UseSocket{caption/label}{#1}
         \UseTaggingSocket{caption/label/end}
         \UseTaggingSocket{para/begin}
          #2
         \UseTaggingSocket{para/end}
         \hfil}%
       \fi
      \UseTaggingSocket{caption/end}
      \vskip\belowcaptionskip}
  }
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
%</package>
%    \end{macrocode}
% \end{implementation}
