summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/latex
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/source/latex')
-rw-r--r--Master/texmf-dist/source/latex/babel/babel.dtx464
-rw-r--r--Master/texmf-dist/source/latex/babel/babel.ins2
-rw-r--r--Master/texmf-dist/source/latex/babel/bbcompat.dtx2
-rw-r--r--Master/texmf-dist/source/latex/babel/locale.zipbin778055 -> 778055 bytes
-rw-r--r--Master/texmf-dist/source/latex/microtype/microtype-utf.dtx116
-rw-r--r--Master/texmf-dist/source/latex/microtype/microtype.dtx867
-rw-r--r--Master/texmf-dist/source/latex/microtype/microtype.ins9
-rw-r--r--Master/texmf-dist/source/latex/nicematrix/nicematrix.dtx998
-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
-rw-r--r--Master/texmf-dist/source/latex/spath3/spath3_code.dtx1261
-rw-r--r--Master/texmf-dist/source/latex/tagpdf/tagpdf-backend.dtx803
-rw-r--r--Master/texmf-dist/source/latex/tagpdf/tagpdf-checks.dtx232
-rw-r--r--Master/texmf-dist/source/latex/tagpdf/tagpdf-mc.dtx779
-rw-r--r--Master/texmf-dist/source/latex/tagpdf/tagpdf-roles.dtx156
-rw-r--r--Master/texmf-dist/source/latex/tagpdf/tagpdf-space.dtx89
-rw-r--r--Master/texmf-dist/source/latex/tagpdf/tagpdf-struct.dtx789
-rw-r--r--Master/texmf-dist/source/latex/tagpdf/tagpdf-tree.dtx294
-rw-r--r--Master/texmf-dist/source/latex/tagpdf/tagpdf.dtx498
-rw-r--r--Master/texmf-dist/source/latex/tagpdf/tagpdf.ins100
-rw-r--r--Master/texmf-dist/source/latex/tikzmark/tikzmark.dtx134
-rw-r--r--Master/texmf-dist/source/latex/tikzmark/tikzmark.ins76
-rw-r--r--Master/texmf-dist/source/latex/udesoftec/CHANGELOG23
-rw-r--r--Master/texmf-dist/source/latex/udesoftec/README4
-rw-r--r--Master/texmf-dist/source/latex/udesoftec/UPDATE-INSTRUCTIONS4
-rw-r--r--Master/texmf-dist/source/latex/udesoftec/udesoftec-doc-examplebib.bib5
-rw-r--r--Master/texmf-dist/source/latex/udesoftec/udesoftec-doc.tex2
38 files changed, 19158 insertions, 1421 deletions
diff --git a/Master/texmf-dist/source/latex/babel/babel.dtx b/Master/texmf-dist/source/latex/babel/babel.dtx
index 1a19d9f2d35..093a61a6f1c 100644
--- a/Master/texmf-dist/source/latex/babel/babel.dtx
+++ b/Master/texmf-dist/source/latex/babel/babel.dtx
@@ -31,7 +31,7 @@
%
% \iffalse
%<*filedriver>
-\ProvidesFile{babel.dtx}[2021/01/26 v3.53 The Babel package]
+\ProvidesFile{babel.dtx}[2021/02/22 v3.54 The Babel package]
\documentclass{ltxdoc}
\GetFileInfo{babel.dtx}
\usepackage{fontspec}
@@ -2408,12 +2408,11 @@ Conveniently, some options allow to fill the language, and \babel{}
warns you about what to do if there is a missing string. Very likely
you will find alerts like that in the |log| file:
\begin{verbatim}
-Package babel Warning: \mylangchaptername not set. Please, define it
-(babel) after the language has been loaded (typically
-(babel) in the preamble) with the help of
-(babel) \setlocalecaption. An example is:
+Package babel Warning: \chaptername not set for 'mylang'. Please,
+(babel) define it after the language has been loaded
+(babel) (typically in the preamble) with:
(babel) \setlocalecaption{mylang}{chapter}{..}
-(babel) Reported on input line 18.
+(babel) Reported on input line 26.
\end{verbatim}
In most cases, you will only need to define a few macros. Note
@@ -3445,10 +3444,8 @@ bidirectional (with both R and L paragraphs) documents in \luatex{}.
\item[graphics] modifies the |picture| environment so that the whole
figure is L but the text is R. It \textit{does not} work with the
-standard |picture|, and \textit{pict2e} is required if you want sloped
-lines \textbf{(With recent versions of \LaTeX, this feature has
-stopped working)}. It attempts to do the same for \textsf{pgf/tikz}.
-Somewhat experimental. \New{3.32}.
+standard |picture|, and \textit{pict2e} is required. It attempts to do
+the same for \textsf{pgf/tikz}. Somewhat experimental. \New{3.32}.
\item[extras] is used for miscellaneous readjustments which do not fit into
the previous groups. Currently redefines in \luatex{} |\underline| and
@@ -4851,8 +4848,8 @@ help from Bernd Raichle, for which I am grateful.
% \section{Tools}
%
% \begin{macrocode}
-%<<version=3.53>>
-%<<date=2021/01/26>>
+%<<version=3.54>>
+%<<date=2021/02/22>>
% \end{macrocode}
%
% \textbf{Do not use the following macros in \texttt{ldf} files. They
@@ -5274,7 +5271,7 @@ help from Bernd Raichle, for which I am grateful.
Babel.debug = false }%
\fi}
<@Basic macros@>
- % Temporarily repeat here the code for errors
+ % Temporarily repeat here the code for errors. TODO.
\def\bbl@error#1#2{%
\begingroup
\def\\{\MessageBreak}%
@@ -5297,16 +5294,18 @@ help from Bernd Raichle, for which I am grateful.
\def\\{\MessageBreak}%
\PackageInfo{babel}{#1}%
\endgroup}
- \def\bbl@nocaption{\protect\bbl@nocaption@i}
+\def\bbl@nocaption{\protect\bbl@nocaption@i}
+% TODO - Wrong for \today !!! Must be a separate macro.
\def\bbl@nocaption@i#1#2{% 1: text to be printed 2: caption macro \langXname
\global\@namedef{#2}{\textbf{?#1?}}%
\@nameuse{#2}%
- \bbl@warning{% TODO.
- \@backslashchar#2 not set. Please, define it\\%
- after the language has been loaded (typically\\%
- in the preamble) with the help of\\%
- \string\setlocalecaption. An example is:\\%
- \string\setlocalecaption{mylang}{chapter}{..}\\
+ \edef\bbl@tempa{#1}%
+ \bbl@sreplace\bbl@tempa{name}{}%
+ \bbl@warning{%
+ \@backslashchar#1 not set for '\languagename'. Please,\\%
+ define it after the language has been loaded\\%
+ (typically in the preamble) with\\%
+ \string\setlocalecaption{\languagename}{\bbl@tempa}{..}\\%
Reported}}
\def\bbl@tentative{\protect\bbl@tentative@i}
\def\bbl@tentative@i#1{%
@@ -7666,6 +7665,7 @@ help from Bernd Raichle, for which I am grateful.
\def\bbl@foreign@s#1#2{% TODO - \shapemode, \@setpar, ?\@@par
\begingroup
{\par}%
+ \let\bbl@select@opts\@empty
\let\BabelText\@firstofone
\foreign@language{#1}%
\bbl@usehooks{foreign*}{}%
@@ -7938,12 +7938,13 @@ help from Bernd Raichle, for which I am grateful.
\def\bbl@nocaption@i#1#2{% 1: text to be printed 2: caption macro \langXname
\global\@namedef{#2}{\textbf{?#1?}}%
\@nameuse{#2}%
- \bbl@warning{%
- \@backslashchar#2 not set. Please, define it\\%
- after the language has been loaded (typically\\%
- in the preamble) with the help of\\%
- \string\setlocalecaption. An example is\\%
- \string\setlocalecaption{mylang}{chapter}{..}\\
+ \edef\bbl@tempa{#1}%
+ \bbl@sreplace\bbl@tempa{name}{}%
+ \bbl@warning{% TODO.
+ \@backslashchar#1 not set for '\languagename'. Please,\\%
+ define it after the language has been loaded\\%
+ (typically in the preamble) with:\\%
+ \string\setlocalecaption{\languagename}{\bbl@tempa}{..}\\%
Reported}}
\def\bbl@tentative{\protect\bbl@tentative@i}
\def\bbl@tentative@i#1{%
@@ -9317,12 +9318,6 @@ help from Bernd Raichle, for which I am grateful.
% attribute being checked, and the third and fourth arguments are
% the true and false clauses.
%
-% First we need to find out if any attributes were set; if not we're
-% done. Then we need to check the list of known attributes. When
-% we're this far |\ifin@| has a value indicating if the attribute in
-% question was set or not. Just to be safe the code to be executed
-% is `thrown over the |\fi|'.
-%
% \begin{macrocode}
\def\bbl@ifattributeset#1#2#3#4{%
\ifx\bbl@known@attribs\@undefined
@@ -9334,8 +9329,7 @@ help from Bernd Raichle, for which I am grateful.
\bbl@afterelse#3%
\else
\bbl@afterfi#4%
- \fi
- }
+ \fi}
% \end{macrocode}
%
% \end{macro}
@@ -9347,9 +9341,7 @@ help from Bernd Raichle, for which I am grateful.
% is known and the \TeX-code to be executed otherwise.
%
% We first assume the attribute is unknown. Then we loop over the
-% list of known attributes, trying to find a match. When a match is
-% found the definition of |\bbl@tempa| is changed. Finally we
-% execute |\bbl@tempa|.
+% list of known attributes, trying to find a match.
%
% \begin{macrocode}
\def\bbl@ifknown@ttrib#1#2{%
@@ -9360,8 +9352,7 @@ help from Bernd Raichle, for which I am grateful.
\let\bbl@tempa\@firstoftwo
\else
\fi}%
- \bbl@tempa
-}
+ \bbl@tempa}
% \end{macrocode}
%
% \end{macro}
@@ -9451,7 +9442,10 @@ help from Bernd Raichle, for which I am grateful.
% Some languages need to have |\frenchspacing| in effect. Others
% don't want that. The command |\bbl@frenchspacing| switches it on
% when it isn't already in effect and |\bbl@nonfrenchspacing|
-% switches it off if necessary.
+% switches it off if necessary. A more refined way to switch the
+% catcodes is done with |ini| files. Here an auxiliary macro is
+% defined, but the main part is in |\babelprovide|. This new method
+% should be ideally the default one.
%
% \begin{macrocode}
\def\bbl@frenchspacing{%
@@ -9462,7 +9456,6 @@ help from Bernd Raichle, for which I am grateful.
\let\bbl@nonfrenchspacing\nonfrenchspacing
\fi}
\let\bbl@nonfrenchspacing\nonfrenchspacing
-%
\let\bbl@elt\relax
\edef\bbl@fs@chars{%
\bbl@elt{\string.}\@m{3000}\bbl@elt{\string?}\@m{3000}%
@@ -9503,7 +9496,7 @@ help from Bernd Raichle, for which I am grateful.
%
% \subsection{Hyphens}
%
-% \begin{macro}{\babelhyphenation}
+% \begin{macro}{\babelhyphenation}
%
% This macro saves hyphenation exceptions. Two macros are used to
% store them: |\bbl@hyphenation@| for the global ones and
@@ -9534,7 +9527,7 @@ help from Bernd Raichle, for which I am grateful.
\bbl@iflanguage\bbl@tempa{%
\bbl@csarg\protected@edef{hyphenation@\bbl@tempa}{%
\bbl@ifunset{bbl@hyphenation@\bbl@tempa}%
- \@empty
+ {}%
{\csname bbl@hyphenation@\bbl@tempa\endcsname\space}%
#2}}}%
\fi}}
@@ -10667,6 +10660,7 @@ help from Bernd Raichle, for which I am grateful.
\let\bbl@KVP@Alph\@nil
\let\bbl@KVP@labels\@nil
\bbl@csarg\let{KVP@labels*}\@nil
+ \global\let\bbl@inidata\@empty
\bbl@forkv{#1}{% TODO - error handling
\in@{/}{##1}%
\ifin@
@@ -10732,7 +10726,8 @@ help from Bernd Raichle, for which I am grateful.
% ==
% At this point all parameters are defined if 'import'. Now we
% execute some code depending on them. But what about if nothing was
- % imported? We just set the very basic parameters.
+ % imported? We just set the basic parameters, but still loading the
+ % whole ini file.
\bbl@load@basic{#2}%
% == script, language ==
% Override the values from ini or defines them
@@ -10974,12 +10969,10 @@ help from Bernd Raichle, for which I am grateful.
\expandafter\bbl@tempb\bbl@captionslist\@empty
\else
\ifx\bbl@initoload\relax
- \bbl@read@ini{\bbl@KVP@captions}0% Here letters cat = 11
+ \bbl@read@ini{\bbl@KVP@captions}2% % Here letters cat = 11
\else
- \bbl@read@ini{\bbl@initoload}0% Here all letters cat = 11
+ \bbl@read@ini{\bbl@initoload}2% % Same
\fi
- \bbl@after@ini
- \bbl@savestrings
\fi
\StartBabelCommands*{#1}{date}%
\ifx\bbl@KVP@import\@nil
@@ -11031,9 +11024,7 @@ help from Bernd Raichle, for which I am grateful.
\def\bbl@provide@renew#1{%
\ifx\bbl@KVP@captions\@nil\else
\StartBabelCommands*{#1}{captions}%
- \bbl@read@ini{\bbl@KVP@captions}0% Here all letters cat = 11
- \bbl@after@ini
- \bbl@savestrings
+ \bbl@read@ini{\bbl@KVP@captions}2% % Here all letters cat = 11
\EndBabelCommands
\fi
\ifx\bbl@KVP@import\@nil\else
@@ -11046,24 +11037,18 @@ help from Bernd Raichle, for which I am grateful.
\ifx\bbl@lbkflag\@empty
\bbl@provide@hyphens{#1}%
\fi}
+% \end{macrocode}
+%
% Load the basic parameters (ids, typography, counters, and a few
% more), while captions and dates are left out. But it may happen some
% data has been loaded before automatically, so we first discard the
% saved values.
-\def\bbl@linebreak@export{%
- \bbl@exportkey{lnbrk}{typography.linebreaking}{h}%
- \bbl@exportkey{hyphr}{typography.hyphenrules}{}%
- \bbl@exportkey{lfthm}{typography.lefthyphenmin}{2}%
- \bbl@exportkey{rgthm}{typography.righthyphenmin}{3}%
- \bbl@exportkey{prehc}{typography.prehyphenchar}{}%
- \bbl@exportkey{hyotl}{typography.hyphenate.other.locale}{}%
- \bbl@exportkey{hyots}{typography.hyphenate.other.script}{}%
- \bbl@exportkey{intsp}{typography.intraspace}{}%
- \bbl@exportkey{chrng}{characters.ranges}{}}
+%
+% \begin{macrocode}
\def\bbl@load@basic#1{%
\bbl@ifunset{bbl@inidata@\languagename}{}%
{\getlocaleproperty\bbl@tempa{\languagename}{identification/load.level}%
- \ifcase\bbl@tempa\else
+ \ifcase\bbl@tempa
\bbl@csarg\let{lname@\languagename}\relax
\fi}%
\bbl@ifunset{bbl@lname@#1}%
@@ -11071,10 +11056,7 @@ help from Bernd Raichle, for which I am grateful.
\begingroup
\let\bbl@ini@captions@aux\@gobbletwo
\def\bbl@inidate ####1.####2.####3.####4\relax ####5####6{}%
- \bbl@read@ini{##1}0%
- \bbl@linebreak@export
- \bbl@exportkey{dgnat}{numbers.digits.native}{}%
- \bbl@exportkey{frspc}{typography.frenchspacing}{u}% unset
+ \bbl@read@ini{##1}1%
\ifx\bbl@initoload\relax\endinput\fi
\endgroup}%
\begingroup % boxed, to avoid extra spaces:
@@ -11126,14 +11108,10 @@ help from Bernd Raichle, for which I am grateful.
{\bbl@exp{\\\adddialect\<l@#1>\bbl@tempa}}}% found in opt list or ini
% \end{macrocode}
%
-% The reader of |ini| files. There are 3 possible cases: a section name
-% (in the form |[...]|), a comment (starting with |;|) and a
-% key/value pair.
+% The reader of |babel-...tex| files. We reset temporarily some
+% catcodes.
%
% \begin{macrocode}
-\ifx\bbl@readstream\@undefined
- \csname newread\endcsname\bbl@readstream
-\fi
\def\bbl@input@texini#1{%
\bbl@bsphack
\bbl@exp{%
@@ -11145,20 +11123,51 @@ help from Bernd Raichle, for which I am grateful.
\catcode`\\\{=\the\catcode`\{\relax
\catcode`\\\}=\the\catcode`\}\relax}%
\bbl@esphack}
-\def\bbl@inipreread#1=#2\@@{%
- \bbl@trim@def\bbl@tempa{#1}% Redundant below !!
+% \end{macrocode}
+%
+% The following macros read and store |ini| files (but don't process
+% them). For each line, there are 3 possible actions: ignore if starts
+% with |;|, switch section if starts with |[|, and store otherwise.
+% There are used in the first step of |\bbl@read@ini|.
+%
+% \begin{macrocode}
+\def\bbl@iniline#1\bbl@iniline{%
+ \@ifnextchar[\bbl@inisect{\@ifnextchar;\bbl@iniskip\bbl@inistore}#1\@@}% ]
+\def\bbl@inisect[#1]#2\@@{\def\bbl@section{#1}}%
+\def\bbl@iniskip#1\@@{}% if starts with ;
+\def\bbl@inistore#1=#2\@@{% full (default)
+ \bbl@trim@def\bbl@tempa{#1}%
\bbl@trim\toks@{#2}%
- % Move trims here ??
\bbl@ifunset{bbl@KVP@\bbl@section/\bbl@tempa}%
{\bbl@exp{%
- \\\g@addto@macro\\\bbl@inidata{%
- \\\bbl@elt{\bbl@section}{\bbl@tempa}{\the\toks@}}}%
- \expandafter\bbl@inireader\bbl@tempa=#2\@@}%
+ \\\g@addto@macro\\\bbl@inidata{%
+ \\\bbl@elt{\bbl@section}{\bbl@tempa}{\the\toks@}}}}%
{}}%
-\def\bbl@fetch@ini#1#2{%
- \bbl@exp{\def\\\bbl@inidata{%
- \\\bbl@elt{identification}{tag.ini}{#1}%
- \\\bbl@elt{identification}{load.level}{#2}}}%
+\def\bbl@inistore@min#1=#2\@@{% minimal (maybe set in \bbl@read@ini)
+ \bbl@trim@def\bbl@tempa{#1}%
+ \bbl@trim\toks@{#2}%
+ \bbl@xin@{.identification.}{.\bbl@section.}%
+ \ifin@
+ \bbl@exp{\\\g@addto@macro\\\bbl@inidata{%
+ \\\bbl@elt{identification}{\bbl@tempa}{\the\toks@}}}%
+ \fi}%
+% \end{macrocode}
+%
+% Now, the ‘main loop’, which \textbf{**must be executed inside a
+% group**}. At this point, |\bbl@inidata| may contain data declared in
+% |\babelprovide|, with ‘slashed’ keys. There are 3 steps: first read
+% the ini file and store it; then traverse the stored values, and
+% process some groups if required (date, captions, labels, counters);
+% finally, ‘export’ some values by defining global macros
+% (identification, typography, characters, numbers). The second
+% argument is 0 when called to read the minimal data for fonts; with
+% |\babelprovide| it's either 1 or 2.
+%
+% \begin{macrocode}
+\ifx\bbl@readstream\@undefined
+ \csname newread\endcsname\bbl@readstream
+\fi
+\def\bbl@read@ini#1#2{%
\openin\bbl@readstream=babel-#1.ini
\ifeof\bbl@readstream
\bbl@error
@@ -11167,12 +11176,20 @@ help from Bernd Raichle, for which I am grateful.
is not complete.}%
{Fix the name or reinstall babel.}%
\else
+ % Store ini data in \bbl@inidata
\catcode`\[=12 \catcode`\]=12 \catcode`\==12 \catcode`\&=12
\catcode`\;=12 \catcode`\|=12 \catcode`\%=14 \catcode`\-=12
\bbl@info{Importing
- \ifcase#2 \or font and identification \or basic \fi
- data for \languagename\\%
+ \ifcase#2font and identification \or basic \fi
+ data for \languagename\\%
from babel-#1.ini. Reported}%
+ \ifnum#2=\z@
+ \global\let\bbl@inidata\@empty
+ \let\bbl@inistore\bbl@inistore@min % Remember it's local
+ \fi
+ \def\bbl@section{identification}%
+ \bbl@exp{\\\bbl@inistore tag.ini=#1\\\@@}%
+ \bbl@inistore load.level=#2\@@
\loop
\if T\ifeof\bbl@readstream F\fi T\relax % Trick, because inside \loop
\endlinechar\m@ne
@@ -11182,95 +11199,70 @@ help from Bernd Raichle, for which I am grateful.
\expandafter\bbl@iniline\bbl@line\bbl@iniline
\fi
\repeat
+ % Process stored data
+ \bbl@csarg\xdef{lini@\languagename}{#1}%
+ \let\bbl@savestrings\@empty
+ \let\bbl@savetoday\@empty
+ \let\bbl@savedate\@empty
+ \def\bbl@elt##1##2##3{%
+ \def\bbl@section{##1}%
+ \in@{=date.}{=##1}% Find a better place
+ \ifin@
+ \bbl@ini@calendar{##1}%
+ \fi
+ \global\bbl@csarg\let{bbl@KVP@##1/##2}\relax
+ \bbl@ifunset{bbl@inikv@##1}{}%
+ {\csname bbl@inikv@##1\endcsname{##2}{##3}}}%
+ \bbl@inidata
+ % 'Export' data
+ \bbl@ini@exports{#2}%
+ \global\bbl@csarg\let{inidata@\languagename}\bbl@inidata
+ \global\let\bbl@inidata\@empty
+ \bbl@exp{\\\bbl@add@list\\\bbl@ini@loaded{\languagename}}%
+ \bbl@toglobal\bbl@ini@loaded
\fi}
-\def\bbl@read@ini#1#2{%
- \bbl@csarg\xdef{lini@\languagename}{#1}%
- \let\bbl@section\@empty
- \let\bbl@savestrings\@empty
- \let\bbl@savetoday\@empty
- \let\bbl@savedate\@empty
- \let\bbl@inireader\bbl@iniskip
- \bbl@fetch@ini{#1}{#2}%
- \bbl@foreach\bbl@renewlist{%
- \bbl@ifunset{bbl@renew@##1}{}{\bbl@inisec[##1]\@@}}%
- \global\let\bbl@renewlist\@empty
- % Ends last section. See \bbl@inisec
- \def\bbl@elt##1##2{\bbl@inireader##1=##2\@@}%
- \bbl@cs{renew@\bbl@section}%
- \global\bbl@csarg\let{renew@\bbl@section}\relax
- \bbl@cs{secpost@\bbl@section}%
- \bbl@csarg{\global\expandafter\let}{inidata@\languagename}\bbl@inidata
- \bbl@exp{\\\bbl@add@list\\\bbl@ini@loaded{\languagename}}%
- \bbl@toglobal\bbl@ini@loaded}
-\def\bbl@iniline#1\bbl@iniline{%
- \@ifnextchar[\bbl@inisec{\@ifnextchar;\bbl@iniskip\bbl@inipreread}#1\@@}% ]
% \end{macrocode}
%
-% The special cases for comment lines and sections are handled by the
-% two following commands. In sections, we provide the posibility to
-% take extra actions at the end or at the start. By default, key=val
-% pairs are ignored. The |secpost| ``hook'' is used only by
-% `identification', while |secpre| only by |date.gregorian.licr|.
+% A somewhat hackish tool to handle calendar sections. To be improved.
%
% \begin{macrocode}
-\def\bbl@iniskip#1\@@{}% if starts with ;
-\def\bbl@inisec[#1]#2\@@{% if starts with opening bracket
- \def\bbl@elt##1##2{%
- \expandafter\toks@\expandafter{%
- \expandafter{\bbl@section}{##1}{##2}}%
- \bbl@exp{%
- \\\g@addto@macro\\\bbl@inidata{\\\bbl@elt\the\toks@}}%
- \bbl@inireader##1=##2\@@}%
- \bbl@cs{renew@\bbl@section}%
- \global\bbl@csarg\let{renew@\bbl@section}\relax
- \bbl@cs{secpost@\bbl@section}%
- % The previous code belongs to the previous section.
- % --------------------------
- % Now start the current one.
- \in@{=date.}{=#1}%
- \ifin@
- \lowercase{\def\bbl@tempa{=#1=}}%
- \bbl@replace\bbl@tempa{=date.gregorian}{}%
- \bbl@replace\bbl@tempa{=date.}{}%
- \in@{.licr=}{#1=}%
- \ifin@
- \ifcase\bbl@engine
- \bbl@replace\bbl@tempa{.licr=}{}%
- \else
- \let\bbl@tempa\relax
- \fi
- \fi
- \ifx\bbl@tempa\relax\else
- \bbl@replace\bbl@tempa{=}{}%
- \bbl@exp{%
- \def\<bbl@inikv@#1>####1=####2\\\@@{%
- \\\bbl@inidate####1...\relax{####2}{\bbl@tempa}}}%
- \fi
- \fi
- \def\bbl@section{#1}%
- \def\bbl@elt##1##2{%
- \@namedef{bbl@KVP@#1/##1}{}}%
- \bbl@cs{renew@#1}%
- \bbl@cs{secpre@#1}% pre-section `hook'
- \bbl@ifunset{bbl@inikv@#1}%
- {\let\bbl@inireader\bbl@iniskip}%
- {\bbl@exp{\let\\\bbl@inireader\<bbl@inikv@#1>}}}
-\let\bbl@renewlist\@empty
-\def\bbl@renewinikey#1/#2\@@#3{%
- \bbl@ifunset{bbl@renew@#1}%
- {\bbl@add@list\bbl@renewlist{#1}}%
- {}%
- \bbl@csarg\bbl@add{renew@#1}{\bbl@elt{#2}{#3}}}
-% \end{macrocode}
-%
-% Reads a key=val line and stores the trimmed val in
-% |\bbl@@kv@<section>.<key>|.
+\def\bbl@ini@calendar#1{%
+ \lowercase{\def\bbl@tempa{=#1=}}%
+ \bbl@replace\bbl@tempa{=date.gregorian}{}%
+ \bbl@replace\bbl@tempa{=date.}{}%
+ \in@{.licr=}{#1=}%
+ \ifin@
+ \ifcase\bbl@engine
+ \bbl@replace\bbl@tempa{.licr=}{}%
+ \else
+ \let\bbl@tempa\relax
+ \fi
+ \fi
+ \ifx\bbl@tempa\relax\else
+ \bbl@replace\bbl@tempa{=}{}%
+ \bbl@exp{%
+ \def\<bbl@inikv@#1>####1####2{%
+ \\\bbl@inidate####1...\relax{####2}{\bbl@tempa}}}%
+ \fi}
+% \end{macrocode}
+%
+% A key with a slash in |\babelprovide| replaces the value in the |ini|
+% file (which is ignored altogether). The mechanism is simple (but
+% suboptimal): add the data to the |ini| one (at this point the |ini|
+% file has not yet been read), and define a dummy macro. When the |ini|
+% file is read, just skip the corresponding key and reset the macro (in
+% |\bbl@inistore| above).
+%
%
% \begin{macrocode}
-\def\bbl@inikv#1=#2\@@{% key=value
- \bbl@trim@def\bbl@tempa{#1}%
- \bbl@trim\toks@{#2}%
- \bbl@csarg\edef{@kv@\bbl@section.\bbl@tempa}{\the\toks@}}
+\def\bbl@renewinikey#1/#2\@@#3{%
+ \edef\bbl@tempa{\zap@space #1 \@empty}% section
+ \edef\bbl@tempb{\zap@space #2 \@empty}% key
+ \bbl@trim\toks@{#3}% value
+ \bbl@exp{%
+ \global\let\<bbl@KVP@\bbl@tempa/\bbl@tempb>\\\@empty % just a flag
+ \\\g@addto@macro\\\bbl@inidata{%
+ \\\bbl@elt{\bbl@tempa}{\bbl@tempb}{\the\toks@}}}}%
% \end{macrocode}
%
% The previous assignments are local, so we need to export them. If
@@ -11289,7 +11281,7 @@ help from Bernd Raichle, for which I am grateful.
%
% Key-value pairs are treated differently depending on the section in
% the |ini| file. The following macros are the readers for
-% |identification| and |typography|. Note |\bbl@secpost@identification|
+% |identification| and |typography|. Note |\bbl@ini@exports|
% is called always (via |\bbl@inisec|), while |\bbl@after@ini| must be
% called explicitly after |\bbl@read@ini| if necessary.
%
@@ -11301,8 +11293,8 @@ help from Bernd Raichle, for which I am grateful.
\bbl@cs{@kv@identification.warning#1}\\%
Reported }}}
%
-\let\bbl@inikv@identification\bbl@inikv
-\def\bbl@secpost@identification{%
+\def\bbl@ini@exports#1{%
+ % Identification always exported
\bbl@iniwarning{}%
\ifcase\bbl@engine
\bbl@iniwarning{.pdflatex}%
@@ -11322,15 +11314,46 @@ help from Bernd Raichle, for which I am grateful.
{\csname bbl@esname@\languagename\endcsname}}%
\bbl@exportkey{sbcp}{identification.script.tag.bcp47}{}%
\bbl@exportkey{sotf}{identification.script.tag.opentype}{DFLT}%
+ % Also maps bcp47 -> languagename
\ifbbl@bcptoname
\bbl@csarg\xdef{bcp@map@\bbl@cl{tbcp}}{\languagename}%
+ \fi
+ % Conditional
+ \ifnum#1>\z@ % 0 = only info, 1, 2 = basic, (re)new
+ \bbl@exportkey{lnbrk}{typography.linebreaking}{h}%
+ \bbl@exportkey{hyphr}{typography.hyphenrules}{}%
+ \bbl@exportkey{lfthm}{typography.lefthyphenmin}{2}%
+ \bbl@exportkey{rgthm}{typography.righthyphenmin}{3}%
+ \bbl@exportkey{prehc}{typography.prehyphenchar}{}%
+ \bbl@exportkey{hyotl}{typography.hyphenate.other.locale}{}%
+ \bbl@exportkey{hyots}{typography.hyphenate.other.script}{}%
+ \bbl@exportkey{intsp}{typography.intraspace}{}%
+ \bbl@exportkey{chrng}{characters.ranges}{}%
+ \bbl@exportkey{dgnat}{numbers.digits.native}{}%
+ \bbl@exportkey{frspc}{typography.frenchspacing}{u}%
+ \ifnum#1=\tw@ % only (re)new
+ \bbl@exportkey{rqtex}{identification.require.babel}{}%
+ \bbl@toglobal\bbl@savetoday
+ \bbl@toglobal\bbl@savedate
+ \bbl@savestrings
+ \fi
\fi}
% \end{macrocode}
%
+% A shared handler for key=val lines to be stored in
+% |\bbl@@kv@<section>.<key>|.
+%
+% \begin{macrocode}
+\def\bbl@inikv#1#2{% key=value
+ \toks@{#2}% This hides #'s from ini values
+ \bbl@csarg\edef{@kv@\bbl@section.#1}{\the\toks@}}
+% \end{macrocode}
+%
% By default, the following sections are just read. Actions are taken
% later.
%
% \begin{macrocode}
+\let\bbl@inikv@identification\bbl@inikv
\let\bbl@inikv@typography\bbl@inikv
\let\bbl@inikv@characters\bbl@inikv
\let\bbl@inikv@numbers\bbl@inikv
@@ -11342,7 +11365,7 @@ help from Bernd Raichle, for which I am grateful.
% the ‘units’.
%
% \begin{macrocode}
-\def\bbl@inikv@counters#1=#2\@@{%
+\def\bbl@inikv@counters#1#2{%
\bbl@ifsamestring{#1}{digits}%
{\bbl@error{The counter name 'digits' is reserved for mapping\\%
decimal digits}%
@@ -11365,13 +11388,6 @@ help from Bernd Raichle, for which I am grateful.
\expandafter\bbl@buildifcase\bbl@tempb* \\ % Space after \\
\bbl@csarg{\global\expandafter\let}{cntr@#1@\languagename}\bbl@tempa
\fi}
-\def\bbl@after@ini{%
- \bbl@linebreak@export
- \bbl@exportkey{dgnat}{numbers.digits.native}{}%
- \bbl@exportkey{rqtex}{identification.require.babel}{}%
- \bbl@exportkey{frspc}{typography.frenchspacing}{u}% unset
- \bbl@toglobal\bbl@savetoday
- \bbl@toglobal\bbl@savedate}
% \end{macrocode}
%
% Now |captions| and |captions.licr|, depending on the engine. And
@@ -11381,10 +11397,10 @@ help from Bernd Raichle, for which I am grateful.
%
% \begin{macrocode}
\ifcase\bbl@engine
- \bbl@csarg\def{inikv@captions.licr}#1=#2\@@{%
+ \bbl@csarg\def{inikv@captions.licr}#1#2{%
\bbl@ini@captions@aux{#1}{#2}}
\else
- \def\bbl@inikv@captions#1=#2\@@{%
+ \def\bbl@inikv@captions#1#2{%
\bbl@ini@captions@aux{#1}{#2}}
\fi
% \end{macrocode}
@@ -11445,7 +11461,7 @@ help from Bernd Raichle, for which I am grateful.
\bbl@ifunset{bbl@map@#1@\languagename}%
{\@nameuse{#1}}%
{\@nameuse{bbl@map@#1@\languagename}}}
-\def\bbl@inikv@labels#1=#2\@@{%
+\def\bbl@inikv@labels#1#2{%
\in@{.map}{#1}%
\ifin@
\ifx\bbl@KVP@labels\@nil\else
@@ -11665,7 +11681,7 @@ help from Bernd Raichle, for which I am grateful.
% \begin{macrocode}
\def\bbl@provide@lsys#1{%
\bbl@ifunset{bbl@lname@#1}%
- {\bbl@ini@basic{#1}}%
+ {\bbl@load@info{#1}}%
{}%
\bbl@csarg\let{lsys@#1}\@empty
\bbl@ifunset{bbl@sname@#1}{\bbl@csarg\gdef{sname@#1}{Default}}{}%
@@ -11717,14 +11733,13 @@ help from Bernd Raichle, for which I am grateful.
% must be enabled. This means we must make sure a few characters are
% not active. The |ini| is not read directly, but with a proxy |tex|
% file named as the language (which means any code in it must be
-% skipped, too.
+% skipped, too).
%
% \begin{macrocode}
-\def\bbl@ini@basic#1{%
+\def\bbl@load@info#1{%
\def\BabelBeforeIni##1##2{%
\begingroup
- \bbl@add\bbl@secpost@identification{\closein\bbl@readstream }%
- \bbl@read@ini{##1}1%
+ \bbl@read@ini{##1}0%
\endinput % babel- .tex may contain onlypreamble's
\endgroup}% boxed, to avoid extra spaces:
{\bbl@input@texini{#1}}}
@@ -11850,7 +11865,7 @@ help from Bernd Raichle, for which I am grateful.
\newcommand\BabelEnsureInfo{%
\ifx\InputIfFileExists\@undefined\else
\def\bbl@ensureinfo##1{%
- \bbl@ifunset{bbl@lname@##1}{\bbl@ini@basic{##1}}{}}%
+ \bbl@ifunset{bbl@lname@##1}{\bbl@load@info{##1}}{}}%
\fi
\bbl@foreach\bbl@loaded{{%
\def\languagename{##1}%
@@ -13373,7 +13388,7 @@ help from Bernd Raichle, for which I am grateful.
\let\bbl@cjkintraspace\relax
\directlua{
Babel = Babel or {}
- require'babel-data-cjk.lua'
+ require('babel-data-cjk.lua')
Babel.cjk_enabled = true
function Babel.cjk_linebreak(head)
local GLYPH = node.id'glyph'
@@ -14276,21 +14291,86 @@ end
\ifcase\bbl@thetextdir
\let\bbl@pictresetdir\relax
\else
- \bodydir TLT
+ \ifcase#1\bodydir TLT % Remember this sets the inner boxes
+ \or\textdir TLT
+ \else\bodydir TLT \textdir TLT
+ \fi
% \(text|par)dir required in pgf:
\def\bbl@pictresetdir{\bodydir TRT\pardir TRT\textdir TRT\relax}%
\fi}%
\ifx\AddToHook\@undefined\else
- \AddToHook{env/picture/begin}{\bbl@pictsetdir\z@}%
+ \AddToHook{env/picture/begin}{\bbl@pictsetdir\tw@}%
+ \directlua{
+ Babel.get_picture_dir = true
+ Babel.picture_has_bidi = 0
+ function Babel.picture_dir (head)
+ if not Babel.get_picture_dir then return head end
+ for item in node.traverse(head) do
+ if item.id == node.id'glyph' then
+ local itemchar = item.char
+ % TODO. Copypaste pattern from Babel.bidi (-r)
+ local chardata = Babel.characters[itemchar]
+ local dir = chardata and chardata.d or nil
+ if not dir then
+ for nn, et in ipairs(Babel.ranges) do
+ if itemchar < et[1] then
+ break
+ elseif itemchar <= et[2] then
+ dir = et[3]
+ break
+ end
+ end
+ end
+ if dir and (dir == 'al' or dir == 'r') then
+ Babel.picture_has_bidi = 1
+ end
+ end
+ end
+ return head
+ end
+ luatexbase.add_to_callback("hpack_filter", Babel.picture_dir,
+ "Babel.picture_dir")
+ }%
+ \AtBeginDocument{%
+ \long\def\put(#1,#2)#3{%
+ \@killglue
+ % Try:
+ \ifx\bbl@pictresetdir\relax
+ \def\bbl@tempc{0}%
+ \else
+ \directlua{
+ Babel.get_picture_dir = true
+ Babel.picture_has_bidi = 0
+ }%
+ \setbox\z@\hb@xt@\z@{%
+ \@defaultunitsset\@tempdimc{#1}\unitlength
+ \kern\@tempdimc
+ #3\hss}%
+ \edef\bbl@tempc{\directlua{tex.print(Babel.picture_has_bidi)}}%
+ \fi
+ % Do:
+ \@defaultunitsset\@tempdimc{#2}\unitlength
+ \raise\@tempdimc\hb@xt@\z@{%
+ \@defaultunitsset\@tempdimc{#1}\unitlength
+ \kern\@tempdimc
+ {\ifnum\bbl@tempc>\z@\bbl@pictresetdir\fi#3}\hss}%
+ \ignorespaces}%
+ \MakeRobust\put}%
\fi
\AtBeginDocument
{\ifx\tikz@atbegin@node\@undefined\else
\let\bbl@OL@pgfpicture\pgfpicture
\bbl@sreplace\pgfpicture{\pgfpicturetrue}%
- {\bbl@pictsetdir\@ne\pgfpicturetrue}%
- \bbl@add\pgfsys@beginpicture{\bbl@pictsetdir\@ne}%
+ {\bbl@pictsetdir\z@\pgfpicturetrue}%
+ \bbl@add\pgfsys@beginpicture{\bbl@pictsetdir\z@}%
\bbl@add\tikz@atbegin@node{\bbl@pictresetdir}%
- \fi}}
+ \bbl@sreplace\tikz{\begingroup}%
+ {\begingroup\bbl@pictsetdir\tw@}%
+ \fi
+ \ifx\AddToHook\@undefined\else
+ \AddToHook{env/tcolorbox/begin}{\bbl@pictsetdir\@ne}%
+ \fi
+ }}
{}
% \end{macrocode}
%
diff --git a/Master/texmf-dist/source/latex/babel/babel.ins b/Master/texmf-dist/source/latex/babel/babel.ins
index cd1597a837a..73a8825c196 100644
--- a/Master/texmf-dist/source/latex/babel/babel.ins
+++ b/Master/texmf-dist/source/latex/babel/babel.ins
@@ -26,7 +26,7 @@
%% and covered by LPPL is defined by the unpacking scripts (with
%% extension .ins) which are part of the distribution.
%%
-\def\filedate{2021/01/26}
+\def\filedate{2021/02/22}
\def\batchfile{babel.ins}
\input docstrip.tex
diff --git a/Master/texmf-dist/source/latex/babel/bbcompat.dtx b/Master/texmf-dist/source/latex/babel/bbcompat.dtx
index 84c388a78cc..bd6f5b7bfd8 100644
--- a/Master/texmf-dist/source/latex/babel/bbcompat.dtx
+++ b/Master/texmf-dist/source/latex/babel/bbcompat.dtx
@@ -30,7 +30,7 @@
%
% \iffalse
%<*dtx>
-\ProvidesFile{bbcompat.dtx}[2021/01/26 v3.53]
+\ProvidesFile{bbcompat.dtx}[2021/02/22 v3.54]
%</dtx>
%
%% File 'bbcompat.dtx'
diff --git a/Master/texmf-dist/source/latex/babel/locale.zip b/Master/texmf-dist/source/latex/babel/locale.zip
index a04b7bdfeb7..6524dc27fcf 100644
--- a/Master/texmf-dist/source/latex/babel/locale.zip
+++ b/Master/texmf-dist/source/latex/babel/locale.zip
Binary files differ
diff --git a/Master/texmf-dist/source/latex/microtype/microtype-utf.dtx b/Master/texmf-dist/source/latex/microtype/microtype-utf.dtx
index 7bc673f3de8..19fd79c25cf 100644
--- a/Master/texmf-dist/source/latex/microtype/microtype-utf.dtx
+++ b/Master/texmf-dist/source/latex/microtype/microtype-utf.dtx
@@ -1,11 +1,11 @@
%\iffalse meta-comment
% !Mode:: "TeX:DTX:UK"
% !smartQuote:: "English"
-% !DTXversion:: "2.8"
+% !DTXversion:: "2.8a"
% ------------------------------------------------------------------------
% The `microtype' package
% Subliminal refinements towards typographical perfection
-% Copyright (c) 2004--2020 R Schlicht <w.m.l@gmx.net>
+% Copyright (c) 2004--2021 R Schlicht <w.m.l@gmx.net>
%
% This work may be distributed and/or modified under the conditions of the
% LaTeX Project Public License, either version 1.3c of this license or (at
@@ -26,11 +26,13 @@
%
\ProvidesFile
%<*driver>
- {\jobname.dtx}[2020/12/07 v2.8]
+ {\jobname.dtx}[2021/02/22 v2.8a]
%</driver>
%<CharisSIL> {mt-CharisSIL.cfg}[2017/07/07 v1.1 microtype config. file: Charis SIL (RS)]
-%<LatinModernRoman> {mt-LatinModernRoman.cfg}[2013/03/13 v1.0 microtype config. file: Latin Modern Roman (RS)]
-%<PalatinoLinotype> {mt-PalatinoLinotype.cfg}[2012/03/10 v1.0 microtype config. file: Palatino Linotype and similar fonts (LBD)]
+%<LatinModernRoman> {mt-LatinModernRoman.cfg}[2021/02/21 v1.1 microtype config. file: Latin Modern Roman (RS)]
+%<Palatino> {mt-Palatino.cfg}[2012/03/10 v1.0 microtype config. file: Palatino and similar fonts (LBD)]
+%<Lato> {mt-Lato.cfg}[2021/02/22 v1.0 microtype config. file: Lato (RS)]
+%<FontAwesome> {mt-FontAwesome.cfg}[2021/02/22 v1.0 microtype config. file: Font Awesome (RS)]
%<*driver>
\documentclass[10pt,a4paper]{ltxdoc}
\usepackage{fontspec}
@@ -44,7 +46,10 @@
\def\setmacrofont#1{\par\def\macro@font{#1}\footnotesize}
\newfontface\LMR{Latin Modern Roman}
\newfontface\CharisSIL{Charis SIL}
- \newfontface\PalatinoLinotype{TeX Gyre Pagella}
+ \newfontface\Palatino{TeX Gyre Pagella}
+% \newfontface\Palatino[RawFeature={fallback=charisfallback}]{TeX Gyre Pagella}
+% \directlua{luaotfload.add_fallback("charisfallback",{"CharisSIL:color=F70A12;mode=harf;"})}
+ \newfontface\Lato{Lato}
\usepackage{luacode}
\tracinglostchars2
% we replace any missing characters (in Palatino) with CharisSIL
@@ -114,6 +119,11 @@ luatexbase.add_to_callback("pre_linebreak_filter", nodeprocessor, "replace missi
%\StopEventually{}
%
% ^^A -------------------------------------------------------------------------
+%\GeneralChanges*
+%\changes{v2.8a}{2021/02/22}{rename \file{mt-PalatinoLinotype.cfg} to \file{mt-Palatino.cfg}
+% (requested by \contributor Karl Berry <karl\at freefriends.org>)}
+% ^^A private mail, 2021/02/22
+%
%\GeneralChanges{Documentation}
%\changes{v2.5a}{2013/05/15}{include OpenType configuration files}
%\changes{v2.6}{2015/12/07}{missing characters printed with Charis <SIL>}
@@ -134,9 +144,9 @@ luatexbase.add_to_callback("pre_linebreak_filter", nodeprocessor, "replace missi
% Latin Modern Roman}
% \item {\CharisSIL
% Charis <SIL>}\footnote{Available at \url{http://software.sil.org/charis}.}
-% \item {\PalatinoLinotype
-% Palatino Linotype}\footnote{These settings have been contributed by
-% \contributor Loren B. Davis <davislo\at eecs.oregonstate.edu>.}
+% \item {\Palatino
+% Palatino}\footnote{These settings have been contributed by
+% \contributor Loren B. Davis <davislo\at eecs.oregonstate.edu>.}
%\end{itemize}
%
%\noindent
@@ -162,6 +172,7 @@ luatexbase.add_to_callback("pre_linebreak_filter", nodeprocessor, "replace missi
{ encoding = {EU1,EU2,TU},
family = Latin Modern Roman }
% \end{macrocode}
+%\changes{v2.8a}{2021/02/21}{specify `ff' ligature as Unicode instead of glyph name}
%{\setmacrofont\LMR
% \begin{macrocode}
{ A = {À,Á,Â,Ã,Ä,Å,Ā,Ă,Ą,Ǻ,Ȁ,Ạ,Ả,Ấ,Ầ,Ẩ,Ẫ,Ậ,Ắ,Ằ,Ẳ,Ặ,
@@ -203,7 +214,7 @@ luatexbase.add_to_callback("pre_linebreak_filter", nodeprocessor, "replace missi
c = {ç,ć,ĉ,ċ,č},
d = {đ,ḍ,ḏ},
e = {è,é,ê,ë,ē,ĕ,ė,ę,ě,ȅ,ẹ,ẻ,ẽ,ế,ề,ể,ễ,ệ},
- f = {/f_f},
+ f = {ff}, % Unicode 64256, glyph name in Latin Modern: /f_f ; in New Computer Modern: /ff
g = {ĝ,ğ,ġ,ģ,ǧ,ǵ},
h = {ĥ,ħ,ḥ,ḧ,ḫ},
i = {ì,í,î,ï,ĩ,ī,ĭ,į,ı,ȉ,ỉ,ị},
@@ -355,17 +366,17 @@ luatexbase.add_to_callback("pre_linebreak_filter", nodeprocessor, "replace missi
%}
% \begin{macrocode}
%</CharisSIL>
-%<*PalatinoLinotype>
+%<*Palatino>
\DeclareCharacterInheritance
{ encoding = {EU1,EU2,TU},
- family = {PalatinoLinotype} }
+ family = {Palatino} }
% \end{macrocode}
% Unfortunately, I don't have a Palatino variant containing all of the following
% glyphs. The settings are typeset in \TeX\ Gyre Pagella;
% missing glyphs, printed in red, are taken from Charis <SIL>;
% glyphs missing even in Charis <SIL> appear as `\char"FFFD@'.
-% To see the real settings, consult \file{mt-PalatinoLinotype.cfg}.
-%{\setmacrofont\PalatinoLinotype
+% To see the real settings, consult \file{mt-Palatino.cfg}.
+%{\setmacrofont\Palatino
% \begin{macrocode}
{ A = {À,Á,Â,Ã,Ä,Ā,Ă,Ą,Ǎ,Ǟ,Ǡ,Ȧ,Ǻ,Ȁ,Ȃ,Ḁ,Ạ,Ả,Ấ,Ầ,Ẩ,Ẫ,Ậ,Ắ,Ằ,Ẳ,Ẵ,Ặ,Ꜳ},
B = {Ḃ,Ḅ,Ḇ},
@@ -421,7 +432,58 @@ luatexbase.add_to_callback("pre_linebreak_filter", nodeprocessor, "replace missi
% \end{macrocode}
%}
% \begin{macrocode}
-%</PalatinoLinotype>
+%</Palatino>
+% \end{macrocode}
+% Less characters in the Lato font \dots
+%\changes{v2.8a}{2021/02/21}{settings for the Lato font
+% (reported by \contributor dsedivec <@\at @>)}
+% ^^A https://tex.stackexchange.com/questions/380812/microtype-warning-unknown-slot-number-of-character-with-lato-font
+% \begin{macrocode}
+%<*Lato>
+\DeclareCharacterInheritance
+ { encoding = {TU,EU1,EU2},
+ family = {Lato} }
+% \end{macrocode}
+%{\setmacrofont\Lato
+% \begin{macrocode}
+ { A = {À,Á,Â,Ã,Ä,Å,Ą},
+ a = {à,á,â,ã,ä,å,ą},
+ C = {Ć,Ç},
+ c = {ć,ç},
+ D = {Ð},
+ E = {È,É,Ê,Ë,Ę},
+ e = {è,é,ê,ë,ę},
+ I = {Ì,Í,Î,Ï},
+ i = {ì,í,î,ï,ı},
+ L = {Ł},
+ l = {ł},
+ N = {Ń,Ñ},
+ n = {ń,ñ},
+ O = {Ø,Ò,Ó,Ô,Õ,Ö},
+ o = {ø,ò,ó,ô,õ,ö},
+ S = {Ś,Š}, % \SS
+ s = {ś,š},
+ U = {Ù,Ú,Û,Ü},
+ u = {ù,ú,û,ü},
+ Y = {Ý,Ÿ},
+ y = {ý,ÿ},
+ Z = {Ź,Ż,Ž},
+ z = {ź,ż,ž}
+ }
+% \end{macrocode}
+%}
+% \begin{macrocode}
+%</Lato>
+% \end{macrocode}
+% \dots\ and even less in the self-professed awesone Font Awesome font.
+%\changes{v2.8a}{2021/02/21}{dummy settings for the Font Awesome font}
+% \begin{macrocode}
+%<*FontAwesome>
+\DeclareCharacterInheritance
+ { encoding = {TU,EU1,EU2},
+ family = {FontAwesome} }
+ { }
+%</FontAwesome>
% \end{macrocode}
%
%\subsection{Character protrusion}
@@ -1056,14 +1118,14 @@ luatexbase.add_to_callback("pre_linebreak_filter", nodeprocessor, "replace missi
% \begin{macrocode}
}
%</CharisSIL>
-%<*PalatinoLinotype>
+%<*Palatino>
\SetProtrusion
[ name = palatino-default ]
{ encoding = {EU1,EU2,TU},
- family = {PalatinoLinotype} }
+ family = {Palatino} }
{
% \end{macrocode}
-%{\setmacrofont\PalatinoLinotype
+%{\setmacrofont\Palatino
% \begin{macrocode}
A = {50,50},
D = { ,50},
@@ -1162,11 +1224,11 @@ luatexbase.add_to_callback("pre_linebreak_filter", nodeprocessor, "replace missi
\SetProtrusion
[ name = palatino-it ]
{ encoding = {EU1,EU2,TU},
- family = {PalatinoLinotype},
+ family = {Palatino},
shape = {it,sl} }
{
% \end{macrocode}
-%{\setmacrofont\PalatinoLinotype
+%{\setmacrofont\Palatino
% \begin{macrocode}
A = {50,50},
Æ = {50, },
@@ -1261,11 +1323,11 @@ luatexbase.add_to_callback("pre_linebreak_filter", nodeprocessor, "replace missi
[ name = palatino-sc,
load = palatino-default ]
{ encoding = {EU1,EU2,TU},
- family = {PalatinoLinotype},
+ family = {Palatino},
shape = sc }
{
% \end{macrocode}
-%{\setmacrofont\PalatinoLinotype
+%{\setmacrofont\Palatino
% \begin{macrocode}
a = {50,50},
æ = {50, },
@@ -1289,7 +1351,15 @@ luatexbase.add_to_callback("pre_linebreak_filter", nodeprocessor, "replace missi
%}
% \begin{macrocode}
}
-%</PalatinoLinotype>
+%</Palatino>
+%<Lato> %% No settings yet.
+%<*FontAwesome>
+\SetProtrusion
+ [ name = empty ]
+ { encoding = {TU,EU1,EU2},
+ family = {FontAwesome} }
+ { }
+%</FontAwesome>
% \end{macrocode}
%\immediate\write \utftmp{\string\setcounter{CodelineNo}{\the\c@CodelineNo}}
diff --git a/Master/texmf-dist/source/latex/microtype/microtype.dtx b/Master/texmf-dist/source/latex/microtype/microtype.dtx
index 698eec07723..f3bec6b762a 100644
--- a/Master/texmf-dist/source/latex/microtype/microtype.dtx
+++ b/Master/texmf-dist/source/latex/microtype/microtype.dtx
@@ -1,11 +1,11 @@
%\iffalse meta-comment
% !Mode:: "TeX:DTX:UK"
% !smartQuote:: "English"
-% !DTXversion:: "2.8"
+% !DTXversion:: "2.8a"
% ------------------------------------------------------------------------
% The `microtype' package
% Subliminal refinements towards typographical perfection
-% Copyright (c) 2004--2020 R Schlicht <w.m.l@gmx.net>
+% Copyright (c) 2004--2021 R Schlicht <w.m.l@gmx.net>
%
% This work may be distributed and/or modified under the conditions of the
% LaTeX Project Public License, either version 1.3c of this license or (at
@@ -37,7 +37,7 @@
%<luatex-def> {microtype-luatex.def}
%<xetex-def> {microtype-xetex.def}
%<*package|letterspace|m-t|pdftex-def|luatex-def|xetex-def>
- [2020/12/07 v2.8
+ [2021/02/22 v2.8a
%<package> Micro-typographical refinements
%<letterspace> Robust letterspacing
%<m-t> microtype main configuration file
@@ -51,8 +51,8 @@
%<luafile>local microtype = microtype
%<luafile>microtype.module = {
%<luafile> name = "microtype",
-%<luafile> version = "2.8",
-%<luafile> date = "2020/12/07",
+%<luafile> version = "2.8a",
+%<luafile> date = "2021/02/22",
%<luafile> description = "microtype module.",
%<luafile> author = "E. Roux, R. Schlicht and P. Gesang",
%<luafile> copyright = "E. Roux, R. Schlicht and P. Gesang",
@@ -62,7 +62,7 @@
%<bch> {mt-bch.cfg}[2007/03/03 v1.5 microtype config. file: Bitstream Charter (RS)]
%<blg> {mt-blg.cfg}[2007/07/14 v1.0 microtype config. file: Bitstream Letter Gothic (RS)]
%<cmr> {mt-cmr.cfg}[2013/05/19 v2.2 microtype config. file: Computer Modern Roman (RS)]
-%<pad> {mt-pad.cfg}[2005/11/07 v1.5 microtype config. file: Adobe Garamond (RS)]
+%<ebg> {mt-EBGaramond.cfg}[2021/02/22 v1.6 microtype config. file: EB Garamond / Adobe Garamond (RS)]
%<pmn> {mt-pmn.cfg}[2009/11/14 v1.3 microtype config. file: Adobe Minion (HH/KK)]
%<ppl> {mt-ppl.cfg}[2005/11/16 v1.6 microtype config. file: Palatino (RS)]
%<ptm> {mt-ptm.cfg}[2006/04/20 v1.7 microtype config. file: Times (RS)]
@@ -73,7 +73,6 @@
%<eur> {mt-eur.cfg}[2006/07/31 v1.1 microtype config. file: AMS Euler Roman (RS)]
%<eus> {mt-eus.cfg}[2006/07/28 v1.2 microtype config. file: AMS Euler Script (RS)]
%<zpeu> {mt-zpeu.cfg}[2006/05/04 v1.0 microtype config. file: Adobe Euro (RS)]
-%<euroitc> {mt-euroitc.cfg}[2006/05/04 v1.0 microtype config. file: ITC Euro (RS)]
%<mvs> {mt-mvs.cfg}[2006/07/05 v1.1 microtype config. file: Marvosym Euro (RS)]
%</config>
%
@@ -196,7 +195,7 @@
\DeclareRobustCommand\TeX{\textoractual{\OrigTeX}{TeX}}
\setlength\textheight{49\baselineskip}
\else
- \let\bfdefault\bfdefault@previous % undo mathdesign's \def\bdefault{b}
+ \let\bfdefault\bfdefault@previous % undo mathdesign's \def\bfdefault{b}
\def\Module#1{{\color{theblue}\textoractual{$\langle$}{<}\textit{#1}\textoractual{$\rangle$}{>}}}
\DeclareRobustCommand\TeX{\textoractual{T\kern-.1em\lower.4ex\hbox{E}\kern-.075emX\@}{TeX}}
\DeclareRobustCommand\LaTeX{\textoractual{L\kern-.26em{\sbox\z@ T\vbox to\ht\z@{%
@@ -505,44 +504,39 @@
\textrm{Text lost! Please install the \pkg{listings} package.}}}%
\@beginparpenalty\predisplaypenalty\@verbatim\MacroFont
\frenchspacing\@vobeyspaces\expandafter\@xverbatim\@gobble}}
-\IfFileExists{listings.sty}{
- \usepackage{listings}
- \lstset{
- gobble=1,columns=flexible,keepspaces,upquote,escapechar=",
- basicstyle=\MacroFont,
- keywords=[0]{\microtypesetup,\DeclareMicrotypeSet,\UseMicrotypeSet,
- \DeclareMicrotypeSetDefault,\SetProtrusion,\SetExpansion,\SetTracking,
- \SetExtraKerning,\SetExtraSpacing,\DisableLigatures,\DeclareCharacterInheritance,
- \DeclareMicrotypeVariants,\DeclareMicrotypeAlias,\DeclareMicrotypeBabelHook,
- \LoadMicrotypeFile,\microtypecontext,\textmicrotypecontext,
- \textls,\lsstyle,\lslig,\Microtype@Hook},
- keywordstyle=[0]\color{thegreen},
- keywords=[1]{protrusion,expansion,activate,DVIoutput,draft,final,verbose,
- config,factor,auto,stretch,shrink,step,selected,unit,tracking,kerning,
- spacing,letterspace,babel,context,
- %defersetup,copyfonts,enable,disable,% undocumented
- noligatures,outerspacing,outerkerning}, % there are three \nobreakspace in this line
- keywordstyle=[1]\color{thered},
- comment=[l]\%,
- commentstyle=\color{thegrey}\itshape,
- alsoother={0123456789_},
- frame=single,backgroundcolor=\color{theshade},rulecolor=\color{theframe},
- framerule=\fboxrule,xleftmargin=3.4pt,xrightmargin=3.4pt,belowskip=\smallskipamount
- }
- \let\verbatim\relax
- \lstnewenvironment{verbatim}[1][]{\lstset{##1}}{}
- \ifpdf \IfFileExists{dummy-space.pfb}{%
- \pdfmapline{=dummy-space <dummy-space.pfb}
- \font\dummyspace=dummy-space
- \pdfglyphtounicode{space}{0020}
- \def\lst@outputspace{% copy spaces (from a font that really has a space at x20)
- \setbox0\hbox{ }\@tempdima\wd0
- \setbox0\hbox{\dummyspace\char"20}\advance\@tempdima-\wd0
- \unhbox0 \kern\@tempdima}
- }\relax \fi
-}{
- \let\lstset\@gobble
-}
+\usepackage{listings}
+\lstset{
+ gobble=1,columns=flexible,keepspaces,upquote,escapechar=",
+ basicstyle=\MacroFont,
+ keywords=[0]{\microtypesetup,\DeclareMicrotypeSet,\UseMicrotypeSet,
+ \DeclareMicrotypeSetDefault,\SetProtrusion,\SetExpansion,\SetTracking,
+ \SetExtraKerning,\SetExtraSpacing,\DisableLigatures,\DeclareCharacterInheritance,
+ \DeclareMicrotypeVariants,\DeclareMicrotypeAlias,\DeclareMicrotypeBabelHook,
+ \LoadMicrotypeFile,\microtypecontext,\textmicrotypecontext,
+ \textls,\lsstyle,\lslig,\Microtype@Hook},
+ keywordstyle=[0]\color{thegreen},
+ keywords=[1]{protrusion,expansion,activate,DVIoutput,draft,final,verbose,
+ config,factor,auto,stretch,shrink,step,selected,unit,tracking,kerning,
+ spacing,letterspace,babel,context,
+ %defersetup,copyfonts,enable,disable,% undocumented
+ noligatures,outerspacing,outerkerning}, % there are three \nobreakspace in this line
+ keywordstyle=[1]\color{thered},
+ comment=[l]\%,
+ commentstyle=\color{thegrey}\itshape,
+ alsoother={0123456789_},
+ frame=single,backgroundcolor=\color{theshade},rulecolor=\color{theframe},
+ framerule=\fboxrule,xleftmargin=3.4pt,xrightmargin=3.4pt,belowskip=\smallskipamount
+}
+\let\verbatim\relax
+\lstnewenvironment{verbatim}[1][]{\lstset{#1}}{}
+\ifpdf
+ \font\dummyspace=dummy-space
+ \pdfglyphtounicode{space}{0020}
+ \def\lst@outputspace{% copy spaces (from a font that really has a space at x20)
+ \setbox0\hbox{ }\@tempdima\wd0
+ \setbox0\hbox{\dummyspace\char"20}\advance\@tempdima-\wd0
+ \unhbox0 \kern\@tempdima}
+\fi
\def\todo#1{\changes{zTo Do}{0000/00/00}{#1}%
\marginpar{\rightskip2\marginparsep plus1em\hangindent1.5em\hangafter-2
\smash{\rlap{\raisebox{-3.3ex}{\colorbox{thered}{\Large\color{white}!}}}}%
@@ -565,13 +559,14 @@
\usepackage{attachfile}
\usepackage{pdfpages}
\hypersetup{
+ keeppdfinfo,
pdftitle={The microtype package},
pdfauthor={R Schlicht <w.m.l@gmx.net>},
pdfsubject={Subliminal refinements towards typographical perfection},
pdfkeywords={TeX, LaTeX, pdfTeX, LuaTeX, XeTeX, typography, micro-typography,
character protrusion, margin kerning, optical alignment, font expansion,
font scaling, hz, kerning, spacing, glue, letterspacing, tracking, ligatures},
- pdfcopyright={\textcopyright\ 2004--2020 R Schlicht\012%
+ pdfcopyright={\textcopyright\ 2004--2021 R Schlicht\012%
This work may be distributed and/or modified under the conditions
of the LaTeX Project Public License, either version 1.3c of this
license or (at your option) any later version.\012%
@@ -580,7 +575,7 @@
}
\pdfcatalog{/Lang(en-GB)}
\ifnum\pdftexversion < 130 \else
- \IfFileExists{hypdestopt.sty}{\usepackage{hypdestopt}}\relax\fi
+ \usepackage{hypdestopt}\fi
\def\usage#1{\textbf{\hyperpage{#1}}}% for indexing of \DescribeMacro ...
\def\changes@#1#2#3{% ... the changes ...
\protected@edef\@tempa{\noexpand\glossary{#1\levelchar
@@ -814,7 +809,7 @@
% other extensions (see section~\ref{sec:lettersp}).
%
%\bigskip\noindent
-% This package is copyright \textcopyright\ 2004\kern.09em--2020 R Schlicht.
+% This package is copyright \textcopyright\ 2004\kern.09em--2021 R Schlicht.
% It may be distributed and/or modified under the conditions of the
% \IfFileExists{lppl.tex}{\hyperref[LPPL:LPPL]}{\href{http://www.latex-project.org/lppl/}}
% {\LaTeX\ Project Public License},
@@ -1042,6 +1037,9 @@
%
%\begin{table}\small
%\changes{v2.3a}{2008/02/25}{add table of available and enabled features}
+%\changes{v2.8a}{2020/12/23}{reorganise table~\ref{tab:available-features} for clarification
+% (suggested by \contributor Daniel Benjamin Miller <dbmiller\at dbmiller.org>)}
+% ^^A private mail, 2020/12/10
%\caption{Availability of micro-typographic features}\label{tab:available-features}
%\catcode`\!=13 \def!{\textcolor{thegreen}{\hskip.9em $\bigstar$}}
%\catcode`\?=13 \def?{\textcolor{theblue} {\hskip 1em $\boxtimes$}}
@@ -1051,7 +1049,7 @@
%\fcolorbox{theframe}{white}{^^A
%\begin{minipage}{\textwidth}
%\def\arraystretch{1.2}
-%\begin{tabular}{*3{@{}L{40pt}}*2{@{}L{43pt}}*4{@{}L{37pt}}@{}}
+%\begin{tabular}{*3{@{}L{40pt}}*6{@{}L{39pt}}@{}}
% \multicolumn{3}{@{}l}{\footnotesize \TeX\ engine}
% & \multicolumn{6}{@{}l}{\footnotesize Micro-typographic features}\\
%\cmidrule(r){1-3}\cmidrule{4-9}
@@ -1059,30 +1057,34 @@
% & \footnotesize Version
% & \footnotesize Output
% & \footnotesize Protrusion
-% & \footnotesize Expansion
-% & \footnotesize (= auto)
+% & \multicolumn{2}{l}{\footnotesize\hspace{2em}Expansion}
+% & \footnotesize Tracking
% & \footnotesize Kerning
-% & \footnotesize Spacing
-% & \footnotesize Tracking\\
-%\cmidrule(r){1-1}\cmidrule(r){2-2}\cmidrule(r){3-3}\cmidrule(r){4-4}
-%\cmidrule(r){5-5}\cmidrule(r){6-6}\cmidrule(r){7-7}\cmidrule(r){8-8}\cmidrule{9-9}
+% & \footnotesize Spacing\\
+%\cmidrule(r){5-6}\addlinespace[-2pt]
+% &&&& \footnotesize \textls[-20]{manual}
+% & \footnotesize \textls[-20]{automatic}\\
+%\cmidrule(r){1-1}\cmidrule(r){2-2}\cmidrule(r){3-3}
+%\cmidrule(r){4-4}\cmidrule(r){5-5}\cmidrule(r){6-6}
+%\cmidrule(r){7-7}\cmidrule(r){8-8}\cmidrule {9-9}
% \pdftex
% & $\less$ 0.14f & <DVI>/<PDF> & _ & _ & _ & _ & _ & _\\
% & $\geq$ 0.14f & <DVI>/<PDF> & ! & ? & _ & _ & _ & _\\
% & $\geq$ 1.20 & <DVI> & ! & ? & _ & _ & _ & _\\
% & & <PDF> & ! & ? & ! & _ & _ & _\\
-% & $\geq$ 1.40 & <DVI> & ! & ? & _ & ? & ? & _\\
+% & $\geq$ 1.40 & <DVI> & ! & ? & _ & _ & ? & ?\\
% & & <PDF> & ! & ? & ! & ? & ? & ?\\
%\cmidrule(r){1-3}
% \luatex ^^A we will have to re-model kerning and spacing with \luatex
% & $\geq$ 0.30 & <DVI> & ! & ? & _ & _ & _ & _\\
% & & <PDF> & ! & ? & ! & _ & _ & _\\
-% & $\geq$ 0.62 & <DVI> & ! & _ & \hskip1em\llap{(}\textcolor{theblue}{$\boxtimes$})\textsuperscript{\itshape a} & _ & _ & ?\\
-% & & <PDF> & ! & _ & ! & _ & _ & ?\\
+% & $\geq$ 0.62 & <DVI> & ! & _ & \hskip1em\llap{(}\textcolor{theblue}{$\boxtimes$})\textsuperscript{\itshape a} & ? & _ & _\\
+% & & <PDF> & ! & _ & ! & ? & _ & _\\
%\cmidrule(r){1-3}
% \let\textoractual\@firstoftwo ^^A why?
% \xetex
% & $\geq$ 0.9997 & <PDF> & ! & _ & _ & _ & _ & _\\
+%\addlinespace[2pt]
%\bottomrule
%\end{tabular}^^A
%\vskip4pt\footnotesize
@@ -1091,7 +1093,7 @@
% ? = not enabled\quad
% _ = not available
%\hfill
-% \textit{a}\quad by means of variable tracking\hskip1em
+% \textit{a}\quad by means of variable tracking
%\vskip4pt
%\end{minipage}^^A
%}\kern-\dimexpr\fboxsep+\fboxrule\relax ^^A end \fcolorbox
@@ -1153,7 +1155,7 @@
% If expanded instances of the fonts are available, they will be used
% regardless whether \opt{auto} is true or not.
%\fi
-% With \luatex, expansion is always automatic.
+% With recent versions of \luatex, expansion is always automatic.
%
% When generating <DVI> files, font expansion has to be enabled explicitly.
% With \pdftex, \emph{automatic} font expansion will not work because
@@ -1204,7 +1206,7 @@
%
%\subsection[Tracking]
% {Tracking \requires{\pdftex~1.40,\luatex~0.62}}
-% \label{sub:option-tracking}
+% \label{sub:options-tracking}
%
%\Describe{Option}{letterspace}{:integer}[100]
% This option changes the default amount for tracking (see section~\ref{sub:tracking})
@@ -1584,7 +1586,7 @@
% With \luatex\ or \xetex, you may additionally specify a (font-specific)
% glyph name, prefixed with `|/|' (\eg, the `fl' ligature as |/f_l|).
% Note that you also have the possibility to declare lists
-% of characters that should inherit settings (see section~\ref{sub:inherit}).
+% of characters that should inherit settings (see section~\ref{sub:inheritance}).
%
%\subsection[Character protrusion]
% {Character protrusion \requires{\pdftex~0.14f,\luatex~0.30,\xetex~0.9997}}
@@ -1744,7 +1746,7 @@
% This method of employing contexts to temporarily apply different
% expansion parameters only works with \pdftex\ version 1.40.4 or later,^^A
% \footnote{For older versions, a dirty trick is laid out in
-% section~\ref{ssec:font-setup} on page~\pageref{exp-hack}.}
+% section~\ref{sub:font-setup} on page~\pageref{exp-hack}.}
% or with \luatex.
% Also note that both \pdftex\ and \luatex\ prohibit the use of fonts with different expansion
% limits or steps (even of different fonts) within one paragraph, hence
@@ -2079,7 +2081,7 @@
%\end{options}
%
%
-%\subsection{Character inheritance}\label{sub:inherit}
+%\subsection{Character inheritance}\label{sub:inheritance}
%
% \Describe{Macro}{\DeclareCharacterInheritance}
% {?features,set of fonts,inheritance lists}
@@ -2123,7 +2125,6 @@
% This package ships with configuration files for a number of font families.
% Table~\ref{tab:fonts} lists them all.
%
-%\enlargethispage{\baselineskip} ^^A layout
%\begin{table}[t]\small
%\changes{v1.6a}{2005/02/02}{add table of fonts with tailored protrusion settings}
%\caption{Fonts with tailored protrusion settings}\label{tab:fonts}
@@ -2133,10 +2134,10 @@
%\begin{minipage}{\textwidth}
%\def\arraystretch{1.2}
%\long\def\@makefntext#1{%
-% \leftskip 1em
-% \parindent -1em
-% \everypar{\parindent -1em}%
-% \leavevmode\hbox to 1em{\@thefnmark\hss}#1}
+% \leftskip 1.2em
+% \parindent -1.2em
+% \everypar{\parindent -1.2em}%
+% \leavevmode\hbox to 1.2em{\@thefnmark\hss}#1}
%\let\footnoterule\relax
%\def\fnref#1{\textsuperscript{\itshape\ifpdf\ref*{#1}\else\ref{#1}\fi}}
%\begin{tabular*}{\textwidth}{@{\extracolsep{\fill}}*3l@{}}
@@ -2151,14 +2152,14 @@
% & n, (it, sl, sc)\fnref{fn:incmpl} \\
% Computer Modern Roman (|cmr|)\footnote{Aliases: Latin Modern Roman (|lmr|),
% \pkg{ae} (|aer|), \pkg{zefonts} (|zer|),
-% \pkg{eco} (|cmor|), \pkg{hfoldsty} (|hfor|)}
+% \pkg{eco} (|cmor|), \pkg{hfoldsty} (|hfor|), \pkg{mlmodern}~(|mlmr|)}
% & <OT1>, <OT4>, <T1>, <T2A>, <T5>, <LY1>, <TS1>
% & n, it, sl, sc \\
% Bitstream Charter (|bch|)\footnote{Aliases: \pkg{mathdesign}/Charter (|mdbch|),
% MicroPress's \pkg{chmath} (|chr|), \pkg{XCharter}}
% & <OT1>, <T1>, <T5>, <LY1>, <TS1>
% & n, it, (sl)\footnote{Settings inherited from italic shape\label{fn:it-sl}}, sc \\
-% Adobe Garamond (|pad|, |padx|, |padj|)
+% <EB> Garamond\footnote{Aliases: Adobe Garamond (|pad|, |padx|, |padj|)}
% & <OT1>, <T1>, <LY1>, <TS1>
% & n, it, (sl)\fnref{fn:it-sl}, sc \\
% <URW> Garamond (|ugm|)\footnote{Aliases: \pkg{mathdesign}/<URW> Garamond (|mdugm|), \pkg{garamondx} (|zgmx|, |zgmj|)}
@@ -2191,7 +2192,7 @@
% & <EU1>/<2>, <TU> [Latin, Cyrillic, Greek]
% & n, it, sc, si\\
%\fi
-% Palatino Linotype\footnote{Aliases: \TeX\ Gyre Pagella, Palatino <LT> Std, Palatino, Domitian}
+% Palatino\footnote{Aliases: Palatino Linotype, \TeX\ Gyre Pagella, Palatino <LT> Std, Palatino, Domitian}
% & <EU1>/<2>, <TU> [Latin]
% & n, it, sc\\
% Computer Modern math (|cmsy|, |cmm|)\footnote{Aliases: Latin Modern (|lmsy|, |lmm|)}
@@ -2218,13 +2219,13 @@
% On its search for a configuration file, the package will also try to remove
% from the font name a suffix of one or more letters that denotes a `variant'
% of the base font (cf. Karl Berry's \cite{fontname}). It is thus possible to
-% put settings for, \eg, the fonts |padx|~(expert set), |padj| (oldstyle
-% numerals) and |pad| (plain) into one and the same file \file{mt-pad.cfg}.
+% put settings for, \eg, the fonts |pplx|~(expert set), |pplj| (oldstyle
+% numerals) and |ppl| (plain) into one and the same file \file{mt-ppl.cfg}.
% This command expects a comma-separated list of variant suffixes. The starred
% version appends the suffix(es) to the existing list. The default declaration
% in \file{microtype.cfg} is:
%\begin{verbatim}
-%\DeclareMicrotypeVariants{x,j,w,a,d,0,1}
+%\DeclareMicrotypeVariants{x,j,w,a,d,0,1,-LF,-TLF,-OsF,-TOsF}
%\end{verbatim}
%
%\medskip
@@ -2237,6 +2238,7 @@
%\begin{verbatim}
%\DeclareMicrotypeAlias{lmr}{cmr}
%\end{verbatim}
+%\ifcmr\else\pagebreak\fi ^^A layout
% which would make the package, whenever it encounters the font |lmr| and does
% not find settings for it, also try the font |cmr|. In fact, you will find
% this very line, along with some others, in the default configuration file.
@@ -2382,7 +2384,6 @@
% the \opt{letterspace} package option, with decreasing significance in this
% order.
%
-%\pagebreak ^^A layout
%\medskip
%\Describe{Macro}{\lslig}{ligature}
% Since the commands \cs{textls} and \cs{lsstyle} will also evaluate the
@@ -2418,7 +2419,7 @@
%\bigskip\noindent
%\DescribePackage{letterspace}
% These three commands (plus the \opt{letterspace} option, described in
-% section~\ref{sub:option-tracking}) are also available with the alternative
+% section~\ref{sub:options-tracking}) are also available with the alternative
% \letterspace\ package, which is in fact a much stripped-down version of
% \microtype, omitting support for all the other extensions (and also omitting
% the possibilities of the \cs{SetTracking} command -- all `|f|' ligatures will
@@ -2660,7 +2661,6 @@
% distributions, this can be changed in the file \file{updmap.cfg} by setting
% |pdftexDownloadBase14| to |true|.
%
-%\ifcmr\else\pagebreak\fi ^^A layout
%\changes{v1.9a}{2005/11/15}{add explanation for error message with non-Type\,1 fonts}
% \item
%\begin{verbatim}
@@ -2882,11 +2882,14 @@
% \contributor Paolo Polesana <@\at @>, ^^A https://tex.stackexchange.com/users/95083/paolo-polesana
% \contributor Oliver Kopp <koppdev\at gmail.com>,
% \contributor Hironori Kitagawa <h_kitagawa2001\at yahoo.co.jp>,
-% `\contributor d909 <@\at @>', ^^A https://tex.stackexchange.com/users/176404/d909
-% \contributor Daniel Benjamin Miller <dbmiller\at dbmiller.org>,
-% \contributor Md Ayquassar <mdayq0\at lenta.ru>
+% \contributor Daniel Benjamin Miller <dbmiller\at dbmiller.org>, ^^A also https://tex.stackexchange.com/users/176404/d909
+% \contributor Md Ayquassar <mdayq0\at lenta.ru>,
+% \contributor Marcel Kr\"uger <tex\at 2krueger.de>,
+% \contributor Ekkehart Schlicht <ekkehart.schlicht\at gmail.com>,
+% `\contributor Canageek <@\at @>', ^^A https://tex.stackexchange.com/users/7880/canageek
+% `\contributor dsedivec <@\at @>' ^^A https://tex.stackexchange.com/users/1680/dsedivec
% and
-% \contributor Marcel Kr\"uger <tex\at 2krueger.de>.
+% `\contributor DORpapst <@\at @>'. ^^A https://tex.stackexchange.com/users/104965/dorpapst
%
%
%\iffalse
@@ -2972,7 +2975,7 @@
%
% \bibitem[\LaTeXe\ font selection]{fntguide}
% \LaTeX3 Project Team, \emph{\LaTeXe\ font selection},
-% \newblock July 2020.
+% \newblock November 2020.
% \newblock (\ctanurl{macros/latex/base/fntguide.pdf})
%
% \bibitem[\pkg{fontspec}]{fontspec}
@@ -2984,7 +2987,7 @@
% \bibitem[\pkg{luaotfload}]{luaotfload}
% \'Elie Roux, Khaled Hosny, Philipp Gesang, Ulrike Fischer, Marcel Kr\"uger,
% \emph{The \pkg{luaotfload} package},
-% \newblock 2~September 2020.
+% \newblock 8~January 2021.
% \newblock (\ctanpkgurl{luaotfload})
%
% \bibitem[\pkg{pdfcprot}]{pdfcprot}
@@ -3035,7 +3038,9 @@
%
%\begin{History}
%
-%\Version{\expandafter\@gobble\fileversion}{\filedate}
+%\VersionDate{\expandafter\@gobble\fileversion}{\filedate}
+%
+%\Version{2.8}{2020/12/07}
% \item New default font sets for expansion and spacing: `|alltext-nott|'
% \refsection{\ref{sec:font-sets}, table~\ref{tab:predefined-font-sets}}
%
@@ -3136,7 +3141,7 @@
% \refsection{\ref{sub:tracking}, \ref{sub:kerning}, \ref{sub:spacing}}
% \item New commands \cs{textls} and \cs{lsstyle} for letterspacing,
% new option `\opt{letterspace}'
-% \refsection{\ref{sub:option-tracking}, \ref{sec:lettersp}}
+% \refsection{\ref{sub:options-tracking}, \ref{sec:lettersp}}
% \item New option `\opt{babel}' for automatic micro-typographic adjustment to
% the selected language
% \refsection{\ref{sub:options-misc}, \ref{sec:context}}
@@ -3275,7 +3280,7 @@
%\Version{1.1}{2004/09/21}
% \item Protrusion settings for Adobe Minion
% \item New command: \cs{DeclareCharacterInheritance}
-% \refsection{\ref{sub:inherit}}
+% \refsection{\ref{sub:inheritance}}
% \item Characters may also be specified as octal or hexadecimal numbers
% \refsection{\ref{sec:fine-tuning}}
%^^A \item Configuration file names in lowercase [\ref{sub:config-file}]
@@ -3453,7 +3458,7 @@
% \item[|bch|] Settings for Bitstream Charter (\file{mt-bch.cfg}).
% \item[|blg|] Settings for Bitstream Letter Gothic (\file{mt-blg.cfg}).
% \item[|cmr|] Settings for Computer Modern Roman (\file{mt-cmr.cfg}).
-% \item[|pad|] Settings for Adobe Garamond (\file{mt-pad.cfg}).
+% \item[|ebg|] Settings for <EB> Garamond (\file{mt-EBGaramond.cfg}).
% \item[|ppl|] Settings for Palatino (\file{mt-ppl.cfg}).
% \item[|ptm|] Settings for Times (\file{mt-ptm.cfg}).
% \item[|pmn|] Settings for Adobe Minion (\file{mt-pmn.cfg}).
@@ -3471,7 +3476,6 @@
% \item[|cfg-e|] Surrounds Euro symbol configurations.
% \begin{description}
% \item[|zpeu|] Settings for Adobe Euro symbol fonts (\file{mt-zpeu.cfg}).
-% \item[|euroitc|] Settings for <ITC> Euro symbol fonts (\file{mt-euroitc.cfg}).
% \item[|mvs|] Settings for \pkg{marvosym} Euro symbol (\file{mt-mvs.cfg}).
% \end{description}
% \end{description}
@@ -3999,10 +4003,11 @@
% \item + default \cmd\efcode\,=\,1000;
% \cmd\protrusionboundary\ [not yet supported] ($\geq$~0.90)
%\todo{interface for \cmd\protrusionboundary}
+% \item + \cmd\glet ($\geq$~1.10)
%\end{enum}
%\changes{v2.6}{2016/04/22}{update for \luatex\ 0.85 (renamed primitives)}
% Also, sometime between 1.0.4 and 1.0.7, the function |font.setexpansion|
-% has been introduced, but we'll test this directly later.
+% has been introduced (but we're not using it for now).
% \begin{macrocode}
%<*luatex-def>
%<debug>\MT@dinfo@nl0{this is luatex (\the\luatexversion)}
@@ -4015,16 +4020,19 @@
%\changes{v2.3d}{2009/03/25}{update for \luatex\ 0.36}
% \begin{macrocode}
\let\MT@lua\directlua
-\def\MT@luatex@no{5}
-\ifnum\luatexversion<90
- \def\MT@luatex@no{4}
- \ifnum\luatexversion<85
- \def\MT@luatex@no{3}
- \ifnum\luatexversion<62
- \def\MT@luatex@no{2}
- \ifnum\luatexversion<36
- \def\MT@lua{\directlua0}
- \def\MT@luatex@no{1}
+\def\MT@luatex@no{6}
+\ifnum\luatexversion<110
+ \def\MT@luatex@no{5}
+ \ifnum\luatexversion<90
+ \def\MT@luatex@no{4}
+ \ifnum\luatexversion<85
+ \def\MT@luatex@no{3}
+ \ifnum\luatexversion<62
+ \def\MT@luatex@no{2}
+ \ifnum\luatexversion<36
+ \def\MT@lua{\directlua0}
+ \def\MT@luatex@no{1}
+ \fi
\fi
\fi
\fi
@@ -4317,8 +4325,11 @@ end
% To be continued, but first back to primitives.
%\begin{macro}{\MT@glet}
%\changes{v1.9f}{2006/08/09}{new macro}
-% Here's the forgotten one.
+% Here's the forgotten one
+%\changes{v2.8a}{2020/02/01}{use \luatex's \cmd\glet, if available}
+% (finally implemented in \luatex).
% \begin{macrocode}
+%<luatex-def>\MT@requires@luatex6{\let\MT@glet\glet}\relax
%<*package|letterspace>
\def\MT@glet{\global\let}
% \end{macrocode}
@@ -5090,15 +5101,15 @@ microtype.do_font = do_font
% \end{macrocode}
%\end{macro}
%
-%\subsubsection{Compatibility}\label{sub:compatibility}
+%\subsubsection{Compatibility}\label{ssub:compatibility}
%
% For the record, the following \LaTeX\ kernel commands will be modified by
% \microtype:
%\begin{itemize}
% \item \cmd\pickup@font
% \item \cmd\do@subst@correction
-% \item \cmd\add@accent\ (all in section~\ref{sssec:impl.hook})
-% \item \cmd\showhyphens\ (in section~\ref{sssec:impl.options})
+% \item \cmd\add@accent\ (all in section~\ref{ssub:impl.hook})
+% \item \cmd\showhyphens\ (in section~\ref{ssub:impl.options})
%\end{itemize}
%
% The \pkg{wordcount} package redefines the font-switching commands, which will
@@ -5542,7 +5553,7 @@ time will almost certainly lead to undesired results. Have your choice!}%
%<package>\expandafter\ifx\the\font\nullfont\normalfont\fi
% \end{macrocode}
%
-%\subsection{Font setup}\label{ssec:font-setup}
+%\subsection{Font setup}\label{sub:font-setup}
%
%\begin{macro}{\MT@setupfont}
% Setting up a font entails checking for each feature whether it should be
@@ -8290,7 +8301,7 @@ end
%\changes{v1.8}{2005/03/29}{reset catcodes of the remaining <ASCII> characters}
% OK, now all printable characters up to 127 are `other'. We hope that letters
% are always letters and numbers other. (\pkg{listings} makes them active, see
-% section~\ref{sub:compatibility}.)
+% section~\ref{ssub:compatibility}.)
%
% We leave |^| at catcode 7, so that stuff like `|^^ff|' remains possible.
% \begin{macrocode}
@@ -8359,7 +8370,7 @@ end
%\begin{macro}{\MT@get@basefamily@}
% This will only remove one suffix (the longest match), so that
% \emph{combinations} of suffixes would have be to added manually (\eg,
-% |\DeclareMicrotypeVariants*{aw}|). But otherwise, something like `|padx|'
+% |\DeclareMicrotypeVariants*{aw}|). But otherwise, something like `|pplx|'
% would be truncated to `|p|'.
% \begin{macrocode}
\def\MT@get@basefamily@#1#2\@nil{%
@@ -9286,7 +9297,7 @@ end
\MT@glet\MT@warn@unknown\relax}%
}
%
-%\subsubsection{Hook into \LaTeX's font selection}\label{sssec:impl.hook}
+%\subsubsection{Hook into \LaTeX's font selection}\label{ssub:impl.hook}
%
% We append \cs{MT@setupfont} to \cmd\pickup@font, which is called by \LaTeX\
% every time a font is selected. We then check whether we've already seen this
@@ -10091,19 +10102,8 @@ end
\else
\MT@let@cn\@tempa{\MT@val}%
\fi
- \ifx\@tempa\relax \else
-% \end{macrocode}
-% The \pkg{relsize} solution of parsing \cmd\@setfontsize\ does not work with the
-% <AMS> classes, among others. I hope my hijacking doesn't do any harm.
-%\changes{v1.2}{2004/09/26}{hijack \cmd\set@fontsize\ instead of \cmd\@setfontsize}
-% We redefine \cmd\set@fontsize\ instead of \cmd\@setfontsize\ because some classes
-% might define the size selection commands by simply using \cmd\fontsize\
-% (\eg, the \pkg{a0poster} class).
-%\changes{v2.3b}{2008/03/07}{grouping}
-% \begin{macrocode}
- \begingroup
- \def\set@fontsize##1##2##3##4\@nil{\endgroup\def\MT@val{##2}}%
- \@tempa\@nil
+ \ifx\@tempa\relax\else
+ \MT@get@size@
\fi
% \end{macrocode}
% Test whether we finally got a number or dimension so that we can strip the
@@ -10121,6 +10121,44 @@ end
}
% \end{macrocode}
%\end{macro}
+%\begin{macro}{\MT@get@size@}
+%\begin{macro}{\MT@get@size@@}
+% The \pkg{relsize} solution of parsing \cmd\@setfontsize\ does not work with the
+% <AMS> classes, among others. I hope my hijacking doesn't do any harm.
+%\changes{v1.2}{2004/09/26}{hijack \cmd\set@fontsize\ instead of \cmd\@setfontsize}
+% We redefine \cmd\set@fontsize\ instead of \cmd\@setfontsize\ because some classes
+% might define the size selection commands by simply using \cmd\fontsize\
+% (\eg, the \pkg{a0poster} class).
+%\changes{v2.3b}{2008/03/07}{grouping}
+% \begin{macrocode}
+\def\MT@get@size@@{%
+ \begingroup
+ \def\set@fontsize##1##2##3##4\@nil{\endgroup\def\MT@val{##2}}%
+ \@tempa\@nil
+}
+% \end{macrocode}
+% The \pkg{svjour3} class defines the size commands using conditionals;
+% using \etex\ primitives, we close any leftovers here.
+%\changes{v2.8a}{2020/12/10}{compatibility with \pkg{svjour3}
+% (reported by \contributor Ekkehart Schlicht <ekkehart.schlicht\at gmail.com> (no relation!!))}
+% ^^A https://groups.google.com/g/de.comp.text.tex/c/46sJ1jFRq-I
+% ^^A MID: <9aa52497-19b5-4ca7-a668-c076cec4ceadn@googlegroups.com>, 2020/11/09
+% \begin{macrocode}
+^^X\@ifclassloaded{svjour3}{%
+^^X \def\MT@get@size@{%
+^^X \@tempcnta=\currentiflevel
+^^X \MT@get@size@@
+^^X \loop
+^^X \ifnum\numexpr\currentiflevel-1>\@tempcnta
+^^X \csname fi\endcsname
+^^X \repeat
+^^X }%
+^^X}{%
+ \let\MT@get@size@\MT@get@size@@
+^^X}
+% \end{macrocode}
+%\end{macro}
+%\end{macro}
%\changes{v1.9}{2005/07/13}{\cs{DeclareMicrotypeSet}: new key: \texttt{font}}
%\begin{macro}{\MT@define@set@key@font}
%\changes{v2.3}{2007/11/20}{\texttt{font}: single asterisk means normal font}
@@ -11089,6 +11127,7 @@ end
%\changes{v1.9d}{2006/02/09}{fix: empty context}
%\changes{v1.9e}{2006/07/26}{new key `\texttt{inputenc}' to set the input encoding}
%\changes{v2.5}{2010/05/18}{allow more than one encoding}
+%\changes{v2.8a}{2021/01/15}{skip settings for tracking}
% This macro may be used in the configuration files to declare characters that
% should inherit protrusion resp. expansion values from other characters. Thus,
% there is no need to define all accented characters (\eg, |\`a|, |\'a|,
@@ -11115,18 +11154,20 @@ end
%\end{macro}
%\end{macro}
%\begin{macro}{\MT@set@inh@list}
-% Safe category codes.
+% No need to create an inheritance list for tracking.
% \begin{macrocode}
\def\MT@set@inh@list#1#2{%
\MT@ifempty\MT@inh@feat{%
- \MT@map@clist@c\MT@features{{\MT@declare@char@inh{##1}{#1}{#2}}}%
+ \MT@map@clist@c\MT@features{{%
+ \MT@ifstreq{##1}{tr}\relax{\MT@declare@char@inh{##1}{#1}{#2}}%
+ }}%
}{%
\MT@map@clist@c\MT@inh@feat{{%
\KV@@sp@def\@tempa{##1}%
\MT@ifempty\@tempa\relax{%
- \MT@exp@one@n\MT@declare@char@inh
- {\csname MT@rbba@\@tempa\endcsname}{#1}{#2}%
- }%
+ \edef\@tempa{\csname MT@rbba@\@tempa\endcsname}%
+ \MT@ifstreq\@tempa{tr}\relax{%
+ \MT@exp@one@n\MT@declare@char@inh{\@tempa}{#1}{#2}}}%
}}%
}%
\MT@end@catcodes
@@ -11217,7 +11258,7 @@ end
% \end{macrocode}
%\end{macro}
%
-%\subsubsection{Permutation}
+%\subsubsection{Permutation}\label{ssub:permutation}
%
%\begin{macro}{\MT@permute}
%\changes{v1.1}{2004/09/15}{don't use sets for empty encoding}
@@ -11237,8 +11278,27 @@ end
% currently defined list. Size ranges are held in a separate macro called
% |\MT@|\meta{list type}|@/|\allowbreak\meta{font axes}|@sizes|, which in turn
% contains the respective \meta{list name}s attached to the ranges.
+% So that,
+%\begin{verbatim}
+%\SetProtrusion
+% { encoding = U,
+% family = {euroitc,euroitcs} }
+% { E = {100,50} }
+%\SetProtrusion
+% { encoding = U,
+% family = {euroitc,euroitcs},
+% shape = it* }
+% { E = {100,} }
+%\end{verbatim}
+% would yield the following assignments:
% \begin{macrocode}
%<*package>
+\MT@gdef@n{MT@pr@c@U/euroitc///}{euroitc}
+\MT@gdef@n{MT@pr@c@U/euroitcs///}{euroitc}
+\MT@gdef@n{MT@pr@c@U/euroitc//it/}{euroitci}
+\MT@gdef@n{MT@pr@c@U/euroitcs//it/}{euroitci}
+\MT@gdef@n{MT@pr@c@euroitc}{E={100,50}}
+\MT@gdef@n{MT@pr@c@euroitci}{E={100,}}
\def\MT@permute{%
\let\MT@cnt@encoding\@ne
\MT@permute@
@@ -12164,7 +12224,7 @@ end
%</package>
% \end{macrocode}
%
-%\subsubsection{Processing the options}\label{sssec:impl.options}
+%\subsubsection{Processing the options}\label{ssub:impl.options}
%
%\begin{macro}{\MT@ProcessOptionsWithKV}
% Parse options.
@@ -12308,7 +12368,7 @@ end
% Since this could still be considered a viable option, we don't disable
% the feature completely, but issue a warning.
%\changes{v2.8}{2020/02/09}{warning when expanding in <DVI> mode with \luatex\
-% (reported by \contributor d909 <@\at @>)}
+% (reported by \contributor Daniel Benjamin Miller <dbmiller\at dbmiller.org>)} ^^A aka `d909'
% ^^A https://tex.stackexchange.com/questions/531413/dvipdfmx-and-dvips-do-not-expand-fonts-properly-with-lualatex-in-dvi-mode
% \begin{macrocode}
%<*pdftex-def|luatex-def>
@@ -12904,6 +12964,9 @@ end
%
%\section{Configuration files}
%\changes{v1.6}{2005/01/24}{restructure \file{dtx} file}
+%\changes{v2.8a}{2021/02/22}{rename \file{mt-pad.cfg} to \file{mt-EBGaramond.cfg}
+% (requested by \contributor Karl Berry <karl\at freefriends.org>)}
+% ^^A private mail, 2021/02/22
%
% Let's now write the font configuration files.
% \begin{macrocode}
@@ -12943,7 +13006,7 @@ end
% \end{macrocode}
%\changes{v2.6}{2014/04/07}{new: \texttt{allmath-nott} and \texttt{alltext-nott}
-% (reqested by \contributor Karl Berry <karl\at freefriends.org>)}
+% (suggested by \contributor Karl Berry <karl\at freefriends.org>)}
% ^^A private mail, 2014/03/21
% \begin{macrocode}
\DeclareMicrotypeSet{allmath-nott}
@@ -13023,11 +13086,14 @@ end
%
% These are the variants I happen to be using (expert encoding, oldstyle
% numerals, swashes, alternative, display, inferior and superior numerals):
+% Additionally, we add the now common variants for Lining, Tabular, Oldstyle,
+% and Tabular Oldstyle numbers.
+%\changes{v2.8a}{2021/02/22}{add \texttt{-LF}, \texttt{-TLF}, \texttt{-OsF} and \texttt{-TOsF} as variants}
% \begin{macrocode}
%%% -----------------------------------------------------------------------
%%% FONT VARIANTS AND ALIASES
-\DeclareMicrotypeVariants{x,j,w,a,d,0,1}
+\DeclareMicrotypeVariants{x,j,w,a,d,0,1,-LF,-TLF,-OsF,-TOsF}
% \end{macrocode}
% Other candidates: |2|~(proportional digits), |e|~(engraved), |f|~(Fraktur),
% |g|~(small text), |h|~(shadow), |l|~(outline), |n|~(informal),
@@ -13062,17 +13128,20 @@ end
\fi
% \end{macrocode}
% The Latin Modern fonts, the virtual fonts from the
-% \pkg{ae} and \pkg{zefonts}, and the \pkg{eco} and \pkg{hfoldsty} packages
-% (oldstyle numerals) all inherit the (basic) settings from Computer Modern
-% Roman. Some of them are in part overwritten later.
+% \pkg{ae} and \pkg{zefonts} and the \pkg{eco} and \pkg{hfoldsty} packages
+% (oldstyle numerals), as well as \pkg{mlmodern}, all inherit the (basic) settings
+% from Computer Modern Roman. Some of them are in part overwritten later.
%\changes{v1.2}{2004/10/03}{declare \texttt{cmor} as an alias of \texttt{cmr}}
%\changes{v1.3}{2004/10/22}{declare \texttt{aer}, \texttt{zer} and \texttt{hfor}
-% as aliases of \texttt{cmr}}
+% as aliases of \texttt{cmr}}^^A
% We mustn't forget the Latin Modern math fonts.
%\changes{v2.5}{2012/07/17}{declare \texttt{lmsy} and \texttt{lmm} as aliases
% of \texttt{cmsy} resp. \texttt{cmm}
% (reported by \contributor Jonas Hogstrom <hjb981\at gmail.com>)}
% ^^A https://tex.stackexchange.com/questions/63558/how-to-get-microtype-to-work-with-mathematical-minus-sign-and-package-lmodern
+%\changes{v2.8a}{2021/01/13}{declare \pkg{mlmodern} fonts as aliases of Latin Modern
+% (reported by \contributor Daniel Benjamin Miller <dbmiller\at dbmiller.org>)}
+% ^^A private mail, 2021/01/12
% \begin{macrocode}
\DeclareMicrotypeAlias{lmsy}{cmsy} % "
\DeclareMicrotypeAlias{lmm} {cmm} % "
@@ -13080,11 +13149,20 @@ end
\DeclareMicrotypeAlias{zer} {cmr} % zefonts
\DeclareMicrotypeAlias{cmor}{cmr} % eco
\DeclareMicrotypeAlias{hfor}{cmr} % hfoldsty
+\DeclareMicrotypeAlias{mlmr}{cmr} % mlmodern
+\DeclareMicrotypeAlias{mlmsy}{cmsy} % "
+\DeclareMicrotypeAlias{mlmm} {cmm} % "
% \end{macrocode}
% Another, new Computer Modern extension.
%\changes{v2.8}{2019/11/22}{declare New Computer Modern as an alias of Latin Modern Roman}
+% The \pkg{newcomputermodern} package loads it by file name.
+%\changes{v2.8a}{2021/01/09}{reference New Computer Modern also by file name
+% (reported by \contributor Canageek <@\at @>)}
+% ^^A https://tex.stackexchange.com/questions/578121/how-do-i-properly-tell-microtype-that-newcomputermodern-is-the-same-as-comput
% \begin{macrocode}
\DeclareMicrotypeAlias{New Computer Modern}{Latin Modern Roman}
+\DeclareMicrotypeAlias{NewCM10-Book.otf} {Latin Modern Roman}
+\DeclareMicrotypeAlias{NewCM10-Regular.otf}{Latin Modern Roman}
% \end{macrocode}
% The packages \pkg{pxfonts} and \pkg{txfonts} fonts inherit Palatino and Times
% settings respectively,
@@ -13125,11 +13203,11 @@ end
%\changes{v2.5}{2012/03/29}{declare TeX Gyre Pagella, Asana Math, Palatino <LT> Std, and Palatino
% as aliases of Palatino Linotype (OpenType version)}
% \begin{macrocode}
-\DeclareMicrotypeAlias{Domitian} {Palatino Linotype}
-\DeclareMicrotypeAlias{TeX Gyre Pagella}{Palatino Linotype}
-\DeclareMicrotypeAlias{Palatino LT Std} {Palatino Linotype}
-\DeclareMicrotypeAlias{Palatino} {Palatino Linotype}
-\DeclareMicrotypeAlias{Asana Math} {Palatino Linotype}
+\DeclareMicrotypeAlias{Palatino Linotype}{Palatino}
+\DeclareMicrotypeAlias{Palatino LT Std} {Palatino}
+\DeclareMicrotypeAlias{TeX Gyre Pagella} {Palatino}
+\DeclareMicrotypeAlias{Domitian} {Palatino}
+\DeclareMicrotypeAlias{Asana Math} {Palatino}
%% -- Times New Roman
\DeclareMicrotypeAlias{txr}{ptm} % txfonts
% \end{macrocode}
@@ -13144,13 +13222,13 @@ end
% The \pkg{tempora} package.
%\changes{v2.7}{2017/02/25}{declare aliases for \pkg{tempora}}
% \begin{macrocode}
-\DeclareMicrotypeAlias{Tempora-TLF}{ptmx} % tempora
+\DeclareMicrotypeAlias{Tempora-TLF} {ptmx} % tempora
\DeclareMicrotypeAlias{Tempora-TOsF}{ptmj} % "
\DeclareMicrotypeAlias{qtm}{ptm} % TeX Gyre Termes (formerly: qfonts/QuasiTimes)
% \end{macrocode}
% The \pkg{step} package.
% \begin{macrocode}
-\DeclareMicrotypeAlias{STEP-TLF}{ptmx} % step
+\DeclareMicrotypeAlias{STEP-TLF} {ptmx} % step
\DeclareMicrotypeAlias{STEP-TOsF}{ptmj} % "
% \end{macrocode}
% The \pkg{stix} and \pkg{stix2} packages (the latter has departed a bit from being
@@ -13197,6 +13275,13 @@ end
\DeclareMicrotypeAlias{zgmj}{ugm} % "
\DeclareMicrotypeAlias{zgmI}{ugm} % "
\DeclareMicrotypeAlias{zgmq}{ugm} % "
+% \end{macrocode}
+% Because a configuration file for Adobe Garamond wouldn't be permitted
+% for \texlive\ distribution, we use <EB> Garamond as the base font.
+% \begin{macrocode}
+\DeclareMicrotypeAlias{pad} {EBGaramond-LF}% Adobe Garamond
+\DeclareMicrotypeAlias{padx}{EBGaramond-TLF}% "
+\DeclareMicrotypeAlias{padj}{EBGaramond-TOsF}% "
%% --
% \end{macrocode}
% <URW> Letter Gothic is similar enough to Bitstream Letter Gothic to share the
@@ -13215,7 +13300,6 @@ end
% \begin{macrocode}
\DeclareMicrotypeAlias{zpeus} {zpeu} % Adobe Euro sans -> serif
\DeclareMicrotypeAlias{eurosans}{zpeu} % Adobe Euro sans -> serif
-\DeclareMicrotypeAlias{euroitcs}{euroitc} % ITC Euro sans -> serif
% \end{macrocode}
%
@@ -13538,7 +13622,7 @@ end
% should be overridden by font-specific ones.
% \begin{macrocode}
\DeclareCharacterInheritance
- { encoding = {EU1,EU2,TU} }
+ { encoding = {TU,EU1,EU2} }
{ A = {\`A,\'A,\^A,\~A,\"A,\r A,\k A,\u A},
a = {\`a,\'a,\^a,\~a,\"a,\r a,\k a,\u a},
C = {\'C,\c C,\v C},
@@ -13844,9 +13928,9 @@ end
% \begin{macrocode}
%<cmr> [ name = cmr-default ]
% \end{macrocode}
-% \item Adobe Garamond (|pad|, |padx|, |padj|)
+% \item <EB> Garamond
% \begin{macrocode}
-%<pad> [ name = pad-default ]
+%<ebg> [ name = EBGaramond-default ]
% \end{macrocode}
% \item Minion\footnote{Contributed by \contributor Harald Harders <h.harders\at tu-bs.de>
% and \contributor Karl Karlsson <karl-karlsson\at yandex.ru>.}
@@ -13871,82 +13955,82 @@ end
% \begin{macrocode}
%<ugm> [ name = ugm-default ]
%<m-t|cmr|pmn> { }
-%<bch|blg|pad|ugm> { encoding = OT1,
+%<bch|blg|ebg|ugm> { encoding = OT1,
%<ppl|ptm> { encoding = {OT1,OT4},
%<bch> family = bch }
%<blg> family = blg }
-%<pad> family = {pad,padx,padj} }
+%<ebg> family = {EBGaramond-LF,EBGaramond-OsF,EBGaramond-TLF,EBGaramond-TOsF} }
%<ppl> family = {ppl,pplx,pplj} }
%<ptm> family = {ptm,ptmx,ptmj} }
%<ugm> family = ugm }
{
-%<m-t|bch|blg|cmr|pad|pmn|ppl|ptm> A = {50,50},
+%<m-t|bch|blg|cmr|ebg|pmn|ppl|ptm> A = {50,50},
%<ugm> A = {50,100},
-%<pad|ptm> \AE = {50, },
+%<ebg|ptm> \AE = {50, },
%<ugm> \AE = {150,50},
%<ugm> B = { ,50},
-%<bch|pad|pmn|ugm> C = {50, },
-%<bch|pad|pmn> D = { ,50},
+%<bch|ebg|pmn|ugm> C = {50, },
+%<bch|ebg|pmn> D = { ,50},
%<ugm> D = { ,70},
%<ugm> E = { ,50},
-%<m-t|bch|cmr|pad|pmn|ptm> F = { ,50},
+%<m-t|bch|cmr|ebg|pmn|ptm> F = { ,50},
%<ugm> F = { ,70},
-%<bch|pad|pmn> G = {50, },
+%<bch|ebg|pmn> G = {50, },
%<ugm> G = {50,50},
%<blg> I = {150,150},
-%<m-t|cmr|pad|pmn|ppl|ptm|ugm> J = {50, },
+%<m-t|cmr|ebg|pmn|ppl|ptm|ugm> J = {50, },
%<bch|blg> J = {100, },
%<!blg> K = { ,50},
%<blg> K = {50, },
-%<m-t|bch|cmr|pad|pmn|ppl> L = { ,50},
+%<m-t|bch|cmr|ebg|pmn|ppl> L = { ,50},
%<blg> L = { ,150},
%<ptm> L = { ,80},
%<ugm> L = { ,120},
-%<bch|pad|pmn|ugm> O = {50,50},
-%<pad> \OE = {50, },
+%<bch|ebg|pmn|ugm> O = {50,50},
+%<ebg> \OE = {50, },
%<ugm> \OE = {50,50},
%<blg> P = { ,100},
%<ugm> P = { ,50},
-%<bch|pad|pmn> Q = {50,70},
+%<bch|ebg|pmn> Q = {50,70},
%<ugm> Q = {50,50},
%<bch> R = { ,50},
%<ugm> R = { ,70},
-%<m-t|bch|cmr|pad|pmn|ppl|ptm> T = {50,50},
+%<m-t|bch|cmr|ebg|pmn|ppl|ptm> T = {50,50},
%<blg> T = {100,100},
%<ugm> T = {70,70},
-%<m-t|bch|cmr|pad|pmn|ppl|ptm> V = {50,50},
+%<m-t|bch|cmr|ebg|pmn|ppl|ptm> V = {50,50},
%<blg|ugm> V = {70,70},
-%<m-t|bch|cmr|pad|pmn|ppl|ptm> W = {50,50},
+%<m-t|bch|cmr|ebg|pmn|ppl|ptm> W = {50,50},
%<ugm> W = {70,70},
-%<m-t|bch|cmr|pad|pmn|ppl|ptm> X = {50,50},
+%<m-t|bch|cmr|ebg|pmn|ppl|ptm> X = {50,50},
%<ugm> X = {50,70},
-%<m-t|bch|cmr|pad|pmn|ppl> Y = {50,50},
+%<m-t|bch|cmr|ebg|pmn|ppl> Y = {50,50},
%<blg|ptm|ugm> Y = {80,80},
%<ugm> Z = {50,50},
%<blg> f = {150,100},
%<blg> i = {150,150},
%<blg> j = {100,100},
-%<m-t|bch|cmr|pad|pmn|ppl|ptm> k = { ,50},
+%<m-t|bch|cmr|ebg|pmn|ppl|ptm> k = { ,50},
%<ugm> k = { ,70},
%<blg> l = {150,150},
%<pmn> l = { ,-50},
-%<pad|ppl> p = {50,50},
+%<ebg|ppl> p = {50,50},
%<ugm> p = { ,50},
-%<pad|ppl> q = {50, },
+%<ebg|ppl> q = {50, },
%<!blg> r = { ,50},
%<blg> r = {100, 80},
-%<cmr|pad|pmn> t = { ,70},
+%<cmr|ebg|pmn> t = { ,70},
%<bch> t = { ,50},
%<blg> t = {150, 80},
%<ugm> t = { ,100},
-%<m-t|bch|cmr|pad|pmn|ppl|ptm> v = {50,50},
+%<m-t|bch|cmr|ebg|pmn|ppl|ptm> v = {50,50},
%<blg> v = {100,100},
%<ugm> v = {50,70},
-%<m-t|bch|cmr|pad|pmn|ppl|ptm> w = {50,50},
+%<m-t|bch|cmr|ebg|pmn|ppl|ptm> w = {50,50},
%<ugm> w = {50,70},
%<!blg> x = {50,50},
%<blg> x = {100,100},
-%<m-t|bch|pad|pmn> y = { ,50},
+%<m-t|bch|ebg|pmn> y = { ,50},
%<blg> y = { 50,100},
%<cmr|ppl|ptm> y = {50,70},
%<ugm> y = { ,70},
@@ -13957,59 +14041,59 @@ end
% \begin{macrocode}
%<cmr> 0 = { ,50},
%<m-t> 1 = {50,50},
-%<bch|blg|pad|ptm|ugm> 1 = {150,150},
+%<bch|blg|ebg|ptm|ugm> 1 = {150,150},
%<cmr> 1 = {100,200},
%<pmn> 1 = { ,50},
%<ppl> 1 = {100,100},
-%<bch|cmr|pad|ugm> 2 = {50,50},
+%<bch|cmr|ebg|ugm> 2 = {50,50},
%<blg> 2 = { ,100},
%<bch|pmn> 3 = {50, },
-%<cmr|pad|ugm> 3 = {50,50},
+%<cmr|ebg|ugm> 3 = {50,50},
%<blg> 3 = {100, },
-%<m-t|pad> 4 = {50,50},
+%<m-t|ebg> 4 = {50,50},
%<bch> 4 = {100,50},
%<blg> 4 = {100, },
%<cmr|ugm> 4 = {70,70},
%<pmn> 4 = {50, },
%<ptm> 4 = {70, },
%<cmr> 5 = { ,50},
-%<pad> 5 = {50,50},
+%<ebg> 5 = {50,50},
%<bch> 6 = {50, },
%<cmr> 6 = { ,50},
-%<pad> 6 = {50,50},
+%<ebg> 6 = {50,50},
%<m-t> 7 = {50,50},
-%<bch|pad|pmn|ugm> 7 = {50,80},
+%<bch|ebg|pmn|ugm> 7 = {50,80},
%<blg> 7 = {100,100},
%<cmr|ptm> 7 = {50,100},
%<ppl> 7 = { ,50},
%<cmr> 8 = { ,50},
-%<bch|pad> 9 = {50,50},
+%<bch|ebg> 9 = {50,50},
%<cmr> 9 = { ,50},
-%<m-t|cmr|pad|pmn|ppl|ptm|ugm> . = { ,700},
+%<m-t|cmr|ebg|pmn|ppl|ptm|ugm> . = { ,700},
%<bch> . = { ,600},
%<blg> . = {400,500},
%<!blg> {,}= { ,500},
%<blg> {,}= {300,400},
-%<m-t|cmr|pad|pmn|ppl|ptm|ugm> : = { ,500},
+%<m-t|cmr|ebg|pmn|ppl|ptm|ugm> : = { ,500},
%<bch> : = { ,400},
%<blg> : = {300,400},
-%<m-t|bch|pad|pmn|ptm> ; = { ,300},
+%<m-t|bch|ebg|pmn|ptm> ; = { ,300},
%<blg> ; = {200,300},
%<cmr|ppl> ; = { ,500},
%<ugm> ; = { ,400},
%<!blg> ! = { ,100},
%<blg> ! = {200,200},
-%<m-t|pad|pmn|ptm> ? = { ,100},
+%<m-t|ebg|pmn|ptm> ? = { ,100},
%<bch|cmr|ppl|ugm> ? = { ,200},
%<blg> ? = {150,150},
%<pmn> " = {300,300},
-%<m-t|bch|cmr|pad|pmn|ppl> @ = {50,50},
+%<m-t|bch|cmr|ebg|pmn|ppl> @ = {50,50},
%<ptm> @ = {100,100},
-%<m-t|bch|blg|cmr|pad|pmn|ppl|ptm> ~ = {200,250},
+%<m-t|bch|blg|cmr|ebg|pmn|ppl|ptm> ~ = {200,250},
%<ugm> ~ = {300,350},
-%<pad|ppl|ptm> & = {50,100},
+%<ebg|ppl|ptm> & = {50,100},
%<ugm> & = { ,100},
-%<m-t|cmr|pad|pmn> \% = {50,50},
+%<m-t|cmr|ebg|pmn> \% = {50,50},
%<bch> \% = { ,50},
%<ppl|ptm> \% = {100,100},
%<ugm> \% = {50,100},
@@ -14017,14 +14101,14 @@ end
%<m-t|ppl|ptm|ugm> * = {200,200},
%<bch|pmn> * = {200,300},
%<blg> * = {150,200},
-%<cmr|pad> * = {300,300},
+%<cmr|ebg> * = {300,300},
%<m-t|cmr|ppl|ptm> + = {250,250},
%<bch> + = {150,250},
-%<pad> + = {300,300},
+%<ebg> + = {300,300},
%<blg|pmn> + = {150,200},
%<ugm> + = {250,300},
%<blg|ugm> {=}= {200,200},
-%<m-t|pad|pmn|ptm> ( = {100, }, ) = { ,200},
+%<m-t|ebg|pmn|ptm> ( = {100, }, ) = { ,200},
%<bch|ugm> ( = {200, }, ) = { ,200},
%<cmr|blg> ( = {300, }, ) = { ,300},
%<ppl> ( = {100, }, ) = { ,300},
@@ -14034,7 +14118,7 @@ end
%\changes{v1.7}{2005/03/15}{fix: remove \textbackslash\ from <OT1>,
% add \cmd\textbackslash\ to <T1> encoding}
% \begin{macrocode}
-%<m-t|pad|pmn|ptm> / = {100,200},
+%<m-t|ebg|pmn|ptm> / = {100,200},
%<bch> / = { ,200},
%<blg> / = {300,300},
%<cmr|ppl> / = {200,300},
@@ -14042,7 +14126,7 @@ end
%<m-t|ptm> - = {500,500},
%<bch|cmr|ppl> - = {400,500},
%<blg> - = {300,400},
-%<pad> - = {300,500},
+%<ebg> - = {300,500},
%<pmn> - = {200,400},
%<ugm> - = {500,600},
%<blg> < = {200,100}, > = {100,200},
@@ -14051,7 +14135,7 @@ end
%<m-t|pmn> \textendash = {200,200}, \textemdash = {150,150},
%<bch> \textendash = {200,300}, \textemdash = {150,250},
%<cmr> \textendash = {400,300}, \textemdash = {300,200},
-%<pad|ppl|ptm> \textendash = {300,300}, \textemdash = {200,200},
+%<ebg|ppl|ptm> \textendash = {300,300}, \textemdash = {200,200},
%<ugm> \textendash = {250,300}, \textemdash = {250,250},
% \end{macrocode}
% Why settings for left \emph{and} right quotes? Because in some languages they
@@ -14060,13 +14144,13 @@ end
%<m-t|bch|pmn> \textquoteleft = {300,400}, \textquoteright = {300,400},
%<blg> \textquoteleft = {400,600}, \textquoteright = {400,600},
%<cmr> \textquoteleft = {500,700}, \textquoteright = {500,600},
-%<pad|ppl> \textquoteleft = {500,700}, \textquoteright = {500,700},
+%<ebg|ppl> \textquoteleft = {500,700}, \textquoteright = {500,700},
%<ptm> \textquoteleft = {500,500}, \textquoteright = {300,500},
%<ugm> \textquoteleft = {300,600}, \textquoteright = {300,600},
%<m-t|bch|pmn> \textquotedblleft = {300,300}, \textquotedblright = {300,300}
%<blg> \textquotedblright = {300,400}
%<cmr> \textquotedblleft = {500,300}, \textquotedblright = {200,600}
-%<pad|ppl|ptm> \textquotedblleft = {300,400}, \textquotedblright = {300,400}
+%<ebg|ppl|ptm> \textquotedblleft = {300,400}, \textquotedblright = {300,400}
%<ugm> \textquotedblleft = {400,400}, \textquotedblright = {400,400}
}
@@ -14125,7 +14209,7 @@ end
%<bch> [ name = bch-T1,
%<blg> [ name = blg-T1,
%<cmr> [ name = cmr-T1,
-%<pad> [ name = pad-T1,
+%<ebg> [ name = EBGaramond-T1,
%<pmn> [ name = pmnj-T1,
%<ppl> [ name = ppl-T1,
%<ptm> [ name = ptm-T1,
@@ -14134,18 +14218,18 @@ end
%<bch> load = bch-default ]
%<blg> load = blg-default ]
%<cmr> load = cmr-default ]
-%<pad> load = pad-default ]
+%<ebg> load = EBGaramond-default ]
%<pmn> load = pmnj-default ]
%<ppl> load = ppl-default ]
%<ptm> load = ptm-default ]
%<ugm> load = ugm-default ]
%<m-t> { encoding = {T1,LY1,EU1,EU2,TU} }
-%<bch|cmr|pad|pmn|ppl> { encoding = {T1,LY1},
+%<bch|cmr|ebg|pmn|ppl> { encoding = {T1,LY1},
%<blg|ptm|ugm> { encoding = {T1},
%<bch> family = bch }
%<blg> family = blg }
%<cmr> family = cmr }
-%<pad> family = {pad,padx,padj} }
+%<ebg> family = {EBGaramond-LF,EBGaramond-TLF,EBGaramond-OsF,EBGaramond-TOsF} }
%<pmn> family = pmnj }
%<ppl> family = {ppl,pplx,pplj} }
%<ptm> family = {ptm,ptmx,ptmj} }
@@ -14161,10 +14245,10 @@ end
%<blg> 127 = {300,400},
%<blg> 156 = {100, }, % IJ
%<blg> 188 = { 80, 80}, % ij
-%<m-t|bch|pad|pmn|ppl|ptm> _ = {100,100},
+%<m-t|bch|ebg|pmn|ppl|ptm> _ = {100,100},
%<cmr> _ = {200,200},
%<ugm> _ = {100,200},
-%<m-t|pad|pmn|ptm> \textbackslash = {100,200},
+%<m-t|ebg|pmn|ptm> \textbackslash = {100,200},
%<bch> \textbackslash = {150,200},
%<blg> \textbackslash = {250,300},
%<cmr|ppl> \textbackslash = {200,300},
@@ -14179,24 +14263,24 @@ end
% The <EC> fonts do something weird: they insert an implicit kern between quote
% and boundary character. Therefore, we must override the settings from <OT1>.
% \begin{macrocode}
-%<m-t|cmr|pad|ppl|ptm|ugm> \quotesinglbase = {400,400}, \quotedblbase = {400,400},
+%<m-t|cmr|ebg|ppl|ptm|ugm> \quotesinglbase = {400,400}, \quotedblbase = {400,400},
%<blg> \quotesinglbase = {400,400}, \quotedblbase = {300,400},
%<bch|pmn> \quotesinglbase = {400,400}, \quotedblbase = {300,300},
%<m-t|bch|pmn> \guilsinglleft = {400,300}, \guilsinglright = {300,400},
%<blg> \guilsinglleft = {300,500}, \guilsinglright = {300,500},
-%<cmr|pad|ppl|ptm> \guilsinglleft = {400,400}, \guilsinglright = {300,500},
+%<cmr|ebg|ppl|ptm> \guilsinglleft = {400,400}, \guilsinglright = {300,500},
%<ugm> \guilsinglleft = {400,400}, \guilsinglright = {300,600},
%<m-t> \guillemotleft = {200,200}, \guillemotright = {200,200},
%<cmr> \guillemotleft = {300,200}, \guillemotright = {100,400},
%<bch|pmn> \guillemotleft = {200,200}, \guillemotright = {150,300},
-%<blg|pad|ppl|ptm> \guillemotleft = {300,300}, \guillemotright = {200,400},
+%<blg|ebg|ppl|ptm> \guillemotleft = {300,300}, \guillemotright = {200,400},
%<ugm> \guillemotleft = {300,400}, \guillemotright = {300,400},
-%<m-t|bch|cmr|pad|pmn|ppl|ugm> \textexclamdown = {100, }, \textquestiondown = {100, },
+%<m-t|bch|cmr|ebg|pmn|ppl|ugm> \textexclamdown = {100, }, \textquestiondown = {100, },
%<blg> \textexclamdown = {200, }, \textquestiondown = {100, },
%<ptm> \textexclamdown = {200, }, \textquestiondown = {200, },
-%<m-t|cmr|pad|ppl|ptm|ugm> \textbraceleft = {400,200}, \textbraceright = {200,400},
+%<m-t|cmr|ebg|ppl|ptm|ugm> \textbraceleft = {400,200}, \textbraceright = {200,400},
%<bch|blg|pmn> \textbraceleft = {200, }, \textbraceright = { ,300},
-%<m-t|bch|cmr|pad|ppl|ptm|ugm> \textless = {200,100}, \textgreater = {100,200}
+%<m-t|bch|cmr|ebg|ppl|ptm|ugm> \textless = {200,100}, \textgreater = {100,200}
%<pmn> \textless = {100, }, \textgreater = { ,100},
%<pmn> \textvisiblespace = {100,100} % not in LY1
% \end{macrocode}
@@ -14470,65 +14554,65 @@ end
%<blg> [ name = blg-it,
%<blg> load = blg-default ]
%<cmr> [ name = cmr-it ]
-%<pad> [ name = pad-it ]
+%<ebg> [ name = EBGaramond-it ]
%<pmn> [ name = pmnj-it ]
%<ppl> [ name = ppl-it ]
%<ptm> [ name = ptm-it ]
%<ugm> [ name = ugm-it ]
-%<m-t|bch|blg|pad|ugm> { encoding = OT1,
+%<m-t|bch|blg|ebg|ugm> { encoding = OT1,
%<ppl|ptm> { encoding = {OT1,OT4},
%<bch> family = bch,
%<blg> family = blg,
-%<pad> family = {pad,padx,padj},
+%<ebg> family = {EBGaramond-LF,EBGaramond-TLF,EBGaramond-OsF,EBGaramond-TOsF},
%<ppl> family = {ppl,pplx,pplj},
%<ptm> family = {ptm,ptmx,ptmj},
%<ugm> family = ugm,
-%<m-t|bch|pad|ppl|ptm> shape = {it,sl} }
+%<m-t|bch|ebg|ppl|ptm> shape = {it,sl} }
%<blg|ugm> shape = it }
%<cmr|pmn> { }
{
%<cmr> A = {100,100},
%<ptm> A = {100,50},
-%<pad|pmn> A = {50, },
+%<ebg|pmn> A = {50, },
%<ugm> A = { ,150},
%<ppl> A = {50,50},
%<ptm> \AE = {100, },
-%<pad|ppl> \AE = {50, },
+%<ebg|ppl> \AE = {50, },
%<cmr> B = {83,-40},
-%<pad|ppl|ptm> B = {50, },
+%<ebg|ppl|ptm> B = {50, },
%<pmn> B = {20,-50},
%<bch|ppl|ptm|ugm> C = {50, },
%<cmr> C = {165,-75},
-%<pad> C = {100, },
+%<ebg> C = {100, },
%<pmn> C = {50,-50},
%<cmr> D = {75, -28},
-%<pad|ppl|ptm> D = {50,50},
+%<ebg|ppl|ptm> D = {50,50},
%<pmn> D = {20, },
%<cmr> E = {80,-55},
-%<pad|ppl|ptm> E = {50, },
+%<ebg|ppl|ptm> E = {50, },
%<pmn> E = {20,-50},
%<cmr> F = {85,-80},
-%<pad|ptm> F = {100, },
+%<ebg|ptm> F = {100, },
%<pmn> F = {10, },
%<ppl> F = {50, },
%<bch|ppl|ptm|ugm> G = {50, },
%<cmr> G = {153,-15},
-%<pad> G = {100, },
+%<ebg> G = {100, },
%<pmn> G = {50,-50},
%<cmr> H = {73,-60},
-%<pad|ppl|ptm> H = {50, },
+%<ebg|ppl|ptm> H = {50, },
%<cmr> I = {140,-120},
-%<pad|ptm> I = {50, },
+%<ebg|ptm> I = {50, },
%<pmn> I = {20,-50},
%<cmr> J = {135,-80},
-%<pad> J = {50, },
+%<ebg> J = {50, },
%<pmn> J = {20, },
%<ptm> J = {100, },
%<cmr> K = {70,-30},
-%<pad|ppl|ptm> K = {50, },
+%<ebg|ppl|ptm> K = {50, },
%<pmn> K = {20, },
%<cmr> L = {87, 40},
-%<pad|ppl|ptm> L = {50, },
+%<ebg|ppl|ptm> L = {50, },
%<pmn> L = {20,50},
%<ugm> L = { ,100},
%<cmr> M = {67,-45},
@@ -14539,37 +14623,37 @@ end
%<ptm> N = {50, },
%<bch|pmn|ppl|ptm> O = {50, },
%<cmr> O = {150,-30},
-%<pad> O = {100, },
+%<ebg> O = {100, },
%<ugm> O = {70,50},
%<ppl|ptm> \OE = {50, },
-%<pad> \OE = {100, },
+%<ebg> \OE = {100, },
%<cmr> P = {82,-50},
-%<pad|ppl|ptm> P = {50, },
+%<ebg|ppl|ptm> P = {50, },
%<pmn> P = {20,-50},
%<bch|pmn|ppl|ptm> Q = {50, },
%<cmr> Q = {150,-30},
-%<pad> Q = {100, },
+%<ebg> Q = {100, },
%<ugm> Q = {70,50},
%<cmr> R = {75, 15},
-%<pad|ppl|ptm> R = {50, },
+%<ebg|ppl|ptm> R = {50, },
%<pmn> R = {20, },
-%<bch|pad|ppl|ptm> S = {50, },
+%<bch|ebg|ppl|ptm> S = {50, },
%<cmr> S = {90,-65},
%<pmn> S = {20,-30},
-%<bch|pad|ppl|ptm> $ = {50, },
+%<bch|ebg|ppl|ptm> $ = {50, },
%<cmr> $ = {100,-20},
%<pmn> $ = {20,-30},
%<bch|pmn|ugm> T = {70, },
%<cmr> T = {220,-85},
-%<pad|ppl|ptm> T = {100, },
+%<ebg|ppl|ptm> T = {100, },
%<cmr> U = {230,-55},
-%<pad|ppl|ptm> U = {50, },
+%<ebg|ppl|ptm> U = {50, },
%<pmn> U = {50,-50},
%<cmr> V = {260,-60},
-%<pad|pmn|ugm> V = {100, },
+%<ebg|pmn|ugm> V = {100, },
%<ppl|ptm> V = {100,50},
%<cmr> W = {185,-55},
-%<pad|pmn|ugm> W = {100, },
+%<ebg|pmn|ugm> W = {100, },
%<ppl> W = {50, },
%<ptm> W = {100,50},
%<cmr> X = {70,-30},
@@ -14587,7 +14671,7 @@ end
%<pmn> d = { ,-50},
%<cmr> e = {180, },
%<cmr> f = { ,-250},
-%<pad|pmn> f = { ,-100},
+%<ebg|pmn> f = { ,-100},
%<cmr> g = {150,-10},
%<cmr> h = {100, },
%<cmr> i = {210, },
@@ -14623,12 +14707,12 @@ end
%<cmr> 0 = {170,-85},
%<bch|ptm> 1 = {150,100},
%<cmr> 1 = {230,110},
-%<pad> 1 = {150, },
+%<ebg> 1 = {150, },
%<pmn> 1 = {50, },
%<ppl> 1 = {100, },
%<ugm> 1 = {150,150},
%<cmr> 2 = {130,-70},
-%<pad|ppl|ptm> 2 = {50, },
+%<ebg|ppl|ptm> 2 = {50, },
%<pmn> 2 = {-50, },
%<bch> 3 = {50, },
%<cmr> 3 = {140,-70},
@@ -14636,31 +14720,31 @@ end
%<ptm> 3 = {100,50},
%<bch> 4 = {100, },
%<cmr> 4 = {130,80},
-%<pad> 4 = {150, },
+%<ebg> 4 = {150, },
%<ppl|ptm> 4 = {50, },
%<cmr> 5 = {160, },
%<ptm> 5 = {50, },
%<bch> 6 = {50, },
%<cmr> 6 = {175,-30},
-%<bch|pad|ptm> 7 = {100, },
+%<bch|ebg|ptm> 7 = {100, },
%<cmr> 7 = {250,-150},
%<pmn> 7 = {20, },
%<ppl> 7 = {50, },
%<cmr> 8 = {130,-40},
%<cmr> 9 = {155,-80},
-%<m-t|cmr|pad|pmn|ppl> . = { ,500},
+%<m-t|cmr|ebg|pmn|ppl> . = { ,500},
%<blg> . = {400,600},
%<bch|ptm|ugm> . = { ,700},
%<blg> {,}= {300,500},
-%<m-t|pad|pmn|ppl> {,}= { ,500},
+%<m-t|ebg|pmn|ppl> {,}= { ,500},
%<cmr> {,}= { ,450},
%<bch|ugm> {,}= { ,600},
%<ptm> {,}= { ,700},
-%<m-t|cmr|pad|ppl> : = { ,300},
+%<m-t|cmr|ebg|ppl> : = { ,300},
%<bch|ugm> : = { ,400},
%<pmn> : = { ,200},
%<ptm> : = { ,500},
-%<m-t|cmr|pad|ppl> ; = { ,300},
+%<m-t|cmr|ebg|ppl> ; = { ,300},
%<bch|ugm> ; = { ,400},
%<pmn> ; = { ,200},
%<ptm> ; = { ,500},
@@ -14669,11 +14753,11 @@ end
%<ptm> ? = { ,100},
%<ppl> ? = { ,300},
%<pmn> " = {400,200},
-%<m-t|pad|pmn|ppl|ptm> & = {50,50},
+%<m-t|ebg|pmn|ppl|ptm> & = {50,50},
%<bch> & = { ,80},
%<cmr> & = {130,30},
%<ugm> & = {50,100},
-%<m-t|pad|pmn> \% = {100, },
+%<m-t|ebg|pmn> \% = {100, },
%<cmr> \% = {180,50},
%<bch> \% = {50,50},
%<ppl|ptm> \% = {100,100},
@@ -14681,27 +14765,27 @@ end
%<m-t|pmn|ppl> * = {200,200},
%<bch> * = {300,200},
%<cmr> * = {380,20},
-%<pad> * = {500,100},
+%<ebg> * = {500,100},
%<ptm|ugm> * = {400,200},
%<m-t|pmn|ppl> + = {150,200},
%<cmr> + = {180,200},
%<bch|ugm> + = {250,250},
-%<pad|ptm> + = {250,200},
-%<m-t|pad|pmn|ppl> @ = {50,50},
+%<ebg|ptm> + = {250,200},
+%<m-t|ebg|pmn|ppl> @ = {50,50},
%<bch> @ = {80,50},
%<cmr> @ = {180,10},
%<ptm> @ = {150,150},
%<m-t|bch|ugm> ~ = {150,150},
-%<cmr|pad|pmn|ppl|ptm> ~ = {200,150},
+%<cmr|ebg|pmn|ppl|ptm> ~ = {200,150},
%<ugm> {=}= {200,200},
-%<m-t|bch|pad|pmn|ppl|ptm|ugm> ( = {200, }, ) = { ,200},
+%<m-t|bch|ebg|pmn|ppl|ptm|ugm> ( = {200, }, ) = { ,200},
%<cmr> ( = {300, }, ) = { ,70},
-%<m-t|pad|ppl|ptm|ugm> / = {100,200},
+%<m-t|ebg|ppl|ptm|ugm> / = {100,200},
%<cmr> / = {100,100},
%<bch> / = { ,150},
%<pmn> / = {100,150},
%<m-t> - = {300,300},
-%<bch|pad> - = {300,400},
+%<bch|ebg> - = {300,400},
%<pmn> - = {200,300},
%<cmr> - = {500,300},
%<ppl> - = {300,500},
@@ -14711,17 +14795,17 @@ end
%<m-t|pmn> \textendash = {200,200}, \textemdash = {150,150},
%<bch> \textendash = {200,300}, \textemdash = {150,200},
%<cmr> \textendash = {500,300}, \textemdash = {400,170},
-%<pad|ppl|ptm|ugm> \textendash = {300,300}, \textemdash = {200,200},
+%<ebg|ppl|ptm|ugm> \textendash = {300,300}, \textemdash = {200,200},
%<m-t|bch|pmn|ugm> \textquoteleft = {400,200}, \textquoteright = {400,200},
%<blg> \textquoteleft = {400,400}, \textquoteright = {400,400},
%<cmr> \textquoteleft = {800,200}, \textquoteright = {800,-20},
-%<pad> \textquoteleft = {800,200}, \textquoteright = {800,200},
+%<ebg> \textquoteleft = {800,200}, \textquoteright = {800,200},
%<ppl> \textquoteleft = {700,400}, \textquoteright = {700,400},
%<ptm> \textquoteleft = {800,500}, \textquoteright = {800,500},
%<m-t|bch|pmn> \textquotedblleft = {400,200}, \textquotedblright = {400,200}
%<blg> \textquotedblright = {300,300}
%<cmr> \textquotedblleft = {540,100}, \textquotedblright = {500,100}
-%<pad> \textquotedblleft = {700,200}, \textquotedblright = {700,200}
+%<ebg> \textquotedblleft = {700,200}, \textquotedblright = {700,200}
%<ppl> \textquotedblleft = {500,300}, \textquotedblright = {500,300}
%<ptm> \textquotedblleft = {700,400}, \textquotedblright = {700,400}
%<ugm> \textquotedblleft = {600,200}, \textquotedblright = {600,200}
@@ -14765,7 +14849,7 @@ end
%<bch> [ name = bch-it-T1,
%<blg> [ name = blg-it-T1,
%<cmr> [ name = cmr-it-T1,
-%<pad> [ name = pad-it-T1,
+%<ebg> [ name = EBGaramond-it-T1,
%<pmn> [ name = pmnj-it-T1,
%<ppl> [ name = ppl-it-T1,
%<ptm> [ name = ptm-it-T1,
@@ -14775,27 +14859,27 @@ end
%<blg> load = blg-T1 ]
%<cmr> load = cmr-it ]
%<pmn> load = pmnj-it ]
-%<pad> load = pad-it ]
+%<ebg> load = EBGaramond-it ]
%<ppl> load = ppl-it ]
%<ptm> load = ptm-it ]
%<ugm> load = ugm-it ]
-%<m-t|bch|cmr|pad|pmn|ppl> { encoding = {T1,LY1},
+%<m-t|bch|cmr|ebg|pmn|ppl> { encoding = {T1,LY1},
%<blg|ptm|ugm> { encoding = T1,
%<bch> family = bch,
%<blg> family = blg,
%<cmr> family = cmr,
%<pmn> family = pmnj,
-%<pad> family = {pad,padx,padj},
+%<ebg> family = {EBGaramond-LF,EBGaramond-TLF,EBGaramond-OsF,EBGaramond-TOsF},
%<ppl> family = {ppl,pplx,pplj},
%<ptm> family = {ptm,ptmx,ptmj},
%<ugm> family = ugm,
-%<m-t|bch|pad|pmn|ppl|ptm> shape = {it,sl} }
+%<m-t|bch|ebg|pmn|ppl|ptm> shape = {it,sl} }
%<blg|cmr|ugm> shape = it }
{
%<m-t|bch|pmn> _ = { ,100},
%<blg> _ = {0,300},
%<cmr|ugm> _ = {100,200},
-%<pad|ppl|ptm> _ = {100,100},
+%<ebg|ppl|ptm> _ = {100,100},
%<blg> . = {400,600},
%<blg> {,}= {300,500},
%<cmr> \AE = {100, },
@@ -14804,11 +14888,11 @@ end
%<cmr> \OE = {100, },
%<pmn> 031 = { ,-100}, % ffl
%<cmr|ptm> 156 = {100, }, % IJ
-%<pad> 156 = {50, }, % IJ
+%<ebg> 156 = {50, }, % IJ
%<pmn> 156 = {20, }, % IJ
%<pmn> 188 = { ,-30}, % ij
%<pmn> \v t = { ,100},
-%<m-t|pad|ppl|ptm> \textbackslash = {100,200},
+%<m-t|ebg|ppl|ptm> \textbackslash = {100,200},
%<cmr|ugm> \textbackslash = {300,300},
%<bch> \textbackslash = {150,150},
%<pmn> \textbackslash = {100,150},
@@ -14820,27 +14904,27 @@ end
%<m-t|ptm> \quotesinglbase = {300,700}, \quotedblbase = {400,500},
%<cmr> \quotesinglbase = {300,700}, \quotedblbase = {200,600},
%<bch|pmn> \quotesinglbase = {200,500}, \quotedblbase = {150,500},
-%<pad|ppl> \quotesinglbase = {500,500}, \quotedblbase = {400,400},
+%<ebg|ppl> \quotesinglbase = {500,500}, \quotedblbase = {400,400},
%<ugm> \quotesinglbase = {300,700}, \quotedblbase = {300,500},
%<m-t|ppl|ptm> \guilsinglleft = {400,400}, \guilsinglright = {300,500},
%<bch|pmn> \guilsinglleft = {300,400}, \guilsinglright = {200,500},
%<cmr> \guilsinglleft = {500,300}, \guilsinglright = {400,400},
-%<pad> \guilsinglleft = {500,400}, \guilsinglright = {300,500},
+%<ebg> \guilsinglleft = {500,400}, \guilsinglright = {300,500},
%<ugm> \guilsinglleft = {400,400}, \guilsinglright = {300,600},
%<m-t|ppl> \guillemotleft = {300,300}, \guillemotright = {300,300},
%<bch|pmn> \guillemotleft = {200,300}, \guillemotright = {150,400},
%<cmr> \guillemotleft = {400,100}, \guillemotright = {200,300},
-%<pad> \guillemotleft = {300,300}, \guillemotright = {200,400},
+%<ebg> \guillemotleft = {300,300}, \guillemotright = {200,400},
%<ptm> \guillemotleft = {300,400}, \guillemotright = {200,400},
%<ugm> \guillemotleft = {300,400}, \guillemotright = {300,400},
-%<m-t|pad|ppl|ugm> \textexclamdown = {100, }, \textquestiondown = {200, },
+%<m-t|ebg|ppl|ugm> \textexclamdown = {100, }, \textquestiondown = {200, },
%<cmr|ptm> \textexclamdown = {200, }, \textquestiondown = {200, },
%<pmn> \textexclamdown = {-50, }, \textquestiondown = {-50, },
%<m-t|ppl|ugm> \textbraceleft = {200,100}, \textbraceright = {200,200},
%<bch|pmn> \textbraceleft = {200, }, \textbraceright = { ,200},
-%<cmr|pad|ptm> \textbraceleft = {400,100}, \textbraceright = {200,200},
+%<cmr|ebg|ptm> \textbraceleft = {400,100}, \textbraceright = {200,200},
%<bch|pmn> \textless = {100, }, \textgreater = { ,100},
-%<cmr|pad|ppl|ptm> \textless = {300,100}, \textgreater = {200,100}
+%<cmr|ebg|ppl|ptm> \textless = {300,100}, \textgreater = {200,100}
%<pmn> \textvisiblespace = {100,100}
}
@@ -15160,47 +15244,47 @@ end
%<m-t> [ name = OT1-sc,
%<bch> [ name = bch-sc,
%<cmr> [ name = cmr-sc-OT1,
-%<pad> [ name = pad-sc,
+%<ebg> [ name = EBGaramond-sc,
%<pmn> [ name = pmnj-sc,
%<ppl> [ name = ppl-sc,
%<ptm> [ name = ptm-sc,
%<m-t> load = default ]
%<bch> load = bch-default ]
%<cmr> load = cmr-OT1 ]
-%<pad> load = pad-default ]
+%<ebg> load = EBGaramond-default ]
%<pmn> load = pmnj-default ]
%<ppl> load = ppl-default ]
%<ptm> load = ptm-default ]
-%<m-t|bch|pad|pmn> { encoding = OT1,
+%<m-t|bch|ebg|pmn> { encoding = OT1,
%<cmr|ppl|ptm> { encoding = {OT1,OT4},
%<bch> family = bch,
%<cmr> family = cmr,
-%<pad> family = {pad,padx,padj},
+%<ebg> family = {EBGaramond-LF,EBGaramond-TLF,EBGaramond-OsF,EBGaramond-TOsF},
%<pmn> family = pmnj,
%<ppl> family = {ppl,pplx,pplj},
%<ptm> family = {ptm,ptmx,ptmj},
shape = sc }
{
a = {50,50},
-%<cmr|pad|ppl|ptm> \ae = {50, },
+%<cmr|ebg|ppl|ptm> \ae = {50, },
%<bch|pmn> c = {50, },
-%<bch|pad|pmn> d = { ,50},
-%<m-t|bch|cmr|pad|pmn|ptm> f = { ,50},
-%<bch|pad|pmn> g = {50, },
-%<m-t|cmr|pad|pmn|ppl|ptm> j = {50, },
+%<bch|ebg|pmn> d = { ,50},
+%<m-t|bch|cmr|ebg|pmn|ptm> f = { ,50},
+%<bch|ebg|pmn> g = {50, },
+%<m-t|cmr|ebg|pmn|ppl|ptm> j = {50, },
%<bch> j = {100, },
-%<m-t|bch|cmr|pad|pmn|ppl> l = { ,50},
+%<m-t|bch|cmr|ebg|pmn|ppl> l = { ,50},
%<ptm> l = { ,80},
-%<m-t|bch|cmr|pad|pmn|ppl> 013 = { ,50}, % fl
+%<m-t|bch|cmr|ebg|pmn|ppl> 013 = { ,50}, % fl
%<ptm> 013 = { ,80}, % fl
-%<bch|pad|pmn> o = {50,50},
-%<pad|pmn> \oe = {50, },
+%<bch|ebg|pmn> o = {50,50},
+%<ebg|pmn> \oe = {50, },
%<ppl> p = { 0, 0},
-%<bch|pad|pmn> q = {50,70},
+%<bch|ebg|pmn> q = {50,70},
%<ppl> q = { 0, },
-%<m-t|cmr|pad|pmn|ppl|ptm> r = { , 0},
+%<m-t|cmr|ebg|pmn|ppl|ptm> r = { , 0},
t = {50,50},
-%<m-t|bch|cmr|pad|pmn|ppl> y = {50,50}
+%<m-t|bch|cmr|ebg|pmn|ppl> y = {50,50}
%<ptm> y = {80,80}
}
@@ -15208,46 +15292,46 @@ end
%<m-t> [ name = T1-sc,
%<bch> [ name = bch-sc-T1,
%<cmr> [ name = cmr-sc-T1,
-%<pad> [ name = pad-sc-T1,
+%<ebg> [ name = EBGaramond-sc-T1,
%<pmn> [ name = pmnj-sc-T1,
%<ppl> [ name = ppl-sc-T1,
%<ptm> [ name = ptm-sc-T1,
%<m-t> load = T1-default ]
%<bch> load = bch-T1 ]
%<cmr> load = cmr-T1 ]
-%<pad> load = pad-T1 ]
+%<ebg> load = EBGaramond-T1 ]
%<pmn> load = pmnj-T1 ]
%<ppl> load = ppl-T1 ]
%<ptm> load = ptm-T1 ]
{ encoding = {T1,LY1},
%<bch> family = bch,
%<cmr> family = cmr,
-%<pad> family = {pad,padx,padj},
+%<ebg> family = {EBGaramond-LF,EBGaramond-TLF,EBGaramond-OsF,EBGaramond-TOsF},
%<pmn> family = pmnj,
%<ppl> family = {ppl,pplx,pplj},
%<ptm> family = {ptm,ptmx,ptmj},
shape = sc }
{
a = {50,50},
-%<cmr|pad|ppl|ptm> \ae = {50, },
+%<cmr|ebg|ppl|ptm> \ae = {50, },
%<bch|pmn> c = {50, },
-%<bch|pad|pmn> d = { ,50},
-%<m-t|bch|cmr|pad|pmn|ptm> f = { ,50},
-%<bch|pad|pmn> g = {50, },
-%<m-t|cmr|pad|pmn|ppl|ptm> j = {50, },
+%<bch|ebg|pmn> d = { ,50},
+%<m-t|bch|cmr|ebg|pmn|ptm> f = { ,50},
+%<bch|ebg|pmn> g = {50, },
+%<m-t|cmr|ebg|pmn|ppl|ptm> j = {50, },
%<bch> j = {100, },
-%<m-t|bch|cmr|pad|pmn|ppl> l = { ,50},
+%<m-t|bch|cmr|ebg|pmn|ppl> l = { ,50},
%<ptm> l = { ,80},
-%<m-t|bch|cmr|pad|pmn|ppl> 029 = { ,50}, % fl
+%<m-t|bch|cmr|ebg|pmn|ppl> 029 = { ,50}, % fl
%<ptm> 029 = { ,80}, % fl
-%<bch|pad|pmn> o = {50,50},
-%<bch|pad|pmn> \oe = {50, },
+%<bch|ebg|pmn> o = {50,50},
+%<bch|ebg|pmn> \oe = {50, },
%<ppl> p = { 0, 0},
-%<bch|pad|pmn> q = {50,70},
+%<bch|ebg|pmn> q = {50,70},
%<ppl> q = { 0, },
-%<m-t|cmr|pad|pmn|ppl|ptm> r = { , 0},
+%<m-t|cmr|ebg|pmn|ppl|ptm> r = { , 0},
t = {50,50},
-%<m-t|bch|cmr|pad|pmn|ppl> y = {50,50}
+%<m-t|bch|cmr|ebg|pmn|ppl> y = {50,50}
%<ptm> y = {80,80}
}
@@ -15456,7 +15540,7 @@ end
%<bch> [ name = bch-textcomp ]
%<blg> [ name = blg-textcomp ]
%<cmr> [ name = cmr-textcomp ]
-%<pad> [ name = pad-textcomp ]
+%<ebg> [ name = EBGaramond-textcomp ]
%<pmn> [ name = pmn-textcomp ]
%<ppl> [ name = ppl-textcomp ]
%<ptm> [ name = ptm-textcomp ]
@@ -15466,7 +15550,7 @@ end
%<bch> family = bch }
%<blg> family = blg }
%<cmr> family = cmr }
-%<pad> family = {pad,padx,padj} }
+%<ebg> family = {EBGaramond-LF,EBGaramond-TLF,EBGaramond-OsF,EBGaramond-TOsF} }
%<pmn> family = {pmnx,pmnj} }
%<ppl> family = {ppl,pplx,pplj} }
%<ptm> family = {ptm,ptmx,ptmj} }
@@ -15474,71 +15558,71 @@ end
{
%<blg> \textquotestraightbase = {400,500},
%<cmr> \textquotestraightbase = {300,300},
-%<pad|pmn> \textquotestraightbase = {400,400},
+%<ebg|pmn> \textquotestraightbase = {400,400},
%<blg> \textquotestraightdblbase = {300,400},
%<cmr|pmn> \textquotestraightdblbase = {300,300},
-%<pad> \textquotestraightdblbase = {400,400},
-%<bch|cmr|pad|pmn|ugm> \texttwelveudash = {200,200},
-%<bch|cmr|pad|pmn> \textthreequartersemdash = {150,150},
+%<ebg> \textquotestraightdblbase = {400,400},
+%<bch|cmr|ebg|pmn|ugm> \texttwelveudash = {200,200},
+%<bch|cmr|ebg|pmn> \textthreequartersemdash = {150,150},
%<ugm> \textthreequartersemdash = {200,200},
%<blg> \textquotesingle = {500,600},
%<cmr|pmn> \textquotesingle = {300,400},
-%<pad> \textquotesingle = {400,500},
+%<ebg> \textquotesingle = {400,500},
%<ptm> \textquotesingle = {500,500},
%<ugm> \textquotesingle = {300,500},
%<bch|cmr|pmn> \textasteriskcentered = {200,300},
%<blg> \textasteriskcentered = {150,200},
-%<pad> \textasteriskcentered = {300,300},
+%<ebg> \textasteriskcentered = {300,300},
%<ugm> \textasteriskcentered = {100,200},
%<pmn> \textfractionsolidus = {-200,-200},
%<cmr> \textoneoldstyle = {100,100},
%<pmn> \textoneoldstyle = { , 50},
%<cmr> \textthreeoldstyle = { , 50},
-%<pad|pmn> \textthreeoldstyle = { 50, },
+%<ebg|pmn> \textthreeoldstyle = { 50, },
%<cmr> \textfouroldstyle = { 50, 50},
-%<pad|pmn> \textfouroldstyle = { 50, },
-%<cmr|pad|pmn> \textsevenoldstyle = { 50, 80},
+%<ebg|pmn> \textfouroldstyle = { 50, },
+%<cmr|ebg|pmn> \textsevenoldstyle = { 50, 80},
%<cmr> \textlangle = {400, },
%<cmr> \textrangle = { ,400},
%<m-t|bch|pmn|ptm> \textminus = {200,200},
-%<cmr|pad|ppl> \textminus = {300,300},
+%<cmr|ebg|ppl> \textminus = {300,300},
%<blg|ugm> \textminus = {250,300},
-%<bch|pad|pmn> \textlbrackdbl = {100, },
+%<bch|ebg|pmn> \textlbrackdbl = {100, },
%<blg> \textlbrackdbl = {200, },
-%<bch|pad|pmn> \textrbrackdbl = { ,100},
+%<bch|ebg|pmn> \textrbrackdbl = { ,100},
%<blg> \textrbrackdbl = { ,200},
%<pmn> \textasciigrave = {200,500},
-%<bch|blg|cmr|pad|pmn> \texttildelow = {200,250},
+%<bch|blg|cmr|ebg|pmn> \texttildelow = {200,250},
%<pmn> \textasciibreve = {300,400},
%<pmn> \textasciicaron = {300,400},
%<pmn> \textacutedbl = {200,300},
%<pmn> \textgravedbl = {150,300},
%<bch|pmn|ugm> \textdagger = { 80, 80},
%<blg> \textdagger = {200,200},
-%<cmr|pad> \textdagger = {100,100},
+%<cmr|ebg> \textdagger = {100,100},
%<ptm> \textdagger = {150,150},
%<blg> \textdaggerdbl = {150,150},
-%<cmr|pad|pmn> \textdaggerdbl = { 80, 80},
+%<cmr|ebg|pmn> \textdaggerdbl = { 80, 80},
%<ptm> \textdaggerdbl = {100,100},
%<bch> \textbardbl = {100,100},
%<blg|ugm> \textbardbl = {150,150},
%<bch> \textbullet = {200,200},
%<blg> \textbullet = {400,500},
-%<cmr|pad|pmn> \textbullet = { ,100},
+%<cmr|ebg|pmn> \textbullet = { ,100},
%<ptm> \textbullet = {150,150},
%<ugm> \textbullet = { 50,100},
%<bch|cmr|pmn> \textcelsius = { 50, },
-%<pad> \textcelsius = { 80, },
+%<ebg> \textcelsius = { 80, },
%<bch> \textflorin = { 50, 50},
%<blg> \textflorin = {100,100},
-%<pad|ugm> \textflorin = { ,100},
+%<ebg|ugm> \textflorin = { ,100},
%<pmn> \textflorin = { 50,100},
%<ptm> \textflorin = { 50, 70},
%<cmr> \textcolonmonetary = { , 50},
-%<pad|pmn> \textcolonmonetary = { 50, },
+%<ebg|pmn> \textcolonmonetary = { 50, },
%<pmn> \textinterrobang = { ,100},
%<pmn> \textinterrobangdown = {100, },
-%<m-t|pad|ptm> \texttrademark = {100,100},
+%<m-t|ebg|ptm> \texttrademark = {100,100},
%<bch> \texttrademark = {150,150},
%<blg|cmr|ppl> \texttrademark = {200,200},
%<pmn> \texttrademark = { 50, 50},
@@ -15551,54 +15635,54 @@ end
%<blg> \textbrokenbar = {250,250},
%<ugm> \textbrokenbar = {200,300},
%<pmn> \textasciidieresis = {300,400},
-%<m-t|bch|cmr|pad|ptm|ugm> \textcopyright = {100,100},
+%<m-t|bch|cmr|ebg|ptm|ugm> \textcopyright = {100,100},
%<pmn> \textcopyright = {100,150},
%<ppl> \textcopyright = {200,200},
%<bch|cmr|ugm> \textordfeminine = {100,200},
-%<pad|pmn> \textordfeminine = {200,200},
-%<bch|cmr|pad|pmn|ugm> \textlnot = {200, },
+%<ebg|pmn> \textordfeminine = {200,200},
+%<bch|cmr|ebg|pmn|ugm> \textlnot = {200, },
%<blg> \textlnot = {200,100},
-%<m-t|bch|cmr|pad|ptm|ugm> \textregistered = {100,100},
+%<m-t|bch|cmr|ebg|ptm|ugm> \textregistered = {100,100},
%<pmn> \textregistered = { 50,150},
%<ppl> \textregistered = {200,200},
%<pmn> \textasciimacron = {150,200},
%<m-t|ppl|ptm> \textdegree = {300,300},
%<bch> \textdegree = {150,200},
%<blg|ugm> \textdegree = {200,200},
-%<cmr|pad> \textdegree = {400,400},
+%<cmr|ebg> \textdegree = {400,400},
%<pmn> \textdegree = {150,400},
-%<bch|cmr|pad|pmn|ugm> \textpm = {150,200},
+%<bch|cmr|ebg|pmn|ugm> \textpm = {150,200},
%<blg> \textpm = {100,100},
%<ptm> \textpm = { 50, 80},
%<bch|blg|ugm> \texttwosuperior = {100,200},
%<cmr> \texttwosuperior = { 50,100},
-%<pad|pmn> \texttwosuperior = {200,200},
+%<ebg|pmn> \texttwosuperior = {200,200},
%<ptm> \texttwosuperior = { 50, 50},
%<bch|blg|ugm> \textthreesuperior = {100,200},
%<cmr> \textthreesuperior = { 50,100},
-%<pad|pmn> \textthreesuperior = {200,200},
+%<ebg|pmn> \textthreesuperior = {200,200},
%<ptm> \textthreesuperior = { 50, 50},
%<pmn> \textasciiacute = {300,400},
%<bch|ugm> \textmu = { ,100},
-%<bch|pad|pmn> \textparagraph = { ,100},
-%<bch|cmr|pad|pmn> \textperiodcentered = {300,400},
+%<bch|ebg|pmn> \textparagraph = { ,100},
+%<bch|cmr|ebg|pmn> \textperiodcentered = {300,400},
%<blg> \textperiodcentered = {400,500},
%<ptm> \textperiodcentered = {300,300},
%<ugm> \textperiodcentered = {200,500},
%<bch|blg|ugm> \textonesuperior = {200,300},
-%<cmr|pad|pmn> \textonesuperior = {200,200},
+%<cmr|ebg|pmn> \textonesuperior = {200,200},
%<ptm> \textonesuperior = {100,100},
-%<bch|pad|pmn|ugm> \textordmasculine = {200,200},
+%<bch|ebg|pmn|ugm> \textordmasculine = {200,200},
%<blg|cmr> \textordmasculine = {100,200},
%<bch|cmr|pmn> \texteuro = {100, },
-%<pad> \texteuro = { 50,100},
+%<ebg> \texteuro = { 50,100},
%<bch> \texttimes = {200,200},
%<blg|ptm> \texttimes = {100,100},
%<cmr> \texttimes = {150,250},
-%<pad> \texttimes = {100,150},
+%<ebg> \texttimes = {100,150},
%<pmn> \texttimes = { 70,100},
%<ugm> \texttimes = {200,300},
-%<bch|pad|pmn> \textdiv = {150,200}
+%<bch|ebg|pmn> \textdiv = {150,200}
%<blg> \textdiv = {100,100}
%<cmr> \textdiv = {150,250}
%<ptm> \textdiv = { 50,100},
@@ -15661,83 +15745,83 @@ end
% \begin{macrocode}
}
-%<*cmr|pad|pmn|ugm>
+%<*cmr|ebg|pmn|ugm>
\SetProtrusion
%<cmr> [ name = cmr-textcomp-it ]
-%<pad> [ name = pad-textcomp-it ]
+%<ebg> [ name = EBGaramond-textcomp-it ]
%<pmn> [ name = pmn-textcomp-it ]
%<ugm> [ name = ugm-textcomp-it ]
{ encoding = TS1,
%<cmr> family = cmr,
-%<pad> family = {pad,padx,padj},
+%<ebg> family = {EBGaramond-LF,EBGaramond-TLF,EBGaramond-OsF,EBGaramond-TOsF},
%<pmn> family = {pmnx,pmnj},
%<ugm> family = ugm,
%<!ugm> shape = {it,sl} }
%<ugm> shape = it }
{
%<cmr> \textquotestraightbase = {300,600},
-%<pad|pmn> \textquotestraightbase = {400,400},
+%<ebg|pmn> \textquotestraightbase = {400,400},
%<cmr> \textquotestraightdblbase = {300,600},
-%<pad> \textquotestraightdblbase = {300,400},
+%<ebg> \textquotestraightdblbase = {300,400},
%<pmn> \textquotestraightdblbase = {300,300},
\texttwelveudash = {200,200},
-%<cmr|pad|pmn> \textthreequartersemdash = {150,150},
+%<cmr|ebg|pmn> \textthreequartersemdash = {150,150},
%<ugm> \textthreequartersemdash = {200,200},
%<cmr> \textquotesingle = {600,300},
-%<pad> \textquotesingle = {800,100},
+%<ebg> \textquotesingle = {800,100},
%<pmn> \textquotesingle = {300,200},
%<ugm> \textquotesingle = {500,500},
%<cmr> \textasteriskcentered = {300,200},
-%<pad> \textasteriskcentered = {500,100},
+%<ebg> \textasteriskcentered = {500,100},
%<pmn> \textasteriskcentered = {200,300},
%<ugm> \textasteriskcentered = {300,150},
%<pmn> \textfractionsolidus = {-200,-200},
%<cmr> \textoneoldstyle = {100, 50},
-%<pad> \textoneoldstyle = {100, },
+%<ebg> \textoneoldstyle = {100, },
%<pmn> \textoneoldstyle = { 50, },
-%<pad> \texttwooldstyle = { 50, },
+%<ebg> \texttwooldstyle = { 50, },
%<pmn> \texttwooldstyle = {-50, },
%<cmr> \textthreeoldstyle = {100, 50},
%<pmn> \textthreeoldstyle = {-100, },
%<cmr> \textfouroldstyle = { 50, 50},
-%<pad> \textfouroldstyle = { 50,100},
+%<ebg> \textfouroldstyle = { 50,100},
%<cmr> \textsevenoldstyle = { 50, 80},
-%<pad> \textsevenoldstyle = { 50, },
+%<ebg> \textsevenoldstyle = { 50, },
%<pmn> \textsevenoldstyle = { 20, },
%<cmr> \textlangle = {400, },
%<cmr> \textrangle = { ,400},
-%<cmr|pad> \textminus = {300,300},
+%<cmr|ebg> \textminus = {300,300},
%<pmn> \textminus = {200,200},
%<ugm> \textminus = {250,300},
-%<pad|pmn> \textlbrackdbl = {100, },
-%<pad|pmn> \textrbrackdbl = { ,100},
+%<ebg|pmn> \textlbrackdbl = {100, },
+%<ebg|pmn> \textrbrackdbl = { ,100},
%<pmn> \textasciigrave = {300,300},
-%<cmr|pad|pmn> \texttildelow = {200,250},
+%<cmr|ebg|pmn> \texttildelow = {200,250},
%<pmn> \textasciibreve = {300,300},
%<pmn> \textasciicaron = {300,300},
%<pmn> \textacutedbl = {200,300},
%<pmn> \textgravedbl = {150,300},
%<cmr> \textdagger = {100,100},
-%<pad> \textdagger = {200,100},
+%<ebg> \textdagger = {200,100},
%<pmn> \textdagger = { 80, 50},
%<ugm> \textdagger = { 80, 80},
-%<cmr|pad> \textdaggerdbl = { 80, 80},
+%<cmr|ebg> \textdaggerdbl = { 80, 80},
%<pmn> \textdaggerdbl = { 80, 50},
%<ugm> \textbardbl = {150,150},
%<cmr> \textbullet = {200,100},
-%<pad> \textbullet = {300, },
+%<ebg> \textbullet = {300, },
%<pmn> \textbullet = { 30, 70},
%<ugm> \textbullet = { 50,100},
%<cmr> \textcelsius = {100, },
-%<pad> \textcelsius = {200, },
+%<ebg> \textcelsius = {200, },
%<pmn> \textcelsius = { 50,-50},
-%<pad> \textflorin = {100, },
+%<ebg> \textflorin = {100, },
%<pmn> \textflorin = { 50,100},
%<ugm> \textflorin = { ,100},
%<cmr> \textcolonmonetary = {150, },
-%<pad> \textcolonmonetary = {100, },
+%<ebg> \textcolonmonetary = {100, },
%<pmn> \textcolonmonetary = { 50,-50},
-%<cmr|pad> \texttrademark = {200, },
+%<cmr|ebg> \texttrademark = {200, },
%<pmn> \texttrademark = { 50,100},
%<ugm> \texttrademark = {150, 50},
%<ugm> \textcent = { 50, },
@@ -15745,35 +15829,35 @@ end
%<ugm> \textbrokenbar = {200,300},
%<pmn> \textasciidieresis = {300,200},
%<cmr> \textcopyright = {100, },
-%<pad> \textcopyright = {200,100},
+%<ebg> \textcopyright = {200,100},
%<pmn> \textcopyright = {100,150},
%<ugm> \textcopyright = {300, },
%<cmr> \textordfeminine = {100,100},
%<pmn> \textordfeminine = {200,200},
%<ugm> \textordfeminine = {100,200},
-%<cmr|pad> \textlnot = {300, },
+%<cmr|ebg> \textlnot = {300, },
%<pmn|ugm> \textlnot = {200, },
%<cmr> \textregistered = {100, },
-%<pad> \textregistered = {200,100},
+%<ebg> \textregistered = {200,100},
%<pmn> \textregistered = { 50,150},
%<ugm> \textregistered = {300, },
%<pmn> \textasciimacron = {150,200},
-%<cmr|pad> \textdegree = {500,100},
+%<cmr|ebg> \textdegree = {500,100},
%<pmn> \textdegree = {150,150},
%<ugm> \textdegree = {300,200},
%<cmr> \textpm = {150,100},
-%<pad> \textpm = {200,150},
+%<ebg> \textpm = {200,150},
%<pmn|ugm> \textpm = {150,200},
%<cmr> \textonesuperior = {400, },
-%<pad> \textonesuperior = {300,100},
+%<ebg> \textonesuperior = {300,100},
%<pmn> \textonesuperior = {200,100},
%<ugm> \textonesuperior = {300,300},
%<cmr> \texttwosuperior = {400, },
-%<pad> \texttwosuperior = {300, },
+%<ebg> \texttwosuperior = {300, },
%<pmn> \texttwosuperior = {200,100},
%<ugm> \texttwosuperior = {300,200},
%<cmr> \textthreesuperior = {400, },
-%<pad> \textthreesuperior = {300, },
+%<ebg> \textthreesuperior = {300, },
%<pmn> \textthreesuperior = {200,100},
%<ugm> \textthreesuperior = {300,200},
%<ugm> \textmu = { ,100},
@@ -15781,18 +15865,18 @@ end
%<cmr> \textparagraph = {200, },
%<pmn> \textparagraph = { ,100},
%<cmr> \textperiodcentered = {500,500},
-%<pad|pmn|ugm> \textperiodcentered = {300,400},
+%<ebg|pmn|ugm> \textperiodcentered = {300,400},
%<cmr> \textordmasculine = {100,100},
%<pmn> \textordmasculine = {200,200},
%<ugm> \textordmasculine = {300,200},
%<cmr> \texteuro = {200, },
-%<pad> \texteuro = {100, },
+%<ebg> \texteuro = {100, },
%<pmn> \texteuro = {100,-50},
%<cmr> \texttimes = {200,200},
-%<pad> \texttimes = {200,100},
+%<ebg> \texttimes = {200,100},
%<pmn> \texttimes = { 70,100},
%<ugm> \texttimes = {200,300},
-%<cmr|pad> \textdiv = {200,200}
+%<cmr|ebg> \textdiv = {200,200}
%<pmn> \textdiv = {150,200}
%<ugm> \textdiv = {200,300},
%<ugm> \textsection = { ,200},
@@ -15802,7 +15886,7 @@ end
%<ugm> \textsurd = { ,100}
}
-%</cmr|pad|pmn|ugm>
+%</cmr|ebg|pmn|ugm>
% \end{macrocode}
%
%\subsubsection{Computer Modern math}
@@ -16698,34 +16782,34 @@ end
% \pkg{europs}), <ITC> Euro fonts (package \pkg{euroitc}) and \pkg{marvosym}\footnote{
% Of course, there are many more symbols in this font. Feel free to contribute
% protrusion settings!}).
+% The \pkg{euroitc} settings are hidden in the package itself (\ref{ssub:permutation})
+% for `free software' compliance reasons.
+% (Not quite sure whether this is what Karl really had in mind~\dots)
+%\changes{v2.8a}{2021/02/22}{hide \pkg{euroitc} settings
+% (requested by \contributor Karl Berry <karl\at freefriends.org>)}
+% ^^A private mail, 2021/02/22
% \begin{macrocode}
%<*cfg-e>
\SetProtrusion
-%<zpeu|euroitc> { encoding = U,
+%<zpeu> { encoding = U,
%<mvs> { encoding = {OT1,U},
%<zpeu> family = zpeu }
-%<euroitc> family = {euroitc,euroitcs} }
%<mvs> family = mvs }
{
%<zpeu> E = {50, }
-%<euroitc> E = {100,50}
%<mvs> 164 = {50,50}, % \EUR
%<mvs> 068 = {50,-100} % \EURdig
}
-%<*zpeu|euroitc>
+%<*zpeu>
\SetProtrusion
{ encoding = U,
-%<zpeu> family = zpeu,
-%<euroitc> family = {euroitc,euroitcs},
+ family = zpeu,
shape = it* }
{
-%<zpeu> E = {100,-50}
-%<euroitc> E = {100,}
+ E = {100,-50}
}
-%</zpeu|euroitc>
-%<*zpeu>
\SetProtrusion
{ encoding = U,
family = {zpeus,eurosans} }
@@ -16986,6 +17070,17 @@ end
}
% \end{macrocode}
+% Empty settings to prevent spurious warnings.
+%\changes{v2.8a}{2021/02/22}{add dummy settings
+% (reported by \contributor DORpapst <@\at @>)}
+% ^^A https://tex.stackexchange.com/questions/584373/package-microtype-warning-i-cannot-find-a-spacing-list-for-font-microtype
+% \begin{macrocode}
+\SetExtraSpacing
+ [ name = empty ]
+ { encoding = {TS1} }
+ { }
+
+% \end{macrocode}
%
% \subsection{Additional kerning}
%\GeneralChanges{Kerning}
@@ -17254,7 +17349,7 @@ normal, and shrunk by 5\%:
% Grave accent \` Left brace \{ Vertical bar \|
% Right brace \} Tilde \~}
%
-% \CheckSum{10748}
+% \CheckSum{10800}
%
% \Finale
%
diff --git a/Master/texmf-dist/source/latex/microtype/microtype.ins b/Master/texmf-dist/source/latex/microtype/microtype.ins
index e26326e802d..b0cc5697008 100644
--- a/Master/texmf-dist/source/latex/microtype/microtype.ins
+++ b/Master/texmf-dist/source/latex/microtype/microtype.ins
@@ -10,7 +10,7 @@
The `microtype' package
Subliminal refinements towards typographical perfection
- Copyright (c) 2004--2020 R Schlicht <w.m.l@gmx.net>
+ Copyright (c) 2004--2021 R Schlicht <w.m.l@gmx.net>
This work may be distributed and/or modified under the conditions of the
LaTeX Project Public License, either version 1.3c of this license or (at
@@ -125,7 +125,7 @@ microtype-xetex.def, microtype.lua and letterspace.sty.
\makecfg{t}{bch}
\makecfg{t}{blg}
\makecfg{t}{cmr}
- \makecfg{t}{pad}
+ \makefile{mt-EBGaramond.cfg}{config,cfg-t,ebg}
\makecfg{t}{ppl}
\makecfg{t}{ptm}
\makecfg{t}{ugm}
@@ -135,14 +135,15 @@ microtype-xetex.def, microtype.lua and letterspace.sty.
\makecfg{u}{eur}
\makecfg{u}{eus}
\makecfg{e}{zpeu}
- \makecfg{e}{euroitc}
\makecfg{e}{mvs}
\makeutfcfg{LatinModernRoman}
\makeutfcfg{CharisSIL}
+ \makeutfcfg{Lato}
+ \makeutfcfg{FontAwesome}
\usepreamble\haraldandkarlpreamble
\makecfg{t}{pmn}
\usepreamble\lorenpreamble
- \makeutfcfg{PalatinoLinotype}
+ \makeutfcfg{Palatino}
\usepreamble\testpreamble
\makefile{test-microtype.tex}{test}
}
diff --git a/Master/texmf-dist/source/latex/nicematrix/nicematrix.dtx b/Master/texmf-dist/source/latex/nicematrix/nicematrix.dtx
index 3b7f4d278ec..24732c133c6 100644
--- a/Master/texmf-dist/source/latex/nicematrix/nicematrix.dtx
+++ b/Master/texmf-dist/source/latex/nicematrix/nicematrix.dtx
@@ -15,8 +15,8 @@
%
% \fi
% \iffalse
-\def\myfileversion{5.10}
-\def\myfiledate{2021/02/05}
+\def\myfileversion{5.11}
+\def\myfiledate{2021/02/22}
%
%
%<*batchfile>
@@ -95,7 +95,8 @@ version 2005/12/01 or later.
\cs_set_protected:Npn}
\DoNotIndex{\bool_if:NTF,\bool_new:N,\bool_set_false:N,\bool_set_true:N,\l_tmpa_bool}
\DoNotIndex{\group_begin:,\group_end:,\c_math_toggle_token}
-\DoNotIndex{\tl_set:Nn,\l_tmpa_tl}
+\DoNotIndex{\tl_set:Nn,\l_tmpa_tl,\l_tmpb_tl}
+\DoNotIndex{\tl_gput_left:Nn,\tl_gput_right:Nn}
\ExplSyntaxOff
\makeatother
@@ -160,6 +161,16 @@ version 2005/12/01 or later.
% distribution as MiKTeX or TeXlive.
%
% \bigskip
+% \emph{Remark}: If you use LaTeX via Internet with, for example, Overleaf, you
+% can upload the file |nicematrix.sty| in the repertory of your
+% project in order to take full advantage of the latest version de
+% \pkg{nicematrix}.\footnote{The latest version of the file
+% \verb|nicematrix.sty| may be downloaded from the \textsc{svn} server of
+% TeXLive:\newline
+% \small
+% \url{https:www.tug.org/svn/texlive/trunk/Master/texmf-dist/tex/latex/nicematrix/nicematrix.sty}}
+%
+% \bigskip
% This package can be used with |xelatex|, |lualatex|, |pdflatex| but also by
% the classical workflow |latex|-|dvips|-|ps2pdf| (or Adobe Distiller).
% \textsl{However, the file nicematrix.dtx of the present documentation should
@@ -191,19 +202,6 @@ version 2005/12/01 or later.
% semi-global).
%
%
-% \bigskip
-% {\bfseries \color{red} Important
-%
-% Since the version 5.0 of \pkg{nicematrix}, one must use the letters |l|, |c| and
-% |r| in the preambles of the environments and no longer the letters |L|, |C| and
-% |R|.
-%
-% For sake of compatibility with the previous versions, there exists an option
-% |define-L-C-R| which must be used when loading \pkg{nicematrix}.
-% \begin{Verbatim}
-% \usepackage[define-L-C-R]{nicematrix}
-% \end{Verbatim}
-% }
%
% \newpage
%
@@ -281,8 +279,8 @@ version 2005/12/01 or later.
% |cell-space-bottom-limit| similar to the parameters |\cellspacetoplimit| and
% |\cellspacebottomlimit| of \pkg{cellspace}.
%
-% \colorbox{yellow!50}{\bfseries{New 5.9}}\enskip
-% There is also a key |cell-space-limits| to set both parameters at once.
+% \colorbox{yellow!30}{New 5.9}\enskip There is also a key |cell-space-limits|
+% to set both parameters at once.
%
% The initial value of these parameters is $0$~pt in order to have for the
% environments of \pkg{nicematrix} the same behaviour as those of \pkg{array}
@@ -747,9 +745,7 @@ version 2005/12/01 or later.
% In the environments of \pkg{nicematrix}, the vertical rules specified by
% \verb+|+ in the preambles of the environments are never broken, even by an
% incomplete row or by a double horizontal rule specified by |\hline\hline|
-% (there is no need to use \pkg{hhline}). \footnote{This is the behaviour since
-% the version 5.1 of \pkg{nicematrix}. Prior to that version, the behaviour was
-% the standard behaviour of \pkg{array}.}
+% (there is no need to use \pkg{hhline}).
%
% \bigskip
% \begin{BVerbatim}[baseline=c,boxwidth=10cm]
@@ -1170,7 +1166,9 @@ version 2005/12/01 or later.
% The extension \pkg{nicematrix} provides a key |code-before| for some code that
% will be executed before the drawing of the tabular. In this |code-before|, new
% commands are available: |\cellcolor|, |\rectanglecolor|, |\rowcolor|,
-% |\columncolor|, |\rowcolors| and |\chessboardcolors|.
+% |\columncolor|, |\rowcolors| and |\chessboardcolors|.\footnote{Remark that, in
+% the \verb|code-before|, some PGF/Tikz nodes corresponding to the position to
+% the potential rules are available: cf.~p.~\pageref{nodes-i}.}
% \label{code-before}
%
% \medskip
@@ -1183,8 +1181,8 @@ version 2005/12/01 or later.
% \pkg{colortbl}.
%
% This command takes in as mandatory arguments a color and a list of cells, each
-% of which with the format $i$-$j$ where $i$ is the number of row and $j$ the
-% number of colummn of the cell.
+% of which with the format $i$-$j$ where $i$ is the number of the row and $j$ the
+% number of the colummn of the cell.
%
%
% \medskip
@@ -1282,17 +1280,17 @@ version 2005/12/01 or later.
% \bigskip
% \item The command |\rowcolors| (with a \emph{s}) takes its name from the
% command |\rowcolors| of \pkg{xcolor}\footnote{The command |\rowcolors| of
-% \pkg{xcolor} is available when \pkg{xcolor} is loaded with the
-% option~|table|.}. The \emph{s} emphasizes the fact that there is \emph{two}
-% colors. This command colors alternately the rows of the tabular with the
-% tow colors (provided in second and third argument), beginning
-% with the row whose number is given in first (mandatory) argument.
+% \pkg{xcolor} is available when \pkg{xcolor} is loaded with the option~|table|.
+% That option also loads the package \pkg{colortbl}.}. The \emph{s} emphasizes
+% the fact that there is \emph{two} colors. This command colors alternately the
+% rows of the tabular with the tow colors (provided in second and third
+% argument), beginning with the row whose number is given in first (mandatory)
+% argument.
%
-% \colorbox{yellow!30}{New 5.8}\enskip In fact, the first (mandatory)
-% argument is, more generally, a comma separated list of intervals describing
-% the rows involved in the action of |\rowcolors| (an interval of the form
-% $i$|-| describes in fact the interval of all the rows of the tabular,
-% beginning with the row~$i$).
+% In fact, the first (mandatory) argument is, more generally, a comma separated
+% list of intervals describing the rows involved in the action of |\rowcolors|
+% (an interval of the form $i$|-| describes in fact the interval of all the rows
+% of the tabular, beginning with the row~$i$).
%
%
%
@@ -1301,15 +1299,15 @@ version 2005/12/01 or later.
% optional argument in the first position corresponds to the colorimetric
% space). The available keys are |cols|, |restart| and |respect-blocks|.
% \begin{itemize}
-% \item \colorbox{yellow!30}{New 5.8}\enskip The key |cols| describes a
-% set of columns. The command |\rowcolors| will color only the cells of these
-% columns. The value is a comma-separated list of intervals of the form $i$-$j$.
-% \item \colorbox{yellow!30}{New 5.8}\enskip With the key |restart|,
-% each interval of rows (specified by the first mandatory argument) begins with
-% the same color.\footnote{Otherwise, the color of a given row relies only upon the
-% parity of its number.}
+% \item The key |cols| describes a set of columns. The command |\rowcolors| will
+% color only the cells of these columns. The value is a comma-separated list of
+% intervals of the form $i$-$j$.
+% \item With the key |restart|, each interval of rows (specified by the first
+% mandatory argument) begins with the same color.\footnote{Otherwise, the color
+% of a given row relies only upon the parity of its number.}
% \item With the key |respect-blocks| the ``rows'' alternately colored may extend over
-% several rows if they have to incorporate blocks (created with the command |\Block|).
+% several rows if they have to incorporate blocks (created with the command
+% |\Block|: cf.~p.~\pageref{Block}).
% \end{itemize}
%
% \medskip
@@ -1402,7 +1400,8 @@ version 2005/12/01 or later.
%
% \bigskip
% One should remark that these commands are compatible with the commands of
-% \pkg{booktabs} (|\toprule|, |\midrule|, |\bottomrule|, etc).
+% \pkg{booktabs} (|\toprule|, |\midrule|, |\bottomrule|, etc). However,
+% \pkg{booktabs} is not loaded by \pkg{nicematrix}.
%
% \medskip
% \begin{scope}
@@ -1451,7 +1450,7 @@ version 2005/12/01 or later.
%
% It's possible to access the preceding tools with a syntax close to the syntax
% of \pkg{colortbl}. For that, one must use the key |colortbl-like| in the
-% current environment.\footnote{As of now, this key is not available in |\NiceMatrixOptions|.}
+% current environment.\footnote{As for now, this key is \emph{not} available in |\NiceMatrixOptions|.}
%
% There are three commands available (they are inspired by \pkg{colortbl} but
% are \emph{independent} of \pkg{colortbl}):
@@ -1463,7 +1462,7 @@ version 2005/12/01 or later.
% with the same syntax as the corresponding command of
% \pkg{colortbl} (however, unlike the command |\columncolor| of \pkg{colortbl},
% this command |\columncolor| can appear within another command, itself used in the
-% preamble).
+% preamble of the array).
% \end{itemize}
%
% \medskip
@@ -1673,10 +1672,13 @@ version 2005/12/01 or later.
% \bigskip
% We have several remarks to do.
% \begin{itemize}[beginpenalty=10000]
-% \item For the environments with an explicit preamble (i.e. |{NiceArray}| and
-% its variants), no letter must be given in that preamble for the potential
-% first column and the potential last column: they will automatically (and
-% necessarily) be of type |r| for the first column and |l| for the last one.
+% \item For the environments with an explicit preamble (i.e. |{NiceTabular}|,
+% |{NiceArray}| and its variants), no letter must be given in that preamble for
+% the potential first column and the potential last column: they will
+% automatically (and necessarily) be of type |r| for the first column and |l|
+% for the last one.\footnote{The users wishing exteriors columns with another
+% type of alignment should consider the command |\SubMatrix| available in the
+% |\CodeAfter| (cf.~p.~\pageref{sub-matrix}).}
% \item One may wonder how \pkg{nicematrix} determines the number of rows and
% columns which are needed for the composition of the ``last row'' and ``last
% column''.
@@ -1705,9 +1707,8 @@ version 2005/12/01 or later.
% \bigskip
% It's possible to control the appearance of these rows and columns with options
% |code-for-first-row|, |code-for-last-row|, |code-for-first-col| and
-% |code-for-last-col|. These options
-% specify tokens that will be inserted before each cell of the corresponding row
-% or column.
+% |code-for-last-col|. These options specify tokens that will be inserted before
+% each cell of the corresponding row or column.
%
%
% \begin{Verbatim}
@@ -1761,9 +1762,12 @@ version 2005/12/01 or later.
%
% \item Logically, the potential option |columns-width| (described
% p.~\pageref{width}) doesn't apply to the ``first column'' and ``last column''.
+%
% \item For technical reasons, it's not possible to use the option of the
-% command |\\| after the ``first row'' or before the ``last row'' (the placement
-% of the delimiters would be wrong).
+% command |\\| after the ``first row'' or before the ``last row''. The placement
+% of the delimiters would be wrong. If you are looking for a workaround,
+% consider the command |\SubMatrix| in the |\CodeAfter| described
+% p.~\pageref{sub-matrix}.
% \end{itemize}
%
%
@@ -1793,7 +1797,7 @@ version 2005/12/01 or later.
% with the option |color|.\footnote{It's also possible to change the color of
% all theses dotted lines with the option |xdots/color| (\textsl{xdots} to
% remind that it works for |\Cdots|, |\Ldots|, |\Vdots|, etc.): cf. p.
-% \pageref{customization}.}\par\nobreak
+% \pageref{customisation}.}\par\nobreak
%
% \bigskip
% \begin{BVerbatim}[baseline=c,boxwidth=10cm]
@@ -2028,10 +2032,12 @@ version 2005/12/01 or later.
% 1 & 2 & 3 & 4 & 5
% \end{pNiceMatrix}$
%
-%
+% \medskip
% Remark: Unlike the command |\hdotsfor| of \pkg{amsmath}, the command
-% |\Hdotsfor| may be used when the package \pkg{colortbl} is loaded (but you
-% might have problem if you use |\rowcolor| on the same row as |\Hdotsfor|).
+% |\Hdotsfor| may be used even when the package \pkg{colortbl}\footnote{We
+% recall that when \pkg{xcolor} is loaded with the option \verb|table|, the
+% package \pkg{colortbl} is loaded.} is loaded (but you might have problem if
+% you use |\rowcolor| on the same row as |\Hdotsfor|).
%
% \bigskip
% The package \pkg{nicematrix} also provides a command |\Vdotsfor| similar to
@@ -2145,9 +2151,9 @@ version 2005/12/01 or later.
% 0 & & 1
% \end{bNiceMatrix}$
%
-% \subsection{Customization of the dotted lines}
+% \subsection{Customisation of the dotted lines}
%
-% \label{customization}
+% \label{customisation}
% The dotted lines drawn by |\Ldots|, |\Cdots|, |\Vdots|, |\Ddots|, |\Iddots|
% and |\Hdotsfor| (and by the command |\line| in the |\CodeAfter| which is described
% p.~\pageref{line-in-code-after}) may be customized by three options (specified
@@ -2158,9 +2164,9 @@ version 2005/12/01 or later.
% \item |line-style|.
% \end{itemize}
%
-% These options may also be fixed with |\NiceMatrixOptions| or at the level of a
-% given environment but, in those cases, they must be prefixed by |xdots|, and,
-% thus have for names:
+% These options may also be fixed with |\NiceMatrixOptions|, as options of
+% |\CodeAfter| or at the level of a given environment but, in those cases, they
+% must be prefixed by |xdots|, and, thus have for names:
% \begin{itemize}
% \item |xdots/color|;
% \item |xdots/shorten|;
@@ -2280,18 +2286,27 @@ version 2005/12/01 or later.
% \medskip
% For the legibility of the code, an alternative syntax is provided: it's
% possible to give the instructions of the |\code-after| at the end of the
-% environment, after the keyword |\CodeAfter|.
+% environment, after the keyword |\CodeAfter|. Although |\CodeAfter| is a
+% keyword, it takes in an optional argument (between square brackets). The keys
+% accepted form a subset of the keys of the command |\WithArrowsOptions|.
%
+%
+% \medskip
+% The experienced users may use, for instance, the PGF/Tikz nodes created by
+% \pkg{nicematrix} in the |\CodeAfter|. These nodes are described further
+% beginning on p.~\pageref{PGF-nodes}.
+%
% \medskip
-% Two special commands are available in the |\CodeAfter|: |line| and
+% Moreover, two special commands are available in the |\CodeAfter|: |line| and
% |\SubMatrix|.
%
% \subsection{The command \textbackslash line in the \textbackslash CodeAfter}
%
-% The command |\line|draws directly dotted lines between nodes. It takes two
-% arguments for the two cells to rely, both of the form $i$-$j$ where is the
-% number of row and $j$ is the number of column. It may be used, for example, to
-% draw a dotted line between two adjacent cells. \label{line-in-code-after}
+% The command |\line| draws directly dotted lines between nodes. It takes in two
+% arguments for the two cells to link, both of the form $i$-$j$ where is the
+% number of the row and $j$ is the number of the column. It may be used, for
+% example, to draw a dotted line between two adjacent
+% cells. \label{line-in-code-after}
%
% \medskip
% \begin{BVerbatim}[baseline=c,boxwidth=11cm]
@@ -2315,13 +2330,18 @@ version 2005/12/01 or later.
% \end{pNiceMatrix}$
% \end{scope}
%
+% \medskip
+% The options available for the customisation of the dotted lines created by
+% |\Cdots|, |\Vdots|, etc. are also available for this command (cf.
+% p.~\pageref{customisation}).
+%
%
% \subsection{The command \textbackslash SubMatrix in the \textbackslash CodeAfter}
%
% \label{sub-matrix}
%
% \colorbox{yellow!50}{\textbf{New 5.10}}\enskip
-% The command |\SubMatrix| provides a way to put delimiters on an portion
+% The command |\SubMatrix| provides a way to put delimiters on a portion
% of the array considered as a submatrix. The command |\SubMatrix| takes in five
% arguments:
% \begin{itemize}
@@ -2343,10 +2363,10 @@ version 2005/12/01 or later.
%
% \medskip
% \begin{scope}
+% \hfuzz=15cm
% \fvset{commandchars=\~\#\+}%
% \begin{BVerbatim}[boxwidth=11cm,baseline=c]
-% \[\begin{NiceArray}{ccc~emphase#@{\hspace{1.5em}}+c}%
-% [cell-space-limits=2pt,~emphase#margin+]
+% \[\begin{NiceArray}{ccc~emphase#@{\hspace{1.5em}}+c}[cell-space-limits=2pt,~emphase#margin+]
% 1 & 1 & 1 & x \\
% \dfrac{1}{4} & \dfrac{1}{2} & \dfrac{1}{4} & y \\
% 1 & 2 & 3 & z
@@ -2372,7 +2392,7 @@ version 2005/12/01 or later.
% exists also the key |xshift| which fixes both parameters);
% \item |extra-height| adds a quantity to the total height of the delimiters
% (height |\ht| + depth |\dp|);
-% \item |delimiters-color| fixes the color of the delimiters (also
+% \item |delimiters/color| fixes the color of the delimiters (also
% available in |\NiceMatrixOptions|, in the environments with delimiters and as
% option of the command |\CodeAfter|);
% \item |slim| is a boolean key: when that key is in force, the horizontal
@@ -2390,10 +2410,10 @@ version 2005/12/01 or later.
%
% \bigskip
% \begin{scope}
+% \hfuzz=12cm
% \fvset{commandchars=\~\#\!}%
% \begin{BVerbatim}[baseline=c,boxwidth=11cm]
-% $\begin{NiceArray}{cc@{\hspace{5mm}}l}%
-% [cell-space-limits=2pt]
+% $\begin{NiceArray}{cc@{\hspace{5mm}}l}[cell-space-limits=2pt]
% & & \frac12 \\
% & & \frac14 \\[1mm]
% a & b & \frac12a+\frac14b \\
@@ -2421,10 +2441,10 @@ version 2005/12/01 or later.
%
% \medskip
% \begin{scope}
+% \hfuzz=12cm
% \fvset{commandchars=\~\#\!}%
% \begin{BVerbatim}[baseline=c,boxwidth=11cm]
-% $\begin{NiceArray}{cc@{\hspace{5mm}}l}%
-% [cell-space-limits=2pt]
+% $\begin{NiceArray}{cc@{\hspace{5mm}}l}[cell-space-limits=2pt]
% & & \frac12 \\
% & & \frac14 \\[1mm]
% a & b & \frac12a+\frac14b \\
@@ -2450,7 +2470,7 @@ version 2005/12/01 or later.
%
% \bigskip
% There is also a key |name| which gives a name to the submatrix created by
-% |\SubMatrix|. That name is used to created PGF/Tiks nodes: cf
+% |\SubMatrix|. That name is used to created PGF/Tikz nodes: cf
% p.~\pageref{node-sub-matrix}.
%
% \section{The notes in the tabulars}
@@ -2570,7 +2590,7 @@ version 2005/12/01 or later.
%
% \begin{center}
% \fvset{commandchars=\~\#\!}
-% \begin{BVerbatim}[formatcom=\small\color{gray}]
+% \begin{Verbatim}[formatcom=\small\color{gray}]
% \begin{table}
% \setlength{\belowcaptionskip}{1ex}
% \centering
@@ -2592,11 +2612,11 @@ version 2005/12/01 or later.
% \bottomrule
% \end{NiceTabular}
% \end{table}
-% \end{BVerbatim}
+% \end{Verbatim}
% \end{center}
%
%
-% \begin{table}
+% \begin{table}[hb]
% \setlength{\belowcaptionskip}{1ex}
% \centering
% \caption{Use of \texttt{\textbackslash tabularnote}\tabularnote{It's possible
@@ -2745,7 +2765,7 @@ version 2005/12/01 or later.
% Initial value:\quad |afterlabel = \nobreak, itemjoin = \quad|
%
%
-% \item The key |notes/code-before| est une token list inserted by \pkg{nicematrix}
+% \item The key |notes/code-before| is a token list inserted by \pkg{nicematrix}
% just before the composition of the notes at the end of the tabular.
%
% Initial value: \textsl{empty}
@@ -2762,7 +2782,7 @@ version 2005/12/01 or later.
%
%
% \bigskip
-% For an example of customization of the tabular notes, see p.~\pageref{ex:notes}.
+% For an example of customisation of the tabular notes, see p.~\pageref{ex:notes}.
%
%
% \subsection{Use of \{NiceTabular\} with threeparttable}
@@ -3055,16 +3075,17 @@ version 2005/12/01 or later.
%
% For the environements with delimiters (|{pNiceArray}|, |{pNiceMatrix}|, etc.),
% it's possible to change the color of the delimiters with the key
-% |delimiters-color|.
+% |delimiters/color|.\footnote{\verb|delimiters-color| is a synonymous
+% (deprecated) for |delimiters/color|.}
%
% \medskip
% \begin{BVerbatim}[boxwidth=12cm,baseline=c]
-% $\begin{bNiceMatrix}[delimiters-color=red]
+% $\begin{bNiceMatrix}[delimiters/color=red]
% 1 & 2 \\
% 3 & 4
% \end{bNiceMatrix}$
% \end{BVerbatim}
-% $\begin{bNiceMatrix}[delimiters-color=red]
+% $\begin{bNiceMatrix}[delimiters/color=red]
% 1 & 2 \\
% 3 & 4
% \end{bNiceMatrix}$
@@ -3098,7 +3119,8 @@ version 2005/12/01 or later.
%
% \section{Use of Tikz with nicematrix}
%
-% \label{name}
+% \label{name}\label{PGF-nodes}
+%
% \subsection{The nodes corresponding to the contents of the cells}
%
% The package \pkg{nicematrix} creates a PGF/Tikz node for each (non-empty) cell
@@ -3419,12 +3441,15 @@ version 2005/12/01 or later.
%
%
%
-% \subsection{The ``row-nodes'' and the ``col-nodes''}
+% \subsection{The nodes which indicate the position of the rules}
%
-% The package \pkg{nicematrix} creates a PGF/Tikz node indicating the potential
-% position of each horizontal rule (with the names |row-|$i$) and each vertical
-% rule (with the names |col-|$j$), as described in the following figure. These
-% nodes are available in the |code-before| and the |\CodeAfter|.
+% \label{nodes-i}
+% \colorbox{yellow!50}{\textbf{New 5.11}}\enskip The package \pkg{nicematrix}
+% creates a PGF/Tikz node merely called $i$ (with the classical prefix) at the
+% intersection of the horizontal rule of number~$i$ and the vertical rule of
+% number~$j$ (more specifically the potential position of those rules because
+% maybe there are not actually drawn). These nodes are available in the
+% |code-before| and the |\CodeAfter|.
% \begin{center}
% \begin{NiceTabular}{ccc}[hvlines,rules/width=1pt,rules/color=gray]
% rose & tulipe & lys \\
@@ -3435,23 +3460,18 @@ version 2005/12/01 or later.
% \begin{tikzpicture}
% \foreach \i in {1,2,3,4}
% {
-% \fill [red] (row-\i) circle (0.5mm) ;
-% \node [red,anchor=east] at (row-\i) {row-\i} ;
-% }
-% \foreach \j in {1,2,3,4}
-% {
-% \fill [blue] (col-\j) circle (0.5mm) ;
-% \node [blue,anchor=north] at (col-\j) {col-\j} ;
+% \fill [red] (\i) circle (0.5mm) ;
+% \node [red,above right] at (\i) {\i} ;
% }
% \end{tikzpicture}
% \end{NiceTabular}
% \end{center}
%
% \bigskip
-% If we use Tikz (we remind that \pkg{nicematrix} does not load Tikz by
-% default), we can access (in the |code-before| and the |\CodeAfter|) to the
-% intersection of the horizontal rule~$i$ and the vertical rule~$j$ with the
-% syntax |(row-|$i$\verb+-|col-+$j$|)|.
+% If we use Tikz (we remind that \pkg{nicematrix} does not load Tikz by default,
+% by only \textsc{pgf}, which is a sub-layer of Tikz), we can access, in the
+% |\CodeAfter| but also in the |code-before|) to the intersection of the horizontal
+% rule~$i$ and the vertical rule~$j$ with the syntax |(|$i$\verb+-|+$j$|)|.
%
% \medskip
% \begin{Verbatim}
@@ -3459,8 +3479,7 @@ version 2005/12/01 or later.
% code-before =
% {
% ~emphase# \tikz \draw [fill = red!15] @
-% ~emphase# (row-7-|col-4) -- (row-8-|col-4) -- (row-8-|col-5) -- @
-% ~emphase# (row-9-|col-5) -- (row-9-|col-6) |- cycle ; @
+% ~emphase# (7-|4) -- (8-|4) -- (8-|5) -- (9-|5) -- (9-|6) |- cycle ; @
% }
% ]
% 1 \\
@@ -3478,8 +3497,7 @@ version 2005/12/01 or later.
% code-before =
% {
% \tikz \draw [fill = red!15]
-% (row-7-|col-4) -- (row-8-|col-4) -- (row-8-|col-5) --
-% (row-9-|col-5) -- (row-9-|col-6) |- cycle ;
+% (7-|4) -- (8-|4) -- (8-|5) -- (9-|5) -- (9-|6) |- cycle ;
% }
% ]
% 1 \\
@@ -3497,8 +3515,9 @@ version 2005/12/01 or later.
%
% \label{node-sub-matrix}
%
+% \colorbox{yellow!50}{\textbf{New 5.10}}\enskip
% The command |\SubMatrix| available in the |\CodeAfter| has been described
-% p.~\pageref{sub-matrix}.
+% p.~\pageref{sub-matrix}.
%
% \smallskip
% If a command |\SubMatrix| has been used with the key |name| with an expression
@@ -3567,51 +3586,37 @@ version 2005/12/01 or later.
% \fvset{commandchars=\§\¤\μ}
% \begin{Verbatim}
%\ExplSyntaxOn
-% \cs_new_protected:Nn \__pantigny_hatchcell:nnn
+% \cs_new_protected:Nn \__pantigny_hatch:nnn
% {
% \begin { tikzpicture }
% \fill [ pattern = north~west~lines , pattern~color = #3 ]
-% ( row - #1 -| col - #2)
-% rectangle
-% ( row - \int_eval:n { #1 + 1 } -| col - \int_eval:n { #2 + 1 } ) ;
+% ( #1 -| #2) rectangle ( \int_eval:n { #1 + 1 } -| \int_eval:n { #2 + 1 } ) ;
% \end { tikzpicture }
% }
%
% \NewDocumentCommand \hatchcell { ! O { black } }
% {
% \tl_gput_right:Nx §emphase¤\g_nicematrix_code_before_tlμ
-% {
-% \__pantigny_hatchcell:nnn
-% { \int_use:c { c@iRow } }
-% { \int_use:c { c@jCol } }
-% { #1 }
-% }
+% { \__pantigny_hatch:nnn { \arabic { iRow } } { \arabic { jCol } } { #1 } }
% }
% \ExplSyntaxOff
% \end{Verbatim}
% \end{scope}
%
%
-%\ExplSyntaxOn
-% \cs_new_protected:Nn \__pantigny_hatchcell:nnn
+% \ExplSyntaxOn
+% \cs_new_protected:Nn \__pantigny_hatch:nnn
% {
% \begin { tikzpicture }
% \fill [ pattern = north~west~lines , pattern~color = #3 ]
-% ( row - #1 -| col - #2)
-% rectangle
-% ( row - \int_eval:n { #1 + 1 } -| col - \int_eval:n { #2 + 1 } ) ;
+% ( #1 -| #2 ) rectangle ( \int_eval:n { #1 + 1 } -| \int_eval:n { #2 + 1 } ) ;
% \end { tikzpicture }
% }
%
% \NewDocumentCommand \hatchcell { ! O { black } }
% {
% \tl_gput_right:Nx \g_nicematrix_code_before_tl
-% {
-% \__pantigny_hatchcell:nnn
-% { \int_use:c { c@iRow } }
-% { \int_use:c { c@jCol } }
-% { #1 }
-% }
+% { \__pantigny_hatch:nnn { \arabic { iRow } } { \arabic { jCol } } { #1 } }
% }
% \ExplSyntaxOff
%
@@ -3623,7 +3628,7 @@ version 2005/12/01 or later.
% \begin{BVerbatim}[baseline=c,boxwidth=9cm]
% \begin{NiceTabular}{ccc}[hvlines]
% Tokyo & Paris & London \\
-% Roma & ~emphase#\hatchcell[blue!30]@Oslo & Miami \\
+% Lima & ~emphase#\hatchcell[blue!30]@Oslo & Miami \\
% Los Angeles & Madrid & Roma
% \end{NiceTabular}
% \end{BVerbatim}
@@ -3643,7 +3648,7 @@ version 2005/12/01 or later.
% The package \pkg{nicematrix} provides the command |\OnlyMainNiceMatrix|
% which is meant to be used in definitions of new column types. Its argument is
% evaluated if and only if we are in the main part of the array, that is to say
-% not in an potential exterior row.
+% not in a potential exterior row.
%
% For example, one may wish to define a new column type |?| in order to draw a
% (black) heavy rule of width 1~pt. The following definition will do the
@@ -3832,7 +3837,7 @@ version 2005/12/01 or later.
% \end{Verbatim}
%
% \bigskip
-% As of now, the package \pkg{nicematrix} is not compatible with
+% As for now, the package \pkg{nicematrix} is not compatible with
% \cls{aastex63}. If you want to use \pkg{nicematrix} with \cls{aastex63}, send
% me an email and I will try to solve the incompatibilies.
%
@@ -3942,103 +3947,7 @@ version 2005/12/01 or later.
%
% \subsection{Dotted lines}
%
-%
-% A permutation matrix (as an example, we have raised the value of
-% |xdots/shorten|).
-%
-% \label{permutation}
-% \bigskip
-% \begin{BVerbatim}[baseline=c]
-% $\begin{pNiceMatrix}[~emphase#xdots/shorten=0.6em@]
-% 0 & 1 & 0 & & \Cdots & 0 \\
-% \Vdots & & & \Ddots & & \Vdots \\
-% & & & \Ddots & & \\
-% & & & \Ddots & & 0 \\
-% 0 & 0 & & & & 1 \\
-% 1 & 0 & & \Cdots & & 0
-% \end{pNiceMatrix}$
-% \end{BVerbatim}
-% \hspace{2.5cm}
-% $\begin{pNiceMatrix}[xdots/shorten=0.6em]
-% 0 & 1 & 0 & & \Cdots & 0 \\
-% \Vdots & & & \Ddots & & \Vdots \\
-% & & & \Ddots & & \\
-% & & & \Ddots & & 0 \\
-% 0 & 0 & & & & 1 \\
-% 1 & 0 & & \Cdots & & 0
-% \end{pNiceMatrix}$
-%
-% \vspace{2cm}
-%
-% An example with |\Iddots| (we have raised again the value of
-% |xdots/shorten|).\par\nobreak
-%
-% \bigskip
-% \begin{BVerbatim}[baseline=c]
-% $\begin{pNiceMatrix}[xdots/shorten=0.9em]
-% 1 & \Cdots & & 1 \\
-% \Vdots & & & 0 \\
-% & ~emphase#\Iddots@ & ~emphase#\Iddots@ & \Vdots \\
-% 1 & 0 & \Cdots & 0
-% \end{pNiceMatrix}$
-% \end{BVerbatim}
-% \hspace{4cm}
-% $\begin{pNiceMatrix}[xdots/shorten=0.9em]
-% 1 & \Cdots & & 1 \\
-% \Vdots & & & 0 \\
-% & \Iddots & \Iddots & \Vdots \\
-% 1 & 0 & \Cdots & 0
-% \end{pNiceMatrix}$
-%
-%
-% \vspace{2cm}
-% An example with |\multicolumn|:\par\nobreak
-%
-% \bigskip
-% \begin{BVerbatim}
-% \begin{BNiceMatrix}[nullify-dots]
-% 1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 & 9 & 10\\
-% 1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 & 9 & 10\\
-% \Cdots & & ~emphase#\multicolumn{6}{C}{10 \text{ other rows}}@ & \Cdots \\
-% 1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 & 9 & 10
-% \end{BNiceMatrix}
-% \end{BVerbatim}
-%
-% \bigskip
-% \[\begin{BNiceMatrix}[nullify-dots]
-% 1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 & 9 & 10\\
-% 1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 & 9 & 10\\
-% \Cdots & & \multicolumn{6}{c}{10 \text{ other rows}} & \Cdots \\
-% 1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 & 9 & 10
-% \end{BNiceMatrix}\]
-%
-% \vspace{2cm}
-% An example with |\Hdotsfor|:\par\nobreak
-%
-% \bigskip
-% \begin{BVerbatim}[baseline=c,boxwidth=11cm]
-% \begin{pNiceMatrix}[nullify-dots]
-% 0 & 1 & 1 & 1 & 1 & 0 \\
-% 0 & 1 & 1 & 1 & 1 & 0 \\
-% \Vdots & ~emphase#\Hdotsfor{4}@ & \Vdots \\
-% & ~emphase#\Hdotsfor{4}@ & \\
-% & ~emphase#\Hdotsfor{4}@ & \\
-% & ~emphase#\Hdotsfor{4}@ & \\
-% 0 & 1 & 1 & 1 & 1 & 0
-% \end{pNiceMatrix}
-% \end{BVerbatim}
-% $\begin{pNiceMatrix}[nullify-dots]
-% 0 & 1 & 1 & 1 & 1 & 0 \\
-% 0 & 1 & 1 & 1 & 1 & 0 \\
-% \Vdots & \Hdotsfor{4} & \Vdots \\
-% & \Hdotsfor{4} & \\
-% & \Hdotsfor{4} & \\
-% & \Hdotsfor{4} & \\
-% 0 & 1 & 1 & 1 & 1 & 0
-% \end{pNiceMatrix}$
-%
-% \vspace{2cm}
-% An example for the resultant of two polynoms:\par\nobreak
+% An example with the resultant of two polynoms:\par\nobreak
%
% \bigskip
% \begin{BVerbatim}
@@ -4100,6 +4009,54 @@ version 2005/12/01 or later.
% The option |line-style| controls the style of the lines drawn by |\Ldots|,
% |\Cdots|, etc. Thus, it's possible with these commands to draw lines which are
% not longer dotted.
+%
+%
+% \begin{Verbatim}[formatcom=\small\color{gray}]
+% \NiceMatrixOptions{code-for-first-row = \scriptstyle,code-for-first-col = \scriptstyle }
+% \setcounter{MaxMatrixCols}{12}
+% \newcommand{\blue}{\color{blue}}
+% \[\begin{pNiceMatrix}[last-row,last-col,nullify-dots,xdots/line-style={dashed,blue}]
+% 1& & & \Vdots & & & & \Vdots \\
+% & \Ddots[line-style=standard] \\
+% & & 1 \\
+% \Cdots[color=blue,line-style=dashed]& & & \blue 0 &
+% \Cdots & & & \blue 1 & & & \Cdots & \blue \leftarrow i \\
+% & & & & 1 \\
+% & & &\Vdots & & \Ddots[line-style=standard] & & \Vdots \\
+% & & & & & & 1 \\
+% \Cdots & & & \blue 1 & \Cdots & & \Cdots & \blue 0 & & & \Cdots & \blue \leftarrow j \\
+% & & & & & & & & 1 \\
+% & & & & & & & & & \Ddots[line-style=standard] \\
+% & & & \Vdots & & & & \Vdots & & & 1 \\
+% & & & \blue \overset{\uparrow}{i} & & & & \blue \overset{\uparrow}{j} \\
+% \end{pNiceMatrix}\]
+% \end{Verbatim}
+%
+%
+% \begin{scope}
+% \NiceMatrixOptions{code-for-first-row = \scriptstyle,code-for-first-col = \scriptstyle }
+% \setcounter{MaxMatrixCols}{12}
+% \newcommand{\blue}{\color{blue}}
+% \[\begin{pNiceMatrix}[last-row,last-col,nullify-dots,xdots/line-style={dashed,blue}]
+% 1& & & \Vdots & & & & \Vdots \\
+% & \Ddots[line-style=standard] \\
+% & & 1 \\
+% \Cdots[color=blue,line-style=dashed]& & & \blue 0 &
+% \Cdots & & & \blue 1 & & & \Cdots & \blue \leftarrow i \\
+% & & & & 1 \\
+% & & &\Vdots & & \Ddots[line-style=standard] & & \Vdots \\
+% & & & & & & 1 \\
+% \Cdots & & & \blue 1 & \Cdots & & \Cdots & \blue 0 & & & \Cdots & \blue \leftarrow j \\
+% & & & & & & & & 1 \\
+% & & & & & & & & & \Ddots[line-style=standard] \\
+% & & & \Vdots & & & & \Vdots & & & 1 \\
+% & & & \blue \overset{\uparrow}{i} & & & & \blue \overset{\uparrow}{j} \\
+% \end{pNiceMatrix}\]
+% \end{scope}
+%
+% \interitem
+% In fact, it's even possible to draw solid lines with the commands |\Cdots|,
+% |\Vdots|, etc.
%
% \begin{Verbatim}
% \NiceMatrixOptions
@@ -4260,7 +4217,29 @@ version 2005/12/01 or later.
%
% \vspace{1cm}
% It's possible to color a row with |\rowcolor| in the |code-before| (or with
-% |\rowcolor| in the first cell of the row if the key |colortbl-like| is used).
+% |\rowcolor| in the first cell of the row if the key |colortbl-like| is
+% used−even when \pkg{colortbl} is not loaded).
+%
+% \medskip
+% \begin{Verbatim}
+% \begin{pNiceArray}{>{\strut}cccc}[margin, extra-margin=2pt,colortbl-like]
+% ~emphase#\rowcolor{red!15}@A_{11} & A_{12} & A_{13} & A_{14} \\
+% A_{21} & ~emphase#\rowcolor{red!15}@A_{22} & A_{23} & A_{24} \\
+% A_{31} & A_{32} & ~emphase#\rowcolor{red!15}@A_{33} & A_{34} \\
+% A_{41} & A_{42} & A_{43} & ~emphase#\rowcolor{red!15}@A_{44}
+% \end{pNiceArray}
+% \end{Verbatim}
+%
+%
+%
+% \[\begin{pNiceArray}{>{\strut}cccc}[margin, extra-margin=2pt,colortbl-like]
+% \rowcolor{red!15}A_{11} & A_{12} & A_{13} & A_{14} \\
+% A_{21} & \rowcolor{red!15}A_{22} & A_{23} & A_{24} \\
+% A_{31} & A_{32} & \rowcolor{red!15}A_{33} & A_{34} \\
+% A_{41} & A_{42} & A_{43} & \rowcolor{red!15}A_{44}
+% \end{pNiceArray}\]
+%
+% \bigskip
% However, it's not possible to do a fine tuning. That's why we describe now a
% method to highlight a row of the matrix. We create a rectangular Tikz node
% which encompasses the nodes of the second row with the Tikz library \pkg{fit}.
@@ -4268,11 +4247,16 @@ version 2005/12/01 or later.
% the text \emph{under} this node, we have to use transparency with the
% |blend mode| equal to |multiply|.
%
+% \medskip
+% \textbf{Caution} : Some \textsc{pdf} readers are not able to show
+% transparency.\footnote{In Overleaf, the ``built-in'' \textsc{pdf} viewer does
+% not show transparency. You can switch to the ``native'' viewer in that case.}
+%
%
% \medskip
% That example and the following ones require Tikz (by default, \pkg{nicematrix}
-% only loads \textsc{pgf}) and the Tikz library |fit|. The following lines in
-% the preamble of your document do the job:
+% only loads \textsc{pgf}, which is a sub-layer of Tikz) and the Tikz library
+% |fit|. The following lines in the preamble of your document do the job:
% \begin{verbatim}
% \usepackage{tikz}
% \usetikzlibrary{fit}
@@ -4439,44 +4423,6 @@ version 2005/12/01 or later.
% a & a & a & L_3
% \end{pNiceArray}\]
%
-%
-%
-% \vspace{1cm}
-%
-% In the following example, we use the ``large nodes'' to highlight a zone of
-% the matrix.\par\nobreak
-% \begin{Verbatim}
-% \begin{pNiceArray}{>{\strut}cccc}[create-large-nodes,margin,extra-margin=2pt]
-% A_{11} & A_{12} & A_{13} & A_{14} \\
-% A_{21} & A_{22} & A_{23} & A_{24} \\
-% A_{31} & A_{32} & A_{33} & A_{34} \\
-% A_{41} & A_{42} & A_{43} & A_{44}
-% \CodeAfter
-% \tikz \path [~emphase#name suffix = -large@,fill = red!15, blend mode = multiply]
-% (1-1.north west)
-% |- (2-2.north west)
-% |- (3-3.north west)
-% |- (4-4.north west)
-% |- (4-4.south east)
-% |- (1-1.north west) ;
-% \end{pNiceArray}
-% \end{Verbatim}
-%
-%
-% \[\begin{pNiceArray}{>{\strut}cccc}[create-large-nodes,margin,extra-margin=2pt]
-% A_{11} & A_{12} & A_{13} & A_{14} \\
-% A_{21} & A_{22} & A_{23} & A_{24} \\
-% A_{31} & A_{32} & A_{33} & A_{34} \\
-% A_{41} & A_{42} & A_{43} & A_{44}
-% \CodeAfter
-% \tikz \path [name suffix = -large,fill = red!15, blend mode = multiply]
-% (1-1.north west)
-% |- (2-2.north west)
-% |- (3-3.north west)
-% |- (4-4.north west)
-% |- (4-4.south east)
-% |- (1-1.north west) ;
-% \end{pNiceArray}\]
%
% \subsection{Direct use of the Tikz nodes}
%
@@ -4607,9 +4553,9 @@ version 2005/12/01 or later.
% \smallskip
% Of course, the package \pkg{nicematrix} uses the features of the package
% \pkg{array}. It tries to be independent of its implementation. Unfortunately,
-% it was not possible to be strictly independent: the package \pkg{nicematrix}
-% relies upon the fact that the package |{array}| uses |\ialign| to begin the
-% |\halign|.
+% it was not possible to be strictly independent. For example, the package
+% \pkg{nicematrix} relies upon the fact that the package |{array}| uses
+% |\ialign| to begin the |\halign|.
%
%
% \bigskip
@@ -4647,8 +4593,9 @@ version 2005/12/01 or later.
% this package for technical reasons.
%
% \bigskip
-% We load some packages.
+% We load some packages. The package \pkg{xparse} is still loaded for use on Overleaf.
% \begin{macrocode}
+\RequirePackage { xparse }
\RequirePackage { array }
\RequirePackage { amsmath }
% \end{macrocode}
@@ -4725,7 +4672,7 @@ version 2005/12/01 or later.
%
% We test whether the current class is \cls{revtex4-1} (deprecated) or
% \cls{revtex4-2} because these classes redefines |\array| (of \pkg{array}) in a
-% way incompatible with our programmation. As of january 2021, the current
+% way incompatible with our programmation. At the date January 2021, the current
% version \cls{revtex4-2} is 4.2e (compatible with \pkg{booktabs}).
%
% \begin{macrocode}
@@ -4792,7 +4739,7 @@ version 2005/12/01 or later.
\cs_set_eq:NN \@@_old_pgfutil@check@rerun \pgfutil@check@rerun
% \end{macrocode}
% The new version of |\pgfutil@check@rerun| will not check the PGF nodes whose
-% names start with |nm-| (which is the prefix for the nodes creates by
+% names start with |nm-| (which is the prefix for the nodes created by
% \pkg{nicematrix}).
% \begin{macrocode}
\cs_set_protected:Npn \pgfutil@check@rerun ##1 ##2
@@ -4816,7 +4763,7 @@ version 2005/12/01 or later.
% \end{macrocode}
% The command |\CT@arc@| is a command of \pkg{colortbl} which sets the color of
% the rules in the array. We will use it to store the instruction of color for
-% the rules even if \pkg{colortbl} is not loaded. Idem for
+% the rules even if \pkg{colortbl} is not loaded.
% \begin{macrocode}
\cs_set_protected:Npn \CT@arc@ { }
\cs_set:Npn \arrayrulecolor #1 # { \CT@arc { #1 } }
@@ -5092,7 +5039,7 @@ version 2005/12/01 or later.
% |\pgfsyspdfmark| in the |aux| file. If he changes its mind and no longer loads
% \pkg{nicematrix}, an error may occur at the next compilation because of
% remanent instructions |\pgfsyspdfmark| in the |aux| file. With the following
-% code, we avoid that situation.
+% code, we try to avoid that situation.
% \begin{macrocode}
\cs_new_protected:Npn \@@_provide_pgfsyspdfmark:
{
@@ -5109,10 +5056,10 @@ version 2005/12/01 or later.
%
% \subsection*{Parameters}
%
-% \bigskip
+% \bigskip
% For compatibility with versions prior to 5.0, we provide a load-time option
-% |define_L_C_R|. With this option, it's possible the letters |L|, |C| and |R|
-% instead of |l|, |c| and |r| in the preamble of the environments of
+% |define_L_C_R|. With this option, it's possible to use the letters |L|, |C|
+% and |R| instead of |l|, |c| and |r| in the preamble of the environments of
% \pkg{nicematrix} as it was mandatory before version~5.0.
% \begin{macrocode}
\bool_new:N \c_@@_define_L_C_R_bool
@@ -5198,7 +5145,7 @@ version 2005/12/01 or later.
% \end{macrocode}
%
% \bigskip
-% Idem pour the blocks mono-row.
+% Idem pour the mono-row blocks.
% \begin{macrocode}
\dim_new:N \g_@@_blocks_ht_dim
\dim_new:N \g_@@_blocks_dp_dim
@@ -5214,7 +5161,7 @@ version 2005/12/01 or later.
% \end{macrocode}
%
% \bigskip
-% We want to know if we are in an environment of \pkg{nicematrix} because we
+% We want to know whether we are in an environment of \pkg{nicematrix} because we
% will raise an error if the user tries to use nested environments.
% \begin{macrocode}
\bool_new:N \l_@@_in_env_bool
@@ -5265,9 +5212,22 @@ version 2005/12/01 or later.
}
% \end{macrocode}
%
+% \bigskip
+% The letter used for the vlines which will be drawn only in the sub-matrices.
+% |vlism| stands for \emph{vertical lines in sub-matrices}.
+% \begin{macrocode}
+\tl_new:N \l_@@_letter_vlism_tl
+% \end{macrocode}
+%
+% The list of the columns where vertical lines in sub-matrices (vlism) must be
+% drawn. Of course, the actual value of this sequence will be known after the
+% analyse of the preamble of the array.
+% \begin{macrocode}
+\seq_new:N \g_@@_cols_vlism_seq
+% \end{macrocode}
%
% \bigskip
-% The following colors will be used to memorize le color of the potential ``first
+% The following colors will be used to memorize the color of the potential ``first
% col'' and the potential ``first row''.
% \begin{macrocode}
\colorlet { nicematrix-last-col } { . }
@@ -5315,7 +5275,7 @@ version 2005/12/01 or later.
% |\g_nicematrix_code_after_tl| but it is used internally by \pkg{nicematrix}.
% In fact, we have to distinguish between |\g_nicematrix_code_after_tl| and
% |\g_@@_internal_code_after_tl| because we must take care of the order in which
-% instructions stored in that paremeters are executed.
+% instructions stored in that parameters are executed.
% \begin{macrocode}
\tl_new:N \g_@@_internal_code_after_tl
% \end{macrocode}
@@ -5394,7 +5354,7 @@ version 2005/12/01 or later.
%
% \bigskip
% \pkg{expl3} provides scratch dimensions |\l_tmpa_dim| and |\l_tmpb_dim|. We
-% creates two other in the same spirit (if they don't exist yet: that's why we
+% creates two more in the same spirit (if they don't exist yet: that's why we
% use |\dim_zero_new:N|).
% \begin{macrocode}
\dim_zero_new:N \l_tmpc_dim
@@ -5408,12 +5368,6 @@ version 2005/12/01 or later.
\bool_new:N \g_@@_empty_cell_bool
% \end{macrocode}
%
-% \bigskip
-% The following dimension will be used to save the current value of
-% |\arraycolsep|.
-% \begin{macrocode}
-\dim_new:N \@@_old_arraycolsep_dim
-% \end{macrocode}
%
% \bigskip
% The following dimensions will be used internally to compute the width of the
@@ -5426,7 +5380,7 @@ version 2005/12/01 or later.
% \bigskip
% The following sequence will contain the characteristics of the blocks of the
% array, specified by the command |\Block|. Each block is represented by 6
-% components surrounded by braces:
+% components surrounded by curly braces:
%
% |{|\textsl{imin}|}{|\textsl{jmin}|}{|\textsl{imax}|}{|\textsl{jmax}|}{|\textsl{options}|}{|\textsl{contents}|}|.
%
@@ -5461,7 +5415,7 @@ version 2005/12/01 or later.
%
% \medskip
% The final user may decide to ``stroke'' a block (using, for example, the key
-% |color=red!15| when using the command |\Block|). In that case, the rules
+% |draw=red!15| when using the command |\Block|). In that case, the rules
% specified, for instance, by |hvlines| must not be drawn around the block.
% That's why we keep the information of all that stroken blocks in the following
% sequence.
@@ -5471,13 +5425,14 @@ version 2005/12/01 or later.
%
%
% \medskip
-% The list of the names of the potential |\SubMatrix| in the |code-after| of an
+% The list of the names of the potential |\SubMatrix| in the |\CodeAfter| of an
% environment. Unfortunately, that list has to be global (we have to use it
% inside the group for the options of a given |\SubMatrix|).
% \begin{macrocode}
\seq_new:N \g_@@_submatrix_names_seq
% \end{macrocode}
-%
+%
+%
% \medskip
% We are able to determine the number of columns specified in the preamble (for
% the environments with explicit preamble, of course and without the potential
@@ -5531,6 +5486,17 @@ version 2005/12/01 or later.
% \begin{macrocode}
\int_new:N \g_@@_block_box_int
% \end{macrocode}
+%
+% \medskip
+% \begin{macrocode}
+\dim_new:N \l_@@_submatrix_extra_height_dim
+\dim_new:N \l_@@_submatrix_left_xshift_dim
+\dim_new:N \l_@@_submatrix_right_xshift_dim
+\clist_new:N \l_@@_submatrix_hlines_clist
+\clist_new:N \l_@@_submatrix_vlines_clist
+% \end{macrocode}
+%
+%
%
% \bigskip
% \textbf{Variables for the exterior rows and columns}\par\nobreak
@@ -5853,7 +5819,7 @@ version 2005/12/01 or later.
% \end{macrocode}
%
% \medskip
-% The command |\@@_pgf_rect_node:nnn| is a variant of |\@@_pgr_rect_node:nnnn|:
+% The command |\@@_pgf_rect_node:nnn| is a variant of |\@@_pgf_rect_node:nnnn|:
% it takes two \textsc{pgf} points as arguments instead of the four dimensions
% which are the coordinates.
% \begin{macrocode}
@@ -6097,7 +6063,7 @@ version 2005/12/01 or later.
% \end{macrocode}
%
% \bigskip
-% The following token list corresponds to the key |delimiters-color|.
+% The following token list corresponds to the key |delimiters/color|.
% \begin{macrocode}
\tl_new:N \l_@@_delimiters_color_tl
% \end{macrocode}
@@ -6150,7 +6116,7 @@ version 2005/12/01 or later.
% construction of the array and not when we draw the dotted lines).
% \begin{macrocode}
draw-first .code:n = \prg_do_nothing: ,
- unknown .code:n = \@@_error:n { Unknown~option~for~xdots }
+ unknown .code:n = \@@_error:n { Unknown~key~for~xdots }
}
% \end{macrocode}
%
@@ -6174,6 +6140,8 @@ version 2005/12/01 or later.
% \begin{macrocode}
\keys_define:nn { NiceMatrix / Global }
{
+ rules .code:n = \keys_set:nn { NiceMatrix / rules } { #1 } ,
+ rules .value_required:n = true ,
standard-cline .bool_set:N = \l_@@_standard_cline_bool ,
standard-cline .default:n = true ,
cell-space-top-limit .dim_set:N = \l_@@_cell_space_top_limit_dim ,
@@ -6206,6 +6174,13 @@ version 2005/12/01 or later.
code-for-last-row .value_required:n = true ,
hlines .bool_set:N = \l_@@_hlines_bool ,
vlines .bool_set:N = \l_@@_vlines_bool ,
+ vlines-in-sub-matrix .code:n =
+ {
+ \tl_if_single_token:nTF { #1 }
+ { \tl_set:Nn \l_@@_letter_vlism_tl { #1 } }
+ { \@@_error:n { One~letter~allowed } }
+ } ,
+ vlines-in-sub-matrix .value_required:n = true ,
hvlines .code:n =
{
\bool_set_true:N \l_@@_vlines_bool
@@ -6369,6 +6344,7 @@ version 2005/12/01 or later.
NiceMatrixOptions / rules .inherit:n = NiceMatrix / rules ,
NiceMatrixOptions / notes .inherit:n = NiceMatrix / notes ,
NiceMatrixOptions / sub-matrix .inherit:n = NiceMatrix / sub-matrix ,
+ SubMatrix / rules .inherit:n = NiceMatrix / rules ,
CodeAfter / xdots .inherit:n = NiceMatrix / xdots ,
NiceMatrix .inherit:n =
{
@@ -6409,6 +6385,8 @@ version 2005/12/01 or later.
% \begin{macrocode}
\keys_define:nn { NiceMatrix / NiceMatrixOptions }
{
+ delimiters / color .tl_set:N = \l_@@_delimiters_color_tl ,
+ delimiters / color .value_required:n = true ,
delimiters-color .tl_set:N = \l_@@_delimiters_color_tl ,
delimiters-color .value_required:n = true ,
last-col .code:n = \tl_if_empty:nF { #1 }
@@ -6478,7 +6456,7 @@ version 2005/12/01 or later.
{
\tl_if_single_token:nTF { #1 }
{ \str_set:Nx \l_@@_letter_for_dotted_lines_str { #1 } }
- { \@@_error:n { Bad~value~for~letter~for~dotted~lines } }
+ { \@@_error:n { One~letter~allowed } }
} ,
letter-for-dotted-lines .value_required:n = true ,
notes .code:n = \keys_set:nn { NiceMatrix / notes } { #1 } ,
@@ -6523,6 +6501,8 @@ version 2005/12/01 or later.
r .code:n = \tl_set:Nn \l_@@_type_of_col_tl r ,
small .bool_set:N = \l_@@_small_bool ,
small .value_forbidden:n = true ,
+ delimiters / color .tl_set:N = \l_@@_delimiters_color_tl ,
+ delimiters / color .value_required:n = true ,
delimiters-color .tl_set:N = \l_@@_delimiters_color_tl ,
delimiters-color .value_required:n = true ,
unknown .code:n = \@@_error:n { Unknown~option~for~NiceMatrix }
@@ -6557,6 +6537,8 @@ version 2005/12/01 or later.
tabularnote .value_required:n = true ,
delimiters-color .tl_set:N = \l_@@_delimiters_color_tl ,
delimiters-color .value_required:n = true ,
+ delimiters / color .tl_set:N = \l_@@_delimiters_color_tl ,
+ delimiters / color .value_required:n = true ,
unknown .code:n = \@@_error:n { Unknown~option~for~NiceArray }
}
% \end{macrocode}
@@ -6795,7 +6777,7 @@ version 2005/12/01 or later.
% \item we test the existence of these nodes in order to determine whether a
% cell is empty when we search the extremities of a dotted line.
% \end{itemize}
-% However, it's very difficult to determine whether a cell is empty. As of now,
+% However, it's very difficult to determine whether a cell is empty. As for now,
% we use the following technic:
% \begin{itemize}
% \item if the width of the box |\l_@@_cell_box| (created with the content of
@@ -6805,7 +6787,7 @@ version 2005/12/01 or later.
% \item the cells with a command |\Ldots| or |\Cdots|, |\Vdots|, etc.,
% should also be considered as empty; if |nullify-dots| is in force, there would
% be nothing to do (in this case the previous commands only write an instruction
-% in a kind of |code-after|); however, if |nullify-dots| is not in force, a
+% in a kind of |\CodeAfter|); however, if |nullify-dots| is not in force, a
% phantom of |\ldots|, |\cdots|, |\vdots| is inserted and its width is not equal
% to zero; that's why these commands raise a boolean |\g_@@_empty_cell_bool| and
% we begin by testing this boolean.
@@ -6897,11 +6879,6 @@ version 2005/12/01 or later.
% \begin{macrocode}
\cs_new_protected:Npn \@@_instruction_of_type:nnn #1 #2 #3
{
-% \end{macrocode}
-% It's important to use a |\tl_gput_right:cx| and not a |\tl_gput_left:cx|
-% because we want the |\Ddots| lines to be drawn in the order of appearance
-% in the array (for parallelisation).
-% \begin{macrocode}
\bool_if:nTF { #1 } \tl_gput_left:cx \tl_gput_right:cx
{ g_@@_ #2 _ lines _ tl }
{
@@ -7414,7 +7391,7 @@ version 2005/12/01 or later.
{
% \end{macrocode}
% First, we give values to the LaTeX counters |iRow| and |jCol|. We remind that,
-% in the |code-before| (and in the |code-after|) they represent the numbers of
+% in the |code-before| (and in the |\CodeAfter|) they represent the numbers of
% rows and columns of the array (without the potential last row and last column).
% \begin{macrocode}
\int_zero_new:N \c@iRow
@@ -7464,6 +7441,15 @@ version 2005/12/01 or later.
{ \pgfpointdiff \@@_picture_position: \@@_node_position: }
}
\endpgfpicture
+% \end{macrocode}
+% Now, you create the diagonal nodes by using the |row| nodes and the |col| nodes.
+% \begin{macrocode}
+ \@@_create_diag_nodes:
+% \end{macrocode}
+%
+% \medskip
+% Now, yet another settings before the executation of the |code-before|.
+% \begin{macrocode}
\group_begin:
\bool_if:NT \c_@@_tikz_loaded_bool
{
@@ -7898,6 +7884,12 @@ version 2005/12/01 or later.
}
{ \tl_gclear:N \g_@@_preamble_tl }
% \end{macrocode}
+% The sequence |\g_@@_cols_vlsim_seq| will contain the numbers of the columns
+% where you will to have to draw vertical lines in the potential sub-matrices
+% (hence the name |vlism|).
+% \begin{macrocode}
+ \seq_clear:N \g_@@_cols_vlism_seq
+% \end{macrocode}
% The counter |\l_tmpa_int| will count the number of consecutive occurrences
% of the symbol \verb+|+.
% \begin{macrocode}
@@ -7957,8 +7949,7 @@ version 2005/12/01 or later.
% \begin{macrocode}
\dim_compare:nNnT \l_@@_tabular_width_dim = \c_zero_dim
{
- \tl_gput_right:Nn
- \g_@@_preamble_tl
+ \tl_gput_right:Nn \g_@@_preamble_tl
{ > { \@@_error_too_much_cols: } l }
}
% \end{macrocode}
@@ -8004,15 +7995,25 @@ version 2005/12/01 or later.
{
\str_if_eq:VnTF \l_@@_letter_for_dotted_lines_str { #1 }
{ \@@_patch_preamble_xi:n #1 }
- {
- \bool_lazy_and:nnTF
- { \str_if_eq_p:nn { : } { #1 } }
- \c_@@_arydshln_loaded_bool
- {
- \tl_gput_right:Nn \g_@@_preamble_tl { : }
+ {
+ \str_if_eq:VnTF \l_@@_letter_vlism_tl { #1 }
+ {
+ \seq_gput_right:Nx \g_@@_cols_vlism_seq
+ { \int_eval:n { \c@jCol + 1 } }
+ \tl_gput_right:Nx \g_@@_preamble_tl
+ { \exp_not:N ! { \skip_horizontal:N \arrayrulewidth } }
\@@_patch_preamble:n
}
- { \@@_fatal:nn { unknown~column~type } { #1 } }
+ {
+ \bool_lazy_and:nnTF
+ { \str_if_eq_p:nn { : } { #1 } }
+ \c_@@_arydshln_loaded_bool
+ {
+ \tl_gput_right:Nn \g_@@_preamble_tl { : }
+ \@@_patch_preamble:n
+ }
+ { \@@_fatal:nn { unknown~column~type } { #1 } }
+ }
}
}
}
@@ -8102,11 +8103,15 @@ version 2005/12/01 or later.
\@@_Cell:
\begin { minipage } [ #1 ] { #3 }
\mode_leave_vertical:
- \arraybackslash % added in the version 5.8
- \box_use:N \@arstrutbox
+ \arraybackslash
+ \vrule height \box_ht:N \@arstrutbox depth 0 pt width 0 pt % v. 5.11
}
c
- < { \box_use:N \@arstrutbox \end { minipage } \@@_end_Cell: }
+ < {
+ \vrule height 0 pt depth \box_dp:N \@arstrutbox width 0 pt % v. 5.11
+ \end { minipage }
+ \@@_end_Cell:
+ }
}
% \end{macrocode}
% We increment the counter of columns, and then we test for the presence of a |<|.
@@ -8603,7 +8608,7 @@ version 2005/12/01 or later.
{ \@@_fatal:n { double-backslash~in~light-syntax } }
}
% \end{macrocode}
-% Now, you extract the |code-after| of the body of the environment. Maybe, there
+% Now, you extract the |\CodeAfter| of the body of the environment. Maybe, there
% is no command |\CodeAfter| in the body. That's why you put a marker
% |\CodeAfter| after |#1|. If there is yet a |\CodeAfter| in |#1|, this second
% (or third...) |\CodeAfter| will be catched in the value of
@@ -8884,6 +8889,12 @@ version 2005/12/01 or later.
{
>
{
+% \end{macrocode}
+% At the beginning of the cell, we link |\CodeAfter| to a command which do
+% \emph{not} begin with |\omit| (whereas the standard version of |\CodeAfter|
+% begins with |\omit|).
+% \begin{macrocode}
+ \cs_set_eq:NN \CodeAfter \@@_CodeAfter_i:n
\bool_gset_true:N \g_@@_after_col_zero_bool
\@@_begin_of_row:
% \end{macrocode}
@@ -8955,6 +8966,12 @@ version 2005/12/01 or later.
>
{
% \end{macrocode}
+% At the beginning of the cell, we link |\CodeAfter| to a command which do
+% \emph{not} begin with |\omit| (whereas the standard version of |\CodeAfter|
+% begins with |\omit|).
+% \begin{macrocode}
+ \cs_set_eq:NN \CodeAfter \@@_CodeAfter_i:n
+% \end{macrocode}
% With the flag |\g_@@_last_col_found_bool|, we will know that the ``last
% column'' is really used.
% \begin{macrocode}
@@ -9259,7 +9276,17 @@ version 2005/12/01 or later.
}
% \end{macrocode}
%
-%
+% \medskip
+% \begin{macrocode}
+ \@@_create_diag_nodes:
+ \str_if_empty:NF \l_@@_name_str
+ {
+ \pgfpicture
+ \pgfrememberpicturepositiononpagetrue
+ \pgfnodealias { \l_@@_name_str - ##1 } { \@@_env: - ##1 }
+ \endpgfpicture
+ }
+% \end{macrocode}
%
% By default, the diagonal lines will be parallelized\footnote{It's possible to
% use the option |parallelize-diags| to disable this parallelization.}. There
@@ -9363,7 +9390,7 @@ version 2005/12/01 or later.
% \end{macrocode}
%
% \bigskip
-% Now, the |code-after|.
+% Now, the |\CodeAfter|.
% \begin{macrocode}
\bool_if:NT \c_@@_tikz_loaded_bool
{
@@ -9389,11 +9416,11 @@ version 2005/12/01 or later.
% \end{macrocode}
%
% We clear the list of the names of the potential |\SubMatrix| that will appear
-% in the |code-after| (unfortunately, that list has to be global).
+% in the |\CodeAfter| (unfortunately, that list has to be global).
% \begin{macrocode}
\seq_gclear:N \g_@@_submatrix_names_seq
% \end{macrocode}
-% And here's the |code-after|. Since the |code-after| may begin with an
+% And here's the |\CodeAfter|. Since the |\CodeAfter| may begin with an
% ``argument'' between square brackets of the options, we extract and treat that
% potential ``argument'' with the command |\@@_CodeAfter_keys:|.
% \begin{macrocode}
@@ -9450,7 +9477,7 @@ version 2005/12/01 or later.
%
% \bigskip
% The following command will extract the potential options (between square
-% brackets) at the beginning of the |code-after| (that is to say, when
+% brackets) at the beginning of the |\CodeAfter| (that is to say, when
% |\CodeAfter| is used, the options of that ``command'' |\CodeAfter|).
% \begin{macrocode}
\NewDocumentCommand \@@_CodeAfter_keys: { O { } }
@@ -9541,6 +9568,26 @@ version 2005/12/01 or later.
%
%
% \bigskip
+% The following command creates the diagonal nodes (in fact, if the matrix is
+% not a square matrix, not all the nodes are on the diagonal).
+%
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_create_diag_nodes:
+ {
+ \int_step_inline:nn { \int_max:nn \c@iRow \c@jCol + 1 }
+ {
+ \pgfpicture
+ \pgfrememberpicturepositiononpagetrue
+ \@@_qpoint:n { row - \int_min:nn { ##1 } { \c@iRow + 1 } }
+ \dim_set_eq:NN \l_tmpa_dim \pgf@y
+ \@@_qpoint:n { col - \int_min:nn { ##1 } { \c@jCol + 1 } }
+ \pgfcoordinate { \@@_env: - ##1 } { \pgfpoint \pgf@x \l_tmpa_dim }
+ \endpgfpicture
+ }
+ }
+% \end{macrocode}
+%
+% \bigskip
% \subsection*{We draw the dotted lines}
%
% A dotted line will be said \emph{open} in one of its extremities when it stops
@@ -11025,7 +11072,7 @@ version 2005/12/01 or later.
% \bigskip
% \subsection*{The command \textbackslash line accessible in code-after}
%
-% In the |code-after|, the command |\@@_line:nn| will be linked to |\line|. This
+% In the |\CodeAfter|, the command |\@@_line:nn| will be linked to |\line|. This
% command takes two arguments which are the specifications of two cells in the
% array (in the format $i$-$j$) and draws a dotted line between these cells.
%
@@ -11033,7 +11080,7 @@ version 2005/12/01 or later.
% First, we write a command with an argument of the format $i$-$j$ and applies
% the command |\int_eval:n| to $i$ and~$j$ ; this must \emph{not} be protected
% (and is, of course fully expandable).\footnote{Indeed, we want that the user
-% may use the command |\line| in |code-after| with LaTeX counters in the
+% may use the command |\line| in |\CodeAfter| with LaTeX counters in the
% arguments --- with the command |\value|.}
% \begin{macrocode}
\cs_new:Npn \@@_double_int_eval:n #1-#2 \q_stop
@@ -11079,7 +11126,7 @@ version 2005/12/01 or later.
\cs_if_free_p:c { pgf @ sh @ ns @ \@@_env: - #2 }
}
{
- \@@_error:nnn { unknown~cell~for~line~in~code-after } { #1 } { #2 }
+ \@@_error:nnn { unknown~cell~for~line~in~CodeAfter } { #1 } { #2 }
}
{ \@@_draw_line_ii:nn { #1 } { #2 } }
}
@@ -11341,7 +11388,7 @@ version 2005/12/01 or later.
cols .tl_set:N = \l_@@_cols_tl ,
restart .bool_set:N = \l_@@_rowcolors_restart_bool ,
restart .default:n = true ,
- unknown .code:n = \@@_error:n { Unknown~option~for~rowcolors }
+ unknown .code:n = \@@_error:n { Unknown~key~for~rowcolors }
}
% \end{macrocode}
%
@@ -11655,7 +11702,7 @@ version 2005/12/01 or later.
}
% \end{macrocode}
% This definition may seem complicated by we must remind that the number of row
-% |\c@iRow| is incremented in the first cell of the row, \emph{after} an
+% |\c@iRow| is incremented in the first cell of the row, \emph{after} a
% potential vertical rule on the left side of the first cell.
%
% \smallskip
@@ -11675,8 +11722,8 @@ version 2005/12/01 or later.
%
% \bigskip
% The following command will be executed in the |internal-code-after|. The rule
-% will be drawn \emph{before} the column |#1|. |#2| is the number of consecutive
-% occurrences of \verb+|+.
+% will be drawn \emph{before} the column |#1| (that is to say on the left side).
+% |#2| is the number of consecutive occurrences of \verb+|+.
% \begin{macrocode}
\cs_new_protected:Npn \@@_vline:nn #1 #2
{
@@ -11715,11 +11762,11 @@ version 2005/12/01 or later.
% \begin{macrocode}
\bool_gset_true:N \g_tmpa_bool
\seq_map_inline:Nn \g_@@_pos_of_blocks_seq
- { \@@_test_if_vline_in_block:nnnn ##1 }
+ { \@@_test_vline_in_block:nnnn ##1 }
\seq_map_inline:Nn \g_@@_pos_of_xdots_seq
- { \@@_test_if_vline_in_block:nnnn ##1 }
+ { \@@_test_vline_in_block:nnnn ##1 }
\seq_map_inline:Nn \g_@@_pos_of_stroken_blocks_seq
- { \@@_test_if_vline_in_stroken_block:nnnn ##1 }
+ { \@@_test_vline_in_stroken_block:nnnn ##1 }
\clist_if_empty:NF \l_@@_except_corners_clist
\@@_test_in_corner_v:
\bool_if:NTF \g_tmpa_bool
@@ -11785,7 +11832,7 @@ version 2005/12/01 or later.
%
% \bigskip
% |#1| is the number of the column; |#2| is the number of vertical rules to
-% draw (with potentially a color between); |#3| and |#4| are the number of the
+% draw (with potentially a color between); |#3| and |#4| are the numbers of the
% rows between which the rule has to be drawn.
% \begin{macrocode}
\cs_new_protected:Npn \@@_vline_ii:nnnn #1 #2 #3 #4
@@ -11831,8 +11878,8 @@ version 2005/12/01 or later.
% \end{macrocode}
%
% \bigskip
-% The following draws a complete vertical rule in the column |#1| (|#2| is the
-% number of consecutive rules specified by the number of \verb+|+ in the
+% The following command draws a complete vertical rule in the column |#1| (|#2|
+% is the number of consecutive rules specified by the number of \verb+|+ in the
% preamble). This command will be used if there is no block in the array (and
% the key |except-corners| is not used).
% \begin{macrocode}
@@ -11875,7 +11922,7 @@ version 2005/12/01 or later.
\cs_new_protected:Npn \@@_hline_i:nn #1 #2
{
% \end{macrocode}
-% |\l_tmpa_tl| is the number of row and |\l_tmpb_tl| the number of column. Whe,
+% |\l_tmpa_tl| is the number of row and |\l_tmpb_tl| the number of column. When
% we have found a column corresponding to a rule to draw, we note its number in
% |\l_tmpc_tl|.
% \begin{macrocode}
@@ -11892,11 +11939,11 @@ version 2005/12/01 or later.
% \begin{macrocode}
\bool_gset_true:N \g_tmpa_bool
\seq_map_inline:Nn \g_@@_pos_of_blocks_seq
- { \@@_test_if_hline_in_block:nnnn ##1 }
+ { \@@_test_hline_in_block:nnnn ##1 }
\seq_map_inline:Nn \g_@@_pos_of_xdots_seq
- { \@@_test_if_hline_in_block:nnnn ##1 }
+ { \@@_test_hline_in_block:nnnn ##1 }
\seq_map_inline:Nn \g_@@_pos_of_stroken_blocks_seq
- { \@@_test_if_hline_in_stroken_block:nnnn ##1 }
+ { \@@_test_hline_in_stroken_block:nnnn ##1 }
\clist_if_empty:NF \l_@@_except_corners_clist \@@_test_in_corner_h:
\bool_if:NTF \g_tmpa_bool
{
@@ -12064,13 +12111,13 @@ version 2005/12/01 or later.
% \subsection*{The key hvlines}
%
%
-% The following command tests wether the current position in the array (given by
-% |\l_tmpa_tl| for the row and |\l_tmpb_tl| for the col) would provide an
+% The following command tests whether the current position in the array (given by
+% |\l_tmpa_tl| for the row and |\l_tmpb_tl| for the column) would provide an
% horizontal rule towards the right in the block delimited by the four arguments
% |#1|, |#2|, |#3| and |#4|. If this rule would be in the block (it must not be
% drawn), the boolean |\l_tmpa_bool| is set to |false|.
% \begin{macrocode}
-\cs_new_protected:Npn \@@_test_if_hline_in_block:nnnn #1 #2 #3 #4
+\cs_new_protected:Npn \@@_test_hline_in_block:nnnn #1 #2 #3 #4
{
\bool_lazy_all:nT
{
@@ -12085,7 +12132,7 @@ version 2005/12/01 or later.
%
% The same for vertical rules.
% \begin{macrocode}
-\cs_new_protected:Npn \@@_test_if_vline_in_block:nnnn #1 #2 #3 #4
+\cs_new_protected:Npn \@@_test_vline_in_block:nnnn #1 #2 #3 #4
{
\bool_lazy_all:nT
{
@@ -12099,7 +12146,7 @@ version 2005/12/01 or later.
% \end{macrocode}
%
% \begin{macrocode}
-\cs_new_protected:Npn \@@_test_if_hline_in_stroken_block:nnnn #1 #2 #3 #4
+\cs_new_protected:Npn \@@_test_hline_in_stroken_block:nnnn #1 #2 #3 #4
{
\bool_lazy_all:nT
{
@@ -12113,7 +12160,7 @@ version 2005/12/01 or later.
% \end{macrocode}
%
% \begin{macrocode}
-\cs_new_protected:Npn \@@_test_if_vline_in_stroken_block:nnnn #1 #2 #3 #4
+\cs_new_protected:Npn \@@_test_vline_in_stroken_block:nnnn #1 #2 #3 #4
{
\bool_lazy_all:nT
{
@@ -12332,7 +12379,7 @@ version 2005/12/01 or later.
%
%
% \medskip
-% The command |\@@_hdottedline:n| is the command written in the |code-after|
+% The command |\@@_hdottedline:n| is the command written in the |\CodeAfter|
% that will actually draw the dotted line. Its argument is the number of the row
% \emph{before} which we will draw the row.
% \begin{macrocode}
@@ -12446,16 +12493,14 @@ version 2005/12/01 or later.
% bracket. The correction by |0.5 \l_@@_inter_dots_dim| is \emph{ad hoc} for a
% better result.
% \begin{macrocode}
- \tl_set:Nn \l_tmpa_tl { ( }
- \tl_if_eq:NNF \l_@@_left_delim_tl \l_tmpa_tl
+ \tl_if_eq:NnF \l_@@_left_delim_tl (
{ \dim_gadd:Nn \l_@@_x_initial_dim { 0.5 \l_@@_inter_dots_dim } }
- \tl_set:Nn \l_tmpa_tl { ) }
- \tl_if_eq:NNF \l_@@_right_delim_tl \l_tmpa_tl
+ \tl_if_eq:NnF \l_@@_right_delim_tl )
{ \dim_gsub:Nn \l_@@_x_final_dim { 0.5 \l_@@_inter_dots_dim } }
% \end{macrocode}
%
% \medskip
-% As of now, we have no option to control the style of the lines drawn by
+% As for now, we have no option to control the style of the lines drawn by
% |\hdottedline| and the specifier ``|:|'' in the preamble. That's why we impose
% the style |standard|.
% \begin{macrocode}
@@ -12523,7 +12568,7 @@ version 2005/12/01 or later.
\@@_qpoint:n { row - \@@_succ:n \c@iRow }
\dim_set:Nn \l_@@_y_final_dim { \pgf@y + 0.5 \l_@@_inter_dots_dim }
% \end{macrocode}
-% As of now, we have no option to control the style of the lines drawn by
+% As for now, we have no option to control the style of the lines drawn by
% |\hdottedline| and the specifier ``|:|'' in the preamble. That's why we impose
% the style |standard|.
% \begin{macrocode}
@@ -12544,7 +12589,7 @@ version 2005/12/01 or later.
% \end{macrocode}
%
% \bigskip
-% As of now, there is only one option available for the environment
+% As for now, there is only one option available for the environment
% |{NiceMatrixBlock}|.
% \begin{macrocode}
\keys_define:nn { NiceMatrix / NiceMatrixBlock }
@@ -13293,7 +13338,7 @@ version 2005/12/01 or later.
% replaced by the line which is commented.
% \begin{macrocode}
color .code:n =
- \@@_error:n { Key~color~for~Block }
+ \@@_fatal:n { Key~color~for~Block }
\tl_set:Nn \l_@@_fill_tl { #1 } ,
% color .code:n = \color { #1 } \tl_set:Nn \l_@@_draw_tl { #1 } ,
color .value_required:n = true ,
@@ -13347,10 +13392,8 @@ version 2005/12/01 or later.
\int_compare:nNnTF { #4 } > { 99 }
{ \int_set_eq:NN \l_@@_last_col_int \c@jCol }
{ \int_set:Nn \l_@@_last_col_int { #4 } }
- \bool_lazy_or:nnTF
- { \int_compare_p:nNn \l_@@_last_row_int > \g_@@_row_total_int }
- { \int_compare_p:nNn \l_@@_last_col_int > \g_@@_col_total_int }
- {
+ \int_compare:nNnTF \l_@@_last_col_int > \g_@@_col_total_int
+ {
\int_compare:nTF
{ \l_@@_last_col_int <= \g_@@_static_num_of_col_int }
{
@@ -13361,9 +13404,13 @@ version 2005/12/01 or later.
\@@_msg_redirect_name:nn { columns~not~used } { none }
\group_end:
}
+ { \msg_error:nnnn { nicematrix } { Block~too~large~1 } { #1 } { #2 } }
+ }
+ {
+ \int_compare:nNnTF \l_@@_last_row_int > \g_@@_row_total_int
{ \msg_error:nnnn { nicematrix } { Block~too~large~1 } { #1 } { #2 } }
+ { \@@_Block_v:nnnnnn { #1 } { #2 } { #3 } { #4 } { #5 } { #6 } }
}
- { \@@_Block_v:nnnnnn { #1 } { #2 } { #3 } { #4 } { #5 } { #6 } }
}
% \end{macrocode}
%
@@ -13979,17 +14026,20 @@ version 2005/12/01 or later.
% \subsection*{The keyword \textbackslash CodeAfter}
%
%
-% The |code-after| (inserted with the key |code-after| or after the keyword
-% |\CodeAfter| can always begin with a list of pairs \emph{key-value} between
-% square brackets). Here the corresponding set of keys.
+% The |\CodeAfter| (inserted with the key |code-after| or after the keyword
+% |\CodeAfter|) may always begin with a list of pairs \emph{key-value} between
+% square brackets. Here is the corresponding set of keys.
% \begin{macrocode}
+\keys_define:nn { NiceMatrix }
+ { CodeAfter / rules .inherit:n = NiceMatrix / rules }
\keys_define:nn { NiceMatrix / CodeAfter }
{
- sub-matrix .code:n =
- \keys_set:nn { NiceMatrix / sub-matrix } { #1 } ,
+ sub-matrix .code:n = \keys_set:nn { NiceMatrix / sub-matrix } { #1 } ,
sub-matrix .value_required:n = true ,
- delimiters-color .tl_set:N = \l_@@_delimiters_color_tl ,
- delimiters-color .value_required:n = true ,
+ delimiters / color .tl_set:N = \l_@@_delimiters_color_tl ,
+ delimiters / color .value_required:n = true ,
+ rules .code:n = \keys_set:nn { NiceMatrix / rules } { #1 } ,
+ rules .value_required:n = true ,
unknown .code:n = \@@_error:n { Unknown~key~for~CodeAfter }
}
% \end{macrocode}
@@ -14034,8 +14084,7 @@ version 2005/12/01 or later.
% If this is really the end of the current environment (of \pkg{nicematrix}), we
% put back the command |\end| and its argument in the TeX flow.
% \begin{macrocode}
- \str_if_eq:eeTF \@currenvir { #1 }
- { \end { #1 } }
+ \str_if_eq:eeTF \@currenvir { #1 } { \end { #1 } }
% \end{macrocode}
% If this is not the |\end| we are looking for, we put those tokens in
% |\g_nicematrix_code_after_tl| and we go on searching for the next command
@@ -14147,7 +14196,7 @@ version 2005/12/01 or later.
}
% \end{macrocode}
%
-% \subsection*{The command SubMatrix}
+% \subsection*{The command \textbackslash SubMatrix}
%
%
% \begin{macrocode}
@@ -14161,15 +14210,15 @@ version 2005/12/01 or later.
right-xshift .value_required:n = true ,
xshift .meta:n = { left-xshift = #1, right-xshift = #1 } ,
xshift .value_required:n = true ,
- delimiters-color .tl_set:N = \l_@@_delimiters_color_tl ,
- delimiters-color .value_required:n = true ,
+ delimiters / color .tl_set:N = \l_@@_delimiters_color_tl ,
+ delimiters / color .value_required:n = true ,
slim .bool_set:N = \l_@@_submatrix_slim_bool ,
slim .default:n = true ,
}
\keys_define:nn { NiceMatrix }
{
- SubMatrix .inherit:n = NiceMatrix /sub-matrix ,
- CodeAfter / sub-matrix .inherit:n = NiceMatrix / sub-matrix
+ SubMatrix .inherit:n = NiceMatrix / sub-matrix ,
+ CodeAfter / sub-matrix .inherit:n = NiceMatrix / sub-matrix ,
}
% \end{macrocode}
%
@@ -14179,6 +14228,10 @@ version 2005/12/01 or later.
% \begin{macrocode}
\keys_define:nn { NiceMatrix / SubMatrix }
{
+ hlines .clist_set:N = \l_@@_submatrix_hlines_clist ,
+ hlines .default:n = all ,
+ vlines .clist_set:N = \l_@@_submatrix_vlines_clist ,
+ vlines .default:n = all ,
name .code:n =
\tl_if_empty:nTF { #1 }
{ \@@_error:n { Invalid~name~format } }
@@ -14194,6 +14247,8 @@ version 2005/12/01 or later.
}
{ \@@_error:n { Invalid~name~format } }
} ,
+ rules .code:n = \keys_set:nn { NiceMatrix / rules } { #1 } ,
+ rules .value_required:n = true ,
name .value_required:n = true ,
unknown .code:n = \@@_error:n { Unknown~key~for~SubMatrix }
}
@@ -14205,7 +14260,7 @@ version 2005/12/01 or later.
% \begin{itemize}
% \item |#1| is the left delimiter;
% \item |#2| is the upper-left cell of the matrix with the format $i$-$j$;
-% \item |#2| is the lower-right cell of the matrix with the format $i$-$j$;
+% \item |#3| is the lower-right cell of the matrix with the format $i$-$j$;
% \item |#4| is the right delimiter;
% \item |#5| is the list of options of the command.
% \end{itemize}
@@ -14229,9 +14284,6 @@ version 2005/12/01 or later.
{ \int_compare_p:nNn \l_tmpd_tl > \g_@@_col_total_int }
{ \@@_error:n { SubMatrix~too~large } }
{
- \dim_zero_new:N \l_@@_submatrix_extra_height_dim
- \dim_zero_new:N \l_@@_submatrix_left_xshift_dim
- \dim_zero_new:N \l_@@_submatrix_right_xshift_dim
\str_clear_new:N \l_@@_submatrix_name_str
\keys_set:nn { NiceMatrix / SubMatrix } { #5 }
\pgfpicture
@@ -14293,6 +14345,109 @@ version 2005/12/01 or later.
\dim_set_eq:NN \nulldelimiterspace \c_zero_dim
% \end{macrocode}
%
+% \bigskip
+% We will draw the rules in the |\SubMatrix|.
+% \begin{macrocode}
+ \group_begin:
+ \pgfsetlinewidth { 1.1 \arrayrulewidth }
+ \tl_if_empty:NF \l_@@_rules_color_tl
+ { \exp_after:wN \@@_set_CT@arc@: \l_@@_rules_color_tl \q_stop }
+ \CT@arc@
+% \end{macrocode}
+% Now, we draw the potential vertical rules specified in the preamble of the
+% environments with the letter fixed with the key |vlines-in-sub-matrix|. The
+% list of the columns where there is such rule to draw is in |\g_@@_cols_vlism_seq|.
+% \begin{macrocode}
+ \seq_map_inline:Nn \g_@@_cols_vlism_seq
+ {
+ \int_compare:nNnT \l_tmpb_tl < { ##1 }
+ {
+ \int_compare:nNnT { ##1 } < { \int_eval:n { \l_tmpd_tl + 1 } }
+ {
+% \end{macrocode}
+% First, we extract the value of the abscissa of the rule we have to draw.
+% \begin{macrocode}
+ \@@_qpoint:n { col - ##1 }
+ \pgfpathmoveto { \pgfpoint \pgf@x \l_@@_y_initial_dim }
+ \pgfpathlineto { \pgfpoint \pgf@x \l_@@_y_final_dim }
+ \pgfusepathqstroke
+ }
+ }
+ }
+% \end{macrocode}
+%
+% \medskip
+% Now, we draw the vertical rules specified in the key |vlines| of |\SubMatrix|.
+% The last argument of |\int_step_inline:nn| or |\clist_map_inline:Nn| is given
+% by curryfication.
+% \begin{macrocode}
+ \tl_if_eq:NnTF \l_@@_submatrix_vlines_clist { all }
+ { \int_step_inline:nn { \l_tmpd_tl - \l_tmpb_tl } }
+ { \clist_map_inline:Nn \l_@@_submatrix_vlines_clist }
+ {
+ \bool_lazy_and:nnTF
+ { \int_compare_p:nNn { ##1 } > 0 }
+ { \int_compare_p:nNn { ##1 } < { \l_tmpd_tl - \l_tmpb_tl + 1 } }
+ {
+ \@@_qpoint:n { col - \int_eval:n { ##1 + \l_tmpb_tl } }
+ \pgfpathmoveto { \pgfpoint \pgf@x \l_@@_y_initial_dim }
+ \pgfpathlineto { \pgfpoint \pgf@x \l_@@_y_final_dim }
+ \pgfusepathqstroke
+ }
+ { \@@_error:nnn { Wrong~line~in~SubMatrix } { vertical } { ##1 } }
+ }
+% \end{macrocode}
+%
+% \medskip
+% Now, we draw the horizontal rules specified in the key |hlines| of
+% |\SubMatrix|.
+% The last argument of |\int_step_inline:nn| or |\clist_map_inline:Nn| is given
+% by curryfication.
+% \begin{macrocode}
+ \tl_if_eq:NnTF \l_@@_submatrix_hlines_clist { all }
+ { \int_step_inline:nn { \l_tmpc_tl - \l_tmpa_tl } }
+ { \clist_map_inline:Nn \l_@@_submatrix_hlines_clist }
+ {
+ \bool_lazy_and:nnTF
+ { \int_compare_p:nNn { ##1 } > 0 }
+ { \int_compare_p:nNn { ##1 } < { \l_tmpc_tl - \l_tmpa_tl + 1 } }
+ {
+ \@@_qpoint:n { row - \int_eval:n { ##1 + \l_tmpa_tl } }
+% \end{macrocode}
+% We use a group to protect |\l_tmpa_dim| and |\l_tmpb_dim|.
+% \begin{macrocode}
+ \group_begin:
+% \end{macrocode}
+% We compute in |\l_tmpa_dim| the $x$-value of the left end of the rule.
+% \begin{macrocode}
+ \dim_set:Nn \l_tmpa_dim
+ { \l_@@_x_initial_dim - \l_@@_submatrix_left_xshift_dim }
+ \str_case:nn { #1 }
+ {
+ ( { \dim_sub:Nn \l_tmpa_dim { 0.9 mm } }
+ [ { \dim_sub:Nn \l_tmpa_dim { 0.2 mm } }
+ \{ { \dim_sub:Nn \l_tmpa_dim { 0.9 mm } }
+ }
+ \pgfpathmoveto { \pgfpoint \l_tmpa_dim \pgf@y }
+% \end{macrocode}
+% We compute in |\l_tmpb_dim| the $x$-value of the right end of the rule.
+% \begin{macrocode}
+ \dim_set:Nn \l_tmpb_dim
+ { \l_@@_x_final_dim + \l_@@_submatrix_right_xshift_dim }
+ \str_case:nn { #4 }
+ {
+ ) { \dim_add:Nn \l_tmpb_dim { 0.9 mm } }
+ ] { \dim_add:Nn \l_tmpb_dim { 0.2 mm } }
+ \} { \dim_add:Nn \l_tmpb_dim { 0.9 mm } }
+ }
+ \pgfpathlineto { \pgfpoint \l_tmpb_dim \pgf@y }
+ \pgfusepathqstroke
+ \group_end:
+ }
+ { \@@_error:nnn { Wrong~line~in~SubMatrix } { horizontal } { ##1 } }
+ }
+% \end{macrocode}
+%
% \medskip
% If the key |name| has been used for the command |\SubMatrix|, we create a PGF
% node with that name for the submatrix (this node does not take into account
@@ -14304,7 +14459,9 @@ version 2005/12/01 or later.
\l_@@_x_initial_dim \l_@@_y_initial_dim
\l_@@_x_final_dim \l_@@_y_final_dim
}
+ \group_end:
% \end{macrocode}
+% The group was for |\CT@arc@| (the color of the rules).
%
% \medskip
% Now, we deal with the left delimiter. Of course, the environment
@@ -14405,6 +14562,9 @@ version 2005/12/01 or later.
}
% \end{macrocode}
%
+%
+%
+%
% \bigskip
% \subsection*{We process the options at package loading}
%
@@ -14420,7 +14580,6 @@ version 2005/12/01 or later.
% instruction is executed.
%
% \medskip
-%% \medskip
% The boolean |\g_@@_footnotehyper_bool| will indicate if the option
% |footnotehyper| is used.
% \begin{macrocode}
@@ -14692,18 +14851,18 @@ version 2005/12/01 or later.
% \end{macrocode}
%
% \begin{macrocode}
-\@@_msg_new:nn { Unknown~option~for~xdots }
+\@@_msg_new:nn { Unknown~key~for~xdots }
{
- As~for~now~there~is~only~three~key~available~here:~'color',~'line-style'~
+ As~for~now,~there~is~only~three~key~available~here:~'color',~'line-style'~
and~'shorten'~(and~you~try~to~use~'\l_keys_key_str').~If~you~go~on,~
this~key~will~be~ignored.
}
% \end{macrocode}
%
% \begin{macrocode}
-\@@_msg_new:nn { Unknown~option~for~rowcolors }
+\@@_msg_new:nn { Unknown~key~for~rowcolors }
{
- As~for~now~there~is~only~two~keys~available~here:~'cols'~and~'respect-blocks'~
+ As~for~now,~there~is~only~two~keys~available~here:~'cols'~and~'respect-blocks'~
(and~you~try~to~use~'\l_keys_key_str').~If~you~go~on,~
this~key~will~be~ignored.
}
@@ -14714,8 +14873,8 @@ version 2005/12/01 or later.
{
The~key~'color'~for~the~command~\token_to_str:N \Block\
is~deprecated:~you~should~use~'fill'~instead.\\
- You~can~go~on~for~this~time~but~remember~that~that~key~
- will~be~deleted~in~a~future~version.
+ This~error~is~fatal.
+
}
% \end{macrocode}
%
@@ -14782,6 +14941,15 @@ version 2005/12/01 or later.
If~you~go~on,~this~key~will~be~ignored.
}
% \end{macrocode}
+%
+% \begin{macrocode}
+\@@_msg_new:nn { Wrong~line~in~SubMatrix }
+ {
+ You~try~to~draw~a~#1~line~of~number~'#2'~in~a~
+ \token_to_str:N \SubMatrix\ of~your~\@@_full_name_env:\ but~that~
+ number~is~not~valid.~If~you~go~on,~it~will~be~ignored.
+ }
+% \end{macrocode}
%
% \begin{macrocode}
\@@_msg_new:nn { empty~environment }
@@ -14798,7 +14966,7 @@ version 2005/12/01 or later.
% \end{macrocode}
%
% \begin{macrocode}
-\@@_msg_new:nn { unknown~cell~for~line~in~code-after }
+\@@_msg_new:nn { unknown~cell~for~line~in~CodeAfter }
{
Your~command~\token_to_str:N\line\{#1\}\{#2\}~in~the~'code-after'~
can't~be~executed~because~a~cell~doesn't~exist.\\
@@ -14947,7 +15115,7 @@ version 2005/12/01 or later.
% \end{macrocode}
%
% \begin{macrocode}
-\@@_msg_new:nn { Bad~value~for~letter~for~dotted~lines }
+\@@_msg_new:nn { One~letter~allowed }
{
The~value~of~key~'\l_keys_key_str'~must~be~of~length~1.\\
If~you~go~on,~it~will~be~ignored.
@@ -14978,7 +15146,8 @@ version 2005/12/01 or later.
}
{
The~available~keys~are~(in~alphabetic~order):~
- delimiters-color,~
+ delimiters/color,~
+ rules~(with~the~subkeys~'color'~and~'width'),~
sub-matrix~(several~subkeys)~
and~xdots~(several~subkeys).~
The~latter~is~for~the~command~\token_to_str:N \line.
@@ -14986,12 +15155,25 @@ version 2005/12/01 or later.
% \end{macrocode}
%
% \begin{macrocode}
-\@@_msg_new:nn { Unknown~key~for~SubMatrix }
+\@@_msg_new:nnn { Unknown~key~for~SubMatrix }
{
The~key~'\l_keys_key_str'~is~unknown.\\
- The~only~keys~available~here~are~'delimiters-color',~'extra-height',~
- 'left-xshift',~'name',~'right-xshift',~'slim'~and~'xshift'.\\
If~you~go~on,~this~key~will~be~ignored. \\
+ For~a~list~of~the~available~keys~in~\token_to_str:N
+ \SubMatrix,~type~H~<return>.
+ }
+ {
+ The~available~keys~are~(in~alphabetic~order):~
+ 'delimiters/color',~
+ 'extra-height',~
+ 'hlines',~
+ 'left-xshift',~
+ 'name',~
+ 'right-xshift',~
+ 'rules'~(with~the~subkeys~'color'~and~'width'),~
+ 'slim',~
+ 'vlines'~and~'xshift'~(which~set~both~'left-xshift'~
+ and~'right-xshift').\\
}
% \end{macrocode}
%
@@ -15037,7 +15219,7 @@ version 2005/12/01 or later.
create-extra-nodes,~
create-medium-nodes,~
create-large-nodes,~
- delimiters-color,~
+ delimiters/color,~
end-of-row,~
first-col,~
first-row,~
@@ -15054,6 +15236,7 @@ version 2005/12/01 or later.
renew-dots,~
renew-matrix,~
right-margin,~
+ rules~(with~the~subkeys~'color'~and~'width'),~
small,~
sub-matrix~(several~subkeys),
vlines,~
@@ -15087,7 +15270,7 @@ version 2005/12/01 or later.
create-extra-nodes,~
create-medium-nodes,~
create-large-nodes,~
- delimiters-color,~
+ delimiters/color,~
extra-left-margin,~
extra-right-margin,~
first-col,~
@@ -15105,8 +15288,7 @@ version 2005/12/01 or later.
nullify-dots,~
renew-dots,~
right-margin,~
- rules/color,~
- rules/width,~
+ rules~(with~the~subkeys~'color'~and~'width'),~
small,~
t,~
vlines,~
@@ -15146,7 +15328,7 @@ version 2005/12/01 or later.
create-extra-nodes,~
create-medium-nodes,~
create-large-nodes,~
- delimiters-color,~
+ delimiters/color,~
extra-left-margin,~
extra-right-margin,~
first-col,~
@@ -15164,8 +15346,7 @@ version 2005/12/01 or later.
r,~
renew-dots,~
right-margin,~
- rules/color,~
- rules/width,~
+ rules~(with~the~subkeys~'color'~and~'width'),~
small,~
t,~
vlines,~
@@ -15218,8 +15399,7 @@ version 2005/12/01 or later.
nullify-dots,~
renew-dots,~
right-margin,~
- rules/color,~
- rules/width,~
+ rules~(with~the~subkeys~'color'~and~'width'),~
t,~
vlines,~
xdots/color,~
@@ -15523,7 +15703,7 @@ version 2005/12/01 or later.
%
% The option |dotted-lines-margin| has been renamed in |xdots/shorten| and the
% options |xdots/color| and |xdots/line-style| have been added for a complete
-% customization of the dotted lines.
+% customisation of the dotted lines.
%
% In the environments without preamble (|{NiceMatrix}|, |{pNiceMatrix}|, etc.),
% it's possible to use the options |l| (=|L|) or |r| (=|R|) to specify the type
@@ -15615,8 +15795,8 @@ version 2005/12/01 or later.
%
% The variable |\g_nicematrix_code_before_tl| is now public.
%
-% The key |baseline| can take in as value of the form \textsl{line-i} to align
-% the |\hline| in the row \textsl{i}.
+% The key |baseline| may take in as value an expression of the form
+% \textsl{line-i} to align the |\hline| in the row \textsl{i}.
%
% The key |hvlines-except-corners| may take in as value a list of corners (eg: NW,SE).
%
@@ -15679,6 +15859,12 @@ version 2005/12/01 or later.
% A (non fatal) error is raised when the key |transparent|, which is
% deprecated, is used.
%
+% \subsection*{Changes between versions 5.10 and 5.11}
+%
+% It's now possible, in the |code-before| and in the |\CodeAfter|, to use the
+% syntax \verb+|(i-|j)+ for the Tikz node at the intersection of the (potential)
+% horizontal rule number~$i$ and the (potential) vertical rule number~$j$.
+%
% \PrintIndex
%
% \tableofcontents
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
diff --git a/Master/texmf-dist/source/latex/spath3/spath3_code.dtx b/Master/texmf-dist/source/latex/spath3/spath3_code.dtx
index 621ab942f7b..afd132938c7 100644
--- a/Master/texmf-dist/source/latex/spath3/spath3_code.dtx
+++ b/Master/texmf-dist/source/latex/spath3/spath3_code.dtx
@@ -143,7 +143,7 @@ and the derived files spath3.ins,
%</driver>
% \fi
%
-% \CheckSum{8404}
+% \CheckSum{8929}
%
% \CharacterTable
% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
@@ -168,6 +168,7 @@ and the derived files spath3.ins,
% \changes{1.4}{2020/12/18}{A fair amount of code reimplementation and reorganisation, together with defining TikZ keys to make functions available for use.}
% \changes{2.0}{2021/01/19}{Refactored the code to remove the OO approach and make it functional, introduced the spath3 TikZ library to provide a user interface.}
% \changes{2.2}{2021/02/05}{Bugfixes and improvements, mainly with regard to the intersection and splitting routines.}
+% \changes{2.4}{2021/02/21}{Rejigged how the routines for using paths were implemented, added some more routines for joining paths.}
%
% \DoNotIndex{\newcommand,\newenvironment}
%
@@ -256,7 +257,7 @@ and the derived files spath3.ins,
\NeedsTeXFormat{LaTeX2e}
\RequirePackage{expl3}
\RequirePackage{pgf}
-\ProvidesExplPackage {spath3} {2021/02/05} {2.2} {Functions for
+\ProvidesExplPackage {spath3} {2021/02/21} {2.4} {Functions for
manipulating PGF soft paths}
\RequirePackage{xparse}
% \end{macrocode}
@@ -1756,7 +1757,7 @@ manipulating PGF soft paths}
{
\spath_splice_between:NVnn #1#1{#2}{#3}
}
-\cs_generate_variant:Nn \spath_splice_between:Nnn {NVV, cnn, cvv, Nvn}
+\cs_generate_variant:Nn \spath_splice_between:Nnn {NVV, cnn, cvv, Nvn, NVn}
\cs_new_protected_nopar:Npn \spath_gsplice_between:Nnnn #1#2#3#4
{
\@@_splice_between:nnn {#2}{#3}{#4}
@@ -1768,7 +1769,7 @@ manipulating PGF soft paths}
{
\spath_gsplice_between:NVnn #1#1{#2}{#3}
}
-\cs_generate_variant:Nn \spath_gsplice_between:Nnn {NVV, cnn, cvv}
+\cs_generate_variant:Nn \spath_gsplice_between:Nnn {NVV, cnn, cvv, Nvn, NVn}
% \end{macrocode}
% \end{macro}
%
@@ -1919,7 +1920,7 @@ manipulating PGF soft paths}
{
\spath_append_no_move:NVn #1#1{#2}
}
-\cs_generate_variant:Nn \spath_append_no_move:Nn {NV, cv, Nv}
+\cs_generate_variant:Nn \spath_append_no_move:Nn {NV, cv, Nv, cV}
\cs_new_protected_nopar:Npn \spath_gappend_no_move:Nnn #1#2#3
{
\@@_append_no_move:nn {#2}{#3}
@@ -1931,7 +1932,7 @@ manipulating PGF soft paths}
{
\spath_gappend_no_move:NVn #1#1{#2}
}
-\cs_generate_variant:Nn \spath_gappend_no_move:Nn {NV, cv, Nv}
+\cs_generate_variant:Nn \spath_gappend_no_move:Nn {NV, cv, Nv, cV}
% \end{macrocode}
% \end{macro}
%
@@ -1953,7 +1954,7 @@ manipulating PGF soft paths}
{
\spath_append:NVn #1#1{#2}
}
-\cs_generate_variant:Nn \spath_append:Nn {NV, Nv, cv}
+\cs_generate_variant:Nn \spath_append:Nn {NV, Nv, cv, cV}
\cs_new_protected_nopar:Npn \spath_gappend:Nnn #1#2#3
{
\tl_gset:Nn #1 {#2}
@@ -1964,7 +1965,7 @@ manipulating PGF soft paths}
{
\spath_gappend:NVn #1#1{#2}
}
-\cs_generate_variant:Nn \spath_gappend:Nn {NV, Nv, cv}
+\cs_generate_variant:Nn \spath_gappend:Nn {NV, Nv, cv, cV}
% \end{macrocode}
% \end{macro}
%
@@ -2235,6 +2236,128 @@ manipulating PGF soft paths}
% \end{macro}
%
% \begin{macro}[internal]{
+% \spath_replace_lines:Nn,
+% \spath_replace_lines:Nn,
+% \spath_replace_lines:Nn,
+% \spath_replace_lines:Nn,
+% }
+% Replace any line segments by B\'ezier curves.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_replace_lines:n #1
+{
+ \group_begin:
+ \tl_set:Nn \l_@@_tmpa_tl {#1}
+ \tl_clear:N \l_@@_tmpb_tl
+ \dim_set:Nn \l_@@_tmpa_dim {0pt}
+ \dim_set:Nn \l_@@_tmpb_dim {0pt}
+
+ \bool_do_until:nn
+ {
+ \tl_if_empty_p:N \l_@@_tmpa_tl
+ }
+ {
+ \tl_set:Nx \l_@@_tmpc_tl {\tl_item:Nn \l_@@_tmpa_tl {1}}
+ \tl_set:Nx \l_@@_tmpd_tl {\tl_item:Nn \l_@@_tmpa_tl {2}}
+ \tl_set:Nx \l_@@_tmpe_tl {\tl_item:Nn \l_@@_tmpa_tl {3}}
+
+ \tl_if_eq:NNTF \l_@@_tmpc_tl \c_spath_lineto_tl
+ {
+ \tl_put_right:NV \l_@@_tmpb_tl \c_spath_curvetoa_tl
+ \tl_put_right:Nx \l_@@_tmpb_tl
+ {
+ {
+ \fp_to_dim:n
+ {
+ 2/3 * (\l_@@_tmpa_dim)
+ +
+ 1/3 * (\l_@@_tmpd_tl)
+ }
+ }
+ }
+ \tl_put_right:Nx \l_@@_tmpb_tl
+ {
+ {
+ \fp_to_dim:n
+ {
+ 2/3 * (\l_@@_tmpb_dim)
+ +
+ 1/3 * (\l_@@_tmpe_tl)
+ }
+ }
+ }
+ \tl_put_right:NV \l_@@_tmpb_tl \c_spath_curvetob_tl
+ \tl_put_right:Nx \l_@@_tmpb_tl
+ {
+ {
+ \fp_to_dim:n
+ {
+ 1/3 * (\l_@@_tmpa_dim)
+ +
+ 2/3 * (\l_@@_tmpd_tl)
+ }
+ }
+ }
+ \tl_put_right:Nx \l_@@_tmpb_tl
+ {
+ {
+ \fp_to_dim:n
+ {
+ 1/3 * (\l_@@_tmpb_dim)
+ +
+ 2/3 * (\l_@@_tmpe_tl)
+ }
+ }
+ }
+ \tl_put_right:NV \l_@@_tmpb_tl \c_spath_curveto_tl
+ \@@_tl_put_right_braced:NV \l_@@_tmpb_tl \l_@@_tmpd_tl
+ \@@_tl_put_right_braced:NV \l_@@_tmpb_tl \l_@@_tmpe_tl
+ }
+ {
+ \tl_put_right:NV \l_@@_tmpb_tl \l_@@_tmpc_tl
+ \@@_tl_put_right_braced:NV \l_@@_tmpb_tl \l_@@_tmpd_tl
+ \@@_tl_put_right_braced:NV \l_@@_tmpb_tl \l_@@_tmpe_tl
+ }
+
+ \dim_set:Nn \l_@@_tmpa_dim {\l_@@_tmpd_tl}
+ \dim_set:Nn \l_@@_tmpb_dim {\l_@@_tmpe_tl}
+
+ \prg_replicate:nn {3}
+ {
+ \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl}
+ }
+ }
+ \tl_gset_eq:NN \g_@@_output_tl \l_@@_tmpb_tl
+ \group_end:
+}
+\cs_generate_variant:Nn \@@_replace_lines:n {V}
+\cs_new_protected_nopar:Npn \spath_replace_lines:Nn #1#2
+{
+ \@@_replace_lines:n {#2}
+ \tl_set_eq:NN #1 \g_@@_output_tl
+ \tl_gclear:N \g_@@_output_tl
+}
+\cs_generate_variant:Nn \spath_replace_lines:Nn {NV, cV, cv, Nv}
+\cs_new_protected_nopar:Npn \spath_replace_lines:N #1
+{
+ \spath_replace_lines:NV #1#1
+}
+\cs_generate_variant:Nn \spath_replace_lines:N {c}
+\cs_new_protected_nopar:Npn \spath_greplace_lines:Nn #1#2
+{
+ \@@_replace_lines:n {#2}
+ \tl_gset_eq:NN #1 \g_@@_output_tl
+ \tl_gclear:N \g_@@_output_tl
+}
+\cs_generate_variant:Nn \spath_greplace_lines:Nn {NV, cV, cv, Nv}
+\cs_new_protected_nopar:Npn \spath_greplace_lines:N #1
+{
+ \spath_greplace_lines:NV #1#1
+}
+\cs_generate_variant:Nn \spath_greplace_lines:N {c}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{
% \spath_remove_empty_components:Nn,
% \spath_remove_empty_components:N,
% \spath_gremove_empty_components:Nn,
@@ -4709,8 +4832,8 @@ manipulating PGF soft paths}
\cs_generate_variant:Nn \spath_show:n {V, v}
% \end{macrocode}
% \end{macro}
-
-% \subsubsection{PGF and TikZ Interface Functions}
+%
+% \subsection{PGF and TikZ Interface Functions}
%
% Spaths come from PGF so we need some functions that get and set spaths from the pgf system.
%
@@ -4845,6 +4968,7 @@ manipulating PGF soft paths}
\tl_clear_new:c {tikz@timer}
\tl_set:cn {tikz@timer}
{
+ \pgftransformreset
\spath_reallength:Nn \l_@@_tmpa_int {#1}
\tl_set_eq:Nc \l_@@_tmpb_tl {tikz@time}
\tl_set:Nx \l_@@_tmpb_tl
@@ -4927,7 +5051,10 @@ manipulating PGF soft paths}
%
% \begin{macrocode}
\msg_new:nnn { spath3 } { missing soft path } { Soft~ path~ #1~ doesn't~ exist }
-\msg_new:nnn { spath3 } { empty soft path } { Soft~ path~ #1~ is~ empty }
+\msg_new:nnnn { spath3 } { empty soft path } { Soft~ path~ #1~ is~ empty}
+{If~ it~ was~ defined~ inside~ a~ group,~ try~ using~ "save~ global". }
+\msg_new:nnn { spath3 } { load intersections }
+{ You~ need~ to~ load~ the~ "intersections"~ library~ to~ work~ with~ intersections }
% \end{macrocode}
%
% When saving a soft path, by default we use a naming convention that is compatible with the intersections library so that paths saved here and paths saved by the \texttt{name path} facility of the intersections library are mutually exchangeable.
@@ -4990,6 +5117,73 @@ manipulating PGF soft paths}
% \end{macrocode}
% \end{macro}
%
+% \begin{macro}[internal]{
+% \@@_tikzset:n
+% }
+% Wrapper around \Verb+\tikzset+ for expansion.
+% \begin{macrocode}
+\cs_set_eq:NN \@@_tikzset:n \tikzset
+\cs_generate_variant:Nn \@@_tikzset:n {V, v}
+% \end{macrocode}
+% \end{macro}
+%
+% When joining two paths we provide a set of options for how to process the second path.
+%
+% \begin{macrocode}
+\bool_new:N \l_@@_reverse_bool
+\bool_new:N \l_@@_weld_bool
+\bool_new:N \l_@@_move_bool
+\bool_new:N \l_@@_global_bool
+\tl_new:N \l_@@_joinpath_tl
+\tl_new:N \l_@@_transformation_tl
+
+\cs_new_protected_nopar:Npn \@@_set_bool:Nn #1#2
+{
+ \tl_if_eq:nnTF {#2}{false}
+ {
+ \bool_set_false:N #1
+ }
+ {
+ \bool_set_true:N #1
+ }
+}
+\tikzset {
+ spath/join/.is~ family,
+ spath/join/.cd,
+ reverse/.code = {
+ \@@_set_bool:Nn \l_@@_reverse_bool {#1}
+ },
+ reverse/.default = true,
+ weld/.code = {
+ \@@_set_bool:Nn \l_@@_weld_bool {#1}
+ },
+ weld/.default = true,
+ no~ weld/.code = {
+ \@@_set_bool:Nn \l_@@_weld_bool {#1}
+ \bool_set:Nn \l_@@_weld_bool {! \l_@@_weld_bool}
+ },
+ no~ weld/.default = true,
+ move/.code = {
+ \@@_set_bool:Nn \l_@@_move_bool {#1}
+ },
+ move/.default = true,
+ no~ move/.code = {
+ \@@_set_bool:Nn \l_@@_move_bool {#1}
+ \bool_set:Nn \l_@@_move_bool {! \l_@@_move_bool}
+ },
+ no~ move/.default = true,
+ global/.code = {
+ \@@_set_bool:Nn \l_@@_global_bool {#1}
+ },
+ global/.default = true,
+ transform/.store~in=\l_@@_transformation_tl,
+ .unknown/.code = {
+ \tl_set_eq:NN \l_@@_joinpath_tl \pgfkeyscurrentname
+ }
+}
+% \end{macrocode}
+%
+%
% When we split a soft path into components, we make it a comma separated list so that it can be fed into a \Verb+\foreach+ loop.
% This can also make it possible to extract a single component, but to do this we need a wrapper around \Verb+\clist_item:Nn+ (there doesn't appear to be a PGF way of getting an item of a CS list).
%
@@ -5042,6 +5236,15 @@ manipulating PGF soft paths}
\l_@@_tmpa_tl
}
},
+ save~ global/.code={
+ \tikz@addmode{
+ \spath_get_current_path:N \l_@@_tmpa_tl
+ \spath_bake_round:NV \l_@@_tmpa_tl \l_@@_tmpa_tl
+ \spath_gsave_path:cV
+ {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+ \l_@@_tmpa_tl
+ }
+ },
clone/.code~ 2~ args={
\tl_if_exist:cTF
{\tl_use:N \l_@@_prefix_tl #2 \tl_use:N \l_@@_suffix_tl}
@@ -5070,15 +5273,6 @@ manipulating PGF soft paths}
\msg_warning:nnn { spath3 } { missing soft path } { #2 }
}
},
- save~ global/.code={
- \tikz@addmode{
- \spath_get_current_path:N \l_@@_tmpa_tl
- \spath_bake_round:NV \l_@@_tmpa_tl \l_@@_tmpa_tl
- \spath_gsave_path:cV
- {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
- \l_@@_tmpa_tl
- }
- },
% \end{macrocode}
%
% Saves a soft path to the aux file.
@@ -5097,77 +5291,152 @@ manipulating PGF soft paths}
},
% \end{macrocode}
%
-% Restores a soft path to the current path.
+% Exports the path as an SVG file.
%
% \begin{macrocode}
- restore/.code={
+ export~ to~ svg/.code={
\tl_if_exist:cTF
{\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
{
- \tl_if_empty:cTF
+ \spath_export_to_svg:nv {#1}
{\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
- {
- \tl_clear:N \l_@@_tmpa_tl
- \tl_put_right:NV \l_@@_tmpa_tl \c_spath_moveto_tl
- \tl_put_right:Nn \l_@@_tmpa_tl {{0pt}{0pt}}
- \spath_set_current_path:V \l_@@_tmpa_tl
- \spath_set_tikz_data:V \l_@@_tmpa_tl
- \msg_warning:nnn { spath3 } { empty soft path } { #1 }
- }
- {
- \spath_set_current_path:c
- {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
- \spath_set_tikz_data:v
- {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
- }
}
{
- \tl_clear:N \l_@@_tmpa_tl
- \tl_put_right:NV \l_@@_tmpa_tl \c_spath_moveto_tl
- \tl_put_right:Nn \l_@@_tmpa_tl {{0pt}{0pt}}
- \spath_set_current_path:V \l_@@_tmpa_tl
- \spath_set_tikz_data:V \l_@@_tmpa_tl
\msg_warning:nnn { spath3 } { missing soft path } { #1 }
}
},
% \end{macrocode}
%
-% Restores the reverse of a soft path to the current path.
+% Inserts the named path at the current point in the path, with options for how this is accomplished.
+% The inserted path can be transformed, reversed, moved to the current point, and welded to the current path.
+% If this is used before the path has been started then it becomes the start of the path (and the ``current point'' is taken as the origin).
+%
%
% \begin{macrocode}
- restore~ reverse/.code={
+ use/.code={
+ \bool_set_false:N \l_@@_reverse_bool
+ \bool_set_false:N \l_@@_weld_bool
+ \bool_set_false:N \l_@@_move_bool
+ \tl_clear:N \l_@@_joinpath_tl
+ \tl_clear:N \l_@@_transformation_tl
+ \tikzset{
+ spath/join/.cd,
+ #1
+ }
+
\tl_if_exist:cTF
- {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
{
- \tl_if_empty:cTF
- {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+ \tl_use:N \l_@@_prefix_tl
+ \tl_use:N \l_@@_joinpath_tl
+ \tl_use:N \l_@@_suffix_tl
+ }
+ {
+ \tl_if_empty:cT
+ {
+ \tl_use:N \l_@@_prefix_tl
+ \tl_use:N \l_@@_joinpath_tl
+ \tl_use:N \l_@@_suffix_tl
+ }
{
- \tl_clear:N \l_@@_tmpa_tl
- \tl_put_right:NV \l_@@_tmpa_tl \c_spath_moveto_tl
- \tl_put_right:Nn \l_@@_tmpa_tl {{0pt}{0pt}}
- \spath_set_current_path:V \l_@@_tmpa_tl
- \spath_set_tikz_data:V \l_@@_tmpa_tl
\msg_warning:nnn { spath3 } { empty soft path } { #1 }
}
+ \tl_set_eq:Nc \l_@@_joinpath_tl
{
- \spath_reverse:Nv
- \l_@@_reverse_tl
- {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
- \spath_set_current_path:N \l_@@_reverse_tl
- \spath_set_tikz_data:V \l_@@_reverse_tl
+ \tl_use:N \l_@@_prefix_tl
+ \tl_use:N \l_@@_joinpath_tl
+ \tl_use:N \l_@@_suffix_tl
+ }
+ \spath_get_current_path:N \l_@@_current_tl
+
+ \bool_if:NT \l_@@_reverse_bool
+ {
+ \spath_reverse:N \l_@@_joinpath_tl
+ }
+
+ \tl_if_empty:NF \l_@@_transformation_tl
+ {
+ \group_begin:
+ \pgftransformreset
+ \@@_tikzset:V \l_@@_transformation_tl
+ \pgfgettransform \l_@@_tmpa_tl
+ \tl_gset:Nn \g_@@_smuggle_tl
+ {
+ \spath_transform:Nnnnnnn
+ \l_@@_joinpath_tl
+ }
+ \tl_gput_right:NV \g_@@_smuggle_tl \l_@@_tmpa_tl
+ \group_end:
+ \tl_use:N \g_@@_smuggle_tl
+ }
+
+ \bool_if:NT \l_@@_move_bool
+ {
+ \tl_if_empty:NTF \l_@@_current_tl
+ {
+ \tl_set:Nn \l_@@_tmpc_tl { {0pt} {0pt} }
+ }
+ {
+ \spath_finalpoint:NV
+ \l_@@_tmpc_tl
+ \l_@@_current_tl
+ }
+ \spath_translate_to:NV \l_@@_joinpath_tl \l_@@_tmpc_tl
+ }
+
+ \tl_if_empty:NTF \l_@@_current_tl
+ {
+ \tl_if_empty:NTF \l_@@_joinpath_tl
+ {
+ \tl_set_eq:NN \l_@@_current_tl \c_spath_moveto_tl
+ \tl_put_right:Nn \l_@@_current_tl {{0pt}{0pt}}
+ }
+ {
+ \tl_set_eq:NN \l_@@_current_tl \l_@@_joinpath_tl
+ }
+ }
+ {
+
+ \tl_clear:N \l_@@_tmpa_tl
+ \tl_set:Nn \l_@@_tmpa_tl {spath_}
+
+ \tl_put_right:Nn \l_@@_tmpa_tl {append}
+
+ \bool_if:NT \l_@@_weld_bool
+ {
+ \tl_put_right:Nn \l_@@_tmpa_tl {_no_move}
+ }
+ \tl_put_right:Nn \l_@@_tmpa_tl {:NV}
+
+ \use:c {\tl_use:N \l_@@_tmpa_tl }
+ \l_@@_current_tl
+ \l_@@_joinpath_tl
}
+
+ \spath_set_current_path:N \l_@@_current_tl
+ \spath_set_tikz_data:V \l_@@_joinpath_tl
}
{
- \tl_clear:N \l_@@_tmpa_tl
- \tl_put_right:NV \l_@@_tmpa_tl \c_spath_moveto_tl
- \tl_put_right:Nn \l_@@_tmpa_tl {{0pt}{0pt}}
- \spath_set_current_path:V \l_@@_tmpa_tl
- \spath_set_tikz_data:V \l_@@_tmpa_tl
- \msg_warning:nnn { spath3 } { missing soft path } { #1 }
+ \msg_warning:nnx
+ { spath3 }
+ { missing soft path }
+ {\tl_use:N \l_@@_joinpath_tl }
}
},
% \end{macrocode}
%
+% Some aliases for the above.
+%
+% \begin{macrocode}
+ restore/.style={/tikz/spath/use={#1}},
+ restore~ reverse/.style={/tikz/spath/use={reverse, #1}},
+ append/.style={/tikz/spath/use={move, weld, #1}},
+ append~ no~ move/.style={/tikz/spath/use={weld, #1}},
+ append~ reverse/.style={/tikz/spath/use={move, weld, reverse, #1}},
+ append~ reverse~ no~ move/.style={/tikz/spath/use={weld, reverse, #1}},
+ insert/.style={/tikz/spath/use={#1}},
+ insert~ reverse/.style={/tikz/spath/use={reverse, #1}},
+% \end{macrocode}
+%
% Diagnostic, show the current path in the terminal and log.
%
% \begin{macrocode}
@@ -5204,45 +5473,99 @@ manipulating PGF soft paths}
},
% \end{macrocode}
%
-% Appends the named path to the current path with a weld.
-%
-% \begin{macrocode}
- append/.code={
- \tl_if_exist:cTF
- {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
- {
- \spath_get_current_path:N \l_@@_current_tl
- \spath_finalpoint:NV \l_@@_tmpa_tl \l_@@_current_tl
- \tl_set_eq:Nc
- \l_@@_tmpb_tl
- {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
- \spath_translate_to:NV \l_@@_tmpb_tl \l_@@_tmpa_tl
- \spath_append_no_move:NV \l_@@_current_tl \l_@@_tmpb_tl
- \spath_set_current_path:N \l_@@_current_tl
- \spath_set_tikz_data:V \l_@@_tmpb_tl
- }
- {
- \msg_warning:nnn { spath3 } { missing soft path } { #1 }
- }
- },
-% \end{macrocode}
-%
-% Joins the second named path to the first.
+% This joins a path on to an existing path, possibly modifying it first.
+% The possible options are the same as those for \Verb+use+.
+% It is possible to specify the same path both for the initial and the joining path as a copy is made internally first.
%
% \begin{macrocode}
join~ with/.code~ 2~ args={
\tl_if_exist:cTF
{\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
{
+ \bool_set_false:N \l_@@_reverse_bool
+ \bool_set_false:N \l_@@_weld_bool
+ \bool_set_false:N \l_@@_move_bool
+ \bool_set_false:N \l_@@_global_bool
+ \tl_clear:N \l_@@_joinpath_tl
+ \tl_clear:N \l_@@_transformation_tl
+ \tikzset{
+ spath/join/.cd,
+ #2
+ }
+
\tl_if_exist:cTF
- {\tl_use:N \l_@@_prefix_tl #2 \tl_use:N \l_@@_suffix_tl}
{
- \spath_append:cv
+ \tl_use:N \l_@@_prefix_tl
+ \tl_use:N \l_@@_joinpath_tl
+ \tl_use:N \l_@@_suffix_tl
+ }
+ {
+ \tl_set_eq:Nc \l_@@_joinpath_tl
+ {
+ \tl_use:N \l_@@_prefix_tl
+ \tl_use:N \l_@@_joinpath_tl
+ \tl_use:N \l_@@_suffix_tl
+ }
+
+ \bool_if:NT \l_@@_reverse_bool
+ {
+ \spath_reverse:N \l_@@_joinpath_tl
+ }
+
+ \tl_if_empty:NF \l_@@_transformation_tl
+ {
+ \group_begin:
+ \pgftransformreset
+ \@@_tikzset:V \l_@@_transformation_tl
+ \pgfgettransform \l_@@_tmpa_tl
+ \tl_gset:Nn \g_@@_smuggle_tl
+ {
+ \spath_transform:Nnnnnnn
+ \l_@@_joinpath_tl
+ }
+ \tl_gput_right:NV \g_@@_smuggle_tl \l_@@_tmpa_tl
+ \group_end:
+ \tl_use:N \g_@@_smuggle_tl
+ }
+
+ \bool_if:NT \l_@@_move_bool
+ {
+ \spath_finalpoint:Nv
+ \l_@@_tmpc_tl
+ {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+ \spath_translate_to:NV \l_@@_joinpath_tl \l_@@_tmpc_tl
+ }
+
+ \tl_clear:N \l_@@_tmpa_tl
+ \tl_set:Nn \l_@@_tmpa_tl {spath_}
+
+ \bool_if:NT \l_@@_global_bool
+ {
+ \tl_put_right:Nn \l_@@_tmpa_tl {g}
+ }
+
+ \tl_put_right:Nn \l_@@_tmpa_tl {append}
+
+ \bool_if:NT \l_@@_weld_bool
+ {
+ \tl_put_right:Nn \l_@@_tmpa_tl {_no_move}
+ }
+ \tl_put_right:Nn \l_@@_tmpa_tl {:cV}
+
+ \cs_if_exist:cF {\tl_use:N \l_@@_tmpa_tl}
+ {
+ \tl_show:N \l_@@_tmpa_tl
+ }
+
+ \use:c {\tl_use:N \l_@@_tmpa_tl }
{\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
- {\tl_use:N \l_@@_prefix_tl #2 \tl_use:N \l_@@_suffix_tl}
+ \l_@@_joinpath_tl
}
{
- \msg_warning:nnn { spath3 } { missing soft path } { #2 }
+ \msg_warning:nnx
+ { spath3 }
+ { missing soft path }
+ {\tl_use:N \l_@@_joinpath_tl }
}
}
{
@@ -5305,113 +5628,6 @@ manipulating PGF soft paths}
},
% \end{macrocode}
%
-% Appends the reversal of the path to the current path.
-%
-% \begin{macrocode}
- append~ reverse/.code={
- \tl_if_exist:cTF
- {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
- {
- \spath_reverse:Nv
- \l_@@_reverse_tl
- {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
- \spath_get_current_path:N \l_@@_current_tl
- \spath_finalpoint:NV \l_@@_tmpa_tl \l_@@_current_tl
- \spath_translate_to:NV \l_@@_reverse_tl \l_@@_tmpa_tl
- \spath_append_no_move:NV \l_@@_current_tl \l_@@_reverse_tl
- \spath_set_current_path:N \l_@@_current_tl
- \spath_set_tikz_data:V \l_@@_reverse_tl
- }
- {
- \msg_warning:nnn { spath3 } { missing soft path } { #1 }
- }
- },
-% \end{macrocode}
-%
-% Inserts the named path into the current path as-is, meaning without transforming or welding it.
-%
-% \begin{macrocode}
- insert/.code={
- \tl_if_exist:cTF
- {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
- {
- \spath_get_current_path:N \l_@@_current_tl
- \spath_append:Nv
- \l_@@_current_tl
- {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
- \spath_set_current_path:N \l_@@_current_tl
- \spath_set_tikz_data:v
- {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
- }
- {
- \msg_warning:nnn { spath3 } { missing soft path } { #1 }
- }
- },
-% \end{macrocode}
-%
-% Inserts the reverse of the named path.
-%
-% \begin{macrocode}
- insert~ reverse/.code={
- \tl_if_exist:cTF
- {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
- {
- \spath_reverse:Nv
- \l_@@_reverse_tl
- {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
- \spath_get_current_path:N \l_@@_current_tl
- \spath_append:NV \l_@@_current_tl \l_@@_reverse_tl
- \spath_set_current_path:N \l_@@_current_tl
- \spath_set_tikz_data:V \l_@@_reverse_tl
- }
- {
- \msg_warning:nnn { spath3 } { missing soft path } { #1 }
- }
- },
-% \end{macrocode}
-%
-% Appends the named path to the current path without translating it.
-%
-% \begin{macrocode}
- append~ no~ move/.code={
- \tl_if_exist:cTF
- {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
- {
- \spath_get_current_path:N \l_@@_current_tl
- \spath_append_no_move:Nv
- \l_@@_current_tl
- {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
- \spath_set_current_path:N \l_@@_current_tl
- \spath_set_tikz_data:v
- {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
- }
- {
- \msg_warning:nnn { spath3 } { missing soft path } { #1 }
- }
- },
-% \end{macrocode}
-%
-% Appends the reverse of the named path without translating it.
-%
-% \begin{macrocode}
- append~ reverse~ no~ move/.code={
- \tl_if_exist:cTF
- {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
- {
- \spath_reverse:Nv
- \l_@@_reverse_tl
- {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
- \spath_get_current_path:N \l_@@_current_tl
- \spath_append_no_move:NV \l_@@_current_tl \l_@@_reverse_tl
- \spath_set_current_path:N \l_@@_current_tl
- \spath_set_tikz_data:V \l_@@_reverse_tl
- }
- {
- \msg_warning:nnn { spath3 } { missing soft path } { #1 }
- }
- },
-% \end{macrocode}
-%
% Adjust a path to span between two points.
%
% \begin{macrocode}
@@ -5519,36 +5735,99 @@ manipulating PGF soft paths}
% \end{macrocode}
%
% Join the components of a path by splicing in the second path whenever the components are sufficiently far apart.
+% The third argument is a list of components to splice after, if it is empty then all components are used and a spot weld is done first so that the splicing only happens if there is an actual gap.
+%
+% The \Verb+upright+ versions will join with the reflection of the splice path if it detects that the gap is ``upside-down''.
+%
%
% \begin{macrocode}
join~ components~ with/.code~2~args={
\tl_if_exist:cTF
{\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
{
+ \tl_if_head_is_group:nTF {#2}
+ {
+ \tl_set:Nx \l_@@_tmpc_tl { \tl_item:nn {#2} {1} }
+ \tl_set:Nx \l_@@_tmpd_tl { \tl_item:nn {#2} {2} }
+ }
+ {
+ \tl_set:Nn \l_@@_tmpc_tl {#2}
+ \tl_clear:N \l_@@_tmpd_tl
+ }
\tl_if_exist:cTF
- {\tl_use:N \l_@@_prefix_tl #2 \tl_use:N \l_@@_suffix_tl}
{
- \spath_spot_weld_components:c
- {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+ \tl_use:N \l_@@_prefix_tl
+ \tl_use:N \l_@@_tmpc_tl
+ \tl_use:N \l_@@_suffix_tl
+ }
+ {
+ \tl_if_empty:NT \l_@@_tmpd_tl
+ {
+ \spath_spot_weld_components:c
+ {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+ }
\spath_components_to_seq:Nv
\l_@@_tmpa_seq
{\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+ \seq_gclear:N \g_@@_tmpa_seq
+
+ \tl_if_empty:NTF \l_@@_tmpd_tl
+ {
+ \int_step_inline:nnnn {1}{1} {\seq_count:N \l_@@_tmpa_seq}
+ {
+ \seq_gput_right:Nn \g_@@_tmpa_seq {##1}
+ }
+ }
+ {
+ \foreach \l_@@_tmpa_tl in \l_@@_tmpd_tl
+ {
+ \seq_gput_right:NV \g_@@_tmpa_seq \l_@@_tmpa_tl
+ }
+ \seq_gsort:Nn \g_@@_tmpa_seq
+ {
+ \int_compare:nNnTF {##1} < {##2}
+ { \sort_return_same: }
+ { \sort_return_swapped: }
+ }
+ }
+
\seq_pop_left:NN \l_@@_tmpa_seq \l_@@_tmpa_tl
-
- \seq_map_inline:Nn \l_@@_tmpa_seq
+ \seq_gpop_left:NN \g_@@_tmpa_seq \l_@@_tmpb_tl
+
+ \seq_map_indexed_inline:Nn \l_@@_tmpa_seq
{
- \spath_splice_between:Nvn \l_@@_tmpa_tl
- {\tl_use:N \l_@@_prefix_tl #2 \tl_use:N \l_@@_suffix_tl}
- {##1}
+ \int_compare:nTF
+ {
+ ##1 == \l_@@_tmpb_tl
+ }
+ {
+ \seq_gpop_left:NNF \g_@@_tmpa_seq \l_@@_tmpb_tl
+ {
+ \tl_set:Nn \l_@@_tmpb_tl {-1}
+ }
+ \spath_splice_between:Nvn \l_@@_tmpa_tl
+ {
+ \tl_use:N \l_@@_prefix_tl
+ \tl_use:N \l_@@_tmpc_tl
+ \tl_use:N \l_@@_suffix_tl
+ }
+ {##2}
+ }
+ {
+ \tl_put_right:Nn \l_@@_tmpa_tl {##2}
+ }
}
\tl_set_eq:cN
{\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
\l_@@_tmpa_tl
}
{
- \msg_warning:nnn { spath3 } { missing soft path } { #2 }
+ \msg_warning:nnx
+ { spath3 }
+ { missing soft path }
+ { \tl_use:N \l_@@_tmpc_tl }
}
}
{
@@ -5559,30 +5838,319 @@ manipulating PGF soft paths}
\tl_if_exist:cTF
{\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
{
+ \tl_if_head_is_group:nTF {#2}
+ {
+ \tl_set:Nx \l_@@_tmpc_tl { \tl_item:nn {#2} {1} }
+ \tl_set:Nx \l_@@_tmpd_tl { \tl_item:nn {#2} {2} }
+ }
+ {
+ \tl_set:Nn \l_@@_tmpc_tl {#2}
+ \tl_clear:N \l_@@_tmpd_tl
+ }
\tl_if_exist:cTF
- {\tl_use:N \l_@@_prefix_tl #2 \tl_use:N \l_@@_suffix_tl}
{
- \spath_spot_gweld_components:c
+ \tl_use:N \l_@@_prefix_tl
+ \tl_use:N \l_@@_tmpc_tl
+ \tl_use:N \l_@@_suffix_tl
+ }
+ {
+ \tl_if_empty:NT \l_@@_tmpd_tl
+ {
+ \spath_spot_weld_components:c
+ {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+ }
+
+ \spath_components_to_seq:Nv
+ \l_@@_tmpa_seq
{\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+
+ \seq_gclear:N \g_@@_tmpa_seq
+ \tl_if_empty:NTF \l_@@_tmpd_tl
+ {
+ \int_step_inline:nnnn {1}{1} {\seq_count:N \l_@@_tmpa_seq}
+ {
+ \seq_gput_right:Nn \g_@@_tmpa_seq {##1}
+ }
+ }
+ {
+ \foreach \l_@@_tmpa_tl in \l_@@_tmpd_tl
+ {
+ \seq_gput_right:NV \g_@@_tmpa_seq \l_@@_tmpa_tl
+ }
+ \seq_gsort:Nn \g_@@_tmpa_seq
+ {
+ \int_compare:nNnTF {##1} < {##2}
+ { \sort_return_same: }
+ { \sort_return_swapped: }
+ }
+ }
+
+ \seq_pop_left:NN \l_@@_tmpa_seq \l_@@_tmpa_tl
+ \seq_gpop_left:NN \g_@@_tmpa_seq \l_@@_tmpb_tl
+
+ \seq_map_indexed_inline:Nn \l_@@_tmpa_seq
+ {
+ \int_compare:nTF
+ {
+ ##1 == \l_@@_tmpb_tl
+ }
+ {
+ \seq_gpop_left:NNF \g_@@_tmpa_seq \l_@@_tmpb_tl
+ {
+ \tl_set:Nn \l_@@_tmpb_tl {-1}
+ }
+ \spath_splice_between:Nvn \l_@@_tmpa_tl
+ {
+ \tl_use:N \l_@@_prefix_tl
+ \tl_use:N \l_@@_tmpc_tl
+ \tl_use:N \l_@@_suffix_tl
+ }
+ {##2}
+ }
+ {
+ \tl_put_right:Nn \l_@@_tmpa_tl {##2}
+ }
+ }
+ \tl_gset_eq:cN
+ {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+ \l_@@_tmpa_tl
+ }
+ {
+ \msg_warning:nnx
+ { spath3 }
+ { missing soft path }
+ { \tl_use:N \l_@@_tmpc_tl }
+ }
+ }
+ {
+ \msg_warning:nnn { spath3 } { missing soft path } { #1 }
+ }
+ },
+ join~ components~ upright~ with/.code~2~args={
+ \tl_if_exist:cTF
+ {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+ {
+ \tl_if_head_is_group:nTF {#2}
+ {
+ \tl_set:Nx \l_@@_tmpc_tl { \tl_item:nn {#2} {1} }
+ \tl_set:Nx \l_@@_tmpd_tl { \tl_item:nn {#2} {2} }
+ }
+ {
+ \tl_set:Nn \l_@@_tmpc_tl {#2}
+ \tl_clear:N \l_@@_tmpd_tl
+ }
+ \tl_if_exist:cTF
+ {
+ \tl_use:N \l_@@_prefix_tl
+ \tl_use:N \l_@@_tmpc_tl
+ \tl_use:N \l_@@_suffix_tl
+ }
+ {
+ \tl_if_empty:NT \l_@@_tmpd_tl
+ {
+ \spath_spot_weld_components:c
+ {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+ }
+
\spath_components_to_seq:Nv
\l_@@_tmpa_seq
{\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+ \seq_gclear:N \g_@@_tmpa_seq
+
+ \tl_if_empty:NTF \l_@@_tmpd_tl
+ {
+ \int_step_inline:nnnn {1}{1} {\seq_count:N \l_@@_tmpa_seq}
+ {
+ \seq_gput_right:Nn \g_@@_tmpa_seq {##1}
+ }
+ }
+ {
+ \foreach \l_@@_tmpa_tl in \l_@@_tmpd_tl
+ {
+ \seq_gput_right:NV \g_@@_tmpa_seq \l_@@_tmpa_tl
+ }
+ \seq_gsort:Nn \g_@@_tmpa_seq
+ {
+ \int_compare:nNnTF {##1} < {##2}
+ { \sort_return_same: }
+ { \sort_return_swapped: }
+ }
+ }
+
\seq_pop_left:NN \l_@@_tmpa_seq \l_@@_tmpa_tl
-
- \seq_map_inline:Nn \l_@@_tmpa_seq
+ \seq_gpop_left:NN \g_@@_tmpa_seq \l_@@_tmpb_tl
+
+ \tl_set_eq:Nc \l_@@_tmpc_tl
{
- \spath_gsplice_between:Nvn \l_@@_tmpa_tl
- {\tl_use:N \l_@@_prefix_tl #2 \tl_use:N \l_@@_suffix_tl}
- {##1}
+ \tl_use:N \l_@@_prefix_tl
+ \tl_use:N \l_@@_tmpc_tl
+ \tl_use:N \l_@@_suffix_tl
+ }
+ \spath_transform:NVnnnnnn \l_@@_tmpd_tl \l_@@_tmpc_tl {1}{0}{0}{-1}{0pt}{0pt}
+
+ \seq_map_indexed_inline:Nn \l_@@_tmpa_seq
+ {
+ \int_compare:nTF
+ {
+ ##1 == \l_@@_tmpb_tl
+ }
+ {
+ \seq_gpop_left:NNF \g_@@_tmpa_seq \l_@@_tmpb_tl
+ {
+ \tl_set:Nn \l_@@_tmpb_tl {-1}
+ }
+ \spath_finalpoint:NV \l_@@_tmpe_tl \l_@@_tmpa_tl
+ \spath_initialpoint:Nn \l_@@_tmpf_tl {##2}
+
+ \dim_compare:nTF
+ {
+ \tl_item:Nn \l_@@_tmpe_tl {1}
+ >
+ \tl_item:Nn \l_@@_tmpf_tl {1}
+ }
+ {
+ \spath_splice_between:NVn
+ \l_@@_tmpa_tl
+ \l_@@_tmpd_tl
+ {##2}
+ }
+ {
+ \spath_splice_between:NVn
+ \l_@@_tmpa_tl
+ \l_@@_tmpc_tl
+ {##2}
+ }
+ }
+ {
+ \tl_put_right:Nn \l_@@_tmpa_tl {##2}
+ }
}
\tl_set_eq:cN
{\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
\l_@@_tmpa_tl
}
{
- \msg_warning:nnn { spath3 } { missing soft path } { #2 }
+ \msg_warning:nnx
+ { spath3 }
+ { missing soft path }
+ { \tl_use:N \l_@@_tmpc_tl }
+ }
+ }
+ {
+ \msg_warning:nnn { spath3 } { missing soft path } { #1 }
+ }
+ },
+ join~ components~ globally~ upright~ with/.code~2~args={
+ \tl_if_exist:cTF
+ {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+ {
+ \tl_if_head_is_group:nTF {#2}
+ {
+ \tl_set:Nx \l_@@_tmpc_tl { \tl_item:nn {#2} {1} }
+ \tl_set:Nx \l_@@_tmpd_tl { \tl_item:nn {#2} {2} }
+ }
+ {
+ \tl_set:Nn \l_@@_tmpc_tl {#2}
+ \tl_clear:N \l_@@_tmpd_tl
+ }
+ \tl_if_exist:cTF
+ {
+ \tl_use:N \l_@@_prefix_tl
+ \tl_use:N \l_@@_tmpc_tl
+ \tl_use:N \l_@@_suffix_tl
+ }
+ {
+ \tl_if_empty:NT \l_@@_tmpd_tl
+ {
+ \spath_spot_weld_components:c
+ {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+ }
+
+ \spath_components_to_seq:Nv
+ \l_@@_tmpa_seq
+ {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+
+ \seq_gclear:N \g_@@_tmpa_seq
+
+ \tl_if_empty:NTF \l_@@_tmpd_tl
+ {
+ \int_step_inline:nnnn {1}{1} {\seq_count:N \l_@@_tmpa_seq}
+ {
+ \seq_gput_right:Nn \g_@@_tmpa_seq {##1}
+ }
+ }
+ {
+ \foreach \l_@@_tmpa_tl in \l_@@_tmpd_tl
+ {
+ \seq_gput_right:NV \g_@@_tmpa_seq \l_@@_tmpa_tl
+ }
+ \seq_gsort:Nn \g_@@_tmpa_seq
+ {
+ \int_compare:nNnTF {##1} < {##2}
+ { \sort_return_same: }
+ { \sort_return_swapped: }
+ }
+ }
+
+ \seq_pop_left:NN \l_@@_tmpa_seq \l_@@_tmpa_tl
+ \seq_gpop_left:NN \g_@@_tmpa_seq \l_@@_tmpb_tl
+
+ \tl_set_eq:Nc \l_@@_tmpc_tl
+ {
+ \tl_use:N \l_@@_prefix_tl
+ \tl_use:N \l_@@_tmpc_tl
+ \tl_use:N \l_@@_suffix_tl
+ }
+ \spath_transform:NVnnnnnn \l_@@_tmpd_tl \l_@@_tmpc_tl {1}{0}{0}{-1}{0pt}{0pt}
+
+ \seq_map_indexed_inline:Nn \l_@@_tmpa_seq
+ {
+ \int_compare:nTF
+ {
+ ##1 == \l_@@_tmpb_tl
+ }
+ {
+ \seq_gpop_left:NNF \g_@@_tmpa_seq \l_@@_tmpb_tl
+ {
+ \tl_set:Nn \l_@@_tmpb_tl {-1}
+ }
+ \spath_finalpoint:NV \l_@@_tmpe_tl \l_@@_tmpa_tl
+ \spath_initialpoint:Nn \l_@@_tmpf_tl {##2}
+
+ \dim_compare:nTF
+ {
+ \tl_item:Nn \l_@@_tmpe_tl {1}
+ >
+ \tl_item:Nn \l_@@_tmpf_tl {1}
+ }
+ {
+ \spath_splice_between:NVn
+ \l_@@_tmpa_tl
+ \l_@@_tmpd_tl
+ {##2}
+ }
+ {
+ \spath_splice_between:NVn
+ \l_@@_tmpa_tl
+ \l_@@_tmpc_tl
+ {##2}
+ }
+ }
+ {
+ \tl_put_right:Nn \l_@@_tmpa_tl {##2}
+ }
+ }
+ \tl_gset_eq:cN
+ {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+ \l_@@_tmpa_tl
+ }
+ {
+ \msg_warning:nnx
+ { spath3 }
+ { missing soft path }
+ { \tl_use:N \l_@@_tmpc_tl }
}
}
{
@@ -5790,22 +6358,6 @@ manipulating PGF soft paths}
},
% \end{macrocode}
%
-% Exports the path as an SVG file.
-%
-% \begin{macrocode}
- export~ to~ svg/.code={
- \tl_if_exist:cTF
- {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
- {
- \spath_export_to_svg:nv {#1}
- {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
- }
- {
- \msg_warning:nnn { spath3 } { missing soft path } { #1 }
- }
- },
-% \end{macrocode}
-%
% Transforms the named path using TikZ transformation specifications.
%
% \begin{macrocode}
@@ -5858,40 +6410,58 @@ manipulating PGF soft paths}
% \begin{macrocode}
split~ at~ intersections~ with/.code~ n~ args={2}{
\tl_if_exist:cTF
- {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+ {
+ tikz@library@intersections@loaded
+ }
{
\tl_if_exist:cTF
- {\tl_use:N \l_@@_prefix_tl #2 \tl_use:N \l_@@_suffix_tl}
+ {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
{
- \spath_split_path_at_intersections:cv
- {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+ \tl_if_exist:cTF
{\tl_use:N \l_@@_prefix_tl #2 \tl_use:N \l_@@_suffix_tl}
+ {
+ \spath_split_path_at_intersections:cv
+ {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+ {\tl_use:N \l_@@_prefix_tl #2 \tl_use:N \l_@@_suffix_tl}
+ }
+ {
+ \msg_warning:nnn { spath3 } { missing soft path } { #2 }
+ }
}
{
- \msg_warning:nnn { spath3 } { missing soft path } { #2 }
+ \msg_warning:nnn { spath3 } { missing soft path } { #1 }
}
}
{
- \msg_warning:nnn { spath3 } { missing soft path } { #1 }
+ \msg_warning:nn { spath3 } { load intersections }
}
},
split~ globally~ at~ intersections~ with/.code~ n~ args={2}{
\tl_if_exist:cTF
- {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
{
- \tl_if_exist:cTF
- {\tl_use:N \l_@@_prefix_tl #2 \tl_use:N \l_@@_suffix_tl}
+ tikz@library@intersections@loaded
+ }
+ {
+ \tl_if_exist:cTF
+ {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
{
- \spath_gsplit_path_at_intersections:cv
- {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+ \tl_if_exist:cTF
{\tl_use:N \l_@@_prefix_tl #2 \tl_use:N \l_@@_suffix_tl}
+ {
+ \spath_gsplit_path_at_intersections:cv
+ {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+ {\tl_use:N \l_@@_prefix_tl #2 \tl_use:N \l_@@_suffix_tl}
+ }
+ {
+ \msg_warning:nnn { spath3 } { missing soft path } { #2 }
+ }
}
{
- \msg_warning:nnn { spath3 } { missing soft path } { #2 }
+ \msg_warning:nnn { spath3 } { missing soft path } { #1 }
}
}
{
- \msg_warning:nnn { spath3 } { missing soft path } { #1 }
+ \msg_warning:nn { spath3 } { load intersections }
}
},
% \end{macrocode}
@@ -5901,40 +6471,58 @@ manipulating PGF soft paths}
% \begin{macrocode}
split~ at~ intersections/.code~ n~ args={2}{
\tl_if_exist:cTF
- {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+ {
+ tikz@library@intersections@loaded
+ }
{
\tl_if_exist:cTF
- {\tl_use:N \l_@@_prefix_tl #2 \tl_use:N \l_@@_suffix_tl}
+ {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
{
- \spath_split_at_intersections:cc
- {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+ \tl_if_exist:cTF
{\tl_use:N \l_@@_prefix_tl #2 \tl_use:N \l_@@_suffix_tl}
+ {
+ \spath_split_at_intersections:cc
+ {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+ {\tl_use:N \l_@@_prefix_tl #2 \tl_use:N \l_@@_suffix_tl}
+ }
+ {
+ \msg_warning:nnn { spath3 } { missing soft path } { #2 }
+ }
}
{
- \msg_warning:nnn { spath3 } { missing soft path } { #2 }
+ \msg_warning:nnn { spath3 } { missing soft path } { #1 }
}
}
{
- \msg_warning:nnn { spath3 } { missing soft path } { #1 }
+ \msg_warning:nn { spath3 } { load intersections }
}
},
split~ globally~ at~ intersections/.code~ n~ args={2}{
\tl_if_exist:cTF
- {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+ {
+ tikz@library@intersections@loaded
+ }
{
\tl_if_exist:cTF
- {\tl_use:N \l_@@_prefix_tl #2 \tl_use:N \l_@@_suffix_tl}
+ {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
{
- \spath_gsplit_at_intersections:cc
- {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+ \tl_if_exist:cTF
{\tl_use:N \l_@@_prefix_tl #2 \tl_use:N \l_@@_suffix_tl}
+ {
+ \spath_gsplit_at_intersections:cc
+ {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+ {\tl_use:N \l_@@_prefix_tl #2 \tl_use:N \l_@@_suffix_tl}
+ }
+ {
+ \msg_warning:nnn { spath3 } { missing soft path } { #2 }
+ }
}
{
- \msg_warning:nnn { spath3 } { missing soft path } { #2 }
+ \msg_warning:nnn { spath3 } { missing soft path } { #1 }
}
}
{
- \msg_warning:nnn { spath3 } { missing soft path } { #1 }
+ \msg_warning:nn { spath3 } { load intersections }
}
},
% \end{macrocode}
@@ -5944,24 +6532,42 @@ manipulating PGF soft paths}
% \begin{macrocode}
split~ at~ self~ intersections/.code={
\tl_if_exist:cTF
- {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
{
- \spath_split_at_self_intersections:c
+ tikz@library@intersections@loaded
+ }
+ {
+ \tl_if_exist:cTF
{\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+ {
+ \spath_split_at_self_intersections:c
+ {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+ }
+ {
+ \msg_warning:nnn { spath3 } { missing soft path } { #1 }
+ }
}
{
- \msg_warning:nnn { spath3 } { missing soft path } { #1 }
+ \msg_warning:nn { spath3 } { load intersections }
}
},
split~ globally~ at~ self~ intersections/.code={
\tl_if_exist:cTF
- {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
{
- \spath_gsplit_at_self_intersections:c
+ tikz@library@intersections@loaded
+ }
+ {
+ \tl_if_exist:cTF
{\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+ {
+ \spath_gsplit_at_self_intersections:c
+ {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+ }
+ {
+ \msg_warning:nnn { spath3 } { missing soft path } { #1 }
+ }
}
{
- \msg_warning:nnn { spath3 } { missing soft path } { #1 }
+ \msg_warning:nn { spath3 } { load intersections }
}
},
% \end{macrocode}
@@ -6069,40 +6675,64 @@ manipulating PGF soft paths}
% The list of components is passed through a \Verb+\foreach+ loop so can use the shortcut syntax from those loops.
%
% \begin{macrocode}
- insert~ gaps~ after~ components/.code~ n~ args={3}{
+ insert~ gaps~ after~ components/.code~ 2~ args={
\tl_if_exist:cTF
{\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
{
\group_begin:
+ \tl_if_head_is_group:nTF {#2}
+ {
+ \tl_set:Nx \l_@@_tmpc_tl { \tl_item:nn {#2} {1} }
+ \tl_set:Nx \l_@@_tmpd_tl { \tl_item:nn {#2} {2} }
+ }
+ {
+ \tl_set:Nn \l_@@_tmpc_tl {#2}
+ \tl_clear:N \l_@@_tmpd_tl
+ }
\seq_gclear:N \g_@@_tmpa_seq
\seq_gclear:N \g_@@_tmpb_seq
\spath_numberofcomponents:Nv \l_@@_tmpa_int
{\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
- \foreach \l_@@_tmpa_tl in {#3}
+
+ \spath_components_to_seq:Nv
+ \l_@@_tmpa_seq
+ {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+
+ \tl_if_empty:NTF \l_@@_tmpd_tl
{
- \seq_gput_right:NV \g_@@_tmpa_seq \l_@@_tmpa_tl
- \seq_gput_right:Nx
- \g_@@_tmpb_seq
- {\int_eval:n
- {
- \int_mod:nn { \l_@@_tmpa_tl }{ \l_@@_tmpa_int } + 1
+ \int_step_inline:nnnn {1}{1} { \l_@@_tmpa_int - 1 }
+ {
+ \seq_gput_right:Nn \g_@@_tmpa_seq {##1}
+ \seq_gput_right:Nx
+ \g_@@_tmpb_seq
+ {\int_eval:n {##1 + 1}}
+ }
+ }
+ {
+ \foreach \l_@@_tmpa_tl in \l_@@_tmpd_tl
+ {
+ \seq_gput_right:NV \g_@@_tmpa_seq \l_@@_tmpa_tl
+ \seq_gput_right:Nx
+ \g_@@_tmpb_seq
+ {\int_eval:n
+ {
+ \int_mod:nn { \l_@@_tmpa_tl }{ \l_@@_tmpa_int } + 1
+ }
}
}
}
- \spath_components_to_seq:Nv
- \l_@@_tmpa_seq
- {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+
\seq_clear:N \l_@@_tmpb_seq
\seq_map_indexed_inline:Nn \l_@@_tmpa_seq
{
\tl_set:Nn \l_@@_tmpa_tl {##2}
\seq_if_in:NnT \g_@@_tmpa_seq {##1}
{
- \spath_shorten_at_end:Nn \l_@@_tmpa_tl {#2/2}
+ \spath_shorten_at_end:Nn \l_@@_tmpa_tl {\l_@@_tmpc_tl/2}
}
\seq_if_in:NnT \g_@@_tmpb_seq {##1}
{
- \spath_shorten_at_start:Nn \l_@@_tmpa_tl {#2/2}
+ \spath_shorten_at_start:Nn \l_@@_tmpa_tl {\l_@@_tmpc_tl/2}
}
\seq_put_right:NV \l_@@_tmpb_seq \l_@@_tmpa_tl
}
@@ -6117,41 +6747,64 @@ manipulating PGF soft paths}
\msg_warning:nnn { spath3 } { missing soft path } { #1 }
}
},
- insert~ gaps~ globally~ after~ components/.code~ n~ args={3}{
+ insert~ gaps~ globally~ after~ components/.code~ 2~ args={
\tl_if_exist:cTF
{\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
{
\group_begin:
+ \tl_if_head_is_group:nTF {#2}
+ {
+ \tl_set:Nx \l_@@_tmpc_tl { \tl_item:nn {#2} {1} }
+ \tl_set:Nx \l_@@_tmpd_tl { \tl_item:nn {#2} {2} }
+ }
+ {
+ \tl_set:Nn \l_@@_tmpc_tl {#2}
+ \tl_clear:N \l_@@_tmpd_tl
+ }
\seq_gclear:N \g_@@_tmpa_seq
\seq_gclear:N \g_@@_tmpb_seq
\spath_numberofcomponents:Nv \l_@@_tmpa_int
{\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
- \foreach \l_@@_tmpa_tl in {#3}
+
+ \spath_components_to_seq:Nv
+ \l_@@_tmpa_seq
+ {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+
+ \tl_if_empty:NTF \l_@@_tmpd_tl
{
- \seq_gput_right:NV \g_@@_tmpa_seq \l_@@_tmpa_tl
- \seq_gput_right:Nx
- \g_@@_tmpb_seq
+ \int_step_inline:nnnn {1}{1} { \l_@@_tmpa_int - 1 }
{
- \int_eval:n
- {
- \int_mod:nn { \l_@@_tmpa_tl }{ \l_@@_tmpa_int } + 1
+ \seq_gput_right:Nn \g_@@_tmpa_seq {##1}
+ \seq_gput_right:Nx
+ \g_@@_tmpb_seq
+ {\int_eval:n {##1 + 1}}
+ }
+ }
+ {
+ \foreach \l_@@_tmpa_tl in \l_@@_tmpd_tl
+ {
+ \seq_gput_right:NV \g_@@_tmpa_seq \l_@@_tmpa_tl
+ \seq_gput_right:Nx
+ \g_@@_tmpb_seq
+ {\int_eval:n
+ {
+ \int_mod:nn { \l_@@_tmpa_tl }{ \l_@@_tmpa_int } + 1
+ }
}
}
}
- \spath_components_to_seq:Nv
- \l_@@_tmpa_seq
- {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+
\seq_clear:N \l_@@_tmpb_seq
\seq_map_indexed_inline:Nn \l_@@_tmpa_seq
{
\tl_set:Nn \l_@@_tmpa_tl {##2}
\seq_if_in:NnT \g_@@_tmpa_seq {##1}
{
- \spath_shorten_at_end:Nn \l_@@_tmpa_tl {#2/2}
+ \spath_shorten_at_end:Nn \l_@@_tmpa_tl {\l_@@_tmpc_tl/2}
}
\seq_if_in:NnT \g_@@_tmpb_seq {##1}
{
- \spath_shorten_at_start:Nn \l_@@_tmpa_tl {#2/2}
+ \spath_shorten_at_start:Nn \l_@@_tmpa_tl {\l_@@_tmpc_tl/2}
}
\seq_put_right:NV \l_@@_tmpb_seq \l_@@_tmpa_tl
}
@@ -6250,6 +6903,33 @@ manipulating PGF soft paths}
},
% \end{macrocode}
%
+% Replace all line segments by B\'ezier curves.
+%
+% \begin{macrocode}
+ replace~ lines/.code={
+ \tl_if_exist:cTF
+ {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+ {
+ \spath_replace_lines:c
+ {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+ }
+ {
+ \msg_warning:nnn { spath3 } { missing soft path } { #1 }
+ }
+ },
+ replace~ lines~ globally/.code={
+ \tl_if_exist:cTF
+ {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+ {
+ \spath_greplace_lines:c
+ {\tl_use:N \l_@@_prefix_tl #1 \tl_use:N \l_@@_suffix_tl}
+ }
+ {
+ \msg_warning:nnn { spath3 } { missing soft path } { #1 }
+ }
+ },
+% \end{macrocode}
+%
%
% Join the specified components together, joining each to its previous one.
%
@@ -6547,7 +7227,10 @@ manipulating PGF soft paths}
}
}
{
- \msg_warning:nnx { spath3 } { missing soft path } { \tl_use:N \l_@@_tmpa_tl }
+ \msg_warning:nnx
+ { spath3 }
+ { missing soft path }
+ { \tl_use:N \l_@@_tmpa_tl }
\tl_gset_eq:NN \g_@@_smuggle_tl \pgfpointorigin
}
\group_end:
diff --git a/Master/texmf-dist/source/latex/tagpdf/tagpdf-backend.dtx b/Master/texmf-dist/source/latex/tagpdf/tagpdf-backend.dtx
new file mode 100644
index 00000000000..d80d56778bc
--- /dev/null
+++ b/Master/texmf-dist/source/latex/tagpdf/tagpdf-backend.dtx
@@ -0,0 +1,803 @@
+% \iffalse meta-comment
+%
+%% File: tagpdf-backend.dtx
+%
+% Copyright (C) 2019-2020 Ulrike Fischer
+%
+% 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 "tagpdf 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/u-fischer/tagpdf
+%
+% for those people who are interested.
+%
+% \fi
+%
+% \begin{macrocode}
+%<@@=tag>
+%<*luatex>
+\ProvidesExplFile {tagpdf-luatex.def} {2021/02/23} {0.80}
+ {tagpdf~driver~for~luatex}
+
+\newattribute \l_@@_mc_type_attr %the value represent the type
+\newattribute \l_@@_mc_cnt_attr %will hold the \c@g_@@_MCID_abs_int value
+
+\newattribute \g_@@_interwordspace_attr
+\newattribute \g_@@_interwordfont_attr
+
+% The lua code
+% ensure that 10pt font has been loaded:
+{
+ \fontencoding{TU}\fontfamily{lmr}\fontseries{m}\fontshape{n}\fontsize{10pt}{10pt}\selectfont
+}
+\directlua { tagpdf=require('tagpdf.lua') }
+
+%%%% driver (lualatex) commands
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+% I probably want also lua tables
+% I put them in the ltx.@@.tables namespaces
+% The tables will be named like the variables but without backslash
+% To access such a table with a dynamical name create a string and then use
+% ltx.@@.tables[string]
+% Old code, I'm not quite sure if this was a good idea. Now I have mix of table in
+% ltx.@@.tables and ltx.@@.mc/struct. And a lot is probably not needed.
+
+\cs_new:Nn \@@_luatex_get_table_name:Nn
+ {
+ \tl_set_rescan:Nnn #1 { \char_set_catcode_ignore:N \\ } { #2 }
+ }
+
+
+\cs_new:Nn \@@_prop_new:N
+ {
+ \prop_new:N #1
+ \@@_luatex_get_table_name:Nn \l_tmpa_tl { #1 }
+ \directlua { ltx.@@.tables.\l_tmpa_tl = {} }
+ }
+
+
+\cs_new:Nn \@@_seq_new:N
+ {
+ \seq_new:N #1
+ \@@_luatex_get_table_name:Nn \l_tmpa_tl { #1 }
+ \directlua { ltx.@@.tables.\l_tmpa_tl = {} }
+ }
+
+
+\cs_new:Nn \@@_prop_gput:Nnn
+ {
+ \prop_gput:Nnn #1 { #2 } { #3 }
+ \@@_luatex_get_table_name:Nn \l_tmpa_tl { #1 }
+ \directlua { ltx.@@.tables.\l_tmpa_tl["#2"] = "#3" }
+ }
+
+
+\cs_new:Nn \@@_seq_gput_right:Nn
+ {
+ \seq_gput_right:Nn #1 { #2 }
+ \@@_luatex_get_table_name:Nn \l_tmpa_tl { #1 }
+ \directlua { table.insert(ltx.@@.tables.\l_tmpa_tl, "#2") }
+ }
+
+%Hm not quite sure about the naming
+
+\cs_new:Npn \@@_seq_item:cn #1 #2
+ {
+ \directlua { tex.print(ltx.@@.tables.#1[#2]) }
+ }
+
+\cs_new:Npn \@@_prop_item:cn #1 #2
+ {
+ \directlua { tex.print(ltx.@@.tables.#1["#2"]) }
+ }
+
+%for debugging commands that show both the seq/prop and the lua tables
+\cs_new:Nn \@@_seq_show:N
+ {
+ \seq_show:N #1
+ \@@_luatex_get_table_name:Nn \l_tmpa_tl { #1 }
+ \directlua { ltx.@@.trace.log ("lua~sequence~array~\l_tmpa_tl",1) }
+ \directlua { ltx.@@.trace.show_seq (ltx.@@.tables.\l_tmpa_tl) }
+ }
+
+\cs_new:Nn \@@_prop_show:N
+ {
+ \prop_show:N #1
+ \@@_luatex_get_table_name:Nn \l_tmpa_tl { #1 }
+ \directlua {ltx.@@.trace.log ("lua~property~table~\l_tmpa_tl",1) }
+ \directlua {ltx.@@.trace.show_prop (ltx.@@.tables.\l_tmpa_tl) }
+ }
+%</luatex>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<*pdftex>
+\ProvidesExplFile {tagpdf-pdftex.def} {2021/02/23} {0.80}
+ {tagpdf~driver~for~pdftex}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%% driver (pdflatex) commands
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+% These commands are only aliases for pdflatex but are defined differently with luatex
+% to get also lua tables.
+\cs_set_eq:NN \@@_prop_new:N \prop_new:N
+
+\cs_set_eq:NN \@@_seq_new:N \seq_new:N
+
+\cs_set_eq:NN \@@_prop_gput:Nnn \prop_gput:Nnn
+
+\cs_set_eq:NN \@@_seq_gput_right:Nn \seq_gput_right:Nn
+
+\cs_set_eq:NN \@@_seq_item:cn \seq_item:cn
+
+\cs_set_eq:NN \@@_prop_item:cn \prop_item:cn
+
+\cs_set_eq:NN \@@_seq_show:N \seq_show:N
+
+\cs_set_eq:NN \@@_prop_show:N \prop_show:N
+
+%</pdftex>
+% \end{macrocode}
+% \begin{macrocode}
+%<*lua>
+-- tagpdf.lua
+-- Ulrike Fischer
+
+local ProvidesLuaModule = {
+ name = "tagpdf",
+ version = "0.80", --TAGVERSION
+ date = "2021-02-23", --TAGDATE
+ description = "tagpdf lua code",
+ license = "The LATEX Project Public License 1.3c"
+}
+
+if luatexbase and luatexbase.provides_module then
+ luatexbase.provides_module (ProvidesLuaModule)
+end
+
+--[[
+The code has quite probably a number of problems
+ - more variables should be local instead of global
+ - the naming is not always consistent due to the development of the code
+ - the traversing of the shipout box must be tested with more complicated setups
+ - it should probably handle more node types
+ -
+--]]
+
+
+
+--[[
+the main table is named ltx.@@. It contains the functions and also the data
+collected during the compilation.
+
+ltx.@@.mc will contain mc connected data.
+ltx.@@.struct will contain structure related data.
+ltx.@@.page will contain page data
+ltx.@@.tables contains also data from mc and struct (from older code). This needs cleaning up.
+ There are certainly dublettes, but I don't dare yet ...
+ltx.@@.func will contain (public) functions.
+ltx.@@.trace will contain tracing/loging functions.
+local funktions starts with __
+functions meant for users will be in ltx.tag
+
+functions
+ ltx.@@.func.get_num_from (tag): takes a tag (string) and returns the id number
+ ltx.@@.func.output_num_from (tag): takes a tag (string) and prints (to tex) the id number
+ ltx.@@.func.get_tag_from (num): takes a num and returns the tag
+ ltx.@@.func.output_tag_from (num): takes a num and prints (to tex) the tag
+ ltx.@@.func.store_mc_data (num,key,data): stores key=data in ltx.@@.mc[num]
+ ltx.@@.func.store_mc_label (label,num): stores label=num in ltx.@@.mc.labels
+ ltx.@@.func.store_mc_kid (mcnum,kid,page): stores the mc-kids of mcnum on page page
+ ltx.@@.func.store_mc_in_page(mcnum,mcpagecnt,page): stores in the page table the number of mcnum on this page
+ ltx.@@.func.store_struct_mcabs (structnum,mcnum): stores relations structnum<->mcnum (abs)
+ ltx.@@.func.mc_insert_kids (mcnum): inserts the /K entries for mcnum by wandering throught the [kids] table
+ ltx.@@.func.mark_page_elements(box,mcpagecnt,mccntprev,mcopen,name,mctypeprev) : the main function
+ ltx.@@.func.mark_shipout (): a wrapper around the core function which inserts the last EMC
+ ltx.@@.func.fill_parent_tree_line (page): outputs the entries of the parenttree for this page
+ ltx.@@.func.output_parenttree(): outputs the content of the parenttree
+ ltx.@@.func.markspaceon(), ltx.@@.func.markspaceoff(): (de)activates the marking of positions for space chars
+ ltx.@@.trace.show_mc_data (num): shows ltx.@@.mc[num]
+ ltx.@@.trace.show_all_mc_data (max): shows a maximum about mc's
+ ltx.@@.trace.show_seq: shows a sequence (array)
+ ltx.@@.trace.show_struct_data (num): shows data of structure num
+ ltx.@@.trace.show_prop: shows a prop
+ ltx.@@.trace.log
+ ltx.@@.trace.showspaces : boolean
+--]]
+
+local mctypeattributeid = luatexbase.registernumber ("l_@@_mc_type_attr")
+local mccntattributeid = luatexbase.registernumber ("l_@@_mc_cnt_attr")
+local iwspaceattributeid = luatexbase.registernumber ("g_@@_interwordspace_attr")
+local iwfontattributeid = luatexbase.registernumber ("g_@@_interwordfont_attr")
+
+
+local catlatex = luatexbase.registernumber("catcodetable@latex")
+local tagunmarkedbool= token.create("g_@@_tagunmarked_bool")
+local truebool = token.create("c_true_bool")
+
+local tableinsert = table.insert
+
+-- not all needed, copied from lua-visual-debug.
+local nodeid = node.id
+local nodecopy = node.copy
+local nodegetattribute = node.get_attribute
+local nodesetattribute = node.set_attribute
+local nodenew = node.new
+local nodetail = node.tail
+local nodeslide = node.slide
+local noderemove = node.remove
+local nodetraverseid = node.traverse_id
+local nodetraverse = node.traverse
+local nodeinsertafter = node.insert_after
+local nodeinsertbefore = node.insert_before
+local pdfpageref = pdf.pageref
+
+local HLIST = node.id("hlist")
+local VLIST = node.id("vlist")
+local RULE = node.id("rule")
+local DISC = node.id("disc")
+local GLUE = node.id("glue")
+local GLYPH = node.id("glyph")
+local KERN = node.id("kern")
+local PENALTY = node.id("penalty")
+local LOCAL_PAR = node.id("local_par")
+local MATH = node.id("math")
+
+local function @@_get_mathsubtype (mathnode)
+ if mathnode.subtype == 0 then
+ subtype = "beginmath"
+ else
+ subtype = "endmath"
+ end
+ return subtype
+end
+
+
+
+ltx = ltx or { }
+ltx.@@ = ltx.@@ or { }
+ltx.@@.mc = ltx.@@.mc or { } -- mc data
+ltx.@@.struct = ltx.@@.struct or { } -- struct data
+ltx.@@.tables = ltx.@@.tables or { } -- tables created with new prop and new seq.
+ -- wasn't a so great idea ...
+ltx.@@.page = ltx.@@.page or { } -- page data, currently only i->{0->mcnum,1->mcnum,...}
+ltx.@@.trace = ltx.@@.trace or { } -- show commands
+ltx.@@.func = ltx.@@.func or { } -- functions
+ltx.@@.conf = ltx.@@.conf or { } -- configuration variables
+
+local @@_log =
+ function (message,loglevel)
+ if (loglevel or 3) <= tex.count["l_@@_loglevel_int"] then
+ texio.write_nl("tagpdf: ".. message)
+ end
+ end
+
+ltx.@@.trace.log = @@_log
+
+
+local @@_get_mc_cnt_type_tag = function (n)
+ local mccnt = nodegetattribute(n,mccntattributeid) or -1
+ local mctype = nodegetattribute(n,mctypeattributeid) or -1
+ local tag = ltx.@@.func.get_tag_from(mctype)
+ return mccnt,mctype,tag
+end
+
+
+local function @@_insert_emc_node (head,current)
+ local emcnode = nodenew("whatsit","pdf_literal")
+ emcnode.data = "EMC"
+ emcnode.mode=1
+ head = node.insert_before(head,current,emcnode)
+ return head
+end
+
+
+local function @@_insert_bmc_node (head,current,tag)
+ local bmcnode = nodenew("whatsit","pdf_literal")
+ bmcnode.data = "/"..tag.." BMC"
+ bmcnode.mode=1
+ head = node.insert_before(head,current,bmcnode)
+ return head
+end
+
+local function @@_insert_bdc_node (head,current,tag,dict)
+ local bdcnode = nodenew("whatsit","pdf_literal")
+ bdcnode.data = "/"..tag.."<<"..dict..">> BDC"
+ bdcnode.mode=1
+ head = node.insert_before(head,current,bdcnode)
+ return head
+end
+
+-- this is for debugging the space chars
+local function @@_show_spacemark (head,current,color,height)
+ local markcolor = color or "1 0 0"
+ local markheight = height or 10
+ local pdfstring = node.new("whatsit","pdf_literal")
+ pdfstring.data =
+ string.format("q "..markcolor.." RG "..markcolor.." rg 0.4 w 0 %g m 0 %g l S Q",-3,markheight)
+ head = node.insert_after(head,current,pdfstring)
+ return head
+end
+
+--[[ a function to mark up places where real space chars should be inserted
+ it only sets an attribute.
+--]]
+
+local function @@_mark_spaces (head)
+ local inside_math = false
+ for n in nodetraverse(head) do
+ local id = n.id
+ if id == GLYPH then
+ local glyph = n
+ if glyph.next and (glyph.next.id == GLUE)
+ and not inside_math and (glyph.next.width >0)
+ then
+ nodesetattribute(glyph.next,iwspaceattributeid,1)
+ nodesetattribute(glyph.next,iwfontattributeid,glyph.font)
+ -- for debugging
+ if ltx.@@.trace.showspaces then
+ @@_show_spacemark (head,glyph)
+ end
+ elseif glyph.next and (glyph.next.id==KERN) and not inside_math then
+ local kern = glyph.next
+ if kern.next and (kern.next.id== GLUE) and (kern.next.width >0)
+ then
+ nodesetattribute(kern.next,iwspaceattributeid,1)
+ nodesetattribute(kern.next,iwfontattributeid,glyph.font)
+ end
+ end
+ elseif id == PENALTY then
+ local glyph = n
+ -- ltx.@@.trace.log ("PENALTY ".. n.subtype.."VALUE"..n.penalty,3)
+ if glyph.next and (glyph.next.id == GLUE)
+ and not inside_math and (glyph.next.width >0) and n.subtype==0
+ then
+ nodesetattribute(glyph.next,iwspaceattributeid,1)
+ -- nodesetattribute(glyph.next,iwfontattributeid,glyph.font)
+ -- for debugging
+ if ltx.@@.trace.showspaces then
+ @@_show_spacemark (head,glyph)
+ end
+ end
+ elseif id == MATH then
+ inside_math = (n.subtype == 0)
+ end
+ end
+ return head
+end
+
+local function @@_activate_mark_space ()
+ if not luatexbase.in_callback ("pre_linebreak_filter","markspaces") then
+ luatexbase.add_to_callback("pre_linebreak_filter",@@_mark_spaces,"markspaces")
+ luatexbase.add_to_callback("hpack_filter",@@_mark_spaces,"markspaces")
+ end
+end
+
+ltx.@@.func.markspaceon=@@_activate_mark_space
+
+local function @@_deactivate_mark_space ()
+ if luatexbase.in_callback ("pre_linebreak_filter","markspaces") then
+ luatexbase.remove_from_callback("pre_linebreak_filter","markspaces")
+ luatexbase.remove_from_callback("hpack_filter","markspaces")
+ end
+end
+--
+ltx.@@.func.markspaceoff=@@_deactivate_mark_space
+
+local default_space_char = node.new(GLYPH)
+local default_fontid = font.id("TU/lmr/m/n/10")
+default_space_char.char = 32
+default_space_char.font = default_fontid
+
+local function @@_insert_space_char (head,n,fontid)
+ if luaotfload.aux.slot_of_name(fontid,"space") then
+ local space
+ -- head, space = node.insert_before(head, n, ) -- Set the right font
+ -- n.width = n.width - space.width
+ -- space.attr = n.attr
+ end
+end
+
+--[[
+ Now follows the core function
+ It wades through the shipout box and checks the attributes
+ ARGUMENTS
+ box: is a box,
+ mcpagecnt: num, the current page cnt of mc (should start at -1 in shipout box), needed for recursion
+ mccntprev: num, the attribute cnt of the previous node/whatever - if different we have a chunk border
+ mcopen: num, records if some bdc/emc is open
+ These arguments are only needed for log messages, if not present are replaces by fix strings:
+ name: string to describe the box
+ mctypeprev: num, the type attribute of the previous node/whatever
+
+ there are lots of logging messages currently. Should be cleaned up in due course.
+ One should also find ways to make the function shorter.
+--]]
+
+function ltx.@@.func.mark_page_elements (box,mcpagecnt,mccntprev,mcopen,name,mctypeprev)
+ local name = name or ("SOMEBOX")
+ local mctypeprev = mctypeprev or -1
+ local abspage = status.total_pages + 1 -- the real counter is increased inside the box so one off
+ -- if the callback is not used.
+ ltx.@@.trace.log ("PAGE " .. abspage,3)
+ ltx.@@.trace.log ("FUNC ARGS: pagecnt".. mcpagecnt.." prev "..mccntprev .. " type prev "..mctypeprev,4)
+ ltx.@@.trace.log ("TRAVERSING BOX ".. tostring(name).." TYPE ".. node.type(node.getid(box)),3)
+ local head = box.head -- ShipoutBox is a vlist?
+ if head then
+ mccnthead, mctypehead,taghead = @@_get_mc_cnt_type_tag (head)
+ ltx.@@.trace.log ("HEAD " .. node.type(node.getid(head)).. " MC"..tostring(mccnthead).." => TAG "..tostring(mctypehead).." => "..tostring(taghead),3)
+ else
+ ltx.@@.trace.log ("HEAD is ".. tostring(head),3)
+ end
+ for n in node.traverse(head) do
+ local mccnt, mctype, tag = @@_get_mc_cnt_type_tag (n)
+ local spaceattr = nodegetattribute(n,iwspaceattributeid) or -1
+ ltx.@@.trace.log ("NODE ".. node.type(node.getid(n)).." MC"..tostring(mccnt).." => TAG "..tostring(mctype).." => " .. tostring(tag),3)
+ if n.id == HLIST
+ then -- enter the hlist
+ mcopen,mcpagecnt,mccntprev,mctypeprev=
+ ltx.@@.func.mark_page_elements (n,mcpagecnt,mccntprev,mcopen,"INTERNAL HLIST",mctypeprev)
+ elseif n.id == VLIST then -- enter the vlist
+ mcopen,mcpagecnt,mccntprev,mctypeprev=
+ ltx.@@.func.mark_page_elements (n,mcpagecnt,mccntprev,mcopen,"INTERNAL VLIST",mctypeprev)
+ elseif n.id == GLUE then -- at glue real space chars are inserted, for the rest it is ignored
+ -- for debugging
+ if ltx.@@.trace.showspaces and spaceattr==1 then
+ @@_show_spacemark (head,n,"0 1 0")
+ end
+ if spaceattr==1 then
+ local space
+ local space_char = node.copy(default_space_char)
+ local curfont = nodegetattribute(n,iwfontattributeid)
+ ltx.@@.trace.log ("FONT ".. tostring(curfont),3)
+ if curfont and luaotfload.aux.slot_of_name(curfont,"space") then
+ space_char.font=curfont
+ end
+ head, space = node.insert_before(head, n, space_char) --
+ n.width = n.width - space.width
+ space.attr = n.attr
+ end
+ elseif n.id == LOCAL_PAR then -- local_par is ignored
+ elseif n.id == PENALTY then -- penalty is ignored
+ elseif n.id == KERN then -- kern is ignored
+ ltx.@@.trace.log ("SUBTYPE KERN ".. n.subtype,3)
+ else
+ -- math is currently only logged.
+ -- we could mark the whole as math
+ -- for inner processing the mlist_to_hlist callback is probably needed.
+ if n.id == MATH then
+ ltx.@@.trace.log("NODE "..node.type(node.getid(n)).." "..@@_get_mathsubtype(n),3)
+ end
+ -- endmath
+ ltx.@@.trace.log("CURRENT "..mccnt.." PREV "..mccntprev,3)
+ if mccnt~=mccntprev then -- a new mc chunk
+ ltx.@@.trace.log ("NODE ".. node.type(node.getid(n)).." MC"..tostring(mccnt).." <=> PREVIOUS "..tostring(mccntprev),3)
+ if mcopen~=0 then -- there is a chunk open, close it (hope there is only one ...
+ box.list=@@_insert_emc_node (box.list,n)
+ mcopen = mcopen - 1
+ ltx.@@.trace.log ("INSERT EMC " .. mcpagecnt .. " MCOPEN = " .. mcopen,2)
+ if mcopen ~=0 then
+ ltx.@@.trace.log ("!WARNING! open mc" .. " MCOPEN = " .. mcopen,1)
+ end
+ end
+ if ltx.@@.mc[mccnt] then
+ if ltx.@@.mc[mccnt]["artifact"] then
+ ltx.@@.trace.log("THIS IS AN ARTIFACT of type "..tostring(ltx.@@.mc[mccnt]["artifact"]),3)
+ if ltx.@@.mc[mccnt]["artifact"] == "" then
+ box.list = @@_insert_bmc_node (box.list,n,"Artifact")
+ else
+ box.list = @@_insert_bdc_node (box.list,n,"Artifact", "/Type /"..ltx.@@.mc[mccnt]["artifact"])
+ end
+ else
+ ltx.@@.trace.log("THIS IS A TAG "..tostring(tag),3)
+ mcpagecnt = mcpagecnt +1
+ ltx.@@.trace.log ("INSERT BDC "..mcpagecnt,2)
+ local dict= "/MCID "..mcpagecnt
+ if ltx.@@.mc[mccnt]["raw"] then
+ ltx.@@.trace.log("RAW CONTENT"..tostring(ltx.@@.mc[mccnt]["raw"]),3)
+ dict= dict .. " " .. ltx.@@.mc[mccnt]["raw"]
+ end
+ if ltx.@@.mc[mccnt]["alt"] then
+ ltx.@@.trace.log("RAW CONTENT"..tostring(ltx.@@.mc[mccnt]["alt"]),3)
+ dict= dict .. " " .. ltx.@@.mc[mccnt]["alt"]
+ end
+ if ltx.@@.mc[mccnt]["actualtext"] then
+ ltx.@@.trace.log("RAW CONTENT"..tostring(ltx.@@.mc[mccnt]["actualtext"]),3)
+ dict= dict .. " " .. ltx.@@.mc[mccnt]["actualtext"]
+ end
+ box.list = @@_insert_bdc_node (box.list,n,tag, dict)
+ ltx.@@.func.store_mc_kid (mccnt,mcpagecnt,abspage)
+ ltx.@@.func.store_mc_in_page(mccnt,mcpagecnt,abspage)
+ ltx.@@.trace.show_mc_data (mccnt)
+ end
+ mcopen = mcopen + 1
+ else
+ ltx.@@.trace.log("THIS HAS NOT BEEN TAGGED",1)
+ -- perhaps code that tag a artifact can be added ...
+ if tagunmarkedbool.mode == truebool.mode then
+ box.list = @@_insert_bmc_node (box.list,n,"Artifact")
+ mcopen = mcopen + 1
+ end
+ end
+ mccntprev = mccnt
+ end
+ end -- end if
+ end -- end for
+ if head then
+ mccnthead, mctypehead,taghead = @@_get_mc_cnt_type_tag (head)
+ ltx.@@.trace.log ("ENDHEAD " .. node.type(node.getid(head)).. " MC"..tostring(mccnthead).." => TAG "..tostring(mctypehead).." => "..tostring(taghead),3)
+ else
+ ltx.@@.trace.log ("ENDHEAD is ".. tostring(head),3)
+ end
+ ltx.@@.trace.log ("QUITTING TRAVERSING BOX ".. tostring(name).." TYPE ".. node.type(node.getid(box)),3)
+ return mcopen,mcpagecnt,mccntprev,mctypeprev
+end
+
+
+
+function ltx.__tag.func.mark_shipout (box)
+ mcopen = ltx.__tag.func.mark_page_elements (box,-1,-100,0,"Shipout",-1)
+ if mcopen~=0 then -- there is a chunk open, close it (hope there is only one ...
+ local emcnode = nodenew("whatsit","pdf_literal")
+ local list = box.list
+ emcnode.data = "EMC"
+ emcnode.mode=1
+ if list then
+ list = node.insert_after (list,node.tail(list),emcnode)
+ mcopen = mcopen - 1
+ ltx.__tag.trace.log ("INSERT LAST EMC, MCOPEN = " .. mcopen,2)
+ else
+ ltx.__tag.trace.log ("UPS ",1)
+ end
+ if mcopen ~=0 then
+ ltx.__tag.trace.log ("!WARNING! open mc" .. " MCOPEN = " .. mcopen,1)
+ end
+ end
+end
+
+
+function ltx.@@.trace.show_seq (seq)
+ if (type(seq) == "table") then
+ for i,v in ipairs(seq) do
+ @@_log ("[" .. i .. "] => " .. tostring(v),1)
+ end
+ else
+ @@_log ("sequence " .. tostring(seq) .. " not found",1)
+ end
+end
+
+local @@_pairs_prop =
+ function (prop)
+ local a = {}
+ for n in pairs(prop) do tableinsert(a, n) end
+ table.sort(a)
+ local i = 0 -- iterator variable
+ local iter = function () -- iterator function
+ i = i + 1
+ if a[i] == nil then return nil
+ else return a[i], prop[a[i]]
+ end
+ end
+ return iter
+ end
+
+
+function ltx.@@.trace.show_prop (prop)
+ if (type(prop) == "table") then
+ for i,v in @@_pairs_prop (prop) do
+ @@_log ("[" .. i .. "] => " .. tostring(v),1)
+ end
+ else
+ @@_log ("prop " .. tostring(prop) .. " not found or not a table",1)
+ end
+ end
+
+
+local @@_get_num_from =
+ function (tag)
+ if ltx.@@.tables["g_@@_role_tags_prop"][tag] then
+ a= ltx.@@.tables["g_@@_role_tags_prop"][tag]
+ else
+ a= -1
+ end
+ return a
+ end
+
+ltx.@@.func.get_num_from = @@_get_num_from
+
+function ltx.@@.func.output_num_from (tag)
+ local num = @@_get_num_from (tag)
+ tex.sprint(catlatex,num)
+ if num == -1 then
+ @@_log ("Unknown tag "..tag.." used")
+ end
+end
+
+local @@_get_tag_from =
+ function (num)
+ if ltx.@@.tables["g_@@_role_tags_seq"][num] then
+ a = ltx.@@.tables["g_@@_role_tags_seq"][num]
+ else
+ a= "UNKNOWN"
+ end
+ return a
+end
+
+ltx.@@.func.get_tag_from = @@_get_tag_from
+
+function ltx.@@.func.output_tag_from (num)
+ tex.sprint(catlatex,@@_get_tag_from (num))
+end
+
+function ltx.@@.func.store_mc_data (num,key,data)
+ ltx.@@.mc[num] = ltx.@@.mc[num] or { }
+ ltx.@@.mc[num][key] = data
+ @@_log ("storing mc"..num..": "..tostring(key).."=>"..tostring(data))
+end
+
+function ltx.@@.trace.show_mc_data (num)
+ if ltx.@@ and ltx.@@.mc and ltx.@@.mc[num] then
+ for k,v in pairs(ltx.@@.mc[num]) do
+ @@_log ("mc"..num..": "..tostring(k).."=>"..tostring(v),3)
+ end
+ if ltx.@@.mc[num]["kids"] then
+ @@_log ("mc" .. num .. " has " .. #ltx.@@.mc[num]["kids"] .. " kids",3)
+ for k,v in ipairs(ltx.@@.mc[num]["kids"]) do
+ @@_log ("mc ".. num .. " kid "..k.." =>" .. v.kid.." on page " ..v.page,3)
+ end
+ end
+ else
+ @@_log ("mc"..num.." not found",3)
+ end
+end
+
+function ltx.@@.trace.show_all_mc_data (max)
+ for i = 1, max do
+ ltx.@@.trace.show_mc_data (i)
+ end
+end
+
+
+function ltx.@@.func.store_mc_label (label,num)
+ ltx.@@.mc["labels"] = ltx.@@.mc["labels"] or { }
+ ltx.@@.mc.labels[label] = num
+end
+
+function ltx.@@.func.store_mc_kid (mcnum,kid,page)
+ ltx.@@.trace.log("MC"..mcnum.." STORING KID" .. kid.." on page " .. page,3)
+ ltx.@@.mc[mcnum]["kids"] = ltx.@@.mc[mcnum]["kids"] or { }
+ local kidtable = {kid=kid,page=page}
+ tableinsert(ltx.@@.mc[mcnum]["kids"], kidtable )
+end
+
+
+function ltx.@@.func.mc_num_of_kids (mcnum)
+ local num = 0
+ if ltx.@@.mc[mcnum] and ltx.@@.mc[mcnum]["kids"] then
+ num = #ltx.@@.mc[mcnum]["kids"]
+ end
+ ltx.@@.trace.log ("MC" .. mcnum .. "has " .. num .. "KIDS",4)
+ return num
+end
+
+function ltx.@@.func.mc_insert_kids (mcnum,single)
+ if ltx.@@.mc[mcnum] then
+ ltx.@@.trace.log("MC-KIDS test " .. mcnum,4)
+ if ltx.@@.mc[mcnum]["kids"] then
+ if #ltx.@@.mc[mcnum]["kids"] > 1 and single==1 then
+ tex.sprint("[")
+ end
+ for i,kidstable in ipairs( ltx.@@.mc[mcnum]["kids"] ) do
+ local kidnum = kidstable["kid"]
+ local kidpage = kidstable["page"]
+ local kidpageobjnum = pdfpageref(kidpage)
+ ltx.@@.trace.log("MC" .. mcnum .. " insert KID " ..i.. " with num " .. kidnum .. " on page " .. kidpage.."/"..kidpageobjnum,3)
+ tex.sprint(catlatex,"<</Type /MCR /Pg "..kidpageobjnum .. " 0 R /MCID "..kidnum.. ">> " )
+ end
+ if #ltx.@@.mc[mcnum]["kids"] > 1 and single==1 then
+ tex.sprint("]")
+ end
+ else
+ ltx.@@.trace.log("WARN! MC"..mcnum.." has no kids",0)
+ if single==1 then
+ tex.sprint("null")
+ end
+ end
+ else
+ ltx.@@.trace.log("WARN! MC"..mcnum.." doesn't exist",0)
+ end
+end
+
+
+function ltx.@@.func.store_struct_mcabs (structnum,mcnum)
+ ltx.@@.struct[structnum]=ltx.@@.struct[structnum] or { }
+ ltx.@@.struct[structnum]["mc"]=ltx.@@.struct[structnum]["mc"] or { }
+ -- a structure can contain more than on mc chunk, the content should be ordered
+ tableinsert(ltx.@@.struct[structnum]["mc"],mcnum)
+ ltx.@@.trace.log("MCNUM "..mcnum.." insert in struct "..structnum,3)
+ -- but every mc can only be in one structure
+ ltx.@@.mc[mcnum]= ltx.@@.mc[mcnum] or { }
+ ltx.@@.mc[mcnum]["parent"] = structnum
+end
+
+function ltx.@@.trace.show_struct_data (num)
+ if ltx.@@ and ltx.@@.struct and ltx.@@.struct[num] then
+ for k,v in ipairs(ltx.@@.struct[num]) do
+ @@_log ("struct "..num..": "..tostring(k).."=>"..tostring(v))
+ end
+ else
+ @@_log ("struct "..num.." not found ")
+ end
+end
+
+-- pay attention: lua counts arrays from 1, tex pages from one
+-- mcid and arrays in pdf count from 0.
+function ltx.@@.func.store_mc_in_page (mcnum,mcpagecnt,page)
+ ltx.@@.page[page] = ltx.@@.page[page] or {}
+ ltx.@@.page[page][mcpagecnt] = mcnum
+ ltx.@@.trace.log("PAGE " .. page .. ": inserting MCID " .. mcpagecnt .. " => " .. mcnum,3)
+end
+
+function ltx.@@.func.fill_parent_tree_line (page)
+ -- we need to get page-> i=kid -> mcnum -> structnum
+ -- pay attention: the kid numbers and the page number in the parent tree start with 0!
+ local numsentry =""
+ local pdfpage = page-1
+ if ltx.@@.page[page] and ltx.@@.page[page][0] then
+ mcchunks=#ltx.@@.page[page]
+ ltx.@@.trace.log("PAGETREE PAGE "..page.." has "..mcchunks.."+1 Elements ",3)
+ for i=0,mcchunks do
+ ltx.@@.trace.log("PAGETREE CHUNKS "..ltx.@@.page[page][i],3)
+ end
+ if mcchunks == 0 then
+ -- only one chunk so no need for an array
+ local mcnum = ltx.@@.page[page][0]
+ local structnum = ltx.@@.mc[mcnum]["parent"]
+ local propname = "g_@@_struct_"..structnum.."_prop"
+ local objref = ltx.@@.tables[propname]["objref"] or "XXXX"
+ texio.write_nl("=====>"..tostring(objref))
+ numsentry = pdfpage .. " [".. objref .. "]"
+ ltx.@@.trace.log("PAGETREE PAGE" .. page.. " NUM ENTRY = ".. numsentry,3)
+ else
+ numsentry = pdfpage .. " ["
+ for i=0,mcchunks do
+ local mcnum = ltx.@@.page[page][i]
+ local structnum = ltx.@@.mc[mcnum]["parent"] or 0
+ local propname = "g_@@_struct_"..structnum.."_prop"
+ local objref = ltx.@@.tables[propname]["objref"] or "XXXX"
+ numsentry = numsentry .. " ".. objref
+ end
+ numsentry = numsentry .. "] "
+ ltx.@@.trace.log("PAGETREE PAGE" .. page.. " NUM ENTRY = ".. numsentry,3)
+ end
+ else
+ ltx.@@.trace.log ("PAGETREE: NO DATA FOR PAGE "..page,3)
+ end
+ return numsentry
+end
+
+function ltx.@@.func.output_parenttree (abspage)
+ for i=1,abspage do
+ line = ltx.@@.func.fill_parent_tree_line (i) .. "^^J"
+ tex.sprint(catlatex,line)
+ end
+end
+
+
+%</lua>
+% \end{macrocode}
diff --git a/Master/texmf-dist/source/latex/tagpdf/tagpdf-checks.dtx b/Master/texmf-dist/source/latex/tagpdf/tagpdf-checks.dtx
new file mode 100644
index 00000000000..ad3866ed76c
--- /dev/null
+++ b/Master/texmf-dist/source/latex/tagpdf/tagpdf-checks.dtx
@@ -0,0 +1,232 @@
+% \iffalse meta-comment
+%
+%% File: tagpdf-checks.dtx
+%
+% Copyright (C) 2019-2020 Ulrike Fischer
+%
+% 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 "tagpdf 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/u-fischer/tagpdf
+%
+% for those people who are interested.
+%
+% \fi
+%
+% \begin{macrocode}
+%<@@=tag>
+%<*checks>
+\ProvidesExplPackage {tagpdf-checks-code} {2021/02/23} {0.80}
+ {part of tagpdf - code related to checks and messages}
+
+
+%messages
+
+% mc
+\msg_new:nnn { tag } {mc-nested} { nested~marked~content~found~-~mcid~#1 }
+\msg_new:nnn { tag } {mc-tag-missing} { required~tag~missing~-~mcid~#1 }
+\msg_new:nnn { tag } {mc-label-unknown} { label~#1~unknown~-~rerun }
+\msg_new:nnn { tag } {mc-used-twice} { mc~#1~has~been~already~used }
+\msg_new:nnn { tag } {mc-not-open} { there~is~no~mc~to~end~at~#1 }
+
+% structures
+\msg_new:nnn { tag } {struct-no-objnum} { objnum~missing~for~structure~#1 }
+\msg_new:nnn { tag } {struct-faulty-nesting} { there~is~no~open~structure~on~the~stack }
+\msg_new:nnn { tag } {struct-missing-tag} { a~structure~must~have~a~tag! }
+\msg_new:nnn { tag } {struct-show-closing} { closing~structure~#1~tagged~\prop_item:cn{g_@@_struct_#1_prop}{S} }
+\msg_new:nnn { tag } {struct-used-twice} { structure~with~label~#1~has~already~been~used}
+\msg_new:nnn { tag } {struct-label-unknown} { structure~with~label~#1~is~unknown~rerun}
+
+% attributes
+\msg_new:nnn { tag } {attr-unknown} { attribute~#1~is~unknown}
+
+
+%Roles
+\msg_new:nnn { tag } {role-missing} { tag~#1~has~no~role~assigned }
+\msg_new:nnn { tag } {role-unknown} { role~#1~is~not~known }
+\msg_new:nnn { tag } {role-unknown-tag} { tag~#1~is~not~known }
+\msg_new:nnn { tag } {role-new-tag} { adding~new~tag~#1~mapped~to~role~#2 }
+
+
+% trees
+\msg_new:nnn { tag } {tree-mcid-index-wrong} {something~is~wrong~with~the~mcid}
+
+% obj
+\msg_new:nnn { tag } {obj-write-num} {write~obj~#1~to~pdf}
+
+% engine problem
+\msg_new:nnn { tag } {sys-no-interwordspace} {engine~#1~doesn't~support~the~interword~spaces}
+
+%checks
+%structures
+
+\cs_new:Nn \@@_check_structure_has_tag:n %#1 struct num %_protected?
+ {
+ \prop_if_in:cnF { g_@@_struct_#1_prop }
+ {S}
+ {
+ \msg_error:nn { tag } {struct-missing-tag}
+ }
+ }
+
+\cs_new:Nn \@@_check_structure_tag:N %_protected?
+ {
+ \prop_if_in:NoF \g_@@_role_tags_prop {#1}
+ {
+ \msg_warning:nnx { tag } {role-unknown-tag} {#1}
+ }
+ }
+
+\cs_new_protected:Nn \@@_check_info_closing_struct:n %#1 struct num
+ {
+ \msg_info:nnn { tag } {struct-show-closing} {#1}
+ }
+
+\cs_generate_variant:Nn \@@_check_info_closing_struct:n {o,x}
+
+\cs_new_protected:Nn \@@_check_no_open_struck:
+ {
+ \msg_error:nn { tag } {struct-faulty-nesting}
+ }
+
+\cs_new_protected:Nn \@@_check_struct_used:n %#1 label
+ {
+ \prop_get:cnNT
+ {g_@@_struct_\@@_ref_value:enn{tagpdfstruct-#1}{tagstruct}{unknown}_prop}
+ {P}
+ \l_tmpa_tl
+ {
+ \msg_warning:nnn { tag } {struct-used-twice} {#1}
+ }
+ }
+
+%roles
+
+\cs_new_protected:Nn \@@_check_add_tag_role:nn %#1 tag, #2 role
+ {
+ \tl_if_empty:nTF {#2}
+ {
+ \msg_warning:nnn { tag } {role-missing} {#1}
+ }
+ {
+ \prop_get:NnNTF \g_@@_role_tags_prop {#2} \l_tmpa_tl
+ {
+ \msg_info:nnnn { tag } {role-new-tag} {#1} {#2}
+ }
+ {
+ \msg_warning:nnn { tag } {role-unknown} {#2}
+ }
+ }
+ }
+
+%mc
+\cs_new_protected:Nn \@@_check_mc_if_nested:
+ {
+ \@@_mc_if_in:T
+ {
+ \msg_warning:nnx { tag } {mc-nested} { \@@_get_mc_abs_cnt: }
+ }
+ }
+
+\cs_new_protected:Nn \@@_check_mc_if_open:
+ {
+ \@@_mc_if_in:F
+ {
+ \msg_warning:nnx { tag } {mc-not-open} { \@@_get_mc_abs_cnt: }
+ }
+ }
+
+\cs_new:Nn \@@_check_mc_tag:N %protected??
+ {
+ \tl_if_empty:NT #1
+ {
+ \msg_error:nnx { tag } {mc-tag-missing} { \@@_get_mc_abs_cnt: }
+ }
+ \prop_if_in:NoF \g_@@_role_tags_prop {#1}
+ {
+ \msg_warning:nnx { tag } {role-unknown-tag} {#1}
+ }
+ }
+
+\seq_new:N \g_@@_check_mc_used_seq
+\cs_new_protected:Nn \@@_check_mc_used:n
+ {
+ \seq_if_in:NnTF \g_@@_check_mc_used_seq {#1}
+ {
+ \msg_warning:nnn { tag } {mc-used-twice} {#1}
+ }
+ {
+ \seq_gput_right:Nx \g_@@_check_mc_used_seq {#1}
+ }
+ }
+
+
+
+\cs_new_protected:Nn \@@_check_show_MCID_by_page:
+ {
+ \tl_set:Nx \l_@@_tmpa_tl
+ {
+ \@@_ref_value_lastpage:nn
+ {abspage}
+ {-1}
+ }
+ \int_step_inline:nnnn {1}{1}
+ {
+ \l_@@_tmpa_tl
+ }
+ {
+ \seq_clear:N \l_tmpa_seq
+ \int_step_inline:nnnn
+ {1}
+ {1}
+ {
+ \@@_ref_value_lastpage:nn
+ {tagmcabs}
+ {-1}
+ }
+ {
+ \int_compare:nT
+ {
+ \@@_ref_value:enn
+ {mcid-####1}
+ {tagabspage}
+ {-1}
+ =
+ ##1
+ }
+ {
+ \seq_gput_right:Nx \l_tmpa_seq
+ {
+ Page##1-####1-
+ \@@_ref_value:enn
+ {mcid-####1}
+ {tagmcid}
+ {-1}
+ }
+ }
+ }
+ \seq_show:N \l_tmpa_seq
+ }
+ }
+
+\cs_new:Nn \@@_check_record_pdfobj_num:n %protected?
+ {
+ \int_compare:nT { \l_@@_loglevel_int >= 3 }
+ {
+ \msg_info:nnx { tag } {obj-write-num} {#1}
+ }
+ }
+
+%</checks>
+% \end{macrocode}
diff --git a/Master/texmf-dist/source/latex/tagpdf/tagpdf-mc.dtx b/Master/texmf-dist/source/latex/tagpdf/tagpdf-mc.dtx
new file mode 100644
index 00000000000..a2cc7f349dc
--- /dev/null
+++ b/Master/texmf-dist/source/latex/tagpdf/tagpdf-mc.dtx
@@ -0,0 +1,779 @@
+% \iffalse meta-comment
+%
+%% File: tagpdf-mc.dtx
+%
+% Copyright (C) 2019-2020 Ulrike Fischer
+%
+% 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 "tagpdf 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/u-fischer/tagpdf
+%
+% for those people who are interested.
+%
+% \fi
+%
+% \begin{macrocode}
+%<@@=tag>
+%<*shared>
+\ProvidesExplPackage {tagpdf-mc-code-shared} {2021/02/23} {0.80}
+ {part of tagpdf - code related to marking chunks -
+ code shared by generic and luamode }
+% I use a latex counter for the absolute count, so that it is added to
+% \cl@@ckpt and restored e.g. in tabulars and align
+% \int_new:N \c@g_@@_MCID_int and
+% \tl_put_right:Nn\cl@@ckpt{\@elt{g_uf_test_int}}
+% would work too, but as the name is not expl3 then too, why bother?
+% the absolute counter can be used to label and to check if the page
+% counter needs a reset.
+
+\newcounter { g_@@_MCID_abs_int }
+\cs_new:Nn \_@@_get_mc_abs_cnt: { \int_use:N \c@g_@@_MCID_abs_int }
+
+% tagmcabs is the label name of the absolute count which is used
+% to identify the chunk
+% the ref code is now in tagpdf.dtx
+
+%stores labels of mcid.
+\cs_new:Nn \_@@_mc_handle_mc_label:n
+ {
+ \@@_ref_label:en{tagpdf-#1}{mc}
+ }
+
+% will hold the structure numbers for the parenttree
+% key: absolute number of the mc (tagmcabs)
+% value: the structure number the mc is in
+\_@@_prop_new:N \g_@@_mc_parenttree_prop
+
+% shared keys
+% the rest are in the splitted code
+\tl_new:N \l_@@_mc_artifact_type_tl
+
+\keys_define:nn { @@ / mc }
+ {
+ stash .bool_set:N = \l_@@_mc_key_stash_bool,
+ artifact-bool .bool_set:N = \l_@@_mc_artifact_bool,
+ artifact-type .choice:,
+ artifact-type / pagination .code:n =
+ {
+ \tl_set:Nn \l_@@_mc_artifact_type_tl { Pagination }
+ },
+ artifact-type / layout .code:n =
+ {
+ \tl_set:Nn \l_@@_mc_artifact_type_tl { Layout }
+ },
+ artifact-type / page .code:n =
+ {
+ \tl_set:Nn \l_@@_mc_artifact_type_tl { Page }
+ },
+ artifact-type / background .code:n =
+ {
+ \tl_set:Nn \l_@@_mc_artifact_type_tl { Background }
+ },
+ artifact-type / notype .code:n =
+ {
+ \tl_set:Nn \l_@@_mc_artifact_type_tl {}
+ },
+ artifact-type / .code:n =
+ {
+ \tl_set:Nn \l_@@_mc_artifact_type_tl {}
+ },
+ }
+% \end{macrocode}
+% \begin{function}[added = 2019-11-20]
+% {
+% \tag_mc_artifact_group_begin:n, \tag_mc_artifact_group_end:
+% }
+% \begin{syntax}
+% \cs{tag_mc_artifact_group_begin:n} \Arg{name}
+% \end{syntax}
+% This command pair create a group with an artifact marker at the begin
+% and the end. Inside the group the tagging commands are disabled.
+% \end{function}
+% \begin{macrocode}
+
+
+\cs_new_protected:Npn \tag_mc_artifact_group_begin:n #1
+ {
+ \tag_mc_begin:n {artifact=#1}
+ \tag_stop_group_begin:
+ }
+
+\cs_new_protected:Npn \tag_mc_artifact_group_end:
+ {
+ \tag_stop_group_end:
+ \tag_mc_end:
+ }
+
+% we need to define it for both modes to avoid a problem with the label
+\int_new:N \g_@@_MCID_tmp_bypage_int
+
+%</shared>
+% \end{macrocode}
+% \begin{macrocode}
+%<*generic>
+\ProvidesExplPackage {tagpdf-mc-code-generic} {2021/02/23} {0.80}
+ {part of tagpdf - code related to marking chunks - generic mode}
+
+% for the label system
+% tagmcid is the id which should be also in the pdf
+% it will be (hopefully) reset by page
+
+% ref code is in tagpdf.dtx now
+%
+% will hold the current maximum on a page
+% it will contain key-value of type "abspagenum=max mcid on this page"
+\@@_prop_new:N \g_@@_MCID_byabspage_prop
+
+%to test nesting mc:
+\bool_new:N \g_@@_in_mc_bool
+
+\prg_new_conditional:Nnn \@@_mc_if_in: {p,T,F,TF}
+ {
+ \bool_if:NTF \g_@@_in_mc_bool
+ { \prg_return_true: }
+ { \prg_return_false: }
+ }
+
+\prg_new_eq_conditional:NNn \tag_mc_if_in: \@@_mc_if_in: {p,T,F,TF}
+
+%deprecated
+\prg_new_eq_conditional:NNn \uftag_mc_if_in: \@@_mc_if_in: {p,T,F,TF}
+
+
+% this are the low level mc command.
+% they insert literals and so a are specific to generic mode
+% checking if the type is defined will done somewhere else
+% #1 is the type/tag
+% change 04.08.2018: I don't try to escape the name, but assume that it is valid.
+% Checks/conversions should perhaps be done on a higher level
+\cs_new_protected:Nn \@@_mc_bmc:n
+ {
+ \pdf_bmc:n {#1}
+% \@@_pdfliteral_page:n
+% {
+% /#1\c_space_tl BMC
+% }
+ }
+
+\cs_new_protected:Nn \@@_mc_emc:
+ {
+ \pdf_emc:
+ %\@@_pdfliteral_page:n
+% {
+% EMC
+% }
+ }
+
+% #1 tag, #2 properties
+% change 04.08.2018: I don't escape the name. Also the dictionary content
+% must imho be done at a higher level
+\cs_new_protected:Nn \@@_mc_bdc:nn
+ {
+ \pdf_bdc:nn { #1 } { #2 }
+ }
+
+\cs_generate_variant:Nn \@@_mc_bdc:nn {nx}
+% bdc with /MCID + more properties
+% we need a ref-label system to ensure that the cnt restarts at 0 on a new page
+
+\tl_new:N \l_@@_mc_ref_abspage_tl %will store the abspage value of label
+\tl_new:N \l_@@_mc_tmp_tl
+
+\cs_new:Nn \@@_mc_bdc_mcid:nn
+ {
+ \int_gincr:N \c@g_@@_MCID_abs_int
+ \tl_set:Nx \l_@@_mc_ref_abspage_tl
+ {
+ \@@_ref_value:enn %3 args
+ {
+ mcid-\int_use:N \c@g_@@_MCID_abs_int
+ }
+ { tagabspage }
+ {-1}
+ }
+ \prop_get:NoNTF
+ \g_@@_MCID_byabspage_prop
+ {
+ \l_@@_mc_ref_abspage_tl
+ }
+ \l_@@_mc_tmp_tl
+ {
+ %key already present, use value for MCID and add 1 for the next
+ \int_gset:Nn \g_@@_MCID_tmp_bypage_int { \l_@@_mc_tmp_tl }
+ \@@_prop_gput:Nxx
+ \g_@@_MCID_byabspage_prop
+ { \l_@@_mc_ref_abspage_tl }
+ { \int_eval:n {\l_@@_mc_tmp_tl +1} }
+ }
+ {
+ %key not present, set MCID to 0 and insert 1
+ \int_gzero:N \g_@@_MCID_tmp_bypage_int
+ \@@_prop_gput:Nxx
+ \g_@@_MCID_byabspage_prop
+ { \l_@@_mc_ref_abspage_tl }
+ {1}
+ }
+ \@@_ref_label:en
+ {
+ mcid-\int_use:N \c@g_@@_MCID_abs_int
+ }
+ { mc }
+ %\exp_args:Nnx
+ \@@_mc_bdc:nx
+ {#1}
+ { /MCID~\int_eval:n { \g_@@_MCID_tmp_bypage_int }~ \exp_not:n { #2 } }
+ }
+
+% only /MCID
+\cs_new:Nn \@@_mc_bdc_mcid:n
+ {
+ \@@_mc_bdc_mcid:nn {#1} {}
+ }
+
+%artifact without type
+\cs_new:Nn \@@_mc_bmc_artifact:
+ {
+ \@@_mc_bmc:n {Artifact}
+ }
+
+%artifact with a type:
+\cs_new:Nn \@@_mc_bmc_artifact:n
+ {
+ \@@_mc_bdc:nn {Artifact}{/Type/#1}
+ }
+
+% perhaps later: more properties for artifacts
+
+
+% keyval definitions for the user commands:
+
+\tl_new:N \l_@@_mc_key_tag_tl
+\tl_new:N \g_@@_mc_key_tag_tl %for "outside" queries
+\tl_new:N \l_@@_mc_key_properties_tl
+
+% Attention! definitions are different in luamode.
+% tag and raw are expanded as \directlua in lua does it too.
+\keys_define:nn { @@ / mc }
+ {
+ tag .code:n = % the name (H,P,Spa) etc
+ {
+ %%????????? \pdfescapename??
+ \tl_set:Nx \l_@@_mc_key_tag_tl { #1 }
+ \tl_gset:Nx \g_@@_mc_key_tag_tl { #1 }
+ },
+ raw .code:n =
+ {
+ \tl_put_right:Nx \l_@@_mc_key_properties_tl { #1 }
+ },
+ alttext .code:n = % Alt property
+ {
+ \str_set_convert:Nnon
+ \l_@@_tmpa_str
+ { #1 }
+ { default }
+ { utf16/hex }
+ \tl_put_right:Nn \l_@@_mc_key_properties_tl { /Alt~< }
+ \tl_put_right:No \l_@@_mc_key_properties_tl { \l_@@_tmpa_str>~ }
+ },
+ alttext-o .code:n = % Alt property
+ {
+ \str_set_convert:Noon
+ \l_@@_tmpa_str
+ { #1 }
+ { default }
+ { utf16/hex }
+ \tl_put_right:Nn \l_@@_mc_key_properties_tl { /Alt~< }
+ \tl_put_right:No \l_@@_mc_key_properties_tl { \l_@@_tmpa_str>~ }
+ },
+ actualtext .code:n = % ActualText property
+ {
+ \str_set_convert:Nnon
+ \l_@@_tmpa_str
+ { #1 }
+ { default }
+ { utf16/hex }
+ \tl_put_right:Nn \l_@@_mc_key_properties_tl { /ActualText~< }
+ \tl_put_right:No \l_@@_mc_key_properties_tl { \l_@@_tmpa_str>~ }
+ },
+ actualtext-o .code:n = % ActualText property
+ {
+ \str_set_convert:Noon
+ \l_@@_tmpa_str
+ { #1 }
+ { default }
+ { utf16/hex }
+ \tl_put_right:Nn \l_@@_mc_key_properties_tl { /ActualText~< }
+ \tl_put_right:No \l_@@_mc_key_properties_tl { \l_@@_tmpa_str>~ }
+ },
+ label .tl_set:N = \l_@@_mc_key_label_tl,
+ artifact .code:n =
+ {
+ \exp_args:Nnx
+ \keys_set:nn
+ { @@ / mc }
+ { artifact-bool, artifact-type=#1 }
+ },
+ artifact .default:n = {notype}
+ }
+
+\cs_new:Nn \@@_mc_handle_artifact:N %#1 contains the artifact type
+ {
+ \tl_if_empty:NTF #1
+ { \@@_mc_bmc_artifact: }
+ { \exp_args:No\@@_mc_bmc_artifact:n {#1} }
+ }
+
+\cs_new:Nn \@@_mc_handle_mcid:nn %#1 tag, #2 properties
+ {
+ \@@_mc_bdc_mcid:nn {#1} {#2}
+ }
+
+\cs_generate_variant:Nn \@@_mc_handle_mcid:nn {VV}
+
+% puts the absolute number of an mcid in the current structure
+\cs_new:Nn \@@_mc_handle_stash:n %1 mcidnum
+ {
+ \@@_check_mc_used:n {#1}
+ \@@_struct_kid_mc_gput_right:nn
+ { \g_@@_struct_stack_current_tl }
+ {#1}
+ \prop_gput:Nxx \g_@@_mc_parenttree_prop
+ {#1}
+ { \g_@@_struct_stack_current_tl }
+ }
+
+\cs_new_protected:Nn \tag_mc_begin:n
+ {
+ \group_begin: %hm
+ \@@_check_mc_if_nested:
+ \bool_gset_true:N \g_@@_in_mc_bool
+ \keys_set:nn { @@ / mc } {#1}
+ \bool_if:NTF \l_@@_mc_artifact_bool
+ { %handle artifact
+ \@@_mc_handle_artifact:N \l_@@_mc_artifact_type_tl
+ }
+ { %handle mcid type
+ \@@_check_mc_tag:N \l_@@_mc_key_tag_tl
+ \@@_mc_handle_mcid:VV
+ \l_@@_mc_key_tag_tl
+ \l_@@_mc_key_properties_tl
+ \tl_if_empty:NF {\l_@@_mc_key_label_tl}
+ {
+ \@@_mc_handle_mc_label:n { \l_@@_mc_key_label_tl }
+ }
+ \bool_if:NF \l_@@_mc_key_stash_bool
+ {
+ \@@_mc_handle_stash:n { \int_use:N \c@g_@@_MCID_abs_int }
+ }
+ }
+ \group_end:
+ }
+
+%deprecated
+\cs_set_eq:NN \uftag_mc_begin:n \tag_mc_begin:n
+
+\cs_new_protected:Nn \tag_mc_end:
+ {
+ \@@_check_mc_if_open:
+ \bool_gset_false:N \g_@@_in_mc_bool
+ \tl_gset:Nn \g_@@_mc_key_tag_tl { }
+ \@@_mc_emc:
+ }
+
+\cs_set_eq:NN \uftag_mc_end: \tag_mc_end:
+
+\cs_new_protected:Nn \tag_mc_use:n %#1: label name
+ {
+ \tl_set:Nx \l_tmpa_tl { \@@_ref_value:enn{tagpdf-#1}{tagmcabs}{} }
+ \tl_if_empty:NTF\l_tmpa_tl
+ {
+ \msg_warning:nnn {tag} {mc-label-unknown} {#1}
+ }
+ {
+ \prop_gput:Nxx
+ \g_@@_mc_parenttree_prop
+ {
+ \@@_ref_value:enn {tagpdf-#1} {tagmcabs} {}
+ }
+ {
+ \g_@@_struct_stack_current_tl
+ }
+ \@@_struct_kid_mc_gput_right:nn
+ {
+ \g_@@_struct_stack_current_tl
+ }
+ {
+ \@@_ref_value:enn {tagpdf-#1} {tagmcabs} {}
+ }
+ }
+ }
+
+%deprecated
+\cs_set_eq:NN \uftag_mc_use:n \tag_mc_use:n
+
+\cs_new:Nn \@@_get_data_mc_tag: { \g_@@_mc_key_tag_tl }
+
+%</generic>
+% \end{macrocode}
+% \begin{macrocode}
+%<*luamode>
+\ProvidesExplPackage {tagpdf-mc-code-lua} {2021/02/23} {0.80}
+ {tagpdf - mc code only for the luamode }
+
+% the two attibutes are defined in the driver file.
+% it also load the lua (as it can also contain functions needed by generic mode.
+% (new) attributes for mc are local:
+% \newattribute \l_@@_mc_type_attr %the value represent the type
+% \newattribute \l_@@_mc_cnt_attr %will hold the \c@g_@@_MCID_abs_int value
+
+
+% An attribute for the current structure probably doesn't make sense as mc chunks can be used later.
+% \newattribute \g_@@_struct_type_attr %represent the current structure type. Not sure if needed
+% \newattribute \g_@@_struct_cnt_attr %will hold \c@g_@@_struct_abs_int a cnt
+
+% handling attribute needs a different system to number the page wise mcid's:
+% a tagmcbegin ... tagmcend pair no longer surrounds exactly one mc chunk: it can be split
+% at page breaks. We know the included mcid(s) only after the ship out. So for the struct-> mcid mapping we
+% need to record struct -> mc-cnt (in \g_@@_mc_parenttree_prop and/or a lua table
+% and at shipout mc-cnt-> {mcid, mcid, ...} (in a table?)
+% and when building the trees connect both
+
+% key definitions are overwritten for luatex to store that data in tables
+% the data for the mc are in ltx.@@.mc[absnum]
+% the fields of the table are
+% tag : the type (a string)
+% raw : more properties (string)
+% label: a string. Do we need a way to retrieve the num from the label from lua??
+% artifact: the presence indicates an artifact, the value (string) is the type.
+% kids: a array of tables {1={kid=num2,page=pagenum1}, 2={kid=num2,page=pagenum2},...},
+% this describes the chunks the mc has been split to by the traversing code
+% parent: the number of the structure it is in. Needed to build the parent tree.
+
+% The main function which wanders through the shipout box to inject the literals.
+% if the new callback is there, it is used.
+\hook_gput_code:nnn{begindocument}{tagpdf/mc}
+ {
+ \bool_if:NT\g__tag_active_mc_bool
+ {
+ \directlua
+ {
+ if~luatexbase.callbacktypes.pre_shipout_filter~then~
+ luatexbase.add_to_callback("pre_shipout_filter", function(TAGBOX)~
+ ltx.__tag.func.mark_shipout(TAGBOX)~return~true~
+ end, "tagpdf")~
+ end
+ }
+ \directlua
+ {
+ if~luatexbase.callbacktypes.pre_shipout_filter~then~
+ token.get_next()~
+ end
+ }\@secondoftwo\@gobble
+ {
+ \hook_gput_code:nnn{shipout/before}{tagpdf/lua}
+ {
+ \directlua
+ { ltx.__tag.func.mark_shipout (tex.box["ShipoutBox"]) }
+ }
+ }
+ }
+ }
+
+\prg_new_conditional:Nnn \@@_mc_if_in: {p,T,F,TF}
+ {
+ \int_compare:nNnTF { -2147483647 }={ \l_@@_mc_type_attr }
+ { \prg_return_false: }
+ { \prg_return_true: }
+ }
+
+\prg_new_eq_conditional:NNn \tag_mc_if_in: \@@_mc_if_in: {p,T,F,TF}
+
+%deprecated
+\prg_new_eq_conditional:NNn \uftag_mc_if_in: \@@_mc_if_in: {p,T,F,TF}
+
+% the keys
+\tl_new:N \l_@@_mc_key_tag_tl
+\tl_new:N \l_@@_mc_key_label_tl
+\tl_new:N \l_@@_mc_key_properties_tl
+
+\keys_define:nn { @@ / mc }
+ {
+ tag .code:n = %
+ {%%????????? \pdfescapename??
+ \tl_set:Nx \l_@@_mc_key_tag_tl { #1 }
+ \directlua
+ {
+ ltx.@@.func.store_mc_data(\@@_get_mc_abs_cnt:,"tag","#1")
+ }
+ },
+ raw .code:n =
+ {
+ \tl_put_right:Nx \l_@@_mc_key_properties_tl { #1 }
+ \directlua
+ {
+ ltx.@@.func.store_mc_data(\@@_get_mc_abs_cnt:,"raw","#1")
+ }
+ },
+ alttext .code:n = % Alt property
+ {
+ \str_set_convert:Nnon
+ \l_@@_tmpa_str
+ { #1 }
+ { default }
+ { utf16/hex }
+ \tl_put_right:Nn \l_@@_mc_key_properties_tl { /Alt~< }
+ \tl_put_right:No \l_@@_mc_key_properties_tl { \l_@@_tmpa_str>~ }
+ \directlua
+ {
+ ltx.@@.func.store_mc_data
+ (
+ \@@_get_mc_abs_cnt:,"alt","/Alt~<\str_use:N \l_@@_tmpa_str>"
+ )
+ }
+ },
+ alttext-o .code:n = % Alt property
+ {
+ \str_set_convert:Noon
+ \l_@@_tmpa_str
+ { #1 }
+ { default }
+ { utf16/hex }
+ \tl_put_right:Nn \l_@@_mc_key_properties_tl { /Alt~< }
+ \tl_put_right:No \l_@@_mc_key_properties_tl { \l_@@_tmpa_str>~ }
+ \directlua
+ {
+ ltx.@@.func.store_mc_data
+ (
+ \@@_get_mc_abs_cnt:,"alt","/Alt~<\str_use:N \l_@@_tmpa_str>"
+ )
+ }
+ },
+ actualtext .code:n = % Alt property
+ {
+ \str_set_convert:Nnon
+ \l_@@_tmpa_str
+ { #1 }
+ { default }
+ { utf16/hex }
+ \tl_put_right:Nn \l_@@_mc_key_properties_tl { /Alt~< }
+ \tl_put_right:No \l_@@_mc_key_properties_tl { \l_@@_tmpa_str>~ }
+ \directlua
+ {
+ ltx.@@.func.store_mc_data
+ (
+ \@@_get_mc_abs_cnt:,"actualtext","/ActualText~<\str_use:N \l_@@_tmpa_str>"
+ )
+ }
+ },
+ actualtext-o .code:n = % Alt property
+ {
+ \str_set_convert:Noon
+ \l_@@_tmpa_str
+ { #1 }
+ { default }
+ { utf16/hex }
+ \tl_put_right:Nn \l_@@_mc_key_properties_tl { /Alt~< }
+ \tl_put_right:No \l_@@_mc_key_properties_tl { \l_@@_tmpa_str>~ }
+ \directlua
+ {
+ ltx.@@.func.store_mc_data
+ (
+ \@@_get_mc_abs_cnt:,
+ "actualtext",
+ "/ActualText~<\str_use:N \l_@@_tmpa_str>"
+ )
+ }
+ },
+ label .code:n =
+ {
+ \tl_set:Nn\l_@@_mc_key_label_tl { #1 }
+ \directlua
+ {
+ ltx.@@.func.store_mc_data
+ (
+ \@@_get_mc_abs_cnt:,"label","#1"
+ )
+ }
+ },
+ __artifact-store .code:n =
+ {
+ \directlua
+ {
+ ltx.@@.func.store_mc_data
+ (
+ \@@_get_mc_abs_cnt:,"artifact","#1"
+ )
+ }
+ },
+ artifact .code:n =
+ {
+ \exp_args:Nnx
+ \keys_set:nn
+ { @@ / mc}
+ { artifact-bool, artifact-type=#1, tag=Artifact }
+ \exp_args:Nnx
+ \keys_set:nn
+ { @@ / mc }
+ { __artifact-store=\l_@@_mc_artifact_type_tl }
+ },
+ artifact .default:n = { notype }
+ }
+
+
+% attributes
+% set the mc from a tag name
+
+\cs_set_protected:Npn \@@_attribute_gset:Nn #1 #2
+ {
+ \tex_global:D \setattribute #1 #2
+ }
+
+\cs_set_protected:Npn \@@_attribute_set:Nn #1 #2
+ {
+ \setattribute #1 #2
+ }
+
+\cs_set_protected:Npn \@@_attribute_gunset:N #1
+ {
+ \tex_global:D \unsetattribute #1
+ }
+
+\cs_set_protected:Npn \@@_attribute_unset:N #1
+ {
+ \unsetattribute #1
+ }
+
+
+\cs_new:Nn \@@_mc_lua_set_mc_type_attr:n % #1 is a tag name
+ {
+ \@@_attribute_set:Nn \l_@@_mc_type_attr
+ {
+ \directlua { ltx.@@.func.output_num_from ("#1") }
+ }
+ \@@_attribute_set:Nn \l_@@_mc_cnt_attr { \@@_get_mc_abs_cnt: }
+ }
+
+\cs_generate_variant:Nn\@@_mc_lua_set_mc_type_attr:n { o }
+
+\cs_new:Nn \@@_mc_lua_unset_mc_type_attr:
+ {
+ \@@_attribute_unset:N \l_@@_mc_type_attr
+ \@@_attribute_unset:N \l_@@_mc_cnt_attr
+ }
+
+
+
+%This command will in the finish code replace the dummy for a mc by the real mcid kids
+%we need a variant for the case that it is the only kid, to get the array right
+\cs_new:Nn \@@_mc_insert_mcid_kids:n
+ {
+ \directlua { ltx.@@.func.mc_insert_kids (#1,0) }
+ }
+
+\cs_new:Nn \@@_mc_insert_mcid_single_kids:n
+ {
+ \directlua {ltx.@@.func.mc_insert_kids (#1,1) }
+ }
+
+
+% we need to pass the info if the kids are alone or already in an array
+% so we add a second argument, which should == 1 if the kids are single
+
+
+% puts an mcid absolute number in the current structure
+\cs_new:Nn \@@_mc_handle_stash:n %1 mcidnum
+ {
+ \@@_check_mc_used:n { #1 }
+ \seq_gput_right:cn % Don't fill a lua table due to the command in the item,
+ % so use the kernel command
+ { g_@@_struct_kids_\g_@@_struct_stack_current_tl _seq }
+ {
+ \@@_mc_insert_mcid_kids:n {#1}%
+ }
+ \directlua
+ {
+ ltx.@@.func.store_struct_mcabs
+ (
+ \g_@@_struct_stack_current_tl,#1
+ )
+ }
+ \prop_gput:Nxx
+ \g_@@_mc_parenttree_prop
+ { #1 }
+ { \g_@@_struct_stack_current_tl }
+ }
+
+\cs_generate_variant:Nn \@@_mc_handle_stash:n { o }
+
+\cs_new_protected:Nn \tag_mc_begin:n
+ {
+ %\group_begin:
+ %\@@_check_mc_if_nested:
+ %\bool_gset_true:N \g_@@_in_mc_bool
+ \bool_set_false:N\l_@@_mc_artifact_bool
+ \int_gincr:N \c@g_@@_MCID_abs_int
+ \tl_clear:N \l_@@_mc_key_properties_tl
+ \keys_set:nn { @@ / mc }{ label={}, #1 }
+ %check that a tag or artifact has been used
+ \@@_check_mc_tag:N \l_@@_mc_key_tag_tl
+ %set the attributes:
+ \@@_mc_lua_set_mc_type_attr:o { \l_@@_mc_key_tag_tl }
+ \bool_if:NF \l_@@_mc_artifact_bool
+ { % store the absolute num name in a label:
+ \tl_if_empty:NF {\l_@@_mc_key_label_tl}
+ {
+ \@@_mc_handle_mc_label:n { \l_@@_mc_key_label_tl }
+ }
+ % if not stashed record the absolute number
+ \bool_if:NF \l_@@_mc_key_stash_bool
+ {
+ \exp_args:Nx \@@_mc_handle_stash:n { \@@_get_mc_abs_cnt: }
+ }
+ }
+ %\bool_set_false:N\l_@@_mc_artifact_bool
+ %\group_end:
+ }
+
+%deprecated
+\cs_set_eq:NN \uftag_mc_begin:n \tag_mc_begin:n
+
+\cs_new_protected:Nn \tag_mc_end:
+ {
+ %\@@_check_mc_if_open:
+ %\bool_gset_false:N \g_@@_in_mc_bool
+ \bool_set_false:N\l_@@_mc_artifact_bool
+ \@@_mc_lua_unset_mc_type_attr:
+ \tl_set:Nn \l_@@_mc_key_tag_tl { }
+ }
+
+\cs_set_eq:NN \uftag_mc_end: \tag_mc_end:
+
+\cs_new_protected:Nn \tag_mc_use:n %#1: label name
+ {
+ \tl_set:Nx \l_tmpa_tl { \@@_ref_value:enn{tagpdf-#1}{tagmcabs}{} }
+ \tl_if_empty:NTF\l_tmpa_tl
+ {
+ \msg_warning:nnn {tag} {mc-label-unknown} { #1 }
+ }
+ {
+ \@@_mc_handle_stash:o { \l_tmpa_tl }
+ }
+ }
+
+\cs_set_eq:NN \uftag_mc_use:n \tag_mc_use:n
+
+\cs_new:Nn \@@_get_data_mc_tag: { \l_@@_mc_key_tag_tl }
+%</luamode>
+% \end{macrocode}
diff --git a/Master/texmf-dist/source/latex/tagpdf/tagpdf-roles.dtx b/Master/texmf-dist/source/latex/tagpdf/tagpdf-roles.dtx
new file mode 100644
index 00000000000..920c6345ca8
--- /dev/null
+++ b/Master/texmf-dist/source/latex/tagpdf/tagpdf-roles.dtx
@@ -0,0 +1,156 @@
+% \iffalse meta-comment
+%
+%% File: tagpdf-roles.dtx
+%
+% Copyright (C) 2019 Ulrike Fischer
+%
+% 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 "tagpdf 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/u-fischer/tagpdf
+%
+% for those people who are interested.
+%
+% \fi
+%
+% \begin{macrocode}
+%<@@=tag>
+%<*roles>
+\ProvidesExplPackage {tagpdf-roles-code} {2021/02/23} {0.80}
+ {part of tagpdf - code related to roles and structure names}
+
+\@@_seq_new:N \g_@@_role_tags_seq %to get names from numbers
+\@@_prop_new:N \g_@@_role_tags_prop %to get numbers from names
+
+%The list of standard adobe tags.
+\clist_const:Nn \c_@@_role_sttags_clist
+ {%possible root elements
+ Document, %A complete document. This is the root element of any structure tree containing
+ %multiple parts or multiple articles.
+ Part, %A large-scale division of a document.
+ Art, %A relatively self-contained body of text constituting a single narrative or exposition
+ %subelements
+ Sect, %A container for grouping related content elements.
+ Div, %A generic block-level element or group of elements
+ BlockQuote, %A portion of text consisting of one or more paragraphs attributed to someone other
+ %than the author of the surrounding text.
+ Caption, %A brief portion of text describing a table or figure.
+ TOC, %A list made up of table of contents item entries (structure tag TOCI; see below)
+ %and/or other nested table of contents entries
+ TOCI, %An individual member of a table of contents. This entry's children can be any of
+ %the following structure tags:
+ %Lbl,Reference,NonStruct,P,TOC
+ Index,
+ NonStruct, %probably not needed
+ H,
+ H1,
+ H2,
+ H3,
+ H4,
+ H5,
+ H6,
+ P,
+ L, %list
+ LI, %list item (around label and list item body)
+ Lbl, %list label
+ LBody, %list item body
+ Table,
+ TR, %table row
+ TH, %table header cell
+ TD, %table data cell
+ THead, %table header (n rows)
+ TBody, %table rows
+ TFoot, %table footer
+ Span, %generic inline marker
+ Quote, %inline quote
+ Note, % footnote, endnote. Lbl can be child
+ Reference, % A citation to content elsewhere in the document.
+ BibEntry, %bibentry
+ Code, %
+ Link, %
+ Annot,
+ Figure,
+ Formula,
+ Form,
+ Artifact
+ }
+
+% get tag name from number: \seq_item:Nn \g_@@_role_tags_seq { n }
+%\seq_gset_from_clist:NN \g_@@_role_tags_seq \c_@@_role_tags_clist
+
+\clist_map_inline:Nn \c_@@_role_sttags_clist
+ {
+ \@@_seq_gput_right:Nn \g_@@_role_tags_seq { #1 }
+ }
+
+
+% get tag number from name: \prop_item:Nn \g_@@_role_tags_prop { name }
+\int_step_inline:nnnn { 1 }{ 1 }{ \seq_count:N \g_@@_role_tags_seq }
+ {
+ \@@_prop_gput:Nxn \g_@@_role_tags_prop
+ {
+ \seq_item:Nn \g_@@_role_tags_seq { #1 }
+ }
+ { #1 }
+ }
+
+\cs_new:Nn \@@_role_get_tag_from_index:nn
+ {
+ \@@_seq_item:cn { #1_seq } { #2 }
+ }
+
+\cs_new:Nn \@@_role_get_index_from_tag:nn
+ {
+ \@@_prop_item:cn { #1_prop } { #2 }
+ }
+
+% new tags and the rolemap
+
+\@@_prop_new:N \g_@@_role_rolemap_prop
+
+\cs_new_protected:Nn \@@_role_add_tag:nn %new name, reference to old
+ {
+ \@@_seq_gput_right:Nn \g_@@_role_tags_seq { #1 }
+ \@@_prop_gput:Nnx \g_@@_role_tags_prop { #1 }
+ {
+ \seq_count:N \g_@@_role_tags_seq
+ }
+ \@@_check_add_tag_role:nn {#1}{#2}
+ \tl_if_empty:nF { #2 }
+ {
+ \@@_prop_gput:Nnn \g_@@_role_rolemap_prop
+ { #1 } { #2 }
+ }
+ }
+
+\cs_generate_variant:Nn \@@_role_add_tag:nn {xx}
+
+\keys_define:nn { @@ / setup }
+ {
+ add-new-tag .code:n =
+ {
+ \seq_set_split:Nnn \l_tmpa_seq { / } {#1/}
+ \@@_role_add_tag:xx
+ {
+ \seq_item:Nn \l_tmpa_seq {1}
+ }
+ {
+ \seq_item:Nn \l_tmpa_seq {2}
+ }
+ }
+ }
+
+
+%</roles>
+% \end{macrocode}
diff --git a/Master/texmf-dist/source/latex/tagpdf/tagpdf-space.dtx b/Master/texmf-dist/source/latex/tagpdf/tagpdf-space.dtx
new file mode 100644
index 00000000000..edc5e445c70
--- /dev/null
+++ b/Master/texmf-dist/source/latex/tagpdf/tagpdf-space.dtx
@@ -0,0 +1,89 @@
+% \iffalse meta-comment
+%
+%% File: tagpdf-space.dtx
+%
+% Copyright (C) 2019 Ulrike Fischer
+%
+% 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 "tagpdf 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/u-fischer/tagpdf
+%
+% for those people who are interested.
+%
+% \fi
+%
+% \begin{macrocode}
+%<@@=tag>
+%<*space>
+\ProvidesExplPackage {tagpdf-space-code} {2021/02/23} {0.80}
+ {part of tagpdf - code related to real space chars}
+% luatex uses an attribute (declared in the driver file) and some luacode in tagpdf.lua
+% perhaps I will split the code by engine in the future
+
+\sys_if_engine_pdftex:T
+ {
+ \pdfglyphtounicode{space}{0020}
+ \keys_define:nn { @@ / setup }
+ {
+ interwordspace .choices:nn = { true, on } { \pdfinterwordspaceon },
+ interwordspace .choices:nn = { false, off }{ \pdfinterwordspaceon },
+ show-spaces .bool_set:N = \l_@@_showspaces_bool
+ }
+ }
+
+
+\sys_if_engine_luatex:T
+ {
+ \keys_define:nn { @@ / setup }
+ {
+ interwordspace .choices:nn =
+ { true, on }
+ { \directlua{ltx.@@.func.markspaceon()} },
+ interwordspace .choices:nn =
+ { false, off }
+ {\directlua{ltx.@@.func.markspaceoff()} },
+ show-spaces .choice:,
+ show-spaces / true .code:n =
+ {\directlua{ltx.@@.trace.showspaces=true}},
+ show-spaces / false .code:n =
+ {\directlua{ltx.@@.trace.showspaces=nil}},
+ show-spaces .default:n = true
+ }
+
+ \cs_new_protected:Nn \@@_fakespace:
+ {
+ \group_begin:
+ \setattribute\g_@@_interwordspace_attr{1}
+ \setattribute\g_@@_interwordfont_attr
+ {
+ \directlua{tex.print(\the\catcodetable@latex, font.current())}
+ }
+ \skip_horizontal:n{\c_zero_skip}
+ \group_end:
+ }
+ }
+
+\sys_if_engine_xetex:T
+ {
+ \keys_define:nn { @@ / setup }
+ {
+ interwordspace .choices:nn = { true, on } { \msg_warning:nnn {tag}{sys-no-interwordspace}{xetex} },
+ interwordspace .choices:nn = { false, off }{ \msg_warning:nnn {tag}{sys-no-interwordspace}{xetex} },
+ show-spaces .bool_set:N = \l_@@_showspaces_bool
+ }
+ }
+
+%</space>
+% \end{macrocode}
diff --git a/Master/texmf-dist/source/latex/tagpdf/tagpdf-struct.dtx b/Master/texmf-dist/source/latex/tagpdf/tagpdf-struct.dtx
new file mode 100644
index 00000000000..09ea3511882
--- /dev/null
+++ b/Master/texmf-dist/source/latex/tagpdf/tagpdf-struct.dtx
@@ -0,0 +1,789 @@
+% \iffalse meta-comment
+%
+%% File: tagpdf-struct.dtx
+%
+% Copyright (C) 2019-2020 Ulrike Fischer
+%
+% 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 "tagpdf 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/u-fischer/tagpdf
+%
+% for those people who are interested.
+%
+% \fi
+%
+% \begin{macrocode}
+%<@@=tag>
+%<*struct>
+\ProvidesExplPackage {tagpdf-struct-code} {2021/02/23} {0.80}
+ {part of tagpdf - code related to storing structure}
+
+% I will use a latex counter for the structure count
+% to have a chance to avoid double structures in align etc
+
+\newcounter { g_@@_struct_abs_int }
+\int_gzero:N \c@g_@@_struct_abs_int
+
+% ref code is in tagpdf.dtx
+
+% a sequence stores structnum -> the obj numbers
+% to allow easy mapping over the structures
+
+\@@_seq_new:N \g_@@_struct_objR_seq
+
+% a sequence for the structure stack. When a sequence is opened it's number is put on the stack.
+\seq_new:N \g_@@_struct_stack_seq
+\seq_gpush:Nn \g_@@_struct_stack_seq {0}
+
+%this variables will hold the top entry and the parent on the stack
+\tl_new:N \l_@@_struct_stack_parent_tmp_tl
+\tl_new:N \g_@@_struct_stack_current_tl
+
+% I need at least one structure: the StructTreeRoot
+% normally it should have only one kid, e.g. the document element.
+
+% The data of the StructTreeRoot and the StructElem are in properties:
+% \g_@@_struct_0_prop for the root
+% \g_@@_struct_N_prop, N >=1
+% they have all the keys
+% objnum - number,
+% Type - StructTreeRoot or StructElem
+% num - number (identical to the num in the name, or 0 for the root)
+% and the keys from the two following lists
+% (the root has a special set of properties).
+% the values of the prop should be already escaped properly
+% when the entries are created (title,lange,alt,E,actualtext)
+
+
+\seq_const_from_clist:Nn \c_@@_struct_StructTreeRoot_entries_seq
+ {%p. 857/858
+ Type, % always /StructTreeRoot
+ K, % kid, dictionary or array of dictionaries
+ IDTree, % currently unused
+ ParentTree, % required,obj ref to the parent tree
+ ParentTreeNextKey, %optional
+ RoleMap,
+ ClassMap
+ }
+
+\seq_const_from_clist:Nn \c_@@_struct_StructElem_entries_seq
+ {%p 858 f
+ Type, %always /StructElem
+ S, %tag/type
+ P, %parent
+ ID, %optional
+ Ref, %optional, pdf 2.0 Use?
+ Pg, %obj num of starting page, optional
+ K, %kids
+ A, %attributes, probably unused
+ C, %class ""
+ %R,
+ T, %title, value in () or <>
+ Lang, %language
+ Alt, % value in () or <>
+ E, %abreviation
+ ActualText,
+ AF, %pdf 2.0, array of dict, associated files
+ NS, %pdf 2.0, dict, namespace
+ PhoneticAlphabet, %pdf 2.0
+ Phoneme %pdf 2.0
+ }
+
+% I need an output handler for each prop, to get expandable output
+% see https://tex.stackexchange.com/questions/424208/expandable-version-of-a-expl3-command/424213#424213
+
+\cs_new:Nn \@@_struct_output_prop_aux:nn %#1 num, #2 key
+ {
+ \prop_if_in:cnT
+ { g_@@_struct_#1_prop }
+ { #2 }
+ {
+ \c_space_tl/#2~ \prop_item:cn{ g_@@_struct_#1_prop } { #2 }
+ }
+ }
+
+\cs_new:Nn \@@_new_output_prop_handler:n
+ {
+ \cs_new:cn { @@_struct_output_prop_#1:n }
+ {
+ \@@_struct_output_prop_aux:nn {#1}{##1}
+ }
+ }
+
+
+% the first one, the StructTreeRoot is special, so
+% created manually:
+\@@_prop_new:c { g_@@_struct_0_prop }
+\@@_new_output_prop_handler:n {0}
+\tl_gset:Nn \g_@@_struct_stack_current_tl {0}
+
+\@@_seq_new:c { g_@@_struct_kids_0_seq }
+
+% deprecated
+%\@@_prop_gput:cno
+% { g_@@_struct_0_prop }
+% { objnum}
+% { \c_@@_tree_obj_structtreeroot_tl }
+
+% new
+\@@_prop_gput:cno
+ { g_@@_struct_0_prop }
+ { objref}
+ { \pdf_object_ref:n { c_@@_struct_0_obj } }
+
+\@@_prop_gput:cno
+ { g_@@_struct_0_prop }
+ { Type }
+ { /StructTreeRoot }
+
+% the constants are defined in the tree code.
+\@@_prop_gput:cnx
+ { g_@@_struct_0_prop }
+ { ParentTree }
+ { \pdf_object_ref:n { c_@@_tree_parenttree_obj } }
+
+\@@_prop_gput:cnx
+ { g_@@_struct_0_prop }
+ { RoleMap }
+ { \pdf_object_ref:n { c_@@_tree_rolemap_obj } }
+
+\@@_prop_gput:cno
+ { g_@@_struct_0_prop }
+ { entries }
+ { StructTreeRoot }
+
+\@@_prop_gput:cno
+ { g_@@_struct_0_prop }
+ { num }
+ { 0 }
+
+% commands to store the kids
+% I don't compare the page objects number yet, but always add the /Pg key, perhaps later
+
+\cs_new:Nn \@@_struct_kid_mc_gput_right:nn %#1 structure num, #2 MCID absnum%
+ {
+ %\@@_store_pdfpageref:Nn \l_tmpa_tl { \@@_ref_value:enn{mcid-#2}{tagabspage}{1} }
+ \@@_seq_gput_right:cx
+ { g_@@_struct_kids_#1_seq }
+ {
+ <<
+ /Type \c_space_tl /MCR \c_space_tl
+ /Pg %\c_space_tl \l_tmpa_tl \c_space_tl 0 \c_space_tl R \c_space_tl
+ \c_space_tl
+ \pdf_pageobject_ref:n { \@@_ref_value:enn{mcid-#2}{tagabspage}{1} }
+ /MCID \c_space_tl \@@_ref_value:enn{mcid-#2}{tagmcid}{1}
+ >>
+ }
+ }
+
+\cs_new:Nn\@@_struct_kid_struct_gput_right:nn %#1 num of parent struct, #2 kid struct
+ {
+ \@@_seq_gput_right:cx
+ { g_@@_struct_kids_#1_seq }
+ {
+ \prop_item:cn
+ { g_@@_struct_#2_prop }
+ { objref }
+ }
+ }
+
+\cs_new:Nn\@@_struct_kid_link_gput_right:nn %#1 num of parent struct, #2 obj reference
+ {
+ \pdf_object_unnamed_write:nx
+ { dict }
+ {
+ /Type \c_space_tl /OBJR \c_space_tl
+ /Obj~#2
+ }
+ \@@_seq_gput_right:cx
+ { g_@@_struct_kids_#1_seq }
+ {
+ \pdf_object_ref_last:
+ }
+ }
+
+\cs_generate_variant:Nn\@@_struct_kid_link_gput_right:nn { nx }
+
+\cs_new:Nn\@@_struct_exchange_kid_command:N %N= seq
+ {
+ \seq_gpop_left:NN #1 \l_tmpa_tl
+ \regex_replace_once:nnN
+ { \c{\@@_mc_insert_mcid_kids:n} }
+ { \c{\@@_mc_insert_mcid_single_kids:n} }
+ \l_tmpa_tl
+ \seq_gput_left:NV #1 \l_tmpa_tl
+ }
+
+\cs_generate_variant:Nn\@@_struct_exchange_kid_command:N { c }
+
+\cs_new:Nn \@@_struct_fill_kid_key:n %#1 is the struct num
+ {
+ \int_case:nnF
+ {
+ \seq_count:c
+ {
+ g_@@_struct_kids_\prop_item:cn{ g_@@_struct_#1_prop }{num}_seq
+ }
+ }
+ {
+ { 0 }
+ { } %no kids, do nothing
+ { 1 } % 1 kid, insert
+ {
+ % in this case we need a special command in
+ %luamode to get the array right. See issue #13
+ \bool_if:NT\g_@@_mode_lua_bool
+ {
+ \@@_struct_exchange_kid_command:c
+ {g_@@_struct_kids_\prop_item:cn{ g_@@_struct_#1_prop }{num}_seq}
+ }
+ \@@_prop_gput:cnx { g_@@_struct_#1_prop } {K}
+ {
+ \seq_item:cn
+ {
+ g_@@_struct_kids_\prop_item:cn{ g_@@_struct_#1_prop }{num}_seq
+ }
+ {1}
+ }
+ } %
+ }
+ { %many kids, use an array
+ \@@_prop_gput:cnx { g_@@_struct_#1_prop } {K}
+ {
+ [
+ \seq_use:cn
+ {
+ g_@@_struct_kids_\prop_item:cn{ g_@@_struct_#1_prop }{num}_seq
+ }
+ {
+ \c_space_tl
+ }
+ ]
+ }
+ }
+ }
+
+% this command can be used for roots and structure elements
+% #1 is a num
+
+\tl_new:N \l_@@_struct_dict_content_tl
+
+\cs_new:Nn \@@_struct_get_dict_content:n
+ {
+ %\tl_set:Nn \l_@@_struct_dict_content_tl {<<}
+ \tl_clear:N \l_@@_struct_dict_content_tl
+ \seq_map_inline:cn
+ {
+ c_@@_struct_\prop_item:cn{ g_@@_struct_#1_prop }{entries}_entries_seq
+ }
+ {
+ \tl_put_right:Nx
+ \l_@@_struct_dict_content_tl
+ {
+ \prop_if_in:cnT
+ { g_@@_struct_#1_prop }
+ { ##1 }
+ {
+ \c_space_tl/##1~\prop_item:cn{ g_@@_struct_#1_prop } { ##1 }
+ }
+ }
+ }
+ %\tl_put_right:Nn \l_@@_struct_dict_content_tl { >> }
+ }
+
+
+% #1 is the struct num
+\cs_new:Nn \@@_struct_write_obj:n
+ {
+ \prop_if_in:cnTF
+ { g_@@_struct_#1_prop }
+ { objref }
+ {
+ \@@_struct_fill_kid_key:n { #1 }
+ %\prop_show:c { g_@@_struct_#1_prop }
+ \@@_struct_get_dict_content:n { #1 }
+ \exp_args:Nx
+ \pdf_object_write:nx
+ { c_@@_struct_#1_obj }
+ {
+ \l_@@_struct_dict_content_tl
+ }
+ }
+ {
+ \msg_error:nnn { tag } { struct-no-objnum } { #1}
+ }
+ }
+
+% keys for the user commands
+% should I pass the values (e.g. the tag) through an escape command?
+\keys_define:nn { @@ / struct }
+ {
+ label .tl_set:N = \l_@@_struct_key_label_tl,
+ stash .bool_set:N = \l_@@_struct_elem_stash_bool,
+ tag .code:n = % S property
+ {%%????????? \pdfescapename??
+ \tl_set:Nx \l_@@_tmpa_tl { #1 }
+ \bool_if:NT \g_@@_check_tags_bool
+ {
+ \@@_check_structure_tag:N \l_@@_tmpa_tl
+ }
+ \@@_prop_gput:cnx
+ { g_@@_struct_\int_eval:n {\c@g_@@_struct_abs_int}_prop }
+ { S }
+ { /\exp_not:V\l_@@_tmpa_tl }
+ },
+ title .code:n = % T property
+ {
+ \str_set_convert:Nnon
+ \l_@@_tmpa_str
+ { #1 }
+ { default }
+ { utf16/hex }
+ \@@_prop_gput:cnx
+ { g_@@_struct_\int_eval:n {\c@g_@@_struct_abs_int}_prop }
+ { T }
+ { <\l_@@_tmpa_str> }
+ },
+ title-o .code:n = % T property
+ {
+ \str_set_convert:Nnon
+ \l_@@_tmpa_str
+ { #1 }
+ { default }
+ { utf16/hex }
+ \@@_prop_gput:cnx
+ { g_@@_struct_\int_eval:n {\c@g_@@_struct_abs_int}_prop }
+ { T }
+ { <\l_@@_tmpa_str> }
+ },
+ alttext .code:n = % Alt property
+ {
+ \str_set_convert:Nnon
+ \l_@@_tmpa_str
+ { #1 }
+ { default }
+ { utf16/hex }
+ \@@_prop_gput:cnx
+ { g_@@_struct_\int_eval:n {\c@g_@@_struct_abs_int}_prop }
+ { Alt }
+ { <\l_@@_tmpa_str> }
+ },
+ alttext-o .code:n = % Alt property
+ {
+ \str_set_convert:Noon
+ \l_@@_tmpa_str
+ { #1 }
+ { default }
+ { utf16/hex }
+ \@@_prop_gput:cnx
+ { g_@@_struct_\int_eval:n {\c@g_@@_struct_abs_int}_prop }
+ { Alt }
+ { <\l_@@_tmpa_str> }
+ },
+ actualtext .code:n = % ActualText property
+ {
+ \str_set_convert:Nnon
+ \l_@@_tmpa_str
+ { #1 }
+ { default }
+ { utf16/hex }
+ \@@_prop_gput:cnx
+ { g_@@_struct_\int_eval:n {\c@g_@@_struct_abs_int}_prop }
+ { ActualText }
+ { <\l_@@_tmpa_str>}
+ },
+ actualtext-o .code:n = % ActualText property
+ {
+ \str_set_convert:Noon
+ \l_@@_tmpa_str
+ { #1 }
+ { default }
+ { utf16/hex }
+ \@@_prop_gput:cnx
+ { g_@@_struct_\int_eval:n {\c@g_@@_struct_abs_int}_prop }
+ { ActualText }
+ { <\l_@@_tmpa_str>}
+ },
+ lang .code:n = % Lang property
+ {
+ \@@_prop_gput:cnx
+ { g_@@_struct_\int_eval:n {\c@g_@@_struct_abs_int}_prop }
+ { Lang }
+ { (#1) }
+ },
+ ref .code:n = % Lang property
+ {
+ \tl_clear:N\l_@@_tmpa_tl
+ \clist_map_inline:nn {#1}
+ {
+ \tl_put_right:Nx \l_@@_tmpa_tl
+ {~\ref_value:nn{tagpdfstruct-##1}{tagstructobj} }
+ }
+ \@@_prop_gput:cnx
+ { g_@@_struct_\int_eval:n {\c@g_@@_struct_abs_int}_prop }
+ { Ref }
+ { [\l_@@_tmpa_tl] }
+ },
+ E .code:n = % E property
+ {
+ \str_set_convert:Nnon
+ \l_@@_tmpa_str
+ { #1 }
+ { default }
+ { utf16/hex }
+ \@@_prop_gput:cnx
+ { g_@@_struct_\int_eval:n {\c@g_@@_struct_abs_int}_prop }
+ { E }
+ { <\l_@@_tmpa_str> }
+ },
+ }
+
+% keys for AF keys, they rely on l3pdffile!
+% The stream variants use txt as extension to get the mimetype.
+\keys_define:nn { @@ / struct }
+ {
+ AF .code:n = % T property
+ {
+ \pdf_object_if_exist:nTF {#1}
+ {
+ \@@_prop_gput:cnx
+ { g_@@_struct_\int_eval:n {\c@g_@@_struct_abs_int}_prop }
+ { AF }
+ { \pdf_object_ref:n {#1} }
+ }
+ {
+
+ }
+ },
+ ,AFinline .code:n =
+ {
+ \group_begin:
+ \exp_args:Ne
+ \pdf_object_if_exist:nF {@@/fileobj\int_use:N\c@g_@@_struct_abs_int}
+ {
+ \pdffile_embed_stream:nxx
+ {#1}
+ {tag-AFfile\int_use:N\c@g_@@_struct_abs_int.txt}
+ {@@/fileobj\int_use:N\c@g_@@_struct_abs_int}
+ }
+ \@@_prop_gput:cnx
+ { g_@@_struct_\int_use:N\c@g_@@_struct_abs_int _prop }
+ { AF }
+ { \pdf_object_ref:e {@@/fileobj\int_use:N\c@g_@@_struct_abs_int } }
+ \group_end:
+ }
+ ,AFinline-o .code:n =
+ {
+ \group_begin:
+ \exp_args:Ne
+ \pdf_object_if_exist:nF {@@/fileobj\int_use:N\c@g_@@_struct_abs_int}
+ {
+ \pdffile_embed_stream:oxx
+ {#1}
+ {tag-AFfile\int_use:N\c@g_@@_struct_abs_int.txt}
+ {@@/fileobj\int_use:N\c@g_@@_struct_abs_int}
+ }
+ \@@_prop_gput:cnx
+ { g_@@_struct_\int_use:N\c@g_@@_struct_abs_int _prop }
+ { AF }
+ { \pdf_object_ref:e {@@/fileobj\int_use:N\c@g_@@_struct_abs_int } }
+ \group_end:
+ }
+ }
+
+\cs_new_protected:Nn \tag_struct_begin:n
+ {
+ \group_begin:
+ \int_gincr:N \c@g_@@_struct_abs_int
+ \@@_prop_new:c { g_@@_struct_\int_eval:n { \c@g_@@_struct_abs_int }_prop }
+ \@@_new_output_prop_handler:n {\int_eval:n { \c@g_@@_struct_abs_int }}
+ \@@_seq_new:c { g_@@_struct_kids_\int_eval:n { \c@g_@@_struct_abs_int }_seq}
+ %\@@_pdfreserveobjnum:N \l_tmpa_tl
+ \exp_args:Ne
+ \pdf_object_new:nn
+ { c_@@_struct_\int_eval:n { \c@g_@@_struct_abs_int }_obj }
+ { dict }
+ \@@_prop_gput:cnx
+ { g_@@_struct_\int_eval:n { \c@g_@@_struct_abs_int }_prop }
+ { objref}
+ {
+ \exp_args:Ne
+ \pdf_object_ref:n
+ {c_@@_struct_\int_eval:n { \c@g_@@_struct_abs_int }_obj}
+ }
+% \prop_show:c { g_@@_struct_\int_eval:n { \c@g_@@_struct_abs_int }_prop }
+ \@@_prop_gput:cnx
+ { g_@@_struct_\int_eval:n { \c@g_@@_struct_abs_int }_prop }
+ { num}
+ { \int_eval:n { \c@g_@@_struct_abs_int } }
+ \@@_prop_gput:cno
+ { g_@@_struct_\int_eval:n { \c@g_@@_struct_abs_int }_prop }
+ { Type }
+ { /StructElem }
+ \@@_prop_gput:cno
+ { g_@@_struct_\int_eval:n { \c@g_@@_struct_abs_int }_prop }
+ { entries }
+ { StructElem }
+ \keys_set:nn { @@ / struct} { #1 }
+ \@@_check_structure_has_tag:n { \int_eval:n {\c@g_@@_struct_abs_int} }
+ \tl_if_empty:NF
+ \l_@@_struct_key_label_tl
+ {
+ \@@_ref_label:en{tagpdfstruct-\l_@@_struct_key_label_tl}{struct}
+ }
+ %get the potential parent from the stack:
+ \seq_get:NNF
+ \g_@@_struct_stack_seq
+ \l_@@_struct_stack_parent_tmp_tl
+ {
+ \msg_error:nn { tag } { struct-faulty-nesting }
+ }
+ \seq_gpush:NV \g_@@_struct_stack_seq \c@g_@@_struct_abs_int
+ \tl_gset:NV \g_@@_struct_stack_current_tl \c@g_@@_struct_abs_int
+ %\seq_show:N \g_@@_struct_stack_seq
+ \bool_if:NF
+ \l_@@_struct_elem_stash_bool
+ {%set the parent
+ \@@_prop_gput:cnx
+ { g_@@_struct_\int_eval:n {\c@g_@@_struct_abs_int}_prop }
+ { P }
+ {
+ \prop_item:cn
+ { g_@@_struct_\l_@@_struct_stack_parent_tmp_tl _prop}
+ { objref }
+ }
+ %record this structure as kid:
+ %\tl_show:N \g_@@_struct_stack_current_tl
+ %\tl_show:N \l_@@_struct_stack_parent_tmp_tl
+ \@@_struct_kid_struct_gput_right:nn
+ { \l_@@_struct_stack_parent_tmp_tl }
+ { \g_@@_struct_stack_current_tl }
+ %\prop_show:c { g_@@_struct_\g_@@_struct_stack_current_tl _prop }
+ %\seq_show:c {g_@@_struct_kids_\l_@@_struct_stack_parent_tmp_tl _seq}
+ }
+ %\prop_show:c { g_@@_struct_\g_@@_struct_stack_current_tl _prop }
+ %\seq_show:c {g_@@_struct_kids_\l_@@_struct_stack_parent_tmp_tl _seq}
+ \group_end:
+ }
+
+%deprecated
+\cs_set_eq:NN \uftag_struct_begin:n \tag_struct_begin:n
+
+\cs_new_protected:Nn \tag_struct_end:
+ { %take the current structure num from the stack:
+ %the objects are written later, lua mode hasn't all needed info yet
+ %\seq_show:N \g_@@_struct_stack_seq
+ \seq_gpop:NNTF \g_@@_struct_stack_seq \l_tmpa_tl
+ {
+ \int_compare:nNnT {\l_@@_loglevel_int} > { 0 }
+ {
+ \@@_check_info_closing_struct:o { \g_@@_struct_stack_current_tl }
+ }
+ }
+ { \@@_check_no_open_struck: }
+ % get the previous one, shouldn't be empty as the root should be there
+ \seq_get:NNTF \g_@@_struct_stack_seq \l_tmpa_tl
+ {
+ \tl_gset:NV \g_@@_struct_stack_current_tl \l_tmpa_tl
+ }
+ {
+ \@@_check_no_open_struck:
+ }
+ }
+
+%deprecated
+\cs_set_eq:NN \uftag_struct_end: \tag_struct_end:
+
+\cs_new_protected:Nn \tag_struct_use:n %#1 is the label
+ {
+ \prop_if_exist:cTF
+ { g_@@_struct_\@@_ref_value:enn{tagpdfstruct-#1}{tagstruct}{unknown}_prop } %??????????
+ {
+ \@@_check_struct_used:n {#1}
+ %add the label structure as kid to the current structure (can be the root)
+ \@@_struct_kid_struct_gput_right:nn
+ { \g_@@_struct_stack_current_tl }
+ { \@@_ref_value:enn{tagpdfstruct-#1}{tagstruct}{0} }
+ %add the current structure to the labeled one as parents
+ \@@_prop_gput:cnx
+ { g_@@_struct_\@@_ref_value:enn{tagpdfstruct-#1}{tagstruct}{0}_prop }
+ { P }
+ {
+ \prop_item:cn
+ { g_@@_struct_\g_@@_struct_stack_current_tl _prop}
+ { objref }
+ }
+ }
+ {
+ \msg_warning:nnn{ tag }{struct-label-unknown}{#1}
+ }
+ }
+
+\cs_set_eq:NN \uftag_struct_use:n \tag_struct_use:n
+
+
+%%%% Code to tag links
+%%%% this works for url, see exp-link.pdf.
+%%%% it must be checked for other links
+
+\cs_new_protected:Nn \@@_struct_finish_link:
+ {
+ \bool_if:NT \g_@@_active_struct_bool
+ {
+ %get the number of the parent link structure:
+ \seq_get:NNF
+ \g_@@_struct_stack_seq
+ \l_@@_struct_stack_parent_tmp_tl
+ {
+ \msg_error:nn { tag } { struct-faulty-nesting }
+ }
+ %put the obj number of link annot in the kid entry:
+ \@@_struct_kid_link_gput_right:nx
+ {
+ \l_@@_struct_stack_parent_tmp_tl
+ }
+ {
+ \pdfannot_link_ref_last:
+ }
+ % add the parent obj number to the parent tree:
+ \@@_parenttree_add_objr:nn
+ {
+ \int_use:N\c@g_@@_parenttree_obj_int
+ }
+ {
+ \prop_item:cn
+ { g_@@_struct_\l_@@_struct_stack_parent_tmp_tl _prop }
+ { objref }
+ }
+ % increase the int:
+ \stepcounter{ g_@@_parenttree_obj_int }
+ }
+ }
+
+%</struct>
+
+% \end{macrocode}
+% \begin{macrocode}
+%<*attr>
+\ProvidesExplPackage {tagpdf-attr-code} {2021/02/23} {0.80}
+ {part of tagpdf - code related to attributes and attribute classes}
+
+% the obj is written in tagpdf-tree-code.
+
+\seq_new:N \g_@@_attr_class_used_seq
+\prop_new:N \g_@@_attr_objref_prop %will contain obj num of used attributes
+
+\prop_new:N \g_@@_attr_entries_prop
+\tl_new:N \g_@@_attr_class_content_tl
+\tl_new:N \l_@@_attr_objtmp_tl
+\tl_new:N \l_@@_attr_value_tl
+
+
+\cs_new_protected:Nn \@@_attr_new_entry:nn %#1:name, #2: content
+ {
+ \prop_gput:Nnn \g_@@_attr_entries_prop
+ {#1}{#2}
+ }
+
+\keys_define:nn { @@ / setup }
+ {
+ newattribute .code:n =
+ {
+ \@@_attr_new_entry:nn #1
+ }
+ }
+
+
+% the key for the structure:
+\keys_define:nn { @@ / struct }
+ {
+ attribute-class .code:n =
+ {
+ \clist_set:No \l_tmpa_clist { #1 }
+ \seq_set_from_clist:NN \l_tmpa_seq \l_tmpa_clist
+ \seq_map_inline:Nn \l_tmpa_seq
+ {
+ \prop_if_in:NnF \g_@@_attr_entries_prop {##1}
+ {
+ \msg_error:nnn { tag } { attr-unknown } { ##1 }
+ }
+ \seq_gput_left:Nn\g_@@_attr_class_used_seq { ##1}
+ }
+ \seq_set_map:NNn \l_tmpb_seq \l_tmpa_seq
+ {
+ /##1
+ }
+ \tl_set:Nx \l_tmpa_tl
+ {
+ \int_compare:nT { \seq_count:N \l_tmpa_seq > 1 }{[}
+ \seq_use:Nn \l_tmpb_seq { \c_space_tl }
+ \int_compare:nT { \seq_count:N \l_tmpa_seq > 1 }{]}
+ }
+ \int_compare:nT { \seq_count:N \l_tmpa_seq > 0 }
+ {
+ \@@_prop_gput:cnx
+ { g_@@_struct_\int_eval:n {\c@g_@@_struct_abs_int}_prop }
+ { C }
+ { \l_tmpa_tl }
+ %\prop_show:c { g_@@_struct_\int_eval:n {\c@g_@@_struct_abs_int}_prop }
+ }
+ }
+ }
+
+\keys_define:nn { @@ / struct }
+ {
+ attribute .code:n = % A property (attribute, value currently a dictionary)
+ {
+ \clist_set:No \l_tmpa_clist { #1 }
+ \seq_set_from_clist:NN \l_tmpa_seq \l_tmpa_clist
+ \tl_set:Nx \l_@@_attr_value_tl
+ {
+ \int_compare:nT { \seq_count:N \l_tmpa_seq > 1 }{[}%]
+ }
+ \seq_map_inline:Nn \l_tmpa_seq
+ {
+ \prop_if_in:NnF \g_@@_attr_entries_prop {##1}
+ {
+ \msg_error:nnn { tag } { attr-unknown } { ##1 }
+ }
+ \prop_if_in:NnF \g_@@_attr_objref_prop {##1}
+ {%\prop_show:N \g_@@_attr_entries_prop
+ \pdf_object_unnamed_write:nx
+ { dict }
+ {
+ \prop_item:Nn\g_@@_attr_entries_prop {##1}
+ }
+ \prop_gput:Nnx \g_@@_attr_objref_prop {##1} {\pdf_object_ref_last:}
+ }
+ \tl_put_right:Nx \l_@@_attr_value_tl
+ {
+ \c_space_tl
+ \prop_item:Nn \g_@@_attr_objref_prop {##1}
+ }
+ % \tl_show:N \l_@@_attr_value_tl
+ }
+ \tl_put_right:Nx \l_@@_attr_value_tl
+ { %[
+ \int_compare:nT { \seq_count:N \l_tmpa_seq > 1 }{]}%
+ }
+ % \tl_show:N \l_@@_attr_value_tl
+ \@@_prop_gput:cnx
+ { g_@@_struct_\int_eval:n {\c@g_@@_struct_abs_int}_prop }
+ { A }
+ { \l_@@_attr_value_tl }
+ },
+ }
+%</attr>
+% \end{macrocode}
diff --git a/Master/texmf-dist/source/latex/tagpdf/tagpdf-tree.dtx b/Master/texmf-dist/source/latex/tagpdf/tagpdf-tree.dtx
new file mode 100644
index 00000000000..35f622ca1c9
--- /dev/null
+++ b/Master/texmf-dist/source/latex/tagpdf/tagpdf-tree.dtx
@@ -0,0 +1,294 @@
+% \iffalse meta-comment
+%
+%% File: tagpdf-tree.dtx
+%
+% Copyright (C) 2019-2020 Ulrike Fischer
+%
+% 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 "tagpdf 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/u-fischer/tagpdf
+%
+% for those people who are interested.
+%
+% \fi
+%
+% \begin{macrocode}
+%<@@=tag>
+%<*tree>
+\ProvidesExplPackage {tagpdf-tree-code} {2021/02/23} {0.80}
+ {part of tagpdf - code related to writing trees and dictionaries to the pdf}
+
+%this does the actual finishing:
+%Is \AfterEndDocument the best places??
+\hook_gput_code:nnn{begindocument}{tagpdf}
+ {
+ \bool_if:NT \g_@@_active_tree_bool
+ {
+ \AfterEndDocument { \tag_finish_structure: }
+ }
+ }
+
+
+% the StructTreeRoot
+% we better get the object number in any case:
+% deprecated
+%\@@_pdfreserveobjnum:N \l_tmpa_tl
+%\tl_const:Nx \c_@@_tree_obj_structtreeroot_tl { \l_tmpa_tl }
+
+%new
+\pdf_object_new:nn { c_@@_struct_0_obj }{ dict }
+
+ %need to think about the best place ...
+\hook_gput_code:nnn{begindocument}{tagpdf}
+ {
+ \bool_if:NT \g_@@_active_struct_bool
+ {
+ \pdfmanagement_add:nnx
+ { Catalog }
+ { StructTreeRoot }
+ { \pdf_object_ref:n { c_@@_struct_0_obj } }
+ }
+ }
+\cs_new_protected:Nn \@@_tree_write_structtreeroot:
+ {
+ \@@_struct_write_obj:n { 0 }
+ }
+
+\cs_new_protected:Nn \@@_tree_write_structelements:
+ {
+ \int_step_inline:nnnn {1}{1}{\c@g_@@_struct_abs_int}
+ {
+ %\prop_show:c {g_@@_struct_##1_prop}
+ \@@_struct_write_obj:n { ##1 } %write the object
+ }
+ }
+
+
+%the ParentTree
+% deprecated
+%\@@_pdfreserveobjnum:N \l_tmpa_tl
+%\tl_const:Nx \c_@@_tree_obj_parenttree_tl { \l_tmpa_tl }
+
+%new
+\pdf_object_new:nn { c_@@_tree_parenttree_obj }{ dict }
+
+% we have two sets of entries in the parent tree:
+% page streams and real objects.
+% The numbers must be distinct and ordered
+% So we rely on abspage and put the real objects at the end
+% I use a counter to have a chance to get the correct number
+% if code is process twice.
+\newcounter { g_@@_parenttree_obj_int }
+\hook_gput_code:nnn{begindocument}{tagpdf}
+ {
+ \int_gset:Nn
+ \c@g_@@_parenttree_obj_int
+ { \@@_ref_value_lastpage:nn{abspage}{100} }
+ }
+
+% we need to record the obj references:
+
+\tl_new:N \g_@@_parenttree_objr_tl
+
+\cs_new_protected:Nn \@@_parenttree_add_objr:nn %#1 Structparent number, #2 objref
+ {
+ \tl_gput_right:Nx \g_@@_parenttree_objr_tl
+ {
+ #1 \c_space_tl #2 ^^J
+ }
+ }
+
+\tl_new:N \l_@@_parenttree_content_tl
+
+\cs_new_protected:Nn \@@_tree_fill_parenttree:
+ {
+ \int_step_inline:nnnn{1}{1}{\@@_ref_value_lastpage:nn{abspage}{-1}} %not quite clear if labels are needed. See lua code
+ { %page ##1\par
+ \prop_clear:N \l_tmpa_prop
+ \int_step_inline:nnnn{1}{1}{\@@_ref_value_lastpage:nn{tagmcabs}{-1}}
+ {
+ %mcid####1
+ \int_compare:nT%F
+ {\@@_ref_value:enn{mcid-####1}{tagabspage}{-1}=##1} %mcid is on current page
+ {% yes\par
+ \prop_put:Nxx
+ \l_tmpa_prop
+ {\@@_ref_value:enn{mcid-####1}{tagmcid}{-1}}
+ {\prop_item:Nn \g_@@_mc_parenttree_prop {####1}}
+ }
+ }
+ %\prop_show:N \l_tmpa_prop
+ \tl_put_right:Nx\l_@@_parenttree_content_tl
+ {
+ \int_eval:n {##1-1}\c_space_tl
+ [\c_space_tl %]
+ }
+ \int_step_inline:nnnn
+ {0}
+ {1}
+ { \prop_map_function:NN \l_tmpa_prop\@@_prop_count:nn -1 }
+ {
+ \prop_get:NnNTF \l_tmpa_prop {####1} \l_tmpb_tl
+ {% page#1:mcid##1:\l_tmpb_tl :content
+ \tl_put_right:Nx \l_@@_parenttree_content_tl
+ {
+ \prop_item:cn { g_@@_struct_\l_tmpb_tl _prop } {objref}
+ \c_space_tl
+ }
+ %\tl_show:N \l_@@_parenttree_content_tl
+ }
+ {
+ \msg_warning:nn { tag } {tree-mcid-index-wrong}
+ }
+ }
+ \tl_put_right:Nn
+ \l_@@_parenttree_content_tl
+ {%[
+ ]^^J
+ }
+ }
+ }
+
+%lua mode must/can do it differently
+\cs_new_protected:Nn \@@_tree_lua_fill_parenttree:
+ {
+ \tl_set:Nn \l_@@_parenttree_content_tl
+ {
+ \directlua
+ {
+ ltx.@@.func.output_parenttree
+ (
+ \int_use:N\g_shipout_readonly_int
+ )
+ }
+ }
+ }
+
+
+
+\cs_new_protected:Nn \@@_tree_write_parenttree:
+ {
+ \bool_if:NTF \g_@@_mode_lua_bool
+ {
+ \@@_tree_lua_fill_parenttree:
+ }
+ {
+ \@@_tree_fill_parenttree:
+ }
+ \tl_put_right:NV \l_@@_parenttree_content_tl\g_@@_parenttree_objr_tl
+ \pdf_object_write:nx { c_@@_tree_parenttree_obj }
+ {
+ /Nums\c_space_tl [\l_@@_parenttree_content_tl]
+ }
+ }
+
+%the Rolemap tree
+%deprecated
+%\@@_pdfreserveobjnum:N \l_tmpa_tl
+%\tl_const:Nx \c_@@_tree_obj_rolemap_tl { \l_tmpa_tl }
+
+%new
+\pdf_object_new:nn { c_@@_tree_rolemap_obj }{ dict }
+
+\tl_new:N \l_@@_rolemap_content_tl
+
+\cs_new_protected:Nn \@@_tree_fill_rolemap:
+ {
+ \prop_map_inline:Nn \g_@@_role_rolemap_prop
+ {
+ \tl_put_right:Nx \l_@@_rolemap_content_tl
+ {
+ /##1\c_space_tl/##2^^J
+ }
+ }
+ }
+
+\cs_new_protected:Nn \@@_tree_write_rolemap:
+ {
+ \@@_tree_fill_rolemap:
+ \pdf_object_write:nx { c_@@_tree_rolemap_obj }
+ {
+ \l_@@_rolemap_content_tl
+ }
+ }
+
+%classmap, should only be written, if values has been used
+
+\cs_new_protected:Nn \@@_tree_write_classmap:
+ {
+ \tl_gclear:N \g_@@_attr_class_content_tl
+ \seq_gremove_duplicates:N \g_@@_attr_class_used_seq
+ \seq_set_map:NNn \l_tmpa_seq \g_@@_attr_class_used_seq
+ {
+ /##1\c_space_tl
+ <<
+ \prop_item:Nn
+ \g_@@_attr_entries_prop
+ {##1}
+ >>
+ }
+ \tl_gset:Nx \g_@@_attr_class_content_tl
+ {
+ \seq_use:Nn
+ \l_tmpa_seq
+ { \iow_newline: }
+ }
+ \tl_if_empty:NF
+ \g_@@_attr_class_content_tl
+ {
+ \pdf_object_new:nn { c_@@_tree_classmap_obj }{ dict }
+ % \@@_pdfreserveobjnum:N \l_tmpa_tl
+ % \tl_const:Nx \c_@@_tree_obj_classmap_tl { \l_tmpa_tl }
+ \pdf_object_write:nx
+ { c_@@_tree_classmap_obj }
+ { \g_@@_attr_class_content_tl }
+ \@@_prop_gput:cnx
+ { g_@@_struct_0_prop }
+ { ClassMap }
+ { \pdf_object_ref:n { c_@@_tree_classmap_obj } }
+ }
+ }
+
+
+\cs_new_protected:Nn \tag_finish_structure:
+ {
+ \@@_tree_write_parenttree:
+ \@@_tree_write_rolemap:
+ \@@_tree_write_classmap:
+ \@@_tree_write_structelements: %this is rather slow!!
+ \@@_tree_write_structtreeroot:
+ }
+
+%deprecated
+\cs_set_eq:NN \uftag_finish_structure: \tag_finish_structure:
+
+%StructParents !!! we need a better hook for \g__pdf_BACKEND_thispage_shipout_tl!!
+% No actually
+\hook_gput_code:nnn{begindocument}{tagpdf}
+ {
+ \bool_if:NT\g_@@_active_tree_bool
+ {
+ \hook_gput_code:nnn{shipout/before} { tagpdf/structparents }
+ {
+ \pdfmanagement_add:nnx
+ { Page }
+ {StructParents}
+ {\int_eval:n { \g_shipout_readonly_int}}
+ }
+ }
+ }
+
+%</tree>
+% \end{macrocode}
diff --git a/Master/texmf-dist/source/latex/tagpdf/tagpdf.dtx b/Master/texmf-dist/source/latex/tagpdf/tagpdf.dtx
new file mode 100644
index 00000000000..145b1509712
--- /dev/null
+++ b/Master/texmf-dist/source/latex/tagpdf/tagpdf.dtx
@@ -0,0 +1,498 @@
+% \iffalse meta-comment
+%
+%% File: tagpdf.dtx
+%
+% Copyright (C) 2019-2020 Ulrike Fischer
+%
+% 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 "tagpdf 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/u-fischer/tagpdf
+%
+% for those people who are interested.
+%
+% \fi
+%
+% \begin{macrocode}
+%<@@=tag>
+%<*package>
+\ProvidesExplPackage {tagpdf} {2021/02/23} {0.80}
+ { A package to experiment with pdf tagging }
+
+\bool_if:nF
+ {
+ \bool_lazy_and_p:nn
+ {\cs_if_exist_p:N \pdfmanagement_if_active_p:}
+ { \pdfmanagement_if_active_p: }
+ }
+ { %error for now, perhaps warning later.
+ \PackageError{tagpdf}
+ {
+ PDF~resource~management~is~no~active!\MessageBreak
+ tagpdf~will~no~work.
+ }
+ {
+ Activate~it~with \MessageBreak
+ \string\RequirePackage{pdfmanagement-testphase}\MessageBreak
+ \string\DeclareDocumentMetadata{<options>}\MessageBreak
+ before~\string\documentclass
+ }
+ }
+
+%\debug_on:n{check-declarations,check-expressions,deprecation}
+
+%map internal tag to package name
+\prop_if_exist:NT \g_msg_module_name_prop
+ {
+ \prop_gput:Nnn \g_msg_module_name_prop { tag }{ tagpdf }
+ }
+
+% storing internal names to my name space:
+\cs_set_eq:NN \@@_tex_global:D \tex_global:D
+
+%%% package options
+\bool_new:N\g_@@_mode_lua_bool
+
+\DeclareOption {luamode} { \sys_if_engine_luatex:T { \bool_gset_true:N \g_@@_mode_lua_bool } }
+\DeclareOption {genericmode}{ \bool_gset_false:N\g_@@_mode_lua_bool }
+\ExecuteOptions{luamode}
+\ProcessOptions
+
+%%% some packages
+%references use l3ref-tmp
+\RequirePackage{l3ref-tmp}
+ %================
+ % temporary code
+ % ===============
+ % faking the LastPage label:
+ \cs_new_protected:Npn \@@_lastpagelabel:
+ {
+ \legacy_if:nT { @filesw }
+ {
+ \exp_args:NNnx \exp_args:NNx\iow_now:Nn \@auxout
+ {
+ \token_to_str:N \newlabeldata
+ {@@_LastPage}
+ {
+ {abspage} { \int_use:N \g_shipout_readonly_int}
+ {tagmcabs}{ \int_use:N \c@g_@@_MCID_abs_int }
+ }
+ }
+ }
+ }
+
+ \AddToHook{enddocument/afterlastpage}
+ {\@@_lastpagelabel:}
+
+ % a command to override the general default. See issue in ref
+ \cs_if_exist:NF \ref_value:nnn
+ {
+ \cs_new:Npn \ref_value:nnn #1#2#3
+ {
+ \exp_args:Nee
+ \__ref_value:nnn
+ { \tl_to_str:n {#1} } { \tl_to_str:n {#2} } {#3}
+ }
+ \cs_new:Npn \__ref_value:nnn #1#2#3
+ {
+ \tl_if_exist:cTF { g__ref_label_ #1 _ #2 _tl }
+ { \tl_use:c { g__ref_label_ #1 _ #2 _tl } }
+ {
+ % test if attribute exist at all?
+ #3
+ }
+ }
+ }
+
+ %=============
+ % attributes
+ %=============
+\ref_attribute_gset:nnnn {tagstruct} {0}{now} { \int_use:N \c@g_@@_struct_abs_int }
+\ref_attribute_gset:nnnn {tagstructobj} {}{now}
+ {
+ \exp_args:Ne
+ \pdf_object_if_exist:nT {c__tag_struct_ \int_use:N \c@g__tag_struct_abs_int _obj}
+ {
+ \pdf_object_ref:e{c__tag_struct_ \int_use:N \c@g_@@_struct_abs_int _obj}
+ }
+ }
+ % replace by abspage??
+\ref_attribute_gset:nnnn {tagabspage}{0}{shipout}{ \int_use:N \g_shipout_readonly_int }
+\ref_attribute_gset:nnnn {tagmcabs } {0}{now} { \int_use:N \c@g_@@_MCID_abs_int }
+\ref_attribute_gset:nnnn {tagmcid } {0}{now} { \int_use:N \g_@@_MCID_tmp_bypage_int }
+%============
+% lists
+%============
+\clist_const:Nn \c_@@_refmc_clist {tagabspage,tagmcabs,tagmcid} %mc is new!!
+\clist_const:Nn \c_@@_refstruct_clist {tagstruct,tagstructobj}
+%=================
+% command to set a label
+%================
+\cs_generate_variant:Nn \ref_label:nn { nv }
+\cs_new_protected:Npn \@@_ref_label:nn #1 #2 %#1 label, #2 name of list mc or struct
+ {
+ \@bsphack
+ \ref_label:nv {#1}{c_@@_ref#2_clist}
+ \@esphack
+ }
+%==============
+% command to retrieve the value
+%===============
+\cs_new:Npn \@@_ref_value:nnn #1 #2 #3 %#1 label, #2 attribute, #3 default
+ {
+ \ref_value:nnn {#1}{#2}{#3}
+ }
+%===============
+% the LastPage label has a different name, so we need a special command for now
+% =============
+\cs_new:Npn \@@_ref_value_lastpage:nn #1 #2
+ {
+ \ref_value:nnn {@@_LastPage}{#1}{#2}
+ }
+
+% as ref doesn't expand label names we need variants:
+\cs_generate_variant:Nn \@@_ref_label:nn {en}
+\cs_generate_variant:Nn \@@_ref_value:nnn {enn}
+
+\RequirePackage{etoolbox}
+%\RequirePackage{l3pdf}
+%\RequirePackage{pdfescape} %check if needed
+%\RequirePackage{pdftexcmds}%check if needed (expandable commands!)
+
+%\RequirePackage{l3str-convert}
+\cs_generate_variant:Nn \str_set_convert:Nnnn {Nonn, Noon, Nnon }
+
+
+
+
+%%% tagpdfsetup,
+%%% TODO: checks need to be improved
+\int_new:N \l_@@_loglevel_int
+\tl_new:N \l_@@_tree_tabs_order_tl
+
+\keys_define:nn { @@ / setup }
+ {
+ activate-mc .bool_gset:N = \g_@@_active_mc_bool,
+ activate-tree .bool_gset:N = \g_@@_active_tree_bool,
+ activate-struct .bool_gset:N = \g_@@_active_struct_bool,
+ activate-all .meta:n ={activate-mc,activate-tree,activate-struct},
+ check-tags .bool_gset:N = \g_@@_check_tags_bool,
+ check-tags .initial:n = true,
+ log .choice:,
+ log / none .code:n = {\int_set:Nn \l_@@_loglevel_int { 0 }},
+ log / v .code:n = {\int_set:Nn \l_@@_loglevel_int { 1 }},
+ log / vv .code:n = {\int_set:Nn \l_@@_loglevel_int { 2 }},
+ log / vvv .code:n = {\int_set:Nn \l_@@_loglevel_int { 3 }},
+ log / all .code:n = {\int_set:Nn \l_@@_loglevel_int { 10 }},
+ tagunmarked .bool_gset:N = \g_@@_tagunmarked_bool,
+ tagunmarked .initial:n = true,
+ tabsorder .choice:,
+ tabsorder / row .code:n = %{\tl_set:Nn \l_@@_tree_tabs_order_tl {/Tabs/R}},
+ \pdfmanagement_add:nnn { Page } {Tabs}{/R},
+ tabsorder / column .code:n = %{\tl_set:Nn \l_@@_tree_tabs_order_tl {/Tabs/C}},
+ \pdfmanagement_add:nnn { Page } {Tabs}{/C},
+ tabsorder / structure .code:n = %{\tl_set:Nn \l_@@_tree_tabs_order_tl {/Tabs/S}},
+ \pdfmanagement_add:nnn { Page } {Tabs}{/S},
+ tabsorder / none .code:n = %{\tl_set:Nn \l_@@_tree_tabs_order_tl {}},
+ \pdfmanagement_remove:nn {Page} {Tabs},
+ tabsorder .initial:n = structure,
+ uncompress .code:n = {\pdf_uncompress: },
+ }
+%need to think about the right place ...
+%\AtBeginDocument
+\hook_gput_code:nnn{begindocument}{tagpdf}
+ {
+ \bool_if:NT \g_@@_active_struct_bool
+ {
+ \pdfmanagement_add:nnn { Catalog / MarkInfo } { Marked } { true }
+ }
+ }
+% escape commands are a bit engine specific so have been moved to the backend files.
+% commands to escape strings so that they can be safely used in pdf
+% currently not much used. But will be needed later, when alt and actualtext are added.
+% we probably need the equivalent \pdfescapestring, \pdfescapename \pdfescapehex
+% the commands of pdfescape adds an additional layout to allow for babel shorthands
+%\cs_set_eq:NN \@@_pdf_escape_string:Nn \EdefEscapeString
+%\cs_set_eq:NN \@@_pdf_escape_name:Nn \EdefEscapeName
+%\cs_set_eq:NN \@@_pdf_escape_hex:Nn \EdefEscapeHex
+
+%\cs_set_eq:NN \@@_pdf_escape_string:n \EdefEscapeString
+%\cs_set_eq:NN \@@_pdf_escape_name:Nn \EdefEscapeName
+
+%escape command. They are backend specific as \pdf@escapehex would ignore most chars
+%outside the "pdflatex" range
+
+
+
+
+
+% a hook for later code and an absolute page counter
+% should be executed before counters are resetted.
+% is it used?
+\cs_new:Nn \@@_finish_page_hook: { }
+
+%\AtBeginShipout
+
+\hook_gput_code:nnn
+ { shipout/before }
+ { tagpdf/cnt }
+ {
+ \@@_finish_page_hook:
+ %\int_gincr:N \g_@@_abspage_int
+ }
+
+
+%testing the engines and loading the backend files
+\sys_if_engine_xetex:T
+ { %lets try with xelatex ...
+ %\PackageError { tagpdf } { xelatex~is~not~supported~-~aborting } {}
+ %\tex_endinput:D
+ \file_input:n {tagpdf-pdftex.def}
+ }
+
+\sys_if_engine_luatex:T
+ {
+ \file_input:n {tagpdf-luatex.def}
+ }
+
+\sys_if_engine_pdftex:T
+ {
+ \file_input:n {tagpdf-pdftex.def}
+ }
+
+\sys_if_output_dvi:T
+ {
+ %\PackageError { tagpdf } { dvi~output~is~not~supported~-~aborting }{}
+ %\tex_endinput:D
+ }
+
+\cs_generate_variant:Nn \@@_prop_gput:Nnn { Nxn , Nxx, Nnx , cnn, cxn, cnx, cno}
+\cs_generate_variant:Nn \@@_seq_gput_right:Nn { Nx , No, cn, cx }
+\cs_generate_variant:Nn \@@_prop_new:N { c }
+\cs_generate_variant:Nn \@@_seq_new:N { c }
+\cs_generate_variant:Nn \@@_seq_show:N { c }
+\cs_generate_variant:Nn \@@_prop_show:N { c }
+\cs_generate_variant:Nn \prop_gput:Nnn {Nxx}
+\cs_generate_variant:Nn \prop_put:Nnn {Nxx}
+
+\cs_generate_variant:Nn \pdffile_embed_stream:nnn {nxx,oxx}
+\cs_generate_variant:Nn \pdf_object_ref:n {e}
+
+
+% few temp tl
+\tl_new:N \g_@@_tmpa_tl
+\tl_new:N \l_@@_tmpa_tl
+\tl_new:N \l_@@_tmpb_tl
+\tl_new:N \l_@@_tmpc_tl
+\tl_new:N \l_@@_tmpd_tl
+\tl_new:N \l_@@_tmpe_tl
+\str_new:N \l_@@_tmpa_str
+
+% helper function to get the propcount.
+% use as \prop_map_function:NN PROP { \@@_prop_count:nn -1 }
+\cs_new:Nn\@@_prop_count:nn { + 1 }
+
+%% Loading the tagpdf sub packages
+\RequirePackage { tagpdf-checks-code }
+\RequirePackage { tagpdf-user }
+\RequirePackage { tagpdf-tree-code }
+\RequirePackage { tagpdf-roles-code }
+\RequirePackage { tagpdf-attr-code }
+% mc-code is split:
+\RequirePackage { tagpdf-mc-code-shared }
+\bool_if:NTF \g_@@_mode_lua_bool
+ {
+ \RequirePackage {tagpdf-mc-code-lua}
+ }
+ {
+ \RequirePackage { tagpdf-mc-code-generic } %
+ }
+
+\RequirePackage { tagpdf-struct-code }
+\RequirePackage { tagpdf-space-code }
+%</package>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<*user>
+\ProvidesExplPackage {tagpdf-user} {2021/02/23} {0.80}
+ {tagpdf - user commands}
+
+\NewDocumentCommand \tagpdfsetup { m }
+ {
+ \keys_set:nn { @@ / setup } { #1 }
+ }
+
+\cs_set_eq:NN\tagpdfifluatexTF \sys_if_engine_luatex:TF
+\cs_set_eq:NN\tagpdfifluatexT \sys_if_engine_luatex:T
+\cs_set_eq:NN\tagpdfifpdftexT \sys_if_engine_pdftex:T
+
+%%% stop tagging
+\bool_new:N \l_@@_stop_bool
+
+\prg_new_conditional:Nnn \@@_if_stop: {p,T,F,TF}
+ {
+ \bool_if:NTF \l_@@_stop_bool
+ { \prg_return_true: }
+ { \prg_return_false: }
+ }
+
+\prg_new_eq_conditional:NNn \tag_if_stop: \@@_if_stop: {p,T,F,TF}
+
+\cs_new_protected:Npn \@@_stop:
+ {
+ \bool_set_true:N \l_@@_stop_bool
+ \cs_set_eq:NN \tag_mc_begin:n \use_none:n
+ \cs_set_eq:NN \tag_mc_end: \prg_do_nothing:
+ \cs_set_eq:NN \tag_mc_use:n \use_none:n
+ \cs_set_eq:NN \tag_struct_begin:n \use_none:n
+ \cs_set_eq:NN \tag_struct_end: \prg_do_nothing:
+ \cs_set_eq:NN \tag_struct_use:n \use_none:n
+ %deprecated
+ \cs_set_eq:NN \uftag_mc_begin:n \tag_mc_begin:n
+ \cs_set_eq:NN \uftag_mc_end: \tag_mc_end:
+ \cs_set_eq:NN \uftag_mc_use:n \tag_mc_use:n
+ \cs_set_eq:NN \uftag_struct_begin:n \tag_struct_begin:n
+ \cs_set_eq:NN \uftag_struct_end: \tag_struct_end:
+ \cs_set_eq:NN \uftag_struct_use:n \tag_struct_use:n
+ }
+
+\cs_new_protected:Npn \tag_stop_group_begin:
+ {
+ \group_begin:
+ \@@_stop:
+ }
+
+\cs_set_eq:NN \tag_stop_group_end: \group_end:
+
+
+%%% a generic command to retrieve data
+
+\cs_new:Npn \tagpdfget #1 { \use:c {@@_get_data_#1: } }
+\cs_new:Npn \tag_get:n #1 { \use:c {@@_get_data_#1: } }
+%deprecated:
+\cs_new:Npn \uftag_get:n #1 { \use:c {@@_get_data_#1: } }
+
+
+%%%% mc related user commands
+\NewDocumentCommand \tagmcifinTF { m m }
+ {
+ \@@_mc_if_in:TF { #1 } { #2 }
+ }
+
+
+\NewDocumentEnvironment{tagmcartifact}{m}
+ {
+ \tag_mc_artifact_group_begin:n { #1}\ignorespaces
+ }
+ {
+ \tag_mc_artifact_group_end:
+ }
+
+\NewDocumentCommand \tagmcbegin { m }
+ {
+ \tag_mc_begin:n {#1}\ignorespaces
+ }
+
+
+\NewDocumentCommand \tagmcend { }
+ {
+ \unskip % this unskip appears to mess up some spacing; can we do this in another way?
+ \tag_mc_end:
+ }
+
+\NewDocumentCommand \tagmcuse { m }
+ {
+ \tag_mc_use:n {#1}
+ }
+
+
+%%%% structure related commands
+
+\NewDocumentCommand \tagstructbegin { m }
+ {
+ \tag_struct_begin:n {#1}
+ }
+
+\NewDocumentCommand \tagstructend { }
+ {
+ \tag_struct_end:
+ }
+
+\NewDocumentCommand \tagstructuse { m }
+ {
+ \tag_struct_use:n {#1}
+ }
+
+
+
+%%%% debug/show commands
+\NewDocumentCommand\showtagpdfmcdata { O {\@@_tag_get_mc_abs_cnt:} }
+ {
+ \bool_if:NT \g_@@_mode_lua_bool
+ {
+ \sys_if_engine_luatex:T
+ {
+ \directlua{ltx.@@.trace.show_all_mc_data(#1)}
+ }
+ }
+ }
+
+\NewDocumentCommand\showtagpdfattributes { }
+ {
+ \bool_if:NT \g_@@_mode_lua_bool
+ {
+ \sys_if_engine_luatex:T
+ {
+ \directlua
+ {
+ ltx.@@.trace.log
+ (
+ "showtagpdfattributes:
+ MC=>abscnt=\@@_get_mc_abs_cnt:
+ =>attr=\the\l_@@_mc_cnt_attr=>tag="
+ ..
+ tostring(ltx.@@.func.get_tag_from (\the\l_@@_mc_type_attr))
+ ..
+ "=\the\l_@@_mc_type_attr",0
+ )
+ }
+ \ignorespaces
+ }
+ }
+ }
+
+\sys_if_engine_luatex:T
+ {
+ \NewDocumentCommand\pdffakespace { }
+ {
+ \@@_fakespace:
+ }
+ }
+
+%</user>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<*deprecated>
+% \uftag_get:n
+% \uftag_mc_if_in:
+% \uftag_mc_begin:n
+% \uftag_mc_end:
+% \uftag_mc_use:n
+% \uftag_struct_begin:n
+% \uftag_struct_end:
+% \uftag_finish_structure:
+%</deprecated>
+% \end{macrocode}
diff --git a/Master/texmf-dist/source/latex/tagpdf/tagpdf.ins b/Master/texmf-dist/source/latex/tagpdf/tagpdf.ins
new file mode 100644
index 00000000000..c94a1808ded
--- /dev/null
+++ b/Master/texmf-dist/source/latex/tagpdf/tagpdf.ins
@@ -0,0 +1,100 @@
+\iffalse meta-comment
+
+File: tagpdf.ins
+
+Copyright (C) 2019 Ulrike Fischer
+
+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 "tagpdf 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/u-fischer/tagpdf
+
+for those people who are interested.
+
+-----------------------------------------------------------------------
+
+\fi
+
+\input l3docstrip.tex
+\askforoverwritefalse
+
+\let\MetaPrefix\relax
+\preamble
+
+Copyright (C) 2019 Ulrike Fischer
+
+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 "tagpdf 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{tagpdf.sty} {\from{tagpdf.dtx}{package}}}
+\generate
+ {\file{tagpdf-user.sty} {\from{tagpdf.dtx}{user}}}
+\generate
+ {\file{tagpdf-deprecated.def}{\from{tagpdf.dtx}{deprecated}}}
+
+\generate
+ {\file{tagpdf-luatex.def}{\from{tagpdf-backend.dtx}{luatex}}}
+\generate
+ {\file{tagpdf-pdftex.def}{\from{tagpdf-backend.dtx}{pdftex}}}
+
+\generate
+ {\file{tagpdf-mc-code-shared.sty}{\from{tagpdf-mc.dtx}{shared}}}
+\generate
+ {\file{tagpdf-mc-code-generic.sty}{\from{tagpdf-mc.dtx}{generic}}}
+\generate
+ {\file{tagpdf-mc-code-lua.sty}{\from{tagpdf-mc.dtx}{luamode}}}
+
+\generate
+ {\file{tagpdf-struct-code.sty}{\from{tagpdf-struct.dtx}{struct}}}
+\generate
+ {\file{tagpdf-attr-code.sty}{\from{tagpdf-struct.dtx}{attr}}}
+
+\generate
+ {\file{tagpdf-checks-code.sty}{\from{tagpdf-checks.dtx}{checks}}}
+
+\generate
+ {\file{tagpdf-roles-code.sty}{\from{tagpdf-roles.dtx}{roles}}}
+
+\generate
+ {\file{tagpdf-space-code.sty}{\from{tagpdf-space.dtx}{space}}}
+
+\generate
+ {\file{tagpdf-tree-code.sty}{\from{tagpdf-tree.dtx}{tree}}}
+
+\def\MetaPrefix{-- }
+\def\defaultpostamble{%
+ \MetaPrefix^^J%
+ \MetaPrefix\space End of File `\outFileName'.%
+}
+\def\currentpostamble{\defaultpostamble}%
+\generate{\file{tagpdf.lua} {\from{tagpdf-backend.dtx}{lua}}}
+\endbatchfile
diff --git a/Master/texmf-dist/source/latex/tikzmark/tikzmark.dtx b/Master/texmf-dist/source/latex/tikzmark/tikzmark.dtx
index 4dfaeb6e78d..88aec1a4ed7 100644
--- a/Master/texmf-dist/source/latex/tikzmark/tikzmark.dtx
+++ b/Master/texmf-dist/source/latex/tikzmark/tikzmark.dtx
@@ -36,7 +36,7 @@ See http://www.latex-project.org/lppl.txt
\endpreamble
\postamble
-Copyright (C) 2011-2018 by Andrew Stacey <loopspace@mathforge.org>
+Copyright (C) 2011-2021 by Andrew Stacey <loopspace@mathforge.org>
This work may be distributed and/or modified under the
conditions of the LaTeX Project Public License (LPPL), either
@@ -206,7 +206,7 @@ and the derived files tikzmark.ins,
%</driver>
% \fi
%
-% \CheckSum{1138}
+% \CheckSum{1178}
%
% \CharacterTable
% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
@@ -234,18 +234,19 @@ and the derived files tikzmark.ins,
% \changes{1.6}{2018/10/18}{Added the ability to save node information between runs and between TeX documents}
% \changes{1.7}{2019/05/07}{Added conditions to test if a tikzmark is on a particular page}
% \changes{1.8}{2019/10/04}{Fixed some bugs with subnode and tikzmarknode inside maths}
+% \changes{1.10}{2021/02/16}{Tikzmarknode is now prefix and suffix aware, and added a test to see if a picture id has been saved to the aux file for times when pictures are thrown away, eg in AMS's text command}
%
% \DoNotIndex{\newcommand,\newenvironment}
%
+% \GetFileInfo{tikzlibrarytikzmark.code.tex}
% \providecommand*{\url}{\texttt}
% \title{The \textsf{tikzmark} package}
% \author{Andrew Stacey \\ \url{loopspace@mathforge.org}}
-% \date{v1.8~from 2019/10/04}
+% \date{\fileversion~from \filedate}
%
%
% \maketitle
%
-%
% \section{Introduction}
%
% The \Verb+\tikzmark+ macro burst onto the scene in a blaze of glory on \href{http://tex.stackexchange.com}{TeX-SX}.
@@ -452,6 +453,23 @@ and the derived files tikzmark.ins,
% This is the TikZ key that is used by \Verb+\tikzmark+ to actually save the connection between the name and the picture coordinate.
% It can be used on an arbitrary picture to save its origin as a tikzmark.
%
+% \item \Verb+/tikz/check picture id+
+%
+% There are circumstances where, behind the scenes, a tikzpicture is actually placed in a box and processed several times (often this involves \Verb+\mathchoice+).
+% In such a situation, when defining nodes then the last one ``wins'' in that each node remembers the id of the last processed picture.
+% However, only the one that is actually used has its location remembered on the page (since the others don't have a position).
+% This can lead to the situation whereby a node becomes disassociated from its picture and so using it for later reference fails.
+% This key tries to get around that situation by checking the \Verb+aux+ file to see if the current picture was actually typeset last time (by checking for the presence of the remembered location) and if it find that it wasn't, it quietly appends the string \Verb+discard-+ to each node name.
+% The idea being that the version of the picture that is actually typeset will not have this happen and so its nodes ``survive''.
+%
+% \item \Verb+/tikz/maybe define node=#1+
+%
+% The previous key can lead to undefined nodes on the first time that the picture is processed.
+% Using this key will ensure that the specified node is aliased to its \Verb+discard-+ version providing it doesn't already exist.
+% This is purely to get rid of pointless error messages, and also should only be used in conjunction with \Verb+check picture id+.
+%
+% Note that due to the order in which code gets executed, \Verb+check picture id+ should be before any \Verb+maybe define node+ keys.
+%
% \item \Verb+/tikz/if picture id=#1#2#3+
%
% This is a key equivalent of the \Verb+\iftikzmark+ command.
@@ -791,6 +809,10 @@ and the derived files tikzmark.ins,
%
% The \Verb+save nodes+ code uses \LaTeX3.
% \begin{macrocode}
+\ProvidesFile{tikzlibrarytikzmark.code.tex}[%
+ 2021/02/16
+ v1.10
+ TikZ library for marking positions in a document]
\RequirePackage{expl3, l3keys2e, xparse}
% \end{macrocode}
%
@@ -819,6 +841,44 @@ and the derived files tikzmark.ins,
},
},
% \end{macrocode}
+% There are times when some code is executed and then discarded, such as in \Verb+\mathchoice+.
+% This can seriously mess with how TikZ pictures are remembered as the last \Verb+pgfpictureid+ to be \emph{processed} is the one that is used, but it is the one that is \emph{used} that is recorded in the \Verb+aux+ file.
+% This isn't particularly a tikzmark issue, but does come up from time to time with tikzmark as it's all about remembering locations.
+%
+% In actual fact, it only occurs with \Verb+\tikzmarknode+ since the issue is about how nodes are associated with pictures.
+%
+% The solution is to check to see if the \Verb+pgfpictureid+ has been recorded in the \Verb+aux+ file and if it hasn't, quietly prefix the node names with a discard term.
+% This needs to be used \emph{after} \Verb+remember picture+ has been invoked.
+% It probably messes with some other stuff so should only be used under controlled conditions, such as \Verb+\tikzmarknode+.
+% \begin{macrocode}
+ check picture id/.code={
+ \ifpgfrememberpicturepositiononpage
+ \@ifundefined{pgf@sys@pdf@mark@pos@\pgfpictureid}{%
+ \tikzset{%
+ name prefix/.get=\tzmk@name@prefix,
+ name prefix/.prefix=discard-,
+ execute at end picture={%
+ \tikzset{name prefix/.expand once=\tzmk@name@prefix}%
+ },
+ }%
+ }{}%
+ \fi
+ },
+% \end{macrocode}
+% We also want a failsafe that quietly handles the case where the document hasn't been compiled enough times (once) to get the information into the \Verb+aux+ file.
+% There will already be messages about needing reruns so we don't need to add to that.
+% We simply ensure that the node exists.
+% \begin{macrocode}
+ maybe define node/.style={%
+ execute at end picture={%
+ \ifpgfrememberpicturepositiononpage
+ \@ifundefined{pgf@sh@pi@\tikz@pp@name{#1}}{%
+ \pgfnodealias{\tikz@pp@name{#1}}{discard-\tikz@pp@name{#1}}%
+ }{}%
+ \fi
+ }%
+ },
+% \end{macrocode}
% The positions are already recorded in the \Verb+aux+ file, all we really need to do is provide them with better names.
% \begin{macrocode}
save picture id/.code={%
@@ -860,10 +920,14 @@ and the derived files tikzmark.ins,
\@ifundefined{save@pt@\tikzmark@pp@name{#1}}{%
\pgfkeysalso{#3}%
}{%
- \@ifundefined{save@pg@\csname save@pt@\tikzmark@pp@name{#1}\endcsname}{%
+ \@ifundefined{%
+ save@pg@\csname save@pt@\tikzmark@pp@name{#1}\endcsname
+ }{%
\pgfkeysalso{#3}%
}{%
- \ifnum\csname save@pg@\csname save@pt@\tikzmark@pp@name{#1}\endcsname\endcsname=\the\value{page}\relax%
+ \ifnum\csname save@pg@%
+ \csname save@pt@\tikzmark@pp@name{#1}\endcsname%
+ \endcsname=\the\value{page}\relax%
\pgfkeysalso{#2}%
\else
\pgfkeysalso{#3}%
@@ -875,10 +939,14 @@ and the derived files tikzmark.ins,
\@ifundefined{save@pt@\tikzmark@pp@name{#1}}{%
\pgfkeysalso{#4}%
}{%
- \@ifundefined{save@pg@\csname save@pt@\tikzmark@pp@name{#1}@label\endcsname}{%
+ \@ifundefined{%
+ save@pg@\csname save@pt@\tikzmark@pp@name{#1}@label\endcsname%
+ }{%
\pgfkeysalso{#4}%
}{%
- \ifnum\csname save@pg@\csname save@pt@\tikzmark@pp@name{#1}\endcsname\endcsname=#2\relax%
+ \ifnum\csname save@pg@%
+ \csname save@pt@\tikzmark@pp@name{#1}\endcsname%
+ \endcsname=#2\relax%
\pgfkeysalso{#3}%
\else
\pgfkeysalso{#4}%
@@ -969,7 +1037,12 @@ and the derived files tikzmark.ins,
\@ifundefined{save@pg@\csname save@pt@\tmk@label\endcsname}{}{%
\@ifundefined{save@pg@\pgfpictureid}{}{%
\pgfkeysvalueof{/tikz/next page vector}%
- \edef\tmk@pg{\the\numexpr \csname save@pg@\csname save@pt@\tmk@label\endcsname\endcsname - \csname save@pg@\pgfpictureid\endcsname\relax}%
+ \edef\tmk@pg{%
+ \the\numexpr \csname save@pg@%
+ \csname save@pt@\tmk@label\endcsname\endcsname%
+ -
+ \csname save@pg@\pgfpictureid\endcsname\relax%
+ }%
\ifnum \tmk@pg > 0 \relax
\advance \pgf@xa by \pgf@x\relax
\advance \pgf@ya by \pgf@y\relax
@@ -995,6 +1068,7 @@ and the derived files tikzmark.ins,
% This version is for when we're outside a tikzpicture environment
% \begin{macrocode}
\newcommand\tikzmark@outside[2][]{%
+\tikzset{external/export next/.try=false}%
\tikz[remember picture with id=#2]{#1}%
}
% \end{macrocode}
@@ -1004,7 +1078,8 @@ and the derived files tikzmark.ins,
\tikzset{remember picture}%
\tikz@scan@one@point\pgfutil@firstofone#2\relax
\protected@write\pgfutil@auxout{}{%
- \string\savepointas{\tikzmark@pp@name{#1}}{\pgfpictureid}{\the\pgf@x}{\the\pgf@y}}%
+ \string\savepointas%
+ {\tikzmark@pp@name{#1}}{\pgfpictureid}{\the\pgf@x}{\the\pgf@y}}%
}
% \end{macrocode}
% And finally, the ultimate invoker:
@@ -1111,7 +1186,9 @@ and the derived files tikzmark.ins,
\@ifundefined{save@pg@\csname save@pt@\tikzmark@pp@name{#1}\endcsname}{%
\tikzmark@false
}{%
- \ifnum\csname save@pg@\csname save@pt@\tikzmark@pp@name{#1}\endcsname\endcsname=#2\relax%
+ \ifnum\csname save@pg@%
+ \csname save@pt@\tikzmark@pp@name{#1}\endcsname%
+ \endcsname=#2\relax%
\tikzmark@true
\else
\tikzmark@false
@@ -1132,7 +1209,9 @@ and the derived files tikzmark.ins,
\@ifundefined{save@pg@\csname save@pt@\tikzmark@pp@name{#1}\endcsname}{%
\tikzmark@false
}{%
- \ifnum\csname save@pg@\csname save@pt@\tikzmark@pp@name{#1}\endcsname\endcsname=\the\value{page}\relax%
+ \ifnum\csname save@pg@%
+ \csname save@pt@\tikzmark@pp@name{#1}\endcsname%
+ \endcsname=\the\value{page}\relax%
\tikzmark@true
\else
\tikzmark@false
@@ -1252,10 +1331,13 @@ and the derived files tikzmark.ins,
% It does its best to work inside a math environment by a sneaky trick involving \Verb+\mathchoice+: the \Verb+remember picture+ key means that only the picture id of the typeset box is saved to the aux file. So comparing the possible picture ids of the four options with the one read from the aux file, we can figure out which box was actually used.
% \begin{macrocode}
\def\tikzmarknode@#1#2#3{%
+\tikzset{external/export next/.try=false}%
\tikz[%
remember picture,
- baseline=(#2.base),
save picture id={#2},
+ check picture id,
+ maybe define node={#2},
+ baseline=(#2.base),
every tikzmarknode picture/.try
] {
\node[
@@ -1290,25 +1372,25 @@ and the derived files tikzmark.ins,
\expandafter\ifx\csname\tzmk@pic\endcsname\relax
\edef\tzmk@pic{\tzmk@prfx\the\numexpr\the\pgf@picture@serial@count-3\relax}%
\expandafter\ifx\csname\tzmk@pic\endcsname\relax
- \pgfutil@ifundefined{pgf@sh@ns@#2}{%
- \pgfnodealias{#2}{#2-t}%
- \tikzmarkalias{#2}{#2-t}%
+ \pgfutil@ifundefined{pgf@sh@ns@\tikz@pp@name{#2}}{%
+ \pgfnodealias{\tikz@pp@name{#2}}{\tikz@pp@name{#2-t}}%
+ \tikzmarkalias{\tikzmark@pp@name{#2}}{\tikzmark@pp@name{#2-t}}%
}{}%
\else
- \pgfnodealias{#2}{#2-d}%
- \tikzmarkalias{#2}{#2-d}%
+ \pgfnodealias{\tikz@pp@name{#2}}{\tikz@pp@name{#2-d}}%
+ \tikzmarkalias{\tikzmark@pp@name{#2}}{\tikzmark@pp@name{#2-d}}%
\fi
\else
- \pgfnodealias{#2}{#2-t}%
- \tikzmarkalias{#2}{#2-t}%
+ \pgfnodealias{\tikz@pp@name{#2}}{\tikz@pp@name{#2-t}}%
+ \tikzmarkalias{\tikzmark@pp@name{#2}}{\tikzmark@pp@name{#2-t}}%
\fi
\else
- \pgfnodealias{#2}{#2-s}%
- \tikzmarkalias{#2}{#2-s}%
+ \pgfnodealias{\tikz@pp@name{#2}}{\tikz@pp@name{#2-s}}%
+ \tikzmarkalias{\tikzmark@pp@name{#2}}{\tikzmark@pp@name{#2-s}}%
\fi
\else
- \pgfnodealias{#2}{#2-ss}%
- \tikzmarkalias{#2}{#2-ss}%
+ \pgfnodealias{\tikz@pp@name{#2}}{\tikz@pp@name{#2-ss}}%
+ \tikzmarkalias{\tikzmark@pp@name{#2}}{\tikzmark@pp@name{#2-ss}}%
\fi
\else
\tikzmarknode@{#1}{#2}{#3}%
@@ -1886,8 +1968,10 @@ and the derived files tikzmark.ins,
%
% \begin{macro}{\iflst@linemark}
% A conditional to help with placing the mark at the first non-whitespace character.
+% Should be set to true so that we notice the first line of the code.
% \begin{macrocode}
- \newif\iflst@linemark
+ \newif\iflst@linemark
+ \lst@linemarktrue
% \end{macrocode}
% \end{macro}
%
diff --git a/Master/texmf-dist/source/latex/tikzmark/tikzmark.ins b/Master/texmf-dist/source/latex/tikzmark/tikzmark.ins
deleted file mode 100644
index 35220fff636..00000000000
--- a/Master/texmf-dist/source/latex/tikzmark/tikzmark.ins
+++ /dev/null
@@ -1,76 +0,0 @@
-%%
-%% This is file `tikzmark.ins',
-%% generated with the docstrip utility.
-%%
-%% The original source files were:
-%%
-%% tikzmark.dtx (with options: `install')
-%% ----------------------------------------------------------------
-%% tikzmark --- remembering absolute positioning with TikZ.
-%% E-mail: loopspace@mathforge.org
-%% Released under the LaTeX Project Public License v1.3c or later
-%% See http://www.latex-project.org/lppl.txt
-%% ----------------------------------------------------------------
-%%
-\input docstrip.tex
-\keepsilent
-\askforoverwritefalse
-\preamble
-----------------------------------------------------------------
-tikzmark --- remembering absolute positioning with TikZ.
-E-mail: loopspace@mathforge.org
-Released under the LaTeX Project Public License v1.3c or later
-See http://www.latex-project.org/lppl.txt
-----------------------------------------------------------------
-
-\endpreamble
-\postamble
-
-Copyright (C) 2011-2018 by Andrew Stacey <loopspace@mathforge.org>
-
-This work 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 work is "maintained" (as per LPPL maintenance status) by
-Andrew Stacey.
-
-This work consists of the file tikzmark.dtx
-and the derived files tikzmark.ins,
- tikzmark.pdf,
- tikzlibrarytikzmark.code.tex, and
- tikzmarklibrarylistings.code.tex
-
-\endpostamble
-\usedir{tex/latex/tikzmark}
-\generate{
- \file{tikzlibrarytikzmark.code.tex}{\from{\jobname.dtx}{tikzlibrary}}
-}
-\generate{
- \file{tikzmarklibrarylistings.code.tex}{\from{\jobname.dtx}{listings}}
-}
-\endbatchfile
-%%
-%% Copyright (C) 2011-2018 by Andrew Stacey <loopspace@mathforge.org>
-%%
-%% This work 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 work is "maintained" (as per LPPL maintenance status) by
-%% Andrew Stacey.
-%%
-%% This work consists of the file tikzmark.dtx
-%% and the derived files tikzmark.ins,
-%% tikzmark.pdf,
-%% tikzlibrarytikzmark.code.tex, and
-%% tikzmarklibrarylistings.code.tex
-%%
-%%
-%% End of file `tikzmark.ins'.
diff --git a/Master/texmf-dist/source/latex/udesoftec/CHANGELOG b/Master/texmf-dist/source/latex/udesoftec/CHANGELOG
index 293c6840751..bd0d036b9b9 100644
--- a/Master/texmf-dist/source/latex/udesoftec/CHANGELOG
+++ b/Master/texmf-dist/source/latex/udesoftec/CHANGELOG
@@ -1,13 +1,20 @@
The version number of all files is changed for every release. Please refer to the details below in order to see which files were changed.
-
+
+2021/02/22 v1.7.1
+* [udesoftec-bibcommon.sty] fixing \bbldoi by switching to pkg:uri
+* [udesoftec.cls] re-enabled auto-output of glossary if existing
+* [udesoftec.cls] add pkg:bookmark to replace bookmarks from pkg:hyperref
+* [udesoftec-biblatex.sty] fix deprecated extrayear
+* [udesoftec-bibcommon.sty] fix deprecated \ifnumber
+* [udesoftec.cls] remove supervisor from example front page
+* [udesoftec.cls] remove deprecationwarnings for \clearscr*
+
2020/03/09 v1.6.6
-* Bumping version number
-
-2020/03/09 v1.7.0
-* Bumping version number
-
-2018/06/20 v1.6.5
-* Bumping version number
+* [udesoftec.cls] fix confidentially clause
+* improve build steps for package, linting of files
+
+2018/06/20 v1.6.5 (unreleased)
+* internal changes
2018/04/24 v1.6.4 (unreleased)
* [udesoftec.cls] fix statutory declaration
diff --git a/Master/texmf-dist/source/latex/udesoftec/README b/Master/texmf-dist/source/latex/udesoftec/README
index 6c76f5355fa..715b50dc96c 100644
--- a/Master/texmf-dist/source/latex/udesoftec/README
+++ b/Master/texmf-dist/source/latex/udesoftec/README
@@ -3,7 +3,7 @@ udesoftec documentclass and bibstyle
Maintainer: J. Peter M. Schuler
E-Mail: j.peter.m.schuler at uni dash due dot de
Copyright: 2013-2015 J. Peter M. Schuler
-Version: 1.6.6 2020/03/09
+Version: 1.7.1 2021/02/22
License: lppl
Topic: dissertation
@@ -18,7 +18,7 @@ Description:
It is based on pdflatex and bibtex using UTF-8 encoded files. It is
thorougly tested on Windows/MikTeX and OSX/BasicTeX, works as well under
- sharelatex.com and thus should be plattform independent.
+ overleaf.com and thus should be plattform independent.
For more information see the instructions in udesoftec-doc.pdf - complete
instructions are available in German, a short abstract in English gives
diff --git a/Master/texmf-dist/source/latex/udesoftec/UPDATE-INSTRUCTIONS b/Master/texmf-dist/source/latex/udesoftec/UPDATE-INSTRUCTIONS
index 5ddcc71b267..be7a4a83d8c 100644
--- a/Master/texmf-dist/source/latex/udesoftec/UPDATE-INSTRUCTIONS
+++ b/Master/texmf-dist/source/latex/udesoftec/UPDATE-INSTRUCTIONS
@@ -1,5 +1 @@
Please look in udesoftec-doc.pdf appendix chapter A.2.
-
-In order to know when an update is available a
-filtered CTAN announce RSS feed is available at
-http://pipes.yahoo.com/jpmschuler/udesoftec?_render=rss \ No newline at end of file
diff --git a/Master/texmf-dist/source/latex/udesoftec/udesoftec-doc-examplebib.bib b/Master/texmf-dist/source/latex/udesoftec/udesoftec-doc-examplebib.bib
index 45a12d23754..87f5ed73bf6 100644
--- a/Master/texmf-dist/source/latex/udesoftec/udesoftec-doc-examplebib.bib
+++ b/Master/texmf-dist/source/latex/udesoftec/udesoftec-doc-examplebib.bib
@@ -22,7 +22,7 @@
booktitle = {Web Engineering},
year = {2006},
address = {Berlin/Heidelberg},
- doi = {10.1007/3-540-28218-1_5}
+ doi = {10.1007/3-540-28218-1\textunderscore 5}
}
@incollection{Mendes.et.al.2006b,
@@ -117,7 +117,6 @@
publisher = {Gabler},
isbn = {978-3-8349-2114-7}
}
-
@techstandard{IEEEStd-1016:1998,
year = {1998-09-23},
title = {IEEE Recommended Practice for Software Design Descriptions},
@@ -126,4 +125,4 @@
author = {IEEE},
type = {IEEE Std},
standard = {IEEE Std 1016-1998}
-}
+} \ No newline at end of file
diff --git a/Master/texmf-dist/source/latex/udesoftec/udesoftec-doc.tex b/Master/texmf-dist/source/latex/udesoftec/udesoftec-doc.tex
index 82d86470bc4..e4e61bb86f6 100644
--- a/Master/texmf-dist/source/latex/udesoftec/udesoftec-doc.tex
+++ b/Master/texmf-dist/source/latex/udesoftec/udesoftec-doc.tex
@@ -1,7 +1,7 @@
% !Mode:: "TeX:UTF-8"
%% udesoftec-doc.tex
%% Copyright 2015 J. Peter M. Schuler
-%% 2020/03/09 v1.7.0 udesoftec
+%% 2021/02/22 v1.7.1 udesoftec
\documentclass[de,omit-sd,omit-lol]{udesoftec}
\usepackage{udesoftec-extra}