% \iffalse meta-comment % %% File: latex-lab-float.dtx (C) Copyright 2023 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-01-16} \def\ltlabfloatversion{0.81m} %<*driver> \DocumentMetadata{tagging=on,pdfstandard=ua-2} \documentclass{l3in2edoc} \EnableCrossrefs \CodelineIndex \begin{document} \DocInput{latex-lab-float.dtx} \end{document} % % % \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} % The code disable the caption patches from hyperref. It will add an anchor at the % begin of the float or a split. It changes \cs{caption} so that a link to a caption label % will go to the begin of the float. % % \section{Keys} % % The code adds the following keys for the \cs{tagpdfsetup} command\footnote{Previously there were also keys for % the \cs{tagtool} command, but this command is now deprecated.} % % % \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} % % To avoid that hyperref interferes we disable its patches: % \begin{macrocode} \def\hyper@nopatch@caption{} % \end{macrocode} % % \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} % % \end{macrocode} % \begin{macrocode} %<*latex-lab> \ProvidesFile{float-latex-lab-testphase.ltx} [\ltlabfloatdate\space v\ltlabfloatversion\space latex-lab wrapper float] \RequirePackage{latex-lab-testphase-float} % % \end{macrocode} % \end{implementation}