summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/latex/pdfmanagement-testphase
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2021-02-23 22:38:24 +0000
committerKarl Berry <karl@freefriends.org>2021-02-23 22:38:24 +0000
commit96be5ed7ba5ce4406ca538c4b0d18edeec9d7aab (patch)
treef903bef02645eac80be0107658487813b3ebc6a7 /Master/texmf-dist/source/latex/pdfmanagement-testphase
parent7389bb9fb813a0f5e8654431dacfcb81d1f116e4 (diff)
pdfmanagement-testphase (23feb21)
git-svn-id: svn://tug.org/texlive/trunk@57862 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/source/latex/pdfmanagement-testphase')
-rw-r--r--Master/texmf-dist/source/latex/pdfmanagement-testphase/hyperref-generic.dtx5118
-rw-r--r--Master/texmf-dist/source/latex/pdfmanagement-testphase/l3backend-testphase.dtx1598
-rw-r--r--Master/texmf-dist/source/latex/pdfmanagement-testphase/l3pdfannot.dtx583
-rw-r--r--Master/texmf-dist/source/latex/pdfmanagement-testphase/l3pdfdict.dtx591
-rw-r--r--Master/texmf-dist/source/latex/pdfmanagement-testphase/l3pdffile.dtx746
-rw-r--r--Master/texmf-dist/source/latex/pdfmanagement-testphase/l3pdfmanagement.dtx1468
-rw-r--r--Master/texmf-dist/source/latex/pdfmanagement-testphase/l3pdfmeta.dtx824
-rw-r--r--Master/texmf-dist/source/latex/pdfmanagement-testphase/l3pdftools.dtx427
-rw-r--r--Master/texmf-dist/source/latex/pdfmanagement-testphase/l3pdfxform.dtx204
-rw-r--r--Master/texmf-dist/source/latex/pdfmanagement-testphase/ltdocinit.dtx354
-rw-r--r--Master/texmf-dist/source/latex/pdfmanagement-testphase/pdfmanagement-firstaid.dtx319
-rw-r--r--Master/texmf-dist/source/latex/pdfmanagement-testphase/pdfmanagement-testphase.dtx429
-rw-r--r--Master/texmf-dist/source/latex/pdfmanagement-testphase/pdfmanagement-testphase.ins211
13 files changed, 12872 insertions, 0 deletions
diff --git a/Master/texmf-dist/source/latex/pdfmanagement-testphase/hyperref-generic.dtx b/Master/texmf-dist/source/latex/pdfmanagement-testphase/hyperref-generic.dtx
new file mode 100644
index 00000000000..c279519c3b5
--- /dev/null
+++ b/Master/texmf-dist/source/latex/pdfmanagement-testphase/hyperref-generic.dtx
@@ -0,0 +1,5118 @@
+% \iffalse meta-comment
+%
+%% File: hyperref-generic.dtx
+%
+% Copyright (C) 2021 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
+%
+% http://www.latex-project.org/lppl.txt
+%
+% This file is part of the "LaTeX PDF management testphase bundle" (The Work in LPPL)
+% and all files in that bundle must be distributed together.
+%
+% The released version of this bundle is available from CTAN.
+%
+% -----------------------------------------------------------------------
+%
+% The development version of the bundle can be found at
+%
+% https://github.com/latex3/pdfresources
+%
+% for those people who are interested.
+%
+%<*driver>
+\RequirePackage{pdfmanagement-testphase}
+\DeclareDocumentMetadata{pdfstandard=A-2b}
+\makeatletter
+\declare@file@substitution{doc.sty}{doc-v3beta.sty}
+\makeatother
+\documentclass{l3doc}
+\usepackage{tabularx,array,booktabs,hyperxmp}
+\hypersetup{pdfauthor=The LaTeX Project,
+ pdftitle=generic hyperref driver (LaTeX PDF management testphase bundle)}
+\premulticols=4cm
+\begin{document}
+ \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
+% \fi
+% \NewDocElement[
+% idxgroup=hypersetup keys\actualchar\cs{hypersetup} keys,
+% idxtype = {hypersetup key},
+% printtype= \textit{setup key}
+% ]{Hypkey}{xhypkey}
+% \ExplSyntaxOn
+% \NewDocumentEnvironment{hypkey}{m}
+% {
+% \clist_map_inline:nn {#1}{\begin{xhypkey}{##1}}
+% }
+% {
+% \clist_map_inline:nn {#1}{\end{xhypkey}}
+% }
+% \ExplSyntaxOff
+% \NewDocElement[
+% idxgroup=color names,
+% idxtype = {color name},
+% printtype= \textit{color name}
+% ]{HypColor}{xhypcolor}
+% \ExplSyntaxOn
+% \NewDocumentEnvironment{hypcolor}{m}
+% {
+% \clist_map_inline:nn {#1}{\begin{xhypcolor}{##1}}
+% }
+% {
+% \clist_map_inline:nn {#1}{\end{xhypcolor}}
+% }
+% \ExplSyntaxOff
+% \NewDocElement[
+% idxgroup=Hooks,
+% printtype= \textit{hook}
+% ]{Hook}{hook}
+%
+% \title{^^A
+% The \pkg{hyperref-generic} module \\ A generic driver for hyperref ^^A
+% }
+%
+% \author{^^A
+% The \LaTeX{} Project\thanks
+% {^^A
+% E-mail:
+% \href{mailto:latex-team@latex-project.org}
+% {latex-team@latex-project.org}^^A
+% }^^A
+% }
+%
+% \date{Version 0.95a, released 2021-02-22}
+%
+% \maketitle
+% \begin{documentation}
+% This module generates a generic driver for \pkg{hyperref} meant to be used
+% with the new \LaTeX{} PDF management code. It is loaded automatically
+% if the PDF management code is active. The name of the driver will change after
+% the testphase.
+%
+% The generic driver can be used with pdflatex, lualatex, xelatex, latex with
+% dvipdfmx, latex with dvips+ps2pdf. latex with dvips+distiller could work too
+% but is untested. (x)dvipdfmx will probably soon support dvilualatex, then this
+% combination should work too.
+%
+% The driver \emph{requires} the new PDF management code, so documents wanting to use it
+% should start like this
+% \begin{verbatim}
+% \RequirePackage{pdfmanagement-testphase} %loads the code
+% \DeclareDocumentMetadata % activates it
+% {
+% %% options
+% %% e.g. pdf version, backend:
+% % pdfversion=1.7,
+% % backend = dvipdfmx
+% }
+% \end{verbatim}
+%
+% The new driver tries to be compatible with the standard \pkg{hyperref} drivers
+% but there are nevertheless differences. Some of them due to the still experimental
+% status of the driver, others are design decisions: one part of the project is
+% to clean up and modernize the code. The following sections try to describe
+% the differences but also to document some of the rationales of the changes,
+% and to add some details and comments about the existing options and so to
+% extend the \pkg{hyperref} manual.
+%
+% \section{Avoiding transition problems}
+% Some code will only work properly after other packages have been adapted to
+% the new PDF management code and the changes in this driver.
+% This will take some time. Until then it is recommended to follow
+% the following rules
+% \begin{itemize}
+% \item Package options are processed at the end of the driver,
+% Class options are ignored. But not every option already works as package options,
+% in some cases \pkg{hyperref} interferes. So
+% it is recommended for most options ---with the exception of a few mentioned below in
+% section~\ref{sec:pkg-options}---to set them in \cs{hypersetup},
+% not as package option.
+% \item This driver uses \pkg{l3color} for the colors. All colors
+% defined with \cs{color_set:nn} or \cs{color_set:nnn} will work.
+% Colors defined with \pkg{xcolor} will work if they don't use one of
+% the special color models not supported by \pkg{l3color} as
+% \pkg{pdfmanagement-firstaid} contains a patch for xcolor.
+% If the package \pkg{color} is used it is currently recommended to define
+% colors after \pkg{hyperref}. This driver uses \pkg{l3color} for the colors,
+% some special color models of \pkg{xcolor} won't work.
+% \item Load a color package or graphicx to get the right page sizes.
+% \item Report problems! Only known problem can be resolved.
+% \end{itemize}
+%
+%
+% \section{Bookmarks / outlines}
+% The new driver doesn't contain code to handle bookmarks/outlines.
+% Instead it forces the loading of the \pkg{bookmark} package
+% unless the package option |bookmarks=false|
+% has been used. Currently \pkg{bookmark} is loaded at the end of the preamble
+% so if commands from \pkg{bookmark} are needed in the preamble the document
+% should load it manually. This is subject to change at some time in the future.
+%
+% \section{\enquote{Metadata}}
+%
+% \enquote{Metadata}, informations about the document, are stored in a PDF in two
+% places: The |/Info| dictionary and the XMP-metadata. \pkg{hyperref} only handles the
+% |/Info| dictionary. The XMP-metadata can be added with like \pkg{pdfx} and
+% \pkg{hyperxmp}.
+%
+% The |/Info| dictionary can be filled with arbitrary keys, but the PDF viewer typically
+% care only about a few, like |/Author|, |/Title| and |/Keywords|.
+% A number of |/Info| keys, like dates and the producer, are added automatically
+% by the engines and backends.
+% Some of them can only be removed with special commands, some not at all.
+% But---with the exception of |/Producer| when using the dvips backend---they
+% can be overwritten.
+%
+% The current handling of the metadata is problematic:
+% \begin{itemize}
+% \item External package like \pkg{hyperxmp} wants to access them too and for
+% this had to patch an number of internal hyperref commands---which is a problem
+% if the internal commands change (as happens with this new driver)
+% \item \pkg {hyperref} (and also \pkg{hyperxmp})
+% tries to deduce some datas from document commands like
+% \cs{title} or \cs{author}---something that worked reasonably well when only
+% some standard classes with well-known definitions of these command existed,
+% but gets problematic with classes and packages which define
+% more powerful commands knowing a variety of optional arguments to set authors and
+% affiliations and title information.
+% \end{itemize}
+%
+% To resolve some of this problem the driver will
+% \begin{itemize}
+% \item \emph{Not} try deduce author and title from documents. They have to be set in
+% \cs{hypersetup} with |pdfauthor| and |pdftitle|. It is recommended to separate
+% more than one author by commas, and to hide commas inside braces if needed:
+%
+% \begin{verbatim}
+% pdfauthor = {Bär, Peter Anteater, {Riley, the sloth}}
+% \end{verbatim}
+% \item All values of relevant keys (including keys from the hyperxmp package)
+% will be stored in a Metadata container, and can be retrieved with
+% \cs{GetDocumentProperties}.
+%
+% \begin{verbatim}
+% \edef\my@pdfauthor{\GetDocumentProperties{hyperref/pdfauthor}}
+% \end{verbatim}
+% If the key hasn't be set, the result is empty. This gives external
+% packages a public and reliable access to the data.
+%
+% \item |pdflang| is deprecated. Instead \cs{DeclareDocumentMetadata}
+% should be used:
+% \begin{verbatim}
+% \DeclareDocumentMetadata{lang=de-DE}
+% \end{verbatim}
+%
+% The value can be retrieved as |document/lang|.
+%
+% \end{itemize}
+% \section{Dates}
+% \pkg{hyperref has a few keys to set dates}. They typically expect the date
+% in \enquote{PDF} format: |D:YYYYMMDDhhmmss+01'00'|.
+%
+% One should be aware that \pkg{hyperxmp} will sometimes
+% overwrites such settings.
+% ^^A XMP: yyyy-mm-ddThh:mm:ss+tt:tt, PDF: D:YYYYMMDDhhmmss+01'00'
+%
+% \section{PDF page size (mediabox)}
+% The standard \pkg{hyperref} driver contain code to set the PDF page size.
+% There is no real justification why this is done by \pkg{hyperref} apart from the
+% fact that \LaTeX{} itself doesn't do it and that the needed special code could
+% be added to the backend drivers.
+%
+% In the new driver this code is gone. The reason is not that it is
+% difficult to set the MediaBox, actually it could be done with one line of code:
+% \begin{verbatim}
+% \pdfmanagement_add:nnn{Page}{MediaBox}
+% {[0~0~\dim_to_decimal_in_bp:n{\paperwidth}~
+% \dim_to_decimal_in_bp:n{\paperheight}]}
+% \end{verbatim}
+%
+% The problem is to know which value to use (with the memoir class e.g.\cs{stockwidth}
+% should be used instead of \cs{paperwidth}),
+% and detecting this not a \pkg{hyperref} task. Instead the packages which change
+% these values should also set the PDF page size. Also there are
+% too many actors here: color/graphicx, geometry,the KOMA-classes, memoir,
+% \ldots\ all try to set this.
+%
+% So if the PDF page size is wrong: load one of the other packages setting it
+% e.g. the \pkg{color} or the \pkg{graphicx} package.
+%
+%
+% \section{Link decorations: border, color, OCG-color, \ldots}
+% Some main changes are
+% \begin{itemize}
+% \item The default colors have been changed.
+% \item |citecolor| is no longer set with |allcolors| and it is not part of the
+% color scheme, it is only supported for compability.
+% \item a number of color schemes have been predefined.
+% \end{itemize}
+%
+% \subsection{Background information}
+% With the standard drivers \pkg{hyperref} allows either to color the link text,
+% or to use a border around it.
+% There is also a (rather unknown) option |frenchlinks| to use small caps
+% for some links instead of colors.
+%
+% The \emph{link border} is a setting in the PDF annotation directory.
+% It can be colored and styled (with the |<xxx>bordercolor|, |pdfborderstyle|
+% and |pdfhighlight| keys), but the exact look depends on the PDF viewer.
+% Such decorations are normally not printed.
+%
+% The \emph{link text} is colored with the standard color commands for text.
+% Such a color is also printed, which is often not wanted. The printing
+% can be avoided in PDF with so-called OCG-layers: They allow to add
+% variants of a text along with instructions which variant should be used for
+% viewing and which for printing. \pkg{hyperref} implements a rather simple version
+% for links: The link text is put in a box and printed twice with different colors
+% on different OCG layers. As boxes are used such links can't be broken. The
+% package \pkg{ocgx2} implements a more sophisticated version which allows to
+% use it for links broken over lines and pages.
+%
+% \pkg{hyperref} has keys to set the color and border for |link|, |url|, |file|,
+% |menu| and |run| types. They correspond to the PDF annotation types
+% |GoTo|, |URI|, |GoToR|, |Named| and |Launch|.
+% Beside this there is a |anchorcolor| which isn't used at all, and |citecolor|
+% which is a semantical category and doesn't fit to the other types.
+%
+% In the standard drivers the decoration options are more or less exclusive and global:
+% One of the options (|colorlinks|, |ocgcolorlinks|, or borders) has to be
+% chosen in the preamble and is then used for the whole document
+% and all link types.
+% Only colors and eventually the border style can be adjusted locally.
+% But there is no technical reason for these restrictions:
+% It is quite possible to change all these attributes
+% at any time both by link type and locally. The restrictions of the current
+% implementation can only be explained by the age of the code: \pkg{hyperref}
+% has been created at a time when memory was small and the main drivers were html
+% and postscript based.
+%
+% While link colors have been traditionally more or less
+% under the control of \pkg{hyperref},
+% the situation with other format options, like the font, is more complicated.
+% The font in \cs{url} is for example determined by \cs{Urlfont},
+% a command from the \pkg{url} package.
+% In the case of internal (GoTo) references packages like \pkg{cleveref} or
+% \pkg{biblatex} or \pkg{glossaries} offer formatting options too.
+% Formatting here is often connected to semantics:
+% an acronym should use a different font than a citation.
+% While \pkg{hyperref} could offer options here, it would probably only clash
+% with package formatting. It is more sensible not to interfere here. For this
+% reason the |frenchlinks| option has been dropped.
+%
+% \subsection{New Keys}
+% Some of the existing keys have been extended to allow individual setting for
+% the link types |link|, |url|, |file| |menu| and |run|:
+%
+% \begin{itemize}
+% \item Beside |pdfborder| there are also |linkborder|, |urlborder| etc
+% \item Beside |pdfhighlight| there are also |linkhighlight|, |urlhighlight| etc
+% \item Beside |pdfborderstyle| there are also |linkborderstyle|, |urlborderstyle| etc
+% \item Beside |colorlinks| there are also |colorlink|, |colorurl| etc
+% \item Beside |ocgcolorlinks| there are also |ocgcolorlink|, |ocgcolorurl|, etc %TODO
+% \item Beside |hidelinks| there are also |hidelink|, |hideurl|, etc
+% \item |bordercolormodel| allows to set the model used in annotations,
+% the allowed values are |rgb| or |cmyk|. |rgb| is the default.
+% It does \emph{not} change the model of text colors. Be aware
+% that while the PDF format allows cmyk (4 numbers) in the |/C| key of an annotation,
+% this is often ignored by pdf viewers and the colors can be wrong.
+% \item The boolean keys |url|, |link|, |run|, |menu|, |file| allow to deactivate
+% locally the link types.
+% \end{itemize}
+%
+% \begin{hypkey}{colorscheme}
+%
+% The new key |colorscheme| allows to switch the colors (both for text and borders)
+% with a key word. It takes one of the values
+% |orginal| (the colors as hyperref uses normally), |phelype|, |daleif|,
+% |szabolcsA|, |szabolcsB|, |tivv|, |julian|, |henryford|.
+%
+% The names refer to the authors in answers and comments in
+% \url{https://tex.stackexchange.com/questions/525261/better-default-colors-for-hyperref-links}.
+%
+% The default is |phelype|.
+% \end{hypkey}
+%
+% \subsection{Public interfaces}
+% The |colorlinks| and |ocgcolorlinks| and related keys are
+% using these booleans:
+% \begin{verbatim}
+% \l_hyp_annot_colorlink_bool,
+% \l_hyp_annot_colorurl_bool,
+% \l_hyp_annot_colorfile_bool,
+% \l_hyp_annot_colorrun_bool,
+% \l_hyp_annot_colormenu_bool,
+% \l_hyp_annot_ocgcolorlink_bool,
+% \l_hyp_annot_ocgcolorurl_bool,
+% \l_hyp_annot_ocgcolorfile_bool,
+% \l_hyp_annot_ocgcolorrun_bool,
+% \l_hyp_annot_ocgcolormenu_bool,
+% \end{verbatim}
+%
+% They are both inserting hook code in the |pdfannot/link/|\meta{type}|/begin|
+% and |pdfannot/link/|\meta{type}|/end| hooks. \meta{type} is one of
+% |GoTo|, |URI|, |GoToR|, |Named| or |Launch|.
+%
+% |colorlinks| uses the label |hyp/color|, and |ocgcolorlinks| the label |hyp/ocg|.
+%
+% They both use the same color names: |hyp/color/link|, |hyp/color/url|,
+% |hyp/color/file|, |hyp/color/run|, |hyp/color/menu|.
+%
+% The cite colors uses the names |hyp/color/cite| and |hyp/color/citeborder|.
+%
+% The border colors aren't saved in color names currently, but if the need
+% would arise it would possible to change this.
+% \subsection{Changed behaviour}
+% \begin{description}
+% \item[colorlinks] |colorlinks| will as before disable the |pdfborder|, but it is possible
+% to use the key in the document at any time, or to reenable the border if wanted.
+% Internally |colorlinks| \& friends will no longer define/undefine
+% |\Hy@colorlink|, but instead use the hooks provided by the \pkg{l3pdfannot} package.
+% \item Color keys accept the following input syntax:
+%
+% \begin{tabular}{ll}
+% model based & |urlbordercolor = [rgb]{1,1,0}| \\
+% color expression & |urlbordercolor = red!50!blue| \\
+% command & |urlbordercolor = \mycolor|
+% \end{tabular}
+%
+% where |\mycolor| should expand to one of the other two syntax variants.
+%
+% \item[frenchlinks] The option |frenchlinks| does nothing at all.
+% \item[cite colors] As mentioned above the support for |citecolor|
+% and |citebordercolor| has been reduced. A package like \pkg{hyperref}
+% can't keep track of such semantic
+% contexts like cite, acronym, glossaries and special references and maintain keys for
+% them. The keys are not completly dropped as this would affect packages like
+% \pkg{natbib}, but they have been separated and are no longer affected by
+% group keys like |allcolors| but must be set individually instead.
+%
+% \item[link margin] The driver sets a default link margin---this is identical
+% to pdftex and luatex driver, but a change for the xetex and dvips driver.
+% The (undocumentated) command \cs{setpdflinkmargin} does nothing.
+% Use either the key |pdflinkmargin| or \cs{pdfannot_link_margin:n} to change the margin.
+% See also the description in section~\ref{sec:keydesc} and in the hyperref manual.
+% \end{description}
+%
+% \section{PDF strings}
+%
+% \pkg{hyperref} uses a command called \cs{pdfstringdef} to convert text input into
+% something that makes sense and is valid in a PDF string, e.g. in the bookmarks
+% or in the info dictionary or as form field values.
+%
+% As the handling of the outlines are delegated to the \pkg{bookmark} package, they
+% will for now still use \cs{pdfstringdef}, but all other strings produced by
+% this driver will use a new method based on the expl3 commands
+% \cs{text_purify:n} and \cs{str_set_convert:Nnnn}. For normal text
+% it shouldn't matter, but a variety of commands and math are handled differently.
+% Like with \cs{pdfstringdef} they are a number of ways to adjust the outcome of
+% \cs{text_purify:n}. These are described in the expl3 documentation interface3.pdf.
+%
+% \emph{The new method is under heavy development!}
+%
+% Important differences here are
+% \begin{itemize}
+% \item \emph{This new method requires that files are utf8-encoded}
+% (at least if non-ascii chars are used in for PDF strings).
+% \item \emph{All} robust commands are currently removed,
+% unless an equivalent has been declared.
+% \item Currently the new method is much more silent: it doesn't warn like
+% \pkg{hyperref} if it removes commands.
+% \end{itemize}
+%
+% \section{Package options from hyperref}\label{sec:pkg-options}
+% The driver will process the package options at the end.
+% But normally options should better be set with \cs{hypersetup} after
+% the package has been loaded. This is also the case for options which normally
+% don't work in \cs{hypersetup}.
+% One option that currently doesn't work correctly as package option is
+% |ocgcolorlinks|
+%
+%
+% Options that still must be set as package options are
+% \begin{itemize}
+% \item |backref|
+% \item |CJKbookmarks| this key should not be used anymore. At some time
+% it will be removed.
+% \item |destlabels| (destination names are taken from \cs{label} if possible)
+% \item |encap|
+% \item |hyperfigures| (according to the \pkg{hyperref} manual
+% it makes figures hyper links, but actually is a no-op for most drivers, and it
+% does nothing with this driver either.)
+% \item |hyperfootnotes|
+% \item |hyperindex|
+% \item |implicit| (redefine \LaTeX\ internals)
+% \item |nesting| unneeded key, see comment below in \ref{sec:keydesc}. At some time
+% it will be either removed or extended (if some use can be found).
+% \item |pagebackref|
+% \item |pdfpagelabels| (set PDF page labels)
+% \item |psdextra| this loads some extra definitions used by \cs{pdfstringdef}.
+% The new driver uses \cs{pdfstringdef} only for the bookmarks, for other strings
+% it is not relevant.
+% \end{itemize}
+%
+% Options that can be without problems set as package options are
+% \begin{itemize}
+% \item |debug|, |verbose| (a boolean)
+% \item |bookmarks| (a boolean)
+% \item |plainpages|
+% \item |draft|, |final|
+% \item |hypertexnames|
+% \item |naturalnames|
+% \item |pageanchor|
+% \end{itemize}
+%
+% Ignored options:
+% \begin{itemize}
+% \item All driver options like |pdftex|, |dvipdfmx|, \ldots
+% \item |raiselinks| (only used in the dviwind, textures and tex4ht driver anyway)
+% \item |frenchlinks|
+% \item |setpagesize|
+% \item |addtopdfcreator|
+% \end{itemize}
+%
+% \section{Disabling links}
+%
+% \pkg{hyperref} knows like many packages the options |draft| and |final|.
+% With \pkg{hyperref} they can be used as package options or in the preamble
+% in \cs{hypersetup} and disable links and anchors completely.
+% The new driver passes the options also to the \pkg{bookmark} package if
+% \pkg{bookmark} hasn't been loaded yet as bookmarks can't work properly if
+% the anchors from hyperref are missing.
+%
+% \DescribeHypkey{link}%
+% \DescribeHypkey{url}%
+% \DescribeHypkey{file}%
+% \DescribeHypkey{run}%
+% \DescribeHypkey{menu}%
+% The |draft| option is a global option that can't be undone (at least not easily).
+% So the new driver offers also boolean keys |link|, |url|, |file|, |run| and |menu|
+% which allow to locally disable a link type. So e.g.
+% |\hypersetup{link=false}\ref{abc}| will give a reference without link (this
+% is naturally also possible with |\ref*{abc}|). This disables also all hooks of
+% the link type, so the link is for example no longer colored. It also removes the
+% implicit grouping of the content.
+%
+%
+% \section{Draftmode}
+% pdftex and other engines knows a
+% draftmode which can be set with |\pdfdraftmode=1|
+% and \pkg{hyperref} honors this in some places. The new
+% driver ignores it, for example |pagelabels| are created in any case.
+% With today's computer power there is not much to gain and it only complicates
+% the code.
+%
+% This should not be confused with the |draft| and |final| package options! They
+% are still honored.
+%
+% \section{Dropped options}
+% A number of options are ignored by this driver
+% \begin{description}
+% \item[pdfversion] The pdfversion should be set in \cs{DeclareDocumentMetadata}
+% \item[setpagesize] The key is ignored and the PDF page size is not
+% set. Load \pkg{color} or \pkg{graphicx} or use a class which sets the PDF page size.
+% \item[breaklinks] The option does nothing sensible anyway (apart from triggering
+% a warning). Currently with latex+dvips links can't be broken. But there is work
+% in progress to change this.
+% \item[unicode] This is always true.
+% \item[pdfa] If this option is set to true \pkg{hyperref} normally checks and sets
+% a small number of requirements for the PDF standard PDF/A.
+% The key is ignored with this driver. Instead the wanted standard should be declared
+% in \cs{DeclareDocumentMetadata}:
+% \begin{verbatim}
+% \DeclareDocumentMetadata{standard=A-2b}
+% \end{verbatim}
+% Currently |A-1b|, |A-2b|, |A-3b| can be set.
+% The support for various requirements is still incomplete, but the parts that
+% \pkg{hyperref} checked are implemented:
+% \begin{itemize}
+% \item The |/F| key is added to links and |Print| is activated, |Hidden|, |Invisible|,
+% |NoView| are deactivated.
+% \item |/NeedAppearances| is suppressed
+% \item Pushbuttons, which use the action |/S/JavaScript| are suppressed.
+% \item Resetbuttons, which use the action |/S/ResetForm| are suppressed.
+% \item In widget annotations, the /AA dictionary is suppressed.
+% \end{itemize}
+% \end{description}
+% \section{Destinations}
+% Destinations (sometimes call anchors in the \pkg{hyperref} documentation)
+% are the places a link jumped too. Unlike the name may suggest they don't described
+% an exact location in the PDF. Instead a destination contains a reference to
+% a page along with an instruction how to display this page.
+% The normally used \enquote{XYZ \textit{top left zoom}} for example instructs
+% the viewer to show the page with the given \textit{zoom} and
+% the top left corner at the \textit{top left} coordinates---which then gives
+% the impression that there is an anchor at this position.
+%
+% From these instructions two (|Fit| and |FitB|) don't take an argument.
+% All others take one (|FitH|, |FitV|, |FitBH|, |FitBV|)
+% or more (|XYZ|, |FitR|) arguments. These arguments are normally
+% coordinates, |XYZ| takes also a zoom factor. The coordinates are
+% absolute coordinates in |bp| relative to the lower left corner
+% of the PDF.
+%
+% With the primitive command \cs{pdfdest} of pdftex almost all instructions are created
+% with a keyword only: The needed coordinate is calculated automatically from the location
+% the \cs{pdfdest} command is issued. So to get a specific coordinate one has to
+% move the command to the right place. E.g.
+% \begin{verbatim}
+% \AddToHookNext{shipout/background}
+% {\put(0,-\pdfpageheight+100bp){\pdfdest name{destA} FitH\relax}}
+% \end{verbatim}
+%
+% Exceptions are the |XYZ| instruction, where pdftex accepts a keyword
+% |zoom| followed by a zoom factor, and the |FitR| instruction
+% which understands the keywords |width|, |height| and |depth|
+% followed by a dimension, which is then used to calculate a rectangle relative to the
+% current location. If no keywords are given the dimensions are taken from the surrounding
+% box---which can also lead to zero sized areas.
+%
+% The manual of \pkg{hyperref} gives a bit the impression as if this
+% coordinates can be set manually by the user but as described above this is
+% mostly wrong: It is for normal destination only possible with a dvi-backend like
+% dvips which make use of |pdfmark.def|. pdftex and luatex can use manual coordinates
+% only for |pdfstartview| and |pdfremotestartview|.
+% As dvips was the first driver of \pkg{hyperref} the option |pdfview| was at first
+% developed for it and then adapted to pdftex. But this had the effect that the handling
+% of the option |pdfview| is inconsequent across the backend and engines:
+% For example with |pdfview=FitH 100| pdftex ignores the
+% number and calculates its own, while dvips sets the coordinate to the absolute
+% 100. The zoom factor of |XYZ| is not supported by the pdftex driver at all, and
+% |FitR| only partially.
+%
+% The generic driver consolidate this but tries to stay compatible with the other
+% drivers as far as possible.
+% It also takes into account that |pdfview| and |pdfstartview| and |pdfremotestartview|
+% have different requirements: While for the first relative coordinates are fine,
+% for the two others absolute coordinates are more sensible.
+%
+% \DescribeHypkey{pdfview}
+% \DescribeHypkey{pdfstartview}
+% \DescribeHypkey{pdfremotestartview}
+% So with this driver the options
+% |pdfview|, |pdfstartview| and |pdfremotestartview| take
+% the following options:
+% \begin{itemize}
+% \item |Fit|, |FitB|, |FitH|, |FitV|,
+% |FitBH|, |FitBV| which can be followed by a positive integer (separated by a space) or the
+% keyword |null|.
+% The number can be gives as a \meta{dimension expression} surrounded with
+% \cs{hypercalcbp}. The driver redefines this command to use
+% \cs{dim_to_decimal_in_bp:n}.
+% \begin{itemize}
+% \item |pdfview| will ignore the integer and any other arguments and calculate
+% the expected coordinates as described above for pdftex with all
+% supported engines and backends.
+% \item |pdfstartview| and |pdfremotestartview| will pass the optional
+% number or keyword after expansion as absolute coordinate. Missing numbers will
+% be filled up with |null|.
+% \end{itemize}
+%
+% \item |XYZ|. This can be followed (separated by spaces) by up to three
+% positive integers or keywords |null| which are then taken as \textit{top left zoom}
+% in this order. \textit{zoom} is a factor, so e.g. 0.5 will give a scaling of 50\%.
+% \begin{itemize}
+% \item |pdfview| will use the last value as \textit{zoom}, ignore all other values
+% and calculate the expected coordinates as described above for pdftex with all
+% supported engines and backends (this means it is possible to use |XYZ 2| to
+% set a zoom of 200\%, it is not necessary to fill in dummy values.)
+% \item |pdfstartview| and |pdfremotestartview| will pass the optional
+% numbers or keyword after expansion as absolute coordinates and zoom.
+% Missing numbers will be filled up with |null|.
+% \end{itemize}
+% This new behaviour is in part incompatible with previous handling with the dvips driver.
+%
+%
+% \item |FitR|.
+% If no argument (separated by spaces) follows then
+% |pdfview| will use with pdftex and luatex
+% the automatic calculation of the coordinates from the encompassing box. With
+% dvips and (x)dvipdfmx it will fall back to |Fit|.
+% |pdfstartview| and |pdfremotestartview| will fallback to |Fit| too.
+%
+% If arguments (separated by spaces) follow they should be
+% four numbers representing \texttt{left bottom right top}.
+% \begin{itemize}\item
+% |pdfview| will use the values to calculate coordinates relative to the current
+% location. So |0 -100 200 400| will give a \enquote{box} of width 200bp,
+% height 400bp and depth 100dp that the destination should encompass.
+% Missing numbers will be set to 0. But one should be aware that is it is quite
+% unpredicable how viewers which support |FitR| handles zero sizes.
+%
+% \item |pdfstartview| and |pdfremotestartview| will pass
+% the values as absolute coordinates.
+% \end{itemize}
+% \end{itemize}
+%
+%
+%\section{Assorted key descriptions}\label{sec:keydesc}
+%The following gives a few details to some keys that are perhaps not
+%completly described in the manual, or are a bit different in this driver.
+%The list is alphabetic.
+%
+% \DescribeHypkey{bookmarkstype} This key takes as value the extension of a list
+% like |toc| or |lof|. If this list uses \cs{addcontentsline} the content will
+% be added to the bookmarks. The key can be use in \cs{hypersetup} and also in
+% the middle of the document to switch the list.
+%
+% \DescribeHypkey{bordercolormodel} With |bordercolormodel| the colormodel used in the |/C|
+% key of the annotation array and in similar keys is set. It does not affect
+% the text and graphics colors in the page stream.
+% Possible choices are |rgb| (three numbers in the array) and |cmyk| (four numbers).
+% While the PDF reference allows four numbers, PDF readers don't necessarly handle
+% this correctly, so the value can be wrong.
+%
+% \DescribeHypkey{destlabel} This is a boolean key. Currently it must be set
+% as package option. If set to true, the name
+% of a destination is taken from a following \cs{label}, if there is one before
+% the next destination command. This requires two compilations to get
+% the correct coordinates in the destination. In the first compilation
+% the alias name is recorded in the aux-file:
+% \begin{verbatim}
+% \hyper@newdestlabel{section.1.2}{sec:sec2}
+% \end{verbatim}
+% The next compilation can then make use of it.
+% The two-pass could be avoided in the future with a better labeling system,
+% where the name if set earlier.
+%
+% \DescribeHypkey{extension} This key sets an variable that has two purposes:
+% It is used if file name has not extension, and it decides if the annotation
+% is a URI or GoToR annotation. So
+% \begin{verbatim}
+% \hypersetup{extension=dvi}
+% \href{mwe1.pdf}{pdf}
+% \href{mwe2.dvi}{dvi}
+% \href{mwe3}{no ext}
+% \end{verbatim}
+% will create
+% \begin{verbatim}
+% /Subtype/Link/A<</S/URI /URI(mwe1.pdf)>>
+% /Subtype/Link/A<</S/GoToR /F (mwe2.dvi)>>
+% /Subtype/Link/A<</S/GoToR /F (mwe3.dvi)>>
+% \end{verbatim}
+% Typically PDF viewer can handle only GoToR annotions pointing to a PDF.
+% So normally the default value |pdf| of this key should not be changed.
+% \DescribeHypkey{nesting}\label{key:nesting}%
+% This key is useless in PDF context. The boolean is only used in
+% the code for anchors/destination where nesting doesn't make sense.
+% It should not be changed.
+%
+% \DescribeHypkey{pdfborder}\DescribeHypkey{linkborder}\DescribeHypkey{urlborder}
+% \DescribeHypkey{runborder}\DescribeHypkey{menuborder}
+% This key set accept as value three numbers or three numbers and an array describing
+% a dash pattern, examples are |0 0 1| or |0 0 1 [3 2]|.
+% The first two numbers should according to the reference set round
+% corners, but PDF viewer seem to ignore it. The third number is the line width
+% of the border. Settings done with |pdfborderstyle| should take precedence.
+%
+% \DescribeHypkey{pdfborderstyle}\DescribeHypkey{linkborderstyle}
+% \DescribeHypkey{urlborderstyle}\DescribeHypkey{fileborderstyle}
+% \DescribeHypkey{runborderstyle}\DescribeHypkey{menuborderstyle}
+% The value of this key is the content of the |BS| dictionary.
+% As an example |/Type/Border /W 1 /S/U /D[3 2]|
+%
+% \begin{tabular}{>{\ttfamily} lll}
+% Key & Values & comment / example\\\hline
+% /Type & |/Border| & optional \\
+% /W & \meta{number} & Width of border line \\
+% /S & |/S| & solid (default)\\
+% & |/D| &dash pattern can be set with /D\\
+% & |/B| & beveled\\
+% & |/I| & inset\\
+% & |/U| & underline\\
+% /D & \meta{array of numbers} & dash pattern (lines/gaps) (default [3])
+% \end{tabular}
+%
+% \DescribeHypkey{pdfcreationdate}\DescribeHypkey{pdfmoddate}
+% Setting these keys is normally not needed. If they are used the values
+% are stored directly in the Info dictionary for |/Creationdate| and |/ModDate|.
+% The values are converted to strings but not processed further, so they should
+% have the correct PDF format without the enclosing parentheses,
+% e.g. |D:20200202111111+01'00'|.
+%
+% \DescribeHypkey{pdflinkmargin}As described in the \pkg{hyperref} manual
+% the behaviour differs between the backends: with dvips it is possible to
+% change links locally, pdflatex and lualatex work by page, with dvipdfmx
+% the setting is global (and has to be done in the preamble).
+%
+% \DescribeHypkey{pdflang} The key will work, but it is recommended to the set
+% the language in \cs{DeclareDocumentMetadata} instead.
+%^^A %% This is an adapted version of hluatex.def
+%^^A %% meant to test the use of the commands
+%^^A %% from pdfmanagement.sty
+%^^A %%
+%^^A %% drivers are loaded in line 4745 in hyperref.sty in a \Hy@AtEndOfPackage command.
+%^^A %%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%^^A %% list of new internal commands
+%^^A %% __hyp_link_goto_begin:nw : start command for links to internal destination
+%^^A %% replaces \find@pdflink
+%^^A %% __hyp_link_goto_end:
+%^^A %% __hyp_destination:n : sets an anchor, replaces \new@pdflink
+%^^A %% \__hyp_PageLabels_gpush: : puts pagelabels in the catalog, used on every storing
+%^^A %% PDF String (text)
+%^^A %% *\@@_text_pdfstring:nnN : replaces Hy@pstringdef, converts #1 to pdfstring in encoding #2
+%^^A %% and stores in N
+%^^A %% Build with:
+%^^A %% *\@@_text_purify:nN
+%^^A %% *\@@_text_cleanup:N
+%^^A %% *\@@_text_convert:nN
+%^^A %%
+%^^A %% Destinations (dest)
+%^^A %% \l_@@_dest_box
+%^^A %%
+%^^A %% References (ref)
+%^^A %% *\@@_ref_label:nn
+%^^A %% *\@@_ref_if_exist:nn
+%^^A %% *\@@_ref_check:nn
+%^^A %% % helps to display key list messages
+%^^A %% \@@_clist_display:n
+%^^A %%
+%^^A %% \__hyp_info_generate_addons: what did this do??
+%^^A %%
+%^^A %% \g__hyp_AcroForm_CoFields_prop
+%^^A %% \g__hyp_AcroForm_Fields_prop
+%^^A %%
+%^^A %% \g_@@_dest_pdfstartpage_tl ,
+%^^A %% \g_@@_dest_pdfstartview_tl ,
+%^^A %% \l_@@_dest_pdfremotestartview_tl ,
+%^^A
+%^^A %% Constants
+%^^A %% *\c_@@_map_annot_hyp_prop
+%^^A %% *\c_@@_dest_undefined_tl
+%^^A %% Temp variables
+%^^A %% \l_@@_tmpa_seq
+%^^A %% \l_@@_tmpa_box
+%^^A %% \l_@@_tmpa_tl
+%^^A %% \l_@@_tmpa_str
+%^^A %% \l_@@_tmpa_int
+%^^A %%
+%^^A %% \l_@@_dest_name_tmpa_tl
+%^^A %% \l_@@_uri_tmpa_tl
+%^^A %% \l_@@_filename_tmpa_tl
+%^^A %% \l_@@_para_tmpa_tl
+%^^A %% \l_@@_text_tmpa_str
+%^^A %% \g_@@_text_tmpa_str
+%^^A %% \l_@@_CheckmarkYes_tl
+%^^A %% \l_@@_CheckmarkOff_tl
+%^^A %% \l_@@_RadioYes_tl
+%^^A %% \g_@@_bordercolormodel_tl
+%
+%^^A %% \l_@@_dest_pdfview_tl
+%^^A %% list of commands which probably will have to change
+% \end{documentation}
+% \begin{implementation}
+% \part{\pkg{hyperref-generic} driver implementation}
+% \begin{macrocode}
+%<*package>
+%<@@=hyp>
+% \end{macrocode}
+% \begin{macrocode}
+\ProvidesFile{hgeneric-testphase.def}
+ [2021/02/22 v0.95a %
+ generic Hyperref driver for the LaTeX PDF management testphase bundle]
+
+\RequirePackage{etoolbox} %why?
+% \end{macrocode}
+% \begin{macrocode}
+\ExplSyntaxOn
+\file_input:n {hyperref-colorschemes.def}
+\ExplSyntaxOff
+% \end{macrocode}
+%
+%
+% \section{messages}
+% Redirect the message name:
+% \begin{macrocode}
+\ExplSyntaxOn
+\prop_gput:Nnn \g_msg_module_name_prop { hyp }{ hyperref }
+% \end{macrocode}
+% At first a message for the testing of the resource management
+% \begin{macrocode}
+\msg_new:nnnn
+ { hyp }
+ { missing-resource-management }
+ { The~PDF~resource~management~is~required~for~this~hyperref~driver! }
+ {
+ Activate~it~with \\
+ \tl_to_str:n{\RequirePackage{pdfmanagement-testphase}}\\
+ \tl_to_str:n{\DeclareDocumentMetadata{<options>}}\\
+ before~\tl_to_str:n{\documentclass}
+ }
+% \end{macrocode}
+% The pdfversion should be set in \cs{DeclareDocumentMetadata}
+% \begin{macrocode}
+\msg_new:nnnn
+ { hyp }
+ { pdfversion-disabled }
+ {
+ This~hyperref~driver~ignores~the~pdfversion~key!\\
+ Set~the~pdfversion~in~\token_to_str:N \DeclareDocumentMetadata
+ }
+ {
+ For example:\\
+ \tl_to_str:n
+ {
+ \DeclareDocumentMetadata { pdfversion=1.7 }
+ }
+ }
+% \end{macrocode}
+% A generic message for ignored keys.
+% \begin{macrocode}
+\msg_new:nnn
+ { hyp }
+ { key-dropped }
+ {
+ This~hyperref~driver~ignores~the~key~#1!\\
+ Please~check~the~documentation.
+ }
+% \end{macrocode}
+% pdf/A messages for fields, this will probably be moved to an external package
+% \begin{macrocode}
+\msg_new:nnn
+ { hyp }
+ { pdfa-no-push-button }
+ { PDF/A:~Push~button~with~JavaScript~is~prohibited }
+
+\msg_new:nnn
+ { hyp }
+ { pdfa-no-reset-button }
+ { PDF/A:~Reset~action~is~prohibited }
+% \end{macrocode}
+% pdf/A message for not allowed Named actions
+% \begin{macrocode}
+\msg_new:nnn
+ { hyp }
+ { pdfa-no-named-action }
+ { PDF/A:~Named~action~#1~is~prohibited }
+% \end{macrocode}
+% A message if the destination name is empty.
+% \begin{macrocode}
+\msg_new:nnn
+ { hyp }
+ { empty-destination-name }
+ {
+ Empty~destination~name,\\
+ using~`#1'
+ }
+% \end{macrocode}
+% A message if the destination check fails
+% \begin{macrocode}
+\msg_new:nnn
+ { hyp }
+ { invalid-destination-value }
+ {
+ Invalid~value~`#1'~of~`#2' \\
+ is~replaced~by~`Fit'~\msg_line_context:.
+ }
+% \end{macrocode}
+% Some options or values should not be used in older pdf versions
+% \begin{macrocode}
+\msg_new:nnn
+ { hyp }
+ { ignore-deprecated-or-unknown-option-in-pdf-version }
+ {
+ Option~`#1'~is~unknown~or~deprecated~in\\
+ pdf~version~#2.~Ignored.
+ }
+\msg_new:nnn
+ { hyp }
+ { ignore-deprecated-or-unknown-value-in-pdf-version }
+ {
+ Value~`#1'~is~unknown~or~deprecated~in\\
+ pdf~version~#2.~Ignored.
+ }
+\msg_new:nnn
+ { hyp }
+ { replace-deprecated-or-unknown-value-in-pdf-version }
+ {
+ Value~`#1'~is~unknown~or~deprecated~in\\
+ pdf~version~#2. Value~`#3'~is used instead.
+ }
+% \end{macrocode}
+% During development not all standard hyperref keys are known and the
+% Hyp-handler needs to process some new keys unknown to him.
+% This issues warnings for now:
+% \begin{macrocode}
+\msg_new:nnn
+ { hyp }
+ { unknown-key }
+ {
+ unknown~key~#2~of~module~’#1’~set~to~’#3’.
+ }
+\msg_new:nnn
+ { hyp }
+ { unknown-key-to-Hyp }
+ {
+ ignored~in~family~Hyp~unknown~key~#1.
+ }
+% \end{macrocode}
+% There are a lot choice keys. This defines messages which shows the valid
+% choices if a faulty one has been used:
+% \begin{macrocode}
+\cs_new:Npn \@@_clist_display:n #1 {*~#1\\}
+\msg_new:nnn
+ { hyp }
+ { unknown-choice }
+ {
+ Value~'#3'~is~invalid~for~key~'#1'.\\
+ The~key~accepts~only~the~choices\\
+ \clist_map_function:nN { #2 }\@@_clist_display:n
+ }
+
+\msg_new:nnn
+ { hyp }
+ { unknown-choice+empty }
+ {
+ Value~'#3'~is~invalid~for~key~'#1'.\\
+ The~key~accepts~only~the~choices\\
+ \clist_map_function:nN { #2 }\@@_clist_display:n
+ An~empty~value~removes~the~setting.
+ }
+
+\msg_new:nnn
+ { hyp }
+ { no-bool }
+ {
+ Value~'#2'~is~invalid~for~key~'#1'.\\
+ The~key~accepts~only~the~choices\\
+ *~true\\
+ *~false \\
+ *~and~an~empty~value~which~removes~the~setting.\\
+ No~value~is~equivalent~to~using~`true`.
+ }
+% \end{macrocode}
+% \section{Variants}
+% \begin{macrocode}
+\cs_generate_variant:Nn\pdf_destination:nn {nf}
+% \end{macrocode}
+% \section{Overwriting/providing commands from hyperref}
+% hyperref checks driver version, we need to suppress this during the development
+% \begin{macrocode}
+\chardef\Hy@VersionChecked=1 %don't check the version!
+% \end{macrocode}
+% \begin{macrocode}
+%\cs_set_protected:Npn \PDF@SetupDoc{}
+%\\PDF@FinishDoc{}% dummy needed for hyperref ...
+% \end{macrocode}
+% \begin{macro}[EXP]{\hypercalcbp}
+% We define a better (expandable) version of \cs{hypercalcbp}
+% \begin{macrocode}
+\cs_set_eq:NN \hypercalcbp \dim_to_decimal_in_bp:n
+% \end{macrocode}
+% \end{macro}
+%
+% This command must be provided for now, but they are unused by the driver:
+% \begin{macrocode}
+\providecommand\@pdfborder{}
+\providecommand\@pdfborderstyle{}
+\newcommand\OBJ@OCG@view {} % needed in hyperref
+\def\Hy@numberline#1{#1\c_space_tl} %needed by bookmark
+% \end{macrocode}
+%
+% We force unicode as option. As bookmarks are still using \cs{pdfstringdef}
+% we also need to load puenc.def.
+% \begin{macrocode}
+\HyPsd@LoadUnicode
+\Hy@unicodetrue
+\let\HyPsd@pdfencoding\HyPsd@pdfencoding@unicode
+\Hy@DisableOption{unicode}
+% \end{macrocode}
+% The pdfversion should be set in \cs{DeclareDocumentMetadata} but we must
+% copy it to the \pkg{hyperref} command:
+% \begin{macrocode}
+\cs_set_eq:NN \Hy@pdfminorversion \pdf_version_minor:
+\cs_set_eq:NN \Hy@pdfmajorversion \pdf_version_major:
+% \end{macrocode}
+% \begin{macrocode}
+\legacy_if:nT { Hy@setpdfversion }
+ {
+ \msg_warning:nn { hyp }{ pdfversion-disabled }
+ }
+\Hy@DisableOption{pdfversion}
+% \end{macrocode}
+% \cs{Acrobatmenu} should use the new internal link command
+% \begin{macrocode}
+\RenewDocumentCommand \Acrobatmenu { m m }
+ {
+ \hyper@linknamed {#1} {#2}
+ }
+% \end{macrocode}
+%
+% \cs{hypersetup} should set the new keys.
+% We can't also execute |\kvsetkeys{Hyp}| as this errors for example with colors.
+% This means the driver has to provide new code for every key!
+%
+% \begin{macrocode}
+% TODO should go at some time ...
+% \kv@set@family@handler{Hyp}
+% { \msg_warning:nnx {hyp}{unknown-key-to-Hyp}{#1} }
+\cs_set_protected:Npn \hypersetup #1
+ {
+ %\kvsetkeys{Hyp} {#1}
+ \keys_set:nn { hyp / setup }{ #1 }
+ }
+% TODO for now unknown keys should only give warnings.
+\keys_define:nn { hyp / setup }
+ {
+ unknown .code:n =
+ {
+ \msg_warning:nnxxx { hyp } { unknown-key }
+ { hyp~/~setup }{ \l_keys_key_str } { #1 }
+ }
+ }
+% \end{macrocode}
+%
+% \section{Compability commands}
+% \subsection{Metadata}
+% A number of values should be accessible from other packages. Until now
+% packages like \pkg{hyperxmp} used variables like \cs{@pdfauthor}. As they are
+% gone we need to provide some other access.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_store_metadata:nn #1 #2 %#1 key, #2 value.
+ {
+ %\tl_set:cn {@#1}{#2}
+ \AddToDocumentProperties[hyperref]{#1}{#2}
+ }
+\cs_generate_variant:Nn \@@_store_metadata:nn {xn,nx,xx}
+% \end{macrocode}
+% \subsection{citecolor}
+% cite is a link context. So we define a hook, and the keys in terms of this hook.
+%
+% \begin{macrocode}
+\hook_new:n{hyp/link/cite}
+\color_set:nnn {hyp/color/cite}{HTML}{2E7E2A}
+\color_set:nn {hyp/color/citeborder}{hyp/color/cite!60!white}
+\keys_define:nn { hyp / setup }
+ {
+ ,citecolor .code:n = {\@@_color_set:nn {hyp/color/cite}{#1}}
+ ,citebordercolor
+ .code:n = {\@@_color_set:nn {hyp/color/citeborder}{#1}}
+ }
+\hook_gput_code:nnn { hyp/link/cite }{hyp/cite}
+ {
+ \keys_set:nn { hyp / setup }
+ {
+ ,linkbordercolor= hyp/color/citeborder
+ ,linkcolor = hyp/color/cite
+ }
+ }
+% \end{macrocode}
+% \section{Checks}
+% The driver can not work properly if the pdfmanagement is not active,
+% as keys need to write to the catalog and to info. But annotations
+% and outlines should work.
+% So should this be a fatal error?
+% Should there be a difference between missing and inactive management?
+% TODO
+% \begin{macrocode}
+\bool_lazy_and:nnF
+ { \cs_if_exist_p:N \pdfmanagement_if_active_p: }{ \pdfmanagement_if_active_p: }
+ { \msg_error:nn { hyp}{ missing-resource-management } }
+% \end{macrocode}
+% Outlines/bookmarks require the bookmark package.
+% TODO check pdfpagemode if booksmarks are suppressed.
+% \begin{macrocode}
+\legacy_if:nT { Hy@bookmarks }
+ {
+ \AddToHook{begindocument/before}[hyperref/bookmark]{\RequirePackage{bookmark}}
+ }
+\legacy_if:nT {Hy@draft}
+ {
+ \PassOptionsToPackage{draft}{bookmark}
+ }
+% \end{macrocode}
+%
+% \section{Reference and label commands}
+% The code uses the l3ref-tmp package which
+% must have been loaded as pdfmanagement is a requirement.
+% The commands use after the module prefix always |_ref|.
+%
+% At first a label command which add the space commands from LaTeX:
+% \begin{macro}
+% {
+% \@@_ref_label:nn,
+% \@@_ref_if_exist:nn,
+% \@@_ref_check:nn,
+% \@@_ref_value:nn
+% }
+% \begin{macrocode}
+%
+\cs_new_protected:Npn \@@_ref_label:nn #1 #2 %label/attributes
+ {
+ \@bsphack
+ \ref_label:nn{#1}{#2}
+ \@esphack
+ }
+\cs_generate_variant:Nn \@@_ref_label:nn {en}
+% \end{macrocode}
+% This provides a condition which tests if a label/attribute combination is known
+% \begin{macrocode}
+\prg_new_eq_conditional:NNn \@@_ref_if_exist:nn \ref_if_exist:nn { p , T , F, TF }
+\prg_generate_conditional_variant:Nnn \@@_ref_if_exist:nn {en} { p , T , F, TF }
+% \end{macrocode}
+% This checks if the label/attribute is known and issues a warning if not.
+% It then also triggers the standard rerun message.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_ref_check:nn #1 #2 %label/attribute
+ {
+ \@@_ref_if_exist:nnF {#1}{#2}
+ {
+ \protect\G@refundefinedtrue
+ \@latex@warning
+ {
+ Reference~`\tl_to_str:n {#1}'~with~attribute~`\tl_to_str:n {#2}'~
+ on~page~\thepage~\space undefined
+ }
+ }
+ }
+\cs_generate_variant:Nn \@@_ref_check:nn {en}
+% \end{macrocode}
+% This retrieves a value, it is a simple wrapper around the \cs{ref_value:nn}
+% \begin{macrocode}
+\cs_new:Npn \@@_ref_value:nn #1 #2
+ {
+ \ref_value:nn{#1}{#2}
+ }
+\cs_generate_variant:Nn \@@_ref_value:nn {en}
+% \end{macrocode}
+% \end{macro}
+% \section{Variables}
+% \subsection{Private temporary variables}
+% At first a few generic tmp variables
+% \begin{variable}
+% {
+% \l_@@_tmpa_tl,
+% \l_@@_tmpa_seq,
+% \l_@@_tmpa_int,
+% \l_@@_tmpa_box,
+% \l_@@_tmpa_str,
+% }
+% \begin{macrocode}
+\box_new:N \l_@@_tmpa_box
+\tl_new:N \l_@@_tmpa_tl
+\seq_new:N \l_@@_tmpa_seq
+\int_new:N \l_@@_tmpa_int
+\str_new:N \l_@@_tmpa_str
+% \end{macrocode}
+% \end{variable}
+%
+% A number of more specific tmp variables. These will perhaps disappear or change.
+% \begin{variable}
+% {
+% \l_@@_dest_name_tmpa_tl,
+% \l_@@_uri_tmpa_tl,
+% \l_@@_filename_tmpa_tl,
+% \l_@@_para_tmpa_tl
+% \l_@@_text_tmpa_str
+% \g_@@_text_tmpa_str
+% }
+% TODO: document and check use!
+% \begin{macrocode}
+\tl_new:N \l_@@_dest_name_tmpa_tl
+\tl_new:N \l_@@_uri_tmpa_tl
+\tl_new:N \l_@@_filename_tmpa_tl
+\tl_new:N \l_@@_para_tmpa_tl
+\str_new:N \l_@@_text_tmpa_str
+\str_new:N \g_@@_text_tmpa_str
+% \end{macrocode}
+% \end{variable}
+%
+% \subsection{Constants}
+% \begin{variable}
+% { \c_@@_dest_undefined_tl }
+% This variable is used if a destination name is empty.
+% \begin{macrocode}
+\tl_const:Nn \c_@@_dest_undefined_tl {UNDEFINED}
+% \end{macrocode}
+% \end{variable}
+% \begin{variable}
+% {
+% \c_@@_annot_types_seq,
+% \c_@@_map_annot_hyp_prop,
+% \c_@@_map_hyp_annot_prop,
+% }
+% This constants holds the link types managed by hyperref
+% along with a mapping from annot names to hyperref names and back.
+% \begin{macrocode}
+\seq_const_from_clist:Nn \c_@@_annot_types_seq
+ {url,link,file,menu,run}
+\prop_const_from_keyval:Nn \c_@@_map_annot_hyp_prop
+ {
+ URI = url,
+ GoTo = link,
+ GoToR = file,
+ Named = menu,
+ Launch= run
+ }
+\prop_const_from_keyval:Nn \c_@@_map_hyp_annot_prop
+ {
+ url = URI,
+ link = GoTo,
+ file = GoToR,
+ menu = Named,
+ run = Launch
+ }
+
+% \end{macrocode}
+% \end{variable}
+% \subsection{Variables}
+% \begin{variable}
+% {
+% \g_@@_dest_pdfstartpage_tl ,
+% \g_@@_dest_pdfstartview_tl ,
+% \l_@@_dest_pdfremotestartview_tl ,
+% }
+% The first holds the (absolute) start page number,
+% the other the startview instruction for the current and remote files.
+% The instruction is in \enquote{PDF format} but without the leading slash!
+% \begin{macrocode}
+\tl_new:N \g_@@_dest_pdfstartpage_tl
+\tl_new:N \g_@@_dest_pdfstartview_tl
+\tl_new:N \l_@@_dest_pdfremotestartview_tl
+% \end{macrocode}
+% \end{variable}
+%
+% It is still unclear which str convert option is the best in the various
+% places, so we use a variable to allow tests and perhaps external configuration.
+% The \enquote{print} type should always have the delimiters.
+% \begin{variable}
+% {
+% \l_@@_text_enc_uri_print_tl,
+% \l_@@_text_enc_info_print_tl,
+% \l_@@_text_enc_dest_tl,
+% \l_@@_text_enc_dest_print_tl,
+% \l_@@_text_enc_file_print_tl,
+% \l_@@_text_enc_para_print_tl
+% }
+% \begin{macrocode}
+\tl_new:N \l_@@_text_enc_uri_print_tl
+\tl_new:N \l_@@_text_enc_info_print_tl
+\tl_new:N \l_@@_text_enc_dest_tl
+\tl_new:N \l_@@_text_enc_dest_print_tl
+\tl_new:N \l_@@_text_enc_file_print_tl
+\tl_new:N \l_@@_text_enc_para_print_tl
+
+\tl_set:Nn \l_@@_text_enc_uri_print_tl {utf8/URI}
+\tl_set:Nn \l_@@_text_enc_info_print_tl {utf16/hex}
+\tl_set:Nn \l_@@_text_enc_dest_tl {utf8/string-raw}
+\tl_set:Nn \l_@@_text_enc_dest_print_tl {utf8/string}
+\tl_set:Nn \l_@@_text_enc_file_print_tl {utf8/string}
+\tl_set:Nn \l_@@_text_enc_para_print_tl {utf8/string}
+% \end{macrocode}
+% \end{variable}
+% \begin{variable}{\l_@@_dest_pdfview_tl}
+% This hold the destination instructions in a format suitable for
+% \cs{pdf_destination:nn}. The special value |fitrbox| indicates a boxed destination.
+% \begin{macrocode}
+\tl_new:N \l_@@_dest_pdfview_tl
+% \end{macrocode}
+% \end{variable}
+% \begin{hypcolor}
+% {
+% hyp/annot/link,
+% hyp/annot/url,
+% hyp/annot/file,
+% hyp/annot/run,
+% hyp/annot/menu,
+% }
+% These color names are used for the annotations (colorlinks). They are initialized
+% at the end when the color scheme is used
+% \end{hypcolor}
+% \begin{variable}{\g_@@_bordercolormodel_str}
+% This holds the export model for border color etc.
+% It is currently either |space-sep-cmyk| or |space-sep-rgb|.
+% The default is the second. It can be change by the key |bordercolormodel|
+% \begin{macrocode}
+\str_new:N \g_@@_bordercolormodel_str
+% \end{macrocode}
+% \end{variable}
+% \subsection{Booleans}
+% \begin{variable}
+% {
+% \l_hyp_annot_colorlink_bool,
+% \l_hyp_annot_colorurl_bool,
+% \l_hyp_annot_colorfile_bool,
+% \l_hyp_annot_colorrun_bool,
+% \l_hyp_annot_colormenu_bool,
+% }
+% These booleans are needed to control the colors.
+% They are public so that other packages can query the state too.
+% \begin{macrocode}
+\seq_map_inline:Nn \c_@@_annot_types_seq
+ {
+ \bool_new:c {l_hyp_annot_color#1_bool}
+ }
+% \end{macrocode}
+% \end{variable}
+% \begin{variable}
+% {
+% \l_hyp_annot_ocgcolorlink_bool,
+% \l_hyp_annot_ocgcolorurl_bool,
+% \l_hyp_annot_ocgcolorfile_bool,
+% \l_hyp_annot_ocgcolorrun_bool,
+% \l_hyp_annot_ocgcolormenu_bool,
+% }
+% These booleans are needed to control the ocgcolors.
+% They are public so that other packages can query the state too.
+% \begin{macrocode}
+\seq_map_inline:Nn \c_@@_annot_types_seq
+ {
+ \bool_new:c {l_hyp_annot_ocgcolor#1_bool}
+ }
+% \end{macrocode}
+% \end{variable}
+% \begin{variable}
+% {
+% \l_@@_annot_GoTo_bool
+% \l_@@_annot_URI_bool
+% \l_@@_annot_GoToR_bool
+% \l_@@_annot_Named_bool
+% \l_@@_annot_Launch_bool
+% }
+% This booleans are used to disable some link types
+% while keeping others.
+% \begin{macrocode}
+\seq_map_inline:Nn \c_pdfannot_link_types_seq
+ {
+ \bool_new:c {l_@@_annot_#1_bool}
+ \bool_set_true:c {l_@@_annot_#1_bool}
+ }
+% \end{macrocode}
+% \end{variable}
+%
+% \subsection{Boxes}
+% \begin{variable}{\l_@@_dest_box}
+% This holds an (empty) box which is used to get the width for FitR destinations.
+% \begin{macrocode}
+\box_new:N \l_@@_dest_box
+% \end{macrocode}
+% \end{variable}
+
+% \subsection{Regex}
+% \begin{variable}{\c_@@_dest_startview_regex}
+% This regex is used to extract the right arguments
+% pdfstartview and pdfremotestartview. Their values is filled up with |null|
+% and then the start extracted.
+% \begin{macrocode}
+\regex_const:Nn \c_@@_dest_startview_regex
+ {
+ \A\ *
+ (?:
+ (?:XYZ (?:\ +(?:(?:\d+|\d*\.\d+)|null)){3}\ )
+ |
+ (?:Fit\b|FitB\b)
+ |
+ (?:(?:FitH|FitV|FitBH|FitBV)(?:\ +(?:\d+|\d*\.\d+)|\ +null){1})
+ |
+ (?:FitR (?:\ +\d+|\ +\d*\.\d+){4}\ )
+ )
+ }
+% \end{macrocode}
+% \end{variable}
+%
+% \subsection{PDF dictionaries}
+% \begin{variable}{l_@@_page/Trans}
+% This dictionary is used for page transitions.
+% \begin{macrocode}
+\pdfdict_new:n {l_@@_page/Trans}
+\pdfdict_put:nnn {l_@@_page/Trans}{Type}{/Trans}
+% \end{macrocode}
+% \end{variable}
+
+% \section{PDF string conversion}
+%
+% This defines a command which is used to replace
+% \cs{pdfstringdef}. This is probably temporary and will be adjusted or
+% replaced if some more generic PDF string command/module exists.
+% All commands here use the \enquote{submodule} name \texttt{text}.
+% At first a hook for user additions:
+% \begin{macro}{hyp/text/pdfstring}
+% \begin{macrocode}
+\hook_new:n {hyp/text/pdfstring}
+% \end{macrocode}
+% \end{macro}
+% The first step to convert input in a PDF string is to purify it, that means
+% to remove/expand commands. As the whole process is not expandable anyway we
+% can use a protected command. The \enquote{output} is a string:
+% \begin{macro}{\@@_text_purify:nN}
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_text_purify:nN #1 #2 %#1 input, #2 str command
+ {
+ \str_set:Nx #2 {\text_purify:n { #1 } }
+ }
+% \end{macrocode}
+% \end{macro}
+% The second step is to cleanup the output of the first step. This is a dummy
+% currently. The argument should be a string variable.
+% \begin{macro}{\@@_text_cleanup:N}
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_text_cleanup:N #1
+ {
+
+ }
+% \end{macrocode}
+% \end{macro}
+% The last step converts the string to a PDF encoding. As we have at least two
+% targets (hex and literal) there is an argument. The conversion assumes
+% utf8 input, it is based on cs{pdf_string_from_unicode:nnN} in l3pdftools.
+%
+% \#2 is str variable,
+% \#1 should be one of
+%
+% \begin{tabular}{ll}
+% utf8/string & \texttt{(lit)} (utf8/string)\\
+% utf8/string-raw & \texttt{lit} (utf8/string)\\
+% utf8/URI & \texttt{(percent encoded url)}\\
+% utf8/URI-raw & \texttt{percent encoded url}\\
+% utf16/hex & \texttt{<HEX>} (utf16/hex)\\
+% utf16/hex-raw & \texttt{HEX} (utf16/hex)\\
+% utf16/string & \texttt{(lit)} (utf16/string)\\
+% utf16/string-raw & \texttt{lit} (utf16/string)
+% \end{tabular}
+% \begin{macro}{ \@@_text_string_from_unicode:nN }
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_text_string_from_unicode:nN #1 #2
+ {
+ \pdf_string_from_unicode:nVN { #1 } #2 #2
+ }
+% \end{macrocode}
+% \end{macro}
+% This command combines everything.
+% |#1|=input, |#2|= handler shortcut |#3|= output str variable
+% The commands uses a group to locally set \cs{Hy@pdfstringtrue}
+% so that \cs{texorpdfstring} works and other local settings can be done.
+%
+% \begin{macro}{ \@@_text_pdfstring:nnN }
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_text_pdfstring:nnN #1 #2 #3
+ {
+ \group_begin:
+ \Hy@pdfstringtrue
+ \hook_use:n {hyp/text/pdfstring}
+ \@@_text_purify:nN { #1 } \l_@@_text_tmpa_str
+ \@@_text_cleanup:N \l_@@_text_tmpa_str
+ \@@_text_string_from_unicode:nN { #2 } \l_@@_text_tmpa_str
+ \str_gset_eq:NN \g_@@_text_tmpa_str\l_@@_text_tmpa_str
+ \group_end:
+ \str_set_eq:NN #3 \g_@@_text_tmpa_str
+ }
+\cs_generate_variant:Nn \@@_text_pdfstring:nnN {xnN,onN,xoN,ooN,noN}
+% \end{macrocode}
+% \end{macro}
+% !!! temporary until all instances are gone
+%^^A TODO check if the redefinition of |~| is needed (probably not)
+%^^A \edef~{\string~}%
+%^^A \char_set_catcode_other:N \~
+%^^A \char_set_active_eq:NN \~ \c_tilde_str
+%^^A \char_set_catcode_active:N \~
+% \begin{macrocode}
+\cs_new_protected:Npn\Hy@pstringdef #1 #2
+ { \@@_text_pdfstring:xnN {#2} {utf8/string-raw}#1 }
+% \end{macrocode}
+%
+% This is a special version for info keys:
+% \begin{macro}{ \@@_text_pdfstring_info:nN }
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_text_pdfstring_info:nN #1 #2
+ {
+ \@@_text_pdfstring:noN { #1 }{ \l_@@_text_enc_info_print_tl } #2
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \section{Pagelabels}
+% Page labels are representations of the page numbers in the PDF viewer. If the hyperref
+% options |pdfpagelabels| is true (the default) roman numbers are e.g. shown as
+% \enquote{ii (2/58)}. To do this the page ranges must be collected, if possible a prefix
+% and the numbering of the counter must be identified and then written
+% to the catalog.
+%
+% The current implementation in hyperref/hyperref drivers:
+% \begin{description}
+% \item[xetex:] hxetex.def, line 80-110\\
+% |\HyPL@StorePageLabel| writes to the aux-file
+% at begin document (after reading the aux)
+% |\HyPL@SetPageLabels| is called (defined in hyperref.sty after the driver
+% loading)
+% which calls |\Hy@PutCatalog{/PageLabels<</Nums[\HyPL@Labels]>>}|
+% \item[dvips:] identical to xetex, line 60 to 90 in pdfmark.def
+% \item[dvipdfm:] identical to xetex
+% \item[pdftex:] |\HyPL@StorePageLabel| stores in |\HyPL@Labels| in the first compilation
+% In |\AtVeryEndDocument| |\HyPL@SetPageLabels| is called.
+% \item[luatex] identical to pdftex
+% \end{description}
+%
+% The code in \pkg{hyperref} inspects |\thepage| and tries to figure out
+% the numbering system and the prefix. E.g. A-\arabic{page} is correctly split.
+% If the counter can not be identified \pkg{hyperref} generates only /P entries with the
+% whole content.
+%
+% The new implementation makes use of the pdf management: The relevant entry in the
+% catalog is continuously updated and pushed out at the end of the document.
+% This works (hopefully \ldots) with all drivers.
+%
+% We do not try to avoid the (in hyperref's wording)
+% \enquote{useless} pagelabel entry
+% |/PageLabels <</Nums[0<</S/D>>]>>|
+% (but it would be possible), we also don't test for empty |\thepage|,
+% \pkg{hyperref} seems to handle this fine and the pdf is valid.
+%
+% The code has to define |\Hy@PutCatalog| as we can't yet
+% change code in hyperref. The switch for draftmode has been removed.
+%
+% \begin{macro}
+% {
+% \@@_PageLabels_gpush:,
+% \Hy@PutCatalog,
+% \HyPL@StorePageLabel
+% }
+% \begin{macrocode}
+\cs_new_protected:Npn\@@_PageLabels_gpush:
+ {
+ \pdfmanagement_add:nnx {Catalog} {PageLabels}{<</Nums[\HyPL@Labels]>>}
+ }
+
+\def\Hy@PutCatalog #1 {}
+
+
+\legacy_if:nT { Hy@pdfpagelabels }
+ {
+ \cs_set_protected:Npn \HyPL@StorePageLabel #1
+ {
+ \tl_gput_right:Nx \HyPL@Labels { \the\Hy@abspage<<#1>> }
+ \@@_PageLabels_gpush:
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \section {Core Hyperref Commands}
+% Every hyperref has to define eight core command:
+% \begin{verbatim}
+% \hyper@anchor
+% \hyper@anchorstart
+% \hyper@anchorend
+% \hyper@link %GoTo
+% \hyper@linkstart %GoTo
+% \hyper@linkend %GoTo
+% \hyper@linkfile %GoToR
+% \hyper@linkurl %URI
+% \end{verbatim}
+%
+% This driver defines for consistency also
+% |\hyper@linklaunch| for Launch and |\hyper@linknamed| for Named.
+%
+% \subsection{ Anchors / destinations}
+% The first three commands are needed for \enquote{anchors}. At first
+% the internal commands to create a destination. It uses
+% |\Hy@WrapperDef| to make it babel safe, it is not clear if this is
+% still needed, but we leave if for now.
+% \begin{function} { \@@_destination:nn }
+% \begin{syntax}
+% \cs{@@_destination:nn} \Arg{destination name} \Arg{location}
+% \end{syntax}
+% The \meta{destination name} is encoded with the method stored in
+% in \cs{l_@@_text_enc_dest_tl}. The location should be one of
+% |fit|, |fith|, |fitv|, |fitbv|, |fitbh|, |fitr|, |xyz|, |fitrbx|.
+% The last will make use of \cs{l_@@_dest_box}
+% \end{function}
+% \begin{macro}{ \@@_destination:nn }
+% \begin{macrocode}
+\Hy@WrapperDef \@@_destination:nn #1 #2
+ {
+ \mode_if_horizontal:T { \@savsf\spacefactor }
+ \Hy@SaveLastskip %defined in hyperref
+ \Hy@VerboseAnchor{#1} %defined in hyperref, for debugging
+ \@@_text_pdfstring:xoN
+ { \HyperDestNameFilter{#1} }
+ { \l_@@_text_enc_dest_tl }
+ \l_@@_tmpa_tl
+ \str_if_eq:nnTF {#2} {fitrbox}
+ {
+ \exp_args:NV
+ \pdf_destination:nnnn \l_@@_tmpa_tl
+ { \box_wd:N \l_@@_dest_box }
+ { \box_ht:N \l_@@_dest_box }
+ { \box_dp:N \l_@@_dest_box }
+ }
+ {
+ \exp_args:NV
+ \pdf_destination:nf
+ { \l_@@_tmpa_tl }
+ { #2 }
+ }
+ \Hy@RestoreLastskip %defined in hyperref
+ \mode_if_horizontal:T { \spacefactor\@savsf }
+ }
+% \end{macrocode}
+% \end{macro}
+% This are the three destinations commands. They are modelled along the
+% xetex version. It is not quite clear if really all three
+% are needed for the backends supported by this driver, but changing the hyperref
+% code would be difficult.
+% \begin{macro}
+% {
+% \hyper@anchor,
+% \hyper@anchorstart,
+% \hyper@anchorend
+% }
+% \begin{macrocode}
+\cs_new_protected:Npn \hyper@anchor #1
+ {
+ \exp_args:NnV
+ \@@_destination:nn {#1} \l_@@_dest_pdfview_tl
+ }
+
+\cs_new_protected:Npn \hyper@anchorstart #1
+ {
+ \Hy@activeanchortrue
+ \exp_args:NnV
+ \@@_destination:nn {#1} \l_@@_dest_pdfview_tl
+ }
+
+\cs_new_protected:Npn \hyper@anchorend
+ {
+ \Hy@activeanchorfalse
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{GoTo Links}
+% The next three commands are for links inside the document,
+% to destinations (GoTo links).
+% The definition in \pkg{hyperref} have a first argument which
+% can be used to pass a semantical context. Currently this argument is
+% only used for \cs{cite} and only to change the color. The new
+% implementation uses it for a real hook.
+%
+% At first the internal link commands:
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_link_goto_begin:nw #1
+ {
+ \mode_leave_vertical:
+ \protected@edef \l_@@_dest_name_tmpa_tl { #1 }
+ \tl_if_empty:NTF \l_@@_dest_name_tmpa_tl
+ {
+ \msg_warning:nnx
+ { hyp }
+ { empty-destination-name }
+ { \c_@@_dest_undefined_tl }
+ \tl_set_eq:NN \l_@@_dest_name_tmpa_tl \c_@@_dest_undefined_tl
+ }
+ {
+ \@@_text_pdfstring:xoN
+ { \exp_args:No \HyperDestNameFilter { \l_@@_dest_name_tmpa_tl } }
+ { \l_@@_text_enc_dest_tl }
+ \l_@@_dest_name_tmpa_tl
+ }
+ \exp_args:No
+ \pdfannot_link_goto_begin:nw { \l_@@_dest_name_tmpa_tl }
+ }
+
+\cs_new_protected:Npn \@@_link_goto_end:
+ {
+ \pdfannot_link_goto_end:
+ }
+% \end{macrocode}
+%
+% Now the three hyperref commands.
+% The splitted commands \cs{hyper@linkstart} and \cs{hyper@linkend} are used for
+% footnotemarks, toc and natbib-cites.
+% \begin{function}{\hyper@link}
+% \begin{syntax}
+% \cs{hyper@link}\Arg{context}\Arg{destination name}\Arg{link text}
+% \end{syntax}
+% This creates a complete GoTo link around the \meta{link text}
+% pointing to \meta{destination name}.
+% The hook |hyp/link/|\meta{context} is executed at the begin if it exists.
+%
+% The only \meta{context} for which a hook is predefined is |cite|.
+% Packages which want to use another \meta{context} should initialize the hook like
+% this:
+% \begin{verbatim}
+% \IfHookExistsTF{hyp/link/context}{}
+% {\NewHook{hyp/link/context}}
+% \end{verbatim}
+%
+% The hook code is executed in a group but before all the pdfannot hooks.
+% \end{function}
+% \begin{function}{\hyper@linkstart,\hyper@linkend}
+% \begin{syntax}
+% \cs{hyper@linkstart}\Arg{context}\Arg{destination name}\\
+% \cs{hyper@linkend}
+% \end{syntax}
+% This creates the start and end commands for a GoTo link around the text
+% between both pointing to \meta{destination name}.
+% The hook |hyp/link/|\meta{context} is executed at the begin if it exists
+% as with \cs{hyper@link}
+%
+% The commands open and close a group, so should be placed carefully. .
+% \end{function}
+
+% \pkg{hyperref} adds a group with \cs{Hy@colorlink}, we move this outside the link
+% so that it groups the context hook too.
+% \begin{macrocode}
+
+\cs_new_protected:Npn \hyper@link #1 #2 #3 %#1 context, #2=destination name, #3 content
+ {
+ \bool_if:NTF \l_@@_annot_GoTo_bool
+ {
+ \Hy@VerboseLinkStart{#1}{#2}
+ \group_begin:
+ \hook_use:n {hyp/link/#1}
+ \@@_link_goto_begin:nw {#2}#3\Hy@xspace@end
+ \__hyp_link_goto_end:
+ \group_end:
+ \Hy@VerboseLinkStop
+ }{#3}
+ }
+
+\cs_new_protected:Npn \hyper@linkstart #1 #2 %#1 context, #2=destination name
+ {
+ \bool_if:NT \l_@@_annot_GoTo_bool
+ {
+ \Hy@VerboseLinkStart{#1}{#2}% only for debug
+ \group_begin:
+ \hook_use:n {hyp/link/#1}
+ \@@_link_goto_begin:nw {#2}
+ }
+ }
+
+\cs_new_protected:Npn \hyper@linkend
+ {
+ \bool_if:NT \l_@@_annot_GoTo_bool
+ {
+ \@@_link_goto_end:
+ \group_end:
+ \Hy@VerboseLinkStop
+ }
+ }
+% \end{macrocode}
+%
+% \subsection{URI links}
+% We define a dictionary for the action dictionary. For now it is public.
+% \begin{macrocode}
+\pdfdict_new:n {l_hyp/annot/A/URI}
+\pdfdict_put:nnn {l_hyp/annot/A/URI}{Type}{/Action}
+\pdfdict_put:nnn {l_hyp/annot/A/URI}{S}{/URI}
+
+\cs_new_protected:Npn \hyper@linkurl #1 #2 %#1:link text #2: URI,
+ {
+ \bool_if:NTF \l_@@_annot_URI_bool
+ {
+ \group_begin:
+ \@@_text_pdfstring:xoN
+ { #2}
+ { \l_@@_text_enc_uri_print_tl }
+ \l_@@_uri_tmpa_tl
+ \pdfdict_put:nno{l_hyp/annot/A/URI}{URI}{\l_@@_uri_tmpa_tl}
+ \ifHy@href@ismap
+ \pdfdict_put:nnn{l_hyp/annot/A/URI}{IsMap}{true}
+ \fi
+ \tl_if_empty:NF \Hy@href@nextactionraw
+ {
+ \str_remove_once:Nn \Hy@href@nextactionraw {/Next}
+ \pdfdict_put:nno{l_hyp/annot/A/Next}{\Hy@href@nextactionraw}
+ }
+ \cs_set_eq:NN \# \c_hash_str
+ \cs_set_eq:NN \% \c_percent_str
+ \Hy@safe@activestrue
+ \mode_leave_vertical:
+ \pdfannot_link:nxn { URI }
+ {
+ /A
+ <<
+ \pdfdict_use:n {l_hyp/annot/A/URI}
+ >>
+ }
+ {
+ #1
+ \Hy@xspace@end
+ \Hy@VerboseLinkStop %where is the start??
+ }
+ \group_end:
+ }
+ {#1}
+ }
+
+% \end{macrocode}
+% \subsection{GoToR Links {files}}
+% \begin{macrocode}
+\pdfdict_new:n {l_hyp/annot/A/GoToR}
+\pdfdict_put:nnn {l_hyp/annot/A/GoToR}{Type}{/Action}
+\pdfdict_put:nnn {l_hyp/annot/A/GoToR}{S}{/GoToR}
+
+\cs_new_protected:Npn \hyper@linkfile #1 #2 #3 % link text, filename, destname
+ {
+ \bool_if:NTF \l_@@_annot_GoToR_bool
+ {
+ \group_begin:
+ \tl_set:Nn \l_@@_filename_tmpa_tl { #2 }
+ \Hy@CleanupFile \l_@@_filename_tmpa_tl
+ \@@_text_pdfstring:ooN
+ { \l_@@_filename_tmpa_tl }
+ { \l_@@_text_enc_file_print_tl }
+ \l_@@_filename_tmpa_tl
+ \pdfdict_put:nno {l_hyp/annot/A/GoToR}{F}{\l_@@_filename_tmpa_tl}
+ \@@_text_pdfstring:nnN
+ { #3 }
+ { \l_@@_text_enc_dest_print_tl }
+ \l_@@_dest_name_tmpa_tl
+ \Hy@MakeRemoteAction
+ \tl_if_blank:eTF {#3}
+ {
+ \pdfdict_put:nnx {l_hyp/annot/A/GoToR}{D}
+ {[\Hy@href@page/\l_@@_dest_pdfremotestartview_tl]}
+ }
+ {
+ \pdfdict_put:nno {l_hyp/annot/A/GoToR}{D}{\l_@@_dest_name_tmpa_tl}
+ }
+ \tl_if_empty:NF \Hy@href@nextactionraw
+ {
+ \str_remove_once:Nn \Hy@href@nextactionraw {/Next}
+ \pdfdict_put:nno{l_hyp/annot/A/Next}{Next}{\Hy@href@nextactionraw}
+ }
+ \mode_leave_vertical:
+ \pdfannot_link:nxn %expansion??
+ { GoToR }
+ {
+ /A<<
+ \pdfdict_use:n {l_hyp/annot/A/GoToR}
+ >>
+ }
+ {
+ #1\Hy@xspace@end
+ \Hy@VerboseLinkStop %where is the start??
+ }
+ \group_end:
+ }
+ {#1}
+ }
+% \end{macrocode}
+%
+% \subsection{Launch links}
+%
+% We define \cs{hyper@linklaunch} for naming consistency
+% \begin{macrocode}
+\pdfdict_new:n {l_hyp/annot/A/Launch}
+\pdfdict_put:nnn {l_hyp/annot/A/Launch}{Type}{/Action}
+\pdfdict_put:nnn {l_hyp/annot/A/Launch}{S}{/Launch}
+
+\cs_new_protected:Npn \hyper@linklaunch #1 #2 #3 % filename, link text, Parameters
+ {
+ \bool_if:NTF \l_@@_annot_Launch_bool
+ {
+ \group_begin:
+ \@@_text_pdfstring:nnN
+ { #1 }
+ { \l_@@_text_enc_file_print_tl }
+ \l_@@_filename_tmpa_tl
+ \pdfdict_put:nno {l_hyp/annot/A/Launch}{F}{\l_@@_filename_tmpa_tl}
+ \@@_text_pdfstring:noN
+ { #3 }
+ { \l_@@_text_enc_para_print_tl }
+ \l_@@_para_tmpa_tl
+ \bool_if:nTF
+ {
+ \str_if_eq_p:Vn \l_@@_para_tmpa_tl {()}
+ ||
+ \pdf_version_compare_p:Nn > {1.9}
+ }
+ {
+ \pdfdict_remove:nn {l_hyp/annot/A/Launch}{Win}
+ }
+ {
+ \pdfdict_put:nnx {l_hyp/annot/A/Launch}{Win}
+ {<</P \l_@@_para_tmpa_tl /F \l_@@_filename_tmpa_tl >>}
+ }
+ \tl_if_empty:NF \Hy@href@nextactionraw
+ {
+ \str_remove_once:Nn \Hy@href@nextactionraw {/Next}
+ \pdfdict_put:nno{l_hyp/annot/A/Next}{Next}{\Hy@href@nextactionraw}
+ }
+ \mode_leave_vertical:
+ \pdfannot_link:nxn
+ { Launch }
+ {
+ /A
+ <<
+ \pdfdict_use:n {l_hyp/annot/A/Launch}
+ >>
+ }
+ {
+ #2\Hy@xspace@end
+ \Hy@VerboseLinkStop %where is the start??
+ }
+ \group_end:
+ }
+ {#2}
+ }
+% \end{macrocode}
+% The actually command used by hyperref is \cs{@hyper@launch} which uses a delimited
+% argument, because of the color the definition is a bit convoluted.
+% \begin{macrocode}
+\use:x
+ { % filename, anchor text, linkname
+ \cs_set_protected:Npn \exp_not:N \@hyper@launch run \c_colon_str ##1 \exp_not:N \\ ##2 ##3
+ }
+ {
+ \hyper@linklaunch {#1}{#2}{#3}
+ }
+% \end{macrocode}
+%
+% \subsection{Named links (menu)}
+% We also define \cs{hyper@linknamed} for consistency.
+% \begin{macrocode}
+\pdfdict_new:n {l_hyp/annot/A/Named}
+\pdfdict_put:nnn {l_hyp/annot/A/Named}{Type}{/Action}
+\pdfdict_put:nnn {l_hyp/annot/A/Named}{S}{/Named}
+
+\cs_new_protected:Npn \hyper@linknamed #1 #2 %#1 action, #2 link text
+ {
+ \bool_if:NTF \l_@@_annot_Named_bool
+ {
+ \group_begin:
+ \pdfmeta_standard_verify:nnTF {named_actions}{#1}
+ {
+ \mode_leave_vertical:
+ \pdfdict_put:nnx {l_hyp/annot/A/Named}{N}
+ {\pdf_name_from_unicode_e:n{#1}}
+ \tl_if_empty:NF \Hy@href@nextactionraw
+ {
+ \str_remove_once:Nn \Hy@href@nextactionraw {/Next}
+ \pdfdict_put:nno{l_hyp/annot/A/Next}{Next}{\Hy@href@nextactionraw}
+ }
+ \pdfannot_link:nxn { Named }
+ {
+ /A
+ <<
+ \pdfdict_use:n { l_hyp/annot/A/Named }
+ >>
+ }
+ {
+ #2
+ \Hy@xspace@end
+ \Hy@VerboseLinkStop
+ }
+ }
+ {
+ \msg_warning:nnn { hyp } { pdfa-no-named-action }{#1}
+ #2
+ }
+ \group_end:
+ }
+ {#2}
+ }
+
+% \end{macrocode}
+%
+% \section{Link decorations}
+% \subsection{Functions to export and select colors}
+% We support two input syntax: color expressions and model with values.
+% \begin{function}{\@@_color_export:nnN,\@@_colormodel_export:nnnN}
+% \begin{syntax}
+% \cs{@@_color_export:nnN} \Arg{color} \Arg{export format} \meta{tlvar}\\
+% \cs{@@_colormodel_export:nnnN} \Arg{color model}\Arg{value} \Arg{export format} \meta{tlvar}
+% \end{syntax}
+% This exports a color as space separated numbers as needed in in |/C|.
+% \Arg{color} should have either the format |[model]{value}| or be a color expression.
+% For examples: |[rgb]{1,0,.5}| or |red!50!blue|. The export format is either
+% |space-sep-cmyk| or |space-sep-rgb|.
+% \end{function}
+% \begin{macro}{\@@_color_export:nnN,\@@_colormodel_export:nnnN}
+% Color keys need to parse color expressions. Two input types are supported:
+% |color=[rgb]{1,0,.5}| and |color=red!50!blue|. The colors are exported
+% to PDF syntax (space separated numbers).
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_color_export:nnN #1 #2 #3
+ {
+ \tl_if_head_eq_charcode:nNTF {#1}[ %]
+ {
+ \@@_colormodel_export:wnnN #1 {#2} #3
+ }
+ {
+ \color_export:nnN {#1} {#2} #3
+ }
+ }
+
+\cs_new_protected:Npn \@@_colormodel_export:wnnN [#1] #2 #3 #4
+ {
+ \color_export:nnnN {#1}{#2}{#3}#4
+ }
+
+\cs_generate_variant:Nn \@@_color_export:nnN {xVN}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{function}{\@@_color_select:n}
+% \begin{syntax}
+% \cs{@@_color_select:nN} \Arg{color} \\
+% \end{syntax}
+% These commands select a (text) color.
+% \Arg{color} should have either the format |[model]{value}| or be a color expression.
+% For examples: |[rgb]{1,0,.5}| or |red!50!blue|
+% \end{function}
+% \begin{macro}{\@@_color_select:n,\@@_colormodel_select_aux:wn}
+% Color keys need to parse color expressions. Two input types are supported:
+% |color=[rgb]{1,0,.5}| and |color=red!50!blue|.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_color_select:n #1
+ {
+ \tl_if_head_eq_charcode:nNTF {#1}[ %]
+ {
+ \@@_colormodel_select_aux:wn #1
+ }
+ {
+ \color_select:n {#1}
+ }
+ }
+
+\cs_new_protected:Npn \@@_colormodel_select_aux:wn [#1] #2
+ {
+ \color_select:nn {#1}{#2}
+ }
+
+\cs_generate_variant:Nn \@@_color_select:n {e}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{function}{\@@_color_set:nn}
+% \begin{syntax}
+% \cs{@@_color_set:nN} \Arg{ name } \Arg{color} \\
+% \end{syntax}
+% These commands store the color in \Arg{name}.
+% \Arg{color} should have either the format |[model]{value}| or be a color expression.
+% For examples: |[rgb]{1,0,.5}| or |red!50!blue|
+% \end{function}
+% \begin{macro}{\@@_color_set:nn,\@@_colormodel_set_aux:nwn}
+% Color keys need to parse color expressions. Two input types are supported:
+% |color=[rgb]{1,0,.5}| and |color=red!50!blue|.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_color_set:nn #1 #2
+ {
+ \tl_if_head_eq_charcode:nNTF {#2}[ %]
+ {
+ \@@_colormodel_set_aux:nwn { #1 } #2
+ }
+ {
+ \color_set:nn {#1} {#2}
+ }
+ }
+
+\cs_new_protected:Npn \@@_colormodel_set_aux:nwn #1 [#2] #3
+ {
+ \color_set:nnn {#1}{#2}{#3}
+ }
+
+\cs_generate_variant:Nn \@@_color_set:nn {ne}
+% \end{macrocode}
+% \end{macro}
+% \subsection{Textcolor of links}
+% colors are added in the hooks. This means that they can also be removed if needed.
+% They add a group---this isn't needed with hyperref code, but could be relevant
+% with low-level annotations.
+% \begin{macrocode}
+\prop_map_inline:Nn \c_@@_map_hyp_annot_prop
+ {
+ \hook_gput_code:nnn
+ {pdfannot/link/#2/begin}
+ {hyp/color}
+ {
+ \bool_if:cT { l_hyp_annot_color#1_bool }
+ {
+ \group_begin:
+ \color_select:n { hyp/color/#1}
+ }
+ }
+ \hook_gput_code:nnn
+ {pdfannot/link/#2/end}
+ {hyp/color}
+ {
+ \bool_if:cT { l_hyp_annot_color#1_bool }
+ {
+ \group_end:
+ }
+ }
+ }
+% \end{macrocode}
+%
+% \begin{hypkey}{colorlinks}
+% This key also resets the border and borderstyle.
+% \begin{macrocode}
+\keys_define:nn { hyp / setup }
+ {
+ ,colorlinks .meta:n =
+ {
+ ,pdfborder={0~0~0}
+ ,pdfborderstyle=
+ ,colorurl =#1
+ ,colorlink =#1
+ ,colorrun =#1
+ ,colormenu =#1
+ ,colorfile =#1
+ }
+ ,colorlinks .default:n = {true}
+ }
+% \end{macrocode}
+% \end{hypkey}
+% \begin{hypkey}{colorurl,colorlink,colorrun,colormenu,colorfile}
+% \begin{hypkey}{urlcolor,linkcolor,runcolor,menucolor,filecolor}
+% \begin{hypkey}{allcolor}
+% \begin{macrocode}
+\seq_map_inline:Nn \c_@@_annot_types_seq
+ {
+ \keys_define:nn { hyp / setup }
+ {
+ ,color#1 .bool_set:c = { l_hyp_annot_color#1_bool }
+ ,#1color .code:n = { \@@_color_set:ne {hyp/color/#1}{##1} }
+ }
+ }
+
+\keys_define:nn { hyp / setup }
+ {
+ ,allcolors .meta:n =
+ {
+ ,urlcolor=#1
+ ,linkcolor=#1
+ ,runcolor=#1
+ ,filecolor=#1
+ ,menucolor=#1
+ }
+ ,allcolors .value_required:n = true
+ }
+% \end{macrocode}
+% \end{hypkey}
+% \end{hypkey}
+% \end{hypkey}
+% \subsection{Style and color of borders}
+% \subsubsection{Border color}
+% The border color is set by link type. The color can be set as rgb (default)
+% or cmyk (unusual). This can be set with the |bordercolormodel| key:
+%\begin{hypkey}{bordercolormodel}
+% \begin{macrocode}
+\keys_define:nn { hyp / setup }
+ {
+ ,bordercolormodel .choices:nn =
+ {rgb,cmyk}
+ { \str_gset:Nn \g_@@_bordercolormodel_str {space-sep-#1}}
+ ,bordercolormodel .initial:n ={rgb}
+ }
+% \end{macrocode}
+% \end{hypkey}
+% \begin{macrocode}
+\prop_map_inline:Nn \c_@@_map_hyp_annot_prop
+ {
+ \keys_define:nn { hyp / setup }
+ {
+ #1bordercolor .code:n =
+ {
+ \tl_if_empty:nTF { ##1 }
+ {
+ \pdfannot_dict_remove:nn
+ {link/#2}
+ { C }
+ }
+ {
+ \@@_color_export:xVN {##1}\g_@@_bordercolormodel_str \l_@@_tmpa_tl
+ \pdfannot_dict_put:nnx
+ {link/#2}
+ { C }
+ { [\l_@@_tmpa_tl] }
+ }
+ }
+ }
+ }
+
+\keys_define:nn { hyp / setup }
+ {
+ ,allbordercolors .meta:n =
+ {
+ ,linkbordercolor=#1
+ ,urlbordercolor =#1
+ ,filebordercolor=#1
+ ,menubordercolor=#1
+ ,runbordercolor =#1
+ }
+ ,allbordercolors .value_required:n = true
+ }
+
+% \end{macrocode}
+%
+% \subsubsection{Borderwidth and -arc}
+%
+% \begin{macrocode}
+\prop_map_inline:Nn \c_@@_map_hyp_annot_prop
+ {
+ \keys_define:nn { hyp / setup }
+ {
+ #1border .code:n =
+ {
+ \tl_if_empty:nTF { ##1 }
+ {
+ \pdfannot_dict_remove:nn
+ {link/#2}
+ { Border }
+ }
+ {
+ \pdfannot_dict_put:nnn
+ {link/#2}
+ { Border }
+ { [##1] }
+ }
+ }
+ }
+ }
+\keys_define:nn { hyp / setup }
+ {
+ ,pdfborder .code:n =
+ {
+ \tl_if_empty:nTF { #1 }
+ {
+ \prop_map_inline:Nn \c_@@_map_hyp_annot_prop
+ {
+ \pdfannot_dict_remove:nn
+ {link/##2}
+ { Border }
+ }
+ }
+ {
+ \prop_map_inline:Nn \c_@@_map_hyp_annot_prop
+ {
+ \pdfannot_dict_put:nnn
+ {link/##2}
+ { Border }
+ { [#1] }
+ }
+ }
+ }
+ ,pdfborder .initial:n = {0~0~1},
+ }
+% \end{macrocode}
+% \subsubsection{Borderstyle}
+% This keys fill the extended /BS entry (a dictionary).
+% \begin{hypkey}{pdfborderstyle,urlborderstyle,linkborderstyle,
+% runborderstyle,fileborderstyle,
+% menuborderstyle}
+% \begin{macrocode}
+\prop_map_inline:Nn \c_@@_map_hyp_annot_prop
+ {
+ \keys_define:nn { hyp / setup }
+ {
+ #1borderstyle .code:n =
+ {
+ \tl_if_empty:nTF { ##1 }
+ {
+ \pdfannot_dict_remove:nn
+ {link/#2}
+ { BS }
+ }
+ {
+ \pdfannot_dict_put:nnn
+ {link/#2}
+ { BS }
+ { <<##1>> }
+ }
+ }
+ }
+ }
+\keys_define:nn { hyp / setup }
+ {
+ ,pdfborderstyle .code:n =
+ {
+ \tl_if_empty:nTF { #1 }
+ {
+ \prop_map_inline:Nn \c_@@_map_hyp_annot_prop
+ {
+ \pdfannot_dict_remove:nn
+ {link/##2}
+ { BS }
+ }
+ }
+ {
+ \prop_map_inline:Nn \c_@@_map_hyp_annot_prop
+ {
+ \pdfannot_dict_put:nnn
+ {link/##2}
+ { BS }
+ { <<#1>> }
+ }
+ }
+ }
+ ,pdfborderstyle .initial:n = {},
+ }
+% \end{macrocode}
+% \end{hypkey}
+% \subsection{ocgcolorlinks}
+% OCG colorlinks need objects and an entry in the catalog.
+% Perhaps the objects need public names to avoid that ocgx2 has to create
+% duplicates?
+% TODO
+% \begin{macro}{\@@_ocg_init:}
+% This commands write the objects as needed if ocg links are used.
+% The initialization should happens only once.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_ocg_init:
+ {
+ \pdf_object_new:nn { l_@@_ocg_view_dict_obj } { dict }
+ \pdf_object_new:nn { l_@@_ocg_print_dict_obj } { dict }
+ \pdf_object_new:nn { l_@@_ocg_config_dict_obj } { dict }
+ \pdf_object_new:nn { l_@@_ocg_ref_array_obj } { array }
+ \pdf_object_write:nx { l_@@_ocg_ref_array_obj }
+ {
+ \pdf_object_ref:n { l_@@_ocg_view_dict_obj }
+ \c_space_tl
+ \pdf_object_ref:n { l_@@_ocg_print_dict_obj }
+ }
+ \pdf_object_write:nn { l_@@_ocg_view_dict_obj }
+ {
+ /Type/OCG
+ /Name(View)
+ /Usage
+ <<
+ /Print <</PrintState/OFF>>~
+ /View <</ViewState/ON >>~
+ >>
+ }
+ \pdf_object_write:nn { l_@@_ocg_print_dict_obj }
+ {
+ /Type/OCG
+ /Name(Print)
+ /Usage
+ <<
+ /Print <</PrintState/ON>>~
+ /View <</ViewState/OFF>>~
+ >>
+ }
+ \pdfmanagement_add:nnx { Catalog / OCProperties }{OCGs }{ \pdf_object_ref:n {l_@@_ocg_view_dict_obj} }
+ \pdfmanagement_add:nnx { Catalog / OCProperties }{OCGs }{ \pdf_object_ref:n {l_@@_ocg_print_dict_obj} }
+ \pdf_object_write:nx { l_@@_ocg_config_dict_obj }
+ {
+ /OFF[\pdf_object_ref:n { l_@@_ocg_print_dict_obj }]
+ /AS[
+ <<
+ /Event/View
+ /OCGs\c_space_tl \pdf_object_ref:n { l_@@_ocg_ref_array_obj }
+ /Category[/View]
+ >>
+ <<
+ /Event/Print
+ /OCGs\c_space_tl \pdf_object_ref:n { l_@@_ocg_ref_array_obj }
+ /Category[/Print]
+ >>
+ <<
+ /Event/Export
+ /OCGs\c_space_tl \pdf_object_ref:n { l_@@_ocg_ref_array_obj }
+ /Category[/Print]
+ >>
+ ]
+ }
+ \pdfmanagement_add:nnx { Catalog / OCProperties }{ D }{ \pdf_object_ref:n { l_@@_ocg_config_dict_obj} }
+ \cs_gset:Npn \@@_ocg_init: {}
+ }
+% \end{macrocode}
+% \end{macro}
+% We use like with colors a hook, this allows ocgx to replace it.
+% The implementation is rather simple and uses a box.
+% \begin{macrocode}
+\prop_map_inline:Nn \c_@@_map_hyp_annot_prop
+ {
+ \hook_gput_code:nnn
+ {pdfannot/link/#2/begin}
+ {hyp/ocg}
+ {
+ \bool_if:cT { l_hyp_annot_ocgcolor#1_bool }
+ {
+ \@@_ocg_init:
+ \group_begin:
+ \hbox_set:Nw \l_@@_tmpa_box
+ }
+ }
+ \hook_gput_code:nnn
+ {pdfannot/link/#2/end}
+ {hyp/ocg}
+ {
+ \bool_if:cT { l_hyp_annot_ocgcolor#1_bool }
+ {
+ \hbox_set_end:
+ \mbox
+ {
+ \pdf_bdcobject:nn {OC}{l_@@_ocg_print_dict_obj}
+ \hbox_overlap_right:n { \box_use:N \l_@@_tmpa_box }
+ \pdf_emc:
+ \pdf_bdcobject:nn {OC}{l_@@_ocg_view_dict_obj}
+ \group_begin:
+ \color_select:n { hyp/color/#1 }
+ \box_use_drop:N \l_@@_tmpa_box
+ \group_end:
+ \pdf_emc:
+ }
+ \group_end:
+ }
+ }
+ }
+% \end{macrocode}
+%
+% \begin{hypkey}
+% {
+% ocgcolorlinks,
+% ocgcolorlink,
+% ocgcolorurl,
+% ocgcolorfile,
+% ocgcolormenu,
+% ocgcolorrun
+% }
+% These are the keys for ocgcolors. We try to disable it
+% for pdf version below 1.5
+% \begin{macrocode}
+\pdf_version_compare:NnTF < {1.5}
+ {
+ \keys_define:nn { hyp / setup }
+ {
+ ,_ocgcolorlinks .code:n =
+ {
+ \msg_warning:nnxx
+ { hyp }
+ { ignore-deprecated-or-unknown-option-in-pdf-version }
+ { ocgcolorlinks } { \pdf_version_major:.\pdf_version_minor: }
+ }
+ }
+ }
+ {
+ \keys_define:nn { hyp / setup }
+ {
+ ,_ocgcolorlinks .meta:n =
+ {
+ ocgcolorlink=#1,
+ ocgcolorurl=#1,
+ ocgcolorfile=#1,
+ ocgcolorrun=#1,
+ ocgcolormenu=#1
+ }
+ ,_ocgcolorlinks .default:n = true
+ }
+ }
+
+\keys_define:nn { hyp / setup }
+ {
+ ,ocgcolorlinks .choice:
+ ,ocgcolorlinks / true .meta:n =
+ {
+ pdfborder ={0~0~0},
+ pdfborderstyle ={},
+ colorlinks = false,
+ _ocgcolorlinks = true
+ }
+ ,ocgcolorlinks / false .meta:n =
+ {
+ _ocgcolorlinks = false
+ }
+ ,ocgcolorlinks .default:n = {true}
+ }
+
+\seq_map_inline:Nn \c_@@_annot_types_seq
+ {
+ \pdf_version_compare:NnTF < {1.5}
+ {
+ \keys_define:nn { hyp / setup }
+ {
+ ,ocgcolor#1 .code:n=
+ {
+ \msg_warning:nnxx
+ { hyp }
+ { ignore-deprecated-or-unknown-option-in-pdf-version }
+ { ocgcolor#1 }
+ { \pdf_version_major:.\pdf_version_minor: }
+ }
+ }
+ }
+ {
+ \keys_define:nn { hyp / setup }
+ {
+ ,ocgcolor#1 .bool_set:c = { l_hyp_annot_ocgcolor#1_bool }
+ }
+ }
+ }
+% \end{macrocode}
+% \end{hypkey}
+% \subsection{Highlighting}
+% This keys set what happens if you click on a link
+% \begin{macrocode}
+\prop_map_inline:Nn \c_@@_map_hyp_annot_prop
+ {
+ \keys_define:nn { hyp / setup }
+ {
+ ,#1highlight .choices:nn =
+ { /I, /N, /O, /P}
+ {
+ \pdfannot_dict_put:nnn
+ {link/#2}
+ { H }
+ { ##1 }
+
+ }
+ ,#1highlight / .code:n =
+ {
+ \pdfannot_dict_remove:nn
+ {link/#2}
+ { H }
+
+ }
+ ,#1highlight / unknown .code:n =
+ {
+ \msg_warning:nnxxx { hyp } { unknown-choice+empty }
+ { pdfhighlight }
+ { /I~(inverse), /N~(no effect), /O~(outline), /P~(inset) }
+ { \exp_not:n {##1} }
+ }
+ }
+ }
+
+
+\keys_define:nn { hyp / setup }
+ {
+ ,pdfhighlight .choices:nn =
+ { /I, /N, /O, /P}
+ {
+ \prop_map_inline:Nn \c_@@_map_hyp_annot_prop
+ {
+ \pdfannot_dict_put:nnn
+ {link/####2}
+ { H }
+ { #1 }
+ }
+ }
+ ,pdfhighlight / .code:n =
+ {
+ \prop_map_inline:Nn \c_@@_map_hyp_annot_prop
+ {
+ \pdfannot_dict_remove:nn
+ {link/##2}
+ { H }
+ }
+ }
+ ,pdfhighlight .initial:n = {/I},
+ ,pdfhighlight / unknown .code:n =
+ {
+ \msg_warning:nnxxx { hyp } { unknown-choice+empty }
+ { pdfhighlight }
+ { /I~(inverse), /N~(no effect), /O~(outline), /P~(inset) }
+ { \exp_not:n {#1} }
+ }
+ }
+% \end{macrocode}
+%
+% \subsection{Hiding links}
+% This key disable all appearance keys. The link themselves are still there.
+% \begin{hypkey}{hidelinks,hidelink,hideurl,hidefile,hiderun,hidemenu}
+% \begin{macrocode}
+\keys_define:nn { hyp / setup }
+ {
+ hidelinks .meta:n =
+ {
+ ,colorlinks = false
+ ,ocgcolorlinks = false
+ ,pdfborder = { 0~0~0 }
+ ,pdfborderstyle=
+ }
+ }
+
+\seq_map_inline:Nn \c_@@_annot_types_seq
+ {
+ \keys_define:nn { hyp / setup }
+ {
+ hide#1 .meta:n =
+ {
+ ,color#1 = false
+ ,ocgcolor#1 = false
+ ,#1border = { 0~0~0 }
+ ,#1borderstyle =
+ }
+ }
+ }
+% \end{macrocode}
+% \end{hypkey}
+% \subsection{color schemes and settings}
+% This define the key for the color schemes and sets the default colors.
+% \begin{hypkey}{colorscheme}
+% \begin{macrocode}
+\keys_define:nn { hyp / setup }
+ {
+ colorscheme .code:n =
+ {
+ \prop_map_inline:cn { c_@@_colorscheme_#1_prop }
+ {
+ \keys_set:nn { hyp /setup }
+ {
+ ##1 = ##2
+ }
+ }
+ }
+ }
+\keys_set:nn { hyp / setup } {colorscheme=phelype}
+% \end{macrocode}
+% \end{hypkey}
+%
+% \section{Keys}
+%
+% \subsection{Ignored keys}
+% The following are ignored (with or without warnings)
+% \begin{hypkey}{unicode,pdfencoding,pdfversion}
+% \begin{macrocode}
+\keys_define:nn { hyp / setup }
+ {
+ ,unicode .code:n = {}
+ ,pdfencoding .code:n = {}
+ ,pdfversion .code:n =
+ {
+ \msg_warning:nn { hyp }{ pdfversion-disabled }
+ }
+ }
+%
+% \end{macrocode}
+% \end{hypkey}
+%
+% \subsection{Various keys for the pdf and linking behaviour}
+% This keys are typically set only once.
+%
+% \begin{hypkey}{verbose,debug,draft,final}
+% \begin{macrocode}
+\keys_define:nn { hyp / setup }
+ {
+ ,verbose .choice:
+ ,verbose / true .code:n = { \Hy@verbosetrue}
+ ,verbose / false .code:n = { \Hy@verbosefalse}
+ ,verbose .default:n = {true}
+ ,debug .meta:n = {verbose=#1}
+ ,debug .default:n = {true}
+ }
+\keys_define:nn { hyp / setup }
+ {
+ ,draft .code:n =
+ {
+ \Hy@drafttrue
+ \PassOptionsToPackage{draft}{bookmark}
+ }
+ ,final .code:n =
+ {
+ \Hy@finaltrue
+ \PassOptionsToPackage{final}{bookmark}
+ }
+ }
+% \end{macrocode}
+% \end{hypkey}
+% \begin{hypkey}{extension,hypertexnames,naturalnames,
+% pageanchor,linktoc,linktocpage,plainpages,localanchorname,
+% linkfileprefix}
+% \begin{macrocode}
+\keys_define:nn { hyp / setup }
+ {
+ ,extension .tl_set:N = \XR@ext
+ ,extension .initial:n= pdf
+ ,hypertexnames .choice:
+ ,hypertexnames / true .code:n = { \Hy@hypertexnamestrue}
+ ,hypertexnames / false .code:n = { \Hy@hypertexnamesfalse}
+ ,hypertexnames .default:n = {true}
+ ,linkfileprefix .tl_set:N = \Hy@linkfileprefix
+ ,localanchorname .choice:
+ ,localanchorname / true .code:n = { \Hy@localanchornametrue }
+ ,localanchorname / false .code:n = { \Hy@localanchornamefalse }
+ ,localanchorname .default:n = {true}
+ ,naturalnames .choice:
+ ,naturalnames / true .code:n = { \Hy@naturalnamestrue}
+ ,naturalnames / false .code:n = { \Hy@naturalnamesfalse}
+ ,naturalnames .default:n = {true}
+ ,pageanchor .choice:
+ ,pageanchor / true .code:n = { \Hy@pageanchortrue}
+ ,pageanchor / false .code:n = { \Hy@pageanchorfalse}
+ ,pageanchor .default:n = {true}
+ ,plainpages .choice:
+ ,plainpages / true .code:n = { \Hy@plainpagestrue}
+ ,plainpages / false .code:n = { \Hy@plainpagesfalse}
+ ,plainpages .default:n = {true}
+ }
+
+\keys_define:nn { hyp / setup }
+ {
+ ,linktoc .choices:nn = { none, section, all, page }
+ {
+ \cs_set_eq:Nc \Hy@linktoc { Hy@linktoc@#1 }
+ }
+ ,linktoc / unknown .code:n =
+ {
+ \msg_warning:nnxxx { hyp } { unknown-choice }
+ { linktoc }
+ { none, section, all, page }
+ { \exp_not:n {#1} }
+ }
+ ,linktocpage .choice:
+ ,linktocpage / true .meta:n = {linktoc=page}
+ ,linktocpage / false .meta:n = {linktoc=section}
+ ,linktocpage .default:n = true
+ }
+
+% \end{macrocode}
+% \end{hypkey}
+% \begin{hypkey}{link,url,file,menu,run}
+% This booleans allow to disable the link types.
+% \begin{macrocode}
+\prop_map_inline:Nn \c_@@_map_hyp_annot_prop
+ {
+ \keys_define:nn { hyp / setup }
+ {
+ ,#1 .bool_set:c = {l_@@_annot_#2_bool}
+ }
+ }
+% \end{macrocode}
+% \end{hypkey}
+%
+% \begin{macrocode}
+\keys_define:nn { hyp / setup }
+ {
+ ,baseurl .code:n =
+ {
+ \@@_text_pdfstring:ooN { #1 } {\l_@@_text_enc_uri_print_tl} \l_@@_tmpa_tl
+ \tl_if_empty:NTF \l_@@_tmpa_tl
+ {
+ \pdfmanagement_remove:nn {Catalog} { URI }
+ }
+ {
+ \pdfmanagement_add:nnx {Catalog} { URI }{ <</Base \l_@@_tmpa_tl>> }
+ }
+ }
+ %only false does something ...
+ ,bookmarks .choice:
+ ,bookmarks / false .code:n = {\RemoveFromHook {begindocument/before}[hyperref/bookmark]}
+ ,bookmarks / true .code:n = {}
+ ,bookmarks .default:n = {true}
+ ,bookmarksnumbered .choice:
+ ,bookmarksnumbered / false .code:n = { \Hy@bookmarksnumberedfalse }
+ ,bookmarksnumbered / true .code:n = { \Hy@bookmarksnumberedtrue }
+ ,bookmarksnumbered .default:n = {true}
+ ,bookmarksopen .choice:
+ ,bookmarksopen / false .code:n = { \Hy@bookmarksopenfalse }
+ ,bookmarksopen / true .code:n = { \Hy@bookmarksopentrue }
+ ,bookmarksopen .default:n = {true}
+ ,bookmarksopenlevel .tl_set:N = \@bookmarksopenlevel
+ ,bookmarkstype .tl_set:N = \Hy@bookmarkstype
+ ,pdfcenterwindow .choice:
+ ,pdfcenterwindow / false .code:n =
+ {
+ \pdfmanagement_remove:nn {Catalog / ViewerPreferences }{ CenterWindow }
+ }
+ ,pdfcenterwindow / true .code:n =
+ {
+ \pdfmanagement_add:nnn {Catalog / ViewerPreferences } { CenterWindow }{ true }
+ }
+ ,pdfcenterwindow / .code:n =
+ {
+ \pdfmanagement_remove:nn {Catalog / ViewerPreferences }{ CenterWindow }
+ }
+ ,pdfcenterwindow / unknown .code:n =
+ {
+ \msg_warning:nnxx { hyp } { no-bool }
+ { pdfcenterwindow }
+ { \exp_not:n {#1} }
+ }
+ ,pdfcenterwindow .default:n = true
+ ,pdfdirection .choice:
+ ,pdfdirection / L2R .code:n =
+ {
+ \pdfmanagement_add:nnn {Catalog / ViewerPreferences } { Direction }{ /L2R }
+ }
+ ,pdfdirection / R2L .code:n =
+ {
+ \pdfmanagement_add:nnn {Catalog / ViewerPreferences } { Direction }{ /R2L }
+ }
+ ,pdfdirection / .code:n =
+ {
+ \pdfmanagement_remove:nn {Catalog / ViewerPreferences } { Direction }
+ }
+ ,pdfdirection / unknown .code:n =
+ {
+ \msg_warning:nnxxx { hyp } { unknown-choice+empty }
+ { pdfdirection }
+ { L2R , R2L }
+ { \exp_not:n {#1} }
+ }
+ ,pdfdisplaydoctitle .choice:
+ ,pdfdisplaydoctitle / false .code:n =
+ {
+ \pdfmanagement_remove:nn {Catalog / ViewerPreferences } { DisplayDocTitle }
+ }
+ ,pdfdisplaydoctitle / true .code:n =
+ {
+ \pdfmanagement_add:nnn {Catalog / ViewerPreferences } { DisplayDocTitle } { true }
+ }
+ ,pdfdisplaydoctitle .default:n = true
+ ,pdfduplex .choices:nn =
+ {Simplex, DuplexFlipShortEdge, DuplexFlipLongEdge}
+ {
+ \pdf_version_compare:NnTF > {1.6}
+ {
+ \pdfmanagement_add:nnn {Catalog / ViewerPreferences }
+ { PrintDuplex } { /#1 }
+ }
+ {
+ \msg_warning:nnxx
+ {hyp}
+ {ignore-deprecated-or-unknown-option-in-pdf-version}
+ {pdfduplex}
+ {\pdf_version:}
+ }
+ }%
+ ,pdfduplex / .code:n =
+ {
+ \pdfmanagement_remove:nn {Catalog / ViewerPreferences } { PrintDuplex }
+ }
+ ,pdfduplex / unknown .code:n =
+ {
+ \msg_warning:nnxxx { hyp } { unknown-choice+empty }
+ { pdfduplex }
+ { Simplex, DuplexFlipShortEdge, DuplexFlipLongEdge }
+ { \exp_not:n {#1} }
+ }
+ ,pdffitwindow .choice:
+ ,pdffitwindow / false .code:n =
+ {
+ \pdfmanagement_remove:nn {Catalog / ViewerPreferences } { FitWindow }
+ }
+ ,pdffitwindow / true .code:n =
+ {
+ \pdfmanagement_add:nnn {Catalog / ViewerPreferences } { FitWindow } { true }
+ }
+ ,pdffitwindow / .code:n =
+ {
+ \pdfmanagement_remove:nn {Catalog / ViewerPreferences } { FitWindow }
+ }
+ ,pdffitwindow .default:n = true
+ ,pdffitwindow / unknown .code:n =
+ {
+ \msg_warning:nnxx { hyp } { no-bool }
+ { pdffitwindow }
+ { \exp_not:n {#1} }
+ }
+ ,pdflinkmargin .code:n = { \pdfannot_link_margin:n { #1 } }
+ ,pdflinkmargin .initial:n = {1pt}
+ ,pdfmenubar .choice:
+ ,pdfmenubar / true .code:n =
+ {
+ \pdfmanagement_remove:nn {Catalog / ViewerPreferences } { HideMenubar }
+ }
+ ,pdfmenubar / false .code:n =
+ {
+ \pdfmanagement_add:nn {Catalog / ViewerPreferences }
+ { HideMenubar } { true }
+ }
+ ,pdfmenubar / .code:n =
+ {
+ \pdfmanagement_remove:nn {Catalog / ViewerPreferences } { HideMenubar }
+ }
+ ,pdfmenubar .default:n = true
+ ,pdfmenubar / unknown .code:n =
+ {
+ \msg_warning:nnxx { hyp } { no-bool }
+ { pdfmenubar }
+ { \exp_not:n {#1} }
+ }
+ ,pdfnewwindow .choice:
+ ,pdfnewwindow / true .code:n =
+ {
+ \pdfdict_put:nnn {l_hyp/annot/A/GoToR}{/NewWindow}{true}
+ \pdfdict_put:nnn {l_hyp/annot/A/Launch}{/NewWindow}{true}
+ }
+ ,pdfnewwindow / false .code:n =
+ {
+ \pdfdict_put:nnn {l_hyp/annot/A/GoToR}{/NewWindow}{false}
+ \pdfdict_put:nnn {l_hyp/annot/A/Launch}{/NewWindow}{false}
+ }
+ ,pdfnewwindow / .code:n =
+ {
+ \pdfdict_remove:nn {l_hyp/annot/A/GoToR}{/NewWindow}
+ \pdfdict_remove:nn {l_hyp/annot/A/Launch}{/NewWindow}
+ }
+ ,pdfnonfullscreenpagemode .choices:nn =
+ { UseNone, UseOutlines, UseThumbs, FullScreen, UseOC } %pdf 1.5
+ {
+ \pdfmanagement_add:nnx {Catalog / ViewerPreferences }
+ { NonFullScreenPageMode} {/#1}
+ }
+ ,pdfnonfullscreenpagemode / UseAttachments .code:n =
+ {
+ \pdf_version_compare:NnTF < {1.6}
+ {
+ %message
+ }
+ {
+ \pdfmanagement_add:nnx {Catalog / ViewerPreferences }
+ {NonFullScreenPageMode}{/UseAttachments}
+ }
+ }
+ ,pdfnonfullscreenpagemode / .code:n =
+ {
+ \pdfmanagement_remove:nn {Catalog / ViewerPreferences } { NonFullScreenPageMode }
+ }
+ ,pdfnonfullscreenpagemode / unknown .code:n =
+ {
+ \msg_warning:nnxxx { hyp } { unknown-choice+empty }
+ { pdfnonfullscreenpagemode }
+ { UseNone, UseOutlines, UseThumbs, FullScreen, UseOC, UseAttachments (PDF 1.6) }
+ { \exp_not:n {#1} }
+ }
+ ,pdfnumcopies .code:n =
+ {
+ \pdf_version_compare:NnTF > {1.6}
+ {
+ \tl_if_empty:nTF {#1}
+ {
+ \pdfmanagement_remove:nn {Catalog / ViewerPreferences } { NumCopies }
+ }
+ {
+ \pdfmanagement_add:nnx {Catalog / ViewerPreferences }
+ {NumCopies}{#1}
+ }
+ }
+ {
+ \msg_warning:nnxx
+ {hyp}
+ {ignore-deprecated-or-unknown-option-in-pdf-version}
+ {pdfnumcopies}
+ {\pdf_version:}
+ }
+ }
+ ,pdfpagelayout .choices:nn =
+ { SinglePage, OneColumn, TwoColumnLeft, TwoColumnRight, TwoPageLeft, TwoPageRight}
+ { \pdfmanagement_add:nnx {Catalog} { PageLayout }{ /#1 } }
+ ,pdfpagelayout / .code:n =
+ { \pdfmanagement_remove:nn {Catalog} { PageLayout } }
+ ,pdfpagelayout / unknown .code:n =
+ {
+ \msg_warning:nnxxx { hyp } { unknown-choice+empty }
+ { pdfpagelayout }
+ { SinglePage, OneColumn, TwoColumnLeft, TwoColumnRight, TwoPageLeft, TwoPageRight }
+ { \exp_not:n {#1} }
+ }
+ ,pdfpagemode .choices:nn =
+ { UseNone, UseOutlines, UseThumbs, FullScreen, UseOC } %pdf 1.5
+ { \pdfmanagement_add:nnx {Catalog} { PageMode }{ /#1 } }
+ ,pdfpagemode / UseAttachments .code:n =
+ {
+ \pdf_version_compare:NnTF > {1.5}
+ {
+ \pdfmanagement_add:nnx {Catalog} { PageMode }{ /UseAttachments }
+ }
+ {
+ \msg_warning:nnxx
+ {hyp}
+ {ignore-deprecated-or-unknown-value-in-pdf-version}
+ {UseAttachments}
+ {\pdf_version:}
+ }
+ }
+ ,pdfpagemode .initial:n = { UseOutlines } %for now ...
+ ,pdfpagemode / unknown .code:n =
+ {
+ \msg_warning:nnxxx { hyp } { unknown-choice+empty }
+ { pdfpagemode }
+ { UseNone, UseOutlines, UseThumbs, FullScreen, UseOC, UseAttachments (PDF 1.6) }
+ { \exp_not:n {#1} }
+ }
+ ,pdfpagescrop .code:n =
+ {
+ \tl_if_empty:nTF %or blank?
+ {
+ \pdfmanagement_remove:nn {Pages} { CropBox }
+ }
+ {
+ \pdfmanagement_add:nnx {Pages} { CropBox } { [#1] }
+ }
+ }
+ ,pdfpicktraybypdfsize .choice:
+ ,pdfpicktraybypdfsize / true .code:n =
+ {
+ \pdf_version_compare:NnTF > {1.6}
+ {
+ \pdfmanagement_add:nnn {Catalog / ViewerPreferences }
+ { PickTrayByPDFSize } { true }
+ }
+ {
+ \msg_warning:nnxx
+ {hyp}
+ {ignore-deprecated-or-unknown-option-in-pdf-version}
+ {pdfpicktraybypdfsize}
+ {\pdf_version:}
+ }
+ }
+ ,pdfpicktraybypdfsize / false .code:n =
+ {
+ \pdf_version_compare:NnTF > {1.6}
+ {
+ \pdfmanagement_add:nnn {Catalog / ViewerPreferences }
+ { PickTrayByPDFSize } { false }
+ }
+ {
+ \msg_warning:nnxx
+ {hyp}
+ {ignore-deprecated-or-unknown-option-in-pdf-version}
+ {pdfpicktraybypdfsize}
+ {\pdf_version:}
+ }
+ }
+ ,pdfpicktraybypdfsize / .code:n =
+ {
+ \pdfmanagement_remove:nn {Catalog / ViewerPreferences } { PickTrayByPDFSize }
+ }
+ ,pdfpicktraybypdfsize / unknown .code:n =
+ {
+ \msg_warning:nnxx { hyp } { no-bool }
+ { picktraybypdfsize }
+ { \exp_not:n {#1} }
+ }
+ ,pdfprintarea .choices:nn =
+ { MediaBox, CropBox, BleedBox, TrimBox, ArtBox }
+ {
+ \pdf_version_compare:NnTF < {2.0}
+ {
+ \pdfmanagement_add:nnx {Catalog / ViewerPreferences }
+ { PrintArea } { /#1 }
+ }
+ {
+ \msg_warning:nnxx
+ {hyp}
+ {ignore-deprecated-or-unknown-option-in-pdf-version}
+ {pdfprintarea}
+ {\pdf_version:}
+ }
+ }%
+ ,pdfprintarea / .code:n =
+ { \pdfmanagement_remove:nn {Catalog / ViewerPreferences } { PrintArea } }
+ ,pdfprintarea / unknown .code:n =
+ {
+ \msg_warning:nnxxx { hyp } { unknown-choice+empty }
+ { pdfprintarea }
+ { MediaBox, CropBox, BleedBox, TrimBox, ArtBox }
+ { \exp_not:n {#1} }
+ }
+ ,pdfprintclip .choices:nn =
+ { MediaBox, CropBox, BleedBox, TrimBox, ArtBox }
+ {
+ \pdf_version_compare:NnTF < {2.0}
+ {
+ \pdfmanagement_add:nnx {Catalog / ViewerPreferences }
+ { PrintClip } { /#1 }
+ }
+ {
+ \msg_warning:nnxx
+ {hyp}
+ {ignore-deprecated-or-unknown-option-in-pdf-version}
+ {pdfprintclip}
+ {\pdf_version:}
+ }
+ }%
+ ,pdfprintclip / .code:n =
+ {
+ \pdfmanagement_remove:nn {Catalog / ViewerPreferences } { PrintClip }
+ }
+ ,pdfprintclip / unknown .code:n =
+ {
+ \msg_warning:nnxxx { hyp } { unknown-choice+empty }
+ { pdfprintclip }
+ { MediaBox, CropBox, BleedBox, TrimBox, ArtBox }
+ { \exp_not:n {#1} }
+ }
+ ,pdfprintpagerange .code:n =
+ {
+ \pdf_version_compare:NnTF > {1.6}
+ {
+ \tl_if_empty:nTF { #1}
+ {
+ \pdfmanagement_remove:nn {Catalog / ViewerPreferences }
+ { PrintPageRange }
+ }
+ {
+ \pdfmanagement_add:nnx {Catalog / ViewerPreferences }
+ {PrintPageRange}{[#1]}
+ }
+ }
+ {
+ \msg_warning:nnxx
+ {hyp}
+ {ignore-deprecated-or-unknown-option-in-pdf-version}
+ {pdfprintpagerange}
+ {\pdf_version:}
+ }
+ }
+ ,pdfprintscaling .choices:nn =
+ { None, AppDefault }
+ {
+ \pdf_version_compare:NnTF > {1.5}
+ {
+ \pdfmanagement_add:nnx {Catalog / ViewerPreferences }
+ { PrintScaling } { /#1 }
+ }
+ {
+ \msg_warning:nnxx
+ {hyp}
+ {ignore-deprecated-or-unknown-option-in-pdf-version}
+ {pdfprintscaling}
+ {\pdf_version:}
+ }
+ }%
+ ,pdfprintscaling / .code:n =
+ {
+ \pdfmanagement_remove:nn {Catalog / ViewerPreferences } {PrintScaling }
+ }
+ ,pdfprintscaling / unknown .code:n =
+ {
+ \msg_warning:nnxxx { hyp } { unknown-choice+empty }
+ { pdfprintarea }
+ { None, AppDefault }
+ { \exp_not:n {#1} }
+ }
+ ,pdfremotestartview .code:n =
+ {
+ \tl_set:Nx \l_@@_tmpa_tl {#1~null~null~null~}
+ \exp_args:NNV
+ \regex_extract_once:NnNTF \c_@@_dest_startview_regex \l_@@_tmpa_tl \l_@@_tmpa_seq
+ {
+ \tl_set:Nx \l_@@_dest_pdfremotestartview_tl {\seq_item:Nn \l_@@_tmpa_seq {1}}
+ }
+ {
+ \msg_warning:nnnn {hyp}{invalid-destination-value}{#1}{pdfremotestartview}
+ \tl_set:Nn \l_@@_dest_pdfremotestartview_tl {Fit}
+ }
+ }
+ ,pdfremotestartview .initial:n = {Fit}
+ % pdfstartpage is special as it shares code with pdfstartview
+ ,pdfstartpage .code:n =
+ {
+ \tl_gset:Nx \g_@@_dest_pdfstartpage_tl { #1 }
+ \bool_if:nTF
+ { \tl_if_empty_p:N \g_@@_dest_pdfstartpage_tl || \tl_if_empty_p:N \g_@@_dest_pdfstartview_tl }
+ {
+ \pdfmanagement_remove:nn {Catalog} { OpenAction }
+ }
+ {
+ \pdfmanagement_add:nnx {Catalog} { OpenAction }
+ {
+ [\pdf_pageobject_ref:n {\g_@@_dest_pdfstartpage_tl}~/\g_@@_dest_pdfstartview_tl]
+ }
+ }
+ }
+ ,pdfstartpage .initial:n =1
+ ,pdfstartview .code:n =
+ {
+ \tl_set:Nx \l_@@_tmpa_tl {#1~null~null~null~}
+ \exp_args:NNV
+ \regex_extract_once:NnNTF \c_@@_dest_startview_regex \l_@@_tmpa_tl \l_@@_tmpa_seq
+ {
+ \tl_gset:Nx \g_@@_dest_pdfstartview_tl {\seq_item:Nn \l_@@_tmpa_seq {1}}
+ }
+ {
+ \msg_warning:nnnn {hyp}{invalid-destination-value}{#1}{pdfstartview}
+ \tl_gset:Nn \g_@@_dest_pdfstartview_tl {Fit}
+ }
+ \bool_if:nTF
+ { \tl_if_empty_p:N \g_@@_dest_pdfstartpage_tl || \tl_if_empty_p:N \g_@@_dest_pdfstartview_tl }
+ {
+ \pdfmanagement_remove:nn {Catalog} { OpenAction }
+ }
+ {
+ \pdfmanagement_add:nnx {Catalog} { OpenAction }
+ {
+ [\pdf_pageobject_ref:n {\g_@@_dest_pdfstartpage_tl}~/\g_@@_dest_pdfstartview_tl]
+ }
+ }
+ }
+ ,pdfstartview .initial:n = Fit
+ ,pdftoolbar .choice:
+ ,pdftoolbar / true .code:n =
+ {
+ \pdfmanagement_remove:nn {Catalog / ViewerPreferences } { HideToolbar }
+ }
+ ,pdftoolbar / false .code:n =
+ {
+ \pdfmanagement_add:nnn {Catalog / ViewerPreferences }
+ { HideToolbar } { true }
+ }
+ ,pdftoolbar / true .code:n =
+ {
+ \pdfmanagement_remove:nn {Catalog / ViewerPreferences } { HideToolbar }
+ }
+ ,pdftoolbar .default:n = true
+ ,pdftoolbar / unknown .code:n =
+ {
+ \msg_warning:nnxx { hyp } { no-bool }
+ { pdftoolbar }
+ { \exp_not:n {#1} }
+ }
+ % pdfview see below.
+ ,pdfviewarea .choices:nn =
+ { MediaBox, CropBox, BleedBox, TrimBox, ArtBox }
+ {
+ \pdf_version_compare:NnTF < {2.0}
+ {
+ \pdfmanagement_add:nnn {Catalog / ViewerPreferences }
+ { ViewArea } { /#1 }
+ }
+ {
+ \msg_warning:nnxx
+ {hyp}
+ {ignore-deprecated-or-unknown-option-in-pdf-version}
+ {pdfviewarea}
+ {\pdf_version:}
+ }
+ }%
+ ,pdfviewarea / .code:n =
+ {
+ \pdfmanagement_remove:nn {Catalog / ViewerPreferences } { ViewArea }
+ }
+ ,pdfviewarea / unknown .code:n =
+ {
+ \msg_warning:nnxxx { hyp } { unknown-choice+empty }
+ { pdfviewarea }
+ { MediaBox, CropBox, BleedBox, TrimBox, ArtBox }
+ { \exp_not:n {#1} }
+ }
+ ,pdfviewclip .choices:nn =
+ { MediaBox, CropBox, BleedBox, TrimBox, ArtBox }
+ {
+ \pdf_version_compare:NnTF < {2.0}
+ {
+ \pdfmanagement_add:nnn {Catalog / ViewerPreferences }
+ { ViewClip } { /#1 }
+ }
+ {
+ \msg_warning:nnxx
+ {hyp}
+ {ignore-deprecated-or-unknown-option-in-pdf-version}
+ {pdfviewclip}
+ {\pdf_version:}
+ }
+ }%
+ ,pdfviewclip / .code:n =
+ {
+ \pdfmanagement_remove:nn {Catalog / ViewerPreferences } { ViewClip }
+ }
+ ,pdfviewclip / unknown .code:n =
+ {
+ \msg_warning:nnxxx { hyp } { unknown-choice+empty }
+ { pdfviewclip }
+ { MediaBox, CropBox, BleedBox, TrimBox, ArtBox }
+ { \exp_not:n {#1} }
+ }
+ ,pdfwindowui .choice:
+ ,pdfwindowui / true .code:n =
+ {
+ \pdfmanagement_remove:nn {Catalog / ViewerPreferences } { HideWindowUI }
+ }
+ ,pdfwindowui / false .code:n =
+ {
+ \pdfmanagement_add:nnn {Catalog / ViewerPreferences }
+ { HideWindowUI } { true }
+ }
+ ,pdfwindowui / .code:n =
+ {
+ \pdfmanagement_remove:nn {Catalog / ViewerPreferences } {HideWindowUI }
+ }
+ ,pdfwindowui / unknown .code:n =
+ {
+ \msg_warning:nnxx { hyp } { no-bool }
+ { pdfwindowui }
+ { \exp_not:n {#1} }
+ }
+ ,pdfwindowui .default:n = true
+ }
+% \end{macrocode}
+%
+% \begin{hypkey}{pdfview}
+% Destination keys. pdfview is a bit more complicated so extra.
+% \begin{macrocode}
+\keys_define:nn { hyp / setup }
+ {
+ ,pdfview .code:n =
+ {
+ \seq_set_split:Nnn \l_@@_tmpa_seq {~}{#1}
+ \str_case_e:nnF { \str_lowercase:f{ \seq_item:Nn \l_@@_tmpa_seq {1} } }
+ {
+ { xyz }
+ {
+ \int_compare:nNnTF {\seq_count:N \l_@@_tmpa_seq } > { 1 }
+ {
+ \seq_get_right:NN \l_@@_tmpa_seq \l_@@_tmpa_tl
+ \tl_if_eq:NnTF \l_@@_tmpa_tl {null}
+ {
+ \tl_set:Nn \l_@@_dest_pdfview_tl {xyz}
+ }
+ {
+ \tl_set:Nx \l_@@_dest_pdfview_tl
+ {
+ \fp_eval:n { \l_@@_tmpa_tl * 100 }
+ }
+ }
+ }
+ {
+ \tl_set:Nn \l_@@_dest_pdfview_tl {xyz}
+ }
+ }
+ { fit } { \tl_set:Nn \l_@@_dest_pdfview_tl {fit} }
+ { fitb } { \tl_set:Nn \l_@@_dest_pdfview_tl {fitb} }
+ { fitbh } { \tl_set:Nn \l_@@_dest_pdfview_tl {fitbh}}
+ { fitbv } { \tl_set:Nn \l_@@_dest_pdfview_tl {fitbv}}
+ { fith } { \tl_set:Nn \l_@@_dest_pdfview_tl {fith} }
+ { fitv } { \tl_set:Nn \l_@@_dest_pdfview_tl {fitv} }
+ { fitr }
+ {
+ \int_compare:nNnTF {\seq_count:N \l_@@_tmpa_seq } = {1}
+ {
+ \tl_set:Nn \l_@@_dest_pdfview_tl {fitr}
+ }
+ {
+ %ensure 4 values ...
+ \tl_set:Nn \l_@@_dest_pdfview_tl {fitrbox}
+ \seq_put_right:Nn \l_@@_tmpa_seq {0}
+ \seq_put_right:Nn \l_@@_tmpa_seq {0}
+ \seq_put_right:Nn \l_@@_tmpa_seq {0}
+ \hbox_set_to_wd:Nnn \l_@@_dest_box
+ {
+ \fp_eval:n
+ {
+ round
+ (
+ abs
+ (
+ \seq_item:Nn\l_@@_tmpa_seq{4}
+ -
+ (\seq_item:Nn\l_@@_tmpa_seq{2})
+ ),
+ 3
+ )
+ }bp
+ }{}
+ \box_set_dp:Nn \l_@@_dest_box
+ {
+ \fp_eval:n
+ {
+ round(0 - (\seq_item:Nn\l_@@_tmpa_seq{3}),3)
+ }bp
+ }
+ \box_set_ht:Nn \l_@@_dest_box
+ {
+ \seq_item:Nn\l_@@_tmpa_seq{5}bp
+ }
+ }
+ }
+ }
+ {
+ \msg_warning:nnnn {hyp}{invalid-destination-value}{#1}{pdfview}
+ \tl_set:Nn \l_@@_dest_pdfview_tl {fit}
+ }
+ }
+ ,pdfview .initial:n = {xyz}
+ }
+% \end{macrocode}
+% \end{hypkey}
+%\subsection{\enquote{MetaData keys}}
+% The following keys are relevant for the metadata: the info dictionary and
+% the xmp-metadata.
+% \begin{hypkey}{pdflang}
+% |pdflang| should be deprecated.
+% \begin{macrocode}
+\keys_define:nn { hyp / setup }
+ {
+ ,pdflang .code:n =
+ {
+ \tl_if_empty:nTF { #1 }
+ {
+ \pdfmanagement_remove:nn {Catalog} { Lang }
+ }
+ {
+ \pdfmanagement_add:nnx {Catalog} { Lang } { (#1) }
+ }
+ \@@_store_metadata:nn {pdflang}{#1}
+ }
+ }
+% \end{macrocode}
+% \end{hypkey}
+%
+% \subsubsection{\enquote{info keys}}
+% \begin{hypkey}{pdfauthor,pdftitle,pdfcreator,pdfsubject,pdfproducer,pdfkeywords}
+% The keys store their value also in the metadate container, so that hyperxmp can
+% use them.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_setup_info_key:nn #1 #2
+ {
+ \keys_define:nn { hyp / setup }
+ {
+ pdf#1 .code:n =
+ {
+ \tl_if_blank:nTF {##1}
+ {
+ \pdfmanagement_remove:nn {Info}{#2}
+ }
+ {
+ \@@_text_pdfstring_info:nN {##1}\l_@@_tmpa_str
+ \str_if_eq:VnF\l_@@_tmpa_str{<FEFF>}
+ {
+ \pdfmanagement_add:nnx {Info}{#2}{\l_@@_tmpa_str}
+ }
+ }
+ \@@_store_metadata:nn {pdf#1}{##1}
+ }
+ }
+ \keys_define:nn { hyp / info }
+ {
+ #2 .code:n =
+ {
+ \tl_if_blank:nTF {##1}
+ {
+ \pdfmanagement_remove:nn {Info}{#2}
+ }
+ {
+ \@@_text_pdfstring_info:nN {##1}\l_@@_tmpa_str
+ \str_if_eq:VnF\l_@@_tmpa_str{<FEFF>}
+ {
+ \pdfmanagement_add:nnx {Info}{#2}{\l_@@_tmpa_str}
+ }
+ }
+ \exp_args:Nx \@@_store_metadata:nn {pdf\str_lowercase:n{#1}}{##1}
+ }
+ ,unknown .code:n =
+ {
+ \@@_text_pdfstring_info:nN {##1}\l_@@_tmpa_str
+ \str_if_eq:VnF\l_@@_tmpa_str{<FEFF>}
+ {
+ \exp_args:Nno
+ \pdfmanagement_add:nnx {Info}
+ { \l_keys_key_str } {\l_@@_tmpa_str}
+ }
+ }
+ }
+ }
+\@@_setup_info_key:nn {author} {Author}
+\@@_setup_info_key:nn {title} {Title}
+\@@_setup_info_key:nn {producer} {Producer}
+\@@_setup_info_key:nn {creator} {Creator}
+% ignored key: addtopdfcreator
+\@@_setup_info_key:nn {subject} {Subject}
+\@@_setup_info_key:nn {keywords} {Keywords}
+% \end{macrocode}
+% \end{hypkey}
+% \begin{hypkey}{pdfcreationdate,pdfmoddate}
+% These keys are not really needed. We store them too in the container.
+% CreationDate and ModDate should not use the hex encoding.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_setup_info_date_key:nn #1 #2
+ {
+ \keys_define:nn { hyp / setup }
+ {
+ pdf#1 .code:n =
+ {
+ \tl_if_blank:nTF {##1}
+ {
+ \pdfmanagement_remove:nn {Info}{#2}
+ }
+ {
+ \pdfmanagement_add:nnx {Info}{#2}{(\tl_to_str:n {##1})}
+ }
+ \@@_store_metadata:nn {pdf#1}{##1}
+ }
+ }
+ \keys_define:nn { hyp / info }
+ {
+ #2 .code:n =
+ {
+ \tl_if_blank:nTF {##1}
+ {
+ \pdfmanagement_remove:nn {Info}{#2}
+ }
+ {
+ \pdfmanagement_add:nnx {Info}{#2}{(\tl_to_str:n {##1})}
+ }
+ \exp_args:Nx \@@_store_metadata:nn {pdf\str_lowercase:n{#1}}{##1}
+ }
+ }
+ }
+
+\@@_setup_info_date_key:nn {creationdate} {CreationDate}
+\@@_setup_info_date_key:nn {moddate} {ModDate}
+% \end{macrocode}
+% \end{hypkey}
+% \begin{hypkey}{pdftrapped}
+% Trapped is a bit curious, it has an value "unknown", and one can't suppress it ...
+% \begin{macrocode}
+\keys_define:nn { hyp / setup }
+ {
+ ,pdftrapped .code:n =
+ {
+ \exp_args:Nne
+ \keys_set:nn { hyp / setup } { _pdftrapped = \str_uppercase:n { #1 } }
+ }
+ ,_pdftrapped .choices:nn = {TRUE,FALSE,UNKNOWN}
+ {
+ \pdfmanagement_add:nnx {Info}{Trapped}
+ {/
+ \str_uppercase:f { \str_head:n { #1 } }
+ \str_lowercase:f { \str_tail:n { #1 } }
+ }
+ \@@_store_metadata:nx {pdftrapped}
+ {
+ \str_uppercase:f { \str_head:n { #1 } }
+ \str_lowercase:f { \str_tail:n { #1 } }
+ }
+ }
+ ,_pdftrapped / unknown .code:n =
+ {
+ \msg_warning:nnxxx { hyp } { unknown-choice }
+ { pdftrapped }
+ { true~(case~insensitive), false~(case~insensitive), unknown~(case~insensitive) }
+ { \exp_not:n {#1} }
+ }
+ }
+% \end{macrocode}
+% \end{hypkey}
+% \begin{hypkey}{pdfinfo}
+% pdfinfo allows to set the info keys with keyval ...
+% \begin{macrocode}
+\keys_define:nn { hyp / setup }
+ {
+ pdfinfo .code:n =
+ {
+ \keys_set:nn { hyp / info } { #1 }
+ }
+ }
+% \end{macrocode}
+% \end{hypkey}
+% Now we set some default values
+% \begin{macrocode}
+\keys_set:nn { hyp / setup} {pdfcreator = LaTeX~with~hyperref}
+\keys_set:nn { hyp / setup} {pdfauthor = }
+\keys_set:nn { hyp / setup} {pdftitle = }
+\keys_set:nn { hyp / setup} {pdfsubject = }
+% \end{macrocode}
+%
+% \subsection{hyperxmp keys}
+% hyperxmp defines lots of keys for \cs{hypersetup}.
+% They now longer work with this driver. So we provide them,
+% but they are only stored as metadata:
+% \begin{macrocode}
+\clist_map_inline:nn
+ {
+ ,pdfcopyright
+ ,pdftype
+ ,pdflicenseurl
+ ,pdfauthortitle
+ ,pdfcaptionwriter
+ ,pdfmetalang
+ ,pdfapart
+ ,pdfaconformance
+ ,pdfuapart
+ ,pdfxstandard
+ ,pdfsource
+ ,pdfdocumentid
+ ,pdfinstanceid
+ ,pdfversionid
+ ,pdfrendition
+ ,pdfpublication
+ ,pdfpubtype
+ ,pdfbytes
+ ,pdfnumpages
+ ,pdfissn
+ ,pdfeissn
+ ,pdfisbn
+ ,pdfbookedition
+ ,pdfpublisher
+ ,pdfvolumenum
+ ,pdfissuenum
+ ,pdfpagerange
+ ,pdfdoi
+ ,pdfurl
+ ,pdfidentifier
+ ,pdfsubtitle
+ ,pdfpubstatus
+ ,pdfcontactaddress
+ ,pdfcontactcity
+ ,pdfcontactregion
+ ,pdfcontactpostcode
+ ,pdfcontactcountry
+ ,pdfcontactphone
+ ,pdfcontactemail
+ ,pdfcontacturl
+ ,pdfdate
+ }
+ {
+ \keys_define:nn { hyp / setup }
+ {
+ #1 .code:n= { \@@_store_metadata:nn {#1}{##1}}
+ }
+ }
+% \end{macrocode}
+%
+% \subsection{Transitions}
+% pdfpageduration sets the duration a page is shown in full screen mode.
+% \begin{macrocode}
+\keys_define:nn { hyp / setup }
+ {
+ pdfpageduration .code:n =
+ {
+ \tl_if_blank:nTF { #1 }
+ {
+ \pdfmanagement_remove:nn {Page}{Dur}
+ }
+ {
+ \pdfmanagement_add:nnn {Page}{Dur}{#1}
+ }
+ }
+ }
+% \end{macrocode}
+% Transition settings are used by (some) pdf viewers when presenting a
+% pdf in full screen mode. They are added to the page settings and describe the
+% transition from the previous page to current page. Transition setting can be
+% set in the preamble for all pages or in the document for the current and the
+% following pages. Due to the asynchronous page breaking one has to be careful
+% to set it on the right page, e.g. only after a |\newpage|.
+% The generic driver uses a different syntax than the other hyperref drivers:
+% various transition options can be set by a keyval syntax in the value of
+% |pdfpagetransition|. A typical setting looks e.g. like this\\
+% |\hypersetup{pdfpagetransition={style=Fly,duration=2,direction=90,opaque=false}}|
+%
+% The keys allowed in the argument of |pdfpagetransition| are
+% \begin{tabular}{l>{\raggedright\arraybackslash}p{6cm}}
+% style & one of Split, Blinds, Box, Wipe, Dissolve, Glitter, R, Fly, Push, Cover, Uncover, Fade\\
+% duration & a number, describes the duration of the transition\\
+% direction& \begin{tabular}[t]{l}
+% H~(horizontal,~only~Split,~Blinds)\\
+% V~(vertical,~only~Split,~Blinds)\\
+% 0~(left~to~right,~only~Wipe,~Glitter,~Fly,~Cover,~Uncover,~Push)\\
+% 90~(bottom~to~top,~only~Wipe)\\
+% 180~(right~to~left,~only~Wipe)\\
+% 270~(top~to~bottom,~only~Wipe,~Glitter,~Fly,~Cover,~Uncover,~Push)\\
+% 315~(top~left~to~bottom,~only~Glitter)\\
+% None~(only~Fly)
+% \end{tabular}\\
+% motion & one of I, O, only relevant for Split, Box and Fly\\
+% scale & a number, only relevant for Fly style \\
+% opaque & true or false, only relevant for Fly style
+% \end{tabular}
+% \begin{macrocode}
+\keys_define:nn { hyp / setup }
+ {
+ pdfpagetransition .code:n =
+ {
+ \tl_if_blank:nTF {#1}
+ {
+ \pdfmanagement_remove:nn {Page}{Trans}
+ }
+ {
+ \group_begin:
+ \keys_set:nn { hyp / trans }{style=R,#1}
+ \pdf_object_unnamed_write:nx { dict }
+ {
+ \pdfdict_use:n {l_@@_page/Trans}
+ }
+ \pdfmanagement_add:nnx {Page}{Trans}{\pdf_object_ref_last:}
+ \group_end:
+ }
+ }
+ }
+\keys_define:nn { hyp / trans }
+ {
+ ,style .choices:nn =
+ {Split,Blinds,Box,Wipe,Dissolve,Glitter,R,Fly,Push,Cover,Uncover,Fade}
+ { \pdfdict_put:nnn {l_@@_page/Trans}{ S }{/#1} }
+ ,style / unknown .code:n =
+ {
+ \msg_warning:nnxxx { hyp } { unknown-choice }
+ { trans / style }
+ { Split,Blinds,Box,Wipe,Dissolve,Glitter,R,Fly,Push,Cover,Uncover,Fade }
+ { \exp_not:n {#1} }
+ }
+ ,duration .code:n =
+ {
+ \pdfdict_put:nnn {l_@@_page/Trans}{ D }{#1}
+ }
+ ,direction .choices:nn =
+ {H,V}
+ { \pdfdict_put:nnn {l_@@_page/Trans}{ S }{/#1} }
+ ,direction .choices:nn =
+ {0,90,180,270,315}
+ { \pdfdict_put:nnn {l_@@_page/Trans}{ DI }{ #1 } }
+ ,direction / None .code:n =
+ { \pdfdict_put:nnn {l_@@_page/Trans}{ DI }{ /None } }
+ ,direction / unknown .code:n =
+ {
+ \msg_warning:nnxxx { hyp } { unknown-choice }
+ { trans / direction }
+ {
+ H~(horizontal,~only~Split,~Blinds),
+ V~(vertical,~only~Split,~Blinds),
+ 0~(left~to~right,~only~Wipe,~Glitter,~Fly,~Cover,~Uncover,~Push),
+ 90~(bottom~to~top,~only~Wipe),
+ 180~(right~to~left,~only~Wipe),
+ 270~(top~to~bottom,~only~Wipe,~Glitter,~Fly,~Cover,~Uncover,~Push),
+ 315~(top~left~to~bottom,~only~Glitter),
+ None~(only~Fly)
+ }
+ { \exp_not:n {#1} }
+ }
+ ,motion .choices:nn =
+ {I,O}
+ { \pdfdict_put:nnn {l_@@_page/Trans}{ M }{/#1} }
+ ,motion / unknown .code:n =
+ {
+ \msg_warning:nnxxx { hyp } { unknown-choice }
+ { trans / motion }
+ { I~(inwards) , O~(outwards) }
+ { \exp_not:n {#1} }
+ }
+ ,scale .code:n =
+ { \pdfdict_put:nnn { l_@@_page/Trans }{ SS }{ #1 } }
+ ,opaque .choices:nn = {true,false}
+ { \pdfdict_put:nnn { l_@@_page/Trans }{ B } { #1} }
+ ,opaque / unknown .code:n =
+ {
+ \msg_warning:nnxxx { hyp } { unknown-choice }
+ { trans / B }
+ { true~(opaque~back,~only~Fly), false~(opaque~back,~only~Fly) }
+ { \exp_not:n {#1} }
+ }
+ % try to set unknown keys as style
+ ,unknown .code:n =
+ {
+ % warning ...
+ \exp_args:Nnx\keys_set:nn {hyp/trans}{ style=\l_keys_key_str }
+ }
+ }
+% \end{macrocode}
+%
+% Finally we process the package option list, to get most keys working
+% \begin{macrocode}
+\keys_set_known:nv{hyp/setup}{opt@hyperref.sty}
+% \end{macrocode}
+%
+% Unfinished
+%% Form field code
+% \begin{macrocode}
+\NewDocumentCommand \MakeFieldObject { m m }
+ {
+ \pdfxform_new:nnn { #2 }{} { #1 }
+ }
+
+
+\prop_new:N \g_@@_AcroForm_CoFields_prop
+\prop_new:N \g_@@_AcroForm_Fields_prop
+
+\let\HyField@afields\ltx@empty
+\let\HyField@cofields\ltx@empty
+%% UF test for old pdftex removed
+%\let\HyField@AuxAddToFields\ltx@gobble
+%\let\HyField@AuxAddToCoFields\ltx@gobbletwo
+\def\HyField@AfterAuxOpen{\Hy@AtBeginDocument}%
+
+% the value doesn't matter, but with a prop we avoid duplicates and it is
+% clearly faster than removing them from a sequence
+\def\HyField@AuxAddToFields#1
+ {
+ \prop_gput:Nnn \g__hyp_AcroForm_Fields_prop {#1}{F}
+ }%
+
+%fields with empty key get a value too -- lets hope that
+%this give the expected behaviour
+\def\HyField@AuxAddToCoFields #1 #2
+ {
+ \prop_gput:Nnn \g__hyp_AcroForm_CoFields_prop {a#1}{#2}
+ }
+
+\Hy@AtBeginDocument
+ {
+ \if@filesw
+ \immediate\write\@mainaux{%
+ \string\providecommand\string\HyField@AuxAddToFields[1]{}%
+ }%
+ \immediate\write\@mainaux{%
+ \string\providecommand\string\HyField@AuxAddToCoFields[2]{}%
+ }%
+ \fi
+ \let\HyField@AfterAuxOpen\@firstofone
+ }%
+
+\def\HyField@AddToFields
+ {
+ \exp_args:Nx\HyField@@AddToFields
+ {
+ \pdfannot_box_ref_last:
+ }
+ \ifx\Fld@calculate@code\ltx@empty
+ \else
+ \begingroup
+ \Hy@safe@activestrue
+ \edef\Hy@temp{%
+ \endgroup
+ \if@filesw
+ \write\@mainaux
+ {
+ \string\HyField@AuxAddToCoFields
+ {
+ \Fld@calculate@sortkey
+ }
+ {
+ \pdfannot_box_ref_last:
+ }
+ }
+ \fi
+ }%
+ \Hy@temp
+ \fi
+ }%
+
+\def\HyField@@AddToFields#1{
+ \HyField@AfterAuxOpen{%
+ \if@filesw
+ \write\@mainaux{%
+ \string\HyField@AuxAddToFields{#1}%
+ }%
+ \fi
+ }%
+ }%
+
+\ExplSyntaxOff
+\ExplSyntaxOn
+\tl_new:N \l_@@_CheckmarkYes_tl
+\tl_set:Nn \l_@@_CheckmarkYes_tl { __hyp_xform_CheckMarkYes }
+\tl_new:N \l_@@_CheckmarkOff_tl
+\tl_set:Nn \l_@@_CheckmarkOff_tl { __hyp_xform_CheckMarkOff }
+
+\def\@Form[#1]
+ {
+ \@ifundefined{textcolor}{\let\textcolor\@gobble}{}
+ \kvsetkeys{Form}{#1}
+ \pdf@ifdraftmode{}
+ {
+ \Hy@FormObjects
+ \prop_map_inline:Nn \g__hyp_AcroForm_Fields_prop
+ {
+ \pdfmanagement_add:nnx { Catalog / AcroForm } { Fields }{##1}
+ %\pdfmanagement_show:n { Catalog / AcroForm }
+ }
+ \prop_if_empty:NF \g__hyp_AcroForm_CoFields_prop
+ {
+ \prop_map_inline:Nn \g__hyp_AcroForm_CoFields_prop
+ {
+ \seq_put_right:Nn \l_@@_tmpa_seq {##1}
+ }
+ \seq_sort:Nn \l_@@_tmpa_seq
+ {
+ \int_compare:nNnTF { \pdf@strcmp{##1}{##2} } > { 0 }
+ { \sort_return_swapped: }
+ { \sort_return_same: }
+ }
+ \seq_map_inline:Nn \l_@@_tmpa_seq
+ {
+ \pdfmanagement_add:nnx { Catalog / AcroForm }
+ { CO }
+ {
+ \prop_item:Nn \g__hyp_AcroForm_CoFields_prop {##1}
+ }
+ }
+ }
+ \pdfmanagement_add:nnx {Catalog / AcroForm/DR/Font }
+ {ZaDb} {\pdf_object_ref:n {l_@@_font_zapfdingbats_obj} }
+ \pdfmanagement_add:nnx {Catalog / AcroForm/DR/Font }
+ {Helv} {\pdf_object_ref:n {l_@@_font_helvetica_obj} }
+ \pdfmanagement_add:nnx {Catalog /AcroForm}
+ {DA}{(/Helv~10~Tf~0~g)}
+ \pdfmeta_standard_verify:nTF {form_no_NeedAppearance}
+ {
+ \legacy_if:nT { HyField@NeedAppearances }
+ {
+ \pdfmanagement_add:nnn {Catalog / AcroForm }{NeedAppearances}{true}
+ }
+ }
+ {
+ \pdfmanagement_remove:nn {Catalog / AcroForm }{NeedAppearances}
+ }
+ }
+ \MakeFieldObject
+ {
+ \group_begin:
+ \fontfamily{pzd}
+ \fontencoding{U}
+ \fontseries{m}
+ \fontshape{n}
+ \selectfont
+ \char123
+ \group_end:
+ }
+ {__hyp_xform_Ding}
+ \MakeFieldObject
+ {
+ \group_begin:
+ \fontfamily{pzd}
+ \fontencoding{U}
+ \fontseries{m}
+ \fontshape{n}
+ \selectfont
+ \phantom{\char123}
+ \group_end:
+ }
+ {__hyp_xform_DingOff}
+ \MakeFieldObject
+ {
+ \group_begin:
+ \fontfamily{pzd}
+ \fontencoding{U}
+ \fontseries{m}
+ \fontshape{n}
+ \selectfont
+ \char51
+ \group_end:
+ }
+ {__hyp_xform_CheckMarkYes}
+ \MakeFieldObject
+ {
+ \group_begin:
+ \fontfamily{pzd}
+ \fontencoding{U}
+ \fontseries{m}
+ \fontshape{n}
+ \selectfont
+ \phantom{\char51} %perhaps xetex needs some small glyph ..
+ \group_end:
+ }
+ {__hyp_xform_CheckMarkOff}
+ \MakeFieldObject
+ {
+ \fbox{\textcolor{yellow}{\textsf{Submit}}} %color?
+ }
+ {__hyp_xform_Submit}
+ \MakeFieldObject
+ {
+ \fbox{\textcolor{yellow}{\textsf{SubmitP}}} %color?
+ }
+ {__hyp_xform_SubmitP}
+ }
+\ExplSyntaxOff
+\let\@endForm\ltx@empty
+\let\HyAnn@AbsPageLabel\ltx@empty
+\let\Fld@pageobjref\ltx@empty
+
+\ExplSyntaxOn
+\newcount\HyAnn@Count
+\HyAnn@Count=\ltx@zero
+\def\HyAnn@AbsPageLabel
+ {
+ \global\advance\HyAnn@Count by\ltx@one
+ %\zref@labelbyprops{HyAnn@\the\HyAnn@Count}{abspage}%
+ %\zref@labelbylist {HyAnn@\the\HyAnn@Count} {l3pdf}
+ %\zref@refused{HyAnn@\the\HyAnn@Count}%
+ \__hyp_ref_label:en {HyAnn@\the\HyAnn@Count}{abspage}
+ \__hyp_ref_check:en {HyAnn@\the\HyAnn@Count}{abspage}
+ }%
+\def\Fld@pageobjref
+ {
+ \__hyp_ref_if_exist:enT {HyAnn@\the\HyAnn@Count}{abspage}
+ {
+ /P~\pdf_pageobject_ref:n
+ {
+ \__hyp_ref_value:en{HyAnn@\the\HyAnn@Count}{abspage}
+ }
+ }
+ }
+\ExplSyntaxOff
+\ExplSyntaxOn
+%% check if the attr should be set through
+%% hooks.
+%% check if options are missing.
+\def\@TextField[#1]#2{% parameters, label
+ \def\Fld@name{#2}%
+ \let\Fld@default\ltx@empty
+ \let\Fld@value\@empty
+ \def\Fld@width{\DefaultWidthofText}%
+ \def\Fld@height{%
+ \ifFld@multiline
+ \DefaultHeightofTextMultiline
+ \else
+ \DefaultHeightofText
+ \fi
+ }%
+ \begingroup
+ \expandafter\HyField@SetKeys\expandafter{%
+ \DefaultOptionsofText,#1%
+ }%
+ \PDFForm@Name
+ \HyField@FlagsText
+ \ifFld@hidden\def\Fld@width{1sp}\fi
+ \ifx\Fld@value\@empty\def\Fld@value{\Fld@default}\fi
+ \LayoutTextField{#2}{%
+ \leavevmode
+ \HyAnn@AbsPageLabel
+ \Hy@escapeform\PDFForm@Text
+ \pdfannot_box:nnnn
+ {\Fld@width}
+ {\Fld@height}
+ {0pt} %is this correct?
+ {\PDFForm@Text}
+ \MakeTextField{\Fld@width}{\Fld@height}
+ \HyField@AddToFields
+ }%
+ \endgroup
+}
+\providecommand\@curropt{}
+\def\@ChoiceMenu[#1]#2#3{% parameters, label, choices
+ \def\Fld@name{#2}
+ \let\Fld@default\relax
+ \let\Fld@value\relax
+ \def\Fld@width{\DefaultWidthofChoiceMenu}
+ \def\Fld@height{\DefaultHeightofChoiceMenu}
+ \begingroup
+ \Fld@menulength=0 %
+ \@tempdima\z@
+ \clist_map_variable:nNn { #3 } \@curropt
+ %\@for\@curropt:=#3\do
+ {%
+ \expandafter\Fld@checkequals\@curropt==\\%
+ \Hy@StepCount\Fld@menulength
+ \settowidth{\@tempdimb}{\@currDisplay}%
+ \ifdim\@tempdimb>\@tempdima\@tempdima\@tempdimb\fi
+ }%
+ \advance\@tempdima by~15\p@
+ \begingroup
+ \HyField@SetKeys{#1}
+ \edef\x{\endgroup
+ \noexpand\expandafter
+ \noexpand\HyField@SetKeys
+ \noexpand\expandafter{%
+ \expandafter\noexpand\csname DefaultOptionsof%
+ \ifFld@radio
+ Radio%
+ \else
+ \ifFld@combo
+ \ifFld@popdown
+ PopdownBox%
+ \else
+ ComboBox%
+ \fi
+ \else
+ ListBox%
+ \fi
+ \fi
+ \endcsname
+ }%
+ }\x
+ \HyField@SetKeys{#1}%
+ \PDFForm@Name
+ \ifFld@hidden\def\Fld@width{1sp}\fi
+ \ifx\Fld@value\relax
+ \let\Fld@value\Fld@default
+ \fi
+ \LayoutChoiceField{#2}{%
+ \ifFld@radio
+ \HyField@FlagsRadioButton
+ \@@Radio{#3}%
+ \else
+ \begingroup
+ \HyField@FlagsChoice
+ \ifdim\Fld@width<\@tempdima
+ \ifdim\@tempdima<1cm\@tempdima1cm\fi
+ \edef\Fld@width{\the\@tempdima}%
+ \fi
+ \ifFld@combo
+ \else
+ \@tempdima=\the\Fld@menulength\Fld@charsize
+ \advance\@tempdima by~\Fld@borderwidth bp %
+ \advance\@tempdima by~\Fld@borderwidth bp %
+ \edef\Fld@height{\the\@tempdima}%
+ \fi
+ \@@Listbox{#3}%
+ \endgroup
+ \fi
+ }%
+ \endgroup
+}
+\tl_new:N \l_@@_RadioYes_tl
+\tl_set:Nn \l_@@_RadioYes_tl { __hyp_xform_Ding }
+\def\@@Radio#1{%
+ \Fld@listcount=0~%
+ %\show\Fld@default
+ \EdefEscapeName\Fld@default{\Fld@default}%
+ \clist_map_variable:nNn { #1 } \@curropt
+ %\@for\@curropt:=#1\do
+ {%
+ \expandafter\Fld@checkequals\@curropt==\\%
+ \EdefEscapeName\@currValue{\@currValue}%
+ \Hy@StepCount\Fld@listcount
+ \@currDisplay\space
+ \leavevmode
+ \HyAnn@AbsPageLabel
+ \Hy@escapeform\PDFForm@Radio
+ \pdfannot_box:nnnn
+ {\Fld@width}
+ {\Fld@height}
+ {0pt} %is this correct?
+ {
+ \PDFForm@Radio
+ /AP
+ <<
+ /N
+ <<
+ /\@currValue\c_space_tl \pdfxform_ref:o {__hyp_xform_Ding}
+ %/Off \c_space_tl \pdfxform_ref:n {__hyp_xform_DingOff} %hm
+ >>
+ >>
+ }
+ {\fbox{ \MakeRadioField{\Fld@width}{\Fld@height}} }
+ \int_compare:nNnT { \Fld@listcount} = { 1 }
+ { \HyField@AddToFields }
+ \c_space_tl % deliberate space between radio buttons
+ % to do: --> should be configurable
+ }%
+}
+
+\newcount\Fld@listcount
+\def\@@Listbox#1
+ {
+ \HyField@PDFChoices{#1}
+ \mode_leave_vertical:
+ \HyAnn@AbsPageLabel
+ \Hy@escapeform\PDFForm@List
+ \pdf_link_user:nnn
+ {widget} %perhaps we need more types??
+ {\PDFForm@List}
+ {\MakeChoiceField{\Fld@width}{\Fld@height}}
+ \HyField@AddToFields
+ }
+
+
+\def\@PushButton[#1]#2{% parameters, label
+ \def\Fld@name{#2}%
+ \group_begin:
+ \exp_args:No\HyField@SetKeys
+ {
+ \DefaultOptionsofPushButton,#1
+ }
+ \PDFForm@Name
+ \pdfmeta_standard_verify:nnTF {annot_action_A}{JavaScript}
+ {
+ \HyField@FlagsPushButton
+ \legacy_if:nT {Fld@hidden}
+ {
+ \def\Fld@width{1sp}
+ }
+ \LayoutPushButtonField
+ {
+ \mode_leave_vertical:
+ \HyAnn@AbsPageLabel
+ \Hy@escapeform\PDFForm@Push
+ \hbox_set:Nn \l_tmpa_box { \MakeButtonField {#2}}
+ \pdfannot_box:nnnn
+ {\box_wd:N\l_tmpa_box}
+ {\box_ht:N\l_tmpa_box}
+ {\box_dp:N\l_tmpa_box} %is this correct?
+ {\PDFForm@Push}
+ {\box_use:N\l_tmpa_box}
+ \HyField@AddToFields
+ }
+ }
+ {
+ \msg_error:nn { hyp }{ pdfa-no-push-button }
+ \LayoutPushButtonField
+ {
+ \mode_leave_vertical:
+ \MakeButtonField{#2}
+ }
+ }
+ \group_end:
+}
+
+\def\@Submit[#1]#2
+ {
+ \def\Fld@width {\DefaultWidthofSubmit}
+ \def\Fld@height{\DefaultHeightofSubmit}
+ \group_begin:
+ \exp_args:No\HyField@SetKeys
+ {
+ \DefaultOptionsofSubmit,#1
+ }
+ \HyField@FlagsPushButton
+ \HyField@FlagsSubmit
+ \legacy_if:nT { Fld@hidden }
+ {
+ \def\Fld@width{1sp}
+ }
+ \mode_leave_vertical:
+ \HyAnn@AbsPageLabel
+ \Hy@escapeform\PDFForm@Submit
+ \hbox_set:Nn \l_tmpa_box { \MakeButtonField {#2}}
+ \pdfannot_box:nnnn
+ {\box_wd:N\l_tmpa_box}
+ {\box_ht:N\l_tmpa_box}
+ {\box_dp:N\l_tmpa_box} %is this correct?
+ {
+ \PDFForm@Submit
+ /AP<<
+ /N~\pdfxform_ref:n {__hyp_xform_Submit}~
+ /D~\pdfxform_ref:n {__hyp_xform_SubmitP}
+ >>
+ }
+ \HyField@AddToFields
+ \box_use:N\l_tmpa_box
+
+ \group_end:
+ }
+
+\def\@Reset[#1]#2
+ {
+ \def\Fld@width {\DefaultWidthofReset}
+ \def\Fld@height{\DefaultHeightofReset}
+ \group_begin:
+ \exp_args:No\HyField@SetKeys
+ {
+ \DefaultOptionsofReset,#1
+ }
+ \mode_leave_vertical:
+ \pdfmeta_standard_verify:nnTF {annot_action_A}{ResetForm}
+ {
+ \HyField@FlagsPushButton
+ \legacy_if:nT { Fld@hidden }
+ { \def\Fld@width{1sp} }
+ \HyAnn@AbsPageLabel
+ \Hy@escapeform\PDFForm@Reset
+ \hbox_set:Nn \l_tmpa_box { \MakeButtonField {#2}}
+ \pdfannot_box:nnnn
+ {\box_wd:N\l_tmpa_box}
+ {\box_ht:N\l_tmpa_box}
+ {\box_dp:N\l_tmpa_box} %is this correct?
+ { \PDFForm@Reset }
+ \HyField@AddToFields
+ \box_use:N \l_tmpa_box
+ }
+ {
+ \msg_error:nn { hyp }{ pdfa-no-reset-button }
+ \MakeButtonField{#2}
+ }
+ \group_end:
+ }
+
+\def\@CheckBox[#1]#2
+ {% parameters, label
+ \def\Fld@name{#2}
+ \def\Fld@default{0}
+ \group_begin:
+ \def\Fld@width {\DefaultWidthofCheckBox}
+ \def\Fld@height{\DefaultHeightofCheckBox}
+ \exp_args:No\HyField@SetKeys
+ {
+ \DefaultOptionsofCheckBox,#1
+ }
+ \PDFForm@Name
+ \HyField@FlagsCheckBox
+ \legacy_if:nT { Fld@hidden }
+ {
+ \def\Fld@width{1sp}
+ }
+ \LayoutCheckField{#2}
+ {
+ \mode_leave_vertical:
+ \HyAnn@AbsPageLabel
+ \Hy@escapeform\PDFForm@Check
+ \pdfannot_box:nnnn
+ {\Fld@width}
+ {\Fld@height}
+ {0pt} %is this correct?
+ {\PDFForm@Check}
+ \HyField@AddToFields %check if this works with xelatex ...
+ }
+ \group_end:
+ }
+\ExplSyntaxOff
+
+%hm. Should a luatex driver use type1 fonts in fields????
+\ExplSyntaxOn
+\def\Hy@FormObjects
+ {
+ \pdf_object_new:nn {l_@@_encoding_pdfdoc_obj } { dict }
+ \pdf_object_new:nn {l_@@_font_zapfdingbats_obj } { dict }
+ \pdf_object_new:nn {l_@@_font_helvetica_obj } { dict }
+ \pdf_object_write:nx {l_@@_encoding_pdfdoc_obj }
+ {
+ /Type/Encoding
+ /Differences[
+ 24/breve/caron/circumflex/dotaccent/hungarumlaut/ogonek
+ /ring/tilde
+ \c_space_tl
+ 39/quotesingle
+ \c_space_tl
+ 96/grave %
+ \iow_newline:
+ 128/bullet/dagger/daggerdbl/ellipsis/emdash/endash/florin
+ /fraction/guilsinglleft/guilsinglright/minus/perthousand
+ /quotedblbase/quotedblleft/quotedblright/quoteleft
+ /quoteright/quotesinglbase/trademark/fi/fl/Lslash/OE
+ /Scaron/Ydieresis/Zcaron/dotlessi/lslash/oe/scaron/zcaron
+ \iow_newline:
+ 164/currency
+ \c_space_tl
+ 166/brokenbar
+ \c_space_tl
+ 168/dieresis/copyright/ordfeminine
+ \c_space_tl
+ 172/logicalnot/.notdef/registered/macron/degree/plusminus
+ /twosuperior/threesuperior/acute/mu
+ \c_space_tl
+ 183/periodcentered/cedilla/onesuperior/ordmasculine
+ \c_space_tl
+ 188/onequarter/onehalf/threequarters
+ \iow_newline:
+ 192/Agrave/Aacute/Acircumflex/Atilde/Adieresis/Aring/AE
+ /Ccedilla/Egrave/Eacute/Ecircumflex/Edieresis/Igrave
+ /Iacute/Icircumflex/Idieresis/Eth/Ntilde/Ograve/Oacute
+ /Ocircumflex/Otilde/Odieresis/multiply/Oslash/Ugrave
+ /Uacute/Ucircumflex/Udieresis/Yacute/Thorn/germandbls
+ /agrave/aacute/acircumflex/atilde/adieresis/aring/ae
+ /ccedilla/egrave/eacute/ecircumflex/edieresis/igrave
+ /iacute/icircumflex/idieresis/eth/ntilde/ograve/oacute
+ /ocircumflex/otilde/odieresis/divide/oslash/ugrave
+ /uacute/ucircumflex/udieresis/yacute/thorn/ydieresis
+ ]
+ }
+ \pdf_object_write:nn {l_@@_font_zapfdingbats_obj }
+ {
+ /Type/Font
+ /Subtype/Type1
+ /Name/ZaDb
+ /BaseFont/ZapfDingbats
+ }
+ \pdf_object_write:nx {l_@@_font_helvetica_obj }
+ {
+ /Type/Font
+ /Subtype/Type1
+ /Name/Helv
+ /BaseFont/Helvetica
+ /Encoding~\pdf_object_ref:n { l_@@_encoding_pdfdoc_obj }
+ }
+ \global\let\Hy@FormObjects\relax
+ }
+\ExplSyntaxOff
+\providecommand*{\Fld@pageobjref}{}
+\ifcsname pdf@escapestring\endcsname
+ \def\Hy@escapeform#1{%
+ \ifHy@pdfescapeform
+ \let\Hy@escapestring\pdfescapestring
+ \else
+ \let\Hy@escapestring\@firstofone
+ \fi
+ }%
+ \Hy@escapeform{}%
+\else
+ \let\Hy@escapestring\@firstofone
+ \def\Hy@escapeform#1{%
+ \ifHy@pdfescapeform
+ \def\Hy@escapestring##1{%
+ \noexpand\Hy@escapestring{\noexpand##1}%
+ }%
+ \edef\Hy@temp{#1}%
+ \expandafter\Hy@@escapeform\Hy@temp\Hy@escapestring{}\@nil
+ \def\Hy@escapestring##1{%
+ \@ifundefined{Hy@esc@\string##1}{%
+ ##1%
+ \ThisShouldNotHappen
+ }{%
+ \csname Hy@esc@\string##1\endcsname
+ }%
+ }%
+ \else
+ \let\Hy@escapestring\@firstofone
+ \fi
+ }%
+ \def\Hy@@escapeform#1\Hy@escapestring#2#3\@nil{%
+ \ifx\\#3\\%
+ \else
+ \expandafter
+ \Hy@pstringdef\csname Hy@esc@\string#2\endcsname{#2}% probably string-hex
+ \ltx@ReturnAfterFi{%
+ \Hy@@escapeform#3\@nil
+ }%
+ \fi
+ }%
+\fi
+\def\PDFForm@Name{%
+ \PDFForm@@Name\Fld@name
+ \ifx\Fld@altname\relax
+ \else
+ \PDFForm@@Name\Fld@altname
+ \fi
+ \ifx\Fld@mappingname\relax
+ \else
+ \PDFForm@@Name\Fld@mappingname
+ \fi
+}
+\def\PDFForm@@Name#1{%
+ \begingroup
+ \ifnum\Hy@pdfversion<5 % implementation note 117, PDF spec 1.7
+ \ifHy@unicode
+ \Hy@unicodefalse
+ \fi
+ \fi
+ \pdfstringdef\Hy@gtemp#1%
+ \endgroup
+ \let#1\Hy@gtemp
+}
+\def\Fld@X@additionalactions{%
+ \ifx\Fld@keystroke@code\@empty
+ \else
+ /K<</S/JavaScript/JS(\Hy@escapestring{\Fld@keystroke@code})>>%
+ \fi
+ \ifx\Fld@format@code\@empty
+ \else
+ /F<</S/JavaScript/JS(\Hy@escapestring{\Fld@format@code})>>%
+ \fi
+ \ifx\Fld@validate@code\@empty
+ \else
+ /V<</S/JavaScript/JS(\Hy@escapestring{\Fld@validate@code})>>%
+ \fi
+ \ifx\Fld@calculate@code\@empty
+ \else
+ /C<</S/JavaScript/JS(\Hy@escapestring{\Fld@calculate@code})>>%
+ \fi
+ \ifx\Fld@onfocus@code\@empty
+ \else
+ /Fo<</S/JavaScript/JS(\Hy@escapestring{\Fld@onfocus@code})>>%
+ \fi
+ \ifx\Fld@onblur@code\@empty
+ \else
+ /Bl<</S/JavaScript/JS(\Hy@escapestring{\Fld@onblur@code})>>%
+ \fi
+ \ifx\Fld@onmousedown@code\@empty
+ \else
+ /D<</S/JavaScript/JS(\Hy@escapestring{\Fld@onmousedown@code})>>%
+ \fi
+ \ifx\Fld@onmouseup@code\@empty
+ \else
+ /U<</S/JavaScript/JS(\Hy@escapestring{\Fld@onmouseup@code})>>%
+ \fi
+ \ifx\Fld@onenter@code\@empty
+ \else
+ /E<</S/JavaScript/JS(\Hy@escapestring{\Fld@onenter@code})>>%
+ \fi
+ \ifx\Fld@onexit@code\@empty
+ \else
+ /X<</S/JavaScript/JS(\Hy@escapestring{\Fld@onexit@code})>>%
+ \fi
+}
+\ExplSyntaxOn
+\def\Fld@additionalactions
+ {%
+ \exp_args:Ne\str_if_eq:nnF {\Fld@X@additionalactions}{}
+ {
+ \pdfmeta_standard_verify:nT {annot_widget_no_AA}
+ {/AA<<\Fld@X@additionalactions>>}
+ }
+ }
+\ExplSyntaxOff
+\def\Fld@annotnames{%
+ /T(\Fld@name)%
+ \ifx\Fld@altname\relax
+ \else
+ /TU(\Fld@altname)%
+ \fi
+ \ifx\Fld@mappingname\relax
+ \else
+ /TM(\Fld@mappingname)%
+ \fi
+}
+\ExplSyntaxOn
+\def\PDFForm@Check
+ {
+ /Subtype/Widget
+ ~\Fld@annotflags
+ ~\Fld@pageobjref
+ ~\Fld@annotnames
+ /FT/Btn
+ \Fld@flags
+ /Q~\Fld@align
+ /BS<</W~\Fld@borderwidth /S/\Fld@borderstyle>>
+ /AP
+ <<
+ /N
+ <<
+ /Yes~\pdfxform_ref:o{\l_@@_CheckmarkYes_tl}
+ /Off~\pdfxform_ref:o{\l_@@_CheckmarkOff_tl}
+ >>
+ >>
+ /MK<<
+ \int_compare:nNnF {\Fld@rotation}={0}
+ {
+ /R~\Fld@rotation
+ }
+ \tl_if_empty:NF\Fld@bordercolor
+ {
+ /BC[\Fld@bordercolor]
+ }
+ \tl_if_empty:NF\Fld@bcolor
+ {
+ /BG[\Fld@bcolor]
+ }
+ /CA(\Hy@escapestring{\Fld@cbsymbol})%
+ >>
+ /DA
+ (
+ /ZaDb~\strip@pt\Fld@charsize\c_space_tl Tf
+ \tl_if_empty:NF \Fld@color
+ {
+ \c_space_tl \Fld@color
+ }
+ )
+ /H/P
+ \legacy_if:nTF {Fld@checked}
+ {
+ /V/Yes /AS/Yes
+ }
+ {
+ /V/Off /AS/Off
+ }
+ \Fld@additionalactions
+}
+\ExplSyntaxOff
+\ExplSyntaxOn
+ \def\PDFForm@Push
+ {
+ /Subtype/Widget
+ ~\Fld@annotflags
+ ~\Fld@pageobjref
+ ~\Fld@annotnames
+ /FT/Btn
+ ~\Fld@flags
+ /H/P
+ /BS<</W~\Fld@borderwidth/S/\Fld@borderstyle>>
+ \bool_if:nT
+ {
+ !\int_compare_p:nNn {\Fld@rotation} = {0}
+ ||
+ \tl_if_exist_p:N \Fld@bordercolor
+ }
+ {
+ /MK
+ <<
+ \int_compare:nNnF {\Fld@rotation} = {0}
+ {
+ /R~\Fld@rotation
+ }
+ \tl_if_exist:NT \Fld@bordercolor
+ {
+ /BC[\Fld@bordercolor]
+ }
+ >>
+ }
+ /A<</S/JavaScript/JS(\Hy@escapestring{\Fld@onclick@code})>>
+ \Fld@additionalactions
+ }
+
+\ExplSyntaxOff
+\def\PDFForm@List{%
+ /Subtype/Widget%
+ \Fld@annotflags
+ \Fld@pageobjref
+ \Fld@annotnames
+ /FT/Ch%
+ \Fld@flags
+ /Q \Fld@align
+ /BS<</W \Fld@borderwidth/S/\Fld@borderstyle>>%
+ \ifcase0\ifnum\Fld@rotation=\z@ \else 1\fi
+ \ifx\Fld@bordercolor\relax\else 1\fi
+ \ifx\fld@bcolor\relax \else 1\fi
+ \space
+ \else
+ /MK<<%
+ \ifnum\Fld@rotation=\z@
+ \else
+ /R \Fld@rotation
+ \fi
+ \ifx\Fld@bordercolor\relax
+ \else
+ /BC[\Fld@bordercolor]%
+ \fi
+ \ifx\Fld@bcolor\relax
+ \else
+ /BG[\Fld@bcolor]%
+ \fi
+ >>%
+ \fi
+ /DA(/Helv \strip@pt\Fld@charsize\space Tf%
+ \ifx\Fld@color\@empty\else\space\Fld@color\fi)%
+ \Fld@choices
+ \Fld@additionalactions
+}
+\ExplSyntaxOn
+\def\PDFForm@Radio
+ {
+ /Subtype/Widget
+ ~\Fld@annotflags
+ ~\Fld@pageobjref
+ ~\Fld@annotnames
+ /FT/Btn
+ \Fld@flags
+ /H/P
+ /BS<</W~\Fld@borderwidth/S/\Fld@borderstyle>>
+ /MK<<
+ \ifnum\Fld@rotation=\z@
+ \else
+ /R~\Fld@rotation
+ \fi
+ \ifx\Fld@bordercolor\relax
+ \else
+ /BC[\Fld@bordercolor]%
+ \fi
+ \ifx\Fld@bcolor\relax
+ \else
+ /BG[\Fld@bcolor]%
+ \fi
+ /CA(\Hy@escapestring{\Fld@radiosymbol})%
+ >>
+ /DA(/ZaDb~\strip@pt\Fld@charsize\space Tf%
+ \ifx\Fld@color\@empty\else\space\Fld@color\fi)%
+ \ifx\Fld@default\@empty
+ /V/Off%
+ /DV/Off%
+ \else
+ /V/\Fld@default
+ /DV/\Fld@default
+ \fi
+ \Fld@additionalactions
+ }
+\ExplSyntaxOff
+\ExplSyntaxOn
+% Does an appeareance dict make sense here?
+\def\PDFForm@Text
+ {
+ /Subtype/Widget
+ ~\Fld@annotflags
+ ~\Fld@pageobjref
+ ~\Fld@annotnames
+ /FT/Tx
+ ~\Fld@flags
+ /Q~\Fld@align
+ /BS<</W~\Fld@borderwidth\c_space_tl /S /\Fld@borderstyle>>
+ \bool_if:nT
+ {
+ !\int_compare_p:nNn {\Fld@rotation} = {0}
+ ||
+ \tl_if_exist_p:N \Fld@bordercolor
+ ||
+ \tl_if_exist_p:N \Fld@bcolor
+ }
+ {
+ /MK
+ <<
+ \int_compare:nNnF {\Fld@rotation} = {0}
+ {
+ /R~\Fld@rotation
+ }
+ \tl_if_exist:NT \Fld@bordercolor
+ {
+ /BC[\Fld@bordercolor]
+ }
+ \tl_if_exist:NT \Fld@bcolor
+ {
+ /BG[\Fld@bcolor]
+ }
+ >>
+ }
+ /DA
+ (
+ /Helv~\strip@pt\Fld@charsize\c_space_tl Tf
+ \tl_if_empty:NF {\c_space_tl\Fld@color}
+ )
+ /DV(\Hy@escapestring{\Fld@default})
+ /V(\Hy@escapestring{\Fld@value})
+ ~\Fld@additionalactions
+ \int_compare:nNnT { \Fld@maxlen}>{0}
+ {
+ /MaxLen~\Fld@maxlen
+ }
+ }
+\ExplSyntaxOff
+
+\def\PDFForm@Submit{%
+ /Subtype/Widget%
+ \Fld@annotflags
+ \Fld@pageobjref
+ \Fld@annotnames
+ /FT/Btn%
+ \Fld@flags
+ /H/P%
+ /BS<</W \Fld@borderwidth/S/\Fld@borderstyle>>%
+ \ifcase0\ifnum\Fld@rotation=\z@ \else 1\fi
+ \ifx\Fld@bordercolor\relax\else 1\fi
+ \space
+ \else
+ /MK<<%
+ \ifnum\Fld@rotation=\z@
+ \else
+ /R \Fld@rotation
+ \fi
+ \ifx\Fld@bordercolor\relax
+ \else
+ /BC[\Fld@bordercolor]%
+ \fi
+ >>%
+ \fi
+ /A<<%
+ /S/SubmitForm%
+ /F<<%
+ /FS/URL%
+ /F(\Hy@escapestring{\Form@action})%
+ >>%
+ \Fld@submitflags
+ >>%
+ \Fld@additionalactions
+}
+\ExplSyntaxOn
+ \def\PDFForm@Reset{%
+ /Subtype/Widget%
+ \Fld@annotflags
+ \Fld@pageobjref
+ \Fld@annotnames
+ /FT/Btn%
+ \Fld@flags
+ /H/P%
+ /DA(/Helv~\strip@pt\Fld@charsize\space Tf~0~0~1~rg)%
+ \ifcase0\ifnum\Fld@rotation=\z@ \else 1\fi
+ \ifx\Fld@bordercolor\relax\else 1\fi
+ \space
+ \else
+ /MK<<%
+ \ifnum\Fld@rotation=\z@
+ \else
+ /R~\Fld@rotation
+ \fi
+ \ifx\Fld@bordercolor\relax
+ \else
+ /BC[\Fld@bordercolor]%
+ \fi
+ >>%
+ \fi
+ /BS<</W \Fld@borderwidth/S/\Fld@borderstyle>>%
+ /A<</S/ResetForm>>%
+ \Fld@additionalactions
+ }%
+
+
+ %these patterns are used in hyperref checks.
+%it is unclear if they are really useful and if a backend support is
+%needed.
+\str_case:VnF \c_sys_backend_str
+ {
+ { pdfmode }
+ {
+ \def\HyPat@ObjRef
+ {
+ [0-9]*[1-9][0-9]*~0~R
+ }
+ }
+ { dvipdfmx }
+ {
+ \def\HyPat@ObjRef
+ {
+ @[^~]+
+ }
+ }
+ { xdvipdfmx }
+ {
+ \def\HyPat@ObjRef
+ {
+ @[^~]+
+ }
+ }
+ }
+ { %also set in hyperref sty, so probably not needed.
+ \def\HyPat@ObjRef/{.+}
+ }
+
+
+\ExplSyntaxOff
+% UF: removed Hy@writebookmark
+% \Hy@currentbookmarklevel{0}
+% \Hy@numberline
+% \@@writetorep
+% counter{bookmark@seq@number}
+% removed \HyPsd@SanitizeForOutFile, not needed
+% removed \currentpdfbookmark, defined by bookmark,
+% should use \newcommand there
+% removed \subpdfbookmark, defined by bookmark,
+% should use \newcommand there
+% removed \belowpdfbookmark, defined by bookmark,
+% should use \newcommand there
+% removed \pdfbookmark, defined by bookmark,
+% \BOOKMARK
+% \@BOOKMARK
+%% \RequirePackage{rerunfilecheck}[2009/12/10]
+%% removed \Hy@OutlineRerunCheck, unneeded with bookmark
+%% removed \ReadBookmarks / unneeded with bookmark.
+%% removed \Hy@OutlineName
+%% removed \check@bm@number
+%% removed \calc@bm@number
+
+\ifHy@implicit
+\else
+ \expandafter\endinput
+\fi
+\newlength\Hy@SectionHShift
+\def\Hy@SectionAnchorHref#1{%
+ \ifx\protect\@typeset@protect
+ \Hy@@SectionAnchor{#1}%
+ \fi
+}
+\DeclareRobustCommand*{\Hy@@SectionAnchor}[1]{%
+ \leavevmode
+ \hbox to 0pt{%
+ \kern-\Hy@SectionHShift
+ \Hy@raisedlink{%
+ \hyper@anchorstart{#1}\hyper@anchorend
+ }%
+ \hss
+ }%
+}
+\let\H@old@ssect\@ssect
+\def\@ssect#1#2#3#4#5{%
+ \Hy@MakeCurrentHrefAuto{section*}%
+ \setlength{\Hy@SectionHShift}{#1}%
+ \begingroup
+ \toks@{\H@old@ssect{#1}{#2}{#3}{#4}}%
+ \toks\tw@\expandafter{%
+ \expandafter\Hy@SectionAnchorHref\expandafter{\@currentHref}%
+ #5%
+ }%
+ \edef\x{\endgroup
+ \the\toks@{\the\toks\tw@}%
+ }\x
+}
+\let\H@old@schapter\@schapter
+\def\@schapter#1{%
+ \begingroup
+ \let\@mkboth\@gobbletwo
+ \Hy@MakeCurrentHrefAuto{\Hy@chapapp*}%
+ \Hy@raisedlink{%
+ \hyper@anchorstart{\@currentHref}\hyper@anchorend
+ }%
+ \endgroup
+ \H@old@schapter{#1}%
+}
+\ltx@IfUndefined{@chapter}{}{%
+ \let\Hy@org@chapter\@chapter
+ \def\@chapter{%
+ \def\Hy@next{%
+ \Hy@MakeCurrentHrefAuto{\Hy@chapapp*}%
+ \Hy@raisedlink{%
+ \hyper@anchorstart{\@currentHref}\hyper@anchorend
+ }%
+ }%
+ \ifnum\c@secnumdepth>\m@ne
+ \ltx@IfUndefined{if@mainmatter}%
+ \iftrue{\csname if@mainmatter\endcsname}%
+ \let\Hy@next\relax
+ \fi
+ \fi
+ \Hy@next
+ \Hy@org@chapter
+ }%
+}
+\let\H@old@part\@part
+\begingroup\expandafter\expandafter\expandafter\endgroup
+\expandafter\ifx\csname chapter\endcsname\relax
+ \let\Hy@secnum@part\z@
+\else
+ \let\Hy@secnum@part\m@ne
+\fi
+\def\@part{%
+ \ifnum\Hy@secnum@part>\c@secnumdepth
+ \phantomsection
+ \fi
+ \H@old@part
+}
+\let\H@old@spart\@spart
+\def\@spart#1{%
+ \Hy@MakeCurrentHrefAuto{part*}%
+ \Hy@raisedlink{%
+ \hyper@anchorstart{\@currentHref}\hyper@anchorend
+ }%
+ \H@old@spart{#1}%
+}
+\let\H@old@sect\@sect
+\def\@sect#1#2#3#4#5#6[#7]#8{%
+ \ifnum #2>\c@secnumdepth
+ \expandafter\@firstoftwo
+ \else
+ \expandafter\@secondoftwo
+ \fi
+ {%
+ \Hy@MakeCurrentHrefAuto{section*}%
+ \setlength{\Hy@SectionHShift}{#3}%
+ \begingroup
+ \toks@{\H@old@sect{#1}{#2}{#3}{#4}{#5}{#6}[{#7}]}%
+ \toks\tw@\expandafter{%
+ \expandafter\Hy@SectionAnchorHref\expandafter{\@currentHref}%
+ #8%
+ }%
+ \edef\x{\endgroup
+ \the\toks@{\the\toks\tw@}%
+ }\x
+ }{%
+ \H@old@sect{#1}{#2}{#3}{#4}{#5}{#6}[{#7}]{#8}%
+ }%
+}
+\expandafter\def\csname Parent-4\endcsname{}
+\expandafter\def\csname Parent-3\endcsname{}
+\expandafter\def\csname Parent-2\endcsname{}
+\expandafter\def\csname Parent-1\endcsname{}
+\expandafter\def\csname Parent0\endcsname{}
+\expandafter\def\csname Parent1\endcsname{}
+\expandafter\def\csname Parent2\endcsname{}
+\expandafter\def\csname Parent3\endcsname{}
+\expandafter\def\csname Parent4\endcsname{}
+%%
+%% End of file `hgeneric-testphase.def'.
+%</package>
+% \end{macrocode}
+% \begin{macrocode}
+%<*colorscheme>
+% collected from https://tex.stackexchange.com/questions/525261/better-default-colors-for-hyperref-links
+% cite color ignored, as it doesn't fit ... should be done by cite packages ?
+% linkcolor=
+%,filecolor=
+%,urlcolor=
+%,menucolor=
+%,runcolor=
+%,linkbordercolor=
+%,filebordercolor=
+%,urlbordercolor=
+%,menubordercolor=
+%,runbordercolor=
+
+\prop_const_from_keyval:Nn \c_@@_colorscheme_original_prop
+ {
+ linkcolor = [rgb]{1,0,0}, %red
+ filecolor = [rgb]{0,1,1}, %cyan
+ urlcolor = [rgb]{1,0,1}, %magenta
+ menucolor = [rgb]{1, 0, 0}, %red
+ runcolor = [rgb]{0,1,1}, %cyan
+ %-------------
+ linkbordercolor = [rgb]{1, 0 ,0 },
+ filebordercolor = [rgb]{0, .5, .5},
+ urlbordercolor = [rgb]{0, 1, 1},
+ menubordercolor = [rgb]{1, 0, 0},
+ runbordercolor = [rgb]{0, .7, .7}
+ }
+
+\prop_const_from_keyval:Nn \c_@@_colorscheme_daleif_prop
+ {
+ linkcolor = [rgb]{0,0.2,0.6},
+ filecolor = [rgb]{0.8,0,0.8},
+ urlcolor = [rgb]{0.8,0,0.8},
+ menucolor = [rgb]{0,0.2,0.6},
+ runcolor = [rgb]{0.8,0,0.8},
+ %------------- %--------
+ linkbordercolor = [rgb]{0,0.2,0.6},
+ filebordercolor = [rgb]{0.8,0,0.8},
+ urlbordercolor = [rgb]{0.8,0,0.8},
+ menubordercolor = [rgb]{0,0.2,0.6},
+ runbordercolor = [rgb]{0.8,0,0.8}
+ }
+
+\prop_const_from_keyval:Nn \c_@@_colorscheme_julian_prop
+ { %two colors: intern/extern
+ linkcolor = [rgb]{0.79216, 0, 0.12549},
+ filecolor = [rgb]{0.01961, 0.44314, 0.6902},
+ urlcolor = [rgb]{0.01961, 0.44314, 0.6902},
+ menucolor = [rgb]{0.79216, 0, 0.12549 },
+ runcolor = [rgb]{0.01961, 0.44314, 0.6902 },
+ %------------- %--------
+ linkbordercolor = [rgb]{0.79216, 0, 0.12549},
+ filebordercolor = [rgb]{0.01961, 0.44314, 0.6902},
+ urlbordercolor = [rgb]{0.01961, 0.44314, 0.6902},
+ menubordercolor = [rgb]{0.79216, 0, 0.12549 },
+ runbordercolor = [rgb]{0.01961, 0.44314, 0.6902 }
+ }
+
+\prop_const_from_keyval:Nn \c_@@_colorscheme_tivv_prop
+ { %all darkgray
+ linkcolor = [rgb]{0.4 ,0.4 ,0.4 },
+ filecolor = [rgb]{0.4 ,0.4 ,0.4 },
+ urlcolor = [rgb]{0.4 ,0.4 ,0.4 },
+ menucolor = [rgb]{0.4 ,0.4 ,0.4 },
+ runcolor = [rgb]{0.4 ,0.4 ,0.4 },
+ %------------- %--------
+ linkbordercolor = [rgb]{0.4 ,0.4 ,0.4 },
+ filebordercolor = [rgb]{0.4 ,0.4 ,0.4 },
+ urlbordercolor = [rgb]{0.4 ,0.4 ,0.4 },
+ menubordercolor = [rgb]{0.4 ,0.4 ,0.4 },
+ runbordercolor = [rgb]{0.4 ,0.4 ,0.4 }
+ }
+
+\prop_const_from_keyval:Nn \c_@@_colorscheme_szabolcsA_prop
+ { %dvipsnam.def
+ linkcolor = [rgb]{0.06, 0.46, 1}, %NavyBlue
+ filecolor = [rgb]{1, 0, 0}, %Red
+ urlcolor = [rgb]{0.06, 0.46, 1}, %NavyBlue
+ menucolor = [rgb]{1, 0, 0}, %Red
+ runcolor = [rgb]{1, 0, 0}, %Red
+ %------------- %------------------
+ linkbordercolor = [rgb]{0.06, 0.46, 1}, %NavyBlue
+ filebordercolor = [rgb]{1, 0, 0}, %Red
+ urlbordercolor = [rgb]{0.06, 0.46, 1}, %NavyBlue
+ menubordercolor = [rgb]{1, 0, 0}, %Red
+ runbordercolor = [rgb]{1, 0, 0} %Red
+ }
+
+\prop_const_from_keyval:Nn \c_@@_colorscheme_szabolcsB_prop
+ { %dvipsnam.def
+ linkcolor = [rgb]{0.72, 0, 0}, %BrickRed
+ filecolor = [rgb]{0, 1, 0}, %Green
+ urlcolor = [rgb]{0.64, 0.08, 0.98}, %Mulberry
+ menucolor = [rgb]{0.06, 0.46, 1}, %NavyBlue
+ runcolor = [rgb]{0.64, 0.08, 0.98}, %Mulberry
+ %------------- %------------------
+ linkbordercolor = [rgb]{0.72, 0, 0}, %BrickRed
+ filebordercolor = [rgb]{0, 1, 0}, %Green
+ urlbordercolor = [rgb]{0.64, 0.08, 0.98}, %Mulberry
+ menubordercolor = [rgb]{0.06, 0.46, 1}, %NavyBlue
+ runbordercolor = [rgb]{0.64, 0.08, 0.98} %Mulberry
+ }
+
+
+\prop_const_from_keyval:Nn \c_@@_colorscheme_phelype_prop
+ {
+ linkcolor = [rgb]{0.50196, 0, 0.02353},
+ filecolor = [rgb]{0.07451, 0.09412, 0.46667},
+ urlcolor = [rgb]{0.54118, 0, 0.52941},
+ menucolor = [rgb]{0.44706, 0.45882, 0},
+ runcolor = [rgb]{0.07451, 0.46667, 0.46275},
+ %------------- %-------------
+ linkbordercolor = [rgb]{0.701176, 0.4, 0.414118},
+ filebordercolor = [rgb]{0.444706, 0.456472, 0.680002},
+ urlbordercolor = [rgb]{0.724708, 0.4, 0.717646},
+ menubordercolor = [rgb]{0.668236, 0.675292, 0.4},
+ runbordercolor = [rgb]{0.444706, 0.680002, 0.67765}
+ }
+
+\prop_const_from_keyval:Nn \c_@@_colorscheme_henryford_prop
+ {
+ linkcolor = [rgb]{0,0,0},
+ filecolor = [rgb]{0,0,0},
+ urlcolor = [rgb]{0,0,0},
+ menucolor = [rgb]{0,0,0},
+ runcolor = [rgb]{0,0,0},
+ %------------- %--------
+ linkbordercolor = [rgb]{0,0,0},
+ filebordercolor = [rgb]{0,0,0},
+ urlbordercolor = [rgb]{0,0,0},
+ menubordercolor = [rgb]{0,0,0},
+ runbordercolor = [rgb]{0,0,0}
+ }
+%</colorscheme>
+% \end{macrocode}
+% \end{implementation}
+% \newpage
+% \PrintIndex
diff --git a/Master/texmf-dist/source/latex/pdfmanagement-testphase/l3backend-testphase.dtx b/Master/texmf-dist/source/latex/pdfmanagement-testphase/l3backend-testphase.dtx
new file mode 100644
index 00000000000..ffa7fd0b633
--- /dev/null
+++ b/Master/texmf-dist/source/latex/pdfmanagement-testphase/l3backend-testphase.dtx
@@ -0,0 +1,1598 @@
+% \iffalse meta-comment
+%
+%% File: l3backend-testphase.dtx
+%
+% Copyright (C) 2019-2021 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
+%
+% This file is part of the "LaTeX PDF management testphase 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/pdfresources
+%
+% for those people who are interested.
+%
+%
+%<*driver>
+\documentclass[full,kernel]{l3doc}
+\begin{document}
+ \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
+% \fi
+%
+% \title{^^A
+% The \textsf{l3backend-testphase} package\\ Additional backend PDF features^^A
+% \\ \LaTeX{} PDF management testphase bundle
+% }
+%
+% \author{^^A
+% The \LaTeX{} Project\thanks
+% {^^A
+% E-mail:
+% \href{mailto:latex-team@latex-project.org}
+% {latex-team@latex-project.org}^^A
+% }^^A
+% }
+%
+% \date{Version 0.95a, released 2021-02-22}
+%
+% \maketitle
+%
+%
+% \begin{implementation}
+%
+% \section{\pkg{l3backend-testphase} Implementation}
+% \begin{macrocode}
+%<drivers>\ProvidesExplFile
+%<*dvipdfmx>
+ {l3backend-testphase-dvipdfmx.def}{2021-02-22}{}
+ {LaTeX~PDF~management~testphase~bundle~backend~support: dvipdfmx}
+%</dvipdfmx>
+%<*dvips>
+ {l3backend-testphase-dvips.def}{2021-02-22}{}
+ {LaTeX~PDF~management~testphase~bundle~backend~support: dvips}
+%</dvips>
+%<*dvisvgm>
+ {l3backend-testphase-dvisvgm.def}{2021-02-22}{}
+ {LaTeX~PDF~management~testphase~bundle~backend~support: dvisvgm}
+%</dvisvgm>
+%<*luatex>
+ {l3backend-testphase-luatex.def}{2021-02-22}{}
+ {LaTeX~PDF~management~testphase~bundle~backend~support: PDF output (LuaTeX)}
+%</luatex>
+%<*pdftex>
+ {l3backend-testphase-pdftex.def}{2021-02-22}{}
+ {LaTeX~PDF~management~testphase~bundle~backend~support: PDF output (pdfTeX)}
+%</pdftex>
+%<*xdvipdfmx>
+ {l3backend-testphase-xetex.def}{2021-02-22}{}
+ {LaTeX~PDF~management~testphase~bundle~backend~support: XeTeX}
+%</xdvipdfmx>
+% \end{macrocode}
+% \subsection{Crossreferences}
+% This uses the temporary l3ref-tmp.sty. It will
+% will be replaced by kernel code later.
+% It is only need to get a reference for the absolute page counter.
+% This uses the counter from the
+% new lthooks/ltshipout package.
+% \begin{macrocode}
+%<@@=pdf>
+%<*drivers>
+\RequirePackage{l3ref-tmp}
+\cs_generate_variant:Nn \ref_label:nn {en}
+\cs_generate_variant:Nn \ref_value:nn {en}
+\cs_new_protected:Npn \@@_backend_ref_label:nn #1 #2
+ {
+ \@bsphack
+ \ref_label:nn{#1}{abspage}
+ \@esphack
+ }
+\cs_new:Npn \@@_backend_ref_value:nn #1 #2
+ {
+ \ref_value:nn{#1}{#2}
+ }
+\cs_generate_variant:Nn \@@_backend_ref_label:nn {en}
+\cs_generate_variant:Nn \@@_backend_ref_value:nn {en}
+%</drivers>
+% \end{macrocode}
+% \begin{macrocode}
+%<*dvipdfmx|xdvipdfmx>
+% avoid that destinations names are optimized.
+% is this still needed??
+% see https://tug.org/pipermail/dvipdfmx/2019-May/000002.html
+ \__kernel_backend_literal:x { dvipdfmx:config~C~ 0x0010 }
+%</dvipdfmx|xdvipdfmx>
+% \end{macrocode}
+% \begin{variable}{\g_@@_tmpa_prop, \l_@@_tmpa_tl, \l_@@_backend_tmpa_box }
+% Some scratch variables
+% \begin{macrocode}
+%<*drivers>
+\prop_new:N \g_@@_tmpa_prop
+\tl_new:N \l_@@_tmpa_tl
+\box_new:N \l_@@_backend_tmpa_box
+%</drivers>
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}
+% {\g_@@_backend_resourceid_int, \g_@@_backend_name_int, \g_@@_backend_page_int}
+% a counter to create labels for the resources, a counter
+% to number properties in bdc marks, a counter for the \cs{pdfpageref} implementation.
+% \begin{macrocode}
+%<*drivers>
+\int_new:N \g_@@_backend_resourceid_int
+\int_new:N \g_@@_backend_name_int
+\int_new:N \g_@@_backend_page_int
+%</drivers>
+% \end{macrocode}
+% \end{variable}
+% \subsection{luacode}
+% Load the lua code.
+% \begin{macrocode}
+%<*luatex>
+ \directlua { require("l3backend-testphase.lua") }
+%</luatex>
+% \end{macrocode}
+% \subsection{Hooks}
+% \subsubsection{Add the \enquote{end run} hooks}
+% Here we add the end run hook to suitable
+% end hooks.
+% \begin{macrocode}
+%<*pdftex|luatex>
+% put in \@kernel@after@enddocument@afterlastpage
+\tl_gput_right:Nn \@kernel@after@enddocument@afterlastpage
+ {
+ \g__kernel_pdfmanagement_end_run_code_tl
+ }
+%</pdftex|luatex>
+%<*dvipdfmx|xdvipdfmx>
+% put in \@kernel@after@shipout@lastpage
+\tl_gput_right:Nn \@kernel@after@shipout@lastpage
+ {
+ \g__kernel_pdfmanagement_end_run_code_tl
+ }
+%</dvipdfmx|xdvipdfmx>
+%<*dvips>
+% put in \@kernel@after@shipout@lastpage
+\tl_gput_right:Nn\@kernel@after@shipout@lastpage
+ {
+ \g__kernel_pdfmanagement_end_run_code_tl
+ }
+%</dvips>
+% \end{macrocode}
+% \subsubsection{Add the \enquote{shipout} hooks}
+% Now we add to the shipout hooks the relevant token lists.
+% We also push the page resources in shipout/firstpage (AtBeginDvi)
+% as the backend code sets color stack there. The xetex driver needs a rule here.
+% If it clashes on the first page, we will need a test ...
+% \begin{macrocode}
+%<*drivers>
+\tl_if_exist:NTF \@kernel@after@shipout@background
+ {
+ \g@addto@macro \@kernel@before@shipout@background{\relax}
+ \g@addto@macro \@kernel@after@shipout@background
+ {
+ \g__kernel_pdfmanagement_thispage_shipout_code_tl
+ }
+ \tl_gput_left:Nn\@kernel@after@shipout@lastpage
+ {
+ \g__kernel_pdfmanagement_lastpage_shipout_code_tl
+ }
+ }
+ {
+ \hook_gput_code:nnn{shipout/background}{pdf}
+ {
+ \g__kernel_pdfmanagement_thispage_shipout_code_tl
+ }
+ \hook_gput_code:nnn {shipout/lastpage} {pdf}
+ {
+ \g__kernel_pdfmanagement_lastpage_shipout_code_tl
+ }
+ }
+
+%</drivers>
+% \end{macrocode}
+% \subsection{ The /Pages dictionary (pdfpagesattr) }
+% \begin{NOTE}{UF}
+% path: Pages
+% pdfpagesattr is a single token register which is used at the end of the compilation.
+% dvips syntax: \verb+\special{ps: [/ABC /CDE /EFG /FGH /Rotate 90 /PAGES pdfmark}+
+% dvipdfmx syntax: \verb+\special{pdf:put @pages <</ABC /WEZ /EFG /XYZ /Rotate 0>>}+
+% both remove duplicate entries automatically, so there is no need to be careful.
+% \end{NOTE}
+% \begin{macro}{\@@_backend_Pages_primitive:n}
+% This is the primitive command to add something to the /Pages dictionary.
+% It works differently for the backends: pdftex and luatex overwrite existing
+% content, dvips and dvipdfmx are additive. luatex sets it in lua.
+% The higher level code has to take this into account.
+% \begin{macrocode}
+%<*pdftex>
+\cs_new_protected:Npn \@@_backend_Pages_primitive:n #1
+ {
+ \tex_global:D \tex_pdfpagesattr:D { #1 }
+ }
+%</pdftex>
+%<*luatex>
+%luatex: does it in lua
+\sys_if_engine_luatex:T
+ {
+ \cs_new_protected:Npn \@@_backend_Pages_primitive:n #1
+ {
+ \tex_directlua:D
+ {
+ pdf.setpagesattributes( \@@_backend_luastring:n { #1 } )
+ }
+ }
+ }
+%</luatex>
+%<*dvips>
+\cs_new_protected:Npx \@@_backend_Pages_primitive:n #1
+ {
+ \tex_special:D{ps:~[#1~/PAGES~pdfmark} %]
+ }
+%</dvips>
+%<*dvipdfmx|xdvipdfmx>
+\cs_new_protected:Npn \@@_backend_Pages_primitive:n #1
+ {
+ \@@_backend:n{put~@pages~<<#1>>}
+ }
+%</dvipdfmx|xdvipdfmx>
+%<*dvisvgm>
+\cs_new_protected:Npn \@@_backend_Pages_primitive:n #1
+ {}
+%</dvisvgm>
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{\enquote{Page} and \enquote{ThisPage} attributes (pdfpageattr)}
+% \begin{NOTE}{UF}
+% path: Page
+% !!!!!!!!!!!!!!!!!!!!!!
+% This part of the code depends on zref/xref as it sets labels.
+% It also depends on code in l3pdfmanagement as the code uses the Core-dictionaries
+% !!!!!!!!!!!!!!!!!!!!!!
+%
+% The engines differ a lot here: pdflatex and lualatex uses a register while with
+% dvips/dvipdfmx a one-shot-special is used. So for pdflatex and lualatex code
+% to assemble the content of the register is needed. Specials are used at shipout,
+% the registers is set directly. With lualatex one can use
+% \cs{latelua} to delay the setting, with pdflatex one has to use a shipout hook.
+% To get the code on the correct page one has to use the aux with pdflatex.
+% In sum this means that quite a lot backend commands are needed to handle
+% this differences. Simply variants of \cs{pdfpageattr} are not enough ...%
+% dvips syntax: \special{ps: [{ThisPage}<</Rotate 90>> /PUT pdfmark}%
+% There seem to be an in-built management code: multiple uses don't lead to
+% multiple entries (/Rotate is special: there is always a /Rotate 0 in the dict,
+% but seems not to do harm).
+% dvipdfmx syntax: \special{pdf: put @thispage << /Rotate 90 >>},
+% like dvips the backend has an in-built management code.
+% Both change only the current page, so to get the pdftex behavior (which sets
+% also the following pages) one need to repeat it on every shipout.
+% \end{NOTE}
+% \begin{macro}
+% {
+% \@@_backend_Page_primitive:n,
+% \@@_backend_Page_gput:nn,
+% \@@_backend_Page_gremove:n,
+% \@@_backend_ThisPage_gput:nn,
+% \@@_backend_ThisPage_gpush:n
+% }
+% \cs{@@_backend_Page_primitive:n} is the primitive command to add
+% something to the /Page dictionary.
+% It works differently for the backends: pdftex and luatex overwrite existing
+% content, dvips and dvipdfmx are additive. luatex sets it in lua.
+% The higher level code has to take this into account.
+% \cs{@@_backend_Page_gput:nn} stores default values.
+% \cs{@@_backend_Page_gremove:n} allows to remove a value.
+% \cs{@@_backend_ThisPage_gput:nn} adds a value to the current page.
+% \cs{@@_backend_ThisPage_gpush:n} merges the default and the current page values
+% and add them to the dictionary of the current page in
+% \cs{g_@@_backend_thispage_shipout_tl}.
+% \begin{macrocode}
+% backend commands
+%<*pdftex>
+ %the primitive
+ \cs_new_protected:Npn \@@_backend_Page_primitive:n #1
+ {
+ \tex_global:D \tex_pdfpageattr:D { #1 }
+ }
+% the command to store default values.
+% Uses a prop with pdflatex + dvi,
+% sets a lua table with lualatex
+ \cs_new_protected:Npn \@@_backend_Page_gput:nn #1 #2 %key,value
+ {
+ \pdfdict_gput:nnn {g_@@_Core/Page}{ #1 }{ #2 }
+ }
+% the command to remove a default value.
+% Uses a prop with pdflatex + dvi,
+% changes a lua table with lualatex
+\cs_new_protected:Npn \@@_backend_Page_gremove:n #1
+ {
+ \pdfdict_gremove:nn {g_@@_Core/Page}{ #1 }
+ }
+% the command used in the document.
+% direct call of the primitive special with dvips/dvipdfmx
+% \latelua: fill a page related table with lualatex, merge it with the page
+% table and push it directly
+% write to aux and store in prop with pdflatex
+\cs_new_protected:Npn \@@_backend_ThisPage_gput:nn #1 #2
+ {
+ %we need to know the page the resource should be added too.
+ \int_gincr:N\g_@@_backend_resourceid_int
+ %\zref@labelbylist {l3pdf\int_use:N\g_@@_backend_resourceid_int} {l3pdf}
+ %\ref_label:en{l3pdf\int_use:N\g_@@_backend_resourceid_int}{abspage}
+ \@@_backend_ref_label:en { l3pdf\int_use:N\g_@@_backend_resourceid_int }{abspage}
+ \tl_set:Nx \l_@@_tmpa_tl
+ {
+ %\zref@extractdefault
+% {l3pdf\int_use:N\g_@@_backend_resourceid_int}
+% {pdf@abspage}
+% {0}
+% \ref_value:en{l3pdf\int_use:N\g_@@_backend_resourceid_int}{abspage}
+ \@@_backend_ref_value:en {l3pdf\int_use:N\g_@@_backend_resourceid_int}{abspage}
+ }
+ \pdfdict_if_exist:nF { g_@@_Core/backend_Page\l_@@_tmpa_tl}
+ {
+ \pdfdict_new:n { g_@@_Core/backend_Page\l_@@_tmpa_tl}
+ }
+ %backend_Page has no handler.
+ \pdfdict_gput:nnn {g_@@_Core/backend_Page\l_@@_tmpa_tl}{ #1 }{ #2 }
+ }
+%the code to push the values, used in shipout
+%merges the two props and then fills the register in pdflatex
+%merges the two tables and then fills (in lua) in luatex
+%issues the values stored in the global prop with dvi
+\cs_new_protected:Npn \@@_backend_ThisPage_gpush:n #1
+ {
+ \prop_gset_eq:Nc \g_@@_tmpa_prop { \__kernel_pdfdict_name:n { g_@@_Core/Page } }
+ \prop_if_exist:cT { \__kernel_pdfdict_name:n { g_@@_Core/backend_Page#1 } }
+ {
+ \prop_map_inline:cn { \__kernel_pdfdict_name:n { g_@@_Core/backend_Page#1 } }
+ {
+ \prop_gput:Nnn \g_@@_tmpa_prop { ##1 }{ ##2 }
+ }
+ }
+ \exp_args:Nx \@@_backend_Page_primitive:n
+ {
+ \prop_map_function:NN \g_@@_tmpa_prop \pdfdict_item:ne
+ }
+ }
+%</pdftex>
+%<*luatex>
+% do we need to use some escaping for the values?????
+\cs_new:Npn \@@_backend_luastring:n #1
+ {
+ "\tex_luaescapestring:D { \tex_unexpanded:D { #1 } }"
+ }
+ %not used, only there for consistency
+\cs_new_protected:Npn \@@_backend_Page_primitive:n #1
+ {
+ \tex_latelua:D
+ {
+ pdf.setpageattributes(\@@_backend_luastring:n { #1 })
+ }
+ }
+ % the command to store default values.
+ % Uses a prop with pdflatex + dvi,
+ % sets a lua table with lualatex
+\cs_new_protected:Npn \@@_backend_Page_gput:nn #1 #2
+ {
+ \tex_directlua:D
+ {
+ ltx.@@.backend_Page_gput
+ (
+ \@@_backend_luastring:n { #1 },
+ \@@_backend_luastring:n { #2 }
+ )
+ }
+ }
+ % the command to remove a default value.
+ % Uses a prop with pdflatex + dvi,
+ % changes a lua table with lualatex
+\cs_new_protected:Npn \@@_backend_Page_gremove:n #1
+ {
+ \tex_directlua:D
+ {
+ ltx.@@.backend_Page_gremove (\@@_backend_luastring:n { #1 })
+ }
+ }
+ % the command used in the document.
+ % direct call of the primitive special with dvips/dvipdfmx
+ % \latelua: fill a page related table with lualatex, merge it with the page
+ % table and push it directly
+ % write to aux and store in prop with pdflatex
+\cs_new_protected:Npn \@@_backend_ThisPage_gput:nn #1 #2
+ {
+ \tex_latelua:D
+ {
+ ltx.@@.backend_ThisPage_gput
+ (
+ tex.count["g_shipout_readonly_int"],
+ \@@_backend_luastring:n { #1 },
+ \@@_backend_luastring:n { #2 }
+ )
+ ltx.@@.backend_ThisPage_gpush (tex.count["g_shipout_readonly_int"])
+ }
+ }
+ %the code to push the values, used in shipout
+ %merges the two props and then fills the register in pdflatex
+ %merges the two tables (the one is probably still empty) and then fills (in lua) in luatex
+ %issues the values stored in the global prop with dvi
+\cs_new_protected:Npn \@@_backend_ThisPage_gpush:n #1
+ {
+ \tex_latelua:D
+ {
+ ltx.@@.backend_ThisPage_gpush (tex.count["g_shipout_readonly_int"])
+ }
+ }
+
+%</luatex>
+%<*dvipdfmx|xdvipdfmx>
+ %the primitive
+\cs_new_protected:Npn \@@_backend_Page_primitive:n #1
+ {
+ \tex_special:D{pdf:~put~@thispage~<<#1>>}
+ }
+ % the command to store default values.
+ % Uses a prop with pdflatex + dvi,
+ % sets a lua table with lualatex
+\cs_new_protected:Npn \@@_backend_Page_gput:nn #1 #2
+ {
+ \pdfdict_gput:nnn {g_@@_Core/Page}{ #1 }{ #2 }
+ }
+ % the command to remove a default value.
+ % Uses a prop with pdflatex + dvi,
+ % changes a lua table with lualatex
+\cs_new_protected:Npn \@@_backend_Page_gremove:n #1
+ {
+ \pdfdict_gremove:nn {g_@@_Core/Page}{ #1 }
+ }
+ % the command used in the document.
+ % direct call of the primitive special with dvips/dvipdfmx
+ % \latelua: fill a page related table with lualatex, merge it with the page
+ % table and push it directly
+ % write to aux and store in prop with pdflatex
+\cs_new_protected:Npn \@@_backend_ThisPage_gput:nn #1 #2
+ {
+ \@@_backend_Page_primitive:n { /#1~#2 }
+ }
+ %the code to push the values, used in shipout
+ %merges the two props and then fills the register in pdflatex
+ %merges the two tables (the one is probably still empty)
+ % and then fills (in lua) in luatex
+ %issues the values stored in the global prop with dvi
+\cs_new_protected:Npn \@@_backend_ThisPage_gpush:n #1
+ {
+ \exp_args:Nx \@@_backend_Page_primitive:n
+ { \pdfdict_use:n { g_@@_Core/Page} }
+ }
+%</dvipdfmx|xdvipdfmx>
+%<*dvips>
+\cs_new_protected:Npn \@@_backend_Page_primitive:n #1
+ {
+ \tex_special:D{ps:~[{ThisPage}<<#1>>~/PUT~pdfmark} %]
+ }
+ % the command to store default values.
+ % Uses a prop with pdflatex + dvi,
+ % sets a lua table with lualatex
+\cs_new_protected:Npn \@@_backend_Page_gput:nn #1 #2
+ {
+ \pdfdict_gput:nnn {g_@@_Core/Page}{ #1 }{ #2 }
+ }
+ % the command to remove a default value.
+ % Uses a prop with pdflatex + dvi,
+ % changes a lua table with lualatex
+\cs_new_protected:Npn \@@_backend_Page_gremove:n #1
+ {
+ \pdfdict_gremove:nn {g_@@_Core/Page}{ #1 }
+ }
+ % the command used in the document.
+ % direct call of the primitive special with dvips/dvipdfmx
+ % \latelua: fill a page related table with lualatex, merge it with the page
+ % table and push it directly
+ % write to aux and store in prop with pdflatex
+\cs_new_protected:Npn \@@_backend_ThisPage_gput:nn #1 #2
+ {
+ \@@_backend_Page_primitive:n { /#1~#2 }
+ }
+ %the code to push the values, used in shipout
+ %merges the two props and then fills the register in pdflatex
+ %merges the two tables (the one is probably still empty)
+ %and then fills (in lua) in luatex
+ %issues the values stored in the global prop with dvi
+\cs_new_protected:Npn \@@_backend_ThisPage_gpush:n #1
+ {
+ \exp_args:Nx \@@_backend_Page_primitive:n
+ { \pdfdict_use:n { g_@@_Core/Page} }
+ }
+%</dvips>
+%<*dvisvgm>
+% mostly only dummies ...
+\cs_new_protected:Npn \@@_backend_Page_primitive:n #1
+ {}
+ % Uses a prop with pdflatex + dvi,
+\cs_new_protected:Npn \@@_backend_Page_gput:nn #1 #2
+ {
+ \pdfdict_gput:nnn {g_@@_Core/Page}{ #1 }{ #2 }
+ }
+ % the command to remove a default value.
+ % Uses a prop with pdflatex + dvi,
+\cs_new_protected:Npn \@@_backend_Page_gremove:n #1
+ {
+ \pdfdict_gremove:nn {g_@@_Core/Page}{ #1 }
+ }
+ % the command used in the document.
+\cs_new_protected:Npn \@@_backend_ThisPage_gput:nn #1 #2
+ {}
+ %the code to push the values, used in shipout
+\cs_new_protected:Npn \@@_backend_ThisPage_gpush:n #1
+ {}
+%</dvisvgm>
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{\enquote{Page/Resources}: ExtGState, ColorSpace, Shading, Pattern}
+% Path: Page/Resources/ExtGState etc. The actual output of the resources is handled
+% together with the bdc/Properties. Here is only special code.
+% \begin{macro}{\@@_backend_PageResources_gput:nnn}
+% stores values for the page resources.
+% \begin{arguments}
+% \item name of the resource (ExtGState, ColorSpace, Shading, Pattern)
+% \item a pdf name without slash
+% \item value
+% \end{arguments}
+% \begin{macro}{\@@_backend_PageResources_obj_gpush:}
+% This pushes out the objects. It is a no-op with xdvipdfmx and dvips.
+% \begin{macrocode}
+% backend commands the command to fill the register
+% and to push the values.
+%
+% The names are quite often needed
+% a similar list is now in l3pdfmanagement. Perhaps it should be merged.
+%<*drivers>
+\clist_const:Nn \c_@@_backend_PageResources_clist
+ {
+ ExtGState,
+ ColorSpace,
+ Pattern,
+ Shading,
+ }
+%</drivers>
+% pdftex and luatex
+%<*pdftex|luatex>
+ %create the backend objects:
+\clist_map_inline:Nn \c_@@_backend_PageResources_clist
+ {
+ \@@_backend_object_new:nn {Page/Resources/#1} {dict}
+ \cs_if_exist:NT \tex_directlua:D
+ {
+ \tex_directlua:D
+ {
+ ltx.@@.object["Page/Resources/#1"]
+ =
+ "\@@_backend_object_ref:n{Page/Resources/#1}"
+ }
+ }
+ }
+%</pdftex|luatex>
+%<*luatex>
+%values are only stored in a prop and will be output at end document.
+\cs_new_protected:Npn \@@_backend_PageResources_gput:nnn #1 #2 #3
+ {
+ \pdfdict_gput:nnn {g_@@_Core/Page/Resources/#1} { #2 }{ #3 }
+ % luatex must also trigger the lua side
+ \tex_latelua:D{ltx.@@.Page.Resources.#1=true}
+ \tex_latelua:D
+ {
+ ltx.pdf.Page_Resources_gpush(tex.count["g_shipout_readonly_int"])
+ }
+ }
+%</luatex>
+%<*pdftex>
+ \cs_new_protected:Npn \@@_backend_PageResources_gput:nnn #1 #2 #3
+ {
+ \pdfdict_gput:nnn {g_@@_Core/Page/Resources/#1} { #2 }{ #3 }
+ }
+%</pdftex>
+%<*pdftex|luatex>
+%code for end of document code
+\cs_new_protected:Npn \@@_backend_PageResources_obj_gpush:
+ {
+ \clist_map_inline:Nn \c_@@_backend_PageResources_clist
+ {
+ \prop_if_empty:cF
+ { \__kernel_pdfdict_name:n { g_@@_Core/Page/Resources/##1} }
+ {
+ \@@_backend_object_write:nx
+ { Page/Resources/##1 }
+ { \pdfdict_use:n { g_@@_Core/Page/Resources/##1} }
+ }
+ }
+ }
+%</pdftex|luatex>
+% xdvipdfmx
+% \special{pdf:pageresources<<#1>>} doesn't work correctly with object names ...
+% https://tug.org/pipermail/dvipdfmx/2019-August/000021.html,
+% so we use \special{pdf:put @resources}
+% this must be issued on every page!
+%<*dvipdfmx|xdvipdfmx>
+%objects should not only be created but also "initialized"
+% initialization should be done before anyone tries to write
+% so we add rules for the backend.
+%<xdvipdfmx>\hook_gset_rule:nnnn{shipout/firstpage}{l3backend-xetex}{after}{pdf}
+%<dvipdfmx>\hook_gset_rule:nnnn{shipout/firstpage}{l3backend-dvipdfmx}{after}{pdf}
+%
+\clist_map_inline:Nn \c_@@_backend_PageResources_clist
+ {
+ \@@_backend_object_new:nn { Page/Resources/#1 } { dict }
+ \hook_gput_code:nnn{shipout/firstpage}{pdf}{\@@_backend_object_write:nn { Page/Resources/#1 } {}}
+ }
+\cs_new_protected:Npn \@@_backend_PageResources:n #1
+ {
+ \@@_backend:n {put~@resources~<<#1>>}
+ }
+\cs_new_protected:Npn \@@_backend_PageResources_gput:nnn #1 #2 #3
+ {
+ % this is not used for output, but there is a test if the resource is empty
+ \exp_args:Nnx
+ \prop_gput:cnn { \__kernel_pdfdict_name:n { g_@@_Core/Page/Resources/#1} }
+ { \str_convert_pdfname:n {#2} }{ #3 }
+ %objects are not filled with \pdf_object_write as this is not additive!
+ \@@_backend:x
+ {
+ put~\@@_backend_object_ref:n {Page/Resources/#1}<</#2~#3>>
+ }
+ }
+
+\cs_new_protected:Npn \@@_backend_PageResources_obj_gpush: {}
+%</dvipdfmx|xdvipdfmx>
+%<*dvips>
+% dvips unneeded, or no-op
+\cs_new_protected:Npn \@@_backend_PageResources:n #1 {}
+\cs_new_protected:Npn \@@_backend_PageResources_gput:nnn #1 #2 #3
+ { %only for the show command TEST!!
+ \pdfdict_gput:nnn {g_@@_Core/Page/Resources/#1} { #2 }{ #3 }
+ }
+\cs_new_protected:Npn \@@_backend_PageResources_obj_gpush: {}
+%</dvips>
+%<*dvisvgm>
+% dvips unneeded, or no-op
+\cs_new_protected:Npn \@@_backend_PageResources:n #1 {}
+\cs_new_protected:Npn \@@_backend_PageResources_gput:nnn #1 #2 #3
+ { %only for the show command TEST!!
+ \pdfdict_gput:nnn {g_@@_Core/Page/Resources/#1} { #2 }{ #3 }
+ }
+\cs_new_protected:Npn \@@_backend_PageResources_obj_gpush: {}
+%</dvisvgm>
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \subsubsection{Page resources /Properties + BDC operators}
+% \begin{macro}
+% {
+% \@@_backend_bdc:nn,
+% \@@_backend_bdcobject:nn,
+% \@@_backend_bdcobject:n,
+% \@@_backend_bmc:n,
+% \@@_backend_emc:,
+% \@@_backend_PageResources_gpush:n
+% }
+% \cs{@@_backend_bdc:nn}, \cs{@@_backend_bdcobject:nn}, \cs{@@_backend_bdcobject:n},
+% \cs{@@_backend_bmc:n} and \cs{@@_backend_emc:}
+% are the backend command that
+% create the bdc/emc marker and store the properties.
+% \cs{@@_backend_PageResources_gpush:n} outputs the /Properties and/or the other
+% resources for the current page.
+% \begin{macrocode}
+% pdftex and luatex (and perhaps dvips ...) need to know if there are in a
+% xform stream ...
+%<*drivers>
+\bool_new:N \l_@@_backend_xform_bool
+%</drivers>
+%<*dvips>
+% dvips is easy: create an object, and reference it in the bdc
+% ghostscript will then automatically replace it by a name
+% and add the name to the /Properties dict
+% special variant von accsupp
+% https://chat.stackexchange.com/transcript/message/50831812#50831812
+%
+\cs_set_protected:Npn \@@_backend_bdc:nn #1 #2 % #1 eg. Span, #2: dict_content
+ {
+ \__pdf_backend_pdfmark:x{/#1~<<#2>>~/BDC}
+ }
+\cs_set_protected:Npn \@@_backend_bdcobject:nn #1 #2 % #1 eg. Span, #2: object name
+ {
+ \__pdf_backend_pdfmark:x{/#1~\@@_backend_object_ref:n{#2}~/BDC}
+ }
+\cs_set_protected:Npn \@@_backend_bdcobject:n #1 % #1 eg. Span,
+ {
+ \__pdf_backend_pdfmark:x{/#1~\@@_backend_object_last:~/BDC}
+ }
+\cs_set_protected:Npn \@@_backend_emc:
+ {
+ \__pdf_backend_pdfmark:n{/EMC} %
+ }
+\cs_set_protected:Npn \@@_backend_bmc:n #1
+ {
+ \__pdf_backend_pdfmark:n{/#1~/BMC} %
+ }
+\cs_new_protected:Npn \@@_backend_PageResources_gpush:n #1 {}
+
+%</dvips>
+%<*dvisvgm>
+% dvisvgm should do nothing
+%
+\cs_set_protected:Npn \@@_backend_bdc:nn #1 #2 % #1 eg. Span, #2: dict_content
+ {}
+\cs_set_protected:Npn \@@_backend_bdcobject:nn #1 #2 % #1 eg. Span, #2: object name
+ {}
+\cs_set_protected:Npn \@@_backend_bdcobject:n #1 % #1 eg. Span,
+ {}
+\cs_set_protected:Npn \@@_backend_emc:
+ {}
+\cs_set_protected:Npn \@@_backend_bmc:n #1
+ {}
+\cs_new_protected:Npn \@@_backend_PageResources_gpush:n #1 {}
+
+%</dvisvgm>
+
+% xetex has to create the entries in the /Properties manually
+% (like the other backends)
+% use pdfbase special
+% https://chat.stackexchange.com/transcript/message/50832016#50832016
+% the property is added to xform resources automatically,
+% no need to worry about it.
+%<*dvipdfmx|xdvipdfmx>
+ \cs_set_protected:Npn \@@_backend_bdcobject:nn #1 #2 % #1 eg. Span, #2: object name
+ {
+ \int_gincr:N \g_@@_backend_name_int
+ \__kernel_backend_literal:x
+ {
+ pdf:code~/#1/l3pdf\int_use:N\g_@@_backend_name_int\c_space_tl BDC
+ }
+ \__kernel_backend_literal:x
+ {
+ pdf:put~@resources~
+ <<
+ /Properties~
+ <<
+ /l3pdf\int_use:N\g_@@_backend_name_int\c_space_tl
+ \@@_backend_object_ref:n { #2 }
+ >>
+ >>
+ }
+ }
+ \cs_set_protected:Npn \@@_backend_bdcobject:n #1 % #1 eg. Span
+ {
+ \int_gincr:N \g_@@_backend_name_int
+ \__kernel_backend_literal:x
+ {
+ pdf:code~/#1/l3pdf\int_use:N\g_@@_backend_name_int\c_space_tl BDC
+ }
+ \__kernel_backend_literal:x
+ {
+ pdf:put~@resources~
+ <<
+ /Properties~
+ <<
+ /l3pdf\int_use:N\g_@@_backend_name_int\c_space_tl
+ \@@_backend_object_last:
+ >>
+ >>
+ }
+ }
+\cs_set_protected:Npn \@@_backend_bmc:n #1
+ {
+ \__kernel_backend_literal:n {pdf:code~/#1~BMC} %pdfbase
+ }
+
+%this require management
+\cs_set_protected:Npn \@@_backend_bdc_contobj:nn #1 #2
+ {
+ \pdf_object_unnamed_write:nn { dict }{ #2 }
+ \@@_backend_bdcobject:n { #1 }
+ }
+
+\cs_set_protected:Npn \@@_backend_bdc_contstream:nn #1 #2
+ {
+ \__kernel_backend_literal:n {pdf:code~ /#1~<<#2>>~BDC }
+ }
+
+\cs_set_protected:Npn \@@_backend_bdc:nn #1 #2
+ {
+ \bool_if:NTF \g__pdfmanagement_active_bool
+ {\cs_gset_eq:NN \@@_backend_bdc:nn \@@_backend_bdc_contobj:nn}
+ {\cs_gset_eq:NN \@@_backend_bdc:nn \@@_backend_bdc_contstream:nn}
+ \@@_backend_bdc:nn {#1}{#2}
+ }
+\cs_set_protected:Npn \@@_backend_emc:
+ {
+ \__kernel_backend_literal:n {pdf:code~EMC} %pdfbase
+ }
+ % properties are handled automatically, but the other resources should be added
+ % at shipout
+\cs_new_protected:Npn \@@_backend_PageResources_gpush:n #1
+ {
+ \clist_map_inline:Nn \c_@@_backend_PageResources_clist
+ {
+ \prop_if_empty:cF { \__kernel_pdfdict_name:n { g_@@_Core/Page/Resources/##1} }
+ {
+ \__kernel_backend_literal:x
+ {
+ pdf:put~@resources~
+ <</##1~\@@_backend_object_ref:n {Page/Resources/##1}>>
+ }
+ }
+ }
+ }
+%</dvipdfmx|xdvipdfmx>
+% luatex + pdftex
+%<*luatex>
+\cs_set_protected:Npn \@@_backend_bdcobject:nn #1 #2 % #1 eg. Span, #2: object name
+ {
+ \int_gincr:N \g_@@_backend_name_int
+ \exp_args:Nx\__kernel_backend_literal_page:n
+ { /#1 ~ /l3pdf\int_use:N\g_@@_backend_name_int\c_space_tl BDC }
+ \bool_if:NTF \l_@@_backend_xform_bool
+ {
+ \exp_args:Nnx\pdfdict_gput:nnn
+ { g_@@_Core/Xform/Resources/Properties }
+ { l3pdf\int_use:N\g_@@_backend_name_int }
+ { \@@_backend_object_ref:n { #2 } }
+ }
+ {
+ \exp_args:Nx \tex_latelua:D
+ {
+ ltx.pdf.Page_Resources_Properties_gput
+ (
+ tex.count["g_shipout_readonly_int"],
+ "l3pdf\int_use:N\g_@@_backend_name_int",
+ "\@@_backend_object_ref:n { #2 }"
+ )
+ }
+ }
+ }
+\cs_set_protected:Npn \@@_backend_bdcobject:n #1% #1 eg. Span
+ {
+ \int_gincr:N \g_@@_backend_name_int
+ \exp_args:Nx\__kernel_backend_literal_page:n
+ { /#1 ~ /l3pdf\int_use:N\g_@@_backend_name_int\c_space_tl BDC }
+ \bool_if:NTF \l_@@_backend_xform_bool
+ {
+ \exp_args:Nnx\pdfdict_gput:nnn %no handler needed
+ { g_@@_Core/Xform/Resources/Properties }
+ { l3pdf\int_use:N\g_@@_backend_name_int }
+ { \@@_backend_object_last: }
+ }
+ {
+ \exp_args:Nx \tex_latelua:D
+ {
+ ltx.pdf.Page_Resources_Properties_gput
+ (
+ tex.count["g_shipout_readonly_int"],
+ "l3pdf\int_use:N\g_@@_backend_name_int",
+ "\@@_backend_object_last:"
+ )
+ }
+ }
+ }
+\cs_set_protected:Npn \@@_backend_bmc:n #1
+ {
+ \__kernel_backend_literal_page:n { /#1~BMC }
+ }
+\cs_set_protected:Npn \@@_backend_bdc_contobj:nn #1 #2
+ {
+ \pdf_object_unnamed_write:nn { dict } { #2 }
+ \@@_backend_bdcobject:n { #1 }
+ }
+\cs_set_protected:Npn \@@_backend_bdc_contstream:nn #1 #2
+ {
+ \__kernel_backend_literal_page:n { /#1~<<#2>>~BDC }
+ }
+\cs_set_protected:Npn \@@_backend_bdc:nn #1 #2
+ {
+ \bool_if:NTF \g__pdfmanagement_active_bool
+ {\cs_gset_eq:NN \@@_backend_bdc:nn \@@_backend_bdc_contobj:nn}
+ {\cs_gset_eq:NN \@@_backend_bdc:nn \@@_backend_bdc_contstream:nn}
+ \@@_backend_bdc:nn {#1}{#2}
+ }
+\cs_set_protected:Npn \@@_backend_emc:
+ {
+ \__kernel_backend_literal_page:n { EMC }
+ }
+
+\cs_new_protected:Npn \@@_backend_PageResources_gpush:n #1 {}
+%</luatex>
+%<*pdftex>
+% pdflatex is the most complicated as it has to go through the aux ...
+% the push command is extended to take other resources too
+\cs_set_protected:Npn \@@_backend_bdcobject:nn #1 #2 % #1 eg. Span, #2: object name
+ {
+ \int_gincr:N \g_@@_backend_name_int
+ \exp_args:Nx\__kernel_backend_literal_page:n
+ { /#1 ~ /l3pdf\int_use:N\g_@@_backend_name_int\c_space_tl BDC }
+ % code to set the property ....
+ \int_gincr:N\g_@@_backend_resourceid_int
+ \bool_if:NTF \l_@@_backend_xform_bool
+ {
+ \exp_args:Nnxx\pdfdict_gput:nnn %no handler needed
+ { g_@@_Core/Xform/Resources/Properties }
+ { l3pdf\int_use:N\g_@@_backend_resourceid_int }
+ { \@@_backend_object_ref:n { #2 } }
+ }
+ {
+ %\zref@labelbylist
+% { l3pdf\int_use:N\g_@@_backend_resourceid_int }
+% { l3pdf }
+% \ref_label:en{l3pdf\int_use:N\g_@@_backend_resourceid_int}{abspage}
+ \@@_backend_ref_label:en{l3pdf\int_use:N\g_@@_backend_resourceid_int}{abspage}
+ \tl_set:Nx \l_@@_tmpa_tl
+ {
+ %\zref@extractdefault
+% { l3pdf\int_use:N\g_@@_backend_resourceid_int }
+% {pdf@abspage}
+% {0}
+ %\ref_value:en{l3pdf\int_use:N\g_@@_backend_resourceid_int}{abspage}
+ \@@_backend_ref_value:en{l3pdf\int_use:N\g_@@_backend_resourceid_int}{abspage}
+ }
+ \pdfdict_if_exist:nF { g_@@_Core/backend_Page\l_@@_tmpa_tl/Resources/Properties }
+ {
+ \pdfdict_new:n { g_@@_Core/backend_Page\l_@@_tmpa_tl/Resources/Properties }
+ }
+ \exp_args:Nnxx\pdfdict_gput:nnn
+ { g_@@_Core/backend_Page\l_@@_tmpa_tl/Resources/Properties }
+ { l3pdf\int_use:N\g_@@_backend_resourceid_int }
+ { \@@_backend_object_ref:n{#2} }
+ }
+ }
+\cs_set_protected:Npn \@@_backend_bdcobject:n #1% #1 eg. Span
+ {
+ \int_gincr:N \g_@@_backend_name_int
+ \exp_args:Nx\__kernel_backend_literal_page:n
+ { /#1 ~ /l3pdf\int_use:N\g_@@_backend_name_int\c_space_tl BDC }
+ % code to set the property ....
+ \int_gincr:N\g_@@_backend_resourceid_int
+ \bool_if:NTF \l_@@_backend_xform_bool
+ {
+ \exp_args:Nnxx\pdfdict_gput:nnn
+ { g_@@_Core/Xform/Resources/Properties }
+ { l3pdf\int_use:N\g_@@_backend_resourceid_int }
+ { \@@_backend_object_last: }
+ }
+ {
+ %\zref@labelbylist
+% { l3pdf\int_use:N\g_@@_backend_resourceid_int }
+% { l3pdf }
+ %\ref_label:en{l3pdf\int_use:N\g_@@_backend_resourceid_int}{abspage}
+ \@@_backend_ref_label:en{l3pdf\int_use:N\g_@@_backend_resourceid_int}{abspage}
+ \tl_set:Nx \l_@@_tmpa_tl
+ {
+ %\zref@extractdefault
+% { l3pdf\int_use:N\g_@@_backend_resourceid_int }
+% {pdf@abspage}
+% {0}
+ % \ref_value:en{l3pdf\int_use:N\g_@@_backend_resourceid_int}{abspage}
+ \@@_backend_ref_value:en{l3pdf\int_use:N\g_@@_backend_resourceid_int}{abspage}
+ }
+ \pdfdict_if_exist:nF { g_@@_Core/backend_Page\l_@@_tmpa_tl/Resources/Properties }
+ {
+ \pdfdict_new:n { g_@@_Core/backend_Page\l_@@_tmpa_tl/Resources/Properties }
+ }
+ \exp_args:Nnxx\pdfdict_gput:nnn
+ { g_@@_Core/backend_Page\l_@@_tmpa_tl/Resources/Properties }
+ { l3pdf\int_use:N\g_@@_backend_resourceid_int }
+ { \@@_backend_object_last: }
+ %\pdfdict_show:n { g_backend_Page\l_@@_tmpa_tl/Resources/Properties }
+ }
+ }
+\cs_set_protected:Npn \@@_backend_bmc:n #1
+ {
+ \__kernel_backend_literal_page:n { /#1~BMC }
+ }
+\cs_set_protected:Npn \@@_backend_bdc_contobj:nn #1 #2
+ {
+ \pdf_object_unnamed_write:nn { dict } { #2 }
+ \@@_backend_bdcobject:n { #1 }
+ }
+\cs_set_protected:Npn \@@_backend_bdc_contstream:nn #1 #2
+ {
+ \__kernel_backend_literal_page:n { /#1~<<#2>>~BDC }
+ }
+\cs_set_protected:Npn \@@_backend_bdc:nn #1 #2
+ {
+ \bool_if:NTF \g__pdfmanagement_active_bool
+ {\cs_gset_eq:NN \@@_backend_bdc:nn \@@_backend_bdc_contobj:nn}
+ {\cs_gset_eq:NN \@@_backend_bdc:nn \@@_backend_bdc_contstream:nn}
+ \@@_backend_bdc:nn {#1}{#2}
+ }
+\cs_set_protected:Npn \@@_backend_emc:
+ {
+ \__kernel_backend_literal_page:n { EMC }
+ }
+
+\cs_new:Npn \@@_backend_PageResources_gpush_aux:n #1 %#1 ExtGState etc
+ {
+ \prop_if_empty:cF
+ { \__kernel_pdfdict_name:n { g_@@_Core/Page/Resources/#1} }
+ {
+ \pdfdict_item:ne { #1 }{ \pdf_object_ref:n {Page/Resources/#1}}
+ }
+ }
+
+\cs_new_protected:Npn \@@_backend_PageResources_gpush:n #1
+ {
+ \exp_args:NNx \tex_global:D \tex_pdfpageresources:D
+ {
+ \prop_if_exist:cT
+ { \__kernel_pdfdict_name:n { g_@@_Core/backend_Page#1/Resources/Properties } }
+ {
+ /Properties~
+ <<
+ \prop_map_function:cN
+ { \__kernel_pdfdict_name:n { g_@@_Core/backend_Page#1/Resources/Properties } }
+ \pdfdict_item:ne
+ >>
+ }
+ %% add ExtGState etc
+ \clist_map_function:NN
+ \c_@@_backend_PageResources_clist
+ \@@_backend_PageResources_gpush_aux:n
+ }
+ }
+
+%</pdftex>
+% \end{macrocode}
+% \end{macro}
+% \subsection{\enquote{Catalog} \& subdirectories (pdfcatalog) }
+% The backend command is already in the driver:
+% \cs{@@_backend_catalog_gput:nn}
+% \subsubsection { Special case: the /Names/EmbeddedFiles dictionary }
+% Entries to /Names are handled differently, in part (/Desc) it is automatic, for
+% other special commands like \cs{pdfnames} must be used. For EmbeddedFiles
+% we need some code to push the tree if files have been added. dvips wants code
+% for every file and then creates the Name tree automatically.
+% \begin{macrocode}
+% pdflatex
+%<*pdftex>
+\cs_new_protected:Npn \@@_backend_NamesEmbeddedFiles_gpush:n #1 %array content
+ {
+ \pdf_object_unnamed_write:nn {dict} {/Names [#1] }
+ \tex_pdfnames:D {/EmbeddedFiles~\pdf_object_ref_last:}
+ }
+%</pdftex>
+%<*luatex>
+\cs_new_protected:Npn \@@_backend_NamesEmbeddedFiles_gpush:n #1 %array content
+ {
+ \pdf_object_unnamed_write:nn {dict} {/Names [#1] }
+ \tex_pdfextension:D~names~{/EmbeddedFiles~\pdf_object_ref_last: }
+ }
+%</luatex>
+%<*dvipdfmx|xdvipdfmx>
+\cs_new_protected:Npn \@@_backend_NamesEmbeddedFiles_gpush:n #1 %array content
+ {
+ \pdf_object_unnamed_write:nn {dict} { /Names [#1] }
+ %n or x?
+ \__pdf_backend:x {put~@names~<</EmbeddedFiles~\pdf_object_ref_last: >>}
+ }
+%</dvipdfmx|xdvipdfmx>
+
+%dvips: noop
+%<*dvips>
+\cs_new_protected:Npn \@@_backend_NamesEmbeddedFiles_gpush:n #1 {}
+%</dvips>
+%dvisvgm: noop
+%<*dvisvgm>
+\cs_new_protected:Npn \@@_backend_NamesEmbeddedFiles_gpush:n #1 {}
+%</dvisvgm>
+
+% \end{macrocode}
+% Names in the EmbeddedFiles name tree must sorted alphabetically,
+% so we need commands to create this names. And we need a sequence to store
+% the names and the objects. We use the prefix l3ef, and we assume that at
+% most 9999 files will be used.
+% \begin{variable}{\g_@@_backend_EmbeddedFiles_int}
+% \end{variable}
+% \begin{macro}{\@@_backend_EmbeddedFiles_name:}
+% \begin{macrocode}
+%<*drivers>
+\int_new:N \g_@@_backend_EmbeddedFiles_int
+\cs_new:Npn \@@_backend_EmbeddedFiles_name:
+ {
+ (
+ l3ef
+ \int_compare:nNnT {\g_@@_backend_EmbeddedFiles_int} < {10}
+ {0}
+ \int_compare:nNnT {\g_@@_backend_EmbeddedFiles_int} < {100}
+ {0}
+ \int_compare:nNnT {\g_@@_backend_EmbeddedFiles_int} < {1000}
+ {0}
+ \int_use:N \g_@@_backend_EmbeddedFiles_int
+ )
+ }
+%</drivers>
+% \end{macrocode}
+% \end{macro}
+% \begin{variable}{\g_@@_backend_EmbeddedFiles_seq,\g_@@_backend_EmbeddedFiles_named_prop}
+% The sequence will hold the content of the array that is pushed out at then
+% end (not with dvips), the prop holds the obj names-names relation.
+% \end{variable}
+% \begin{macrocode}
+%<*drivers>
+\seq_new:N \g_@@_backend_EmbeddedFiles_seq
+\prop_new:N \g_@@_backend_EmbeddedFiles_named_prop
+%</drivers>
+% \end{macrocode}
+% \begin{macro}{\@@_backend_NamesEmbeddedFiles_add:n}
+% This command saves an object reference of a filespec dictionary in the
+% EmbeddedFiles name tree. We define a prop to store the relation between
+% object name and name in the name tree.
+% \begin{macrocode}
+%<*pdftex|luatex|dvipdfmx|xdvipdfmx>
+\cs_new_protected:Npn \@@_backend_NamesEmbeddedFiles_add:n #1
+ %#1 object ref
+ {
+ \int_gincr:N \g_@@_backend_EmbeddedFiles_int
+ \prop_gput:Nnx \g_@@_backend_EmbeddedFiles_named_prop
+ { #1 }
+ { \@@_backend_EmbeddedFiles_name: }
+ \seq_gput_right:Nx \g_@@_backend_EmbeddedFiles_seq
+ { \@@_backend_EmbeddedFiles_name: \c_space_tl #1 }
+ }
+
+%</pdftex|luatex|dvipdfmx|xdvipdfmx>
+%<*dvips>
+\cs_new_protected:Npn \@@_backend_NamesEmbeddedFiles_add:n #1
+ {
+ \int_gincr:N \g_@@_backend_EmbeddedFiles_int
+ \prop_gput:Nnx \g_@@_backend_EmbeddedFiles_named_prop
+ { #1 }
+ { \@@_backend_EmbeddedFiles_name: }
+ \@@_backend_pdfmark:x
+ {
+ /Name~\@@_backend_EmbeddedFiles_name:~
+ /FS~#1~
+ /EMBED
+ }
+ }
+%</dvips>
+%<*dvisvgm>
+%no op. Or is there any sensible use for it?
+\cs_new_protected:Npn \@@_backend_NamesEmbeddedFiles_add:n #1
+ {}
+%</dvisvgm>
+% \end{macrocode}
+% \end{macro}
+% \subsubsection{Form XObject / backend }
+% \begin{macro}{ \@@_backend_xform_new:nnnn }
+% \begin{arguments}
+% \item name
+% \item attributes
+% \item resources %needed?? or are all resources autogenerated?
+% \item content, this doesn't need to be a box!
+% \end{arguments}
+% \begin{macro}{ \@@_backend_xform_use:n, \@@_backend_xform_ref:n }
+% \begin{macrocode}
+%<*pdftex>
+\cs_new_protected:Npn \@@_backend_xform_new:nnnn #1 #2 #3 #4
+% #1 name
+% #2 attributes
+% #3 resources
+% #4 content, not necessarily a box!
+ {
+ \hbox_set:Nn \l_@@_backend_tmpa_box
+ {
+ \bool_set_true:N \l_@@_backend_xform_bool
+ \prop_gclear:c {\__kernel_pdfdict_name:n { g_@@_Core/Xform/Resources/Properties }}
+ #4
+ }
+ %store the dimensions
+ \tl_const:cx
+ { c_@@_backend_xform_wd_ \tl_to_str:n {#1} _tl }
+ { \tex_the:D \box_wd:N \l_@@_backend_tmpa_box }
+ \tl_const:cx
+ { c_@@_backend_xform_ht_ \tl_to_str:n {#1} _tl }
+ { \tex_the:D \box_ht:N \l_@@_backend_tmpa_box }
+ \tl_const:cx
+ { c_@@_backend_xform_dp_ \tl_to_str:n {#1} _tl }
+ { \tex_the:D \box_dp:N \l_@@_backend_tmpa_box }
+ %% do we need to test if #2 and #3 are empty??
+ \tex_immediate:D \tex_pdfxform:D
+ ~ attr ~ { #2 }
+ %% which other resources should be default? Is an argument actually needed?
+ ~ resources ~
+ {
+ #3
+ \int_compare:nNnT
+ { \prop_count:c { \__kernel_pdfdict_name:n { g_@@_Core/Xform/Resources/Properties } } }
+ >
+ { 0 }
+ {
+ /Properties~
+ <<
+ \pdfdict_use:n { g_@@_Core/Xform/Resources/Properties }
+ >>
+ }
+
+ \prop_if_empty:cF
+ { \__kernel_pdfdict_name:n { g_@@_Core/Page/Resources/ExtGState } }
+ {
+ /ExtGState~ \pdf_object_ref:n { Page/Resources/ExtGState }
+ }
+ \prop_if_empty:cF
+ { \__kernel_pdfdict_name:n { g_@@_Core/Page/Resources/Pattern } }
+ {
+ /Pattern~ \pdf_object_ref:n { Page/Resources/Pattern }
+ }
+ \prop_if_empty:cF
+ { \__kernel_pdfdict_name:n { g_@@_Core/Page/Resources/Shading } }
+ {
+ /Shading~ \pdf_object_ref:n { Page/Resources/Shading }
+ }
+ \prop_if_empty:cF
+ { \__kernel_pdfdict_name:n { g_@@_Core/Page/Resources/ColorSpace } }
+ {
+ /ColorSpace~ \pdf_object_ref:n { Page/Resources/ColorSpace }
+ }
+ }
+ \l_@@_backend_tmpa_box
+ \int_const:cn
+ { c_@@_backend_xform_ \tl_to_str:n {#1} _int }
+ { \tex_pdflastxform:D }
+ }
+
+\cs_new_protected:Npn \@@_backend_xform_use:n #1
+ {
+ \tex_pdfrefxform:D
+ \int_use:c { c_@@_backend_xform_ \tl_to_str:n {#1} _int }
+ \scan_stop:
+ }
+
+\cs_new:Npn \@@_backend_xform_ref:n #1
+ {
+ \int_use:c { c_@@_backend_xform_ \tl_to_str:n {#1} _int } ~ 0 ~ R
+ }
+%</pdftex>
+%<*luatex>
+%luatex
+%nearly identical but not completely ...
+\cs_new_protected:Npn \@@_backend_xform_new:nnnn #1 #2 #3 #4
+% #1 name
+% #2 attributes
+% #3 resources
+% #4 content, not necessarily a box!
+ {
+ \hbox_set:Nn \l_@@_backend_tmpa_box
+ {
+ \bool_set_true:N \l_@@_backend_xform_bool
+ \prop_gclear:c { \__kernel_pdfdict_name:n { g_@@_Core/Xform/Resources/Properties } }
+ #4
+ }
+ \tl_const:cx
+ { c_@@_backend_xform_wd_ \tl_to_str:n {#1} _tl }
+ { \tex_the:D \box_wd:N \l_@@_backend_tmpa_box }
+ \tl_const:cx
+ { c_@@_backend_xform_ht_ \tl_to_str:n {#1} _tl }
+ { \tex_the:D \box_ht:N \l_@@_backend_tmpa_box }
+ \tl_const:cx
+ { c_@@_backend_xform_dp_ \tl_to_str:n {#1} _tl }
+ { \tex_the:D \box_dp:N \l_@@_backend_tmpa_box }
+ %% do we need to test if #2 and #3 are empty??
+ \tex_immediate:D \tex_pdfxform:D
+ ~ attr ~ { #2 }
+ %% which resources should be default? Is an argument actually needed?
+ ~ resources ~
+ {
+ #3
+ \int_compare:nNnT
+ {\prop_count:c { \__kernel_pdfdict_name:n { g_@@_Core/Xform/Resources/Properties } }}
+ >
+ { 0 }
+ {
+ /Properties~
+ <<
+ \pdfdict_use:n { g_@@_Core/Xform/Resources/Properties }
+ >>
+ }
+ \prop_if_empty:cF
+ { \__kernel_pdfdict_name:n { g_@@_Core/Page/Resources/ExtGState } }
+ {
+ /ExtGState~ \pdf_object_ref:n { Page/Resources/ExtGState }
+ }
+ \prop_if_empty:cF
+ { \__kernel_pdfdict_name:n { g_@@_Core/Page/Resources/Pattern } }
+ {
+ /Pattern~ \pdf_object_ref:n { Page/Resources/Pattern }
+ }
+ \prop_if_empty:cF
+ { \__kernel_pdfdict_name:n { g_@@_Core/Page/Resources/Shading } }
+ {
+ /Shading~ \pdf_object_ref:n { Page/Resources/Shading }
+ }
+ \prop_if_empty:cF
+ { \__kernel_pdfdict_name:n { g_@@_Core/Page/Resources/ColorSpace } }
+ {
+ /ColorSpace~ \pdf_object_ref:n { Page/Resources/ColorSpace }
+ }
+ }
+ \l_@@_backend_tmpa_box
+ \int_const:cn
+ { c_@@_backend_xform_ \tl_to_str:n {#1} _int }
+ { \tex_pdflastxform:D }
+ }
+
+\cs_new_protected:Npn \@@_backend_xform_use:n #1 %protected as with xelatex
+ {
+ \tex_pdfrefxform:D \int_use:c
+ {
+ c_@@_backend_xform_ \tl_to_str:n {#1} _int
+ }
+ \scan_stop:
+ }
+
+\cs_new:Npn \@@_backend_xform_ref:n #1
+ { \int_use:c { c_@@_backend_xform_ \tl_to_str:n {#1} _int } ~ 0 ~ R }
+
+%</luatex>
+%<*dvipdfmx|xdvipdfmx>
+% xetex
+ % it needs a bit testing if it really works to set the box to 0 before the special ...
+ % does it disturb viewing the xobject?
+ % what happens with the resources (bdc)? (should work as they are specials too)
+ % xetex requires that the special is in horizontal mode. This means it affects
+ % typesetting. But we can no delay the whole form code to shipout
+ % as the object reference and the size is often wanted on the current page.
+ % so we need to allocate a box - but probably they won't be thousands xform
+ % in a document so it shouldn't matter.
+ \cs_new_protected:Npn \@@_backend_xform_new:nnnn #1 #2 #3 #4
+ % #1 name
+ % #2 attributes
+ % #3 resources
+ % #4 content, not necessarily a box!
+ {
+ \int_gincr:N \g_@@_backend_object_int
+ \int_const:cn
+ { c_@@_backend_xform_ \tl_to_str:n {#1} _int }
+ { \g_@@_backend_object_int }
+ \box_new:c { g_@@_backend_xform_#1_box }
+ \hbox_gset:cn { g_@@_backend_xform_#1_box }
+ {
+ \bool_set_true:N \l_@@_backend_xform_bool
+ #4
+ }
+ \tl_const:cx
+ { c_@@_backend_xform_wd_ \tl_to_str:n {#1} _tl }
+ { \tex_the:D \box_wd:c { g_@@_backend_xform_#1_box } }
+ \tl_const:cx
+ { c_@@_backend_xform_ht_ \tl_to_str:n {#1} _tl }
+ { \tex_the:D \box_ht:c { g_@@_backend_xform_#1_box } }
+ \tl_const:cx
+ { c_@@_backend_xform_dp_ \tl_to_str:n {#1} _tl }
+ { \tex_the:D \box_dp:c { g_@@_backend_xform_#1_box } }
+ \box_set_dp:cn { g_@@_backend_xform_#1_box } { \c_zero_dim }
+ \box_set_ht:cn { g_@@_backend_xform_#1_box } { \c_zero_dim }
+ \box_set_wd:cn { g_@@_backend_xform_#1_box } { \c_zero_dim }
+ \hook_gput_next_code:nn {shipout/background}
+ {
+ \mode_leave_vertical: %needed, the xform disappears without it.
+ \@@_backend:x
+ {
+ bxobj ~ \@@_backend_xform_ref:n { #1 }
+ \c_space_tl width ~ \pdfxform_wd:n { #1 }
+ \c_space_tl height ~ \pdfxform_ht:n { #1 }
+ \c_space_tl depth ~ \pdfxform_dp:n { #1 }
+ }
+ \box_use_drop:c { g_@@_backend_xform_#1_box }
+ \@@_backend:x {put ~ @resources ~<<#3>> }
+ \@@_backend:x
+ {
+ put~ @resources ~
+ <<
+ /ExtGState~ \pdf_object_ref:n { Page/Resources/ExtGState }
+ >>
+ }
+ \@@_backend:x
+ {
+ put~ @resources ~
+ <<
+ /Pattern~ \pdf_object_ref:n { Page/Resources/Pattern }
+ >>
+ }
+ \@@_backend:x
+ {
+ put~ @resources ~
+ <<
+ /Shading~ \pdf_object_ref:n { Page/Resources/Shading }
+ >>
+ }
+ \@@_backend:x
+ {
+ put~ @resources ~
+ <<
+ /ColorSpace~
+ \pdf_object_ref:n { Page/Resources/ColorSpace }
+ >>
+ }
+ \exp_args:Nx
+ \@@_backend:x {exobj ~<<#2>>}
+ }
+ }
+
+
+
+ \cs_new:Npn \@@_backend_xform_ref:n #1
+ {
+ @pdf.xform \int_use:c { c_@@_backend_xform_ \tl_to_str:n {#1} _int }
+ }
+
+ \cs_new_protected:Npn \@@_backend_xform_use:n #1
+ {
+ \hbox_set:Nn \l_@@_backend_tmpa_box
+ {
+ \@@_backend:x
+ {
+ uxobj~ \@@_backend_xform_ref:n { #1 }
+ }
+ }
+ \box_set_wd:Nn \l_@@_backend_tmpa_box { \pdfxform_wd:n { #1 } }
+ \box_set_ht:Nn \l_@@_backend_tmpa_box { \pdfxform_ht:n { #1 } }
+ \box_set_dp:Nn \l_@@_backend_tmpa_box { \pdfxform_dp:n { #1 } }
+ \box_use_drop:N \l_@@_backend_tmpa_box
+ }
+%</dvipdfmx|xdvipdfmx>
+%<*dvisvgm>
+% unclear what it should do!!
+\cs_new_protected:Npn \@@_backend_xform_new:nnnn #1 #2 #3 #4 {}
+\cs_new_protected:Npn \@@_backend_xform_use:n #1 {}
+\cs_new:Npn \@@_backend_xform_ref:n {}
+%</dvisvgm>
+%<*drivers>
+%% all
+\prg_new_conditional:Npnn \@@_backend_xform_if_exist:n #1 { p , T , F , TF }
+ {
+ \int_if_exist:cTF { c_@@_backend_xform_ \tl_to_str:n {#1} _int }
+ { \prg_return_true: }
+ { \prg_return_false:}
+ }
+\prg_new_eq_conditional:NNn \pdfxform_if_exist:n\@@_backend_xform_if_exist:n
+ { TF , T , F , p }
+%</drivers>
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \subsection{lua code for lualatex}
+% \begin{macrocode}
+%<*lua>
+ltx= ltx or {}
+ltx.@@ = ltx.@@ or {}
+ltx.@@.Page = ltx.@@.Page or {}
+ltx.@@.Page.dflt = ltx.@@.Page.dflt or {}
+ltx.@@.Page.Resources = ltx.@@.Resources or {}
+ltx.@@.Page.Resources.Properties = ltx.@@.Page.Resources.Properties or {}
+ltx.@@.Page.Resources.List={"ExtGState","ColorSpace","Pattern","Shading"}
+ltx.@@.object = ltx.@@.object or {}
+
+ltx.pdf= ltx.pdf or {} -- for "public" functions
+
+local @@ = ltx.@@
+local pdf = pdf
+
+local function @@_backend_Page_gput (name,value)
+ @@.Page.dflt[name]=value
+end
+
+local function @@_backend_Page_gremove (name)
+ @@.Page.dflt[name]=nil
+end
+
+local function @@_backend_Page_gclear ()
+ @@.Page.dflt={}
+end
+
+local function @@_backend_ThisPage_gput (page,name,value)
+ @@.Page[page] = @@.Page[page] or {}
+ @@.Page[page][name]=value
+end
+
+local function @@_backend_ThisPage_gpush (page)
+ local token=""
+ local t = {}
+ local tkeys= {}
+ for name,value in pairs(@@.Page.dflt) do
+ t[name]=value
+ end
+ if @@.Page[page] then
+ for name,value in pairs(@@.Page[page]) do
+ t[name] = value
+ end
+ end
+ -- sort the table to get reliable test files.
+ for name,value in pairs(t) do
+ table.insert(tkeys,name)
+ end
+ table.sort(tkeys)
+ for _,name in ipairs(tkeys) do
+ token = token .. "/"..name.." "..t[name]
+ end
+ return token
+end
+
+function ltx.@@.backend_ThisPage_gput (page,name,value) -- tex.count["g_shipout_readonly_int"]
+ @@_backend_ThisPage_gput (page,name,value)
+end
+
+function ltx.@@.backend_ThisPage_gpush (page)
+ pdf.setpageattributes(@@_backend_ThisPage_gpush (page))
+end
+
+function ltx.@@.backend_Page_gput (name,value)
+ @@_backend_Page_gput (name,value)
+end
+
+function ltx.@@.backend_Page_gremove (name)
+ @@_backend_Page_gremove (name)
+end
+
+function ltx.@@.backend_Page_gclear ()
+ @@_backend_Page_gclear ()
+end
+
+
+local Properties = ltx.@@.Page.Resources.Properties
+local ResourceList= ltx.@@.Page.Resources.List
+local function @@_backend_PageResources_gpush (page)
+ local token=""
+ if Properties[page] then
+-- we sort the table, so that the pdf test works
+ local t = {}
+ for name,value in pairs (Properties[page]) do
+ table.insert (t,name)
+ end
+ table.sort (t)
+ for _,name in ipairs(t) do
+ token = token .. "/"..name.." ".. Properties[page][name]
+ end
+ token = "/Properties <<"..token..">>"
+ end
+ for i,name in ipairs(ResourceList) do
+ if ltx.@@.Page.Resources[name] then
+ token = token .. "/"..name.." "..ltx.pdf.object_ref("Page/Resources/"..name)
+ end
+ end
+ return token
+end
+
+-- the function is public, as I probably need it in tagpdf too ...
+function ltx.pdf.Page_Resources_Properties_gput (page,name,value) -- tex.count["g_shipout_readonly_int"]
+ Properties[page] = Properties[page] or {}
+ Properties[page][name]=value
+ pdf.setpageresources(@@_backend_PageResources_gpush (page))
+end
+
+function ltx.pdf.Page_Resources_gpush(page)
+ pdf.setpageresources(@@_backend_PageResources_gpush (page))
+end
+
+function ltx.pdf.object_ref (objname)
+ if ltx.@@.object[objname] then
+ local ref= ltx.@@.object[objname]
+ return ref
+ else
+ return "false"
+ end
+end
+%</lua>
+% \end{macrocode}
+% \end{implementation}
+%
+% \PrintIndex
diff --git a/Master/texmf-dist/source/latex/pdfmanagement-testphase/l3pdfannot.dtx b/Master/texmf-dist/source/latex/pdfmanagement-testphase/l3pdfannot.dtx
new file mode 100644
index 00000000000..94b7a89af87
--- /dev/null
+++ b/Master/texmf-dist/source/latex/pdfmanagement-testphase/l3pdfannot.dtx
@@ -0,0 +1,583 @@
+% \iffalse meta-comment
+%
+%% File: l3pdfannot.dtx
+%
+% Copyright (C) 2021 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
+%
+% http://www.latex-project.org/lppl.txt
+%
+% This file is part of the "LaTeX PDF management testphase 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/pdfresources
+%
+% for those people who are interested.
+%
+%<*driver>
+\RequirePackage{pdfmanagement-testphase}
+\DeclareDocumentMetadata{pdfstandard=A-2b}
+\makeatletter
+\declare@file@substitution{doc.sty}{doc-v3beta.sty}
+\makeatother
+\documentclass[full]{l3doc}
+\usepackage{array,booktabs,hyperxmp}
+\hypersetup{pdfauthor=The LaTeX Project,
+ pdftitle=l3pdfannot (LaTeX PDF management testphase bundle)}
+\begin{document}
+ \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
+% \fi
+% \providecommand\hook[1]{\texttt{#1}}
+% \title{^^A
+% The \pkg{l3pdfannot} module\\ Commands for PDF annotations ^^A
+% \\ \LaTeX{} PDF management testphase bundle
+% }
+%
+% \author{^^A
+% The \LaTeX{} Project\thanks
+% {^^A
+% E-mail:
+% \href{mailto:latex-team@latex-project.org}
+% {latex-team@latex-project.org}^^A
+% }^^A
+% }
+%
+% \date{Version 0.95a, released 2021-02-21}
+%
+% \maketitle
+% \begin{documentation}
+%
+% \section{\pkg{l3pdfannot} documentation}
+% This module contains a number of commands to create PDF annotations.
+% The commands are \emph{not} always simple wrappers around primitive commands.
+% To allow external packages to configure links and other annotations,
+% some of the commands have hooks and use shared attribute dictionaries.
+% For these commands the hooks and dictionaries are selected depending on the \meta{type}
+% of the annotation. Currently the module only supports some general commands
+% and link annotations. Commands for other annotations like widgets will be added
+% later.
+%
+% \subsection{General annotation commands}
+%
+% \begin{function}[added = 2019-09-05, updated = 2020-04-14]
+% { \pdfannot_box:nnnn }
+% \begin{syntax}
+% \cs{pdfannot_box:nnnn} \Arg{width} \Arg{height} \Arg{depth} \Arg{annot spec}
+% \end{syntax}
+% This creates an \texttt{/Type/Annot} object with the given dimensions.
+% It doesn't use hooks or dictionaries.
+% \end{function}
+% \begin{function}[added = 2020-03-30]
+% { \pdfannot_box:nnnnn }
+% \begin{syntax}
+% \cs{pdfannot_box:nnnnn} \Arg{type} \Arg{width} \Arg{height} \Arg{depth} \Arg{annot spec}
+% \end{syntax}
+% This creates an \texttt{/Type/Annot} object with the given dimensions.
+% \meta{type} should be currently one of |link/URI|, |link/GoToR|,
+% |link/Launch|, |link/GoTo| or |link/Named| or
+% |widget|, it will then insert the attribute dictionary of this type
+% additionally to the manually given \meta{annot spec}.
+% The attribute dictionaries can be filled with commands described below.
+% Hooks are not used.
+% \end{function}
+% \begin{function}[added = 2019-09-05]
+% { \pdfannot_box_ref_last: }
+% \begin{syntax}
+% \cs{pdfannot_box_ref_last:}
+% \end{syntax}
+% This retrieves the object reference of the last box annotation created.
+% \end{function}
+% \subsection{Link annotations}
+% Link annotations are special cases of annotations. In the PDF they are identified
+% by an |/Subtype/Link| entry in the dictionary.
+% Link annotations are quite important as many documents contain links,
+% both internal and external. They need a set of special commands for two reasons:
+%
+% At first the content of links are not only boxes. Links can contain line
+% and page breaks (this is normally implemented by the primitive command by
+% creating a set of annotations).
+%
+% At second link annotations are objects that need some
+% \enquote{management} as more than one
+% package wants to configure their look and behaviour.
+% For example \pkg{hyperref}, \pkg{ocgx2} and the code for tagged PDF (currently
+% in \pkg{tagpdf}) all want to add keys and values to the dictionaries of
+% link annotation and code around links.
+% So commands to create link annotations should offer suitable hooks.
+% There are three standard places in a link where such hooks are needed:
+% At the begin (for example for a structure command or color),
+% in the \emph{attr spec} dictionary of the link (for example for the border), and
+% at the end of the link (to close a structure or the color group).
+% For the begin and end hooks of the LaTeX hook management are predefined and used.
+% To add and remove values from the \emph{attr spec} dictionary special
+% commands described below are provided. The link commands switch to horizontal mode
+% as the commands of pdftex and luatex can't be used in vertical mode.
+%
+% \begin{variable}{\c_pdfannot_link_types_seq}
+% There are currently five link types, \texttt{URI}, \texttt{GoToR},
+% \texttt{Launch}, \texttt{GoTo} or \texttt{Named}, and there are store in this
+% constant.
+% \end{variable}
+% \begin{variable}
+% {
+% pdfannot/link/TYPE/before,
+% pdfannot/link/TYPE/begin,
+% pdfannot/link/TYPE/end,
+% pdfannot/link/TYPE/after
+% }
+% These are the hooks used by the following commands. TYPE can be one of
+% \texttt{URI}, \texttt{GoToR},
+% \texttt{Launch}, \texttt{GoTo} or \texttt{Named}
+% \end{variable}
+% \begin{variable}
+% {
+% link/TYPE
+% }
+% These is the name of the dictionary used by the following commands. TYPE can be one of
+% \texttt{URI}, \texttt{GoToR},
+% \texttt{Launch}, \texttt{GoTo} or \texttt{Named}. The dictionary can be changed
+% by the commands \cs{pdfannot_dict_put:nnn} and friends described below.
+% \end{variable}
+% \begin{function}[added = 2020-03-12, updated = 2020-12-06]{ \pdfannot_link:nnn }
+% \begin{syntax}
+% \cs{pdfannot_link:nnn} \Arg{type} \Arg{user action spec} \Arg{link text}
+% \end{syntax}
+% This creates a link around the \meta{link text} with the specified
+% \meta{user action spec}\footnote{The wording follows the pdftex documentation}.
+% \texttt{/Subtype/Link} is added automatically.
+% \meta{type} should be one of \texttt{URI}, \texttt{GoToR},
+% \texttt{Launch}, \texttt{GoTo} or \texttt{Named}. The |GoTo| variant does
+% \emph{not} complain if the destination name is not known like
+% \cs{pdfannot_link_goto_begin:nw}.
+% The attributes stored in the local dictionary
+% \texttt{link/}\meta{type} are inserted as
+% \emph{attr spec} and the code in the begin and end hook
+% \texttt{pdfannot/link/\meta{type}/before}
+% and \texttt{pdfannot/link/\meta{type}/after}
+% is executed before and after the link (outside the link command)
+% while \texttt{pdfannot/link/\meta{type}/begin}
+% and \texttt{pdfannot/link/\meta{type}/end} are directly around the link
+% text. None of the hooks introduce a group.
+% \meta{type} should normally be identical to the value of the |/S| key
+% in the action dictionary.
+% As example
+% \begin{verbatim}
+% \pdfannot_dict_put:nnn
+% {link/URI} { C } {[1~0~0]} %red border
+% \pdfannot_link:nnn { URI }
+% {
+% /A
+% <<
+% /Type/Action
+% /S/URI
+% /URI(https://www.latex-project.org)
+% >>
+% }
+% { link text }
+% \end{verbatim}
+%
+%
+% \end{function}
+% \begin{function}[updated = 2020-12-06]{ \pdfannot_link_begin:nnw, \pdfannot_link_end:n }
+% \begin{syntax}
+% \cs{pdfannot_link_begin:nnw} \Arg{type} \Arg{user action spec} \meta{content}
+% \cs{pdfannot_link_end:n} \Arg{type}
+% \end{syntax}
+% This creates a link around the \meta{content} with the specified
+% \meta{user action spec} (e.g. an /A dictionary with an URI) or
+% \meta{destination} (a name as defined with the
+% first argument of \cs{pdf_destination:nn}).
+% \texttt{/Subtype/Link} is added automatically.
+% In contrast to \cs{pdfannot_link:nnn} this function
+% does not absorb the argument when finding the \meta{content}, and so can
+% be used in circumstances where the \meta{content} may not be a simple
+% argument. But beside this, it works similar and use the same hooks.
+% As example
+% \begin{verbatim}
+% \pdfannot_link_begin:nnw { URI }
+% {
+% /A<<
+% /Type/Action
+% /S/URI
+% /URI(https://www.latex-project.org)
+% >>
+% }
+% link text
+% \pdfannot_link_end:n { URI }
+% \end{verbatim}
+% \end{function}
+% \begin{function}[updated = 2020-12-06]{ \pdfannot_link_goto_begin:nw, \pdfannot_link_goto_end: }
+% \begin{syntax}
+% \cs{pdfannot_link_goto_begin:nw} \Arg{destination} \meta{content}
+% \cs{pdfannot_link_goto_end:}
+% \end{syntax}
+% This is a special, shorter version for links to internal destinations. It always
+% uses the hooks and dictionary of the |GoTo| link type. \meta{destination} is a
+% destination name. In difference to |\pdfannot_link:nnn { GoTo }| it will complain if
+% \meta{destination} is an unknown destination and give the message
+%
+% |name{ZZZZ} has been referenced but does not exist, replaced by a fixed one|
+%
+% \end{function}
+% \begin{function}[added = 2021-02-14]{ \pdfannot_link_ref_last: }
+% This retrieves the object reference a link created previously with the commands
+% above. This doesn't work currently with xelatex but a feature request has
+% been made. see https://tug.org/pipermail/dvipdfmx/2020-December/000134.html
+% \end{function}
+% \begin{function}[added = 2021-02-14]{ \pdfannot_ref_last: }
+% This retrieves the object reference a previously annotation
+% created either with a link or a general box command. When the last was a link
+% it won't work with xelatex.
+% see https://tug.org/pipermail/dvipdfmx/2020-December/000134.html
+% \end{function}
+% \begin{NOTE}{UF}
+% only annot link or also annot?
+% \end{NOTE}
+% \begin{function}[added = 2020-03-12]{ \pdfannot_link_margin:n }
+% \begin{syntax}
+% \cs{pdfannot_link_margin:n} \Arg{dimen}
+% \end{syntax}
+% This sets the dimension of the link margin.
+% \end{function}
+% \begin{function}[added = 2020-12-04]{ \pdfannot_dict_put:nnn }
+% \begin{syntax}
+% \cs{pdfannot_dict_put:nnn} \Arg{dictionary name} \Arg{key} \Arg{value}
+% \end{syntax}
+% This adds (locally) a key-value to the internal annot dictionaries used
+% by the link commands above.
+% \meta{dictionary name} should be currently one of \texttt{link/URI},
+% \texttt{link/URI},\texttt{link/GoToR}, \texttt{link/Launch},
+% \texttt{link/GoTo}, \texttt{link/Named}.
+% \end{function}
+% \begin{function}[added = 2020-12-04]{ \pdfannot_dict_remove:nn }
+% \begin{syntax}
+% \cs{pdfannot_dict_remove:nn} \Arg{dictionary name} \Arg{key}
+% \end{syntax}
+% This removes a key-value from the internal annot dictionary
+% \meta{dictionary name} should be currently one of
+% \texttt{link/URI}, \texttt{link/GoToR}, \texttt{link/Launch},
+% \texttt{link/GoTo}, \texttt{link/Named}.
+% \end{function}
+% \begin{function}[added = 2020-12-04]{ \pdfannot_dict_show:n }
+% \begin{syntax}
+% \cs{pdfannot_dict_show:n} \Arg{dictionary name}
+% \end{syntax}
+% This shows the content of the internal annot dictionary.
+% \meta{dictionary name} should be currently one of \texttt{link/URI},
+% \texttt{link/URI}, \texttt{link/GoToR}, \texttt{link/Launch},
+% \texttt{link/GoTo}, \texttt{link/Named}.
+% \end{function}
+%
+% \begin{variable}[added = 2020-12-28]{\l_pdfannot_F_bitset}
+% This is a bitset variable, with the named index names suitable for the
+% /F flag in an annotation.
+% It can be used for example like this:
+% \begin{verbatim}
+% \pdfannot_dict_put:nnn {link/URI} {F}
+% { \bitset_to_arabic:N \l_pdfannot_F_bitset }
+% \bitset_set_true:Nn \l_pdfannot_F_bitset {Print}
+% \end{verbatim}
+% The known keys for the bitset are |Invisible|, |Hidden|,
+% |Print|, |NoZoom|, |NoRotate|, |NoView|, |ReadOnly|, |Locked|, |ToggleNoView|,
+% |LockedContents| which correspond to the names used in the PDF references.
+% \end{variable}
+% \end{documentation}
+%
+% \begin{implementation}
+%
+% \section{\pkg{l3pdfannot} implementation}
+%
+% \begin{macrocode}
+%<@@=pdfannot>
+%<*header>
+\ProvidesExplPackage {l3pdfannot} {2021-02-22} {0.95a}
+ {PDF-annotations}
+\RequirePackage{l3pdfdict}
+%</header>
+% \end{macrocode}
+% Annotations have a /F flag, we provide a public
+% bitset for it.
+% \begin{macrocode}
+%<*package>
+\RequirePackage{l3bitset}
+\bitset_new:Nn \l_pdfannot_F_bitset
+ {
+ Invisible = 1,
+ Hidden = 2,
+ Print = 3,
+ NoZoom = 4,
+ NoRotate = 5,
+ NoView = 6,
+ ReadOnly = 7,
+ Locked = 8,
+ ToggleNoView = 9,
+ LockedContents = 10
+ }
+% \end{macrocode}
+% \begin{NOTE}{UF}
+% The code/naming tries to unify general annotations and the special type of
+% link under a common name.
+% regarding naming and relation of annotation commands see
+% https://github.com/FrankMittelbach/AccessiblePDF/issues/73
+% \subsection{Annotations / backend}
+% The backend commands are in l3backend:
+% \cs{__pdf_backend_annotation:nnnn} and \cs{__pdf_backend_annotation_last:}
+% \cs{__pdf_backend_link_begin_user:nnw}, etc
+% \end{NOTE}
+%
+% \subsection{ General Annotations }
+% \begin{variable}
+% { \g_@@_use_lastlink_bool }
+% The pdf engines have two different primitive commands to refer to the last created
+% annotation: one for links, one for boxed annotation. We use a boolean to decide
+% which one should be used, so that only one user command is needed.
+% \begin{macrocode}
+\bool_new:N \g_@@_use_lastlink_bool
+% \end{macrocode}
+% \end{variable}
+% \begin{NOTE}{UF}
+% type or not type? Syntax for type?
+% should there be a version without type?
+% \end{NOTE}
+
+% \begin{macrocode}
+\cs_new_protected:Npn \pdfannot_box:nnnn #1 #2 #3 #4
+ {
+ \__pdf_backend_annotation:nnnn {#1}{#2}{#3}{#4}
+ \bool_gset_false:N\g_@@_use_lastlink_bool
+ }
+
+\cs_new:Npn \pdfannot_box_ref_last:
+ {
+ \__pdf_backend_annotation_last:
+ }
+
+\cs_new_protected:Npn \pdfannot_box:nnnnn #1 #2 #3 #4 #5
+ {
+ \exp_args:Nx
+ \__pdf_backend_annotation:nnnn {#2}{#3}{#4}
+ {
+ \pdfdict_if_exist:nT { l_@@/#1 }
+ {
+ \pdfdict_use:n { l_@@/#1}
+ }
+ #5
+ }
+ \bool_gset_false:N\g_@@_use_lastlink_bool
+ }
+% \end{macrocode}
+% \subsection{Annotations, subtype Widget}\label{pdf:annot:widget}
+% Currently no code is provided here.
+% The local dictionary \texttt{l_@@/Widget} is a skeleton
+% dictionary for this subtype. It currently contains as only entry
+% the subtype setting (the /Type is added by the backend).
+% \begin{macrocode}
+ \pdfdict_new:n { l_@@/widget }
+ \pdfdict_put:nnn { l_@@/widget }{ Subtype }{ /Widget }
+% \end{macrocode}
+%
+% \subsection{Annotations, subtype Link}\label{sec:links}
+% The code assumes that there will be different link types
+% (currently URI, GoToR, Launch, GoTo, Named, hyperref uses the names
+% url,file,run,link,menu) and that links of the same type share
+% the \emph{attr spec} and also the same begin/end
+% code. The list of link types need to stay restricted and well documented so that
+% all packages know which types they have to handle. It is stored in a constant
+% seq.
+% \begin{NOTE}{UF}
+% Perhaps a |cite| type will be useful at some time. -- Thinking more about it,
+% a |cite| type is not sensible. hyperref supports it, but it doesn't fit in.
+% Commands like cite, gls, acro, footnote and so on should locally change
+% linkcolor and linkbordercolor.
+% Probably we will need some commands to add an attribute to all link types
+% at once.
+% hyperref commands for the various type:
+% url |\hyper@linkurl|,
+% file |\hyper@linkfile|,
+% run |\@hyper@launch run|,
+% link |\hyper@link|, |\find@pdflink|
+% menu |\Acrobatmenu|
+% \end{NOTE}
+% \begin{variable}[added = 2020-03-12]{ \c_pdfannot_link_types_seq }
+% This constant sequence contains the list of currently supported link types
+% for which hooks and dictionaries exist.
+% \end{variable}
+%
+% \begin{variable}
+% {
+% link/TYPE,
+% pdfannot/link/TYPE/before,
+% pdfannot/link/TYPE/begin,
+% pdfannot/link/TYPE/end,
+% pdfannot/link/TYPE/after
+% }
+% These setup the dictionary and the hook pairs.
+% \begin{macrocode}
+\seq_const_from_clist:Nn \c_pdfannot_link_types_seq { URI , GoToR , Launch , GoTo, Named }
+\seq_map_inline:Nn \c_pdfannot_link_types_seq
+ {
+ \pdfdict_new:n { l_@@/link/#1 }
+ \hook_new_pair:nn
+ {pdfannot/link/#1/before}
+ {pdfannot/link/#1/after}
+ \hook_new_pair:nn
+ {pdfannot/link/#1/begin}
+ {pdfannot/link/#1/end}
+ }
+% \end{macrocode}
+% \end{variable}
+% \subsubsection{Annotations, subtype Link /management}
+%
+% \begin{macro}{\pdfannot_link:nnn,\pdfannot_link:nxn}
+% \begin{macrocode}
+\cs_new_protected:Nn \pdfannot_link:nnn %#1 type (URI, GoTo etc),
+ %#2 action spec, #3 link text
+ {
+ \hook_use:n { pdfannot/link/#1/before}
+ \mode_leave_vertical:
+ \exp_args:Nxx %xetex needs expansion
+ \__pdf_backend_link_begin_user:nnw
+ {
+ \pdfdict_if_exist:nT { l_@@/link/#1 }
+ {
+ \pdfdict_use:n { l_@@/link/#1}
+ }
+ }
+ {
+ /Subtype/Link
+ #2 %exp_not?
+ }
+ \bool_gset_true:N \g_@@_use_lastlink_bool
+ \hook_use:n { pdfannot/link/#1/begin}
+ #3
+ \hook_use:n { pdfannot/link/#1/end}
+ \__pdf_backend_link_end:
+ \bool_gset_true:N \g_@@_use_lastlink_bool
+ \hook_use:n { pdfannot/link/#1/after}
+ }
+\cs_generate_variant:Nn \pdfannot_link:nnn {nxn}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{
+% \pdfannot_link_begin:nnw,
+% \pdfannot_link_begin:nxw,
+% \pdfannot_link_end:n }
+% \begin{macrocode}
+\cs_new_protected:Npn \pdfannot_link_begin:nnw #1 #2 %#1 type, #2 action spec
+ {
+ \hook_use:n { pdfannot/link/#1/before}
+ \mode_leave_vertical:
+ \exp_args:Nxx %xetex needs expansion
+ \__pdf_backend_link_begin_user:nnw
+ {
+ \pdfdict_if_exist:nT { l_@@/link/#1 }
+ {
+ \pdfdict_use:n { l_@@/link/#1}
+ }
+ }
+ { #2 }
+ \bool_gset_true:N \g_@@_use_lastlink_bool
+ \hook_use:n { pdfannot/link/#1/begin}
+ }
+
+\cs_new_protected:Nn \pdfannot_link_end:n %#1 type, e.g. url
+ {
+ \hook_use:n { pdfannot/link/#1/end}
+ \__pdf_backend_link_end:
+ \bool_gset_true:N \g_@@_use_lastlink_bool
+ \hook_use:n { pdfannot/link/#1/after}
+ }
+\cs_generate_variant:Nn \pdfannot_link_begin:nnw {nxw}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\pdfannot_link_goto_begin:nw, \pdfannot_link_goto_end:}
+% \begin{macrocode}
+\cs_new_protected:Npn \pdfannot_link_goto_begin:nw #1 %#1 destination
+ {
+ \hook_use:n { pdfannot/link/GoTo/before}
+ \mode_leave_vertical:
+ \exp_args:Nxx %xetex needs expansion
+ \__pdf_backend_link_begin_goto:nnw
+ {
+ \pdfdict_use:n { l_@@/link/GoTo}
+ }
+ { #1 }
+ \bool_gset_true:N \g_@@_use_lastlink_bool
+ \hook_use:n { pdfannot/link/GoTo/begin}
+ }
+
+\cs_new_protected:Nn \pdfannot_link_goto_end:
+ {
+ \hook_use:n { pdfannot/link/GoTo/end}
+ \__pdf_backend_link_end:
+ \bool_gset_true:N \g_@@_use_lastlink_bool
+ \hook_use:n { pdfannot/link/GoTo/after}
+ }
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}[EXP]{\pdfannot_link_ref_last:, \pdfannot_ref_last:}
+% \begin{macrocode}
+\cs_new:Nn \pdfannot_link_ref_last: { \__pdf_backend_link_last: }
+% \end{macrocode}
+% \begin{macrocode}
+\cs_new:Npn \pdfannot_ref_last:
+ {
+ \bool_if:NTF \g_@@_use_lastlink_bool
+ {
+ \__pdf_backend_link_last:
+ }
+ {
+ \__pdf_backend_annotation_last:
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{ \pdfannot_link_margin:n}
+% \begin{macrocode}
+\cs_new_protected:Npn \pdfannot_link_margin:n #1
+ {
+ \__pdf_backend_link_margin:n { #1 }
+ }
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}
+% {
+% \pdfannot_dict_put:nnn,
+% \pdfannot_dict_put:nnx,
+% \pdfannot_dict_remove:nn,
+% \pdfannot_dict_show:n
+% }
+% \begin{macrocode}
+\cs_new_protected:Npn \pdfannot_dict_put:nnn #1 #2 #3
+ {
+ \pdfdict_put:nnn { l_@@/#1 } { #2 }{ #3 }
+ }
+\cs_generate_variant:Nn \pdfannot_dict_put:nnn {nnx}
+% \end{macrocode}
+% \begin{macrocode}
+\cs_new_protected:Npn \pdfannot_dict_remove:nn #1 #2
+ {
+ \pdfdict_remove:nn { l_@@/#1 } { #2 }
+ }
+% \end{macrocode}
+% \begin{macrocode}
+\cs_new_protected:Npn \pdfannot_dict_show:n #1
+ {
+ \pdfdict_show:n { l_@@/#1 }
+ }
+%</package>
+% \end{macrocode}
+% \end{macro}
+% \end{implementation}
+%
+% \PrintIndex
diff --git a/Master/texmf-dist/source/latex/pdfmanagement-testphase/l3pdfdict.dtx b/Master/texmf-dist/source/latex/pdfmanagement-testphase/l3pdfdict.dtx
new file mode 100644
index 00000000000..558b721ca57
--- /dev/null
+++ b/Master/texmf-dist/source/latex/pdfmanagement-testphase/l3pdfdict.dtx
@@ -0,0 +1,591 @@
+% \iffalse meta-comment
+%
+%% File: l3pdfdict.dtx
+%
+% Copyright (C) 2018-2021 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
+%
+% http://www.latex-project.org/lppl.txt
+%
+% This file is part of the "LaTeX PDF management testphase 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/pdfresources
+%
+% for those people who are interested.
+%
+%<*driver>
+\RequirePackage{pdfmanagement-testphase}
+\DeclareDocumentMetadata{pdfstandard=A-2b}
+\makeatletter
+\declare@file@substitution{doc.sty}{doc-v3beta.sty}
+\makeatother
+\documentclass[full]{l3doc}
+\usepackage{array,booktabs,hyperxmp}
+\hypersetup{pdfauthor=The LaTeX Project,
+ pdftitle=l3pdfdict (LaTeX PDF management testphase bundle)}
+
+\begin{document}
+ \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
+% \fi
+% \title{^^A
+% The \pkg{l3pdfdict} module---tools for PDF dictionaries ^^A
+% \\
+% \LaTeX{} PDF management testphase bundle
+% }
+%
+% \author{^^A
+% The \LaTeX{} Project\thanks
+% {^^A
+% E-mail:
+% \href{mailto:latex-team@latex-project.org}
+% {latex-team@latex-project.org}^^A
+% }^^A
+% }
+%
+% \date{Version 0.95a, released 2021-02-22}
+%
+% \maketitle
+% \begin{documentation}
+%
+% \section{\pkg{l3pdfdict} documentation}
+% Many PDF objects are or contain dictionaries---structures
+% containing a number of \mbox{(pdf-)}name/value pairs.
+% Examples are attributes of links,
+% filespec dictionaries, xform dictionaries, the catalog, the info dictionary.
+% The commands in this module offer an number of
+% tools to handle such dictionaries. The module setups a name space for the
+% dictionary names and offers some commands to output dictionaries.
+%
+% The dictionaries work in many respects
+% like property lists with a few PDF specific changes:
+% \begin{itemize}
+% \item The keys are always converted with \cs{str_convert_pdfname:n}
+% to get a correct PDF name;
+% \item a key with a empty value can not be added, it will be ignored;
+% \item there is a dedicated function to output the property as space
+% separated list with keys with slash: \texttt{/key1 value1 /key2 value2}.
+% \end{itemize}
+% Local and global dictionaries can be created.
+%
+% \subsection{User Commands}
+% \begin{function}[updated = 2020-12-03]
+% {\pdfdict_new:n}
+% \begin{syntax}
+% \cs{pdfdict_new:n} \Arg{dictionary name}
+% \end{syntax}
+% This function create a new local or global dictionary. Which one depends on
+% \meta{dictionary name}: If it begins with the standard |g| the dictionary is global,
+% with |l| the dictionary is local, other starting chars will give an error.
+% It is recommended to begin the name in the standard expl3 naming scheme
+% with one or two underscores and a module name,
+% so |g_module_XXXX| or |g__module_XXXX|.
+% \end{function}
+%
+% \begin{function}[added = 2020-06-16,updated = 2020-12-03]
+% {\pdfdict_set_eq:nn,\pdfdict_gset_eq:nn}
+% \begin{syntax}
+% \cs{pdfdict_set_eq:nn} \Arg{local dictionary name_1} \Arg{dictionary name_2}\\
+% \cs{pdfdict_gset_eq:nn} \Arg{global dictionary name_1}\Arg{dictionary name_2}
+% \end{syntax}
+% This functions copy \meta{dictionary name_2} into
+% \meta{local/global dictionary name_1} locally or globally. If the
+% dictionary \meta{local/global dictionary name_1} doesn't exist yet, it will be created.
+% If \meta{dictionary name_2} doesn't exist yet, an error will be raised.
+% \end{function}
+%
+% \begin{function}[added = 2020-04-06]
+% {\pdfdict_put:nnn, \pdfdict_gput:nnn}
+% \begin{syntax}
+% \cs{pdfdict_put:nnn} \Arg{local dictionary} \Arg{name} \Arg{value} \\
+% \cs{pdfdict_gput:nnn} \Arg{global dictionary} \Arg{name} \Arg{value}
+% \end{syntax}
+% This function puts key \meta{name} and value \meta{value} locally or globally in the
+% \meta{dictionary} created with \cs{pdfdict_new:n}.
+% \Arg{name} should be a PDF Name without the starting slash. It will be stored
+% with \cs{str_convert_pdfname:n}, so will be automatically correctly escaped in case
+% it contains slashes, spaces or other chars not allowed in a PDF name.
+% \meta{value} should be a valid PDF value for this name in the
+% target dictionary. The value is \emph{neither} converted \emph{nor} escaped automatically.
+% If the value is blank nothing is added to the dictionary.
+%
+% When adding a value keep in mind that the expansion behaviour
+% of the backends differ. Some backends expand a
+% value always fully when writing to the PDF, with other backends commands
+% could end as strings in the PDF. This makes controlling the
+% expansion quite tricky. It is better to not rely on
+% \meta{value} to be expanded nor not expanded by the backend commands.
+% \end{function}
+%
+% \begin{function}[EXP,added = 2020-12-04]
+% { \pdfdict_item:nn, \pdfdict_item:ne }
+% \begin{syntax}
+% \cs{pdfdict_item:nn} \Arg{key} \Arg{value}
+% \end{syntax}
+% A simple command to output key-value as |/key value|. This is
+% needed to output dictionaries in mapping commands. The command doesn't
+% do any escaping, it expects that the name has been escaped when the value
+% has been stored into the dictionary.
+% If the value is blank nothing is output.
+% The command is expandable if the content is it.
+% \end{function}
+%
+% \begin{function}[EXP,updated = 2020-12-03]
+% { \pdfdict_use:n }
+% \begin{syntax}
+% \cs{pdfdict_use:n} \Arg{dictionary}
+% \end{syntax}
+% This outputs the property list of the dictionary as a list of
+% |/key value| pairs.
+% This can be used e.g. when writing a dictionary object with
+% \cs{pdf_object_write:nx}
+% \end{function}
+%
+% \begin{function}[updated = 2020-12-03]
+% {\pdfdict_show:n }
+% \begin{syntax}
+% \cs{pdfdict_show:n} \Arg{dictionary}
+% \end{syntax}
+% This shows the content of \meta{dictionary} in the log and on the terminal.
+% \end{function}
+%\begin{function}[EXP, pTF,updated = 2020-12-03]
+% { \pdfdict_if_exist:n }
+% \begin{syntax}
+% \cs{pdfdict_if_exist:n} \Arg{dictionary}
+% \end{syntax}
+% This tests if the dictionary exists.
+% \end{function}
+% \begin{function}[EXP, pTF,updated = 2020-12-03]
+% { \pdfdict_if_empty:n }
+% \begin{syntax}
+% \cs{pdfdict_if_empty:n} \Arg{dictionary}
+% \end{syntax}
+% This tests if the dictionary is empty. The result is false if the
+% dictionary doesn't exist.
+% \end{function}
+% \begin{function}[added = 2020-07-06]
+% {\pdfdict_get:nnN }
+% \begin{syntax}
+% \cs{pdfdict_get:nnN} \Arg{dictionary} \Arg{name} \meta{tl var}
+% \end{syntax}
+% Recovers the \meta{value} stored by \cs{pdfdict_put:nnn} or
+% \cs{pdfdict_gput:nnn}
+% for \meta{name} and places this in the \meta{token list
+% variable}. If \meta{name} is not found
+% then the \meta{token list variable} is set
+% to the special marker \cs{q_no_value}. \meta{name} is first converted
+% with \cs{str_convert_pdfname:n}. The \meta{token list
+% variable} is set within the current \TeX{} group.
+% \end{function}
+%
+% \begin{function}[updated = 2020-12-03]
+% {
+% \pdfdict_remove:nn, \pdfdict_gremove:nn
+% }
+% \begin{syntax}
+% \cs{pdfdict_remove:nn} \Arg{local dictionary} \Arg{name}\\
+% \cs{pdfdict_gremove:nn} \Arg{global dictionary} \Arg{name}
+% \end{syntax}
+% Removes \meta{name} and its associated \meta{value} from
+% the \Arg{dictionary}
+% The removal is local from local dictionaries
+% and global from global dictionaries.
+% If \meta{name} is not found no change occurs,
+% \emph{i.e}~there is no need to test for the existence of a name before
+% trying to remove it. \meta{name} is first converted
+% with \cs{str_convert_pdfname:n}.
+% \end{function}
+% \end{documentation}
+%
+% \begin{implementation}
+% \section{\pkg{l3pdfdict} implementation}
+% \begin{macrocode}
+%<@@=pdfdict>
+%<*header>
+\ProvidesExplPackage {l3pdfdict} {2021-02-22} {0.95a}
+ {Tools for PDF dictionaries (LaTeX PDF management testphase bundle)}
+%</header>
+% \end{macrocode}
+% \subsection{messages}
+% \begin{macrocode}
+%<*package>
+\cs_new:Npn \@@_get_type:n #1
+ {
+ \str_case_e:nn { \str_head:n{#1} }
+ {
+ {g}{global}
+ {l}{local}
+ }
+ }
+\msg_new:nnn { pdfdict } { show-dict }
+ { %#1: name of the dictionary
+ %#2: expanded content
+ %#3: type
+ The~#3~dictionary~'#1'~
+ \tl_if_empty:nTF {#2}
+ { is~empty \\>~ . }
+ { contains~the~pairs~(without~outer~braces): #2 . }
+ }
+\msg_new:nnn { pdfdict } { unknown-dict }
+ {
+ The~dictionary~'#1'~is~unknown.
+ }
+\msg_new:nnn { pdfdict } { dict-already-defined }
+ {
+ The~#2~dictionary~'#1'~is~already~defined.
+ }
+\msg_new:nnn { pdfdict } { empty-value }
+ { The~value~#1~for~#2~is~blank~and~will~be~ignored }
+
+\msg_new:nnn { pdfdict } { invalid-name }
+ { Name~'#1'~is~not~valid\\
+ Names~of~dictionaries~should~start~with~'g_'~or~'l_' }
+
+% \end{macrocode}
+%
+
+% \subsection{Creating dictionaries}
+% \begin{variable}
+% {\g_@@_names_seq,\g_@@_gnames_seq}
+% Two seq to store the used names for diagnostics.
+% \begin{macrocode}
+\seq_new:N \g_@@_lnames_seq
+\seq_new:N \g_@@_gnames_seq
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}
+% {
+% \@@_name:n, \__kernel_pdfdict_name:n,
+% \@@_new:n, \pdfdict_new:n,
+% }
+%
+% This are the commands to create new dictionaries and to access their internal
+% name. All internal names start with |g__pdfdict_/| or |l__pdfdict_/|.
+%
+% For the other modules we also need a kernel command to access the internal
+% name to speed up the code and allow the use standard commands
+% of the \texttt{prop} module to deal with the dictionaries. For example\\
+% |\prop_clear:c { \__kernel_pdfdict_name:n { name }}|
+%
+% \begin{macrocode}
+\cs_new:Npn \@@_name:n #1 % #1 dictionary name
+ {
+ \str_head:n{#1}_@@_/#1_prop
+ }
+\cs_set_eq:NN \__kernel_pdfdict_name:n \@@_name:n
+
+\cs_new_protected:Npn \@@_new:n #1
+ {
+ \@@_if_exist:nTF { #1 }
+ {
+ \msg_error:nnxx
+ { pdfdict }
+ { dict-already-defined }
+ { \tl_to_str:n {#1} }
+ { \@@_get_type:n{#1} }
+ }
+ {
+ \str_case_e:nnF { \str_head:n{#1} }
+ {
+ {g}
+ {
+ \prop_new:c { \@@_name:n { #1 } }
+ \seq_gput_right:cn {g_@@_gnames_seq} { #1 }
+ }
+ {l}
+ {
+ \prop_new:c { \@@_name:n { #1 } }
+ \seq_gput_right:cn {g_@@_lnames_seq} { #1 }
+ }
+ }
+ {
+ \msg_error:nnx{pdfdict}{invalid-name}{\tl_to_str:n{#1}}
+ }
+ }
+ }
+
+\cs_set_eq:NN \pdfdict_new:n \@@_new:n
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}
+% {
+% \@@_set_eq:nn,\pdfdict_set_eq:nn,
+% \@@_gset_eq:nn,\pdfdict_gset_eq:nn
+% }
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_set_eq:nn #1 #2
+ {
+ \@@_if_exist:nTF { #2 }
+ {
+ \@@_if_exist:nF { #1 }
+ {
+ \@@_new:n { #1 }
+ }
+ \prop_set_eq:cc { \@@_name:n {#1} }{ \@@_name:n {#2} }
+ }
+ {
+ \msg_error:nnn { pdfdict } { unknown-dict } { #1 }
+ }
+ }
+
+\cs_set_eq:NN \pdfdict_set_eq:nn \@@_set_eq:nn
+
+\cs_new_protected:Npn \@@_gset_eq:nn #1 #2
+ {
+ \@@_if_exist:nTF { #2 }
+ {
+ \@@_if_exist:nF { #1 }
+ {
+ \@@_new:n { #1 }
+ }
+ \prop_gset_eq:cc { \@@_name:n {#1} }{ \@@_name:n {#2} }
+ }
+ {
+ \msg_error:nnn { pdfdict } { unknown-dict } { #1 }
+ }
+ }
+
+\cs_set_eq:NN \pdfdict_gset_eq:nn \@@_gset_eq:nn
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}
+% {
+% \@@_if_exist:n, \pdfdict_if_exist:n,
+% }
+%
+% Existence tests.
+% \begin{macrocode}
+%local
+\prg_new_conditional:Npnn \@@_if_exist:n #1 { p , T , F , TF }
+ {
+ \prop_if_exist:cTF
+ { \@@_name:n { #1 } }
+ { \prg_return_true: }
+ { \prg_return_false: }
+ }
+\prg_set_eq_conditional:NNn
+ \pdfdict_if_exist:n \@@_if_exist:n { p , T , F , TF }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}
+% {
+% \@@_if_empty:n, \pdfdict_if_empty:n,
+% }
+%
+% Tests for emptiness.
+% \begin{macrocode}
+\prg_new_conditional:Npnn \@@_if_empty:n #1 { p , T , F , TF }
+ {
+ \prop_if_empty:cTF
+ { \@@_name:n { #1 } }
+ { \prg_return_true: }
+ { \prg_return_false: }
+ }
+
+\prg_set_eq_conditional:NNn
+ \pdfdict_if_empty:n \@@_if_empty:n { p , T , F , TF }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}
+% {
+% \@@_put:nnn, \pdfdict_put:nnn,
+% \@@_gput:nnn,\pdfdict_gput:nnn
+% }
+% These are the commands to store values into the dictionaries.
+% The main difference to adding values to a normal property list is,
+% that the keys are converted with \cs{str_convert_pdfname:n}
+% and that empty values are ignored.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_put:nnn #1 #2 #3 %#1 (local) dict, #2 name, #3 value
+ {
+ \tl_if_blank:nTF { #3 }
+ {
+ \msg_warning:nnnn { pdfdict }{ empty-value }{ #2 } { #1 }
+ }
+ {
+ \@@_if_exist:nTF { #1 }
+ {
+ \exp_args:Nnx \prop_put:cnn
+ { \@@_name:n { #1 } }{ \str_convert_pdfname:n { #2 } } { #3 }
+ }
+ {
+ \msg_error:nnn { pdfdict } { unknown-dict } { #1 }
+ }
+ }
+ }
+
+\cs_set_eq:NN \pdfdict_put:nnn \@@_put:nnn
+\cs_generate_variant:Nn \pdfdict_put:nnn {nnx,nno}
+
+\cs_new_protected:Npn \@@_gput:nnn #1 #2 #3 %#1 global dict, #2 name, #3 value
+ {
+ \tl_if_empty:nTF { #3 }
+ {
+ \msg_warning:nnnn { pdfdict }{ empty-value }{ #2 } { #1 }
+ }
+ {
+ \@@_if_exist:nTF { #1 }
+ {
+ \exp_args:Nnx \prop_gput:cnn
+ { \@@_name:n { #1 } }{ \str_convert_pdfname:n { #2 } } { #3 }
+ }
+ {
+ \msg_error:nnn { pdfdict } { unknown-dict } { #1 }
+ }
+ }
+ }
+
+\cs_set_eq:NN \pdfdict_gput:nnn \@@_gput:nnn
+\cs_generate_variant:Nn \pdfdict_gput:nnn {nnx,nno}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}
+% {
+% \@@_get:nnN, \pdfdict_get:nnN,
+% }
+% Recover the values. The name must be first escaped to match the stored name.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_get:nnN #1 #2 #3 %dict,key,macro
+ {
+ \@@_if_exist:nTF { #1 }
+ {
+ \exp_args:Nnx \prop_get:cnN
+ { \@@_name:n { #1 } }
+ { \str_convert_pdfname:n { #2 } } #3
+ }
+ {
+ \msg_error:nnn { pdfdict } { unknown-dict } { #1 }
+ }
+ }
+
+\cs_set_eq:NN \pdfdict_get:nnN \@@_get:nnN
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}
+% {
+% \@@_remove:nn, \pdfdict_remove:nn,
+% \@@_gremove:nn,\pdfdict_gremove:nn
+% }
+% This removes a name/value pair from a dictionary.
+% The name has to be passed through the escaping.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_remove:nn #1 #2 %dict,name
+ {
+ \@@_if_exist:nTF { #1 }
+ {
+ \exp_args:Nnx \prop_remove:cn
+ { \@@_name:n { #1 } }{ \str_convert_pdfname:n { #2 } }
+ }
+ {
+ \msg_error:nnn { pdfdict } { unknown-dict } { #1 }
+ }
+ }
+\cs_set_eq:NN \pdfdict_remove:nn \@@_remove:nn
+
+\cs_new_protected:Npn \@@_gremove:nn #1 #2 %dict,name
+ {
+ \@@_if_exist:nTF { #1 }
+ {
+ \exp_args:Nnx \prop_gremove:cn
+ { \@@_name:n { #1 } }{ \str_convert_pdfname:n { #2 } }
+ }
+ {
+ \msg_error:nnn { pdfdict } { unknown-dict } { #1 }
+ }
+ }
+
+\cs_set_eq:NN \pdfdict_gremove:nn \@@_gremove:nn
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}
+% { \@@_show:Nn, \pdfdict_show:n }
+% This allows to show the content of dictionaries. It also displays if a
+% dictionary is local or global. If both exists both are shown.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_show:Nn #1#2 %#1 message command, #2 dict
+ {
+ \prop_if_exist:cTF { \@@_name:n { #2 } }
+ {
+ #1
+ { pdfdict }
+ { show-dict }
+ { \tl_to_str:n {#2} }
+ { \prop_map_function:cN {\@@_name:n { #2 }} \msg_show_item:nn }
+ { \@@_get_type:n{#2} }
+ { }
+ }
+ {
+ #1 { pdfdict } { unknown-dict } { #2 } {}{}{}
+ }
+ }
+\cs_new_protected:Npn \pdfdict_show:n #1
+ {
+ \@@_show:Nn \msg_show:nnxxxx {#1}
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}{\@@_item:nn, \@@_item:ne}
+% \begin{macro}{\pdfdict_item:nn, \pdfdict_item:ne}
+% \begin{macrocode}
+\cs_new:Npn \@@_item:nn #1 #2 %#1 name, #2 value
+ {
+ \tl_if_blank:nF {#2} { /#1~#2~ }
+ }
+\cs_generate_variant:Nn \@@_item:nn {ne}
+\cs_set_eq:NN \pdfdict_item:nn \@@_item:nn
+\cs_generate_variant:Nn \pdfdict_item:nn {ne}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+%
+% \begin{macro}
+% {
+% \@@_use:n,\pdfdict_use:n
+% }
+% \cs{@@_use:n} outputs a prop as needed in a dictionary:
+% as a list of /\meta{key} \meta{value} pairs.
+% \begin{NOTE}{UF}
+% !! is e-expansion the right thing?
+% \end{NOTE}
+% \begin{macrocode}
+\cs_new:Npn \@@_use:n #1 %#1 dict
+ {
+ \prop_map_function:cN { \@@_name:n { #1 } } \@@_item:ne
+ }
+
+\cs_set_eq:NN \pdfdict_use:n \@@_use:n
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macrocode}
+%</package>
+% \end{macrocode}
+%
+% \end{implementation}
+%
+% \PrintIndex
diff --git a/Master/texmf-dist/source/latex/pdfmanagement-testphase/l3pdffile.dtx b/Master/texmf-dist/source/latex/pdfmanagement-testphase/l3pdffile.dtx
new file mode 100644
index 00000000000..c1a2a25591d
--- /dev/null
+++ b/Master/texmf-dist/source/latex/pdfmanagement-testphase/l3pdffile.dtx
@@ -0,0 +1,746 @@
+% \iffalse meta-comment
+%
+%% File: l3pdffile.dtx
+%
+% Copyright (C) 2018-2021 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
+%
+% http://www.latex-project.org/lppl.txt
+%
+% This file is part of the "LaTeX PDF management testphase bundle" (The Work in LPPL)
+% and all files in that bundle must be distributed together.
+%
+% -----------------------------------------------------------------------
+%
+% The development version of the package can be found at
+%
+% https://github.com/latex3/pdfresources
+%
+% for those people who are interested.
+%
+%<*driver>
+\RequirePackage{pdfmanagement-testphase}
+\DeclareDocumentMetadata{pdfstandard=A-2b}
+\makeatletter
+\declare@file@substitution{doc.sty}{doc-v3beta.sty}
+\makeatother
+\documentclass[full]{l3doc}
+\usepackage{array,booktabs,hyperxmp}
+\hypersetup{pdfauthor=The LaTeX Project,pdftitle=l3pdffile (LaTeX PDF management testphase bundle)}
+
+\providecommand\potentialclash{\noindent\llap{\dbend\ }}
+\begin{document}
+ \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
+% \fi
+%
+% \title{^^A
+% The \pkg{l3pdffile} module\\ Embedding and referencing files in a PDF ^^A
+% \\ \LaTeX{} PDF management testphase bundle
+% }
+%
+% \author{^^A
+% The \LaTeX{} Project\thanks
+% {^^A
+% E-mail:
+% \href{mailto:latex-team@latex-project.org}
+% {latex-team@latex-project.org}^^A
+% }^^A
+% }
+%
+% \date{Version 0.95a, released 2021-02-22}
+%
+% \maketitle
+% \begin{documentation}
+%
+% \section{\pkg{l3pdffile} documentation}
+% \subsection{Introduction}
+% \subsubsection{Background}
+% External files can be referenced from a PDF in three ways:
+% \begin{enumerate}
+% \item through an annotation of type Link,
+% \item by referencing a local file in the file system,
+% \item by embedding the file directly into the PDF
+% \end{enumerate}
+% Case 1 (Links) are created with the \cs{pdfannot} commands.
+% This module handles the two other cases. Actually from the view
+% of the PDF format they are quite similar: Case 2 is case 3 without the stream
+% object and without the /EF entry in the /FileSpec dictionary (this points to the
+% stream object of the file). Not embedding the file makes the PDF smaller. But it is
+% also less portable: the files can only be found if they are in the right location
+% relative to the PDF. The normal case is to embed the file.
+%
+% The tasks to embed and reference such a file are
+% \begin{enumerate}
+% \item Embed the file in a stream.
+% \item Create a FileSpec dictionary which references the stream object in the /EF
+% dictionary:
+% \begin{verbatim}
+% <<
+% /Type /Filespec
+% /F (l3pdffile.dtx)
+% /UF (l3pdffile.dtx)
+% /AFRelationship /Source
+% /EF <</F 21 0 R /UF 21 0 R>> %case 3, embedded file
+% >>
+% \end{verbatim}
+% The file names in the /UF and /F value don't need to be identical to the
+% name of file on the disc. It is quite possible to embed a \texttt{zzz.tex}
+% and name it \texttt{blub.tex}. The second name is then what the user will see
+% in the attachment list or in the properties of an annotation.
+%
+%\item Reference the FileSpec dictionary so that the user can access the file.
+% This can be done in various way:
+% \begin{enumerate}
+% \item With an annotation (/Subtype/FileAttachment). This is done by
+% \pkg{attachfile}, \pkg{attachfile2} and \pkg{intopdf}.
+% Typical entries of such an annotation are:
+%
+% \medskip
+% \begin{tabular}{lll}
+% key & value type & notes\\\hline
+% /FS & object reference &(FileSpec dictionary)\\
+% /Name & name & /Graph, /PushPin, /Paperclip, /Tag\\
+% /Contents & text string & optional but recommended\\
+% /F & integer & Flags\\
+% /AP & dictionary & Appearance (required if rectangle >0) \\
+% /AS & name\\
+% \end{tabular}
+%
+% The |/AP| takes precedence over Border and similar keys.
+% \item Through an entry in the |/EmbeddedFiles| name tree.
+% This is what \pkg{embedfiles} does.
+% \begin{verbatim}
+% 20 0 obj %Document Name tree
+% <</EmbeddedFiles 21 0 R>>
+% endobj
+% 21 0 obj %Embedded Files Name dictionary
+% <</Names [(AcmeCustomCrypto Protected PDF.pdf) 17 0 R]>>
+% endobj
+% \end{verbatim}
+% The strings (keys) in the |/Names| dictionary must be sorted lexically.
+% But they don't have to be the file name or anything related to
+% the file name. The resource management code uses l3emb0001, l3emb0002~\ldots,
+% which allows up to 9999 files.
+% The key can be needed to identify the start file in a collection,
+% so their relation to the files are stored in a property list.
+%
+% \item Through the |/AF| key in various objects (pdf 2.0).
+% The value is normally an array of object
+% references, but it can also be a name which is mapped to an array in /Properties:
+% \begin{verbatim}
+% /AF /NamedAF BDC
+% /Properties <</NamedAF [12 0 R]
+% \end{verbatim}
+% The related |/FileSpec| dictionary should contain an
+% |/AFRelationship| key in this case (but it doesn't harm to add it by
+% default anyway). The values of this key is describe in table~\ref{tab:AFrel}.
+%
+% \begin{table}
+% \caption{Values of the \texttt{/AFRelationship} key\label{tab:AFrel}}
+% \begin{tabular}{lp{8cm}}
+% Source & shall be used if this file specification is the original
+% source material for the associated content.\\
+% Data & shall be used if this file specification represents
+% information used to
+% derive a visual presentation – such as for a table or a graph.\\
+% Alternative & shall be used if this file specification is an
+% alternative representation of content, for example audio.\\
+% Supplement & shall be used if this file specification represents
+% a supplemental representation of the original source or data
+% that may be more easily consumable
+% (e.g., A MathML version of an equation).\\
+% EncryptedPayload & shall be used if this file specification
+% is an encrypted payload document that should be displayed to the user
+% if the PDF processor has the cryptographic filter
+% needed to decrypt the document.\\
+% FormData & shall be used if this file specification
+% is the data associated with the AcroForm
+% (see 12.7.3, \enquote{Interactive form dictionary}) of this PDF.\\
+% Schema & shall be used if this file specification is a schema
+% definition for the associated object
+% (e.g. an XML schema associated with a metadata stream).\\
+% Unspecified &(default value) shall be used when the
+% relationship is not known
+% or cannot be described using one of the other values.\\
+% Other names & Second-class names (see Annex E,
+% \enquote{(normative) PDF Name Registry}) should be used to
+% represent other types of relationships.
+% \end{tabular}
+% \end{table}
+% \end{enumerate}
+% \end{enumerate}
+%
+% \subsubsection{Task 1: Embedding a file}
+% Embedding an existing file is in most cases quite straightforward. This module
+% offers commands, but it can also be done with the basic commands
+% from the |l3pdf| module \cs{pdf_object_unnamed_write:nn} or
+% \cs{pdf_object_new:nn}/\cs{pdf_object_write:nn} or primitive commands
+% to create objects.
+% The object number should be stored for the reference
+% in the |/FileSpec| dictionary.
+%
+% \begin{verbatim}
+% \pdf_object_unnamed_write:nx {fstream}
+% {
+% {
+% /Type /EmbeddedFile
+% /Subtype /application\c_hash_str2Fpostscript
+% /Params
+% <<
+% /ModDate ~ (\file_timestamp:n{example-image.eps})
+% /Size ~ \file_size:n {example-image.eps}
+% /CheckSum ~ (\file_mdfive_hash:n {example-image.eps})
+% >>
+% }
+% {example-image.eps}
+% }
+% \tl_set:Nx \l_my_fileobj_tl {\pdf_object_ref_last:}
+% \end{verbatim}
+%
+% \begin{itemize}
+% \item The |/Params| dictionary is not always required, but the commands of
+% these module will prefill them as shown in the examples. A |/CreationDate| entry
+% has to be added explicitly as there is no sensible way
+% to retrieve this automatically.
+% \item The mimetype (in the |/Subtype|) should be properly escaped.
+% This module contains a property list with maps a number of file extensions
+% to mimetypes and the commands try to detect and fill the mimetype automatically.
+% \item The dictionary can contain additional keys (|/Filter|, |/DecodeParms|),
+% see the pdf reference.
+% \end{itemize}
+%
+% \subsubsection{Task 2: Creating the \texttt{/FileSpec} dictionary}
+% The |/FileSpec| dictionary is a simple dictionary object, and can also
+% be created in various ways. If it refers to an embedded file it should
+% reference it in the |/EF| key.
+%
+% \subsubsection{Task 3: Referencing the \texttt{/FileSpec} dictionary}
+%
+% Using the dictionary reference in annotations and |/AF| keys is unproblematic.
+%
+% \potentialclash
+% But to add it to the |/EmbeddedFiles| name tree so that it appears in the
+% attachment panel requires special care:
+% This name tree is a global resource and uncoordinated access can lead to
+% clashes and files that are not visible or inaccessible.
+% The access here is managed by the \pkg{l3pdfmanagement} module:\\[\smallskipamount]%
+% |\pdfmanagement_add:nnx{Catalog/Names}{EmbeddedFiles}{|\meta{objref}|}|
+%
+% \subsection{Commands and tools of these module}
+% \begin{function}{file, file/Params, file/streamParams,file/FileSpec}
+% The module predefines and uses a number of local dictionaries for the
+% components of the stream and the |/FileSpec| object. These dictionaries are
+% then used by the \cs{pdffile_embed_XX}.
+% The content of these dictionaries can be changed by users with the commands
+% from the \pkg{l3pdfdict} module, but it should be done only locally
+% to avoid side effects on uses by other packages/commands.
+
+% The preset values are of these dictionaries are shown in table~\ref{tab:filedict}.
+% \end{function}
+% \begin{table}
+% \caption{Preset values in the file dictionaries\label{tab:filedict}}
+% \begin{tabular}{lll}
+% dictionary & key & value \\\hline
+% l\_pdffile & Type & /EmbeddedFile\\
+% l\_pdffile/Params& Size & |\file_size:n{\l_pdffile_source_name_str}|\\
+% l\_pdffile/Params& ModDate & |(\file_timestamp:n {\l_pdffile_source_name_str})|\\
+% l\_pdffile/Params& CheckSum & |(\file_mdfive_hash:n{\l_pdffile_source_name_str})|\\
+% l\_pdffile/streamParams& & a /ModDate entry with year/month/date (used with \cs{pdffile_embed_stream:nnn})\\
+% l\_pdffile/FileSpec & Type & /FileSpec\\
+% l\_pdffile/FileSpec & AFRelationship &Unspecified
+% \end{tabular}
+% \end{table}
+% \begin{function}{\pdffile_embed_file:nnn}
+% \begin{syntax}
+% \cs{pdffile_embed_file:nnn} \Arg{source filename} \Arg{target filename} \Arg{object name }
+% \end{syntax}
+% This commands embeds the file \meta{source filename} in the PDF,
+% and creates a |/FileSpec| dictionary object named \meta{object name}.
+% The object name must be unique.
+% The command uses the content of the local
+% dictionaries |l_pdffile|, |l_pdffile/Params| and |l_pdffile/FileSpec|
+% to setup the dictionary entries of the stream object and the
+% |/FileSpec| dictionary. The |/F| and |/UF| entry are filled
+% with \meta{target filename}.
+%
+% It is an error if both \meta{target filename} and \meta{source filename}
+% are empty.
+%
+% If \meta{target filename} is empty \meta{source filename} is used instead.
+%
+% If \meta{source filename} is empty, only a |/FileSpec| dictionary is
+% created.
+%
+% If the |l_pdffile| dictionary doesn't contain a
+% Subtype entry with the mimetype, the command tries to guess it
+% from the file extension of \meta{source filename}. Unknown file extensions can be
+% added (or known extension be changed) by adding to or changing the value in
+% the property \cs{g_pdffile_mimetypes_prop}, see below.
+%
+% When using \texttt{dvips} and \texttt{pstopdf} the actual embedding is
+% done by \texttt{pstopdf}. \texttt{pstopdf} will embed files
+% only if used with the option \texttt{-dNOSAFER} and will not be able
+% to use files which are found with \texttt{kpathsea}.
+%
+% \meta{target filename} doesn't need to be a file name with an extension,
+% but it is recommended as security settings in the pdf
+% viewer can restrict access to known file types.
+% \end{function}
+%
+% \begin{NOTE}{UF}
+% we should perhaps also consider the chunk method see pdfbase and
+% https://chat.stackexchange.com/transcript/message/54181193#54181193
+% \end{NOTE}
+%
+% \begin{function}{\pdffile_embed_stream:nnn}
+% \begin{syntax}
+% \cs{pdffile_embed_stream:nnn} \Arg{content} \Arg{target filename} \Arg{object name }
+% \end{syntax}
+% This commands embeds the \meta{content} in the PDF in a stream objects and
+% creates a |/FileSpec| dictionary object named \meta{object name}.
+% \meta{content} is wrapped in a \cs{exp_not:n}.
+% The object name must be unique. The command uses the content of the local
+% dictionaries |l_pdffile|, |l_pdffile/streamParams| and |l_pdffile/FileSpec|
+% to setup the dictionary entries of the stream object and the /FileSpec dictionary.
+% The /F and /UF entry are filled with \meta{target filename}.
+% If \meta{target filename} is empty the fix name \texttt{stream.txt}
+% is used instead.
+%
+% If the |l_pdffile| dictionary doesn't contain a
+% Subtype entry with the mimetype, the command tries to guess it
+% from the file extension of \meta{target filename}.
+%
+% \meta{target filename} doesn't need to be a file name with an extension,
+% but it is recommended as security settings in the pdf
+% viewer can restrict access to known file types.
+%
+% The stream should not be too long, at least PS imposes a size limit for strings.
+% \end{function}
+%
+% \begin{variable}{\g_pdffile_mimetypes_prop}
+% This property contains a list of extensions and their mimetypes.
+% Values can be added or changed with the standard commands:
+%
+% |\prop_gput:Nnn \g_pdffile_mimetypes_prop {.abc}{text/plain}|
+%
+% The extension should start with a period, the mimetype should be given
+% as plain text (it will be escaped internally). Extensions with two periods
+% are not supported.
+% \end{variable}
+%
+% \begin{variable}{\l_pdffile_source_name_str}
+% This variable is set at the begin of \cs{pdffile_embed_file:nnn}. It can be
+% (and is) used in the file dictionaries, see table~\ref{tab:filedict} for examples.
+% \end{variable}
+%
+% \begin{variable} {\g_pdffile_embed_prop}
+% This property holds a list of embedded files. It is used by the following
+% show command. The keys are the object names, the argument holds a key word,
+% the source file name and the target file name.
+% \end{variable}
+%
+% \begin{function}{\pdffile_embed_show:}
+% This shows the embedded files with their source and target name.
+% \end{function}
+%
+% \subsection{Example}
+% \begin{verbatim}
+% \group_begin:
+% %set the relationship:
+% \pdfdict_put:nnn {l_pdffile/FileSpec} {AFRelationship}{/Source}
+% %set the description key. The text must first be converted:
+% \pdf_string_from_unicode:nnN {utf16/string}
+% {this~is~an~odd~description~with~öäü}
+% \l_tmpa_str
+% \pdfdict_put:nnx {l_pdffile/FileSpec} {Desc}{\l_tmpa_str}
+% %embeds testinput.txt and calls it grüße.txt
+% \pdffile_embed_file:nnn {testinput.txt}{grüße.txt}{file:example1}
+% %reference it in the panel
+% \pdfmanagement_add:nnx
+% {Catalog/Names}
+% {EmbeddedFiles}
+% {\pdf_object_ref:n{file:example1}}
+% \group_end:
+% \end{verbatim}
+% \end{documentation}
+%
+% \begin{implementation}
+%
+% \section{\pkg{l3pdffile} implementation}
+%
+% \begin{macrocode}
+%<*header>
+\ProvidesExplPackage {l3pdffile} {2021-02-22} {0.95a}
+ {embedding and referencing files in PDF---LaTeX PDF management testphase bundle}
+\RequirePackage{l3pdftools} %temporarly!!
+%</header>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<*package>
+%<@@=pdffile>
+\cs_new_protected:Npn \@@_filename_convert_to_print:nN #1 #2
+ {\pdf_string_from_unicode:nnN {utf16/hex}{#1}{#2}}
+% \end{macrocode}
+% \subsection{Messages}
+% \begin{macrocode}
+\msg_new:nnn { pdffile } { file-not-found }
+ {
+ File~'\tl_to_str:n{#1}'~not~found
+ }
+
+\msg_new:nnn { pdffile } { mimetype-missing }
+ {
+ Mime~type~not~set~for~file~'\tl_to_str:n{#1}'
+ }
+
+\msg_new:nnn { pdffile } { target-name-missing }
+ {
+ a~target~name~for~the~/FileSpec~dictionary~is~missing.
+ }
+
+\msg_new:nnn { pdffile } { object-exists }
+ {
+ object~name~'#1'~is~already~used.
+ }
+
+\msg_new:nnn { pdffile } { show-files }
+ {
+ The~following~files~have~been~embedded\\
+ #1
+ }
+% \end{macrocode}
+% \begin{variable}
+% {
+% \l_@@_tmpa_tl,
+% \l_@@_tmpb_tl,
+% \l_@@_tmpa_str,
+% \l_@@_tmpb_str,
+% \l_@@_ext_str,
+% \l_@@_automimetype_tl,
+% \l_@@_embed_ref_tl
+% }
+% temporary variables: generic, for extension, subtype, to store the ref.
+% \end{variable}
+% \begin{macrocode}
+\tl_new:N \l_@@_tmpa_tl
+\tl_new:N \l_@@_tmpb_tl
+\str_new:N \l_@@_tmpa_str
+\str_new:N \l_@@_tmpb_str
+\str_new:N \l_@@_ext_str
+\tl_new:N \l_@@_automimetype_tl
+\tl_new:N \l_@@_embed_ref_tl
+% \end{macrocode}
+% \begin{variable} {\g_pdffile_mimetypes_prop}
+% This variable holds common mimetypes. The key is an extension with (one) period,
+% the value the description, e.g. \texttt{text/csv}.
+% \end{variable}
+% \begin{macrocode}
+\prop_new:N \g_pdffile_mimetypes_prop
+\prop_set_from_keyval:Nn \g_pdffile_mimetypes_prop
+ {
+ ,.csv = text/csv
+ ,.html= text/html
+ ,.dtx = text/plain %or application/x-tex, not in iana.org list
+ ,.eps = application/postscript
+ ,.jpg = image/jpeg
+ ,.mp4 = video/mp4
+ ,.pdf = application/pdf
+ ,.png = image/png
+ ,.tex = text/plain %or application/x-tex, not in iana.org list
+ ,.txt = text/plain
+ ,.sty = text/plain
+ }
+% \end{macrocode}
+% \begin{variable}
+% {
+% \l_pdffile_source_name_str
+% }
+% \cs{l_pdffile_source_name_str} will be set at the begin of the command and
+% contains the full file name and can be used e.g. with \cs{file_timestamp:n}.
+% \end{variable}
+% \begin{macrocode}
+\str_new:N \l_pdffile_source_name_str
+% \end{macrocode}
+% Here we define and setup the local dictionaries.
+% We add a ModDate to ensure that there is an entry if
+% associated files are used.
+% \begin{macrocode}
+\pdfdict_new:n { l_pdffile }
+\pdfdict_put:nnn { l_pdffile }{Type}{/EmbeddedFile}
+\pdfdict_new:n { l_pdffile/Params }
+\pdfdict_put:nnn { l_pdffile/Params }
+ {ModDate} { (\file_timestamp:n { \l_pdffile_source_name_str }) }
+\pdfdict_put:nnn { l_pdffile/Params }
+ {Size} { \file_size:n { \l_pdffile_source_name_str } }
+\pdfdict_put:nnn { l_pdffile/Params }
+ {CheckSum} { (\file_mdfive_hash:n { \l_pdffile_source_name_str }) }
+\pdfdict_new:n { l_pdffile/streamParams }
+\pdfdict_put:nnn { l_pdffile/streamParams }
+ {ModDate} {
+ (
+ D:\int_use:N\c_sys_year_int
+ \int_compare:nNnT{\c_sys_month_int}<{10}{0}
+ \int_use:N\c_sys_month_int
+ \int_compare:nNnT{\c_sys_day_int}<{10}{0}
+ \int_use:N\c_sys_day_int
+ )
+ }
+\pdfdict_new:n { l_pdffile/FileSpec }
+\pdfdict_put:nnn { l_pdffile/FileSpec }
+ {Type} { /FileSpec }
+\pdfdict_put:nnn { l_pdffile/FileSpec }
+ {AFRelationship} { /Unspecified }
+
+% \end{macrocode}
+% \begin{variable}{\g_pdffile_embed_prop}
+% we record here the relation\\%
+% \meta{object name} $\Rightarrow$
+% \Arg{file/stream or empty}\Arg{sourcename}\Arg{targetname}
+%
+% \begin{macrocode}
+\prop_new:N \g_pdffile_embed_prop
+% \end{macrocode}
+% \end{variable}
+% \begin{macro}{\pdffile_embed_show:}
+% \begin{macrocode}
+\cs_new_protected:Npn \pdffile_embed_show:
+ {
+ \msg_show:nnx
+ {pdffile}{show-files}
+ {
+ \prop_map_function:NN {\g_pdffile_embed_prop} \msg_show_item:nn
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\pdffile_embed_file:nnn, \pdffile_embed_stream:nnn}
+% At first a command to set the mimetype. It either uses the current value
+% in the file dictionary, or tries to guess it from the extension.
+% \begin{macro}{\@@_mimetype_set:nN,\@@_mimetype_set:VN}
+% \begin{macro}{\@@_fstream_write:nN, \@@_fstream_write:VN}
+% \begin{macro}{\@@_stream_write:nN, \@@_stream_write:VN}
+% \begin{macrocode}
+%#1 file name,
+%#2 tl to return the (printed) value for the guessed mimetype
+\cs_new_protected:Npn \@@_mimetype_set:nN #1 #2
+ {
+ \file_parse_full_name:nNNN
+ {#1}
+ \l_@@_tmpa_str %unused
+ \l_@@_tmpb_str %unused
+ \l_@@_ext_str
+ %check if Subtype has been set
+ \pdfdict_get:nnN { l_pdffile}{Subtype}\l_@@_tmpa_tl
+ %if not look up in the prop:
+ \quark_if_no_value:NT \l_@@_tmpa_tl
+ {
+ \prop_get:NVNTF
+ \g_pdffile_mimetypes_prop
+ \l_@@_ext_str
+ \l_@@_tmpb_tl
+ {
+ \tl_set:Nx #2 {/Subtype~\pdf_name_from_unicode_e:V \l_@@_tmpb_tl}
+ }
+ {
+ \msg_warning:nnx { pdffile }{ mimetype-missing} {#1}
+ \tl_clear:N #2
+ }
+ }
+ }
+
+\cs_generate_variant:Nn \@@_mimetype_set:nN {VN}
+
+%#1 file name,
+%#2 tl, should be empty or contain /Subtype /mimetype
+% e.g. result from \@@_mimetype_set:NN
+\cs_new_protected:Npn \@@_fstream_write:nN #1 #2
+ {
+ \pdf_object_unnamed_write:nx { fstream }
+ {
+ {
+ #2
+ \pdfdict_use:n { l_pdffile}
+ \pdfdict_if_empty:nF { l_pdffile/Params}
+ {
+ /Params
+ <<
+ \pdfdict_use:n { l_pdffile/Params}
+ >>
+ }
+ }
+ { #1 }
+ }
+ \tl_clear:N \l_@@_automimetype_tl
+ }
+
+\cs_generate_variant:Nn \@@_fstream_write:nN {VN}
+
+%#1 file content
+%#2 tl, should be empty or contain /Subtype /mimtype
+% e.g. result from \@@_mimetype_set:NN
+\cs_new_protected:Npn \@@_stream_write:nN #1 #2
+ {
+ \pdf_object_unnamed_write:nx { stream }
+ {
+ {
+ #2
+ \pdfdict_use:n { l_pdffile}
+ \pdfdict_if_empty:nF { l_pdffile/streamParams}
+ {
+ /Params
+ <<
+ \pdfdict_use:n { l_pdffile/streamParams}
+ >>
+ }
+ }
+ { \exp_not:n { #1 } }
+ }
+ \tl_clear:N \l_@@_automimetype_tl
+ }
+
+\cs_generate_variant:Nn \@@_stream_write:nN {VN}
+
+%#1 symbolic name of dict object
+%#2 target file name,
+%#3 object ref of the file stream.
+\cs_new_protected:Npn \@@_filespec_write:nnn #1 #2 #3
+ {
+ \tl_if_blank:nT { #2 }
+ {
+ \msg_error:nn {pdffile}{target-name-missing}
+ }
+ {
+ \pdf_object_new:nn { #1 } {dict}
+ \group_begin:
+ \@@_filename_convert_to_print:nN { #2 } \l_@@_tmpa_str
+ \pdfdict_put:nnx {l_pdffile/FileSpec}{F} { \l_@@_tmpa_str }
+ \pdfdict_put:nnx {l_pdffile/FileSpec}{UF}{ \l_@@_tmpa_str }
+ \pdf_object_write:nx { #1 }
+ {
+ \pdfdict_use:n { l_pdffile/FileSpec}
+ \tl_if_empty:nF { #3 }
+ {
+ /EF <</F~#3 /UF~#3>>
+ }
+ }
+ \group_end:
+ }
+ }
+
+
+%#1 {source filename}
+%#2 {target filename}
+%#3 { filespec object name } (will internally get a prefix!)
+\cs_new_protected:Npn \pdffile_embed_file:nnn #1 #2 #3
+ { % if #1 empty => only filespec
+ % if #2 empty => = #1
+ \pdf_object_if_exist:nTF { #3 }
+ {
+ \msg_error:nnn { pdffile }{ object-exists } { #3 }
+ }
+ {
+ \tl_if_blank:nTF { #1 }
+ {
+ \tl_set:Nn \l_@@_embed_ref_tl {}
+ }
+ {
+ \file_get_full_name:nNTF {#1} \l_pdffile_source_name_str
+ {
+ \@@_mimetype_set:VN
+ \l_pdffile_source_name_str
+ \l_@@_automimetype_tl
+ \@@_fstream_write:VN
+ \l_pdffile_source_name_str
+ \l_@@_automimetype_tl
+ \tl_set:Nx \l_@@_embed_ref_tl { \pdf_object_ref_last: }
+ }
+ {
+ \msg_error:nnn { pdffile }{ file-not-found }{ #1 }
+ }
+
+ }
+ \prop_gput:Nnx
+ \g_pdffile_embed_prop
+ { #3 }
+ {
+ { \tl_if_blank:nTF { #1 } {filespec}{file} }
+ {\l_pdffile_source_name_str}
+ {
+ \tl_if_blank:nTF { #2 }
+ { \l_pdffile_source_name_str }
+ { \tl_to_str:n{#2}}
+ }
+ }
+ \tl_if_blank:nTF { #2 }
+ {
+ \exp_args:Nnnx
+ \@@_filespec_write:nnn
+ %#1 dict, #2 target file name, #3 object ref
+ { #3 }
+ { #1 }
+ {\l_@@_embed_ref_tl}
+ }
+ {
+ \exp_args:Nnnx
+ \@@_filespec_write:nnn
+ %#1 dict, #2 target file name, #3 object ref
+ { #3 }
+ { #2 }
+ {\l_@@_embed_ref_tl}
+ }
+ }
+ }
+
+
+%#1{stream content}
+%#2{target filename}
+%#3{file object name }
+\cs_new_protected:Npn \pdffile_embed_stream:nnn #1 #2 #3
+ {
+ % if #2 empty => error
+ \pdf_object_if_exist:nTF { #3 }
+ {
+ \msg_error:nnn { pdffile }{ object-exists } { #3 }
+ }
+ {
+ \prop_gput:Nnx
+ \g_pdffile_embed_prop
+ { #3 }
+ {{stream}{}{\tl_if_blank:nTF {#2}{stream.txt}{\exp_not:n{#2}}}}
+ \tl_if_blank:nTF {#2}
+ { \@@_mimetype_set:nN {stream.txt}\l_@@_automimetype_tl}
+ { \@@_mimetype_set:nN { #2 } \l_@@_automimetype_tl }
+ \@@_stream_write:nN
+ { #1 }
+ \l_@@_automimetype_tl
+ \tl_set:Nx \l_@@_embed_ref_tl { \pdf_object_ref_last: }
+ \exp_args:Nnxx
+ \@@_filespec_write:nnn
+ %#1 dict, #2 target file name, #3 object ref
+ { #3 }
+ { \tl_if_blank:nTF {#2}{stream.txt}{\exp_not:n{#2}} }
+ {\l_@@_embed_ref_tl}
+ }
+ }
+
+
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \begin{macrocode}
+%</package>
+% \end{macrocode}
+%
+% \end{implementation}
+%
+% \PrintIndex
diff --git a/Master/texmf-dist/source/latex/pdfmanagement-testphase/l3pdfmanagement.dtx b/Master/texmf-dist/source/latex/pdfmanagement-testphase/l3pdfmanagement.dtx
new file mode 100644
index 00000000000..55514bd06c0
--- /dev/null
+++ b/Master/texmf-dist/source/latex/pdfmanagement-testphase/l3pdfmanagement.dtx
@@ -0,0 +1,1468 @@
+% \iffalse meta-comment
+%
+%% File: l3pdfmanagement.dtx
+%
+% Copyright (C) 2018-2021 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
+%
+% http://www.latex-project.org/lppl.txt
+%
+% This file is part of the "LaTeX PDF management testphase 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/pdfresources
+%
+% for those people who are interested.
+%
+%<*driver>
+\RequirePackage{pdfmanagement-testphase}
+\DeclareDocumentMetadata{pdfstandard=A-2b}
+\makeatletter
+\declare@file@substitution{doc.sty}{doc-v3beta.sty}
+\makeatother
+\documentclass[full]{l3doc}
+\usepackage{tabularx}
+\usepackage{array,booktabs,hyperxmp}
+\hypersetup{pdfauthor=The LaTeX Project,pdftitle=l3pdfmanagement (LaTeX PDF management testphase bundle)}
+
+\providecommand\potentialclash{\noindent\llap{\dbend\ }}
+
+% Fixing footnotes in functions and variables: this should be in l3doc!
+\newcommand\fixfootnote[2]{\footnotemark
+ \AddToHookNext{env/#1/after}{\footnotetext{#2}}}
+\AddToHook{env/function/begin}{\def\footnote{\fixfootnote{function}}}
+\AddToHook{env/variable/begin}{\def\footnote{\fixfootnote{variable}}}
+
+\begin{document}
+ \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
+% \fi
+%
+% \title{^^A
+% The \pkg{l3pdfmanagement} module\\ Managing central PDF resources ^^A
+% \\\LaTeX{} PDF management testphase bundle
+% }
+%
+% \author{^^A
+% The \LaTeX{} Project\thanks
+% {^^A
+% E-mail:
+% \href{mailto:latex-team@latex-project.org}
+% {latex-team@latex-project.org}^^A
+% }^^A
+% }
+%
+% \date{Version 0.95a,released 2021-02-22}
+%
+% \maketitle
+% \begin{documentation}
+%
+% \section{\pkg{l3pdfmanagement} documentation}
+% When creating a pdf a number of objects, dictionaries and entries to
+% central \enquote{core} dictionaries must be created.
+%
+% The commands in this module offer interfaces to this core PDF dictionaries
+% They unify a number of primitives like the pdftex
+% registers and commands \cs{pdfcatalog}, \cs{pdfpageattr},
+% \cs{pdfpagesattr}, \cs{pdfinfo}, \cs{pdfpageresources}
+% and similar commands of the other backends in a backend independant way.
+%
+% The supported backends are pdflatex, lualatex, (x)dvipdfmx (latex, xelatex
+% and---starting in texlive 2021--lualatex)
+% and dvips with ps2pdf (not completely yet). dvips with distiller could work too
+% but is untested.
+%
+% That the interfaces are backend independent doesn't mean that the results and even
+% the compilation behavior is identical. The backends are too different to allow
+% this. Some backends expand arguments e.g. in a \cs{special} while other don't.
+% Some backends can insert a resource at the first compilation, while another uses
+% the aux-file and a label and so needs at least two. Some backends create and
+% manage resources automatically which must be managed manually by other backends.
+%
+% The dictionaries and resources handled by this module are inserted only
+% once in a PDF or only once per page. Examples are the Catalog dictionary,
+% the Info dictionary, the page resources. For these dictionaries and resources
+% management by the \LaTeX{} kernel is necessary to avoid
+% that packages overwrite settings from
+% other packages which would lead to clashes and incompatibilities.
+% It is therefore necessary that \emph{all} packages which want to add content to these
+% dictionaries and resources use the interface provided by this module.
+%
+% As these dictionaries and resources are so central for the PDF format values to these
+% dictionaries are always added globally. Through the interface values
+% can be added (and in many cases also removed) by users and packages,
+% but the actually writing of the
+% dictionary entries and resources to the PDF is handled by
+% the kernel code.
+%
+% The interface uses as main name to address the resources \emph{Paths}
+% which follow the names and structure described in the PDF reference. This
+% should make it easy to identify the names needed to insert a specific
+% PDF resources with the new interfaces.
+% All \emph{Paths} have names starting with an uppercase letter.
+%
+% The following tabular summarize the \emph{Paths} and which pdftex primitive they
+% replace:
+%
+% \begin{tabular}{ll}
+% Info & \cs{pdfinfo} \\
+% Catalog \& various subdictionaries & \cs{pdfcatalog} \\
+% Pages & \cs{pdfpagesattr} \\
+% Page, ThisPage & \cs{pdfpageattr} \\
+% Page/Resources/ExtGState & \cs{pdfpageresources} \\
+% Page/Resources/Shading & \cs{pdfpageresources} \\
+% Page/Resources/Pattern & \cs{pdfpageresources} \\
+% Page/Resources/ColorSpace & \cs{pdfpageresources} \\%
+% \end{tabular}
+%
+% There is no \texttt{Page/Resources/Properties} dictionary in the list,
+% because this dictionary is not filled directly, but
+% managed through side effects when setting BDC-marks.
+%
+% \subsection{User Commands}
+% To avoid problems with older documents the resource management of this
+% module is not activated unconditionally. The values are pushed out to the
+% dictionaries only if a boolean has been set to true. The state can be tested
+% with a conditional.
+% \begin{function}[EXP,pTF,added=2020-07-04]
+% {\pdfmanagement_if_active:}
+% This conditional tests if the resource management code is active.
+% \end{function}
+%
+% \begin{function}[added = 2020-04-06]
+% {\pdfmanagement_add:nnn,\pdfmanagement_add:nnx,\pdfmanagement_add:nxx}
+% \begin{syntax}
+% \cs{pdfmanagement_add:nnn} \Arg{resource path} \Arg{name} \Arg{value}
+% \end{syntax}
+% This function puts \Arg{name} \Arg{value} in the PDF resource described by
+% the symbolic name \Arg{resource path}. Technically it stores it globally in an internal
+% property lists and writes it later into the right PDF dictionary\footnote{Currently all
+% resources are PDF dictionaries, so resource and dictionary mean the same.}
+% Which values for \Arg{resource path} exist is described in the following.
+% \Arg{name} should be a PDF Name without the starting slash. Like with all
+% keys used in PDF dictionaries (see the l3pdfdict module) the name is escaped
+% with \cs{str_convert_pdfname:n} when stored.
+% \Arg{value} should be a valid PDF value for this Name in the
+% target dictionary.
+%
+%
+% The code works with all major engines but not necessarily
+% in the same way. Most importantly
+% \begin{itemize}
+% \item The expansion behaviour of the backends can differ. Some backends expand a
+% value always fully when writing to the PDF, with other backends command names
+% could end as strings in the PDF. So one should neither rely on \Arg{name}
+% \Arg{value} to be expanded nor not expanded by the backend commands.
+% \item The number of compilations needed can differ between the engines and
+% backends. Some engines have to use labels and the aux-file to setup
+% the dictionaries and so need at least two compilations to put everything
+% in place.
+% \end{itemize}
+% \end{function}
+%
+% \begin{function}[added = 2020-04-08]
+% {\pdfmanagement_show:n }
+% \begin{syntax}
+% \cs{pdfmanagement_show:n} \Arg{resource path}
+% \end{syntax}
+% This shows the content of the dictionary targetted by
+% \Arg{resource path} in the log and on the terminal if possible.
+%
+% It is not reliable for page resources as these are filled at shipout.
+%
+% It also doesn't show necessarly all the content.
+% For example most backends add automatically
+% entries to the Info dictionary.
+% \end{function}
+%
+% \begin{function}[added = 2020-04-07]
+% {
+% \pdfmanagement_remove:nn,
+% }
+% \begin{syntax}
+% \cs{pdfmanagement_remove:nn} \Arg{resource path} \Arg{name}
+% \end{syntax}
+% Removes |/|\meta{name} and its associated \meta{value} from the
+% dictionary described with \Arg{resource path}
+% The removal is global.
+% If \meta{name} is not found no change occurs,
+% \emph{i.e}~there is no need to test for the existence of a name before
+% trying to remove it.
+% Values from the special Catalog entries where the values are collected in arrays
+% can't be removed (but should ever a use case appear it could be added).
+% \end{function}
+%
+% \subsection{Description of the resource pathes}
+% \subsubsection{Info: The Info dictionary}
+% \begin{NOTE}{UF}
+% path: Info
+% The info dictionary is filled by e.g. \cs{pdfinfo}. Multiple appearances of
+% \cs{pdfinfo} are concatenated, so one could end with multiple /Title or /Author entries.
+% It is then viewer dependent which one is showed, so it is better to avoid this.
+% We therefore setup a property which is filled and written to the info
+% directory in one go. According to hyperref a few odd drivers (hvtex, dvipsone, dviwind)
+% don't support arbitrary keys, but this should be handle elsewhere.
+% As entries with empty content
+% should be omitted we add a test. The string command should perhaps escape the argument,
+% but for now we are assuming that the argument is pdf safe.
+% hyperref writes to the info dictionary at the shipout of the first page --
+% probably to catch the case that \cs{title} is issued after the begin of the document.
+% We are outputting at the last page -- this needs a second compilation but
+% this is needed anyway.
+% \end{NOTE}
+% \potentialclash If the primitive commands of the engines are used too there will
+% be double entries in the pdf (at least with the backend pdftex and luatex).
+% How pdf viewer handles this is unpredictable.
+%
+% \begin{function}
+% {
+% pdfmanagement: Info
+% }
+% \begin{syntax}
+% \cs{pdfmanagement_add:nnn} \{Info\} \Arg{name} \Arg{value}
+% \end{syntax}
+% Adds |/|\meta{name} and the \meta{value} to the Info dictionary.
+% \meta{name} should be a PDF name without the leading slash,
+% Like with all
+% keys used in PDF dictionaries (see the l3pdfdict module) the name is escaped
+% with \cs{str_convert_pdfname:n} when stored.
+% \meta{value} should be a valid pdf value. Any escaping or (re)encoding must be
+% done explicitly.
+% If a \meta{name} is used twice, only the last \meta{value}
+% set will be used. The Info dictionary is written at the end of the compilation,
+% so values can be set at any time.
+% The Info dictionary expects utf16be in the strings, so a conversion like this is
+% normally sensible:
+% \begin{verbatim}
+% \str_set_convert:Nnnn \l_tmpa_str { Grüße }{ default } {utf16/string}
+% \pdfmanagement_add:nnx {Info} {Title}{(\l_tmpa_str)}
+% \end{verbatim}
+% \end{function}
+%
+% The entries in Info dictionary are rather special as the engines/backends adds some
+% core entries, and changing or removing these entries is not always possible.
+%
+% The special entries are
+% \begin{description}
+% \item[Producer] Added by all engines and backends. Removing the entry is only possible
+% with luatex with |\pdfvariable suppressoptionalinfo 128|. Changing is possible
+% with \cs{pdfmanagement_add:nnn} with the exception of dvips/pstopdf where the entry is
+% always something like |GPL Ghostscript 9.53.3|.
+% \item[Creator] Added by all engines and backends. Removal only possible in luatex by adding
+% 16 to the bitset. Changing is possible with the management command.
+% \item[CreationDate] Added by all engines and backends. With the exception of |dvips/ps2pdf|
+% |SOURCE_DATE_EPOCH| is honored. With pdftex it is possible to suppress it with
+% |\pdfinfoomitdate = 1|, and in luatex by adding 32 to the bitset.
+% Changing is possible with the management command and will overwrite an epoch setting.
+% \item[ModDate] Added by all engines and backends with the exception of xdvipdfmx.
+% With the exception of |dvips/ps2pdf| |SOURCE_DATE_EPOCH| is honored.
+% Suppressing it is possible in pdftex with
+% |\pdfinfoomitdate = 1|, and in luatex by adding 64 to the bitset. Changing is possible with
+% the management command.
+% \item[Trapped] Added by pdftex and luatex. Removal only possible in
+% luatex by adding 256 to the bitset. Changing (and adding in the other backends) is
+% possible with the management command.
+% \item[PTEX.Fullbanner] Added by pdftex and luatex. Removal possible in pdftex with
+% |\pdfsuppressptexinfo-1|, in luatex by adding 512 to the bitset.
+% Changing is not possible.
+% \item[Title] Added by dvips/ps2pdf and set to |filename.dvi|. Removal is probably
+% not possible, but it can be overwritten with the management command.%
+% \end{description}
+% \subsubsection{Pages: The \enquote{Pages} dictionary}
+% \potentialclash As the content of this dictionary is written at the end it will
+% in pdftex and luatex overwrite values added with the primitive commands (e.g.
+% \cs{pdfpagesattr}.
+% Package authors should use the management commands instead.
+
+% By using this path with the pdfmanagement interface,
+% values can be added to the /Pages object.
+% This replaces for example \cs{pdfpagesattr}.
+%
+% \begin{function}{pdfmanagement: Pages}
+% \begin{syntax}
+% \cs{pdfmanagement_add:nnn} \{Pages\} \Arg{name} \Arg{value}
+% \end{syntax}
+%
+% Adds |/|\meta{name} \meta{value} to the |/Pages| dictionary.
+% It is always stored globally. The content is written to the pdf
+% at the end of the compilation, so values can be added, changed or
+% removed until then.
+% \meta{name} should be a valid pdf name without the leading slash,
+% \meta{value} should be a valid pdf value. Any escaping or (re)encoding must
+% be done explicitly. Some backends expand the value but this should not be
+% relied on. If a \meta{name} is used twice, only the last \meta{value}
+% set will be used.
+%
+% \end{function}
+%
+% \subsubsection{\enquote{Page} and \enquote{ThisPage}}
+% \begin{NOTE}{UF}
+% Open is the question if one need a command to set attribute on a page by page number.
+% Open is the setter for /AF (and perhaps /OutputIntents).
+% See also https://tex.stackexchange.com/questions/479812/extension-of-rotating-package-to-set-pdf-rotation
+% (should work now)
+% \end{NOTE}
+% \begin{function}[added = 2020-04-12]
+% {pdfmanagement: Page}
+% \begin{syntax}
+% \cs{pdfmanagement_add:nnn} \{Page\} \Arg{name} \Arg{value}
+% \end{syntax}
+% Values added with the path \texttt{Page} are added to the page dictionary
+% of the current page and the following pages. The current page means the page
+% on which the command is \emph{executed}. \meta{name} should be a valid pdf name
+% without the leading slash. Typical names used here are e.g.
+% \texttt{Rotate} and \texttt{CropBox}.
+% \meta{value} should be a valid pdf value.
+% Any escaping or (re)encoding must be done explicitly. Some backends expand the
+% value but this should not be relied on.
+% To avoid problems with the asynchronous page breaking
+% the command should be used after \cs{newpage} or in the header.
+% It should not be used in a float, as it will then quite probably be executed
+% on the wrong page.
+% The value is assigned directly and is always stored globally.
+% If a \meta{name} is used twice, only the last \meta{value}
+% set will be used. Names set with \cs{pdfmanagement_add:nnn}|{ThisPage}| will overwrite
+% names set with \cs{pdfmanagement_add:nnn}|{Page}| if there is a clash.
+% Values can be removed again with \cs{pdfmanagement_remove:nn}.
+% This replaces \cs{pdfpageattr}.
+% \end{function}
+% \begin{function}[added = 2020-04-12]
+% { pdfmanagement: ThisPage}
+% \begin{syntax}
+% \cs{pdfmanagement_add:nnn} \{ThisPage\} \Arg{name} \Arg{value}
+% \end{syntax}
+% Adds |/|\meta{name} \meta{value} at \emph{shipout} to the page dictionary of the
+% current page. Current page means here the \emph{shipout} page.
+% It is always stored globally.
+% If \Arg{name} has already a value set in the \texttt{Page}
+% dictionary it will be overwritten for this page.
+% \meta{name} should be a valid pdf name without the leading slash,
+% \meta{value} should be a valid pdf value. Any escaping or (re)encoding must be
+% done explicitly. If a \meta{name} is used twice, only the last \meta{value}
+% set will be used.
+% With the engine pdflatex (at least) a second compilation is needed.
+% Values added to \texttt{ThisPage} can not be removed. It is not possible to
+% show the content of this dictionary with \cs{pdfmanagement_show:n}.
+% \end{function}
+% \subsubsection{\enquote{Page/Resources}: ExtGState, ColorSpace, Shading, Pattern}
+% \begin{NOTE}{UF}
+% Only for pdf/luatex and xdvipdfmx backend- and pdf-code is needed to add values
+% to these resources.
+% With dvips the resources are added through high-level code (e.g. transparency), so the
+% backend/pdf commands are no-ops.
+% For every resources there is only one object. References to these objects are added to
+% all pages starting from the page where the first time something has been added to the
+% resource and to all XObjects. For luatex and pdftex it must be done together
+% with the /Properties, see above.
+% I don't see a need to set e.g. /ColorSpace page wise: preflight handles this
+% fine, see experiment colorspace-resources.
+% As pgf does the same, there is a need to patch it for now. Ditto for package colorspace.
+% \end{NOTE}
+% \begin{function}[updated = 2020-04-10]
+% {
+% pdfmanagement: Page/Resources/ExtGState,
+% pdfmanagement: Page/Resources/ColorSpace,
+% pdfmanagement: Page/Resources/Shading,
+% pdfmanagement: Page/Resources/Pattern,
+% }
+% \begin{syntax}
+% \cs{pdfmanagement_add:nnn} \{Page/Resources/\meta{resource}\} \Arg{name} \Arg{value}
+% \end{syntax}
+% Adds |/|\meta{name} \meta{value} to the page resource \meta{resource}.
+% \meta{resource} can be |ExtGState|, |ColorSpace|, |Pattern| oder |Shading|.
+% The values are always stored globally. The content is written to the pdf
+% at the end of the compilation, so values can be added until then.
+% \meta{name} should be a valid pdf name without the leading slash,
+% \meta{value} should be a valid pdf value for the resource.
+% Any escaping or (re)encoding must be done explicitly. If a \meta{name} is
+% used twice, only the last \meta{value} set will be used.
+%
+% With the dvips backend the command does nothing: these resources are managed by
+% ghostscript or the distiller if e.\,g. transparency is used.
+%
+% The resources are added to all pages starting with the first where something has
+% been added to a resources. That means that for example
+% all ExtGState resources are combined in one
+% dictionary object and every page with a ExtGState resource refer to this object%
+% \footnote{This is similar to how pgf handles this resources}.
+%
+% \potentialclash The primitive commands (e.g. \cs{pdfpageresources})
+% to set the resources should not be used
+% together with this code as the calls will overwrite each other and values
+% will be lost. This means that currently there are clashes with the packages tikz,
+% transparent and colorspace.
+% \end{function}
+% \subsubsection{\enquote{Catalog} \& subdirectories}
+% \begin{NOTE}{UF}
+% Perhaps some tools to create the AF-file specification dictionaries is useful.
+% Open for now:
+% /Extensions (dict, pdf 2.0)
+% /Dests ? difference to subdict in Names?
+% /DSS (dict, pdf 2.0)
+% /Acroform/DR/ExtGState etc probably unneeded.
+% \end{NOTE}
+% The catalog is a central dictionary in a PDF with a number of subdictionaries.
+% Entries to the top level of the catalog can be added with\\
+% |\pdfmanagement_add:nnn {Catalog}|\Arg{Name}\Arg{Value}.
+% Entries to subdictionaries by using in the first
+% argument one of the pathes described later.
+% The entries in the catalog have varying requirements regarding the
+% PDF management. Some entries (like \texttt{/Lang}) are simple values
+% where new values should
+% overwrite existing values, other like for example \texttt{/OutputIntents}
+% can contain a number of values and can be filled from more than one source.
+% In some cases the values that needs to be added are not at the top-level
+% but in some subsubdictionary or are actually part of an array.
+% To handle the pdf management uses a variety of internal, special handlers.
+%
+% \potentialclash In some cases entries are added implicitly.
+% For example entries to the name
+% tree of the \texttt{/EmbeddedFiles} key in the \texttt{/Names} directory are
+% added with the commands of the \texttt{l3pdffile} module. This clashes with
+% e.g. the embedfile package which should not be used!
+%
+%
+% \paragraph{Entries at the top level of the catalog}
+% The Names in the following tabular are entries that are added to the
+% top level of the catalog.
+%
+% If \meta{Name} gets assigned a value more than once the last one wins.
+% There is no check that the values have the correct type and format.
+% It is up to the user to ensure that the value does what is intended.
+%
+% The required PDF version is only mentioned if it is larger than 1.5.
+%
+% Example: |\pdfmanagement_add:nnn {Catalog}{PageMode}{/UseNone}|
+%
+% \medskip
+% \noindent
+% \begin{tabularx}{\linewidth}{ll>{\raggedright\arraybackslash}X}
+% \bfseries Name & \bfseries Value & \bfseries Remark \\\midrule
+% Collection & objref or dict & the content should be
+% build by external packages (see eg embedfile) \\
+% DPartRoot & objref or dict & PDF 2.0 \\
+% Lang & string & e.g. \texttt{(de-DE)} \\
+% Legal & objref or dict \\
+% Metadata & objref or stream \\
+% NeedsRendering & boolean & PDF 1.7\\
+% OpenAction & array (dest) or dict (action) \\
+% PageLabels & objref or dict & number tree \\
+% PageLayout & name & one of /SinglePage, /OneColumn,
+% /TwoColumnLeft, /TwoColumnRight,
+% /TwoPageLeft,
+% /TwoPageRight \\
+% PageMode & name & one of /UseNone, /UseOutlines, /UseThumbs,
+% /UseOC, /UseAttachments (PDF 1.6)\\
+% Perms & objref or dict & permissions\\
+% PieceInfo & objref or dict \\
+% SpiderInfo & objref or dict \\
+% StructTreeRoot & objref or dict \\
+% Threads & objref to an array\\
+% URI & objref or dict \\
+% Version & name & eg. \texttt{/1.7} \\
+% \meta{unknown} & & an unknown \meta{name} will be
+% inserted without a warning.\\
+% \end{tabularx}
+% \par\medskip
+%
+% \paragraph{Simple entries in subdictionaries of the catalog}
+% The following resource pathes have been predeclared and allow to
+% add values to the respective subdictionaries of the catalog. The
+% names of the dictionaries follow the naming and location of the dictionaries
+% in the PDF reference.
+% If \meta{Name} gets assigned two values the last one wins.
+%
+% Example: |\pdfmanagement_add:nnn {Catalog/MarkInfo}{Marked}{true}|
+%
+% \medskip
+% \noindent
+% \begin{tabularx}{\linewidth}{lll>{\raggedright\arraybackslash}X}
+% \bfseries Path/dictionary & \bfseries Names & \bfseries Value & \bfseries Remark
+% \\\midrule
+% Catalog/AA &WC, WS, DS, WP,DP& all dict \\
+% Catalog/AcroForm & NeedAppearances& boolean & In pdf 2.0
+% NeedAppearances
+% is deprecated,
+% it is then required
+% that every widget has
+% an appearance streams.\\
+% & SigFlags & Integer\\
+% & DA & String \\
+% & Q & Integer\\
+% & XFA & stream or array & pdf 1.5\\
+% Catalog/AcroForm/DR & \meta{name} & & probably unneeded \\
+% Catalog/AcroForm/DR/Font & \meta{name} & dict & \\
+% Catalog/MarkInfo & Marked & boolean \\
+% & UserProperties & boolean \\
+% & Suspects & boolean \\
+% Catalog/ViewerPreferences & HideToolbar & boolean \\
+% & Direction & /R2L or /L2R \\
+% & \ldots & & many more, see the reference \\
+% \end{tabularx}
+%
+%
+% \paragraph{Catalog entries with multiple values in arrays}
+% The following entries are special: Their values are arrays and
+% it must be possible to append to such arrays. This means that a new
+% call to set this value doesn't replace the value but appends it.
+% The value is an object reference. It is sensible to declare the object
+% first. E.g.
+% \begin{verbatim}
+% \pdf_object_new:nn {pkg@intent}{dict}
+% \pdf_object_write:nn {pkg@intent}{...}
+% \pdfmanagement_add:nnx {Catalog} {OutputIntents}{\pdf_object_ref:n {pkg@intent}}
+% \end{verbatim}
+%
+% or
+% \begin{verbatim}
+% \pdf_object_unnamed_write:nn {dict} { ... }
+% \pdfmanagement_add:nnx {Catalog} {OutputIntents}{\pdf_object_ref_last:}
+% \end{verbatim}
+%
+%
+% \medskip
+% \noindent
+% \begin{tabularx}{\linewidth}{lll>{\raggedright\arraybackslash}X}
+% \bfseries Path/dictionary &\bfseries Name & \bfseries Value & \bfseries Remark \\\midrule
+% Catalog/AcroForm & Fields & object reference\\
+% Catalog/AcroForm & CO & object reference\\
+% Catalog & AF & object reference & PDF 2.0, associated files\\
+% Catalog/OCProperties & OCGs & object reference &if there are OCProperties, OCGs and D are required.\\
+% Catalog/OCProperties & Configs & object reference \\
+% Catalog/OCProperties & D & object reference & This is actually a single value as
+% there can be only one default.
+% If the value is set twice, the
+% second wins, and the first is
+% added to OCProperties/Configs.\\
+% Catalog & OutputIntents & object reference\\
+% Catalog & Requirements & object reference & PDF 1.7 \\
+% Catalog/Names & EmbeddedFiles & object reference & This should reference a filespec dictionary. It will
+% attach the file to the file panel.
+% \end{tabularx}
+%
+% \end{documentation}
+%
+% \begin{implementation}
+% \section{\pkg{l3pdfmanagement} implementation}
+% \begin{macrocode}
+%<@@=pdfmanagement>
+%<*header>
+%
+\ProvidesExplPackage {l3pdfmanagement} {2021-02-22} {0.95a}
+ {Management of core PDF dictionaries (LaTeX PDF management testphase bundle)}
+%</header>
+% \end{macrocode}
+% \subsection{Messages}
+% \begin{macrocode}
+%<*package>
+\msg_new:nnn { pdfmanagement } { unknown-dict }
+ { The~PDF~management~resource~'#1'~is~unknown. }
+
+\msg_new:nnn { pdfmanagement } { empty-value }
+ { The~value~for~#1~is~empty~and~will~be~ignored }
+
+\msg_new:nnn { pdfmanagement } { no-removal }
+ { It~is~not~possible~to~remove~values~from~'#1'.}
+
+\msg_new:nnn { pdfmanagement } { no-show }
+ { It~is~not~possible~to~show~the~content~of~'#1'.}
+
+\msg_new:nnn { pdfmanagement } { show-dict }
+ {
+ The~PDF~resource~'#1'~
+ \tl_if_empty:nTF {#2}
+ { is~empty \\>~ . }
+ { contains~the~pairs~(without~outer~braces): #2 . }
+ }
+\msg_new:nnn { pdfmanagement } { dict-already-defined }
+ {
+ The~path~'#1'~is~already~defined.
+ }
+\msg_new:nnn { pdfmanagement } { inactive }
+ {
+ The~PDF~resources~management~is~not~active\\
+ command~'#1'~ignored.
+ }
+% \end{macrocode}
+% \begin{variable}{\g_@@_active_bool}
+% This boolean will control the activation of the management code.
+% It is used in the hooks, and in some backend files.
+% % \cs{DeclareDocumentMetadata} should set it to true
+% \begin{macrocode}
+\bool_new:N \g_@@_active_bool
+% \end{macrocode}
+% \end{variable}
+% A user predicate to test if the management code is active
+% \begin{macrocode}
+\prg_new_conditional:Npnn \@@_if_active: { p , T , F , TF }
+ {
+ \bool_if:NTF \g_@@_active_bool
+ { \prg_return_true: }
+ { \prg_return_false: }
+ }
+\prg_set_eq_conditional:NNn
+ \pdfmanagement_if_active: \@@_if_active: { p , T , F , TF }
+
+% \end{macrocode}
+% We use a hook, to collect value added before the backend is ready.
+% \begin{macrocode}
+\hook_new:n {pdfmanagement/add}
+\cs_new_protected:Npn \pdfmanagement_add:nnn #1 #2 #3
+ {
+ \@@_if_active:TF
+ {
+ \pdfdict_if_exist:nTF { g__pdf_Core/#1 }
+ {
+ \hook_gput_code:nnn
+ {pdfmanagement/add}
+ {pdfmanagement}
+ {
+ \@@_handler_gput:nnn { #1 }{ #2 }{ #3 }
+ }
+ }
+ {
+ \msg_error:nnn{pdfmanagement}{unknown-dict}{#1}
+ }
+ }
+ {
+ \msg_warning:nnx {pdfmanagement}{inactive}
+ {\tl_to_str:n {\pdfmanagement_add:nnn}}
+ }
+ }
+
+\cs_generate_variant:Nn \pdfmanagement_add:nnn {nnx,nxx}
+% \end{macrocode}
+% \subsection{Hooks -- shipout and end of run code}
+% Code is executed in three places: At shipout of every page,
+% at shipout of the last page, at the end of the document
+% (after the last clearpage). Due to backend differences the code in the
+% three places (and the exact timing) can be different: pdflatex/lualatex
+% can execute code after the last \cs{clearpage} which the dvi-based
+% drivers have to add on a shipout page.
+%
+% \begin{variable}
+% {
+% \g__kernel_pdfmanagement_thispage_shipout_code_tl
+% \g__kernel_pdfmanagement_lastpage_shipout_code_tl
+% \g__kernel_pdfmanagement_end_run_code_tl
+% }
+% This variables contain the code run in the three places.
+% \begin{macrocode}
+\tl_new:N \g__kernel_pdfmanagement_thispage_shipout_code_tl
+\tl_new:N \g__kernel_pdfmanagement_lastpage_shipout_code_tl
+\tl_new:N \g__kernel_pdfmanagement_end_run_code_tl
+% \end{macrocode}
+% \end{variable}
+% \begin{macrocode}
+\tl_gset:Nn \g__kernel_pdfmanagement_thispage_shipout_code_tl
+ {
+ \bool_if:NT \g_@@_active_bool
+ {
+ \exp_args:NV \__pdf_backend_ThisPage_gpush:n { \g_shipout_readonly_int }
+ \exp_args:NV \__pdf_backend_PageResources_gpush:n { \g_shipout_readonly_int }
+ }
+ }
+
+\tl_gset:Nn \g__kernel_pdfmanagement_lastpage_shipout_code_tl
+ {
+ \bool_if:NT \g_@@_active_bool
+ {
+ \__pdf_backend_PageResources_obj_gpush: %ExtGState etc
+ }
+ }
+
+\tl_gset:Nn \g__kernel_pdfmanagement_end_run_code_tl
+ {
+ \bool_if:NT \g_@@_active_bool
+ {
+ \@@_Pages_gpush: %pagesattr
+ \@@_Info_gpush: %pdfinfo
+ \@@_Catalog_gpush:
+ }
+ }
+% \end{macrocode}
+% \subsection{Naming convention}
+
+% Currently the following names are used: ^^A!!!!! check, compare with g_@@_gnames_seq
+% All have internally additionally a \texttt{Core} before the slash, to
+% hide the real name a bit.
+% \begin{verbatim}
+% /Info % (\pdfinfo)
+% /Catalog % (\pdfcatalog)
+% /Catalog/AA %
+% /Catalog/AcroForm
+% /Catalog/OCProperties
+% /Catalog/OutputIntents
+% /Catalog/AcroForm/DR
+% /Catalog/AcroForm/DR/Font
+% /Catalog/MarkInfo
+% /Catalog/ViewerPreferences
+% /Pages % (\pagesattr)
+% /Page % (\pageattr)
+% /ThisPage % (\pageattr)
+% /backend_PageN/Resources/Properties % this is only internal.
+% /Page/Resources/ExtGState
+% /Page/Resources/ColorSpace
+% /Page/Resources/Pattern
+% /Page/Resources/Shading
+% /Page/Resources/Properties
+% /Xform/Resources/Properties
+% \end{verbatim}
+
+% \begin{macro}{
+% \@@_handler_gput:nnn,
+% \@@_get:nnN,
+% \@@_gremove:nn,
+% \@@_show:n
+% }
+% \cs{@@_handler_gput:nnn} is the main command to fill the dictionaries.
+% In simple cases it directly fill the property list, but if a handler exists
+% this is called. It is important to use it only in places where this make sense.
+%
+% \begin{macrocode}
+
+%global
+\cs_new_protected:Npn \@@_handler_gput:nnn #1 #2 #3 %#1 dict, #2 name, #3 value
+ {
+ \tl_if_empty:nTF { #3 }
+ {
+ \msg_none:nnn { pdfmanagement }{ empty-value }{ /#1/#2 }
+ }
+ {
+ \pdfdict_if_exist:nTF { g__pdf_Core/#1 }
+ {
+ \cs_if_exist:cTF
+ { @@_handler/#1/?_gput:nn } %general, name independant handler
+ { \use:c {@@_handler/#1/?_gput:nn} {#2} {#3} }
+ {
+ \cs_if_exist:cTF
+ { @@_handler/#1/#2_gput:n }
+ { \use:c {@@_handler/#1/#2_gput:n} {#3} } %special handler
+ {
+ \exp_args:Nnx
+ \prop_gput:cnn
+ { \__kernel_pdfdict_name:n { g__pdf_Core/#1 } }
+ { \str_convert_pdfname:n { #2 } }
+ { #3 }
+ }
+ }
+ }
+ {
+ \msg_error:nnn { pdfmanagement } { unknown-dict } { #1 }
+ }
+ }
+ }
+
+
+\cs_generate_variant:Nn \@@_handler_gput:nnn {nxx}
+
+\cs_new_protected:Npn \@@_get:nnN #1 #2 #3 %path,key,macro
+ {
+ \exp_args:Nnx
+ \prop_get:cnN
+ { \__kernel_pdfdict_name:n { g__pdf_Core/#1 } }
+ { \str_convert_pdfname:n {#2} } #3
+ }
+
+
+\cs_new_protected:Npn \@@_handler_gremove:nn #1 #2 %path,key
+ {
+ \pdfdict_if_exist:nTF { g__pdf_Core/#1 }
+ {
+ \cs_if_exist:cTF
+ { @@_handler/#1/?_gremove:n } %general, name independant handler
+ { \use:c {@@_handler/#1/?_gremove:n} {#2} }
+ {
+ \cs_if_exist:cTF
+ { @@_handler/#1/#2_gremove: }
+ { \use:c {@@_handler/#1/#2_gremove:} } %special handler
+ {
+ \exp_args:Nnx
+ \prop_gremove:cn
+ { \__kernel_pdfdict_name:n { g__pdf_Core/#1 } }
+ { \str_convert_pdfname:n {#2} }
+ }
+ }
+ }
+ {
+ \msg_error:nnn { pdfmanagement } { unknown-dict } { #1 }
+ }
+ }
+
+\cs_new_protected:Npn \@@_gremove:nn #1 #2 %path,key
+ {
+ \pdfdict_if_exist:nTF { g__pdf_Core/#1 }
+ {
+ \exp_args:Nnx
+ \prop_gremove:cn
+ { \__kernel_pdfdict_name:n { g__pdf_Core/#1 } }
+ { \str_convert_pdfname:n{#2} }
+ }
+ {
+ \msg_error:nnn { pdfmanagement } { unknown-dict } { #1 }
+ }
+ }
+
+
+\cs_new_protected:Npn \@@_show:Nn #1#2
+ {
+ \cs_if_exist:cTF
+ { @@_handler/#2/?_show: } %general, name independant handler
+ { \use:c {@@_handler/#2/?_show:} }
+ {
+ \prop_if_exist:cTF { \__kernel_pdfdict_name:n { g__pdf_Core/#2 } }
+ {
+ #1
+ { pdfmanagement } { show-dict }
+ { \tl_to_str:n {#2} }
+ {
+ \prop_map_function:cN
+ {\__kernel_pdfdict_name:n { g__pdf_Core/#2 }}
+ \msg_show_item:nn
+ }
+ { } { }
+ }
+ {
+ #1 { pdfmanagement } { unknown-dict } {#2}{}{}{}
+ }
+ }
+ }
+
+\cs_new_protected:Npn \@@_show:n #1 %path
+ {
+ \prop_show:c { \__kernel_pdfdict_name:n { g__pdf_Core/#1 } }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macrocode}
+\cs_new_protected:Npn \pdfmanagement_show:n #1
+ {
+ \@@_show:Nn \msg_show:nnxxxx {#1}
+ }
+% \end{macrocode}
+% \begin{macrocode}
+\cs_new_protected:Npn \pdfmanagement_remove:nn #1 #2
+ {
+ \pdfdict_if_exist:nTF { g__pdf_Core/#1 }
+ {
+ \@@_handler_gremove:nn { #1 }{ #2 }
+ }
+ {
+ \msg_error:nnn{pdfmanagement}{unknown-dict}{#1}
+ }
+ }
+% \end{macrocode}
+% \begin{macrocode}
+\cs_new_protected:Npn \pdfmanagement_get:nnN #1 #2 #3
+ {
+ \pdfdict_if_exist:nTF { g__pdf_Core/#1 }
+ {
+ \@@_get:nnN { #1 }{ #2 } #3
+ }
+ {
+ \msg_error:nnn{pdfmanagement}{unknown-dict}{#1}
+ }
+ }
+% \end{macrocode}
+% \subsection{The Info dictionary}
+% Initialization of the dictionary:
+% \begin{macrocode}
+\pdfdict_new:n { g__pdf_Core/Info}
+% \end{macrocode}
+%
+% \begin{macro}{\@@_Info_gpush:}
+% \cs{@@_Info_gpush:} is the command that outputs the info dictionary (currently
+% in the end-of-run hooks).
+% \begin{macrocode}
+% push to the register command / issue the special
+\cs_new_protected:Npn \@@_Info_gpush:
+ {
+ \prop_map_function:cN
+ { \__kernel_pdfdict_name:n { g__pdf_Core/Info} }
+ \__pdf_backend_info_gput:nn
+ \prop_gclear:c { \__kernel_pdfdict_name:n { g__pdf_Core/Info} }
+ }
+% \end{macrocode}
+% \end{macro}
+% \subsection{The Pages dictionary code}
+% \begin{NOTE}{UF}
+% The register is normally used only a few times in a document, so it would be
+% okay to update the register/add the special at every change,
+% but with dvips/dvipdfmx this would disable removing entries.
+% So we issue the push code only at the end of the document.
+% \end{NOTE}
+% At first the initialisation
+% \begin{macrocode}
+\pdfdict_new:n { g__pdf_Core/Pages}
+% \end{macrocode}
+%
+% \begin{macro}{\@@_Pages_gpush:}
+% This is the command that outputs the Pages dictionary. It is used
+% at the end of the document in \cs{g__pdf_backend_end_run_tl}
+% \begin{macrocode}
+% push to the register command / issue the special
+\cs_new_protected:Npn \@@_Pages_gpush:
+ {
+ \exp_args:Nx \__pdf_backend_Pages_primitive:n
+ {
+ \pdfdict_use:n { g__pdf_Core/Pages}
+ }
+ }
+
+% \end{macrocode}
+% \end{macro}
+% \subsection{The Page and ThisPage dictionary}
+% At first the initialisation.
+% \begin{macrocode}
+\pdfdict_new:n { g__pdf_Core/Page }
+\pdfdict_new:n { g__pdf_Core/ThisPage }
+
+%handler for pdfmanagement
+\cs_new_protected:cpn { @@_handler/Page/?_gput:nn } #1 #2
+ {
+ \__pdf_backend_Page_gput:nn { #1 }{ #2 }
+ }
+% remove:
+\cs_new_protected:cpn { @@_handler/Page/?_gremove:n } #1
+ {
+ \__pdf_backend_Page_gremove:n { #1 }
+ }
+
+% handler for pdfmanagement
+\cs_new_protected:cpn { @@_handler/ThisPage/?_gput:nn } #1 #2
+ {
+ \prop_gput:cnn { \__kernel_pdfdict_name:n { g__pdf_Core/ThisPage } }{ #1 } { #2 }
+ \bool_if:NT \g_@@_active_bool
+ {
+ \__pdf_backend_ThisPage_gput:nn { #1 }{ #2 }
+ }
+ }
+
+\cs_new_protected:cpn { @@_handler/ThisPage/?_gremove:n } #1
+ {
+ \msg_warning:nnn { pdfmanagement } { no-removal }{ThisPage}
+ }
+
+\cs_new_protected:cpn { @@_handler/ThisPage/?_show: }
+ {
+ \msg_warning:nnn { pdfmanagement } { no-show }{ThisPage}
+ }
+
+% \end{macrocode}
+% \subsubsection{\enquote{Page/Resources}: ExtGState, ColorSpace, Shading, Pattern}
+% \begin{macrocode}
+\clist_const:Nn \c_@@_PageResources_clist
+ {
+ ExtGState,
+ ColorSpace,
+ Pattern,
+ Shading,
+ }
+
+\clist_map_inline:Nn \c_@@_PageResources_clist
+ {
+ \pdfdict_new:n { g__pdf_Core/Page/Resources/#1}
+ }
+%
+% setter: #1 is the name of the resource
+\cs_new_protected:cpn { @@_handler/Page/Resources/ExtGState/?_gput:nn } #1 #2
+ {
+ \__pdf_backend_PageResources_gput:nnn {ExtGState} { #1 }{ #2 }
+ }
+
+\cs_new_protected:cpn { @@_handler/Page/Resources/ColorSpace/?_gput:nn } #1 #2
+ {
+ \__pdf_backend_PageResources_gput:nnn {ColorSpace} { #1 }{ #2 }
+ }
+
+\cs_new_protected:cpn { @@_handler/Page/Resources/Shading/?_gput:nn } #1 #2
+ {
+ \__pdf_backend_PageResources_gput:nnn {Shading} { #1 }{ #2 }
+ }
+
+\cs_new_protected:cpn { @@_handler/Page/Resources/Pattern/?_gput:nn } #1 #2
+ {
+ \__pdf_backend_PageResources_gput:nnn {Pattern} { #1 }{ #2 }
+ }
+% \end{macrocode}
+% \subsubsection{\enquote{Catalog}}
+% The catalog has mixed entries: toplevel, subdictionaries, and entries
+% which must build arrays.
+% \begin{variable}[added=2019-08-24]
+% {
+% \c_@@_Catalog_toplevel_clist,
+% \c_@@_Catalog_sub_clist,
+% \c_@@_Catalog_seq_clist,
+% }
+% This variables hold the list of the various types of entries. With it
+% the various \verb=_gput= commands are generated.
+% \end{variable}
+% \begin{macro}{ \@@_catalog_XX_gput:n }
+% Various commands to handle subentries and special cases.
+% \begin{macrocode}
+\pdfdict_new:n { g__pdf_Core/Catalog}
+
+\clist_const:Nn \c_@@_Catalog_toplevel_clist
+ {
+ Collection,
+ DPartRoot,
+ Lang,
+ Legal,
+ Metadata,
+ NeedsRendering,
+ OCProperties/D,
+ OpenAction,
+ PageLabels,
+ PageLayout,
+ PageMode,
+ Perms,
+ PieceInfo,
+ SpiderInfo,
+ StructTreeRoot,
+ Threads,
+ URI,
+ Version
+ }
+
+\clist_const:Nn \c_@@_Catalog_sub_clist
+ {
+ AA,
+ AcroForm,
+ AcroForm/DR,
+ AcroForm/DR/Font,
+ MarkInfo,
+ ViewerPreferences,
+ OCProperties
+ }
+
+\clist_map_inline:Nn \c_@@_Catalog_sub_clist
+ {
+ \pdfdict_new:n { g__pdf_Core/Catalog/#1}
+ }
+
+
+\clist_const:Nn \c_@@_Catalog_seq_clist
+ {
+ AF,
+ OCProperties/OCGs,
+ OCProperties/Configs,
+ OutputIntents,
+ Requirements,
+ AcroForm/Fields,
+ AcroForm/CO
+ }
+
+
+
+\clist_map_inline:Nn \c_@@_Catalog_seq_clist
+ {
+ \seq_new:c { g_@@_/Catalog/#1_seq } % new name later
+ \cs_new_protected:cpn { @@_handler/Catalog/#1_gput:n } ##1
+ {
+ \seq_gput_right:cn { g_@@_/Catalog/#1_seq } { ##1 }
+ }
+ }
+
+\cs_new_protected:cpn { @@_handler/Catalog/OCProperties/D_gput:n } #1
+ {
+ \seq_gput_left:cn
+ { g_@@_/Catalog/OCProperties/Configs_seq }
+ { #1 }
+ }
+% \end{macrocode}
+% \end{macro}
+% % \paragraph {Building the catalog: Push order}
+% \begin{macro}{\@@_Catalog_gpush:}
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_Catalog_gpush:
+ {
+ \use:c { @@_/Catalog/AA_gpush: }
+ \use:c { @@_/Catalog/AcroForm_gpush: }
+ \use:c { @@_/Catalog/AF_gpush: }
+ \use:c { @@_/Catalog/MarkInfo_gpush: }
+ \pdfmeta_standard_verify:nT {Catalog_no_OCProperties}
+ {
+ \use:c { @@_/Catalog/OCProperties_gpush: }
+ }
+ \use:c { @@_/Catalog/OutputIntents_gpush: }
+ \use:c { @@_/Catalog/Requirements_gpush: }
+ \use:c { @@_/Catalog/ViewerPreferences_gpush: }
+ % output the single values:
+ \prop_map_function:cN
+ { \__kernel_pdfdict_name:n { g__pdf_Core/Catalog} }
+ \__pdf_backend_catalog_gput:nn
+ % output names tree:
+ \use:c { @@_/Catalog/Names/EmbeddedFiles_gpush: }
+ }
+% \end{macrocode}
+% \end{macro}
+% \paragraph{Building catalog entries: AA}
+% \begin{macro}{\@@_/Catalog/AA_gpush:}
+% \begin{macrocode}
+\cs_new_protected:cpn { @@_/Catalog/AA_gpush: }
+ {
+ \prop_if_empty:cF
+ { \__kernel_pdfdict_name:n { g__pdf_Core/Catalog/AA } }
+ {
+ \__pdf_backend_object_new:nn { g_@@_/Catalog/AA_obj } { dict }
+ \__pdf_backend_object_write:nx
+ { g_@@_/Catalog/AA_obj }
+ { \pdfdict_use:n { g__pdf_Core/Catalog/AA } }
+ \exp_args:Nnx
+ \__pdf_backend_catalog_gput:nn
+ {AA}
+ {
+ \__pdf_backend_object_ref:n { g_@@_/Catalog/AA_obj }
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \paragraph{Building catalog entries: AcroForm}
+% This is the most complicated case.
+% The entries is build from
+% /Catalog/AcroForm/Fields (array),
+% /Catalog/AcroForm/CO (array),
+% /Catalog/AcroForm/DR/Font (dict),
+% /Catalog/AcroForm/DR (dict),
+% /Catalog/AcroForm
+%
+% \begin{macro}{\@@_/Catalog/AcroForm_gpush:}
+% \begin{macrocode}
+\cs_new_protected:cpn { @@_/Catalog/AcroForm_gpush: }
+ {
+ \seq_if_empty:cF { g_@@_/Catalog/AcroForm/Fields_seq }
+ {
+ \__pdf_backend_object_new:nn { g_@@_/Catalog/AcroForm/Fields_obj } { array }
+ \__pdf_backend_object_write:nx
+ { g_@@_/Catalog/AcroForm/Fields_obj }
+ { \seq_use:cn { g_@@_/Catalog/AcroForm/Fields_seq } {~} }
+ \exp_args:Nnnx
+ \prop_gput:cnn %we have to use \prop here to avoid the handler ...
+ { \__kernel_pdfdict_name:n { g__pdf_Core/Catalog/AcroForm } }
+ { Fields }
+ { \__pdf_backend_object_ref:n { g_@@_/Catalog/AcroForm/Fields_obj } }
+ }
+ \seq_if_empty:cF { g_@@_/Catalog/AcroForm/CO_seq }
+ {
+ \__pdf_backend_object_new:nn { g_@@_/Catalog/AcroForm/CO_obj } { array }
+ \exp_args:Nnx
+ \__pdf_backend_object_write:nn
+ { g_@@_/Catalog/AcroForm/CO_obj }
+ { \seq_use:cn { g_@@_/Catalog/AcroForm/CO_seq } {~} }
+ \exp_args:Nnnx
+ \prop_gput:cnn %we have to use \prop here to avoid the handler ...
+ { \__kernel_pdfdict_name:n { g__pdf_Core/Catalog/AcroForm } }
+ { CO }
+ { \__pdf_backend_object_ref:n { g_@@_/Catalog/AcroForm/CO_obj } }
+ }
+ \prop_if_empty:cF { \__kernel_pdfdict_name:n { g__pdf_Core/Catalog/AcroForm/DR/Font}}
+ {
+ \__pdf_backend_object_new:nn { g_@@_/Catalog/AcroForm/DR/Font_obj } {dict}
+ \exp_args:Nnx
+ \__pdf_backend_object_write:nn
+ { g_@@_/Catalog/AcroForm/DR/Font_obj }
+ { \pdfdict_use:n { g__pdf_Core/Catalog/AcroForm/DR/Font } }
+ \exp_args:Nnnx
+ \prop_gput:cnn %we have to use \prop here to avoid the handler ...
+ { \__kernel_pdfdict_name:n { g__pdf_Core/Catalog/AcroForm/DR } }
+ { Font }
+ { \__pdf_backend_object_ref:n { g_@@_/Catalog/AcroForm/DR/Font_obj } }
+ }
+ \prop_if_empty:cF { \__kernel_pdfdict_name:n { g__pdf_Core/Catalog/AcroForm/DR}}
+ {
+ \__pdf_backend_object_new:nn { g_@@_/Catalog/AcroForm/DR_obj } {dict}
+ \exp_args:Nnx
+ \__pdf_backend_object_write:nn
+ { g_@@_/Catalog/AcroForm/DR_obj }
+ { \pdfdict_use:n { g__pdf_Core/Catalog/AcroForm/DR } }
+ \exp_args:Nnnx
+ \prop_gput:cnn %we have to use \prop here to avoid the handler ...
+ { \__kernel_pdfdict_name:n { g__pdf_Core/Catalog/AcroForm } }
+ { DR }
+ { \__pdf_backend_object_ref:n { g_@@_/Catalog/AcroForm/DR_obj } }
+ }
+ \prop_if_empty:cF { \__kernel_pdfdict_name:n { g__pdf_Core/Catalog/AcroForm} }
+ {
+ \__pdf_backend_object_new:nn { g_@@_/Catalog/AcroForm_obj } {dict}
+ \exp_args:Nnx
+ \__pdf_backend_object_write:nn
+ { g_@@_/Catalog/AcroForm_obj }
+ { \pdfdict_use:n { g__pdf_Core/Catalog/AcroForm } }
+ \exp_args:Nnnx
+ \@@_handler_gput:nnn
+ { Catalog }
+ { AcroForm }
+ { \__pdf_backend_object_ref:n { g_@@_/Catalog/AcroForm_obj } }
+ }
+ }
+
+% \end{macrocode}
+% \end{macro}
+%
+% \paragraph{Building catalog entries: AF}
+% AF is an array.
+% \begin{macro}{\@@_/Catalog/AF_gpush:}
+% \begin{macrocode}
+\cs_new_protected:cpn { @@_/Catalog/AF_gpush: }
+ {
+ \seq_if_empty:cF
+ { g_@@_/Catalog/AF_seq }
+ {
+ \__pdf_backend_object_new:nn { g_@@_/Catalog/AF_obj } { array }
+ \exp_args:Nnx
+ \__pdf_backend_object_write:nn
+ { g_@@_/Catalog/AF_obj }
+ { \seq_use:cn { g_@@_/Catalog/AF_seq } {~} }
+ \exp_args:Nnx
+ \__pdf_backend_catalog_gput:nn
+ {AF}
+ {
+ \__pdf_backend_object_ref:n {g_@@_/Catalog/AF_obj}
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% %
+% \paragraph{Building catalog entries: MarkInfo}
+% \begin{macro}{\@@_/Catalog/MarkInfo_gpush:}
+% \begin{macrocode}
+\cs_new_protected:cpn { @@_/Catalog/MarkInfo_gpush: }
+ {
+ \prop_if_empty:cF
+ { \__kernel_pdfdict_name:n { g__pdf_Core/Catalog/MarkInfo } }
+ {
+ \__pdf_backend_object_new:nn { g_@@_/Catalog/MarkInfo_obj } { dict }
+ \exp_args:Nnx
+ \__pdf_backend_object_write:nn
+ { g_@@_/Catalog/MarkInfo_obj }
+ { \pdfdict_use:n { g__pdf_Core/Catalog/MarkInfo } }
+ \exp_args:Nnx
+ \__pdf_backend_catalog_gput:nn
+ {MarkInfo}
+ {
+ \__pdf_backend_object_ref:n {g_@@_/Catalog/MarkInfo_obj}
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%\paragraph{Building catalog entries: OCProperties}
+% This is a dictionary with three entries:
+% \begin{description}
+% \item[/OCGs] (required) An array of indirect references,
+% access needed for more than one package.
+% \item[/D] (required) a dict (given as an object name) to the default
+% configuration
+% \item[/Configs] (optional) an array of indirect references to more
+% configurations.
+% \end{description}
+% The /D entry is also a config, it is the first of the seq.
+% The overall structure is nested: a dict with arrays.
+% \begin{macro}{\@@_/Catalog/OCProperties_gpush:}
+% \begin{macrocode}
+% Catalog/OCProperties: OCGs + D is required
+\cs_new_protected:cpn { @@_/Catalog/OCProperties_gpush: }
+ {
+ \int_compare:nNnT
+ {
+ ( \seq_count:c { g_@@_/Catalog/OCProperties/OCGs_seq } )*
+ ( \seq_count:c { g_@@_/Catalog/OCProperties/Configs_seq } )
+ }
+ >
+ { 0 }
+ {
+ \__pdf_backend_object_new:nn { g_@@_/Catalog/OCProperties_obj } { dict }
+ \seq_gpop_left:cN { g_@@_/Catalog/OCProperties/Configs_seq} \l_tmpa_tl
+ \exp_args:Nnx
+ \__pdf_backend_object_write:nn {g_@@_/Catalog/OCProperties_obj}
+ {
+ /OCGs~[ \seq_use:cn { g_@@_/Catalog/OCProperties/OCGs_seq } {~} ]
+ /D~\l_tmpa_tl~
+ \seq_if_empty:cF { g_@@_/Catalog/OCProperties/Configs_seq }
+ {
+ /Configs~
+ [ \seq_use:cn { g_@@_/Catalog/OCProperties/Configs_seq} {~} ]
+ }
+ }
+ \exp_args:Nnx
+ \__pdf_backend_catalog_gput:nn
+ { OCProperties }
+ { \__pdf_backend_object_ref:n {g_@@_/Catalog/OCProperties_obj} }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \paragraph{Building catalog entries: OutputIntents}
+% OutputIntents is an array.
+% \begin{macro}{\@@_/Catalog/OutputIntents_gpush:}
+% \begin{macrocode}
+\cs_new_protected:cpn { @@_/Catalog/OutputIntents_gpush: }
+ {
+ \seq_if_empty:cF
+ { g_@@_/Catalog/OutputIntents_seq }
+ {
+ \__pdf_backend_object_new:nn { g_@@_/Catalog/OutputIntents_obj } { array }
+ \exp_args:Nnx
+ \__pdf_backend_object_write:nn
+ { g_@@_/Catalog/OutputIntents_obj }
+ { \seq_use:cn { g_@@_/Catalog/OutputIntents_seq } {~} }
+ \exp_args:Nnx
+ \__pdf_backend_catalog_gput:nn
+ {OutputIntents}
+ {
+ \__pdf_backend_object_ref:n {g_@@_/Catalog/OutputIntents_obj}
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \paragraph{Building catalog entries: Requirements}
+% Requirements is an array.
+% \begin{macro}{\@@_/Catalog/Requirements_gpush:}
+% \begin{macrocode}
+\cs_new_protected:cpn { @@_/Catalog/Requirements_gpush: }
+ {
+ \seq_if_empty:cF
+ { g_@@_/Catalog/Requirements_seq }
+ {
+ \__pdf_backend_object_new:nn { g_@@_/Catalog/Requirements_obj } { array }
+ \exp_args:Nnx
+ \__pdf_backend_object_write:nn
+ { g_@@_/Catalog/Requirements_obj }
+ { \seq_use:cn { g_@@_/Catalog/Requirements_seq } {~} }
+ \exp_args:Nnx
+ \__pdf_backend_catalog_gput:nn
+ {Requirements}
+ {
+ \__pdf_backend_object_ref:n { g_@@_/Catalog/Requirements_obj }
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \paragraph{Building catalog entries: ViewerPreferences}
+% \begin{macro}{\@@_/Catalog/ViewerPreferences_gpush:}
+% \begin{macrocode}
+\cs_new_protected:cpn { @@_/Catalog/ViewerPreferences_gpush: }
+ {
+ \prop_if_empty:cF
+ { \__kernel_pdfdict_name:n { g__pdf_Core/Catalog/ViewerPreferences } }
+ {
+ \__pdf_backend_object_new:nn { g_@@_/Catalog/ViewerPreferences_obj } { dict }
+ \exp_args:Nnx
+ \__pdf_backend_object_write:nn
+ { g_@@_/Catalog/ViewerPreferences_obj }
+ { \pdfdict_use:n { g__pdf_Core/Catalog/ViewerPreferences } }
+ \exp_args:Nnx
+ \__pdf_backend_catalog_gput:nn
+ {ViewerPreferences}
+ {
+ \__pdf_backend_object_ref:n {g_@@_/Catalog/ViewerPreferences_obj}
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \paragraph{Building catalog entries: Names/EmbeddedFiles}
+% \begin{NOTE}{UF}
+% TODO access function for the name in the name tree
+% \end{NOTE}
+% \begin{macro}{ Handler}
+% EmbeddedFiles is an array and needs a special handler to add values.
+% \begin{macrocode}
+\pdfdict_new:n { g__pdf_Core/Catalog/Names }
+
+\cs_new_protected:cpn { @@_handler/Catalog/Names/EmbeddedFiles_gput:n } #1
+ {
+ \__pdf_backend_NamesEmbeddedFiles_add:n { #1 }
+ }
+% \end{macrocode}
+% \end{macro}
+% The entry should only be added if there are actually embedded files.
+% This can be tested by checking the names_seq
+% \begin{macro}{\@@_/Catalog/Names/EmbeddedFiles_gpush:}
+% \begin{macrocode}
+%
+\cs_new_protected:cpn { @@_/Catalog/Names/EmbeddedFiles_gpush: }
+ {
+ \seq_if_empty:NF \g__pdf_backend_EmbeddedFiles_seq
+ {
+ \exp_args:Nx \__pdf_backend_NamesEmbeddedFiles_gpush:n
+ {
+ \seq_use:Nn \g__pdf_backend_EmbeddedFiles_seq {~}
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{@@_handler/Catalog/?_show:}
+% A handler to show the catalog.
+% \begin{macrocode}
+\cs_new_protected:cpn {@@_handler/Catalog/?_show:}
+ {
+ \iow_term:x
+ {
+ \iow_newline:
+ The~Catalog~contains~in~the~top~level~the~single~value~entries
+ \prop_map_function:cN
+ {\__kernel_pdfdict_name:n { g__pdf_Core/Catalog }}
+ \msg_show_item:nn
+ }
+ \clist_map_inline:Nn \c_@@_Catalog_seq_clist
+ {
+ \seq_if_empty:cF { g_@@_/Catalog/##1_seq }
+ {
+ \iow_term:x
+ {
+ The~'##1'~array~contains~the~entries
+ \seq_map_function:cN { g_@@_/Catalog/##1_seq } \msg_show_item:n
+ }
+ }
+ }
+ \clist_map_inline:Nn \c_@@_Catalog_sub_clist
+ {
+ \prop_if_empty:cF { \__kernel_pdfdict_name:n { g__pdf_Core/Catalog/##1 } }
+ {
+ \iow_term:x
+ {
+ The~Catalog~subdirectory~'##1'~contains~the~single~value~entries
+ \prop_map_function:cN
+ {\__kernel_pdfdict_name:n { g__pdf_Core/Catalog/##1 }}
+ \msg_show_item:nn
+ }
+ }
+ }
+ \tl_show:x {\tl_to_str:n{\pdfmanagement_show:n{Catalog}}}
+ }
+% \end{macrocode}
+% \end{macro}
+% \subsection{ xform / Properties }
+% \begin{macrocode}
+\pdfdict_new:n { g__pdf_Core/Xform/Resources/Properties}
+% \end{macrocode}
+% \begin{macrocode}
+%</package>
+% \end{macrocode}
+%
+% \end{implementation}
+%
+% \PrintIndex
diff --git a/Master/texmf-dist/source/latex/pdfmanagement-testphase/l3pdfmeta.dtx b/Master/texmf-dist/source/latex/pdfmanagement-testphase/l3pdfmeta.dtx
new file mode 100644
index 00000000000..a374e39fc7f
--- /dev/null
+++ b/Master/texmf-dist/source/latex/pdfmanagement-testphase/l3pdfmeta.dtx
@@ -0,0 +1,824 @@
+% \iffalse meta-comment
+%
+%% File: l3pdfmeta.dtx
+%
+% Copyright (C) 2018-2021 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
+%
+% http://www.latex-project.org/lppl.txt
+%
+% This file is part of the "LaTeX PDF management testphase 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/pdfresources
+%
+% for those people who are interested.
+%
+%<*driver>
+\RequirePackage{pdfmanagement-testphase}
+\DeclareDocumentMetadata{pdfstandard=A-2b}
+\makeatletter
+\declare@file@substitution{doc.sty}{doc-v3beta.sty}
+\makeatother
+\documentclass[full]{l3doc}
+\usepackage{array,booktabs,hyperxmp}
+\hypersetup{pdfauthor=The LaTeX Project,pdftitle=l3pdfmeta (LaTeX PDF management testphase bundle)}
+
+\begin{document}
+ \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
+% \fi
+%
+% \title{^^A
+% The \pkg{l3pdfmeta} module\\ PDF standards ^^A
+% \\
+% \LaTeX{} PDF management testphase bundle
+% }
+%
+% \author{^^A
+% The \LaTeX{} Project\thanks
+% {^^A
+% E-mail:
+% \href{mailto:latex-team@latex-project.org}
+% {latex-team@latex-project.org}^^A
+% }^^A
+% }
+%
+% \date{Version 0.95a, released 2021-02-21}
+%
+% \maketitle
+% \begin{documentation}
+%
+% \section{\pkg{l3pdfmeta} documentation}
+% This module sets up some tools and commands needed
+% for PDF standards in general.
+% The goal is to collect the requirements and to provide code to check and fulfill them.
+%
+% In future is will probably also contain
+% code to setup XMP-metadata.
+% Until then XMP-metadata can be added by one of two mutual incompatible packages:
+% \pkg{hyperxmp} and \pkg{pdfx}. Both
+% packages aren't yet compatible with the new PDF management,
+% but for \pkg{hyperxmp} some patches are provided, so the basic functions works.
+%
+% \begin{NOTE}{UF}
+% This module should not replace both packages.
+% Regarding XMP-metadata its goal
+% is to create a skeleton metadata stream, add some core default values
+% and to define interfaces that allows other packages
+% to add data to this metadata and so to extend them.
+% The problems to solve here are
+% \begin{itemize}
+% \item which tree structure is sensible
+% \item how to escape if needed the input (or which tools are needed to allow
+% the users to correctly escape their input)
+% \item how interface to input data should look
+% \end{itemize}
+% \end{NOTE}
+%
+% \subsection{Verifying requirements of PDF standards}
+%
+% Standards like pdf/A set requirements on a PDF: Some things have be in the PDF,
+% e.g. the catalog has to contain a /Lang entry and an colorprofile and
+% an /OutputIntent, some other things are forbidden or restricted, e.g.
+% the action dictionary of an annotation should not contain Javascript.
+%
+% The \pkg{l3pdfmeta} module collects a number of relevant requirements,
+% tries to enforce the ones which can be enforced and offers some tools
+% for package authors to test if an action is allowed in the standard or not.
+%
+% This is work in progress and more tests will be added. But it should be noted
+% that it will probably never be possible to prevent all forbidden actions
+% or enforce all required ones or even to simply check all of them.
+% The commands here don't replace a check with an external validator.
+%
+% Verifying against a PDF-standard involves two different task:
+%
+% \begin{itemize}
+% \item Check if you are allowed to ignore the requirement.
+% \item Decide which action to take if the answer to the first question is NO.
+% \end{itemize}
+%
+% The following conditionals address the first task. Because of the second task
+% a return value |FALSE| means that the standard requires you to do some
+% special action. |TRUE| means that you can ignore this
+% requirement.\footnote{One could also make the logic the
+% other way round---there are arguments for both---but I had to decide.}
+%
+% In most cases it only matters if a requirement is in the standard,
+% for example |Catalog_no_OCProperties| means \enquote{don't use |/OCProperties|
+% in the catalog}. For a small number of requirements it is also needed to
+% test a user value against a standard value. For example, |named_actions|
+% restricts the allowed named actions in an annotation of subtype |/Named|,
+% in this case it is needed to check not only if the requirement is
+% in the standard but also if the user value is in the allowed list.
+%
+% \begin{function}[EXP,pTF]{\pdfmeta_standard_verify:n}
+% \begin{syntax}
+% \cs{pdfmeta_standard_verify:n}\Arg{requirement}
+% \end{syntax}
+%
+% This checks if \meta{requirement} is listed in the standard.
+% |FALSE| as result means that the requirement is in the standard and
+% that probably some special action is required---which one depends
+% on the requirement, see the descriptions below.
+% |TRUE| means that the requirement is not there and so no special
+% action is needed.
+% This check can be used for simple requirements where neither
+% a user nor a standard value is of importance.
+% \end{function}
+%
+% \begin{function}[TF]{\pdfmeta_standard_verify:nn}
+% \begin{syntax}
+% \cs{pdfmeta_standard_verify:nn}\Arg{requirement}\Arg{value}
+% \end{syntax}
+%
+% This checks if \meta{requirement} is listed in the standard,
+% if yes it tries to find a predefined test handler for
+% the requirement and passes \meta{value} and the value recorded
+% in the standard to it. The handler returns |FALSE| if some special
+% action is needed (e.g. if \meta{value} violates the rule)
+% and |TRUE| if no special action is needed. If no handler exists
+% this commands works like \cs{pdfmeta_standard_verify:n}.
+% \end{function}
+%
+% In some cases one needs to query the value in the standard,
+% e.g. to correct a wrong minimal PDF version you need to know
+% which version is required by |min_pdf_version|.
+% For this two commands to access the value are provided:
+%
+% \begin{function}[EXP]{\pdfmeta_standard_item:n}
+% \begin{syntax}
+% \cs{pdfmeta_standard_item:n}\Arg{requirement}
+% \end{syntax}
+% This retrieves the value of \meta{requirement} and leaves it in the input.
+% If the requirement isn't in the standard the result is empty,
+% that means that requirements not in the standard and
+% requirement without values can not be distinguished here.
+% \end{function}
+%
+%
+% \begin{function}{\pdfmeta_standard_get:nN}
+% \begin{syntax}
+% \cs{pdfmeta_standard_get:nN}\Arg{requirement} \meta{tl var}
+% \end{syntax}
+% This retrieves the value of \meta{requirement} and stores
+% it in the \meta{token list variable}.
+% If the \meta{requirement} is not found the special
+% value |\q_no_value| is used.
+% The \meta{token list variable} is assigned locally.
+% \end{function}
+%
+%
+% The following describe the requirements which can be currently tested.
+% Requirements with a value should use \cs{pdfmeta_standard_verify:nn}
+% or \cs{pdfmeta_standard_verify:nnN} to test a local value against the standard.
+% The rule numbers refer to \url{https://docs.verapdf.org/validation/pdfa-part1/}
+%
+% \subsubsection{Simple tests without handler}
+%
+% \begin{description}
+%
+% \item[|outputintent_A|] requires to embed a color profile and
+% reference it in a /Outputintent and that all output intents reference
+% the same colorprofile. The value stores the subtype.
+% {\em This requirement is detected and fulfilled by \pkg{l3pdfmeta} if the
+% provided interface in \cs{DeclareDocumentMetadata} is used, see below}.
+%
+% \item[|annot_flags|] in annotations the |Print| flag should be true,
+% |Hidden|, |Invisible|, |NoView| should be false.
+% {\em This requirement is detected and set by \pkg{l3pdfmeta} for annotations
+% created with the \pkg{l3pdfannot}.
+% A new check is only needed if the flags are changed
+% or if links are created by other means.}
+%
+% \item[|no_encryption|] don't encrypt
+% \item[|no_external_content|] no |/F|, |/FFilter|, or |/FDecodeParms|
+% in stream dictionaries
+% \item[|no_embed_content|] no |/EF| key in filespec, no |/Type/EmbeddedFiles|.
+% \emph{This will be checked in future by \pkg{l3pdffiles}
+% for the files it embeds.}
+% The restrictment is set for only PDF/A-1b.
+% PDF/A-2b and PDF/A3-b lifted this restriction: PDF/A-2b allows
+% to embed other PDF documents conforming to either PDF/A-1 or PDF/A-2,
+% and PDF/A-3 allows any embedded files. I don't see a way to test the
+% PDF/A-2b requirement so currently it will simply allow everything. Perhaps
+% a test for at least the PDF-format will be added in future.
+% \item[|Catalog_no_OCProperties|] don't add |/OCProperties| to the catalog
+% {\em l3pdfmeta removes this entry at the end of the document}
+% \item[|annot_widget_no_AA|] (rule 6.6.2-1)
+% no AA dictionary in widget annotation,
+% this will e.g. be checked by the new hyperref driver.
+% \item[|annot_widget_no_A_AA|] (rule 6.9-2) no A and AA dictionary in widget.
+% \item[|form_no_AA|] (6.9-3) no /AA dictionary in form field
+% \end{description}
+%
+% \subsubsection{Tests with values and special handlers}
+%
+% \begin{description}
+%
+% \item[|min_pdf_version|] stores the minimal PDF version.
+% It should be checked against the current PDF version (\cs{pdf_version:}).
+% A failure means that the version should be changed.
+% This check is done by \pkg{l3pdfmeta} when the version is set with
+% \cs{DeclareDocumentMetadata} so more checks are only needed if the version is changed later.
+%
+% \item[|named_actions|] this requirement restricts the list of
+% allowed named actions to |NextPage|, |PrevPage|, |FirstPage|, |LastPage|.
+% The check should supply the named action without slash
+% (e.g. |View| (failure) or |NextPage| (pass)).
+%
+% \item[|annot_action_A|] (rule 6.6.1-1) this requirement restricts
+% the allowed subtypes of the
+% |/A| dictionary of an action. The check should supply the user
+% subtype without slash e.g. as |GoTo| (pass) or |Movie| (failure).
+% \end{description}
+%
+% \subsection{Colorprofiles and OutputIntent}
+%
+% The pdf/A standards require that a color profile is embedded and
+% referenced in the catalog in the |/OutputIntent| array.
+%
+% The problem is that the pdf/A standards also require, that if the PDF has more then
+% one entry in the |/OutputIntent| array (which is allowed), their |/DestOutputProfile|
+% should all reference the same color profile\footnote{see rule 6.2.2-2 at
+% \url{https://docs.verapdf.org/validation/pdfa-part1/}}.
+%
+% Enforcing this fully is impossible if entries are added manually by users or
+% packages with |\pdfmanagement_add:nnn {Catalog}{OutputIntents}{|\meta{object reference}|}|
+% as it is difficult to inspect and remove entries from the |/OutputIntent| array.
+%
+% So we provide a dedicated interface to avoid the need of manual
+% user settings and allow the code to handle the requirements of the standard.
+% The interface doesn't handle yet all finer points for PDF/X standards, e.g.
+% named profiles, it is meant as a starting point to get at least PDF/A validation
+% here.
+%
+% \begin{NOTE}{UF}
+% The interface has to handle the following points:
+% \begin{itemize}
+% \item We have to assume that some documents wants to add more
+% than one OutputIntent with varying subtypes.
+% \item While currently only |/GTS_PDFA1| and |/GTS_PDFX| seem to
+% be relevant, we have to assume that the list of subtypes is open.
+% \item But we can imho assume that every subtype is there at most once.
+% \item The referenced color profile can be used also other means, e.g. an /ICCBased
+% color space. We must avoid that it is embedded twice in this case.
+% This will need coordination with l3color. It should probably provide the
+% code to embed the profile.
+% \item While we can predeclare some standard icc-profiles, an interface to
+% setup more is needed. This is currently not handled, as it needs
+% coordination with a setup in l3color too.
+% \item The implementation doesn't really handle yet all finer points for pdf/X
+% see \url{tn0002_color_in_pdfa-1_2008-03-141.pdf}
+% \end{itemize}
+% \end{NOTE}
+% The interface looks like this
+%
+% \begin{verbatim}
+% \DeclareDocumentMetadata
+% {
+% %other options for example pdfstandard
+% colorprofiles=
+% {
+% A = sRGB.icc, %or a or longer GTS_PDFA1 = sRGB.icc
+% X = FOGRA39L_coated.icc, % or x or longer GTS_PDFX
+% ISO_PDFE1 = whatever.icc
+% }
+%
+% }
+% \end{verbatim}
+%
+% |sRGB.icc| and |FOGRA39L_coated.icc| (from the \pkg{colorprofiles} package
+% are predefined and will work directly\footnote{The \texttt{dvips} route
+% will require that \texttt{ps2pdf} is called with \texttt{-dNOSAFER},
+% and that the color profiles are in the current folder as \texttt{ps2pdf} doesn't
+% use \texttt{kpathsea} to find them.}. |whatever.icc| will need special setup in
+% the document preamble to declare the values for the
+% |OutputIntent| dictionary, but the interface hasn't be added yet. This will be
+% decided later.
+%
+%
+% If an A-standard is detected or set which requires
+% that all |/DestOutputProfile| reference the same
+% color profile, the setting is changed to the equivalent of
+%
+% \begin{verbatim}
+% \DeclareDocumentMetadata
+% {
+% %other options
+% pdfstandard=A-2b,
+% colorprofiles=
+% {
+% A = sRGB.icc, %or longer GTS_PDFA1 = sRGB.icc
+% X = sRGB.icc,
+% ISO_PDFE1 = sRGB.icc
+% }
+%
+% }
+% \end{verbatim}
+%
+% The pdf/A standards will use |A=sRGB.icc| by default, so this doesn't
+% need to be declared explicitly.
+%
+%
+% \end{documentation}
+%
+% \begin{implementation}
+%
+% \section{\pkg{l3pdfmeta} implementation}
+%
+% \begin{macrocode}
+%<@@=pdfmeta>
+%<*header>
+\ProvidesExplPackage {l3pdfmeta} {2021-02-22} {0.95a}
+ {PDF-Standards---LaTeX PDF management testphase bundle}
+%</header>
+% \end{macrocode}
+% Message for unknown standards
+% \begin{macrocode}
+%<*package>
+\msg_new:nnn {pdf }{unknown-standard}{The~standard~'#1'~is~unknown~and~has~been~ignored}
+% \end{macrocode}
+% \begin{variable}{\l_@@_tmpa_tl,\l_@@_tmpb_tl,\l_@@_tmpa_str}
+% \begin{macrocode}
+\tl_new:N\l_@@_tmpa_tl
+\tl_new:N\l_@@_tmpb_tl
+\str_new:N \l_@@_tmpa_str
+% \end{macrocode}
+% \end{variable}
+% \subsection{Standards (work in progress)}
+% \subsubsection{Tools and tests}
+% This internal property will contain for now the settings for the document.
+% \begin{variable}{\g_@@_standard_prop}
+% \begin{macrocode}
+\prop_new:N \g_@@_standard_prop
+% \end{macrocode}
+% \end{variable}
+% \subsubsection{Functions to check a requirement}
+% At first two commands to get the standard value if needed:
+% \begin{macro}[EXP]{\pdfmeta_standard_item:n}
+% \begin{macrocode}
+\cs_new:Npn \pdfmeta_standard_item:n #1
+ {
+ \prop_item:Nn \g_@@_standard_prop {#1}
+ }
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\pdfmeta_standard_get:nN}
+% \begin{macrocode}
+\cs_new_protected:Npn \pdfmeta_standard_get:nN #1 #2
+ {
+ \prop_get:NnN \g_@@_standard_prop {#1} #2
+ }
+% \end{macrocode}
+% \end{macro}
+% Now two functions to check the requirement. A simple and one value/handler based.
+% \begin{macro}[pTF]{\pdfmeta_standard_verify:n}
+% This is a simple test is the requirement is in the prop.
+% \begin{macrocode}
+\prg_new_conditional:Npnn \pdfmeta_standard_verify:n #1 {T,F,TF}
+ {
+ \prop_if_in:NnTF \g_@@_standard_prop {#1}
+ {
+ \prg_return_false:
+ }
+ {
+ \prg_return_true:
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}[TF]{\pdfmeta_standard_verify:nn}
+% This allows to test against a user value. It calls a test handler if this
+% exists and passes the user and the standard value to it. The test
+% handler should return true or false.
+% \begin{macrocode}
+\prg_new_protected_conditional:Npnn \pdfmeta_standard_verify:nn #1 #2 {T,F,TF}
+ {
+ \prop_if_in:NnTF \g_@@_standard_prop {#1}
+ {
+ \cs_if_exist:cTF {@@_standard_verify_handler_#1:nn}
+ {
+ \exp_args:Nnnx
+ \use:c
+ {@@_standard_verify_handler_#1:nn}
+ { #2 }
+ { \prop_item:Nn \g_@@_standard_prop {#1} }
+ }
+ {
+ \prg_return_false:
+ }
+ }
+ {
+ \prg_return_true:
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% Now we setup a number of handlers.
+%
+% The first actually ignores the user values and tests against the
+% current pdf version. If this is smaller than the minimum we report a failure.
+% |#1| is the user value, |#2| the reference value from the standard.
+% \begin{macro}{\@@_standard_verify_handler_min_pdf_version:nn}
+% \begin{macrocode}
+%
+\cs_new_protected:Npn \@@_standard_verify_handler_min_pdf_version:nn #1 #2
+ {
+ \pdf_version_compare:NnTF <
+ { #2 }
+ {\prg_return_false:}
+ {\prg_return_true:}
+ }
+% \end{macrocode}
+% \end{macro}
+% The next checks if the user value is in the list and returns a failure if not.
+% \begin{macro}{\@@_standard_verify_handler_named_actions:nn}
+% \begin{macrocode}
+
+\cs_new_protected:Npn \@@_standard_verify_handler_named_actions:nn #1 #2
+ {
+ \tl_if_in:nnTF { #2 }{ #1 }
+ {\prg_return_true:}
+ {\prg_return_false:}
+ }
+% \end{macrocode}
+% \end{macro}
+% The next checks if the user value is in the list and returns a failure if not.
+% \begin{macro}{\@@_standard_verify_handler_annot_action_A:nn}
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_standard_verify_handler_annot_action_A:nn #1 #2
+ {
+ \tl_if_in:nnTF { #2 }{ #1 }
+ {\prg_return_true:}
+ {\prg_return_false:}
+ }
+% \end{macrocode}
+% \end{macro}
+% This check is probably not needed, but for completeness
+% \begin{macro}{\@@_standard_verify_handler_outputintent_subtype:nn}
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_standard_verify_handler_outputintent_subtype:nn #1 #2
+ {
+ \tl_if_eq:nnTF { #2 }{ #1 }
+ {\prg_return_true:}
+ {\prg_return_false:}
+ }
+% \end{macrocode}
+% \end{macro}
+% \subsubsection{Enforcing requirements}
+% A number of requirements can sensibly be enforced by us.
+% \paragraph{Annot flags}
+% pdf/A require a number of settings here, we store them in a command which
+% can be added to the property of the standard:
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_verify_pdfa_annot_flags:
+ {
+ \bitset_set_true:Nn \l_pdfannot_F_bitset {Print}
+ \bitset_set_false:Nn \l_pdfannot_F_bitset {Hidden}
+ \bitset_set_false:Nn \l_pdfannot_F_bitset {Invisible}
+ \bitset_set_false:Nn \l_pdfannot_F_bitset {NoView}
+ \pdfannot_dict_put:nnn {link/URI}{F}{ \bitset_to_arabic:N \l_pdfannot_F_bitset }
+ \pdfannot_dict_put:nnn {link/GoTo}{F}{ \bitset_to_arabic:N \l_pdfannot_F_bitset }
+ \pdfannot_dict_put:nnn {link/GoToR}{F}{ \bitset_to_arabic:N \l_pdfannot_F_bitset }
+ \pdfannot_dict_put:nnn {link/Launch}{F}{ \bitset_to_arabic:N \l_pdfannot_F_bitset }
+ \pdfannot_dict_put:nnn {link/Named}{F}{ \bitset_to_arabic:N \l_pdfannot_F_bitset }
+ }
+% \end{macrocode}
+% At begin document this should be checked:
+% \begin{macrocode}
+\hook_gput_code:nnn {begindocument} {pdf}
+ {
+ \pdfmeta_standard_verify:nF { annot_flags }
+ { \@@_verify_pdfa_annot_flags: }
+ }
+% \end{macrocode}
+%
+% \subsubsection{pdf/A}
+% We use global properties so that follow up standards can be
+% copied and then adjusted.
+% Some note about requirements for more standard can
+% be found in info/pdfstandard.tex.
+% \begin{variable}{
+% \g_@@_standard_pdf/A-1B_prop ,
+% \g_@@_standard_pdf/A-2B_prop ,
+% \g_@@_standard_pdf/A-3B_prop
+% }
+% \begin{macrocode}
+\prop_new:c { g_@@_standard_pdf/A-1B_prop }
+\prop_set_from_keyval:cn { g_@@_standard_pdf/A-1B_prop }
+ {
+ ,name = pdf/A-1B
+ ,type = A
+ ,year = 2005
+ ,min_pdf_version = 1.4 %minimum
+ ,no_encryption =
+ ,no_external_content = % no F, FFilter, or FDecodeParms in stream dicts
+ ,no_embed_content = % no EF key in filespec, no /Type/EmbeddedFiles
+ ,max_string_size = 65535
+ ,max_array_size = 8191
+ ,max_dict_size = 4095
+ ,max_obj_num = 8388607
+ ,max_nest_qQ = 28
+ ,named_actions = {NextPage, PrevPage, FirstPage, LastPage}
+ ,annot_flags =
+ %booleans. Only the existence of the key matter.
+ %If the entry is added it means a requirements is there
+ %(in most cases "don't use ...")
+ %
+ %===============
+ % Rule 6.1.13-1 CosDocument, isOptionalContentPresent == false
+ ,Catalog_no_OCProperties =
+ %===============
+ % Rule 6.6.1-1: PDAction, S == "GoTo" || S == "GoToR" || S == "Thread"
+ % || S == "URI" || S == "Named" || S == "SubmitForm"
+ % means: no /S/Launch, /S/Sound, /S/Movie, /S/ResetForm, /S/ImportData,
+ % /S/JavaScript, /S/Hide
+ ,annot_action_A = {GoTo,GoToR,Thread,URI,Named,SubmitForm}
+ %===============
+ % Rule 6.6.2-1: PDAnnot, Subtype != "Widget" || AA_size == 0
+ % means: no AA dictionary
+ ,annot_widget_no_AA =
+ %===============
+ % Rule 6.9-2: PDAnnot, Subtype != "Widget" || (A_size == 0 && AA_size == 0)
+ % (looks like a tightening of the previous rule)
+ ,annot_widget_no_A_AA =
+ %===============
+ % Rule 6.9-1 PDAcroForm, NeedAppearances == null || NeedAppearances == false
+ ,form_no_NeedAppearances =
+ %===============
+ %Rule 6.9-3 PDFormField, AA_size == 0
+ ,form_no_AA =
+ %===============
+ % to be continued https://docs.verapdf.org/validation/pdfa-part1/
+ % - Outputintent/colorprofiles requirements
+ % an outputintent should be loaded and is unique.
+ ,outputintent_A = {GTS_PDFA1}
+ % - no Alternates key in image dictionaries
+ % - no OPI, Ref, Subtype2 with PS key in xobjects
+ % - Interpolate = false in images
+ % - no TR, TR2 in ExtGstate
+ }
+
+%A-2b ==============
+\prop_new:c { g_@@_standard_pdf/A-2B_prop }
+\prop_gset_eq:cc
+ { g_@@_standard_pdf/A-2B_prop }
+ { g_@@_standard_pdf/A-1B_prop }
+\prop_gput:cnn
+ { g_@@_standard_pdf/A-2B_prop }{name}{pdf/A-2B}
+\prop_gput:cnn
+ { g_@@_standard_pdf/A-2B_prop }{year}{2011}
+% embedding files is allowed (with restrictions)
+\prop_gremove:cn
+ { g_@@_standard_pdf/A-2B_prop }
+ { embed_content}
+
+%A-3b ==============
+\prop_new:c { g_@@_standard_pdf/A-3B_prop }
+\prop_gset_eq:cc
+ { g_@@_standard_pdf/A-3B_prop }
+ { g_@@_standard_pdf/A-2B_prop }
+\prop_gput:cnn
+ { g_@@_standard_pdf/A-3B_prop }{name}{pdf/A-3B}
+\prop_gput:cnn
+ { g_@@_standard_pdf/A-2B_prop }{year}{2012}
+% embedding files is allowed (with restrictions)
+\prop_gremove:cn
+ { g_@@_standard_pdf/A-3B_prop }
+ { embed_content}
+% \end{macrocode}
+% \end{variable}
+%
+% \subsubsection{Colorprofiles and Outputintents}
+% The following provides a minimum of interface to add a color profile
+% and an outputintent need for PDF/A for now. There will be need to extend it later,
+% so we try for enough generality.
+%
+% Adding a profile and an intent is technically easy:
+% \begin{enumerate}
+% \item Embed the profile as stream with
+% \begin{verbatim}
+% \pdf_object_unnamed_write:nn{fstream} {{/N~4}{XXX.icc}}
+% \end{verbatim}
+% \item Write a |/OutputIntent| dictionary for this
+% \begin{verbatim}
+% \pdf_object_unnamed_write:nx {dict}
+% {
+% /Type /OutputIntent
+% /S /GTS_PDFA1 % or GTS_PDFX or ISO_PDFE1 or ...
+% /DestOutputProfile \pdf_object_ref_last: % ref the color profile
+% /OutputConditionIdentifier ...
+% ... %more info
+% }
+% \end{verbatim}
+% \item Reference the dictionary in the catalog:
+% \begin{verbatim}
+% \pdfmanagement_add:nnx {Catalog}{OutputIntents}{\pdf_object_ref_last:}
+% \end{verbatim}
+% \end{enumerate}
+% But we need to do a bit more work, to get the interface right.
+% The object for the profile should be named, to allow l3color to reuse it
+% if needed. And we need container to store the profiles, to handle the
+% standard requirements.
+%
+% \begin{variable}{\g_@@_outputintents_prop}
+% This variable will hold the profiles for the subtypes. We assume
+% that every subtype has only only color profile.
+% \begin{macrocode}
+\prop_new:N \g_@@_outputintents_prop
+% \end{macrocode}
+% \end{variable}
+% Some keys to fill the property.
+% \begin{macrocode}
+\keys_define:nn { document / metadata }
+ {
+ colorprofiles .code:n =
+ {
+ \keys_set:nn { document / metadata / colorprofiles }{#1}
+ }
+ }
+\keys_define:nn { document / metadata / colorprofiles }
+ {
+ ,A .code:n =
+ {
+ \tl_if_blank:nF {#1}
+ {
+ \prop_gput:Nnn \g_@@_outputintents_prop
+ { GTS_PDFA1 } {#1}
+ }
+ }
+ ,a .code:n =
+ {
+ \tl_if_blank:nF {#1}
+ {
+ \prop_gput:Nnn \g_@@_outputintents_prop
+ { GTS_PDFA1 } {#1}
+ }
+ }
+ ,X .code:n =
+ {
+ \tl_if_blank:nF {#1}
+ {
+ \prop_gput:Nnn \g_@@_outputintents_prop
+ { GTS_PDFX } {#1}
+ }
+ }
+ ,x .code:n =
+ {
+ \tl_if_blank:nF {#1}
+ {
+ \prop_gput:Nnn \g_@@_outputintents_prop
+ { GTS_PDFX } {#1}
+ }
+ }
+ ,unknown .code:n =
+ {
+ \tl_if_blank:nF {#1}
+ {
+ \exp_args:NNo
+ \prop_gput:Nnn \g_@@_outputintents_prop
+ { \l_keys_key_str } {#1}
+ }
+ }
+ }
+% \end{macrocode}
+% At first we setup our two default profiles. This is internal as
+% the public interface is still undecided.
+% \begin{macrocode}
+\pdfdict_new:n {l_pdfmeta/outputintent}
+\pdfdict_put:nnn {l_pdfmeta/outputintent}
+ {Type}{/OutputIntent}
+\prop_const_from_keyval:cn { c_@@_colorprofile_sRGB.icc}
+ {
+ ,OutputConditionIdentifier=IEC~sRGB
+ ,Info=IEC~61966-2.1~Default~RGB~colour~space~-~sRGB
+ ,RegistryName=http://www.iec.ch
+ ,N = 3
+ }
+\prop_const_from_keyval:cn { c_@@_colorprofile_FOGRA39L_coated.icc}
+ {
+ ,OutputConditionIdentifier=FOGRA39L~Coated
+ ,Info={Offset~printing,~according~to~ISO~12647-2:2004/Amd~1,~OFCOM,~ %
+ paper~type~1~or~2~=~coated~art,~115~g/m2,~tone~value~increase~
+ curves~A~(CMY)~and~B~(K)}
+ ,RegistryName=http://www.fogra.org
+ ,N = 4
+ }
+% \end{macrocode}
+% \begin{macro}{\@@_embed_colorprofile:n,\@@_write_outputintent:nn}
+% The commands embed the profile, and write the dictionary and add it to
+% the catalog. The first command should perhaps be moved to l3color
+% as it needs such profiles too. We used named objects so that we can
+% check if the profile is already there. This is not full proof if pathes are
+% used.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_embed_colorprofile:n #1%#1 file name
+ {
+ \pdf_object_if_exist:nF { __color_icc_ #1 }
+ {
+ \pdf_object_new:nn { __color_icc_ #1 }{fstream}
+ \pdf_object_write:nx { __color_icc_ #1 }
+ {
+ {/N\c_space_tl
+ \prop_item:cn{c_@@_colorprofile_#1}{N}
+ }
+ {#1}
+ }
+ }
+ }
+
+\cs_new_protected:Npn \@@_write_outputintent:nn #1 #2 %#1 file name, #2 subtype
+ {
+ \group_begin:
+ \pdfdict_put:nnx {l_pdfmeta/outputintent}{S}{/\str_convert_pdfname:n{#2}}
+ \pdfdict_put:nnx {l_pdfmeta/outputintent}
+ {DestOutputProfile}
+ {\pdf_object_ref:n{ __color_icc_ #1 }}
+ \clist_map_inline:nn { OutputConditionIdentifier, Info, RegistryName }
+ {
+ \prop_get:cnNT
+ { c_@@_colorprofile_#1}
+ { ##1 }
+ \l_@@_tmpa_tl
+ {
+ \pdf_string_from_unicode:nVN {utf8/string}\l_@@_tmpa_tl\l_@@_tmpa_str
+ \pdfdict_put:nnx
+ {l_pdfmeta/outputintent}{##1}{\l_@@_tmpa_str}
+ }
+ }
+ \pdf_object_unnamed_write:nx {dict}{\pdfdict_use:n {l_pdfmeta/outputintent} }
+ \pdfmanagement_add:nnx {Catalog}{OutputIntents}{\pdf_object_ref_last:}
+ \group_end:
+ }
+% \end{macrocode}
+% \end{macro}
+% Now the verifying code.
+% If no requirement is set we simply loop over the property
+% \begin{macrocode}
+
+\AddToHook{begindocument/end}
+ {
+ \pdfmeta_standard_verify:nTF {outputintent_A}
+ {
+ \prop_map_inline:Nn \g_@@_outputintents_prop
+ {
+ \@@_embed_colorprofile:n
+ {#2}
+ \@@_write_outputintent:nn
+ {#2}
+ {#1}
+ }
+ }
+% \end{macrocode}
+% If an output intent is required for pdf/A we need to ensure, that the key of
+% default subtype has a value, as default we take sRGB.icc.
+% Then we loop but take always the same profile.
+% \begin{macrocode}
+ {
+ \exp_args:NNx
+ \prop_if_in:NnF
+ \g_@@_outputintents_prop
+ { \pdfmeta_standard_item:n { outputintent_A } }
+ {
+ \exp_args:NNx
+ \prop_gput:Nnn
+ \g_@@_outputintents_prop
+ { \pdfmeta_standard_item:n { outputintent_A } }
+ { sRGB.icc }
+ }
+ \exp_args:NNx
+ \prop_get:NnN
+ \g_@@_outputintents_prop
+ { \pdfmeta_standard_item:n { outputintent_A } }
+ \l_@@_tmpb_tl
+ \exp_args:NV \@@_embed_colorprofile:n \l_@@_tmpb_tl
+ \prop_map_inline:Nn \g_@@_outputintents_prop
+ {
+ \exp_args:NV
+ \@@_write_outputintent:nn
+ \l_@@_tmpb_tl
+ { #1 }
+ }
+ }
+ }
+% \end{macrocode}
+%
+% \begin{macrocode}
+%</package>
+% \end{macrocode}
+%
+% \end{implementation}
+%
+% \PrintIndex
diff --git a/Master/texmf-dist/source/latex/pdfmanagement-testphase/l3pdftools.dtx b/Master/texmf-dist/source/latex/pdfmanagement-testphase/l3pdftools.dtx
new file mode 100644
index 00000000000..481ddce8724
--- /dev/null
+++ b/Master/texmf-dist/source/latex/pdfmanagement-testphase/l3pdftools.dtx
@@ -0,0 +1,427 @@
+% \iffalse meta-comment
+%
+%% File: l3pdftools.dtx
+%
+% Copyright (C) 2018-2021 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
+%
+% http://www.latex-project.org/lppl.txt
+%
+% This file is part of the "LaTeX PDF management testphase 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/pdfresources
+%
+% for those people who are interested.
+%
+%<*driver>
+\RequirePackage{pdfmanagement-testphase}
+\DeclareDocumentMetadata{pdfstandard=A-2b}
+\makeatletter
+\declare@file@substitution{doc.sty}{doc-v3beta.sty}
+\makeatother
+\documentclass[full]{l3doc}
+\usepackage{array,booktabs,hyperxmp}
+\hypersetup{pdfauthor=The LaTeX Project,pdftitle=l3pdftools (LaTeX PDF management testphase bundle)}
+
+\providecommand\potentialclash{\noindent\llap{\dbend\ }}
+\begin{document}
+ \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
+% \fi
+%
+% \title{^^A
+% The \pkg{l3pdftools} module\\ temporary collection of pdf related commands ^^A
+% \\ LaTeX PDF management testphase bundle
+% }
+%
+% \author{^^A
+% The \LaTeX{} Project\thanks
+% {^^A
+% E-mail:
+% \href{mailto:latex-team@latex-project.org}
+% {latex-team@latex-project.org}^^A
+% }^^A
+% }
+%
+% \date{Version 0.95a, released 2021-02-22}
+%
+% \maketitle
+% \begin{documentation}
+%
+% \section{\pkg{l3pdftools} documentation}
+%
+% This module collects a number of candidate commands for the l3pdf module
+%
+% \begin{function}[EXP,added=2021-02-14]
+% {\pdf_name_from_unicode_e:n}
+% \begin{syntax}
+% \cs{pdf_name_from_unicode_e:n} \Arg{content}
+% \end{syntax}
+% This converts \meta{content} to a format suitable for a PDF Name.
+% It will first expand the content with \cs{text_expand:n} and
+% then escape it in the way needed in a PDF Name with
+% \cs{str_convert_pdfname:e}, and at last prepend a slash before.
+% Typically such names use only ascii,
+% but non-ascii is supported, but should be utf8 encoded. For example\\
+% |\pdf_name_from_unicode_e:n {A~B\c_percent_str C\c_hash_str D€}}|\\
+% will output |/A#20B#25C#23D#E2#82#AC|.
+% \end{function}
+% \begin{function}[added=2020-07-04]
+% {\pdf_string_from_unicode:nnN}
+% \begin{syntax}
+% \cs{pdf_string_from_unicode:nnN} \Arg{format} \Arg{content} \Arg{tlvar}
+% \end{syntax}
+% This converts \meta{content} following the rules defined by \meta{format} and stores
+% the result in \meta{tlvar}. The assignment is done locally.
+% Non-ascii input should be utf8 encoded.
+% Currently the following formats exist:
+% \begin{description}
+% \item[utf8/string-raw]
+% this converts with \cs{str_set_convert:Nnnn} into utf8/string.
+% \item[utf8/string]
+% this converts into utf8/string and adds parentheses around the result.%
+% \item[utf8/URI-raw]
+% this converts with \cs{str_set_convert:Nnnn} into utf8/url and
+% then replaces reserved and digits back from the percent encoding. Parentheses
+% are escaped.
+% \item[utf8/URI]
+% this converts into utf8/URI and adds parentheses around the result.%
+% \item[utf16/string-raw]
+% this converts with \cs{str_set_convert:Nnnn} into utf16/string.
+% \item[utf16/string]
+% this converts into utf16/string and adds parentheses around the result.
+% \item[utf16/hex-raw]
+% this converts into utf16/hex
+% \item[utf16/hex]
+% this converts into utf16/hex and adds bracket around the result.
+% \end{description}
+% \end{function}
+%
+% \subsection{BDC operator / Properties resource}
+% \begin{NOTE}{UF}
+% we need a switch for the case that the resource should be added to
+% xform resource instead of a page resources, see pdfbase.sty
+% - xdvipdfmx: looks fine, the resource is added to the xform resource automatically
+% - pdftex should now work okay too
+% \end{NOTE}
+% Entries to the /Properties dictionary in the page resources can
+% be added with dvips only through side-effects: if a BDC-mark is created
+% dvips/ghostscript will automatically create the necessary objects and names.
+% To get a sensible abstraction the code does the same for the other backends if the
+% core management code has been activated. This means that the behaviour
+% of the command is different then. The \cs{pdf_bdcobject:..} should only be used
+% if the management is active.
+% \begin{function}[updated = 2020-07-03]
+% {
+% \pdf_bdc:nn
+% }
+% \begin{syntax}
+% \cs{pdf_bdc:nn} \Arg{tag} \Arg{dictionary content}
+% \end{syntax}
+% This command adds a BDC marked content operator to the current page stream.
+% \meta{tag} is the tag of this operator (without the leading slash),
+% \meta{dictionary content} is the content of the second argument.
+% If the PDF resource management is active an dictionary object with the
+% content is created and referenced with a name in the BDC operator.
+% Without the resource management the content is used directly. It then
+% depends on the backend how it is handled: with dvips a name is used
+% while the pdfmode engines and dvipdfmx write the content into the stream.
+%
+% \end{function}
+% \begin{function}[added = 2020-07-03]
+% {
+% \pdf_bdcobject:nn
+% }
+% \begin{syntax}
+% \cs{pdf_bdcobject:nn} \Arg{tag} \Arg{object name}
+% \end{syntax}
+% This command adds a BDC marked content operator to the current page stream.
+% \meta{tag} is the tag of this operator (without the leading slash),
+% \meta{object name} is a the name of an dictionary object reserved with
+% \cs{pdf_object_new:nn} and filled with \cs{pdf_object_write:n} with
+% the properties of the BDC. Reusing a predefined object can save space
+% but the command works correctly
+% only if the resources management has been activated and should be used only
+% if this can be ensured.
+% \end{function}
+% \begin{function}[updated = 2020-07-03]
+% {
+% \pdf_bdcobject:n
+% }
+% \begin{syntax}
+% \cs{pdf_bdcobject:n} \Arg{tag}
+% \end{syntax}
+% This command adds a BDC marked content operator to the current page stream.
+% \meta{tag} is the tag of this operator (without the leading slash).
+% As object this commands uses the last anonymous dictionary object created with
+% \cs{pdf_object_now:nn}. It lies in the responsibility of the user that the last
+% object is the wanted one. Like with \cs{pdf_bdcobject:nn} the command works correctly
+% only if the resources management has been activated and should be used only
+% if this can be ensured.
+% \end{function}
+% \begin{function}[added = 2019-10-17]
+% {
+% \pdf_bmc:n
+% }
+% \begin{syntax}
+% \cs{pdf_bmc:n} \Arg{tag}
+% \end{syntax}
+% This command created a BMC marked content operator. The argument is the
+% tag without the leading slash. It can be e.g. used for simple artifact
+% markers.
+% \end{function}
+% \begin{function}[added = 2019-06-30]
+% {
+% \pdf_emc:
+% }
+% \begin{syntax}
+% \cs{pdf_emc:}
+% \end{syntax}
+% This command closes the BDC marked content operator opened with \cs{pdf_bdc:nn}.
+% It should be on the same page as the bdc-command.
+%
+% \begin{verbatim}
+% \pdf_object_new:nn {objA}{dict}
+% \pdf_object_write:nn {objA}{/Type/Artifact}
+% \pdf_bdc:nn {Span}{objA}
+% text
+% \pdf_emc:
+% \end{verbatim}
+% \end{function}
+%
+%
+% \end{documentation}
+%
+% \begin{implementation}
+%
+% \section{\pkg{l3pdftools} implementation}
+%
+% \begin{macrocode}
+%<*header>
+\ProvidesExplPackage {l3pdftools} {2021-02-22} {0.95a}
+ {candidate commands for l3pdf---LaTeX PDF management testphase bundle}
+%</header>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<@@=pdf>
+%<*package>
+% \end{macrocode}
+% \subsection{Conversions and export functions}
+% \begin{macro}{\pdf_name_from_unicode_e:n,\pdf_name_from_unicode_e:V}
+% \begin{macrocode}
+\cs_generate_variant:Nn \str_convert_pdfname:n { e }
+
+\cs_new:Npn \pdf_name_from_unicode_e:n #1
+ {
+ / \str_convert_pdfname:e { \text_expand:n { #1 } }
+ }
+
+\cs_generate_variant:Nn \pdf_name_from_unicode_e:n {V}
+% \end{macrocode}
+% \end{macro}
+%
+% The convert command must use a different value the source encoding
+% depending on the engines. Until the PR in str-convert is active we add the alias here
+% too
+% \begin{macrocode}
+\bool_lazy_any:nTF
+ {
+ \sys_if_engine_luatex_p:
+ \sys_if_engine_xetex_p:
+ }
+ {
+ \prop_gput:Nnn \g__str_alias_prop { default } { }
+ }
+ {
+ \prop_gput:Nnn \g__str_alias_prop { default } { utf8 }
+ }
+% \end{macrocode}
+% \begin{macro}{\pdf_string_from_unicode:nnN}
+% \begin{macrocode}
+\cs_new:Npn \pdf_string_from_unicode:nnN #1 #2 #3
+ {
+ \cs_if_exist_use:cF { @@_string_from_unicode_#1:nN }
+ {
+ \__kernel_msg_error:nnn { pdf } { unknown-convert } {#1}
+ \use_none:nn
+ }
+ { #2 } #3
+ }
+
+\cs_generate_variant:Nn \pdf_string_from_unicode:nnN {nVN}
+% \end{macrocode}
+% \end{macro}
+% Most converter are simply wrapper around the str-convert commands and so
+% use the same names, with the addition raw if no delimiters are added.
+% The exception is the one for url's: it reverts most of the percent encodings
+% and escapes the parentheses.
+% That's why its name is URI instead of url. The current code is probably quite
+% slow and will need a replacement.
+% \begin{macro}{ @@_string_from_unicode_utf8/string-raw:nN }
+% \begin{macro}{ @@_string_from_unicode_utf8/string:nN }
+% \begin{macro}{ @@_string_from_unicode_utf8/URI-raw:nN }
+% \begin{macro}{ @@_string_from_unicode_utf8/URI:nN }
+% \begin{macro}{ @@_string_from_unicode_utf16/string-raw:nN }
+% \begin{macro}{ @@_string_from_unicode_utf16/string:nN }
+% \begin{macro}{ @@_string_from_unicode_utf16/hex-raw:nN }
+% \begin{macro}{ @@_string_from_unicode_utf16/hex:nN }
+% \begin{macrocode}
+%% TODO Names need a review when it is clear which converters
+%% are actually needed
+%% string conversions and printing
+%% we assume here that the text purify step has been done. The input is
+%% a list of (utf8) chars.
+%% str convert, not expandable.
+% filespec (attachment view) tests:
+% utf8: gr\303\274\303\237e.txt
+% %doesn't work, umlaut wrong,
+% utf8 with BOM \357\273\277gr\303\274\303\237e.txt
+% %doesn't work, umlaut wrong, bom visible
+% utf16 with BE: (FEFF)
+% \376\377\000g\000r\000\374\000\337\000e\000.\000t\000x\000t %works
+% xetex converts to <feff0067007200fc00df0065002e007400780074>
+% utf16 with BE / HEX: <FEFF0067007200FC00DF0065002E007400780074> works
+
+% bookmarks: as pdfoutline uses () currently only utf16 with BE is usable.
+% check if one can use HEX too when directly writing the object
+% ==========
+% uri: utf16BE/string seems not to work, hex neither
+% utf8/string works but not on macos,
+% so a specfic utf8/url variant is needed
+% ==========
+% "input" is utf8 for pdftex, empty (native) for unicode engine
+% commands to output literal strings (...)
+
+\cs_new_protected:cpn { @@_string_from_unicode_utf8/string-raw:nN } #1 #2
+ {
+ \str_set_convert:Nnnn #2
+ { #1 }
+ { default }
+ {utf8/string}
+ }
+
+\cs_new_protected:cpn { @@_string_from_unicode_utf8/string:nN } #1 #2
+ {
+ \use:c { @@_string_from_unicode_utf8/string-raw:nN } { #1 } #2
+ \str_put_left:Nn #2 {(}
+ \str_put_right:Nn #2 {)}
+ }
+% special url command:
+\cs_new_protected:cpx { @@_string_from_unicode_utf8/URI-raw:nN } #1 #2
+ {
+ \exp_not:N \str_set_convert:Nnnn #2
+ { #1 }
+ { default }
+ {utf8/url}
+ \exp_not:N \str_replace_all:Nnn #2 {\c_percent_str 3A} {:}
+ \exp_not:N \str_replace_all:Nnn #2 {\c_percent_str 2F} {/}
+ \exp_not:N \str_replace_all:Nnn #2 {\c_percent_str 23} {\c_hash_str}
+ \exp_not:N \str_replace_all:Nnn #2 {\c_percent_str 5B} {[}
+ \exp_not:N \str_replace_all:Nnn #2 {\c_percent_str 5D} {]}
+ \exp_not:N \str_replace_all:Nnn #2 {\c_percent_str 40} {\c_atsign_str}
+ \exp_not:N \str_replace_all:Nnn #2 {\c_percent_str 21} {!}
+ \exp_not:N \str_replace_all:Nnn #2 {\c_percent_str 24} {\c_dollar_str}
+ \exp_not:N \str_replace_all:Nnn #2 {\c_percent_str 26} {\c_ampersand_str}
+ \exp_not:N \str_replace_all:Nnn #2 {\c_percent_str 27} {'}
+ \exp_not:N \str_replace_all:Nnn #2 {\c_percent_str 2A} {*}
+ \exp_not:N \str_replace_all:Nnn #2 {\c_percent_str 2B} {+}
+ \exp_not:N \str_replace_all:Nnn #2 {\c_percent_str 2C} {,}
+ \exp_not:N \str_replace_all:Nnn #2 {\c_percent_str 3B} {;}
+ \exp_not:N \str_replace_all:Nnn #2 {\c_percent_str 3D} {=}
+ \exp_not:N \str_replace_all:Nnn #2 {\c_percent_str 30} {0}
+ \exp_not:N \str_replace_all:Nnn #2 {\c_percent_str 31} {1}
+ \exp_not:N \str_replace_all:Nnn #2 {\c_percent_str 32} {2}
+ \exp_not:N \str_replace_all:Nnn #2 {\c_percent_str 33} {3}
+ \exp_not:N \str_replace_all:Nnn #2 {\c_percent_str 34} {4}
+ \exp_not:N \str_replace_all:Nnn #2 {\c_percent_str 35} {5}
+ \exp_not:N \str_replace_all:Nnn #2 {\c_percent_str 36} {6}
+ \exp_not:N \str_replace_all:Nnn #2 {\c_percent_str 37} {7}
+ \exp_not:N \str_replace_all:Nnn #2 {\c_percent_str 38} {8}
+ \exp_not:N \str_replace_all:Nnn #2 {\c_percent_str 39} {9}
+ \exp_not:N \str_replace_all:Nnn #2 {\c_percent_str 28} {\c_backslash_str(}
+ \exp_not:N \str_replace_all:Nnn #2 {\c_percent_str 29} {\c_backslash_str)}
+ }
+
+\cs_new_protected:cpn { @@_string_from_unicode_utf8/URI:nN } #1 #2
+ {
+ \use:c { @@_string_from_unicode_utf8/URI-raw:nN } {#1} #2
+ \str_put_left:Nn #2 {(}
+ \str_put_right:Nn #2 {)}
+ }
+% with utf16 with BE marker
+\cs_new_protected:cpn { @@_string_from_unicode_utf16/string-raw:nN } #1 #2
+ {
+ \str_set_convert:Nnnn #2
+ { #1 }
+ { default }
+ {utf16/string}
+ }
+
+\cs_new_protected:cpn { @@_string_from_unicode_utf16/string:nN } #1 #2
+ {
+ \use:c { @@_string_from_unicode_utf16/string-raw:nN } {#1} #2
+ \str_put_left:Nn #2 {(}
+ \str_put_right:Nn #2 {)}
+ }
+
+\cs_new_protected:cpn { @@_string_from_unicode_utf16/hex-raw:nN } #1 #2
+ {
+ \str_set_convert:Nnnn #2
+ { #1 }
+ { default }
+ {utf16/hex}
+ }
+
+\cs_new_protected:cpn { @@_string_from_unicode_utf16/hex:nN } #1 #2
+ {
+ \use:c { @@_string_from_unicode_utf16/hex-raw:nN } {#1} #2
+ \str_put_left:Nn #2 {<}
+ \str_put_right:Nn #2 {>}
+ }
+
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \subsubsection{BDC operator commands}
+% \begin{macro}{\pdf_bdc:nn}
+% \begin{macro}{\pdf_bdcobject:nn}
+% \begin{macro}{\pdf_bdcobject:n}
+% \begin{macro}{\pdf_bmc:n}
+% \begin{macro}{\pdf_emc:}
+% \begin{macrocode}
+\cs_new_protected:Npn \pdf_bdc:nn #1 #2 { \@@_backend_bdc:nn { #1 }{ #2 } }
+\cs_new_protected:Npn \pdf_bdcobject:nn #1 #2 { \@@_backend_bdcobject:nn { #1 }{ #2 } }
+\cs_new_protected:Npn \pdf_bdcobject:n #1 { \@@_backend_bdcobject:n { #1 } }
+\cs_new_protected:Npn \pdf_bmc:n #1 { \@@_backend_bmc:n { #1 } }
+\cs_new_protected:Npn \pdf_emc: { \@@_backend_emc: }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \begin{macrocode}
+%</package>
+% \end{macrocode}
+%
+% \end{implementation}
+%
+% \PrintIndex
diff --git a/Master/texmf-dist/source/latex/pdfmanagement-testphase/l3pdfxform.dtx b/Master/texmf-dist/source/latex/pdfmanagement-testphase/l3pdfxform.dtx
new file mode 100644
index 00000000000..ec9afe865db
--- /dev/null
+++ b/Master/texmf-dist/source/latex/pdfmanagement-testphase/l3pdfxform.dtx
@@ -0,0 +1,204 @@
+% \iffalse meta-comment
+%
+%% File: l3pdfxform.dtx
+%
+% Copyright (C) 2018-2021 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
+%
+% http://www.latex-project.org/lppl.txt
+%
+% This file is part of the "LaTeX PDF management testphase 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/pdfresources
+%
+% for those people who are interested.
+%
+%<*driver>
+\RequirePackage{pdfmanagement-testphase}
+\DeclareDocumentMetadata{pdfstandard=A-2b}
+\makeatletter
+\declare@file@substitution{doc.sty}{doc-v3beta.sty}
+\makeatother
+\documentclass[full]{l3doc}
+\usepackage{array,booktabs,hyperxmp}
+\hypersetup{pdfauthor=The LaTeX Project,pdftitle=l3pdfxform (LaTeX PDF management testphase bundle)}
+
+\begin{document}
+ \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
+% \fi
+%
+% \title{^^A
+% The \pkg{l3pdfxform} module\\ Commands for form XObjects ^^A
+% \\ \LaTeX{} PDF management testphase bundle
+% }
+%
+% \author{^^A
+% The \LaTeX{} Project\thanks
+% {^^A
+% E-mail:
+% \href{mailto:latex-team@latex-project.org}
+% {latex-team@latex-project.org}^^A
+% }^^A
+% }
+%
+% \date{Version 0.95a, released 2021-02-22}
+%
+% \maketitle
+% \begin{documentation}
+%
+% \section{\pkg{l3pdfxform} documentation}
+% This module contains a number of commands to create \enquote{form XObjects},
+% for which pdf\TeX{} introduced the short name \enquote{xforms}.
+%
+% The status is still beta, so the style itself is currently named
+% \pkg{l3pdfxform-beta}. Missing is for example code for the dvips route.
+% Probably some of the function will also need to be enhanced by hooks.
+%
+% \begin{function}[added = 2019-08-05,updated=2021-02-14]
+% {
+% \pdfxform_new:nnn
+% }
+% \begin{syntax}
+% \cs{pdfxform_new:nnn} \Arg{name} \Arg{attributes} \Arg{content}
+% \end{syntax}
+% This command create a new form XObject that can be used as appearance or
+% directly later.
+% If the \meta{content} contains BDC-marks it should \emph{not} be given as a
+% previously typeset box, but directly so that the names of the
+% BDC-marks can be added to the resources of the xform. The xform will automatically
+% include the resources of the current page.
+% The content will be typeset in a hbox. With pdflatex and luatex
+% the surrounding color is \emph{not} stored in the form XObject
+% but should be if wanted added e.g. with |\color_select:n{.}|. This keeps
+% the option of color injection open.
+% \end{function}
+% \begin{function}[added = 2019-08-05]
+% {
+% \pdfxform_use:n
+% }
+% \begin{syntax}
+% \cs{pdfxform_use:n} \Arg{name}
+% \end{syntax}
+% This command uses (typesets) a previously created form XObject.
+% If the surrounding color is different, it is injected in the form XObject with the
+% engines pdftex or luatex.
+% \end{function}
+% \begin{function}[EXP,added = 2019-08-05]
+% {
+% \pdfxform_ref:n
+% }
+% \begin{syntax}
+% \cs{pdfxform_ref:n} \Arg{name}
+% \end{syntax}
+% Inserts the appropriate information to reference the xform \meta{name}
+% in for example appearance dictionaries.
+% \end{function}
+% \begin{function}[EXP,added = 2019-08-05]
+% {
+% \pdfxform_wd:n, \pdfxform_ht:n, \pdfxform_dp:n
+% }
+% \begin{syntax}
+% \cs{pdfxform_wd:n} \Arg{name}
+% \end{syntax}
+% These command give back the sizes of the form XObject. The values are stored in
+% tl-variables with the unit pt and not in dimensions!
+% \end{function}
+% \begin{function}[EXP,pTF,added = 2020-04-29]
+% {
+% \pdfxform_if_exist:n
+% }
+% \begin{syntax}
+% \cs{pdfxform_if_exist_p:n} \Arg{name}
+% \cs{pdfxform_if_exist:NTF} \meta{name} \Arg{true code} \Arg{false code}
+% \end{syntax}
+% These command tests if an xform with name \Arg{name} has been already defined.
+% \end{function}%
+% \end{documentation}
+%
+% \begin{implementation}
+%
+% \section{\pkg{l3pdfxform} implementation}
+%
+% \begin{macrocode}
+%<@@=pdf>
+%<*header>
+\ProvidesExplPackage {l3pdfxform-beta} {2021-02-22} {0.95a}
+ {command to create xforms (beta)---LaTeX PDF management testphase bundle}
+%</header>
+% \end{macrocode}
+% \subsection{Form XObject (pdfxform)}
+% \begin{NOTE}{UF}
+% - As in dvi mode the xform is immediate, this is done for pdftex/luatex too.
+% If needed a delayed version can be added later.
+% - the argument for attributes is needed to add e.g. /StructParents
+% - it is not clear if an argument for additional resources is needed, probably they
+% should / need to be added automatically.
+% - code for adding ExtGState etc to the local resource is missing, will be
+% added when the object name is clear.
+% - should the size be stored in dim or tl?
+% - dvips implementation is missing for ideas: pdfbase, atfi-dvips.def,
+% \end{NOTE}
+% \begin{macro}{\pdfxform_new:nnn}
+% \begin{macrocode}
+%<*package>
+\cs_new_protected:Npn \pdfxform_new:nnn #1 #2 #3
+ {
+ \@@_backend_xform_new:nnnn { #1 } { #2 } { } { #3 }
+ }
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\pdfxform_use:n}
+% \begin{macrocode}
+\cs_new_protected:Npn \pdfxform_use:n #1
+ {
+ \@@_backend_xform_use:n { #1 }
+ }
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\pdfxform_ref:n,\pdfxform_ref:o}
+% \begin{macrocode}
+% expansion?
+\cs_new:Npn \pdfxform_ref:n #1
+ {
+ \@@_backend_xform_ref:n { #1 }
+ }
+
+\cs_generate_variant:Nn \pdfxform_ref:n {o}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\pdfxform_wd:n,\pdfxform_ht:n,\pdfxform_dp:n,}
+% \begin{macrocode}
+\cs_new:Npn \pdfxform_wd:n #1
+ {
+ \tl_use:c { c_@@_backend_xform_wd_ \tl_to_str:n { #1 } _tl }
+ }
+
+\cs_new:Npn \pdfxform_ht:n #1
+ {
+ \tl_use:c { c_@@_backend_xform_ht_ \tl_to_str:n { #1 } _tl }
+ }
+
+\cs_new:Npn \pdfxform_dp:n #1
+ {
+ \tl_use:c { c_@@_backend_xform_dp_ \tl_to_str:n { #1 } _tl }
+ }
+% \end{macrocode}
+% \end{macro}
+% \begin{macrocode}
+%</package>
+% \end{macrocode}
+%
+% \end{implementation}
+%
+% \PrintIndex
diff --git a/Master/texmf-dist/source/latex/pdfmanagement-testphase/ltdocinit.dtx b/Master/texmf-dist/source/latex/pdfmanagement-testphase/ltdocinit.dtx
new file mode 100644
index 00000000000..f37514d936c
--- /dev/null
+++ b/Master/texmf-dist/source/latex/pdfmanagement-testphase/ltdocinit.dtx
@@ -0,0 +1,354 @@
+% \iffalse meta-comment
+%
+%% File: ltdocinit.dtx
+%
+% Copyright (C) 2018-2021 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
+%
+% http://www.latex-project.org/lppl.txt
+%
+% This file is part of the "LaTeX PDF management testphase 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/pdfresources
+%
+% for those people who are interested.
+%
+%<*driver>
+\RequirePackage{pdfmanagement-testphase}
+\DeclareDocumentMetadata{pdfstandard=A-2b}
+\makeatletter
+\declare@file@substitution{doc.sty}{doc-v3beta.sty}
+\makeatother
+\documentclass[full]{l3doc}
+\usepackage{array,booktabs,hyperxmp}
+\hypersetup{pdfauthor=The LaTeX Project,pdftitle=ltdocinit (LaTeX PDF management testphase bundle)}
+
+\begin{document}
+ \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
+% \fi
+%
+% \title{^^A
+% The \pkg{ltdocinit} module
+% }
+%
+% \author{^^A
+% The \LaTeX{} Project\thanks
+% {^^A
+% E-mail:
+% \href{mailto:latex-team@latex-project.org}
+% {latex-team@latex-project.org}^^A
+% }^^A
+% }
+%
+% \date{Version 0.95a, released 2021-02-22}
+%
+% \maketitle
+% \begin{documentation}
+%
+% \section{\pkg{ltdocinit} documentation}
+% This small module defines \cs{DeclareDocumentMetadata} and the related keys.
+% It also defines commands to store document properties in a global container.
+%
+% \subsection{\cs{DeclareDocumentMetadata}}
+%
+% \begin{function}{\DeclareDocumentMetadata}
+% \begin{syntax}
+% \cs{DeclareDocumentMetadata}\Arg{key-value list}
+% \end{syntax}
+% \end{function}
+%
+% Currently there is 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{DeclareDocumentMetadata} as a new command
+% should unify such settings in one place.
+% It should be used before \cs{documentclass}, directly after
+% loading \pkg{pdfmanagement-testphase}. \cs{DeclareDocumentMetadata}
+% can be used more than once.
+%
+% The keys defined for \cs{DeclareDocumentMetadata}
+% currently allows 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 colorprofiles.
+%
+% \cs{DeclareDocumentMetadata} 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{DeclareDocumentMetadata}.
+%
+% Currently the following keys are implemented
+%
+% \begin{description}
+% \item[\texttt{backend}] passes the backend name to expl3.
+% This will probably be extended to pass the value also to packages.
+% \item[\texttt{pdfversion}] e.g. \texttt{pdfversion=1.7}
+% \item[\texttt{uncompress}] no value. Forces an uncompressed pdf.
+% \item[\texttt{lang}] to set the Lang entry in the Catalog.
+% E.g. \texttt{lang=de-DE}. The initial value is |en-US|
+% \item[\texttt{pdfstandard}] Choice key to set the pdf standard.
+% Currently |A-1b|, |A-2b| and |A-3b| are accepted as
+% values. The underlying code to ensure the requirements (as far as they
+% can be ensured) is incomplete, but a color profile is included and the
+% /OutputIntent is set. More information can be found in the documentation
+% of \pkg{l3pdfmeta}.
+% \item[\texttt{colorprofiles}] This allows to load icc-colorprofiles. Details
+% are described in the documentation of \pkg{l3pdfmeta}.
+% \item[\texttt{pdfmanagement}] Boolean. This activates/deactivates
+% the core management code. By default the value is true.
+% \item[firstaidoff] This accepts a comma lists of keysword and disable the patches
+% related to them. More information can be found in the documentation of
+% \pkg{pdfmanagement-firstaid}.
+% \end{description}
+%
+% \subsection{Container for document properties}
+%
+% The module provides a container where classes, packages and users can store
+% properties of the document which are perhaps of interest
+% or use for other packages or the author.
+%
+% The properties are stored with a key |label/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 choosen, it should be one which avoids clashes with other packages
+% using the container. The label |document| is reserved.
+% \end{function}
+%
+% \begin{function}{\GetDocumentProperties}
+% \begin{syntax}
+% \cs{AddToDocumentProperties}\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.
+% The result is returned within \cs{exp_not:n}, which means
+% that the \meta{value} does not expand further
+% when appearing in an x-type argument expansion.
+% \end{function}
+%
+% \begin{function}{\ShowDocumentProperties}
+% \begin{syntax}
+% \cs{ShowDocumentProperties}
+% \end{syntax}
+% This show the current content of the container.
+% \end{function}
+%
+% \end{documentation}
+%
+% \begin{implementation}
+%
+% \section{\pkg{ltdocinit} implementation}
+% \subsection{\cs{DeclareDocumentMetadata}}
+% \begin{macrocode}
+%<@@=pdfmanagement>
+%<*header>
+\ProvidesExplPackage {ltdocinit} {2021-02-22} {0.95a}
+ {Initialize document metadata}
+%</header>
+% \end{macrocode}
+% \cs{DeclareDocumentMetadata} should for now not be used after
+% \cs{documentclass} so we error in this case. It can be used more than once
+% but follow-up calls should not do the initialization code.
+% \begin{macrocode}
+%<*package>
+\msg_new:nnn { document } { setup-after-documentclass }
+ {
+ \token_to_str:N \DeclareDocumentMetadata \c_space_tl
+ should~be~used~only~before~\token_to_str:N\documentclass
+ }
+% \end{macrocode}
+% \begin{macro}{\DeclareDocumentMetadata}
+% \begin{macrocode}
+\NewDocumentCommand\DeclareDocumentMetadata { m }
+ {
+ \cs_if_eq:NNTF \documentclass \@twoclasseserror
+ { \msg_error:nn { document }{ setup-after-documentclass } }
+ {
+% \end{macrocode}
+% The wanted backend must be detected first, we read the init key and then
+% force the loading by either loading l3pdf (+ expl3) or only expl3.
+% \begin{macrocode}
+ \keys_set_groups:nnn { document / metadata} {init}{ #1 }
+ %should be loaded after the backend is set, and only if not in the kernel
+ \cs_if_free:NTF \pdf_uncompress:
+ {\RequirePackage{l3pdf}}{\RequirePackage{expl3}}
+% \end{macrocode}
+% Now we load the extra backend code and set the boolean to true
+% \begin{macrocode}
+ \ExplSyntaxOn\makeatletter
+ \file_input:n {l3backend-testphase-\c_sys_backend_str.def}
+ \ExplSyntaxOff\makeatother
+ \bool_gset_true:N \g_@@_active_bool
+% \end{macrocode}
+% set the default language, process the rest of the keys,
+% and setup the generic driver
+% \begin{macrocode}
+ \keys_set_filter:nnn { document / metadata } { init } { lang=en-US, #1 }
+ \bool_if:NT \g_@@_active_bool
+ {
+ \PassOptionsToPackage{customdriver=hgeneric-testphase}{hyperref}
+ }
+% \end{macrocode}
+% \cs{pdfmanagement_add:nnn} has collected values in this hook.
+% \begin{macrocode}
+ \hook_use_once:n {pdfmanagement/add}
+% \end{macrocode}
+% Redefine \cs{DeclareDocumentMetadata} so that it only process the keys.
+% We need to update the hyperref option if the active status changes.
+% \begin{macrocode}
+ \RenewDocumentCommand\DeclareDocumentMetadata { m }
+ {
+ \keys_set_filter:nnn { document / metadata } { init } { ##1 }
+ \bool_if:NTF \g_@@_active_bool
+ {
+ \str_remove_all:cn {opt@hyperref.sty}{customdriver=hgeneric-testphase}
+ \PassOptionsToPackage{customdriver=hgeneric-testphase}{hyperref}
+ }
+ {
+ \str_remove_all:cn {opt@hyperref.sty}{customdriver=hgeneric-testphase}
+ }
+ }
+% \end{macrocode}
+% Load more modules and the firstaid code.
+% \begin{macrocode}
+ \RequirePackage{pdfmanagement-firstaid}
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \subsection{Container for document Properties}
+% The container for the document properties is a prop
+% \begin{variable}{\g_@@_documentproperties_prop}
+% \begin{macrocode}
+\prop_new:N \g_@@_documentproperties_prop %
+% \end{macrocode}
+% \end{variable}
+% \begin{macro}{\AddToDocumentProperties}
+% \begin{macrocode}
+\NewDocumentCommand\AddToDocumentProperties{O{\@currname}mm}
+ {
+ \exp_args:NNx
+ \prop_gput:Nnn \g_@@_documentproperties_prop
+ {
+ \tl_if_blank:eTF {#1}{top-level/}{#1/} #2
+ }
+ { #3}
+ }
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\GetDocumentProperties}
+% \begin{macrocode}
+\NewExpandableDocumentCommand\GetDocumentProperties{m}
+ {
+ \prop_item:Nn \g_@@_documentproperties_prop {#1}
+ }
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\ShowDocumentProperties}
+% \begin{macrocode}
+\msg_new:nnn { pdfmanagement } { show-properties }
+ {
+ The~following~document~properties~have~been~stored:
+ #1
+ }
+\NewDocumentCommand\ShowDocumentProperties {}
+ {
+ \msg_show:nnx {pdfmanagement}{show-properties}
+ {
+ \prop_map_function:NN \g_@@_documentproperties_prop \msg_show_item:nn
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \subsection{The keys for \cs{DeclareDocumentMetadata}}
+% As they use \cs{AddToDocumentProperties} they have to come after
+% it has been defined.
+%
+% \begin{variable}{\g_@@_firstaidoff_clist}
+% A list to store the firstaid code which should be disabled
+% \begin{macrocode}
+\clist_new:N \g_@@_firstaidoff_clist
+% \end{macrocode}
+% \end{variable}
+% \begin{macrocode}
+\keys_define:nn { document / metadata }
+ {
+ backend .code:n =
+ {
+ \PassOptionsToPackage { driver=#1 } {expl3}
+ \AddToDocumentProperties[document]{backend}{#1}
+ },
+ backend .groups:n = { init } ,
+ }
+
+\keys_define:nn { document / metadata }
+ {
+ ,pdfversion .code:n =
+ {
+ \pdf_version_gset:n { #1 }
+ \AddToDocumentProperties[document]{pdfversion}{#1}
+ }
+ ,uncompress .code:n =
+ {
+ \pdf_uncompress:
+ }
+ ,uncompress .value_forbidden:n = true
+ ,lang .code:n =
+ {
+ \pdfmanagement_add:nnn {Catalog} {Lang}{(#1)}
+ \AddToDocumentProperties[document]{lang}{#1}
+ }
+ %,xmpmeta .bool_gset:N = \g_pdfmeta_xmp_bool %see pdfmeta unused and undefined for now!
+ % this uses internal command from pdfmeta, it should probably move there ...
+ ,pdfstandard .code:n =
+ {
+ \exp_args:Nnx
+ \keys_set:nn {document / metadata} {_pdfstandard=\str_uppercase:n{#1}}
+ }
+ ,_pdfstandard .choices:nn =
+ {A-1B,A-2B,A-3B}
+ {
+ \prop_if_exist:cT { g__pdfmeta_standard_pdf/#1_prop }
+ {
+ \prop_gset_eq:Nc \g__pdfmeta_standard_prop { g__pdfmeta_standard_pdf/#1 _prop }
+ }
+ \AddToDocumentProperties [document]{pdfstandard}{#1}
+ }
+ ,_pdfstandard / unknown .code:n =
+ {
+ \msg_warning:nnn{pdf}{unknown-standard}{#1}
+ }
+ ,pdfmanagement .bool_gset:N = \g_@@_active_bool
+ ,pdfmanagement .initial:n = {true}
+ ,firstaidoff .clist_gset:N = \g_@@_firstaidoff_clist
+ }
+% \end{macrocode}
+% \begin{macrocode}
+%</package>
+% \end{macrocode}
+%
+% \end{implementation}
+%
+% \PrintIndex
diff --git a/Master/texmf-dist/source/latex/pdfmanagement-testphase/pdfmanagement-firstaid.dtx b/Master/texmf-dist/source/latex/pdfmanagement-testphase/pdfmanagement-firstaid.dtx
new file mode 100644
index 00000000000..08fbf856db1
--- /dev/null
+++ b/Master/texmf-dist/source/latex/pdfmanagement-testphase/pdfmanagement-firstaid.dtx
@@ -0,0 +1,319 @@
+% \iffalse meta-comment
+%
+%% File: pdfmanagement-firstaid.dtx
+%
+% Copyright (C) 2018-2021 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
+%
+% http://www.latex-project.org/lppl.txt
+%
+% This file is part of the "LaTeX PDF management testphase 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/pdfresources
+%
+% for those people who are interested.
+%
+%<*driver>
+\RequirePackage{pdfmanagement-testphase}
+\DeclareDocumentMetadata{pdfstandard=A-2b}
+\makeatletter
+\declare@file@substitution{doc.sty}{doc-v3beta.sty}
+\makeatother
+\documentclass[full]{l3doc}
+\usepackage{array,booktabs,hyperxmp}
+\hypersetup{pdfauthor=The LaTeX Project,pdftitle=pdfmanagement-firstaid
+ (LaTeX PDF management testphase bundle)}
+\begin{document}
+ \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
+% \fi
+% \title{^^A
+% The \pkg{pdfmanagement-firstaid} package -- temporary patches and package replacements ^^A
+% \\ \LaTeX{} PDF management testphase bundle
+% }
+%
+% \author{^^A
+% The \LaTeX{} Project\thanks
+% {^^A
+% E-mail:
+% \href{mailto:latex-team@latex-project.org}
+% {latex-team@latex-project.org}^^A
+% }^^A
+% }
+%
+% \date{Version 0.95a, released 2021-02-22}
+%
+% \maketitle
+% \begin{documentation}
+%
+% \section{\pkg{pdfmanagement-firstaid} documentation}
+% This code is temporary! It tries to patch commands of other packages or even
+% replace package which are incompatible with the pdfmanagement,
+% to remove clashes and test if everything works as expected.
+% This code should disappear when packages adapt to the central interfaces.
+%
+% The package contains an number of sections for various packages. Every
+% section can be disabled in (the first) \cs{DeclareDocumentMetadata} with
+% |firstaidoff={name1,name2,...}|.
+% \begin{macrocode}
+%<*package>
+\ProvidesExplPackage {pdfmanagement-firstaid} {2021-02-22} {0.95a}
+ {LaTeX PDF management testphase bundle / firstaid-patches}
+
+%<@@=pdfmanagement>
+\clist_map_inline:nn {pgf,transparent,hyperxmp,pdflscape,xcolor,color}
+ {
+ \bool_new:c { g_@@_firstaid_#1_bool }
+ \bool_gset_true:c { g_@@_firstaid_#1_bool }
+ }
+\clist_map_inline:Nn \g_@@_firstaidoff_clist
+ {
+ \bool_if_exist:cT { g_@@_firstaid_#1_bool }
+ {
+ \bool_gset_false:c { g_@@_firstaid_#1_bool }
+ }
+ }
+\msg_new:nnn { pdfmanagement } { firstaid }
+ { loading~pdfmanagement~firstaid~code~for~#1 }
+% \end{macrocode}
+% \subsection{\pkg{color}}
+%
+% \pkg{color} is not incompatible, but the new \pkg{hyperref} driver makes use of
+% \pkg{l3color} to set the colors. It is therefore necessary to patch some
+% internal \pkg{color} commands, so
+% that colors defined with its \cs{definecolor} command are known to \pkg{l3color} and
+% so \pkg{hyperref}. This only supports the color models from l3color (which covers
+% all standard model of the \pkg{color} package). The |named| model is mapped to
+% \cs{color_set:nn}.
+%
+% This patch serves also as test to check if this change can be safely
+% added to \pkg{color} later.
+% \begin{macrocode}
+\@ifundefined{color_set:nn}{
+\RequirePackage{l3color}}{}
+\bool_if:NT \g_@@_firstaid_color_bool
+ {
+ \declare@file@substitution{color.sty}{color-ltx.sty}
+ }
+% \end{macrocode}
+%
+% \subsection{\pkg{xcolor}}
+%
+% \pkg{xcolor} is not incompatible, but the new \pkg{hyperref} driver makes use of
+% \pkg{l3color} to set the colors. It is therefore necessary to patch \pkg{xcolor}, so
+% that colors defined with its \cs{definecolor} command are known to \pkg{l3color} and
+% so \pkg{hyperref}. This only supports the color model from l3color. Colors defined
+% with the models |cmy| and |tHsb| are silently ignored.
+%
+% The |named| model is mapped to \cs{color_set:nn}.
+%
+% \begin{macrocode}
+\@ifundefined{color_set:nn}{
+\RequirePackage{l3color}}{}
+\bool_if:NT \g_@@_firstaid_xcolor_bool
+ {
+ \AddToHook{package/after/xcolor}
+ {\RequirePackage{xcolor-patches-tmp-ltx}\XC@@@@names}
+ }
+% \end{macrocode}
+% \subsection{\pkg{pgf}}
+%
+% In \pkg{pgf}, resource management is set up in the file |pgfutil-common.tex|.
+% This then provides three functions for adding to the resources, all of which
+% are objects:
+% \begin{itemize}
+% \item \cs{pgfutil@addpdfresource@extgs}: Extended graphics state
+% \item \cs{pgfutil@addpdfresource@colorspaces}: Color spaces
+% \item \cs{pgfutil@addpdfresource@patterns}: Patterns
+% \end{itemize}
+%
+% These resource dictionaries are used by adding entries in a cumulative sense;
+% the macro layer deals with ensuring that each entry is only given once. Note
+% that the objects themselves must be given only once for each page.
+%
+% To support these functions, there are a series of set-up macros which install
+% these resources. That has to take place for every page: the exact route
+% therefore depends on the driver.
+%
+% For the pdfmanagement project we need to avoid that pgf interferes in ExtGState,
+% ColorSpace and Pattern (Shadings are added to the xform resources and so probably
+% unproblematic for now).
+% The actual patch is in a file hook guarded by the boolean,
+% the rest of the code is always defined.
+% \begin{macrocode}
+
+\bool_if:NT \g_@@_firstaid_pgf_bool
+ {
+ \msg_info:nnn{pdfmanagement }{firstaid}{pgf}
+ \AddToHook{file/after/pgfrcs.sty}
+ {
+ \cs_set_eq:NN
+ \@@_pgfori_pgfutil@setuppdfresources
+ \pgfutil@setuppdfresources
+ \def\pgfutil@setuppdfresources
+ {
+ \pdfmanagement_if_active:TF
+ {
+ \@@_pgf_sys_setuppdfresources_plain:
+ }
+ {
+ \@@_pgfori_pgfutil@setuppdfresources
+ }
+ }
+ }
+ }
+%\def\pgfutil@addpdfresource@extgs#1{\pgf@sys@addpdfresource@extgs@plain{#1}}
+%\def\pgfutil@addpdfresource@colorspaces#1{\pgf@sys@addpdfresource@colorspaces@plain{#1}}
+%\def\pgfutil@addpdfresource@patterns#1{\pgf@sys@addpdfresource@patterns@plain{#1}}
+%\def\pgfutil@setuppdfresources{\pgf@sys@setuppdfresources@plain}
+% \pgf@sys@pdf@possible@resources %used in xform
+%Trying to patch pgf ..
+\cs_new_protected:Npn \@@_pgf_sys_setuppdfresources_plain:
+ {
+ %objects are already created ...
+ \def\pgf@sys@pdf@possible@resources
+ {
+ /ColorSpace~\pdf_object_ref:n {Page/Resources/ColorSpace}
+ /Pattern ~\pdf_object_ref:n {Page/Resources/Pattern}
+ /ExtGState ~\pdf_object_ref:n {Page/Resources/ExtGState}
+ }
+ \let\pgf@sys@pdf@check@resources=\relax%
+ %not sure if needed, but perhaps the lists are used somewhere else ...
+ \let\pgf@sys@pgf@resource@list@extgs=\pgfutil@empty%
+ \let\pgf@sys@pgf@resource@list@patterns=\pgfutil@empty%
+ \let\pgf@sys@pgf@resource@list@colorspaces=\pgfutil@empty%
+ % the commands to add page resources
+ \def\pgf@sys@addpdfresource@extgs@plain##1
+ {
+ \exp_after:wN %for transparent which passes a command
+ \@@_patch_pgfextgs:w ##1\q_stop
+ }
+ \def\pgf@sys@addpdfresource@patterns@plain##1
+ {
+ \@@_patch_pgfpatterns:w ##1\q_stop
+ }
+ \def\pgf@sys@addpdfresource@colorspaces@plain##1
+ {
+ \@@_patch_pgfcolorspaces:w ##1\q_stop
+ }
+ }
+
+%\AtEndPreamble{\pgfutil@setuppdfresources}
+% helper commands as pgf doesn't pass resources as two arguments
+% code to add to the resources existing stuff in the format "/name value":
+\cs_new:Npn \@@_split_dict_entry_aux:NNw #1 #2 /#3~#4\q_stop
+ {
+ \tl_set:Nn #1 {#3}
+ \tl_set:Nn #2 {#4}
+ }
+
+\cs_new:Npn \@@_patch_pgfextgs:w #1/#2<<#3>>#4\q_stop
+ {
+ \exp_args:Nne
+ \__pdf_backend_PageResources_gput:nnn
+ {ExtGState}{\tl_trim_spaces:n{#2}}{<<#3>>}
+ }
+\cs_new:Npn \@@_patch_pgfpatterns:w #1/#2\space#3\q_stop
+ {
+ \exp_args:Nnxx
+ \__pdf_backend_PageResources_gput:nnn
+ {Pattern}{\tl_trim_spaces:n{#2}}{#3}
+ }
+\cs_new:Npn \@@_patch_pgfcolorspaces:w #1/#2[#3]#4\q_stop
+ {
+ \exp_args:Nne
+ \__pdf_backend_PageResources_gput:nnn
+ {ColorSpace}{\tl_trim_spaces:n{#2}}{[#3]}
+ }
+
+% \end{macrocode}
+% \subsection{\pkg{transparent}}
+% We simply replace by the new version.
+% \begin{macrocode}
+\bool_if:NT \g_@@_firstaid_transparent_bool
+ {
+ \declare@file@substitution{transparent.sty}{transparent-ltx.sty}
+ }
+% \end{macrocode}
+% \subsection{\pkg{pdflscape}}
+% We simply replace by the new version.
+% \begin{macrocode}
+\bool_if:NT \g_@@_firstaid_pdflscape_bool
+ {
+ \declare@file@substitution{pdflscape.sty}{pdflscape-ltx.sty}
+ }
+% \end{macrocode}
+% \subsection{hyperxmp}
+% We add some code at the end of hyperxmp.sty.
+% \begin{macrocode}
+\bool_if:NT \g_@@_firstaid_hyperxmp_bool
+ {
+ \AddToHook
+ {file/after/hyperxmp.sty}
+ {\RequirePackage{hyperxmp-patches-tmp-ltx}}
+ }
+%</package>
+% \end{macrocode}
+% \subsection{\pkg{colorspace}}
+% This is rather difficult as no real places to inject patches
+% at first a try to avoid that its ExtGState is missing:
+% it can not be avoided to recreate the objects (and so to get duplicates)
+% as colorspace uses temporary macros whose contents is lost.
+% \begin{macrocode}
+%<*package>
+%<@@=pdf>
+% this must be earlier, to avoid problems with luatex which has two pageresources
+% lua/tex
+\hook_gput_code:nnn {begindocument} {pdf}
+ {
+ \tl_if_exist:NT \spc@op
+ {
+ \def\spc@Pageresources#1{}
+ }
+
+ }
+
+\hook_gput_code:nnn {begindocument/end} {pdf}
+ {
+ \tl_if_exist:NT \spc@op
+ {
+ \@@_backend_object_new:nn {__spc_extgstate_op_false}{dict}
+ \@@_backend_object_write:nn
+ {__spc_extgstate_op_false}
+ {/Type /ExtGState~/op~false~/OP~false}
+ \pdfmanagement_add:nnn
+ {Page/Resources/ExtGState}
+ {SPCko}
+ {\@@_backend_object_ref:n {__spc_extgstate_op_false}}
+ \@@_backend_object_new:nn {__spc_extgstate_op_true0}{dict}
+ \@@_backend_object_write:nn
+ {__spc_extgstate_op_true0}
+ {/Type /ExtGState~/op~true~/OP~true~/OPM~0}%
+ \pdfmanagement_add:nnn
+ {Page/Resources/ExtGState}
+ {SPCmz}
+ {\@@_backend_object_ref:n {__spc_extgstate_op_true0}}
+ \@@_backend_object_new:nn {__spc_extgstate_op_true1}{dict}
+ \@@_backend_object_write:nn
+ {__spc_extgstate_op_true1}
+ {/Type /ExtGState~/op~true~/OP~true~/OPM~1}%
+ \pdfmanagement_add:nnn
+ {Page/Resources/ExtGState}
+ {SPCop}
+ {\@@_backend_object_ref:n {__spc_extgstate_op_true1}}
+ }
+ }
+%</package>
+% \end{macrocode}%
+% \end{documentation}
+% \PrintIndex
diff --git a/Master/texmf-dist/source/latex/pdfmanagement-testphase/pdfmanagement-testphase.dtx b/Master/texmf-dist/source/latex/pdfmanagement-testphase/pdfmanagement-testphase.dtx
new file mode 100644
index 00000000000..4b63544d179
--- /dev/null
+++ b/Master/texmf-dist/source/latex/pdfmanagement-testphase/pdfmanagement-testphase.dtx
@@ -0,0 +1,429 @@
+% \iffalse meta-comment
+%
+%% File: pdfmanagement-testphase.dtx
+%
+% Copyright (C) 2019-2021 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
+%
+% This file is part of the "LaTeX PDF management testphase 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/pdfresources
+%
+% for those people who are interested.
+%
+%<*driver>
+\RequirePackage{pdfmanagement-testphase}
+\DeclareDocumentMetadata{pdfstandard=A-2b}
+\makeatletter
+\declare@file@substitution{doc.sty}{doc-v3beta.sty}
+\makeatother
+\documentclass{l3doc}
+\usepackage{tabularx,array,booktabs,hyperxmp}
+\hypersetup{pdfauthor=The LaTeX Project,pdftitle=LaTeX PDF management testphase bundle}
+\newcommand\potentialclash{\noindent\llap{\dbend\ }}
+\raggedbottom
+\begin{document}
+ \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
+% \fi
+%
+%
+% \title{The \LaTeX{} PDF management testphase bundle}
+%
+% \author{^^A
+% The \LaTeX{} Project\thanks
+% {^^A
+% E-mail:
+% \href{mailto:latex-team@latex-project.org}
+% {latex-team@latex-project.org}^^A
+% }^^A
+% }
+%
+% \date{Version 0.95a, released 2021-02-22}
+%
+% \maketitle
+% \begin{documentation}
+% \section*{Abstract}
+% {\em This is a temporary package created to allow the manual
+% loading of the new \LaTeX{} PDF management code during a test phase.
+% It will disappear when the code is integrated into the \LaTeX{} format.}
+%
+% \medskip
+% \noindent During the test phase the package should be used like this:
+%
+% \begin{verbatim}
+% \RequirePackage{pdfmanagement-testphase} % load the package
+%
+% \DeclareDocumentMetadata % activate the PDF management (with options)
+% {
+% % options
+% }
+%
+% \documentclass {...}
+% \end{verbatim}
+% Note that the activation has to happen before the \cs{documentclass} declaration.
+% Because of this, the package needs loading with \cs{RequirePackage}.
+%
+%
+%
+% \section*{Feedback wanted!}
+%
+% Bug reports and feedback are welcome. Please open an issue at
+% \url{https://github.com/latex3/pdfresources}.
+%
+% While the code targets PDF as output format, feedback about the
+% effect on other formats is needed too.
+%
+% \section{Introduction}
+% The \LaTeX{} format currently contains nearly no code specific to the now quite
+% central output format, PDF. It also offers nearly no interfaces to important PDF related
+% primitive commands for package writers.
+%
+% Important tasks like supporting PDF standards,
+% creating links, adding special colors, managing the content of
+% central PDF-directories or even simple tasks like setting the PDF version
+% are delegated to external packages which have to recourse to
+% the primitive low-level commands in their code.
+%
+% This is problematic for three reasons:
+% \begin{itemize}
+%\item At first using primitives directly can lead to clashes and duplicate
+% settings with conflicting values---nothing prevent packages to add for example
+% the \texttt{/Title} twice to the Info dictionary, the \texttt{/Lang} entry
+% twice to the Catalog, or to add two \texttt{/ExtGState}
+% resources to a page. The PDF normally doesn't break in such
+% cases---the format is quite robust---but it will ignore one of the duplicates and
+% the output can be wrong.
+%
+% \item At second the primitives differ between the various engines and backends with
+% which \LaTeX{} is used. To support the engines and backend
+% packages have to write and maintain
+% \enquote{driver} files which they did to a varying degree. This makes it
+% difficult for users to assess if a package will work with their work-flow and
+% is a strain for package writers as they have to keep track of engine and backend changes.
+%
+% \item And at last generic hooks and configuration points to various
+% PDF related structures are missing and difficult to add.
+% \end{itemize}
+%
+% Despite the potential problems, until now the number of conflicts were
+% small and could be resolved in an ad-hoc fashion. But the future plans for
+% \LaTeX{} regarding support for tagged PDF and
+% PDF standards mean that much more PDF specific code will have to be
+% written by the kernel directly and this can not be done without proper,
+% well-defined and well-behaving interfaces and hooks.
+%
+% Some first steps for better support of PDF related commands have been already done
+% with the \pkg{l3pdf} package which has now been integrated into \pkg{l3kernel}.
+% It offers backend independent commands to create
+% PDF objects and destination, to set the compress level and the PDF version.
+%
+% The PDF management bundle extends this to more PDF related areas
+% and provides interfaces to them in a backend independent way.
+%
+% The new PDF management has three main objectives
+% connected with the problems identified above:
+% \begin{itemize}
+% \item For commands with \enquote{clash potential} it implements commands to
+% replace the primitives and so to resolve potential conflicts.
+%
+% \item It implements commands for a variety of PDF related tasks
+% and supports a well-defined set of backends.
+%
+% \item If sensible this commands are enhanced by hooks from the new
+% \LaTeX{} hook system. This has been e.g.\ done for annotations in the
+% \pkg{l3pdfannot} bundle.
+% \end{itemize}
+%
+% \section{\enquote{Change Strategy}: The integration into \LaTeX\label{sec:change}}
+%
+% The central module of this bundle, \pkg{l3pdfmanagement}, defines an interface
+% for the (pdf\TeX) primitives \cs{pdfcatalog}, \cs{pdfinfo},
+% \cs{pdfpagesattr}, \cs{pdfpagesattr} and \cs{pdfpageresources} and
+% the analog commands from the other engines and backends.
+%
+% All these commands have a \enquote{clash potential}, this means that the new
+% interface is incompatible with a parallel use of the primitive commands
+% which it targets to replace and supersede.
+% This doesn't affect many packages, but the list of package using such primitives
+% contains central and important packages like \pkg{hyperref}, \pkg{tikz},
+% \pkg{pdfx} and more.
+%
+% So while the goal is to integrate the code into the \LaTeX{} format directly,
+% this can not be done immediately without conflicts with existing documents and packages.
+%
+% As an intermediary step the package \pkg{pdfmanagement-testphase} has been
+% created which loads the code manually.
+% With it package authors and users can test the new code, give feedback
+% and packages can be adapted.
+%
+% Loading the package will only \emph{load} the modules,
+% to \emph{activate} the core PDF management the trigger command
+% \cs{DeclareDocumentMetadata} has to be used too.
+% The loading and activation has to be done
+% \emph{before} the \cs{documentclass} command.
+%
+%
+% We hope that this setup will allow packages writers and users to test the
+% PDF management code and adapt packages and documents safely.
+%
+%
+% \section{Backend support}
+% The supported backends are pdflatex, lualatex, (x)dvipdfmx (latex, xelatex,
+% dvilualatex (in texlive 2021))
+% and dvips with ps2pdf (not completely yet). dvips with distiller could work too
+% but is untested.
+%
+% That the interfaces and commands are backend independent doesn't mean
+% that the results and even the compilation behavior is identical.
+% The backends are too different to allow this.
+% Some backends expand arguments e.g. in a \cs{special} while other don't.
+% Some backends can insert a resource at the first compilation, while another uses
+% the aux-file and a label and so needs at least two compilation runs.
+% Some backends manage some of the resources through side-effects,
+% some manage them automatically.
+% All this mean that package writers will still have to keep an eye on
+% backend requirements and run tests for all variants. Also backend specific code
+% will still be needed in some cases.
+%
+% \section{Use}\label{sec:use}
+% The package should be loaded before \cs{documentclass}. To activate
+% the resource management it should be followed by
+% \cs{DeclareDocumentMetadata}\marg{key-val}.
+% The options of \cs{DeclareDocumentMetadata} are described in the documentation of
+% \pkg{ltdocinit}.
+%
+% \begin{verbatim}
+% \RequirePackage{pdfmanagement-testphase} % load the package
+% \DeclareDocumentMetadata % activates the PDF management interface
+% {
+% %options
+% }
+% \documentclass {...}
+% \end{verbatim}
+%
+% The PDF management can be deactivated either setting the key
+% \texttt{pdfmanagement} to \texttt{false} or by commenting out
+% the whole \cs{DeclareDocumentMetadata} declaration.
+%
+% To test if the PDF management is active the predicate
+% \cs{pdfmanagement_if_active:TF} can be used, see the documentation of \pkg{l3pdfmanagement}.
+%
+% \section{Requirements}
+% The new PDF management requires a \LaTeX{} format from 2020/10/01 or later
+% and an L3 programming layer of 2021-02-18 or later.
+% It currently depends on the experimental packages \pkg{l3ref-tmp} and \pkg{l3bitset}.
+% In some places, e.g. when writing strings to the pdf it assumes that
+% the file is utf8 encoded -- ascii will naturally work too, but legacy 8bit encodings are
+% not supported.
+%
+% \section{Modules}
+% The bundle contains a number of modules. The majority of the modules don't
+% have a stand alone \texttt{sty}, their code is combined
+% in one file and loaded by the main package. The organization and naming is bound
+% to change over time: For almost all modules the goal is to
+% integrate them into the format and the individual files to disappear.
+%
+% The description items give the name of the documentation
+% of the modules. There doesn't exist in all cases a related |.sty|.
+%
+% \begin{description}
+% \item[l3pdfdict] This module provides commands for PDF dictionaries. Its main
+% purpose is to create name spaces. The code used e.g. by \pkg{l3pdfmanagement} and
+% \pkg{l3pdfannot}.
+%
+% \item[l3pdfannot] This module provides commands for annotations. Currently mainly
+% link annotations, widget annotations will be added later. It doesn't require
+% the PDF management to be active.
+%
+% \item[l3pdfmanagement] This is the core code of the PDF management.
+%
+% \item[ltdocinit] This module provides the \cs{DeclareDocumentMetadata} command.
+%
+% \item[hyperref-generic] This module provides a new generic hyperref driver.
+% The driver will
+% be loaded automatically by hyperref if the PDF management code is active.
+%
+% \item[l3backend-testphase] This module contains backend code needed by the
+% PDF management. It will in due time be integrated into l3backend.
+%
+% \item[l3pdfmeta] This module contains code to handle PDF standards.
+% Currently it handles pdf/A and colorprofiles/outputintents.
+%
+% \item[l3pdfxform] Commands for form XObjects (xforms).
+%
+% \item[l3pdf\/tool] A number of commands like text conversion commands and
+% bcd/emc. The commands will at some time be moved into the \pkg{l3pdf}
+% module of l3kernel.
+%
+% \item[l3pdf\/file] This module provides commands for to embed files.
+%
+% \item[pdfmanagement-firstaid] This module provides a number of patches
+% for external incompatible packages. This patches will disappear as soon as
+% the packages are natively compatible. It is loaded automatically.
+%
+% \end{description}
+% \section{Incompabilities}
+%
+% As described in section~\ref{sec:change}, if activated
+% the new PDF management takes over the management of core PDF dictionaries.
+% All packages
+% that bypass the PDF management and access these dictionaries with primitives like
+% \cs{pdfcatalog}, \cs{pdfinfo}, \cs{pdfpageresources}, \cs{pdfpagesattr}
+% and \cs{pdfpageattr} or similar commands from other engines and backends are
+% basically incompatible: values can get lost or will be wrong.
+%
+% The following describes known incompatible packages along with some suggestions
+% how this should or will be handled in future. The list is not exhaustive.
+%
+% \subsection{hyperref}
+% A generic driver that can
+% be used as replacement has been developed and is provided by this bundle.
+% It will be loaded automatically if the pdf management is active.
+%
+% The generic driver differs in some points from other \pkg{hyperref} drivers:
+% \begin{itemize}
+% \item The code for bookmarks has been removed from this driver, instead
+% the \pkg{bookmarks} is loaded and used.
+% \item The driver isn't yet fully integrated into hyperref. This means that
+% it doesn't react to a number of package options. Instead \cs{hypersetup} should
+% be used.
+% \item Incomplete is the support for form fields. Quite probably form fields will
+% be extracted in a dedicated package.
+% \item The driver uses for the color handling the l3color package. While normally
+% it should be able to use colors defined with color and xcolor, there could be
+% edge cases where it fails.
+% \item The colors have been changed (this counts probably as an improvement \ldots).
+% \end{itemize}
+%
+% More details can be found in the documentation \pkg{hyperref-generic.pdf}.
+%
+% \subsection{pdfx}
+% \pkg{pdfx} is not compatible. It uses the commands \cs{pdfpagesattr}, \cs{pdfpageattr},
+% \cs{pdfinfo} and \cs{pdfcatalog}. The needed changes are not many, but can
+% not be done by external patches.
+%
+% It is also one goal of the pdfmanagement project to
+% offer support for standards natively. The code is under development,
+% see the documentation of \pkg{l3pdfmeta}.
+%
+% \subsection{hyperxmp}
+% \pkg{hyperxmp} uses \cs{pdfcatalog} to insert the \texttt{/MetaData} reference. This
+% makes it incompatible, but adjusting this is even possible with external
+% patches. \pkg{hyperxmp} also relies on some \pkg{hyperref} internals, so
+% changes in \pkg{hyperref} must be coordinated.
+%
+% Some patch code is provided by the bundle and loaded automatically,
+% but it is not complete currently. Failures are e.g. possible with complicated
+% author or title settings. The handling of dates isn't correct either yet.
+% The patch code can be disabled by using |firstaidoff=hyperxmp| in \cs{DeclareDocumentMetadata}
+%
+% \subsection{tikz/pgf}
+% \pkg{pgf} writes to the page resources too and so is incompatible. The needed
+% changes are rather small and will be done in coordination with the maintainer.
+% Until this works, \pkg{pagemanagement} will load the patches automatically.
+% This can be disabled by using |firstaidoff=pgf| in \cs{DeclareDocumentMetadata}
+%
+% \subsection{transparent}
+% The package \pkg{transparent} is incompatible. A replacement has been written
+% (\pkg{transparent-ltx}) and is loaded automatically. It requires a very recent
+% L3 programming layer!
+% This can be disabled by using |firstaidoff=transparent| in \cs{DeclareDocumentMetadata}
+% \subsection{pdflscape}
+% The package \pkg{pdflscape} is incompatible. A replacement has been written
+% (\pkg{pdflscape-ltx}) and is loaded automatically.
+% This can be disabled by using |firstaidoff=pdflscape| in \cs{DeclareDocumentMetadata}
+%
+% \subsection{colorspace}
+% The package is incompatible. Some patches
+% have been added to \pkg{pdfmanagement-firstaid}.
+% Alternative code for spot colors is
+% in the \pkg{l3color} package which has now been add to \pkg{l3kernel}.
+%
+% \subsection{embedfile, attachfile, attachfile2}
+% Tools needed to be able to write a replacement
+% to replace these packages have been developed in the \pkg{l3pdffile} package.
+% Full replacements for the packages don't exist yet.
+%
+% \subsection{tagpdf}
+% The development code is compatible and will be uploaded in time.
+%
+% \subsection{ocgx2, animate, media9}
+% These package all make use of low-level PDF command and will
+% have to be reviewed.
+%
+% \subsection{acrotex}
+% The \pkg{acrotex} makes heavy use of PDF commands and so must be reviewed and
+% adapted, including the currently untested route dvips + distiller.
+%
+% \subsection{fancytooltips}
+% This package uses \cs{pdfpageattr} and \pkg{acrotex} and so must be reviewed.
+% \end{documentation}
+%
+%
+% \begin{implementation}
+%
+% \section{Implementation}
+%
+% \begin{macrocode}
+%<@@=pdf>
+%<*package>
+\ProvidesExplPackage {pdfmanagement-testphase} {2021-02-22} {0.95a}
+ {LaTeX PDF management testphase bundle}
+\providecommand\IfFormatAtLeastTF{\@ifl@t@r\fmtversion}
+\IfFormatAtLeastTF{2020-10-01}{}{
+ \PackageWarning{pdfmanagement-testphase}
+ {This~package~needs~LaTeX~2020-10-01~or~newer.
+ \MessageBreak Loading~is~aborted.}{}
+ \DeclareOption { debug }{}
+ \newcommand\DeclareDocumentMetadata[1]{}
+ \ProcessOptions\relax
+ }
+\IfFormatAtLeastTF{2020-10-01}{}{\endinput}
+
+\DeclareOption { debug }
+ {
+ \msg_redirect_module:nnn { pdf } { none } { warning }
+ }
+
+\ProcessOptions\relax
+%</package>
+% \end{macrocode}
+%
+% \subsection{Loading the core files.}
+% This loads the core files. The backend should not be loaded
+% to allow to set it in the document.
+% \begin{macrocode}
+%<*header>
+\ProvidesExplFile
+ {pdfmanagement-testphase.ltx}{2021-02-22}{0.95a}
+ {PDF~management~code~(testphase)}
+%</header>
+%<*package>
+%\RequirePackage{l3pdfdict} % needed by l3pdfmanagement
+%\RequirePackage{l3pdfmanagement} % loads the core code with the boolean
+%\RequirePackage{ltdocinit} % DeclareDocumentMetadata,
+%% can perhaps be combined or made optional ...
+%\RequirePackage{l3pdfannot}
+%\RequirePackage{l3pdfxform-beta}
+%\RequirePackage{l3pdfmeta} %
+%\RequirePackage{l3pdftools}
+%\RequirePackage{l3pdffile}
+\input{pdfmanagement-testphase.ltx}
+%</package>
+% \end{macrocode}
+% \end{implementation}
+% \newpage
+% \PrintIndex
diff --git a/Master/texmf-dist/source/latex/pdfmanagement-testphase/pdfmanagement-testphase.ins b/Master/texmf-dist/source/latex/pdfmanagement-testphase/pdfmanagement-testphase.ins
new file mode 100644
index 00000000000..6452b24c68d
--- /dev/null
+++ b/Master/texmf-dist/source/latex/pdfmanagement-testphase/pdfmanagement-testphase.ins
@@ -0,0 +1,211 @@
+\iffalse meta-comment
+
+File: pdfmanagement-testphase.ins
+
+Copyright (C) 2019-2021 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
+
+This file is part of the "LaTeX PDF management testphase bundle" (The Work in LPPL)
+and all files in that bundle must be distributed together.
+
+The released version of this bundle is available from CTAN.
+
+-----------------------------------------------------------------------
+
+The development version of the bundle can be found at
+
+ https://github.com/latex3/pdfresources
+
+for those people who are interested.
+
+-----------------------------------------------------------------------
+
+\fi
+
+\input l3docstrip.tex
+\askforoverwritefalse
+
+\let\MetaPrefix\relax
+\preamble
+
+Copyright (C) 2019-2021 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
+
+This file is part of the "LaTeX PDF management testphase bundle" (The Work in LPPL)
+and all files in that bundle must be distributed together.
+
+\endpreamble
+\let\MetaPrefix\DoubleperCent
+% stop docstrip adding \endinput
+\postamble
+\endpostamble
+
+\keepsilent
+
+\generate
+ {%
+ \file{pdfmanagement-testphase.sty}
+ {%
+ \from{pdfmanagement-testphase.dtx}{package}
+ }%
+ }
+
+%\generate{\file{ltdocinit.sty}
+% {
+% \from{ltdocinit.dtx} {header,package}
+% }
+%}
+%\generate{\file{l3pdfdict.sty}
+% {
+% \from{l3pdfdict.dtx} {header,package}
+% }
+%}
+%
+%\generate{\file{l3pdfmanagement.sty}
+% {
+% \from{l3pdfmanagement.dtx} {header,package}
+% }
+%}
+%
+%\generate{\file{l3pdfmeta.sty}
+% {
+% \from{l3pdfmeta.dtx} {header,package}
+% }
+%}
+%
+%\generate{\file{l3pdftools.sty}
+% {
+% \from{l3pdftools.dtx} {header,package}
+% }
+%}
+
+\generate
+ {%
+ \file{pdfmanagement-firstaid.sty}
+ {%
+ \from{pdfmanagement-firstaid.dtx}{package}
+ }%
+ }
+
+%\generate
+% {%
+% \file{l3pdfannot.sty}
+% {%
+% \from{l3pdfannot.dtx}{header,package}
+% }%
+% }
+%
+%\generate
+% {%
+% \file{l3pdfxform-beta.sty}
+% {%
+% \from{l3pdfxform.dtx}{header,package}
+% }%
+% }
+%
+%\generate
+% {%
+% \file{l3pdffile.sty}
+% {%
+% \from{l3pdffile.dtx}{header,package}
+% }%
+% }
+
+\generate
+ {
+ \file{l3backend-testphase-dvipdfmx.def}
+ {
+ \from{l3backend-testphase.dtx}{drivers,dvipdfmx}
+ }
+ }
+
+\generate
+ {
+ \file{l3backend-testphase-dvips.def}
+ {
+ \from{l3backend-testphase.dtx}{drivers,dvips}
+ }
+ }
+
+\generate
+ {
+ \file{l3backend-testphase-dvisvgm.def}
+ {
+ \from{l3backend-testphase.dtx}{drivers,dvisvgm}
+ }
+ }
+
+\generate
+ {
+ \file{l3backend-testphase-luatex.def}
+ {
+ \from{l3backend-testphase.dtx}{drivers,luatex}
+ }
+ }
+
+\generate
+ {
+ \file{l3backend-testphase-pdftex.def}
+ {
+ \from{l3backend-testphase.dtx}{drivers,pdftex}
+ }
+ }
+\generate
+ {
+ \file {l3backend-testphase-xetex.def}
+ {
+ \from{l3backend-testphase.dtx}{drivers,xdvipdfmx}
+ }
+ }
+
+\generate
+ {
+ \file {hgeneric-testphase.def}
+ {
+ \from{hyperref-generic.dtx}{package}
+ }
+ }
+\generate
+ {
+ \file {hyperref-colorschemes.def}
+ {
+ \from{hyperref-generic.dtx}{colorscheme}
+ }
+ }
+
+\generate
+ {
+ \file {pdfmanagement-testphase.ltx}
+ {
+ \from{pdfmanagement-testphase.dtx}{header}
+ \from{l3pdfdict.dtx}{package}
+ \from{l3pdfmanagement.dtx}{package}
+ \from{ltdocinit.dtx}{package}
+ \from{l3pdfannot.dtx}{package}
+ \from{l3pdfxform.dtx}{package}
+ \from{l3pdfmeta.dtx}{package}
+ \from{l3pdftools.dtx}{package}
+ \from{l3pdffile.dtx}{package}
+ }
+ }
+
+\def\MetaPrefix{-- }
+\def\defaultpostamble{%
+ \MetaPrefix^^J%
+ \MetaPrefix\space End of File `\outFileName'.%
+}
+\def\currentpostamble{\defaultpostamble}%
+\generate{\file{l3backend-testphase.lua} {\from{l3backend-testphase.dtx}{lua}}}
+\endbatchfile