% \iffalse meta-comment
%
%% File: ltmeta.dtx
%% Copyright (C) 2021-2026
%% Frank Mittelbach, The 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
%
%
%%% From File: ltmeta.dtx
%<*driver>
% \fi
\ProvidesFile{ltmeta.dtx}
             [2026-05-27 v1.0g LaTeX Kernel (Document Metadata)]
% \iffalse
%
\documentclass{l3in2edoc}
\GetFileInfo{ltmeta.dtx}

\EnableCrossrefs
\CodelineIndex
\begin{document}
  \DocInput{ltmeta.dtx}
\end{document}
%</driver>
%
% \fi
%
% \providecommand\hook[1]{\texttt{#1}}
% \providecommand\env[1]{\texttt{#1}}
%
%
%
% \title{The \texttt{ltmeta.dtx} code\thanks{This file has version
%    \fileversion\ dated \filedate, \copyright\ \LaTeX\
%    Project.}}
% \author{Frank Mittelbach}
%
% \maketitle
%
%
% \begin{abstract}
%    This code defines the \cs{DocumentMetadata} interface.
% \end{abstract}
%
% \tableofcontents
%
%
% \section{Introduction}
%
%
%    In the past there was no dedicated location to declare settings
%    concerning a document as a whole. Settings are placed somewhere
%    in the preamble or with the class options or even with some
%    package options.  For some settings this can be too late, for
%    example the pdf version can no longer be changed if a package has
%    used code which already opened the PDF.
%
%    \cs{DocumentMetadata} as a new command unifies such settings in
%    one place.  It must be used before \cs{documentclass} but can be
%    issued more than once there.
%
%    At the moment most of the code run by \cs{DocumentMetadata} is
%    external to the format and subject to change. This includes the
%    supported key/values.
%
%    For that reason all that happens right now in the format is to
%    look for suitable support files and if found, to redirect the
%    processing to them.
%
% \subsection{\cs{DocumentMetadata}}
%
% \begin{function}{\DocumentMetadata}
% \begin{syntax}
%  \cs{DocumentMetadata}\Arg{key-value list}
% \end{syntax}
% \end{function}
%
%
%
%    The keys defined for \cs{DocumentMetadata}
%    currently allow to set the PDF version, to set the PDF \texttt{/Lang},
%    to uncompress a PDF, to set the language and to declare a few PDF standards
%    and some color profiles.
%
%    \cs{DocumentMetadata} is also used to
%    activate the new PDF management code and it loads
%    a number of required files for the PDF management code.
%    As this forces the loading of the backend files, a backend
%    which can't be detected automatically like |dvipdfmx|,
%    must be set in the first \cs{DocumentMetadata} call (if there is more than one).
%
%    The full set of keys currently supported is documented in \texttt{documentmetadata-support.pdf}
%    for now.
%
% \subsection{Storing and retrieving document properties}
%
% We provide a storage container where classes, packages and users can store
% properties and metadata about the current document which may be of interest to 
% other packages or to the user. This data can then be retrieved as necessary 
% by packages or by the document author.
%
% The properties are stored with a key \meta{label}\texttt{/}\meta{property}. 
% The values can be retrieved expandably.
%
% \begin{function}{\AddToDocumentProperties}
% \begin{syntax}
%  \cs{AddToDocumentProperties}\oarg{label}\Arg{property}\Arg{value}
% \end{syntax}
% This stores \meta{value} under the key \meta{label}/\meta{property}.
% By default \meta{label} is the current package name |\@currname|. If another
% label is chosen, it should be one which avoids clashes with other packages
% using the container. The label |document| is used by the PDF management and by the
% \LaTeX{} kernel and so reserved.
% If the key \meta{label}/\meta{property} already exists in the container, its value
% is overwritten without warning or error. 
% \end{function}
%
% \begin{function}{\GetDocumentProperty}
% \begin{syntax}
%  \cs{GetDocumentProperty}\Arg{label/property}
% \end{syntax}
% Expands to the \meta{value} corresponding to \meta{label/property}
% in the container. If \meta{label/property} is missing,
% this has an empty expansion. In particular, there is no error!
% The result is returned within \cs{exp_not:n}, which means
% that the \meta{value} does not expand further
% when appearing in an e-type or x-type argument expansion.
% \end{function}
%
%
% \begin{function}{\ShowDocumentProperties,\LogDocumentProperties}
% \begin{syntax}
%  \cs{ShowDocumentProperties}\\
%  \cs{LogDocumentProperties}
% \end{syntax}
% This shows/logs the current content of the container.
% \end{function}
%
% \StopEventually{\setlength\IndexMin{200pt}  \PrintIndex  }
%
%
% \section{The Implementation}
%
%
% \subsection{\cs{DocumentMetadata}}
%    \begin{macrocode}
%<*2ekernel|latexrelease>
%    \end{macrocode}
%    Not needed yet but \ldots
%    \begin{macrocode}
%\ExplSyntaxOn
%    \end{macrocode}
%
%    \begin{macrocode}
%<latexrelease>\NewModuleRelease{2022/06/01}{ltmeta}
%<latexrelease>                 {Document Metadata handling}
%    \end{macrocode}
%    We start by making the conditionals testing for the use of
%    \cs{DocumentMetadata} execute the the false branch. Then, inside
%    \cs{DocumentMetadata}, we change them to select the true branch.  
% \changes{v1.0d}{2025/03/01}{Provide T F variants of
%                             \cs{IfDocumentMetadataTF} (gh/1522)}
%    \begin{macrocode}
\let \IfDocumentMetadataTF \@secondoftwo
\let \IfDocumentMetadataT \@gobble
\let \IfDocumentMetadataF \@firstofone
\protected\def\DocumentMetadata{%
  \InputIfFileExists{documentmetadata-support.ltx}%
     {%
%    \end{macrocode}
%    Support for \cs{DocumentMetadata} is available, so change the conditionals.
%    \begin{macrocode}
       \let \IfDocumentMetadataTF \@firstoftwo
       \let \IfDocumentMetadataT  \@firstofone
       \let \IfDocumentMetadataF  \@gobble
     }%
%    \end{macrocode}
%    The above file is changing \cs{DocumentMetadata} to a suitable
%    definition (or so we hope) so that it can be safely used several times
%    in the premable.
%
%    If the file can't be found we say so and carry on without it.
%    \begin{macrocode}
     {%
       \@latex@error{No support files for
                    \noexpand\DocumentMetadata found}
         {Is the 'LaTeX-lab' bundle installed?%
         \MessageBreak
         Without it, the declaration is ignored.}%
%    \end{macrocode}
%    No point in trying this more than once if there are several calls
%    in the document.
%    \begin{macrocode}
      \let\DocumentMetadata\@gobble
     }%
  \DocumentMetadata
}
%    \end{macrocode}
%
% \subsection{Document properties}
% \changes{1.0g}{2026-05-27}{Add commands related to document properties container}
% 
% The container for the document properties is a prop:
% 
% \begin{variable}{\g__kernel_documentproperties_prop}
%    \begin{macrocode}
\ExplSyntaxOn
   \prop_new:N \g__kernel_documentproperties_prop 
%    \end{macrocode}
% \end{variable}
% \begin{macro}{\AddToDocumentProperties}
%    \begin{macrocode}
\NewDocumentCommand\AddToDocumentProperties{O{\@currname}mm}
  {    
    \prop_gput:Nen \g__kernel_documentproperties_prop
      {
        \tl_if_blank:eTF {#1}{top-level/}{#1/} #2
      }
      { #3}
  }
%    \end{macrocode}
% \end{macro}
% 
% \begin{macro}[EXP]{\GetDocumentProperty}
%    \begin{macrocode}
\cs_new:Npn\GetDocumentProperty #1
  {
    \prop_item:Nn \g__kernel_documentproperties_prop {#1}
  }
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\ShowDocumentProperties,\LogDocumentProperties}
%    \begin{macrocode}
\msg_new:nnn  { latex2e } { show-properties }
  {
    The~following~document~properties~have~been~stored:
    #1
  }
\NewDocumentCommand\ShowDocumentProperties {}
  {
    \msg_show:nne {latex2e}{show-properties}
      {
        \prop_map_function:NN \g__kernel_documentproperties_prop \msg_show_item:nn
      }
  }
\NewDocumentCommand\LogDocumentProperties {}
  {
    \msg_log:nne {latex2e}{show-properties}
      {
        \prop_map_function:NN \g__kernel_documentproperties_prop \msg_show_item:nn
      }
  }
\ExplSyntaxOff  
%    \end{macrocode}
% \end{macro}
%
% \subsection{Targets}
%   To allow package and class author to support for document links
%   we provide also the new interface commands of the hyperref package
%   for the creation of targets.
%   The commands are not only useful for document links: 
%   When tagging is active the commands can also be used to reference structures.
%   This is done in the \texttt{recordtarget} socket, which records the target name.
%   Both for links and structure references it can be useful to change the name of the 
%   next target. We therefore insert a hook \texttt{target/setname/after} after the name
%   has be set. This hook is used in the \cs{NextLinkTarget} command to adapt the target name
%   \cs{@currentHref}. 
% \changes{v1.0b}{2022/05/17}{Default definition for targets added}
% \changes{v1.0c}{2024/09/21}{Added tagging support}
% \changes{v1.0e}{2026/04/22}{Add hook to change target name and use it in \cs{NextLinkTarget}}
% \changes{v1.0f}{2026/05/06}{Add \cs{SaveLastSkip} and \cs{RestoreLastSkip} to better mimic 
%     hyperref's spacing behavior, gh/2070}
% \changes{v1.0f}{2026/05/06}{Use \cs{latelua} to mimic a whatsit to avoid spurious warning, gh/2070}
%  \begin{macro}{\MakeLinkTarget}
%  \begin{macro}{\LinkTargetOn}
%  \begin{macro}{\LinkTargetOff}
%  \begin{macro}{\NextLinkTarget}
%    \begin{macrocode}
%<latexrelease>\IncludeInRelease{2026/06/01}%
%<latexrelease>                 {\MakeLinkTarget}{Record target name for tagging support}%
\ExplSyntaxOn
%    \end{macrocode}
% luatex complains about non-PDF specials if \cs{special} is used, so we use \cs{latelua} instead
% to create an empty whatsit node.
%    \begin{macrocode}
\ifx\directlua\@undefined
 \def\@kernel@whatsit{\special{}}
\else
 \def\@kernel@whatsit{\latelua{}}
\fi 
%    \end{macrocode}
% This definition is copied from \pkg{hyperref}, only the command names are changed. It is the code
% \pkg{hyperref} uses around anchors/destination to avoid that they affect the spacing.  
%    \begin{macrocode}
\let\RestoreLastSkip\relax
\def\SaveLastSkip{%
  \let\RestoreLastSkip\relax
  \ifvmode
    \ifdim\lastskip=\z@
      \ifnum\lastnodetype=11 %
        \let\RestoreLastSkip\nobreak
      \else
        \let\RestoreLastSkip\relax
      \fi
    \else
      \begingroup
        \skip@=-\lastskip
        \edef\x{%
          \endgroup
          \def\noexpand\RestoreLastSkip{%
            \noexpand\ifvmode
              \noexpand\nobreak
              \vskip\the\skip@
              \vskip\the\lastskip\relax
            \noexpand\fi
          }%
        }%
      \x
    \fi
  \else
    \ifhmode
      \ifdim\lastskip=\z@
        \let\RestoreLastSkip\nobreak
      \else
        \begingroup
          \skip@=-\lastskip
          \edef\x{%
            \endgroup
            \def\noexpand\RestoreLastSkip{%
              \noexpand\ifhmode
                \noexpand\nobreak
                \hskip\the\skip@
                \hskip\the\lastskip\relax
              \noexpand\fi
            }%
          }%
        \x
      \fi
    \fi
  \fi
}
\hook_new:n{target/setname/after}
\int_new:N\g__kernel_target_int
\NewDocumentCommand\MakeLinkTarget{sO{}m}{%
  \ifvmode
    \SaveLastSkip\@kernel@whatsit\RestoreLastSkip
  \else
    \@savsf\spacefactor
    \SaveLastSkip\smash{}\RestoreLastSkip
    \spacefactor\@savsf
  \fi
  \IfBooleanTF {#1}
   {
     \tl_gset:Ne \@currentHref {#3}
   }
   {
     \int_gincr:N\g__kernel_target_int
     \tl_gset:Ne \@currentHref {target*.\int_use:N\g__kernel_target_int}
   }
  \hook_use:n{target/setname/after} 
  \UseTaggingSocket{recordtarget} 
   }
\ExplSyntaxOff   
%<latexrelease>\EndIncludeInRelease
%<latexrelease>\IncludeInRelease{2024/11/01}%
%<latexrelease>                 {\MakeLinkTarget}{Record target name for tagging support}%
%<latexrelease>\ExplSyntaxOn
%<latexrelease>\NewDocumentCommand\MakeLinkTarget{sO{}m}{%
%<latexrelease>  \ifvmode
%<latexrelease>    \special{}%
%<latexrelease>  \else
%<latexrelease>    \@savsf\spacefactor
%<latexrelease>    \smash{}%
%<latexrelease>    \spacefactor\@savsf
%<latexrelease>  \fi
%<latexrelease>  \IfBooleanTF {#1}
%<latexrelease>   {
%<latexrelease>     \tl_gset:Ne \@currentHref {#3}
%<latexrelease>   }
%<latexrelease>   {
%<latexrelease>     \int_gincr:N\g__kernel_target_int
%<latexrelease>     \tl_gset:Ne \@currentHref {target*.\int_use:N\g__kernel_target_int}
%<latexrelease>   }
%<latexrelease>  \hook_use:n{target/setname/after} 
%<latexrelease>  \UseTaggingSocket{recordtarget} 
%<latexrelease>   }
%<latexrelease>\ExplSyntaxOff   
%<latexrelease>\EndIncludeInRelease
%<latexrelease>\IncludeInRelease{2022/06/01}%
%<latexrelease>                 {\MakeLinkTarget}{Record target name for tagging support}%
%<latexrelease>\NewDocumentCommand\MakeLinkTarget{sO{}m}{%
%<latexrelease>  \ifvmode
%<latexrelease>    \special{}%
%<latexrelease>  \else
%<latexrelease>    \@savsf\spacefactor
%<latexrelease>    \smash{}%
%<latexrelease>    \spacefactor\@savsf
%<latexrelease>  \fi}
%<latexrelease>\EndIncludeInRelease
\NewDocumentCommand\LinkTargetOn{}{}
\NewDocumentCommand\LinkTargetOff{}{}
\NewDocumentCommand\NextLinkTarget{m}{%
  \AddToHookNext{target/setname/after}{\xdef\@currentHref {#1}}}
%    \end{macrocode}
%  \end{macro}
%  \end{macro}
%  \end{macro}
%  \end{macro}
%
%
%    We do not undo \cs{MakeLinkTarget} and friends if we roll back, in
%    case they are used in packages that themselves do not offer
%    rollback. This way a roll forward adds them, but the dummies remain
%    if you roll back and you don't get missing csname errors if they
%    are used.
%    \begin{macrocode}
%<latexrelease>\IncludeInRelease{0000/00/00}{ltmeta}%
%<latexrelease>                 {Undo Document Metadata handling}
%<latexrelease>
%<latexrelease>\let\DocumentMetadata\@undefined
%<latexrelease>
%<latexrelease>\EndModuleRelease
%    \end{macrocode}
%    Again for the future \ldots
%    \begin{macrocode}
%\ExplSyntaxOff
%    \end{macrocode}
%    \begin{macrocode}
%</2ekernel|latexrelease>
%    \end{macrocode}
%
%    Restore module prefix (if any):
%    \begin{macrocode}
%<@@=>
%    \end{macrocode}
%
%
%
%
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\endinput
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
